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