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 public static final String EXTRA_THEME = "theme"; 69 public static final String EXTRA_USE_IMMERSIVE_MODE = "useImmersiveMode"; 70 71 public static final String SETTINGS_GLOBAL_DEVICE_PROVISIONED = "device_provisioned"; 72 public static final String SETTINGS_SECURE_USER_SETUP_COMPLETE = "user_setup_complete"; 73 74 /** 75 * Gets an intent that will invoke the next step of setup wizard. 76 * 77 * @param originalIntent The original intent that was used to start the step, usually via {@link 78 * Activity#getIntent()}. 79 * @param resultCode The result code of the step. See {@link ResultCodes}. 80 * @return A new intent that can be used with {@link Activity#startActivityForResult(Intent, int)} 81 * to start the next step of the setup flow. 82 */ getNextIntent(Intent originalIntent, int resultCode)83 public static Intent getNextIntent(Intent originalIntent, int resultCode) { 84 return getNextIntent(originalIntent, resultCode, null); 85 } 86 87 /** 88 * Gets an intent that will invoke the next step of setup wizard. 89 * 90 * @param originalIntent The original intent that was used to start the step, usually via {@link 91 * Activity#getIntent()}. 92 * @param resultCode The result code of the step. See {@link ResultCodes}. 93 * @param data An intent containing extra result data. 94 * @return A new intent that can be used with {@link Activity#startActivityForResult(Intent, int)} 95 * to start the next step of the setup flow. 96 */ getNextIntent(Intent originalIntent, int resultCode, Intent data)97 public static Intent getNextIntent(Intent originalIntent, int resultCode, Intent data) { 98 Intent intent = new Intent(ACTION_NEXT); 99 copyWizardManagerExtras(originalIntent, intent); 100 intent.putExtra(EXTRA_RESULT_CODE, resultCode); 101 if (data != null && data.getExtras() != null) { 102 intent.putExtras(data.getExtras()); 103 } 104 intent.putExtra(EXTRA_THEME, originalIntent.getStringExtra(EXTRA_THEME)); 105 106 return intent; 107 } 108 109 /** 110 * Copies the internal extras used by setup wizard from one intent to another. For low-level use 111 * only, such as when using {@link Intent#FLAG_ACTIVITY_FORWARD_RESULT} to relay to another 112 * intent. 113 * 114 * @param srcIntent Intent to get the wizard manager extras from. 115 * @param dstIntent Intent to copy the wizard manager extras to. 116 */ copyWizardManagerExtras(Intent srcIntent, Intent dstIntent)117 public static void copyWizardManagerExtras(Intent srcIntent, Intent dstIntent) { 118 dstIntent.putExtra(EXTRA_WIZARD_BUNDLE, srcIntent.getBundleExtra(EXTRA_WIZARD_BUNDLE)); 119 for (String key : 120 Arrays.asList( 121 EXTRA_IS_FIRST_RUN, 122 EXTRA_IS_DEFERRED_SETUP, 123 EXTRA_IS_PRE_DEFERRED_SETUP, 124 EXTRA_IS_PORTAL_SETUP, 125 EXTRA_IS_SETUP_FLOW)) { 126 dstIntent.putExtra(key, srcIntent.getBooleanExtra(key, false)); 127 } 128 129 for (String key : Arrays.asList(EXTRA_THEME, EXTRA_SCRIPT_URI, EXTRA_ACTION_ID)) { 130 dstIntent.putExtra(key, srcIntent.getStringExtra(key)); 131 } 132 } 133 134 /** @deprecated Use {@link isInitialSetupWizard} instead. */ 135 @Deprecated isSetupWizardIntent(Intent intent)136 public static boolean isSetupWizardIntent(Intent intent) { 137 return intent.getBooleanExtra(EXTRA_IS_FIRST_RUN, false); 138 } 139 140 /** 141 * Checks whether the current user has completed Setup Wizard. This is true if the current user 142 * has gone through Setup Wizard. The current user may or may not be the device owner and the 143 * device owner may have already completed setup wizard. 144 * 145 * @param context The context to retrieve the settings. 146 * @return true if the current user has completed Setup Wizard. 147 * @see #isDeviceProvisioned(Context) 148 */ isUserSetupComplete(Context context)149 public static boolean isUserSetupComplete(Context context) { 150 if (VERSION.SDK_INT >= VERSION_CODES.JELLY_BEAN_MR1) { 151 return Settings.Secure.getInt( 152 context.getContentResolver(), SETTINGS_SECURE_USER_SETUP_COMPLETE, 0) 153 == 1; 154 } else { 155 // For versions below JB MR1, there are no user profiles. Just return the global device 156 // provisioned state. 157 return Settings.Secure.getInt( 158 context.getContentResolver(), SETTINGS_GLOBAL_DEVICE_PROVISIONED, 0) 159 == 1; 160 } 161 } 162 163 /** 164 * Checks whether the device is provisioned. This means that the device has gone through Setup 165 * Wizard at least once. Note that the user can still be in Setup Wizard even if this is true, for 166 * a secondary user profile triggered through Settings > Add account. 167 * 168 * @param context The context to retrieve the settings. 169 * @return true if the device is provisioned. 170 * @see #isUserSetupComplete(Context) 171 */ isDeviceProvisioned(Context context)172 public static boolean isDeviceProvisioned(Context context) { 173 if (VERSION.SDK_INT >= VERSION_CODES.JELLY_BEAN_MR1) { 174 return Settings.Global.getInt( 175 context.getContentResolver(), SETTINGS_GLOBAL_DEVICE_PROVISIONED, 0) 176 == 1; 177 } else { 178 return Settings.Secure.getInt( 179 context.getContentResolver(), SETTINGS_GLOBAL_DEVICE_PROVISIONED, 0) 180 == 1; 181 } 182 } 183 184 /** 185 * Checks whether an intent is running in the deferred setup wizard flow. 186 * 187 * @param originalIntent The original intent that was used to start the step, usually via {@link 188 * Activity#getIntent()}. 189 * @return true if the intent passed in was running in deferred setup wizard. 190 */ isDeferredSetupWizard(Intent originalIntent)191 public static boolean isDeferredSetupWizard(Intent originalIntent) { 192 return originalIntent != null && originalIntent.getBooleanExtra(EXTRA_IS_DEFERRED_SETUP, false); 193 } 194 195 /** 196 * Checks whether an intent is running in "pre-deferred" setup wizard flow. 197 * 198 * @param originalIntent The original intent that was used to start the step, usually via {@link 199 * Activity#getIntent()}. 200 * @return true if the intent passed in was running in "pre-deferred" setup wizard. 201 */ isPreDeferredSetupWizard(Intent originalIntent)202 public static boolean isPreDeferredSetupWizard(Intent originalIntent) { 203 return originalIntent != null 204 && originalIntent.getBooleanExtra(EXTRA_IS_PRE_DEFERRED_SETUP, false); 205 } 206 207 /** 208 * Checks whether an intent is is running in the initial setup wizard flow. 209 * 210 * @param intent The intent to be checked, usually from {@link Activity#getIntent()}. 211 * @return true if the intent passed in was intended to be used with setup wizard. 212 */ isInitialSetupWizard(Intent intent)213 public static boolean isInitialSetupWizard(Intent intent) { 214 return intent.getBooleanExtra(EXTRA_IS_FIRST_RUN, false); 215 } 216 217 /** 218 * Returns true if the intent passed in indicates that it is running in any setup wizard flow, 219 * including initial setup and deferred setup etc. 220 * 221 * @param originalIntent The original intent that was used to start the step, usually via {@link 222 * Activity#getIntent()}. 223 */ isAnySetupWizard(@ullable Intent originalIntent)224 public static boolean isAnySetupWizard(@Nullable Intent originalIntent) { 225 if (originalIntent == null) { 226 return false; 227 } 228 229 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) { 230 return originalIntent.getBooleanExtra(EXTRA_IS_SETUP_FLOW, false); 231 } else { 232 return isInitialSetupWizard(originalIntent) 233 || isPreDeferredSetupWizard(originalIntent) 234 || isDeferredSetupWizard(originalIntent); 235 } 236 } 237 WizardManagerHelper()238 private WizardManagerHelper() {} 239 } 240