blob: aeffbc0f520bff618d7750763616eac894cde089 [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
Michael Kolb8233fac2010-10-26 16:08:53 -070019import com.android.browser.IntentHandler.UrlData;
20
The Android Open Source Project0c908882009-03-03 19:32:16 -080021import android.os.Bundle;
The Android Open Source Project0c908882009-03-03 19:32:16 -080022import android.util.Log;
The Android Open Source Project0c908882009-03-03 19:32:16 -080023import android.webkit.WebBackForwardList;
The Android Open Source Project0c908882009-03-03 19:32:16 -080024import android.webkit.WebView;
The Android Open Source Project0c908882009-03-03 19:32:16 -080025
26import java.io.File;
27import java.util.ArrayList;
Elliott Slaughter3d6df162010-08-25 13:17:44 -070028import java.util.HashMap;
The Android Open Source Project0c908882009-03-03 19:32:16 -080029import java.util.Vector;
30
31class TabControl {
32 // Log Tag
33 private static final String LOGTAG = "TabControl";
34 // Maximum number of tabs.
Michael Kolb6e4653e2010-09-27 16:22:38 -070035 private int mMaxTabs;
The Android Open Source Project0c908882009-03-03 19:32:16 -080036 // Private array of WebViews that are used as tabs.
Michael Kolb6e4653e2010-09-27 16:22:38 -070037 private ArrayList<Tab> mTabs;
The Android Open Source Project0c908882009-03-03 19:32:16 -080038 // Queue of most recently viewed tabs.
Michael Kolb6e4653e2010-09-27 16:22:38 -070039 private ArrayList<Tab> mTabQueue;
The Android Open Source Project0c908882009-03-03 19:32:16 -080040 // Current position in mTabs.
41 private int mCurrentTab = -1;
Michael Kolb8233fac2010-10-26 16:08:53 -070042 // the main browser controller
43 private final Controller mController;
44
The Android Open Source Project0c908882009-03-03 19:32:16 -080045 private final File mThumbnailDir;
46
47 /**
Michael Kolb8233fac2010-10-26 16:08:53 -070048 * Construct a new TabControl object
The Android Open Source Project0c908882009-03-03 19:32:16 -080049 */
Michael Kolb8233fac2010-10-26 16:08:53 -070050 TabControl(Controller controller) {
51 mController = controller;
52 mThumbnailDir = mController.getActivity()
53 .getDir("thumbnails", 0);
54 mMaxTabs = mController.getMaxTabs();
Michael Kolb6e4653e2010-09-27 16:22:38 -070055 mTabs = new ArrayList<Tab>(mMaxTabs);
56 mTabQueue = new ArrayList<Tab>(mMaxTabs);
The Android Open Source Project0c908882009-03-03 19:32:16 -080057 }
58
59 File getThumbnailDir() {
60 return mThumbnailDir;
61 }
62
Michael Kolb68775752010-08-19 12:42:01 -070063 /**
The Android Open Source Project0c908882009-03-03 19:32:16 -080064 * Return the current tab's main WebView. This will always return the main
65 * WebView for a given tab and not a subwindow.
66 * @return The current tab's WebView.
67 */
68 WebView getCurrentWebView() {
69 Tab t = getTab(mCurrentTab);
70 if (t == null) {
71 return null;
72 }
Grace Kloba22ac16e2009-10-07 18:00:23 -070073 return t.getWebView();
Ben Murdochbff2d602009-07-01 20:19:05 +010074 }
75
76 /**
The Android Open Source Project0c908882009-03-03 19:32:16 -080077 * Return the current tab's top-level WebView. This can return a subwindow
78 * if one exists.
79 * @return The top-level WebView of the current tab.
80 */
81 WebView getCurrentTopWebView() {
82 Tab t = getTab(mCurrentTab);
83 if (t == null) {
84 return null;
85 }
Grace Kloba22ac16e2009-10-07 18:00:23 -070086 return t.getTopWindow();
The Android Open Source Project0c908882009-03-03 19:32:16 -080087 }
88
89 /**
90 * Return the current tab's subwindow if it exists.
91 * @return The subwindow of the current tab or null if it doesn't exist.
92 */
93 WebView getCurrentSubWindow() {
94 Tab t = getTab(mCurrentTab);
95 if (t == null) {
96 return null;
97 }
Grace Kloba22ac16e2009-10-07 18:00:23 -070098 return t.getSubWebView();
The Android Open Source Project0c908882009-03-03 19:32:16 -080099 }
100
101 /**
102 * Return the tab at the specified index.
103 * @return The Tab for the specified index or null if the tab does not
104 * exist.
105 */
106 Tab getTab(int index) {
107 if (index >= 0 && index < mTabs.size()) {
108 return mTabs.get(index);
109 }
110 return null;
111 }
112
113 /**
114 * Return the current tab.
115 * @return The current tab.
116 */
117 Tab getCurrentTab() {
118 return getTab(mCurrentTab);
119 }
120
121 /**
122 * Return the current tab index.
123 * @return The current tab index
124 */
125 int getCurrentIndex() {
126 return mCurrentTab;
127 }
Michael Kolbfe251992010-07-08 15:41:55 -0700128
The Android Open Source Project0c908882009-03-03 19:32:16 -0800129 /**
130 * Given a Tab, find it's index
131 * @param Tab to find
132 * @return index of Tab or -1 if not found
133 */
134 int getTabIndex(Tab tab) {
Patrick Scottae641ac2009-04-20 13:51:49 -0400135 if (tab == null) {
136 return -1;
137 }
The Android Open Source Project0c908882009-03-03 19:32:16 -0800138 return mTabs.indexOf(tab);
139 }
140
Grace Kloba22ac16e2009-10-07 18:00:23 -0700141 boolean canCreateNewTab() {
Michael Kolb6e4653e2010-09-27 16:22:38 -0700142 return mMaxTabs != mTabs.size();
Grace Kloba22ac16e2009-10-07 18:00:23 -0700143 }
144
The Android Open Source Project0c908882009-03-03 19:32:16 -0800145 /**
Elliott Slaughtere440a882010-08-20 13:54:45 -0700146 * Returns true if there are any incognito tabs open.
147 * @return True when any incognito tabs are open, false otherwise.
148 */
149 boolean hasAnyOpenIncognitoTabs() {
150 for (Tab tab : mTabs) {
Elliott Slaughter3d6df162010-08-25 13:17:44 -0700151 if (tab.getWebView() != null && tab.getWebView().isPrivateBrowsingEnabled()) {
Elliott Slaughtere440a882010-08-20 13:54:45 -0700152 return true;
153 }
154 }
155 return false;
156 }
157
158 /**
The Android Open Source Projectf59ec872009-03-13 13:04:24 -0700159 * Create a new tab.
The Android Open Source Project0c908882009-03-03 19:32:16 -0800160 * @return The newly createTab or null if we have reached the maximum
161 * number of open tabs.
162 */
Elliott Slaughterf0f03952010-07-14 18:10:36 -0700163 Tab createNewTab(boolean closeOnExit, String appId, String url,
164 boolean privateBrowsing) {
The Android Open Source Project0c908882009-03-03 19:32:16 -0800165 int size = mTabs.size();
166 // Return false if we have maxed out on tabs
Michael Kolb6e4653e2010-09-27 16:22:38 -0700167 if (mMaxTabs == size) {
The Android Open Source Project0c908882009-03-03 19:32:16 -0800168 return null;
169 }
Elliott Slaughterf0f03952010-07-14 18:10:36 -0700170 final WebView w = createNewWebView(privateBrowsing);
Steve Block2bc69912009-07-30 14:45:13 +0100171
The Android Open Source Project0c908882009-03-03 19:32:16 -0800172 // Create a new tab and add it to the tab list
Michael Kolb8233fac2010-10-26 16:08:53 -0700173 Tab t = new Tab(mController, w, closeOnExit, appId, url);
The Android Open Source Project0c908882009-03-03 19:32:16 -0800174 mTabs.add(t);
The Android Open Source Project4e5f5872009-03-09 11:52:14 -0700175 // Initially put the tab in the background.
Grace Kloba22ac16e2009-10-07 18:00:23 -0700176 t.putInBackground();
The Android Open Source Project0c908882009-03-03 19:32:16 -0800177 return t;
178 }
179
180 /**
The Android Open Source Projectf59ec872009-03-13 13:04:24 -0700181 * Create a new tab with default values for closeOnExit(false),
Elliott Slaughterf0f03952010-07-14 18:10:36 -0700182 * appId(null), url(null), and privateBrowsing(false).
The Android Open Source Projectf59ec872009-03-13 13:04:24 -0700183 */
184 Tab createNewTab() {
Elliott Slaughterf0f03952010-07-14 18:10:36 -0700185 return createNewTab(false, null, null, false);
The Android Open Source Projectf59ec872009-03-13 13:04:24 -0700186 }
187
188 /**
Leon Scrogginsfde97462010-01-11 13:06:21 -0500189 * Remove the parent child relationships from all tabs.
190 */
191 void removeParentChildRelationShips() {
192 for (Tab tab : mTabs) {
193 tab.removeFromTree();
194 }
195 }
196
197 /**
The Android Open Source Project0c908882009-03-03 19:32:16 -0800198 * Remove the tab from the list. If the tab is the current tab shown, the
199 * last created tab will be shown.
200 * @param t The tab to be removed.
201 */
202 boolean removeTab(Tab t) {
203 if (t == null) {
204 return false;
205 }
Grace Kloba22ac16e2009-10-07 18:00:23 -0700206
Patrick Scottd944d4d2010-01-27 16:39:11 -0500207 // Grab the current tab before modifying the list.
208 Tab current = getCurrentTab();
209
210 // Remove t from our list of tabs.
211 mTabs.remove(t);
212
213 // Put the tab in the background only if it is the current one.
214 if (current == t) {
Grace Kloba22ac16e2009-10-07 18:00:23 -0700215 t.putInBackground();
216 mCurrentTab = -1;
Patrick Scottd944d4d2010-01-27 16:39:11 -0500217 } else {
218 // If a tab that is earlier in the list gets removed, the current
219 // index no longer points to the correct tab.
220 mCurrentTab = getTabIndex(current);
The Android Open Source Project0c908882009-03-03 19:32:16 -0800221 }
222
Grace Kloba22ac16e2009-10-07 18:00:23 -0700223 // destroy the tab
224 t.destroy();
The Android Open Source Project0c908882009-03-03 19:32:16 -0800225 // clear it's references to parent and children
226 t.removeFromTree();
The Android Open Source Project0c908882009-03-03 19:32:16 -0800227
228 // The tab indices have shifted, update all the saved state so we point
229 // to the correct index.
230 for (Tab tab : mTabs) {
Grace Kloba22ac16e2009-10-07 18:00:23 -0700231 Vector<Tab> children = tab.getChildTabs();
232 if (children != null) {
233 for (Tab child : children) {
The Android Open Source Project0c908882009-03-03 19:32:16 -0800234 child.setParentTab(tab);
235 }
236 }
237 }
238
The Android Open Source Project0c908882009-03-03 19:32:16 -0800239 // Remove it from the queue of viewed tabs.
240 mTabQueue.remove(t);
The Android Open Source Project0c908882009-03-03 19:32:16 -0800241 return true;
242 }
243
244 /**
The Android Open Source Project0c908882009-03-03 19:32:16 -0800245 * Destroy all the tabs and subwindows
246 */
247 void destroy() {
The Android Open Source Project0c908882009-03-03 19:32:16 -0800248 for (Tab t : mTabs) {
Grace Kloba22ac16e2009-10-07 18:00:23 -0700249 t.destroy();
The Android Open Source Project0c908882009-03-03 19:32:16 -0800250 }
251 mTabs.clear();
252 mTabQueue.clear();
253 }
254
255 /**
256 * Returns the number of tabs created.
257 * @return The number of tabs created.
258 */
259 int getTabCount() {
260 return mTabs.size();
261 }
262
The Android Open Source Project0c908882009-03-03 19:32:16 -0800263
264 /**
265 * Save the state of all the Tabs.
266 * @param outState The Bundle to save the state to.
267 */
268 void saveState(Bundle outState) {
269 final int numTabs = getTabCount();
Grace Kloba22ac16e2009-10-07 18:00:23 -0700270 outState.putInt(Tab.NUMTABS, numTabs);
The Android Open Source Project0c908882009-03-03 19:32:16 -0800271 final int index = getCurrentIndex();
Grace Kloba22ac16e2009-10-07 18:00:23 -0700272 outState.putInt(Tab.CURRTAB, (index >= 0 && index < numTabs) ? index : 0);
The Android Open Source Project0c908882009-03-03 19:32:16 -0800273 for (int i = 0; i < numTabs; i++) {
274 final Tab t = getTab(i);
Grace Kloba22ac16e2009-10-07 18:00:23 -0700275 if (t.saveState()) {
276 outState.putBundle(Tab.WEBVIEW + i, t.getSavedState());
The Android Open Source Project0c908882009-03-03 19:32:16 -0800277 }
278 }
279 }
280
281 /**
282 * Restore the state of all the tabs.
283 * @param inState The saved state of all the tabs.
284 * @return True if there were previous tabs that were restored. False if
285 * there was no saved state or restoring the state failed.
286 */
Elliott Slaughter3d6df162010-08-25 13:17:44 -0700287 boolean restoreState(Bundle inState, boolean dontRestoreIncognitoTabs) {
The Android Open Source Project0c908882009-03-03 19:32:16 -0800288 final int numTabs = (inState == null)
Grace Kloba22ac16e2009-10-07 18:00:23 -0700289 ? -1 : inState.getInt(Tab.NUMTABS, -1);
The Android Open Source Project0c908882009-03-03 19:32:16 -0800290 if (numTabs == -1) {
291 return false;
292 } else {
Elliott Slaughter3d6df162010-08-25 13:17:44 -0700293 final int oldCurrentTab = inState.getInt(Tab.CURRTAB, -1);
294
295 // Determine whether the saved current tab can be restored, and
296 // if not, which tab will take its place.
297 int currentTab = -1;
298 if (!dontRestoreIncognitoTabs
299 || !inState.getBundle(Tab.WEBVIEW + oldCurrentTab).getBoolean(Tab.INCOGNITO)) {
300 currentTab = oldCurrentTab;
301 } else {
302 for (int i = 0; i < numTabs; i++) {
303 if (!inState.getBundle(Tab.WEBVIEW + i).getBoolean(Tab.INCOGNITO)) {
304 currentTab = i;
305 break;
306 }
307 }
308 }
309 if (currentTab < 0) {
310 return false;
311 }
312
313 // Map saved tab indices to new indices, in case any incognito tabs
314 // need to not be restored.
315 HashMap<Integer, Integer> originalTabIndices = new HashMap<Integer, Integer>();
316 originalTabIndices.put(-1, -1);
The Android Open Source Project0c908882009-03-03 19:32:16 -0800317 for (int i = 0; i < numTabs; i++) {
Elliott Slaughter3d6df162010-08-25 13:17:44 -0700318 Bundle state = inState.getBundle(Tab.WEBVIEW + i);
319
320 if (dontRestoreIncognitoTabs && state != null && state.getBoolean(Tab.INCOGNITO)) {
321 originalTabIndices.put(i, -1);
322 } else if (i == currentTab) {
The Android Open Source Projectf59ec872009-03-13 13:04:24 -0700323 Tab t = createNewTab();
The Android Open Source Project0c908882009-03-03 19:32:16 -0800324 // Me must set the current tab before restoring the state
325 // so that all the client classes are set.
326 setCurrentTab(t);
Elliott Slaughter3d6df162010-08-25 13:17:44 -0700327 if (!t.restoreState(state)) {
The Android Open Source Project0c908882009-03-03 19:32:16 -0800328 Log.w(LOGTAG, "Fail in restoreState, load home page.");
Grace Kloba22ac16e2009-10-07 18:00:23 -0700329 t.getWebView().loadUrl(BrowserSettings.getInstance()
The Android Open Source Project0c908882009-03-03 19:32:16 -0800330 .getHomePage());
331 }
Elliott Slaughter3d6df162010-08-25 13:17:44 -0700332 originalTabIndices.put(i, getTabCount() - 1);
The Android Open Source Project0c908882009-03-03 19:32:16 -0800333 } else {
334 // Create a new tab and don't restore the state yet, add it
335 // to the tab list
Michael Kolb8233fac2010-10-26 16:08:53 -0700336 Tab t = new Tab(mController, null, false, null, null);
Grace Kloba22ac16e2009-10-07 18:00:23 -0700337 if (state != null) {
338 t.setSavedState(state);
339 t.populatePickerDataFromSavedState();
The Android Open Source Projectf59ec872009-03-13 13:04:24 -0700340 // Need to maintain the app id and original url so we
341 // can possibly reuse this tab.
Grace Kloba22ac16e2009-10-07 18:00:23 -0700342 t.setAppId(state.getString(Tab.APPID));
343 t.setOriginalUrl(state.getString(Tab.ORIGINALURL));
The Android Open Source Project0c908882009-03-03 19:32:16 -0800344 }
345 mTabs.add(t);
Grace Klobaf56f68d2010-04-11 22:53:42 -0700346 // added the tab to the front as they are not current
347 mTabQueue.add(0, t);
Elliott Slaughter3d6df162010-08-25 13:17:44 -0700348 originalTabIndices.put(i, getTabCount() - 1);
The Android Open Source Project0c908882009-03-03 19:32:16 -0800349 }
350 }
Elliott Slaughter3d6df162010-08-25 13:17:44 -0700351
The Android Open Source Project0c908882009-03-03 19:32:16 -0800352 // Rebuild the tree of tabs. Do this after all tabs have been
353 // created/restored so that the parent tab exists.
354 for (int i = 0; i < numTabs; i++) {
Grace Kloba22ac16e2009-10-07 18:00:23 -0700355 final Bundle b = inState.getBundle(Tab.WEBVIEW + i);
The Android Open Source Project0c908882009-03-03 19:32:16 -0800356 final Tab t = getTab(i);
357 if (b != null && t != null) {
Elliott Slaughter3d6df162010-08-25 13:17:44 -0700358 final Integer parentIndex = originalTabIndices.get(b.getInt(Tab.PARENTTAB, -1));
The Android Open Source Project0c908882009-03-03 19:32:16 -0800359 if (parentIndex != -1) {
360 final Tab parent = getTab(parentIndex);
361 if (parent != null) {
362 parent.addChildTab(t);
363 }
364 }
365 }
366 }
367 }
368 return true;
369 }
370
371 /**
Grace Klobaf56f68d2010-04-11 22:53:42 -0700372 * Free the memory in this order, 1) free the background tabs; 2) free the
The Android Open Source Project0c908882009-03-03 19:32:16 -0800373 * WebView cache;
374 */
375 void freeMemory() {
Grace Kloba92c18a52009-07-31 23:48:32 -0700376 if (getTabCount() == 0) return;
377
Grace Klobaf56f68d2010-04-11 22:53:42 -0700378 // free the least frequently used background tabs
379 Vector<Tab> tabs = getHalfLeastUsedTabs(getCurrentTab());
380 if (tabs.size() > 0) {
381 Log.w(LOGTAG, "Free " + tabs.size() + " tabs in the browser");
382 for (Tab t : tabs) {
383 // store the WebView's state.
384 t.saveState();
385 // destroy the tab
386 t.destroy();
387 }
The Android Open Source Project0c908882009-03-03 19:32:16 -0800388 return;
389 }
390
Derek Sollenberger4433d032009-06-10 15:37:21 -0400391 // free the WebView's unused memory (this includes the cache)
392 Log.w(LOGTAG, "Free WebView's unused memory and cache");
The Android Open Source Project0c908882009-03-03 19:32:16 -0800393 WebView view = getCurrentWebView();
394 if (view != null) {
Derek Sollenberger4433d032009-06-10 15:37:21 -0400395 view.freeMemory();
The Android Open Source Project0c908882009-03-03 19:32:16 -0800396 }
The Android Open Source Project0c908882009-03-03 19:32:16 -0800397 }
398
Grace Klobaf56f68d2010-04-11 22:53:42 -0700399 private Vector<Tab> getHalfLeastUsedTabs(Tab current) {
400 Vector<Tab> tabsToGo = new Vector<Tab>();
401
Patrick Scott2a67de42009-08-31 09:48:37 -0400402 // Don't do anything if we only have 1 tab or if the current tab is
403 // null.
404 if (getTabCount() == 1 || current == null) {
Grace Klobaf56f68d2010-04-11 22:53:42 -0700405 return tabsToGo;
The Android Open Source Project0c908882009-03-03 19:32:16 -0800406 }
407
Grace Klobaf56f68d2010-04-11 22:53:42 -0700408 if (mTabQueue.size() == 0) {
409 return tabsToGo;
The Android Open Source Project0c908882009-03-03 19:32:16 -0800410 }
411
Grace Klobaf56f68d2010-04-11 22:53:42 -0700412 // Rip through the queue starting at the beginning and tear down half of
413 // available tabs which are not the current tab or the parent of the
414 // current tab.
415 int openTabCount = 0;
416 for (Tab t : mTabQueue) {
417 if (t != null && t.getWebView() != null) {
418 openTabCount++;
419 if (t != current && t != current.getParentTab()) {
420 tabsToGo.add(t);
421 }
422 }
423 }
424
425 openTabCount /= 2;
426 if (tabsToGo.size() > openTabCount) {
427 tabsToGo.setSize(openTabCount);
428 }
429
430 return tabsToGo;
The Android Open Source Project0c908882009-03-03 19:32:16 -0800431 }
432
The Android Open Source Project0c908882009-03-03 19:32:16 -0800433 /**
434 * Show the tab that contains the given WebView.
435 * @param view The WebView used to find the tab.
436 */
437 Tab getTabFromView(WebView view) {
438 final int size = getTabCount();
439 for (int i = 0; i < size; i++) {
440 final Tab t = getTab(i);
Grace Kloba22ac16e2009-10-07 18:00:23 -0700441 if (t.getSubWebView() == view || t.getWebView() == view) {
The Android Open Source Project0c908882009-03-03 19:32:16 -0800442 return t;
443 }
444 }
445 return null;
446 }
447
448 /**
The Android Open Source Projectf59ec872009-03-13 13:04:24 -0700449 * Return the tab with the matching application id.
450 * @param id The application identifier.
451 */
452 Tab getTabFromId(String id) {
453 if (id == null) {
454 return null;
455 }
456 final int size = getTabCount();
457 for (int i = 0; i < size; i++) {
458 final Tab t = getTab(i);
Grace Kloba22ac16e2009-10-07 18:00:23 -0700459 if (id.equals(t.getAppId())) {
The Android Open Source Projectf59ec872009-03-13 13:04:24 -0700460 return t;
461 }
462 }
463 return null;
464 }
465
Grace Kloba22ac16e2009-10-07 18:00:23 -0700466 /**
467 * Stop loading in all opened WebView including subWindows.
468 */
Grace Kloba5d0e02e2009-10-05 15:15:36 -0700469 void stopAllLoading() {
470 final int size = getTabCount();
471 for (int i = 0; i < size; i++) {
Grace Kloba22ac16e2009-10-07 18:00:23 -0700472 final Tab t = getTab(i);
473 final WebView webview = t.getWebView();
Grace Kloba5d0e02e2009-10-05 15:15:36 -0700474 if (webview != null) {
475 webview.stopLoading();
476 }
Grace Kloba22ac16e2009-10-07 18:00:23 -0700477 final WebView subview = t.getSubWebView();
478 if (subview != null) {
479 webview.stopLoading();
480 }
Grace Kloba5d0e02e2009-10-05 15:15:36 -0700481 }
482 }
483
Patrick Scottcd115892009-07-16 09:42:58 -0400484 // This method checks if a non-app tab (one created within the browser)
485 // matches the given url.
486 private boolean tabMatchesUrl(Tab t, String url) {
Grace Kloba22ac16e2009-10-07 18:00:23 -0700487 if (t.getAppId() != null) {
Patrick Scottcd115892009-07-16 09:42:58 -0400488 return false;
Grace Kloba22ac16e2009-10-07 18:00:23 -0700489 }
490 WebView webview = t.getWebView();
491 if (webview == null) {
Patrick Scottcd115892009-07-16 09:42:58 -0400492 return false;
Grace Kloba22ac16e2009-10-07 18:00:23 -0700493 } else if (url.equals(webview.getUrl())
494 || url.equals(webview.getOriginalUrl())) {
Patrick Scottcd115892009-07-16 09:42:58 -0400495 return true;
496 }
497 return false;
498 }
499
500 /**
501 * Return the tab that has no app id associated with it and the url of the
502 * tab matches the given url.
503 * @param url The url to search for.
504 */
505 Tab findUnusedTabWithUrl(String url) {
506 if (url == null) {
507 return null;
508 }
509 // Check the current tab first.
510 Tab t = getCurrentTab();
511 if (t != null && tabMatchesUrl(t, url)) {
512 return t;
513 }
514 // Now check all the rest.
515 final int size = getTabCount();
516 for (int i = 0; i < size; i++) {
517 t = getTab(i);
518 if (tabMatchesUrl(t, url)) {
519 return t;
520 }
521 }
522 return null;
523 }
524
The Android Open Source Projectf59ec872009-03-13 13:04:24 -0700525 /**
526 * Recreate the main WebView of the given tab. Returns true if the WebView
Leon Scroggins6eac63e2010-03-15 18:19:14 -0400527 * requires a load, whether it was due to the fact that it was deleted, or
528 * it is because it was a voice search.
The Android Open Source Projectf59ec872009-03-13 13:04:24 -0700529 */
Michael Kolb8233fac2010-10-26 16:08:53 -0700530 boolean recreateWebView(Tab t, UrlData urlData) {
Leon Scroggins6eac63e2010-03-15 18:19:14 -0400531 final String url = urlData.mUrl;
Grace Kloba22ac16e2009-10-07 18:00:23 -0700532 final WebView w = t.getWebView();
The Android Open Source Projectf59ec872009-03-13 13:04:24 -0700533 if (w != null) {
Leon Scroggins47208682010-04-07 17:59:48 -0400534 if (url != null && url.equals(t.getOriginalUrl())
535 // Treat a voice intent as though it is a different URL,
536 // since it most likely is.
537 && urlData.mVoiceIntent == null) {
The Android Open Source Projectf59ec872009-03-13 13:04:24 -0700538 // The original url matches the current url. Just go back to the
539 // first history item so we can load it faster than if we
540 // rebuilt the WebView.
541 final WebBackForwardList list = w.copyBackForwardList();
542 if (list != null) {
543 w.goBackOrForward(-list.getCurrentIndex());
544 w.clearHistory(); // maintains the current page.
545 return false;
546 }
547 }
Grace Kloba22ac16e2009-10-07 18:00:23 -0700548 t.destroy();
The Android Open Source Projectf59ec872009-03-13 13:04:24 -0700549 }
550 // Create a new WebView. If this tab is the current tab, we need to put
551 // back all the clients so force it to be the current tab.
Steve Block2bc69912009-07-30 14:45:13 +0100552 t.setWebView(createNewWebView());
The Android Open Source Projectf59ec872009-03-13 13:04:24 -0700553 if (getCurrentTab() == t) {
554 setCurrentTab(t, true);
555 }
Grace Kloba22ac16e2009-10-07 18:00:23 -0700556 // Clear the saved state and picker data
557 t.setSavedState(null);
558 t.clearPickerData();
The Android Open Source Projectf59ec872009-03-13 13:04:24 -0700559 // Save the new url in order to avoid deleting the WebView.
Grace Kloba22ac16e2009-10-07 18:00:23 -0700560 t.setOriginalUrl(url);
The Android Open Source Projectf59ec872009-03-13 13:04:24 -0700561 return true;
562 }
563
564 /**
565 * Creates a new WebView and registers it with the global settings.
566 */
567 private WebView createNewWebView() {
Elliott Slaughterf0f03952010-07-14 18:10:36 -0700568 return createNewWebView(false);
569 }
570
571 /**
572 * Creates a new WebView and registers it with the global settings.
573 * @param privateBrowsing When true, enables private browsing in the new
574 * WebView.
575 */
576 private WebView createNewWebView(boolean privateBrowsing) {
Michael Kolb8233fac2010-10-26 16:08:53 -0700577 return mController.getWebViewFactory().createWebView(privateBrowsing);
The Android Open Source Projectf59ec872009-03-13 13:04:24 -0700578 }
579
580 /**
The Android Open Source Project0c908882009-03-03 19:32:16 -0800581 * Put the current tab in the background and set newTab as the current tab.
582 * @param newTab The new tab. If newTab is null, the current tab is not
583 * set.
584 */
585 boolean setCurrentTab(Tab newTab) {
The Android Open Source Projectf59ec872009-03-13 13:04:24 -0700586 return setCurrentTab(newTab, false);
587 }
588
Grace Kloba22ac16e2009-10-07 18:00:23 -0700589 void pauseCurrentTab() {
Mike Reed7bfa63b2009-05-28 11:08:32 -0400590 Tab t = getCurrentTab();
591 if (t != null) {
Grace Kloba22ac16e2009-10-07 18:00:23 -0700592 t.pause();
Mike Reed7bfa63b2009-05-28 11:08:32 -0400593 }
594 }
595
Grace Kloba22ac16e2009-10-07 18:00:23 -0700596 void resumeCurrentTab() {
Mike Reed7bfa63b2009-05-28 11:08:32 -0400597 Tab t = getCurrentTab();
598 if (t != null) {
Grace Kloba22ac16e2009-10-07 18:00:23 -0700599 t.resume();
Mike Reed7bfa63b2009-05-28 11:08:32 -0400600 }
601 }
602
The Android Open Source Projectf59ec872009-03-13 13:04:24 -0700603 /**
604 * If force is true, this method skips the check for newTab == current.
605 */
606 private boolean setCurrentTab(Tab newTab, boolean force) {
The Android Open Source Project0c908882009-03-03 19:32:16 -0800607 Tab current = getTab(mCurrentTab);
The Android Open Source Projectf59ec872009-03-13 13:04:24 -0700608 if (current == newTab && !force) {
The Android Open Source Project0c908882009-03-03 19:32:16 -0800609 return true;
610 }
611 if (current != null) {
Grace Kloba22ac16e2009-10-07 18:00:23 -0700612 current.putInBackground();
613 mCurrentTab = -1;
The Android Open Source Project0c908882009-03-03 19:32:16 -0800614 }
The Android Open Source Project0c908882009-03-03 19:32:16 -0800615 if (newTab == null) {
616 return false;
617 }
618
619 // Move the newTab to the end of the queue
620 int index = mTabQueue.indexOf(newTab);
621 if (index != -1) {
622 mTabQueue.remove(index);
623 }
624 mTabQueue.add(newTab);
625
The Android Open Source Project0c908882009-03-03 19:32:16 -0800626 // Display the new current tab
627 mCurrentTab = mTabs.indexOf(newTab);
Grace Kloba22ac16e2009-10-07 18:00:23 -0700628 WebView mainView = newTab.getWebView();
The Android Open Source Project0c908882009-03-03 19:32:16 -0800629 boolean needRestore = (mainView == null);
630 if (needRestore) {
631 // Same work as in createNewTab() except don't do new Tab()
Steve Block2bc69912009-07-30 14:45:13 +0100632 mainView = createNewWebView();
633 newTab.setWebView(mainView);
The Android Open Source Project0c908882009-03-03 19:32:16 -0800634 }
Grace Kloba22ac16e2009-10-07 18:00:23 -0700635 newTab.putInForeground();
The Android Open Source Project0c908882009-03-03 19:32:16 -0800636 if (needRestore) {
637 // Have to finish setCurrentTab work before calling restoreState
Grace Kloba22ac16e2009-10-07 18:00:23 -0700638 if (!newTab.restoreState(newTab.getSavedState())) {
The Android Open Source Project0c908882009-03-03 19:32:16 -0800639 mainView.loadUrl(BrowserSettings.getInstance().getHomePage());
640 }
641 }
642 return true;
643 }
Michael Kolbfe251992010-07-08 15:41:55 -0700644
The Android Open Source Project0c908882009-03-03 19:32:16 -0800645}