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.android.setupwizardlib.util; 18 19 import android.content.Context; 20 import android.content.Intent; 21 import android.content.res.Resources.Theme; 22 import android.os.Build.VERSION; 23 import android.os.Build.VERSION_CODES; 24 import android.provider.Settings; 25 import android.support.annotation.StyleRes; 26 import android.support.annotation.VisibleForTesting; 27 28 import com.android.setupwizardlib.R; 29 30 public class WizardManagerHelper { 31 32 private static final String ACTION_NEXT = "com.android.wizard.NEXT"; 33 34 // EXTRA_SCRIPT_URI and EXTRA_ACTION_ID are used in setup wizard in versions before M and are 35 // kept for backwards compatibility. 36 @VisibleForTesting 37 static final String EXTRA_SCRIPT_URI = "scriptUri"; 38 @VisibleForTesting 39 static final String EXTRA_ACTION_ID = "actionId"; 40 41 @VisibleForTesting 42 static final String EXTRA_WIZARD_BUNDLE = "wizardBundle"; 43 private static final String EXTRA_RESULT_CODE = "com.android.setupwizard.ResultCode"; 44 @VisibleForTesting 45 static final String EXTRA_IS_FIRST_RUN = "firstRun"; 46 @VisibleForTesting 47 static final String EXTRA_IS_DEFERRED_SETUP = "deferredSetup"; 48 49 public static final String EXTRA_THEME = "theme"; 50 public static final String EXTRA_USE_IMMERSIVE_MODE = "useImmersiveMode"; 51 52 public static final String SETTINGS_GLOBAL_DEVICE_PROVISIONED = "device_provisioned"; 53 public static final String SETTINGS_SECURE_USER_SETUP_COMPLETE = "user_setup_complete"; 54 55 public static final String THEME_HOLO = "holo"; 56 public static final String THEME_HOLO_LIGHT = "holo_light"; 57 public static final String THEME_MATERIAL = "material"; 58 public static final String THEME_MATERIAL_LIGHT = "material_light"; 59 60 /** 61 * Passed in a setup wizard intent as {@link #EXTRA_THEME}. This is the dark variant of the 62 * theme used in setup wizard for Nougat MR1. 63 */ 64 public static final String THEME_GLIF = "glif"; 65 66 /** 67 * Passed in a setup wizard intent as {@link #EXTRA_THEME}. This is the default theme used in 68 * setup wizard for Nougat MR1. 69 */ 70 public static final String THEME_GLIF_LIGHT = "glif_light"; 71 72 /** 73 * Passed in a setup wizard intent as {@link #EXTRA_THEME}. This is the dark variant of the 74 * theme used in setup wizard for O DR. 75 */ 76 public static final String THEME_GLIF_V2 = "glif_v2"; 77 78 /** 79 * @deprecated Use {@link #THEME_GLIF_V2} instead. 80 */ 81 @Deprecated 82 public static final String THEME_GLIF_PIXEL = THEME_GLIF_V2; 83 84 /** 85 * Passed in a setup wizard intent as {@link #EXTRA_THEME}. This is the default theme used in 86 * setup wizard for O DR. 87 */ 88 public static final String THEME_GLIF_V2_LIGHT = "glif_v2_light"; 89 90 /** 91 * @deprecated Use {@link #THEME_GLIF_V2_LIGHT} instead. 92 */ 93 @Deprecated 94 public static final String THEME_GLIF_PIXEL_LIGHT = THEME_GLIF_V2_LIGHT; 95 96 /** 97 * Get an intent that will invoke the next step of setup wizard. 98 * 99 * @param originalIntent The original intent that was used to start the step, usually via 100 * {@link android.app.Activity#getIntent()}. 101 * @param resultCode The result code of the step. See {@link ResultCodes}. 102 * @return A new intent that can be used with 103 * {@link android.app.Activity#startActivityForResult(Intent, int)} to start the next 104 * step of the setup flow. 105 */ 106 public static Intent getNextIntent(Intent originalIntent, int resultCode) { 107 return getNextIntent(originalIntent, resultCode, null); 108 } 109 110 /** 111 * Get an intent that will invoke the next step of setup wizard. 112 * 113 * @param originalIntent The original intent that was used to start the step, usually via 114 * {@link android.app.Activity#getIntent()}. 115 * @param resultCode The result code of the step. See {@link ResultCodes}. 116 * @param data An intent containing extra result data. 117 * @return A new intent that can be used with 118 * {@link android.app.Activity#startActivityForResult(Intent, int)} to start the next 119 * step of the setup flow. 120 */ 121 public static Intent getNextIntent(Intent originalIntent, int resultCode, Intent data) { 122 Intent intent = new Intent(ACTION_NEXT); 123 copyWizardManagerExtras(originalIntent, intent); 124 intent.putExtra(EXTRA_RESULT_CODE, resultCode); 125 if (data != null && data.getExtras() != null) { 126 intent.putExtras(data.getExtras()); 127 } 128 intent.putExtra(EXTRA_THEME, originalIntent.getStringExtra(EXTRA_THEME)); 129 130 return intent; 131 } 132 133 /** 134 * Copy the internal extras used by setup wizard from one intent to another. For low-level use 135 * only, such as when using {@link Intent#FLAG_ACTIVITY_FORWARD_RESULT} to relay to another 136 * intent. 137 * 138 * @param srcIntent Intent to get the wizard manager extras from. 139 * @param dstIntent Intent to copy the wizard manager extras to. 140 */ 141 public static void copyWizardManagerExtras(Intent srcIntent, Intent dstIntent) { 142 dstIntent.putExtra(EXTRA_WIZARD_BUNDLE, srcIntent.getBundleExtra(EXTRA_WIZARD_BUNDLE)); 143 dstIntent.putExtra(EXTRA_THEME, srcIntent.getStringExtra(EXTRA_THEME)); 144 dstIntent.putExtra(EXTRA_IS_FIRST_RUN, 145 srcIntent.getBooleanExtra(EXTRA_IS_FIRST_RUN, false)); 146 dstIntent.putExtra(EXTRA_IS_DEFERRED_SETUP, 147 srcIntent.getBooleanExtra(EXTRA_IS_DEFERRED_SETUP, false)); 148 dstIntent.putExtra(EXTRA_SCRIPT_URI, srcIntent.getStringExtra(EXTRA_SCRIPT_URI)); 149 dstIntent.putExtra(EXTRA_ACTION_ID, srcIntent.getStringExtra(EXTRA_ACTION_ID)); 150 } 151 152 /** 153 * Check whether an intent is intended to be used within the setup wizard flow. 154 * 155 * @param intent The intent to be checked, usually from 156 * {@link android.app.Activity#getIntent()}. 157 * @return true if the intent passed in was intended to be used with setup wizard. 158 */ 159 public static boolean isSetupWizardIntent(Intent intent) { 160 return intent.getBooleanExtra(EXTRA_IS_FIRST_RUN, false); 161 } 162 163 /** 164 * Checks whether the current user has completed Setup Wizard. This is true if the current user 165 * has gone through Setup Wizard. The current user may or may not be the device owner and the 166 * device owner may have already completed setup wizard. 167 * 168 * @param context The context to retrieve the settings. 169 * @return true if the current user has completed Setup Wizard. 170 * @see #isDeviceProvisioned(android.content.Context) 171 */ 172 public static boolean isUserSetupComplete(Context context) { 173 if (VERSION.SDK_INT >= VERSION_CODES.JELLY_BEAN_MR1) { 174 return Settings.Secure.getInt(context.getContentResolver(), 175 SETTINGS_SECURE_USER_SETUP_COMPLETE, 0) == 1; 176 } else { 177 // For versions below JB MR1, there are no user profiles. Just return the global device 178 // provisioned state. 179 return Settings.Secure.getInt(context.getContentResolver(), 180 SETTINGS_GLOBAL_DEVICE_PROVISIONED, 0) == 1; 181 } 182 } 183 184 /** 185 * Checks whether the device is provisioned. This means that the device has gone through Setup 186 * Wizard at least once. Note that the user can still be in Setup Wizard even if this is true, 187 * for a secondary user profile triggered through Settings > Add account. 188 * 189 * @param context The context to retrieve the settings. 190 * @return true if the device is provisioned. 191 * @see #isUserSetupComplete(android.content.Context) 192 */ 193 public static boolean isDeviceProvisioned(Context context) { 194 if (VERSION.SDK_INT >= VERSION_CODES.JELLY_BEAN_MR1) { 195 return Settings.Global.getInt(context.getContentResolver(), 196 SETTINGS_GLOBAL_DEVICE_PROVISIONED, 0) == 1; 197 } else { 198 return Settings.Secure.getInt(context.getContentResolver(), 199 SETTINGS_GLOBAL_DEVICE_PROVISIONED, 0) == 1; 200 } 201 } 202 203 /** 204 * Checks whether an intent is running in the deferred setup wizard flow. 205 * 206 * @param originalIntent The original intent that was used to start the step, usually via 207 * {@link android.app.Activity#getIntent()}. 208 * @return true if the intent passed in was running in deferred setup wizard. 209 */ 210 public static boolean isDeferredSetupWizard(Intent originalIntent) { 211 return originalIntent != null 212 && originalIntent.getBooleanExtra(EXTRA_IS_DEFERRED_SETUP, false); 213 } 214 215 /** 216 * Checks the intent whether the extra indicates that the light theme should be used or not. If 217 * the theme is not specified in the intent, or the theme specified is unknown, the value def 218 * will be returned. 219 * 220 * @param intent The intent used to start the activity, which the theme extra will be read from. 221 * @param def The default value if the theme is not specified. 222 * @return True if the activity started by the given intent should use light theme. 223 */ 224 public static boolean isLightTheme(Intent intent, boolean def) { 225 final String theme = intent.getStringExtra(EXTRA_THEME); 226 return isLightTheme(theme, def); 227 } 228 229 /** 230 * Checks whether {@code theme} represents a light or dark theme. If the theme specified is 231 * unknown, the value def will be returned. 232 * 233 * @param theme The theme as specified from an intent sent from setup wizard. 234 * @param def The default value if the theme is not known. 235 * @return True if {@code theme} represents a light theme. 236 */ 237 public static boolean isLightTheme(String theme, boolean def) { 238 if (THEME_HOLO_LIGHT.equals(theme) || THEME_MATERIAL_LIGHT.equals(theme) 239 || THEME_GLIF_LIGHT.equals(theme) || THEME_GLIF_V2_LIGHT.equals(theme)) { 240 return true; 241 } else if (THEME_HOLO.equals(theme) || THEME_MATERIAL.equals(theme) 242 || THEME_GLIF.equals(theme) || THEME_GLIF_V2.equals(theme)) { 243 return false; 244 } else { 245 return def; 246 } 247 } 248 249 /** 250 * Gets the theme style resource defined by this library for the theme specified in the given 251 * intent. For example, for THEME_GLIF_LIGHT, the theme @style/SuwThemeGlif.Light is returned. 252 * 253 * @param intent The intent passed by setup wizard, or one with the theme propagated along using 254 * {@link #copyWizardManagerExtras(Intent, Intent)}. 255 * @return The style corresponding to the theme in the given intent, or {@code defaultTheme} if 256 * the given theme is not recognized. 257 * 258 * @see #getThemeRes(String, int) 259 */ 260 public static @StyleRes int getThemeRes(Intent intent, @StyleRes int defaultTheme) { 261 final String theme = intent.getStringExtra(EXTRA_THEME); 262 return getThemeRes(theme, defaultTheme); 263 } 264 265 /** 266 * Gets the theme style resource defined by this library for the given theme name. For example, 267 * for THEME_GLIF_LIGHT, the theme @style/SuwThemeGlif.Light is returned. 268 * 269 * <p>If you require extra theme attributes but want to ensure forward compatibility with new 270 * themes added here, consider overriding {@link android.app.Activity#onApplyThemeResource} in 271 * your activity and call {@link Theme#applyStyle(int, boolean)} using your theme overlay. 272 * 273 * <pre>{@code 274 * protected void onApplyThemeResource(Theme theme, int resid, boolean first) { 275 * super.onApplyThemeResource(theme, resid, first); 276 * theme.applyStyle(R.style.MyThemeOverlay, true); 277 * } 278 * }</pre> 279 * 280 * @param theme The string representation of the theme. 281 * @return The style corresponding to the given {@code theme}, or {@code defaultTheme} if the 282 * given theme is not recognized. 283 */ 284 public static @StyleRes int getThemeRes(String theme, @StyleRes int defaultTheme) { 285 if (theme != null) { 286 switch (theme) { 287 case THEME_GLIF_V2_LIGHT: 288 return R.style.SuwThemeGlifV2_Light; 289 case THEME_GLIF_V2: 290 return R.style.SuwThemeGlifV2; 291 case THEME_GLIF_LIGHT: 292 return R.style.SuwThemeGlif_Light; 293 case THEME_GLIF: 294 return R.style.SuwThemeGlif; 295 case THEME_MATERIAL_LIGHT: 296 return R.style.SuwThemeMaterial_Light; 297 case THEME_MATERIAL: 298 return R.style.SuwThemeMaterial; 299 default: 300 // fall through 301 } 302 } 303 return defaultTheme; 304 } 305 } 306