blob: 1110bda3f986c775d77ac005f0c1a118c3310907 [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
John Reckd8c74522011-06-14 08:45:00 -070019import android.content.ContentResolver;
20import android.database.Cursor;
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.WebView;
The Android Open Source Project0c908882009-03-03 19:32:16 -080024
John Reckd8c74522011-06-14 08:45:00 -070025import com.android.browser.provider.BrowserProvider2.Snapshots;
26
The Android Open Source Project0c908882009-03-03 19:32:16 -080027import java.io.File;
28import java.util.ArrayList;
Elliott Slaughter3d6df162010-08-25 13:17:44 -070029import java.util.HashMap;
Michael Kolb1bf23132010-11-19 12:55:12 -080030import java.util.List;
The Android Open Source Project0c908882009-03-03 19:32:16 -080031import java.util.Vector;
32
33class TabControl {
34 // Log Tag
35 private static final String LOGTAG = "TabControl";
Michael Kolbc831b632011-05-11 09:30:34 -070036
John Reckd8c74522011-06-14 08:45:00 -070037 // next Tab ID, starting at 1
38 private static long sNextId = 1;
Michael Kolbc831b632011-05-11 09:30:34 -070039
40 private static final String POSITIONS = "positions";
41 private static final String CURRENT = "current";
42
The Android Open Source Project0c908882009-03-03 19:32:16 -080043 // Maximum number of tabs.
Michael Kolb6e4653e2010-09-27 16:22:38 -070044 private int mMaxTabs;
The Android Open Source Project0c908882009-03-03 19:32:16 -080045 // Private array of WebViews that are used as tabs.
Michael Kolb6e4653e2010-09-27 16:22:38 -070046 private ArrayList<Tab> mTabs;
The Android Open Source Project0c908882009-03-03 19:32:16 -080047 // Queue of most recently viewed tabs.
Michael Kolb6e4653e2010-09-27 16:22:38 -070048 private ArrayList<Tab> mTabQueue;
The Android Open Source Project0c908882009-03-03 19:32:16 -080049 // Current position in mTabs.
50 private int mCurrentTab = -1;
Michael Kolb8233fac2010-10-26 16:08:53 -070051 // the main browser controller
52 private final Controller mController;
53
The Android Open Source Project0c908882009-03-03 19:32:16 -080054 private final File mThumbnailDir;
55
56 /**
Michael Kolb8233fac2010-10-26 16:08:53 -070057 * Construct a new TabControl object
The Android Open Source Project0c908882009-03-03 19:32:16 -080058 */
Michael Kolb8233fac2010-10-26 16:08:53 -070059 TabControl(Controller controller) {
60 mController = controller;
61 mThumbnailDir = mController.getActivity()
62 .getDir("thumbnails", 0);
63 mMaxTabs = mController.getMaxTabs();
Michael Kolb6e4653e2010-09-27 16:22:38 -070064 mTabs = new ArrayList<Tab>(mMaxTabs);
65 mTabQueue = new ArrayList<Tab>(mMaxTabs);
The Android Open Source Project0c908882009-03-03 19:32:16 -080066 }
67
Michael Kolbc831b632011-05-11 09:30:34 -070068 static long getNextId() {
69 return sNextId++;
70 }
71
The Android Open Source Project0c908882009-03-03 19:32:16 -080072 File getThumbnailDir() {
73 return mThumbnailDir;
74 }
75
Michael Kolb68775752010-08-19 12:42:01 -070076 /**
The Android Open Source Project0c908882009-03-03 19:32:16 -080077 * Return the current tab's main WebView. This will always return the main
78 * WebView for a given tab and not a subwindow.
79 * @return The current tab's WebView.
80 */
81 WebView getCurrentWebView() {
82 Tab t = getTab(mCurrentTab);
83 if (t == null) {
84 return null;
85 }
Grace Kloba22ac16e2009-10-07 18:00:23 -070086 return t.getWebView();
Ben Murdochbff2d602009-07-01 20:19:05 +010087 }
88
89 /**
The Android Open Source Project0c908882009-03-03 19:32:16 -080090 * Return the current tab's top-level WebView. This can return a subwindow
91 * if one exists.
92 * @return The top-level WebView of the current tab.
93 */
94 WebView getCurrentTopWebView() {
95 Tab t = getTab(mCurrentTab);
96 if (t == null) {
97 return null;
98 }
Grace Kloba22ac16e2009-10-07 18:00:23 -070099 return t.getTopWindow();
The Android Open Source Project0c908882009-03-03 19:32:16 -0800100 }
101
102 /**
103 * Return the current tab's subwindow if it exists.
104 * @return The subwindow of the current tab or null if it doesn't exist.
105 */
106 WebView getCurrentSubWindow() {
107 Tab t = getTab(mCurrentTab);
108 if (t == null) {
109 return null;
110 }
Grace Kloba22ac16e2009-10-07 18:00:23 -0700111 return t.getSubWebView();
The Android Open Source Project0c908882009-03-03 19:32:16 -0800112 }
113
114 /**
Michael Kolb1bf23132010-11-19 12:55:12 -0800115 * return the list of tabs
116 */
117 List<Tab> getTabs() {
118 return mTabs;
119 }
120
121 /**
Michael Kolbc831b632011-05-11 09:30:34 -0700122 * Return the tab at the specified position.
123 * @return The Tab for the specified position or null if the tab does not
The Android Open Source Project0c908882009-03-03 19:32:16 -0800124 * exist.
125 */
Michael Kolbc831b632011-05-11 09:30:34 -0700126 Tab getTab(int position) {
127 if (position >= 0 && position < mTabs.size()) {
128 return mTabs.get(position);
The Android Open Source Project0c908882009-03-03 19:32:16 -0800129 }
130 return null;
131 }
132
133 /**
134 * Return the current tab.
135 * @return The current tab.
136 */
137 Tab getCurrentTab() {
138 return getTab(mCurrentTab);
139 }
140
141 /**
Michael Kolbc831b632011-05-11 09:30:34 -0700142 * Return the current tab position.
143 * @return The current tab position
The Android Open Source Project0c908882009-03-03 19:32:16 -0800144 */
Michael Kolbc831b632011-05-11 09:30:34 -0700145 int getCurrentPosition() {
The Android Open Source Project0c908882009-03-03 19:32:16 -0800146 return mCurrentTab;
147 }
Michael Kolbfe251992010-07-08 15:41:55 -0700148
The Android Open Source Project0c908882009-03-03 19:32:16 -0800149 /**
Michael Kolbc831b632011-05-11 09:30:34 -0700150 * Given a Tab, find it's position
The Android Open Source Project0c908882009-03-03 19:32:16 -0800151 * @param Tab to find
Michael Kolbc831b632011-05-11 09:30:34 -0700152 * @return position of Tab or -1 if not found
The Android Open Source Project0c908882009-03-03 19:32:16 -0800153 */
Michael Kolbc831b632011-05-11 09:30:34 -0700154 int getTabPosition(Tab tab) {
Patrick Scottae641ac2009-04-20 13:51:49 -0400155 if (tab == null) {
156 return -1;
157 }
The Android Open Source Project0c908882009-03-03 19:32:16 -0800158 return mTabs.indexOf(tab);
159 }
160
Grace Kloba22ac16e2009-10-07 18:00:23 -0700161 boolean canCreateNewTab() {
Michael Kolb6e4653e2010-09-27 16:22:38 -0700162 return mMaxTabs != mTabs.size();
Grace Kloba22ac16e2009-10-07 18:00:23 -0700163 }
164
The Android Open Source Project0c908882009-03-03 19:32:16 -0800165 /**
Elliott Slaughtere440a882010-08-20 13:54:45 -0700166 * Returns true if there are any incognito tabs open.
167 * @return True when any incognito tabs are open, false otherwise.
168 */
169 boolean hasAnyOpenIncognitoTabs() {
170 for (Tab tab : mTabs) {
Michael Kolbc831b632011-05-11 09:30:34 -0700171 if (tab.getWebView() != null
172 && tab.getWebView().isPrivateBrowsingEnabled()) {
Elliott Slaughtere440a882010-08-20 13:54:45 -0700173 return true;
174 }
175 }
176 return false;
177 }
178
Michael Kolb14612442011-06-24 13:06:29 -0700179 void addPreloadedTab(Tab tab) {
180 tab.setId(getNextId());
181 mTabs.add(tab);
182 tab.setController(mController);
183 mController.onSetWebView(tab, tab.getWebView());
184 tab.putInBackground();
185 }
186
Elliott Slaughtere440a882010-08-20 13:54:45 -0700187 /**
The Android Open Source Projectf59ec872009-03-13 13:04:24 -0700188 * Create a new tab.
The Android Open Source Project0c908882009-03-03 19:32:16 -0800189 * @return The newly createTab or null if we have reached the maximum
190 * number of open tabs.
191 */
Michael Kolb7bcafde2011-05-09 13:55:59 -0700192 Tab createNewTab(boolean privateBrowsing) {
The Android Open Source Project0c908882009-03-03 19:32:16 -0800193 int size = mTabs.size();
194 // Return false if we have maxed out on tabs
Michael Kolb6e4653e2010-09-27 16:22:38 -0700195 if (mMaxTabs == size) {
The Android Open Source Project0c908882009-03-03 19:32:16 -0800196 return null;
197 }
Elliott Slaughterf0f03952010-07-14 18:10:36 -0700198 final WebView w = createNewWebView(privateBrowsing);
Steve Block2bc69912009-07-30 14:45:13 +0100199
The Android Open Source Project0c908882009-03-03 19:32:16 -0800200 // Create a new tab and add it to the tab list
Michael Kolb7bcafde2011-05-09 13:55:59 -0700201 Tab t = new Tab(mController, w);
Michael Kolbc831b632011-05-11 09:30:34 -0700202 t.setId(getNextId());
The Android Open Source Project0c908882009-03-03 19:32:16 -0800203 mTabs.add(t);
The Android Open Source Project4e5f5872009-03-09 11:52:14 -0700204 // Initially put the tab in the background.
Grace Kloba22ac16e2009-10-07 18:00:23 -0700205 t.putInBackground();
The Android Open Source Project0c908882009-03-03 19:32:16 -0800206 return t;
207 }
208
209 /**
The Android Open Source Projectf59ec872009-03-13 13:04:24 -0700210 * Create a new tab with default values for closeOnExit(false),
Elliott Slaughterf0f03952010-07-14 18:10:36 -0700211 * appId(null), url(null), and privateBrowsing(false).
The Android Open Source Projectf59ec872009-03-13 13:04:24 -0700212 */
213 Tab createNewTab() {
Michael Kolb7bcafde2011-05-09 13:55:59 -0700214 return createNewTab(false);
The Android Open Source Projectf59ec872009-03-13 13:04:24 -0700215 }
216
John Reckd8c74522011-06-14 08:45:00 -0700217 SnapshotTab createSnapshotTab(long snapshotId) {
218 // TODO: Don't count this against the limit
219 SnapshotTab t = new SnapshotTab(mController, snapshotId);
220 t.setId(getNextId());
221 mTabs.add(t);
222 return t;
223 }
224
The Android Open Source Projectf59ec872009-03-13 13:04:24 -0700225 /**
Leon Scrogginsfde97462010-01-11 13:06:21 -0500226 * Remove the parent child relationships from all tabs.
227 */
228 void removeParentChildRelationShips() {
229 for (Tab tab : mTabs) {
230 tab.removeFromTree();
231 }
232 }
233
234 /**
The Android Open Source Project0c908882009-03-03 19:32:16 -0800235 * Remove the tab from the list. If the tab is the current tab shown, the
236 * last created tab will be shown.
237 * @param t The tab to be removed.
238 */
239 boolean removeTab(Tab t) {
240 if (t == null) {
241 return false;
242 }
Grace Kloba22ac16e2009-10-07 18:00:23 -0700243
Patrick Scottd944d4d2010-01-27 16:39:11 -0500244 // Grab the current tab before modifying the list.
245 Tab current = getCurrentTab();
246
247 // Remove t from our list of tabs.
248 mTabs.remove(t);
249
250 // Put the tab in the background only if it is the current one.
251 if (current == t) {
Grace Kloba22ac16e2009-10-07 18:00:23 -0700252 t.putInBackground();
253 mCurrentTab = -1;
Patrick Scottd944d4d2010-01-27 16:39:11 -0500254 } else {
255 // If a tab that is earlier in the list gets removed, the current
256 // index no longer points to the correct tab.
Michael Kolbc831b632011-05-11 09:30:34 -0700257 mCurrentTab = getTabPosition(current);
The Android Open Source Project0c908882009-03-03 19:32:16 -0800258 }
259
Grace Kloba22ac16e2009-10-07 18:00:23 -0700260 // destroy the tab
261 t.destroy();
The Android Open Source Project0c908882009-03-03 19:32:16 -0800262 // clear it's references to parent and children
263 t.removeFromTree();
The Android Open Source Project0c908882009-03-03 19:32:16 -0800264
The Android Open Source Project0c908882009-03-03 19:32:16 -0800265 // Remove it from the queue of viewed tabs.
266 mTabQueue.remove(t);
The Android Open Source Project0c908882009-03-03 19:32:16 -0800267 return true;
268 }
269
270 /**
The Android Open Source Project0c908882009-03-03 19:32:16 -0800271 * Destroy all the tabs and subwindows
272 */
273 void destroy() {
The Android Open Source Project0c908882009-03-03 19:32:16 -0800274 for (Tab t : mTabs) {
Grace Kloba22ac16e2009-10-07 18:00:23 -0700275 t.destroy();
The Android Open Source Project0c908882009-03-03 19:32:16 -0800276 }
277 mTabs.clear();
278 mTabQueue.clear();
279 }
280
281 /**
282 * Returns the number of tabs created.
283 * @return The number of tabs created.
284 */
285 int getTabCount() {
286 return mTabs.size();
287 }
288
The Android Open Source Project0c908882009-03-03 19:32:16 -0800289 /**
Michael Kolbc831b632011-05-11 09:30:34 -0700290 * save the tab state:
291 * current position
292 * position sorted array of tab ids
293 * for each tab id, save the tab state
294 * @param outState
John Reckaed9c542011-05-27 16:08:53 -0700295 * @param saveImages
The Android Open Source Project0c908882009-03-03 19:32:16 -0800296 */
John Reckaed9c542011-05-27 16:08:53 -0700297 void saveState(Bundle outState, boolean saveImages) {
The Android Open Source Project0c908882009-03-03 19:32:16 -0800298 final int numTabs = getTabCount();
John Reck24f18262011-06-17 14:47:20 -0700299 if (numTabs == 0) {
300 return;
301 }
Michael Kolbc831b632011-05-11 09:30:34 -0700302 long[] ids = new long[numTabs];
303 int i = 0;
304 for (Tab tab : mTabs) {
305 ids[i++] = tab.getId();
306 if (tab.saveState()) {
John Reckaed9c542011-05-27 16:08:53 -0700307 outState.putBundle(Long.toString(tab.getId()),
308 tab.getSavedState(saveImages));
The Android Open Source Project0c908882009-03-03 19:32:16 -0800309 }
310 }
John Reck24f18262011-06-17 14:47:20 -0700311 if (!outState.isEmpty()) {
312 outState.putLongArray(POSITIONS, ids);
313 Tab current = getCurrentTab();
314 long cid = -1;
315 if (current != null) {
316 cid = current.getId();
317 }
318 outState.putLong(CURRENT, cid);
Michael Kolbdbf39812011-06-10 14:06:40 -0700319 }
The Android Open Source Project0c908882009-03-03 19:32:16 -0800320 }
321
322 /**
Patrick Scott7d50a932011-02-04 09:27:26 -0500323 * Check if the state can be restored. If the state can be restored, the
Michael Kolbc831b632011-05-11 09:30:34 -0700324 * current tab id is returned. This can be passed to restoreState below
Patrick Scott7d50a932011-02-04 09:27:26 -0500325 * in order to restore the correct tab. Otherwise, -1 is returned and the
326 * state cannot be restored.
327 */
Michael Kolbc831b632011-05-11 09:30:34 -0700328 long canRestoreState(Bundle inState, boolean restoreIncognitoTabs) {
329 final long[] ids = (inState == null) ? null : inState.getLongArray(POSITIONS);
330 if (ids == null) {
Patrick Scott7d50a932011-02-04 09:27:26 -0500331 return -1;
332 }
Michael Kolbc831b632011-05-11 09:30:34 -0700333 final long oldcurrent = inState.getLong(CURRENT);
334 long current = -1;
Patrick Scott7d50a932011-02-04 09:27:26 -0500335 if (restoreIncognitoTabs ||
Michael Kolbc831b632011-05-11 09:30:34 -0700336 !inState.getBundle(Long.toString(oldcurrent)).getBoolean(Tab.INCOGNITO)) {
337 current = oldcurrent;
Patrick Scott7d50a932011-02-04 09:27:26 -0500338 } else {
Michael Kolbc831b632011-05-11 09:30:34 -0700339 // pick first non incognito tab
340 for (long id : ids) {
341 if (!inState.getBundle(Long.toString(id)).getBoolean(Tab.INCOGNITO)) {
342 current = id;
Patrick Scott7d50a932011-02-04 09:27:26 -0500343 break;
344 }
345 }
346 }
Michael Kolbc831b632011-05-11 09:30:34 -0700347 return current;
Patrick Scott7d50a932011-02-04 09:27:26 -0500348 }
349
350 /**
The Android Open Source Project0c908882009-03-03 19:32:16 -0800351 * Restore the state of all the tabs.
Michael Kolbc831b632011-05-11 09:30:34 -0700352 * @param currentId The tab id to restore.
The Android Open Source Project0c908882009-03-03 19:32:16 -0800353 * @param inState The saved state of all the tabs.
Michael Kolb1bf23132010-11-19 12:55:12 -0800354 * @param restoreIncognitoTabs Restoring private browsing tabs
355 * @param restoreAll All webviews get restored, not just the current tab
356 * (this does not override handling of incognito tabs)
The Android Open Source Project0c908882009-03-03 19:32:16 -0800357 * @return True if there were previous tabs that were restored. False if
358 * there was no saved state or restoring the state failed.
359 */
Michael Kolbc831b632011-05-11 09:30:34 -0700360 void restoreState(Bundle inState, long currentId,
Patrick Scott7d50a932011-02-04 09:27:26 -0500361 boolean restoreIncognitoTabs, boolean restoreAll) {
Michael Kolbc831b632011-05-11 09:30:34 -0700362 if (currentId == -1) {
Patrick Scott7d50a932011-02-04 09:27:26 -0500363 return;
364 }
Michael Kolbc831b632011-05-11 09:30:34 -0700365 long[] ids = inState.getLongArray(POSITIONS);
366 long maxId = -Long.MAX_VALUE;
367 HashMap<Long, Tab> tabMap = new HashMap<Long, Tab>();
368 for (long id : ids) {
369 if (id > maxId) {
370 maxId = id;
371 }
372 final String idkey = Long.toString(id);
373 Bundle state = inState.getBundle(idkey);
John Reckd8c74522011-06-14 08:45:00 -0700374 if (state == null || state.isEmpty()) {
375 // Skip tab
376 continue;
377 } else if (!restoreIncognitoTabs
Michael Kolbc831b632011-05-11 09:30:34 -0700378 && state.getBoolean(Tab.INCOGNITO)) {
379 // ignore tab
380 } else if (id == currentId || restoreAll) {
Patrick Scott7d50a932011-02-04 09:27:26 -0500381 Tab t = createNewTab();
Michael Kolbc831b632011-05-11 09:30:34 -0700382 tabMap.put(id, t);
Patrick Scott7d50a932011-02-04 09:27:26 -0500383 // Me must set the current tab before restoring the state
384 // so that all the client classes are set.
Michael Kolbc831b632011-05-11 09:30:34 -0700385 if (id == currentId) {
Patrick Scott7d50a932011-02-04 09:27:26 -0500386 setCurrentTab(t);
387 }
388 if (!t.restoreState(state)) {
389 Log.w(LOGTAG, "Fail in restoreState, load home page.");
390 t.getWebView().loadUrl(BrowserSettings.getInstance()
391 .getHomePage());
392 }
Elliott Slaughter3d6df162010-08-25 13:17:44 -0700393 } else {
Patrick Scott7d50a932011-02-04 09:27:26 -0500394 // Create a new tab and don't restore the state yet, add it
395 // to the tab list
Michael Kolb7bcafde2011-05-09 13:55:59 -0700396 Tab t = new Tab(mController, null);
Michael Kolbc831b632011-05-11 09:30:34 -0700397 t.setId(id);
398 tabMap.put(id, t);
Patrick Scott7d50a932011-02-04 09:27:26 -0500399 if (state != null) {
400 t.setSavedState(state);
401 // Need to maintain the app id and original url so we
402 // can possibly reuse this tab.
403 t.setAppId(state.getString(Tab.APPID));
Elliott Slaughter3d6df162010-08-25 13:17:44 -0700404 }
Patrick Scott7d50a932011-02-04 09:27:26 -0500405 mTabs.add(t);
406 // added the tab to the front as they are not current
407 mTabQueue.add(0, t);
Elliott Slaughter3d6df162010-08-25 13:17:44 -0700408 }
Michael Kolbc831b632011-05-11 09:30:34 -0700409 // make sure that there is no id overlap between the restored
410 // and new tabs
411 sNextId = maxId + 1;
Elliott Slaughter3d6df162010-08-25 13:17:44 -0700412
Michael Kolbc831b632011-05-11 09:30:34 -0700413 }
John Reckd8c74522011-06-14 08:45:00 -0700414 if (mCurrentTab == -1) {
415 if (getTabCount() > 0) {
416 setCurrentTab(getTab(0));
417 } else {
418 Tab t = createNewTab();
419 setCurrentTab(t);
420 t.getWebView().loadUrl(BrowserSettings.getInstance()
421 .getHomePage());
422 }
423 }
Michael Kolbc831b632011-05-11 09:30:34 -0700424 // restore parent/child relationships
425 for (long id : ids) {
426 final Tab tab = tabMap.get(id);
427 final Bundle b = inState.getBundle(Long.toString(id));
428 if ((b != null) && (tab != null)) {
429 final long parentId = b.getLong(Tab.PARENTTAB, -1);
430 if (parentId != -1) {
431 final Tab parent = tabMap.get(parentId);
Patrick Scott7d50a932011-02-04 09:27:26 -0500432 if (parent != null) {
Michael Kolbc831b632011-05-11 09:30:34 -0700433 parent.addChildTab(tab);
The Android Open Source Project0c908882009-03-03 19:32:16 -0800434 }
435 }
436 }
437 }
John Reckd8c74522011-06-14 08:45:00 -0700438 loadSnapshotTabs();
439
440 }
441
442 void loadSnapshotTabs() {
443 ContentResolver cr = mController.getActivity().getContentResolver();
444 Cursor c = cr.query(Snapshots.CONTENT_URI, new String[] { "_id" },
445 null, null, null);
446 try {
447 while (c.moveToNext()) {
448 createSnapshotTab(c.getLong(0));
449 }
450 } finally {
451 c.close();
452 }
The Android Open Source Project0c908882009-03-03 19:32:16 -0800453 }
454
455 /**
Grace Klobaf56f68d2010-04-11 22:53:42 -0700456 * Free the memory in this order, 1) free the background tabs; 2) free the
The Android Open Source Project0c908882009-03-03 19:32:16 -0800457 * WebView cache;
458 */
459 void freeMemory() {
Grace Kloba92c18a52009-07-31 23:48:32 -0700460 if (getTabCount() == 0) return;
461
Grace Klobaf56f68d2010-04-11 22:53:42 -0700462 // free the least frequently used background tabs
463 Vector<Tab> tabs = getHalfLeastUsedTabs(getCurrentTab());
464 if (tabs.size() > 0) {
465 Log.w(LOGTAG, "Free " + tabs.size() + " tabs in the browser");
466 for (Tab t : tabs) {
467 // store the WebView's state.
468 t.saveState();
469 // destroy the tab
470 t.destroy();
471 }
The Android Open Source Project0c908882009-03-03 19:32:16 -0800472 return;
473 }
474
Derek Sollenberger4433d032009-06-10 15:37:21 -0400475 // free the WebView's unused memory (this includes the cache)
476 Log.w(LOGTAG, "Free WebView's unused memory and cache");
The Android Open Source Project0c908882009-03-03 19:32:16 -0800477 WebView view = getCurrentWebView();
478 if (view != null) {
Derek Sollenberger4433d032009-06-10 15:37:21 -0400479 view.freeMemory();
The Android Open Source Project0c908882009-03-03 19:32:16 -0800480 }
The Android Open Source Project0c908882009-03-03 19:32:16 -0800481 }
482
Grace Klobaf56f68d2010-04-11 22:53:42 -0700483 private Vector<Tab> getHalfLeastUsedTabs(Tab current) {
484 Vector<Tab> tabsToGo = new Vector<Tab>();
485
Patrick Scott2a67de42009-08-31 09:48:37 -0400486 // Don't do anything if we only have 1 tab or if the current tab is
487 // null.
488 if (getTabCount() == 1 || current == null) {
Grace Klobaf56f68d2010-04-11 22:53:42 -0700489 return tabsToGo;
The Android Open Source Project0c908882009-03-03 19:32:16 -0800490 }
491
Grace Klobaf56f68d2010-04-11 22:53:42 -0700492 if (mTabQueue.size() == 0) {
493 return tabsToGo;
The Android Open Source Project0c908882009-03-03 19:32:16 -0800494 }
495
Grace Klobaf56f68d2010-04-11 22:53:42 -0700496 // Rip through the queue starting at the beginning and tear down half of
497 // available tabs which are not the current tab or the parent of the
498 // current tab.
499 int openTabCount = 0;
500 for (Tab t : mTabQueue) {
501 if (t != null && t.getWebView() != null) {
502 openTabCount++;
Michael Kolbc831b632011-05-11 09:30:34 -0700503 if (t != current && t != current.getParent()) {
Grace Klobaf56f68d2010-04-11 22:53:42 -0700504 tabsToGo.add(t);
505 }
506 }
507 }
508
509 openTabCount /= 2;
510 if (tabsToGo.size() > openTabCount) {
511 tabsToGo.setSize(openTabCount);
512 }
513
514 return tabsToGo;
The Android Open Source Project0c908882009-03-03 19:32:16 -0800515 }
516
The Android Open Source Project0c908882009-03-03 19:32:16 -0800517 /**
518 * Show the tab that contains the given WebView.
519 * @param view The WebView used to find the tab.
520 */
521 Tab getTabFromView(WebView view) {
Michael Kolbc831b632011-05-11 09:30:34 -0700522 for (Tab t : mTabs) {
Grace Kloba22ac16e2009-10-07 18:00:23 -0700523 if (t.getSubWebView() == view || t.getWebView() == view) {
The Android Open Source Project0c908882009-03-03 19:32:16 -0800524 return t;
525 }
526 }
527 return null;
528 }
529
530 /**
The Android Open Source Projectf59ec872009-03-13 13:04:24 -0700531 * Return the tab with the matching application id.
532 * @param id The application identifier.
533 */
Michael Kolbc831b632011-05-11 09:30:34 -0700534 Tab getTabFromAppId(String id) {
The Android Open Source Projectf59ec872009-03-13 13:04:24 -0700535 if (id == null) {
536 return null;
537 }
Michael Kolbc831b632011-05-11 09:30:34 -0700538 for (Tab t : mTabs) {
Grace Kloba22ac16e2009-10-07 18:00:23 -0700539 if (id.equals(t.getAppId())) {
The Android Open Source Projectf59ec872009-03-13 13:04:24 -0700540 return t;
541 }
542 }
543 return null;
544 }
545
Grace Kloba22ac16e2009-10-07 18:00:23 -0700546 /**
547 * Stop loading in all opened WebView including subWindows.
548 */
Grace Kloba5d0e02e2009-10-05 15:15:36 -0700549 void stopAllLoading() {
Michael Kolbc831b632011-05-11 09:30:34 -0700550 for (Tab t : mTabs) {
Grace Kloba22ac16e2009-10-07 18:00:23 -0700551 final WebView webview = t.getWebView();
Grace Kloba5d0e02e2009-10-05 15:15:36 -0700552 if (webview != null) {
553 webview.stopLoading();
554 }
Grace Kloba22ac16e2009-10-07 18:00:23 -0700555 final WebView subview = t.getSubWebView();
556 if (subview != null) {
557 webview.stopLoading();
558 }
Grace Kloba5d0e02e2009-10-05 15:15:36 -0700559 }
560 }
561
John Reckdb22ec42011-06-29 11:31:24 -0700562 // This method checks if a tab matches the given url.
Patrick Scottcd115892009-07-16 09:42:58 -0400563 private boolean tabMatchesUrl(Tab t, String url) {
John Reckdb22ec42011-06-29 11:31:24 -0700564 return url.equals(t.getUrl()) || url.equals(t.getOriginalUrl());
Patrick Scottcd115892009-07-16 09:42:58 -0400565 }
566
567 /**
John Reckdb22ec42011-06-29 11:31:24 -0700568 * Return the tab that matches the given url.
Patrick Scottcd115892009-07-16 09:42:58 -0400569 * @param url The url to search for.
570 */
John Reckdb22ec42011-06-29 11:31:24 -0700571 Tab findTabWithUrl(String url) {
Patrick Scottcd115892009-07-16 09:42:58 -0400572 if (url == null) {
573 return null;
574 }
575 // Check the current tab first.
John Reckdb22ec42011-06-29 11:31:24 -0700576 Tab currentTab = getCurrentTab();
577 if (currentTab != null && tabMatchesUrl(currentTab, url)) {
578 return currentTab;
Patrick Scottcd115892009-07-16 09:42:58 -0400579 }
580 // Now check all the rest.
Michael Kolbc831b632011-05-11 09:30:34 -0700581 for (Tab tab : mTabs) {
582 if (tabMatchesUrl(tab, url)) {
John Reckdb22ec42011-06-29 11:31:24 -0700583 return tab;
Patrick Scottcd115892009-07-16 09:42:58 -0400584 }
585 }
586 return null;
587 }
588
The Android Open Source Projectf59ec872009-03-13 13:04:24 -0700589 /**
John Reck30c714c2010-12-16 17:30:34 -0800590 * Recreate the main WebView of the given tab.
The Android Open Source Projectf59ec872009-03-13 13:04:24 -0700591 */
John Reck30c714c2010-12-16 17:30:34 -0800592 void recreateWebView(Tab t) {
Grace Kloba22ac16e2009-10-07 18:00:23 -0700593 final WebView w = t.getWebView();
The Android Open Source Projectf59ec872009-03-13 13:04:24 -0700594 if (w != null) {
Grace Kloba22ac16e2009-10-07 18:00:23 -0700595 t.destroy();
The Android Open Source Projectf59ec872009-03-13 13:04:24 -0700596 }
597 // Create a new WebView. If this tab is the current tab, we need to put
598 // back all the clients so force it to be the current tab.
Steve Block2bc69912009-07-30 14:45:13 +0100599 t.setWebView(createNewWebView());
The Android Open Source Projectf59ec872009-03-13 13:04:24 -0700600 if (getCurrentTab() == t) {
601 setCurrentTab(t, true);
602 }
Grace Kloba22ac16e2009-10-07 18:00:23 -0700603 // Clear the saved state and picker data
604 t.setSavedState(null);
The Android Open Source Projectf59ec872009-03-13 13:04:24 -0700605 }
606
607 /**
608 * Creates a new WebView and registers it with the global settings.
609 */
610 private WebView createNewWebView() {
Elliott Slaughterf0f03952010-07-14 18:10:36 -0700611 return createNewWebView(false);
612 }
613
614 /**
615 * Creates a new WebView and registers it with the global settings.
616 * @param privateBrowsing When true, enables private browsing in the new
617 * WebView.
618 */
619 private WebView createNewWebView(boolean privateBrowsing) {
Michael Kolb8233fac2010-10-26 16:08:53 -0700620 return mController.getWebViewFactory().createWebView(privateBrowsing);
The Android Open Source Projectf59ec872009-03-13 13:04:24 -0700621 }
622
623 /**
The Android Open Source Project0c908882009-03-03 19:32:16 -0800624 * Put the current tab in the background and set newTab as the current tab.
625 * @param newTab The new tab. If newTab is null, the current tab is not
626 * set.
627 */
628 boolean setCurrentTab(Tab newTab) {
The Android Open Source Projectf59ec872009-03-13 13:04:24 -0700629 return setCurrentTab(newTab, false);
630 }
631
632 /**
633 * If force is true, this method skips the check for newTab == current.
634 */
635 private boolean setCurrentTab(Tab newTab, boolean force) {
The Android Open Source Project0c908882009-03-03 19:32:16 -0800636 Tab current = getTab(mCurrentTab);
The Android Open Source Projectf59ec872009-03-13 13:04:24 -0700637 if (current == newTab && !force) {
The Android Open Source Project0c908882009-03-03 19:32:16 -0800638 return true;
639 }
640 if (current != null) {
Grace Kloba22ac16e2009-10-07 18:00:23 -0700641 current.putInBackground();
642 mCurrentTab = -1;
The Android Open Source Project0c908882009-03-03 19:32:16 -0800643 }
The Android Open Source Project0c908882009-03-03 19:32:16 -0800644 if (newTab == null) {
645 return false;
646 }
647
648 // Move the newTab to the end of the queue
649 int index = mTabQueue.indexOf(newTab);
650 if (index != -1) {
651 mTabQueue.remove(index);
652 }
653 mTabQueue.add(newTab);
654
The Android Open Source Project0c908882009-03-03 19:32:16 -0800655 // Display the new current tab
656 mCurrentTab = mTabs.indexOf(newTab);
Grace Kloba22ac16e2009-10-07 18:00:23 -0700657 WebView mainView = newTab.getWebView();
John Reckd8c74522011-06-14 08:45:00 -0700658 boolean needRestore = !newTab.isSnapshot() && (mainView == null);
The Android Open Source Project0c908882009-03-03 19:32:16 -0800659 if (needRestore) {
660 // Same work as in createNewTab() except don't do new Tab()
Steve Block2bc69912009-07-30 14:45:13 +0100661 mainView = createNewWebView();
662 newTab.setWebView(mainView);
The Android Open Source Project0c908882009-03-03 19:32:16 -0800663 }
Grace Kloba22ac16e2009-10-07 18:00:23 -0700664 newTab.putInForeground();
The Android Open Source Project0c908882009-03-03 19:32:16 -0800665 if (needRestore) {
666 // Have to finish setCurrentTab work before calling restoreState
Grace Kloba22ac16e2009-10-07 18:00:23 -0700667 if (!newTab.restoreState(newTab.getSavedState())) {
The Android Open Source Project0c908882009-03-03 19:32:16 -0800668 mainView.loadUrl(BrowserSettings.getInstance().getHomePage());
669 }
670 }
671 return true;
672 }
Michael Kolbfe251992010-07-08 15:41:55 -0700673
The Android Open Source Project0c908882009-03-03 19:32:16 -0800674}