Move Tab out of TabControl to its own class. So that
each tab has its own WebViewClient, WebChromeClient, 
ErrorConsoleView, lock icon type and inLoad (matching
mPageStarted) state.

Clean up BrowserActivity, TabControl, create a new Tab class.

Fix stopAllLoading() to stop all main window and sub window loading.

Remove mScale/mScrollX/Y from PickerData as it is not used any more.

Remove doFlick/SensorManager as it is not used any more.

Remove whiteList as it is not used any more.

Remove MASF proxy service as it is not used any more.

With this change,
we will take the snapshot even when it is in the background.
we will update the touchicon url even when it is in the background.
we will update the bookmark/history even when it is in the background.
we will update database quota and max appCache size even when it is in the background.
we will show the error dialog of the background tab when it is brought to the foreground. (New behavior)
we will update the lock icon correctly when switching tabs.
we will proceed the http auth request for the background tab if we already have username and password.

Fix http://b/issue?id=2158621
diff --git a/src/com/android/browser/TabControl.java b/src/com/android/browser/TabControl.java
index 40f6c31..8373182 100644
--- a/src/com/android/browser/TabControl.java
+++ b/src/com/android/browser/TabControl.java
@@ -16,33 +16,13 @@
 
 package com.android.browser;
 
-import android.content.Context;
-import android.graphics.Bitmap;
-import android.graphics.Picture;
-import android.net.http.SslError;
 import android.os.Bundle;
-import android.os.Message;
 import android.util.Log;
-import android.view.Gravity;
-import android.view.LayoutInflater;
 import android.view.View;
-import android.view.ViewGroup;
-import android.view.View.OnClickListener;
-import android.webkit.HttpAuthHandler;
-import android.webkit.JsPromptResult;
-import android.webkit.JsResult;
-import android.webkit.SslErrorHandler;
 import android.webkit.WebBackForwardList;
-import android.webkit.WebChromeClient;
-import android.webkit.WebHistoryItem;
 import android.webkit.WebView;
-import android.webkit.WebViewClient;
-import android.widget.FrameLayout;
-import android.widget.ImageButton;
-import android.widget.LinearLayout;
 
 import java.io.File;
-import java.io.FileInputStream;
 import java.util.ArrayList;
 import java.util.Vector;
 
@@ -50,13 +30,7 @@
     // Log Tag
     private static final String LOGTAG = "TabControl";
     // Maximum number of tabs.
-    static final int MAX_TABS = 8;
-    // Static instance of an empty callback.
-    private static final WebViewClient mEmptyClient =
-            new WebViewClient();
-    // Instance of BackgroundChromeClient for background tabs.
-    private final BackgroundChromeClient mBackgroundChromeClient =
-            new BackgroundChromeClient();
+    private static final int MAX_TABS = 8;
     // Private array of WebViews that are used as tabs.
     private ArrayList<Tab> mTabs = new ArrayList<Tab>(MAX_TABS);
     // Queue of most recently viewed tabs.
@@ -66,393 +40,6 @@
     // A private instance of BrowserActivity to interface with when adding and
     // switching between tabs.
     private final BrowserActivity mActivity;
-    // Inflation service for making subwindows.
-    private final LayoutInflater mInflateService;
-    // Subclass of WebViewClient used in subwindows to notify the main
-    // WebViewClient of certain WebView activities.
-    private static class SubWindowClient extends WebViewClient {
-        // The main WebViewClient.
-        private final WebViewClient mClient;
-
-        SubWindowClient(WebViewClient client) {
-            mClient = client;
-        }
-        @Override
-        public void doUpdateVisitedHistory(WebView view, String url,
-                boolean isReload) {
-            mClient.doUpdateVisitedHistory(view, url, isReload);
-        }
-        @Override
-        public boolean shouldOverrideUrlLoading(WebView view, String url) {
-            return mClient.shouldOverrideUrlLoading(view, url);
-        }
-        @Override
-        public void onReceivedSslError(WebView view, SslErrorHandler handler,
-                SslError error) {
-            mClient.onReceivedSslError(view, handler, error);
-        }
-        @Override
-        public void onReceivedHttpAuthRequest(WebView view,
-                HttpAuthHandler handler, String host, String realm) {
-            mClient.onReceivedHttpAuthRequest(view, handler, host, realm);
-        }
-        @Override
-        public void onFormResubmission(WebView view, Message dontResend,
-                Message resend) {
-            mClient.onFormResubmission(view, dontResend, resend);
-        }
-        @Override
-        public void onReceivedError(WebView view, int errorCode,
-                String description, String failingUrl) {
-            mClient.onReceivedError(view, errorCode, description, failingUrl);
-        }
-        @Override
-        public boolean shouldOverrideKeyEvent(WebView view,
-                android.view.KeyEvent event) {
-            return mClient.shouldOverrideKeyEvent(view, event);
-        }
-        @Override
-        public void onUnhandledKeyEvent(WebView view,
-                android.view.KeyEvent event) {
-            mClient.onUnhandledKeyEvent(view, event);
-        }
-    }
-    // Subclass of WebChromeClient to display javascript dialogs.
-    private class SubWindowChromeClient extends WebChromeClient {
-        // This subwindow's tab.
-        private final Tab mTab;
-        // The main WebChromeClient.
-        private final WebChromeClient mClient;
-
-        SubWindowChromeClient(Tab t, WebChromeClient client) {
-            mTab = t;
-            mClient = client;
-        }
-        @Override
-        public void onProgressChanged(WebView view, int newProgress) {
-            mClient.onProgressChanged(view, newProgress);
-        }
-        @Override
-        public boolean onCreateWindow(WebView view, boolean dialog,
-                boolean userGesture, android.os.Message resultMsg) {
-            return mClient.onCreateWindow(view, dialog, userGesture, resultMsg);
-        }
-        @Override
-        public void onCloseWindow(WebView window) {
-            if (Browser.DEBUG && window != mTab.mSubView) {
-                throw new AssertionError("Can't close the window");
-            }
-            mActivity.dismissSubWindow(mTab);
-        }
-    }
-    // Background WebChromeClient for focusing tabs
-    private class BackgroundChromeClient extends WebChromeClient {
-        @Override
-        public void onRequestFocus(WebView view) {
-            Tab t = getTabFromView(view);
-            if (t != getCurrentTab()) {
-                mActivity.switchToTab(getTabIndex(t));
-            }
-        }
-    }
-
-    // Extra saved information for displaying the tab in the picker.
-    public static class PickerData {
-        String  mUrl;
-        String  mTitle;
-        Bitmap  mFavicon;
-        float   mScale;
-        int     mScrollX;
-        int     mScrollY;
-    }
-
-    /**
-     * Private class for maintaining Tabs with a main WebView and a subwindow.
-     */
-    public class Tab {
-        // The Geolocation permissions prompt
-        private GeolocationPermissionsPrompt mGeolocationPermissionsPrompt;
-        private View mContainer;
-        // Main WebView
-        private WebView mMainView;
-        // Subwindow WebView
-        private WebView mSubView;
-        // Subwindow container
-        private View mSubViewContainer;
-        // Subwindow callback
-        private SubWindowClient mSubViewClient;
-        // Subwindow chrome callback
-        private SubWindowChromeClient mSubViewChromeClient;
-        // Saved bundle for when we are running low on memory. It contains the
-        // information needed to restore the WebView if the user goes back to
-        // the tab.
-        private Bundle mSavedState;
-        // Data used when displaying the tab in the picker.
-        private PickerData mPickerData;
-
-        // Parent Tab. This is the Tab that created this Tab, or null
-        // if the Tab was created by the UI
-        private Tab mParentTab;
-        // Tab that constructed by this Tab. This is used when this
-        // Tab is destroyed, it clears all mParentTab values in the 
-        // children.
-        private Vector<Tab> mChildTabs;
-
-        private Boolean mCloseOnExit;
-        // Application identifier used to find tabs that another application
-        // wants to reuse.
-        private String mAppId;
-        // Keep the original url around to avoid killing the old WebView if the
-        // url has not changed.
-        private String mOriginalUrl;
-
-        private ErrorConsoleView mErrorConsole;
-        // the lock icon type and previous lock icon type for the tab
-        private int mSavedLockIconType;
-        private int mSavedPrevLockIconType;
-
-        // Construct a new tab
-        private Tab(WebView w, boolean closeOnExit, String appId, String url, Context context) {
-            mCloseOnExit = closeOnExit;
-            mAppId = appId;
-            mOriginalUrl = url;
-            mSavedLockIconType = BrowserActivity.LOCK_ICON_UNSECURE;
-            mSavedPrevLockIconType = BrowserActivity.LOCK_ICON_UNSECURE;
-
-            // The tab consists of a container view, which contains the main
-            // WebView, as well as any other UI elements associated with the tab.
-            LayoutInflater factory = LayoutInflater.from(context);
-            mContainer = factory.inflate(R.layout.tab, null);
-
-            mGeolocationPermissionsPrompt =
-                (GeolocationPermissionsPrompt) mContainer.findViewById(
-                    R.id.geolocation_permissions_prompt);
-
-            setWebView(w);
-        }
-
-        /**
-         * Sets the WebView for this tab, correctly removing the old WebView
-         * from the container view.
-         */
-        public void setWebView(WebView w) {
-            if (mMainView == w) {
-                return;
-            }
-            // If the WebView is changing, the page will be reloaded, so any ongoing Geolocation
-            // permission requests are void.
-            mGeolocationPermissionsPrompt.hide();
-
-            // Just remove the old one.
-            FrameLayout wrapper =
-                    (FrameLayout) mContainer.findViewById(R.id.webview_wrapper);
-            wrapper.removeView(mMainView);
-            mMainView = w;
-        }
-
-        /**
-         * This method attaches both the WebView and any sub window to the
-         * given content view.
-         */
-        public void attachTabToContentView(ViewGroup content) {
-            if (mMainView == null) {
-                return;
-            }
-
-            // Attach the WebView to the container and then attach the
-            // container to the content view.
-            FrameLayout wrapper =
-                    (FrameLayout) mContainer.findViewById(R.id.webview_wrapper);
-            wrapper.addView(mMainView);
-            content.addView(mContainer, BrowserActivity.COVER_SCREEN_PARAMS);
-            attachSubWindow(content);
-        }
-
-        /**
-         * Remove the WebView and any sub window from the given content view.
-         */
-        public void removeTabFromContentView(ViewGroup content) {
-            if (mMainView == null) {
-                return;
-            }
-
-            // Remove the container from the content and then remove the
-            // WebView from the container. This will trigger a focus change
-            // needed by WebView.
-            FrameLayout wrapper =
-                    (FrameLayout) mContainer.findViewById(R.id.webview_wrapper);
-            wrapper.removeView(mMainView);
-            content.removeView(mContainer);
-            removeSubWindow(content);
-        }
-
-        /**
-         * Attach the sub window to the content view.
-         */
-        public void attachSubWindow(ViewGroup content) {
-            if (mSubView != null) {
-                content.addView(mSubViewContainer,
-                        BrowserActivity.COVER_SCREEN_PARAMS);
-            }
-        }
-
-        /**
-         * Remove the sub window from the content view.
-         */
-        public void removeSubWindow(ViewGroup content) {
-            if (mSubView != null) {
-                content.removeView(mSubViewContainer);
-            }
-        }
-
-        /**
-         * Return the top window of this tab; either the subwindow if it is not
-         * null or the main window.
-         * @return The top window of this tab.
-         */
-        public WebView getTopWindow() {
-            if (mSubView != null) {
-                return mSubView;
-            }
-            return mMainView;
-        }
-
-        /**
-         * Return the main window of this tab. Note: if a tab is freed in the
-         * background, this can return null. It is only guaranteed to be 
-         * non-null for the current tab.
-         * @return The main WebView of this tab.
-         */
-        public WebView getWebView() {
-            return mMainView;
-        }
-
-        /**
-         * @return The geolocation permissions prompt for this tab.
-         */
-        public GeolocationPermissionsPrompt getGeolocationPermissionsPrompt() {
-            return mGeolocationPermissionsPrompt;
-        }
-
-        /**
-         * Return the subwindow of this tab or null if there is no subwindow.
-         * @return The subwindow of this tab or null.
-         */
-        public WebView getSubWebView() {
-            return mSubView;
-        }
-
-        /**
-         * Get the url of this tab.  Valid after calling populatePickerData, but
-         * before calling wipePickerData, or if the webview has been destroyed.
-         * 
-         * @return The WebView's url or null.
-         */
-        public String getUrl() {
-            if (mPickerData != null) {
-                return mPickerData.mUrl;
-            }
-            return null;
-        }
-
-        /**
-         * Get the title of this tab.  Valid after calling populatePickerData, 
-         * but before calling wipePickerData, or if the webview has been 
-         * destroyed.  If the url has no title, use the url instead.
-         * 
-         * @return The WebView's title (or url) or null.
-         */
-        public String getTitle() {
-            if (mPickerData != null) {
-                return mPickerData.mTitle;
-            }
-            return null;
-        }
-
-        public Bitmap getFavicon() {
-            if (mPickerData != null) {
-                return mPickerData.mFavicon;
-            }
-            return null;
-        }
-
-        private void setParentTab(Tab parent) {
-            mParentTab = parent;
-            // This tab may have been freed due to low memory. If that is the
-            // case, the parent tab index is already saved. If we are changing
-            // that index (most likely due to removing the parent tab) we must
-            // update the parent tab index in the saved Bundle.
-            if (mSavedState != null) {
-                if (parent == null) {
-                    mSavedState.remove(PARENTTAB);
-                } else {
-                    mSavedState.putInt(PARENTTAB, getTabIndex(parent));
-                }
-            }
-        }
-        
-        /**
-         * When a Tab is created through the content of another Tab, then 
-         * we associate the Tabs. 
-         * @param child the Tab that was created from this Tab
-         */
-        public void addChildTab(Tab child) {
-            if (mChildTabs == null) {
-                mChildTabs = new Vector<Tab>();
-            }
-            mChildTabs.add(child);
-            child.setParentTab(this);
-        }
-        
-        private void removeFromTree() {
-            // detach the children
-            if (mChildTabs != null) {
-                for(Tab t : mChildTabs) {
-                    t.setParentTab(null);
-                }
-            }
-            
-            // Find myself in my parent list
-            if (mParentTab != null) {
-                mParentTab.mChildTabs.remove(this);
-            }
-        }
-        
-        /**
-         * If this Tab was created through another Tab, then this method
-         * returns that Tab.
-         * @return the Tab parent or null
-         */
-        public Tab getParentTab() {
-            return mParentTab;
-        }
-
-        /**
-         * Return whether this tab should be closed when it is backing out of
-         * the first page.
-         * @return TRUE if this tab should be closed when exit.
-         */
-        public boolean closeOnExit() {
-            return mCloseOnExit;
-        }
-
-        void setLockIconType(int type) {
-            mSavedLockIconType = type;
-        }
-
-        int getLockIconType() {
-            return mSavedLockIconType;
-        }
-
-        void setPrevLockIconType(int type) {
-            mSavedPrevLockIconType = type;
-        }
-
-        int getPrevLockIconType() {
-            return mSavedPrevLockIconType;
-        }
-    };
-
     // Directory to store thumbnails for each WebView.
     private final File mThumbnailDir;
 
@@ -464,9 +51,6 @@
      */
     TabControl(BrowserActivity activity) {
         mActivity = activity;
-        mInflateService =
-                ((LayoutInflater) activity.getSystemService(
-                        Context.LAYOUT_INFLATER_SERVICE));
         mThumbnailDir = activity.getDir("thumbnails", 0);
     }
 
@@ -488,29 +72,7 @@
         if (t == null) {
             return null;
         }
-        return t.mMainView;
-    }
-
-    /**
-     * Return the current tab's error console. Creates the console if createIfNEcessary
-     * is true and we haven't already created the console.
-     * @param createIfNecessary Flag to indicate if the console should be created if it has
-     *                          not been already.
-     * @return The current tab's error console, or null if one has not been created and
-     *         createIfNecessary is false.
-     */
-    ErrorConsoleView getCurrentErrorConsole(boolean createIfNecessary) {
-        Tab t = getTab(mCurrentTab);
-        if (t == null) {
-            return null;
-        }
-
-        if (createIfNecessary && t.mErrorConsole == null) {
-            t.mErrorConsole = new ErrorConsoleView(mActivity);
-            t.mErrorConsole.setWebView(t.mMainView);
-        }
-
-        return t.mErrorConsole;
+        return t.getWebView();
     }
 
     /**
@@ -523,7 +85,7 @@
         if (t == null) {
             return null;
         }
-        return t.mSubView != null ? t.mSubView : t.mMainView;
+        return t.getTopWindow();
     }
 
     /**
@@ -535,7 +97,7 @@
         if (t == null) {
             return null;
         }
-        return t.mSubView;
+        return t.getSubWebView();
     }
 
     /**
@@ -578,6 +140,10 @@
         return mTabs.indexOf(tab);
     }
 
+    boolean canCreateNewTab() {
+        return MAX_TABS != mTabs.size();
+    }
+
     /**
      * Create a new tab.
      * @return The newly createTab or null if we have reached the maximum
@@ -592,10 +158,10 @@
         final WebView w = createNewWebView();
 
         // Create a new tab and add it to the tab list
-        Tab t = new Tab(w, closeOnExit, appId, url, mActivity);
+        Tab t = new Tab(mActivity, w, closeOnExit, appId, url);
         mTabs.add(t);
         // Initially put the tab in the background.
-        putTabInBackground(t);
+        t.putInBackground();
         return t;
     }
 
@@ -616,86 +182,51 @@
         if (t == null) {
             return false;
         }
+
         // Only remove the tab if it is the current one.
         if (getCurrentTab() == t) {
-            putTabInBackground(t);
+            t.putInBackground();
+            mCurrentTab = -1;
         }
 
-        // Only destroy the WebView if it still exists.
-        if (t.mMainView != null) {
-            // Take down the sub window.
-            dismissSubWindow(t);
-            // Remove the WebView's settings from the BrowserSettings list of
-            // observers.
-            BrowserSettings.getInstance().deleteObserver(
-                    t.mMainView.getSettings());
-            WebView w = t.mMainView;
-            t.setWebView(null);
-            // Destroy the main view
-            w.destroy();
-        }
+        // destroy the tab
+        t.destroy();
         // clear it's references to parent and children
         t.removeFromTree();
-        
         // Remove it from our list of tabs.
         mTabs.remove(t);
 
         // The tab indices have shifted, update all the saved state so we point
         // to the correct index.
         for (Tab tab : mTabs) {
-            if (tab.mChildTabs != null) {
-                for (Tab child : tab.mChildTabs) {
+            Vector<Tab> children = tab.getChildTabs();
+            if (children != null) {
+                for (Tab child : children) {
                     child.setParentTab(tab);
                 }
             }
         }
 
-
         // This tab may have been pushed in to the background and then closed.
         // If the saved state contains a picture file, delete the file.
-        if (t.mSavedState != null) {
-            if (t.mSavedState.containsKey(CURRPICTURE)) {
-                new File(t.mSavedState.getString(CURRPICTURE)).delete();
+        Bundle savedState = t.getSavedState();
+        if (savedState != null) {
+            if (savedState.containsKey(Tab.CURRPICTURE)) {
+                new File(savedState.getString(Tab.CURRPICTURE)).delete();
             }
         }
 
         // Remove it from the queue of viewed tabs.
         mTabQueue.remove(t);
-        mCurrentTab = -1;
         return true;
     }
 
     /**
-     * Clear the back/forward list for all the current tabs.
-     */
-    void clearHistory() {
-        int size = getTabCount();
-        for (int i = 0; i < size; i++) {
-            Tab t = mTabs.get(i);
-            // TODO: if a tab is freed due to low memory, its history is not
-            // cleared here.
-            if (t.mMainView != null) {
-                t.mMainView.clearHistory();
-            }
-            if (t.mSubView != null) {
-                t.mSubView.clearHistory();
-            }
-        }
-    }
-
-    /**
      * Destroy all the tabs and subwindows
      */
     void destroy() {
-        BrowserSettings s = BrowserSettings.getInstance();
         for (Tab t : mTabs) {
-            if (t.mMainView != null) {
-                dismissSubWindow(t);
-                s.deleteObserver(t.mMainView.getSettings());
-                WebView w = t.mMainView;
-                t.setWebView(null);
-                w.destroy();
-            }
+            t.destroy();
         }
         mTabs.clear();
         mTabQueue.clear();
@@ -709,17 +240,6 @@
         return mTabs.size();
     }
 
-    // Used for saving and restoring each Tab
-    private static final String WEBVIEW = "webview";
-    private static final String NUMTABS = "numTabs";
-    private static final String CURRTAB = "currentTab";
-    private static final String CURRURL = "currentUrl";
-    private static final String CURRTITLE = "currentTitle";
-    private static final String CURRPICTURE = "currentPicture";
-    private static final String CLOSEONEXIT = "closeonexit";
-    private static final String PARENTTAB = "parentTab";
-    private static final String APPID = "appid";
-    private static final String ORIGINALURL = "originalUrl";
 
     /**
      * Save the state of all the Tabs.
@@ -727,13 +247,13 @@
      */
     void saveState(Bundle outState) {
         final int numTabs = getTabCount();
-        outState.putInt(NUMTABS, numTabs);
+        outState.putInt(Tab.NUMTABS, numTabs);
         final int index = getCurrentIndex();
-        outState.putInt(CURRTAB, (index >= 0 && index < numTabs) ? index : 0);
+        outState.putInt(Tab.CURRTAB, (index >= 0 && index < numTabs) ? index : 0);
         for (int i = 0; i < numTabs; i++) {
             final Tab t = getTab(i);
-            if (saveState(t)) {
-                outState.putBundle(WEBVIEW + i, t.mSavedState);
+            if (t.saveState()) {
+                outState.putBundle(Tab.WEBVIEW + i, t.getSavedState());
             }
         }
     }
@@ -746,33 +266,34 @@
      */
     boolean restoreState(Bundle inState) {
         final int numTabs = (inState == null)
-                ? -1 : inState.getInt(NUMTABS, -1);
+                ? -1 : inState.getInt(Tab.NUMTABS, -1);
         if (numTabs == -1) {
             return false;
         } else {
-            final int currentTab = inState.getInt(CURRTAB, -1);
+            final int currentTab = inState.getInt(Tab.CURRTAB, -1);
             for (int i = 0; i < numTabs; i++) {
                 if (i == currentTab) {
                     Tab t = createNewTab();
                     // Me must set the current tab before restoring the state
                     // so that all the client classes are set.
                     setCurrentTab(t);
-                    if (!restoreState(inState.getBundle(WEBVIEW + i), t)) {
+                    if (!t.restoreState(inState.getBundle(Tab.WEBVIEW + i))) {
                         Log.w(LOGTAG, "Fail in restoreState, load home page.");
-                        t.mMainView.loadUrl(BrowserSettings.getInstance()
+                        t.getWebView().loadUrl(BrowserSettings.getInstance()
                                 .getHomePage());
                     }
                 } else {
                     // Create a new tab and don't restore the state yet, add it
                     // to the tab list
-                    Tab t = new Tab(null, false, null, null, mActivity);
-                    t.mSavedState = inState.getBundle(WEBVIEW + i);
-                    if (t.mSavedState != null) {
-                        populatePickerDataFromSavedState(t);
+                    Tab t = new Tab(mActivity, null, false, null, null);
+                    Bundle state = inState.getBundle(Tab.WEBVIEW + i);
+                    if (state != null) {
+                        t.setSavedState(state);
+                        t.populatePickerDataFromSavedState();
                         // Need to maintain the app id and original url so we
                         // can possibly reuse this tab.
-                        t.mAppId = t.mSavedState.getString(APPID);
-                        t.mOriginalUrl = t.mSavedState.getString(ORIGINALURL);
+                        t.setAppId(state.getString(Tab.APPID));
+                        t.setOriginalUrl(state.getString(Tab.ORIGINALURL));
                     }
                     mTabs.add(t);
                     mTabQueue.add(t);
@@ -781,10 +302,10 @@
             // Rebuild the tree of tabs. Do this after all tabs have been
             // created/restored so that the parent tab exists.
             for (int i = 0; i < numTabs; i++) {
-                final Bundle b = inState.getBundle(WEBVIEW + i);
+                final Bundle b = inState.getBundle(Tab.WEBVIEW + i);
                 final Tab t = getTab(i);
                 if (b != null && t != null) {
-                    final int parentIndex = b.getInt(PARENTTAB, -1);
+                    final int parentIndex = b.getInt(Tab.PARENTTAB, -1);
                     if (parentIndex != -1) {
                         final Tab parent = getTab(parentIndex);
                         if (parent != null) {
@@ -808,9 +329,10 @@
         Tab t = getLeastUsedTab(getCurrentTab());
         if (t != null) {
             Log.w(LOGTAG, "Free a tab in the browser");
-            freeTab(t);
-            // force a gc
-            System.gc();
+            // store the WebView's state.
+            t.saveState();
+            // destroy the tab
+            t.destroy();
             return;
         }
 
@@ -820,8 +342,6 @@
         if (view != null) {
             view.freeMemory();
         }
-        // force a gc
-        System.gc();
     }
 
     private Tab getLeastUsedTab(Tab current) {
@@ -831,7 +351,7 @@
             return null;
         }
 
-        // Rip through the queue starting at the beginning and teardown the
+        // Rip through the queue starting at the beginning and tear down the
         // next available tab.
         Tab t = null;
         int i = 0;
@@ -842,69 +362,18 @@
         do {
             t = mTabQueue.get(i++);
         } while (i < queueSize
-                && ((t != null && t.mMainView == null)
-                    || t == current.mParentTab));
+                && ((t != null && t.getWebView() == null)
+                    || t == current.getParentTab()));
 
         // Don't do anything if the last remaining tab is the current one or if
         // the last tab has been freed already.
-        if (t == current || t.mMainView == null) {
+        if (t == current || t.getWebView() == null) {
             return null;
         }
 
         return t;
     }
 
-    private void freeTab(Tab t) {
-        // Store the WebView's state.
-        saveState(t);
-
-        // Tear down the tab.
-        dismissSubWindow(t);
-        // Remove the WebView's settings from the BrowserSettings list of
-        // observers.
-        BrowserSettings.getInstance().deleteObserver(t.mMainView.getSettings());
-        WebView w = t.mMainView;
-        t.setWebView(null);
-        w.destroy();
-    }
-
-    /**
-     * Create a new subwindow unless a subwindow already exists.
-     * @return True if a new subwindow was created. False if one already exists.
-     */
-    void createSubWindow() {
-        Tab t = getTab(mCurrentTab);
-        if (t != null && t.mSubView == null) {
-            final View v = mInflateService.inflate(R.layout.browser_subwindow, null);
-            final WebView w = (WebView) v.findViewById(R.id.webview);
-            w.setMapTrackballToArrowKeys(false); // use trackball directly
-            final SubWindowClient subClient =
-                    new SubWindowClient(mActivity.getWebViewClient());
-            final SubWindowChromeClient subChromeClient =
-                    new SubWindowChromeClient(t,
-                            mActivity.getWebChromeClient());
-            w.setWebViewClient(subClient);
-            w.setWebChromeClient(subChromeClient);
-            w.setDownloadListener(mActivity);
-            w.setOnCreateContextMenuListener(mActivity);
-            final BrowserSettings s = BrowserSettings.getInstance();
-            s.addObserver(w.getSettings()).update(s, null);
-            t.mSubView = w;
-            t.mSubViewClient = subClient;
-            t.mSubViewChromeClient = subChromeClient;
-            // FIXME: I really hate having to know the name of the view
-            // containing the webview.
-            t.mSubViewContainer = v.findViewById(R.id.subwindow_container);
-            final ImageButton cancel =
-                    (ImageButton) v.findViewById(R.id.subwindow_close);
-            cancel.setOnClickListener(new OnClickListener() {
-                    public void onClick(View v) {
-                        subChromeClient.onCloseWindow(w);
-                    }
-                });
-        }
-    }
-
     /**
      * Show the tab that contains the given WebView.
      * @param view The WebView used to find the tab.
@@ -913,7 +382,7 @@
         final int size = getTabCount();
         for (int i = 0; i < size; i++) {
             final Tab t = getTab(i);
-            if (t.mSubView == view || t.mMainView == view) {
+            if (t.getSubWebView() == view || t.getWebView() == view) {
                 return t;
             }
         }
@@ -931,32 +400,42 @@
         final int size = getTabCount();
         for (int i = 0; i < size; i++) {
             final Tab t = getTab(i);
-            if (id.equals(t.mAppId)) {
+            if (id.equals(t.getAppId())) {
                 return t;
             }
         }
         return null;
     }
 
+    /**
+     * Stop loading in all opened WebView including subWindows.
+     */
     void stopAllLoading() {
         final int size = getTabCount();
         for (int i = 0; i < size; i++) {
-            final WebView webview = getTab(i).getTopWindow();
+            final Tab t = getTab(i);
+            final WebView webview = t.getWebView();
             if (webview != null) {
                 webview.stopLoading();
             }
+            final WebView subview = t.getSubWebView();
+            if (subview != null) {
+                webview.stopLoading();
+            }
         }
     }
 
     // This method checks if a non-app tab (one created within the browser)
     // matches the given url.
     private boolean tabMatchesUrl(Tab t, String url) {
-        if (t.mAppId != null) {
+        if (t.getAppId() != null) {
             return false;
-        } else if (t.mMainView == null) {
+        }
+        WebView webview = t.getWebView();
+        if (webview == null) {
             return false;
-        } else if (url.equals(t.mMainView.getUrl()) ||
-                url.equals(t.mMainView.getOriginalUrl())) {
+        } else if (url.equals(webview.getUrl())
+                || url.equals(webview.getOriginalUrl())) {
             return true;
         }
         return false;
@@ -992,9 +471,9 @@
      * was deleted.
      */
     boolean recreateWebView(Tab t, String url) {
-        final WebView w = t.mMainView;
+        final WebView w = t.getWebView();
         if (w != null) {
-            if (url != null && url.equals(t.mOriginalUrl)) {
+            if (url != null && url.equals(t.getOriginalUrl())) {
                 // The original url matches the current url. Just go back to the
                 // first history item so we can load it faster than if we
                 // rebuilt the WebView.
@@ -1005,11 +484,7 @@
                     return false;
                 }
             }
-            // Remove the settings object from the global settings and destroy
-            // the WebView.
-            BrowserSettings.getInstance().deleteObserver(
-                    t.mMainView.getSettings());
-            t.mMainView.destroy();
+            t.destroy();
         }
         // Create a new WebView. If this tab is the current tab, we need to put
         // back all the clients so force it to be the current tab.
@@ -1017,12 +492,11 @@
         if (getCurrentTab() == t) {
             setCurrentTab(t, true);
         }
-        // Clear the saved state except for the app id and close-on-exit
-        // values.
-        t.mSavedState = null;
-        t.mPickerData = null;
+        // Clear the saved state and picker data
+        t.setSavedState(null);
+        t.clearPickerData();
         // Save the new url in order to avoid deleting the WebView.
-        t.mOriginalUrl = url;
+        t.setOriginalUrl(url);
         return true;
     }
 
@@ -1037,6 +511,11 @@
         w.setMapTrackballToArrowKeys(false); // use trackball directly
         // Enable the built-in zoom
         w.getSettings().setBuiltInZoomControls(true);
+        // Attach DownloadManager so that downloads can start in an active or
+        // a non-active window. This can happen when going to a site that does
+        // a redirect after a period of time. The user could have switched to
+        // another tab while waiting for the download to start.
+        w.setDownloadListener(mActivity);
         // Add this WebView to the settings observer list and update the
         // settings
         final BrowserSettings s = BrowserSettings.getInstance();
@@ -1053,48 +532,20 @@
         return setCurrentTab(newTab, false);
     }
 
-    /*package*/ void pauseCurrentTab() {
+    void pauseCurrentTab() {
         Tab t = getCurrentTab();
         if (t != null) {
-            t.mMainView.onPause();
-            if (t.mSubView != null) {
-                t.mSubView.onPause();
-            }
+            t.pause();
         }
     }
 
-    /*package*/ void resumeCurrentTab() {
+    void resumeCurrentTab() {
         Tab t = getCurrentTab();
         if (t != null) {
-            t.mMainView.onResume();
-            if (t.mSubView != null) {
-                t.mSubView.onResume();
-            }
+            t.resume();
         }
     }
 
-    private void putViewInForeground(WebView v, WebViewClient vc,
-                                     WebChromeClient cc) {
-        v.setWebViewClient(vc);
-        v.setWebChromeClient(cc);
-        v.setOnCreateContextMenuListener(mActivity);
-        v.setDownloadListener(mActivity);
-        v.onResume();
-    }
-
-    private void putViewInBackground(WebView v) {
-        // Set an empty callback so that default actions are not triggered.
-        v.setWebViewClient(mEmptyClient);
-        v.setWebChromeClient(mBackgroundChromeClient);
-        v.setOnCreateContextMenuListener(null);
-        // Leave the DownloadManager attached so that downloads can start in
-        // a non-active window. This can happen when going to a site that does
-        // a redirect after a period of time. The user could have switched to
-        // another tab while waiting for the download to start.
-        v.setDownloadListener(mActivity);
-        v.onPause();
-    }
-
     /**
      * If force is true, this method skips the check for newTab == current.
      */
@@ -1104,10 +555,9 @@
             return true;
         }
         if (current != null) {
-            // Remove the current WebView and the container of the subwindow
-            putTabInBackground(current);
+            current.putInBackground();
+            mCurrentTab = -1;
         }
-
         if (newTab == null) {
             return false;
         }
@@ -1119,214 +569,22 @@
         }
         mTabQueue.add(newTab);
 
-        WebView mainView;
-
         // Display the new current tab
         mCurrentTab = mTabs.indexOf(newTab);
-        mainView = newTab.mMainView;
+        WebView mainView = newTab.getWebView();
         boolean needRestore = (mainView == null);
         if (needRestore) {
             // Same work as in createNewTab() except don't do new Tab()
             mainView = createNewWebView();
             newTab.setWebView(mainView);
         }
-        putViewInForeground(mainView, mActivity.getWebViewClient(),
-                            mActivity.getWebChromeClient());
-        // Add the subwindow if it exists
-        if (newTab.mSubViewContainer != null) {
-            putViewInForeground(newTab.mSubView, newTab.mSubViewClient,
-                                newTab.mSubViewChromeClient);
-        }
+        newTab.putInForeground();
         if (needRestore) {
             // Have to finish setCurrentTab work before calling restoreState
-            if (!restoreState(newTab.mSavedState, newTab)) {
+            if (!newTab.restoreState(newTab.getSavedState())) {
                 mainView.loadUrl(BrowserSettings.getInstance().getHomePage());
             }
         }
         return true;
     }
-
-    /*
-     * Put the tab in the background using all the empty/background clients.
-     */
-    private void putTabInBackground(Tab t) {
-        putViewInBackground(t.mMainView);
-        if (t.mSubView != null) {
-            putViewInBackground(t.mSubView);
-        }
-    }
-
-    /*
-     * Dismiss the subwindow for the given tab.
-     */
-    void dismissSubWindow(Tab t) {
-        if (t != null && t.mSubView != null) {
-            BrowserSettings.getInstance().deleteObserver(
-                    t.mSubView.getSettings());
-            t.mSubView.destroy();
-            t.mSubView = null;
-            t.mSubViewContainer = null;
-        }
-    }
-
-    /**
-     * Ensure that Tab t has data to display in the tab picker.
-     * @param  t   Tab to populate.
-     */
-    /* package */ void populatePickerData(Tab t) {
-        if (t == null) {
-            return;
-        }
-
-        // mMainView == null indicates that the tab has been freed.
-        if (t.mMainView == null) {
-            populatePickerDataFromSavedState(t);
-            return;
-        }
-
-        // FIXME: The only place we cared about subwindow was for 
-        // bookmarking (i.e. not when saving state). Was this deliberate?
-        final WebBackForwardList list = t.mMainView.copyBackForwardList();
-        final WebHistoryItem item =
-                list != null ? list.getCurrentItem() : null;
-        populatePickerData(t, item);
-    }
-
-    // Create the PickerData and populate it using the saved state of the tab.
-    private void populatePickerDataFromSavedState(Tab t) {
-        if (t.mSavedState == null) {
-            return;
-        }
-
-        final PickerData data = new PickerData();
-        final Bundle state = t.mSavedState;
-        data.mUrl = state.getString(CURRURL);
-        data.mTitle = state.getString(CURRTITLE);
-        // XXX: These keys are from WebView.savePicture so if they change, this
-        // will break.
-        data.mScale = state.getFloat("scale", 1.0f);
-        data.mScrollX = state.getInt("scrollX", 0);
-        data.mScrollY = state.getInt("scrollY", 0);
-
-        // Set the tab's picker data.
-        t.mPickerData = data;
-    }
-
-    // Populate the picker data using the given history item and the current
-    // top WebView.
-    private void populatePickerData(Tab t, WebHistoryItem item) {
-        final PickerData data = new PickerData();
-        if (item != null) {
-            data.mUrl = item.getUrl();
-            data.mTitle = item.getTitle();
-            data.mFavicon = item.getFavicon();
-            if (data.mTitle == null) {
-                data.mTitle = data.mUrl;
-            }
-        }
-        // We want to display the top window in the tab picker but use the url
-        // and title of the main window.
-        final WebView w = t.getTopWindow();
-        data.mScale = w.getScale();
-        data.mScrollX = w.getScrollX();
-        data.mScrollY = w.getScrollY();
-
-        t.mPickerData = data;
-    }
-    
-    /**
-     * Clean up the data for all tabs.
-     */
-    /* package */ void wipeAllPickerData() {
-        int size = getTabCount();
-        for (int i = 0; i < size; i++) {
-            final Tab t = getTab(i);
-            if (t != null && t.mSavedState == null) {
-                t.mPickerData = null;
-            }
-        }
-    }
-
-    /*
-     * Save the state for an individual tab.
-     */
-    private boolean saveState(Tab t) {
-        if (t != null) {
-            final WebView w = t.mMainView;
-            // If the WebView is null it means we ran low on memory and we
-            // already stored the saved state in mSavedState.
-            if (w == null) {
-                return true;
-            }
-            final Bundle b = new Bundle();
-            final WebBackForwardList list = w.saveState(b);
-            if (list != null) {
-                final File f = new File(mThumbnailDir, w.hashCode()
-                        + "_pic.save");
-                if (w.savePicture(b, f)) {
-                    b.putString(CURRPICTURE, f.getPath());
-                }
-            }
-
-            // Store some extra info for displaying the tab in the picker.
-            final WebHistoryItem item =
-                    list != null ? list.getCurrentItem() : null;
-            populatePickerData(t, item);
-
-            // XXX: WebView.savePicture stores the scale and scroll positions
-            // in the bundle so we don't have to do it here.
-            final PickerData data = t.mPickerData;
-            if (data.mUrl != null) {
-                b.putString(CURRURL, data.mUrl);
-            }
-            if (data.mTitle != null) {
-                b.putString(CURRTITLE, data.mTitle);
-            }
-            b.putBoolean(CLOSEONEXIT, t.mCloseOnExit);
-            if (t.mAppId != null) {
-                b.putString(APPID, t.mAppId);
-            }
-            if (t.mOriginalUrl != null) {
-                b.putString(ORIGINALURL, t.mOriginalUrl);
-            }
-
-            // Remember the parent tab so the relationship can be restored.
-            if (t.mParentTab != null) {
-                b.putInt(PARENTTAB, getTabIndex(t.mParentTab));
-            }
-
-            // Remember the saved state.
-            t.mSavedState = b;
-            return true;
-        }
-        return false;
-    }
-
-    /*
-     * Restore the state of the tab.
-     */
-    private boolean restoreState(Bundle b, Tab t) {
-        if (b == null) {
-            return false;
-        }
-        // Restore the internal state even if the WebView fails to restore.
-        // This will maintain the app id, original url and close-on-exit values.
-        t.mSavedState = null;
-        t.mPickerData = null;
-        t.mCloseOnExit = b.getBoolean(CLOSEONEXIT);
-        t.mAppId = b.getString(APPID);
-        t.mOriginalUrl = b.getString(ORIGINALURL);
-
-        final WebView w = t.mMainView;
-        final WebBackForwardList list = w.restoreState(b);
-        if (list == null) {
-            return false;
-        }
-        if (b.containsKey(CURRPICTURE)) {
-            final File f = new File(b.getString(CURRPICTURE));
-            w.restorePicture(b, f);
-            f.delete();
-        }
-        return true;
-    }
 }