• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2018 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.android.settings.core;
18 
19 import android.annotation.StringRes;
20 import android.content.Context;
21 import android.content.Intent;
22 import android.os.Bundle;
23 import android.os.UserHandle;
24 import android.text.TextUtils;
25 
26 import androidx.annotation.VisibleForTesting;
27 import androidx.fragment.app.Fragment;
28 
29 import com.android.settings.SettingsActivity;
30 import com.android.settings.SubSettings;
31 import com.android.settingslib.core.instrumentation.MetricsFeatureProvider;
32 import com.android.settingslib.transition.SettingsTransitionHelper.TransitionType;
33 
34 public class SubSettingLauncher {
35 
36     private final Context mContext;
37     private final LaunchRequest mLaunchRequest;
38     private boolean mLaunched;
39 
SubSettingLauncher(Context context)40     public SubSettingLauncher(Context context) {
41         if (context == null) {
42             throw new IllegalArgumentException("Context must be non-null.");
43         }
44         mContext = context;
45         mLaunchRequest = new LaunchRequest();
46         mLaunchRequest.mTransitionType = TransitionType.TRANSITION_SHARED_AXIS;
47     }
48 
setDestination(String fragmentName)49     public SubSettingLauncher setDestination(String fragmentName) {
50         mLaunchRequest.mDestinationName = fragmentName;
51         return this;
52     }
53 
54     /**
55      * Set title with resource string id.
56      *
57      * @param titleResId res id of string
58      */
setTitleRes(@tringRes int titleResId)59     public SubSettingLauncher setTitleRes(@StringRes int titleResId) {
60         return setTitleRes(null /*titlePackageName*/, titleResId);
61     }
62 
63     /**
64      * Set title with resource string id, and package name to resolve the resource id.
65      *
66      * @param titlePackageName package name to resolve resource
67      * @param titleResId       res id of string, will use package name to resolve
68      */
setTitleRes(String titlePackageName, @StringRes int titleResId)69     public SubSettingLauncher setTitleRes(String titlePackageName, @StringRes int titleResId) {
70         mLaunchRequest.mTitleResPackageName = titlePackageName;
71         mLaunchRequest.mTitleResId = titleResId;
72         mLaunchRequest.mTitle = null;
73         return this;
74     }
75 
76     /**
77      * Set title with text,
78      * This method is only for user generated string,
79      * display text will not update after locale change,
80      * if title string is from resource id, please use setTitleRes.
81      *
82      * @param title text title
83      */
setTitleText(CharSequence title)84     public SubSettingLauncher setTitleText(CharSequence title) {
85         mLaunchRequest.mTitle = title;
86         return this;
87     }
88 
setArguments(Bundle arguments)89     public SubSettingLauncher setArguments(Bundle arguments) {
90         mLaunchRequest.mArguments = arguments;
91         return this;
92     }
93 
setExtras(Bundle extras)94     public SubSettingLauncher setExtras(Bundle extras) {
95         mLaunchRequest.mExtras = extras;
96         return this;
97     }
98 
setSourceMetricsCategory(int sourceMetricsCategory)99     public SubSettingLauncher setSourceMetricsCategory(int sourceMetricsCategory) {
100         mLaunchRequest.mSourceMetricsCategory = sourceMetricsCategory;
101         return this;
102     }
103 
setResultListener(Fragment listener, int resultRequestCode)104     public SubSettingLauncher setResultListener(Fragment listener, int resultRequestCode) {
105         mLaunchRequest.mRequestCode = resultRequestCode;
106         mLaunchRequest.mResultListener = listener;
107         return this;
108     }
109 
addFlags(int flags)110     public SubSettingLauncher addFlags(int flags) {
111         mLaunchRequest.mFlags |= flags;
112         return this;
113     }
114 
setUserHandle(UserHandle userHandle)115     public SubSettingLauncher setUserHandle(UserHandle userHandle) {
116         mLaunchRequest.mUserHandle = userHandle;
117         return this;
118     }
119 
setTransitionType(int transitionType)120     public SubSettingLauncher setTransitionType(int transitionType) {
121         mLaunchRequest.mTransitionType = transitionType;
122         return this;
123     }
124 
125     /** Decide whether the next page is second layer page or not. */
setIsSecondLayerPage(boolean isSecondLayerPage)126     public SubSettingLauncher setIsSecondLayerPage(boolean isSecondLayerPage) {
127         mLaunchRequest.mIsSecondLayerPage = isSecondLayerPage;
128         return this;
129     }
130 
launch()131     public void launch() {
132         if (mLaunched) {
133             throw new IllegalStateException(
134                     "This launcher has already been executed. Do not reuse");
135         }
136         mLaunched = true;
137 
138         final Intent intent = toIntent();
139 
140         boolean launchAsUser = mLaunchRequest.mUserHandle != null
141                 && mLaunchRequest.mUserHandle.getIdentifier() != UserHandle.myUserId();
142         boolean launchForResult = mLaunchRequest.mResultListener != null;
143         if (launchAsUser && launchForResult) {
144             launchForResultAsUser(intent, mLaunchRequest.mUserHandle,
145                     mLaunchRequest.mResultListener, mLaunchRequest.mRequestCode);
146         } else if (launchAsUser && !launchForResult) {
147             launchAsUser(intent, mLaunchRequest.mUserHandle);
148         } else if (!launchAsUser && launchForResult) {
149             launchForResult(mLaunchRequest.mResultListener, intent, mLaunchRequest.mRequestCode);
150         } else {
151             launch(intent);
152         }
153     }
154 
toIntent()155     public Intent toIntent() {
156         final Intent intent = new Intent(Intent.ACTION_MAIN);
157         copyExtras(intent);
158         intent.setClass(mContext, SubSettings.class);
159         if (TextUtils.isEmpty(mLaunchRequest.mDestinationName)) {
160             throw new IllegalArgumentException("Destination fragment must be set");
161         }
162         intent.putExtra(SettingsActivity.EXTRA_SHOW_FRAGMENT, mLaunchRequest.mDestinationName);
163 
164         if (mLaunchRequest.mSourceMetricsCategory < 0) {
165             throw new IllegalArgumentException("Source metrics category must be set");
166         }
167         intent.putExtra(MetricsFeatureProvider.EXTRA_SOURCE_METRICS_CATEGORY,
168                 mLaunchRequest.mSourceMetricsCategory);
169 
170         intent.putExtra(SettingsActivity.EXTRA_SHOW_FRAGMENT_ARGUMENTS, mLaunchRequest.mArguments);
171         intent.putExtra(SettingsActivity.EXTRA_SHOW_FRAGMENT_TITLE_RES_PACKAGE_NAME,
172                 mLaunchRequest.mTitleResPackageName);
173         intent.putExtra(SettingsActivity.EXTRA_SHOW_FRAGMENT_TITLE_RESID,
174                 mLaunchRequest.mTitleResId);
175         intent.putExtra(SettingsActivity.EXTRA_SHOW_FRAGMENT_TITLE, mLaunchRequest.mTitle);
176         intent.addFlags(mLaunchRequest.mFlags);
177         intent.putExtra(SettingsBaseActivity.EXTRA_PAGE_TRANSITION_TYPE,
178                 mLaunchRequest.mTransitionType);
179         intent.putExtra(SettingsActivity.EXTRA_IS_SECOND_LAYER_PAGE,
180                 mLaunchRequest.mIsSecondLayerPage);
181 
182         return intent;
183     }
184 
185     @VisibleForTesting
launch(Intent intent)186     void launch(Intent intent) {
187         mContext.startActivity(intent);
188     }
189 
190     @VisibleForTesting
launchAsUser(Intent intent, UserHandle userHandle)191     void launchAsUser(Intent intent, UserHandle userHandle) {
192         mContext.startActivityAsUser(intent, userHandle);
193     }
194 
195     @VisibleForTesting
launchForResultAsUser(Intent intent, UserHandle userHandle, Fragment resultListener, int requestCode)196     void launchForResultAsUser(Intent intent, UserHandle userHandle,
197             Fragment resultListener, int requestCode) {
198         resultListener.getActivity().startActivityForResultAsUser(intent, requestCode, userHandle);
199     }
200 
201     @VisibleForTesting
launchForResult(Fragment listener, Intent intent, int requestCode)202     void launchForResult(Fragment listener, Intent intent, int requestCode) {
203         listener.startActivityForResult(intent, requestCode);
204     }
205 
copyExtras(Intent intent)206     private void copyExtras(Intent intent) {
207         if (mLaunchRequest.mExtras != null) {
208             intent.replaceExtras(mLaunchRequest.mExtras);
209         }
210     }
211 
212     /**
213      * Simple container that has information about how to launch a subsetting.
214      */
215     static class LaunchRequest {
216         String mDestinationName;
217         int mTitleResId;
218         String mTitleResPackageName;
219         CharSequence mTitle;
220         int mSourceMetricsCategory = -100;
221         int mFlags;
222         Fragment mResultListener;
223         int mRequestCode;
224         UserHandle mUserHandle;
225         int mTransitionType;
226         Bundle mArguments;
227         Bundle mExtras;
228         boolean mIsSecondLayerPage;
229     }
230 }
231