summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--chrome/android/java/AndroidManifest.xml20
-rw-r--r--chrome/android/java/res/layout/upgrade_activity.xml52
-rw-r--r--chrome/android/java/src/org/chromium/chrome/browser/ChromeSwitches.java5
-rw-r--r--chrome/android/java/src/org/chromium/chrome/browser/ChromeTabbedActivity.java3
-rw-r--r--chrome/android/java/src/org/chromium/chrome/browser/UpgradeActivity.java136
-rw-r--r--chrome/android/java/src/org/chromium/chrome/browser/document/ChromeLauncherActivity.java28
-rw-r--r--chrome/android/java/src/org/chromium/chrome/browser/document/DocumentActivity.java24
-rw-r--r--chrome/android/java/src/org/chromium/chrome/browser/init/AsyncInitializationActivity.java13
-rw-r--r--chrome/android/java/src/org/chromium/chrome/browser/preferences/MainPreferences.java11
-rw-r--r--chrome/android/java/src/org/chromium/chrome/browser/tabmodel/DocumentModeAssassin.java81
-rw-r--r--chrome/android/java/src/org/chromium/chrome/browser/tabmodel/document/TabDelegate.java4
-rw-r--r--chrome/android/java_sources.gni1
-rw-r--r--chrome/android/javatests/src/org/chromium/chrome/browser/tabmodel/DocumentModeAssassinTest.java9
-rw-r--r--ui/android/java/strings/android_ui_strings.grd5
14 files changed, 348 insertions, 44 deletions
diff --git a/chrome/android/java/AndroidManifest.xml b/chrome/android/java/AndroidManifest.xml
index 4691aac..144e8e1 100644
--- a/chrome/android/java/AndroidManifest.xml
+++ b/chrome/android/java/AndroidManifest.xml
@@ -201,6 +201,21 @@ by a child template that "extends" this file.
<meta-data android:name="android.app.searchable"
android:resource="@xml/searchable" />
</activity-alias>
+
+ <!-- Upgrade related -->
+ <activity android:name="org.chromium.chrome.browser.UpgradeActivity"
+ android:excludeFromRecents="true"
+ android:theme="@style/MainTheme"
+ android:windowSoftInputMode="adjustResize"
+ android:taskAffinity=""
+ android:launchMode="singleInstance"
+ android:persistableMode="persistNever"
+ android:autoRemoveFromRecents="false"
+ android:configChanges="orientation|keyboardHidden|keyboard|screenSize|mcc|mnc|screenLayout|smallestScreenSize"
+ android:hardwareAccelerated="false">
+ </activity>
+
+ <!-- Document mode Activities. -->
<activity android:name="org.chromium.chrome.browser.document.DocumentActivity"
android:exported="false"
android:theme="@style/MainTheme"
@@ -228,6 +243,8 @@ by a child template that "extends" this file.
<activity-alias android:name="com.google.android.apps.chrome.document.IncognitoDocumentActivity"
android:targetActivity="org.chromium.chrome.browser.document.IncognitoDocumentActivity"
android:exported="false"/>
+
+ <!-- Custom Tabs -->
<activity android:name="org.chromium.chrome.browser.customtabs.CustomTabActivity"
android:theme="@style/MainTheme"
android:exported="false"
@@ -235,6 +252,8 @@ by a child template that "extends" this file.
android:configChanges="orientation|keyboardHidden|keyboard|screenSize|mcc|mnc|screenLayout|smallestScreenSize"
android:hardwareAccelerated="false">
</activity>
+
+ <!-- ChromeTabbedActivity related -->
<activity android:name="org.chromium.chrome.browser.ChromeTabbedActivity"
android:theme="@style/MainTheme"
android:exported="false"
@@ -252,6 +271,7 @@ by a child template that "extends" this file.
android:configChanges="orientation|keyboardHidden|keyboard|screenSize|mcc|mnc|screenLayout|smallestScreenSize"
android:hardwareAccelerated="false">
</activity>
+
<activity android:name="org.chromium.chrome.browser.sync.ui.PassphraseActivity"
android:theme="@style/MainTheme"
android:autoRemoveFromRecents="true">
diff --git a/chrome/android/java/res/layout/upgrade_activity.xml b/chrome/android/java/res/layout/upgrade_activity.xml
new file mode 100644
index 0000000..975cf93
--- /dev/null
+++ b/chrome/android/java/res/layout/upgrade_activity.xml
@@ -0,0 +1,52 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright 2016 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. -->
+
+<!-- Adapted from webapp_splash_screen_large.xml.
+ Actual layout pending UX review. -->
+<RelativeLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/webapp_splash_screen_layout"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:layout_marginBottom="@dimen/webapp_splash_offset" >
+
+ <ImageView
+ android:id="@+id/logo_view"
+ android:layout_width="@dimen/signin_image_carousel_width"
+ android:layout_height="wrap_content"
+ android:layout_centerInParent="true"
+ android:contentDescription="@null"
+ android:src="@drawable/fre_product_logo" />
+
+ <LinearLayout
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_alignParentBottom="true"
+ android:layout_centerHorizontal="true"
+ android:layout_marginBottom="@dimen/webapp_splash_large_title_margin_bottom"
+ android:gravity="center"
+ android:orientation="horizontal" >
+
+ <ProgressBar
+ android:layout_width="20dp"
+ android:layout_height="20dp"
+ android:layout_marginEnd="12dp"
+ android:layout_weight="0" />
+
+ <TextView
+ android:id="@+id/message_view"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_weight="0"
+ android:text="@string/updating_chrome"
+ android:textSize="20sp"
+ android:textColor="@color/default_text_color"
+ android:gravity="center"
+ android:fontFamily="sans-serif"
+ android:maxLines="1" />
+
+ </LinearLayout>
+
+</RelativeLayout>
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/ChromeSwitches.java b/chrome/android/java/src/org/chromium/chrome/browser/ChromeSwitches.java
index 534fdef..07c8b0f 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/ChromeSwitches.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/ChromeSwitches.java
@@ -231,6 +231,11 @@ public abstract class ChromeSwitches {
"disable-web-notification-custom-layouts";
/**
+ * Forces a user down the document to tabbed mode migration pathway.
+ */
+ public static final String ENABLE_FORCED_MIGRATION = "enable-forced-migration";
+
+ /**
* Determines which of the Herb prototypes is being tested.
* See about:flags for descriptions.
*/
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/ChromeTabbedActivity.java b/chrome/android/java/src/org/chromium/chrome/browser/ChromeTabbedActivity.java
index 3d64a3f..e2bf87d 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/ChromeTabbedActivity.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/ChromeTabbedActivity.java
@@ -725,6 +725,9 @@ public class ChromeTabbedActivity extends ChromeActivity implements OverviewMode
if (tabIndex != TabModel.INVALID_TAB_INDEX) {
getTabModelSelector().selectModel(otherModel.isIncognito());
TabModelUtils.setIndex(otherModel, tabIndex);
+ } else {
+ Log.e(TAG, "Failed to bring tab to front because it doesn't exist.");
+ return;
}
} else {
TabModelUtils.setIndex(tabModel, tabIndex);
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/UpgradeActivity.java b/chrome/android/java/src/org/chromium/chrome/browser/UpgradeActivity.java
new file mode 100644
index 0000000..e203e67
--- /dev/null
+++ b/chrome/android/java/src/org/chromium/chrome/browser/UpgradeActivity.java
@@ -0,0 +1,136 @@
+// Copyright 2016 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;
+
+import android.content.Context;
+import android.content.Intent;
+import android.os.Bundle;
+import android.os.Handler;
+import android.os.Looper;
+import android.support.v7.app.AppCompatActivity;
+
+import org.chromium.base.ApiCompatibilityUtils;
+import org.chromium.base.ApplicationStatus;
+import org.chromium.chrome.R;
+import org.chromium.chrome.browser.tabmodel.DocumentModeAssassin;
+import org.chromium.chrome.browser.tabmodel.DocumentModeAssassin.DocumentModeAssassinObserver;
+import org.chromium.chrome.browser.util.IntentUtils;
+
+/**
+ * Activity that interrupts launch and shows that users are being upgraded to a new version of
+ * Chrome.
+ *
+ * TODO(dfalcantara): Do we need to worry about onNewIntent()?
+ */
+public class UpgradeActivity extends AppCompatActivity {
+ public static final String EXTRA_INTENT_TO_REFIRE =
+ "org.chromium.chrome.browser.INTENT_TO_REFIRE";
+
+ private static final long MIN_MS_TO_DISPLAY_ACTIVITY = 500;
+ private static final long INVALID_TIMESTAMP = -1;
+
+ private final Handler mHandler;
+ private final DocumentModeAssassinObserver mObserver;
+
+ private Intent mIntentToFireAfterUpgrade;
+ private long mStartTimestamp = INVALID_TIMESTAMP;
+ private boolean mIsDestroyed;
+
+ public static void launchInstance(Context context, Intent originalIntent) {
+ Intent intent = new Intent();
+ intent.setClass(context, UpgradeActivity.class);
+ intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+ intent.putExtra(UpgradeActivity.EXTRA_INTENT_TO_REFIRE, originalIntent);
+ context.startActivity(intent);
+ }
+
+ public UpgradeActivity() {
+ mHandler = new Handler(Looper.getMainLooper());
+
+ mObserver = new DocumentModeAssassinObserver() {
+ @Override
+ public void onStageChange(int newStage) {
+ if (newStage != DocumentModeAssassin.STAGE_DONE) return;
+ DocumentModeAssassin.getInstance().removeObserver(this);
+
+ // Always post to avoid any issues that could arise from firing the Runnable
+ // while other Observers are being alerted.
+ long msElapsed = System.currentTimeMillis() - mStartTimestamp;
+ long msRemaining = Math.max(0, MIN_MS_TO_DISPLAY_ACTIVITY - msElapsed);
+ mHandler.postDelayed(new Runnable() {
+ @Override
+ public void run() {
+ continueApplicationLaunch();
+ }
+ }, msRemaining);
+ }
+ };
+ }
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ mIntentToFireAfterUpgrade = getIntentToFireAfterUpgrade(getIntent());
+ setContentView(R.layout.upgrade_activity);
+
+ DocumentModeAssassin assassin = DocumentModeAssassin.getInstance();
+ if (!DocumentModeAssassin.isMigrationNecessary()
+ || assassin.getStage() == DocumentModeAssassin.STAGE_DONE) {
+ // Migration finished in the background.
+ continueApplicationLaunch();
+ } else {
+ // Kick off migration if it hasn't already started.
+ assassin.addObserver(mObserver);
+ assassin.migrateFromDocumentToTabbedMode();
+ }
+ }
+
+ @Override
+ protected void onResume() {
+ super.onResume();
+
+ // Set the timestamp after the Activity is visible to avoid shortening the timer.
+ if (mStartTimestamp == INVALID_TIMESTAMP) mStartTimestamp = System.currentTimeMillis();
+ }
+
+ @Override
+ protected void onDestroy() {
+ mIsDestroyed = true;
+ super.onDestroy();
+ }
+
+ private static Intent getIntentToFireAfterUpgrade(Intent activityIntent) {
+ Intent intentToFire = null;
+
+ // Retrieve the Intent that caused the user to end up on the upgrade pathway.
+ if (activityIntent != null) {
+ intentToFire = (Intent) IntentUtils.safeGetParcelableExtra(
+ activityIntent, EXTRA_INTENT_TO_REFIRE);
+ }
+
+ // If there's no Intent to refire, send them to the browser.
+ if (intentToFire == null) {
+ intentToFire = new Intent(Intent.ACTION_MAIN);
+ intentToFire.setPackage(ApplicationStatus.getApplicationContext().getPackageName());
+ }
+
+ // Fire the Intent into a different task so that this one can go away.
+ intentToFire.addFlags(
+ Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_NEW_DOCUMENT);
+
+ return intentToFire;
+ }
+
+ private void continueApplicationLaunch() {
+ if (mIsDestroyed) return;
+
+ ApiCompatibilityUtils.finishAndRemoveTask(this);
+ if (mIntentToFireAfterUpgrade != null && ApplicationStatus.hasVisibleActivities()) {
+ startActivity(mIntentToFireAfterUpgrade);
+ overridePendingTransition(android.R.anim.fade_in, 0);
+ mIntentToFireAfterUpgrade = null;
+ }
+ }
+}
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/document/ChromeLauncherActivity.java b/chrome/android/java/src/org/chromium/chrome/browser/document/ChromeLauncherActivity.java
index c314adf..cd495fa 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/document/ChromeLauncherActivity.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/document/ChromeLauncherActivity.java
@@ -42,6 +42,7 @@ import org.chromium.chrome.browser.IntentHandler;
import org.chromium.chrome.browser.IntentHandler.TabOpenType;
import org.chromium.chrome.browser.ShortcutHelper;
import org.chromium.chrome.browser.ShortcutSource;
+import org.chromium.chrome.browser.UpgradeActivity;
import org.chromium.chrome.browser.UrlConstants;
import org.chromium.chrome.browser.WarmupManager;
import org.chromium.chrome.browser.customtabs.CustomTabActivity;
@@ -59,6 +60,7 @@ import org.chromium.chrome.browser.preferences.DocumentModeManager;
import org.chromium.chrome.browser.tab.Tab;
import org.chromium.chrome.browser.tab.TabIdManager;
import org.chromium.chrome.browser.tabmodel.AsyncTabParamsManager;
+import org.chromium.chrome.browser.tabmodel.DocumentModeAssassin;
import org.chromium.chrome.browser.tabmodel.document.ActivityDelegate;
import org.chromium.chrome.browser.tabmodel.document.AsyncTabCreationParams;
import org.chromium.chrome.browser.tabmodel.document.DocumentTabModel;
@@ -217,13 +219,6 @@ public class ChromeLauncherActivity extends Activity
return;
}
- // Check if we're just closing all of the Incognito tabs.
- if (TextUtils.equals(intent.getAction(), ACTION_CLOSE_ALL_INCOGNITO)) {
- ChromeApplication.getDocumentTabModelSelector().getModel(true).closeAllTabs();
- ApiCompatibilityUtils.finishAndRemoveTask(this);
- return;
- }
-
// Check if we should launch the FirstRunActivity. This occurs after the check to launch
// ChromeTabbedActivity because ChromeTabbedActivity handles FRE in its own way.
if (launchFirstRunExperience()) return;
@@ -234,8 +229,23 @@ public class ChromeLauncherActivity extends Activity
return;
}
- // Launch a DocumentActivity to handle the Intent.
- handleDocumentActivityIntent();
+ if (DocumentModeAssassin.isMigrationNecessary()) {
+ Log.d(TAG, "Diverting to UpgradeActivity via ChromeLauncherActivity.");
+ UpgradeActivity.launchInstance(this, intent);
+ ApiCompatibilityUtils.finishAndRemoveTask(this);
+ return;
+ } else {
+ // Check if we're just closing all of the Incognito tabs.
+ if (TextUtils.equals(intent.getAction(), ACTION_CLOSE_ALL_INCOGNITO)) {
+ ChromeApplication.getDocumentTabModelSelector().getModel(true).closeAllTabs();
+ ApiCompatibilityUtils.finishAndRemoveTask(this);
+ return;
+ }
+
+ // Launch a DocumentActivity to handle the Intent.
+ handleDocumentActivityIntent();
+ }
+
if (!mIsFinishDelayed) ApiCompatibilityUtils.finishAndRemoveTask(this);
}
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/document/DocumentActivity.java b/chrome/android/java/src/org/chromium/chrome/browser/document/DocumentActivity.java
index eee242a..62d9864 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/document/DocumentActivity.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/document/DocumentActivity.java
@@ -230,8 +230,30 @@ public class DocumentActivity extends ChromeActivity {
@Override
protected boolean isStartedUpCorrectly(Intent intent) {
- int tabId = ActivityDelegate.getTabIdFromIntent(getIntent());
boolean isDocumentMode = FeatureUtilities.isDocumentMode(this);
+ int tabId = ActivityDelegate.getTabIdFromIntent(getIntent());
+
+ if (!isDocumentMode) {
+ // Fire a MAIN Intent to send the user back through ChromeLauncherActivity.
+ Log.e(TAG, "User is not in document mode. Sending back to ChromeLauncherActivity.");
+
+ // Try to bring this tab forward after migration.
+ Intent tabbedIntent = null;
+ if (tabId != Tab.INVALID_TAB_ID) tabbedIntent = Tab.createBringTabToFrontIntent(tabId);
+
+ if (tabbedIntent == null) {
+ tabbedIntent = new Intent(Intent.ACTION_MAIN);
+ tabbedIntent.setPackage(getPackageName());
+ }
+
+ // Launch the other Activity in its own task so it stays when this one finishes.
+ tabbedIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+ tabbedIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_DOCUMENT);
+
+ startActivity(tabbedIntent);
+ overridePendingTransition(0, 0);
+ }
+
boolean isStartedUpCorrectly = tabId != Tab.INVALID_TAB_ID && isDocumentMode;
if (!isStartedUpCorrectly) {
Log.e(TAG, "Discarding Intent: Tab = " + tabId + ", Document mode = " + isDocumentMode);
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/init/AsyncInitializationActivity.java b/chrome/android/java/src/org/chromium/chrome/browser/init/AsyncInitializationActivity.java
index 2c5d3a8..bfd5880 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/init/AsyncInitializationActivity.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/init/AsyncInitializationActivity.java
@@ -27,10 +27,12 @@ import org.chromium.base.TraceEvent;
import org.chromium.base.library_loader.LoaderErrors;
import org.chromium.base.library_loader.ProcessInitException;
import org.chromium.chrome.browser.ChromeApplication;
+import org.chromium.chrome.browser.UpgradeActivity;
import org.chromium.chrome.browser.WarmupManager;
import org.chromium.chrome.browser.metrics.LaunchMetrics;
import org.chromium.chrome.browser.metrics.MemoryUma;
import org.chromium.chrome.browser.profiles.Profile;
+import org.chromium.chrome.browser.tabmodel.DocumentModeAssassin;
import org.chromium.ui.base.DeviceFormFactor;
import java.lang.reflect.Field;
@@ -189,6 +191,17 @@ public abstract class AsyncInitializationActivity extends AppCompatActivity impl
*/
@Override
protected final void onCreate(Bundle savedInstanceState) {
+ if (DocumentModeAssassin.isMigrationNecessary()) {
+ super.onCreate(null);
+
+ // Kick the user to the MigrationActivity.
+ UpgradeActivity.launchInstance(this, getIntent());
+
+ // Don't remove this task -- it may be a DocumentActivity that exists only in Recents.
+ finish();
+ return;
+ }
+
if (!isStartedUpCorrectly(getIntent())) {
sBadIntentMetric.recordHit();
super.onCreate(null);
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/preferences/MainPreferences.java b/chrome/android/java/src/org/chromium/chrome/browser/preferences/MainPreferences.java
index 2e655d14..cf5469a 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/preferences/MainPreferences.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/preferences/MainPreferences.java
@@ -11,7 +11,10 @@ import android.preference.Preference;
import android.preference.Preference.OnPreferenceClickListener;
import android.preference.PreferenceFragment;
+import org.chromium.base.ApplicationStatus;
+import org.chromium.base.CommandLine;
import org.chromium.chrome.R;
+import org.chromium.chrome.browser.ChromeSwitches;
import org.chromium.chrome.browser.PasswordUIView;
import org.chromium.chrome.browser.autofill.PersonalDataManager;
import org.chromium.chrome.browser.net.spdyproxy.DataReductionProxySettings;
@@ -103,8 +106,14 @@ public class MainPreferences extends PreferenceFragment implements SignInStateOb
});
mSignInPreference.setEnabled(true);
+ // TODO(dfalcantara): Delete this preference entirely. https://crbug.com/582539
Preference documentMode = findPreference(PREF_DOCUMENT_MODE);
- if (FeatureUtilities.isDocumentModeEligible(getActivity())) {
+ boolean showDocumentToggle = FeatureUtilities.isDocumentModeEligible(getActivity());
+ if (CommandLine.getInstance().hasSwitch(ChromeSwitches.ENABLE_FORCED_MIGRATION)) {
+ showDocumentToggle &=
+ FeatureUtilities.isDocumentMode(ApplicationStatus.getApplicationContext());
+ }
+ if (showDocumentToggle) {
setOnOffSummary(documentMode,
!DocumentModeManager.getInstance(getActivity()).isOptedOutOfDocumentMode());
} else {
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/tabmodel/DocumentModeAssassin.java b/chrome/android/java/src/org/chromium/chrome/browser/tabmodel/DocumentModeAssassin.java
index 89936ef..bc7e0ba 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/tabmodel/DocumentModeAssassin.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/tabmodel/DocumentModeAssassin.java
@@ -12,6 +12,7 @@ import android.os.Build;
import android.util.Pair;
import org.chromium.base.ApplicationStatus;
+import org.chromium.base.CommandLine;
import org.chromium.base.FileUtils;
import org.chromium.base.Log;
import org.chromium.base.ObserverList;
@@ -19,6 +20,7 @@ import org.chromium.base.StreamUtil;
import org.chromium.base.ThreadUtils;
import org.chromium.base.VisibleForTesting;
import org.chromium.chrome.browser.ChromeApplication;
+import org.chromium.chrome.browser.ChromeSwitches;
import org.chromium.chrome.browser.TabState;
import org.chromium.chrome.browser.document.DocumentActivity;
import org.chromium.chrome.browser.document.DocumentUtils;
@@ -42,6 +44,8 @@ import java.nio.channels.FileChannel;
import java.util.HashSet;
import java.util.Set;
+import javax.annotation.Nullable;
+
/**
* Divorces Chrome's tabs from Android's Overview menu. Assumes native libraries are unavailable.
*
@@ -52,7 +56,6 @@ import java.util.Set;
* into the tabbed mode directory. Incognito tabs are silently dropped, as with the previous
* migration pathway.
*
- * TODO(dfalcantara): Check what happens if a user last viewed an Incognito tab.
* TODO(dfalcantara): Check what happens on other launchers.
*
* Once all TabState files are copied, a TabModel metadata file is written out for the tabbed
@@ -64,7 +67,6 @@ import java.util.Set;
* DocumentActivity tasks in Android's Recents are removed, TabState files in the document mode
* directory are deleted, and document mode preferences are cleared.
*
- * TODO(dfalcantara): Clean up the incognito notification, if possible.
* TODO(dfalcantara): Add histograms for tracking migration progress.
*
* TODO(dfalcantara): Potential pitfalls that need to be accounted for:
@@ -105,7 +107,7 @@ public class DocumentModeAssassin {
static final int STAGE_CHANGE_SETTINGS_STARTED = 6;
static final int STAGE_CHANGE_SETTINGS_DONE = 7;
static final int STAGE_DELETION_STARTED = 8;
- static final int STAGE_DONE = 9;
+ public static final int STAGE_DONE = 9;
private static final String TAG = "DocumentModeAssassin";
@@ -137,7 +139,8 @@ public class DocumentModeAssassin {
/** Returns whether or not a migration to tabbed mode from document mode is necessary. */
public static boolean isMigrationNecessary() {
- return FeatureUtilities.isDocumentMode(ApplicationStatus.getApplicationContext());
+ return CommandLine.getInstance().hasSwitch(ChromeSwitches.ENABLE_FORCED_MIGRATION)
+ && FeatureUtilities.isDocumentMode(ApplicationStatus.getApplicationContext());
}
/** Migrates the user from document mode to tabbed mode if necessary. */
@@ -165,18 +168,39 @@ public class DocumentModeAssassin {
*
* TODO(dfalcantara): Prevent migrating chrome:// pages?
*
- * @param selectedTabId ID of the last viewed non-Incognito tab.
- * @param documentDirectory File pointing at the DocumentTabModel TabState file directory.
- * @param tabbedDirectory File pointing at tabbed mode TabState file directory.
+ * @param selectedTabId ID of the last viewed non-Incognito tab.
+ * @param context Context to use when accessing directories.
+ * @param documentDirectoryOverride Overrides the default location for where document mode's
+ * TabState files are expected to be.
+ * @param tabbedDirectoryOverride Overrides the default location for where tabbed mode's
+ * TabState files are expected to be.
*/
- void copyTabStateFiles(
- final int selectedTabId, final File documentDirectory, final File tabbedDirectory) {
+ void copyTabStateFiles(final int selectedTabId, final Context context,
+ @Nullable final File documentDirectoryOverride,
+ @Nullable final File tabbedDirectoryOverride) {
ThreadUtils.assertOnUiThread();
if (!setStage(STAGE_INITIALIZED, STAGE_COPY_TAB_STATES_STARTED)) return;
new AsyncTask<Void, Void, Void>() {
+ private DocumentTabModelImpl mNormalTabModel;
+
+ @Override
+ protected void onPreExecute() {
+ if (documentDirectoryOverride == null) {
+ mNormalTabModel = (DocumentTabModelImpl)
+ ChromeApplication.getDocumentTabModelSelector().getModel(false);
+ }
+ }
+
@Override
protected Void doInBackground(Void... params) {
+ File documentDirectory = documentDirectoryOverride == null
+ ? mNormalTabModel.getStorageDelegate().getStateDirectory()
+ : documentDirectoryOverride;
+ File tabbedDirectory = tabbedDirectoryOverride == null
+ ? TabPersistentStore.getStateDirectory(context, TAB_MODEL_INDEX)
+ : tabbedDirectoryOverride;
+
Log.d(TAG, "Copying TabState files from document to tabbed mode directory.");
assert mMigratedTabIds.size() == 0;
@@ -186,11 +210,12 @@ public class DocumentModeAssassin {
// before all the other ones to mitigate storage issues for devices with limited
// available storage.
if (selectedTabId != Tab.INVALID_TAB_ID) {
- copyTabStateFilesInternal(allTabStates, selectedTabId, true);
+ copyTabStateFilesInternal(
+ allTabStates, tabbedDirectory, selectedTabId, true);
}
// Copy over everything else.
- copyTabStateFilesInternal(allTabStates, selectedTabId, false);
+ copyTabStateFilesInternal(allTabStates, tabbedDirectory, selectedTabId, false);
}
return null;
}
@@ -205,12 +230,13 @@ public class DocumentModeAssassin {
* Copies the files from the document mode directory to the tabbed mode directory.
*
* @param allTabStates Listing of all files in the document mode directory.
+ * @param tabbedDirectory Directory for the tabbed mode files.
* @param selectedTabId ID of the non-Incognito tab the user last viewed. May be
* {@link Tab#INVALID_TAB_ID} if the ID is unknown.
* @param copyOnlySelectedTab Copy only the TabState file for the selectedTabId.
*/
- private void copyTabStateFilesInternal(
- File[] allTabStates, int selectedTabId, boolean copyOnlySelectedTab) {
+ private void copyTabStateFilesInternal(File[] allTabStates, File tabbedDirectory,
+ int selectedTabId, boolean copyOnlySelectedTab) {
assert !ThreadUtils.runningOnUiThread();
for (int i = 0; i < allTabStates.length; i++) {
// Trawl the directory for non-Incognito TabState files.
@@ -281,12 +307,15 @@ public class DocumentModeAssassin {
* means that the user loses some navigation history, but it's not a case document mode would
* have been able to recover from anyway because the TabState stores the URL data.
*
- * @param tabbedDirectory Directory containing all of the main TabModel's files.
- * @param normalTabModel DocumentTabModel containing information about non-Incognito tabs.
- * @param migratedTabIds IDs of Tabs whose TabState files were copied successfully.
+ * @param normalTabModel DocumentTabModel containing info about non-Incognito tabs.
+ * @param migratedTabIds IDs of Tabs whose TabState files were copied successfully.
+ * @param context Context to access Files from.
+ * @param tabbedDirectoryOverride Overrides the default location for where tabbed mode's
+ * TabState files are expected to be.
*/
- void writeTabModelMetadata(final File tabbedDirectory, final DocumentTabModel normalTabModel,
- final Set<Integer> migratedTabIds) {
+ void writeTabModelMetadata(final DocumentTabModel normalTabModel,
+ final Set<Integer> migratedTabIds, final Context context,
+ @Nullable final File tabbedDirectoryOverride) {
ThreadUtils.assertOnUiThread();
if (!setStage(STAGE_COPY_TAB_STATES_DONE, STAGE_WRITE_TABMODEL_METADATA_STARTED)) return;
@@ -329,6 +358,9 @@ public class DocumentModeAssassin {
@Override
protected Boolean doInBackground(Void... params) {
if (mSerializedMetadata != null) {
+ File tabbedDirectory = tabbedDirectoryOverride == null
+ ? TabPersistentStore.getStateDirectory(context, TAB_MODEL_INDEX)
+ : tabbedDirectoryOverride;
TabPersistentStore.saveListToFile(tabbedDirectory, mSerializedMetadata);
return true;
} else {
@@ -440,22 +472,14 @@ public class DocumentModeAssassin {
Context context = ApplicationStatus.getApplicationContext();
if (newStage == STAGE_INITIALIZED) {
Log.d(TAG, "Migrating user into tabbed mode.");
- DocumentTabModelSelector selector = ChromeApplication.getDocumentTabModelSelector();
- DocumentTabModelImpl normalTabModel =
- (DocumentTabModelImpl) selector.getModel(false);
int selectedTabId = DocumentUtils.getLastShownTabIdFromPrefs(context, false);
-
- File documentDirectory = normalTabModel.getStorageDelegate().getStateDirectory();
- File tabbedDirectory = TabPersistentStore.getStateDirectory(context, TAB_MODEL_INDEX);
- copyTabStateFiles(selectedTabId, documentDirectory, tabbedDirectory);
+ copyTabStateFiles(selectedTabId, context, null, null);
} else if (newStage == STAGE_COPY_TAB_STATES_DONE) {
Log.d(TAG, "Writing tabbed mode metadata file.");
DocumentTabModelSelector selector = ChromeApplication.getDocumentTabModelSelector();
DocumentTabModelImpl normalTabModel =
(DocumentTabModelImpl) selector.getModel(false);
- File tabbedDirectory =
- TabPersistentStore.getStateDirectory(context, TAB_MODEL_INDEX);
- writeTabModelMetadata(tabbedDirectory, normalTabModel, mMigratedTabIds);
+ writeTabModelMetadata(normalTabModel, mMigratedTabIds, context, null);
} else if (newStage == STAGE_WRITE_TABMODEL_METADATA_DONE) {
Log.d(TAG, "Changing user preference.");
changePreferences(context);
@@ -471,6 +495,7 @@ public class DocumentModeAssassin {
*/
@VisibleForTesting
public int getStage() {
+ ThreadUtils.assertOnUiThread();
return mStage;
}
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/tabmodel/document/TabDelegate.java b/chrome/android/java/src/org/chromium/chrome/browser/tabmodel/document/TabDelegate.java
index ff8ccad..a31f2b4 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/tabmodel/document/TabDelegate.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/tabmodel/document/TabDelegate.java
@@ -11,6 +11,8 @@ import android.net.Uri;
import android.text.TextUtils;
import org.chromium.base.ApplicationStatus;
+import org.chromium.base.CommandLine;
+import org.chromium.chrome.browser.ChromeSwitches;
import org.chromium.chrome.browser.IntentHandler;
import org.chromium.chrome.browser.TabState;
import org.chromium.chrome.browser.UrlConstants;
@@ -177,6 +179,6 @@ public class TabDelegate extends TabCreator {
* @return Whether the TabDelegate is allowed to directly launch a DocumentActivity.
*/
protected boolean isAllowedToLaunchDocumentActivity(Context context) {
- return true;
+ return !CommandLine.getInstance().hasSwitch(ChromeSwitches.ENABLE_FORCED_MIGRATION);
}
} \ No newline at end of file
diff --git a/chrome/android/java_sources.gni b/chrome/android/java_sources.gni
index 95ef7e1..1e47a1f 100644
--- a/chrome/android/java_sources.gni
+++ b/chrome/android/java_sources.gni
@@ -50,6 +50,7 @@ chrome_java_sources = [
"java/src/org/chromium/chrome/browser/SwipeRefreshHandler.java",
"java/src/org/chromium/chrome/browser/TabState.java",
"java/src/org/chromium/chrome/browser/TtsPlatformImpl.java",
+ "java/src/org/chromium/chrome/browser/UpgradeActivity.java",
"java/src/org/chromium/chrome/browser/UrlConstants.java",
"java/src/org/chromium/chrome/browser/WarmupManager.java",
"java/src/org/chromium/chrome/browser/WebContentsFactory.java",
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/tabmodel/DocumentModeAssassinTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/tabmodel/DocumentModeAssassinTest.java
index 0e3566d..bceb753 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/tabmodel/DocumentModeAssassinTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/tabmodel/DocumentModeAssassinTest.java
@@ -210,12 +210,13 @@ public class DocumentModeAssassinTest extends NativeLibraryTestBase {
int numFilesBefore = tabbedModeFilesBefore.length;
assertEquals(0, writeStartedCallback.getCallCount());
assertEquals(0, writeDoneCallback.getCallCount());
+ final Context context = getInstrumentation().getTargetContext();
ThreadUtils.runOnUiThreadBlocking(new Runnable() {
@Override
public void run() {
assassin.addObserver(observer);
- assassin.writeTabModelMetadata(
- mTabbedModeDirectory.getDataDirectory(), testTabModel, migratedTabIds);
+ assassin.writeTabModelMetadata(testTabModel, migratedTabIds, context,
+ mTabbedModeDirectory.getDataDirectory());
}
});
@@ -231,7 +232,6 @@ public class DocumentModeAssassinTest extends NativeLibraryTestBase {
loadNativeLibraryAndInitBrowserProcess();
TabPersistentStore.setBaseStateDirectory(mTabbedModeDirectory.getBaseDirectory());
- Context context = getInstrumentation().getTargetContext();
TestTabModelSelector selector = new TestTabModelSelector(context);
TabPersistentStore store = selector.mTabPersistentStore;
MockTabPersistentStoreObserver mockObserver = selector.mTabPersistentStoreObserver;
@@ -329,7 +329,8 @@ public class DocumentModeAssassinTest extends NativeLibraryTestBase {
assertEquals(0, copyStartedCallback.getCallCount());
assertEquals(0, copyDoneCallback.getCallCount());
assertEquals(0, copyCallback.getCallCount());
- assassin.copyTabStateFiles(selectedTabId, mDocumentModeDirectory.getDataDirectory(),
+ assassin.copyTabStateFiles(selectedTabId, getInstrumentation().getTargetContext(),
+ mDocumentModeDirectory.getDataDirectory(),
mTabbedModeDirectory.getDataDirectory());
}
});
diff --git a/ui/android/java/strings/android_ui_strings.grd b/ui/android/java/strings/android_ui_strings.grd
index 1ce51bc..5d69aba 100644
--- a/ui/android/java/strings/android_ui_strings.grd
+++ b/ui/android/java/strings/android_ui_strings.grd
@@ -234,6 +234,11 @@
<message name="IDS_AUTOFILL_KEYBOARD_ACCESSORY_CONTENT_DESCRIPTION" desc="The text announced by the screen reader when the autofill suggestions are shown.">
Suggestions available
</message>
+
+ <!-- Migration strings -->
+ <message name="IDS_UPDATING_CHROME" desc="String that indicates that Chrome is updating">
+ Updating Chrome...
+ </message>
</messages>
</release>
</grit>