• 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.transitionType = TransitionType.TRANSITION_SHARED_AXIS;
47     }
48 
setDestination(String fragmentName)49     public SubSettingLauncher setDestination(String fragmentName) {
50         mLaunchRequest.destinationName = 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.titleResPackageName = titlePackageName;
71         mLaunchRequest.titleResId = titleResId;
72         mLaunchRequest.title = 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.title = title;
86         return this;
87     }
88 
setArguments(Bundle arguments)89     public SubSettingLauncher setArguments(Bundle arguments) {
90         mLaunchRequest.arguments = arguments;
91         return this;
92     }
93 
setExtras(Bundle extras)94     public SubSettingLauncher setExtras(Bundle extras) {
95         mLaunchRequest.extras = extras;
96         return this;
97     }
98 
setSourceMetricsCategory(int sourceMetricsCategory)99     public SubSettingLauncher setSourceMetricsCategory(int sourceMetricsCategory) {
100         mLaunchRequest.sourceMetricsCategory = 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.flags |= flags;
112         return this;
113     }
114 
setUserHandle(UserHandle userHandle)115     public SubSettingLauncher setUserHandle(UserHandle userHandle) {
116         mLaunchRequest.userHandle = userHandle;
117         return this;
118     }
119 
setTransitionType(int transitionType)120     public SubSettingLauncher setTransitionType(int transitionType) {
121         mLaunchRequest.transitionType = transitionType;
122         return this;
123     }
124 
launch()125     public void launch() {
126         if (mLaunched) {
127             throw new IllegalStateException(
128                     "This launcher has already been executed. Do not reuse");
129         }
130         mLaunched = true;
131 
132         final Intent intent = toIntent();
133 
134         boolean launchAsUser = mLaunchRequest.userHandle != null
135                 && mLaunchRequest.userHandle.getIdentifier() != UserHandle.myUserId();
136         boolean launchForResult = mLaunchRequest.mResultListener != null;
137         if (launchAsUser && launchForResult) {
138             launchForResultAsUser(intent, mLaunchRequest.userHandle, mLaunchRequest.mResultListener,
139                     mLaunchRequest.mRequestCode);
140         } else if (launchAsUser && !launchForResult) {
141             launchAsUser(intent, mLaunchRequest.userHandle);
142         } else if (!launchAsUser && launchForResult) {
143             launchForResult(mLaunchRequest.mResultListener, intent, mLaunchRequest.mRequestCode);
144         } else {
145             launch(intent);
146         }
147     }
148 
toIntent()149     public Intent toIntent() {
150         final Intent intent = new Intent(Intent.ACTION_MAIN);
151         copyExtras(intent);
152         intent.setClass(mContext, SubSettings.class);
153         if (TextUtils.isEmpty(mLaunchRequest.destinationName)) {
154             throw new IllegalArgumentException("Destination fragment must be set");
155         }
156         intent.putExtra(SettingsActivity.EXTRA_SHOW_FRAGMENT, mLaunchRequest.destinationName);
157 
158         if (mLaunchRequest.sourceMetricsCategory < 0) {
159             throw new IllegalArgumentException("Source metrics category must be set");
160         }
161         intent.putExtra(MetricsFeatureProvider.EXTRA_SOURCE_METRICS_CATEGORY,
162                 mLaunchRequest.sourceMetricsCategory);
163 
164         intent.putExtra(SettingsActivity.EXTRA_SHOW_FRAGMENT_ARGUMENTS, mLaunchRequest.arguments);
165         intent.putExtra(SettingsActivity.EXTRA_SHOW_FRAGMENT_TITLE_RES_PACKAGE_NAME,
166                 mLaunchRequest.titleResPackageName);
167         intent.putExtra(SettingsActivity.EXTRA_SHOW_FRAGMENT_TITLE_RESID,
168                 mLaunchRequest.titleResId);
169         intent.putExtra(SettingsActivity.EXTRA_SHOW_FRAGMENT_TITLE, mLaunchRequest.title);
170         intent.addFlags(mLaunchRequest.flags);
171         intent.putExtra(SettingsBaseActivity.EXTRA_PAGE_TRANSITION_TYPE,
172                 mLaunchRequest.transitionType);
173 
174         return intent;
175     }
176 
177     @VisibleForTesting
launch(Intent intent)178     void launch(Intent intent) {
179         mContext.startActivity(intent);
180     }
181 
182     @VisibleForTesting
launchAsUser(Intent intent, UserHandle userHandle)183     void launchAsUser(Intent intent, UserHandle userHandle) {
184         mContext.startActivityAsUser(intent, userHandle);
185     }
186 
187     @VisibleForTesting
launchForResultAsUser(Intent intent, UserHandle userHandle, Fragment resultListener, int requestCode)188     void launchForResultAsUser(Intent intent, UserHandle userHandle,
189             Fragment resultListener, int requestCode) {
190         resultListener.getActivity().startActivityForResultAsUser(intent, requestCode, userHandle);
191     }
192 
193     @VisibleForTesting
launchForResult(Fragment listener, Intent intent, int requestCode)194     void launchForResult(Fragment listener, Intent intent, int requestCode) {
195         listener.startActivityForResult(intent, requestCode);
196     }
197 
copyExtras(Intent intent)198     private void copyExtras(Intent intent) {
199         if (mLaunchRequest.extras != null) {
200             intent.replaceExtras(mLaunchRequest.extras);
201         }
202     }
203 
204     /**
205      * Simple container that has information about how to launch a subsetting.
206      */
207     static class LaunchRequest {
208         String destinationName;
209         int titleResId;
210         String titleResPackageName;
211         CharSequence title;
212         int sourceMetricsCategory = -100;
213         int flags;
214         Fragment mResultListener;
215         int mRequestCode;
216         UserHandle userHandle;
217         int transitionType;
218         Bundle arguments;
219         Bundle extras;
220     }
221 }
222