| Index: chrome/android/java/src/org/chromium/chrome/browser/tabmodel/document/DocumentTabModelSelector.java
|
| diff --git a/chrome/android/java/src/org/chromium/chrome/browser/tabmodel/document/DocumentTabModelSelector.java b/chrome/android/java/src/org/chromium/chrome/browser/tabmodel/document/DocumentTabModelSelector.java
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..a60fb632de501dd31095bf6120d25cfa8418ba45
|
| --- /dev/null
|
| +++ b/chrome/android/java/src/org/chromium/chrome/browser/tabmodel/document/DocumentTabModelSelector.java
|
| @@ -0,0 +1,244 @@
|
| +// Copyright 2014 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.tabmodel.document;
|
| +
|
| +import android.annotation.TargetApi;
|
| +import android.app.Activity;
|
| +import android.app.ActivityManager;
|
| +import android.app.ActivityManager.RecentTaskInfo;
|
| +import android.content.Context;
|
| +import android.content.SharedPreferences;
|
| +import android.net.Uri;
|
| +import android.os.Build;
|
| +import android.util.SparseArray;
|
| +
|
| +import org.chromium.base.ActivityState;
|
| +import org.chromium.base.ApplicationStatus;
|
| +import org.chromium.base.ApplicationStatus.ActivityStateListener;
|
| +import org.chromium.base.ThreadUtils;
|
| +import org.chromium.chrome.browser.Tab;
|
| +import org.chromium.chrome.browser.UrlConstants;
|
| +import org.chromium.chrome.browser.document.DocumentUtils;
|
| +import org.chromium.chrome.browser.document.PendingDocumentData;
|
| +import org.chromium.chrome.browser.tabmodel.OffTheRecordTabModel.OffTheRecordTabModelDelegate;
|
| +import org.chromium.chrome.browser.tabmodel.TabModel;
|
| +import org.chromium.chrome.browser.tabmodel.TabModel.TabLaunchType;
|
| +import org.chromium.chrome.browser.tabmodel.TabModelSelectorBase;
|
| +import org.chromium.content_public.browser.LoadUrlParams;
|
| +
|
| +/**
|
| + * Stores DocumentTabModels for Chrome Activities running in Document-mode.
|
| + * Also manages the transfer of data from one DocumentActivity to another, e.g. WebContents that are
|
| + * created by one Activity but need to be loaded in another Tab.
|
| + */
|
| +@TargetApi(Build.VERSION_CODES.LOLLIPOP)
|
| +public class DocumentTabModelSelector extends TabModelSelectorBase
|
| + implements ActivityStateListener {
|
| + public static final String PREF_PACKAGE = "com.google.android.apps.chrome.document";
|
| + public static final String PREF_IS_INCOGNITO_SELECTED = "is_incognito_selected";
|
| +
|
| + /**
|
| + * ID of the Tab to prioritize when initializing the TabState.
|
| + */
|
| + private static int sPrioritizedTabId = Tab.INVALID_TAB_ID;
|
| +
|
| + /**
|
| + * Interacts with DocumentActivities.
|
| + */
|
| + private final ActivityDelegate mActivityDelegate;
|
| +
|
| + /**
|
| + * Creates new Tabs.
|
| + */
|
| + private final TabDelegate mTabDelegate;
|
| +
|
| + /**
|
| + * TabModel that keeps track of regular tabs. This is always not null.
|
| + */
|
| + private final DocumentTabModel mRegularTabModel;
|
| +
|
| + /**
|
| + * TabModel that keeps track of incognito tabs. This may be null if no incognito tabs exist.
|
| + */
|
| + private final OffTheRecordDocumentTabModel mIncognitoTabModel;
|
| +
|
| + /**
|
| + * A map of tab IDs to PendingDocumentData to be consumed by opening activities.
|
| + */
|
| + private final SparseArray<PendingDocumentData> mPendingDocumentData =
|
| + new SparseArray<PendingDocumentData>();
|
| +
|
| + /**
|
| + * If the TabModels haven't been initialized yet, prioritize the correct one to load the Tab.
|
| + * @param prioritizedTabId ID of the tab to prioritize.
|
| + */
|
| + public static void setPrioritizedTabId(int prioritizedTabId) {
|
| + sPrioritizedTabId = prioritizedTabId;
|
| + }
|
| +
|
| + public DocumentTabModelSelector(ActivityDelegate activityDelegate, TabDelegate tabDelegate) {
|
| + mActivityDelegate = activityDelegate;
|
| + mTabDelegate = tabDelegate;
|
| +
|
| + mRegularTabModel = new DocumentTabModelImpl(
|
| + activityDelegate, tabDelegate, false, sPrioritizedTabId);
|
| + mIncognitoTabModel = new OffTheRecordDocumentTabModel(new OffTheRecordTabModelDelegate() {
|
| + @Override
|
| + public TabModel createTabModel() {
|
| + DocumentTabModel incognitoModel = new DocumentTabModelImpl(
|
| + mActivityDelegate, mTabDelegate, true, sPrioritizedTabId);
|
| + if (mRegularTabModel.isNativeInitialized()) {
|
| + incognitoModel.initializeNative();
|
| + }
|
| + return incognitoModel;
|
| + }
|
| +
|
| + @Override
|
| + public int getOffTheRecordTabCount() {
|
| + // TODO(dfalcantara): Devices in document mode do not trigger the TabWindowManager.
|
| + // Revisit this when we have a Samsung L multi-instance device.
|
| + return mIncognitoTabModel.getCount();
|
| + }
|
| + }, mActivityDelegate);
|
| + initializeTabIdCounter();
|
| +
|
| + // Re-select the previously selected TabModel.
|
| + Context context = ApplicationStatus.getApplicationContext();
|
| + SharedPreferences prefs = context.getSharedPreferences(PREF_PACKAGE, Context.MODE_PRIVATE);
|
| + boolean startIncognito = prefs.getBoolean(PREF_IS_INCOGNITO_SELECTED, false);
|
| + initialize(startIncognito, mRegularTabModel, mIncognitoTabModel);
|
| +
|
| + ApplicationStatus.registerStateListenerForAllActivities(this);
|
| + }
|
| +
|
| + private void initializeTabIdCounter() {
|
| + int biggestId = getLargestTaskIdFromRecents();
|
| + biggestId = getMaxTabId(mRegularTabModel, biggestId);
|
| + biggestId = getMaxTabId(mIncognitoTabModel, biggestId);
|
| + Tab.incrementIdCounterTo(biggestId + 1);
|
| + }
|
| +
|
| + private int getMaxTabId(DocumentTabModel tabModel, int min) {
|
| + int biggestId = min;
|
| + int numTabs = tabModel.getCount();
|
| + for (int tabIndex = 0; tabIndex < numTabs; tabIndex++) {
|
| + biggestId = Math.max(biggestId, tabModel.getTabAt(tabIndex).getId());
|
| + }
|
| + return biggestId;
|
| + }
|
| +
|
| + private int getLargestTaskIdFromRecents() {
|
| + int biggestId = Tab.INVALID_TAB_ID;
|
| + Context context = ApplicationStatus.getApplicationContext();
|
| + ActivityManager activityManager =
|
| + (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
|
| + for (ActivityManager.AppTask task : activityManager.getAppTasks()) {
|
| + RecentTaskInfo info = DocumentUtils.getTaskInfoFromTask(task);
|
| + if (info == null) continue;
|
| + biggestId = Math.max(biggestId, info.persistentId);
|
| + }
|
| + return biggestId;
|
| + }
|
| +
|
| + @Override
|
| + public void onActivityStateChange(Activity activity, int newState) {
|
| + if (!mActivityDelegate.isDocumentActivity(activity)) return;
|
| +
|
| + // Tabs swiped away when their Activity is dead don't trigger destruction notifications.
|
| + if (newState == ActivityState.STARTED || newState == ActivityState.DESTROYED) {
|
| + mRegularTabModel.updateRecentlyClosed();
|
| + mIncognitoTabModel.updateRecentlyClosed();
|
| + }
|
| + }
|
| +
|
| + @Override
|
| + public Tab openNewTab(LoadUrlParams loadUrlParams, TabLaunchType type, Tab parent,
|
| + boolean incognito) {
|
| + PendingDocumentData params = null;
|
| + if (loadUrlParams.getPostData() != null
|
| + || loadUrlParams.getVerbatimHeaders() != null
|
| + || loadUrlParams.getReferrer() != null) {
|
| + params = new PendingDocumentData();
|
| + params.postData = loadUrlParams.getPostData();
|
| + params.extraHeaders = loadUrlParams.getVerbatimHeaders();
|
| + params.referrer = loadUrlParams.getReferrer();
|
| + }
|
| +
|
| + Activity parentActivity =
|
| + parent == null ? null : parent.getWindowAndroid().getActivity().get();
|
| + mTabDelegate.createTabInForeground(parentActivity, incognito, loadUrlParams, params);
|
| + return null;
|
| + }
|
| +
|
| + @Override
|
| + public void selectModel(boolean incognito) {
|
| + super.selectModel(incognito);
|
| +
|
| + Context context = ApplicationStatus.getApplicationContext();
|
| + SharedPreferences prefs = context.getSharedPreferences(PREF_PACKAGE, Context.MODE_PRIVATE);
|
| + SharedPreferences.Editor editor = prefs.edit();
|
| + editor.putBoolean(PREF_IS_INCOGNITO_SELECTED, incognito);
|
| + editor.apply();
|
| + }
|
| +
|
| + @Override
|
| + public DocumentTabModel getModel(boolean incognito) {
|
| + return (DocumentTabModel) super.getModel(incognito);
|
| + }
|
| +
|
| + @Override
|
| + public DocumentTabModel getModelForTabId(int id) {
|
| + return (DocumentTabModel) super.getModelForTabId(id);
|
| + }
|
| +
|
| + /**
|
| + * Alerts the TabModels that the native library is ready.
|
| + */
|
| + public void onNativeLibraryReady() {
|
| + mRegularTabModel.initializeNative();
|
| + mIncognitoTabModel.initializeNative();
|
| + }
|
| +
|
| + /**
|
| + * Generates an ID for a new Tab. Makes sure the DocumentTabModels are loaded beforehand to
|
| + * ensure that the ID counter is properly initialized.
|
| + * @return ID to use for the new Tab.
|
| + */
|
| + public int generateValidTabId() {
|
| + return Tab.generateValidId(Tab.INVALID_TAB_ID);
|
| + }
|
| +
|
| + /**
|
| + * Stores PendingUrlParams to be used when the tab with the given ID is launched via intent.
|
| + * @param tabId The ID of the tab that will be launched via intent.
|
| + * @param params The PendingUrlParams to use when loading the URL in the tab.
|
| + */
|
| + public void addPendingDocumentData(int tabId, PendingDocumentData params) {
|
| + ThreadUtils.assertOnUiThread();
|
| + mPendingDocumentData.put(tabId, params);
|
| + }
|
| +
|
| + /**
|
| + * @return Retrieves and removes PendingDocumentData for a particular tab id.
|
| + */
|
| + public PendingDocumentData removePendingDocumentData(int tabId) {
|
| + ThreadUtils.assertOnUiThread();
|
| + PendingDocumentData data = mPendingDocumentData.get(tabId);
|
| + mPendingDocumentData.remove(tabId);
|
| + return data;
|
| + }
|
| +
|
| + /**
|
| + * Creates a data string which stores the base information we need to relaunch a task: a unique
|
| + * identifier and the URL to load.
|
| + * @param id ID of the tab in the DocumentActivity.
|
| + * @param initialUrl URL to load in the DocumentActivity.
|
| + * @return a Uri that has the identifier and the URL mashed together.
|
| + */
|
| + public static Uri createDocumentDataString(int id, String initialUrl) {
|
| + return new Uri.Builder().scheme(UrlConstants.DOCUMENT_SCHEME).authority(String.valueOf(id))
|
| + .query(initialUrl).build();
|
| + }
|
| +}
|
|
|