Merge commit 'remotes/korg/cupcake' into merge

Conflicts:
	src/com/android/browser/BrowserActivity.java
diff --git a/src/com/android/browser/BrowserActivity.java b/src/com/android/browser/BrowserActivity.java
index 789babe..e018eb4 100644
--- a/src/com/android/browser/BrowserActivity.java
+++ b/src/com/android/browser/BrowserActivity.java
@@ -16,26 +16,28 @@
 
 package com.android.browser;
 
+import com.google.android.googleapps.IGoogleLoginService;
+import com.google.android.googlelogin.GoogleLoginServiceConstants;
+
 import android.app.Activity;
 import android.app.ActivityManager;
 import android.app.AlertDialog;
-import android.app.SearchManager;
 import android.app.ProgressDialog;
+import android.app.SearchManager;
 import android.content.ActivityNotFoundException;
-import android.content.res.AssetManager;
 import android.content.BroadcastReceiver;
 import android.content.ComponentName;
 import android.content.ContentResolver;
 import android.content.ContentValues;
 import android.content.Context;
-import android.content.DialogInterface.OnCancelListener;
 import android.content.DialogInterface;
 import android.content.Intent;
 import android.content.IntentFilter;
 import android.content.ServiceConnection;
-import android.content.pm.ActivityInfo;
+import android.content.DialogInterface.OnCancelListener;
 import android.content.pm.PackageManager;
 import android.content.pm.ResolveInfo;
+import android.content.res.AssetManager;
 import android.content.res.Configuration;
 import android.content.res.Resources;
 import android.database.Cursor;
@@ -54,10 +56,10 @@
 import android.graphics.drawable.PaintDrawable;
 import android.hardware.SensorListener;
 import android.hardware.SensorManager;
+import android.net.ConnectivityManager;
 import android.net.Uri;
 import android.net.WebAddress;
 import android.net.http.EventHandler;
-import android.net.http.RequestQueue;
 import android.net.http.SslCertificate;
 import android.net.http.SslError;
 import android.os.AsyncTask;
@@ -75,10 +77,10 @@
 import android.os.SystemProperties;
 import android.preference.PreferenceManager;
 import android.provider.Browser;
-import android.provider.Contacts.Intents.Insert;
 import android.provider.Contacts;
 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;
@@ -86,8 +88,6 @@
 import android.util.Config;
 import android.util.Log;
 import android.view.ContextMenu;
-import android.view.ContextMenu.ContextMenuInfo;
-import android.view.MenuItem.OnMenuItemClickListener;
 import android.view.Gravity;
 import android.view.KeyEvent;
 import android.view.LayoutInflater;
@@ -97,6 +97,9 @@
 import android.view.View;
 import android.view.ViewGroup;
 import android.view.Window;
+import android.view.WindowManager;
+import android.view.ContextMenu.ContextMenuInfo;
+import android.view.MenuItem.OnMenuItemClickListener;
 import android.view.animation.AlphaAnimation;
 import android.view.animation.Animation;
 import android.view.animation.AnimationSet;
@@ -120,16 +123,14 @@
 import android.widget.TextView;
 import android.widget.Toast;
 
-import com.google.android.googleapps.IGoogleLoginService;
-import com.google.android.googlelogin.GoogleLoginServiceConstants;
-
 import java.io.BufferedOutputStream;
 import java.io.File;
 import java.io.FileInputStream;
 import java.io.FileOutputStream;
-import java.io.InputStream;
 import java.io.IOException;
+import java.io.InputStream;
 import java.net.MalformedURLException;
+import java.net.URI;
 import java.net.URL;
 import java.net.URLEncoder;
 import java.text.ParseException;
@@ -138,9 +139,9 @@
 import java.util.HashMap;
 import java.util.List;
 import java.util.Locale;
+import java.util.Vector;
 import java.util.regex.Matcher;
 import java.util.regex.Pattern;
-import java.util.Vector;
 import java.util.zip.ZipEntry;
 import java.util.zip.ZipFile;
 
@@ -202,7 +203,7 @@
                     if (googleUser == null || !hostedUser.equals(googleUser)) {
                         String domain = hostedUser.substring(hostedUser.lastIndexOf('@')+1);
                         homepage = "http://www.google.com/m/a/" + domain + "?client=ms-" +
-                            SystemProperties.get("ro.com.google.clientid", "unknown");
+                            SystemProperties.get("persist.sys.com.google.clientid", "unknown");
                     }
                 } catch (RemoteException ignore) {
                     // Login service died; carry on
@@ -685,9 +686,11 @@
             // 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.
+            String url = getUrlFromIntent(intent);
             final TabControl.Tab t = mTabControl.createNewTab(
                     Intent.ACTION_VIEW.equals(intent.getAction()) &&
-                    intent.getData() != null);
+                    intent.getData() != null,
+                    intent.getStringExtra(Browser.EXTRA_APPLICATION_ID), url);
             mTabControl.setCurrentTab(t);
             // This is one of the only places we call attachTabToContentView
             // without animating from the tab picker.
@@ -709,7 +712,6 @@
             }
             copyPlugins(true);
 
-            String url = getUrlFromIntent(intent);
             if (url == null || url.length() == 0) {
                 if (mSettings.isLoginInitialized()) {
                     webView.loadUrl(mSettings.getHomePage());
@@ -730,19 +732,18 @@
            http stack */
         mNetworkStateChangedFilter = new IntentFilter();
         mNetworkStateChangedFilter.addAction(
-                RequestQueue.HTTP_NETWORK_STATE_CHANGED_INTENT);
+                ConnectivityManager.CONNECTIVITY_ACTION);
         mNetworkStateIntentReceiver = new BroadcastReceiver() {
                 @Override
                 public void onReceive(Context context, Intent intent) {
                     if (intent.getAction().equals(
-                            RequestQueue.HTTP_NETWORK_STATE_CHANGED_INTENT)) {
-                        Boolean up = (Boolean)intent.getExtra(
-                                RequestQueue.HTTP_NETWORK_STATE_UP);
-                        onNetworkToggle(up);
+                            ConnectivityManager.CONNECTIVITY_ACTION)) {
+                        boolean down = intent.getBooleanExtra(
+                                ConnectivityManager.EXTRA_NO_CONNECTIVITY, false);
+                        onNetworkToggle(!down);
                     }
                 }
             };
-        setRequestedOrientation(mSettings.getOrientation());
     }
 
     @Override
@@ -778,11 +779,44 @@
             }
             if (Intent.ACTION_VIEW.equals(action) &&
                     (flags & Intent.FLAG_ACTIVITY_BROUGHT_TO_FRONT) != 0) {
+                final String appId =
+                        intent.getStringExtra(Browser.EXTRA_APPLICATION_ID);
+                final TabControl.Tab appTab = mTabControl.getTabFromId(appId);
+                if (appTab != null) {
+                    Log.i(LOGTAG, "Reusing tab for " + appId);
+                    // Dismiss the subwindow if applicable.
+                    dismissSubWindow(appTab);
+                    // Since we might kill the WebView, remove it from the
+                    // content view first.
+                    removeTabFromContentView(appTab);
+                    // Recreate the main WebView after destroying the old one.
+                    // If the WebView has the same original url and is on that
+                    // page, it can be reused.
+                    boolean needsLoad =
+                            mTabControl.recreateWebView(appTab, url);
+                    if (current != appTab) {
+                        showTab(appTab, needsLoad ? url : null);
+                    } else {
+                        if (mTabOverview != null && mAnimationCount == 0) {
+                            sendAnimateFromOverview(appTab, false,
+                                    needsLoad ? url : null, TAB_OVERVIEW_DELAY,
+                                    null);
+                        } else {
+                            // If the tab was the current tab, we have to attach
+                            // it to the view system again.
+                            attachTabToContentView(appTab);
+                            if (needsLoad) {
+                                appTab.getWebView().loadUrl(url);
+                            }
+                        }
+                    }
+                    return;
+                }
                 // if FLAG_ACTIVITY_BROUGHT_TO_FRONT flag is on, the url will be
                 // 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);
+                openTabAndShow(url, null, true, appId);
             } else {
                 if ("about:debug".equals(url)) {
                     mSettings.toggleDebugSettings();
@@ -1289,13 +1323,12 @@
     }
 
     /**
-     * Overriding this forces the search key to launch global search.  The difference
-     * is the final "true" which requests global search.
+     * Overriding this to insert a local information bundle
      */
     @Override
     public boolean onSearchRequested() {
         startSearch(null, false,
-                createGoogleSearchSourceBundle(GOOGLE_SEARCH_SOURCE_SEARCHKEY), true);
+                createGoogleSearchSourceBundle(GOOGLE_SEARCH_SOURCE_SEARCHKEY), false);
         return true;
     }
 
@@ -1324,19 +1357,13 @@
                 }
                 break;
 
-            case R.id.search_menu_id:
-                // launch using "global" search, which will bring up the Google search box
-                startSearch(null, false,
-                        createGoogleSearchSourceBundle(GOOGLE_SEARCH_SOURCE_SEARCHMENU), true);
-                break;
-
             case R.id.bookmarks_menu_id:
-                bookmarksPicker();
+                bookmarksOrHistoryPicker(false);
                 break;
 
             case R.id.windows_menu_id:
                 if (mTabControl.getTabCount() == 1) {
-                    openTabAndShow(mSettings.getHomePage(), null, false);
+                    openTabAndShow(mSettings.getHomePage(), null, false, null);
                 } else {
                     tabPicker(true, mTabControl.getCurrentIndex(), false);
                 }
@@ -1412,12 +1439,7 @@
                 break;
 
             case R.id.classic_history_menu_id:
-                loadHistory();
-                break;
-
-            case R.id.bookmark_page_menu_id:
-                Browser.saveBookmark(this, getTopWindow().getTitle(),
-                        getTopWindow().getUrl());
+                bookmarksOrHistoryPicker(true);
                 break;
 
             case R.id.share_page_menu_id:
@@ -1428,12 +1450,6 @@
                 getTopWindow().debugDump();
                 break;
 
-            case R.id.zoom_menu_id:
-                // FIXME: Can we move this out of WebView? How does this work
-                // for a subwindow?
-                getTopWindow().invokeZoomPicker();
-                break;
-
             case R.id.zoom_in_menu_id:
                 getTopWindow().zoomIn();
                 break;
@@ -1446,18 +1462,6 @@
                 viewDownloads(null);
                 break;
 
-            case R.id.flip_orientation_menu_id:
-                if (mSettings.getOrientation() !=
-                        ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE) {
-                    mSettings.setOrientation(this,
-                            ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);
-                } else {
-                    mSettings.setOrientation(this,
-                            ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED);
-                }
-                setRequestedOrientation(mSettings.getOrientation());
-                break;
-
             // -- Tab menu
             case R.id.view_tab_menu_id:
                 if (mTabListener != null && mTabOverview != null) {
@@ -1499,17 +1503,12 @@
                 }
                 break;
 
-            case R.id.history_tab_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.history_tab_menu_id:
+                bookmarksOrHistoryPicker(true);
                 break;
 
             case R.id.bookmarks_tab_menu_id:
-                bookmarksPicker();
+                bookmarksOrHistoryPicker(false);
                 break;
 
             case R.id.properties_tab_menu_id:
@@ -1570,6 +1569,7 @@
                 if (mCurrentMenuState != mMenuState) {
                     menu.setGroupVisible(R.id.MAIN_MENU, false);
                     menu.setGroupEnabled(R.id.MAIN_MENU, false);
+                    menu.setGroupEnabled(R.id.MAIN_SHORTCUT_MENU, false);
                     menu.setGroupVisible(R.id.TAB_MENU, true);
                     menu.setGroupEnabled(R.id.TAB_MENU, true);
                 }
@@ -1582,6 +1582,7 @@
                 if (mCurrentMenuState != mMenuState) {
                     menu.setGroupVisible(R.id.MAIN_MENU, false);
                     menu.setGroupEnabled(R.id.MAIN_MENU, false);
+                    menu.setGroupEnabled(R.id.MAIN_SHORTCUT_MENU, false);
                     menu.setGroupVisible(R.id.TAB_MENU, false);
                     menu.setGroupEnabled(R.id.TAB_MENU, false);
                 }
@@ -1590,47 +1591,34 @@
                 if (mCurrentMenuState != mMenuState) {
                     menu.setGroupVisible(R.id.MAIN_MENU, true);
                     menu.setGroupEnabled(R.id.MAIN_MENU, true);
+                    menu.setGroupEnabled(R.id.MAIN_SHORTCUT_MENU, true);
                     menu.setGroupVisible(R.id.TAB_MENU, false);
                     menu.setGroupEnabled(R.id.TAB_MENU, false);
                 }
                 final WebView w = getTopWindow();
-                boolean canGoBack = w.canGoBack();
+                boolean canGoBack = false;
+                boolean canGoForward = false;
+                boolean isHome = false;
+                if (w != null) {
+                    canGoBack = w.canGoBack();
+                    canGoForward = w.canGoForward();
+                    isHome = mSettings.getHomePage().equals(w.getUrl());
+                }
                 final MenuItem back = menu.findItem(R.id.back_menu_id);
-                back.setVisible(canGoBack);
                 back.setEnabled(canGoBack);
-                final MenuItem flip =
-                        menu.findItem(R.id.flip_orientation_menu_id);
-                boolean keyboardClosed =
-                        getResources().getConfiguration().hardKeyboardHidden ==
-                        Configuration.HARDKEYBOARDHIDDEN_YES;
-                flip.setEnabled(keyboardClosed);
 
-                boolean isHome = mSettings.getHomePage().equals(w.getUrl());
                 final MenuItem home = menu.findItem(R.id.homepage_menu_id);
-                home.setVisible(!isHome);
                 home.setEnabled(!isHome);
 
                 menu.findItem(R.id.forward_menu_id)
-                        .setEnabled(w.canGoForward());
-
-                menu.findItem(R.id.zoom_in_menu_id).setVisible(false);
-                menu.findItem(R.id.zoom_out_menu_id).setVisible(false);
+                        .setEnabled(canGoForward);
 
                 // decide whether to show the share link option
                 PackageManager pm = getPackageManager();
                 Intent send = new Intent(Intent.ACTION_SEND);
                 send.setType("text/plain");
-                List<ResolveInfo> list = pm.queryIntentActivities(send,
-                        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);
-                }
+                ResolveInfo ri = pm.resolveActivity(send, PackageManager.MATCH_DEFAULT_ONLY);
+                menu.findItem(R.id.share_page_menu_id).setVisible(ri != null);
 
                 // If there is only 1 window, the text will be "New window"
                 final MenuItem windows = menu.findItem(R.id.windows_menu_id);
@@ -1737,14 +1725,16 @@
                 PackageManager pm = getPackageManager();
                 Intent send = new Intent(Intent.ACTION_SEND);
                 send.setType("text/plain");
-                List<ResolveInfo> list = pm.queryIntentActivities(send,
-                        PackageManager.MATCH_DEFAULT_ONLY);
-                menu.findItem(R.id.share_link_context_menu_id).setVisible(
-                        list.size() > 0);
-                break;
-
+                ResolveInfo ri = pm.resolveActivity(send, PackageManager.MATCH_DEFAULT_ONLY);
+                menu.findItem(R.id.share_link_context_menu_id).setVisible(ri != null);
+                if (type == WebView.HitTestResult.SRC_ANCHOR_TYPE) {
+                    break;
+                }
+                // otherwise fall through to handle image part
             case WebView.HitTestResult.IMAGE_TYPE:
-                menu.setHeaderTitle(extra);
+                if (type == 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).
@@ -1757,22 +1747,11 @@
         }
     }
 
-    // Used by attachTabToContentView for the WebView's ZoomControl widget.
-    private static final FrameLayout.LayoutParams ZOOM_PARAMS =
-            new FrameLayout.LayoutParams(
-                    ViewGroup.LayoutParams.FILL_PARENT,
-                    ViewGroup.LayoutParams.WRAP_CONTENT,
-                    Gravity.BOTTOM);
-
     // Attach the given tab to the content view.
     private void attachTabToContentView(TabControl.Tab t) {
         final WebView main = t.getWebView();
         // Attach the main WebView.
         mContentView.addView(main, COVER_SCREEN_PARAMS);
-        // Attach the Zoom control widget and hide it.
-        final View zoom = main.getZoomControls();
-        mContentView.addView(zoom, ZOOM_PARAMS);
-        zoom.setVisibility(View.GONE);
         // Attach the sub window if necessary
         attachSubWindow(t);
         // Request focus on the top window.
@@ -1792,8 +1771,7 @@
 
     // Remove the given tab from the content view.
     private void removeTabFromContentView(TabControl.Tab t) {
-        // Remove the Zoom widget and the main WebView.
-        mContentView.removeView(t.getWebView().getZoomControls());
+        // Remove the main WebView.
         mContentView.removeView(t.getWebView());
         // Remove the sub window if it exists.
         if (t.getSubWebView() != null) {
@@ -1838,7 +1816,13 @@
         // Send the animate message.
         final HashMap map = new HashMap();
         map.put("view", view);
-        map.put("url", url);
+        // Load the url after the AnimatingView has captured the picture. This
+        // prevents any bad layout or bad scale from being used during
+        // animation.
+        if (url != null) {
+            dismissSubWindow(tab);
+            tab.getWebView().loadUrl(url);
+        }
         map.put("msg", msg);
         mHandler.sendMessageDelayed(mHandler.obtainMessage(
                 ANIMATE_FROM_OVERVIEW, newTab ? 1 : 0, 0, map), delay);
@@ -1858,6 +1842,10 @@
 
     // Called by TabControl when a tab is requesting focus
     /* package */ void showTab(TabControl.Tab t) {
+        showTab(t, null);
+    }
+
+    private void showTab(TabControl.Tab t, String url) {
         // Disallow focus change during a tab animation.
         if (mAnimationCount > 0) {
             return;
@@ -1869,7 +1857,7 @@
             delay = TAB_ANIMATION_DURATION + TAB_OVERVIEW_DELAY;
             tabPicker(false, mTabControl.getTabIndex(t), false);
         }
-        sendAnimateFromOverview(t, false, null, delay, null);
+        sendAnimateFromOverview(t, false, url, delay, null);
     }
 
     // This method does a ton of stuff. It will attempt to create a new tab
@@ -1881,7 +1869,7 @@
     // method is called from TabListener.onClick(), the method will animate
     // away from the tab overview.
     private void openTabAndShow(String url, final Message msg,
-            boolean closeOnExit) {
+            boolean closeOnExit, String appId) {
         final boolean newTab = mTabControl.getTabCount() != TabControl.MAX_TABS;
         final TabControl.Tab currentTab = mTabControl.getCurrentTab();
         if (newTab) {
@@ -1909,8 +1897,9 @@
                 }
                 // Animate from the Tab overview after any animations have
                 // finished.
-                sendAnimateFromOverview(mTabControl.createNewTab(closeOnExit),
-                        true, url, delay, msg);
+                sendAnimateFromOverview(
+                        mTabControl.createNewTab(closeOnExit, appId, url), true,
+                        url, delay, msg);
             }
         } else if (url != null) {
             // We should not have a msg here.
@@ -1987,15 +1976,17 @@
                             public void run() {
                                 // Remove the AnimatingView.
                                 mContentView.removeView(view);
-                                // 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 (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();
+                                    }
                                 }
                                 // If a remove was requested, remove the tab.
                                 if (remove) {
@@ -2013,10 +2004,12 @@
                                     if (currentTab != tab) {
                                         mTabControl.setCurrentTab(currentTab);
                                     }
-                                    mTabOverview.remove(newIndex);
-                                    // Make the current tab visible.
-                                    mTabOverview.setCurrentIndex(
-                                            mTabControl.getCurrentIndex());
+                                    if (mTabOverview != null) {
+                                        mTabOverview.remove(newIndex);
+                                        // Make the current tab visible.
+                                        mTabOverview.setCurrentIndex(
+                                                mTabControl.getCurrentIndex());
+                                    }
                                 }
                             }
                         });
@@ -2041,7 +2034,7 @@
     // Animate from the tab picker. The index supplied is the index to animate
     // from.
     private void animateFromTabOverview(final AnimatingView view,
-            final boolean newTab, final String url, final Message msg) {
+            final boolean newTab, final Message msg) {
         // 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();
@@ -2063,7 +2056,7 @@
         // Find the view at this location.
         final View v = mTabOverview.getChildAt(location);
 
-        // Wait until the animation completes to load the url.
+        // Wait until the animation completes to replace the AnimatingView.
         final Animation.AnimationListener l =
                 new Animation.AnimationListener() {
                     public void onAnimationStart(Animation a) {}
@@ -2078,15 +2071,9 @@
                                 dismissTabOverview(v == null);
                                 TabControl.Tab t =
                                         mTabControl.getCurrentTab();
-                                WebView w = t.getWebView();
-                                if (url != null) {
-                                    // Dismiss the subwindow if one exists.
-                                    dismissSubWindow(t);
-                                    w.loadUrl(url);
-                                }
                                 mMenuState = R.id.MAIN_MENU;
                                 // Resume regular updates.
-                                w.resumeTimers();
+                                t.getWebView().resumeTimers();
                                 // Dispatch the message after the animation
                                 // completes.
                                 if (msg != null) {
@@ -2111,7 +2098,7 @@
             // Make the view VISIBLE during the animation.
             view.setVisibility(View.VISIBLE);
         } else {
-            // Go ahead and load the url.
+            // Go ahead and do all the cleanup.
             l.onAnimationEnd(null);
         }
     }
@@ -2126,7 +2113,12 @@
         }
         // Just in case there was a problem with animating away from the tab
         // overview
-        mTabControl.getCurrentWebView().setVisibility(View.VISIBLE);
+        WebView current = mTabControl.getCurrentWebView();
+        if (current != null) {
+            current.setVisibility(View.VISIBLE);
+        } else {
+            Log.e(LOGTAG, "No current WebView in dismissTabOverview");
+        }
         // Make the sub window container visible.
         if (mTabControl.getCurrentSubWindow() != null) {
             mTabControl.getCurrentTab().getSubWebViewContainer()
@@ -2140,12 +2132,12 @@
 
     private void openTab(String url) {
         if (mSettings.openInBackground()) {
-            TabControl.Tab t = mTabControl.createNewTab(false);
+            TabControl.Tab t = mTabControl.createNewTab();
             if (t != null) {
                 t.getWebView().loadUrl(url);
             }
         } else {
-            openTabAndShow(url, null, false);
+            openTabAndShow(url, null, false, null);
         }
     }
 
@@ -2218,8 +2210,6 @@
         }
         resetTitleAndIcon(current);
         int progress = current.getProgress();
-        mInLoad = (progress != 100);
-        updateInLoadMenuItems();
         mWebChromeClient.onProgressChanged(current, progress);
     }
 
@@ -2450,7 +2440,7 @@
                 return KeyTracker.State.DONE_TRACKING;
             }
             if (stage == KeyTracker.Stage.LONG_REPEAT) {
-                loadHistory();
+                bookmarksOrHistoryPicker(true);
                 return KeyTracker.State.DONE_TRACKING;
             } else if (stage == KeyTracker.Stage.UP) {
                 // FIXME: Currently, we do not have a notion of the
@@ -2522,13 +2512,6 @@
         }
     }
 
-    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));
@@ -2555,8 +2538,7 @@
                 case ANIMATE_FROM_OVERVIEW:
                     final HashMap map = (HashMap) msg.obj;
                     animateFromTabOverview((AnimatingView) map.get("view"),
-                            msg.arg1 == 1, (String) map.get("url"),
-                            (Message) map.get("msg"));
+                            msg.arg1 == 1, (Message) map.get("msg"));
                     break;
 
                 case ANIMATE_TO_OVERVIEW:
@@ -2569,7 +2551,7 @@
                     // the method relies on the value being 0 to start the next
                     // animation.
                     mAnimationCount--;
-                    openTabAndShow((String) msg.obj, null, false);
+                    openTabAndShow((String) msg.obj, null, false, null);
                     break;
 
                 case FOCUS_NODE_HREF:
@@ -2723,6 +2705,18 @@
 
             mInLoad = true;
             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();
+                }
+                if (view != null) {
+                    view.setNetworkAvailable(false);
+                }
+            }
 
             // schedule to check memory condition
             mHandler.sendMessageDelayed(mHandler.obtainMessage(CHECK_MEMORY),
@@ -2739,7 +2733,7 @@
             updateLockIconImage(mLockIconType);
 
             // Performance probe
-             if (false) {
+            if (false) {
                 long[] sysCpu = new long[7];
                 if (Process.readProcFile("/proc/stat", SYSTEM_CPU_FORMAT, null,
                         sysCpu, null)) {
@@ -2834,11 +2828,6 @@
                 }
             }
 
-            if (mInLoad) {
-                mInLoad = false;
-                updateInLoadMenuItems();
-            }
-
             mHandler.removeMessages(CHECK_MEMORY);
             checkMemory();
         }
@@ -3180,7 +3169,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, false);
+                openTabAndShow(null, msg, false, null);
                 parent.addChildTab(mTabControl.getCurrentTab());
                 WebView.WebViewTransport transport =
                         (WebView.WebViewTransport) msg.obj;
@@ -3296,6 +3285,18 @@
                 // onPageFinished() is only called for the main frame. sync
                 // cookie and cache promptly here.
                 CookieSyncManager.getInstance().sync();
+                if (mInLoad) {
+                    mInLoad = false;
+                    updateInLoadMenuItems();
+                }
+            } else {
+                // 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();
+                }
             }
         }
 
@@ -3367,8 +3368,8 @@
             //     that matches.
             Intent intent = new Intent(Intent.ACTION_VIEW);
             intent.setDataAndType(Uri.parse(url), mimetype);
-            if (getPackageManager().queryIntentActivities(intent,
-                        PackageManager.MATCH_DEFAULT_ONLY).size() != 0) {
+            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);
@@ -3424,10 +3425,44 @@
             return;
         }
 
+        // java.net.URI is a lot stricter than KURL so we have to undo
+        // KURL's percent-encoding and redo the encoding using java.net.URI.
+        URI uri = null;
+        try {
+            // Undo the percent-encoding that KURL may have done.
+            String newUrl = new String(URLUtil.decode(url.getBytes()));
+            // Parse the url into pieces
+            WebAddress w = new WebAddress(newUrl);
+            String frag = null;
+            String query = null;
+            String path = w.mPath;
+            // Break the path into path, query, and fragment
+            if (path.length() > 0) {
+                // Strip the fragment
+                int idx = path.lastIndexOf('#');
+                if (idx != -1) {
+                    frag = path.substring(idx + 1);
+                    path = path.substring(0, idx);
+                }
+                idx = path.lastIndexOf('?');
+                if (idx != -1) {
+                    query = path.substring(idx + 1);
+                    path = path.substring(0, idx);
+                }
+            }
+            uri = new URI(w.mScheme, w.mAuthInfo, w.mHost, w.mPort, path,
+                    query, frag);
+        } catch (Exception e) {
+            Log.e(LOGTAG, "Could not parse url for download: " + url, e);
+            return;
+        }
+
+        // XXX: Have to use the old url since the cookies were stored using the
+        // old percent-encoded url.
         String cookies = CookieManager.getInstance().getCookie(url);
 
         ContentValues values = new ContentValues();
-        values.put(Downloads.COLUMN_URI, url);
+        values.put(Downloads.COLUMN_URI, uri.toString());
         values.put(Downloads.COLUMN_COOKIE_DATA, cookies);
         values.put(Downloads.COLUMN_USER_AGENT, userAgent);
         values.put(Downloads.COLUMN_NOTIFICATION_PACKAGE,
@@ -3437,7 +3472,7 @@
         values.put(Downloads.COLUMN_VISIBILITY, Downloads.VISIBILITY_VISIBLE_NOTIFY_COMPLETED);
         values.put(Downloads.COLUMN_MIME_TYPE, mimetype);
         values.put(Downloads.COLUMN_FILE_NAME_HINT, filename);
-        values.put(Downloads.COLUMN_DESCRIPTION, Uri.parse(url).getHost());
+        values.put(Downloads.COLUMN_DESCRIPTION, uri.getHost());
         if (contentLength > 0) {
             values.put(Downloads.COLUMN_TOTAL_BYTES, contentLength);
         }
@@ -3884,7 +3919,7 @@
         }
 
         mHttpAuthHandler = handler;
-        mHttpAuthenticationDialog = new AlertDialog.Builder(this)
+        AlertDialog dialog = new AlertDialog.Builder(this)
                 .setTitle(titleText)
                 .setIcon(android.R.drawable.ic_dialog_alert)
                 .setView(v)
@@ -3920,12 +3955,17 @@
                             mHttpAuthenticationDialog = null;
                             mHttpAuthHandler = null;
                         }})
-                .show();
+                .create();
+        // Make the IME appear when the dialog is displayed if applicable.
+        dialog.getWindow().setSoftInputMode(
+                WindowManager.LayoutParams.SOFT_INPUT_STATE_VISIBLE);
+        dialog.show();
         if (focusId != 0) {
-            mHttpAuthenticationDialog.findViewById(focusId).requestFocus();
+            dialog.findViewById(focusId).requestFocus();
         } else {
             v.findViewById(R.id.username_edit).requestFocus();
         }
+        mHttpAuthenticationDialog = dialog;
     }
 
     public int getProgress() {
@@ -3956,16 +3996,20 @@
     }
 
     /**
-     * http stack says net has come or gone... inform the user
+     * connectivity manager says net has come or gone... inform the user
      * @param up true if net has come up, false if net has gone down
      */
     public void onNetworkToggle(boolean up) {
-        if (up) {
+        if (up == mIsNetworkUp) {
+            return;
+        } else if (up) {
+            mIsNetworkUp = true;
             if (mAlertDialog != null) {
                 mAlertDialog.cancel();
                 mAlertDialog = null;
             }
         } else {
+            mIsNetworkUp = false;
             if (mInLoad && mAlertDialog == null) {
                 mAlertDialog = new AlertDialog.Builder(this)
                         .setTitle(R.string.loadSuspendedTitle)
@@ -3984,8 +4028,7 @@
     protected void onActivityResult(int requestCode, int resultCode,
                                     Intent intent) {
         switch (requestCode) {
-            case BOOKMARKS_PAGE:
-            case CLASSIC_HISTORY_PAGE:
+            case COMBO_PAGE:
                 if (resultCode == RESULT_OK && intent != null) {
                     String data = intent.getAction();
                     Bundle extras = intent.getExtras();
@@ -4048,7 +4091,7 @@
                 // If the user removes the last tab, act like the New Tab item
                 // was clicked on.
                 if (mTabControl.getTabCount() == 0) {
-                    current = mTabControl.createNewTab(false);
+                    current = mTabControl.createNewTab();
                     sendAnimateFromOverview(current, true,
                             mSettings.getHomePage(), TAB_OVERVIEW_DELAY, null);
                 } else {
@@ -4088,7 +4131,7 @@
 
             // NEW_TAB means that the "New Tab" cell was clicked on.
             if (index == ImageGrid.NEW_TAB) {
-                openTabAndShow(mSettings.getHomePage(), null, false);
+                openTabAndShow(mSettings.getHomePage(), null, false, null);
             } else {
                 sendAnimateFromOverview(mTabControl.getTab(index),
                         false, null, 0, null);
@@ -4202,13 +4245,13 @@
         mMenuState = EMPTY_MENU;
     }
 
-    private void bookmarksPicker() {
+    private void bookmarksOrHistoryPicker(boolean startWithHistory) {
         WebView current = mTabControl.getCurrentWebView();
         if (current == null) {
             return;
         }
         Intent intent = new Intent(this,
-                BrowserBookmarksPage.class);
+                CombinedBookmarkHistoryActivity.class);
         String title = current.getTitle();
         String url = current.getUrl();
         // Just in case the user opens bookmarks before a page finishes loading
@@ -4228,7 +4271,11 @@
         intent.putExtra("url", url);
         intent.putExtra("maxTabsOpen",
                 mTabControl.getTabCount() >= TabControl.MAX_TABS);
-        startActivityForResult(intent, BOOKMARKS_PAGE);
+        if (startWithHistory) {
+            intent.putExtra(CombinedBookmarkHistoryActivity.STARTING_TAB,
+                    CombinedBookmarkHistoryActivity.HISTORY_TAB);
+        }
+        startActivityForResult(intent, COMBO_PAGE);
     }
 
     // Called when loading from context menu or LOAD_URL message
@@ -4351,7 +4398,7 @@
         return composeSearchUrl(inUrl);
     }
 
-    /* package */static String composeSearchUrl(String search) {
+    /* package */ String composeSearchUrl(String search) {
         return URLUtil.composeSearchUrl(search, QuickSearch_G,
                 QUERY_PLACE_HOLDER);
     }
@@ -4376,7 +4423,7 @@
                     R.string.google_search_base, l.getLanguage(),
                     l.getCountry().toLowerCase())
                     + "client=ms-"
-                    + SystemProperties.get("ro.com.google.clientid", "unknown")
+                    + SystemProperties.get("persist.sys.com.google.clientid", "unknown")
                     + "&source=android-" + GOOGLE_SEARCH_SOURCE_SUGGEST + "&q=%s";
         } else {
             QuickSearch_G = url;
@@ -4409,6 +4456,7 @@
     boolean mCanChord;
 
     private boolean mInLoad;
+    private boolean mIsNetworkUp;
 
     private boolean mPageStarted;
     private boolean mActivityInPause = true;
@@ -4503,8 +4551,6 @@
 
     // "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
@@ -4543,10 +4589,9 @@
     private BroadcastReceiver mNetworkStateIntentReceiver;
 
     // activity requestCode
-    final static int BOOKMARKS_PAGE         = 1;
-    final static int CLASSIC_HISTORY_PAGE   = 2;
-    final static int DOWNLOAD_PAGE          = 3;
-    final static int PREFERENCES_PAGE       = 4;
+    final static int COMBO_PAGE             = 1;
+    final static int DOWNLOAD_PAGE          = 2;
+    final static int PREFERENCES_PAGE       = 3;
 
     // the frenquency of checking whether system memory is low
     final static int CHECK_MEMORY_INTERVAL = 30000;     // 30 seconds