| Index: chrome/android/java/src/org/chromium/chrome/browser/tabmodel/TabModelBase.java
|
| diff --git a/chrome/android/java/src/org/chromium/chrome/browser/tabmodel/TabModelBase.java b/chrome/android/java/src/org/chromium/chrome/browser/tabmodel/TabModelBase.java
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..0e2b0a263e87921c077a72207b8c656c6d1035c3
|
| --- /dev/null
|
| +++ b/chrome/android/java/src/org/chromium/chrome/browser/tabmodel/TabModelBase.java
|
| @@ -0,0 +1,638 @@
|
| +// 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;
|
| +
|
| +import org.chromium.base.CalledByNative;
|
| +import org.chromium.base.ObserverList;
|
| +import org.chromium.base.TraceEvent;
|
| +import org.chromium.chrome.browser.Tab;
|
| +import org.chromium.chrome.browser.profiles.Profile;
|
| +import org.chromium.chrome.browser.util.MathUtils;
|
| +
|
| +import java.util.ArrayList;
|
| +import java.util.List;
|
| +
|
| +/**
|
| + * This is the default implementation of the {@link TabModel} interface.
|
| + */
|
| +public abstract class TabModelBase implements TabModel {
|
| + private static final String TAG = "TabModelBase";
|
| +
|
| + /**
|
| + * The main list of tabs. Note that when this changes, all pending closures must be committed
|
| + * via {@link #commitAllTabClosures()} as the indices are no longer valid. Also
|
| + * {@link RewoundList#resetRewoundState()} must be called so that the full model will be up to
|
| + * date.
|
| + */
|
| + private final List<Tab> mTabs = new ArrayList<Tab>();
|
| +
|
| + private final boolean mIsIncognito;
|
| +
|
| + private final TabModelOrderController mOrderController;
|
| +
|
| + protected final TabModelDelegate mModelDelegate;
|
| +
|
| + private final ObserverList<TabModelObserver> mObservers;
|
| +
|
| + // Undo State Tracking -------------------------------------------------------------------------
|
| +
|
| + /**
|
| + * A {@link TabList} that represents the complete list of {@link Tab}s. This is so that
|
| + * certain UI elements can call {@link TabModel#getComprehensiveModel()} to get a full list of
|
| + * {@link Tab}s that includes rewindable entries, as the typical {@link TabModel} does not
|
| + * return rewindable entries.
|
| + */
|
| + private final RewoundList mRewoundList = new RewoundList();
|
| +
|
| + /**
|
| + * This specifies the current {@link Tab} in {@link #mTabs}.
|
| + */
|
| + private int mIndex = INVALID_TAB_INDEX;
|
| +
|
| + /** Native Tab pointer which will be set by nativeInit(). */
|
| + private long mNativeTabModelImpl = 0;
|
| +
|
| + public TabModelBase(boolean incognito, TabModelOrderController orderController,
|
| + TabModelDelegate modelDelegate) {
|
| + mIsIncognito = incognito;
|
| + mNativeTabModelImpl = nativeInit(incognito);
|
| + mOrderController = orderController;
|
| + mModelDelegate = modelDelegate;
|
| + mObservers = new ObserverList<TabModelObserver>();
|
| + }
|
| +
|
| + @Override
|
| + public Profile getProfile() {
|
| + return nativeGetProfileAndroid(mNativeTabModelImpl);
|
| + }
|
| +
|
| + @Override
|
| + public boolean isIncognito() {
|
| + return mIsIncognito;
|
| + }
|
| +
|
| + @Override
|
| + public void destroy() {
|
| + for (Tab tab : mTabs) {
|
| + if (tab.isInitialized()) tab.destroy();
|
| + }
|
| +
|
| + mRewoundList.destroy();
|
| +
|
| + if (mNativeTabModelImpl != 0) {
|
| + nativeDestroy(mNativeTabModelImpl);
|
| + mNativeTabModelImpl = 0;
|
| + }
|
| + }
|
| +
|
| + @Override
|
| + public void addObserver(TabModelObserver observer) {
|
| + mObservers.addObserver(observer);
|
| + }
|
| +
|
| + @Override
|
| + public void removeObserver(TabModelObserver observer) {
|
| + mObservers.removeObserver(observer);
|
| + }
|
| +
|
| + /**
|
| + * Initializes the newly created tab, adds it to controller, and dispatches creation
|
| + * step notifications.
|
| + */
|
| + @Override
|
| + public void addTab(Tab tab, int index, TabLaunchType type) {
|
| + TraceEvent.begin();
|
| +
|
| + for (TabModelObserver obs : mObservers) obs.willAddTab(tab, type);
|
| +
|
| + boolean selectTab = mOrderController.willOpenInForeground(type, mIsIncognito);
|
| +
|
| + index = mOrderController.determineInsertionIndex(type, index, tab);
|
| + assert index <= mTabs.size();
|
| +
|
| + assert tab.isIncognito() == mIsIncognito;
|
| +
|
| + // TODO(dtrainor): Update the list of undoable tabs instead of committing it.
|
| + commitAllTabClosures();
|
| +
|
| + if (index < 0 || index > mTabs.size()) {
|
| + mTabs.add(tab);
|
| + } else {
|
| + mTabs.add(index, tab);
|
| + if (index <= mIndex) {
|
| + mIndex++;
|
| + }
|
| + }
|
| +
|
| + if (!isCurrentModel()) {
|
| + // When adding new tabs in the background, make sure we set a valid index when the
|
| + // first one is added. When in the foreground, calls to setIndex will take care of
|
| + // this.
|
| + mIndex = Math.max(mIndex, 0);
|
| + }
|
| +
|
| + mRewoundList.resetRewoundState();
|
| +
|
| + int newIndex = indexOf(tab);
|
| + mModelDelegate.didChange();
|
| + mModelDelegate.didCreateNewTab(tab);
|
| +
|
| + if (mNativeTabModelImpl != 0) nativeTabAddedToModel(mNativeTabModelImpl, tab);
|
| +
|
| + for (TabModelObserver obs : mObservers) obs.didAddTab(tab, type);
|
| +
|
| + if (selectTab) {
|
| + mModelDelegate.selectModel(mIsIncognito);
|
| + setIndex(newIndex, TabModel.TabSelectionType.FROM_NEW);
|
| + }
|
| +
|
| + TraceEvent.end();
|
| + }
|
| +
|
| + @Override
|
| + public void moveTab(int id, int newIndex) {
|
| + newIndex = MathUtils.clamp(newIndex, 0, mTabs.size());
|
| +
|
| + int curIndex = TabModelUtils.getTabIndexById(this, id);
|
| +
|
| + if (curIndex == INVALID_TAB_INDEX || curIndex == newIndex || curIndex + 1 == newIndex) {
|
| + return;
|
| + }
|
| +
|
| + // TODO(dtrainor): Update the list of undoable tabs instead of committing it.
|
| + commitAllTabClosures();
|
| +
|
| + Tab tab = mTabs.remove(curIndex);
|
| + if (curIndex < newIndex) --newIndex;
|
| +
|
| + mTabs.add(newIndex, tab);
|
| +
|
| + if (curIndex == mIndex) {
|
| + mIndex = newIndex;
|
| + } else if (curIndex < mIndex && newIndex >= mIndex) {
|
| + --mIndex;
|
| + } else if (curIndex > mIndex && newIndex <= mIndex) {
|
| + ++mIndex;
|
| + }
|
| +
|
| + mRewoundList.resetRewoundState();
|
| +
|
| + mModelDelegate.didChange();
|
| + for (TabModelObserver obs : mObservers) obs.didMoveTab(tab, newIndex, curIndex);
|
| + }
|
| +
|
| + @Override
|
| + @CalledByNative
|
| + public boolean closeTab(Tab tab) {
|
| + return closeTab(tab, true, false, false);
|
| + }
|
| +
|
| + private Tab findTabInAllTabModels(int tabId) {
|
| + Tab tab = TabModelUtils.getTabById(mModelDelegate.getModel(mIsIncognito), tabId);
|
| + if (tab != null) return tab;
|
| + return TabModelUtils.getTabById(mModelDelegate.getModel(!mIsIncognito), tabId);
|
| + }
|
| +
|
| + @Override
|
| + public Tab getNextTabIfClosed(int id) {
|
| + Tab tabToClose = TabModelUtils.getTabById(this, id);
|
| + Tab currentTab = TabModelUtils.getCurrentTab(this);
|
| + if (tabToClose == null) return currentTab;
|
| +
|
| + int closingTabIndex = indexOf(tabToClose);
|
| + Tab adjacentTab = getTabAt((closingTabIndex == 0) ? 1 : closingTabIndex - 1);
|
| + Tab parentTab = findTabInAllTabModels(tabToClose.getParentId());
|
| +
|
| + // Determine which tab to select next according to these rules:
|
| + // * If closing a background tab, keep the current tab selected.
|
| + // * Otherwise, if not in overview mode, select the parent tab if it exists.
|
| + // * Otherwise, select an adjacent tab if one exists.
|
| + // * Otherwise, if closing the last incognito tab, select the current normal tab.
|
| + // * Otherwise, select nothing.
|
| + Tab nextTab = null;
|
| + if (tabToClose != currentTab && currentTab != null) {
|
| + nextTab = currentTab;
|
| + } else if (parentTab != null && !mModelDelegate.isInOverviewMode()) {
|
| + nextTab = parentTab;
|
| + } else if (adjacentTab != null) {
|
| + nextTab = adjacentTab;
|
| + } else if (mIsIncognito) {
|
| + nextTab = TabModelUtils.getCurrentTab(mModelDelegate.getModel(false));
|
| + }
|
| +
|
| + return nextTab;
|
| + }
|
| +
|
| + @Override
|
| + public boolean isClosurePending(int tabId) {
|
| + return mRewoundList.getPendingRewindTab(tabId) != null;
|
| + }
|
| +
|
| + @Override
|
| + public boolean supportsPendingClosures() {
|
| + return !mIsIncognito;
|
| + }
|
| +
|
| + @Override
|
| + public TabList getComprehensiveModel() {
|
| + if (!supportsPendingClosures()) return this;
|
| + return mRewoundList;
|
| + }
|
| +
|
| + @Override
|
| + public void cancelTabClosure(int tabId) {
|
| + Tab tab = mRewoundList.getPendingRewindTab(tabId);
|
| + if (tab == null) return;
|
| +
|
| + tab.setClosing(false);
|
| +
|
| + // Find a valid previous tab entry so we know what tab to insert after. With the following
|
| + // example, calling cancelTabClosure(4) would need to know to insert after 2. So we have to
|
| + // track across mRewoundTabs and mTabs and see what the last valid mTabs entry was (2) when
|
| + // we hit the 4 in the rewound list. An insertIndex of -1 represents the beginning of the
|
| + // list, as this is the index of tab to insert after.
|
| + // mTabs: 0 2 5
|
| + // mRewoundTabs 0 1 2 3 4 5
|
| + int prevIndex = -1;
|
| + final int stopIndex = mRewoundList.indexOf(tab);
|
| + for (int rewoundIndex = 0; rewoundIndex < stopIndex; rewoundIndex++) {
|
| + Tab rewoundTab = mRewoundList.getTabAt(rewoundIndex);
|
| + if (prevIndex == mTabs.size() - 1) break;
|
| + if (rewoundTab == mTabs.get(prevIndex + 1)) prevIndex++;
|
| + }
|
| +
|
| + // Figure out where to insert the tab. Just add one to prevIndex, as -1 represents the
|
| + // beginning of the list, so we'll insert at 0.
|
| + int insertIndex = prevIndex + 1;
|
| + if (mIndex >= insertIndex) mIndex++;
|
| + mTabs.add(insertIndex, tab);
|
| +
|
| + boolean activeModel = mModelDelegate.getCurrentModel() == this;
|
| +
|
| + // If we're the active model call setIndex to actually select this tab, otherwise just set
|
| + // mIndex but don't kick off everything that happens when calling setIndex().
|
| + if (activeModel) {
|
| + setIndex(insertIndex);
|
| + } else {
|
| + mIndex = insertIndex;
|
| + }
|
| +
|
| + for (TabModelObserver obs : mObservers) obs.tabClosureUndone(tab);
|
| + }
|
| +
|
| + @Override
|
| + public void commitTabClosure(int tabId) {
|
| + Tab tab = mRewoundList.getPendingRewindTab(tabId);
|
| + if (tab == null) return;
|
| +
|
| + // We're committing the close, actually remove it from the lists and finalize the closing
|
| + // operation.
|
| + mRewoundList.removeTab(tab);
|
| + finalizeTabClosure(tab);
|
| + for (TabModelObserver obs : mObservers) obs.tabClosureCommitted(tab);
|
| + }
|
| +
|
| + @Override
|
| + public void commitAllTabClosures() {
|
| + while (mRewoundList.getCount() > mTabs.size()) {
|
| + commitTabClosure(mRewoundList.getNextRewindableTab().getId());
|
| + }
|
| +
|
| + assert !mRewoundList.hasPendingClosures();
|
| + }
|
| +
|
| + @Override
|
| + public boolean closeTab(Tab tabToClose, boolean animate, boolean uponExit, boolean canUndo) {
|
| + if (tabToClose == null) {
|
| + assert false : "Tab is null!";
|
| + return false;
|
| + }
|
| +
|
| + if (!mTabs.contains(tabToClose)) {
|
| + assert false : "Tried to close a tab from another model!";
|
| + return false;
|
| + }
|
| +
|
| + canUndo &= supportsPendingClosures();
|
| +
|
| + if (canUndo) {
|
| + for (TabModelObserver obs : mObservers) obs.tabPendingClosure(tabToClose);
|
| + }
|
| + startTabClosure(tabToClose, animate, uponExit, canUndo);
|
| + if (!canUndo) finalizeTabClosure(tabToClose);
|
| +
|
| + return true;
|
| + }
|
| +
|
| + @Override
|
| + public void closeAllTabs() {
|
| + commitAllTabClosures();
|
| +
|
| + while (getCount() > 0) {
|
| + TabModelUtils.closeTabByIndex(this, 0);
|
| + }
|
| + }
|
| +
|
| + @Override
|
| + @CalledByNative
|
| + public Tab getTabAt(int index) {
|
| + // This will catch INVALID_TAB_INDEX and return null
|
| + if (index < 0 || index >= mTabs.size()) return null;
|
| + return mTabs.get(index);
|
| + }
|
| +
|
| + // Index of the given tab in the order of the tab stack.
|
| + @Override
|
| + public int indexOf(Tab tab) {
|
| + return mTabs.indexOf(tab);
|
| + }
|
| +
|
| + /**
|
| + * @return true if this is the current model according to the model selector
|
| + */
|
| + private boolean isCurrentModel() {
|
| + return mModelDelegate.getCurrentModel() == this;
|
| + }
|
| +
|
| + // TODO(aurimas): Move this method to TabModelSelector when notifications move there.
|
| + private int getLastId(TabSelectionType type) {
|
| + if (type == TabSelectionType.FROM_CLOSE) return Tab.INVALID_TAB_ID;
|
| +
|
| + // Get the current tab in the current tab model.
|
| + Tab currentTab = TabModelUtils.getCurrentTab(mModelDelegate.getCurrentModel());
|
| + return currentTab != null ? currentTab.getId() : Tab.INVALID_TAB_ID;
|
| + }
|
| +
|
| + // This function is complex and its behavior depends on persisted state, including mIndex.
|
| + @Override
|
| + public void setIndex(int i, final TabSelectionType type) {
|
| + TraceEvent.begin();
|
| + int lastId = getLastId(type);
|
| +
|
| + if (!isCurrentModel()) {
|
| + mModelDelegate.selectModel(isIncognito());
|
| + }
|
| +
|
| + if (mTabs.size() <= 0) {
|
| + mIndex = INVALID_TAB_INDEX;
|
| + } else {
|
| + mIndex = MathUtils.clamp(i, 0, mTabs.size() - 1);
|
| + }
|
| +
|
| + Tab tab = TabModelUtils.getCurrentTab(this);
|
| +
|
| + mModelDelegate.requestToShowTab(tab, type);
|
| +
|
| + if (tab != null) {
|
| + for (TabModelObserver obs : mObservers) obs.didSelectTab(tab, type, lastId);
|
| + }
|
| +
|
| + // notifyDataSetChanged() can call into
|
| + // ChromeViewHolderTablet.handleTabChangeExternal(), which will eventually move the
|
| + // ContentView onto the current view hierarchy (with addView()).
|
| + mModelDelegate.didChange();
|
| + TraceEvent.end();
|
| + }
|
| +
|
| + /**
|
| + * @param incognito
|
| + * @param nativeWebContents
|
| + * @param parentId
|
| + * @return
|
| + */
|
| + @CalledByNative
|
| + protected abstract Tab createTabWithNativeContents(boolean incognito, long nativeWebContents,
|
| + int parentId);
|
| +
|
| + /**
|
| + * Performs the necessary actions to remove this {@link Tab} from this {@link TabModel}.
|
| + * This does not actually destroy the {@link Tab} (see
|
| + * {@link #finalizeTabClosure(Tab)}.
|
| + *
|
| + * @param tab The {@link Tab} to remove from this {@link TabModel}.
|
| + * @param animate Whether or not to animate the closing.
|
| + * @param uponExit Whether or not this is closing while the Activity is exiting.
|
| + * @param canUndo Whether or not this operation can be undone. Note that if this is {@code true}
|
| + * and {@link #supportsPendingClosures()} is {@code true},
|
| + * {@link #commitTabClosure(int)} or {@link #commitAllTabClosures()} needs to be
|
| + * called to actually delete and clean up {@code tab}.
|
| + */
|
| + private void startTabClosure(Tab tab, boolean animate, boolean uponExit, boolean canUndo) {
|
| + final int closingTabId = tab.getId();
|
| + final int closingTabIndex = indexOf(tab);
|
| +
|
| + tab.setClosing(true);
|
| +
|
| + for (TabModelObserver obs : mObservers) obs.willCloseTab(tab, animate);
|
| +
|
| + Tab currentTab = TabModelUtils.getCurrentTab(this);
|
| + Tab adjacentTab = getTabAt(closingTabIndex == 0 ? 1 : closingTabIndex - 1);
|
| + Tab nextTab = getNextTabIfClosed(closingTabId);
|
| +
|
| + // TODO(dtrainor): Update the list of undoable tabs instead of committing it.
|
| + if (!canUndo) commitAllTabClosures();
|
| + mTabs.remove(tab);
|
| +
|
| + boolean nextIsIncognito = nextTab == null ? false : nextTab.isIncognito();
|
| + int nextTabId = nextTab == null ? Tab.INVALID_TAB_ID : nextTab.getId();
|
| + int nextTabIndex = nextTab == null ? INVALID_TAB_INDEX : TabModelUtils.getTabIndexById(
|
| + mModelDelegate.getModel(nextIsIncognito), nextTabId);
|
| +
|
| + if (nextTab != currentTab) {
|
| + if (nextIsIncognito != isIncognito()) mIndex = indexOf(adjacentTab);
|
| +
|
| + TabModel nextModel = mModelDelegate.getModel(nextIsIncognito);
|
| + nextModel.setIndex(nextTabIndex,
|
| + uponExit ? TabSelectionType.FROM_EXIT : TabSelectionType.FROM_CLOSE);
|
| + } else {
|
| + mIndex = nextTabIndex;
|
| + }
|
| +
|
| + if (!canUndo) mRewoundList.resetRewoundState();
|
| + }
|
| +
|
| + /**
|
| + * Actually closes and cleans up {@code tab}.
|
| + * @param tab The {@link Tab} to close.
|
| + */
|
| + private void finalizeTabClosure(Tab tab) {
|
| + for (TabModelObserver obs : mObservers) obs.didCloseTab(tab);
|
| + tab.destroy();
|
| + }
|
| +
|
| + private class RewoundList implements TabList {
|
| + /**
|
| + * A list of {@link Tab}s that represents the completely rewound list (if all
|
| + * rewindable closes were undone). If there are no possible rewindable closes this list
|
| + * should match {@link #mTabs}.
|
| + */
|
| + private List<Tab> mRewoundTabs = new ArrayList<Tab>();
|
| +
|
| + @Override
|
| + public boolean isIncognito() {
|
| + return TabModelBase.this.isIncognito();
|
| + }
|
| +
|
| + /**
|
| + * If {@link TabModel} has a valid selected tab, this will return that same tab in the
|
| + * context of the rewound list of tabs. If {@link TabModel} has no tabs but the rewound
|
| + * list is not empty, it will return 0, the first tab. Otherwise it will return
|
| + * {@link TabModel#INVALID_TAB_INDEX}.
|
| + * @return The selected index of the rewound list of tabs (includes all pending closures).
|
| + */
|
| + @Override
|
| + public int index() {
|
| + if (TabModelBase.this.index() != INVALID_TAB_INDEX) {
|
| + return mRewoundTabs.indexOf(TabModelUtils.getCurrentTab(TabModelBase.this));
|
| + }
|
| + if (!mRewoundTabs.isEmpty()) return 0;
|
| + return INVALID_TAB_INDEX;
|
| + }
|
| +
|
| + @Override
|
| + public int getCount() {
|
| + return mRewoundTabs.size();
|
| + }
|
| +
|
| + @Override
|
| + public Tab getTabAt(int index) {
|
| + if (index < 0 || index >= mRewoundTabs.size()) return null;
|
| + return mRewoundTabs.get(index);
|
| + }
|
| +
|
| + @Override
|
| + public int indexOf(Tab tab) {
|
| + return mRewoundTabs.indexOf(tab);
|
| + }
|
| +
|
| + @Override
|
| + public boolean isClosurePending(int tabId) {
|
| + return TabModelBase.this.isClosurePending(tabId);
|
| + }
|
| +
|
| + /**
|
| + * Resets this list to match the original {@link TabModel}. Note that if the
|
| + * {@link TabModel} doesn't support pending closures this model will be empty. This should
|
| + * be called whenever {@link #mTabs} changes.
|
| + */
|
| + public void resetRewoundState() {
|
| + mRewoundTabs.clear();
|
| +
|
| + if (TabModelBase.this.supportsPendingClosures()) {
|
| + for (int i = 0; i < TabModelBase.this.getCount(); i++) {
|
| + mRewoundTabs.add(TabModelBase.this.getTabAt(i));
|
| + }
|
| + }
|
| + }
|
| +
|
| + /**
|
| + * Finds the {@link Tab} specified by {@code tabId} and only returns it if it is
|
| + * actually a {@link Tab} that is in the middle of being closed (which means that it
|
| + * is present in this model but not in {@link #mTabs}.
|
| + *
|
| + * @param tabId The id of the {@link Tab} to search for.
|
| + * @return The {@link Tab} specified by {@code tabId} as long as that tab only exists
|
| + * in this model and not in {@link #mTabs}. {@code null} otherwise.
|
| + */
|
| + public Tab getPendingRewindTab(int tabId) {
|
| + if (!TabModelBase.this.supportsPendingClosures()) return null;
|
| + if (TabModelUtils.getTabById(TabModelBase.this, tabId) != null) return null;
|
| + return TabModelUtils.getTabById(this, tabId);
|
| + }
|
| +
|
| + /**
|
| + * A utility method for easily finding a {@link Tab} that can be closed.
|
| + * @return The next tab that is in the middle of being closed.
|
| + */
|
| + public Tab getNextRewindableTab() {
|
| + if (!hasPendingClosures()) return null;
|
| +
|
| + for (int i = 0; i < mRewoundTabs.size(); i++) {
|
| + Tab tab = i < TabModelBase.this.getCount() ? TabModelBase.this.getTabAt(i) : null;
|
| + Tab rewoundTab = mRewoundTabs.get(i);
|
| +
|
| + if (tab == null || rewoundTab.getId() != tab.getId()) return rewoundTab;
|
| + }
|
| +
|
| + return null;
|
| + }
|
| +
|
| + /**
|
| + * Removes a {@link Tab} from this internal list.
|
| + * @param tab The {@link Tab} to remove.
|
| + */
|
| + public void removeTab(Tab tab) {
|
| + mRewoundTabs.remove(tab);
|
| + }
|
| +
|
| + /**
|
| + * Destroy all tabs in this model. This will check to see if the tab is already destroyed
|
| + * before destroying it.
|
| + */
|
| + public void destroy() {
|
| + for (Tab tab : mRewoundTabs) {
|
| + if (tab.isInitialized()) tab.destroy();
|
| + }
|
| + }
|
| +
|
| + public boolean hasPendingClosures() {
|
| + return TabModelBase.this.supportsPendingClosures()
|
| + && mRewoundTabs.size() > TabModelBase.this.getCount();
|
| + }
|
| + }
|
| +
|
| + /**
|
| + * Broadcast a notification (in native code) that all tabs are now loaded from storage.
|
| + */
|
| + public void broadcastSessionRestoreComplete() {
|
| + nativeBroadcastSessionRestoreComplete(mNativeTabModelImpl);
|
| + }
|
| +
|
| + // JNI related methods -------------------------------------------------------------------------
|
| +
|
| + @Override
|
| + @CalledByNative
|
| + public int getCount() {
|
| + return mTabs.size();
|
| + }
|
| +
|
| + @Override
|
| + @CalledByNative
|
| + public int index() {
|
| + return mIndex;
|
| + }
|
| +
|
| + @SuppressWarnings("unused")
|
| + @CalledByNative
|
| + private void setIndex(int index) {
|
| + TabModelUtils.setIndex(this, index);
|
| + }
|
| +
|
| + /**
|
| + * Used by Developer Tools to create a new tab with a given URL.
|
| + *
|
| + * @param url The URL to open.
|
| + * @return The new tab.
|
| + */
|
| + @CalledByNative
|
| + protected abstract Tab createNewTabForDevTools(String url);
|
| +
|
| + /**
|
| + * Opens the Clear Browsing Data dialog.
|
| + */
|
| + @CalledByNative
|
| + protected abstract void openClearBrowsingData();
|
| +
|
| + @CalledByNative
|
| + private boolean isSessionRestoreInProgress() {
|
| + return mModelDelegate.isSessionRestoreInProgress();
|
| + }
|
| +
|
| + private native long nativeInit(boolean isIncognito);
|
| + private native void nativeDestroy(long nativeTabModelBase);
|
| + private native void nativeBroadcastSessionRestoreComplete(long nativeTabModelBase);
|
| + private native Profile nativeGetProfileAndroid(long nativeTabModelBase);
|
| + private native void nativeTabAddedToModel(long nativeTabModelBase, Tab tab);
|
| +}
|
|
|