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

Unified Diff: chrome/android/java_staging/src/org/chromium/chrome/browser/tabmodel/TabModelSelectorImpl.java

Issue 1141283003: Upstream oodles of Chrome for Android code into Chromium. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: final patch? Created 5 years, 7 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_staging/src/org/chromium/chrome/browser/tabmodel/TabModelSelectorImpl.java
diff --git a/chrome/android/java_staging/src/org/chromium/chrome/browser/tabmodel/TabModelSelectorImpl.java b/chrome/android/java_staging/src/org/chromium/chrome/browser/tabmodel/TabModelSelectorImpl.java
new file mode 100644
index 0000000000000000000000000000000000000000..4a24a4daf66ccb219963ba63296a48a9c056bdd9
--- /dev/null
+++ b/chrome/android/java_staging/src/org/chromium/chrome/browser/tabmodel/TabModelSelectorImpl.java
@@ -0,0 +1,431 @@
+// 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.tabmodel;
+
+import android.content.Context;
+import android.os.Handler;
+
+import org.chromium.base.metrics.RecordHistogram;
+import org.chromium.chrome.browser.ChromeActivity;
+import org.chromium.chrome.browser.Tab;
+import org.chromium.chrome.browser.compositor.layouts.OverviewModeBehavior;
+import org.chromium.chrome.browser.compositor.layouts.content.TabContentManager;
+import org.chromium.chrome.browser.ntp.NativePageFactory;
+import org.chromium.chrome.browser.tabmodel.OffTheRecordTabModel.OffTheRecordTabModelDelegate;
+import org.chromium.chrome.browser.tabmodel.TabModel.TabLaunchType;
+import org.chromium.chrome.browser.tabmodel.TabModel.TabSelectionType;
+import org.chromium.chrome.browser.tabmodel.TabPersistentStore.TabPersistentStoreObserver;
+import org.chromium.content_public.browser.LoadUrlParams;
+import org.chromium.ui.base.WindowAndroid;
+
+import java.util.concurrent.atomic.AtomicBoolean;
+
+/**
+ * This class manages all the ContentViews in the app. As it manipulates views, it must be
+ * instantiated and used in the UI Thread. It acts as a TabModel which delegates all
+ * TabModel methods to the active model that it contains.
+ */
+public class TabModelSelectorImpl extends TabModelSelectorBase implements TabModelDelegate {
+
+ private final ChromeActivity mActivity;
+
+ /** Flag set to false when the asynchronous loading of tabs is finished. */
+ private final AtomicBoolean mSessionRestoreInProgress =
+ new AtomicBoolean(true);
+ private final TabPersistentStore mTabSaver;
+
+ // This flag signifies the object has gotten an onNativeReady callback and
+ // has not been destroyed.
+ private boolean mActiveState = false;
+
+ private final TabModelOrderController mOrderController;
+
+ private OverviewModeBehavior mOverviewModeBehavior;
+
+ private TabContentManager mTabContentManager;
+
+ private Tab mVisibleTab;
+
+ private final TabModelSelectorUma mUma;
+
+ private CloseAllTabsDelegate mCloseAllTabsDelegate;
+
+ private static class TabModelImplCreator implements OffTheRecordTabModelDelegate {
+ private final ChromeActivity mActivity;
+ private final TabModelSelectorUma mUma;
+ private final TabModelOrderController mOrderController;
+ private final TabContentManager mTabContentManager;
+ private final TabPersistentStore mTabSaver;
+ private final TabModelDelegate mModelDelegate;
+
+ /**
+ * Constructor for an Incognito TabModelImpl.
+ *
+ * @param activity The activity owning this TabModel.
+ * @param uma Handles UMA tracking for the model.
+ * @param orderController Determines the order for inserting new Tabs.
+ * @param tabContentManager Manages the display content of the tab.
+ * @param tabSaver Handler for saving tabs.
+ * @param modelDelegate Delegate to handle external dependencies and interactions.
+ */
+ public TabModelImplCreator(ChromeActivity activity, TabModelSelectorUma uma,
+ TabModelOrderController orderController, TabContentManager tabContentManager,
+ TabPersistentStore tabSaver, TabModelDelegate modelDelegate) {
+ mActivity = activity;
+ mUma = uma;
+ mOrderController = orderController;
+ mTabContentManager = tabContentManager;
+ mTabSaver = tabSaver;
+ mModelDelegate = modelDelegate;
+ }
+
+ @Override
+ public TabModel createTabModel() {
+ return new TabModelImpl(true, mActivity, mUma, mOrderController,
+ mTabContentManager, mTabSaver, mModelDelegate);
+ }
+
+ @Override
+ public boolean doOffTheRecordTabsExist() {
+ return TabWindowManager.getInstance().getIncognitoTabCount() > 0;
+ }
+ }
+
+ /**
+ * Builds a {@link TabModelSelectorImpl} instance.
+ * @param activity The {@link ChromeActivity} this model selector lives in.
+ * @param selectorIndex The index this selector represents in the list of selectors.
+ * @param windowAndroid The {@link WindowAndroid} associated with this model selector.
+ */
+ public TabModelSelectorImpl(ChromeActivity activity, int selectorIndex,
+ WindowAndroid windowAndroid) {
+ super();
+ mActivity = activity;
+ mUma = new TabModelSelectorUma(mActivity);
+ final TabPersistentStoreObserver persistentStoreObserver =
+ new TabPersistentStoreObserver() {
+ @Override
+ public void onStateLoaded(Context context) {
+ markTabStateInitialized();
+ }
+
+ @Override
+ public void onInitialized(int tabCountAtStartup) {
+ RecordHistogram.recordCountHistogram("Tabs.CountAtStartup", tabCountAtStartup);
+ }
+ };
+ mTabSaver = new TabPersistentStore(this, selectorIndex, mActivity, mActivity,
+ persistentStoreObserver);
+ mOrderController = new TabModelOrderController(this);
+ ChromeTabCreator regularTabCreator = new ChromeTabCreator(mActivity, windowAndroid,
+ mOrderController, mTabSaver, false);
+ ChromeTabCreator incognitoTabCreator = new ChromeTabCreator(mActivity, windowAndroid,
+ mOrderController, mTabSaver, true);
+ mActivity.setTabCreators(regularTabCreator, incognitoTabCreator);
+ }
+
+ @Override
+ protected void markTabStateInitialized() {
+ super.markTabStateInitialized();
+ if (!mSessionRestoreInProgress.getAndSet(false)) return;
+
+ // This is the first time we set
+ // |mSessionRestoreInProgress|, so we need to broadcast.
+ TabModelImpl model = (TabModelImpl) getModel(false);
+
+ if (model != null) {
+ model.broadcastSessionRestoreComplete();
+ } else {
+ assert false : "Normal tab model is null after tab state loaded.";
+ }
+ }
+
+ private void handleOnPageLoadStopped(Tab tab) {
+ if (tab != null) mTabSaver.addTabToSaveQueue(tab);
+ }
+
+ /**
+ *
+ * @param overviewModeBehavior The {@link OverviewModeBehavior} that should be used to determine
+ * when the app is in overview mode or not.
+ */
+ public void setOverviewModeBehavior(OverviewModeBehavior overviewModeBehavior) {
+ assert overviewModeBehavior != null;
+ mOverviewModeBehavior = overviewModeBehavior;
+ }
+
+ /**
+ * Should be called when the app starts showing a view with multiple tabs.
+ */
+ public void onTabsViewShown() {
+ mUma.onTabsViewShown();
+ }
+
+ /**
+ * Should be called once the native library is loaded so that the actual internals of this
+ * class can be initialized.
+ * @param tabContentProvider A {@link TabContentManager} instance.
+ */
+ public void onNativeLibraryReady(TabContentManager tabContentProvider) {
+ assert !mActiveState : "onNativeLibraryReady called twice!";
+ mTabContentManager = tabContentProvider;
+
+ TabModel normalModel = new TabModelImpl(false, mActivity, mUma, mOrderController,
+ mTabContentManager, mTabSaver, this);
+ TabModel incognitoModel = new OffTheRecordTabModel(new TabModelImplCreator(
+ mActivity, mUma, mOrderController, mTabContentManager, mTabSaver, this));
+ initialize(isIncognitoSelected(), normalModel, incognitoModel);
+ mActivity.getTabCreator(false).setTabModel(normalModel, mTabContentManager);
+ mActivity.getTabCreator(true).setTabModel(incognitoModel, mTabContentManager);
+
+ mTabSaver.setTabContentManager(tabContentProvider);
+
+ addObserver(new EmptyTabModelSelectorObserver() {
+ @Override
+ public void onNewTabCreated(Tab tab) {
+ // Only invalidate if the tab exists in the currently selected model.
+ if (TabModelUtils.getTabById(getCurrentModel(), tab.getId()) != null) {
+ mTabContentManager.invalidateIfChanged(tab.getId(), tab.getUrl());
+ }
+ }
+ });
+
+ mActiveState = true;
+
+ new TabModelSelectorTabObserver(this) {
+ @Override
+ public void onUrlUpdated(Tab tab) {
+ TabModel model = getModelForTabId(tab.getId());
+ if (model == getCurrentModel()) {
+ mTabContentManager.invalidateIfChanged(tab.getId(), tab.getUrl());
+ }
+ }
+
+ @Override
+ public void onLoadStopped(Tab tab) {
+ handleOnPageLoadStopped(tab);
+ }
+
+ @Override
+ public void onPageLoadStarted(Tab tab) {
+ String url = tab.getUrl();
+ if (NativePageFactory.isNativePageUrl(url, tab.isIncognito())) {
+ mTabContentManager.invalidateTabThumbnail(tab.getId(), url);
+ } else {
+ mTabContentManager.removeTabThumbnail(tab.getId());
+ }
+ }
+
+ @Override
+ public void onPageLoadFinished(Tab tab) {
+ mUma.onPageLoadFinished(tab.getId());
+ }
+
+ @Override
+ public void onPageLoadFailed(Tab tab, int errorCode) {
+ mUma.onPageLoadFailed(tab.getId());
+ }
+
+ @Override
+ public void onCrash(Tab tab, boolean sadTabShown) {
+ if (sadTabShown) {
+ mTabContentManager.removeTabThumbnail(tab.getId());
+ }
+ mUma.onTabCrashed(tab.getId());
+ }
+ };
+ }
+
+ @Override
+ public void setCloseAllTabsDelegate(CloseAllTabsDelegate delegate) {
+ mCloseAllTabsDelegate = delegate;
+ }
+
+ @Override
+ public TabModel getModelAt(int index) {
+ return mActiveState ? super.getModelAt(index) : EmptyTabModel.getInstance();
+ }
+
+ @Override
+ public void selectModel(boolean incognito) {
+ TabModel oldModel = getCurrentModel();
+ super.selectModel(incognito);
+ TabModel newModel = getCurrentModel();
+ if (oldModel != newModel) {
+ TabModelUtils.setIndex(newModel, newModel.index());
+
+ // Make the call to notifyDataSetChanged() after any delayed events
+ // have had a chance to fire. Otherwise, this may result in some
+ // drawing to occur before animations have a chance to work.
+ new Handler().post(new Runnable() {
+ @Override
+ public void run() {
+ notifyChanged();
+ }
+ });
+ }
+ }
+
+ /**
+ * Commits all pending tab closures for all {@link TabModel}s in this {@link TabModelSelector}.
+ */
+ @Override
+ public void commitAllTabClosures() {
+ for (int i = 0; i < getModels().size(); i++) {
+ getModelAt(i).commitAllTabClosures();
+ }
+ }
+
+ @Override
+ public boolean closeAllTabsRequest(boolean incognito) {
+ return mCloseAllTabsDelegate.closeAllTabsRequest(incognito);
+ }
+
+ public void saveState() {
+ commitAllTabClosures();
+ mTabSaver.saveState();
+ }
+
+ /**
+ * Load the saved tab state. This should be called before any new tabs are created. The saved
+ * tabs shall not be restored until {@link #restoreTabs} is called.
+ */
+ public void loadState() {
+ int nextId = mTabSaver.loadState();
+ if (nextId >= 0) Tab.incrementIdCounterTo(nextId);
+ }
+
+ /**
+ * Restore the saved tabs which were loaded by {@link #loadState}.
+ *
+ * @param setActiveTab If true, synchronously load saved active tab and set it as the current
+ * active tab.
+ */
+ public void restoreTabs(boolean setActiveTab) {
+ mTabSaver.restoreTabs(setActiveTab);
+ }
+
+ /**
+ * If there is an asynchronous session restore in-progress, try to synchronously restore
+ * the state of a tab with the given url as a frozen tab. This method has no effect if
+ * there isn't a tab being restored with this url, or the tab has already been restored.
+ *
+ * @return true if there exists a tab with the url.
+ */
+ public boolean tryToRestoreTabStateForUrl(String url) {
+ if (!isSessionRestoreInProgress()) return false;
+ return mTabSaver.restoreTabStateForUrl(url);
+ }
+
+ /**
+ * If there is an asynchronous session restore in-progress, try to synchronously restore
+ * the state of a tab with the given id as a frozen tab. This method has no effect if
+ * there isn't a tab being restored with this id, or the tab has already been restored.
+ *
+ * @return true if there exists a tab with the id.
+ */
+ public boolean tryToRestoreTabStateForId(int id) {
+ if (!isSessionRestoreInProgress()) return false;
+ return mTabSaver.restoreTabStateForId(id);
+ }
+
+ public void clearState() {
+ mTabSaver.clearState();
+ }
+
+ public void clearEncryptedState() {
+ mTabSaver.clearEncryptedState();
+ }
+
+ @Override
+ public void destroy() {
+ mTabSaver.destroy();
+ mUma.destroy();
+ super.destroy();
+ mActiveState = false;
+ }
+
+ @Override
+ public Tab openNewTab(LoadUrlParams loadUrlParams, TabLaunchType type, Tab parent,
+ boolean incognito) {
+ return mActivity.getTabCreator(incognito).createNewTab(loadUrlParams, type, parent);
+ }
+
+ /**
+ * @return Number of restored tabs on cold startup.
+ */
+ public int getRestoredTabCount() {
+ return mTabSaver.getRestoredTabCount();
+ }
+
+ @Override
+ public void requestToShowTab(Tab tab, TabSelectionType type) {
+ boolean isFromExternalApp = tab != null
+ && tab.getLaunchType() == TabLaunchType.FROM_EXTERNAL_APP;
+
+ if (mVisibleTab != tab && tab != null && !tab.isNativePage()) {
+ TabModelBase.startTabSwitchLatencyTiming(type);
+ }
+ if (mVisibleTab != null && mVisibleTab != tab && !mVisibleTab.needsReload()) {
+ // TODO(dtrainor): Once we figure out why we can't grab a snapshot from the current
+ // tab when we have other tabs loading from external apps remove the checks for
+ // FROM_EXTERNAL_APP/FROM_NEW.
+ if (!mVisibleTab.isClosing()
+ && (!isFromExternalApp || type != TabSelectionType.FROM_NEW)) {
+ cacheTabBitmap(mVisibleTab);
+ }
+ mVisibleTab.hide();
+ mVisibleTab.setFullscreenManager(null);
+ mTabSaver.addTabToSaveQueue(mVisibleTab);
+ mVisibleTab = null;
+ }
+
+ if (tab == null) {
+ notifyChanged();
+ return;
+ }
+
+ // We hit this case when the user enters tab switcher and comes back to the current tab
+ // without actual tab switch.
+ if (mVisibleTab == tab && !mVisibleTab.isHidden()) {
+ // The current tab might have been killed by the os while in tab switcher.
+ tab.loadIfNeeded();
+ return;
+ }
+
+ tab.setFullscreenManager(mActivity.getFullscreenManager());
+ mVisibleTab = tab;
+
+ // Don't execute the tab display part if Chrome has just been sent to background. This
+ // avoids uneccessary work (tab restore) and prevents pollution of tab display metrics - see
+ // http://crbug.com/316166.
+ if (type != TabSelectionType.FROM_EXIT) {
+ tab.show(type);
+ mUma.onShowTab(tab.getId(), tab.isBeingRestored());
+ }
+ }
+
+ private void cacheTabBitmap(Tab tabToCache) {
+ // Trigger a capture of this tab.
+ if (tabToCache == null) return;
+ mTabContentManager.cacheTabThumbnail(tabToCache);
+ }
+
+ @Override
+ public boolean isInOverviewMode() {
+ return mOverviewModeBehavior != null && mOverviewModeBehavior.overviewVisible();
+ }
+
+ @Override
+ public boolean isSessionRestoreInProgress() {
+ return mSessionRestoreInProgress.get();
+ }
+
+ // TODO(tedchoc): Remove the need for this to be exposed.
+ @Override
+ public void notifyChanged() {
+ super.notifyChanged();
+ }
+}

Powered by Google App Engine
This is Rietveld 408576698