Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(1015)

Unified Diff: chrome/android/java/src/org/chromium/chrome/browser/firstrun/FirstRunFlowSequencer.java

Issue 978653002: Upstream FirstRunActivity and friends. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Created 5 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: chrome/android/java/src/org/chromium/chrome/browser/firstrun/FirstRunFlowSequencer.java
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/firstrun/FirstRunFlowSequencer.java b/chrome/android/java/src/org/chromium/chrome/browser/firstrun/FirstRunFlowSequencer.java
new file mode 100644
index 0000000000000000000000000000000000000000..babf92f1cc174432620f3ff31b65edeb3a34ba39
--- /dev/null
+++ b/chrome/android/java/src/org/chromium/chrome/browser/firstrun/FirstRunFlowSequencer.java
@@ -0,0 +1,259 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package org.chromium.chrome.browser.firstrun;
+
+import android.accounts.Account;
+import android.app.Activity;
+import android.content.Context;
+import android.content.Intent;
+import android.content.pm.ApplicationInfo;
+import android.os.Bundle;
+
+import org.chromium.base.ApiCompatibilityUtils;
+import org.chromium.base.CommandLine;
+import org.chromium.base.VisibleForTesting;
+import org.chromium.chrome.ChromeSwitches;
+import org.chromium.chrome.browser.ChromeVersionInfo;
+import org.chromium.chrome.browser.ChromiumApplication;
+import org.chromium.chrome.browser.preferences.PrefServiceBridge;
+import org.chromium.chrome.browser.preferences.privacy.PrivacyPreferencesManager;
+import org.chromium.chrome.browser.services.AndroidEduAndChildAccountHelper;
+import org.chromium.chrome.browser.signin.SigninManager;
+import org.chromium.chrome.browser.util.FeatureUtilities;
+import org.chromium.sync.signin.AccountManagerHelper;
+import org.chromium.sync.signin.ChromeSigninController;
+
+/**
+ * A helper to determine what should be the sequence of First Run Experience screens.
+ * Usage:
+ * new FirstRunFlowSequencer(activity, launcherProvidedProperties) {
+ * override onFlowIsKnown
+ * }.start();
+ */
+public abstract class FirstRunFlowSequencer {
+ private final Activity mActivity;
+ private final Bundle mLaunchProperties;
+
+ private boolean mIsAndroidEduDevice;
+ private boolean mHasChildAccount;
+
+ /**
+ * Callback that is called once the flow is determined.
+ * If the properties is null, the First Run experience needs to finish and
+ * restart the original intent if necessary.
+ * @param activity An activity.
+ * @param freProperties Properties to be used in the First Run activity, or null.
+ */
+ public abstract void onFlowIsKnown(Activity activity, Bundle freProperties);
+
+ public FirstRunFlowSequencer(Activity activity, Bundle launcherProvidedProperties) {
+ mActivity = activity;
+ mLaunchProperties = launcherProvidedProperties;
+ }
+
+ /**
+ * Starts determining parameters for the First Run.
+ * Once finished, calls onFlowIsKnown().
+ */
+ public void start() {
+ if (CommandLine.getInstance().hasSwitch(ChromeSwitches.DISABLE_FIRST_RUN_EXPERIENCE)) {
+ onFlowIsKnown(mActivity, null);
+ return;
+ }
+
+ if (!mLaunchProperties.getBoolean(FirstRunActivity.USE_FRE_FLOW_SEQUENCER)) {
+ onFlowIsKnown(mActivity, mLaunchProperties);
+ return;
+ }
+
+ new AndroidEduAndChildAccountHelper() {
+ @Override
+ public void onParametersReady() {
+ mIsAndroidEduDevice = isAndroidEduDevice();
+ mHasChildAccount = hasChildAccount();
+ processFreEnvironment();
+ }
+ }.start(mActivity);
+ }
+
+ /**
+ * @return Whether the sync could be turned on.
+ */
+ @VisibleForTesting
+ boolean isSyncAllowed() {
+ return FeatureUtilities.canAllowSync(mActivity)
+ && !SigninManager.get(mActivity.getApplicationContext()).isSigninDisabledByPolicy();
+ }
+
+ /**
+ * @return Whether Terms of Service could be assumed to be accepted.
+ */
+ @VisibleForTesting
+ boolean didAcceptToS() {
+ return ToSAckedReceiver.checkAnyUserHasSeenToS(mActivity)
+ || PrefServiceBridge.getInstance().isFirstRunEulaAccepted();
+ }
+
+ /**
+ * @return Whether Chrome was installed as a part of the system image.
+ */
+ @VisibleForTesting
+ boolean isSystemInstall() {
+ return ((mActivity.getApplicationInfo().flags & ApplicationInfo.FLAG_SYSTEM) != 0);
+ }
+
+ private void processFreEnvironment() {
+ final Context context = mActivity.getApplicationContext();
+
+ if (FirstRunStatus.getFirstRunFlowComplete(mActivity)
+ && FirstRunIntroPage.wereAllNecessaryPagesShown(mActivity)) {
+ assert PrefServiceBridge.getInstance().isFirstRunEulaAccepted();
+ // We do not need any interactive FRE.
+ onFlowIsKnown(mActivity, null);
+ return;
+ }
+
+ Bundle freProperties = new Bundle();
+ freProperties.putAll(mLaunchProperties);
+ freProperties.remove(FirstRunActivity.USE_FRE_FLOW_SEQUENCER);
+
+ final Account[] googleAccounts = AccountManagerHelper.get(context).getGoogleAccounts();
+ final boolean onlyOneAccount = googleAccounts.length == 1;
+
+ // EDU devices should always have exactly 1 google account, which will be automatically
+ // signed-in. All FRE screens are skipped in this case.
+ final boolean forceEduSignIn = mIsAndroidEduDevice
+ && onlyOneAccount
+ && !ChromeSigninController.get(context).isSignedIn();
+
+ final boolean shouldSkipFirstUseHints =
+ ApiCompatibilityUtils.shouldSkipFirstUseHints(context.getContentResolver());
+
+ if (!FirstRunStatus.getFirstRunFlowComplete(context)) {
+ // In the full FRE we always show the Welcome page, except on EDU devices.
+ final boolean showWelcomePage = !forceEduSignIn;
+ freProperties.putBoolean(FirstRunActivity.SHOW_WELCOME_PAGE, showWelcomePage);
+
+ // Enable reporting by default on non-Stable releases.
+ // The user can turn it off on the Welcome page.
+ // This is controlled by the administrator via a policy on EDU devices.
+ if (!ChromeVersionInfo.isStableBuild()) {
+ PrivacyPreferencesManager.getInstance(mActivity).initCrashUploadPreference(true);
+ }
+
+ // We show the sign-in page if sync is allowed, and this is not an EDU device, and
+ // - no "skip the first use hints" is set, or
+ // - "skip the first use hints" is set, but there is at least one account.
+ final boolean syncOk = isSyncAllowed();
+ final boolean offerSignInOk = syncOk
+ && !forceEduSignIn
+ && (!shouldSkipFirstUseHints || googleAccounts.length > 0);
+ freProperties.putBoolean(FirstRunActivity.SHOW_SIGNIN_PAGE, offerSignInOk);
+
+ if (offerSignInOk || forceEduSignIn) {
+ // If the user has accepted the ToS in the Setup Wizard and there is exactly
+ // one account, or if the device has a child account, or if the device is an
+ // Android EDU device and there is exactly one account, preselect the sign-in
+ // account and force the selection if necessary.
+ if ((ToSAckedReceiver.checkAnyUserHasSeenToS(mActivity) && onlyOneAccount)
+ || mHasChildAccount
+ || forceEduSignIn) {
+ freProperties.putString(AccountFirstRunFragment.FORCE_SIGNIN_ACCOUNT_TO,
+ googleAccounts[0].name);
+ freProperties.putBoolean(AccountFirstRunFragment.PRESELECT_BUT_ALLOW_TO_CHANGE,
+ !forceEduSignIn && !mHasChildAccount);
+ }
+ }
+ } else {
+ // If the full FRE has already been shown, don't show Welcome or Sign-In pages.
+ freProperties.putBoolean(FirstRunActivity.SHOW_WELCOME_PAGE, false);
+ freProperties.putBoolean(FirstRunActivity.SHOW_SIGNIN_PAGE, false);
+ }
+
+ // We always show all not-yet-shown intro pages that could be shown.
+ freProperties.putLong(FirstRunActivity.SHOW_INTRO_BITMAP,
+ FirstRunIntroPage.getAllPresentablePages(mActivity)
+ & ~FirstRunIntroPage.getAlreadyShownPagesBitmap(mActivity));
+ freProperties.putBoolean(FirstRunActivity.SKIP_ALL_INTRO,
+ shouldSkipFirstUseHints || forceEduSignIn);
+ freProperties.putBoolean(AccountFirstRunFragment.IS_CHILD_ACCOUNT, mHasChildAccount);
+
+ onFlowIsKnown(mActivity, freProperties);
+ }
+
+ /**
+ * Marks a given flow as completed.
+ * @param activity An activity.
+ * @param data Resulting FRE properties bundle.
+ */
+ public static void markFlowAsCompleted(Activity activity, Bundle data) {
+ // When the user accepts ToS in the Setup Wizard (see ToSAckedReceiver), we do not
+ // show the ToS page to the user because the user has already accepted one outside FRE.
+ if (!PrefServiceBridge.getInstance().isFirstRunEulaAccepted()) {
+ PrefServiceBridge.getInstance().setEulaAccepted();
+ }
+
+ // Mark the intro pages we have shown as complete.
+ FirstRunIntroPage.markAsShown(activity, data.getLong(FirstRunActivity.SHOW_INTRO_BITMAP));
+
+ // Mark the FRE flow as complete and set the sign-in flow preferences if necessary.
+ FirstRunSignInProcessor.finalizeFirstRunFlowState(activity, data);
+ }
+
+ /**
+ * Checks if the First Run needs to be launched.
+ * @return The intent to launch the First Run Experience if necessary, or null.
+ * @param activity The context
+ * @param originalIntent An original intent
+ * @param fromChromeIcon Whether Chrome is opened via the Chrome icon
+ */
+ public static Intent checkIfFirstRunIsNecessary(Activity activity,
+ Intent originalIntent, boolean fromChromeIcon) {
+ // If FRE is disabled (e.g. in tests), proceed directly to the intent handling.
+ if (CommandLine.getInstance().hasSwitch(ChromeSwitches.DISABLE_FIRST_RUN_EXPERIENCE)) {
+ return null;
+ }
+
+ // If Chrome isn't opened via the Chrome icon, and the user accepted the ToS
+ // in the Setup Wizard, skip any First Run Experience screens and proceed directly
+ // to the intent handling.
+ if (!fromChromeIcon && ToSAckedReceiver.checkAnyUserHasSeenToS(activity)) return null;
+
+ // If the user hasn't been through the First Run Activity -- it must be shown.
+ final boolean baseFreComplete = FirstRunStatus.getFirstRunFlowComplete(activity);
+ if (!baseFreComplete) {
+ return createGenericFirstRunIntent(activity, originalIntent, fromChromeIcon);
+ }
+
+ // If Chrome isn't opened via the Chrome icon, or the user has already been through all
+ // intro screens, proceed directly to the intent handling.
+ if (!fromChromeIcon || FirstRunIntroPage.wereAllNecessaryPagesShown(activity)) return null;
+
+ // Otherwise (Chrome is launched via the Chrome icon and the user has already been through
+ // the First Run Activity, but not through all intro screens), check if we could show some
+ // intro screen.
+ if (FirstRunIntroPage.getAllPresentablePages(activity) == 0L) return null;
+
+ return createGenericFirstRunIntent(activity, originalIntent, fromChromeIcon);
+ }
+
+ /**
+ * @return A generic intent to show the First Run Activity.
+ * @param activity The context
+ * @param originalIntent An original intent
+ * @param fromChromeIcon Whether Chrome is opened via the Chrome icon
+ */
+ public static Intent createGenericFirstRunIntent(
+ Activity activity, Intent originalIntent, boolean fromChromeIcon) {
+ ChromiumApplication application = (ChromiumApplication) activity.getApplication();
+ String activityName = application.getFirstRunActivityName();
+
+ Intent intent = new Intent();
+ intent.setClassName(activity, activityName);
+ intent.putExtra(FirstRunActivity.COMING_FROM_CHROME_ICON, fromChromeIcon);
+ intent.putExtra(FirstRunActivity.USE_FRE_FLOW_SEQUENCER, true);
+ return intent;
+ }
+}

Powered by Google App Engine
This is Rietveld 408576698