OSDN Git Service

don't create the fake title bar when getGlobalVisible fails
[android-x86/packages-apps-Browser.git] / src / com / android / browser / BrowserActivity.java
index dda1795..15f986e 100644 (file)
@@ -45,19 +45,19 @@ import android.database.Cursor;
 import android.database.sqlite.SQLiteDatabase;
 import android.database.sqlite.SQLiteException;
 import android.graphics.Bitmap;
+import android.graphics.BitmapFactory;
 import android.graphics.Canvas;
-import android.graphics.Color;
 import android.graphics.DrawFilter;
 import android.graphics.Paint;
 import android.graphics.PaintFlagsDrawFilter;
 import android.graphics.Picture;
-import android.graphics.drawable.BitmapDrawable;
+import android.graphics.PixelFormat;
+import android.graphics.Rect;
 import android.graphics.drawable.Drawable;
-import android.graphics.drawable.LayerDrawable;
-import android.graphics.drawable.PaintDrawable;
 import android.hardware.SensorListener;
 import android.hardware.SensorManager;
 import android.net.ConnectivityManager;
+import android.net.NetworkInfo;
 import android.net.Uri;
 import android.net.WebAddress;
 import android.net.http.EventHandler;
@@ -76,14 +76,15 @@ import android.os.RemoteException;
 import android.os.ServiceManager;
 import android.os.SystemClock;
 import android.provider.Browser;
-import android.provider.Contacts;
+import android.provider.ContactsContract;
+import android.provider.ContactsContract.Intents.Insert;
 import android.provider.Downloads;
 import android.provider.MediaStore;
-import android.provider.Contacts.Intents.Insert;
 import android.text.IClipboard;
 import android.text.TextUtils;
 import android.text.format.DateFormat;
 import android.text.util.Regex;
+import android.util.AttributeSet;
 import android.util.Log;
 import android.view.ContextMenu;
 import android.view.Gravity;
@@ -149,8 +150,7 @@ import java.util.zip.ZipEntry;
 import java.util.zip.ZipFile;
 
 public class BrowserActivity extends Activity
-    implements KeyTracker.OnKeyTracker,
-        View.OnCreateContextMenuListener,
+    implements View.OnCreateContextMenuListener,
         DownloadListener {
 
     /* Define some aliases to make these debugging flags easier to refer to.
@@ -288,22 +288,17 @@ public class BrowserActivity extends Activity
         }
     }
 
-    // Flag to enable the touchable browser bar with buttons
-    private final boolean CUSTOM_BROWSER_BAR = true;
+    /**
+     * This layout holds everything you see below the status bar, including the
+     * error console, the custom view container, and the webviews.
+     */
+    private FrameLayout mBrowserFrameLayout;
 
     @Override public void onCreate(Bundle icicle) {
         if (LOGV_ENABLED) {
             Log.v(LOGTAG, this + " onStart");
         }
         super.onCreate(icicle);
-        if (CUSTOM_BROWSER_BAR) {
-            this.requestWindowFeature(Window.FEATURE_NO_TITLE);
-        } else {
-            this.requestWindowFeature(Window.FEATURE_LEFT_ICON);
-            this.requestWindowFeature(Window.FEATURE_RIGHT_ICON);
-            this.requestWindowFeature(Window.FEATURE_PROGRESS);
-            this.requestWindowFeature(Window.FEATURE_INDETERMINATE_PROGRESS);
-        }
         // test the browser in OpenGL
         // requestWindowFeature(Window.FEATURE_OPENGL);
 
@@ -311,6 +306,13 @@ public class BrowserActivity extends Activity
 
         mResolver = getContentResolver();
 
+        // If this was a web search request, pass it on to the default web
+        // search provider and finish this activity.
+        if (handleWebSearchIntent(getIntent())) {
+            finish();
+            return;
+        }
+
         //
         // start MASF proxy service
         //
@@ -325,39 +327,19 @@ public class BrowserActivity extends Activity
                 android.R.drawable.ic_secure);
         mMixLockIcon = Resources.getSystem().getDrawable(
                 android.R.drawable.ic_partial_secure);
-        mGenericFavicon = getResources().getDrawable(
-                R.drawable.app_web_browser_sm);
 
         FrameLayout frameLayout = (FrameLayout) getWindow().getDecorView()
                 .findViewById(com.android.internal.R.id.content);
-        if (CUSTOM_BROWSER_BAR) {
-            // This FrameLayout will hold the custom FrameLayout and a LinearLayout
-            // that contains the title bar and a FrameLayout, which
-            // holds everything else.
-            FrameLayout browserFrameLayout = (FrameLayout) LayoutInflater.from(this)
-                    .inflate(R.layout.custom_screen, null);
-            mTitleBar = (TitleBarSet) browserFrameLayout.findViewById(R.id.title_bar);
-            mContentView = (FrameLayout) browserFrameLayout.findViewById(
-                    R.id.main_content);
-            mErrorConsoleContainer = (LinearLayout) browserFrameLayout.findViewById(
-                    R.id.error_console);
-            mCustomViewContainer = (FrameLayout) browserFrameLayout
-                    .findViewById(R.id.fullscreen_custom_content);
-            frameLayout.addView(browserFrameLayout, COVER_SCREEN_PARAMS);
-        } else {
-            mCustomViewContainer = new FrameLayout(this);
-            mCustomViewContainer.setBackgroundColor(Color.BLACK);
-            mContentView = new FrameLayout(this);
-
-            LinearLayout linearLayout = new LinearLayout(this);
-            linearLayout.setOrientation(LinearLayout.VERTICAL);
-            mErrorConsoleContainer = new LinearLayout(this);
-            linearLayout.addView(mErrorConsoleContainer, new LinearLayout.LayoutParams(
-                    ViewGroup.LayoutParams.FILL_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT));
-            linearLayout.addView(mContentView, COVER_SCREEN_PARAMS);
-            frameLayout.addView(mCustomViewContainer, COVER_SCREEN_PARAMS);
-            frameLayout.addView(linearLayout, COVER_SCREEN_PARAMS);
-        }
+        mBrowserFrameLayout = (FrameLayout) LayoutInflater.from(this)
+                .inflate(R.layout.custom_screen, null);
+        mContentView = (FrameLayout) mBrowserFrameLayout.findViewById(
+                R.id.main_content);
+        mErrorConsoleContainer = (LinearLayout) mBrowserFrameLayout
+                .findViewById(R.id.error_console);
+        mCustomViewContainer = (FrameLayout) mBrowserFrameLayout
+                .findViewById(R.id.fullscreen_custom_content);
+        frameLayout.addView(mBrowserFrameLayout, COVER_SCREEN_PARAMS);
+        mTitleBar = new TitleBar(this);
 
         // Create the tab control and our initial tab
         mTabControl = new TabControl(this);
@@ -383,9 +365,11 @@ public class BrowserActivity extends Activity
                 public void onReceive(Context context, Intent intent) {
                     if (intent.getAction().equals(
                             ConnectivityManager.CONNECTIVITY_ACTION)) {
-                        boolean down = intent.getBooleanExtra(
-                                ConnectivityManager.EXTRA_NO_CONNECTIVITY, false);
-                        onNetworkToggle(!down);
+                        NetworkInfo info =
+                                (NetworkInfo) intent.getParcelableExtra(
+                                        ConnectivityManager.EXTRA_NETWORK_INFO);
+                        onNetworkToggle(
+                                (info != null) ? info.isConnected() : false);
                     }
                 }
             };
@@ -436,12 +420,6 @@ public class BrowserActivity extends Activity
         };
         registerReceiver(mPackageInstallationReceiver, filter);
 
-        // If this was a web search request, pass it on to the default web search provider.
-        if (handleWebSearchIntent(getIntent())) {
-            moveTaskToBack(true);
-            return;
-        }
-
         if (!mTabControl.restoreState(icicle)) {
             // clear up the thumbnail directory if we can't restore the state as
             // none of the files in the directory are referenced any more.
@@ -481,7 +459,11 @@ public class BrowserActivity extends Activity
             }
 
             if (urlData.isEmpty()) {
-                bookmarksOrHistoryPicker(false, true);
+                if (mSettings.isLoginInitialized()) {
+                    webView.loadUrl(mSettings.getHomePage());
+                } else {
+                    waitForCredentials();
+                }
             } else {
                 if (extra != null) {
                     urlData.setPostData(extra
@@ -495,17 +477,6 @@ public class BrowserActivity extends Activity
             attachTabToContentView(mTabControl.getCurrentTab());
         }
 
-        if (CUSTOM_BROWSER_BAR) {
-            // Create title bars for all of the tabs that have been created
-            for (int i = 0; i < mTabControl.getTabCount(); i ++) {
-                WebView view = mTabControl.getTab(i).getWebView();
-                mTitleBar.addTab(view, false);
-            }
-
-            mTitleBar.setBrowserActivity(this);
-            mTitleBar.setCurrentTab(mTabControl.getCurrentIndex());
-        }
-
         // Read JavaScript flags if it exists.
         String jsFlags = mSettings.getJsFlags();
         if (jsFlags.trim().length() != 0) {
@@ -526,9 +497,6 @@ public class BrowserActivity extends Activity
                 return;
             }
             mTabControl.setCurrentTab(current);
-            if (CUSTOM_BROWSER_BAR) {
-                mTitleBar.setCurrentTab(mTabControl.getTabIndex(current));
-            }
             attachTabToContentView(current);
             resetTitleAndIcon(current.getWebView());
         }
@@ -593,8 +561,11 @@ public class BrowserActivity extends Activity
                     // No matching application tab, try to find a regular tab
                     // with a matching url.
                     appTab = mTabControl.findUnusedTabWithUrl(urlData.mUrl);
-                    if (appTab != null && current != appTab) {
-                        switchToTab(mTabControl.getTabIndex(appTab));
+                    if (appTab != null) {
+                        if (current != appTab) {
+                            switchToTab(mTabControl.getTabIndex(appTab));
+                        }
+                        // Otherwise, we are already viewing the correct tab.
                     } else {
                         // if FLAG_ACTIVITY_BROUGHT_TO_FRONT flag is on, the url
                         // will be opened in a new tab unless we have reached
@@ -648,7 +619,8 @@ public class BrowserActivity extends Activity
                 || Intent.ACTION_WEB_SEARCH.equals(action)) {
             url = intent.getStringExtra(SearchManager.QUERY);
         }
-        return handleWebSearchRequest(url, intent.getBundleExtra(SearchManager.APP_DATA));
+        return handleWebSearchRequest(url, intent.getBundleExtra(SearchManager.APP_DATA),
+                intent.getStringExtra(SearchManager.EXTRA_DATA_KEY));
     }
 
     /**
@@ -656,7 +628,7 @@ public class BrowserActivity extends Activity
      * was identified as plain search terms and not URL/shortcut.
      * @return true if the request was handled and web search activity was launched, false if not.
      */
-    private boolean handleWebSearchRequest(String inUrl, Bundle appData) {
+    private boolean handleWebSearchRequest(String inUrl, Bundle appData, String extraData) {
         if (inUrl == null) return false;
 
         // In general, we shouldn't modify URL from Intent.
@@ -680,6 +652,9 @@ public class BrowserActivity extends Activity
         if (appData != null) {
             intent.putExtra(SearchManager.APP_DATA, appData);
         }
+        if (extraData != null) {
+            intent.putExtra(SearchManager.EXTRA_DATA_KEY, extraData);
+        }
         intent.putExtra(Browser.EXTRA_APPLICATION_ID, getPackageName());
         startActivity(intent);
 
@@ -740,6 +715,24 @@ public class BrowserActivity extends Activity
     }
 
     /* package */ static String fixUrl(String inUrl) {
+        // FIXME: Converting the url to lower case
+        // duplicates functionality in smartUrlFilter().
+        // However, changing all current callers of fixUrl to
+        // call smartUrlFilter in addition may have unwanted
+        // consequences, and is deferred for now.
+        int colon = inUrl.indexOf(':');
+        boolean allLower = true;
+        for (int index = 0; index < colon; index++) {
+            char ch = inUrl.charAt(index);
+            if (!Character.isLetter(ch)) {
+                break;
+            }
+            allLower &= Character.isLowerCase(ch);
+            if (index == colon - 1 && !allLower) {
+                inUrl = inUrl.substring(0, colon).toLowerCase()
+                        + inUrl.substring(colon);
+            }
+        }
         if (inUrl.startsWith("http://") || inUrl.startsWith("https://"))
             return inUrl;
         if (inUrl.startsWith("http:") ||
@@ -889,6 +882,207 @@ public class BrowserActivity extends Activity
     }
 
     /**
+     * Since the actual title bar is embedded in the WebView, and removing it
+     * would change its appearance, create a temporary title bar to go at
+     * the top of the screen while the menu is open.
+     */
+    private TitleBar mFakeTitleBar;
+
+    /**
+     * Holder for the fake title bar.  It will have a foreground shadow, as well
+     * as a white background, so the fake title bar looks like the real one.
+     */
+    private ViewGroup mFakeTitleBarHolder;
+
+    /**
+     * Layout parameters for the fake title bar within mFakeTitleBarHolder
+     */
+    private FrameLayout.LayoutParams mFakeTitleBarParams
+            = new FrameLayout.LayoutParams(
+            ViewGroup.LayoutParams.FILL_PARENT,
+            ViewGroup.LayoutParams.WRAP_CONTENT);
+    /**
+     * Keeps track of whether the options menu is open.  This is important in
+     * determining whether to show or hide the title bar overlay.
+     */
+    private boolean mOptionsMenuOpen;
+
+    /**
+     * Only meaningful when mOptionsMenuOpen is true.  This variable keeps track
+     * of whether the configuration has changed.  The first onMenuOpened call
+     * after a configuration change is simply a reopening of the same menu
+     * (i.e. mIconView did not change).
+     */
+    private boolean mConfigChanged;
+
+    /**
+     * Whether or not the options menu is in its smaller, icon menu form.  When
+     * true, we want the title bar overlay to be up.  When false, we do not.
+     * Only meaningful if mOptionsMenuOpen is true.
+     */
+    private boolean mIconView;
+
+    @Override
+    public boolean onMenuOpened(int featureId, Menu menu) {
+        if (Window.FEATURE_OPTIONS_PANEL == featureId) {
+            if (mOptionsMenuOpen) {
+                if (mConfigChanged) {
+                    // We do not need to make any changes to the state of the
+                    // title bar, since the only thing that happened was a
+                    // change in orientation
+                    mConfigChanged = false;
+                } else {
+                    if (mIconView) {
+                        // Switching the menu to expanded view, so hide the
+                        // title bar.
+                        hideFakeTitleBar();
+                        mIconView = false;
+                    } else {
+                        // Switching the menu back to icon view, so show the
+                        // title bar once again.
+                        showFakeTitleBar();
+                        mIconView = true;
+                    }
+                }
+            } else {
+                // The options menu is closed, so open it, and show the title
+                showFakeTitleBar();
+                mOptionsMenuOpen = true;
+                mConfigChanged = false;
+                mIconView = true;
+            }
+        }
+        return true;
+    }
+
+    /**
+     * Special class used exclusively for the shadow drawn underneath the fake
+     * title bar.  The shadow does not need to be drawn if the WebView
+     * underneath is scrolled to the top, because it will draw directly on top
+     * of the embedded shadow.
+     */
+    private static class Shadow extends View {
+        private WebView mWebView;
+
+        public Shadow(Context context, AttributeSet attrs) {
+            super(context, attrs);
+        }
+
+        public void setWebView(WebView view) {
+            mWebView = view;
+        }
+
+        @Override
+        public void draw(Canvas canvas) {
+            // In general onDraw is the method to override, but we care about
+            // whether or not the background gets drawn, which happens in draw()
+            if (mWebView == null || mWebView.getScrollY() > getHeight()) {
+                super.draw(canvas);
+            }
+            // Need to invalidate so that if the scroll position changes, we
+            // still draw as appropriate.
+            invalidate();
+        }
+    }
+
+    private void showFakeTitleBar() {
+        final View decor = getWindow().peekDecorView();
+        if (mFakeTitleBar == null && mActiveTabsPage == null
+                && !mActivityInPause && decor != null
+                && decor.getWindowToken() != null) {
+            Rect visRect = new Rect();
+            if (!mBrowserFrameLayout.getGlobalVisibleRect(visRect)) {
+                if (LOGD_ENABLED) {
+                    Log.d(LOGTAG, "showFakeTitleBar visRect failed");
+                }
+                return;
+            }
+            final WebView webView = getTopWindow();
+            mFakeTitleBar = new TitleBar(this);
+            mFakeTitleBar.setTitleAndUrl(null, webView.getUrl());
+            mFakeTitleBar.setProgress(webView.getProgress());
+            mFakeTitleBar.setFavicon(webView.getFavicon());
+            updateLockIconToLatest();
+
+            WindowManager manager
+                    = (WindowManager) getSystemService(Context.WINDOW_SERVICE);
+
+            // Add the title bar to the window manager so it can receive touches
+            // while the menu is up
+            WindowManager.LayoutParams params
+                    = new WindowManager.LayoutParams(
+                    ViewGroup.LayoutParams.FILL_PARENT,
+                    ViewGroup.LayoutParams.WRAP_CONTENT,
+                    WindowManager.LayoutParams.TYPE_APPLICATION_SUB_PANEL,
+                    WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE,
+                    PixelFormat.TRANSLUCENT);
+            params.gravity = Gravity.TOP;
+            WebView mainView = mTabControl.getCurrentWebView();
+            boolean atTop = mainView != null && mainView.getScrollY() == 0;
+            params.windowAnimations = atTop ? 0
+                    : com.android.internal.R.style.Animation_DropDownDown;
+            // XXX : Without providing an offset, the fake title bar will be
+            // placed underneath the status bar.  Use the global visible rect
+            // of mBrowserFrameLayout to determine the bottom of the status bar
+            params.y = visRect.top;
+            // Add a holder for the title bar.  It also holds a shadow to show
+            // below the title bar.
+            if (mFakeTitleBarHolder == null) {
+                mFakeTitleBarHolder = (ViewGroup) LayoutInflater.from(this)
+                    .inflate(R.layout.title_bar_bg, null);
+            }
+            Shadow shadow = (Shadow) mFakeTitleBarHolder.findViewById(
+                    R.id.shadow);
+            shadow.setWebView(mainView);
+            mFakeTitleBarHolder.addView(mFakeTitleBar, 0, mFakeTitleBarParams);
+            manager.addView(mFakeTitleBarHolder, params);
+        }
+    }
+
+    @Override
+    public void onOptionsMenuClosed(Menu menu) {
+        mOptionsMenuOpen = false;
+        if (!mInLoad) {
+            hideFakeTitleBar();
+        } else if (!mIconView) {
+            // The page is currently loading, and we are in expanded mode, so
+            // we were not showing the menu.  Show it once again.  It will be
+            // removed when the page finishes.
+            showFakeTitleBar();
+        }
+    }
+    private void hideFakeTitleBar() {
+        if (mFakeTitleBar == null) return;
+        WindowManager.LayoutParams params = (WindowManager.LayoutParams)
+                mFakeTitleBarHolder.getLayoutParams();
+        WebView mainView = mTabControl.getCurrentWebView();
+        // Although we decided whether or not to animate based on the current
+        // scroll position, the scroll position may have changed since the
+        // fake title bar was displayed.  Make sure it has the appropriate
+        // animation/lack thereof before removing.
+        params.windowAnimations = mainView != null && mainView.getScrollY() == 0
+                ? 0 : com.android.internal.R.style.Animation_DropDownDown;
+        WindowManager manager
+                    = (WindowManager) getSystemService(Context.WINDOW_SERVICE);
+        manager.updateViewLayout(mFakeTitleBarHolder, params);
+        mFakeTitleBarHolder.removeView(mFakeTitleBar);
+        manager.removeView(mFakeTitleBarHolder);
+        mFakeTitleBar = null;
+    }
+
+    /**
+     * Special method for the fake title bar to call when displaying its context
+     * menu, since it is in its own Window, and its parent does not show a
+     * context menu.
+     */
+    /* package */ void showTitleBarContextMenu() {
+        if (null == mTitleBar.getParent()) {
+            return;
+        }
+        openContextMenu(mTitleBar);
+    }
+
+    /**
      *  onSaveInstanceState(Bundle map)
      *  onSaveInstanceState is called right before onStop(). The map contains
      *  the saved state.
@@ -929,6 +1123,14 @@ public class BrowserActivity extends Activity
         }
         mCredsDlg = null;
 
+        // FIXME: This removes the active tabs page and resets the menu to
+        // MAIN_MENU.  A better solution might be to do this work in onNewIntent
+        // but then we would need to save it in onSaveInstanceState and restore
+        // it in onCreate/onRestoreInstanceState
+        if (mActiveTabsPage != null) {
+            removeActiveTabPage(true);
+        }
+
         cancelStopToast();
 
         // unregister network state listener
@@ -945,6 +1147,9 @@ public class BrowserActivity extends Activity
             Log.v(LOGTAG, "BrowserActivity.onDestroy: this=" + this);
         }
         super.onDestroy();
+
+        if (mTabControl == null) return;
+
         // Remove the current tab and sub window
         TabControl.Tab t = mTabControl.getCurrentTab();
         if (t != null) {
@@ -974,6 +1179,7 @@ public class BrowserActivity extends Activity
 
     @Override
     public void onConfigurationChanged(Configuration newConfig) {
+        mConfigChanged = true;
         super.onConfigurationChanged(newConfig);
 
         if (mPageInfoDialog != null) {
@@ -1156,15 +1362,20 @@ public class BrowserActivity extends Activity
         // options selector, so set mCanChord to true so we can access them.
         mCanChord = true;
         int id = item.getItemId();
-        final WebView webView = getTopWindow();
-        if (null == webView) {
-            return false;
-        }
-        final HashMap hrefMap = new HashMap();
-        hrefMap.put("webview", webView);
-        final Message msg = mHandler.obtainMessage(
-                FOCUS_NODE_HREF, id, 0, hrefMap);
         switch (id) {
+            // For the context menu from the title bar
+            case R.id.title_bar_share_page_url:
+            case R.id.title_bar_copy_page_url:
+                WebView mainView = mTabControl.getCurrentWebView();
+                if (null == mainView) {
+                    return false;
+                }
+                if (id == R.id.title_bar_share_page_url) {
+                    Browser.sendString(this, mainView.getUrl());
+                } else {
+                    copy(mainView.getUrl());
+                }
+                break;
             // -- Browser context menu
             case R.id.open_context_menu_id:
             case R.id.open_newtab_context_menu_id:
@@ -1172,6 +1383,14 @@ public class BrowserActivity extends Activity
             case R.id.save_link_context_menu_id:
             case R.id.share_link_context_menu_id:
             case R.id.copy_link_context_menu_id:
+                final WebView webView = getTopWindow();
+                if (null == webView) {
+                    return false;
+                }
+                final HashMap hrefMap = new HashMap();
+                hrefMap.put("webview", webView);
+                final Message msg = mHandler.obtainMessage(
+                        FOCUS_NODE_HREF, id, 0, hrefMap);
                 webView.requestFocusNodeHref(msg);
                 break;
 
@@ -1194,6 +1413,7 @@ public class BrowserActivity extends Activity
      */
     @Override
     public boolean onSearchRequested() {
+        if (mOptionsMenuOpen) closeOptionsMenu();
         String url = (getTopWindow() == null) ? null : getTopWindow().getUrl();
         startSearch(mSettings.getHomePage().equals(url) ? null : url, true,
                 createGoogleSearchSourceBundle(GOOGLE_SEARCH_SOURCE_SEARCHKEY), false);
@@ -1229,22 +1449,24 @@ public class BrowserActivity extends Activity
             // we do not need to remove it
             removeTabFromContentView(currentTab);
         }
-        removeTabFromContentView(tab);
         mTabControl.setCurrentTab(tab);
         attachTabToContentView(tab);
+        resetTitleIconAndProgress();
+        updateLockIconToLatest();
         return true;
     }
 
+    /* package */ TabControl.Tab openTabToHomePage() {
+        return openTabAndShow(mSettings.getHomePage(), false, null);
+    }
+
     /* package */ void closeCurrentWindow() {
         final TabControl.Tab current = mTabControl.getCurrentTab();
         if (mTabControl.getTabCount() == 1) {
-            // This is the last tab.  Open a new one, as well as the history
-            // picker, and close the current one.
-            TabControl.Tab newTab = openTabAndShow(
-                    BrowserActivity.EMPTY_URL_DATA, false, null);
-            bookmarksOrHistoryPicker(false, true);
+            // This is the last tab.  Open a new one, with the home
+            // page and close the current one.
+            TabControl.Tab newTab = openTabToHomePage();
             closeTab(current);
-            mTabControl.setCurrentTab(newTab);
             return;
         }
         final TabControl.Tab parent = current.getParentTab();
@@ -1266,6 +1488,23 @@ public class BrowserActivity extends Activity
         }
     }
 
+    private ActiveTabsPage mActiveTabsPage;
+
+    /**
+     * Remove the active tabs page.
+     * @param needToAttach If true, the active tabs page did not attach a tab
+     *                     to the content view, so we need to do that here.
+     */
+    /* package */ void removeActiveTabPage(boolean needToAttach) {
+        mContentView.removeView(mActiveTabsPage);
+        mActiveTabsPage = null;
+        mMenuState = R.id.MAIN_MENU;
+        if (needToAttach) {
+            attachTabToContentView(mTabControl.getCurrentTab());
+        }
+        getTopWindow().requestFocus();
+    }
+
     @Override
     public boolean onOptionsItemSelected(MenuItem item) {
         if (!mCanChord) {
@@ -1285,8 +1524,25 @@ public class BrowserActivity extends Activity
         }
         switch (item.getItemId()) {
             // -- Main menu
+            case R.id.new_tab_menu_id:
+                openTabToHomePage();
+                break;
+
             case R.id.goto_menu_id:
-                bookmarksOrHistoryPicker(false, false);
+                onSearchRequested();
+                break;
+
+            case R.id.bookmarks_menu_id:
+                bookmarksOrHistoryPicker(false);
+                break;
+
+            case R.id.active_tabs_menu_id:
+                mActiveTabsPage = new ActiveTabsPage(this, mTabControl);
+                removeTabFromContentView(mTabControl.getCurrentTab());
+                hideFakeTitleBar();
+                mContentView.addView(mActiveTabsPage, COVER_SCREEN_PARAMS);
+                mActiveTabsPage.requestFocus();
+                mMenuState = EMPTY_MENU;
                 break;
 
             case R.id.add_bookmark_menu_id:
@@ -1295,6 +1551,8 @@ public class BrowserActivity extends Activity
                 WebView w = getTopWindow();
                 i.putExtra("url", w.getUrl());
                 i.putExtra("title", w.getTitle());
+                i.putExtra("touch_icon_url", w.getTouchIconUrl());
+                i.putExtra("thumbnail", createScreenshot(w));
                 startActivity(i);
                 break;
 
@@ -1354,11 +1612,12 @@ public class BrowserActivity extends Activity
                 break;
 
             case R.id.classic_history_menu_id:
-                bookmarksOrHistoryPicker(true, false);
+                bookmarksOrHistoryPicker(true);
                 break;
 
             case R.id.share_page_menu_id:
-                Browser.sendString(this, getTopWindow().getUrl());
+                Browser.sendString(this, getTopWindow().getUrl(),
+                        getText(R.string.choosertitle_sharevia).toString());
                 break;
 
             case R.id.dump_nav_menu_id:
@@ -1393,7 +1652,6 @@ public class BrowserActivity extends Activity
                             if (desiredTab != null &&
                                     desiredTab != mTabControl.getCurrentTab()) {
                                 switchToTab(id);
-                                mTitleBar.setCurrentTab(id);
                             }
                             break;
                         }
@@ -1456,6 +1714,9 @@ public class BrowserActivity extends Activity
                 menu.findItem(R.id.forward_menu_id)
                         .setEnabled(canGoForward);
 
+                menu.findItem(R.id.new_tab_menu_id).setEnabled(
+                        mTabControl.getTabCount() < TabControl.MAX_TABS);
+
                 // decide whether to show the share link option
                 PackageManager pm = getPackageManager();
                 Intent send = new Intent(Intent.ACTION_SEND);
@@ -1523,7 +1784,7 @@ public class BrowserActivity extends Activity
                                 .parse(WebView.SCHEME_TEL + extra)));
                 Intent addIntent = new Intent(Intent.ACTION_INSERT_OR_EDIT);
                 addIntent.putExtra(Insert.PHONE, Uri.decode(extra));
-                addIntent.setType(Contacts.People.CONTENT_ITEM_TYPE);
+                addIntent.setType(ContactsContract.Contacts.CONTENT_ITEM_TYPE);
                 menu.findItem(R.id.add_contact_context_menu_id).setIntent(
                         addIntent);
                 menu.findItem(R.id.copy_phone_context_menu_id).setOnMenuItemClickListener(
@@ -1585,10 +1846,11 @@ public class BrowserActivity extends Activity
     }
 
     // Attach the given tab to the content view.
+    // this should only be called for the current tab.
     private void attachTabToContentView(TabControl.Tab t) {
         // Attach the container that contains the main WebView and any other UI
         // associated with the tab.
-        mContentView.addView(t.getContainer(), COVER_SCREEN_PARAMS);
+        t.attachTabToContentView(mContentView);
 
         if (mShouldShowErrorConsole) {
             ErrorConsoleView errorConsole = mTabControl.getCurrentErrorConsole(true);
@@ -1603,50 +1865,66 @@ public class BrowserActivity extends Activity
                                                   ViewGroup.LayoutParams.WRAP_CONTENT));
         }
 
-        // Attach the sub window if necessary
-        attachSubWindow(t);
+        setLockIconType(t.getLockIconType());
+        setPrevLockType(t.getPrevLockIconType());
+
+        // this is to match the code in removeTabFromContentView()
+        if (!mPageStarted && t.getTopWindow().getProgress() < 100) {
+            mPageStarted = true;
+        }
+
+        WebView view = t.getWebView();
+        view.setEmbeddedTitleBar(mTitleBar);
         // Request focus on the top window.
         t.getTopWindow().requestFocus();
     }
 
     // Attach a sub window to the main WebView of the given tab.
     private void attachSubWindow(TabControl.Tab t) {
-        // If a sub window exists, attach it to the content view.
-        final WebView subView = t.getSubWebView();
-        if (subView != null) {
-            final View container = t.getSubWebViewContainer();
-            mContentView.addView(container, COVER_SCREEN_PARAMS);
-            subView.requestFocus();
-        }
+        t.attachSubWindow(mContentView);
+        getTopWindow().requestFocus();
     }
 
     // Remove the given tab from the content view.
     private void removeTabFromContentView(TabControl.Tab t) {
         // Remove the container that contains the main WebView.
-        mContentView.removeView(t.getContainer());
+        t.removeTabFromContentView(mContentView);
 
         if (mTabControl.getCurrentErrorConsole(false) != null) {
             mErrorConsoleContainer.removeView(mTabControl.getCurrentErrorConsole(false));
         }
 
-        // Remove the sub window if it exists.
-        if (t.getSubWebView() != null) {
-            mContentView.removeView(t.getSubWebViewContainer());
+        WebView view = t.getWebView();
+        if (view != null) {
+            view.setEmbeddedTitleBar(null);
+        }
+
+        // unlike attachTabToContentView(), removeTabFromContentView() can be
+        // called for the non-current tab. Need to add the check.
+        if (t == mTabControl.getCurrentTab()) {
+            t.setLockIconType(getLockIconType());
+            t.setPrevLockIconType(getPrevLockType());
+
+            // this is not a perfect solution. But currently there is one
+            // WebViewClient for all the WebView. if user switches from an
+            // in-load window to an already loaded window, mPageStarted will not
+            // be set to false. If user leaves the Browser, pauseWebViewTimers()
+            // won't do anything and leaves the timer running even Browser is in
+            // the background.
+            if (mPageStarted) {
+                mPageStarted = false;
+            }
         }
     }
 
     // Remove the sub window if it exists. Also called by TabControl when the
     // user clicks the 'X' to dismiss a sub window.
     /* package */ void dismissSubWindow(TabControl.Tab t) {
-        final WebView mainView = t.getWebView();
-        if (t.getSubWebView() != null) {
-            // Remove the container view and request focus on the main WebView.
-            mContentView.removeView(t.getSubWebViewContainer());
-            mainView.requestFocus();
-            // Tell the TabControl to dismiss the subwindow. This will destroy
-            // the WebView.
-            mTabControl.dismissSubWindow(t);
-        }
+        t.removeSubWindow(mContentView);
+        // Tell the TabControl to dismiss the subwindow. This will destroy
+        // the WebView.
+        mTabControl.dismissSubWindow(t);
+        getTopWindow().requestFocus();
     }
 
     // A wrapper function of {@link #openTabAndShow(UrlData, boolean, String)}
@@ -1667,14 +1945,15 @@ public class BrowserActivity extends Activity
             final TabControl.Tab tab = mTabControl.createNewTab(
                     closeOnExit, appId, urlData.mUrl);
             WebView webview = tab.getWebView();
-            if (CUSTOM_BROWSER_BAR) {
-                mTitleBar.addTab(webview, true);
+            // If the last tab was removed from the active tabs page, currentTab
+            // will be null.
+            if (currentTab != null) {
+                removeTabFromContentView(currentTab);
             }
-            removeTabFromContentView(currentTab);
-            attachTabToContentView(tab);
             // We must set the new tab as the current tab to reflect the old
             // animation behavior.
             mTabControl.setCurrentTab(tab);
+            attachTabToContentView(tab);
             if (!urlData.isEmpty()) {
                 urlData.loadIn(webview);
             }
@@ -1695,9 +1974,6 @@ public class BrowserActivity extends Activity
             TabControl.Tab t = mTabControl.createNewTab();
             if (t != null) {
                 WebView view = t.getWebView();
-                if (CUSTOM_BROWSER_BAR) {
-                    mTitleBar.addTab(view, false);
-                }
                 view.loadUrl(url);
             }
             return t;
@@ -1744,15 +2020,6 @@ public class BrowserActivity extends Activity
     }
 
     /**
-     * Resets the browser title-view to whatever it must be (for example, if we
-     * load a page from history).
-     */
-    private void resetTitle() {
-        resetLockIcon();
-        resetTitleIconAndProgress();
-    }
-
-    /**
      * Resets the browser title-view to whatever it must be
      * (for example, if we had a loading error)
      * When we have a new page, we call resetTitle, when we
@@ -1782,10 +2049,10 @@ public class BrowserActivity extends Activity
     private void resetTitleAndIcon(WebView view) {
         WebHistoryItem item = view.copyBackForwardList().getCurrentItem();
         if (item != null) {
-            setUrlTitle(item.getUrl(), item.getTitle(), view);
+            setUrlTitle(item.getUrl(), item.getTitle());
             setFavicon(item.getFavicon());
         } else {
-            setUrlTitle(null, null, view);
+            setUrlTitle(null, null);
             setFavicon(null);
         }
     }
@@ -1795,47 +2062,17 @@ public class BrowserActivity extends Activity
      * @param url The URL of the site being loaded.
      * @param title The title of the site being loaded.
      */
-    private void setUrlTitle(String url, String title, WebView view) {
+    private void setUrlTitle(String url, String title) {
         mUrl = url;
         mTitle = title;
 
-        if (CUSTOM_BROWSER_BAR) {
-            mTitleBar.setTitleAndUrl(title, url, view);
-        } else {
-            setTitle(buildUrlTitle(url, title));
+        mTitleBar.setTitleAndUrl(title, url);
+        if (mFakeTitleBar != null) {
+            mFakeTitleBar.setTitleAndUrl(title, url);
         }
     }
 
     /**
-     * Builds and returns the page title, which is some
-     * combination of the page URL and title.
-     * @param url The URL of the site being loaded.
-     * @param title The title of the site being loaded.
-     * @return The page title.
-     */
-    private String buildUrlTitle(String url, String title) {
-        String urlTitle = "";
-
-        if (url != null) {
-            String titleUrl = buildTitleUrl(url);
-
-            if (title != null && 0 < title.length()) {
-                if (titleUrl != null && 0 < titleUrl.length()) {
-                    urlTitle = titleUrl + ": " + title;
-                } else {
-                    urlTitle = title;
-                }
-            } else {
-                if (titleUrl != null) {
-                    urlTitle = titleUrl;
-                }
-            }
-        }
-
-        return urlTitle;
-    }
-
-    /**
      * @param url The URL to build a title version of the URL from.
      * @return The title version of the URL or null if fails.
      * The title version of the URL can be either the URL hostname,
@@ -1874,33 +2111,9 @@ public class BrowserActivity extends Activity
 
     // Set the favicon in the title bar.
     private void setFavicon(Bitmap icon) {
-        if (CUSTOM_BROWSER_BAR) {
-            Drawable[] array = new Drawable[3];
-            array[0] = new PaintDrawable(Color.BLACK);
-            PaintDrawable p = new PaintDrawable(Color.WHITE);
-            array[1] = p;
-            if (icon == null) {
-                array[2] = mGenericFavicon;
-            } else {
-                array[2] = new BitmapDrawable(icon);
-            }
-            LayerDrawable d = new LayerDrawable(array);
-            d.setLayerInset(1, 1, 1, 1, 1);
-            d.setLayerInset(2, 2, 2, 2, 2);
-            mTitleBar.setFavicon(d, getTopWindow());
-        } else {
-            Drawable[] array = new Drawable[2];
-            PaintDrawable p = new PaintDrawable(Color.WHITE);
-            p.setCornerRadius(3f);
-            array[0] = p;
-            if (icon == null) {
-                array[1] = mGenericFavicon;
-            } else {
-                array[1] = new BitmapDrawable(icon);
-            }
-            LayerDrawable d = new LayerDrawable(array);
-            d.setLayerInset(1, 2, 2, 2, 2);
-            getWindow().setFeatureDrawable(Window.FEATURE_LEFT_ICON, d);
+        mTitleBar.setFavicon(icon);
+        if (mFakeTitleBar != null) {
+            mFakeTitleBar.setFavicon(icon);
         }
     }
 
@@ -1926,15 +2139,22 @@ public class BrowserActivity extends Activity
                   " revert lock icon to " + mLockIconType);
         }
 
-        updateLockIconImage(mLockIconType);
+        updateLockIconToLatest();
     }
 
     /**
-     * Close the tab after removing its associated title bar.
+     * Close the tab, remove its associated title bar, and adjust mTabControl's
+     * current tab to a valid value.
      */
-    private void closeTab(TabControl.Tab t) {
-        mTitleBar.removeTab(mTabControl.getTabIndex(t));
+    /* package */ void closeTab(TabControl.Tab t) {
+        int currentIndex = mTabControl.getCurrentIndex();
+        int removeIndex = mTabControl.getTabIndex(t);
         mTabControl.removeTab(t);
+        if (currentIndex >= removeIndex && currentIndex != 0) {
+            currentIndex--;
+        }
+        mTabControl.setCurrentTab(mTabControl.getTab(currentIndex));
+        resetTitleIconAndProgress();
     }
 
     private void goBackOnePageOrQuit() {
@@ -1948,6 +2168,7 @@ public class BrowserActivity extends Activity
              * moveTaskToBack().
              */
             moveTaskToBack(true);
+            return;
         }
         WebView w = current.getWebView();
         if (w.canGoBack()) {
@@ -1962,13 +2183,27 @@ public class BrowserActivity extends Activity
                 closeTab(current);
             } else {
                 if (current.closeOnExit()) {
+                    // force mPageStarted to be false as we are going to either
+                    // finish the activity or remove the tab. This will ensure
+                    // pauseWebView() taking action.
+                    mPageStarted = false;
                     if (mTabControl.getTabCount() == 1) {
                         finish();
                         return;
                     }
                     // call pauseWebViewTimers() now, we won't be able to call
                     // it in onPause() as the WebView won't be valid.
+                    // Temporarily change mActivityInPause to be true as
+                    // pauseWebViewTimers() will do nothing if mActivityInPause
+                    // is false.
+                    boolean savedState = mActivityInPause;
+                    if (savedState) {
+                        Log.e(LOGTAG, "BrowserActivity is already paused "
+                                + "while handing goBackOnePageOrQuit.");
+                    }
+                    mActivityInPause = true;
                     pauseWebViewTimers();
+                    mActivityInPause = savedState;
                     removeTabFromContentView(current);
                     mTabControl.removeTab(current);
                 }
@@ -1984,83 +2219,76 @@ public class BrowserActivity extends Activity
         }
     }
 
-    public KeyTracker.State onKeyTracker(int keyCode,
-                                         KeyEvent event,
-                                         KeyTracker.Stage stage,
-                                         int duration) {
-        // if onKeyTracker() is called after activity onStop()
-        // because of accumulated key events,
-        // we should ignore it as browser is not active any more.
-        WebView topWindow = getTopWindow();
-        if (topWindow == null && mCustomView == null)
-            return KeyTracker.State.NOT_TRACKING;
-
-        if (keyCode == KeyEvent.KEYCODE_BACK) {
-            // Check if a custom view is currently showing and, if it is, hide it.
-            if (mCustomView != null) {
-                mWebChromeClient.onHideCustomView();
-                return KeyTracker.State.DONE_TRACKING;
-            }
-            if (stage == KeyTracker.Stage.LONG_REPEAT) {
-                bookmarksOrHistoryPicker(true, false);
-                return KeyTracker.State.DONE_TRACKING;
-            } else if (stage == KeyTracker.Stage.UP) {
-                // FIXME: Currently, we do not have a notion of the
-                // history picker for the subwindow, but maybe we
-                // should?
-                WebView subwindow = mTabControl.getCurrentSubWindow();
-                if (subwindow != null) {
-                    if (subwindow.canGoBack()) {
-                        subwindow.goBack();
-                    } else {
-                        dismissSubWindow(mTabControl.getCurrentTab());
-                    }
+    @Override
+    public boolean onKeyDown(int keyCode, KeyEvent event) {
+        // The default key mode is DEFAULT_KEYS_SEARCH_LOCAL. As the MENU is
+        // still down, we don't want to trigger the search. Pretend to consume
+        // the key and do nothing.
+        if (mMenuIsDown) return true;
+
+        switch(keyCode) {
+            case KeyEvent.KEYCODE_MENU:
+                mMenuIsDown = true;
+                break;
+            case KeyEvent.KEYCODE_SPACE:
+                // WebView/WebTextView handle the keys in the KeyDown. As
+                // the Activity's shortcut keys are only handled when WebView
+                // doesn't, have to do it in onKeyDown instead of onKeyUp.
+                if (event.isShiftPressed()) {
+                    getTopWindow().pageUp(false);
                 } else {
-                    goBackOnePageOrQuit();
+                    getTopWindow().pageDown(false);
                 }
-                return KeyTracker.State.DONE_TRACKING;
-            }
-            return KeyTracker.State.KEEP_TRACKING;
+                return true;
+            case KeyEvent.KEYCODE_BACK:
+                if (event.getRepeatCount() == 0) {
+                    event.startTracking();
+                    return true;
+                } else if (mCustomView == null && mActiveTabsPage == null
+                        && event.isLongPress()) {
+                    bookmarksOrHistoryPicker(true);
+                    return true;
+                }
+                break;
         }
-        return KeyTracker.State.NOT_TRACKING;
+        return super.onKeyDown(keyCode, event);
     }
 
-    @Override public boolean onKeyDown(int keyCode, KeyEvent event) {
-        if (keyCode == KeyEvent.KEYCODE_MENU) {
-            mMenuIsDown = true;
-        } else if (mMenuIsDown) {
-            // The default key mode is DEFAULT_KEYS_SEARCH_LOCAL. As the MENU is
-            // still down, we don't want to trigger the search. Pretend to
-            // consume the key and do nothing.
-            return true;
-        }
-        boolean handled =  mKeyTracker.doKeyDown(keyCode, event);
-        if (!handled) {
-            switch (keyCode) {
-                case KeyEvent.KEYCODE_SPACE:
-                    if (event.isShiftPressed()) {
-                        getTopWindow().pageUp(false);
+    @Override
+    public boolean onKeyUp(int keyCode, KeyEvent event) {
+        switch(keyCode) {
+            case KeyEvent.KEYCODE_MENU:
+                mMenuIsDown = false;
+                break;
+            case KeyEvent.KEYCODE_BACK:
+                if (event.isTracking() && !event.isCanceled()) {
+                    if (mCustomView != null) {
+                        // if a custom view is showing, hide it
+                        mWebChromeClient.onHideCustomView();
+                    } else if (mActiveTabsPage != null) {
+                        // if tab page is showing, hide it
+                        removeActiveTabPage(true);
                     } else {
-                        getTopWindow().pageDown(false);
+                        WebView subwindow = mTabControl.getCurrentSubWindow();
+                        if (subwindow != null) {
+                            if (subwindow.canGoBack()) {
+                                subwindow.goBack();
+                            } else {
+                                dismissSubWindow(mTabControl.getCurrentTab());
+                            }
+                        } else {
+                            goBackOnePageOrQuit();
+                        }
                     }
-                    handled = true;
-                    break;
-
-                default:
-                    break;
-            }
-        }
-        return handled || super.onKeyDown(keyCode, event);
-    }
-
-    @Override public boolean onKeyUp(int keyCode, KeyEvent event) {
-        if (keyCode == KeyEvent.KEYCODE_MENU) {
-            mMenuIsDown = false;
+                    return true;
+                }
+                break;
         }
-        return mKeyTracker.doKeyUp(keyCode, event) || super.onKeyUp(keyCode, event);
+        return super.onKeyUp(keyCode, event);
     }
 
-    private void stopLoading() {
+    /* package */ void stopLoading() {
+        mDidStopLoad = true;
         resetTitleAndRevertLockIcon();
         WebView w = getTopWindow();
         w.stopLoading();
@@ -2093,12 +2321,15 @@ public class BrowserActivity extends Activity
     private static final int CANCEL_CREDS_REQUEST    = 103;
     private static final int RELEASE_WAKELOCK        = 107;
 
+    private static final int UPDATE_BOOKMARK_THUMBNAIL = 108;
+
     // Private handler for handling javascript and saving passwords
     private Handler mHandler = new Handler() {
 
         public void handleMessage(Message msg) {
             switch (msg.what) {
                 case FOCUS_NODE_HREF:
+                {
                     String url = (String) msg.getData().get("url");
                     if (url == null || url.length() == 0) {
                         break;
@@ -2129,7 +2360,8 @@ public class BrowserActivity extends Activity
                             startActivity(intent);
                             break;
                         case R.id.share_link_context_menu_id:
-                            Browser.sendString(BrowserActivity.this, url);
+                            Browser.sendString(BrowserActivity.this, url,
+                                    getText(R.string.choosertitle_sharevia).toString());
                             break;
                         case R.id.copy_link_context_menu_id:
                             copy(url);
@@ -2140,6 +2372,7 @@ public class BrowserActivity extends Activity
                             break;
                     }
                     break;
+                }
 
                 case LOAD_URL:
                     loadURL(getTopWindow(), (String) msg.obj);
@@ -2158,6 +2391,13 @@ public class BrowserActivity extends Activity
                         mWakeLock.release();
                     }
                     break;
+
+                case UPDATE_BOOKMARK_THUMBNAIL:
+                    WebView view = (WebView) msg.obj;
+                    if (view != null) {
+                        updateScreenshot(view);
+                    }
+                    break;
             }
         }
     };
@@ -2168,9 +2408,10 @@ public class BrowserActivity extends Activity
         // FIXME: Would like to make sure there is actually something to
         // draw, but the API for that (WebViewCore.pictureReady()) is not
         // currently accessible here.
+
         ContentResolver cr = getContentResolver();
         final Cursor c = BrowserBookmarksAdapter.queryBookmarksForUrl(
-                cr, view.getOriginalUrl(), view.getUrl(), false);
+                cr, view.getOriginalUrl(), view.getUrl(), true);
         if (c != null) {
             boolean succeed = c.moveToFirst();
             ContentValues values = null;
@@ -2178,16 +2419,7 @@ public class BrowserActivity extends Activity
                 if (values == null) {
                     final ByteArrayOutputStream os
                             = new ByteArrayOutputStream();
-                    Picture thumbnail = view.capturePicture();
-                    // Keep width and height in sync with BrowserBookmarksPage
-                    // and bookmark_thumb
-                    Bitmap bm = Bitmap.createBitmap(100, 80,
-                            Bitmap.Config.ARGB_4444);
-                    Canvas canvas = new Canvas(bm);
-                    // May need to tweak these values to determine what is the
-                    // best scale factor
-                    canvas.scale(.5f, .5f);
-                    thumbnail.draw(canvas);
+                    Bitmap bm = createScreenshot(view);
                     bm.compress(Bitmap.CompressFormat.PNG, 100, os);
                     values = new ContentValues();
                     values.put(Browser.BookmarkColumns.THUMBNAIL,
@@ -2201,6 +2433,58 @@ public class BrowserActivity extends Activity
         }
     }
 
+    /**
+     * Values for the size of the thumbnail created when taking a screenshot.
+     * Lazily initialized.  Instead of using these directly, use
+     * getDesiredThumbnailWidth() or getDesiredThumbnailHeight().
+     */
+    private static int THUMBNAIL_WIDTH = 0;
+    private static int THUMBNAIL_HEIGHT = 0;
+
+    /**
+     * Return the desired width for thumbnail screenshots, which are stored in
+     * the database, and used on the bookmarks screen.
+     * @param context Context for finding out the density of the screen.
+     * @return int desired width for thumbnail screenshot.
+     */
+    /* package */ static int getDesiredThumbnailWidth(Context context) {
+        if (THUMBNAIL_WIDTH == 0) {
+            float density = context.getResources().getDisplayMetrics().density;
+            THUMBNAIL_WIDTH = (int) (90 * density);
+            THUMBNAIL_HEIGHT = (int) (80 * density);
+        }
+        return THUMBNAIL_WIDTH;
+    }
+
+    /**
+     * Return the desired height for thumbnail screenshots, which are stored in
+     * the database, and used on the bookmarks screen.
+     * @param context Context for finding out the density of the screen.
+     * @return int desired height for thumbnail screenshot.
+     */
+    /* package */ static int getDesiredThumbnailHeight(Context context) {
+        // To ensure that they are both initialized.
+        getDesiredThumbnailWidth(context);
+        return THUMBNAIL_HEIGHT;
+    }
+
+    private Bitmap createScreenshot(WebView view) {
+        Picture thumbnail = view.capturePicture();
+        Bitmap bm = Bitmap.createBitmap(getDesiredThumbnailWidth(this),
+                getDesiredThumbnailHeight(this), Bitmap.Config.ARGB_4444);
+        Canvas canvas = new Canvas(bm);
+        // May need to tweak these values to determine what is the
+        // best scale factor
+        int thumbnailWidth = thumbnail.getWidth();
+        if (thumbnailWidth > 0) {
+            float scaleFactor = (float) getDesiredThumbnailWidth(this) /
+                    (float)thumbnailWidth;
+            canvas.scale(scaleFactor, scaleFactor);
+        }
+        thumbnail.draw(canvas);
+        return bm;
+    }
+
     // -------------------------------------------------------------------------
     // WebViewClient implementation.
     //-------------------------------------------------------------------------
@@ -2218,7 +2502,15 @@ public class BrowserActivity extends Activity
     private void updateIcon(WebView view, Bitmap icon) {
         if (icon != null) {
             BrowserBookmarksAdapter.updateBookmarkFavicon(mResolver,
-                    view, icon);
+                    view.getOriginalUrl(), view.getUrl(), icon);
+        }
+        setFavicon(icon);
+    }
+
+    private void updateIcon(String url, Bitmap icon) {
+        if (icon != null) {
+            BrowserBookmarksAdapter.updateBookmarkFavicon(mResolver,
+                    null, url, icon);
         }
         setFavicon(icon);
     }
@@ -2227,7 +2519,21 @@ public class BrowserActivity extends Activity
         @Override
         public void onPageStarted(WebView view, String url, Bitmap favicon) {
             resetLockIcon(url);
-            setUrlTitle(url, null, view);
+            setUrlTitle(url, null);
+
+            // We've started to load a new page. If there was a pending message
+            // to save a screenshot then we will now take the new page and
+            // save an incorrect screenshot. Therefore, remove any pending
+            // thumbnail messages from the queue.
+            mHandler.removeMessages(UPDATE_BOOKMARK_THUMBNAIL);
+
+            // If we start a touch icon load and then load a new page, we don't
+            // want to cancel the current touch icon loader. But, we do want to
+            // create a new one when the touch icon url is known.
+            if (mTouchIconLoader != null) {
+                mTouchIconLoader.mActivity = null;
+                mTouchIconLoader = null;
+            }
 
             ErrorConsoleView errorConsole = mTabControl.getCurrentErrorConsole(false);
             if (errorConsole != null) {
@@ -2239,7 +2545,7 @@ public class BrowserActivity extends Activity
 
             // Call updateIcon instead of setFavicon so the bookmark
             // database can be updated.
-            updateIcon(view, favicon);
+            updateIcon(url, favicon);
 
             if (mSettings.isTracing()) {
                 String host;
@@ -2281,15 +2587,11 @@ public class BrowserActivity extends Activity
             CookieSyncManager.getInstance().resetSync();
 
             mInLoad = true;
+            mDidStopLoad = false;
+            showFakeTitleBar();
             updateInLoadMenuItems();
             if (!mIsNetworkUp) {
-                if ( mAlertDialog == null) {
-                    mAlertDialog = new AlertDialog.Builder(BrowserActivity.this)
-                        .setTitle(R.string.loadSuspendedTitle)
-                        .setMessage(R.string.loadSuspended)
-                        .setPositiveButton(R.string.ok, null)
-                        .show();
-                }
+                createAndShowNetworkDialog();
                 if (view != null) {
                     view.setNetworkAvailable(false);
                 }
@@ -2302,9 +2604,15 @@ public class BrowserActivity extends Activity
             // load.
             resetTitleAndIcon(view);
 
+            if (!mDidStopLoad) {
+                // Only update the bookmark screenshot if the user did not
+                // cancel the load early.
+                Message updateScreenshot = Message.obtain(mHandler, UPDATE_BOOKMARK_THUMBNAIL, view);
+                mHandler.sendMessageDelayed(updateScreenshot, 500);
+            }
+
             // Update the lock icon image only once we are done loading
-            updateLockIconImage(mLockIconType);
-            updateScreenshot(view);
+            updateLockIconToLatest();
 
             // Performance probe
             if (false) {
@@ -2579,7 +2887,7 @@ public class BrowserActivity extends Activity
                 }
             }
             ErrorDialog errDialog = new ErrorDialog(
-                    err == EventHandler.FILE_NOT_FOUND_ERROR ?
+                    err == WebViewClient.ERROR_FILE_NOT_FOUND ?
                     R.string.browserFrameFileErrorLabel :
                     R.string.browserFrameNetworkErrorLabel,
                     desc, err);
@@ -2608,11 +2916,11 @@ public class BrowserActivity extends Activity
         @Override
         public void onReceivedError(WebView view, int errorCode,
                 String description, String failingUrl) {
-            if (errorCode != EventHandler.ERROR_LOOKUP &&
-                    errorCode != EventHandler.ERROR_CONNECT &&
-                    errorCode != EventHandler.ERROR_BAD_URL &&
-                    errorCode != EventHandler.ERROR_UNSUPPORTED_SCHEME &&
-                    errorCode != EventHandler.FILE_ERROR) {
+            if (errorCode != WebViewClient.ERROR_HOST_LOOKUP &&
+                    errorCode != WebViewClient.ERROR_CONNECT &&
+                    errorCode != WebViewClient.ERROR_BAD_URL &&
+                    errorCode != WebViewClient.ERROR_UNSUPPORTED_SCHEME &&
+                    errorCode != WebViewClient.ERROR_FILE) {
                 queueError(errorCode, description);
             }
             Log.e(LOGTAG, "onReceivedError " + errorCode + " " + failingUrl
@@ -2659,6 +2967,17 @@ public class BrowserActivity extends Activity
             if (url.regionMatches(true, 0, "about:", 0, 6)) {
                 return;
             }
+            // remove "client" before updating it to the history so that it wont
+            // show up in the auto-complete list.
+            int index = url.indexOf("client=ms-");
+            if (index > 0 && url.contains(".google.")) {
+                int end = url.indexOf('&', index);
+                if (end > 0) {
+                    url = url.substring(0, index-1).concat(url.substring(end));
+                } else {
+                    url = url.substring(0, index-1);
+                }
+            }
             Browser.updateVisitedHistory(mResolver, url, true);
             WebIconDatabase.getInstance().retainIconForPageUrl(url);
         }
@@ -2837,20 +3156,6 @@ public class BrowserActivity extends Activity
         }
 
         @Override
-        public void onChangeViewingMode(boolean toZoomedOut) {
-            if (!CUSTOM_BROWSER_BAR) {
-                return;
-            }
-            if (toZoomedOut) {
-                // FIXME: animate the title bar into view
-                mTitleBar.setVisibility(View.VISIBLE);
-            } else {
-                // FXIME: animate the title bar out of view
-                mTitleBar.setVisibility(View.GONE);
-            }
-        }
-
-        @Override
         public boolean onCreateWindow(WebView view, final boolean dialog,
                 final boolean userGesture, final Message resultMsg) {
             // Short-circuit if we can't create any more tabs or sub windows.
@@ -2925,29 +3230,40 @@ public class BrowserActivity extends Activity
 
         @Override
         public void onProgressChanged(WebView view, int newProgress) {
-            if (CUSTOM_BROWSER_BAR) {
-                mTitleBar.setProgress(newProgress, view);
-            } else {
-                getWindow().setFeatureInt(Window.FEATURE_PROGRESS,
-                        newProgress * 100);
+            mTitleBar.setProgress(newProgress);
+            if (mFakeTitleBar != null) {
+                mFakeTitleBar.setProgress(newProgress);
             }
 
             if (newProgress == 100) {
-                // onProgressChanged() is called for sub-frame too while
-                // onPageFinished() is only called for the main frame. sync
-                // cookie and cache promptly here.
+                // onProgressChanged() may continue to be called after the main
+                // frame has finished loading, as any remaining sub frames
+                // continue to load. We'll only get called once though with
+                // newProgress as 100 when everything is loaded.
+                // (onPageFinished is called once when the main frame completes
+                // loading regardless of the state of any sub frames so calls
+                // to onProgressChanges may continue after onPageFinished has
+                // executed)
+
+                // sync cookies and cache promptly here.
                 CookieSyncManager.getInstance().sync();
                 if (mInLoad) {
                     mInLoad = false;
                     updateInLoadMenuItems();
+                    // If the options menu is open, leave the title bar
+                    if (!mOptionsMenuOpen || !mIconView) {
+                        hideFakeTitleBar();
+                    }
                 }
-            } else {
+            } else if (!mInLoad) {
                 // onPageFinished may have already been called but a subframe
                 // is still loading and updating the progress. Reset mInLoad
                 // and update the menu items.
-                if (!mInLoad) {
-                    mInLoad = true;
-                    updateInLoadMenuItems();
+                mInLoad = true;
+                updateInLoadMenuItems();
+                if (!mOptionsMenuOpen || mIconView) {
+                    // This page has begun to load, so show the title bar
+                    showFakeTitleBar();
                 }
             }
         }
@@ -2957,7 +3273,7 @@ public class BrowserActivity extends Activity
             String url = view.getUrl();
 
             // here, if url is null, we want to reset the title
-            setUrlTitle(url, title, view);
+            setUrlTitle(url, title);
 
             if (url == null ||
                 url.length() >= SQLiteDatabase.SQLITE_MAX_LIKE_PATTERN_LENGTH) {
@@ -3000,14 +3316,26 @@ public class BrowserActivity extends Activity
         }
 
         @Override
-        public void onReceivedTouchIconUrl(WebView view, String url) {
+        public void onReceivedTouchIconUrl(WebView view, String url,
+                boolean precomposed) {
             final ContentResolver cr = getContentResolver();
             final Cursor c =
                     BrowserBookmarksAdapter.queryBookmarksForUrl(cr,
                             view.getOriginalUrl(), view.getUrl(), true);
             if (c != null) {
                 if (c.getCount() > 0) {
-                    new DownloadTouchIcon(cr, c, view).execute(url);
+                    // Let precomposed icons take precedence over non-composed
+                    // icons.
+                    if (precomposed && mTouchIconLoader != null) {
+                        mTouchIconLoader.cancel(false);
+                        mTouchIconLoader = null;
+                    }
+                    // Have only one async task at a time.
+                    if (mTouchIconLoader == null) {
+                        mTouchIconLoader = new DownloadTouchIcon(
+                                BrowserActivity.this, cr, c, view);
+                        mTouchIconLoader.execute(url);
+                    }
                 } else {
                     c.close();
                 }
@@ -3059,17 +3387,18 @@ public class BrowserActivity extends Activity
          * @param databaseIdentifier the identifier of the database on
          *     which the transaction that caused the quota overflow was run
          * @param currentQuota the current quota for the origin.
+         * @param estimatedSize the estimated size of the database.
          * @param totalUsedQuota is the sum of all origins' quota.
          * @param quotaUpdater The callback to run when a decision to allow or
          *     deny quota has been made. Don't forget to call this!
          */
         @Override
         public void onExceededDatabaseQuota(String url,
-            String databaseIdentifier, long currentQuota, long totalUsedQuota,
-            WebStorage.QuotaUpdater quotaUpdater) {
+            String databaseIdentifier, long currentQuota, long estimatedSize,
+            long totalUsedQuota, WebStorage.QuotaUpdater quotaUpdater) {
             mSettings.getWebStorageSizeManager().onExceededDatabaseQuota(
-                    url, databaseIdentifier, currentQuota, totalUsedQuota,
-                    quotaUpdater);
+                    url, databaseIdentifier, currentQuota, estimatedSize,
+                    totalUsedQuota, quotaUpdater);
         }
 
         /**
@@ -3126,6 +3455,38 @@ public class BrowserActivity extends Activity
                 }
             Log.w(LOGTAG, "Console: " + message + " " + sourceID + ":" + lineNumber);
         }
+
+        /**
+         * Ask the browser for an icon to represent a <video> element.
+         * This icon will be used if the Web page did not specify a poster attribute.
+         *
+         * @return Bitmap The icon or null if no such icon is available.
+         * @hide pending API Council approval
+         */
+        @Override
+        public Bitmap getDefaultVideoPoster() {
+            if (mDefaultVideoPoster == null) {
+                mDefaultVideoPoster = BitmapFactory.decodeResource(
+                        getResources(), R.drawable.default_video_poster);
+            }
+            return mDefaultVideoPoster;
+        }
+
+        /**
+         * Ask the host application for a custom progress view to show while
+         * a <video> is loading.
+         *
+         * @return View The progress view.
+         * @hide pending API Council approval
+         */
+        @Override
+        public View getVideoLoadingProgressView() {
+            if (mVideoProgressView == null) {
+                LayoutInflater inflater = LayoutInflater.from(BrowserActivity.this);
+                mVideoProgressView = inflater.inflate(R.layout.video_loading_progress, null);
+            }
+            return mVideoProgressView;
+        }
     };
 
     /**
@@ -3142,23 +3503,36 @@ public class BrowserActivity extends Activity
         // if we're dealing wih A/V content that's not explicitly marked
         //     for download, check if it's streamable.
         if (contentDisposition == null
-                        || !contentDisposition.regionMatches(true, 0, "attachment", 0, 10)) {
+                || !contentDisposition.regionMatches(
+                        true, 0, "attachment", 0, 10)) {
             // query the package manager to see if there's a registered handler
             //     that matches.
             Intent intent = new Intent(Intent.ACTION_VIEW);
             intent.setDataAndType(Uri.parse(url), mimetype);
-            if (getPackageManager().resolveActivity(intent,
-                        PackageManager.MATCH_DEFAULT_ONLY) != null) {
-                // someone knows how to handle this mime type with this scheme, don't download.
-                try {
-                    startActivity(intent);
-                    return;
-                } catch (ActivityNotFoundException ex) {
-                    if (LOGD_ENABLED) {
-                        Log.d(LOGTAG, "activity not found for " + mimetype
-                                + " over " + Uri.parse(url).getScheme(), ex);
+            ResolveInfo info = getPackageManager().resolveActivity(intent,
+                    PackageManager.MATCH_DEFAULT_ONLY);
+            if (info != null) {
+                ComponentName myName = getComponentName();
+                // If we resolved to ourselves, we don't want to attempt to
+                // load the url only to try and download it again.
+                if (!myName.getPackageName().equals(
+                        info.activityInfo.packageName)
+                        || !myName.getClassName().equals(
+                                info.activityInfo.name)) {
+                    // someone (other than us) knows how to handle this mime
+                    // type with this scheme, don't download.
+                    try {
+                        startActivity(intent);
+                        return;
+                    } catch (ActivityNotFoundException ex) {
+                        if (LOGD_ENABLED) {
+                            Log.d(LOGTAG, "activity not found for " + mimetype
+                                    + " over " + Uri.parse(url).getScheme(),
+                                    ex);
+                        }
+                        // Best behavior is to fall back to a download in this
+                        // case
                     }
-                    // Best behavior is to fall back to a download in this case
                 }
             }
         }
@@ -3287,23 +3661,27 @@ public class BrowserActivity extends Activity
         updateLockIconImage(LOCK_ICON_UNSECURE);
     }
 
-    /**
-     * Resets the lock icon.  This method is called when the icon needs to be
-     * reset but we do not know whether we are loading a secure or not secure
-     * page.
-     */
-    private void resetLockIcon() {
-        // Save the lock-icon state (we revert to it if the load gets cancelled)
-        saveLockIcon();
+    /* package */ void setLockIconType(int type) {
+        mLockIconType = type;
+    }
 
-        mLockIconType = LOCK_ICON_UNSECURE;
+    /* package */ int getLockIconType() {
+        return mLockIconType;
+    }
 
-        if (LOGV_ENABLED) {
-          Log.v(LOGTAG, "BrowserActivity.resetLockIcon:" +
-                " reset lock icon to " + mLockIconType);
-        }
+    /* package */ void setPrevLockType(int type) {
+        mPrevLockType = type;
+    }
 
-        updateLockIconImage(LOCK_ICON_UNSECURE);
+    /* package */ int getPrevLockType() {
+        return mPrevLockType;
+    }
+
+    /**
+     * Update the lock icon to correspond to our latest state.
+     */
+    /* package */ void updateLockIconToLatest() {
+        updateLockIconImage(mLockIconType);
     }
 
     /**
@@ -3316,10 +3694,9 @@ public class BrowserActivity extends Activity
         } else if (lockIconType == LOCK_ICON_MIXED) {
             d = mMixLockIcon;
         }
-        if (CUSTOM_BROWSER_BAR) {
-            mTitleBar.setLock(d, getTopWindow());
-        } else {
-            getWindow().setFeatureDrawable(Window.FEATURE_RIGHT_ICON, d);
+        mTitleBar.setLock(d);
+        if (mFakeTitleBar != null) {
+            mFakeTitleBar.setLock(d);
         }
     }
 
@@ -3789,13 +4166,9 @@ public class BrowserActivity extends Activity
             }
         } else {
             mIsNetworkUp = false;
-            if (mInLoad && mAlertDialog == null) {
-                mAlertDialog = new AlertDialog.Builder(this)
-                        .setTitle(R.string.loadSuspendedTitle)
-                        .setMessage(R.string.loadSuspended)
-                        .setPositiveButton(R.string.ok, null)
-                        .show();
-            }
+            if (mInLoad) {
+                createAndShowNetworkDialog();
+           }
         }
         WebView w = mTabControl.getCurrentWebView();
         if (w != null) {
@@ -3803,6 +4176,18 @@ public class BrowserActivity extends Activity
         }
     }
 
+    // This method shows the network dialog alerting the user that the net is
+    // down. It will only show the dialog if mAlertDialog is null.
+    private void createAndShowNetworkDialog() {
+        if (mAlertDialog == null) {
+            mAlertDialog = new AlertDialog.Builder(this)
+                    .setTitle(R.string.loadSuspendedTitle)
+                    .setMessage(R.string.loadSuspended)
+                    .setPositiveButton(R.string.ok, null)
+                    .show();
+        }
+    }
+
     @Override
     protected void onActivityResult(int requestCode, int resultCode,
                                     Intent intent) {
@@ -3812,16 +4197,7 @@ public class BrowserActivity extends Activity
                     String data = intent.getAction();
                     Bundle extras = intent.getExtras();
                     if (extras != null && extras.getBoolean("new_window", false)) {
-                        final TabControl.Tab newTab = openTab(data);
-                        if (mSettings.openInBackground() &&
-                                newTab != null) {
-                            mTabControl.populatePickerData(newTab);
-                            mTabControl.setCurrentTab(newTab);
-                            int newIndex = mTabControl.getCurrentIndex();
-                            if (CUSTOM_BROWSER_BAR) {
-                                mTitleBar.setCurrentTab(newIndex);
-                            }
-                        }
+                        openTab(data);
                     } else {
                         final TabControl.Tab currentTab =
                                 mTabControl.getCurrentTab();
@@ -3830,25 +4206,12 @@ public class BrowserActivity extends Activity
                             getTopWindow().loadUrl(data);
                         }
                     }
-                } else if (resultCode == RESULT_CANCELED
-                        && mCancelGoPageMeansClose) {
-                    if (mTabControl.getTabCount() == 1) {
-                        // finish the Browser.  When the Browser opens up again,
-                        // we will go through onCreate and once again open up
-                        // the Go page.
-                        finish();
-                        return;
-                    }
-                    closeCurrentWindow();
                 }
                 break;
             default:
                 break;
         }
-        mCancelGoPageMeansClose = false;
-        if (getTopWindow() != null) {
-            getTopWindow().requestFocus();
-        }
+        getTopWindow().requestFocus();
     }
 
     /*
@@ -3864,20 +4227,12 @@ public class BrowserActivity extends Activity
 
     }
 
-    // True if canceling the "Go" screen should result in closing the current
-    // window/browser.
-    private boolean mCancelGoPageMeansClose;
-
     /**
      * Open the Go page.
      * @param startWithHistory If true, open starting on the history tab.
      *                         Otherwise, start with the bookmarks tab.
-     * @param cancelGoPageMeansClose Set to true if this came from a new tab, or
-     *                               from the only tab, and canceling means to
-     *                               close the tab (and possibly the browser)
      */
-    /* package */ void bookmarksOrHistoryPicker(boolean startWithHistory,
-            boolean cancelGoPageMeansClose) {
+    /* package */ void bookmarksOrHistoryPicker(boolean startWithHistory) {
         WebView current = mTabControl.getCurrentWebView();
         if (current == null) {
             return;
@@ -3886,6 +4241,8 @@ public class BrowserActivity extends Activity
                 CombinedBookmarkHistoryActivity.class);
         String title = current.getTitle();
         String url = current.getUrl();
+        Bitmap thumbnail = createScreenshot(current);
+
         // Just in case the user opens bookmarks before a page finishes loading
         // so the current history item, and therefore the page, is null.
         if (null == url) {
@@ -3901,17 +4258,15 @@ public class BrowserActivity extends Activity
         }
         intent.putExtra("title", title);
         intent.putExtra("url", url);
-        // If this is opening in a new window, then disable opening in a
-        // (different) new window.  Also disable it if we have maxed out the
-        // windows.
-        intent.putExtra("disable_new_window", cancelGoPageMeansClose
-                || mTabControl.getTabCount() >= TabControl.MAX_TABS);
+        intent.putExtra("thumbnail", thumbnail);
+        // Disable opening in a new window if we have maxed out the windows
+        intent.putExtra("disable_new_window", mTabControl.getTabCount()
+                >= TabControl.MAX_TABS);
         intent.putExtra("touch_icon_url", current.getTouchIconUrl());
         if (startWithHistory) {
             intent.putExtra(CombinedBookmarkHistoryActivity.STARTING_TAB,
                     CombinedBookmarkHistoryActivity.HISTORY_TAB);
         }
-        mCancelGoPageMeansClose = cancelGoPageMeansClose;
         startActivityForResult(intent, COMBO_PAGE);
     }
 
@@ -4036,9 +4391,9 @@ public class BrowserActivity extends Activity
 
     }
 
-    private final static int LOCK_ICON_UNSECURE = 0;
-    private final static int LOCK_ICON_SECURE   = 1;
-    private final static int LOCK_ICON_MIXED    = 2;
+    final static int LOCK_ICON_UNSECURE = 0;
+    final static int LOCK_ICON_SECURE   = 1;
+    final static int LOCK_ICON_MIXED    = 2;
 
     private int mLockIconType = LOCK_ICON_UNSECURE;
     private int mPrevLockType = LOCK_ICON_UNSECURE;
@@ -4066,17 +4421,13 @@ public class BrowserActivity extends Activity
 
     private boolean mInLoad;
     private boolean mIsNetworkUp;
+    private boolean mDidStopLoad;
 
     private boolean mPageStarted;
     private boolean mActivityInPause = true;
 
     private boolean mMenuIsDown;
 
-    private final KeyTracker mKeyTracker = new KeyTracker(this);
-
-    // As trackball doesn't send repeat down, we have to track it ourselves
-    private boolean mTrackTrackball;
-
     private static boolean mInTrace;
 
     // Performance probe
@@ -4102,7 +4453,6 @@ public class BrowserActivity extends Activity
 
     private Drawable    mMixLockIcon;
     private Drawable    mSecLockIcon;
-    private Drawable    mGenericFavicon;
 
     /* hold a ref so we can auto-cancel if necessary */
     private AlertDialog mAlertDialog;
@@ -4182,7 +4532,7 @@ public class BrowserActivity extends Activity
 
     private Toast mStopToast;
 
-    private TitleBarSet mTitleBar;
+    private TitleBar mTitleBar;
 
     private LinearLayout mErrorConsoleContainer = null;
     private boolean mShouldShowErrorConsole = false;
@@ -4200,11 +4550,19 @@ public class BrowserActivity extends Activity
 
     private BroadcastReceiver mPackageInstallationReceiver;
 
+    // AsyncTask for downloading touch icons
+    /* package */ DownloadTouchIcon mTouchIconLoader;
+
     // activity requestCode
     final static int COMBO_PAGE                 = 1;
     final static int DOWNLOAD_PAGE              = 2;
     final static int PREFERENCES_PAGE           = 3;
 
+    // the default <video> poster
+    private Bitmap mDefaultVideoPoster;
+    // the video progress view
+    private View mVideoProgressView;
+
     /**
      * A UrlData class to abstract how the content will be set to WebView.
      * This base class uses loadUrl to show the content.