10c90888c75eed12f6e2e14a9044faf50bd4af8edThe Android Open Source Project/*
20c90888c75eed12f6e2e14a9044faf50bd4af8edThe Android Open Source Project * Copyright (C) 2007 The Android Open Source Project
30c90888c75eed12f6e2e14a9044faf50bd4af8edThe Android Open Source Project *
40c90888c75eed12f6e2e14a9044faf50bd4af8edThe Android Open Source Project * Licensed under the Apache License, Version 2.0 (the "License");
50c90888c75eed12f6e2e14a9044faf50bd4af8edThe Android Open Source Project * you may not use this file except in compliance with the License.
60c90888c75eed12f6e2e14a9044faf50bd4af8edThe Android Open Source Project * You may obtain a copy of the License at
70c90888c75eed12f6e2e14a9044faf50bd4af8edThe Android Open Source Project *
80c90888c75eed12f6e2e14a9044faf50bd4af8edThe Android Open Source Project *      http://www.apache.org/licenses/LICENSE-2.0
90c90888c75eed12f6e2e14a9044faf50bd4af8edThe Android Open Source Project *
100c90888c75eed12f6e2e14a9044faf50bd4af8edThe Android Open Source Project * Unless required by applicable law or agreed to in writing, software
110c90888c75eed12f6e2e14a9044faf50bd4af8edThe Android Open Source Project * distributed under the License is distributed on an "AS IS" BASIS,
120c90888c75eed12f6e2e14a9044faf50bd4af8edThe Android Open Source Project * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
130c90888c75eed12f6e2e14a9044faf50bd4af8edThe Android Open Source Project * See the License for the specific language governing permissions and
140c90888c75eed12f6e2e14a9044faf50bd4af8edThe Android Open Source Project * limitations under the License.
150c90888c75eed12f6e2e14a9044faf50bd4af8edThe Android Open Source Project */
160c90888c75eed12f6e2e14a9044faf50bd4af8edThe Android Open Source Project
170c90888c75eed12f6e2e14a9044faf50bd4af8edThe Android Open Source Projectpackage com.android.browser;
180c90888c75eed12f6e2e14a9044faf50bd4af8edThe Android Open Source Project
190c90888c75eed12f6e2e14a9044faf50bd4af8edThe Android Open Source Projectimport android.os.Bundle;
200c90888c75eed12f6e2e14a9044faf50bd4af8edThe Android Open Source Projectimport android.util.Log;
210c90888c75eed12f6e2e14a9044faf50bd4af8edThe Android Open Source Projectimport android.webkit.WebView;
220c90888c75eed12f6e2e14a9044faf50bd4af8edThe Android Open Source Project
230c90888c75eed12f6e2e14a9044faf50bd4af8edThe Android Open Source Projectimport java.util.ArrayList;
243d6df16f1c9a64cf2dc5b41a2078f4c49b0c296aElliott Slaughterimport java.util.HashMap;
251bf231334fd4bda8dbde5b9a0345c756a213b3a2Michael Kolbimport java.util.List;
260c90888c75eed12f6e2e14a9044faf50bd4af8edThe Android Open Source Projectimport java.util.Vector;
270c90888c75eed12f6e2e14a9044faf50bd4af8edThe Android Open Source Project
280c90888c75eed12f6e2e14a9044faf50bd4af8edThe Android Open Source Projectclass TabControl {
290c90888c75eed12f6e2e14a9044faf50bd4af8edThe Android Open Source Project    // Log Tag
300c90888c75eed12f6e2e14a9044faf50bd4af8edThe Android Open Source Project    private static final String LOGTAG = "TabControl";
31c831b63308dd1f8ef71808db8344ca2566ba4ed4Michael Kolb
32d8c7452a7d8975a2d60414c5a33842b4a743e631John Reck    // next Tab ID, starting at 1
33d8c7452a7d8975a2d60414c5a33842b4a743e631John Reck    private static long sNextId = 1;
34c831b63308dd1f8ef71808db8344ca2566ba4ed4Michael Kolb
35c831b63308dd1f8ef71808db8344ca2566ba4ed4Michael Kolb    private static final String POSITIONS = "positions";
36c831b63308dd1f8ef71808db8344ca2566ba4ed4Michael Kolb    private static final String CURRENT = "current";
37c831b63308dd1f8ef71808db8344ca2566ba4ed4Michael Kolb
388ee633fd62f94cd66c85c2904232d7c9e204cc9cJohn Reck    public static interface OnThumbnailUpdatedListener {
398ee633fd62f94cd66c85c2904232d7c9e204cc9cJohn Reck        void onThumbnailUpdated(Tab t);
408ee633fd62f94cd66c85c2904232d7c9e204cc9cJohn Reck    }
418ee633fd62f94cd66c85c2904232d7c9e204cc9cJohn Reck
420c90888c75eed12f6e2e14a9044faf50bd4af8edThe Android Open Source Project    // Maximum number of tabs.
436e4653ee2adbee765d210e44ed38600d79135a06Michael Kolb    private int mMaxTabs;
440c90888c75eed12f6e2e14a9044faf50bd4af8edThe Android Open Source Project    // Private array of WebViews that are used as tabs.
456e4653ee2adbee765d210e44ed38600d79135a06Michael Kolb    private ArrayList<Tab> mTabs;
460c90888c75eed12f6e2e14a9044faf50bd4af8edThe Android Open Source Project    // Queue of most recently viewed tabs.
476e4653ee2adbee765d210e44ed38600d79135a06Michael Kolb    private ArrayList<Tab> mTabQueue;
480c90888c75eed12f6e2e14a9044faf50bd4af8edThe Android Open Source Project    // Current position in mTabs.
490c90888c75eed12f6e2e14a9044faf50bd4af8edThe Android Open Source Project    private int mCurrentTab = -1;
508233facddcc51865d612a919d450db6954aa48e3Michael Kolb    // the main browser controller
518233facddcc51865d612a919d450db6954aa48e3Michael Kolb    private final Controller mController;
528233facddcc51865d612a919d450db6954aa48e3Michael Kolb
538ee633fd62f94cd66c85c2904232d7c9e204cc9cJohn Reck    private OnThumbnailUpdatedListener mOnThumbnailUpdatedListener;
540c90888c75eed12f6e2e14a9044faf50bd4af8edThe Android Open Source Project
550c90888c75eed12f6e2e14a9044faf50bd4af8edThe Android Open Source Project    /**
568233facddcc51865d612a919d450db6954aa48e3Michael Kolb     * Construct a new TabControl object
570c90888c75eed12f6e2e14a9044faf50bd4af8edThe Android Open Source Project     */
588233facddcc51865d612a919d450db6954aa48e3Michael Kolb    TabControl(Controller controller) {
598233facddcc51865d612a919d450db6954aa48e3Michael Kolb        mController = controller;
608233facddcc51865d612a919d450db6954aa48e3Michael Kolb        mMaxTabs = mController.getMaxTabs();
616e4653ee2adbee765d210e44ed38600d79135a06Michael Kolb        mTabs = new ArrayList<Tab>(mMaxTabs);
626e4653ee2adbee765d210e44ed38600d79135a06Michael Kolb        mTabQueue = new ArrayList<Tab>(mMaxTabs);
630c90888c75eed12f6e2e14a9044faf50bd4af8edThe Android Open Source Project    }
640c90888c75eed12f6e2e14a9044faf50bd4af8edThe Android Open Source Project
6552be4785a258687055515117775d5bcb8bec1c12John Reck    synchronized static long getNextId() {
66c831b63308dd1f8ef71808db8344ca2566ba4ed4Michael Kolb        return sNextId++;
67c831b63308dd1f8ef71808db8344ca2566ba4ed4Michael Kolb    }
68c831b63308dd1f8ef71808db8344ca2566ba4ed4Michael Kolb
6968775756e20243d73f273e4ce25ff3edeb148e41Michael Kolb    /**
700c90888c75eed12f6e2e14a9044faf50bd4af8edThe Android Open Source Project     * Return the current tab's main WebView. This will always return the main
710c90888c75eed12f6e2e14a9044faf50bd4af8edThe Android Open Source Project     * WebView for a given tab and not a subwindow.
720c90888c75eed12f6e2e14a9044faf50bd4af8edThe Android Open Source Project     * @return The current tab's WebView.
730c90888c75eed12f6e2e14a9044faf50bd4af8edThe Android Open Source Project     */
740c90888c75eed12f6e2e14a9044faf50bd4af8edThe Android Open Source Project    WebView getCurrentWebView() {
750c90888c75eed12f6e2e14a9044faf50bd4af8edThe Android Open Source Project        Tab t = getTab(mCurrentTab);
760c90888c75eed12f6e2e14a9044faf50bd4af8edThe Android Open Source Project        if (t == null) {
770c90888c75eed12f6e2e14a9044faf50bd4af8edThe Android Open Source Project            return null;
780c90888c75eed12f6e2e14a9044faf50bd4af8edThe Android Open Source Project        }
7922ac16eab0b62d24a99fc360f2ccea14837f4127Grace Kloba        return t.getWebView();
80bff2d603c022691237c31d9a57ad8c217c6e7e11Ben Murdoch    }
81bff2d603c022691237c31d9a57ad8c217c6e7e11Ben Murdoch
82bff2d603c022691237c31d9a57ad8c217c6e7e11Ben Murdoch    /**
830c90888c75eed12f6e2e14a9044faf50bd4af8edThe Android Open Source Project     * Return the current tab's top-level WebView. This can return a subwindow
840c90888c75eed12f6e2e14a9044faf50bd4af8edThe Android Open Source Project     * if one exists.
850c90888c75eed12f6e2e14a9044faf50bd4af8edThe Android Open Source Project     * @return The top-level WebView of the current tab.
860c90888c75eed12f6e2e14a9044faf50bd4af8edThe Android Open Source Project     */
870c90888c75eed12f6e2e14a9044faf50bd4af8edThe Android Open Source Project    WebView getCurrentTopWebView() {
880c90888c75eed12f6e2e14a9044faf50bd4af8edThe Android Open Source Project        Tab t = getTab(mCurrentTab);
890c90888c75eed12f6e2e14a9044faf50bd4af8edThe Android Open Source Project        if (t == null) {
900c90888c75eed12f6e2e14a9044faf50bd4af8edThe Android Open Source Project            return null;
910c90888c75eed12f6e2e14a9044faf50bd4af8edThe Android Open Source Project        }
9222ac16eab0b62d24a99fc360f2ccea14837f4127Grace Kloba        return t.getTopWindow();
930c90888c75eed12f6e2e14a9044faf50bd4af8edThe Android Open Source Project    }
940c90888c75eed12f6e2e14a9044faf50bd4af8edThe Android Open Source Project
950c90888c75eed12f6e2e14a9044faf50bd4af8edThe Android Open Source Project    /**
960c90888c75eed12f6e2e14a9044faf50bd4af8edThe Android Open Source Project     * Return the current tab's subwindow if it exists.
970c90888c75eed12f6e2e14a9044faf50bd4af8edThe Android Open Source Project     * @return The subwindow of the current tab or null if it doesn't exist.
980c90888c75eed12f6e2e14a9044faf50bd4af8edThe Android Open Source Project     */
990c90888c75eed12f6e2e14a9044faf50bd4af8edThe Android Open Source Project    WebView getCurrentSubWindow() {
1000c90888c75eed12f6e2e14a9044faf50bd4af8edThe Android Open Source Project        Tab t = getTab(mCurrentTab);
1010c90888c75eed12f6e2e14a9044faf50bd4af8edThe Android Open Source Project        if (t == null) {
1020c90888c75eed12f6e2e14a9044faf50bd4af8edThe Android Open Source Project            return null;
1030c90888c75eed12f6e2e14a9044faf50bd4af8edThe Android Open Source Project        }
10422ac16eab0b62d24a99fc360f2ccea14837f4127Grace Kloba        return t.getSubWebView();
1050c90888c75eed12f6e2e14a9044faf50bd4af8edThe Android Open Source Project    }
1060c90888c75eed12f6e2e14a9044faf50bd4af8edThe Android Open Source Project
1070c90888c75eed12f6e2e14a9044faf50bd4af8edThe Android Open Source Project    /**
1081bf231334fd4bda8dbde5b9a0345c756a213b3a2Michael Kolb     * return the list of tabs
1091bf231334fd4bda8dbde5b9a0345c756a213b3a2Michael Kolb     */
1101bf231334fd4bda8dbde5b9a0345c756a213b3a2Michael Kolb    List<Tab> getTabs() {
1111bf231334fd4bda8dbde5b9a0345c756a213b3a2Michael Kolb        return mTabs;
1121bf231334fd4bda8dbde5b9a0345c756a213b3a2Michael Kolb    }
1131bf231334fd4bda8dbde5b9a0345c756a213b3a2Michael Kolb
1141bf231334fd4bda8dbde5b9a0345c756a213b3a2Michael Kolb    /**
115c831b63308dd1f8ef71808db8344ca2566ba4ed4Michael Kolb     * Return the tab at the specified position.
116c831b63308dd1f8ef71808db8344ca2566ba4ed4Michael Kolb     * @return The Tab for the specified position or null if the tab does not
1170c90888c75eed12f6e2e14a9044faf50bd4af8edThe Android Open Source Project     *         exist.
1180c90888c75eed12f6e2e14a9044faf50bd4af8edThe Android Open Source Project     */
119c831b63308dd1f8ef71808db8344ca2566ba4ed4Michael Kolb    Tab getTab(int position) {
120c831b63308dd1f8ef71808db8344ca2566ba4ed4Michael Kolb        if (position >= 0 && position < mTabs.size()) {
121c831b63308dd1f8ef71808db8344ca2566ba4ed4Michael Kolb            return mTabs.get(position);
1220c90888c75eed12f6e2e14a9044faf50bd4af8edThe Android Open Source Project        }
1230c90888c75eed12f6e2e14a9044faf50bd4af8edThe Android Open Source Project        return null;
1240c90888c75eed12f6e2e14a9044faf50bd4af8edThe Android Open Source Project    }
1250c90888c75eed12f6e2e14a9044faf50bd4af8edThe Android Open Source Project
1260c90888c75eed12f6e2e14a9044faf50bd4af8edThe Android Open Source Project    /**
1270c90888c75eed12f6e2e14a9044faf50bd4af8edThe Android Open Source Project     * Return the current tab.
1280c90888c75eed12f6e2e14a9044faf50bd4af8edThe Android Open Source Project     * @return The current tab.
1290c90888c75eed12f6e2e14a9044faf50bd4af8edThe Android Open Source Project     */
1300c90888c75eed12f6e2e14a9044faf50bd4af8edThe Android Open Source Project    Tab getCurrentTab() {
1310c90888c75eed12f6e2e14a9044faf50bd4af8edThe Android Open Source Project        return getTab(mCurrentTab);
1320c90888c75eed12f6e2e14a9044faf50bd4af8edThe Android Open Source Project    }
1330c90888c75eed12f6e2e14a9044faf50bd4af8edThe Android Open Source Project
1340c90888c75eed12f6e2e14a9044faf50bd4af8edThe Android Open Source Project    /**
135c831b63308dd1f8ef71808db8344ca2566ba4ed4Michael Kolb     * Return the current tab position.
136c831b63308dd1f8ef71808db8344ca2566ba4ed4Michael Kolb     * @return The current tab position
1370c90888c75eed12f6e2e14a9044faf50bd4af8edThe Android Open Source Project     */
138c831b63308dd1f8ef71808db8344ca2566ba4ed4Michael Kolb    int getCurrentPosition() {
1390c90888c75eed12f6e2e14a9044faf50bd4af8edThe Android Open Source Project        return mCurrentTab;
1400c90888c75eed12f6e2e14a9044faf50bd4af8edThe Android Open Source Project    }
141fe25199a6f975c67d28afcc1de56b0f987b66cd8Michael Kolb
1420c90888c75eed12f6e2e14a9044faf50bd4af8edThe Android Open Source Project    /**
143c831b63308dd1f8ef71808db8344ca2566ba4ed4Michael Kolb     * Given a Tab, find it's position
1440c90888c75eed12f6e2e14a9044faf50bd4af8edThe Android Open Source Project     * @param Tab to find
145c831b63308dd1f8ef71808db8344ca2566ba4ed4Michael Kolb     * @return position of Tab or -1 if not found
1460c90888c75eed12f6e2e14a9044faf50bd4af8edThe Android Open Source Project     */
147c831b63308dd1f8ef71808db8344ca2566ba4ed4Michael Kolb    int getTabPosition(Tab tab) {
148ae641ac4bbe1c7c3fb235774cb84d910573595c7Patrick Scott        if (tab == null) {
149ae641ac4bbe1c7c3fb235774cb84d910573595c7Patrick Scott            return -1;
150ae641ac4bbe1c7c3fb235774cb84d910573595c7Patrick Scott        }
1510c90888c75eed12f6e2e14a9044faf50bd4af8edThe Android Open Source Project        return mTabs.indexOf(tab);
1520c90888c75eed12f6e2e14a9044faf50bd4af8edThe Android Open Source Project    }
1530c90888c75eed12f6e2e14a9044faf50bd4af8edThe Android Open Source Project
15422ac16eab0b62d24a99fc360f2ccea14837f4127Grace Kloba    boolean canCreateNewTab() {
155c3ad9eada3ab7acac5d194fd4a8d30443079e80eNarayan Kamath        return mMaxTabs > mTabs.size();
15622ac16eab0b62d24a99fc360f2ccea14837f4127Grace Kloba    }
15722ac16eab0b62d24a99fc360f2ccea14837f4127Grace Kloba
1580c90888c75eed12f6e2e14a9044faf50bd4af8edThe Android Open Source Project    /**
159e440a88fd81c86d1ca6fc18b8b3f68e383e574b4Elliott Slaughter     * Returns true if there are any incognito tabs open.
160e440a88fd81c86d1ca6fc18b8b3f68e383e574b4Elliott Slaughter     * @return True when any incognito tabs are open, false otherwise.
161e440a88fd81c86d1ca6fc18b8b3f68e383e574b4Elliott Slaughter     */
162e440a88fd81c86d1ca6fc18b8b3f68e383e574b4Elliott Slaughter    boolean hasAnyOpenIncognitoTabs() {
163e440a88fd81c86d1ca6fc18b8b3f68e383e574b4Elliott Slaughter        for (Tab tab : mTabs) {
164c831b63308dd1f8ef71808db8344ca2566ba4ed4Michael Kolb            if (tab.getWebView() != null
165c831b63308dd1f8ef71808db8344ca2566ba4ed4Michael Kolb                    && tab.getWebView().isPrivateBrowsingEnabled()) {
166e440a88fd81c86d1ca6fc18b8b3f68e383e574b4Elliott Slaughter                return true;
167e440a88fd81c86d1ca6fc18b8b3f68e383e574b4Elliott Slaughter            }
168e440a88fd81c86d1ca6fc18b8b3f68e383e574b4Elliott Slaughter        }
169e440a88fd81c86d1ca6fc18b8b3f68e383e574b4Elliott Slaughter        return false;
170e440a88fd81c86d1ca6fc18b8b3f68e383e574b4Elliott Slaughter    }
171e440a88fd81c86d1ca6fc18b8b3f68e383e574b4Elliott Slaughter
1721461244018a225006a8d4c203f9dfe294ffe94faMichael Kolb    void addPreloadedTab(Tab tab) {
173e09305e4ad0430571efb8ae880762204ddeaeb33Mathew Inwood        for (Tab current : mTabs) {
174e09305e4ad0430571efb8ae880762204ddeaeb33Mathew Inwood            if (current != null && current.getId() == tab.getId()) {
175e09305e4ad0430571efb8ae880762204ddeaeb33Mathew Inwood                throw new IllegalStateException("Tab with id " + tab.getId() + " already exists: "
176e09305e4ad0430571efb8ae880762204ddeaeb33Mathew Inwood                        + current.toString());
177e09305e4ad0430571efb8ae880762204ddeaeb33Mathew Inwood            }
178e09305e4ad0430571efb8ae880762204ddeaeb33Mathew Inwood        }
1791461244018a225006a8d4c203f9dfe294ffe94faMichael Kolb        mTabs.add(tab);
1801461244018a225006a8d4c203f9dfe294ffe94faMichael Kolb        tab.setController(mController);
1811461244018a225006a8d4c203f9dfe294ffe94faMichael Kolb        mController.onSetWebView(tab, tab.getWebView());
1821461244018a225006a8d4c203f9dfe294ffe94faMichael Kolb        tab.putInBackground();
1831461244018a225006a8d4c203f9dfe294ffe94faMichael Kolb    }
1841461244018a225006a8d4c203f9dfe294ffe94faMichael Kolb
185e440a88fd81c86d1ca6fc18b8b3f68e383e574b4Elliott Slaughter    /**
186f59ec877363eaf43118677f249008eddc7a9ce11The Android Open Source Project     * Create a new tab.
1870c90888c75eed12f6e2e14a9044faf50bd4af8edThe Android Open Source Project     * @return The newly createTab or null if we have reached the maximum
1880c90888c75eed12f6e2e14a9044faf50bd4af8edThe Android Open Source Project     *         number of open tabs.
1890c90888c75eed12f6e2e14a9044faf50bd4af8edThe Android Open Source Project     */
1907bcafde2ba532941c1eb8c9022eebd5398aeae2aMichael Kolb    Tab createNewTab(boolean privateBrowsing) {
1911cf4b79a0020bc18c83ca8bde0e318ecd5252bc2John Reck        return createNewTab(null, privateBrowsing);
1921cf4b79a0020bc18c83ca8bde0e318ecd5252bc2John Reck    }
1931cf4b79a0020bc18c83ca8bde0e318ecd5252bc2John Reck
1941cf4b79a0020bc18c83ca8bde0e318ecd5252bc2John Reck    Tab createNewTab(Bundle state, boolean privateBrowsing) {
1951cf4b79a0020bc18c83ca8bde0e318ecd5252bc2John Reck        int size = mTabs.size();
1961cf4b79a0020bc18c83ca8bde0e318ecd5252bc2John Reck        // Return false if we have maxed out on tabs
197c3ad9eada3ab7acac5d194fd4a8d30443079e80eNarayan Kamath        if (!canCreateNewTab()) {
1980c90888c75eed12f6e2e14a9044faf50bd4af8edThe Android Open Source Project            return null;
1990c90888c75eed12f6e2e14a9044faf50bd4af8edThe Android Open Source Project        }
200c3ad9eada3ab7acac5d194fd4a8d30443079e80eNarayan Kamath
201f0f03954b3092296c58dcb040e2dabd1696dd5c4Elliott Slaughter        final WebView w = createNewWebView(privateBrowsing);
2022bc69918d97a767a02132090e58718077381ba1aSteve Block
2030c90888c75eed12f6e2e14a9044faf50bd4af8edThe Android Open Source Project        // Create a new tab and add it to the tab list
2041cf4b79a0020bc18c83ca8bde0e318ecd5252bc2John Reck        Tab t = new Tab(mController, w, state);
2050c90888c75eed12f6e2e14a9044faf50bd4af8edThe Android Open Source Project        mTabs.add(t);
2064e5f58704099c37186d4825c3d55ea5b0527867fThe Android Open Source Project        // Initially put the tab in the background.
20722ac16eab0b62d24a99fc360f2ccea14837f4127Grace Kloba        t.putInBackground();
2080c90888c75eed12f6e2e14a9044faf50bd4af8edThe Android Open Source Project        return t;
2090c90888c75eed12f6e2e14a9044faf50bd4af8edThe Android Open Source Project    }
2100c90888c75eed12f6e2e14a9044faf50bd4af8edThe Android Open Source Project
2110c90888c75eed12f6e2e14a9044faf50bd4af8edThe Android Open Source Project    /**
212f59ec877363eaf43118677f249008eddc7a9ce11The Android Open Source Project     * Create a new tab with default values for closeOnExit(false),
213f0f03954b3092296c58dcb040e2dabd1696dd5c4Elliott Slaughter     * appId(null), url(null), and privateBrowsing(false).
214f59ec877363eaf43118677f249008eddc7a9ce11The Android Open Source Project     */
215f59ec877363eaf43118677f249008eddc7a9ce11The Android Open Source Project    Tab createNewTab() {
2167bcafde2ba532941c1eb8c9022eebd5398aeae2aMichael Kolb        return createNewTab(false);
217f59ec877363eaf43118677f249008eddc7a9ce11The Android Open Source Project    }
218f59ec877363eaf43118677f249008eddc7a9ce11The Android Open Source Project
219d8c7452a7d8975a2d60414c5a33842b4a743e631John Reck    SnapshotTab createSnapshotTab(long snapshotId) {
220d8c7452a7d8975a2d60414c5a33842b4a743e631John Reck        SnapshotTab t = new SnapshotTab(mController, snapshotId);
221d8c7452a7d8975a2d60414c5a33842b4a743e631John Reck        mTabs.add(t);
222d8c7452a7d8975a2d60414c5a33842b4a743e631John Reck        return t;
223d8c7452a7d8975a2d60414c5a33842b4a743e631John Reck    }
224d8c7452a7d8975a2d60414c5a33842b4a743e631John Reck
225f59ec877363eaf43118677f249008eddc7a9ce11The Android Open Source Project    /**
226fde9746ac3055848e110c35f19ec5893c621f766Leon Scroggins     * Remove the parent child relationships from all tabs.
227fde9746ac3055848e110c35f19ec5893c621f766Leon Scroggins     */
228fde9746ac3055848e110c35f19ec5893c621f766Leon Scroggins    void removeParentChildRelationShips() {
229fde9746ac3055848e110c35f19ec5893c621f766Leon Scroggins        for (Tab tab : mTabs) {
230fde9746ac3055848e110c35f19ec5893c621f766Leon Scroggins            tab.removeFromTree();
231fde9746ac3055848e110c35f19ec5893c621f766Leon Scroggins        }
232fde9746ac3055848e110c35f19ec5893c621f766Leon Scroggins    }
233fde9746ac3055848e110c35f19ec5893c621f766Leon Scroggins
234fde9746ac3055848e110c35f19ec5893c621f766Leon Scroggins    /**
2350c90888c75eed12f6e2e14a9044faf50bd4af8edThe Android Open Source Project     * Remove the tab from the list. If the tab is the current tab shown, the
2360c90888c75eed12f6e2e14a9044faf50bd4af8edThe Android Open Source Project     * last created tab will be shown.
2370c90888c75eed12f6e2e14a9044faf50bd4af8edThe Android Open Source Project     * @param t The tab to be removed.
2380c90888c75eed12f6e2e14a9044faf50bd4af8edThe Android Open Source Project     */
2390c90888c75eed12f6e2e14a9044faf50bd4af8edThe Android Open Source Project    boolean removeTab(Tab t) {
2400c90888c75eed12f6e2e14a9044faf50bd4af8edThe Android Open Source Project        if (t == null) {
2410c90888c75eed12f6e2e14a9044faf50bd4af8edThe Android Open Source Project            return false;
2420c90888c75eed12f6e2e14a9044faf50bd4af8edThe Android Open Source Project        }
24322ac16eab0b62d24a99fc360f2ccea14837f4127Grace Kloba
244d944d4d63c9e93b51fae38fc86f0d87fff0e3a21Patrick Scott        // Grab the current tab before modifying the list.
245d944d4d63c9e93b51fae38fc86f0d87fff0e3a21Patrick Scott        Tab current = getCurrentTab();
246d944d4d63c9e93b51fae38fc86f0d87fff0e3a21Patrick Scott
247d944d4d63c9e93b51fae38fc86f0d87fff0e3a21Patrick Scott        // Remove t from our list of tabs.
248d944d4d63c9e93b51fae38fc86f0d87fff0e3a21Patrick Scott        mTabs.remove(t);
249d944d4d63c9e93b51fae38fc86f0d87fff0e3a21Patrick Scott
250d944d4d63c9e93b51fae38fc86f0d87fff0e3a21Patrick Scott        // Put the tab in the background only if it is the current one.
251d944d4d63c9e93b51fae38fc86f0d87fff0e3a21Patrick Scott        if (current == t) {
25222ac16eab0b62d24a99fc360f2ccea14837f4127Grace Kloba            t.putInBackground();
25322ac16eab0b62d24a99fc360f2ccea14837f4127Grace Kloba            mCurrentTab = -1;
254d944d4d63c9e93b51fae38fc86f0d87fff0e3a21Patrick Scott        } else {
255d944d4d63c9e93b51fae38fc86f0d87fff0e3a21Patrick Scott            // If a tab that is earlier in the list gets removed, the current
256d944d4d63c9e93b51fae38fc86f0d87fff0e3a21Patrick Scott            // index no longer points to the correct tab.
257c831b63308dd1f8ef71808db8344ca2566ba4ed4Michael Kolb            mCurrentTab = getTabPosition(current);
2580c90888c75eed12f6e2e14a9044faf50bd4af8edThe Android Open Source Project        }
2590c90888c75eed12f6e2e14a9044faf50bd4af8edThe Android Open Source Project
26022ac16eab0b62d24a99fc360f2ccea14837f4127Grace Kloba        // destroy the tab
26122ac16eab0b62d24a99fc360f2ccea14837f4127Grace Kloba        t.destroy();
2620c90888c75eed12f6e2e14a9044faf50bd4af8edThe Android Open Source Project        // clear it's references to parent and children
2630c90888c75eed12f6e2e14a9044faf50bd4af8edThe Android Open Source Project        t.removeFromTree();
2640c90888c75eed12f6e2e14a9044faf50bd4af8edThe Android Open Source Project
2650c90888c75eed12f6e2e14a9044faf50bd4af8edThe Android Open Source Project        // Remove it from the queue of viewed tabs.
2660c90888c75eed12f6e2e14a9044faf50bd4af8edThe Android Open Source Project        mTabQueue.remove(t);
2670c90888c75eed12f6e2e14a9044faf50bd4af8edThe Android Open Source Project        return true;
2680c90888c75eed12f6e2e14a9044faf50bd4af8edThe Android Open Source Project    }
2690c90888c75eed12f6e2e14a9044faf50bd4af8edThe Android Open Source Project
2700c90888c75eed12f6e2e14a9044faf50bd4af8edThe Android Open Source Project    /**
2710c90888c75eed12f6e2e14a9044faf50bd4af8edThe Android Open Source Project     * Destroy all the tabs and subwindows
2720c90888c75eed12f6e2e14a9044faf50bd4af8edThe Android Open Source Project     */
2730c90888c75eed12f6e2e14a9044faf50bd4af8edThe Android Open Source Project    void destroy() {
2740c90888c75eed12f6e2e14a9044faf50bd4af8edThe Android Open Source Project        for (Tab t : mTabs) {
27522ac16eab0b62d24a99fc360f2ccea14837f4127Grace Kloba            t.destroy();
2760c90888c75eed12f6e2e14a9044faf50bd4af8edThe Android Open Source Project        }
2770c90888c75eed12f6e2e14a9044faf50bd4af8edThe Android Open Source Project        mTabs.clear();
2780c90888c75eed12f6e2e14a9044faf50bd4af8edThe Android Open Source Project        mTabQueue.clear();
2790c90888c75eed12f6e2e14a9044faf50bd4af8edThe Android Open Source Project    }
2800c90888c75eed12f6e2e14a9044faf50bd4af8edThe Android Open Source Project
2810c90888c75eed12f6e2e14a9044faf50bd4af8edThe Android Open Source Project    /**
2820c90888c75eed12f6e2e14a9044faf50bd4af8edThe Android Open Source Project     * Returns the number of tabs created.
2830c90888c75eed12f6e2e14a9044faf50bd4af8edThe Android Open Source Project     * @return The number of tabs created.
2840c90888c75eed12f6e2e14a9044faf50bd4af8edThe Android Open Source Project     */
2850c90888c75eed12f6e2e14a9044faf50bd4af8edThe Android Open Source Project    int getTabCount() {
2860c90888c75eed12f6e2e14a9044faf50bd4af8edThe Android Open Source Project        return mTabs.size();
2870c90888c75eed12f6e2e14a9044faf50bd4af8edThe Android Open Source Project    }
2880c90888c75eed12f6e2e14a9044faf50bd4af8edThe Android Open Source Project
2890c90888c75eed12f6e2e14a9044faf50bd4af8edThe Android Open Source Project    /**
290c831b63308dd1f8ef71808db8344ca2566ba4ed4Michael Kolb     * save the tab state:
291c831b63308dd1f8ef71808db8344ca2566ba4ed4Michael Kolb     * current position
292c831b63308dd1f8ef71808db8344ca2566ba4ed4Michael Kolb     * position sorted array of tab ids
293c831b63308dd1f8ef71808db8344ca2566ba4ed4Michael Kolb     * for each tab id, save the tab state
294c831b63308dd1f8ef71808db8344ca2566ba4ed4Michael Kolb     * @param outState
295aed9c54d8e67bb683a5a415b3775525a3ac00508John Reck     * @param saveImages
2960c90888c75eed12f6e2e14a9044faf50bd4af8edThe Android Open Source Project     */
2971cf4b79a0020bc18c83ca8bde0e318ecd5252bc2John Reck    void saveState(Bundle outState) {
2980c90888c75eed12f6e2e14a9044faf50bd4af8edThe Android Open Source Project        final int numTabs = getTabCount();
29924f1826440334ba8a3d2453699c51c1a4b117c7bJohn Reck        if (numTabs == 0) {
30024f1826440334ba8a3d2453699c51c1a4b117c7bJohn Reck            return;
30124f1826440334ba8a3d2453699c51c1a4b117c7bJohn Reck        }
302c831b63308dd1f8ef71808db8344ca2566ba4ed4Michael Kolb        long[] ids = new long[numTabs];
303c831b63308dd1f8ef71808db8344ca2566ba4ed4Michael Kolb        int i = 0;
304c831b63308dd1f8ef71808db8344ca2566ba4ed4Michael Kolb        for (Tab tab : mTabs) {
3051cf4b79a0020bc18c83ca8bde0e318ecd5252bc2John Reck            Bundle tabState = tab.saveState();
3061cf4b79a0020bc18c83ca8bde0e318ecd5252bc2John Reck            if (tabState != null) {
3073ae7f74a64fd1dc101910f1b14f315b34d1f1274Michael Kolb                ids[i++] = tab.getId();
30852be4785a258687055515117775d5bcb8bec1c12John Reck                String key = Long.toString(tab.getId());
30952be4785a258687055515117775d5bcb8bec1c12John Reck                if (outState.containsKey(key)) {
31052be4785a258687055515117775d5bcb8bec1c12John Reck                    // Dump the tab state for debugging purposes
31152be4785a258687055515117775d5bcb8bec1c12John Reck                    for (Tab dt : mTabs) {
31252be4785a258687055515117775d5bcb8bec1c12John Reck                        Log.e(LOGTAG, dt.toString());
31352be4785a258687055515117775d5bcb8bec1c12John Reck                    }
31452be4785a258687055515117775d5bcb8bec1c12John Reck                    throw new IllegalStateException(
31552be4785a258687055515117775d5bcb8bec1c12John Reck                            "Error saving state, duplicate tab ids!");
31652be4785a258687055515117775d5bcb8bec1c12John Reck                }
31752be4785a258687055515117775d5bcb8bec1c12John Reck                outState.putBundle(key, tabState);
3183ae7f74a64fd1dc101910f1b14f315b34d1f1274Michael Kolb            } else {
3193ae7f74a64fd1dc101910f1b14f315b34d1f1274Michael Kolb                ids[i++] = -1;
32052be4785a258687055515117775d5bcb8bec1c12John Reck                // Since we won't be restoring the thumbnail, delete it
32152be4785a258687055515117775d5bcb8bec1c12John Reck                tab.deleteThumbnail();
3220c90888c75eed12f6e2e14a9044faf50bd4af8edThe Android Open Source Project            }
3230c90888c75eed12f6e2e14a9044faf50bd4af8edThe Android Open Source Project        }
32424f1826440334ba8a3d2453699c51c1a4b117c7bJohn Reck        if (!outState.isEmpty()) {
32524f1826440334ba8a3d2453699c51c1a4b117c7bJohn Reck            outState.putLongArray(POSITIONS, ids);
32624f1826440334ba8a3d2453699c51c1a4b117c7bJohn Reck            Tab current = getCurrentTab();
32724f1826440334ba8a3d2453699c51c1a4b117c7bJohn Reck            long cid = -1;
32824f1826440334ba8a3d2453699c51c1a4b117c7bJohn Reck            if (current != null) {
32924f1826440334ba8a3d2453699c51c1a4b117c7bJohn Reck                cid = current.getId();
33024f1826440334ba8a3d2453699c51c1a4b117c7bJohn Reck            }
33124f1826440334ba8a3d2453699c51c1a4b117c7bJohn Reck            outState.putLong(CURRENT, cid);
332dbf3981ccbacb11a99c262fc5ebbece62b207a2dMichael Kolb        }
3330c90888c75eed12f6e2e14a9044faf50bd4af8edThe Android Open Source Project    }
3340c90888c75eed12f6e2e14a9044faf50bd4af8edThe Android Open Source Project
3350c90888c75eed12f6e2e14a9044faf50bd4af8edThe Android Open Source Project    /**
3367d50a9364107c21e3358e1dbc51a06359a5287fbPatrick Scott     * Check if the state can be restored.  If the state can be restored, the
337c831b63308dd1f8ef71808db8344ca2566ba4ed4Michael Kolb     * current tab id is returned.  This can be passed to restoreState below
3387d50a9364107c21e3358e1dbc51a06359a5287fbPatrick Scott     * in order to restore the correct tab.  Otherwise, -1 is returned and the
3397d50a9364107c21e3358e1dbc51a06359a5287fbPatrick Scott     * state cannot be restored.
3407d50a9364107c21e3358e1dbc51a06359a5287fbPatrick Scott     */
341c831b63308dd1f8ef71808db8344ca2566ba4ed4Michael Kolb    long canRestoreState(Bundle inState, boolean restoreIncognitoTabs) {
342c831b63308dd1f8ef71808db8344ca2566ba4ed4Michael Kolb        final long[] ids = (inState == null) ? null : inState.getLongArray(POSITIONS);
343c831b63308dd1f8ef71808db8344ca2566ba4ed4Michael Kolb        if (ids == null) {
3447d50a9364107c21e3358e1dbc51a06359a5287fbPatrick Scott            return -1;
3457d50a9364107c21e3358e1dbc51a06359a5287fbPatrick Scott        }
346c831b63308dd1f8ef71808db8344ca2566ba4ed4Michael Kolb        final long oldcurrent = inState.getLong(CURRENT);
347c831b63308dd1f8ef71808db8344ca2566ba4ed4Michael Kolb        long current = -1;
3483ae7f74a64fd1dc101910f1b14f315b34d1f1274Michael Kolb        if (restoreIncognitoTabs || (hasState(oldcurrent, inState) && !isIncognito(oldcurrent, inState))) {
3491cf4b79a0020bc18c83ca8bde0e318ecd5252bc2John Reck            current = oldcurrent;
3507d50a9364107c21e3358e1dbc51a06359a5287fbPatrick Scott        } else {
351c831b63308dd1f8ef71808db8344ca2566ba4ed4Michael Kolb            // pick first non incognito tab
352c831b63308dd1f8ef71808db8344ca2566ba4ed4Michael Kolb            for (long id : ids) {
3533ae7f74a64fd1dc101910f1b14f315b34d1f1274Michael Kolb                if (hasState(id, inState) && !isIncognito(id, inState)) {
354c831b63308dd1f8ef71808db8344ca2566ba4ed4Michael Kolb                    current = id;
3557d50a9364107c21e3358e1dbc51a06359a5287fbPatrick Scott                    break;
3567d50a9364107c21e3358e1dbc51a06359a5287fbPatrick Scott                }
3577d50a9364107c21e3358e1dbc51a06359a5287fbPatrick Scott            }
3587d50a9364107c21e3358e1dbc51a06359a5287fbPatrick Scott        }
359c831b63308dd1f8ef71808db8344ca2566ba4ed4Michael Kolb        return current;
3607d50a9364107c21e3358e1dbc51a06359a5287fbPatrick Scott    }
3617d50a9364107c21e3358e1dbc51a06359a5287fbPatrick Scott
3623ae7f74a64fd1dc101910f1b14f315b34d1f1274Michael Kolb    private boolean hasState(long id, Bundle state) {
3633ae7f74a64fd1dc101910f1b14f315b34d1f1274Michael Kolb        if (id == -1) return false;
3643ae7f74a64fd1dc101910f1b14f315b34d1f1274Michael Kolb        Bundle tab = state.getBundle(Long.toString(id));
3653ae7f74a64fd1dc101910f1b14f315b34d1f1274Michael Kolb        return ((tab != null) && !tab.isEmpty());
3663ae7f74a64fd1dc101910f1b14f315b34d1f1274Michael Kolb    }
3673ae7f74a64fd1dc101910f1b14f315b34d1f1274Michael Kolb
3683ae7f74a64fd1dc101910f1b14f315b34d1f1274Michael Kolb    private boolean isIncognito(long id, Bundle state) {
3693ae7f74a64fd1dc101910f1b14f315b34d1f1274Michael Kolb        Bundle tabstate = state.getBundle(Long.toString(id));
3703ae7f74a64fd1dc101910f1b14f315b34d1f1274Michael Kolb        if ((tabstate != null) && !tabstate.isEmpty()) {
3713ae7f74a64fd1dc101910f1b14f315b34d1f1274Michael Kolb            return tabstate.getBoolean(Tab.INCOGNITO);
3723ae7f74a64fd1dc101910f1b14f315b34d1f1274Michael Kolb        }
3733ae7f74a64fd1dc101910f1b14f315b34d1f1274Michael Kolb        return false;
3743ae7f74a64fd1dc101910f1b14f315b34d1f1274Michael Kolb    }
3753ae7f74a64fd1dc101910f1b14f315b34d1f1274Michael Kolb
3767d50a9364107c21e3358e1dbc51a06359a5287fbPatrick Scott    /**
3770c90888c75eed12f6e2e14a9044faf50bd4af8edThe Android Open Source Project     * Restore the state of all the tabs.
378c831b63308dd1f8ef71808db8344ca2566ba4ed4Michael Kolb     * @param currentId The tab id to restore.
3790c90888c75eed12f6e2e14a9044faf50bd4af8edThe Android Open Source Project     * @param inState The saved state of all the tabs.
3801bf231334fd4bda8dbde5b9a0345c756a213b3a2Michael Kolb     * @param restoreIncognitoTabs Restoring private browsing tabs
3811bf231334fd4bda8dbde5b9a0345c756a213b3a2Michael Kolb     * @param restoreAll All webviews get restored, not just the current tab
3821bf231334fd4bda8dbde5b9a0345c756a213b3a2Michael Kolb     *        (this does not override handling of incognito tabs)
3830c90888c75eed12f6e2e14a9044faf50bd4af8edThe Android Open Source Project     */
384c831b63308dd1f8ef71808db8344ca2566ba4ed4Michael Kolb    void restoreState(Bundle inState, long currentId,
3857d50a9364107c21e3358e1dbc51a06359a5287fbPatrick Scott            boolean restoreIncognitoTabs, boolean restoreAll) {
386c831b63308dd1f8ef71808db8344ca2566ba4ed4Michael Kolb        if (currentId == -1) {
3877d50a9364107c21e3358e1dbc51a06359a5287fbPatrick Scott            return;
3887d50a9364107c21e3358e1dbc51a06359a5287fbPatrick Scott        }
389c831b63308dd1f8ef71808db8344ca2566ba4ed4Michael Kolb        long[] ids = inState.getLongArray(POSITIONS);
390c831b63308dd1f8ef71808db8344ca2566ba4ed4Michael Kolb        long maxId = -Long.MAX_VALUE;
391c831b63308dd1f8ef71808db8344ca2566ba4ed4Michael Kolb        HashMap<Long, Tab> tabMap = new HashMap<Long, Tab>();
392c831b63308dd1f8ef71808db8344ca2566ba4ed4Michael Kolb        for (long id : ids) {
393c831b63308dd1f8ef71808db8344ca2566ba4ed4Michael Kolb            if (id > maxId) {
394c831b63308dd1f8ef71808db8344ca2566ba4ed4Michael Kolb                maxId = id;
395c831b63308dd1f8ef71808db8344ca2566ba4ed4Michael Kolb            }
396c831b63308dd1f8ef71808db8344ca2566ba4ed4Michael Kolb            final String idkey = Long.toString(id);
397c831b63308dd1f8ef71808db8344ca2566ba4ed4Michael Kolb            Bundle state = inState.getBundle(idkey);
398d8c7452a7d8975a2d60414c5a33842b4a743e631John Reck            if (state == null || state.isEmpty()) {
399d8c7452a7d8975a2d60414c5a33842b4a743e631John Reck                // Skip tab
400d8c7452a7d8975a2d60414c5a33842b4a743e631John Reck                continue;
401d8c7452a7d8975a2d60414c5a33842b4a743e631John Reck            } else if (!restoreIncognitoTabs
402c831b63308dd1f8ef71808db8344ca2566ba4ed4Michael Kolb                    && state.getBoolean(Tab.INCOGNITO)) {
403c831b63308dd1f8ef71808db8344ca2566ba4ed4Michael Kolb                // ignore tab
404c831b63308dd1f8ef71808db8344ca2566ba4ed4Michael Kolb            } else if (id == currentId || restoreAll) {
4051cf4b79a0020bc18c83ca8bde0e318ecd5252bc2John Reck                Tab t = createNewTab(state, false);
40679e5d8d14609a2d5bc5cac8daf7cad1cc9a98d4eNarayan Kamath                if (t == null) {
40779e5d8d14609a2d5bc5cac8daf7cad1cc9a98d4eNarayan Kamath                    // We could "break" at this point, but we want
40879e5d8d14609a2d5bc5cac8daf7cad1cc9a98d4eNarayan Kamath                    // sNextId to be set correctly.
40979e5d8d14609a2d5bc5cac8daf7cad1cc9a98d4eNarayan Kamath                    continue;
41079e5d8d14609a2d5bc5cac8daf7cad1cc9a98d4eNarayan Kamath                }
411c831b63308dd1f8ef71808db8344ca2566ba4ed4Michael Kolb                tabMap.put(id, t);
4127d50a9364107c21e3358e1dbc51a06359a5287fbPatrick Scott                // Me must set the current tab before restoring the state
4137d50a9364107c21e3358e1dbc51a06359a5287fbPatrick Scott                // so that all the client classes are set.
414c831b63308dd1f8ef71808db8344ca2566ba4ed4Michael Kolb                if (id == currentId) {
4157d50a9364107c21e3358e1dbc51a06359a5287fbPatrick Scott                    setCurrentTab(t);
4167d50a9364107c21e3358e1dbc51a06359a5287fbPatrick Scott                }
4177d50a9364107c21e3358e1dbc51a06359a5287fbPatrick Scott            } else {
4187d50a9364107c21e3358e1dbc51a06359a5287fbPatrick Scott                // Create a new tab and don't restore the state yet, add it
4197d50a9364107c21e3358e1dbc51a06359a5287fbPatrick Scott                // to the tab list
4201cf4b79a0020bc18c83ca8bde0e318ecd5252bc2John Reck                Tab t = new Tab(mController, state);
421c831b63308dd1f8ef71808db8344ca2566ba4ed4Michael Kolb                tabMap.put(id, t);
4227d50a9364107c21e3358e1dbc51a06359a5287fbPatrick Scott                mTabs.add(t);
4237d50a9364107c21e3358e1dbc51a06359a5287fbPatrick Scott                // added the tab to the front as they are not current
4247d50a9364107c21e3358e1dbc51a06359a5287fbPatrick Scott                mTabQueue.add(0, t);
4250c90888c75eed12f6e2e14a9044faf50bd4af8edThe Android Open Source Project            }
426c831b63308dd1f8ef71808db8344ca2566ba4ed4Michael Kolb        }
42779e5d8d14609a2d5bc5cac8daf7cad1cc9a98d4eNarayan Kamath
42879e5d8d14609a2d5bc5cac8daf7cad1cc9a98d4eNarayan Kamath        // make sure that there is no id overlap between the restored
42979e5d8d14609a2d5bc5cac8daf7cad1cc9a98d4eNarayan Kamath        // and new tabs
43079e5d8d14609a2d5bc5cac8daf7cad1cc9a98d4eNarayan Kamath        sNextId = maxId + 1;
43179e5d8d14609a2d5bc5cac8daf7cad1cc9a98d4eNarayan Kamath
432d8c7452a7d8975a2d60414c5a33842b4a743e631John Reck        if (mCurrentTab == -1) {
433d8c7452a7d8975a2d60414c5a33842b4a743e631John Reck            if (getTabCount() > 0) {
434d8c7452a7d8975a2d60414c5a33842b4a743e631John Reck                setCurrentTab(getTab(0));
435d8c7452a7d8975a2d60414c5a33842b4a743e631John Reck            }
436d8c7452a7d8975a2d60414c5a33842b4a743e631John Reck        }
437c831b63308dd1f8ef71808db8344ca2566ba4ed4Michael Kolb        // restore parent/child relationships
438c831b63308dd1f8ef71808db8344ca2566ba4ed4Michael Kolb        for (long id : ids) {
439c831b63308dd1f8ef71808db8344ca2566ba4ed4Michael Kolb            final Tab tab = tabMap.get(id);
440c831b63308dd1f8ef71808db8344ca2566ba4ed4Michael Kolb            final Bundle b = inState.getBundle(Long.toString(id));
441c831b63308dd1f8ef71808db8344ca2566ba4ed4Michael Kolb            if ((b != null) && (tab != null)) {
442c831b63308dd1f8ef71808db8344ca2566ba4ed4Michael Kolb                final long parentId = b.getLong(Tab.PARENTTAB, -1);
443c831b63308dd1f8ef71808db8344ca2566ba4ed4Michael Kolb                if (parentId != -1) {
444c831b63308dd1f8ef71808db8344ca2566ba4ed4Michael Kolb                    final Tab parent = tabMap.get(parentId);
4457d50a9364107c21e3358e1dbc51a06359a5287fbPatrick Scott                    if (parent != null) {
446c831b63308dd1f8ef71808db8344ca2566ba4ed4Michael Kolb                        parent.addChildTab(tab);
4470c90888c75eed12f6e2e14a9044faf50bd4af8edThe Android Open Source Project                    }
4480c90888c75eed12f6e2e14a9044faf50bd4af8edThe Android Open Source Project                }
4490c90888c75eed12f6e2e14a9044faf50bd4af8edThe Android Open Source Project            }
4500c90888c75eed12f6e2e14a9044faf50bd4af8edThe Android Open Source Project        }
4510c90888c75eed12f6e2e14a9044faf50bd4af8edThe Android Open Source Project    }
4520c90888c75eed12f6e2e14a9044faf50bd4af8edThe Android Open Source Project
4530c90888c75eed12f6e2e14a9044faf50bd4af8edThe Android Open Source Project    /**
454f56f68d291ae26ff25db4dc62122692c1dd1f4f9Grace Kloba     * Free the memory in this order, 1) free the background tabs; 2) free the
4550c90888c75eed12f6e2e14a9044faf50bd4af8edThe Android Open Source Project     * WebView cache;
4560c90888c75eed12f6e2e14a9044faf50bd4af8edThe Android Open Source Project     */
4570c90888c75eed12f6e2e14a9044faf50bd4af8edThe Android Open Source Project    void freeMemory() {
45892c18a52ca7a79c114028b5ba22c3dfe443bd1a4Grace Kloba        if (getTabCount() == 0) return;
45992c18a52ca7a79c114028b5ba22c3dfe443bd1a4Grace Kloba
460f56f68d291ae26ff25db4dc62122692c1dd1f4f9Grace Kloba        // free the least frequently used background tabs
461f56f68d291ae26ff25db4dc62122692c1dd1f4f9Grace Kloba        Vector<Tab> tabs = getHalfLeastUsedTabs(getCurrentTab());
462f56f68d291ae26ff25db4dc62122692c1dd1f4f9Grace Kloba        if (tabs.size() > 0) {
463f56f68d291ae26ff25db4dc62122692c1dd1f4f9Grace Kloba            Log.w(LOGTAG, "Free " + tabs.size() + " tabs in the browser");
464f56f68d291ae26ff25db4dc62122692c1dd1f4f9Grace Kloba            for (Tab t : tabs) {
465f56f68d291ae26ff25db4dc62122692c1dd1f4f9Grace Kloba                // store the WebView's state.
466f56f68d291ae26ff25db4dc62122692c1dd1f4f9Grace Kloba                t.saveState();
467f56f68d291ae26ff25db4dc62122692c1dd1f4f9Grace Kloba                // destroy the tab
468f56f68d291ae26ff25db4dc62122692c1dd1f4f9Grace Kloba                t.destroy();
469f56f68d291ae26ff25db4dc62122692c1dd1f4f9Grace Kloba            }
4700c90888c75eed12f6e2e14a9044faf50bd4af8edThe Android Open Source Project            return;
4710c90888c75eed12f6e2e14a9044faf50bd4af8edThe Android Open Source Project        }
4720c90888c75eed12f6e2e14a9044faf50bd4af8edThe Android Open Source Project
4734433d0333f18ea1e5c5c531db48908665c6f8446Derek Sollenberger        // free the WebView's unused memory (this includes the cache)
4744433d0333f18ea1e5c5c531db48908665c6f8446Derek Sollenberger        Log.w(LOGTAG, "Free WebView's unused memory and cache");
4750c90888c75eed12f6e2e14a9044faf50bd4af8edThe Android Open Source Project        WebView view = getCurrentWebView();
4760c90888c75eed12f6e2e14a9044faf50bd4af8edThe Android Open Source Project        if (view != null) {
4774433d0333f18ea1e5c5c531db48908665c6f8446Derek Sollenberger            view.freeMemory();
4780c90888c75eed12f6e2e14a9044faf50bd4af8edThe Android Open Source Project        }
4790c90888c75eed12f6e2e14a9044faf50bd4af8edThe Android Open Source Project    }
4800c90888c75eed12f6e2e14a9044faf50bd4af8edThe Android Open Source Project
481f56f68d291ae26ff25db4dc62122692c1dd1f4f9Grace Kloba    private Vector<Tab> getHalfLeastUsedTabs(Tab current) {
482f56f68d291ae26ff25db4dc62122692c1dd1f4f9Grace Kloba        Vector<Tab> tabsToGo = new Vector<Tab>();
483f56f68d291ae26ff25db4dc62122692c1dd1f4f9Grace Kloba
4842a67de4059775466071da52c07b18627c51c677cPatrick Scott        // Don't do anything if we only have 1 tab or if the current tab is
4852a67de4059775466071da52c07b18627c51c677cPatrick Scott        // null.
4862a67de4059775466071da52c07b18627c51c677cPatrick Scott        if (getTabCount() == 1 || current == null) {
487f56f68d291ae26ff25db4dc62122692c1dd1f4f9Grace Kloba            return tabsToGo;
4880c90888c75eed12f6e2e14a9044faf50bd4af8edThe Android Open Source Project        }
4890c90888c75eed12f6e2e14a9044faf50bd4af8edThe Android Open Source Project
490f56f68d291ae26ff25db4dc62122692c1dd1f4f9Grace Kloba        if (mTabQueue.size() == 0) {
491f56f68d291ae26ff25db4dc62122692c1dd1f4f9Grace Kloba            return tabsToGo;
4920c90888c75eed12f6e2e14a9044faf50bd4af8edThe Android Open Source Project        }
493f56f68d291ae26ff25db4dc62122692c1dd1f4f9Grace Kloba
494f56f68d291ae26ff25db4dc62122692c1dd1f4f9Grace Kloba        // Rip through the queue starting at the beginning and tear down half of
495f56f68d291ae26ff25db4dc62122692c1dd1f4f9Grace Kloba        // available tabs which are not the current tab or the parent of the
496f56f68d291ae26ff25db4dc62122692c1dd1f4f9Grace Kloba        // current tab.
497f56f68d291ae26ff25db4dc62122692c1dd1f4f9Grace Kloba        int openTabCount = 0;
498f56f68d291ae26ff25db4dc62122692c1dd1f4f9Grace Kloba        for (Tab t : mTabQueue) {
499f56f68d291ae26ff25db4dc62122692c1dd1f4f9Grace Kloba            if (t != null && t.getWebView() != null) {
500f56f68d291ae26ff25db4dc62122692c1dd1f4f9Grace Kloba                openTabCount++;
501c831b63308dd1f8ef71808db8344ca2566ba4ed4Michael Kolb                if (t != current && t != current.getParent()) {
502f56f68d291ae26ff25db4dc62122692c1dd1f4f9Grace Kloba                    tabsToGo.add(t);
503f56f68d291ae26ff25db4dc62122692c1dd1f4f9Grace Kloba                }
504f56f68d291ae26ff25db4dc62122692c1dd1f4f9Grace Kloba            }
5050c90888c75eed12f6e2e14a9044faf50bd4af8edThe Android Open Source Project        }
5060c90888c75eed12f6e2e14a9044faf50bd4af8edThe Android Open Source Project
507f56f68d291ae26ff25db4dc62122692c1dd1f4f9Grace Kloba        openTabCount /= 2;
508f56f68d291ae26ff25db4dc62122692c1dd1f4f9Grace Kloba        if (tabsToGo.size() > openTabCount) {
509f56f68d291ae26ff25db4dc62122692c1dd1f4f9Grace Kloba            tabsToGo.setSize(openTabCount);
510f56f68d291ae26ff25db4dc62122692c1dd1f4f9Grace Kloba        }
511f56f68d291ae26ff25db4dc62122692c1dd1f4f9Grace Kloba
512f56f68d291ae26ff25db4dc62122692c1dd1f4f9Grace Kloba        return tabsToGo;
5130c90888c75eed12f6e2e14a9044faf50bd4af8edThe Android Open Source Project    }
5140c90888c75eed12f6e2e14a9044faf50bd4af8edThe Android Open Source Project
515ff6a748ae78165cc2298f5120a4374b4ed6f836bMichael Kolb    Tab getLeastUsedTab(Tab current) {
516ff6a748ae78165cc2298f5120a4374b4ed6f836bMichael Kolb        if (getTabCount() == 1 || current == null) {
517ff6a748ae78165cc2298f5120a4374b4ed6f836bMichael Kolb            return null;
518ff6a748ae78165cc2298f5120a4374b4ed6f836bMichael Kolb        }
519ff6a748ae78165cc2298f5120a4374b4ed6f836bMichael Kolb        if (mTabQueue.size() == 0) {
520ff6a748ae78165cc2298f5120a4374b4ed6f836bMichael Kolb            return null;
521ff6a748ae78165cc2298f5120a4374b4ed6f836bMichael Kolb        }
522ff6a748ae78165cc2298f5120a4374b4ed6f836bMichael Kolb        // find a tab which is not the current tab or the parent of the
523ff6a748ae78165cc2298f5120a4374b4ed6f836bMichael Kolb        // current tab
524ff6a748ae78165cc2298f5120a4374b4ed6f836bMichael Kolb        for (Tab t : mTabQueue) {
525ff6a748ae78165cc2298f5120a4374b4ed6f836bMichael Kolb            if (t != null && t.getWebView() != null) {
526ff6a748ae78165cc2298f5120a4374b4ed6f836bMichael Kolb                if (t != current && t != current.getParent()) {
527ff6a748ae78165cc2298f5120a4374b4ed6f836bMichael Kolb                    return t;
528ff6a748ae78165cc2298f5120a4374b4ed6f836bMichael Kolb                }
529ff6a748ae78165cc2298f5120a4374b4ed6f836bMichael Kolb            }
530ff6a748ae78165cc2298f5120a4374b4ed6f836bMichael Kolb        }
531ff6a748ae78165cc2298f5120a4374b4ed6f836bMichael Kolb        return null;
532ff6a748ae78165cc2298f5120a4374b4ed6f836bMichael Kolb    }
533ff6a748ae78165cc2298f5120a4374b4ed6f836bMichael Kolb
5340c90888c75eed12f6e2e14a9044faf50bd4af8edThe Android Open Source Project    /**
5350c90888c75eed12f6e2e14a9044faf50bd4af8edThe Android Open Source Project     * Show the tab that contains the given WebView.
5360c90888c75eed12f6e2e14a9044faf50bd4af8edThe Android Open Source Project     * @param view The WebView used to find the tab.
5370c90888c75eed12f6e2e14a9044faf50bd4af8edThe Android Open Source Project     */
5380c90888c75eed12f6e2e14a9044faf50bd4af8edThe Android Open Source Project    Tab getTabFromView(WebView view) {
539c831b63308dd1f8ef71808db8344ca2566ba4ed4Michael Kolb        for (Tab t : mTabs) {
54022ac16eab0b62d24a99fc360f2ccea14837f4127Grace Kloba            if (t.getSubWebView() == view || t.getWebView() == view) {
5410c90888c75eed12f6e2e14a9044faf50bd4af8edThe Android Open Source Project                return t;
5420c90888c75eed12f6e2e14a9044faf50bd4af8edThe Android Open Source Project            }
5430c90888c75eed12f6e2e14a9044faf50bd4af8edThe Android Open Source Project        }
5440c90888c75eed12f6e2e14a9044faf50bd4af8edThe Android Open Source Project        return null;
5450c90888c75eed12f6e2e14a9044faf50bd4af8edThe Android Open Source Project    }
5460c90888c75eed12f6e2e14a9044faf50bd4af8edThe Android Open Source Project
5470c90888c75eed12f6e2e14a9044faf50bd4af8edThe Android Open Source Project    /**
548f59ec877363eaf43118677f249008eddc7a9ce11The Android Open Source Project     * Return the tab with the matching application id.
549f59ec877363eaf43118677f249008eddc7a9ce11The Android Open Source Project     * @param id The application identifier.
550f59ec877363eaf43118677f249008eddc7a9ce11The Android Open Source Project     */
551c831b63308dd1f8ef71808db8344ca2566ba4ed4Michael Kolb    Tab getTabFromAppId(String id) {
552f59ec877363eaf43118677f249008eddc7a9ce11The Android Open Source Project        if (id == null) {
553f59ec877363eaf43118677f249008eddc7a9ce11The Android Open Source Project            return null;
554f59ec877363eaf43118677f249008eddc7a9ce11The Android Open Source Project        }
555c831b63308dd1f8ef71808db8344ca2566ba4ed4Michael Kolb        for (Tab t : mTabs) {
55622ac16eab0b62d24a99fc360f2ccea14837f4127Grace Kloba            if (id.equals(t.getAppId())) {
557f59ec877363eaf43118677f249008eddc7a9ce11The Android Open Source Project                return t;
558f59ec877363eaf43118677f249008eddc7a9ce11The Android Open Source Project            }
559f59ec877363eaf43118677f249008eddc7a9ce11The Android Open Source Project        }
560f59ec877363eaf43118677f249008eddc7a9ce11The Android Open Source Project        return null;
561f59ec877363eaf43118677f249008eddc7a9ce11The Android Open Source Project    }
562f59ec877363eaf43118677f249008eddc7a9ce11The Android Open Source Project
56322ac16eab0b62d24a99fc360f2ccea14837f4127Grace Kloba    /**
56422ac16eab0b62d24a99fc360f2ccea14837f4127Grace Kloba     * Stop loading in all opened WebView including subWindows.
56522ac16eab0b62d24a99fc360f2ccea14837f4127Grace Kloba     */
5665d0e02e646e46b14289168f75c2a8f6ed43cac54Grace Kloba    void stopAllLoading() {
567c831b63308dd1f8ef71808db8344ca2566ba4ed4Michael Kolb        for (Tab t : mTabs) {
56822ac16eab0b62d24a99fc360f2ccea14837f4127Grace Kloba            final WebView webview = t.getWebView();
5695d0e02e646e46b14289168f75c2a8f6ed43cac54Grace Kloba            if (webview != null) {
5705d0e02e646e46b14289168f75c2a8f6ed43cac54Grace Kloba                webview.stopLoading();
5715d0e02e646e46b14289168f75c2a8f6ed43cac54Grace Kloba            }
57222ac16eab0b62d24a99fc360f2ccea14837f4127Grace Kloba            final WebView subview = t.getSubWebView();
57322ac16eab0b62d24a99fc360f2ccea14837f4127Grace Kloba            if (subview != null) {
5749727af8453990808bd0a104bd9ceb8671e335ab5Mattias Nilsson                subview.stopLoading();
57522ac16eab0b62d24a99fc360f2ccea14837f4127Grace Kloba            }
5765d0e02e646e46b14289168f75c2a8f6ed43cac54Grace Kloba        }
5775d0e02e646e46b14289168f75c2a8f6ed43cac54Grace Kloba    }
5785d0e02e646e46b14289168f75c2a8f6ed43cac54Grace Kloba
579db22ec4ee014900988062d910bc810172a07df56John Reck    // This method checks if a tab matches the given url.
580cd11589fc3930906d4b9b7dd18aa52a9f1eb0c8aPatrick Scott    private boolean tabMatchesUrl(Tab t, String url) {
581db22ec4ee014900988062d910bc810172a07df56John Reck        return url.equals(t.getUrl()) || url.equals(t.getOriginalUrl());
582cd11589fc3930906d4b9b7dd18aa52a9f1eb0c8aPatrick Scott    }
583cd11589fc3930906d4b9b7dd18aa52a9f1eb0c8aPatrick Scott
584cd11589fc3930906d4b9b7dd18aa52a9f1eb0c8aPatrick Scott    /**
585db22ec4ee014900988062d910bc810172a07df56John Reck     * Return the tab that matches the given url.
586cd11589fc3930906d4b9b7dd18aa52a9f1eb0c8aPatrick Scott     * @param url The url to search for.
587cd11589fc3930906d4b9b7dd18aa52a9f1eb0c8aPatrick Scott     */
588db22ec4ee014900988062d910bc810172a07df56John Reck    Tab findTabWithUrl(String url) {
589cd11589fc3930906d4b9b7dd18aa52a9f1eb0c8aPatrick Scott        if (url == null) {
590cd11589fc3930906d4b9b7dd18aa52a9f1eb0c8aPatrick Scott            return null;
591cd11589fc3930906d4b9b7dd18aa52a9f1eb0c8aPatrick Scott        }
592cd11589fc3930906d4b9b7dd18aa52a9f1eb0c8aPatrick Scott        // Check the current tab first.
593db22ec4ee014900988062d910bc810172a07df56John Reck        Tab currentTab = getCurrentTab();
594db22ec4ee014900988062d910bc810172a07df56John Reck        if (currentTab != null && tabMatchesUrl(currentTab, url)) {
595db22ec4ee014900988062d910bc810172a07df56John Reck            return currentTab;
596cd11589fc3930906d4b9b7dd18aa52a9f1eb0c8aPatrick Scott        }
597cd11589fc3930906d4b9b7dd18aa52a9f1eb0c8aPatrick Scott        // Now check all the rest.
598c831b63308dd1f8ef71808db8344ca2566ba4ed4Michael Kolb        for (Tab tab : mTabs) {
599c831b63308dd1f8ef71808db8344ca2566ba4ed4Michael Kolb            if (tabMatchesUrl(tab, url)) {
600db22ec4ee014900988062d910bc810172a07df56John Reck                return tab;
601cd11589fc3930906d4b9b7dd18aa52a9f1eb0c8aPatrick Scott            }
602cd11589fc3930906d4b9b7dd18aa52a9f1eb0c8aPatrick Scott        }
603cd11589fc3930906d4b9b7dd18aa52a9f1eb0c8aPatrick Scott        return null;
604cd11589fc3930906d4b9b7dd18aa52a9f1eb0c8aPatrick Scott    }
605cd11589fc3930906d4b9b7dd18aa52a9f1eb0c8aPatrick Scott
606f59ec877363eaf43118677f249008eddc7a9ce11The Android Open Source Project    /**
60730c714c853a4239e72ab1e238ce2a92472d06ab0John Reck     * Recreate the main WebView of the given tab.
608f59ec877363eaf43118677f249008eddc7a9ce11The Android Open Source Project     */
60930c714c853a4239e72ab1e238ce2a92472d06ab0John Reck    void recreateWebView(Tab t) {
61022ac16eab0b62d24a99fc360f2ccea14837f4127Grace Kloba        final WebView w = t.getWebView();
611f59ec877363eaf43118677f249008eddc7a9ce11The Android Open Source Project        if (w != null) {
61222ac16eab0b62d24a99fc360f2ccea14837f4127Grace Kloba            t.destroy();
613f59ec877363eaf43118677f249008eddc7a9ce11The Android Open Source Project        }
614f59ec877363eaf43118677f249008eddc7a9ce11The Android Open Source Project        // Create a new WebView. If this tab is the current tab, we need to put
615f59ec877363eaf43118677f249008eddc7a9ce11The Android Open Source Project        // back all the clients so force it to be the current tab.
61691911a26058418e622950cffc616f99ada49df1dMichael Kolb        t.setWebView(createNewWebView(), false);
617f59ec877363eaf43118677f249008eddc7a9ce11The Android Open Source Project        if (getCurrentTab() == t) {
618f59ec877363eaf43118677f249008eddc7a9ce11The Android Open Source Project            setCurrentTab(t, true);
619f59ec877363eaf43118677f249008eddc7a9ce11The Android Open Source Project        }
620f59ec877363eaf43118677f249008eddc7a9ce11The Android Open Source Project    }
621f59ec877363eaf43118677f249008eddc7a9ce11The Android Open Source Project
622f59ec877363eaf43118677f249008eddc7a9ce11The Android Open Source Project    /**
623f59ec877363eaf43118677f249008eddc7a9ce11The Android Open Source Project     * Creates a new WebView and registers it with the global settings.
624f59ec877363eaf43118677f249008eddc7a9ce11The Android Open Source Project     */
625f59ec877363eaf43118677f249008eddc7a9ce11The Android Open Source Project    private WebView createNewWebView() {
626f0f03954b3092296c58dcb040e2dabd1696dd5c4Elliott Slaughter        return createNewWebView(false);
627f0f03954b3092296c58dcb040e2dabd1696dd5c4Elliott Slaughter    }
628f0f03954b3092296c58dcb040e2dabd1696dd5c4Elliott Slaughter
629f0f03954b3092296c58dcb040e2dabd1696dd5c4Elliott Slaughter    /**
630f0f03954b3092296c58dcb040e2dabd1696dd5c4Elliott Slaughter     * Creates a new WebView and registers it with the global settings.
631f0f03954b3092296c58dcb040e2dabd1696dd5c4Elliott Slaughter     * @param privateBrowsing When true, enables private browsing in the new
632f0f03954b3092296c58dcb040e2dabd1696dd5c4Elliott Slaughter     *        WebView.
633f0f03954b3092296c58dcb040e2dabd1696dd5c4Elliott Slaughter     */
634f0f03954b3092296c58dcb040e2dabd1696dd5c4Elliott Slaughter    private WebView createNewWebView(boolean privateBrowsing) {
6358233facddcc51865d612a919d450db6954aa48e3Michael Kolb        return mController.getWebViewFactory().createWebView(privateBrowsing);
636f59ec877363eaf43118677f249008eddc7a9ce11The Android Open Source Project    }
637f59ec877363eaf43118677f249008eddc7a9ce11The Android Open Source Project
638f59ec877363eaf43118677f249008eddc7a9ce11The Android Open Source Project    /**
6390c90888c75eed12f6e2e14a9044faf50bd4af8edThe Android Open Source Project     * Put the current tab in the background and set newTab as the current tab.
6400c90888c75eed12f6e2e14a9044faf50bd4af8edThe Android Open Source Project     * @param newTab The new tab. If newTab is null, the current tab is not
6410c90888c75eed12f6e2e14a9044faf50bd4af8edThe Android Open Source Project     *               set.
6420c90888c75eed12f6e2e14a9044faf50bd4af8edThe Android Open Source Project     */
6430c90888c75eed12f6e2e14a9044faf50bd4af8edThe Android Open Source Project    boolean setCurrentTab(Tab newTab) {
644f59ec877363eaf43118677f249008eddc7a9ce11The Android Open Source Project        return setCurrentTab(newTab, false);
645f59ec877363eaf43118677f249008eddc7a9ce11The Android Open Source Project    }
646f59ec877363eaf43118677f249008eddc7a9ce11The Android Open Source Project
647f59ec877363eaf43118677f249008eddc7a9ce11The Android Open Source Project    /**
648f59ec877363eaf43118677f249008eddc7a9ce11The Android Open Source Project     * If force is true, this method skips the check for newTab == current.
649f59ec877363eaf43118677f249008eddc7a9ce11The Android Open Source Project     */
650f59ec877363eaf43118677f249008eddc7a9ce11The Android Open Source Project    private boolean setCurrentTab(Tab newTab, boolean force) {
6510c90888c75eed12f6e2e14a9044faf50bd4af8edThe Android Open Source Project        Tab current = getTab(mCurrentTab);
652f59ec877363eaf43118677f249008eddc7a9ce11The Android Open Source Project        if (current == newTab && !force) {
6530c90888c75eed12f6e2e14a9044faf50bd4af8edThe Android Open Source Project            return true;
6540c90888c75eed12f6e2e14a9044faf50bd4af8edThe Android Open Source Project        }
6550c90888c75eed12f6e2e14a9044faf50bd4af8edThe Android Open Source Project        if (current != null) {
65622ac16eab0b62d24a99fc360f2ccea14837f4127Grace Kloba            current.putInBackground();
65722ac16eab0b62d24a99fc360f2ccea14837f4127Grace Kloba            mCurrentTab = -1;
6580c90888c75eed12f6e2e14a9044faf50bd4af8edThe Android Open Source Project        }
6590c90888c75eed12f6e2e14a9044faf50bd4af8edThe Android Open Source Project        if (newTab == null) {
6600c90888c75eed12f6e2e14a9044faf50bd4af8edThe Android Open Source Project            return false;
6610c90888c75eed12f6e2e14a9044faf50bd4af8edThe Android Open Source Project        }
6620c90888c75eed12f6e2e14a9044faf50bd4af8edThe Android Open Source Project
6630c90888c75eed12f6e2e14a9044faf50bd4af8edThe Android Open Source Project        // Move the newTab to the end of the queue
6640c90888c75eed12f6e2e14a9044faf50bd4af8edThe Android Open Source Project        int index = mTabQueue.indexOf(newTab);
6650c90888c75eed12f6e2e14a9044faf50bd4af8edThe Android Open Source Project        if (index != -1) {
6660c90888c75eed12f6e2e14a9044faf50bd4af8edThe Android Open Source Project            mTabQueue.remove(index);
6670c90888c75eed12f6e2e14a9044faf50bd4af8edThe Android Open Source Project        }
6680c90888c75eed12f6e2e14a9044faf50bd4af8edThe Android Open Source Project        mTabQueue.add(newTab);
6690c90888c75eed12f6e2e14a9044faf50bd4af8edThe Android Open Source Project
6700c90888c75eed12f6e2e14a9044faf50bd4af8edThe Android Open Source Project        // Display the new current tab
6710c90888c75eed12f6e2e14a9044faf50bd4af8edThe Android Open Source Project        mCurrentTab = mTabs.indexOf(newTab);
67222ac16eab0b62d24a99fc360f2ccea14837f4127Grace Kloba        WebView mainView = newTab.getWebView();
673d8c7452a7d8975a2d60414c5a33842b4a743e631John Reck        boolean needRestore = !newTab.isSnapshot() && (mainView == null);
6740c90888c75eed12f6e2e14a9044faf50bd4af8edThe Android Open Source Project        if (needRestore) {
6750c90888c75eed12f6e2e14a9044faf50bd4af8edThe Android Open Source Project            // Same work as in createNewTab() except don't do new Tab()
6762bc69918d97a767a02132090e58718077381ba1aSteve Block            mainView = createNewWebView();
6772bc69918d97a767a02132090e58718077381ba1aSteve Block            newTab.setWebView(mainView);
6780c90888c75eed12f6e2e14a9044faf50bd4af8edThe Android Open Source Project        }
67922ac16eab0b62d24a99fc360f2ccea14837f4127Grace Kloba        newTab.putInForeground();
6800c90888c75eed12f6e2e14a9044faf50bd4af8edThe Android Open Source Project        return true;
6810c90888c75eed12f6e2e14a9044faf50bd4af8edThe Android Open Source Project    }
682fe25199a6f975c67d28afcc1de56b0f987b66cd8Michael Kolb
6838ee633fd62f94cd66c85c2904232d7c9e204cc9cJohn Reck    public void setOnThumbnailUpdatedListener(OnThumbnailUpdatedListener listener) {
6848ee633fd62f94cd66c85c2904232d7c9e204cc9cJohn Reck        mOnThumbnailUpdatedListener = listener;
6858ee633fd62f94cd66c85c2904232d7c9e204cc9cJohn Reck        for (Tab t : mTabs) {
6868ee633fd62f94cd66c85c2904232d7c9e204cc9cJohn Reck            WebView web = t.getWebView();
6878ee633fd62f94cd66c85c2904232d7c9e204cc9cJohn Reck            if (web != null) {
6888ee633fd62f94cd66c85c2904232d7c9e204cc9cJohn Reck                web.setPictureListener(listener != null ? t : null);
6898ee633fd62f94cd66c85c2904232d7c9e204cc9cJohn Reck            }
6908ee633fd62f94cd66c85c2904232d7c9e204cc9cJohn Reck        }
6918ee633fd62f94cd66c85c2904232d7c9e204cc9cJohn Reck    }
6928ee633fd62f94cd66c85c2904232d7c9e204cc9cJohn Reck
6938ee633fd62f94cd66c85c2904232d7c9e204cc9cJohn Reck    public OnThumbnailUpdatedListener getOnThumbnailUpdatedListener() {
6948ee633fd62f94cd66c85c2904232d7c9e204cc9cJohn Reck        return mOnThumbnailUpdatedListener;
6958ee633fd62f94cd66c85c2904232d7c9e204cc9cJohn Reck    }
6968ee633fd62f94cd66c85c2904232d7c9e204cc9cJohn Reck
6970c90888c75eed12f6e2e14a9044faf50bd4af8edThe Android Open Source Project}
698