auto import from //branches/cupcake/...@130745
diff --git a/src/com/android/browser/AddBookmarkPage.java b/src/com/android/browser/AddBookmarkPage.java
index ea65a46..23c0fac 100644
--- a/src/com/android/browser/AddBookmarkPage.java
+++ b/src/com/android/browser/AddBookmarkPage.java
@@ -48,8 +48,8 @@
     private Bundle      mMap;
     
     private static final String[]   mProjection = 
-        { "_id", "url", "bookmark", "created", "title" };
-    private static final String     WHERE_CLAUSE = "url = ? AND bookmark = 0";
+        { "_id", "url", "bookmark", "created", "title", "visits" };
+    private static final String     WHERE_CLAUSE = "url = ?";
     private final String[]          SELECTION_ARGS = new String[1];
 
     private View.OnClickListener mSaveBookmark = new View.OnClickListener() {
@@ -163,25 +163,58 @@
                         WHERE_CLAUSE,
                         SELECTION_ARGS,
                         null);
-                if (c.moveToFirst()) {
-                    // This means we have been to this site, so convert the 
-                    // history item to a bookmark.
-                    ContentValues map = new ContentValues();
+                ContentValues map = new ContentValues();
+                if (c.moveToFirst() && c.getInt(c.getColumnIndexOrThrow(
+                        Browser.BookmarkColumns.BOOKMARK)) == 0) {
+                    // This means we have been to this site but not bookmarked
+                    // it, so convert the history item to a bookmark                    
                     map.put(Browser.BookmarkColumns.CREATED, creationTime);
                     map.put(Browser.BookmarkColumns.TITLE, title);
                     map.put(Browser.BookmarkColumns.BOOKMARK, 1);
                     cr.update(Browser.BOOKMARKS_URI, map, 
                             "_id = " + c.getInt(0), null);
                 } else {
-                    // Adding a bookmark for a site the user has not been to.
-                    ContentValues map = new ContentValues();
-                    map.put(Browser.BookmarkColumns.TITLE, title);
-                    map.put(Browser.BookmarkColumns.URL, url);
-                    map.put(Browser.BookmarkColumns.CREATED, creationTime);
-                    map.put(Browser.BookmarkColumns.BOOKMARK, 1);
-                    map.put(Browser.BookmarkColumns.DATE, 0);
-                    map.put(Browser.BookmarkColumns.VISITS, 0);
-                    cr.insert(Browser.BOOKMARKS_URI, map);
+                    int count = c.getCount();
+                    boolean matchedTitle = false;
+                    for (int i = 0; i < count; i++) {
+                        // One or more bookmarks already exist for this site.
+                        // Check the names of each
+                        c.moveToPosition(i);
+                        if (c.getString(c.getColumnIndexOrThrow(
+                                Browser.BookmarkColumns.TITLE)).equals(title)) {
+                            // The old bookmark has the same name.
+                            // Update its creation time.
+                            map.put(Browser.BookmarkColumns.CREATED,
+                                    creationTime);
+                            cr.update(Browser.BOOKMARKS_URI, map, 
+                                    "_id = " + c.getInt(0), null);
+                            matchedTitle = true;
+                        }
+                    }
+                    if (!matchedTitle) {
+                        // Adding a bookmark for a site the user has visited,
+                        // or a new bookmark (with a different name) for a site
+                        // the user has visited
+                        map.put(Browser.BookmarkColumns.TITLE, title);
+                        map.put(Browser.BookmarkColumns.URL, url);
+                        map.put(Browser.BookmarkColumns.CREATED, creationTime);
+                        map.put(Browser.BookmarkColumns.BOOKMARK, 1);
+                        map.put(Browser.BookmarkColumns.DATE, 0);
+                        int visits = 0;
+                        if (count > 0) {
+                            // The user has already bookmarked, and possibly
+                            // visited this site.  However, they are creating
+                            // a new bookmark with the same url but a different
+                            // name.  The new bookmark should have the same
+                            // number of visits as the already created bookmark.
+                            visits = c.getInt(c.getColumnIndexOrThrow(
+                                    Browser.BookmarkColumns.VISITS));
+                        }
+                        // Bookmark starts with 3 extra visits so that it will
+                        // bubble up in the most visited and goto search box
+                        map.put(Browser.BookmarkColumns.VISITS, visits + 3);
+                        cr.insert(Browser.BOOKMARKS_URI, map);
+                    }
                 }
                 WebIconDatabase.getInstance().retainIconForPageUrl(url);
                 c.deactivate();
diff --git a/src/com/android/browser/AddNewBookmark.java b/src/com/android/browser/AddNewBookmark.java
index 748c9c2..a75d002 100644
--- a/src/com/android/browser/AddNewBookmark.java
+++ b/src/com/android/browser/AddNewBookmark.java
@@ -63,10 +63,6 @@
      *  @param url  The new url for the bookmark item.
      */
     /* package */ void setUrl(String url) {
-        if (url.length() > BrowserSettings.MAX_TEXTVIEW_LEN) {
-            mUrlText.setText(url.substring(0, BrowserSettings.MAX_TEXTVIEW_LEN));
-        } else {
-            mUrlText.setText(url);
-        }
+        mUrlText.setText(url);
     }
 }
diff --git a/src/com/android/browser/BookmarkItem.java b/src/com/android/browser/BookmarkItem.java
index 0015eaf..a70dd4f 100644
--- a/src/com/android/browser/BookmarkItem.java
+++ b/src/com/android/browser/BookmarkItem.java
@@ -19,19 +19,20 @@
 import android.content.Context;
 import android.graphics.Bitmap;
 import android.view.LayoutInflater;
+import android.view.View;
 import android.widget.ImageView;
-import android.widget.RelativeLayout;
+import android.widget.LinearLayout;
 import android.widget.TextView;
 
 /**
  *  Custom layout for an item representing a bookmark in the browser.
  */
-class BookmarkItem extends RelativeLayout {
+class BookmarkItem extends LinearLayout {
 
-    private TextView    mTextView;
-    private TextView    mUrlText;
-    private ImageView   mImageView;
-    private LayoutInflater mFactory;
+    protected TextView    mTextView;
+    protected TextView    mUrlText;
+    protected ImageView   mImageView;
+    protected String      mUrl;
 
     /**
      *  Instantiate a bookmark item, including a default favicon.
@@ -41,11 +42,13 @@
     BookmarkItem(Context context) {
         super(context);
 
-        mFactory = LayoutInflater.from(context);
-        mFactory.inflate(R.layout.bookmark_item, this);
+        LayoutInflater factory = LayoutInflater.from(context);
+        factory.inflate(R.layout.history_item, this);
         mTextView = (TextView) findViewById(R.id.title);
         mUrlText = (TextView) findViewById(R.id.url);
         mImageView = (ImageView) findViewById(R.id.favicon);
+        View star = findViewById(R.id.star);
+        star.setVisibility(View.GONE);
     }
 
     /**
@@ -61,8 +64,8 @@
     /**
      * Return the name assigned to this bookmark item.
      */
-    /* package */ CharSequence getName() {
-        return mTextView.getText();
+    /* package */ String getName() {
+        return mTextView.getText().toString();
     }
 
     /**
@@ -72,6 +75,10 @@
         return mTextView;
     }
 
+    /* package */ String getUrl() {
+        return mUrl;
+    }
+
     /**
      *  Set the favicon for this item.
      *
@@ -101,5 +108,6 @@
      */
     /* package */ void setUrl(String url) {
         mUrlText.setText(url);
+        mUrl = url;
     }
 }
diff --git a/src/com/android/browser/BrowserActivity.java b/src/com/android/browser/BrowserActivity.java
index 170083d..b6942d2 100644
--- a/src/com/android/browser/BrowserActivity.java
+++ b/src/com/android/browser/BrowserActivity.java
@@ -54,10 +54,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;
@@ -97,6 +97,7 @@
 import android.view.View;
 import android.view.ViewGroup;
 import android.view.Window;
+import android.view.WindowManager;
 import android.view.animation.AlphaAnimation;
 import android.view.animation.Animation;
 import android.view.animation.AnimationSet;
@@ -730,19 +731,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
@@ -1324,14 +1324,8 @@
                 }
                 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:
@@ -1412,12 +1406,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 +1417,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 +1429,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 +1470,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 +1536,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 +1549,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,31 +1558,27 @@
                 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();
@@ -1625,13 +1589,6 @@
                 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 ?
@@ -1741,10 +1698,14 @@
                         PackageManager.MATCH_DEFAULT_ONLY);
                 menu.findItem(R.id.share_link_context_menu_id).setVisible(
                         list.size() > 0);
-                break;
-
+                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).
@@ -1838,7 +1799,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);
@@ -2041,7 +2008,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 +2030,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 +2045,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 +2072,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);
         }
     }
@@ -2450,7 +2411,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 +2483,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 +2509,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:
@@ -2723,6 +2676,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),
@@ -3884,7 +3849,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 +3885,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 +3926,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 +3958,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();
@@ -4202,13 +4175,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 +4201,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 +4328,7 @@
         return composeSearchUrl(inUrl);
     }
 
-    /* package */static String composeSearchUrl(String search) {
+    /* package */ String composeSearchUrl(String search) {
         return URLUtil.composeSearchUrl(search, QuickSearch_G,
                 QUERY_PLACE_HOLDER);
     }
@@ -4409,6 +4386,7 @@
     boolean mCanChord;
 
     private boolean mInLoad;
+    private boolean mIsNetworkUp;
 
     private boolean mPageStarted;
     private boolean mActivityInPause = true;
@@ -4503,8 +4481,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 +4519,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
diff --git a/src/com/android/browser/BrowserBookmarksPage.java b/src/com/android/browser/BrowserBookmarksPage.java
index 5c509a8..7708e8b 100644
--- a/src/com/android/browser/BrowserBookmarksPage.java
+++ b/src/com/android/browser/BrowserBookmarksPage.java
@@ -162,7 +162,7 @@
         }
 
         mBookmarksAdapter = new BrowserBookmarksAdapter(this, 
-                getIntent().getStringExtra("title"), mCreateShortcut);
+                getIntent().getStringExtra("url"), mCreateShortcut);
         mMaxTabsOpen = getIntent().getBooleanExtra("maxTabsOpen", false);
 
         ListView listView = (ListView) findViewById(R.id.list);
@@ -204,7 +204,7 @@
             } else {
                 final Intent intent = createShortcutIntent(getUrl(position),
                         getBookmarkTitle(position));
-                setResult(RESULT_OK, intent);
+                setResultToParent(RESULT_OK, intent);
                 finish();
             }
         }
@@ -231,7 +231,8 @@
     }
 
     private void loadUrl(int position) {
-        setResult(RESULT_OK, (new Intent()).setAction(getUrl(position)));
+        Intent intent = (new Intent()).setAction(getUrl(position));
+        setResultToParent(RESULT_OK, intent);
         finish();
     }
 
@@ -262,7 +263,7 @@
     private void openInNewWindow(int position) {
         Bundle b = new Bundle();
         b.putBoolean("new_window", true);
-        setResult(RESULT_OK,
+        setResultToParent(RESULT_OK,
                 (new Intent()).setAction(getUrl(position)).putExtras(b));
 
         finish();
@@ -367,9 +368,18 @@
     
     public boolean dispatchKeyEvent(KeyEvent event) {    
         if (event.getKeyCode() ==  KeyEvent.KEYCODE_BACK && event.isDown()) {
-            setResult(RESULT_CANCELED);
+            setResultToParent(RESULT_CANCELED, null);
             mCanceled = true;
         }
         return super.dispatchKeyEvent(event);
     }
+
+    // This Activity is generally a sub-Activity of CombinedHistoryActivity. In
+    // that situation, we need to pass our result code up to our parent.
+    // However, if someone calls this Activity directly, then this has no
+    // parent, and it needs to set it on itself.
+    private void setResultToParent(int resultCode, Intent data) {
+        Activity a = getParent() == null ? this : getParent();
+        a.setResult(resultCode, data);
+    }
 }
diff --git a/src/com/android/browser/BrowserDownloadAdapter.java b/src/com/android/browser/BrowserDownloadAdapter.java
index 0b509ef..38b83fe 100644
--- a/src/com/android/browser/BrowserDownloadAdapter.java
+++ b/src/com/android/browser/BrowserDownloadAdapter.java
@@ -180,6 +180,7 @@
                     sb.append("/");
                     sb.append(Formatter.formatFileSize(mContext, totalBytes));
                     sb.append(")");
+                    pb.setIndeterminate(false);
                     pb.setProgress(progressAmount);
                 } else {
                     pb.setIndeterminate(true);
diff --git a/src/com/android/browser/BrowserHistoryPage.java b/src/com/android/browser/BrowserHistoryPage.java
index 3059126..f7e97c0 100644
--- a/src/com/android/browser/BrowserHistoryPage.java
+++ b/src/com/android/browser/BrowserHistoryPage.java
@@ -16,14 +16,17 @@
 
 package com.android.browser;
 
-import android.app.ListActivity;
+import android.app.Activity;
+import android.app.ExpandableListActivity;
 import android.content.Intent;
 import android.content.pm.PackageManager;
 import android.content.pm.ResolveInfo;
+import android.database.ContentObserver;
 import android.database.Cursor;
 import android.database.DataSetObserver;
 import android.graphics.Bitmap;
 import android.os.Bundle;
+import android.os.Handler;
 import android.os.ServiceManager;
 import android.provider.Browser;
 import android.text.IClipboard;
@@ -41,11 +44,11 @@
 import android.webkit.DateSorter;
 import android.webkit.WebIconDatabase.IconListener;
 import android.widget.AdapterView;
-import android.widget.ListAdapter;
-import android.widget.ListView;
+import android.widget.ExpandableListAdapter;
+import android.widget.ExpandableListView;
+import android.widget.ExpandableListView.ExpandableListContextMenuInfo;
 import android.widget.TextView;
 
-import java.util.HashMap;
 import java.util.List;
 import java.util.Vector;
 
@@ -53,22 +56,16 @@
  * Activity for displaying the browser's history, divided into
  * days of viewing.
  */
-public class BrowserHistoryPage extends ListActivity {
+public class BrowserHistoryPage extends ExpandableListActivity {
     private HistoryAdapter          mAdapter;
     private DateSorter              mDateSorter;
     private boolean                 mMaxTabsOpen;
 
     private final static String LOGTAG = "browser";
 
-    // FIXME: Make this a part of Browser so we do not have more than one
-    // copy (other copy is in BrowserBookmarksAdapter).
-    // Used to store favicons as we get them from the database
-    private final HashMap<String, Bitmap> mUrlsToIcons =
-            new HashMap<String, Bitmap>();
     // Implementation of WebIconDatabase.IconListener
     private class IconReceiver implements IconListener {
         public void onReceivedIcon(String url, Bitmap icon) {
-            mUrlsToIcons.put(url, icon);
             setListAdapter(mAdapter);
         }
     }
@@ -87,7 +84,7 @@
             b.putBoolean("new_window", true);
             intent.putExtras(b);
         }
-        setResult(RESULT_OK, intent);
+        setResultToParent(RESULT_OK, intent);
         finish();
     }
     
@@ -111,20 +108,25 @@
 
         mAdapter = new HistoryAdapter();
         setListAdapter(mAdapter);
-        ListView list = getListView();
+        final ExpandableListView list = getExpandableListView();
         list.setOnCreateContextMenuListener(this);
         LayoutInflater factory = LayoutInflater.from(this);
         View v = factory.inflate(R.layout.empty_history, null);
         addContentView(v, new LayoutParams(LayoutParams.FILL_PARENT,
                 LayoutParams.FILL_PARENT));
         list.setEmptyView(v);
-
+        list.post(new Runnable() {
+            public void run() {
+                list.expandGroup(0);
+            }
+        });
         mMaxTabsOpen = getIntent().getBooleanExtra("maxTabsOpen", false);
-        Browser.requestAllIcons(getContentResolver(), null, mIconReceiver);
+        CombinedBookmarkHistoryActivity.getIconListenerSet(getContentResolver())
+                .addListener(mIconReceiver);
         
         // initialize the result to canceled, so that if the user just presses
         // back then it will have the correct result
-        setResult(RESULT_CANCELED);
+        setResultToParent(RESULT_CANCELED, null);
     }
 
     @Override
@@ -160,9 +162,12 @@
     @Override
     public void onCreateContextMenu(ContextMenu menu, View v,
             ContextMenuInfo menuInfo) {
-        AdapterView.AdapterContextMenuInfo i = 
-            (AdapterView.AdapterContextMenuInfo)
-            menuInfo;
+        ExpandableListContextMenuInfo i = 
+            (ExpandableListContextMenuInfo) menuInfo;
+        // Do not allow a context menu to come up from the group views.
+        if (!(i.targetView instanceof HistoryItem)) {
+            return;
+        }
 
         // Inflate the menu
         MenuInflater inflater = getMenuInflater();
@@ -174,7 +179,7 @@
         // Only show open in new tab if we have not maxed out available tabs
         menu.findItem(R.id.new_window_context_menu_id).setVisible(!mMaxTabsOpen);
         
-     // decide whether to show the share link option
+        // decide whether to show the share link option
         PackageManager pm = getPackageManager();
         Intent send = new Intent(Intent.ACTION_SEND);
         send.setType("text/plain");
@@ -188,8 +193,8 @@
     
     @Override
     public boolean onContextItemSelected(MenuItem item) {
-        AdapterView.AdapterContextMenuInfo i = 
-            (AdapterView.AdapterContextMenuInfo)item.getMenuInfo();
+        ExpandableListContextMenuInfo i = 
+            (ExpandableListContextMenuInfo) item.getMenuInfo();
         String url = ((HistoryItem)i.targetView).getUrl();
         String title = ((HistoryItem)i.targetView).getName();
         switch (item.getItemId()) {
@@ -219,13 +224,41 @@
     }
     
     @Override
-    protected void onListItemClick(ListView l, View v, int position, long id) {
+    public boolean onChildClick(ExpandableListView parent, View v,
+            int groupPosition, int childPosition, long id) {
         if (v instanceof HistoryItem) {
             loadUrl(((HistoryItem) v).getUrl(), false);
+            return true;
         }
+        return false;
     }
 
-    private class HistoryAdapter implements ListAdapter {
+    // This Activity is generally a sub-Activity of CombinedHistoryActivity. In
+    // that situation, we need to pass our result code up to our parent.
+    // However, if someone calls this Activity directly, then this has no
+    // parent, and it needs to set it on itself.
+    private void setResultToParent(int resultCode, Intent data) {
+        Activity a = getParent() == null ? this : getParent();
+        a.setResult(resultCode, data);
+    }
+
+    private class ChangeObserver extends ContentObserver {
+        public ChangeObserver() {
+            super(new Handler());
+        }
+
+        @Override
+        public boolean deliverSelfNotifications() {
+            return true;
+        }
+
+        @Override
+        public void onChange(boolean selfChange) {
+            mAdapter.refreshData();
+        }
+    }
+    
+    private class HistoryAdapter implements ExpandableListAdapter {
         
         // Map of items. Negative values are labels, positive values
         // and zero are cursor offsets.
@@ -245,6 +278,7 @@
                     whereClause, null, orderBy);
             
             buildMap();
+            mCursor.registerContentObserver(new ChangeObserver());
         }
         
         void refreshData() {
@@ -255,107 +289,109 @@
             }
         }
         
-        public void buildMap() {
+        private void buildMap() {
             // The cursor is sorted by date
-            // Make one pass to build up the ItemMap with the inserted 
-            // section separators. 
-            int array[] = new int[mCursor.getCount() + DateSorter.DAY_COUNT];
+            // The ItemMap will store the number of items in each bin.
+            int array[] = new int[DateSorter.DAY_COUNT];
+            // Zero out the array.
+            for (int j = 0; j < DateSorter.DAY_COUNT; j++) {
+                array[j] = 0;
+            }
             int dateIndex = -1;
             if (mCursor.moveToFirst() && mCursor.getCount() > 0) {
-                int itemIndex = 0;
                 while (!mCursor.isAfterLast()) {
                     long date = mCursor.getLong(Browser.HISTORY_PROJECTION_DATE_INDEX);
                     int index = mDateSorter.getIndex(date);
                     if (index > dateIndex) {
+                        if (index == DateSorter.DAY_COUNT - 1) {
+                            // We are already in the last bin, so it will
+                            // include all the remaining items
+                            array[index] = mCursor.getCount()
+                                    - mCursor.getPosition();
+                            break;
+                        }
                         dateIndex = index;
-                        array[itemIndex] = dateIndex - DateSorter.DAY_COUNT;
-                        itemIndex++;
                     }
-                    array[itemIndex] = mCursor.getPosition();
-                    itemIndex++;
+                    array[dateIndex]++;
                     mCursor.moveToNext();
                 }
-            } else {
-                // The db is empty, just add the heading for the first item
-                dateIndex = 0;
-                array[0] = dateIndex - DateSorter.DAY_COUNT;
             }
-            // Compress the array as the trailing date sections may be
-            // empty
-            int extraEntries = DateSorter.DAY_COUNT - dateIndex - 1;
-            if (extraEntries > 0) {
-                int newArraySize = array.length - extraEntries;
-                mItemMap = new int[newArraySize];
-                System.arraycopy(array, 0, mItemMap, 0, newArraySize);
-            } else {
-                mItemMap = array;
-            }
-        }
-
-        public View getView(int position, View convertView, ViewGroup parent) {
-            if (mItemMap[position] < 0) {
-                return getHeaderView(position, convertView);
-            }
-            return getHistoryItem(position, convertView);
+            mItemMap = array;
         }
         
-        View getHistoryItem(int position, View convertView) {
+        public View getChildView(int groupPosition, int childPosition, boolean isLastChild,
+                View convertView, ViewGroup parent) {
             HistoryItem item;
             if (null == convertView || !(convertView instanceof HistoryItem)) {
                 item = new HistoryItem(BrowserHistoryPage.this);
+                // Add padding on the left so it will be indented from the
+                // arrows on the group views.
+                item.setPadding(item.getPaddingLeft() + 10,
+                        item.getPaddingTop(),
+                        item.getPaddingRight(),
+                        item.getPaddingBottom());
             } else {
                 item = (HistoryItem) convertView;
             }
-            mCursor.moveToPosition(mItemMap[position]);
+            int index = childPosition;
+            for (int i = 0; i < groupPosition; i++) {
+                index += mItemMap[i];
+            }
+            mCursor.moveToPosition(index);
             item.setName(mCursor.getString(Browser.HISTORY_PROJECTION_TITLE_INDEX));
             String url = mCursor.getString(Browser.HISTORY_PROJECTION_URL_INDEX);
             item.setUrl(url);
-            item.setFavicon((Bitmap) mUrlsToIcons.get(url));
+            item.setFavicon(CombinedBookmarkHistoryActivity.getIconListenerSet(
+                    getContentResolver()).getFavicon(url));
+            item.setIsBookmark(1 ==
+                    mCursor.getInt(Browser.HISTORY_PROJECTION_BOOKMARK_INDEX));
             return item;
         }
         
-        View getHeaderView(int position, View convertView) {
+        public View getGroupView(int groupPosition, boolean isExpanded, View convertView, ViewGroup parent) {
             TextView item;
             if (null == convertView || !(convertView instanceof TextView)) {
                 LayoutInflater factory = 
                         LayoutInflater.from(BrowserHistoryPage.this);
                 item = (TextView) 
-                        factory.inflate(android.R.layout.preference_category, null);
+                        factory.inflate(R.layout.history_header, null);
             } else {
                 item = (TextView) convertView;
             }
-            item.setText(mDateSorter.getLabel(
-                    mItemMap[position] + DateSorter.DAY_COUNT));
+            item.setText(mDateSorter.getLabel(groupPosition));
             return item;
         }
 
         public boolean areAllItemsEnabled() {
-            return false;
+            return true;
         }
 
-        public boolean isEnabled(int position) {
-            return mItemMap[position] >= 0;
+        public boolean isChildSelectable(int groupPosition, int childPosition) {
+            return true;
         }
 
-        public int getCount() {
-            return mItemMap.length;
+        public int getGroupCount() {
+            return DateSorter.DAY_COUNT;
         }
 
-        public Object getItem(int position) {
+        public int getChildrenCount(int groupPosition) {
+            return mItemMap[groupPosition];
+        }
+
+        public Object getGroup(int groupPosition) {
             return null;
         }
 
-        public long getItemId(int position) {
-            return mItemMap[position];
+        public Object getChild(int groupPosition, int childPosition) {
+            return null;
         }
 
-        // 0 for TextView, 1 for HistoryItem
-        public int getItemViewType(int position) {
-            return mItemMap[position] < 0 ? 0 : 1;
+        public long getGroupId(int groupPosition) {
+            return groupPosition;
         }
 
-        public int getViewTypeCount() {
-            return 2;
+        public long getChildId(int groupPosition, int childPosition) {
+            return (childPosition << 3) + groupPosition;
         }
 
         public boolean hasStableIds() {
@@ -370,8 +406,24 @@
             mObservers.remove(observer);
         }
 
+        public void onGroupExpanded(int groupPosition) {
+        
+        }
+
+        public void onGroupCollapsed(int groupPosition) {
+        
+        }
+
+        public long getCombinedChildId(long groupId, long childId) {
+            return childId;
+        }
+
+        public long getCombinedGroupId(long groupId) {
+            return groupId;
+        }
+
         public boolean isEmpty() {
-            return getCount() == 1;
+            return mCursor.getCount() == 0;
         }
     }
 }
diff --git a/src/com/android/browser/BrowserProvider.java b/src/com/android/browser/BrowserProvider.java
index 7aa5bb2..0c930c6 100644
--- a/src/com/android/browser/BrowserProvider.java
+++ b/src/com/android/browser/BrowserProvider.java
@@ -16,23 +16,26 @@
 
 package com.android.browser;
 
+import android.app.ISearchManager;
 import android.app.SearchManager;
+import android.content.ComponentName;
 import android.content.ContentProvider;
-import android.content.ContentResolver;
 import android.content.ContentUris;
 import android.content.ContentValues;
 import android.content.Context;
+import android.content.Intent;
 import android.content.UriMatcher;
 import android.database.AbstractCursor;
-import android.database.ContentObserver;
 import android.database.Cursor;
-import android.database.DataSetObserver;
 import android.database.sqlite.SQLiteOpenHelper;
 import android.database.sqlite.SQLiteDatabase;
 import android.net.Uri;
+import android.os.RemoteException;
+import android.os.ServiceManager;
 import android.os.SystemProperties;
 import android.provider.Browser;
 import android.util.Log;
+import android.server.search.SearchableInfo;
 import android.text.util.Regex;
 
 public class BrowserProvider extends ContentProvider {
@@ -40,22 +43,41 @@
     private SQLiteOpenHelper mOpenHelper;
     private static final String sDatabaseName = "browser.db";
     private static final String TAG = "BrowserProvider";
-    private static final String ORDER_BY = "date DESC";
+    private static final String ORDER_BY = "visits DESC, date DESC";
 
     private static final String[] TABLE_NAMES = new String[] {
         "bookmarks", "searches"
     };
-    private static final String[] SUGGEST_PROJECTION = new String [] {
-        "0 AS " + SearchManager.SUGGEST_COLUMN_FORMAT,
-        "url AS " + SearchManager.SUGGEST_COLUMN_INTENT_DATA,
-        "url AS " + SearchManager.SUGGEST_COLUMN_TEXT_1,
-        "title AS " + SearchManager.SUGGEST_COLUMN_TEXT_2,
-        "_id"
+    private static final String[] SUGGEST_PROJECTION = new String[] {
+            "_id", "url", "title", "bookmark"
     };
     private static final String SUGGEST_SELECTION = 
             "url LIKE ? OR url LIKE ? OR url LIKE ? OR url LIKE ?";
     private String[] SUGGEST_ARGS = new String[4];
 
+    // shared suggestion array index, make sure to match COLUMNS
+    private static final int SUGGEST_COLUMN_INTENT_ACTION_ID = 1;
+    private static final int SUGGEST_COLUMN_INTENT_DATA_ID = 2;
+    private static final int SUGGEST_COLUMN_TEXT_1_ID = 3;
+    private static final int SUGGEST_COLUMN_TEXT_2_ID = 4;
+    private static final int SUGGEST_COLUMN_ICON_1_ID = 5;
+    private static final int SUGGEST_COLUMN_ICON_2_ID = 6;
+    private static final int SUGGEST_COLUMN_QUERY_ID = 7;
+
+    // shared suggestion columns
+    private static final String[] COLUMNS = new String[] {
+            "_id",
+            SearchManager.SUGGEST_COLUMN_INTENT_ACTION,
+            SearchManager.SUGGEST_COLUMN_INTENT_DATA,
+            SearchManager.SUGGEST_COLUMN_TEXT_1,
+            SearchManager.SUGGEST_COLUMN_TEXT_2,
+            SearchManager.SUGGEST_COLUMN_ICON_1,
+            SearchManager.SUGGEST_COLUMN_ICON_2,
+            SearchManager.SUGGEST_COLUMN_QUERY};
+
+    private static final int MAX_SUGGESTION_SHORT_ENTRIES = 3;
+    private static final int MAX_SUGGESTION_LONG_ENTRIES = 6;
+
     // make sure that these match the index of TABLE_NAMES
     private static final int URI_MATCH_BOOKMARKS = 0;
     private static final int URI_MATCH_SEARCHES = 1;
@@ -206,221 +228,195 @@
     }
 
     /*
-     * Subclass AbstractCursor so we can add "Google Search"
+     * Subclass AbstractCursor so we can combine multiple Cursors and add
+     * "Google Search".
+     * Here are the rules.
+     * 1. We only have MAX_SUGGESTION_LONG_ENTRIES in the list plus 
+     *      "Google Search";
+     * 2. If bookmark/history entries are less than 
+     *      (MAX_SUGGESTION_SHORT_ENTRIES -1), we include Google suggest.
      */
     private class MySuggestionCursor extends AbstractCursor {
-        private Cursor  mCursor;
+        private Cursor  mHistoryCursor;
+        private Cursor  mSuggestCursor;
+        private int     mHistoryCount;
+        private int     mSuggestionCount;
         private boolean mBeyondCursor;
         private String  mString;
-        private Uri     mNotifyUri;
-        private ContentResolver mContentResolver;
-        private AbstractCursor.SelfContentObserver mObserver;
-        private final Object mObserverLock = new Object();
 
-        public MySuggestionCursor(Cursor c, String string) {
-            mCursor = c;
-            if (Regex.WEB_URL_PATTERN.matcher(string).matches()) {
-                mString = "";
-            } else {
-                mString = string;
+        public MySuggestionCursor(Cursor hc, Cursor sc, String string) {
+            mHistoryCursor = hc;
+            mSuggestCursor = sc;
+            mHistoryCount = hc.getCount();
+            mSuggestionCount = sc != null ? sc.getCount() : 0;
+            if (mSuggestionCount > (MAX_SUGGESTION_LONG_ENTRIES - mHistoryCount)) {
+                mSuggestionCount = MAX_SUGGESTION_LONG_ENTRIES - mHistoryCount;
             }
+            mString = string;
             mBeyondCursor = false;
         }
 
+        @Override
         public boolean onMove(int oldPosition, int newPosition) {
-            if (mCursor.getCount() == newPosition) {
-                mBeyondCursor = true;
-            } else {
-                mCursor.moveToPosition(newPosition);
+            if (mHistoryCursor == null) {
+                return false;
+            }
+            if (mHistoryCount > newPosition) {
+                mHistoryCursor.moveToPosition(newPosition);
                 mBeyondCursor = false;
+            } else if (mHistoryCount + mSuggestionCount > newPosition) {
+                mSuggestCursor.moveToPosition(newPosition - mHistoryCount);
+                mBeyondCursor = false;
+            } else {
+                mBeyondCursor = true;
             }
             return true;
         }
 
+        @Override
         public int getCount() {
             if (mString.length() > 0) {
-                return mCursor.getCount() + 1;
+                return mHistoryCount + mSuggestionCount + 1;
             } else {
-                return mCursor.getCount();
+                return mHistoryCount + mSuggestionCount;
             }
         }
 
-        public boolean deleteRow() {
-            return !mBeyondCursor && mCursor.deleteRow();
-        }
-
+        @Override
         public String[] getColumnNames() {
-            return mCursor.getColumnNames();
+            return COLUMNS;
         }
 
-        public int getColumnCount() {
-            return mCursor.getColumnCount();
-        }
-
+        @Override
         public String getString(int columnIndex) {
-            if (!mBeyondCursor) {
-                return mCursor.getString(columnIndex);
+            if ((mPos != -1 && mHistoryCursor != null)) {
+                switch(columnIndex) {
+                    case SUGGEST_COLUMN_INTENT_ACTION_ID:
+                        if (mHistoryCount > mPos) {
+                            return Intent.ACTION_VIEW;
+                        } else {
+                            return Intent.ACTION_SEARCH;
+                        }
+
+                    case SUGGEST_COLUMN_INTENT_DATA_ID:
+                        if (mHistoryCount > mPos) {
+                            return mHistoryCursor.getString(1);
+                        } else {
+                            return null;
+                        }
+
+                    case SUGGEST_COLUMN_TEXT_1_ID:
+                        if (mHistoryCount > mPos) {
+                            return mHistoryCursor.getString(1);
+                        } else if (!mBeyondCursor) {
+                            return mSuggestCursor.getString(1);
+                        } else {
+                            return mString;
+                        }
+
+                    case SUGGEST_COLUMN_TEXT_2_ID:
+                        if (mHistoryCount > mPos) {
+                            return mHistoryCursor.getString(2);
+                        } else if (!mBeyondCursor) {
+                            return mSuggestCursor.getString(2);
+                        } else {
+                            return getContext().getString(R.string.search_google);
+                        }
+
+                    case SUGGEST_COLUMN_ICON_1_ID:
+                        if (mHistoryCount > mPos) {
+                            if (mHistoryCursor.getInt(3) == 1) {
+                                return new Integer(
+                                        R.drawable.ic_search_category_bookmark)
+                                        .toString();
+                            } else {
+                                return new Integer(
+                                        R.drawable.ic_search_category_history)
+                                        .toString();
+                            }
+                        } else {
+                            return new Integer(
+                                    R.drawable.ic_search_category_suggest)
+                                    .toString();
+                        }
+
+                    case SUGGEST_COLUMN_ICON_2_ID:
+                        return new String("0");
+
+                    case SUGGEST_COLUMN_QUERY_ID:
+                        if (mHistoryCount > mPos) {
+                            return null;
+                        } else if (!mBeyondCursor) {
+                            return mSuggestCursor.getString(3);
+                        } else {
+                            return mString;
+                        }
+                }
             }
-            switch (columnIndex) {
-                case 2: // SearchManager.SUGGEST_COLUMN_TEXT_1
-                    return "Google Search for \"" + mString + "\"";
-                case 1: // SearchManager.SUGGEST_COLUMN_INTENT_DATA
-                    return BrowserActivity.composeSearchUrl(mString);
-                case 3: // SearchManager.SUGGEST_COLUMN_TEXT_2
-                default:
-                    return "";
+            return null;
+        }
+
+        @Override
+        public double getDouble(int column) {
+            throw new UnsupportedOperationException();
+        }
+
+        @Override
+        public float getFloat(int column) {
+            throw new UnsupportedOperationException();
+        }
+
+        @Override
+        public int getInt(int column) {
+            throw new UnsupportedOperationException();
+        }
+
+        @Override
+        public long getLong(int column) {
+            if ((mPos != -1) && column == 0) {
+                return mPos;        // use row# as the _Id
             }
+            throw new UnsupportedOperationException();
         }
 
-        public short getShort(int columnIndex) {
-            if (!mBeyondCursor) {
-                return mCursor.getShort(columnIndex);
-            }
-            if (0 == columnIndex) {
-                return 0;
-            }
-            return -1;
+        @Override
+        public short getShort(int column) {
+            throw new UnsupportedOperationException();
         }
 
-        public int getInt(int columnIndex) {
-            if (!mBeyondCursor) {
-                return mCursor.getInt(columnIndex);
-            }
-            if (0 == columnIndex) {
-                return 0;
-            }
-            return -1;
-        }
-
-        public long getLong(int columnIndex) {
-            if (!mBeyondCursor) {
-                return mCursor.getLong(columnIndex);
-            }
-            if (0 == columnIndex) {
-                return 0;
-            }
-            return -1;
-        }
-
-        public float getFloat(int columnIndex) {
-            if (!mBeyondCursor) {
-                return mCursor.getFloat(columnIndex);
-            }
-            if (0 == columnIndex) {
-                return 0f;
-            }
-            return -1f;
-        }
-
-        public double getDouble(int columnIndex) {
-            if (!mBeyondCursor) {
-                return mCursor.getDouble(columnIndex);
-            }
-            if (0 == columnIndex) {
-                return 0.0;
-            }
-            return -1.0;
-        }
-
-        public boolean isNull(int columnIndex) {
-            return mCursor.isNull(columnIndex);
-        }
-
-        public boolean supportsUpdates() {
-            return false;
-        }
-
-        public boolean hasUpdates() {
-            return false;
-        }
-
-        public boolean updateString(int columnIndex, String value) {
-            return false;
-        }
-
-        public boolean updateShort(int columnIndex, short value) {
-            return false;
-        }
-
-        public boolean updateInt(int columnIndex, int value) {
-            return false;
-        }
-
-        public boolean updateLong(int columnIndex, long value) {
-            return false;
-        }
-
-        public boolean updateFloat(int columnIndex, float value) {
-            return false;
-        }
-
-        public boolean updateDouble(int columnIndex, double value) {
-            return false;
+        @Override
+        public boolean isNull(int column) {
+            throw new UnsupportedOperationException();
         }
 
         // TODO Temporary change, finalize after jq's changes go in
         public void deactivate() {
-            if (mCursor != null) {
-                mCursor.deactivate();
+            if (mHistoryCursor != null) {
+                mHistoryCursor.deactivate();
+            }
+            if (mSuggestCursor != null) {
+                mSuggestCursor.deactivate();
             }
             super.deactivate();
         }
 
         public boolean requery() {
-            return mCursor.requery();
+            return (mHistoryCursor != null ? mHistoryCursor.requery() : false) |
+                    (mSuggestCursor != null ? mSuggestCursor.requery() : false);
         }
 
         // TODO Temporary change, finalize after jq's changes go in
         public void close() {
             super.close();
-            if (mCursor != null) {
-                mCursor.close();
-                mCursor = null;
+            if (mHistoryCursor != null) {
+                mHistoryCursor.close();
+                mHistoryCursor = null;
             }
-        }
-
-        public void registerContentObserver(ContentObserver observer) {
-            super.registerContentObserver(observer);
-        }
-
-        public void unregisterContentObserver(ContentObserver observer) {
-            super.unregisterContentObserver(observer);
-        }
-
-        public void registerDataSetObserver(DataSetObserver observer) {
-            super.registerDataSetObserver(observer);
-        }
-
-        public void unregisterDataSetObserver(DataSetObserver observer) {
-            super.unregisterDataSetObserver(observer);
-        }
-
-        protected void onChange(boolean selfChange) {
-            synchronized (mObserverLock) {
-                super.onChange(selfChange);
-                if (mNotifyUri != null && selfChange) {
-                    mContentResolver.notifyChange(mNotifyUri, mObserver);
-                }
+            if (mSuggestCursor != null) {
+                mSuggestCursor.close();
+                mSuggestCursor = null;
             }
         }
-
-        public void setNotificationUri(ContentResolver cr, Uri uri) {
-            synchronized (mObserverLock) {
-                if (mObserver != null) {
-                    cr.unregisterContentObserver(mObserver);
-                }
-                mObserver = new AbstractCursor.SelfContentObserver(this);
-                cr.registerContentObserver(uri, true, mObserver);
-                mCursor.setNotificationUri(cr, uri);
-                super.setNotificationUri(cr, uri);
-                mContentResolver = cr;
-                mNotifyUri = uri;
-            }
-        }
-
-        public boolean getWantsAllOnMoveCalls() {
-            return mCursor.getWantsAllOnMoveCalls();
-        }
     }
 
     @Override
@@ -455,13 +451,58 @@
                     suggestSelection = SUGGEST_SELECTION;
                 }
             }
-            // Suggestions are always performed with the default sort order:
-            // date ASC.
+
             Cursor c = db.query(TABLE_NAMES[URI_MATCH_BOOKMARKS],
                     SUGGEST_PROJECTION, suggestSelection, myArgs, null, null,
-                    ORDER_BY, null);
-            c.setNotificationUri(getContext().getContentResolver(), url);
-            return new MySuggestionCursor(c, selectionArgs[0]);
+                    ORDER_BY,
+                    (new Integer(MAX_SUGGESTION_LONG_ENTRIES)).toString());
+
+            if (Regex.WEB_URL_PATTERN.matcher(selectionArgs[0]).matches()) {
+                return new MySuggestionCursor(c, null, "");
+            } else {
+                // get Google suggest if there is still space in the list
+                if (myArgs != null && myArgs.length > 1
+                        && c.getCount() < (MAX_SUGGESTION_SHORT_ENTRIES - 1)) {
+                    ISearchManager sm = ISearchManager.Stub
+                            .asInterface(ServiceManager
+                                    .getService(Context.SEARCH_SERVICE));
+                    SearchableInfo si = null;
+                    try {
+                        // use the global search to get Google suggest provider
+                        si = sm.getSearchableInfo(new ComponentName(
+                                getContext(), "com.android.browser"), true);
+
+                        // similar to the getSuggestions() in SearchDialog.java
+                        StringBuilder uriStr = new StringBuilder("content://");
+                        uriStr.append(si.getSuggestAuthority());
+                        // if content path provided, insert it now
+                        final String contentPath = si.getSuggestPath();
+                        if (contentPath != null) {
+                            uriStr.append('/');
+                            uriStr.append(contentPath);
+                        }
+                        // append standard suggestion query path 
+                        uriStr.append('/' + SearchManager.SUGGEST_URI_PATH_QUERY);
+                        // inject query, either as selection args or inline
+                        String[] selArgs = null;
+                        if (si.getSuggestSelection() != null) {
+                            selArgs = new String[] {selectionArgs[0]};
+                        } else {
+                            uriStr.append('/');
+                            uriStr.append(Uri.encode(selectionArgs[0]));
+                        }
+
+                        // finally, make the query
+                        Cursor sc = getContext().getContentResolver().query(
+                                Uri.parse(uriStr.toString()), null,
+                                si.getSuggestSelection(), selArgs, null);
+
+                        return new MySuggestionCursor(c, sc, selectionArgs[0]);
+                    } catch (RemoteException e) {
+                    }
+                }
+                return new MySuggestionCursor(c, null, selectionArgs[0]);
+            }
         }
 
         String[] projection = null;
diff --git a/src/com/android/browser/BrowserSettings.java b/src/com/android/browser/BrowserSettings.java
index 6164e38..5038a4e 100644
--- a/src/com/android/browser/BrowserSettings.java
+++ b/src/com/android/browser/BrowserSettings.java
@@ -67,7 +67,6 @@
     private String homeUrl = "http://www.google.com/m?client=ms-" + 
         SystemProperties.get("ro.com.google.clientid", "unknown");
     private boolean loginInitialized = false;
-    private int orientation = ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
     private boolean autoFitPage = true;
     private boolean showDebugSettings = false;
     
@@ -231,7 +230,6 @@
         loginInitialized = p.getBoolean("login_initialized", loginInitialized);
         textSize = WebSettings.TextSize.valueOf(
                 p.getString(PREF_TEXT_SIZE, textSize.name()));
-        orientation = p.getInt("orientation", orientation);
         autoFitPage = p.getBoolean("autofit_pages", autoFitPage);
         useWideViewPort = true; // use wide view port for either setting
         if (autoFitPage) {
@@ -301,22 +299,7 @@
         ed.putBoolean("login_initialized", loginInitialized);
         ed.commit();
     }
-    
-    public int getOrientation() {
-        return orientation;
-    }
-    
-    public void setOrientation(Context context, int o) {
-        if (orientation == o) {
-            return;
-        }
-        orientation = o;
-        Editor ed = PreferenceManager.
-                getDefaultSharedPreferences(context).edit();      
-        ed.putInt("orientation", orientation);
-        ed.commit();
-    }
-    
+
     public WebSettings.TextSize getTextSize() {
         return textSize;
     }
diff --git a/src/com/android/browser/CombinedBookmarkHistoryActivity.java b/src/com/android/browser/CombinedBookmarkHistoryActivity.java
new file mode 100644
index 0000000..963f179
--- /dev/null
+++ b/src/com/android/browser/CombinedBookmarkHistoryActivity.java
@@ -0,0 +1,124 @@
+/*
+ * Copyright (C) 2009 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.browser;
+
+import android.app.Activity;
+import android.app.TabActivity;
+import android.content.ContentResolver;
+import android.content.Intent;
+import android.content.res.Resources;
+import android.graphics.Bitmap;
+import android.os.Bundle;
+import android.provider.Browser;
+import android.webkit.WebIconDatabase.IconListener;
+import android.widget.TabHost;
+import android.widget.TabHost.TabSpec;
+import android.view.Window;
+
+import java.util.HashMap;
+import java.util.Vector;
+
+public class CombinedBookmarkHistoryActivity extends TabActivity
+        implements TabHost.OnTabChangeListener {
+    /* package */ static String BOOKMARKS_TAB = "bookmark";
+    /* package */ static String VISITED_TAB = "visited";
+    /* package */ static String HISTORY_TAB = "history";
+    /* package */ static String STARTING_TAB = "tab";
+
+    static class IconListenerSet implements IconListener {
+        // Used to store favicons as we get them from the database
+        // FIXME: We use a different method to get the Favicons in
+        // BrowserBookmarksAdapter. They should probably be unified.
+        private HashMap<String, Bitmap> mUrlsToIcons;
+        private Vector<IconListener> mListeners;
+
+        public IconListenerSet() {
+            mUrlsToIcons = new HashMap<String, Bitmap>();
+            mListeners = new Vector<IconListener>();
+        }
+        public void onReceivedIcon(String url, Bitmap icon) {
+            mUrlsToIcons.put(url, icon);
+            for (IconListener listener : mListeners) {
+                listener.onReceivedIcon(url, icon);
+            }
+        }
+        public void addListener(IconListener listener) {
+            mListeners.add(listener);
+        }
+        public Bitmap getFavicon(String url) {
+            return (Bitmap) mUrlsToIcons.get(url);
+        }
+    }
+    private static IconListenerSet sIconListenerSet;
+    static IconListenerSet getIconListenerSet(ContentResolver cr) {
+        if (null == sIconListenerSet) {
+            sIconListenerSet = new IconListenerSet();
+            Browser.requestAllIcons(cr, null, sIconListenerSet);
+        }
+        return sIconListenerSet;
+    }
+
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        requestWindowFeature(Window.FEATURE_NO_TITLE);
+        setContentView(R.layout.tabs);
+        TabHost tabHost = getTabHost();
+        tabHost.setOnTabChangedListener(this);
+
+        Bundle extras = getIntent().getExtras();
+        Resources resources = getResources();
+
+        getIconListenerSet(getContentResolver());
+        Intent bookmarksIntent = new Intent(this, BrowserBookmarksPage.class);
+        bookmarksIntent.putExtras(extras);
+        tabHost.addTab(tabHost.newTabSpec(BOOKMARKS_TAB)
+                .setIndicator(resources.getString(R.string.tab_bookmarks),
+                resources.getDrawable(R.drawable.browser_bookmark_tab))
+                .setContent(bookmarksIntent));
+
+        Intent visitedIntent = new Intent(this, MostVisitedActivity.class);
+        visitedIntent.putExtras(extras);
+        tabHost.addTab(tabHost.newTabSpec(VISITED_TAB)
+                .setIndicator(resources.getString(R.string.tab_most_visited),
+                resources.getDrawable(R.drawable.browser_visited_tab))
+                .setContent(visitedIntent));
+
+        Intent historyIntent = new Intent(this, BrowserHistoryPage.class);
+        historyIntent.putExtras(extras);
+        tabHost.addTab(tabHost.newTabSpec(HISTORY_TAB)
+                .setIndicator(resources.getString(R.string.tab_history),
+                resources.getDrawable(R.drawable.
+                browser_history_tab)).setContent(historyIntent));
+
+        String defaultTab = extras.getString(STARTING_TAB);
+        if (defaultTab != null) {
+            tabHost.setCurrentTab(2);
+        }
+    }
+
+    // Copied from DialTacts Activity
+    /** {@inheritDoc} */
+    public void onTabChanged(String tabId) {
+        Activity activity = getLocalActivityManager().getActivity(tabId);
+        if (activity != null) {
+            activity.onWindowFocusChanged(true);
+        }
+    }
+
+    
+}
diff --git a/src/com/android/browser/FindDialog.java b/src/com/android/browser/FindDialog.java
index 2b26784..44109ff 100644
--- a/src/com/android/browser/FindDialog.java
+++ b/src/com/android/browser/FindDialog.java
@@ -29,6 +29,7 @@
 import android.view.View;
 import android.view.ViewGroup;
 import android.view.Window;
+import android.view.WindowManager;
 import android.webkit.WebView;
 import android.widget.EditText;
 import android.widget.TextView;
@@ -121,6 +122,8 @@
         mMatches = (TextView) findViewById(R.id.matches);
         mMatchesView = findViewById(R.id.matches_view);
         disableButtons();
+        theWindow.setSoftInputMode(
+                WindowManager.LayoutParams.SOFT_INPUT_STATE_VISIBLE);
     }
     
     public void dismiss() {
diff --git a/src/com/android/browser/HistoryItem.java b/src/com/android/browser/HistoryItem.java
index c83ced1..55e43f0 100644
--- a/src/com/android/browser/HistoryItem.java
+++ b/src/com/android/browser/HistoryItem.java
@@ -17,26 +17,31 @@
  
 package com.android.browser;
 
+import android.content.ContentResolver;
+import android.content.ContentUris;
+import android.content.ContentValues;
 import android.content.Context;
+import android.database.Cursor;
 import android.graphics.Bitmap;
-import android.graphics.Color;
-import android.graphics.drawable.BitmapDrawable;
-import android.graphics.drawable.Drawable;
-import android.graphics.drawable.LayerDrawable;
-import android.graphics.drawable.PaintDrawable;
-import android.view.LayoutInflater;
-import android.widget.LinearLayout;
+import android.net.Uri;
+import android.provider.Browser;
+import android.util.Log;
+import android.view.View;
+import android.webkit.WebIconDatabase;
+import android.widget.CompoundButton;
+import android.widget.ImageView;
 import android.widget.TextView;
+import android.widget.Toast;
+
+import java.util.Date;
 
 /**
  *  Layout representing a history item in the classic history viewer.
  */
-/* package */ class HistoryItem extends LinearLayout {
+/* package */ class HistoryItem extends BookmarkItem {
 
-    private TextView    mTitleView; // Truncated Title
-    private String      mUrl;       // Full Url
-    private TextView    mUrlText;   // Truncated Url
-    
+    private CompoundButton  mStar;      // Star for bookmarking
+    private CompoundButton.OnCheckedChangeListener  mListener;
     /**
      *  Create a new HistoryItem.
      *  @param context  Context for this HistoryItem.
@@ -44,83 +49,79 @@
     /* package */ HistoryItem(Context context) {
         super(context);
 
-        setWillNotDraw(false);
-        LayoutInflater factory = LayoutInflater.from(context);
-        factory.inflate(R.layout.history_item, this);
-        mTitleView = (TextView) findViewById(R.id.title);
-        mUrlText = (TextView) findViewById(R.id.url);
+        mStar = (CompoundButton) findViewById(R.id.star);
+        mStar.setVisibility(View.VISIBLE);
+        mListener = new CompoundButton.OnCheckedChangeListener() {
+            public void onCheckedChanged(CompoundButton buttonView,
+                    boolean isChecked) {
+                ContentResolver cr = mContext.getContentResolver();
+                Cursor cursor = cr.query(
+                        Browser.BOOKMARKS_URI,
+                        Browser.HISTORY_PROJECTION,
+                        "url = ?",
+                        new String[] { mUrl },
+                        null);
+                boolean first = cursor.moveToFirst();
+                // Should be in the database no matter what
+                if (!first) {
+                    throw new AssertionError("URL is not in the database!");
+                }
+                if (isChecked) {
+                    // Add to bookmarks
+                    // FIXME: Share code with AddBookmarkPage.java
+                    ContentValues map = new ContentValues();
+                    map.put(Browser.BookmarkColumns.CREATED,
+                            new Date().getTime());
+                    map.put(Browser.BookmarkColumns.TITLE, getName());
+                    map.put(Browser.BookmarkColumns.BOOKMARK, 1);
+                    try {
+                        cr.update(Browser.BOOKMARKS_URI, map, 
+                                "_id = " + cursor.getInt(0), null);
+                    } catch (IllegalStateException e) {
+                        Log.e("HistoryItem", "no database!");
+                    }
+                    WebIconDatabase.getInstance().retainIconForPageUrl(mUrl);
+                    // catch IllegalStateException?
+                    Toast.makeText(mContext, R.string.added_to_bookmarks,
+                            Toast.LENGTH_LONG).show();
+                } else {
+                    // Remove from bookmarks
+                    // FIXME: This code should be shared with
+                    // BrowserBookmarksAdapter.java
+                    WebIconDatabase.getInstance().releaseIconForPageUrl(mUrl);
+                    Uri uri = ContentUris.withAppendedId(Browser.BOOKMARKS_URI,
+                            cursor.getInt(Browser.HISTORY_PROJECTION_ID_INDEX));
+                    // It is no longer a bookmark, but it is still a visited
+                    // site.
+                    ContentValues values = new ContentValues();
+                    values.put(Browser.BookmarkColumns.BOOKMARK, 0);
+                    try {
+                        cr.update(uri, values, null, null);
+                    } catch (IllegalStateException e) {
+                        Log.e("HistoryItem", "no database!");
+                    }
+                    Toast.makeText(mContext, R.string.removed_from_bookmarks,
+                            Toast.LENGTH_LONG).show();
+                }
+                cursor.deactivate();
+            }
+        };
     }
     
     void copyTo(HistoryItem item) {
-        item.mTitleView.setText(mTitleView.getText());
+        item.mTextView.setText(mTextView.getText());
         item.mUrlText.setText(mUrlText.getText());
-    }
-    
-    /**
-     * Return the name of this HistoryItem.
-     * @return  String name of this HistoryItem.
-     /
-    /* package */ String getName() {
-        return mTitleView.getText().toString();
+        item.setIsBookmark(mStar.isChecked());
+        item.mImageView.setImageDrawable(mImageView.getDrawable());
     }
 
     /**
-     * Return the url of this HistoryItem.
-     * @return  String url of this HistoryItem.
-     /
-    /* package */ String getUrl() {
-        return mUrl;
-    }
-
-    /**
-     *  Set the favicon for this item.
-     *
-     *  @param b    The new bitmap for this item.
-     *              If it is null, will use the default.
+     *  Set whether or not this represents a bookmark, and make sure the star
+     *  behaves appropriately.
      */
-    /* package */ void setFavicon(Bitmap b) {
-        Drawable[] array = new Drawable[2];
-        PaintDrawable p = new PaintDrawable(Color.WHITE);
-        p.setCornerRadius(3f);
-        array[0] = p;
-        if (b != null) {
-            array[1] = new BitmapDrawable(b);
-        } else {
-            array[1] = new BitmapDrawable(mContext.getResources().
-                    openRawResource(R.drawable.app_web_browser_sm));
-        }
-        LayerDrawable d = new LayerDrawable(array);
-        d.setLayerInset(1, 2, 2, 2, 2);
-        d.setBounds(0, 0, 20, 20);
-        mTitleView.setCompoundDrawables(d, null, null, null);
-    }
-    
-    /**
-     *  Set the name for this HistoryItem.
-     *  If the name is longer that BrowserSettings.MAX_TEXTVIEW_LEN characters, 
-     *  the name is truncated to BrowserSettings.MAX_TEXTVIEW_LEN characters. 
-     *  The History activity does not expose a UI element that can show the 
-     *  full title.
-     *  @param  name String representing new name for this HistoryItem.
-     */
-    /* package */ void setName(String name) {
-        if (name != null && name.length() > BrowserSettings.MAX_TEXTVIEW_LEN) {
-            name = name.substring(0, BrowserSettings.MAX_TEXTVIEW_LEN);
-        }
-        mTitleView.setText(name);
-    }
-    
-    /**
-     *  Set the url for this HistoryItem.
-     *  @param  url String representing new url for this HistoryItem.
-     */
-    /* package */ void setUrl(String url) {
-        mUrl = url;
-        // Truncate the url for the screen
-        if (url.length() > BrowserSettings.MAX_TEXTVIEW_LEN) {
-            mUrlText.setText(url.substring(0, BrowserSettings.MAX_TEXTVIEW_LEN));
-        } else {
-            mUrlText.setText(url);
-        }
+    void setIsBookmark(boolean isBookmark) {
+        mStar.setOnCheckedChangeListener(null);
+        mStar.setChecked(isBookmark);
+        mStar.setOnCheckedChangeListener(mListener);
     }
 }
diff --git a/src/com/android/browser/MostVisitedActivity.java b/src/com/android/browser/MostVisitedActivity.java
new file mode 100644
index 0000000..aeaf2a6
--- /dev/null
+++ b/src/com/android/browser/MostVisitedActivity.java
@@ -0,0 +1,191 @@
+/*
+ * Copyright (C) 2009 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.browser;
+
+import android.app.Activity;
+import android.app.ListActivity;
+import android.content.Intent;
+import android.database.ContentObserver;
+import android.database.Cursor;
+import android.database.DataSetObserver;
+import android.graphics.Bitmap;
+import android.os.Bundle;
+import android.os.Handler;
+import android.provider.Browser;
+import android.webkit.WebIconDatabase.IconListener;
+import android.widget.ListAdapter;
+import android.widget.ListView;
+import android.widget.SimpleCursorAdapter;
+import android.widget.TextView;
+import android.view.View;
+import android.view.ViewGroup;
+
+import java.util.Vector;
+
+public class MostVisitedActivity extends ListActivity {
+
+    private MyAdapter   mAdapter;
+
+    @Override
+    public void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        mAdapter = new MyAdapter();
+        CombinedBookmarkHistoryActivity.getIconListenerSet(getContentResolver())
+                .addListener(new IconReceiver());
+        setListAdapter(mAdapter);
+    }
+
+    private class IconReceiver implements IconListener {
+        public void onReceivedIcon(String url, Bitmap icon) {
+            setListAdapter(mAdapter);
+        }
+    }
+
+    protected void onListItemClick(ListView l, View v, int position, long id) {
+        TextView tv = (TextView) v.findViewById(R.id.url);
+        String url = tv.getText().toString();
+        loadUrl(url, false);
+    }
+
+    private void loadUrl(String url, boolean newWindow) {
+        Intent intent = new Intent().setAction(url);
+        if (newWindow) {
+            Bundle b = new Bundle();
+            b.putBoolean("new_window", true);
+            intent.putExtras(b);
+        }
+        setResultToParent(RESULT_OK, intent);
+        finish();
+    }
+
+    private class MyAdapter implements ListAdapter {
+        private Vector<DataSetObserver> mObservers;
+        private Cursor mCursor;
+        // These correspond with projection below.
+        private final int mUrlIndex = 0;
+        private final int mTitleIndex = 1;
+        private final int mBookmarkIndex = 2;
+
+        MyAdapter() {
+            mObservers = new Vector<DataSetObserver>();
+            String[] projection = new String[] {
+                    Browser.BookmarkColumns.URL,
+                    Browser.BookmarkColumns.TITLE,
+                    Browser.BookmarkColumns.BOOKMARK };
+            String whereClause = Browser.BookmarkColumns.VISITS + " != 0";
+            String orderBy = Browser.BookmarkColumns.VISITS + " DESC";
+            mCursor = managedQuery(Browser.BOOKMARKS_URI, projection,
+                    whereClause, null, orderBy);
+            mCursor.registerContentObserver(new ChangeObserver());
+        }
+
+        private class ChangeObserver extends ContentObserver {
+            public ChangeObserver() {
+                super(new Handler());
+            }
+
+            @Override
+            public boolean deliverSelfNotifications() {
+                return true;
+            }
+
+            @Override
+            public void onChange(boolean selfChange) {
+                MyAdapter.this.refreshData();
+            }
+        }
+
+        void refreshData() {
+            mCursor.requery();
+            for (DataSetObserver o : mObservers) {
+                o.onChanged();
+            }
+        }
+
+        public View getView(int position, View convertView, ViewGroup parent) {
+            HistoryItem item;
+            if (null == convertView) {
+                item = new HistoryItem(MostVisitedActivity.this);
+            } else {
+                item = (HistoryItem) convertView;
+            }
+            mCursor.moveToPosition(position);
+            item.setName(mCursor.getString(mTitleIndex));
+            String url = mCursor.getString(mUrlIndex);
+            item.setUrl(url);
+            item.setFavicon(CombinedBookmarkHistoryActivity.getIconListenerSet(
+                    getContentResolver()).getFavicon(url));
+            item.setIsBookmark(1 == mCursor.getInt(mBookmarkIndex));
+            return item;
+        }
+
+        public boolean areAllItemsEnabled() {
+            return true;
+        }
+
+        public boolean isEnabled(int position) {
+            return true;
+        }
+
+        public int getCount() {
+            return mCursor.getCount();
+        }
+
+        public Object getItem(int position) {
+            return null;
+        }
+
+        public long getItemId(int position) {
+            return position;
+        }
+
+        // Always a HistoryItem
+        public int getItemViewType(int position) {
+            return 0;
+        }
+
+        public int getViewTypeCount() {
+            return 1;
+        }
+
+        public boolean hasStableIds() {
+            return true;
+        }
+
+        public void registerDataSetObserver(DataSetObserver observer) {
+            mObservers.add(observer);
+        }
+
+        public void unregisterDataSetObserver(DataSetObserver observer) {
+            mObservers.remove(observer);
+        }
+
+        public boolean isEmpty() {
+            return getCount() == 0;
+        }
+    }
+
+    // This Activity is generally a sub-Activity of CombinedHistoryActivity. In
+    // that situation, we need to pass our result code up to our parent.
+    // However, if someone calls this Activity directly, then this has no
+    // parent, and it needs to set it on itself.
+    private void setResultToParent(int resultCode, Intent data) {
+        Activity a = getParent() == null ? this : getParent();
+        a.setResult(resultCode, data);
+    }
+}
+
diff --git a/src/com/android/browser/TabControl.java b/src/com/android/browser/TabControl.java
index dfac185..69610bf 100644
--- a/src/com/android/browser/TabControl.java
+++ b/src/com/android/browser/TabControl.java
@@ -17,7 +17,9 @@
 package com.android.browser;
 
 import android.content.Context;
+import android.net.http.SslError;
 import android.os.Bundle;
+import android.os.Message;
 import android.util.Config;
 import android.util.Log;
 import android.view.Gravity;
@@ -25,8 +27,10 @@
 import android.view.View;
 import android.view.ViewGroup;
 import android.view.View.OnClickListener;
+import android.webkit.HttpAuthHandler;
 import android.webkit.JsPromptResult;
 import android.webkit.JsResult;
+import android.webkit.SslErrorHandler;
 import android.webkit.WebBackForwardList;
 import android.webkit.WebChromeClient;
 import android.webkit.WebHistoryItem;
@@ -79,6 +83,26 @@
         public boolean shouldOverrideUrlLoading(WebView view, String url) {
             return mClient.shouldOverrideUrlLoading(view, url);
         }
+        @Override
+        public void onReceivedSslError(WebView view, SslErrorHandler handler,
+                SslError error) {
+            mClient.onReceivedSslError(view, handler, error);
+        }
+        @Override
+        public void onReceivedHttpAuthRequest(WebView view,
+                HttpAuthHandler handler, String host, String realm) {
+            mClient.onReceivedHttpAuthRequest(view, handler, host, realm);
+        }
+        @Override
+        public void onFormResubmission(WebView view, Message dontResend,
+                Message resend) {
+            mClient.onFormResubmission(view, dontResend, resend);
+        }
+        @Override
+        public void onReceivedError(WebView view, int errorCode,
+                String description, String failingUrl) {
+            mClient.onReceivedError(view, errorCode, description, failingUrl);
+        }
     }
     // Subclass of WebChromeClient to display javascript dialogs.
     private class SubWindowChromeClient extends WebChromeClient {