| // 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.ObserverList; |
| import org.chromium.chrome.browser.tab.Tab; |
| import org.chromium.chrome.browser.tab.TabCreationState; |
| import org.chromium.chrome.browser.tab.TabLaunchType; |
| import org.chromium.chrome.browser.tab.TabSelectionType; |
| import org.chromium.content_public.browser.LoadUrlParams; |
| |
| import java.util.ArrayList; |
| import java.util.Collections; |
| import java.util.List; |
| |
| /** |
| * Implement methods shared across the different model implementations. |
| */ |
| public abstract class TabModelSelectorBase implements TabModelSelector { |
| private static final int MODEL_NOT_FOUND = -1; |
| |
| private static TabModelSelectorObserver sObserver; |
| |
| private List<TabModel> mTabModels = new ArrayList<>(); |
| |
| /** |
| * This is a dummy implementation intended to stub out TabModelFilterProvider before native is |
| * ready. |
| */ |
| private TabModelFilterProvider mTabModelFilterProvider = new TabModelFilterProvider(); |
| |
| private final TabModelFilterFactory mTabModelFilterFactory; |
| private int mActiveModelIndex; |
| private final ObserverList<TabModelSelectorObserver> mObservers = new ObserverList<>(); |
| private boolean mTabStateInitialized; |
| private boolean mStartIncognito; |
| private boolean mReparentingInProgress; |
| |
| private final TabCreatorManager mTabCreatorManager; |
| |
| protected TabModelSelectorBase(TabCreatorManager tabCreatorManager, |
| TabModelFilterFactory tabModelFilterFactory, boolean startIncognito) { |
| mTabCreatorManager = tabCreatorManager; |
| mTabModelFilterFactory = tabModelFilterFactory; |
| mStartIncognito = startIncognito; |
| } |
| |
| protected final void initialize(TabModel... models) { |
| // Only normal and incognito supported for now. |
| assert mTabModels.isEmpty(); |
| assert models.length > 0; |
| |
| Collections.addAll(mTabModels, models); |
| mActiveModelIndex = getModelIndex(mStartIncognito); |
| assert mActiveModelIndex != MODEL_NOT_FOUND; |
| mTabModelFilterProvider = new TabModelFilterProvider(mTabModelFilterFactory, mTabModels); |
| addObserver(mTabModelFilterProvider); |
| |
| TabModelObserver tabModelObserver = new TabModelObserver() { |
| @Override |
| public void didAddTab( |
| Tab tab, @TabLaunchType int type, @TabCreationState int creationState) { |
| notifyChanged(); |
| notifyNewTabCreated(tab, creationState); |
| } |
| |
| @Override |
| public void didSelectTab(Tab tab, @TabSelectionType int type, int lastId) { |
| notifyChanged(); |
| } |
| |
| @Override |
| public void didMoveTab(Tab tab, int newIndex, int curIndex) { |
| notifyChanged(); |
| } |
| }; |
| |
| mTabModelFilterProvider.addTabModelFilterObserver(tabModelObserver); |
| |
| if (sObserver != null) { |
| addObserver(sObserver); |
| } |
| |
| notifyChanged(); |
| } |
| |
| public static void setObserverForTests(TabModelSelectorObserver observer) { |
| sObserver = observer; |
| } |
| |
| @Override |
| public void selectModel(boolean incognito) { |
| if (mTabModels.size() == 0) { |
| mStartIncognito = incognito; |
| return; |
| } |
| int newIndex = getModelIndex(incognito); |
| assert newIndex != MODEL_NOT_FOUND; |
| if (newIndex == mActiveModelIndex) return; |
| |
| TabModel newModel = mTabModels.get(newIndex); |
| TabModel previousModel = mTabModels.get(mActiveModelIndex); |
| mActiveModelIndex = newIndex; |
| for (TabModelSelectorObserver listener : mObservers) { |
| listener.onTabModelSelected(newModel, previousModel); |
| } |
| } |
| |
| @Override |
| public Tab getCurrentTab() { |
| return TabModelUtils.getCurrentTab(getCurrentModel()); |
| } |
| |
| @Override |
| public int getCurrentTabId() { |
| Tab tab = getCurrentTab(); |
| return tab != null ? tab.getId() : Tab.INVALID_TAB_ID; |
| } |
| |
| @Override |
| public TabModel getModelForTabId(int id) { |
| for (int i = 0; i < mTabModels.size(); i++) { |
| TabModel model = mTabModels.get(i); |
| if (TabModelUtils.getTabById(model, id) != null || model.isClosurePending(id)) { |
| return model; |
| } |
| } |
| return null; |
| } |
| |
| @Override |
| public TabModel getCurrentModel() { |
| if (mTabModels.size() == 0) return EmptyTabModel.getInstance(); |
| return mTabModels.get(mActiveModelIndex); |
| } |
| |
| @Override |
| public int getCurrentModelIndex() { |
| return mActiveModelIndex; |
| } |
| |
| @Override |
| public TabModel getModel(boolean incognito) { |
| int index = getModelIndex(incognito); |
| if (index == MODEL_NOT_FOUND) return EmptyTabModel.getInstance(); |
| return mTabModels.get(index); |
| } |
| |
| private int getModelIndex(boolean incognito) { |
| for (int i = 0; i < mTabModels.size(); i++) { |
| if (incognito == mTabModels.get(i).isIncognito()) return i; |
| } |
| return MODEL_NOT_FOUND; |
| } |
| |
| @Override |
| public TabModelFilterProvider getTabModelFilterProvider() { |
| return mTabModelFilterProvider; |
| } |
| |
| @Override |
| public boolean isIncognitoSelected() { |
| if (mTabModels.size() == 0) return mStartIncognito; |
| return getCurrentModel().isIncognito(); |
| } |
| |
| @Override |
| public List<TabModel> getModels() { |
| return mTabModels; |
| } |
| |
| @Override |
| public Tab openNewTab( |
| LoadUrlParams loadUrlParams, @TabLaunchType int type, Tab parent, boolean incognito) { |
| return mTabCreatorManager.getTabCreator(incognito).createNewTab( |
| loadUrlParams, type, parent); |
| } |
| |
| @Override |
| public boolean closeTab(Tab tab) { |
| for (int i = 0; i < getModels().size(); i++) { |
| TabModel model = mTabModels.get(i); |
| if (model.indexOf(tab) >= 0) { |
| return model.closeTab(tab); |
| } |
| } |
| assert false : "Tried to close a tab that is not in any model!"; |
| return false; |
| } |
| |
| @Override |
| public void commitAllTabClosures() { |
| for (int i = 0; i < mTabModels.size(); i++) { |
| mTabModels.get(i).commitAllTabClosures(); |
| } |
| } |
| |
| @Override |
| public Tab getTabById(int id) { |
| for (int i = 0; i < getModels().size(); i++) { |
| Tab tab = TabModelUtils.getTabById(mTabModels.get(i), id); |
| if (tab != null) return tab; |
| } |
| return null; |
| } |
| |
| @Override |
| public void closeAllTabs() { |
| closeAllTabs(false); |
| } |
| |
| @Override |
| public void closeAllTabs(boolean uponExit) { |
| for (int i = 0; i < getModels().size(); i++) { |
| mTabModels.get(i).closeAllTabs(!uponExit, uponExit); |
| } |
| } |
| |
| @Override |
| public int getTotalTabCount() { |
| int count = 0; |
| for (int i = 0; i < getModels().size(); i++) { |
| count += mTabModels.get(i).getCount(); |
| } |
| return count; |
| } |
| |
| @Override |
| public void addObserver(TabModelSelectorObserver observer) { |
| if (!mObservers.hasObserver(observer)) mObservers.addObserver(observer); |
| } |
| |
| @Override |
| public void removeObserver(TabModelSelectorObserver observer) { |
| mObservers.removeObserver(observer); |
| } |
| |
| @Override |
| public void setCloseAllTabsDelegate(CloseAllTabsDelegate delegate) { } |
| |
| /** |
| * Marks the task state being initialized and notifies observers. |
| */ |
| public void markTabStateInitialized() { |
| if (mTabStateInitialized) return; |
| mTabStateInitialized = true; |
| for (TabModelSelectorObserver listener : mObservers) listener.onTabStateInitialized(); |
| } |
| |
| @Override |
| public boolean isTabStateInitialized() { |
| return mTabStateInitialized; |
| } |
| |
| @Override |
| public void mergeState() {} |
| |
| @Override |
| public void destroy() { |
| removeObserver(mTabModelFilterProvider); |
| mTabModelFilterProvider.destroy(); |
| for (int i = 0; i < getModels().size(); i++) mTabModels.get(i).destroy(); |
| mTabModels.clear(); |
| } |
| |
| /** |
| * Notifies all the listeners that the {@link TabModelSelector} or its {@link TabModel} has |
| * changed. |
| */ |
| protected void notifyChanged() { |
| for (TabModelSelectorObserver listener : mObservers) { |
| listener.onChange(); |
| } |
| } |
| |
| /** |
| * Notifies all the listeners that a new tab has been created. |
| * @param tab The tab that has been created. |
| * @param creationSTate How the tab was created. |
| */ |
| private void notifyNewTabCreated(Tab tab, @TabCreationState int creationState) { |
| for (TabModelSelectorObserver listener : mObservers) { |
| listener.onNewTabCreated(tab, creationState); |
| } |
| } |
| |
| protected TabCreatorManager getTabCreatorManager() { |
| return mTabCreatorManager; |
| } |
| |
| @Override |
| public void enterReparentingMode() { |
| mReparentingInProgress = true; |
| } |
| |
| @Override |
| public boolean isReparentingInProgress() { |
| return mReparentingInProgress; |
| } |
| } |