Code drop from //branches/cupcake/...@124589
diff --git a/src/com/android/browser/BrowserActivity.java b/src/com/android/browser/BrowserActivity.java
index fc4acfc..fe27f8d 100644
--- a/src/com/android/browser/BrowserActivity.java
+++ b/src/com/android/browser/BrowserActivity.java
@@ -62,6 +62,7 @@
 import android.net.http.RequestQueue;
 import android.net.http.SslCertificate;
 import android.net.http.SslError;
+import android.os.AsyncTask;
 import android.os.Build;
 import android.os.Bundle;
 import android.os.Debug;
@@ -75,13 +76,16 @@
 import android.os.ServiceManager;
 import android.os.SystemClock;
 import android.os.SystemProperties;
-import android.pim.DateFormat;
+import android.preference.PreferenceManager;
 import android.provider.Browser;
 import android.provider.Checkin;
 import android.provider.Contacts.Intents.Insert;
 import android.provider.Contacts;
 import android.provider.Downloads;
+import android.provider.MediaStore;
 import android.text.IClipboard;
+import android.text.TextUtils;
+import android.text.format.DateFormat;
 import android.text.util.Regex;
 import android.util.Config;
 import android.util.Log;
@@ -94,7 +98,6 @@
 import android.view.Menu;
 import android.view.MenuInflater;
 import android.view.MenuItem;
-import android.view.MotionEvent;
 import android.view.View;
 import android.view.ViewGroup;
 import android.view.Window;
@@ -142,6 +145,7 @@
 import java.util.HashMap;
 import java.util.HashSet;
 import java.util.List;
+import java.util.Locale;
 import java.util.regex.Matcher;
 import java.util.regex.Pattern;
 import java.util.Vector;
@@ -179,6 +183,8 @@
     private void setupHomePage() {
         final Runnable getAccount = new Runnable() {
             public void run() {
+                // Lower priority
+                Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
                 // get the default home page
                 String homepage = mSettings.getHomePage();
 
@@ -242,7 +248,9 @@
                 mGls = IGoogleLoginService.Stub.asInterface(service);
                 if (done[0] == false) {
                     done[0] = true;
-                    new Thread(getAccount).start();
+                    Thread account = new Thread(getAccount);
+                    account.setName("GLSAccount");
+                    account.start();
                 }
             }
             public void onServiceDisconnected(ComponentName className) {
@@ -513,6 +521,8 @@
          * as there is a limit of 1Mb (see Asset.h)
          */
         public void run() {
+            // Lower the priority
+            Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
             try {
                 if (pluginsPath == null) {
                     Log.e(TAG, "No plugins path found!");
@@ -598,11 +608,24 @@
         if (copyPluginsFromAssets.newSystemImage())  {
           if (copyPluginsFromAssets.checkIsDifferentVersions()) {
             copyPluginsFromAssets.cleanPluginsDirectory();
-            new Thread(copyPluginsFromAssets).start();
+            Thread copyplugins = new Thread(copyPluginsFromAssets);
+            copyplugins.setName("CopyPlugins");
+            copyplugins.start();
           }
         }
     }
 
+    private class ClearThumbnails extends AsyncTask<File, Void, Void> {
+        @Override
+        public Void doInBackground(File... files) {
+            if (files != null) {
+                for (File f : files) {
+                    f.delete();
+                }
+            }
+            return null;
+        }
+    }
 
     @Override public void onCreate(Bundle icicle) {
         if (Config.LOGV) {
@@ -621,6 +644,9 @@
 
         mResolver = getContentResolver();
 
+        setBaseSearchUrl(PreferenceManager.getDefaultSharedPreferences(this)
+                .getString("search_url", ""));
+
         //
         // start MASF proxy service
         //
@@ -658,10 +684,19 @@
         mWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "Browser");
 
         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.
+            new ClearThumbnails().execute(
+                    mTabControl.getThumbnailDir().listFiles());
             final Intent intent = getIntent();
             final Bundle extra = intent.getExtras();
             // Create an initial tab.
-            final TabControl.Tab t = mTabControl.createNewTab();
+            // If the intent is ACTION_VIEW and data is not null, the Browser is
+            // invoked to view the content by another application. In this case,
+            // the tab will be close when exit.
+            final TabControl.Tab t = mTabControl.createNewTab(
+                    Intent.ACTION_VIEW.equals(intent.getAction()) &&
+                    intent.getData() != null);
             mTabControl.setCurrentTab(t);
             // This is one of the only places we call attachTabToContentView
             // without animating from the tab picker.
@@ -722,6 +757,15 @@
 
     @Override
     protected void onNewIntent(Intent intent) {
+        // When a tab is closed on exit, the current tab index is set to -1.
+        // Reset before proceed as Browser requires the current tab to be set.
+        if (mTabControl.getCurrentIndex() == -1) {
+            TabControl.Tab current = mTabControl.getTab(0);
+            mTabControl.setCurrentTab(current);
+            attachTabToContentView(current);
+            mWebView = current.getWebView();
+            resetTitleAndIcon(mWebView);
+        }
         if (mWebView == null) {
             return;
         }
@@ -734,6 +778,7 @@
         }
         if (Intent.ACTION_VIEW.equals(action)
                 || Intent.ACTION_SEARCH.equals(action)
+                || MediaStore.INTENT_ACTION_MEDIA_SEARCH.equals(action)
                 || Intent.ACTION_WEB_SEARCH.equals(action)) {
             String url = getUrlFromIntent(intent);
             if (url == null || url.length() == 0) {
@@ -742,9 +787,10 @@
             if (Intent.ACTION_VIEW.equals(action) && 
                     (flags & Intent.FLAG_ACTIVITY_BROUGHT_TO_FRONT) != 0) {
                 // if FLAG_ACTIVITY_BROUGHT_TO_FRONT flag is on, the url will be
-                // opened in a new tab unless we have reached MAX_TABS and the
-                // url will be opened in the current tab
-                openTabAndShow(url, null);
+                // opened in a new tab unless we have reached MAX_TABS. Then the
+                // url will be opened in the current tab. If a new tab is
+                // created, it will have "true" for exit on close.
+                openTabAndShow(url, null, true);
             } else {
                 if ("about:debug".equals(url)) {
                     mSettings.toggleDebugSettings();
@@ -779,24 +825,39 @@
                     }
                 }
             } else if (Intent.ACTION_SEARCH.equals(action)
+                    || MediaStore.INTENT_ACTION_MEDIA_SEARCH.equals(action)
                     || Intent.ACTION_WEB_SEARCH.equals(action)) {
                 url = intent.getStringExtra(SearchManager.QUERY);
-                mLastEnteredUrl = url;
-                // Don't add Urls, just search terms.
-                // Urls will get added when the page is loaded.
-                if (!Regex.WEB_URL_PATTERN.matcher(url).matches()) {
-                    Browser.updateVisitedHistory(mResolver, url, false);
+                if (url != null) {
+                    mLastEnteredUrl = url;
+                    // Don't add Urls, just search terms.
+                    // Urls will get added when the page is loaded.
+                    if (!Regex.WEB_URL_PATTERN.matcher(url).matches()) {
+                        Browser.updateVisitedHistory(mResolver, url, false);
+                    }
+                    // In general, we shouldn't modify URL from Intent.
+                    // But currently, we get the user-typed URL from search box as well.
+                    url = fixUrl(url);
+                    url = smartUrlFilter(url);
+                    String searchSource = "&source=android-" + GOOGLE_SEARCH_SOURCE_SUGGEST + "&";
+                    if (url.contains(searchSource)) {
+                        String source = null;
+                        final Bundle appData = intent.getBundleExtra(SearchManager.APP_DATA);
+                        if (appData != null) {
+                            source = appData.getString(SearchManager.SOURCE);
+                        }
+                        if (TextUtils.isEmpty(source)) {
+                            source = GOOGLE_SEARCH_SOURCE_UNKNOWN;
+                        }
+                        url = url.replace(searchSource, "&source=android-"+source+"&");
+                    }
                 }
-                // In general, we shouldn't modify URL from Intent.
-                // But currently, we get the user-typed URL from search box as well.
-                url = fixUrl(url);
-                url = smartUrlFilter(url);
             }
         }
         return url;
     }
 
-    private String fixUrl(String inUrl) {
+    /* package */ static String fixUrl(String inUrl) {
         if (inUrl.startsWith("http://") || inUrl.startsWith("https://"))
             return inUrl;
         if (inUrl.startsWith("http:") ||
@@ -970,7 +1031,7 @@
         }
 
         mActivityInPause = true;
-        if (!pauseWebView()) {
+        if (mTabControl.getCurrentIndex() >= 0 && !pauseWebView()) {
             mWakeLock.acquire();
             mHandler.sendMessageDelayed(mHandler
                     .obtainMessage(RELEASE_WAKELOCK), WAKELOCK_TIMEOUT);
@@ -1057,6 +1118,9 @@
             showHttpAuthentication(mHttpAuthHandler, null, null, title,
                     name, password, focusId);
         }
+        if (mFindDialog != null && mFindDialog.isShowing()) {
+            mFindDialog.onConfigurationChanged(newConfig);
+        }
     }
 
     @Override public void onLowMemory() {
@@ -1192,6 +1256,11 @@
         // options selector, so set mCanChord to true so we can access them.
         mCanChord = true;
         int id = item.getItemId();
+        final WebView webView = getTopWindow();
+        final HashMap hrefMap = new HashMap();
+        hrefMap.put("webview", webView);
+        final Message msg = mHandler.obtainMessage(
+                FOCUS_NODE_HREF, id, 0, hrefMap);
         switch (id) {
             // -- Browser context menu
             case R.id.open_context_menu_id:
@@ -1200,21 +1269,9 @@
             case R.id.save_link_context_menu_id:
             case R.id.share_link_context_menu_id:
             case R.id.copy_link_context_menu_id:
-                Message msg = mHandler.obtainMessage(
-                        FOCUS_NODE_HREF, id, 0);
-                WebView webview = getTopWindow();
-                msg.obj = webview;
-                webview.requestFocusNodeHref(msg);
+                webView.requestFocusNodeHref(msg);
                 break;
 
-            case R.id.download_context_menu_id:
-            case R.id.view_image_context_menu_id:
-                Message m = mHandler.obtainMessage(
-                        FOCUS_NODE_HREF, id, 0);
-                WebView w = getTopWindow();
-                m.obj = w;
-                w.requestImageRef(m);
-                break;
             default:
                 // For other context menus
                 return onOptionsItemSelected(item);
@@ -1222,18 +1279,34 @@
         mCanChord = false;
         return true;
     }
-    
+
+    private Bundle createGoogleSearchSourceBundle(String source) {
+        Bundle bundle = new Bundle();
+        bundle.putString(SearchManager.SOURCE, source);
+        return bundle;
+    }
+
     /**
      * Overriding this forces the search key to launch global search.  The difference
      * is the final "true" which requests global search.
      */
     @Override
     public boolean onSearchRequested() {
-        startSearch(null, false, null, true); 
+        startSearch(null, false,
+                createGoogleSearchSourceBundle(GOOGLE_SEARCH_SOURCE_SEARCHKEY), true);
         return true;
     }
 
     @Override
+    public void startSearch(String initialQuery, boolean selectInitialQuery, 
+            Bundle appSearchData, boolean globalSearch) {
+        if (appSearchData == null) {
+            appSearchData = createGoogleSearchSourceBundle(GOOGLE_SEARCH_SOURCE_TYPE);
+        }
+        super.startSearch(initialQuery, selectInitialQuery, appSearchData, globalSearch);
+    }
+
+    @Override
     public boolean onOptionsItemSelected(MenuItem item) {
         if (!mCanChord) {
             // The user has already fired a shortcut with this hold down of the
@@ -1244,23 +1317,27 @@
             // -- Main menu
             case R.id.goto_menu_id: {
                 String url = getTopWindow().getUrl();
-                // TODO: Activities are requested to call onSearchRequested, and to override
-                // that function in order to insert custom fields (e.g. the search query).
-                startSearch(mSettings.getHomePage().equals(url) ? null : url, true, null, false);
+                startSearch(mSettings.getHomePage().equals(url) ? null : url, true,
+                        createGoogleSearchSourceBundle(GOOGLE_SEARCH_SOURCE_GOTO), false);
                 }
                 break;
-                
+
             case R.id.search_menu_id:
                 // launch using "global" search, which will bring up the Google search box
-                onSearchRequested(); 
+                startSearch(null, false,
+                        createGoogleSearchSourceBundle(GOOGLE_SEARCH_SOURCE_SEARCHMENU), true);
                 break;
-        
+
             case R.id.bookmarks_menu_id:
                 bookmarksPicker();
                 break;
 
             case R.id.windows_menu_id:
-                tabPicker(true, mTabControl.getCurrentIndex(), false);
+                if (mTabControl.getTabCount() == 1) {
+                    openTabAndShow(mSettings.getHomePage(), null, false);
+                } else {
+                    tabPicker(true, mTabControl.getCurrentIndex(), false);
+                }
                 break;
 
             case R.id.stop_reload_menu_id:
@@ -1299,7 +1376,7 @@
                         indexToShow--;
                     }
                 }
-                removeTabAndShow(currentIndex, indexToShow);
+                switchTabs(currentIndex, indexToShow, true);
                 break;
 
             case R.id.homepage_menu_id:
@@ -1313,39 +1390,21 @@
                 startActivityForResult(intent, PREFERENCES_PAGE);
                 break;
 
-/*
-            Disable Find for version 1.0
             case R.id.find_menu_id:
                 if (null == mFindDialog) {
                     mFindDialog = new FindDialog(this);
-                    FrameLayout.LayoutParams lp = 
-                        new FrameLayout.LayoutParams(
-                        ViewGroup.LayoutParams.FILL_PARENT, 
-                        ViewGroup.LayoutParams.WRAP_CONTENT, 
-                        Gravity.BOTTOM);
-                        mFindDialog.setLayoutParams(lp);
                 }
                 mFindDialog.setWebView(getTopWindow());
-                mContentView.addView(mFindDialog);
                 mFindDialog.show();
-                Animation anim =AnimationUtils.loadAnimation(this,
-                        R.anim.find_dialog_enter);
-                mFindDialog.startAnimation(anim);
                 mMenuState = EMPTY_MENU;
                 break;
-*/
 
             case R.id.page_info_menu_id:
-                showPageInfo(mWebView, false);
+                showPageInfo(mTabControl.getCurrentTab(), false);
                 break;
 
-            case R.id.classic_history_menu_id: {
-                    Intent i = new Intent(this, BrowserHistoryPage.class);
-                    i.putExtra("maxTabsOpen",
-                            mTabControl.getTabCount() >=
-                            TabControl.MAX_TABS);
-                    startActivityForResult(i, CLASSIC_HISTORY_PAGE);
-                }
+            case R.id.classic_history_menu_id:
+                loadHistory();
                 break;
 
             case R.id.bookmark_page_menu_id:
@@ -1448,15 +1507,33 @@
             case R.id.properties_tab_menu_id:
                 if (mTabListener != null && mTabOverview != null) {
                     int pos = mTabOverview.getContextMenuPosition(item);
-                    TabControl.Tab t = mTabControl.getTab(pos);
-                    // Use the tab's data for the page info dialog.
-                    if (t.getWebView() != null) {
-                        showPageInfo(t.getWebView(), false);
-                    }
-                    // FIXME: what should we display if the WebView is null?
+                    showPageInfo(mTabControl.getTab(pos), false);
                 }
                 break;
 
+            case R.id.window_one_menu_id:
+            case R.id.window_two_menu_id:
+            case R.id.window_three_menu_id:
+            case R.id.window_four_menu_id:
+            case R.id.window_five_menu_id:
+            case R.id.window_six_menu_id:
+            case R.id.window_seven_menu_id:
+            case R.id.window_eight_menu_id:
+                {
+                    int menuid = item.getItemId();
+                    for (int id = 0; id < WINDOW_SHORTCUT_ID_ARRAY.length; id++) {
+                        if (WINDOW_SHORTCUT_ID_ARRAY[id] == menuid) {
+                            TabControl.Tab desiredTab = mTabControl.getTab(id);
+                            if (desiredTab != null && 
+                                    desiredTab != mTabControl.getCurrentTab()) {
+                                switchTabs(mTabControl.getCurrentIndex(), id, false);
+                            }
+                            break;
+                        } 
+                    }
+                }
+                break;
+                
             default:
                 if (!super.onOptionsItemSelected(item)) {
                     return false;
@@ -1468,29 +1545,9 @@
     }
 
     public void closeFind() {
-        Animation anim = AnimationUtils.loadAnimation(this,
-                R.anim.find_dialog_exit);
-        mFindDialog.startAnimation(anim);
-        mContentView.removeView(mFindDialog);
-        getTopWindow().requestFocus();
         mMenuState = R.id.MAIN_MENU;
     }
 
-    @Override
-    public boolean dispatchTouchEvent(MotionEvent event) {
-        if (super.dispatchTouchEvent(event)) {
-            return true;
-        } else {
-            // We do not use the Dialog class because it places dialogs in the
-            // middle of the screen.  It would take care of dismissing find if
-            // were using it, but we are doing it manually since we are not.
-            if (mFindDialog != null && mFindDialog.hasFocus()) {
-                mFindDialog.dismiss();
-            }
-            return false;
-        }
-    }
-    
     @Override public boolean onPrepareOptionsMenu(Menu menu)
     {
         // This happens when the user begins to hold down the menu key, so
@@ -1533,14 +1590,11 @@
                 final MenuItem back = menu.findItem(R.id.back_menu_id);
                 back.setVisible(canGoBack);
                 back.setEnabled(canGoBack);
-                final MenuItem close = menu.findItem(R.id.close_menu_id);
-                close.setVisible(!canGoBack);
-                close.setEnabled(!canGoBack);
                 final MenuItem flip = 
                         menu.findItem(R.id.flip_orientation_menu_id);
                 boolean keyboardClosed = 
-                        getResources().getConfiguration().keyboardHidden == 
-                        Configuration.KEYBOARDHIDDEN_YES;
+                        getResources().getConfiguration().hardKeyboardHidden == 
+                        Configuration.HARDKEYBOARDHIDDEN_YES;
                 flip.setEnabled(keyboardClosed);
 
                 boolean isHome = mSettings.getHomePage().equals(w.getUrl());
@@ -1562,6 +1616,19 @@
                         PackageManager.MATCH_DEFAULT_ONLY);
                 menu.findItem(R.id.share_page_menu_id).setVisible(
                         list.size() > 0);
+                
+                // Hide the menu+<window number> items
+                // Can't set visibility in menu xml file b/c when a
+                // group is set visible, all items are set visible.
+                for (int i = 0; i < WINDOW_SHORTCUT_ID_ARRAY.length; i++) {
+                    menu.findItem(WINDOW_SHORTCUT_ID_ARRAY[i]).setVisible(false);
+                }
+
+                // If there is only 1 window, the text will be "New window"
+                final MenuItem windows = menu.findItem(R.id.windows_menu_id);
+                windows.setTitleCondensed(mTabControl.getTabCount() > 1 ?
+                        getString(R.string.view_tabs_condensed) :
+                        getString(R.string.tab_picker_new_tab));
 
                 boolean isNavDump = mSettings.isNavDump();
                 final MenuItem nav = menu.findItem(R.id.dump_nav_menu_id);
@@ -1608,26 +1675,22 @@
         menu.setGroupVisible(R.id.GEO_MENU,
                 type == WebView.HitTestResult.GEO_TYPE);
         menu.setGroupVisible(R.id.IMAGE_MENU,
-                type == WebView.HitTestResult.IMAGE_TYPE ||
-                type == WebView.HitTestResult.IMAGE_ANCHOR_TYPE
+                type == WebView.HitTestResult.IMAGE_TYPE
                 || type == WebView.HitTestResult.SRC_IMAGE_ANCHOR_TYPE);
         menu.setGroupVisible(R.id.ANCHOR_MENU,
-                type == WebView.HitTestResult.ANCHOR_TYPE ||
-                type == WebView.HitTestResult.IMAGE_ANCHOR_TYPE
-                || type == WebView.HitTestResult.SRC_ANCHOR_TYPE
+                type == WebView.HitTestResult.SRC_ANCHOR_TYPE
                 || type == WebView.HitTestResult.SRC_IMAGE_ANCHOR_TYPE);
 
         // Setup custom handling depending on the type
         switch (type) {
             case WebView.HitTestResult.PHONE_TYPE:
-                menu.setHeaderTitle(extra);
+                menu.setHeaderTitle(Uri.decode(extra));
                 menu.findItem(R.id.dial_context_menu_id).setIntent(
                         new Intent(Intent.ACTION_VIEW, Uri
                                 .parse(WebView.SCHEME_TEL + extra)));
-                Intent addIntent = new Intent(Intent.ACTION_INSERT,
-                        Contacts.People.CONTENT_URI);
-                addIntent.putExtra(Insert.FULL_MODE, true);
-                addIntent.putExtra(Insert.PHONE, extra);
+                Intent addIntent = new Intent(Intent.ACTION_INSERT_OR_EDIT);
+                addIntent.putExtra(Insert.PHONE, Uri.decode(extra));
+                addIntent.setType(Contacts.People.CONTENT_ITEM_TYPE);
                 menu.findItem(R.id.add_contact_context_menu_id).setIntent(
                         addIntent);
                 menu.findItem(R.id.copy_phone_context_menu_id).setOnMenuItemClickListener(
@@ -1653,35 +1716,16 @@
                         new Copy(extra));
                 break;
 
-            case WebView.HitTestResult.ANCHOR_TYPE:
-            case WebView.HitTestResult.IMAGE_ANCHOR_TYPE:
             case WebView.HitTestResult.SRC_ANCHOR_TYPE:
             case WebView.HitTestResult.SRC_IMAGE_ANCHOR_TYPE:
-                mTitleView = (TextView) LayoutInflater.from(this)
+                TextView titleView = (TextView) LayoutInflater.from(this)
                         .inflate(android.R.layout.browser_link_context_header,
                         null);
-                menu.setHeaderView(mTitleView);
+                titleView.setText(extra);
+                menu.setHeaderView(titleView);
                 // decide whether to show the open link in new tab option
                 menu.findItem(R.id.open_newtab_context_menu_id).setVisible(
                         mTabControl.getTabCount() < TabControl.MAX_TABS);
-                if (type == WebView.HitTestResult.ANCHOR_TYPE
-                        || type == WebView.HitTestResult.IMAGE_ANCHOR_TYPE){
-                    menu.findItem(R.id.bookmark_context_menu_id).setVisible(
-                            false);
-                    menu.findItem(R.id.save_link_context_menu_id).setVisible(
-                            false);
-                    menu.findItem(R.id.copy_link_context_menu_id).setVisible(
-                            false);
-                    menu.findItem(R.id.share_link_context_menu_id).setVisible(
-                            false);
-                    mTitleView.setText(R.string.contextmenu_javascript);
-                    break;
-                }
-                Message headerMessage = mHandler.obtainMessage(FOCUS_NODE_HREF,
-                        HEADER_FLAG, 0);
-                headerMessage.obj = webview;
-                webview.requestFocusNodeHref(headerMessage);
-                // decide whether to show the share link option
                 PackageManager pm = getPackageManager();
                 Intent send = new Intent(Intent.ACTION_SEND);
                 send.setType("text/plain");
@@ -1689,12 +1733,14 @@
                         PackageManager.MATCH_DEFAULT_ONLY);
                 menu.findItem(R.id.share_link_context_menu_id).setVisible(
                         list.size() > 0);
-                if (type == WebView.HitTestResult.ANCHOR_TYPE) {
-                    break;
-                }
-                //fall through
+                break;
 
             case WebView.HitTestResult.IMAGE_TYPE:
+                menu.setHeaderTitle(extra);
+                menu.findItem(R.id.view_image_context_menu_id).setIntent(
+                        new Intent(Intent.ACTION_VIEW, Uri.parse(extra)));
+                menu.findItem(R.id.download_context_menu_id).
+                        setOnMenuItemClickListener(new Download(extra));
                 break;
 
             default:
@@ -1793,10 +1839,10 @@
         // Increment the count to indicate that we are in an animation.
         mAnimationCount++;
         // Remove the listener so we don't get any more tab changes.
-        if (mTabOverview != null) {
-            mTabOverview.setListener(null);
-        }
+        mTabOverview.setListener(null);
         mTabListener = null;
+        // Make the menu empty until the animation completes.
+        mMenuState = EMPTY_MENU;
 
     }
 
@@ -1828,7 +1874,8 @@
     // the given Message. If the tab overview is already showing (i.e. this
     // method is called from TabListener.onClick(), the method will animate
     // away from the tab overview.
-    private void openTabAndShow(String url, final Message msg) {
+    private void openTabAndShow(String url, final Message msg,
+            boolean closeOnExit) {
         final boolean newTab = mTabControl.getTabCount() != TabControl.MAX_TABS;
         final TabControl.Tab currentTab = mTabControl.getCurrentTab();
         if (newTab) {
@@ -1856,7 +1903,7 @@
                 }
                 // Animate from the Tab overview after any animations have
                 // finished.
-                sendAnimateFromOverview(mTabControl.createNewTab(),
+                sendAnimateFromOverview(mTabControl.createNewTab(closeOnExit),
                         true, url, delay, msg);
             }
         } else if (url != null) {
@@ -1900,10 +1947,6 @@
     // be displayed to the user.
     private void animateToTabOverview(final int newIndex, final boolean remove,
             final AnimatingView view) {
-        if (mTabOverview == null) {
-            return;
-        }
-
         // Find the view in the ImageGrid allowing for the "New Tab" cell.
         int position = mTabControl.getTabIndex(view.mTab);
         if (!((ImageAdapter) mTabOverview.getAdapter()).maxedOut()) {
@@ -1920,12 +1963,10 @@
         final Animation.AnimationListener l =
                 new Animation.AnimationListener() {
                     public void onAnimationStart(Animation a) {
-                        if (mTabOverview != null) {
-                            mTabOverview.requestFocus();
-                            // Clear the listener so we don't trigger a tab
-                            // selection.
-                            mTabOverview.setListener(null);
-                        }
+                        mTabOverview.requestFocus();
+                        // Clear the listener so we don't trigger a tab
+                        // selection.
+                        mTabOverview.setListener(null);
                     }
                     public void onAnimationRepeat(Animation a) {}
                     public void onAnimationEnd(Animation a) {
@@ -1940,17 +1981,15 @@
                             public void run() {
                                 // Remove the AnimatingView.
                                 mContentView.removeView(view);
-                                if (mTabOverview != null) {
-                                    // Make newIndex visible.
-                                    mTabOverview.setCurrentIndex(newIndex);
-                                    // Restore the listener.
-                                    mTabOverview.setListener(mTabListener);
-                                    // Change the menu to TAB_MENU if the
-                                    // ImageGrid is interactive.
-                                    if (mTabOverview.isLive()) {
-                                        mMenuState = R.id.TAB_MENU;
-                                        mTabOverview.requestFocus();
-                                    }
+                                // Make newIndex visible.
+                                mTabOverview.setCurrentIndex(newIndex);
+                                // Restore the listener.
+                                mTabOverview.setListener(mTabListener);
+                                // Change the menu to TAB_MENU if the
+                                // ImageGrid is interactive.
+                                if (mTabOverview.isLive()) {
+                                    mMenuState = R.id.TAB_MENU;
+                                    mTabOverview.requestFocus();
                                 }
                                 // If a remove was requested, remove the tab.
                                 if (remove) {
@@ -1968,12 +2007,10 @@
                                     if (currentTab != tab) {
                                         mTabControl.setCurrentTab(currentTab);
                                     }
-                                    if (mTabOverview != null) {
-                                        mTabOverview.remove(newIndex);
-                                        // Make the current tab visible.
-                                        mTabOverview.setCurrentIndex(
-                                                mTabControl.getCurrentIndex());
-                                    }
+                                    mTabOverview.remove(newIndex);
+                                    // Make the current tab visible.
+                                    mTabOverview.setCurrentIndex(
+                                            mTabControl.getCurrentIndex());
                                 }
                             }
                         });
@@ -1999,11 +2036,6 @@
     // from.
     private void animateFromTabOverview(final AnimatingView view,
             final boolean newTab, final String url, final Message msg) {
-        // mTabOverview may have been dismissed
-        if (mTabOverview == null) {
-            return;
-        }
-
         // firstVisible is the first visible tab on the screen.  This helps
         // to know which corner of the screen the selected tab is.
         int firstVisible = mTabOverview.getFirstVisiblePosition();
@@ -2025,32 +2057,19 @@
         // Find the view at this location.
         final View v = mTabOverview.getChildAt(location);
 
-        // Use a delay of 1 second in case we get a bad position
-        long delay = 1000;
-        boolean fade = false;
-
         // Wait until the animation completes to load the url.
         final Animation.AnimationListener l =
                 new Animation.AnimationListener() {
                     public void onAnimationStart(Animation a) {}
                     public void onAnimationRepeat(Animation a) {}
                     public void onAnimationEnd(Animation a) {
-                        // The animation is done so allow key events and other
-                        // animations to begin.
-                        mAnimationCount--;
                         mHandler.post(new Runnable() {
                             public void run() {
-                                if (v != null) {
-                                    mContentView.removeView(view);
-                                    mWebView.setVisibility(View.VISIBLE);
-                                    // Make the sub window container visible if
-                                    // there is one.
-                                    if (mTabControl.getCurrentSubWindow() != null) {
-                                        mTabControl.getCurrentTab()
-                                                .getSubWebViewContainer()
-                                                .setVisibility(View.VISIBLE);
-                                    }
-                                }
+                                mContentView.removeView(view);
+                                // Dismiss the tab overview. If the cell at the
+                                // given location is null, set the fade
+                                // parameter to true.
+                                dismissTabOverview(v == null);
                                 if (url != null) {
                                     // Dismiss the subwindow if one exists.
                                     dismissSubWindow(
@@ -2065,6 +2084,12 @@
                                 if (msg != null) {
                                     msg.sendToTarget();
                                 }
+                                // The animation is done and the tab overview is
+                                // gone so allow key events and other animations
+                                // to begin.
+                                mAnimationCount--;
+                                // Reset all the title bar info.
+                                resetTitle();
                             }
                         });
                     }
@@ -2077,32 +2102,42 @@
             view.startAnimation(anim);
             // Make the view VISIBLE during the animation.
             view.setVisibility(View.VISIBLE);
-            // Dismiss the tab overview after the animation completes.
-            delay = anim.getDuration();
         } else {
-            // dismiss mTabOverview and have it fade out just in case we get a
-            // bad location.
-            fade = true;
             // Go ahead and load the url.
             l.onAnimationEnd(null);
         }
-        // Reset all the title bar info.
-        resetTitle();
-        // Dismiss the tab overview either after the animation or after a
-        // second.
-        mHandler.sendMessageDelayed(mHandler.obtainMessage(
-                DISMISS_TAB_OVERVIEW, fade ? 1 : 0, 0), delay);
+    }
+
+    // Dismiss the tab overview applying a fade if needed.
+    private void dismissTabOverview(final boolean fade) {
+        if (fade) {
+            AlphaAnimation anim = new AlphaAnimation(1.0f, 0.0f);
+            anim.setDuration(500);
+            anim.startNow();
+            mTabOverview.startAnimation(anim);
+        }
+        // Just in case there was a problem with animating away from the tab
+        // overview
+        mWebView.setVisibility(View.VISIBLE);
+        // Make the sub window container visible.
+        if (mTabControl.getCurrentSubWindow() != null) {
+            mTabControl.getCurrentTab().getSubWebViewContainer()
+                    .setVisibility(View.VISIBLE);
+        }
+        mContentView.removeView(mTabOverview);
+        mTabOverview.clear();
+        mTabOverview = null;
+        mTabListener = null;
     }
 
     private void openTab(String url) {
         if (mSettings.openInBackground()) {
-            TabControl.Tab t = mTabControl.createNewTab();
+            TabControl.Tab t = mTabControl.createNewTab(false);
             if (t != null) {
-                WebView w = t.getWebView();
-                w.loadUrl(url);
+                t.getWebView().loadUrl(url);
             }
         } else {
-            openTabAndShow(url, null);
+            openTabAndShow(url, null, false);
         }
     }
 
@@ -2118,6 +2153,19 @@
             mText = toCopy;
         }
     }
+    
+    private class Download implements OnMenuItemClickListener {
+        private String mText;
+
+        public boolean onMenuItemClick(MenuItem item) {
+            onDownloadStartNoStream(mText, null, null, null, -1);
+            return true;
+        }
+
+        public Download(String toDownload) {
+            mText = toDownload;
+        }
+    }
 
     private void copy(CharSequence text) {
         try {
@@ -2184,7 +2232,11 @@
         mUrl = url;
         mTitle = title;
 
-        setTitle(buildUrlTitle(url, title));
+        // While the tab overview is animating or being shown, block changes
+        // to the title.
+        if (mAnimationCount == 0 && mTabOverview == null) {
+            setTitle(buildUrlTitle(url, title));
+        }
     }
 
     /**
@@ -2255,6 +2307,11 @@
 
     // Set the favicon in the title bar.
     private void setFavicon(Bitmap icon) {
+        // While the tab overview is animating or being shown, block changes to
+        // the favicon.
+        if (mAnimationCount > 0 || mTabOverview != null) {
+            return;
+        }
         Drawable[] array = new Drawable[2];
         PaintDrawable p = new PaintDrawable(Color.WHITE);
         p.setCornerRadius(3f);
@@ -2294,11 +2351,11 @@
         updateLockIconImage(mLockIconType);
     }
 
-    private void removeTabAndShow(int indexToRemove, int indexToShow) {
+    private void switchTabs(int indexFrom, int indexToShow, boolean remove) {
         int delay = TAB_ANIMATION_DURATION + TAB_OVERVIEW_DELAY;
         // Animate to the tab picker, remove the current tab, then
         // animate away from the tab picker to the parent WebView.
-        tabPicker(false, indexToRemove, true);
+        tabPicker(false, indexFrom, remove);
         // Change to the parent tab
         final TabControl.Tab tab = mTabControl.getTab(indexToShow);
         if (tab != null) {
@@ -2315,13 +2372,25 @@
         if (mWebView.canGoBack()) {
             mWebView.goBack();
         } else {
+            TabControl.Tab self = mTabControl.getCurrentTab();
             // Check to see if we are closing a window that was created by
             // another window. If so, we switch back to that window.
-            TabControl.Tab parent = mTabControl.getCurrentTab().getParentTab();
+            TabControl.Tab parent = self.getParentTab();
             if (parent != null) {
-                removeTabAndShow(mTabControl.getCurrentIndex(),
-                        mTabControl.getTabIndex(parent));
+                switchTabs(mTabControl.getCurrentIndex(),
+                        mTabControl.getTabIndex(parent), true);
             } else {
+                if (self.closeOnExit()) {
+                    if (mTabControl.getTabCount() == 1) {
+                        finish();
+                        return;
+                    }
+                    // call pauseWebView() now, we won't be able to call it in
+                    // onPause() as the mWebView won't be valid.
+                    pauseWebView();
+                    removeTabFromContentView(self);
+                    mTabControl.removeTab(self);
+                }
                 /*
                  * Instead of finishing the activity, simply push this to the back
                  * of the stack and let ActivityManager to choose the foreground
@@ -2352,7 +2421,10 @@
             if (mAnimationCount > 0) {
                 return KeyTracker.State.DONE_TRACKING;
             }
-            if (stage == KeyTracker.Stage.UP) {
+            if (stage == KeyTracker.Stage.LONG_REPEAT) {
+                loadHistory();
+                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?
@@ -2381,14 +2453,12 @@
         if (!handled) {
             switch (keyCode) {
                 case KeyEvent.KEYCODE_SPACE:
-                    if (mMenuState == R.id.MAIN_MENU){
-                        if (event.isShiftPressed()) {
-                            getTopWindow().pageUp(false);
-                        } else {
-                            getTopWindow().pageDown(false);
-                        }
-                        handled = true;
+                    if (event.isShiftPressed()) {
+                        getTopWindow().pageUp(false);
+                    } else {
+                        getTopWindow().pageDown(false);
                     }
+                    handled = true;
                     break;
 
                 default:
@@ -2424,6 +2494,13 @@
         }
     }
 
+    private void loadHistory() {
+        Intent intent = new Intent(this, BrowserHistoryPage.class);
+        intent.putExtra("maxTabsOpen",
+                mTabControl.getTabCount() >= TabControl.MAX_TABS);
+        startActivityForResult(intent, CLASSIC_HISTORY_PAGE);
+    }
+
     // called by a non-UI thread to post the message
     public void postMessage(int what, int arg1, int arg2, Object obj) {
         mHandler.sendMessage(mHandler.obtainMessage(what, arg1, arg2, obj));
@@ -2436,13 +2513,12 @@
     // Message Ids
     private static final int JS_CONFIRM              = 101;
     private static final int FOCUS_NODE_HREF         = 102;
-    private static final int DISMISS_TAB_OVERVIEW    = 103;
-    private static final int CANCEL_CREDS_REQUEST    = 104;
-    private static final int ANIMATE_FROM_OVERVIEW   = 105;
-    private static final int ANIMATE_TO_OVERVIEW     = 106;
-    private static final int OPEN_TAB_AND_SHOW       = 107;
-    private static final int CHECK_MEMORY            = 108;
-    private static final int RELEASE_WAKELOCK        = 109;
+    private static final int CANCEL_CREDS_REQUEST    = 103;
+    private static final int ANIMATE_FROM_OVERVIEW   = 104;
+    private static final int ANIMATE_TO_OVERVIEW     = 105;
+    private static final int OPEN_TAB_AND_SHOW       = 106;
+    private static final int CHECK_MEMORY            = 107;
+    private static final int RELEASE_WAKELOCK        = 108;
 
     // Private handler for handling javascript and saving passwords
     private Handler mHandler = new Handler() {
@@ -2458,37 +2534,6 @@
                     }
                     break;
 
-                case DISMISS_TAB_OVERVIEW:
-                    if (mTabOverview != null) {
-                        if (msg.arg1 == 1) {
-                            AlphaAnimation anim =
-                                    new AlphaAnimation(1.0f, 0.0f);
-                            anim.setDuration(500);
-                            anim.startNow();
-                            mTabOverview.startAnimation(anim);
-                        }
-                        // Just in case there was a problem with animating away
-                        // from the tab overview
-                        mWebView.setVisibility(View.VISIBLE);
-                        // Make the sub window container visible.
-                        if (mTabControl.getCurrentSubWindow() != null) {
-                            mTabControl.getCurrentTab().getSubWebViewContainer()
-                                    .setVisibility(View.VISIBLE);
-                        }
-                        mContentView.removeView(mTabOverview);
-                        mTabOverview.clear();
-                        // XXX: There are checks for mTabOverview throughout
-                        // this file because this message can be received
-                        // before it is expected. This is because we are not
-                        // enforcing the order of animations properly. In order
-                        // to get this right, we would need to rewrite a lot of
-                        // the code to dispatch this messages after all
-                        // animations have completed.
-                        mTabOverview = null;
-                        mTabListener = null;
-                    }
-                    break;
-                    
                 case ANIMATE_FROM_OVERVIEW:
                     final HashMap map = (HashMap) msg.obj;
                     animateFromTabOverview((AnimatingView) map.get("view"),
@@ -2502,7 +2547,7 @@
                     break;
 
                 case OPEN_TAB_AND_SHOW:
-                    openTabAndShow((String) msg.obj, null);
+                    openTabAndShow((String) msg.obj, null, false);
                     break;
 
                 case FOCUS_NODE_HREF:
@@ -2510,18 +2555,16 @@
                     if (url == null || url.length() == 0) {
                         break;
                     }
-                    WebView view = (WebView) msg.obj;
+                    HashMap focusNodeMap = (HashMap) msg.obj;
+                    WebView view = (WebView) focusNodeMap.get("webview");
                     // Only apply the action if the top window did not change.
                     if (getTopWindow() != view) {
                         break;
                     }
                     switch (msg.arg1) {
-                        case HEADER_FLAG:
-                            mTitleView.setText(url);
-                            break;
                         case R.id.open_context_menu_id:
                         case R.id.view_image_context_menu_id:
-                            loadURL(url);
+                            loadURL(getTopWindow(), url);
                             break;
                         case R.id.open_newtab_context_menu_id:
                             openTab(url);
@@ -2546,7 +2589,7 @@
                     break;
 
                 case LOAD_URL:
-                    loadURL((String) msg.obj);
+                    loadURL(getTopWindow(), (String) msg.obj);
                     break;
 
                 case STOP_LOAD:
@@ -2574,9 +2617,6 @@
         }
     };
 
-    private static final int HEADER_FLAG = Integer.MIN_VALUE;
-    private TextView mTitleView = null;
-
     // -------------------------------------------------------------------------
     // WebViewClient implementation.
     //-------------------------------------------------------------------------
@@ -2591,14 +2631,22 @@
         return mWebViewClient;
     }
 
+    private void updateIcon(String url, Bitmap icon) {
+        if (icon != null) {
+            BrowserBookmarksAdapter.updateBookmarkFavicon(mResolver,
+                    url, icon);
+        }
+        setFavicon(icon);
+    }
+
     private final WebViewClient mWebViewClient = new WebViewClient() {
         @Override
         public void onPageStarted(WebView view, String url, Bitmap favicon) {
             resetLockIcon(url);
             setUrlTitle(url, null);
-            // Call onReceivedIcon instead of setFavicon so the bookmark
+            // Call updateIcon instead of setFavicon so the bookmark
             // database can be updated.
-            mWebChromeClient.onReceivedIcon(view, favicon);
+            updateIcon(url, favicon);
 
             if (mSettings.isTracing() == true) {
                 // FIXME: we should save the trace file somewhere other than data.
@@ -2664,8 +2712,6 @@
             // Reset the title and icon in case we stopped a provisional
             // load.
             resetTitleAndIcon(view);
-            // Make the progress full.
-            getWindow().setFeatureInt(Window.FEATURE_PROGRESS, 10000);
 
             // Update the lock icon image only once we are done loading
             updateLockIconImage(mLockIconType);
@@ -2891,6 +2937,7 @@
             if (errorCode != EventHandler.ERROR_LOOKUP &&
                     errorCode != EventHandler.ERROR_CONNECT &&
                     errorCode != EventHandler.ERROR_BAD_URL &&
+                    errorCode != EventHandler.ERROR_UNSUPPORTED_SCHEME &&
                     errorCode != EventHandler.FILE_ERROR) {
                 new AlertDialog.Builder(BrowserActivity.this)
                         .setTitle((errorCode == EventHandler.FILE_NOT_FOUND_ERROR) ?
@@ -3106,7 +3153,7 @@
                 // openTabAndShow will dispatch the message after creating the
                 // new WebView. This will prevent another request from coming
                 // in during the animation.
-                openTabAndShow(null, msg);
+                openTabAndShow(null, msg, false);
                 parent.addChildTab(mTabControl.getCurrentTab());
                 WebView.WebViewTransport transport = 
                     (WebView.WebViewTransport) msg.obj;
@@ -3204,13 +3251,18 @@
                     mTabControl.getCurrentTab().getParentTab();
             if (parent != null) {
                 // JavaScript can only close popup window.
-                removeTabAndShow(currentIndex, mTabControl.getTabIndex(parent));
+                switchTabs(currentIndex, mTabControl.getTabIndex(parent), true);
             }
         }
 
         @Override
         public void onProgressChanged(WebView view, int newProgress) {
-            getWindow().setFeatureInt(Window.FEATURE_PROGRESS, newProgress*100);
+            // Block progress updates to the title bar while the tab overview
+            // is animating or being displayed.
+            if (mAnimationCount == 0 && mTabOverview == null) {
+                getWindow().setFeatureInt(Window.FEATURE_PROGRESS,
+                        newProgress * 100);
+            }
 
             if (newProgress == 100) {
                 // onProgressChanged() is called for sub-frame too while
@@ -3222,7 +3274,7 @@
 
         @Override
         public void onReceivedTitle(WebView view, String title) {
-            String url = view.getUrl();
+            String url = view.getOriginalUrl();
 
             // here, if url is null, we want to reset the title
             setUrlTitle(url, title);
@@ -3245,7 +3297,9 @@
                 Cursor c = mResolver.query(Browser.BOOKMARKS_URI,
                     Browser.HISTORY_PROJECTION, where, selArgs, null);
                 if (c.moveToFirst()) {
-                    Log.d(LOGTAG, "updating cursor");
+                    if (Config.LOGV) {
+                        Log.v(LOGTAG, "updating cursor");
+                    }
                     // Current implementation of database only has one entry per
                     // url.
                     int titleIndex =
@@ -3263,11 +3317,7 @@
 
         @Override
         public void onReceivedIcon(WebView view, Bitmap icon) {
-            if (icon != null) {
-                BrowserBookmarksAdapter.updateBookmarkFavicon(mResolver,
-                        view.getUrl(), icon);
-            }
-            setFavicon(icon);
+            updateIcon(view.getUrl(), icon);
         }
 
         //----------------------------------------------------------------------
@@ -3470,20 +3520,29 @@
      * @param mimetype The mimetype of the content reported by the server
      * @param contentLength The file size reported by the server
      */
-    public void onDownloadStartNoStream(String url, String userAgent,
+    /*package */ void onDownloadStartNoStream(String url, String userAgent,
             String contentDisposition, String mimetype, long contentLength) {
 
         String filename = URLUtil.guessFileName(url,
                 contentDisposition, mimetype);
 
         // Check to see if we have an SDCard
-        if (!Environment.getExternalStorageState().
-                equals(Environment.MEDIA_MOUNTED)) {
-            String msg =
-                getString(R.string.download_no_sdcard_dlg_msg, filename);
+        String status = Environment.getExternalStorageState();
+        if (!status.equals(Environment.MEDIA_MOUNTED)) {
+            int title;
+            String msg;
+
+            // Check to see if the SDCard is busy, same as the music app
+            if (status.equals(Environment.MEDIA_SHARED)) {
+                msg = getString(R.string.download_sdcard_busy_dlg_msg);
+                title = R.string.download_sdcard_busy_dlg_title;
+            } else {
+                msg = getString(R.string.download_no_sdcard_dlg_msg, filename);
+                title = R.string.download_no_sdcard_dlg_title;
+            }
 
             new AlertDialog.Builder(this)
-                .setTitle(R.string.download_no_sdcard_dlg_title)
+                .setTitle(title)
                 .setIcon(R.drawable.ic_dialog_alert)
                 .setMessage(msg)
                 .setPositiveButton(R.string.ok, null)
@@ -3508,9 +3567,15 @@
         if (contentLength > 0) {
             values.put(Downloads.TOTAL_BYTES, contentLength);
         }
-        final Uri contentUri =
-                getContentResolver().insert(Downloads.CONTENT_URI, values);
-        viewDownloads(contentUri);
+        if (mimetype == null) {
+            // We must have long pressed on a link or image to download it. We
+            // are not sure of the mimetype in this case, so do a head request
+            new FetchUrlMimeType(this).execute(values);
+        } else {
+            final Uri contentUri =
+                    getContentResolver().insert(Downloads.CONTENT_URI, values);
+            viewDownloads(contentUri);
+        }
 
     }
 
@@ -3563,29 +3628,38 @@
         } else if (lockIconType == LOCK_ICON_MIXED) {
             d = mMixLockIcon;
         }
-        getWindow().setFeatureDrawable(Window.FEATURE_RIGHT_ICON, d);
+        // If the tab overview is animating or being shown, do not update the
+        // lock icon.
+        if (mAnimationCount == 0 && mTabOverview == null) {
+            getWindow().setFeatureDrawable(Window.FEATURE_RIGHT_ICON, d);
+        }
     }
 
     /**
      * Displays a page-info dialog.
-     * @param view The target web-view.
+     * @param tab The tab to show info about
      * @param fromShowSSLCertificateOnError The flag that indicates whether
      * this dialog was opened from the SSL-certificate-on-error dialog or
      * not. This is important, since we need to know whether to return to
      * the parent dialog or simply dismiss.
      */
-    private void showPageInfo(final WebView view,
+    private void showPageInfo(final TabControl.Tab tab,
                               final boolean fromShowSSLCertificateOnError) {
         final LayoutInflater factory = LayoutInflater
                 .from(this);
 
         final View pageInfoView = factory.inflate(R.layout.page_info, null);
+        
+        final WebView view = tab.getWebView();
 
         String url = null;
         String title = null;
 
-        // Use the cached title and url if this is the current WebView
-        if (view == mWebView) {
+        if (view == null) {
+            url = tab.getUrl();
+            title = tab.getTitle();
+        }else if (view == mWebView) {
+             // Use the cached title and url if this is the current WebView
             url = mUrl;
             title = mTitle;
         } else {
@@ -3603,7 +3677,7 @@
         ((TextView) pageInfoView.findViewById(R.id.address)).setText(url);
         ((TextView) pageInfoView.findViewById(R.id.title)).setText(title);
 
-        mPageInfoView = view;
+        mPageInfoView = tab;
         mPageInfoFromShowSSLCertificateOnError = new Boolean(fromShowSSLCertificateOnError);
 
         AlertDialog.Builder alertDialogBuilder =
@@ -3649,7 +3723,8 @@
 
         // if we have a main top-level page SSL certificate set or a certificate
         // error
-        if (fromShowSSLCertificateOnError || view.getCertificate() != null) {
+        if (fromShowSSLCertificateOnError || 
+                (view != null && view.getCertificate() != null)) {
             // add a 'View Certificate' button
             alertDialogBuilder.setNeutralButton(
                 R.string.view_certificate,
@@ -3671,7 +3746,7 @@
                             // otherwise, display the top-most certificate from
                             // the chain
                             if (view.getCertificate() != null) {
-                                showSSLCertificate(view);
+                                showSSLCertificate(tab);
                             }
                         }
                     }
@@ -3684,9 +3759,9 @@
        /**
      * Displays the main top-level page SSL certificate dialog
      * (accessible from the Page-Info dialog).
-     * @param view The target web-view.
+     * @param tab The tab to show certificate for.
      */
-    private void showSSLCertificate(final WebView view) {
+    private void showSSLCertificate(final TabControl.Tab tab) {
         final View certificateView =
             inflateCertificateView(mWebView.getCertificate());
         if (certificateView == null) {
@@ -3703,7 +3778,7 @@
         ((TextView)ll.findViewById(R.id.success))
             .setText(R.string.ssl_certificate_is_valid);
 
-        mSSLCertificateView = view;
+        mSSLCertificateView = tab;
         mSSLCertificateDialog =
             new AlertDialog.Builder(this)
                 .setTitle(R.string.ssl_certificate).setIcon(
@@ -3716,7 +3791,7 @@
                                 mSSLCertificateDialog = null;
                                 mSSLCertificateView = null;
 
-                                showPageInfo(view, false);
+                                showPageInfo(tab, false);
                             }
                         })
                 .setOnCancelListener(
@@ -3725,7 +3800,7 @@
                                 mSSLCertificateDialog = null;
                                 mSSLCertificateView = null;
 
-                                showPageInfo(view, false);
+                                showPageInfo(tab, false);
                             }
                         })
                 .show();
@@ -3811,7 +3886,8 @@
                                 // need to show the dialog again once the
                                 // user is done exploring the page-info details
 
-                                showPageInfo(view, true);
+                                showPageInfo(mTabControl.getTabFromView(view), 
+                                        true);
                             }
                         })
                 .setOnCancelListener(
@@ -4016,6 +4092,7 @@
                         .show();
             }
         }
+        mTabControl.getCurrentWebView().setNetworkAvailable(up);
     }
 
     @Override
@@ -4030,14 +4107,19 @@
                     if (extras != null && extras.getBoolean("new_window", false)) {
                         openTab(data);
                     } else {
+                        final TabControl.Tab currentTab =
+                                mTabControl.getCurrentTab();
                         // If the Window overview is up and we are not in the
                         // middle of an animation, animate away from it to the
                         // current tab.
                         if (mTabOverview != null && mAnimationCount == 0) {
-                            sendAnimateFromOverview(mTabControl.getCurrentTab(),
-                                    false, data, TAB_OVERVIEW_DELAY, null);
+                            sendAnimateFromOverview(currentTab, false, data,
+                                    TAB_OVERVIEW_DELAY, null);
                         } else {
-                            loadURL(data);
+                            dismissSubWindow(currentTab);
+                            if (data != null && data.length() != 0) {
+                                getTopWindow().loadUrl(data);
+                            }
                         }
                     }
                 }
@@ -4053,7 +4135,7 @@
      * menu to see the download window, or when a download changes state. It
      * shows the download window ontop of the current window.
      */
-    private void viewDownloads(Uri downloadRecord) {
+    /* package */ void viewDownloads(Uri downloadRecord) {
         Intent intent = new Intent(this,
                 BrowserDownloadPage.class);
         intent.setData(downloadRecord);
@@ -4071,30 +4153,41 @@
                 throw new AssertionError();
             }
 
-            mTabControl.removeTab(mTabControl.getTab(position));
+            // Remember the current tab.
+            TabControl.Tab current = mTabControl.getCurrentTab();
+            final TabControl.Tab remove = mTabControl.getTab(position);
+            mTabControl.removeTab(remove);
+            // If we removed the current tab, use the tab at position - 1 if
+            // possible.
+            if (current == remove) {
+                // If the user removes the last tab, act like the New Tab item
+                // was clicked on.
+                if (mTabControl.getTabCount() == 0) {
+                    current = mTabControl.createNewTab(false);
+                    sendAnimateFromOverview(current, true,
+                            mSettings.getHomePage(), TAB_OVERVIEW_DELAY, null);
+                } else {
+                    final int index = position > 0 ? (position - 1) : 0;
+                    current = mTabControl.getTab(index);
+                }
+            }
+
             // The tab overview could have been dismissed before this method is
             // called.
             if (mTabOverview != null) {
                 // Remove the tab and change the index.
-                mTabOverview.remove(position--);
-                mTabOverview.setCurrentIndex(position);
-            } else {
-                position--;
+                mTabOverview.remove(position);
+                mTabOverview.setCurrentIndex(mTabControl.getTabIndex(current));
             }
 
             // FIXME: This isn't really right. We don't have a current WebView
             // since we are switching between tabs and haven't selected a new
             // one. This just prevents a NPE in case the user hits home from the
             // tab switcher.
-            int index = position;
-            if (index == ImageGrid.NEW_TAB) {
-                index = 0;
-            }
-            final TabControl.Tab t = mTabControl.getTab(index);
             // Only the current tab ensures its WebView is non-null. This
             // implies that we are reloading the freed tab.
-            mTabControl.setCurrentTab(t);
-            mWebView = t.getWebView();
+            mTabControl.setCurrentTab(current);
+            mWebView = current.getWebView();
         }
         public void onClick(int index) {
             // Change the tab if necessary.
@@ -4112,13 +4205,10 @@
             // Clear all the data for tab picker so next time it will be
             // recreated.
             mTabControl.wipeAllPickerData();
-            BrowserActivity.this.getWindow().setFeatureInt(
-                    Window.FEATURE_PROGRESS, Window.PROGRESS_VISIBILITY_ON);
-            BrowserActivity.this.mMenuState = EMPTY_MENU;
 
             // NEW_TAB means that the "New Tab" cell was clicked on.
             if (index == ImageGrid.NEW_TAB) {
-                openTabAndShow(mSettings.getHomePage(), null);
+                openTabAndShow(mSettings.getHomePage(), null, false);
             } else {
                 sendAnimateFromOverview(mTabControl.getTab(index),
                         false, null, 0, null);
@@ -4156,11 +4246,13 @@
         protected void onDraw(Canvas canvas) {
             canvas.save();
             canvas.drawColor(Color.WHITE);
-            canvas.setDrawFilter(sZoomFilter);
-            float scale = getWidth() * mScale;
-            canvas.scale(scale, scale);
-            canvas.translate(-mScrollX, -mScrollY);
-            canvas.drawPicture(mPicture);
+            if (mPicture != null) {
+                canvas.setDrawFilter(sZoomFilter);
+                float scale = getWidth() * mScale;
+                canvas.scale(scale, scale);
+                canvas.translate(-mScrollX, -mScrollY);
+                canvas.drawPicture(mPicture);
+            }
             canvas.restore();
         }
     }
@@ -4219,12 +4311,13 @@
         // set it here to prevent another request to animate from coming in
         // between now and when ANIMATE_TO_OVERVIEW is handled.
         mAnimationCount++;
-        if (stay) {
-            getWindow().setFeatureDrawable(Window.FEATURE_LEFT_ICON, null);
-            getWindow().setFeatureInt(Window.FEATURE_PROGRESS,
-                    Window.PROGRESS_VISIBILITY_OFF);
-            setTitle(R.string.tab_picker_title);
-        }
+        // Always change the title bar to the window overview title while
+        // animating.
+        getWindow().setFeatureDrawable(Window.FEATURE_LEFT_ICON, null);
+        getWindow().setFeatureDrawable(Window.FEATURE_RIGHT_ICON, null);
+        getWindow().setFeatureInt(Window.FEATURE_PROGRESS,
+                Window.PROGRESS_VISIBILITY_OFF);
+        setTitle(R.string.tab_picker_title);
         // Make the menu empty until the animation completes.
         mMenuState = EMPTY_MENU;
     }
@@ -4254,14 +4347,13 @@
         startActivityForResult(intent, BOOKMARKS_PAGE);
     }
 
-    // Called when loading from bookmarks or goto.
-    private void loadURL(String url) {
+    // Called when loading from context menu or LOAD_URL message
+    private void loadURL(WebView view, String url) {
         // In case the user enters nothing.
-        if (url != null && url.length() != 0) {
+        if (url != null && url.length() != 0 && view != null) {
             url = smartUrlFilter(url);
-            WebView w = getTopWindow();
-            if (!mWebViewClient.shouldOverrideUrlLoading(w, url)) {
-                w.loadUrl(url);
+            if (!mWebViewClient.shouldOverrideUrlLoading(view, url)) {
+                view.loadUrl(url);
             }
         }
     }
@@ -4316,21 +4408,23 @@
      * @return Original or modified URL
      *
      */
-    String smartUrlFilter(String inUrl) {
+    String smartUrlFilter(String url) {
 
+        String inUrl = url.trim();
         boolean hasSpace = inUrl.indexOf(' ') != -1;
 
-        if (!hasSpace) {
-            Matcher matcher = ACCEPTED_URI_SCHEMA.matcher(inUrl);
-            if (matcher.matches()) {
-                // force scheme to lowercase
-                String scheme = matcher.group(1);
-                String lcScheme = scheme.toLowerCase();
-                if (!lcScheme.equals(scheme)) {
-                    return lcScheme + matcher.group(2);
-                }
-                return inUrl;
+        Matcher matcher = ACCEPTED_URI_SCHEMA.matcher(inUrl);
+        if (matcher.matches()) {
+            if (hasSpace) {
+                inUrl = inUrl.replace(" ", "%20");
             }
+            // force scheme to lowercase
+            String scheme = matcher.group(1);
+            String lcScheme = scheme.toLowerCase();
+            if (!lcScheme.equals(scheme)) {
+                return lcScheme + matcher.group(2);
+            }
+            return inUrl;
         }
         if (hasSpace) {
             // FIXME: quick search, need to be customized by setting
@@ -4378,6 +4472,33 @@
                 QUERY_PLACE_HOLDER);
     }
 
+    /* package */void setBaseSearchUrl(String url) {
+        if (url == null || url.length() == 0) {
+            /*
+             * get the google search url based on the SIM. Default is US. NOTE:
+             * This code uses resources to optionally select the search Uri,
+             * based on the MCC value from the SIM. The default string will most
+             * likely be fine. It is parameterized to accept info from the
+             * Locale, the language code is the first parameter (%1$s) and the
+             * country code is the second (%2$s). This code must function in the
+             * same way as a similar lookup in
+             * com.android.googlesearch.SuggestionProvider#onCreate(). If you
+             * change either of these functions, change them both. (The same is
+             * true for the underlying resource strings, which are stored in
+             * mcc-specific xml files.)
+             */
+            Locale l = Locale.getDefault();
+            QuickSearch_G = getResources().getString(
+                    R.string.google_search_base, l.getLanguage(),
+                    l.getCountry().toLowerCase())
+                    + "client=ms-"
+                    + SystemProperties.get("ro.com.google.clientid", "unknown")
+                    + "&source=android-" + GOOGLE_SEARCH_SOURCE_SUGGEST + "&q=%s";
+        } else {
+            QuickSearch_G = url;
+        }
+    }
+
     private final static int LOCK_ICON_UNSECURE = 0;
     private final static int LOCK_ICON_SECURE   = 1;
     private final static int LOCK_ICON_MIXED    = 2;
@@ -4458,7 +4579,7 @@
     // As PageInfo has different style for landscape / portrait, we have
     // to re-open it when configuration changed
     private AlertDialog mPageInfoDialog;
-    private WebView mPageInfoView;
+    private TabControl.Tab mPageInfoView;
     // If the Page-Info dialog is launched from the SSL-certificate-on-error
     // dialog, we should not just dismiss it, but should get back to the
     // SSL-certificate-on-error dialog. This flag is used to store this state
@@ -4474,7 +4595,7 @@
     // as SSLCertificate has different style for landscape / portrait, we
     // have to re-open it when configuration changed
     private AlertDialog mSSLCertificateDialog;
-    private WebView mSSLCertificateView;
+    private TabControl.Tab mSSLCertificateView;
 
     // as HttpAuthentication has different style for landscape / portrait, we
     // have to re-open it when configuration changed
@@ -4487,10 +4608,7 @@
                                             ViewGroup.LayoutParams.FILL_PARENT);
     // We may provide UI to customize these
     // Google search from the browser
-    final static String QuickSearch_G =
-            "http://www.google.com/m?client=ms-"
-            + SystemProperties.get("ro.com.google.clientid", "unknown")
-            + "&source=android-chrome&q=%s";
+    static String QuickSearch_G;
     // Wikipedia search
     final static String QuickSearch_W = "http://en.wikipedia.org/w/index.php?search=%s&go=Go";
     // Dictionary search
@@ -4498,7 +4616,20 @@
     // Google Mobile Local search
     final static String QuickSearch_L = "http://www.google.com/m/search?site=local&q=%s&near=mountain+view";
 
-    private final static String QUERY_PLACE_HOLDER = "%s";
+    final static String QUERY_PLACE_HOLDER = "%s";
+
+    // "source" parameter for Google search through search key
+    final static String GOOGLE_SEARCH_SOURCE_SEARCHKEY = "browser-key";
+    // "source" parameter for Google search through search menu
+    final static String GOOGLE_SEARCH_SOURCE_SEARCHMENU = "browser-menu";
+    // "source" parameter for Google search through goto menu
+    final static String GOOGLE_SEARCH_SOURCE_GOTO = "browser-goto";
+    // "source" parameter for Google search through simplily type
+    final static String GOOGLE_SEARCH_SOURCE_TYPE = "browser-type";
+    // "source" parameter for Google search suggested by the browser
+    final static String GOOGLE_SEARCH_SOURCE_SUGGEST = "browser-suggest";
+    // "source" parameter for Google search from unknown source
+    final static String GOOGLE_SEARCH_SOURCE_UNKNOWN = "unknown";
 
     private final static String LOGTAG = "browser";
 
@@ -4516,6 +4647,13 @@
     // overlap. A count of 0 means no animation where a count of > 0 means
     // there are animations in progress.
     private int mAnimationCount;
+    
+    // As the ids are dynamically created, we can't guarantee that they will
+    // be in sequence, so this static array maps ids to a window number.
+    final static private int[] WINDOW_SHORTCUT_ID_ARRAY = 
+    { R.id.window_one_menu_id, R.id.window_two_menu_id, R.id.window_three_menu_id,
+      R.id.window_four_menu_id, R.id.window_five_menu_id, R.id.window_six_menu_id,
+      R.id.window_seven_menu_id, R.id.window_eight_menu_id };
 
     // monitor platform changes
     private IntentFilter mNetworkStateChangedFilter;