Merge "Menu shuffling"
diff --git a/Android.mk b/Android.mk
index b85a869..06b02d6 100644
--- a/Android.mk
+++ b/Android.mk
@@ -5,7 +5,9 @@
 
 LOCAL_STATIC_JAVA_LIBRARIES := \
         android-common \
-        guava
+        guava \
+        android-support-v13 \
+        android-support-v4 \
 
 LOCAL_SRC_FILES := \
         $(call all-java-files-under, src) \
diff --git a/AndroidManifest.xml b/AndroidManifest.xml
index 9a8a73b..e21c539 100644
--- a/AndroidManifest.xml
+++ b/AndroidManifest.xml
@@ -192,8 +192,7 @@
             </intent-filter>
         </activity>
 
-        <activity android:name="ComboViewActivity"
-                  android:configChanges="orientation|keyboardHidden|keyboard|screenSize">
+        <activity android:name="ComboViewActivity">
         </activity>
 
         <!-- Bookmark thumbnail homescreen widget -->
diff --git a/res/layout-sw600dp/title_bar_nav.xml b/res/layout-sw600dp/title_bar_nav.xml
index 37bea35..3ef6d35 100644
--- a/res/layout-sw600dp/title_bar_nav.xml
+++ b/res/layout-sw600dp/title_bar_nav.xml
@@ -58,11 +58,12 @@
         android:background="@drawable/url_background">
         <ImageView
             android:id="@+id/url_icon"
-            android:layout_width="wrap_content"
+            android:layout_width="48dp"
             android:layout_height="match_parent"
             android:src="@drawable/ic_web_holo_dark"
             android:contentDescription="@string/accessibility_button_uaswitch"
-            style="@style/HoloIcon" />
+            android:scaleType="center"
+            style="@style/HoloButton" />
         <ImageView
             android:id="@+id/lock"
             android:layout_width="wrap_content"
@@ -74,7 +75,6 @@
             android:layout_width="0dip"
             android:layout_weight="1.0"
             android:layout_height="match_parent"
-            android:layout_marginLeft="16dip"
             android:paddingLeft="0dip"
             android:paddingRight="0dip"
             android:background="@null"
diff --git a/res/layout/bookmarks.xml b/res/layout/bookmarks.xml
index e02e2ff..09b442e 100644
--- a/res/layout/bookmarks.xml
+++ b/res/layout/bookmarks.xml
@@ -14,39 +14,25 @@
      limitations under the License.
 -->
 
-<LinearLayout
+<FrameLayout
     xmlns:android="http://schemas.android.com/apk/res/android"
-    android:id="@+id/bookmarks"
     android:layout_width="match_parent"
     android:layout_height="match_parent"
-    android:orientation="vertical"
     android:paddingTop="@dimen/combo_paddingTop">
-
-    <FrameLayout
-        android:id="@+id/header_container"
+    <com.android.browser.view.BookmarkExpandableView
+        android:id="@+id/grid"
         android:layout_width="match_parent"
+        android:layout_height="match_parent"
+        android:layout_gravity="center_horizontal"
+        android:childDivider="@android:color/transparent"
+        android:divider="@android:color/transparent"
+        android:dividerHeight="0dp" />
+    <TextView
+        android:id="@android:id/empty"
+        android:layout_width="wrap_content"
         android:layout_height="wrap_content"
+        android:layout_gravity="center"
+        android:textAppearance="?android:attr/textAppearanceLarge"
+        android:text="@string/empty_bookmarks_folder"
         android:visibility="gone" />
-
-    <FrameLayout
-        android:layout_width="match_parent"
-        android:layout_height="match_parent">
-        <com.android.browser.view.BookmarkExpandableView
-            android:id="@+id/grid"
-            android:layout_width="match_parent"
-            android:layout_height="match_parent"
-            android:layout_gravity="center_horizontal"
-            android:childDivider="@android:color/transparent"
-            android:divider="@android:color/transparent"
-            android:dividerHeight="0dp" />
-        <TextView
-            android:id="@android:id/empty"
-            android:layout_width="wrap_content"
-            android:layout_height="wrap_content"
-            android:layout_gravity="center"
-            android:textAppearance="?android:attr/textAppearanceLarge"
-            android:text="@string/empty_bookmarks_folder"
-            android:visibility="gone" />
-    </FrameLayout>
-
-</LinearLayout>
+</FrameLayout>
diff --git a/res/values-w720dp/dimensions.xml b/res/values-w720dp/dimensions.xml
index dcb5927..9fe5c68 100644
--- a/res/values-w720dp/dimensions.xml
+++ b/res/values-w720dp/dimensions.xml
@@ -13,7 +13,5 @@
 <resources
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <!-- The width of a selected tab -->
-    <dimen name="tab_width_selected">280dp</dimen>
-    <!-- The width of an unselected tab -->
-    <dimen name="tab_width_unselected">240dp</dimen>
+    <dimen name="tab_width">240dp</dimen>
 </resources>
diff --git a/res/values/dimensions.xml b/res/values/dimensions.xml
index 8fca68a..3d3d7ce 100644
--- a/res/values/dimensions.xml
+++ b/res/values/dimensions.xml
@@ -12,10 +12,7 @@
 -->
 <resources
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <!-- The width of a selected tab -->
-    <dimen name="tab_width_selected">200dp</dimen>
-    <!-- The width of an unselected tab -->
-    <dimen name="tab_width_unselected">160dp</dimen>
+    <dimen name="tab_width">180dp</dimen>
     <dimen name="tab_height">44dp</dimen>
     <dimen name="tab_overlap">8dp</dimen>
     <dimen name="tab_addoverlap">14dp</dimen>
@@ -54,7 +51,7 @@
     <dimen name="widgetHorizontalSpacing">14dip</dimen>
     <dimen name="widgetVerticalSpacing">12dip</dimen>
     <!-- For the combined Bookmarks History view -->
-    <dimen name="combo_paddingTop">10dip</dimen>
+    <dimen name="combo_paddingTop">0dip</dimen>
     <dimen name="combo_horizontalSpacing">6dip</dimen>
     <dimen name="tab_view_thumbnail_height">76dip</dimen>
     <!-- Preference activity side margins -->
diff --git a/src/com/android/browser/AutoFillSettingsFragment.java b/src/com/android/browser/AutoFillSettingsFragment.java
index 141de34..04f45b5 100644
--- a/src/com/android/browser/AutoFillSettingsFragment.java
+++ b/src/com/android/browser/AutoFillSettingsFragment.java
@@ -116,16 +116,21 @@
         mHandler = new Handler() {
             @Override
             public void handleMessage(Message msg) {
+                Context c = getActivity();
                 switch (msg.what) {
                 case PROFILE_SAVED_MSG:
-                    Toast.makeText(getActivity(), R.string.autofill_profile_successful_save,
-                            Toast.LENGTH_SHORT).show();
-                    closeEditor();
+                    if (c != null) {
+                        Toast.makeText(c, R.string.autofill_profile_successful_save,
+                                Toast.LENGTH_SHORT).show();
+                        closeEditor();
+                    }
                     break;
 
                 case PROFILE_DELETED_MSG:
-                    Toast.makeText(getActivity(), R.string.autofill_profile_successful_delete,
-                            Toast.LENGTH_SHORT).show();
+                    if (c != null) {
+                        Toast.makeText(c, R.string.autofill_profile_successful_delete,
+                                Toast.LENGTH_SHORT).show();
+                    }
                     break;
                 }
             }
diff --git a/src/com/android/browser/BrowserBookmarksPage.java b/src/com/android/browser/BrowserBookmarksPage.java
index a03590b..46521cb 100644
--- a/src/com/android/browser/BrowserBookmarksPage.java
+++ b/src/com/android/browser/BrowserBookmarksPage.java
@@ -101,14 +101,6 @@
     HashMap<Integer, BrowserBookmarksAdapter> mBookmarkAdapters = new HashMap<Integer, BrowserBookmarksAdapter>();
     BookmarkDragHandler mDragHandler;
 
-    static BrowserBookmarksPage newInstance(BookmarksPageCallbacks cb,
-            Bundle args, ViewGroup headerContainer) {
-        BrowserBookmarksPage bbp = new BrowserBookmarksPage();
-        bbp.mCallbacks = cb;
-        bbp.setArguments(args);
-        return bbp;
-    }
-
     @Override
     public Loader<Cursor> onCreateLoader(int id, Bundle args) {
         if (id == LOADER_ACCOUNTS) {
@@ -295,9 +287,6 @@
             String url = cursor.getString(BookmarksLoader.COLUMN_INDEX_URL);
             item.setUrl(url);
             Bitmap bitmap = getBitmap(cursor, BookmarksLoader.COLUMN_INDEX_FAVICON);
-            if (bitmap == null) {
-                bitmap = CombinedBookmarkHistoryView.getIconListenerSet().getFavicon(url);
-            }
             item.setFavicon(bitmap);
         }
     }
@@ -311,8 +300,37 @@
         Bundle args = getArguments();
         mDisableNewWindow = args == null ? false : args.getBoolean(EXTRA_DISABLE_WINDOW, false);
         setHasOptionsMenu(true);
+        if (mCallbacks == null && getActivity() instanceof CombinedBookmarksCallbacks) {
+            mCallbacks = new CombinedBookmarksCallbackWrapper(
+                    (CombinedBookmarksCallbacks) getActivity());
+        }
     }
 
+    private static class CombinedBookmarksCallbackWrapper
+            implements BookmarksPageCallbacks {
+
+        private CombinedBookmarksCallbacks mCombinedCallback;
+
+        private CombinedBookmarksCallbackWrapper(CombinedBookmarksCallbacks cb) {
+            mCombinedCallback = cb;
+        }
+
+        @Override
+        public boolean onOpenInNewWindow(String... urls) {
+            mCombinedCallback.openInNewTab(urls);
+            return true;
+        }
+
+        @Override
+        public boolean onBookmarkSelected(Cursor c, boolean isFolder) {
+            if (isFolder) {
+                return false;
+            }
+            mCombinedCallback.openUrl(BrowserBookmarksPage.getUrl(c));
+            return true;
+        }
+    };
+
     @Override
     public View onCreateView(LayoutInflater inflater, ViewGroup container,
             Bundle savedInstanceState) {
@@ -520,10 +538,6 @@
         loader.forceLoad();
     }
 
-    public boolean onBackPressed() {
-        return false;
-    }
-
     public void setCallbackListener(BookmarksPageCallbacks callbackListener) {
         mCallbacks = callbackListener;
     }
diff --git a/src/com/android/browser/BrowserHistoryPage.java b/src/com/android/browser/BrowserHistoryPage.java
index 942a8fd..6625e55 100644
--- a/src/com/android/browser/BrowserHistoryPage.java
+++ b/src/com/android/browser/BrowserHistoryPage.java
@@ -61,8 +61,6 @@
 import android.widget.TextView;
 import android.widget.Toast;
 
-import com.android.browser.CombinedBookmarkHistoryView.CombinedBookmarksCallbacks;
-
 /**
  * Activity for displaying the browser's history, divided into
  * days of viewing.
@@ -112,13 +110,6 @@
         cm.setText(text);
     }
 
-    static BrowserHistoryPage newInstance(CombinedBookmarksCallbacks cb, Bundle args) {
-        BrowserHistoryPage bhp = new BrowserHistoryPage();
-        bhp.mCallback = cb;
-        bhp.setArguments(args);
-        return bhp;
-    }
-
     @Override
     public Loader<Cursor> onCreateLoader(int id, Bundle args) {
         Uri.Builder combinedBuilder = Combined.CONTENT_URI.buildUpon();
@@ -208,6 +199,7 @@
         mDisableNewWindow = args.getBoolean(BrowserBookmarksPage.EXTRA_DISABLE_WINDOW, false);
         int mvlimit = getResources().getInteger(R.integer.most_visits_limit);
         mMostVisitsLimit = Integer.toString(mvlimit);
+        mCallback = (CombinedBookmarksCallbacks) getActivity();
     }
 
     @Override
@@ -663,9 +655,6 @@
             if (data != null) {
                 item.setFavicon(BitmapFactory.decodeByteArray(data, 0,
                         data.length));
-            } else {
-                item.setFavicon(CombinedBookmarkHistoryView
-                        .getIconListenerSet().getFavicon(url));
             }
             item.setIsBookmark(cursor.getInt(HistoryQuery.INDEX_IS_BOOKMARK) == 1);
             return item;
diff --git a/src/com/android/browser/BrowserSnapshotPage.java b/src/com/android/browser/BrowserSnapshotPage.java
index 0953879..72aa1b9 100644
--- a/src/com/android/browser/BrowserSnapshotPage.java
+++ b/src/com/android/browser/BrowserSnapshotPage.java
@@ -43,7 +43,6 @@
 import android.widget.ResourceCursorAdapter;
 import android.widget.TextView;
 
-import com.android.browser.CombinedBookmarkHistoryView.CombinedBookmarksCallbacks;
 import com.android.browser.provider.SnapshotProvider.Snapshots;
 
 import java.text.DateFormat;
@@ -76,12 +75,10 @@
     SnapshotAdapter mAdapter;
     CombinedBookmarksCallbacks mCallback;
 
-    public static BrowserSnapshotPage newInstance(CombinedBookmarksCallbacks cb,
-            Bundle extras) {
-        BrowserSnapshotPage instance = new BrowserSnapshotPage();
-        instance.mCallback = cb;
-        instance.setArguments(extras);
-        return instance;
+    @Override
+    public void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        mCallback = (CombinedBookmarksCallbacks) getActivity();
     }
 
     @Override
diff --git a/src/com/android/browser/CombinedBookmarkHistoryView.java b/src/com/android/browser/CombinedBookmarkHistoryView.java
deleted file mode 100644
index 86afe1e..0000000
--- a/src/com/android/browser/CombinedBookmarkHistoryView.java
+++ /dev/null
@@ -1,297 +0,0 @@
-/*
- * 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.ActionBar;
-import android.app.ActionBar.Tab;
-import android.app.ActionBar.TabListener;
-import android.app.Activity;
-import android.app.FragmentManager;
-import android.app.FragmentTransaction;
-import android.content.res.Configuration;
-import android.database.Cursor;
-import android.graphics.Bitmap;
-import android.os.Bundle;
-import android.view.Gravity;
-import android.view.LayoutInflater;
-import android.view.MotionEvent;
-import android.view.View;
-import android.view.View.OnTouchListener;
-import android.view.ViewGroup;
-import android.webkit.WebIconDatabase.IconListener;
-import android.widget.FrameLayout;
-import android.widget.LinearLayout;
-
-import com.android.browser.UI.ComboViews;
-
-import java.util.HashMap;
-import java.util.Vector;
-
-public class CombinedBookmarkHistoryView extends LinearLayout
-        implements OnTouchListener, TabListener {
-
-    final static String STARTING_FRAGMENT = "fragment";
-
-    final static int INVALID_ID = 0;
-    final static int FRAGMENT_ID_BOOKMARKS = 1;
-    final static int FRAGMENT_ID_HISTORY = 2;
-    final static int FRAGMENT_ID_SNAPSHOTS = 3;
-
-    private ActionBar mActionBar;
-    private FragmentManager mFragmentManager;
-
-    private Bundle mExtras;
-
-    int mCurrentFragment = INVALID_ID;
-
-    ActionBar.Tab mTabBookmarks;
-    ActionBar.Tab mTabHistory;
-    ActionBar.Tab mTabSnapshots;
-    ViewGroup mBookmarksHeader;
-
-    BrowserBookmarksPage mBookmarks;
-    BrowserHistoryPage mHistory;
-    BrowserSnapshotPage mSnapshots;
-    CombinedBookmarksCallbacks mCallback;
-
-    public static interface CombinedBookmarksCallbacks {
-        void openUrl(String url);
-        void openInNewTab(String... urls);
-        void openSnapshot(long id);
-        void close();
-    }
-
-    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>();
-        }
-        @Override
-        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 void removeListener(IconListener listener) {
-            mListeners.remove(listener);
-        }
-        public Bitmap getFavicon(String url) {
-            return mUrlsToIcons.get(url);
-        }
-    }
-
-    private static IconListenerSet sIconListenerSet;
-    static IconListenerSet getIconListenerSet() {
-        if (null == sIconListenerSet) {
-            sIconListenerSet = new IconListenerSet();
-        }
-        return sIconListenerSet;
-    }
-
-    public CombinedBookmarkHistoryView(Activity activity,
-            CombinedBookmarksCallbacks cb, ComboViews startingView,
-            Bundle extras) {
-        super(activity);
-        mExtras = extras;
-        mActionBar = activity.getActionBar();
-        mCallback = cb;
-        mFragmentManager = activity.getFragmentManager();
-
-        View v = LayoutInflater.from(activity).inflate(R.layout.bookmarks_history, this);
-        v.setOnTouchListener(this);
-
-        mBookmarksHeader = new FrameLayout(activity);
-        mBookmarksHeader.setLayoutParams(new FrameLayout.LayoutParams(
-                FrameLayout.LayoutParams.WRAP_CONTENT,
-                FrameLayout.LayoutParams.MATCH_PARENT,
-                Gravity.CENTER_VERTICAL));
-
-        // Start up the default fragment
-        initFragments(mExtras);
-
-        setupActionBar(startingView);
-    }
-
-    void setupActionBar(ComboViews startingView) {
-        if (BrowserActivity.isTablet(mContext)) {
-            mActionBar.setDisplayOptions(ActionBar.DISPLAY_SHOW_HOME
-                    | ActionBar.DISPLAY_USE_LOGO);
-        } else {
-            mActionBar.setDisplayOptions(0);
-        }
-        mActionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_TABS);
-        mActionBar.removeAllTabs();
-        mTabBookmarks = mActionBar.newTab();
-        mTabBookmarks.setText(R.string.tab_bookmarks);
-        mTabBookmarks.setTabListener(this);
-        mActionBar.addTab(mTabBookmarks, ComboViews.Bookmarks == startingView);
-        mTabHistory = mActionBar.newTab();
-        mTabHistory.setText(R.string.tab_history);
-        mTabHistory.setTabListener(this);
-        mActionBar.addTab(mTabHistory, ComboViews.History == startingView);
-        mTabSnapshots = mActionBar.newTab();
-        mTabSnapshots.setText(R.string.tab_snapshots);
-        mTabSnapshots.setTabListener(this);
-        mActionBar.addTab(mTabSnapshots, ComboViews.Snapshots == startingView);
-        mActionBar.setCustomView(mBookmarksHeader);
-        mActionBar.show();
-    }
-
-    void tearDownActionBar() {
-        if (mActionBar != null) {
-            mActionBar.removeAllTabs();
-            mTabBookmarks.setTabListener(null);
-            mTabHistory.setTabListener(null);
-            mTabSnapshots.setTabListener(null);
-            mTabBookmarks = null;
-            mTabHistory = null;
-            mTabSnapshots = null;
-            mActionBar = null;
-        }
-    }
-
-    @Override
-    protected void onConfigurationChanged(Configuration newConfig) {
-        super.onConfigurationChanged(newConfig);
-        if (mCurrentFragment == FRAGMENT_ID_HISTORY) {
-            // Warning, ugly hack below
-            // This is done because history uses orientation-specific padding
-            mHistory = BrowserHistoryPage.newInstance(mCallback, mHistory.getArguments());
-            mFragmentManager.beginTransaction().replace(R.id.fragment, mHistory).commit();
-        }
-    }
-
-    private BookmarksPageCallbacks mBookmarkCallbackWrapper = new BookmarksPageCallbacks() {
-        @Override
-        public boolean onOpenInNewWindow(String... urls) {
-            mCallback.openInNewTab(urls);
-            return true;
-        }
-
-        @Override
-        public boolean onBookmarkSelected(Cursor c, boolean isFolder) {
-            if (isFolder) {
-                return false;
-            }
-            mCallback.openUrl(BrowserBookmarksPage.getUrl(c));
-            return true;
-        }
-    };
-
-    private void initFragments(Bundle extras) {
-        mBookmarks = BrowserBookmarksPage.newInstance(mBookmarkCallbackWrapper,
-                extras, mBookmarksHeader);
-        mHistory = BrowserHistoryPage.newInstance(mCallback, extras);
-        mSnapshots = BrowserSnapshotPage.newInstance(mCallback, extras);
-    }
-
-    private void loadFragment(int id, FragmentTransaction ft) {
-        if (mCurrentFragment == id) return;
-
-        switch (id) {
-            case FRAGMENT_ID_BOOKMARKS:
-                ft.replace(R.id.fragment, mBookmarks);
-                break;
-            case FRAGMENT_ID_HISTORY:
-                ft.replace(R.id.fragment, mHistory);
-                break;
-            case FRAGMENT_ID_SNAPSHOTS:
-                ft.replace(R.id.fragment, mSnapshots);
-                break;
-            default:
-                throw new IllegalArgumentException();
-        }
-        mCurrentFragment = id;
-    }
-
-    @Override
-    protected void onDetachedFromWindow() {
-        super.onDetachedFromWindow();
-        tearDownActionBar();
-        if (mCurrentFragment != INVALID_ID) {
-            try {
-                FragmentTransaction transaction = mFragmentManager.beginTransaction();
-                if (mCurrentFragment == FRAGMENT_ID_BOOKMARKS) {
-                    transaction.remove(mBookmarks);
-                } else if (mCurrentFragment == FRAGMENT_ID_HISTORY) {
-                    transaction.remove(mHistory);
-                } else if (mCurrentFragment == FRAGMENT_ID_SNAPSHOTS) {
-                    transaction.remove(mSnapshots);
-                }
-                transaction.commit();
-            } catch (IllegalStateException ex) {
-                // This exception is thrown if the fragment isn't added
-                // This will happen if the activity is finishing, and the
-                // fragment was already removed before this view was detached
-                // Aka, success!
-            }
-            mCurrentFragment = INVALID_ID;
-        }
-    }
-
-    /**
-     * callback for back key presses
-     */
-    boolean onBackPressed() {
-        if (mCurrentFragment == FRAGMENT_ID_BOOKMARKS) {
-            return mBookmarks.onBackPressed();
-        }
-        return false;
-    }
-
-    /**
-     * capture touch events to prevent them from going to the underlying
-     * WebView
-     */
-    @Override
-    public boolean onTouch(View v, MotionEvent event) {
-        return true;
-    }
-
-    @Override
-    public void onTabReselected(Tab tab, FragmentTransaction ft) {
-        // Ignore
-    }
-
-    @Override
-    public void onTabSelected(Tab tab, FragmentTransaction ft) {
-        if (tab == mTabBookmarks) {
-            loadFragment(FRAGMENT_ID_BOOKMARKS, ft);
-        } else if (tab == mTabHistory) {
-            loadFragment(FRAGMENT_ID_HISTORY, ft);
-        } else if (tab == mTabSnapshots) {
-            loadFragment(FRAGMENT_ID_SNAPSHOTS, ft);
-        }
-    }
-
-    @Override
-    public void onTabUnselected(Tab tab, FragmentTransaction ft) {
-        // Ignore
-    }
-
-}
diff --git a/src/com/android/browser/CombinedBookmarksCallbacks.java b/src/com/android/browser/CombinedBookmarksCallbacks.java
new file mode 100644
index 0000000..cdffb6b
--- /dev/null
+++ b/src/com/android/browser/CombinedBookmarksCallbacks.java
@@ -0,0 +1,23 @@
+/*
+ * Copyright (C) 2011 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;
+
+public interface CombinedBookmarksCallbacks {
+    void openUrl(String url);
+    void openInNewTab(String... urls);
+    void openSnapshot(long id);
+    void close();
+}
\ No newline at end of file
diff --git a/src/com/android/browser/ComboViewActivity.java b/src/com/android/browser/ComboViewActivity.java
index cea1884..9bdce18 100644
--- a/src/com/android/browser/ComboViewActivity.java
+++ b/src/com/android/browser/ComboViewActivity.java
@@ -15,18 +15,26 @@
  */
 package com.android.browser;
 
+import android.app.ActionBar;
 import android.app.Activity;
+import android.app.Fragment;
+import android.app.FragmentTransaction;
+import android.content.Context;
 import android.content.Intent;
 import android.net.Uri;
 import android.os.Bundle;
+import android.support.v13.app.FragmentPagerAdapter;
+import android.support.v4.view.ViewPager;
 import android.view.Menu;
 import android.view.MenuItem;
 
-import com.android.browser.CombinedBookmarkHistoryView.CombinedBookmarksCallbacks;
 import com.android.browser.UI.ComboViews;
 
+import java.util.ArrayList;
+
 public class ComboViewActivity extends Activity implements CombinedBookmarksCallbacks {
 
+    private static final String STATE_SELECTED_TAB = "tab";
     public static final String EXTRA_COMBO_ARGS = "combo_args";
     public static final String EXTRA_INITIAL_VIEW = "initial_view";
 
@@ -34,8 +42,8 @@
     public static final String EXTRA_OPEN_ALL = "open_all";
     public static final String EXTRA_CURRENT_URL = "url";
     public static final String EXTRA_BOOKMARK_PAGE = "create_bookmark";
-
-    private CombinedBookmarkHistoryView mComboView;
+    private ViewPager mViewPager;
+    private TabsAdapter mTabsAdapter;
 
     @Override
     protected void onCreate(Bundle savedInstanceState) {
@@ -47,9 +55,50 @@
         ComboViews startingView = svStr != null
                 ? ComboViews.valueOf(svStr)
                 : ComboViews.Bookmarks;
-        mComboView = new CombinedBookmarkHistoryView(this, this,
-                startingView, args);
-        setContentView(mComboView);
+        mViewPager = new ViewPager(this);
+        mViewPager.setId(R.id.tab_view);
+        setContentView(mViewPager);
+
+        final ActionBar bar = getActionBar();
+        bar.setNavigationMode(ActionBar.NAVIGATION_MODE_TABS);
+        if (BrowserActivity.isTablet(this)) {
+            bar.setDisplayOptions(ActionBar.DISPLAY_SHOW_HOME
+                    | ActionBar.DISPLAY_USE_LOGO);
+        } else {
+            bar.setDisplayOptions(0);
+        }
+
+        mTabsAdapter = new TabsAdapter(this, mViewPager);
+        mTabsAdapter.addTab(bar.newTab().setText(R.string.tab_bookmarks),
+                BrowserBookmarksPage.class, args);
+        mTabsAdapter.addTab(bar.newTab().setText(R.string.tab_history),
+                BrowserHistoryPage.class, args);
+        mTabsAdapter.addTab(bar.newTab().setText(R.string.tab_snapshots),
+                BrowserSnapshotPage.class, args);
+
+        if (savedInstanceState != null) {
+            bar.setSelectedNavigationItem(
+                    savedInstanceState.getInt(STATE_SELECTED_TAB, 0));
+        } else {
+            switch (startingView) {
+            case Bookmarks:
+                mViewPager.setCurrentItem(0);
+                break;
+            case History:
+                mViewPager.setCurrentItem(1);
+                break;
+            case Snapshots:
+                mViewPager.setCurrentItem(2);
+                break;
+            }
+        }
+    }
+
+    @Override
+    protected void onSaveInstanceState(Bundle outState) {
+        super.onSaveInstanceState(outState);
+        outState.putInt(STATE_SELECTED_TAB,
+                getActionBar().getSelectedNavigationIndex());
     }
 
     @Override
@@ -81,13 +130,6 @@
     }
 
     @Override
-    public void onBackPressed() {
-        if (!mComboView.onBackPressed()) {
-            super.onBackPressed();
-        }
-    }
-
-    @Override
     public boolean onCreateOptionsMenu(Menu menu) {
         getMenuInflater().inflate(R.menu.combined, menu);
         return super.onCreateOptionsMenu(menu);
@@ -107,4 +149,101 @@
         }
         return super.onOptionsItemSelected(item);
     }
+
+    /**
+     * This is a helper class that implements the management of tabs and all
+     * details of connecting a ViewPager with associated TabHost.  It relies on a
+     * trick.  Normally a tab host has a simple API for supplying a View or
+     * Intent that each tab will show.  This is not sufficient for switching
+     * between pages.  So instead we make the content part of the tab host
+     * 0dp high (it is not shown) and the TabsAdapter supplies its own dummy
+     * view to show as the tab content.  It listens to changes in tabs, and takes
+     * care of switch to the correct page in the ViewPager whenever the selected
+     * tab changes.
+     */
+    public static class TabsAdapter extends FragmentPagerAdapter
+            implements ActionBar.TabListener, ViewPager.OnPageChangeListener {
+        private final Context mContext;
+        private final ActionBar mActionBar;
+        private final ViewPager mViewPager;
+        private final ArrayList<TabInfo> mTabs = new ArrayList<TabInfo>();
+
+        static final class TabInfo {
+            private final Class<?> clss;
+            private final Bundle args;
+
+            TabInfo(Class<?> _class, Bundle _args) {
+                clss = _class;
+                args = _args;
+            }
+        }
+
+        public TabsAdapter(Activity activity, ViewPager pager) {
+            super(activity.getFragmentManager());
+            mContext = activity;
+            mActionBar = activity.getActionBar();
+            mViewPager = pager;
+            mViewPager.setAdapter(this);
+            mViewPager.setOnPageChangeListener(this);
+        }
+
+        public void addTab(ActionBar.Tab tab, Class<?> clss, Bundle args) {
+            TabInfo info = new TabInfo(clss, args);
+            tab.setTag(info);
+            tab.setTabListener(this);
+            mTabs.add(info);
+            mActionBar.addTab(tab);
+            notifyDataSetChanged();
+        }
+
+        @Override
+        public int getCount() {
+            return mTabs.size();
+        }
+
+        @Override
+        public Fragment getItem(int position) {
+            TabInfo info = mTabs.get(position);
+            return Fragment.instantiate(mContext, info.clss.getName(), info.args);
+        }
+
+        @Override
+        public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
+        }
+
+        @Override
+        public void onPageSelected(int position) {
+            mActionBar.setSelectedNavigationItem(position);
+        }
+
+        @Override
+        public void onPageScrollStateChanged(int state) {
+        }
+
+        @Override
+        public void onTabSelected(android.app.ActionBar.Tab tab,
+                FragmentTransaction ft) {
+            Object tag = tab.getTag();
+            for (int i=0; i<mTabs.size(); i++) {
+                if (mTabs.get(i) == tag) {
+                    mViewPager.setCurrentItem(i);
+                }
+            }
+        }
+
+        @Override
+        public void onTabUnselected(android.app.ActionBar.Tab tab,
+                FragmentTransaction ft) {
+        }
+
+        @Override
+        public void onTabReselected(android.app.ActionBar.Tab tab,
+                FragmentTransaction ft) {
+        }
+    }
+
+    private static String makeFragmentName(int viewId, int index) {
+        return "android:switcher:" + viewId + ":" + index;
+    }
+
 }
diff --git a/src/com/android/browser/NavigationBarBase.java b/src/com/android/browser/NavigationBarBase.java
index a4130b8..aa8b79f 100644
--- a/src/com/android/browser/NavigationBarBase.java
+++ b/src/com/android/browser/NavigationBarBase.java
@@ -172,7 +172,7 @@
             if (mUrlInput.getText().length() == 0) {
                 Tab currentTab = mUiController.getTabControl().getCurrentTab();
                 if (currentTab != null) {
-                    mUrlInput.setText(currentTab.getUrl(), false);
+                    setDisplayTitle(currentTab.getUrl());
                 }
             }
             mBaseUi.suggestHideTitleBar();
diff --git a/src/com/android/browser/NavigationBarPhone.java b/src/com/android/browser/NavigationBarPhone.java
index 8173377..49228db 100644
--- a/src/com/android/browser/NavigationBarPhone.java
+++ b/src/com/android/browser/NavigationBarPhone.java
@@ -128,11 +128,12 @@
      */
     @Override
     void setDisplayTitle(String title) {
+        mUrlInput.setTag(title);
         if (!isEditingUrl()) {
             if (title == null) {
                 mUrlInput.setText(R.string.new_tab);
             } else {
-                mUrlInput.setText(title);
+                mUrlInput.setText(UrlUtils.stripUrl(title), false);
             }
             mUrlInput.setSelection(0);
         }
@@ -198,6 +199,18 @@
     }
 
     @Override
+    public void onFocusChange(View view, boolean hasFocus) {
+        if (view == mUrlInput) {
+            if (hasFocus) {
+                mUrlInput.setText((String) mUrlInput.getTag(), false);
+            } else {
+                setDisplayTitle(mUrlInput.getText().toString());
+            }
+        }
+        super.onFocusChange(view, hasFocus);
+    }
+
+    @Override
     public void onStateChanged(int state) {
         switch(state) {
         case StateListener.STATE_NORMAL:
diff --git a/src/com/android/browser/NavigationBarTablet.java b/src/com/android/browser/NavigationBarTablet.java
index e3059ea..7f6992a 100644
--- a/src/com/android/browser/NavigationBarTablet.java
+++ b/src/com/android/browser/NavigationBarTablet.java
@@ -22,6 +22,7 @@
 import android.content.Context;
 import android.content.res.Configuration;
 import android.content.res.Resources;
+import android.graphics.Bitmap;
 import android.graphics.drawable.Drawable;
 import android.text.TextUtils;
 import android.util.AttributeSet;
@@ -53,6 +54,7 @@
     private Drawable mFocusDrawable;
     private Drawable mUnfocusDrawable;
     private boolean mHideNavButtons;
+    private Drawable mFaviconDrawable;
 
     public NavigationBarTablet(Context context) {
         super(context);
@@ -191,10 +193,25 @@
         }
     }
 
+    @Override
+    public void setFavicon(Bitmap icon) {
+        mFaviconDrawable = mBaseUi.getFaviconDrawable(icon);
+        updateUrlIcon();
+    }
+
     void updateUrlIcon() {
-        mUrlIcon.setImageResource(mInVoiceMode ?
-                R.drawable.ic_search_holo_dark
-                : R.drawable.ic_web_holo_dark);
+        if (mUrlInput.hasFocus()) {
+            mUrlIcon.setImageResource(R.drawable.ic_search_holo_dark);
+        } else {
+            if (mInVoiceMode) {
+                mUrlIcon.setImageResource(R.drawable.ic_search_holo_dark);
+            } else {
+                if (mFaviconDrawable == null) {
+                    mFaviconDrawable = mBaseUi.getFaviconDrawable(null);
+                }
+                mUrlIcon.setImageDrawable(mFaviconDrawable);
+            }
+        }
     }
 
     @Override
diff --git a/src/com/android/browser/ShortcutActivity.java b/src/com/android/browser/ShortcutActivity.java
index 134bf23..612116e 100644
--- a/src/com/android/browser/ShortcutActivity.java
+++ b/src/com/android/browser/ShortcutActivity.java
@@ -63,13 +63,6 @@
     }
 
     @Override
-    public void onBackPressed() {
-        if (!mBookmarks.onBackPressed()) {
-            super.onBackPressed();
-        }
-    }
-
-    @Override
     public void onClick(View v) {
         switch (v.getId()) {
         case R.id.cancel:
diff --git a/src/com/android/browser/TabBar.java b/src/com/android/browser/TabBar.java
index d1652dd..d549ac3 100644
--- a/src/com/android/browser/TabBar.java
+++ b/src/com/android/browser/TabBar.java
@@ -35,10 +35,8 @@
 import android.graphics.drawable.Drawable;
 import android.graphics.drawable.LayerDrawable;
 import android.graphics.drawable.PaintDrawable;
-import android.view.ContextMenu;
 import android.view.Gravity;
 import android.view.LayoutInflater;
-import android.view.MenuInflater;
 import android.view.View;
 import android.view.View.OnClickListener;
 import android.widget.ImageButton;
@@ -62,8 +60,7 @@
     private TabControl mTabControl;
     private XLargeUi mUi;
 
-    private int mTabWidthSelected;
-    private int mTabWidthUnselected;
+    private int mTabWidth;
 
     private TabScrollView mTabs;
 
@@ -72,8 +69,6 @@
 
     private Map<Tab, TabView> mTabMap;
 
-    private Drawable mGenericFavicon;
-
     private int mCurrentTextureWidth = 0;
     private int mCurrentTextureHeight = 0;
 
@@ -101,8 +96,7 @@
         mTabControl = mUiController.getTabControl();
         mUi = ui;
         Resources res = activity.getResources();
-        mTabWidthSelected = (int) res.getDimension(R.dimen.tab_width_selected);
-        mTabWidthUnselected = (int) res.getDimension(R.dimen.tab_width_unselected);
+        mTabWidth = (int) res.getDimension(R.dimen.tab_width);
         mActiveDrawable = res.getDrawable(R.drawable.bg_urlbar);
         mInactiveDrawable = res.getDrawable(R.drawable.browsertab_inactive);
 
@@ -113,7 +107,6 @@
         mTabs = (TabScrollView) findViewById(R.id.tabs);
         mNewTab = (ImageButton) findViewById(R.id.newtab);
         mNewTab.setOnClickListener(this);
-        mGenericFavicon = res.getDrawable(R.drawable.app_web_browser_sm);
 
         updateTabs(mUiController.getTabs());
         mButtonWidth = -1;
@@ -138,8 +131,7 @@
     public void onConfigurationChanged(Configuration config) {
         super.onConfigurationChanged(config);
         Resources res = mActivity.getResources();
-        mTabWidthSelected = (int) res.getDimension(R.dimen.tab_width_selected);
-        mTabWidthUnselected = (int) res.getDimension(R.dimen.tab_width_unselected);
+        mTabWidth = (int) res.getDimension(R.dimen.tab_width);
         // force update of tab bar
         mTabs.updateLayout();
     }
@@ -309,7 +301,7 @@
             setDisplayTitle(displayTitle);
             setProgress(mTab.getLoadProgress());
             if (mTab.getFavicon() != null) {
-                setFavicon(renderFavicon(mTab.getFavicon()));
+                setFavicon(mUi.getFaviconDrawable(mTab.getFavicon()));
             }
             updateTabIcons();
         }
@@ -326,6 +318,7 @@
         public void setActivated(boolean selected) {
             mSelected = selected;
             mClose.setVisibility(mSelected ? View.VISIBLE : View.GONE);
+            mIconView.setVisibility(mSelected ? View.GONE : View.VISIBLE);
             mTitle.setTextAppearance(mActivity, mSelected ?
                     R.style.TabTitleSelected : R.style.TabTitleUnselected);
             setHorizontalFadingEdgeEnabled(!mSelected);
@@ -337,7 +330,7 @@
 
         public void updateLayoutParams() {
             LayoutParams lp = (LinearLayout.LayoutParams) getLayoutParams();
-            lp.width = mSelected ? mTabWidthSelected : mTabWidthUnselected;
+            lp.width = mTabWidth;
             lp.height =  LayoutParams.MATCH_PARENT;
             setLayoutParams(lp);
         }
@@ -447,29 +440,6 @@
 
     }
 
-    static Drawable createFaviconBackground(Context context) {
-        PaintDrawable faviconBackground = new PaintDrawable();
-        Resources res = context.getResources();
-        faviconBackground.getPaint().setColor(context.getResources()
-                .getColor(R.color.tabFaviconBackground));
-        faviconBackground.setCornerRadius(
-                res.getDimension(R.dimen.tab_favicon_corner_radius));
-        return faviconBackground;
-    }
-
-    private Drawable renderFavicon(Bitmap icon) {
-        Drawable[] array = new Drawable[2];
-        array[0] = createFaviconBackground(getContext());
-        if (icon == null) {
-            array[1] = mGenericFavicon;
-        } else {
-            array[1] = new BitmapDrawable(icon);
-        }
-        LayerDrawable d = new LayerDrawable(array);
-        d.setLayerInset(1, 2, 2, 2, 2);
-        return d;
-    }
-
     private void animateTabOut(final Tab tab, final TabView tv) {
         ObjectAnimator scalex = ObjectAnimator.ofFloat(tv, "scaleX", 1.0f, 0.0f);
         ObjectAnimator scaley = ObjectAnimator.ofFloat(tv, "scaleY", 1.0f, 0.0f);
@@ -542,7 +512,7 @@
     public void onFavicon(Tab tab, Bitmap favicon) {
         TabView tv = mTabMap.get(tab);
         if (tv != null) {
-            tv.setFavicon(renderFavicon(favicon));
+            tv.setFavicon(mUi.getFaviconDrawable(favicon));
         }
     }
 
diff --git a/src/com/android/browser/UrlUtils.java b/src/com/android/browser/UrlUtils.java
index c922e55..681b242 100644
--- a/src/com/android/browser/UrlUtils.java
+++ b/src/com/android/browser/UrlUtils.java
@@ -40,28 +40,29 @@
     private final static String QUICKSEARCH_G = "http://www.google.com/m?q=%s";
     private final static String QUERY_PLACE_HOLDER = "%s";
 
-    // Regular expression which matches http://, followed by some stuff, followed by
-    // optionally a trailing slash, all matched as separate groups.
-    private static final Pattern STRIP_URL_PATTERN = Pattern.compile("^(http://)(.*?)(/$)?");
+    // Regular expression to strip http://, optionally www., and optionally
+    // the trailing slash
+    private static final Pattern STRIP_URL_PATTERN =
+            Pattern.compile("^http://(?:www\\.)?(.*?)/?$");
 
     private UrlUtils() { /* cannot be instantiated */ }
 
     /**
-     * Strips the provided url of preceding "http://" and any trailing "/". Does not
+     * Strips the provided url of preceding "http://", "www.", and any trailing "/". Does not
      * strip "https://". If the provided string cannot be stripped, the original string
      * is returned.
      *
      * TODO: Put this in TextUtils to be used by other packages doing something similar.
      *
      * @param url a url to strip, like "http://www.google.com/"
-     * @return a stripped url like "www.google.com", or the original string if it could
+     * @return a stripped url like "google.com", or the original string if it could
      *         not be stripped
      */
     public static String stripUrl(String url) {
         if (url == null) return null;
         Matcher m = STRIP_URL_PATTERN.matcher(url);
-        if (m.matches() && m.groupCount() == 3) {
-            return m.group(2);
+        if (m.matches()) {
+            return m.group(1);
         } else {
             return url;
         }
diff --git a/src/com/android/browser/XLargeUi.java b/src/com/android/browser/XLargeUi.java
index 5c11b58..724708b 100644
--- a/src/com/android/browser/XLargeUi.java
+++ b/src/com/android/browser/XLargeUi.java
@@ -18,6 +18,12 @@
 
 import android.app.ActionBar;
 import android.app.Activity;
+import android.content.res.Resources;
+import android.graphics.Bitmap;
+import android.graphics.drawable.BitmapDrawable;
+import android.graphics.drawable.Drawable;
+import android.graphics.drawable.LayerDrawable;
+import android.graphics.drawable.PaintDrawable;
 import android.os.Bundle;
 import android.os.Handler;
 import android.util.Log;
@@ -38,6 +44,8 @@
 
     private static final String LOGTAG = "XLargeUi";
 
+    private PaintDrawable mFaviconBackground;
+
     private ActionBar mActionBar;
     private TabBar mTabBar;
 
@@ -348,4 +356,30 @@
         return mUseQuickControls;
     }
 
+    private Drawable getFaviconBackground() {
+        if (mFaviconBackground == null) {
+            mFaviconBackground = new PaintDrawable();
+            Resources res = mActivity.getResources();
+            mFaviconBackground.getPaint().setColor(
+                    res.getColor(R.color.tabFaviconBackground));
+            mFaviconBackground.setCornerRadius(
+                    res.getDimension(R.dimen.tab_favicon_corner_radius));
+        }
+        return mFaviconBackground;
+    }
+
+    @Override
+    public Drawable getFaviconDrawable(Bitmap icon) {
+        Drawable[] array = new Drawable[2];
+        array[0] = getFaviconBackground();
+        if (icon == null) {
+            array[1] = mGenericFavicon;
+        } else {
+            array[1] = new BitmapDrawable(mActivity.getResources(), icon);
+        }
+        LayerDrawable d = new LayerDrawable(array);
+        d.setLayerInset(1, 2, 2, 2, 2);
+        return d;
+    }
+
 }
diff --git a/src/com/android/browser/search/.DefaultSearchEngine.java.swp b/src/com/android/browser/search/.DefaultSearchEngine.java.swp
deleted file mode 100644
index 441153c..0000000
--- a/src/com/android/browser/search/.DefaultSearchEngine.java.swp
+++ /dev/null
Binary files differ
diff --git a/src/com/android/browser/search/DefaultSearchEngine.java b/src/com/android/browser/search/DefaultSearchEngine.java
index 0a7afcf..a575404 100644
--- a/src/com/android/browser/search/DefaultSearchEngine.java
+++ b/src/com/android/browser/search/DefaultSearchEngine.java
@@ -15,6 +15,7 @@
  */
 package com.android.browser.search;
 
+import android.app.PendingIntent;
 import android.app.SearchManager;
 import android.app.SearchableInfo;
 import android.content.ActivityNotFoundException;
@@ -92,6 +93,12 @@
                 intent.putExtra(SearchManager.EXTRA_DATA_KEY, extraData);
             }
             intent.putExtra(Browser.EXTRA_APPLICATION_ID, context.getPackageName());
+            Intent viewIntent = new Intent(Intent.ACTION_VIEW);
+            viewIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+            viewIntent.setPackage(context.getPackageName());
+            PendingIntent pending = PendingIntent.getActivity(context, 0, viewIntent,
+                    PendingIntent.FLAG_ONE_SHOT);
+            intent.putExtra(SearchManager.EXTRA_WEB_SEARCH_PENDINGINTENT, pending);
             context.startActivity(intent);
         } catch (ActivityNotFoundException ex) {
             Log.e(TAG, "Web search activity not found: " + mSearchable.getSearchActivity());