OLD | NEW |
(Empty) | |
| 1 // Copyright 2015 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. |
| 4 |
| 5 package org.chromium.chrome.browser.tabmodel; |
| 6 |
| 7 import android.app.Activity; |
| 8 |
| 9 import org.chromium.base.ActivityState; |
| 10 import org.chromium.base.ApplicationStatus; |
| 11 import org.chromium.base.ApplicationStatus.ActivityStateListener; |
| 12 import org.chromium.base.ThreadUtils; |
| 13 import org.chromium.base.VisibleForTesting; |
| 14 import org.chromium.chrome.browser.ChromeActivity; |
| 15 import org.chromium.ui.base.WindowAndroid; |
| 16 |
| 17 import java.util.ArrayList; |
| 18 import java.util.HashMap; |
| 19 import java.util.List; |
| 20 import java.util.Map; |
| 21 |
| 22 /** |
| 23 * Manages multiple {@link TabModelSelector} instances, each owned by different
{@link Activity}s. |
| 24 */ |
| 25 public class TabWindowManager implements ActivityStateListener { |
| 26 /** |
| 27 * An index that represents the invalid state (i.e. when the window wasn't f
ound in the list. |
| 28 */ |
| 29 public static final int INVALID_WINDOW_INDEX = -1; |
| 30 |
| 31 /** The maximum number of simultaneous TabModelSelector instances in this Ap
plication. */ |
| 32 @VisibleForTesting |
| 33 public static final int MAX_SIMULTANEOUS_SELECTORS = 3; |
| 34 |
| 35 /** |
| 36 * A factory interface for building a {@link TabModelSelector} instance. |
| 37 */ |
| 38 public interface TabModelSelectorFactory { |
| 39 /** |
| 40 * Builds a {@link TabModelSelector}. |
| 41 * @param activity A {@link ChromeActivity} instance. |
| 42 * @param windowAndroid A {@link WindowAndroid} instance that should con
nect to |
| 43 * {@code activity}. |
| 44 * @param selectorIndex The index of the {@link TabModelSelector}. |
| 45 * @return A new {@link TabModelSelector} instance. |
| 46 */ |
| 47 TabModelSelector buildSelector(ChromeActivity activity, WindowAndroid wi
ndowAndroid, |
| 48 int selectorIndex); |
| 49 } |
| 50 |
| 51 /** The singleton reference. */ |
| 52 private static TabWindowManager sInstance; |
| 53 |
| 54 private TabModelSelectorFactory mSelectorFactory = new DefaultTabModelSelect
orFactory(); |
| 55 |
| 56 private List<TabModelSelector> mSelectors = new ArrayList<TabModelSelector>(
); |
| 57 |
| 58 private Map<Activity, TabModelSelector> mAssignments = |
| 59 new HashMap<Activity, TabModelSelector>(); |
| 60 |
| 61 /** |
| 62 * @return The singleton instance of {@link TabWindowManager}. |
| 63 */ |
| 64 public static TabWindowManager getInstance() { |
| 65 ThreadUtils.assertOnUiThread(); |
| 66 if (sInstance == null) sInstance = new TabWindowManager(); |
| 67 return sInstance; |
| 68 } |
| 69 |
| 70 /** |
| 71 * Called to request a {@link TabModelSelector} based on {@code index}. Not
e that the |
| 72 * {@link TabModelSelector} returned might not actually be the one related t
o {@code index} |
| 73 * and {@link #getIndexForWindow(Activity)} should be called to grab the act
ual index if |
| 74 * required. |
| 75 * @param activity An instance of {@link ChromeActivity}. Must be the same
{@link Activity} as |
| 76 * the one referenced by {@code window}. |
| 77 * @param window A {@link WindowAndroid} as an instance. The {@link TabMo
delSelector} that is |
| 78 * created is bound to the {@link Activity} stored inside th
is window. |
| 79 * @param index The index of the requested {@link TabModelSelector}. Not
guaranteed to be |
| 80 * the index of the {@link TabModelSelector} returned. |
| 81 * @return A {@link TabModelSelector} index, or {@code null} if ther
e are too many |
| 82 * {@link TabModelSelector}s already built. |
| 83 */ |
| 84 public TabModelSelector requestSelector(ChromeActivity activity, WindowAndro
id window, |
| 85 int index) { |
| 86 if (mAssignments.get(activity) != null) { |
| 87 return mAssignments.get(activity); |
| 88 } |
| 89 |
| 90 if (index < 0 || index >= mSelectors.size()) index = 0; |
| 91 |
| 92 if (mSelectors.get(index) != null) { |
| 93 for (int i = 0; i < mSelectors.size(); i++) { |
| 94 if (mSelectors.get(i) == null) { |
| 95 index = i; |
| 96 break; |
| 97 } |
| 98 } |
| 99 } |
| 100 |
| 101 // Too many activities going at once. |
| 102 if (mSelectors.get(index) != null) return null; |
| 103 |
| 104 TabModelSelector selector = mSelectorFactory.buildSelector(activity, win
dow, index); |
| 105 mSelectors.set(index, selector); |
| 106 mAssignments.put(activity, selector); |
| 107 |
| 108 return selector; |
| 109 } |
| 110 |
| 111 /** |
| 112 * Finds the current index of the {@link TabModelSelector} bound to {@code w
indow}. |
| 113 * @param activity The {@link Activity} to find the index of the {@link TabM
odelSelector} |
| 114 * for. This uses the underlying {@link Activity} stored in
the |
| 115 * {@link WindowAndroid}. |
| 116 * @return The index of the {@link TabModelSelector} or {@link #INVA
LID_WINDOW_INDEX} if |
| 117 * not found. |
| 118 */ |
| 119 public int getIndexForWindow(Activity activity) { |
| 120 if (activity == null) return INVALID_WINDOW_INDEX; |
| 121 TabModelSelector selector = mAssignments.get(activity); |
| 122 if (selector == null) return INVALID_WINDOW_INDEX; |
| 123 int index = mSelectors.indexOf(selector); |
| 124 return index == -1 ? INVALID_WINDOW_INDEX : index; |
| 125 } |
| 126 |
| 127 /** |
| 128 * @return The number of {@link TabModelSelector}s currently assigned to {@l
ink Activity}s. |
| 129 */ |
| 130 public int getNumberOfAssignedTabModelSelectors() { |
| 131 return mAssignments.size(); |
| 132 } |
| 133 |
| 134 /** |
| 135 * @return The total number of incognito tabs across all tab model selectors
. |
| 136 */ |
| 137 public int getIncognitoTabCount() { |
| 138 int count = 0; |
| 139 for (int i = 0; i < mSelectors.size(); i++) { |
| 140 if (mSelectors.get(i) != null) { |
| 141 count += mSelectors.get(i).getModel(true).getCount(); |
| 142 } |
| 143 } |
| 144 return count; |
| 145 } |
| 146 |
| 147 @Override |
| 148 public void onActivityStateChange(Activity activity, int newState) { |
| 149 if (newState == ActivityState.DESTROYED && mAssignments.containsKey(acti
vity)) { |
| 150 int index = mSelectors.indexOf(mAssignments.remove(activity)); |
| 151 if (index >= 0) mSelectors.set(index, null); |
| 152 // TODO(dtrainor): Move TabModelSelector#destroy() calls here. |
| 153 } |
| 154 } |
| 155 |
| 156 /** |
| 157 * Allows overriding the default {@link TabModelSelectorFactory} with anothe
r one. Typically |
| 158 * for testing. |
| 159 * @param factory A {@link TabModelSelectorFactory} instance. |
| 160 */ |
| 161 @VisibleForTesting |
| 162 public void setTabModelSelectorFactory(TabModelSelectorFactory factory) { |
| 163 mSelectorFactory = factory; |
| 164 } |
| 165 |
| 166 private TabWindowManager() { |
| 167 ApplicationStatus.registerStateListenerForAllActivities(this); |
| 168 |
| 169 for (int i = 0; i < MAX_SIMULTANEOUS_SELECTORS; i++) mSelectors.add(null
); |
| 170 } |
| 171 |
| 172 private static class DefaultTabModelSelectorFactory implements TabModelSelec
torFactory { |
| 173 @Override |
| 174 public TabModelSelector buildSelector(ChromeActivity activity, WindowAnd
roid windowAndroid, |
| 175 int selectorIndex) { |
| 176 assert activity == windowAndroid.getActivity().get(); |
| 177 return new TabModelSelectorImpl(activity, selectorIndex, windowAndro
id); |
| 178 } |
| 179 } |
| 180 } |
OLD | NEW |