blob: 37834c0593af5e852ee8f6e4f28ce9beffcb2193 [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;
32import java.util.Vector;
33
34class TabControl {
35 // Log Tag
36 private static final String LOGTAG = "TabControl";
37 // Maximum number of tabs.
Grace Kloba22ac16e2009-10-07 18:00:23 -070038 private static final int MAX_TABS = 8;
The Android Open Source Project0c908882009-03-03 19:32:16 -080039 // Private array of WebViews that are used as tabs.
40 private ArrayList<Tab> mTabs = new ArrayList<Tab>(MAX_TABS);
41 // Queue of most recently viewed tabs.
42 private ArrayList<Tab> mTabQueue = new ArrayList<Tab>(MAX_TABS);
43 // Current position in mTabs.
44 private int mCurrentTab = -1;
45 // A private instance of BrowserActivity to interface with when adding and
46 // switching between tabs.
47 private final BrowserActivity mActivity;
The Android Open Source Project0c908882009-03-03 19:32:16 -080048 // Directory to store thumbnails for each WebView.
49 private final File mThumbnailDir;
50
51 /**
52 * Construct a new TabControl object that interfaces with the given
53 * BrowserActivity instance.
54 * @param activity A BrowserActivity instance that TabControl will interface
55 * with.
56 */
57 TabControl(BrowserActivity activity) {
58 mActivity = activity;
The Android Open Source Project0c908882009-03-03 19:32:16 -080059 mThumbnailDir = activity.getDir("thumbnails", 0);
60 }
61
62 File getThumbnailDir() {
63 return mThumbnailDir;
64 }
65
66 BrowserActivity getBrowserActivity() {
67 return mActivity;
68 }
69
70 /**
71 * Return the current tab's main WebView. This will always return the main
72 * WebView for a given tab and not a subwindow.
73 * @return The current tab's WebView.
74 */
75 WebView getCurrentWebView() {
76 Tab t = getTab(mCurrentTab);
77 if (t == null) {
78 return null;
79 }
Grace Kloba22ac16e2009-10-07 18:00:23 -070080 return t.getWebView();
Ben Murdochbff2d602009-07-01 20:19:05 +010081 }
82
83 /**
The Android Open Source Project0c908882009-03-03 19:32:16 -080084 * Return the current tab's top-level WebView. This can return a subwindow
85 * if one exists.
86 * @return The top-level WebView of the current tab.
87 */
88 WebView getCurrentTopWebView() {
89 Tab t = getTab(mCurrentTab);
90 if (t == null) {
91 return null;
92 }
Grace Kloba22ac16e2009-10-07 18:00:23 -070093 return t.getTopWindow();
The Android Open Source Project0c908882009-03-03 19:32:16 -080094 }
95
96 /**
97 * Return the current tab's subwindow if it exists.
98 * @return The subwindow of the current tab or null if it doesn't exist.
99 */
100 WebView getCurrentSubWindow() {
101 Tab t = getTab(mCurrentTab);
102 if (t == null) {
103 return null;
104 }
Grace Kloba22ac16e2009-10-07 18:00:23 -0700105 return t.getSubWebView();
The Android Open Source Project0c908882009-03-03 19:32:16 -0800106 }
107
108 /**
109 * Return the tab at the specified index.
110 * @return The Tab for the specified index or null if the tab does not
111 * exist.
112 */
113 Tab getTab(int index) {
114 if (index >= 0 && index < mTabs.size()) {
115 return mTabs.get(index);
116 }
117 return null;
118 }
119
120 /**
121 * Return the current tab.
122 * @return The current tab.
123 */
124 Tab getCurrentTab() {
125 return getTab(mCurrentTab);
126 }
127
128 /**
129 * Return the current tab index.
130 * @return The current tab index
131 */
132 int getCurrentIndex() {
133 return mCurrentTab;
134 }
Michael Kolbfe251992010-07-08 15:41:55 -0700135
The Android Open Source Project0c908882009-03-03 19:32:16 -0800136 /**
137 * Given a Tab, find it's index
138 * @param Tab to find
139 * @return index of Tab or -1 if not found
140 */
141 int getTabIndex(Tab tab) {
Patrick Scottae641ac2009-04-20 13:51:49 -0400142 if (tab == null) {
143 return -1;
144 }
The Android Open Source Project0c908882009-03-03 19:32:16 -0800145 return mTabs.indexOf(tab);
146 }
147
Grace Kloba22ac16e2009-10-07 18:00:23 -0700148 boolean canCreateNewTab() {
149 return MAX_TABS != mTabs.size();
150 }
151
The Android Open Source Project0c908882009-03-03 19:32:16 -0800152 /**
Elliott Slaughtere440a882010-08-20 13:54:45 -0700153 * Returns true if there are any incognito tabs open.
154 * @return True when any incognito tabs are open, false otherwise.
155 */
156 boolean hasAnyOpenIncognitoTabs() {
157 for (Tab tab : mTabs) {
158 if (tab.getWebView().isPrivateBrowsingEnabled()) {
159 return true;
160 }
161 }
162 return false;
163 }
164
165 /**
The Android Open Source Projectf59ec872009-03-13 13:04:24 -0700166 * Create a new tab.
The Android Open Source Project0c908882009-03-03 19:32:16 -0800167 * @return The newly createTab or null if we have reached the maximum
168 * number of open tabs.
169 */
Elliott Slaughterf0f03952010-07-14 18:10:36 -0700170 Tab createNewTab(boolean closeOnExit, String appId, String url,
171 boolean privateBrowsing) {
The Android Open Source Project0c908882009-03-03 19:32:16 -0800172 int size = mTabs.size();
173 // Return false if we have maxed out on tabs
174 if (MAX_TABS == size) {
175 return null;
176 }
Elliott Slaughterf0f03952010-07-14 18:10:36 -0700177 final WebView w = createNewWebView(privateBrowsing);
Steve Block2bc69912009-07-30 14:45:13 +0100178
The Android Open Source Project0c908882009-03-03 19:32:16 -0800179 // Create a new tab and add it to the tab list
Grace Kloba22ac16e2009-10-07 18:00:23 -0700180 Tab t = new Tab(mActivity, w, closeOnExit, appId, url);
The Android Open Source Project0c908882009-03-03 19:32:16 -0800181 mTabs.add(t);
The Android Open Source Project4e5f5872009-03-09 11:52:14 -0700182 // Initially put the tab in the background.
Grace Kloba22ac16e2009-10-07 18:00:23 -0700183 t.putInBackground();
Michael Kolbfe251992010-07-08 15:41:55 -0700184 if (mTabChangeListener != null) {
185 mTabChangeListener.onNewTab(t);
186 }
The Android Open Source Project0c908882009-03-03 19:32:16 -0800187 return t;
188 }
189
190 /**
The Android Open Source Projectf59ec872009-03-13 13:04:24 -0700191 * Create a new tab with default values for closeOnExit(false),
Elliott Slaughterf0f03952010-07-14 18:10:36 -0700192 * appId(null), url(null), and privateBrowsing(false).
The Android Open Source Projectf59ec872009-03-13 13:04:24 -0700193 */
194 Tab createNewTab() {
Elliott Slaughterf0f03952010-07-14 18:10:36 -0700195 return createNewTab(false, null, null, false);
The Android Open Source Projectf59ec872009-03-13 13:04:24 -0700196 }
197
198 /**
Leon Scrogginsfde97462010-01-11 13:06:21 -0500199 * Remove the parent child relationships from all tabs.
200 */
201 void removeParentChildRelationShips() {
202 for (Tab tab : mTabs) {
203 tab.removeFromTree();
204 }
205 }
206
207 /**
The Android Open Source Project0c908882009-03-03 19:32:16 -0800208 * Remove the tab from the list. If the tab is the current tab shown, the
209 * last created tab will be shown.
210 * @param t The tab to be removed.
211 */
212 boolean removeTab(Tab t) {
213 if (t == null) {
214 return false;
215 }
Grace Kloba22ac16e2009-10-07 18:00:23 -0700216
Patrick Scottd944d4d2010-01-27 16:39:11 -0500217 // Grab the current tab before modifying the list.
218 Tab current = getCurrentTab();
219
220 // Remove t from our list of tabs.
221 mTabs.remove(t);
222
223 // Put the tab in the background only if it is the current one.
224 if (current == t) {
Grace Kloba22ac16e2009-10-07 18:00:23 -0700225 t.putInBackground();
226 mCurrentTab = -1;
Patrick Scottd944d4d2010-01-27 16:39:11 -0500227 } else {
228 // If a tab that is earlier in the list gets removed, the current
229 // index no longer points to the correct tab.
230 mCurrentTab = getTabIndex(current);
The Android Open Source Project0c908882009-03-03 19:32:16 -0800231 }
232
Grace Kloba22ac16e2009-10-07 18:00:23 -0700233 // destroy the tab
234 t.destroy();
The Android Open Source Project0c908882009-03-03 19:32:16 -0800235 // clear it's references to parent and children
236 t.removeFromTree();
The Android Open Source Project0c908882009-03-03 19:32:16 -0800237
238 // The tab indices have shifted, update all the saved state so we point
239 // to the correct index.
240 for (Tab tab : mTabs) {
Grace Kloba22ac16e2009-10-07 18:00:23 -0700241 Vector<Tab> children = tab.getChildTabs();
242 if (children != null) {
243 for (Tab child : children) {
The Android Open Source Project0c908882009-03-03 19:32:16 -0800244 child.setParentTab(tab);
245 }
246 }
247 }
248
The Android Open Source Project0c908882009-03-03 19:32:16 -0800249 // Remove it from the queue of viewed tabs.
250 mTabQueue.remove(t);
Michael Kolbfe251992010-07-08 15:41:55 -0700251 if (mTabChangeListener != null) {
252 mTabChangeListener.onRemoveTab(t);
253 }
The Android Open Source Project0c908882009-03-03 19:32:16 -0800254 return true;
255 }
256
257 /**
The Android Open Source Project0c908882009-03-03 19:32:16 -0800258 * Destroy all the tabs and subwindows
259 */
260 void destroy() {
The Android Open Source Project0c908882009-03-03 19:32:16 -0800261 for (Tab t : mTabs) {
Grace Kloba22ac16e2009-10-07 18:00:23 -0700262 t.destroy();
The Android Open Source Project0c908882009-03-03 19:32:16 -0800263 }
264 mTabs.clear();
265 mTabQueue.clear();
266 }
267
268 /**
269 * Returns the number of tabs created.
270 * @return The number of tabs created.
271 */
272 int getTabCount() {
273 return mTabs.size();
274 }
275
The Android Open Source Project0c908882009-03-03 19:32:16 -0800276
277 /**
278 * Save the state of all the Tabs.
279 * @param outState The Bundle to save the state to.
280 */
281 void saveState(Bundle outState) {
282 final int numTabs = getTabCount();
Grace Kloba22ac16e2009-10-07 18:00:23 -0700283 outState.putInt(Tab.NUMTABS, numTabs);
The Android Open Source Project0c908882009-03-03 19:32:16 -0800284 final int index = getCurrentIndex();
Grace Kloba22ac16e2009-10-07 18:00:23 -0700285 outState.putInt(Tab.CURRTAB, (index >= 0 && index < numTabs) ? index : 0);
The Android Open Source Project0c908882009-03-03 19:32:16 -0800286 for (int i = 0; i < numTabs; i++) {
287 final Tab t = getTab(i);
Grace Kloba22ac16e2009-10-07 18:00:23 -0700288 if (t.saveState()) {
289 outState.putBundle(Tab.WEBVIEW + i, t.getSavedState());
The Android Open Source Project0c908882009-03-03 19:32:16 -0800290 }
291 }
292 }
293
294 /**
295 * Restore the state of all the tabs.
296 * @param inState The saved state of all the tabs.
297 * @return True if there were previous tabs that were restored. False if
298 * there was no saved state or restoring the state failed.
299 */
300 boolean restoreState(Bundle inState) {
301 final int numTabs = (inState == null)
Grace Kloba22ac16e2009-10-07 18:00:23 -0700302 ? -1 : inState.getInt(Tab.NUMTABS, -1);
The Android Open Source Project0c908882009-03-03 19:32:16 -0800303 if (numTabs == -1) {
304 return false;
305 } else {
Grace Kloba22ac16e2009-10-07 18:00:23 -0700306 final int currentTab = inState.getInt(Tab.CURRTAB, -1);
The Android Open Source Project0c908882009-03-03 19:32:16 -0800307 for (int i = 0; i < numTabs; i++) {
308 if (i == currentTab) {
The Android Open Source Projectf59ec872009-03-13 13:04:24 -0700309 Tab t = createNewTab();
The Android Open Source Project0c908882009-03-03 19:32:16 -0800310 // Me must set the current tab before restoring the state
311 // so that all the client classes are set.
312 setCurrentTab(t);
Grace Kloba22ac16e2009-10-07 18:00:23 -0700313 if (!t.restoreState(inState.getBundle(Tab.WEBVIEW + i))) {
The Android Open Source Project0c908882009-03-03 19:32:16 -0800314 Log.w(LOGTAG, "Fail in restoreState, load home page.");
Grace Kloba22ac16e2009-10-07 18:00:23 -0700315 t.getWebView().loadUrl(BrowserSettings.getInstance()
The Android Open Source Project0c908882009-03-03 19:32:16 -0800316 .getHomePage());
317 }
318 } else {
319 // Create a new tab and don't restore the state yet, add it
320 // to the tab list
Grace Kloba22ac16e2009-10-07 18:00:23 -0700321 Tab t = new Tab(mActivity, null, false, null, null);
322 Bundle state = inState.getBundle(Tab.WEBVIEW + i);
323 if (state != null) {
324 t.setSavedState(state);
325 t.populatePickerDataFromSavedState();
The Android Open Source Projectf59ec872009-03-13 13:04:24 -0700326 // Need to maintain the app id and original url so we
327 // can possibly reuse this tab.
Grace Kloba22ac16e2009-10-07 18:00:23 -0700328 t.setAppId(state.getString(Tab.APPID));
329 t.setOriginalUrl(state.getString(Tab.ORIGINALURL));
The Android Open Source Project0c908882009-03-03 19:32:16 -0800330 }
331 mTabs.add(t);
Grace Klobaf56f68d2010-04-11 22:53:42 -0700332 // added the tab to the front as they are not current
333 mTabQueue.add(0, t);
The Android Open Source Project0c908882009-03-03 19:32:16 -0800334 }
335 }
336 // Rebuild the tree of tabs. Do this after all tabs have been
337 // created/restored so that the parent tab exists.
338 for (int i = 0; i < numTabs; i++) {
Grace Kloba22ac16e2009-10-07 18:00:23 -0700339 final Bundle b = inState.getBundle(Tab.WEBVIEW + i);
The Android Open Source Project0c908882009-03-03 19:32:16 -0800340 final Tab t = getTab(i);
341 if (b != null && t != null) {
Grace Kloba22ac16e2009-10-07 18:00:23 -0700342 final int parentIndex = b.getInt(Tab.PARENTTAB, -1);
The Android Open Source Project0c908882009-03-03 19:32:16 -0800343 if (parentIndex != -1) {
344 final Tab parent = getTab(parentIndex);
345 if (parent != null) {
346 parent.addChildTab(t);
347 }
348 }
349 }
350 }
351 }
352 return true;
353 }
354
355 /**
Grace Klobaf56f68d2010-04-11 22:53:42 -0700356 * Free the memory in this order, 1) free the background tabs; 2) free the
The Android Open Source Project0c908882009-03-03 19:32:16 -0800357 * WebView cache;
358 */
359 void freeMemory() {
Grace Kloba92c18a52009-07-31 23:48:32 -0700360 if (getTabCount() == 0) return;
361
Grace Klobaf56f68d2010-04-11 22:53:42 -0700362 // free the least frequently used background tabs
363 Vector<Tab> tabs = getHalfLeastUsedTabs(getCurrentTab());
364 if (tabs.size() > 0) {
365 Log.w(LOGTAG, "Free " + tabs.size() + " tabs in the browser");
366 for (Tab t : tabs) {
367 // store the WebView's state.
368 t.saveState();
369 // destroy the tab
370 t.destroy();
371 }
The Android Open Source Project0c908882009-03-03 19:32:16 -0800372 return;
373 }
374
Derek Sollenberger4433d032009-06-10 15:37:21 -0400375 // free the WebView's unused memory (this includes the cache)
376 Log.w(LOGTAG, "Free WebView's unused memory and cache");
The Android Open Source Project0c908882009-03-03 19:32:16 -0800377 WebView view = getCurrentWebView();
378 if (view != null) {
Derek Sollenberger4433d032009-06-10 15:37:21 -0400379 view.freeMemory();
The Android Open Source Project0c908882009-03-03 19:32:16 -0800380 }
The Android Open Source Project0c908882009-03-03 19:32:16 -0800381 }
382
Grace Klobaf56f68d2010-04-11 22:53:42 -0700383 private Vector<Tab> getHalfLeastUsedTabs(Tab current) {
384 Vector<Tab> tabsToGo = new Vector<Tab>();
385
Patrick Scott2a67de42009-08-31 09:48:37 -0400386 // Don't do anything if we only have 1 tab or if the current tab is
387 // null.
388 if (getTabCount() == 1 || current == null) {
Grace Klobaf56f68d2010-04-11 22:53:42 -0700389 return tabsToGo;
The Android Open Source Project0c908882009-03-03 19:32:16 -0800390 }
391
Grace Klobaf56f68d2010-04-11 22:53:42 -0700392 if (mTabQueue.size() == 0) {
393 return tabsToGo;
The Android Open Source Project0c908882009-03-03 19:32:16 -0800394 }
395
Grace Klobaf56f68d2010-04-11 22:53:42 -0700396 // Rip through the queue starting at the beginning and tear down half of
397 // available tabs which are not the current tab or the parent of the
398 // current tab.
399 int openTabCount = 0;
400 for (Tab t : mTabQueue) {
401 if (t != null && t.getWebView() != null) {
402 openTabCount++;
403 if (t != current && t != current.getParentTab()) {
404 tabsToGo.add(t);
405 }
406 }
407 }
408
409 openTabCount /= 2;
410 if (tabsToGo.size() > openTabCount) {
411 tabsToGo.setSize(openTabCount);
412 }
413
414 return tabsToGo;
The Android Open Source Project0c908882009-03-03 19:32:16 -0800415 }
416
The Android Open Source Project0c908882009-03-03 19:32:16 -0800417 /**
418 * Show the tab that contains the given WebView.
419 * @param view The WebView used to find the tab.
420 */
421 Tab getTabFromView(WebView view) {
422 final int size = getTabCount();
423 for (int i = 0; i < size; i++) {
424 final Tab t = getTab(i);
Grace Kloba22ac16e2009-10-07 18:00:23 -0700425 if (t.getSubWebView() == view || t.getWebView() == view) {
The Android Open Source Project0c908882009-03-03 19:32:16 -0800426 return t;
427 }
428 }
429 return null;
430 }
431
432 /**
The Android Open Source Projectf59ec872009-03-13 13:04:24 -0700433 * Return the tab with the matching application id.
434 * @param id The application identifier.
435 */
436 Tab getTabFromId(String id) {
437 if (id == null) {
438 return null;
439 }
440 final int size = getTabCount();
441 for (int i = 0; i < size; i++) {
442 final Tab t = getTab(i);
Grace Kloba22ac16e2009-10-07 18:00:23 -0700443 if (id.equals(t.getAppId())) {
The Android Open Source Projectf59ec872009-03-13 13:04:24 -0700444 return t;
445 }
446 }
447 return null;
448 }
449
Grace Kloba22ac16e2009-10-07 18:00:23 -0700450 /**
451 * Stop loading in all opened WebView including subWindows.
452 */
Grace Kloba5d0e02e2009-10-05 15:15:36 -0700453 void stopAllLoading() {
454 final int size = getTabCount();
455 for (int i = 0; i < size; i++) {
Grace Kloba22ac16e2009-10-07 18:00:23 -0700456 final Tab t = getTab(i);
457 final WebView webview = t.getWebView();
Grace Kloba5d0e02e2009-10-05 15:15:36 -0700458 if (webview != null) {
459 webview.stopLoading();
460 }
Grace Kloba22ac16e2009-10-07 18:00:23 -0700461 final WebView subview = t.getSubWebView();
462 if (subview != null) {
463 webview.stopLoading();
464 }
Grace Kloba5d0e02e2009-10-05 15:15:36 -0700465 }
466 }
467
Patrick Scottcd115892009-07-16 09:42:58 -0400468 // This method checks if a non-app tab (one created within the browser)
469 // matches the given url.
470 private boolean tabMatchesUrl(Tab t, String url) {
Grace Kloba22ac16e2009-10-07 18:00:23 -0700471 if (t.getAppId() != null) {
Patrick Scottcd115892009-07-16 09:42:58 -0400472 return false;
Grace Kloba22ac16e2009-10-07 18:00:23 -0700473 }
474 WebView webview = t.getWebView();
475 if (webview == null) {
Patrick Scottcd115892009-07-16 09:42:58 -0400476 return false;
Grace Kloba22ac16e2009-10-07 18:00:23 -0700477 } else if (url.equals(webview.getUrl())
478 || url.equals(webview.getOriginalUrl())) {
Patrick Scottcd115892009-07-16 09:42:58 -0400479 return true;
480 }
481 return false;
482 }
483
484 /**
485 * Return the tab that has no app id associated with it and the url of the
486 * tab matches the given url.
487 * @param url The url to search for.
488 */
489 Tab findUnusedTabWithUrl(String url) {
490 if (url == null) {
491 return null;
492 }
493 // Check the current tab first.
494 Tab t = getCurrentTab();
495 if (t != null && tabMatchesUrl(t, url)) {
496 return t;
497 }
498 // Now check all the rest.
499 final int size = getTabCount();
500 for (int i = 0; i < size; i++) {
501 t = getTab(i);
502 if (tabMatchesUrl(t, url)) {
503 return t;
504 }
505 }
506 return null;
507 }
508
The Android Open Source Projectf59ec872009-03-13 13:04:24 -0700509 /**
510 * Recreate the main WebView of the given tab. Returns true if the WebView
Leon Scroggins6eac63e2010-03-15 18:19:14 -0400511 * requires a load, whether it was due to the fact that it was deleted, or
512 * it is because it was a voice search.
The Android Open Source Projectf59ec872009-03-13 13:04:24 -0700513 */
Leon Scroggins6eac63e2010-03-15 18:19:14 -0400514 boolean recreateWebView(Tab t, BrowserActivity.UrlData urlData) {
515 final String url = urlData.mUrl;
Grace Kloba22ac16e2009-10-07 18:00:23 -0700516 final WebView w = t.getWebView();
The Android Open Source Projectf59ec872009-03-13 13:04:24 -0700517 if (w != null) {
Leon Scroggins47208682010-04-07 17:59:48 -0400518 if (url != null && url.equals(t.getOriginalUrl())
519 // Treat a voice intent as though it is a different URL,
520 // since it most likely is.
521 && urlData.mVoiceIntent == null) {
The Android Open Source Projectf59ec872009-03-13 13:04:24 -0700522 // The original url matches the current url. Just go back to the
523 // first history item so we can load it faster than if we
524 // rebuilt the WebView.
525 final WebBackForwardList list = w.copyBackForwardList();
526 if (list != null) {
527 w.goBackOrForward(-list.getCurrentIndex());
528 w.clearHistory(); // maintains the current page.
529 return false;
530 }
531 }
Grace Kloba22ac16e2009-10-07 18:00:23 -0700532 t.destroy();
The Android Open Source Projectf59ec872009-03-13 13:04:24 -0700533 }
534 // Create a new WebView. If this tab is the current tab, we need to put
535 // back all the clients so force it to be the current tab.
Steve Block2bc69912009-07-30 14:45:13 +0100536 t.setWebView(createNewWebView());
The Android Open Source Projectf59ec872009-03-13 13:04:24 -0700537 if (getCurrentTab() == t) {
538 setCurrentTab(t, true);
539 }
Grace Kloba22ac16e2009-10-07 18:00:23 -0700540 // Clear the saved state and picker data
541 t.setSavedState(null);
542 t.clearPickerData();
The Android Open Source Projectf59ec872009-03-13 13:04:24 -0700543 // Save the new url in order to avoid deleting the WebView.
Grace Kloba22ac16e2009-10-07 18:00:23 -0700544 t.setOriginalUrl(url);
The Android Open Source Projectf59ec872009-03-13 13:04:24 -0700545 return true;
546 }
547
548 /**
549 * Creates a new WebView and registers it with the global settings.
550 */
551 private WebView createNewWebView() {
Elliott Slaughterf0f03952010-07-14 18:10:36 -0700552 return createNewWebView(false);
553 }
554
555 /**
556 * Creates a new WebView and registers it with the global settings.
557 * @param privateBrowsing When true, enables private browsing in the new
558 * WebView.
559 */
560 private WebView createNewWebView(boolean privateBrowsing) {
The Android Open Source Projectf59ec872009-03-13 13:04:24 -0700561 // Create a new WebView
Michael Kolba2b2ba82010-08-04 17:54:03 -0700562 ScrollWebView w = new ScrollWebView(mActivity, null,
Elliott Slaughterf0f03952010-07-14 18:10:36 -0700563 com.android.internal.R.attr.webViewStyle, privateBrowsing);
Michael Kolba2b2ba82010-08-04 17:54:03 -0700564 w.setScrollListener(mActivity.getScrollListener());
Grace Kloba67f0a562009-09-28 21:24:51 -0700565 w.setScrollbarFadingEnabled(true);
566 w.setScrollBarStyle(View.SCROLLBARS_OUTSIDE_OVERLAY);
The Android Open Source Projectf59ec872009-03-13 13:04:24 -0700567 w.setMapTrackballToArrowKeys(false); // use trackball directly
The Android Open Source Projecta3c0aab2009-03-18 17:39:48 -0700568 // Enable the built-in zoom
569 w.getSettings().setBuiltInZoomControls(true);
The Android Open Source Projectf59ec872009-03-13 13:04:24 -0700570 // Add this WebView to the settings observer list and update the
571 // settings
572 final BrowserSettings s = BrowserSettings.getInstance();
573 s.addObserver(w.getSettings()).update(s, null);
Mike Reedd5a80a52009-11-12 12:49:34 -0500574
Mike Reeda947d2d2010-01-14 14:57:45 -0800575 // pick a default
Mike Reedd5c3e0f2010-02-24 11:12:54 -0500576 if (false) {
Mike Reede5073c22010-01-29 11:31:39 -0500577 MeshTracker mt = new MeshTracker(2);
578 Paint paint = new Paint();
579 Bitmap bm = BitmapFactory.decodeResource(mActivity.getResources(),
580 R.drawable.pattern_carbon_fiber_dark);
581 paint.setShader(new BitmapShader(bm, Shader.TileMode.REPEAT,
582 Shader.TileMode.REPEAT));
583 mt.setBGPaint(paint);
584 w.setDragTracker(mt);
585 }
The Android Open Source Projectf59ec872009-03-13 13:04:24 -0700586 return w;
587 }
588
589 /**
The Android Open Source Project0c908882009-03-03 19:32:16 -0800590 * Put the current tab in the background and set newTab as the current tab.
591 * @param newTab The new tab. If newTab is null, the current tab is not
592 * set.
593 */
594 boolean setCurrentTab(Tab newTab) {
The Android Open Source Projectf59ec872009-03-13 13:04:24 -0700595 return setCurrentTab(newTab, false);
596 }
597
Grace Kloba22ac16e2009-10-07 18:00:23 -0700598 void pauseCurrentTab() {
Mike Reed7bfa63b2009-05-28 11:08:32 -0400599 Tab t = getCurrentTab();
600 if (t != null) {
Grace Kloba22ac16e2009-10-07 18:00:23 -0700601 t.pause();
Mike Reed7bfa63b2009-05-28 11:08:32 -0400602 }
603 }
604
Grace Kloba22ac16e2009-10-07 18:00:23 -0700605 void resumeCurrentTab() {
Mike Reed7bfa63b2009-05-28 11:08:32 -0400606 Tab t = getCurrentTab();
607 if (t != null) {
Grace Kloba22ac16e2009-10-07 18:00:23 -0700608 t.resume();
Mike Reed7bfa63b2009-05-28 11:08:32 -0400609 }
610 }
611
The Android Open Source Projectf59ec872009-03-13 13:04:24 -0700612 /**
613 * If force is true, this method skips the check for newTab == current.
614 */
615 private boolean setCurrentTab(Tab newTab, boolean force) {
The Android Open Source Project0c908882009-03-03 19:32:16 -0800616 Tab current = getTab(mCurrentTab);
The Android Open Source Projectf59ec872009-03-13 13:04:24 -0700617 if (current == newTab && !force) {
The Android Open Source Project0c908882009-03-03 19:32:16 -0800618 return true;
619 }
620 if (current != null) {
Grace Kloba22ac16e2009-10-07 18:00:23 -0700621 current.putInBackground();
622 mCurrentTab = -1;
The Android Open Source Project0c908882009-03-03 19:32:16 -0800623 }
The Android Open Source Project0c908882009-03-03 19:32:16 -0800624 if (newTab == null) {
625 return false;
626 }
627
628 // Move the newTab to the end of the queue
629 int index = mTabQueue.indexOf(newTab);
630 if (index != -1) {
631 mTabQueue.remove(index);
632 }
633 mTabQueue.add(newTab);
634
The Android Open Source Project0c908882009-03-03 19:32:16 -0800635 // Display the new current tab
636 mCurrentTab = mTabs.indexOf(newTab);
Grace Kloba22ac16e2009-10-07 18:00:23 -0700637 WebView mainView = newTab.getWebView();
The Android Open Source Project0c908882009-03-03 19:32:16 -0800638 boolean needRestore = (mainView == null);
639 if (needRestore) {
640 // Same work as in createNewTab() except don't do new Tab()
Steve Block2bc69912009-07-30 14:45:13 +0100641 mainView = createNewWebView();
642 newTab.setWebView(mainView);
The Android Open Source Project0c908882009-03-03 19:32:16 -0800643 }
Grace Kloba22ac16e2009-10-07 18:00:23 -0700644 newTab.putInForeground();
The Android Open Source Project0c908882009-03-03 19:32:16 -0800645 if (needRestore) {
646 // Have to finish setCurrentTab work before calling restoreState
Grace Kloba22ac16e2009-10-07 18:00:23 -0700647 if (!newTab.restoreState(newTab.getSavedState())) {
The Android Open Source Project0c908882009-03-03 19:32:16 -0800648 mainView.loadUrl(BrowserSettings.getInstance().getHomePage());
649 }
650 }
651 return true;
652 }
Michael Kolbfe251992010-07-08 15:41:55 -0700653
654 interface TabChangeListener {
655
656 public void onNewTab(Tab tab);
657
658 public void onRemoveTab(Tab tab);
659
660 public void onCurrentTab(Tab tab);
661
662 public void onProgress(Tab tab, int progress);
663
664 public void onUrlAndTitle(Tab tab, String url, String title);
665
666 public void onFavicon(Tab tab, Bitmap favicon);
667
668 public void onPageStarted(Tab tab);
669
670 public void onPageFinished(Tab tab);
671
672 }
673
674 private TabChangeListener mTabChangeListener;
675
676 /**
677 * register the TabChangeListener with the tab control
678 * @param listener
679 */
680 void setOnTabChangeListener(TabChangeListener listener) {
681 mTabChangeListener = listener;
682 }
683
684 /**
685 * get the current TabChangeListener (used by the tabs)
686 */
687 TabChangeListener getTabChangeListener() {
688 return mTabChangeListener;
689 }
690
The Android Open Source Project0c908882009-03-03 19:32:16 -0800691}