blob: 1e21431ea59273f1593f25e1e57c4eeb811d5197 [file] [log] [blame]
The Android Open Source Project0c908882009-03-03 19:32:16 -08001/*
2 * Copyright (C) 2007 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package com.android.browser;
18
The Android Open Source Project0c908882009-03-03 19:32:16 -080019import android.os.Bundle;
The Android Open Source Project0c908882009-03-03 19:32:16 -080020import android.util.Log;
The Android Open Source Project0c908882009-03-03 19:32:16 -080021import android.webkit.WebView;
The Android Open Source Project0c908882009-03-03 19:32:16 -080022
23import java.io.File;
24import java.util.ArrayList;
Elliott Slaughter3d6df162010-08-25 13:17:44 -070025import java.util.HashMap;
Michael Kolb1bf23132010-11-19 12:55:12 -080026import java.util.List;
The Android Open Source Project0c908882009-03-03 19:32:16 -080027import java.util.Vector;
28
29class TabControl {
30 // Log Tag
31 private static final String LOGTAG = "TabControl";
Michael Kolbc831b632011-05-11 09:30:34 -070032
33 // next Tab ID
34 private static long sNextId = 0;
35
36 private static final String POSITIONS = "positions";
37 private static final String CURRENT = "current";
38
The Android Open Source Project0c908882009-03-03 19:32:16 -080039 // Maximum number of tabs.
Michael Kolb6e4653e2010-09-27 16:22:38 -070040 private int mMaxTabs;
The Android Open Source Project0c908882009-03-03 19:32:16 -080041 // Private array of WebViews that are used as tabs.
Michael Kolb6e4653e2010-09-27 16:22:38 -070042 private ArrayList<Tab> mTabs;
The Android Open Source Project0c908882009-03-03 19:32:16 -080043 // Queue of most recently viewed tabs.
Michael Kolb6e4653e2010-09-27 16:22:38 -070044 private ArrayList<Tab> mTabQueue;
The Android Open Source Project0c908882009-03-03 19:32:16 -080045 // Current position in mTabs.
46 private int mCurrentTab = -1;
Michael Kolb8233fac2010-10-26 16:08:53 -070047 // the main browser controller
48 private final Controller mController;
49
The Android Open Source Project0c908882009-03-03 19:32:16 -080050 private final File mThumbnailDir;
51
52 /**
Michael Kolb8233fac2010-10-26 16:08:53 -070053 * Construct a new TabControl object
The Android Open Source Project0c908882009-03-03 19:32:16 -080054 */
Michael Kolb8233fac2010-10-26 16:08:53 -070055 TabControl(Controller controller) {
56 mController = controller;
57 mThumbnailDir = mController.getActivity()
58 .getDir("thumbnails", 0);
59 mMaxTabs = mController.getMaxTabs();
Michael Kolb6e4653e2010-09-27 16:22:38 -070060 mTabs = new ArrayList<Tab>(mMaxTabs);
61 mTabQueue = new ArrayList<Tab>(mMaxTabs);
The Android Open Source Project0c908882009-03-03 19:32:16 -080062 }
63
Michael Kolbc831b632011-05-11 09:30:34 -070064 static long getNextId() {
65 return sNextId++;
66 }
67
The Android Open Source Project0c908882009-03-03 19:32:16 -080068 File getThumbnailDir() {
69 return mThumbnailDir;
70 }
71
Michael Kolb68775752010-08-19 12:42:01 -070072 /**
The Android Open Source Project0c908882009-03-03 19:32:16 -080073 * Return the current tab's main WebView. This will always return the main
74 * WebView for a given tab and not a subwindow.
75 * @return The current tab's WebView.
76 */
77 WebView getCurrentWebView() {
78 Tab t = getTab(mCurrentTab);
79 if (t == null) {
80 return null;
81 }
Grace Kloba22ac16e2009-10-07 18:00:23 -070082 return t.getWebView();
Ben Murdochbff2d602009-07-01 20:19:05 +010083 }
84
85 /**
The Android Open Source Project0c908882009-03-03 19:32:16 -080086 * Return the current tab's top-level WebView. This can return a subwindow
87 * if one exists.
88 * @return The top-level WebView of the current tab.
89 */
90 WebView getCurrentTopWebView() {
91 Tab t = getTab(mCurrentTab);
92 if (t == null) {
93 return null;
94 }
Grace Kloba22ac16e2009-10-07 18:00:23 -070095 return t.getTopWindow();
The Android Open Source Project0c908882009-03-03 19:32:16 -080096 }
97
98 /**
99 * Return the current tab's subwindow if it exists.
100 * @return The subwindow of the current tab or null if it doesn't exist.
101 */
102 WebView getCurrentSubWindow() {
103 Tab t = getTab(mCurrentTab);
104 if (t == null) {
105 return null;
106 }
Grace Kloba22ac16e2009-10-07 18:00:23 -0700107 return t.getSubWebView();
The Android Open Source Project0c908882009-03-03 19:32:16 -0800108 }
109
110 /**
Michael Kolb1bf23132010-11-19 12:55:12 -0800111 * return the list of tabs
112 */
113 List<Tab> getTabs() {
114 return mTabs;
115 }
116
117 /**
Michael Kolbc831b632011-05-11 09:30:34 -0700118 * Return the tab at the specified position.
119 * @return The Tab for the specified position or null if the tab does not
The Android Open Source Project0c908882009-03-03 19:32:16 -0800120 * exist.
121 */
Michael Kolbc831b632011-05-11 09:30:34 -0700122 Tab getTab(int position) {
123 if (position >= 0 && position < mTabs.size()) {
124 return mTabs.get(position);
The Android Open Source Project0c908882009-03-03 19:32:16 -0800125 }
126 return null;
127 }
128
129 /**
130 * Return the current tab.
131 * @return The current tab.
132 */
133 Tab getCurrentTab() {
134 return getTab(mCurrentTab);
135 }
136
137 /**
Michael Kolbc831b632011-05-11 09:30:34 -0700138 * Return the current tab position.
139 * @return The current tab position
The Android Open Source Project0c908882009-03-03 19:32:16 -0800140 */
Michael Kolbc831b632011-05-11 09:30:34 -0700141 int getCurrentPosition() {
The Android Open Source Project0c908882009-03-03 19:32:16 -0800142 return mCurrentTab;
143 }
Michael Kolbfe251992010-07-08 15:41:55 -0700144
The Android Open Source Project0c908882009-03-03 19:32:16 -0800145 /**
Michael Kolbc831b632011-05-11 09:30:34 -0700146 * Given a Tab, find it's position
The Android Open Source Project0c908882009-03-03 19:32:16 -0800147 * @param Tab to find
Michael Kolbc831b632011-05-11 09:30:34 -0700148 * @return position of Tab or -1 if not found
The Android Open Source Project0c908882009-03-03 19:32:16 -0800149 */
Michael Kolbc831b632011-05-11 09:30:34 -0700150 int getTabPosition(Tab tab) {
Patrick Scottae641ac2009-04-20 13:51:49 -0400151 if (tab == null) {
152 return -1;
153 }
The Android Open Source Project0c908882009-03-03 19:32:16 -0800154 return mTabs.indexOf(tab);
155 }
156
Grace Kloba22ac16e2009-10-07 18:00:23 -0700157 boolean canCreateNewTab() {
Michael Kolb6e4653e2010-09-27 16:22:38 -0700158 return mMaxTabs != mTabs.size();
Grace Kloba22ac16e2009-10-07 18:00:23 -0700159 }
160
The Android Open Source Project0c908882009-03-03 19:32:16 -0800161 /**
Elliott Slaughtere440a882010-08-20 13:54:45 -0700162 * Returns true if there are any incognito tabs open.
163 * @return True when any incognito tabs are open, false otherwise.
164 */
165 boolean hasAnyOpenIncognitoTabs() {
166 for (Tab tab : mTabs) {
Michael Kolbc831b632011-05-11 09:30:34 -0700167 if (tab.getWebView() != null
168 && tab.getWebView().isPrivateBrowsingEnabled()) {
Elliott Slaughtere440a882010-08-20 13:54:45 -0700169 return true;
170 }
171 }
172 return false;
173 }
174
175 /**
The Android Open Source Projectf59ec872009-03-13 13:04:24 -0700176 * Create a new tab.
The Android Open Source Project0c908882009-03-03 19:32:16 -0800177 * @return The newly createTab or null if we have reached the maximum
178 * number of open tabs.
179 */
Michael Kolb7bcafde2011-05-09 13:55:59 -0700180 Tab createNewTab(boolean privateBrowsing) {
The Android Open Source Project0c908882009-03-03 19:32:16 -0800181 int size = mTabs.size();
182 // Return false if we have maxed out on tabs
Michael Kolb6e4653e2010-09-27 16:22:38 -0700183 if (mMaxTabs == size) {
The Android Open Source Project0c908882009-03-03 19:32:16 -0800184 return null;
185 }
Elliott Slaughterf0f03952010-07-14 18:10:36 -0700186 final WebView w = createNewWebView(privateBrowsing);
Steve Block2bc69912009-07-30 14:45:13 +0100187
The Android Open Source Project0c908882009-03-03 19:32:16 -0800188 // Create a new tab and add it to the tab list
Michael Kolb7bcafde2011-05-09 13:55:59 -0700189 Tab t = new Tab(mController, w);
Michael Kolbc831b632011-05-11 09:30:34 -0700190 t.setId(getNextId());
The Android Open Source Project0c908882009-03-03 19:32:16 -0800191 mTabs.add(t);
The Android Open Source Project4e5f5872009-03-09 11:52:14 -0700192 // Initially put the tab in the background.
Grace Kloba22ac16e2009-10-07 18:00:23 -0700193 t.putInBackground();
The Android Open Source Project0c908882009-03-03 19:32:16 -0800194 return t;
195 }
196
197 /**
The Android Open Source Projectf59ec872009-03-13 13:04:24 -0700198 * Create a new tab with default values for closeOnExit(false),
Elliott Slaughterf0f03952010-07-14 18:10:36 -0700199 * appId(null), url(null), and privateBrowsing(false).
The Android Open Source Projectf59ec872009-03-13 13:04:24 -0700200 */
201 Tab createNewTab() {
Michael Kolb7bcafde2011-05-09 13:55:59 -0700202 return createNewTab(false);
The Android Open Source Projectf59ec872009-03-13 13:04:24 -0700203 }
204
205 /**
Leon Scrogginsfde97462010-01-11 13:06:21 -0500206 * Remove the parent child relationships from all tabs.
207 */
208 void removeParentChildRelationShips() {
209 for (Tab tab : mTabs) {
210 tab.removeFromTree();
211 }
212 }
213
214 /**
The Android Open Source Project0c908882009-03-03 19:32:16 -0800215 * Remove the tab from the list. If the tab is the current tab shown, the
216 * last created tab will be shown.
217 * @param t The tab to be removed.
218 */
219 boolean removeTab(Tab t) {
220 if (t == null) {
221 return false;
222 }
Grace Kloba22ac16e2009-10-07 18:00:23 -0700223
Patrick Scottd944d4d2010-01-27 16:39:11 -0500224 // Grab the current tab before modifying the list.
225 Tab current = getCurrentTab();
226
227 // Remove t from our list of tabs.
228 mTabs.remove(t);
229
230 // Put the tab in the background only if it is the current one.
231 if (current == t) {
Grace Kloba22ac16e2009-10-07 18:00:23 -0700232 t.putInBackground();
233 mCurrentTab = -1;
Patrick Scottd944d4d2010-01-27 16:39:11 -0500234 } else {
235 // If a tab that is earlier in the list gets removed, the current
236 // index no longer points to the correct tab.
Michael Kolbc831b632011-05-11 09:30:34 -0700237 mCurrentTab = getTabPosition(current);
The Android Open Source Project0c908882009-03-03 19:32:16 -0800238 }
239
Grace Kloba22ac16e2009-10-07 18:00:23 -0700240 // destroy the tab
241 t.destroy();
The Android Open Source Project0c908882009-03-03 19:32:16 -0800242 // clear it's references to parent and children
243 t.removeFromTree();
The Android Open Source Project0c908882009-03-03 19:32:16 -0800244
The Android Open Source Project0c908882009-03-03 19:32:16 -0800245 // Remove it from the queue of viewed tabs.
246 mTabQueue.remove(t);
The Android Open Source Project0c908882009-03-03 19:32:16 -0800247 return true;
248 }
249
250 /**
The Android Open Source Project0c908882009-03-03 19:32:16 -0800251 * Destroy all the tabs and subwindows
252 */
253 void destroy() {
The Android Open Source Project0c908882009-03-03 19:32:16 -0800254 for (Tab t : mTabs) {
Grace Kloba22ac16e2009-10-07 18:00:23 -0700255 t.destroy();
The Android Open Source Project0c908882009-03-03 19:32:16 -0800256 }
257 mTabs.clear();
258 mTabQueue.clear();
259 }
260
261 /**
262 * Returns the number of tabs created.
263 * @return The number of tabs created.
264 */
265 int getTabCount() {
266 return mTabs.size();
267 }
268
The Android Open Source Project0c908882009-03-03 19:32:16 -0800269 /**
Michael Kolbc831b632011-05-11 09:30:34 -0700270 * save the tab state:
271 * current position
272 * position sorted array of tab ids
273 * for each tab id, save the tab state
274 * @param outState
John Reckaed9c542011-05-27 16:08:53 -0700275 * @param saveImages
The Android Open Source Project0c908882009-03-03 19:32:16 -0800276 */
John Reckaed9c542011-05-27 16:08:53 -0700277 void saveState(Bundle outState, boolean saveImages) {
The Android Open Source Project0c908882009-03-03 19:32:16 -0800278 final int numTabs = getTabCount();
Michael Kolbc831b632011-05-11 09:30:34 -0700279 long[] ids = new long[numTabs];
280 int i = 0;
281 for (Tab tab : mTabs) {
282 ids[i++] = tab.getId();
283 if (tab.saveState()) {
John Reckaed9c542011-05-27 16:08:53 -0700284 outState.putBundle(Long.toString(tab.getId()),
285 tab.getSavedState(saveImages));
The Android Open Source Project0c908882009-03-03 19:32:16 -0800286 }
287 }
Michael Kolbc831b632011-05-11 09:30:34 -0700288 outState.putLongArray(POSITIONS, ids);
Michael Kolbdbf39812011-06-10 14:06:40 -0700289 Tab current = getCurrentTab();
290 long cid = -1;
291 if (current != null) {
292 cid = current.getId();
293 }
Michael Kolbc831b632011-05-11 09:30:34 -0700294 outState.putLong(CURRENT, cid);
The Android Open Source Project0c908882009-03-03 19:32:16 -0800295 }
296
297 /**
Patrick Scott7d50a932011-02-04 09:27:26 -0500298 * Check if the state can be restored. If the state can be restored, the
Michael Kolbc831b632011-05-11 09:30:34 -0700299 * current tab id is returned. This can be passed to restoreState below
Patrick Scott7d50a932011-02-04 09:27:26 -0500300 * in order to restore the correct tab. Otherwise, -1 is returned and the
301 * state cannot be restored.
302 */
Michael Kolbc831b632011-05-11 09:30:34 -0700303 long canRestoreState(Bundle inState, boolean restoreIncognitoTabs) {
304 final long[] ids = (inState == null) ? null : inState.getLongArray(POSITIONS);
305 if (ids == null) {
Patrick Scott7d50a932011-02-04 09:27:26 -0500306 return -1;
307 }
Michael Kolbc831b632011-05-11 09:30:34 -0700308 final long oldcurrent = inState.getLong(CURRENT);
309 long current = -1;
Patrick Scott7d50a932011-02-04 09:27:26 -0500310 if (restoreIncognitoTabs ||
Michael Kolbc831b632011-05-11 09:30:34 -0700311 !inState.getBundle(Long.toString(oldcurrent)).getBoolean(Tab.INCOGNITO)) {
312 current = oldcurrent;
Patrick Scott7d50a932011-02-04 09:27:26 -0500313 } else {
Michael Kolbc831b632011-05-11 09:30:34 -0700314 // pick first non incognito tab
315 for (long id : ids) {
316 if (!inState.getBundle(Long.toString(id)).getBoolean(Tab.INCOGNITO)) {
317 current = id;
Patrick Scott7d50a932011-02-04 09:27:26 -0500318 break;
319 }
320 }
321 }
Michael Kolbc831b632011-05-11 09:30:34 -0700322 return current;
Patrick Scott7d50a932011-02-04 09:27:26 -0500323 }
324
325 /**
The Android Open Source Project0c908882009-03-03 19:32:16 -0800326 * Restore the state of all the tabs.
Michael Kolbc831b632011-05-11 09:30:34 -0700327 * @param currentId The tab id to restore.
The Android Open Source Project0c908882009-03-03 19:32:16 -0800328 * @param inState The saved state of all the tabs.
Michael Kolb1bf23132010-11-19 12:55:12 -0800329 * @param restoreIncognitoTabs Restoring private browsing tabs
330 * @param restoreAll All webviews get restored, not just the current tab
331 * (this does not override handling of incognito tabs)
The Android Open Source Project0c908882009-03-03 19:32:16 -0800332 * @return True if there were previous tabs that were restored. False if
333 * there was no saved state or restoring the state failed.
334 */
Michael Kolbc831b632011-05-11 09:30:34 -0700335 void restoreState(Bundle inState, long currentId,
Patrick Scott7d50a932011-02-04 09:27:26 -0500336 boolean restoreIncognitoTabs, boolean restoreAll) {
Michael Kolbc831b632011-05-11 09:30:34 -0700337 if (currentId == -1) {
Patrick Scott7d50a932011-02-04 09:27:26 -0500338 return;
339 }
Michael Kolbc831b632011-05-11 09:30:34 -0700340 long[] ids = inState.getLongArray(POSITIONS);
341 long maxId = -Long.MAX_VALUE;
342 HashMap<Long, Tab> tabMap = new HashMap<Long, Tab>();
343 for (long id : ids) {
344 if (id > maxId) {
345 maxId = id;
346 }
347 final String idkey = Long.toString(id);
348 Bundle state = inState.getBundle(idkey);
349 if (!restoreIncognitoTabs && state != null
350 && state.getBoolean(Tab.INCOGNITO)) {
351 // ignore tab
352 } else if (id == currentId || restoreAll) {
Patrick Scott7d50a932011-02-04 09:27:26 -0500353 Tab t = createNewTab();
Michael Kolbc831b632011-05-11 09:30:34 -0700354 tabMap.put(id, t);
Patrick Scott7d50a932011-02-04 09:27:26 -0500355 // Me must set the current tab before restoring the state
356 // so that all the client classes are set.
Michael Kolbc831b632011-05-11 09:30:34 -0700357 if (id == currentId) {
Patrick Scott7d50a932011-02-04 09:27:26 -0500358 setCurrentTab(t);
359 }
360 if (!t.restoreState(state)) {
361 Log.w(LOGTAG, "Fail in restoreState, load home page.");
362 t.getWebView().loadUrl(BrowserSettings.getInstance()
363 .getHomePage());
364 }
Elliott Slaughter3d6df162010-08-25 13:17:44 -0700365 } else {
Patrick Scott7d50a932011-02-04 09:27:26 -0500366 // Create a new tab and don't restore the state yet, add it
367 // to the tab list
Michael Kolb7bcafde2011-05-09 13:55:59 -0700368 Tab t = new Tab(mController, null);
Michael Kolbc831b632011-05-11 09:30:34 -0700369 t.setId(id);
370 tabMap.put(id, t);
Patrick Scott7d50a932011-02-04 09:27:26 -0500371 if (state != null) {
372 t.setSavedState(state);
373 // Need to maintain the app id and original url so we
374 // can possibly reuse this tab.
375 t.setAppId(state.getString(Tab.APPID));
Elliott Slaughter3d6df162010-08-25 13:17:44 -0700376 }
Patrick Scott7d50a932011-02-04 09:27:26 -0500377 mTabs.add(t);
378 // added the tab to the front as they are not current
379 mTabQueue.add(0, t);
Elliott Slaughter3d6df162010-08-25 13:17:44 -0700380 }
Michael Kolbc831b632011-05-11 09:30:34 -0700381 // make sure that there is no id overlap between the restored
382 // and new tabs
383 sNextId = maxId + 1;
Elliott Slaughter3d6df162010-08-25 13:17:44 -0700384
Michael Kolbc831b632011-05-11 09:30:34 -0700385 }
386 // restore parent/child relationships
387 for (long id : ids) {
388 final Tab tab = tabMap.get(id);
389 final Bundle b = inState.getBundle(Long.toString(id));
390 if ((b != null) && (tab != null)) {
391 final long parentId = b.getLong(Tab.PARENTTAB, -1);
392 if (parentId != -1) {
393 final Tab parent = tabMap.get(parentId);
Patrick Scott7d50a932011-02-04 09:27:26 -0500394 if (parent != null) {
Michael Kolbc831b632011-05-11 09:30:34 -0700395 parent.addChildTab(tab);
The Android Open Source Project0c908882009-03-03 19:32:16 -0800396 }
397 }
398 }
399 }
The Android Open Source Project0c908882009-03-03 19:32:16 -0800400 }
401
402 /**
Grace Klobaf56f68d2010-04-11 22:53:42 -0700403 * Free the memory in this order, 1) free the background tabs; 2) free the
The Android Open Source Project0c908882009-03-03 19:32:16 -0800404 * WebView cache;
405 */
406 void freeMemory() {
Grace Kloba92c18a52009-07-31 23:48:32 -0700407 if (getTabCount() == 0) return;
408
Grace Klobaf56f68d2010-04-11 22:53:42 -0700409 // free the least frequently used background tabs
410 Vector<Tab> tabs = getHalfLeastUsedTabs(getCurrentTab());
411 if (tabs.size() > 0) {
412 Log.w(LOGTAG, "Free " + tabs.size() + " tabs in the browser");
413 for (Tab t : tabs) {
414 // store the WebView's state.
415 t.saveState();
416 // destroy the tab
417 t.destroy();
418 }
The Android Open Source Project0c908882009-03-03 19:32:16 -0800419 return;
420 }
421
Derek Sollenberger4433d032009-06-10 15:37:21 -0400422 // free the WebView's unused memory (this includes the cache)
423 Log.w(LOGTAG, "Free WebView's unused memory and cache");
The Android Open Source Project0c908882009-03-03 19:32:16 -0800424 WebView view = getCurrentWebView();
425 if (view != null) {
Derek Sollenberger4433d032009-06-10 15:37:21 -0400426 view.freeMemory();
The Android Open Source Project0c908882009-03-03 19:32:16 -0800427 }
The Android Open Source Project0c908882009-03-03 19:32:16 -0800428 }
429
Grace Klobaf56f68d2010-04-11 22:53:42 -0700430 private Vector<Tab> getHalfLeastUsedTabs(Tab current) {
431 Vector<Tab> tabsToGo = new Vector<Tab>();
432
Patrick Scott2a67de42009-08-31 09:48:37 -0400433 // Don't do anything if we only have 1 tab or if the current tab is
434 // null.
435 if (getTabCount() == 1 || current == null) {
Grace Klobaf56f68d2010-04-11 22:53:42 -0700436 return tabsToGo;
The Android Open Source Project0c908882009-03-03 19:32:16 -0800437 }
438
Grace Klobaf56f68d2010-04-11 22:53:42 -0700439 if (mTabQueue.size() == 0) {
440 return tabsToGo;
The Android Open Source Project0c908882009-03-03 19:32:16 -0800441 }
442
Grace Klobaf56f68d2010-04-11 22:53:42 -0700443 // Rip through the queue starting at the beginning and tear down half of
444 // available tabs which are not the current tab or the parent of the
445 // current tab.
446 int openTabCount = 0;
447 for (Tab t : mTabQueue) {
448 if (t != null && t.getWebView() != null) {
449 openTabCount++;
Michael Kolbc831b632011-05-11 09:30:34 -0700450 if (t != current && t != current.getParent()) {
Grace Klobaf56f68d2010-04-11 22:53:42 -0700451 tabsToGo.add(t);
452 }
453 }
454 }
455
456 openTabCount /= 2;
457 if (tabsToGo.size() > openTabCount) {
458 tabsToGo.setSize(openTabCount);
459 }
460
461 return tabsToGo;
The Android Open Source Project0c908882009-03-03 19:32:16 -0800462 }
463
The Android Open Source Project0c908882009-03-03 19:32:16 -0800464 /**
465 * Show the tab that contains the given WebView.
466 * @param view The WebView used to find the tab.
467 */
468 Tab getTabFromView(WebView view) {
Michael Kolbc831b632011-05-11 09:30:34 -0700469 for (Tab t : mTabs) {
Grace Kloba22ac16e2009-10-07 18:00:23 -0700470 if (t.getSubWebView() == view || t.getWebView() == view) {
The Android Open Source Project0c908882009-03-03 19:32:16 -0800471 return t;
472 }
473 }
474 return null;
475 }
476
477 /**
The Android Open Source Projectf59ec872009-03-13 13:04:24 -0700478 * Return the tab with the matching application id.
479 * @param id The application identifier.
480 */
Michael Kolbc831b632011-05-11 09:30:34 -0700481 Tab getTabFromAppId(String id) {
The Android Open Source Projectf59ec872009-03-13 13:04:24 -0700482 if (id == null) {
483 return null;
484 }
Michael Kolbc831b632011-05-11 09:30:34 -0700485 for (Tab t : mTabs) {
Grace Kloba22ac16e2009-10-07 18:00:23 -0700486 if (id.equals(t.getAppId())) {
The Android Open Source Projectf59ec872009-03-13 13:04:24 -0700487 return t;
488 }
489 }
490 return null;
491 }
492
Grace Kloba22ac16e2009-10-07 18:00:23 -0700493 /**
494 * Stop loading in all opened WebView including subWindows.
495 */
Grace Kloba5d0e02e2009-10-05 15:15:36 -0700496 void stopAllLoading() {
Michael Kolbc831b632011-05-11 09:30:34 -0700497 for (Tab t : mTabs) {
Grace Kloba22ac16e2009-10-07 18:00:23 -0700498 final WebView webview = t.getWebView();
Grace Kloba5d0e02e2009-10-05 15:15:36 -0700499 if (webview != null) {
500 webview.stopLoading();
501 }
Grace Kloba22ac16e2009-10-07 18:00:23 -0700502 final WebView subview = t.getSubWebView();
503 if (subview != null) {
504 webview.stopLoading();
505 }
Grace Kloba5d0e02e2009-10-05 15:15:36 -0700506 }
507 }
508
Patrick Scottcd115892009-07-16 09:42:58 -0400509 // This method checks if a non-app tab (one created within the browser)
510 // matches the given url.
511 private boolean tabMatchesUrl(Tab t, String url) {
Grace Kloba22ac16e2009-10-07 18:00:23 -0700512 if (t.getAppId() != null) {
Patrick Scottcd115892009-07-16 09:42:58 -0400513 return false;
Grace Kloba22ac16e2009-10-07 18:00:23 -0700514 }
515 WebView webview = t.getWebView();
516 if (webview == null) {
Patrick Scottcd115892009-07-16 09:42:58 -0400517 return false;
Grace Kloba22ac16e2009-10-07 18:00:23 -0700518 } else if (url.equals(webview.getUrl())
519 || url.equals(webview.getOriginalUrl())) {
Patrick Scottcd115892009-07-16 09:42:58 -0400520 return true;
521 }
522 return false;
523 }
524
525 /**
526 * Return the tab that has no app id associated with it and the url of the
527 * tab matches the given url.
528 * @param url The url to search for.
529 */
530 Tab findUnusedTabWithUrl(String url) {
531 if (url == null) {
532 return null;
533 }
534 // Check the current tab first.
535 Tab t = getCurrentTab();
536 if (t != null && tabMatchesUrl(t, url)) {
537 return t;
538 }
539 // Now check all the rest.
Michael Kolbc831b632011-05-11 09:30:34 -0700540 for (Tab tab : mTabs) {
541 if (tabMatchesUrl(tab, url)) {
Patrick Scottcd115892009-07-16 09:42:58 -0400542 return t;
543 }
544 }
545 return null;
546 }
547
The Android Open Source Projectf59ec872009-03-13 13:04:24 -0700548 /**
John Reck30c714c2010-12-16 17:30:34 -0800549 * Recreate the main WebView of the given tab.
The Android Open Source Projectf59ec872009-03-13 13:04:24 -0700550 */
John Reck30c714c2010-12-16 17:30:34 -0800551 void recreateWebView(Tab t) {
Grace Kloba22ac16e2009-10-07 18:00:23 -0700552 final WebView w = t.getWebView();
The Android Open Source Projectf59ec872009-03-13 13:04:24 -0700553 if (w != null) {
Grace Kloba22ac16e2009-10-07 18:00:23 -0700554 t.destroy();
The Android Open Source Projectf59ec872009-03-13 13:04:24 -0700555 }
556 // Create a new WebView. If this tab is the current tab, we need to put
557 // back all the clients so force it to be the current tab.
Steve Block2bc69912009-07-30 14:45:13 +0100558 t.setWebView(createNewWebView());
The Android Open Source Projectf59ec872009-03-13 13:04:24 -0700559 if (getCurrentTab() == t) {
560 setCurrentTab(t, true);
561 }
Grace Kloba22ac16e2009-10-07 18:00:23 -0700562 // Clear the saved state and picker data
563 t.setSavedState(null);
The Android Open Source Projectf59ec872009-03-13 13:04:24 -0700564 }
565
566 /**
567 * Creates a new WebView and registers it with the global settings.
568 */
569 private WebView createNewWebView() {
Elliott Slaughterf0f03952010-07-14 18:10:36 -0700570 return createNewWebView(false);
571 }
572
573 /**
574 * Creates a new WebView and registers it with the global settings.
575 * @param privateBrowsing When true, enables private browsing in the new
576 * WebView.
577 */
578 private WebView createNewWebView(boolean privateBrowsing) {
Michael Kolb8233fac2010-10-26 16:08:53 -0700579 return mController.getWebViewFactory().createWebView(privateBrowsing);
The Android Open Source Projectf59ec872009-03-13 13:04:24 -0700580 }
581
582 /**
The Android Open Source Project0c908882009-03-03 19:32:16 -0800583 * Put the current tab in the background and set newTab as the current tab.
584 * @param newTab The new tab. If newTab is null, the current tab is not
585 * set.
586 */
587 boolean setCurrentTab(Tab newTab) {
The Android Open Source Projectf59ec872009-03-13 13:04:24 -0700588 return setCurrentTab(newTab, false);
589 }
590
591 /**
592 * If force is true, this method skips the check for newTab == current.
593 */
594 private boolean setCurrentTab(Tab newTab, boolean force) {
The Android Open Source Project0c908882009-03-03 19:32:16 -0800595 Tab current = getTab(mCurrentTab);
The Android Open Source Projectf59ec872009-03-13 13:04:24 -0700596 if (current == newTab && !force) {
The Android Open Source Project0c908882009-03-03 19:32:16 -0800597 return true;
598 }
599 if (current != null) {
Grace Kloba22ac16e2009-10-07 18:00:23 -0700600 current.putInBackground();
601 mCurrentTab = -1;
The Android Open Source Project0c908882009-03-03 19:32:16 -0800602 }
The Android Open Source Project0c908882009-03-03 19:32:16 -0800603 if (newTab == null) {
604 return false;
605 }
606
607 // Move the newTab to the end of the queue
608 int index = mTabQueue.indexOf(newTab);
609 if (index != -1) {
610 mTabQueue.remove(index);
611 }
612 mTabQueue.add(newTab);
613
The Android Open Source Project0c908882009-03-03 19:32:16 -0800614 // Display the new current tab
615 mCurrentTab = mTabs.indexOf(newTab);
Grace Kloba22ac16e2009-10-07 18:00:23 -0700616 WebView mainView = newTab.getWebView();
The Android Open Source Project0c908882009-03-03 19:32:16 -0800617 boolean needRestore = (mainView == null);
618 if (needRestore) {
619 // Same work as in createNewTab() except don't do new Tab()
Steve Block2bc69912009-07-30 14:45:13 +0100620 mainView = createNewWebView();
621 newTab.setWebView(mainView);
The Android Open Source Project0c908882009-03-03 19:32:16 -0800622 }
Grace Kloba22ac16e2009-10-07 18:00:23 -0700623 newTab.putInForeground();
The Android Open Source Project0c908882009-03-03 19:32:16 -0800624 if (needRestore) {
625 // Have to finish setCurrentTab work before calling restoreState
Grace Kloba22ac16e2009-10-07 18:00:23 -0700626 if (!newTab.restoreState(newTab.getSavedState())) {
The Android Open Source Project0c908882009-03-03 19:32:16 -0800627 mainView.loadUrl(BrowserSettings.getInstance().getHomePage());
628 }
629 }
630 return true;
631 }
Michael Kolbfe251992010-07-08 15:41:55 -0700632
The Android Open Source Project0c908882009-03-03 19:32:16 -0800633}