• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2015 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.google.android.setupcompat.util;
18 
19 import android.app.Activity;
20 import android.content.Context;
21 import android.content.Intent;
22 import android.os.Build;
23 import android.os.Build.VERSION;
24 import android.os.Build.VERSION_CODES;
25 import android.provider.Settings;
26 import androidx.annotation.Nullable;
27 import androidx.annotation.VisibleForTesting;
28 import java.util.Arrays;
29 
30 /**
31  * Helper to interact with Wizard Manager in setup wizard, which should be used when a screen is
32  * shown inside the setup flow. This includes things like parsing extras passed by Wizard Manager,
33  * and invoking Wizard Manager to start the next action.
34  */
35 public final class WizardManagerHelper {
36 
37   @VisibleForTesting public static final String ACTION_NEXT = "com.android.wizard.NEXT";
38 
39   // EXTRA_SCRIPT_URI and EXTRA_ACTION_ID are used in setup wizard in versions before M and are
40   // kept for backwards compatibility.
41   @VisibleForTesting static final String EXTRA_SCRIPT_URI = "scriptUri";
42   @VisibleForTesting static final String EXTRA_ACTION_ID = "actionId";
43 
44   @VisibleForTesting static final String EXTRA_WIZARD_BUNDLE = "wizardBundle";
45   private static final String EXTRA_RESULT_CODE = "com.android.setupwizard.ResultCode";
46 
47   /** Extra for notifying an Activity that it is inside the first SetupWizard flow or not. */
48   public static final String EXTRA_IS_FIRST_RUN = "firstRun";
49 
50   /** Extra for notifying an Activity that it is inside the Deferred SetupWizard flow or not. */
51   public static final String EXTRA_IS_DEFERRED_SETUP = "deferredSetup";
52 
53   /** Extra for notifying an Activity that it is inside the "Pre-Deferred Setup" flow. */
54   public static final String EXTRA_IS_PRE_DEFERRED_SETUP = "preDeferredSetup";
55 
56   /** Extra for notifying an Activity that it is inside the "Portal Setup" flow. */
57   public static final String EXTRA_IS_PORTAL_SETUP = "portalSetup";
58 
59   /**
60    * Extra for notifying an Activity that it is inside the any setup flow.
61    *
62    * <p>Apps that target API levels below {@link android.os.Build.VERSION_CODES#Q} is able to
63    * determine whether Activity is inside the any setup flow by one of {@link #EXTRA_IS_FIRST_RUN},
64    * {@link #EXTRA_IS_DEFERRED_SETUP}, and {@link #EXTRA_IS_PRE_DEFERRED_SETUP} is true.
65    */
66   public static final String EXTRA_IS_SETUP_FLOW = "isSetupFlow";
67 
68   /** Extra for notifying an activity that was called from suggested action activity. */
69   public static final String EXTRA_IS_SUW_SUGGESTED_ACTION_FLOW = "isSuwSuggestedActionFlow";
70 
71   public static final String EXTRA_THEME = "theme";
72   public static final String EXTRA_USE_IMMERSIVE_MODE = "useImmersiveMode";
73 
74   public static final String SETTINGS_GLOBAL_DEVICE_PROVISIONED = "device_provisioned";
75   public static final String SETTINGS_SECURE_USER_SETUP_COMPLETE = "user_setup_complete";
76 
77   /**
78    * Gets an intent that will invoke the next step of setup wizard.
79    *
80    * @param originalIntent The original intent that was used to start the step, usually via {@link
81    *     Activity#getIntent()}.
82    * @param resultCode The result code of the step. See {@link ResultCodes}.
83    * @return A new intent that can be used with {@link Activity#startActivityForResult(Intent, int)}
84    *     to start the next step of the setup flow.
85    */
getNextIntent(Intent originalIntent, int resultCode)86   public static Intent getNextIntent(Intent originalIntent, int resultCode) {
87     return getNextIntent(originalIntent, resultCode, null);
88   }
89 
90   /**
91    * Gets an intent that will invoke the next step of setup wizard.
92    *
93    * @param originalIntent The original intent that was used to start the step, usually via {@link
94    *     Activity#getIntent()}.
95    * @param resultCode The result code of the step. See {@link ResultCodes}.
96    * @param data An intent containing extra result data.
97    * @return A new intent that can be used with {@link Activity#startActivityForResult(Intent, int)}
98    *     to start the next step of the setup flow.
99    */
getNextIntent(Intent originalIntent, int resultCode, Intent data)100   public static Intent getNextIntent(Intent originalIntent, int resultCode, Intent data) {
101     Intent intent = new Intent(ACTION_NEXT);
102     copyWizardManagerExtras(originalIntent, intent);
103     intent.putExtra(EXTRA_RESULT_CODE, resultCode);
104     if (data != null && data.getExtras() != null) {
105       intent.putExtras(data.getExtras());
106     }
107     intent.putExtra(EXTRA_THEME, originalIntent.getStringExtra(EXTRA_THEME));
108 
109     return intent;
110   }
111 
112   /**
113    * Copies the internal extras used by setup wizard from one intent to another. For low-level use
114    * only, such as when using {@link Intent#FLAG_ACTIVITY_FORWARD_RESULT} to relay to another
115    * intent.
116    *
117    * @param srcIntent Intent to get the wizard manager extras from.
118    * @param dstIntent Intent to copy the wizard manager extras to.
119    */
copyWizardManagerExtras(Intent srcIntent, Intent dstIntent)120   public static void copyWizardManagerExtras(Intent srcIntent, Intent dstIntent) {
121     dstIntent.putExtra(EXTRA_WIZARD_BUNDLE, srcIntent.getBundleExtra(EXTRA_WIZARD_BUNDLE));
122     for (String key :
123         Arrays.asList(
124             EXTRA_IS_FIRST_RUN,
125             EXTRA_IS_DEFERRED_SETUP,
126             EXTRA_IS_PRE_DEFERRED_SETUP,
127             EXTRA_IS_PORTAL_SETUP,
128             EXTRA_IS_SETUP_FLOW,
129             EXTRA_IS_SUW_SUGGESTED_ACTION_FLOW)) {
130       dstIntent.putExtra(key, srcIntent.getBooleanExtra(key, false));
131     }
132 
133     for (String key : Arrays.asList(EXTRA_THEME, EXTRA_SCRIPT_URI, EXTRA_ACTION_ID)) {
134       dstIntent.putExtra(key, srcIntent.getStringExtra(key));
135     }
136   }
137 
138   /** @deprecated Use {@link isInitialSetupWizard} instead. */
139   @Deprecated
isSetupWizardIntent(Intent intent)140   public static boolean isSetupWizardIntent(Intent intent) {
141     return intent.getBooleanExtra(EXTRA_IS_FIRST_RUN, false);
142   }
143 
144   /**
145    * Checks whether the current user has completed Setup Wizard. This is true if the current user
146    * has gone through Setup Wizard. The current user may or may not be the device owner and the
147    * device owner may have already completed setup wizard.
148    *
149    * @param context The context to retrieve the settings.
150    * @return true if the current user has completed Setup Wizard.
151    * @see #isDeviceProvisioned(Context)
152    */
isUserSetupComplete(Context context)153   public static boolean isUserSetupComplete(Context context) {
154     if (VERSION.SDK_INT >= VERSION_CODES.JELLY_BEAN_MR1) {
155       return Settings.Secure.getInt(
156               context.getContentResolver(), SETTINGS_SECURE_USER_SETUP_COMPLETE, 0)
157           == 1;
158     } else {
159       // For versions below JB MR1, there are no user profiles. Just return the global device
160       // provisioned state.
161       return Settings.Secure.getInt(
162               context.getContentResolver(), SETTINGS_GLOBAL_DEVICE_PROVISIONED, 0)
163           == 1;
164     }
165   }
166 
167   /**
168    * Checks whether the device is provisioned. This means that the device has gone through Setup
169    * Wizard at least once. Note that the user can still be in Setup Wizard even if this is true, for
170    * a secondary user profile triggered through Settings > Add account.
171    *
172    * @param context The context to retrieve the settings.
173    * @return true if the device is provisioned.
174    * @see #isUserSetupComplete(Context)
175    */
isDeviceProvisioned(Context context)176   public static boolean isDeviceProvisioned(Context context) {
177     if (VERSION.SDK_INT >= VERSION_CODES.JELLY_BEAN_MR1) {
178       return Settings.Global.getInt(
179               context.getContentResolver(), SETTINGS_GLOBAL_DEVICE_PROVISIONED, 0)
180           == 1;
181     } else {
182       return Settings.Secure.getInt(
183               context.getContentResolver(), SETTINGS_GLOBAL_DEVICE_PROVISIONED, 0)
184           == 1;
185     }
186   }
187 
188   /**
189    * Checks whether an intent is running in the portal setup wizard flow. This API is supported
190    * since S.
191    *
192    * @param originalIntent The original intent that was used to start the step, usually via {@link
193    *     Activity#getIntent()}.
194    * @return true if the intent passed in was running in portal setup wizard.
195    */
isPortalSetupWizard(Intent originalIntent)196   public static boolean isPortalSetupWizard(Intent originalIntent) {
197     return originalIntent != null && originalIntent.getBooleanExtra(EXTRA_IS_PORTAL_SETUP, false);
198   }
199 
200   /**
201    * Checks whether an intent is running in the deferred setup wizard flow.
202    *
203    * @param originalIntent The original intent that was used to start the step, usually via {@link
204    *     Activity#getIntent()}.
205    * @return true if the intent passed in was running in deferred setup wizard.
206    */
isDeferredSetupWizard(Intent originalIntent)207   public static boolean isDeferredSetupWizard(Intent originalIntent) {
208     return originalIntent != null && originalIntent.getBooleanExtra(EXTRA_IS_DEFERRED_SETUP, false);
209   }
210 
211   /**
212    * Checks whether an intent is running in "pre-deferred" setup wizard flow.
213    *
214    * @param originalIntent The original intent that was used to start the step, usually via {@link
215    *     Activity#getIntent()}.
216    * @return true if the intent passed in was running in "pre-deferred" setup wizard.
217    */
isPreDeferredSetupWizard(Intent originalIntent)218   public static boolean isPreDeferredSetupWizard(Intent originalIntent) {
219     return originalIntent != null
220         && originalIntent.getBooleanExtra(EXTRA_IS_PRE_DEFERRED_SETUP, false);
221   }
222 
223   /**
224    * Checks whether an intent is is running in the initial setup wizard flow.
225    *
226    * @param intent The intent to be checked, usually from {@link Activity#getIntent()}.
227    * @return true if the intent passed in was intended to be used with setup wizard.
228    */
isInitialSetupWizard(Intent intent)229   public static boolean isInitialSetupWizard(Intent intent) {
230     return intent.getBooleanExtra(EXTRA_IS_FIRST_RUN, false);
231   }
232 
233   /**
234    * Since Q, returns true if the intent passed in indicates that it is running in setup wizard
235    * flows, including initial, predeferred, deferred. Since S, it also supports portal setup.
236    *
237    * <p>Pre-Q, it is running in three setup wizard flows, including initial, predeferred, deferred
238    * setup.
239    *
240    * @param originalIntent The original intent that was used to start the step, usually via {@link
241    *     Activity#getIntent()}.
242    */
isAnySetupWizard(@ullable Intent originalIntent)243   public static boolean isAnySetupWizard(@Nullable Intent originalIntent) {
244     if (originalIntent == null) {
245       return false;
246     }
247 
248     if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
249       return originalIntent.getBooleanExtra(EXTRA_IS_SETUP_FLOW, false);
250     } else {
251       return isInitialSetupWizard(originalIntent)
252           || isPreDeferredSetupWizard(originalIntent)
253           || isDeferredSetupWizard(originalIntent);
254     }
255   }
256 
WizardManagerHelper()257   private WizardManagerHelper() {}
258 }
259