blob: d7435d71278374131562af2c0c0a61504ed2ad75 [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
Mike Reede5073c22010-01-29 11:31:39 -050019import android.graphics.Bitmap;
20import android.graphics.BitmapFactory;
21import android.graphics.BitmapShader;
22import android.graphics.Paint;
23import android.graphics.Shader;
The Android Open Source Project0c908882009-03-03 19:32:16 -080024import android.os.Bundle;
The Android Open Source Project0c908882009-03-03 19:32:16 -080025import android.util.Log;
The Android Open Source Project0c908882009-03-03 19:32:16 -080026import android.view.View;
The Android Open Source Project0c908882009-03-03 19:32:16 -080027import android.webkit.WebBackForwardList;
The Android Open Source Project0c908882009-03-03 19:32:16 -080028import android.webkit.WebView;
The Android Open Source Project0c908882009-03-03 19:32:16 -080029
30import java.io.File;
31import java.util.ArrayList;
Elliott Slaughter3d6df162010-08-25 13:17:44 -070032import java.util.HashMap;
The Android Open Source Project0c908882009-03-03 19:32:16 -080033import java.util.Vector;
34
35class TabControl {
36 // Log Tag
37 private static final String LOGTAG = "TabControl";
38 // Maximum number of tabs.
Grace Kloba22ac16e2009-10-07 18:00:23 -070039 private static final int MAX_TABS = 8;
The Android Open Source Project0c908882009-03-03 19:32:16 -080040 // Private array of WebViews that are used as tabs.
41 private ArrayList<Tab> mTabs = new ArrayList<Tab>(MAX_TABS);
42 // Queue of most recently viewed tabs.
43 private ArrayList<Tab> mTabQueue = new ArrayList<Tab>(MAX_TABS);
44 // Current position in mTabs.
45 private int mCurrentTab = -1;
46 // A private instance of BrowserActivity to interface with when adding and
47 // switching between tabs.
48 private final BrowserActivity mActivity;
The Android Open Source Project0c908882009-03-03 19:32:16 -080049 // Directory to store thumbnails for each WebView.
50 private final File mThumbnailDir;
Michael Kolb68775752010-08-19 12:42:01 -070051 // Use on screen zoom buttons
52 private boolean mDisplayZoomControls;
The Android Open Source Project0c908882009-03-03 19:32:16 -080053
54 /**
55 * Construct a new TabControl object that interfaces with the given
56 * BrowserActivity instance.
57 * @param activity A BrowserActivity instance that TabControl will interface
58 * with.
59 */
60 TabControl(BrowserActivity activity) {
61 mActivity = activity;
The Android Open Source Project0c908882009-03-03 19:32:16 -080062 mThumbnailDir = activity.getDir("thumbnails", 0);
Michael Kolb68775752010-08-19 12:42:01 -070063 mDisplayZoomControls = true;
The Android Open Source Project0c908882009-03-03 19:32:16 -080064 }
65
66 File getThumbnailDir() {
67 return mThumbnailDir;
68 }
69
70 BrowserActivity getBrowserActivity() {
71 return mActivity;
72 }
73
74 /**
Michael Kolb68775752010-08-19 12:42:01 -070075 * Set if the webview should use the on screen zoom controls
76 * @param enabled
77 */
78 void setDisplayZoomControls(boolean enabled) {
79 mDisplayZoomControls = enabled;
80 }
81
82 /**
The Android Open Source Project0c908882009-03-03 19:32:16 -080083 * Return the current tab's main WebView. This will always return the main
84 * WebView for a given tab and not a subwindow.
85 * @return The current tab's WebView.
86 */
87 WebView getCurrentWebView() {
88 Tab t = getTab(mCurrentTab);
89 if (t == null) {
90 return null;
91 }
Grace Kloba22ac16e2009-10-07 18:00:23 -070092 return t.getWebView();
Ben Murdochbff2d602009-07-01 20:19:05 +010093 }
94
95 /**
The Android Open Source Project0c908882009-03-03 19:32:16 -080096 * Return the current tab's top-level WebView. This can return a subwindow
97 * if one exists.
98 * @return The top-level WebView of the current tab.
99 */
100 WebView getCurrentTopWebView() {
101 Tab t = getTab(mCurrentTab);
102 if (t == null) {
103 return null;
104 }
Grace Kloba22ac16e2009-10-07 18:00:23 -0700105 return t.getTopWindow();
The Android Open Source Project0c908882009-03-03 19:32:16 -0800106 }
107
108 /**
109 * Return the current tab's subwindow if it exists.
110 * @return The subwindow of the current tab or null if it doesn't exist.
111 */
112 WebView getCurrentSubWindow() {
113 Tab t = getTab(mCurrentTab);
114 if (t == null) {
115 return null;
116 }
Grace Kloba22ac16e2009-10-07 18:00:23 -0700117 return t.getSubWebView();
The Android Open Source Project0c908882009-03-03 19:32:16 -0800118 }
119
120 /**
121 * Return the tab at the specified index.
122 * @return The Tab for the specified index or null if the tab does not
123 * exist.
124 */
125 Tab getTab(int index) {
126 if (index >= 0 && index < mTabs.size()) {
127 return mTabs.get(index);
128 }
129 return null;
130 }
131
132 /**
133 * Return the current tab.
134 * @return The current tab.
135 */
136 Tab getCurrentTab() {
137 return getTab(mCurrentTab);
138 }
139
140 /**
141 * Return the current tab index.
142 * @return The current tab index
143 */
144 int getCurrentIndex() {
145 return mCurrentTab;
146 }
Michael Kolbfe251992010-07-08 15:41:55 -0700147
The Android Open Source Project0c908882009-03-03 19:32:16 -0800148 /**
149 * Given a Tab, find it's index
150 * @param Tab to find
151 * @return index of Tab or -1 if not found
152 */
153 int getTabIndex(Tab tab) {
Patrick Scottae641ac2009-04-20 13:51:49 -0400154 if (tab == null) {
155 return -1;
156 }
The Android Open Source Project0c908882009-03-03 19:32:16 -0800157 return mTabs.indexOf(tab);
158 }
159
Grace Kloba22ac16e2009-10-07 18:00:23 -0700160 boolean canCreateNewTab() {
161 return MAX_TABS != mTabs.size();
162 }
163
The Android Open Source Project0c908882009-03-03 19:32:16 -0800164 /**
Elliott Slaughtere440a882010-08-20 13:54:45 -0700165 * Returns true if there are any incognito tabs open.
166 * @return True when any incognito tabs are open, false otherwise.
167 */
168 boolean hasAnyOpenIncognitoTabs() {
169 for (Tab tab : mTabs) {
Elliott Slaughter3d6df162010-08-25 13:17:44 -0700170 if (tab.getWebView() != null && tab.getWebView().isPrivateBrowsingEnabled()) {
Elliott Slaughtere440a882010-08-20 13:54:45 -0700171 return true;
172 }
173 }
174 return false;
175 }
176
177 /**
The Android Open Source Projectf59ec872009-03-13 13:04:24 -0700178 * Create a new tab.
The Android Open Source Project0c908882009-03-03 19:32:16 -0800179 * @return The newly createTab or null if we have reached the maximum
180 * number of open tabs.
181 */
Elliott Slaughterf0f03952010-07-14 18:10:36 -0700182 Tab createNewTab(boolean closeOnExit, String appId, String url,
183 boolean privateBrowsing) {
The Android Open Source Project0c908882009-03-03 19:32:16 -0800184 int size = mTabs.size();
185 // Return false if we have maxed out on tabs
186 if (MAX_TABS == size) {
187 return null;
188 }
Elliott Slaughterf0f03952010-07-14 18:10:36 -0700189 final WebView w = createNewWebView(privateBrowsing);
Steve Block2bc69912009-07-30 14:45:13 +0100190
The Android Open Source Project0c908882009-03-03 19:32:16 -0800191 // Create a new tab and add it to the tab list
Grace Kloba22ac16e2009-10-07 18:00:23 -0700192 Tab t = new Tab(mActivity, w, closeOnExit, appId, url);
The Android Open Source Project0c908882009-03-03 19:32:16 -0800193 mTabs.add(t);
The Android Open Source Project4e5f5872009-03-09 11:52:14 -0700194 // Initially put the tab in the background.
Grace Kloba22ac16e2009-10-07 18:00:23 -0700195 t.putInBackground();
Michael Kolbfe251992010-07-08 15:41:55 -0700196 if (mTabChangeListener != null) {
197 mTabChangeListener.onNewTab(t);
198 }
The Android Open Source Project0c908882009-03-03 19:32:16 -0800199 return t;
200 }
201
202 /**
The Android Open Source Projectf59ec872009-03-13 13:04:24 -0700203 * Create a new tab with default values for closeOnExit(false),
Elliott Slaughterf0f03952010-07-14 18:10:36 -0700204 * appId(null), url(null), and privateBrowsing(false).
The Android Open Source Projectf59ec872009-03-13 13:04:24 -0700205 */
206 Tab createNewTab() {
Elliott Slaughterf0f03952010-07-14 18:10:36 -0700207 return createNewTab(false, null, null, false);
The Android Open Source Projectf59ec872009-03-13 13:04:24 -0700208 }
209
210 /**
Leon Scrogginsfde97462010-01-11 13:06:21 -0500211 * Remove the parent child relationships from all tabs.
212 */
213 void removeParentChildRelationShips() {
214 for (Tab tab : mTabs) {
215 tab.removeFromTree();
216 }
217 }
218
219 /**
The Android Open Source Project0c908882009-03-03 19:32:16 -0800220 * Remove the tab from the list. If the tab is the current tab shown, the
221 * last created tab will be shown.
222 * @param t The tab to be removed.
223 */
224 boolean removeTab(Tab t) {
225 if (t == null) {
226 return false;
227 }
Grace Kloba22ac16e2009-10-07 18:00:23 -0700228
Patrick Scottd944d4d2010-01-27 16:39:11 -0500229 // Grab the current tab before modifying the list.
230 Tab current = getCurrentTab();
231
232 // Remove t from our list of tabs.
233 mTabs.remove(t);
234
235 // Put the tab in the background only if it is the current one.
236 if (current == t) {
Grace Kloba22ac16e2009-10-07 18:00:23 -0700237 t.putInBackground();
238 mCurrentTab = -1;
Patrick Scottd944d4d2010-01-27 16:39:11 -0500239 } else {
240 // If a tab that is earlier in the list gets removed, the current
241 // index no longer points to the correct tab.
242 mCurrentTab = getTabIndex(current);
The Android Open Source Project0c908882009-03-03 19:32:16 -0800243 }
244
Grace Kloba22ac16e2009-10-07 18:00:23 -0700245 // destroy the tab
246 t.destroy();
The Android Open Source Project0c908882009-03-03 19:32:16 -0800247 // clear it's references to parent and children
248 t.removeFromTree();
The Android Open Source Project0c908882009-03-03 19:32:16 -0800249
250 // The tab indices have shifted, update all the saved state so we point
251 // to the correct index.
252 for (Tab tab : mTabs) {
Grace Kloba22ac16e2009-10-07 18:00:23 -0700253 Vector<Tab> children = tab.getChildTabs();
254 if (children != null) {
255 for (Tab child : children) {
The Android Open Source Project0c908882009-03-03 19:32:16 -0800256 child.setParentTab(tab);
257 }
258 }
259 }
260
The Android Open Source Project0c908882009-03-03 19:32:16 -0800261 // Remove it from the queue of viewed tabs.
262 mTabQueue.remove(t);
Michael Kolbfe251992010-07-08 15:41:55 -0700263 if (mTabChangeListener != null) {
264 mTabChangeListener.onRemoveTab(t);
265 }
The Android Open Source Project0c908882009-03-03 19:32:16 -0800266 return true;
267 }
268
269 /**
The Android Open Source Project0c908882009-03-03 19:32:16 -0800270 * Destroy all the tabs and subwindows
271 */
272 void destroy() {
The Android Open Source Project0c908882009-03-03 19:32:16 -0800273 for (Tab t : mTabs) {
Grace Kloba22ac16e2009-10-07 18:00:23 -0700274 t.destroy();
The Android Open Source Project0c908882009-03-03 19:32:16 -0800275 }
276 mTabs.clear();
277 mTabQueue.clear();
278 }
279
280 /**
281 * Returns the number of tabs created.
282 * @return The number of tabs created.
283 */
284 int getTabCount() {
285 return mTabs.size();
286 }
287
The Android Open Source Project0c908882009-03-03 19:32:16 -0800288
289 /**
290 * Save the state of all the Tabs.
291 * @param outState The Bundle to save the state to.
292 */
293 void saveState(Bundle outState) {
294 final int numTabs = getTabCount();
Grace Kloba22ac16e2009-10-07 18:00:23 -0700295 outState.putInt(Tab.NUMTABS, numTabs);
The Android Open Source Project0c908882009-03-03 19:32:16 -0800296 final int index = getCurrentIndex();
Grace Kloba22ac16e2009-10-07 18:00:23 -0700297 outState.putInt(Tab.CURRTAB, (index >= 0 && index < numTabs) ? index : 0);
The Android Open Source Project0c908882009-03-03 19:32:16 -0800298 for (int i = 0; i < numTabs; i++) {
299 final Tab t = getTab(i);
Grace Kloba22ac16e2009-10-07 18:00:23 -0700300 if (t.saveState()) {
301 outState.putBundle(Tab.WEBVIEW + i, t.getSavedState());
The Android Open Source Project0c908882009-03-03 19:32:16 -0800302 }
303 }
304 }
305
306 /**
307 * Restore the state of all the tabs.
308 * @param inState The saved state of all the tabs.
309 * @return True if there were previous tabs that were restored. False if
310 * there was no saved state or restoring the state failed.
311 */
Elliott Slaughter3d6df162010-08-25 13:17:44 -0700312 boolean restoreState(Bundle inState, boolean dontRestoreIncognitoTabs) {
The Android Open Source Project0c908882009-03-03 19:32:16 -0800313 final int numTabs = (inState == null)
Grace Kloba22ac16e2009-10-07 18:00:23 -0700314 ? -1 : inState.getInt(Tab.NUMTABS, -1);
The Android Open Source Project0c908882009-03-03 19:32:16 -0800315 if (numTabs == -1) {
316 return false;
317 } else {
Elliott Slaughter3d6df162010-08-25 13:17:44 -0700318 final int oldCurrentTab = inState.getInt(Tab.CURRTAB, -1);
319
320 // Determine whether the saved current tab can be restored, and
321 // if not, which tab will take its place.
322 int currentTab = -1;
323 if (!dontRestoreIncognitoTabs
324 || !inState.getBundle(Tab.WEBVIEW + oldCurrentTab).getBoolean(Tab.INCOGNITO)) {
325 currentTab = oldCurrentTab;
326 } else {
327 for (int i = 0; i < numTabs; i++) {
328 if (!inState.getBundle(Tab.WEBVIEW + i).getBoolean(Tab.INCOGNITO)) {
329 currentTab = i;
330 break;
331 }
332 }
333 }
334 if (currentTab < 0) {
335 return false;
336 }
337
338 // Map saved tab indices to new indices, in case any incognito tabs
339 // need to not be restored.
340 HashMap<Integer, Integer> originalTabIndices = new HashMap<Integer, Integer>();
341 originalTabIndices.put(-1, -1);
The Android Open Source Project0c908882009-03-03 19:32:16 -0800342 for (int i = 0; i < numTabs; i++) {
Elliott Slaughter3d6df162010-08-25 13:17:44 -0700343 Bundle state = inState.getBundle(Tab.WEBVIEW + i);
344
345 if (dontRestoreIncognitoTabs && state != null && state.getBoolean(Tab.INCOGNITO)) {
346 originalTabIndices.put(i, -1);
347 } else if (i == currentTab) {
The Android Open Source Projectf59ec872009-03-13 13:04:24 -0700348 Tab t = createNewTab();
The Android Open Source Project0c908882009-03-03 19:32:16 -0800349 // Me must set the current tab before restoring the state
350 // so that all the client classes are set.
351 setCurrentTab(t);
Elliott Slaughter3d6df162010-08-25 13:17:44 -0700352 if (!t.restoreState(state)) {
The Android Open Source Project0c908882009-03-03 19:32:16 -0800353 Log.w(LOGTAG, "Fail in restoreState, load home page.");
Grace Kloba22ac16e2009-10-07 18:00:23 -0700354 t.getWebView().loadUrl(BrowserSettings.getInstance()
The Android Open Source Project0c908882009-03-03 19:32:16 -0800355 .getHomePage());
356 }
Elliott Slaughter3d6df162010-08-25 13:17:44 -0700357 originalTabIndices.put(i, getTabCount() - 1);
The Android Open Source Project0c908882009-03-03 19:32:16 -0800358 } else {
359 // Create a new tab and don't restore the state yet, add it
360 // to the tab list
Grace Kloba22ac16e2009-10-07 18:00:23 -0700361 Tab t = new Tab(mActivity, null, false, null, null);
Grace Kloba22ac16e2009-10-07 18:00:23 -0700362 if (state != null) {
363 t.setSavedState(state);
364 t.populatePickerDataFromSavedState();
The Android Open Source Projectf59ec872009-03-13 13:04:24 -0700365 // Need to maintain the app id and original url so we
366 // can possibly reuse this tab.
Grace Kloba22ac16e2009-10-07 18:00:23 -0700367 t.setAppId(state.getString(Tab.APPID));
368 t.setOriginalUrl(state.getString(Tab.ORIGINALURL));
The Android Open Source Project0c908882009-03-03 19:32:16 -0800369 }
370 mTabs.add(t);
Grace Klobaf56f68d2010-04-11 22:53:42 -0700371 // added the tab to the front as they are not current
372 mTabQueue.add(0, t);
Elliott Slaughter3d6df162010-08-25 13:17:44 -0700373 originalTabIndices.put(i, getTabCount() - 1);
The Android Open Source Project0c908882009-03-03 19:32:16 -0800374 }
375 }
Elliott Slaughter3d6df162010-08-25 13:17:44 -0700376
The Android Open Source Project0c908882009-03-03 19:32:16 -0800377 // Rebuild the tree of tabs. Do this after all tabs have been
378 // created/restored so that the parent tab exists.
379 for (int i = 0; i < numTabs; i++) {
Grace Kloba22ac16e2009-10-07 18:00:23 -0700380 final Bundle b = inState.getBundle(Tab.WEBVIEW + i);
The Android Open Source Project0c908882009-03-03 19:32:16 -0800381 final Tab t = getTab(i);
382 if (b != null && t != null) {
Elliott Slaughter3d6df162010-08-25 13:17:44 -0700383 final Integer parentIndex = originalTabIndices.get(b.getInt(Tab.PARENTTAB, -1));
The Android Open Source Project0c908882009-03-03 19:32:16 -0800384 if (parentIndex != -1) {
385 final Tab parent = getTab(parentIndex);
386 if (parent != null) {
387 parent.addChildTab(t);
388 }
389 }
390 }
391 }
392 }
393 return true;
394 }
395
396 /**
Grace Klobaf56f68d2010-04-11 22:53:42 -0700397 * Free the memory in this order, 1) free the background tabs; 2) free the
The Android Open Source Project0c908882009-03-03 19:32:16 -0800398 * WebView cache;
399 */
400 void freeMemory() {
Grace Kloba92c18a52009-07-31 23:48:32 -0700401 if (getTabCount() == 0) return;
402
Grace Klobaf56f68d2010-04-11 22:53:42 -0700403 // free the least frequently used background tabs
404 Vector<Tab> tabs = getHalfLeastUsedTabs(getCurrentTab());
405 if (tabs.size() > 0) {
406 Log.w(LOGTAG, "Free " + tabs.size() + " tabs in the browser");
407 for (Tab t : tabs) {
408 // store the WebView's state.
409 t.saveState();
410 // destroy the tab
411 t.destroy();
412 }
The Android Open Source Project0c908882009-03-03 19:32:16 -0800413 return;
414 }
415
Derek Sollenberger4433d032009-06-10 15:37:21 -0400416 // free the WebView's unused memory (this includes the cache)
417 Log.w(LOGTAG, "Free WebView's unused memory and cache");
The Android Open Source Project0c908882009-03-03 19:32:16 -0800418 WebView view = getCurrentWebView();
419 if (view != null) {
Derek Sollenberger4433d032009-06-10 15:37:21 -0400420 view.freeMemory();
The Android Open Source Project0c908882009-03-03 19:32:16 -0800421 }
The Android Open Source Project0c908882009-03-03 19:32:16 -0800422 }
423
Grace Klobaf56f68d2010-04-11 22:53:42 -0700424 private Vector<Tab> getHalfLeastUsedTabs(Tab current) {
425 Vector<Tab> tabsToGo = new Vector<Tab>();
426
Patrick Scott2a67de42009-08-31 09:48:37 -0400427 // Don't do anything if we only have 1 tab or if the current tab is
428 // null.
429 if (getTabCount() == 1 || current == null) {
Grace Klobaf56f68d2010-04-11 22:53:42 -0700430 return tabsToGo;
The Android Open Source Project0c908882009-03-03 19:32:16 -0800431 }
432
Grace Klobaf56f68d2010-04-11 22:53:42 -0700433 if (mTabQueue.size() == 0) {
434 return tabsToGo;
The Android Open Source Project0c908882009-03-03 19:32:16 -0800435 }
436
Grace Klobaf56f68d2010-04-11 22:53:42 -0700437 // Rip through the queue starting at the beginning and tear down half of
438 // available tabs which are not the current tab or the parent of the
439 // current tab.
440 int openTabCount = 0;
441 for (Tab t : mTabQueue) {
442 if (t != null && t.getWebView() != null) {
443 openTabCount++;
444 if (t != current && t != current.getParentTab()) {
445 tabsToGo.add(t);
446 }
447 }
448 }
449
450 openTabCount /= 2;
451 if (tabsToGo.size() > openTabCount) {
452 tabsToGo.setSize(openTabCount);
453 }
454
455 return tabsToGo;
The Android Open Source Project0c908882009-03-03 19:32:16 -0800456 }
457
The Android Open Source Project0c908882009-03-03 19:32:16 -0800458 /**
459 * Show the tab that contains the given WebView.
460 * @param view The WebView used to find the tab.
461 */
462 Tab getTabFromView(WebView view) {
463 final int size = getTabCount();
464 for (int i = 0; i < size; i++) {
465 final Tab t = getTab(i);
Grace Kloba22ac16e2009-10-07 18:00:23 -0700466 if (t.getSubWebView() == view || t.getWebView() == view) {
The Android Open Source Project0c908882009-03-03 19:32:16 -0800467 return t;
468 }
469 }
470 return null;
471 }
472
473 /**
The Android Open Source Projectf59ec872009-03-13 13:04:24 -0700474 * Return the tab with the matching application id.
475 * @param id The application identifier.
476 */
477 Tab getTabFromId(String id) {
478 if (id == null) {
479 return null;
480 }
481 final int size = getTabCount();
482 for (int i = 0; i < size; i++) {
483 final Tab t = getTab(i);
Grace Kloba22ac16e2009-10-07 18:00:23 -0700484 if (id.equals(t.getAppId())) {
The Android Open Source Projectf59ec872009-03-13 13:04:24 -0700485 return t;
486 }
487 }
488 return null;
489 }
490
Grace Kloba22ac16e2009-10-07 18:00:23 -0700491 /**
492 * Stop loading in all opened WebView including subWindows.
493 */
Grace Kloba5d0e02e2009-10-05 15:15:36 -0700494 void stopAllLoading() {
495 final int size = getTabCount();
496 for (int i = 0; i < size; i++) {
Grace Kloba22ac16e2009-10-07 18:00:23 -0700497 final Tab t = getTab(i);
498 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.
540 final int size = getTabCount();
541 for (int i = 0; i < size; i++) {
542 t = getTab(i);
543 if (tabMatchesUrl(t, url)) {
544 return t;
545 }
546 }
547 return null;
548 }
549
The Android Open Source Projectf59ec872009-03-13 13:04:24 -0700550 /**
551 * Recreate the main WebView of the given tab. Returns true if the WebView
Leon Scroggins6eac63e2010-03-15 18:19:14 -0400552 * requires a load, whether it was due to the fact that it was deleted, or
553 * it is because it was a voice search.
The Android Open Source Projectf59ec872009-03-13 13:04:24 -0700554 */
Leon Scroggins6eac63e2010-03-15 18:19:14 -0400555 boolean recreateWebView(Tab t, BrowserActivity.UrlData urlData) {
556 final String url = urlData.mUrl;
Grace Kloba22ac16e2009-10-07 18:00:23 -0700557 final WebView w = t.getWebView();
The Android Open Source Projectf59ec872009-03-13 13:04:24 -0700558 if (w != null) {
Leon Scroggins47208682010-04-07 17:59:48 -0400559 if (url != null && url.equals(t.getOriginalUrl())
560 // Treat a voice intent as though it is a different URL,
561 // since it most likely is.
562 && urlData.mVoiceIntent == null) {
The Android Open Source Projectf59ec872009-03-13 13:04:24 -0700563 // The original url matches the current url. Just go back to the
564 // first history item so we can load it faster than if we
565 // rebuilt the WebView.
566 final WebBackForwardList list = w.copyBackForwardList();
567 if (list != null) {
568 w.goBackOrForward(-list.getCurrentIndex());
569 w.clearHistory(); // maintains the current page.
570 return false;
571 }
572 }
Grace Kloba22ac16e2009-10-07 18:00:23 -0700573 t.destroy();
The Android Open Source Projectf59ec872009-03-13 13:04:24 -0700574 }
575 // Create a new WebView. If this tab is the current tab, we need to put
576 // back all the clients so force it to be the current tab.
Steve Block2bc69912009-07-30 14:45:13 +0100577 t.setWebView(createNewWebView());
The Android Open Source Projectf59ec872009-03-13 13:04:24 -0700578 if (getCurrentTab() == t) {
579 setCurrentTab(t, true);
580 }
Grace Kloba22ac16e2009-10-07 18:00:23 -0700581 // Clear the saved state and picker data
582 t.setSavedState(null);
583 t.clearPickerData();
The Android Open Source Projectf59ec872009-03-13 13:04:24 -0700584 // Save the new url in order to avoid deleting the WebView.
Grace Kloba22ac16e2009-10-07 18:00:23 -0700585 t.setOriginalUrl(url);
The Android Open Source Projectf59ec872009-03-13 13:04:24 -0700586 return true;
587 }
588
589 /**
590 * Creates a new WebView and registers it with the global settings.
591 */
592 private WebView createNewWebView() {
Elliott Slaughterf0f03952010-07-14 18:10:36 -0700593 return createNewWebView(false);
594 }
595
596 /**
597 * Creates a new WebView and registers it with the global settings.
598 * @param privateBrowsing When true, enables private browsing in the new
599 * WebView.
600 */
601 private WebView createNewWebView(boolean privateBrowsing) {
The Android Open Source Projectf59ec872009-03-13 13:04:24 -0700602 // Create a new WebView
Michael Kolba2b2ba82010-08-04 17:54:03 -0700603 ScrollWebView w = new ScrollWebView(mActivity, null,
Elliott Slaughterf0f03952010-07-14 18:10:36 -0700604 com.android.internal.R.attr.webViewStyle, privateBrowsing);
Michael Kolba2b2ba82010-08-04 17:54:03 -0700605 w.setScrollListener(mActivity.getScrollListener());
Grace Kloba67f0a562009-09-28 21:24:51 -0700606 w.setScrollbarFadingEnabled(true);
607 w.setScrollBarStyle(View.SCROLLBARS_OUTSIDE_OVERLAY);
The Android Open Source Projectf59ec872009-03-13 13:04:24 -0700608 w.setMapTrackballToArrowKeys(false); // use trackball directly
The Android Open Source Projecta3c0aab2009-03-18 17:39:48 -0700609 // Enable the built-in zoom
610 w.getSettings().setBuiltInZoomControls(true);
Michael Kolb68775752010-08-19 12:42:01 -0700611 w.getSettings().setDisplayZoomControls(mDisplayZoomControls);
The Android Open Source Projectf59ec872009-03-13 13:04:24 -0700612 // Add this WebView to the settings observer list and update the
613 // settings
614 final BrowserSettings s = BrowserSettings.getInstance();
615 s.addObserver(w.getSettings()).update(s, null);
Mike Reedd5a80a52009-11-12 12:49:34 -0500616
Mike Reeda947d2d2010-01-14 14:57:45 -0800617 // pick a default
Mike Reedd5c3e0f2010-02-24 11:12:54 -0500618 if (false) {
Mike Reede5073c22010-01-29 11:31:39 -0500619 MeshTracker mt = new MeshTracker(2);
620 Paint paint = new Paint();
621 Bitmap bm = BitmapFactory.decodeResource(mActivity.getResources(),
622 R.drawable.pattern_carbon_fiber_dark);
623 paint.setShader(new BitmapShader(bm, Shader.TileMode.REPEAT,
624 Shader.TileMode.REPEAT));
625 mt.setBGPaint(paint);
626 w.setDragTracker(mt);
627 }
The Android Open Source Projectf59ec872009-03-13 13:04:24 -0700628 return w;
629 }
630
631 /**
The Android Open Source Project0c908882009-03-03 19:32:16 -0800632 * Put the current tab in the background and set newTab as the current tab.
633 * @param newTab The new tab. If newTab is null, the current tab is not
634 * set.
635 */
636 boolean setCurrentTab(Tab newTab) {
The Android Open Source Projectf59ec872009-03-13 13:04:24 -0700637 return setCurrentTab(newTab, false);
638 }
639
Grace Kloba22ac16e2009-10-07 18:00:23 -0700640 void pauseCurrentTab() {
Mike Reed7bfa63b2009-05-28 11:08:32 -0400641 Tab t = getCurrentTab();
642 if (t != null) {
Grace Kloba22ac16e2009-10-07 18:00:23 -0700643 t.pause();
Mike Reed7bfa63b2009-05-28 11:08:32 -0400644 }
645 }
646
Grace Kloba22ac16e2009-10-07 18:00:23 -0700647 void resumeCurrentTab() {
Mike Reed7bfa63b2009-05-28 11:08:32 -0400648 Tab t = getCurrentTab();
649 if (t != null) {
Grace Kloba22ac16e2009-10-07 18:00:23 -0700650 t.resume();
Mike Reed7bfa63b2009-05-28 11:08:32 -0400651 }
652 }
653
The Android Open Source Projectf59ec872009-03-13 13:04:24 -0700654 /**
655 * If force is true, this method skips the check for newTab == current.
656 */
657 private boolean setCurrentTab(Tab newTab, boolean force) {
The Android Open Source Project0c908882009-03-03 19:32:16 -0800658 Tab current = getTab(mCurrentTab);
The Android Open Source Projectf59ec872009-03-13 13:04:24 -0700659 if (current == newTab && !force) {
The Android Open Source Project0c908882009-03-03 19:32:16 -0800660 return true;
661 }
662 if (current != null) {
Grace Kloba22ac16e2009-10-07 18:00:23 -0700663 current.putInBackground();
664 mCurrentTab = -1;
The Android Open Source Project0c908882009-03-03 19:32:16 -0800665 }
The Android Open Source Project0c908882009-03-03 19:32:16 -0800666 if (newTab == null) {
667 return false;
668 }
669
670 // Move the newTab to the end of the queue
671 int index = mTabQueue.indexOf(newTab);
672 if (index != -1) {
673 mTabQueue.remove(index);
674 }
675 mTabQueue.add(newTab);
676
The Android Open Source Project0c908882009-03-03 19:32:16 -0800677 // Display the new current tab
678 mCurrentTab = mTabs.indexOf(newTab);
Grace Kloba22ac16e2009-10-07 18:00:23 -0700679 WebView mainView = newTab.getWebView();
The Android Open Source Project0c908882009-03-03 19:32:16 -0800680 boolean needRestore = (mainView == null);
681 if (needRestore) {
682 // Same work as in createNewTab() except don't do new Tab()
Steve Block2bc69912009-07-30 14:45:13 +0100683 mainView = createNewWebView();
684 newTab.setWebView(mainView);
The Android Open Source Project0c908882009-03-03 19:32:16 -0800685 }
Grace Kloba22ac16e2009-10-07 18:00:23 -0700686 newTab.putInForeground();
The Android Open Source Project0c908882009-03-03 19:32:16 -0800687 if (needRestore) {
688 // Have to finish setCurrentTab work before calling restoreState
Grace Kloba22ac16e2009-10-07 18:00:23 -0700689 if (!newTab.restoreState(newTab.getSavedState())) {
The Android Open Source Project0c908882009-03-03 19:32:16 -0800690 mainView.loadUrl(BrowserSettings.getInstance().getHomePage());
691 }
692 }
693 return true;
694 }
Michael Kolbfe251992010-07-08 15:41:55 -0700695
696 interface TabChangeListener {
697
698 public void onNewTab(Tab tab);
699
700 public void onRemoveTab(Tab tab);
701
702 public void onCurrentTab(Tab tab);
703
704 public void onProgress(Tab tab, int progress);
705
706 public void onUrlAndTitle(Tab tab, String url, String title);
707
708 public void onFavicon(Tab tab, Bitmap favicon);
709
710 public void onPageStarted(Tab tab);
711
712 public void onPageFinished(Tab tab);
713
714 }
715
716 private TabChangeListener mTabChangeListener;
717
718 /**
719 * register the TabChangeListener with the tab control
720 * @param listener
721 */
722 void setOnTabChangeListener(TabChangeListener listener) {
723 mTabChangeListener = listener;
724 }
725
726 /**
727 * get the current TabChangeListener (used by the tabs)
728 */
729 TabChangeListener getTabChangeListener() {
730 return mTabChangeListener;
731 }
732
The Android Open Source Project0c908882009-03-03 19:32:16 -0800733}