Merge "Import initial translations for 20 new locales."
diff --git a/res/layout/bookmarklistwidget.xml b/res/layout/bookmarklistwidget.xml
index ffaa0c3..983854c 100644
--- a/res/layout/bookmarklistwidget.xml
+++ b/res/layout/bookmarklistwidget.xml
@@ -19,7 +19,7 @@
     android:layout_width="match_parent"
     android:layout_height="match_parent"
     android:orientation="vertical"
-    android:background="#00000000"
+    android:background="@null"
     android:focusable="true"
     android:clickable="true">
     <LinearLayout
@@ -28,7 +28,7 @@
         android:layout_height="wrap_content"
         android:orientation="horizontal"
         android:padding="8dip"
-        android:background="#383847">
+        android:background="@color/bookmarkWidgetHeader">
         <ImageView
             android:id="@+id/logo"
             android:layout_width="32dp"
@@ -40,15 +40,14 @@
             android:layout_gravity="center_vertical"
             android:text="@string/tab_bookmarks"
             android:textAppearance="?android:attr/textAppearanceMedium"
-            android:textColor="@color/white"
             android:paddingLeft="8dip" />
     </LinearLayout>
     <ListView
         android:id="@+id/bookmarks_list"
         android:layout_width="match_parent"
         android:layout_height="match_parent"
-        android:background="#2b2b3c"
-        android:cacheColorHint="#2b2b3c"
-        android:dividerHeight="0dp"
-        android:divider="#00000000" />
+        android:background="@color/bookmarkWidgetItemBackground"
+        android:cacheColorHint="@color/bookmarkWidgetItemBackground"
+        android:dividerHeight="1px"
+        android:divider="@color/bookmarkWidgetDivider" />
 </LinearLayout>
diff --git a/res/layout/bookmarklistwidget_item.xml b/res/layout/bookmarklistwidget_item.xml
index 2257a26..9e41d39 100644
--- a/res/layout/bookmarklistwidget_item.xml
+++ b/res/layout/bookmarklistwidget_item.xml
@@ -19,9 +19,10 @@
     android:id="@+id/list_item"
     android:layout_width="match_parent"
     android:layout_height="match_parent"
+    android:minHeight="@dimen/widgetItemMinHeight"
     android:orientation="horizontal"
     android:padding="8dip"
-    android:background="#383847">
+    android:background="@color/bookmarkWidgetFolderBackground">
     <ImageView
         android:id="@+id/thumb"
         android:src="@drawable/browser_thumbnail"
@@ -35,7 +36,6 @@
         android:layout_height="wrap_content"
         android:layout_gravity="center_vertical"
         android:textAppearance="?android:attr/textAppearanceSmall"
-        android:textColor="@color/white"
         android:paddingLeft="8dip"
         android:maxLines="1"
         android:scrollHorizontally="true"
diff --git a/res/menu/historycontext.xml b/res/menu/historycontext.xml
index bd4ede4..3eaeb20 100644
--- a/res/menu/historycontext.xml
+++ b/res/menu/historycontext.xml
@@ -15,6 +15,7 @@
 -->
 
 <menu xmlns:android="http://schemas.android.com/apk/res/android">
+  <group android:id="@+id/CONTEXT_MENU">
     <item android:id="@+id/open_context_menu_id"
         android:title="@string/contextmenu_openlink"/>
     <item android:id="@+id/new_window_context_menu_id"
@@ -29,4 +30,5 @@
         android:title="@string/remove_history_item"/>
     <item android:id="@+id/homepage_context_menu_id"
         android:title="@string/set_as_homepage"/>
+  </group>
 </menu>
diff --git a/res/values/colors.xml b/res/values/colors.xml
index 822c3b4..5a5d255 100644
--- a/res/values/colors.xml
+++ b/res/values/colors.xml
@@ -24,4 +24,9 @@
     <color name="black">#ff000000</color>
     
     <color name="geolocation_permissions_prompt_background">#ffdddddd</color>
+
+    <color name="bookmarkWidgetHeader">#383847</color>
+    <color name="bookmarkWidgetDivider">#383847</color>
+    <color name="bookmarkWidgetItemBackground">#2b2b3c</color>
+    <color name="bookmarkWidgetFolderBackground">#A0383847</color>
 </resources>
diff --git a/res/values/dimensions.xml b/res/values/dimensions.xml
index f550cf7..404b2ac 100644
--- a/res/values/dimensions.xml
+++ b/res/values/dimensions.xml
@@ -23,4 +23,5 @@
     <dimen name="bookmarkThumbnailHeight">80dip</dimen>
     <dimen name="add_bookmark_width">500dip</dimen>
     <dimen name="folder_selector_height">300dip</dimen>
+    <dimen name="widgetItemMinHeight">48dip</dimen>
 </resources>
diff --git a/res/values/integers.xml b/res/values/integers.xml
index c923805..4e029b1 100644
--- a/res/values/integers.xml
+++ b/res/values/integers.xml
@@ -21,4 +21,6 @@
     <!--  The duration of the tab animations in millisecs  -->
     <integer name="tab_animation_duration">500</integer>
     <integer name="max_width_crumb">200</integer>
+    <!-- The maximum number of most visited URLs in the history tab -->
+    <integer name="most_visits_limit">10</integer>
 </resources>
diff --git a/src/com/android/browser/BrowserHistoryPage.java b/src/com/android/browser/BrowserHistoryPage.java
index 3b0292d..a3ce0b4 100644
--- a/src/com/android/browser/BrowserHistoryPage.java
+++ b/src/com/android/browser/BrowserHistoryPage.java
@@ -32,8 +32,10 @@
 import android.database.Cursor;
 import android.graphics.Bitmap;
 import android.graphics.BitmapFactory;
+import android.net.Uri;
 import android.os.Bundle;
 import android.provider.Browser;
+import android.provider.BrowserContract;
 import android.provider.BrowserContract.History;
 import android.view.ContextMenu;
 import android.view.ContextMenu.ContextMenuInfo;
@@ -47,6 +49,7 @@
 import android.widget.ExpandableListView;
 import android.widget.ExpandableListView.ExpandableListContextMenuInfo;
 import android.widget.ExpandableListView.OnChildClickListener;
+import android.widget.TextView;
 import android.widget.Toast;
 
 /**
@@ -57,6 +60,7 @@
         implements LoaderCallbacks<Cursor>, OnChildClickListener {
 
     static final int LOADER_HISTORY = 1;
+    static final int LOADER_MOST_VISITED = 2;
 
     BookmarksHistoryCallbacks mCallbacks;
     ExpandableListView mList;
@@ -64,6 +68,7 @@
     HistoryAdapter mAdapter;
     boolean mDisableNewWindow;
     HistoryItem mContextHeader;
+    String mMostVisitsLimit;
 
     // Implementation of WebIconDatabase.IconListener
     class IconReceiver implements IconListener {
@@ -83,6 +88,7 @@
                 History.TITLE, // 2
                 History.URL, // 3
                 History.FAVICON, // 4
+                History.VISITS // 5
         };
 
         static final int INDEX_ID = 0;
@@ -90,6 +96,7 @@
         static final int INDEX_TITE = 2;
         static final int INDEX_URL = 3;
         static final int INDEX_FAVICON = 4;
+        static final int INDEX_VISITS = 5;
     }
 
     private void copy(CharSequence text) {
@@ -114,6 +121,16 @@
                 return loader;
             }
 
+            case LOADER_MOST_VISITED: {
+                Uri uri = History.CONTENT_URI
+                        .buildUpon()
+                        .appendQueryParameter(BrowserContract.PARAM_LIMIT, mMostVisitsLimit)
+                        .build();
+                CursorLoader loader = new CursorLoader(getActivity(), uri,
+                        HistoryQuery.PROJECTION, null, null, History.VISITS + " DESC");
+                return loader;
+            }
+
             default: {
                 throw new IllegalArgumentException();
             }
@@ -129,20 +146,15 @@
                 // Add an empty view late, so it does not claim an empty
                 // history before the adapter is present
                 mList.setEmptyView(mEmptyView);
+                break;
+            }
 
-                // Do not post the runnable if there is nothing in the list.
-                if (mList.getExpandableListAdapter().getGroupCount() > 0) {
-                    mList.post(new Runnable() {
-                        @Override
-                        public void run() {
-                            // In case the history gets cleared before this
-                            // event happens
-                            if (mList.getExpandableListAdapter().getGroupCount() > 0) {
-                                mList.expandGroup(0);
-                            }
-                        }
-                    });
-                }
+            case LOADER_MOST_VISITED: {
+                mAdapter.changeMostVisitedCursor(data);
+
+                // Add an empty view late, so it does not claim an empty
+                // history before the adapter is present
+                mList.setEmptyView(mEmptyView);
                 break;
             }
 
@@ -160,6 +172,8 @@
 
         Bundle args = getArguments();
         mDisableNewWindow = args.getBoolean(BrowserBookmarksPage.EXTRA_DISABLE_WINDOW, false);
+        int mvlimit = getResources().getInteger(R.integer.most_visits_limit);
+        mMostVisitsLimit = Integer.toString(mvlimit);
     }
 
     @Override
@@ -177,6 +191,7 @@
 
         // Start the loader
         getLoaderManager().initLoader(LOADER_HISTORY, null, this);
+        getLoaderManager().initLoader(LOADER_MOST_VISITED, null, this);
 
         // Register to receive icons in case they haven't all been loaded.
         CombinedBookmarkHistoryView.getIconListenerSet().addListener(mIconReceiver);
@@ -188,6 +203,7 @@
         super.onDestroy();
         CombinedBookmarkHistoryView.getIconListenerSet().removeListener(mIconReceiver);
         getLoaderManager().stopLoader(LOADER_HISTORY);
+        getLoaderManager().stopLoader(LOADER_MOST_VISITED);
     }
 
     @Override
@@ -329,11 +345,102 @@
     }
 
     private class HistoryAdapter extends DateSortedExpandableListAdapter {
+        private Cursor mMostVisited, mHistoryCursor;
+
         HistoryAdapter(Context context) {
             super(context, HistoryQuery.INDEX_DATE_LAST_VISITED);
         }
 
         @Override
+        public void changeCursor(Cursor cursor) {
+            mHistoryCursor = cursor;
+            super.changeCursor(cursor);
+        }
+
+        void changeMostVisitedCursor(Cursor cursor) {
+            if (mMostVisited == cursor) {
+                return;
+            }
+            if (mMostVisited != null) {
+                mMostVisited.unregisterDataSetObserver(mDataSetObserver);
+                mMostVisited.close();
+            }
+            mMostVisited = cursor;
+            mMostVisited.registerDataSetObserver(mDataSetObserver);
+        }
+
+        @Override
+        public long getChildId(int groupPosition, int childPosition) {
+            if (!mDataValid) return 0;
+            if (moveCursorToChildPosition(groupPosition, childPosition)) {
+                Cursor cursor = getCursor(groupPosition);
+                return cursor.getLong(HistoryQuery.INDEX_ID);
+            }
+            return 0;
+        }
+
+        @Override
+        public int getGroupCount() {
+            return super.getGroupCount() + (mMostVisited != null ? 1 : 0);
+        }
+
+        @Override
+        public int getChildrenCount(int groupPosition) {
+            if (groupPosition >= super.getGroupCount()) {
+                return mMostVisited.getCount();
+            }
+            return super.getChildrenCount(groupPosition);
+        }
+
+        @Override
+        public boolean isEmpty() {
+            if (!super.isEmpty()) {
+                return false;
+            }
+            return mMostVisited == null
+                    || mMostVisited.isClosed()
+                    || mMostVisited.getCount() == 0;
+        }
+
+        Cursor getCursor(int groupPosition) {
+            if (groupPosition >= super.getGroupCount()) {
+                return mMostVisited;
+            }
+            return mHistoryCursor;
+        }
+
+        @Override
+        public View getGroupView(int groupPosition, boolean isExpanded,
+                View convertView, ViewGroup parent) {
+            if (groupPosition >= super.getGroupCount()) {
+                if (!mDataValid) throw new IllegalStateException("Data is not valid");
+                TextView item;
+                if (null == convertView || !(convertView instanceof TextView)) {
+                    LayoutInflater factory = LayoutInflater.from(getContext());
+                    item = (TextView) factory.inflate(R.layout.history_header, null);
+                } else {
+                    item = (TextView) convertView;
+                }
+                item.setText(R.string.tab_most_visited);
+                return item;
+            }
+            return super.getGroupView(groupPosition, isExpanded, convertView, parent);
+        }
+
+        @Override
+        boolean moveCursorToChildPosition(
+                int groupPosition, int childPosition) {
+            if (groupPosition >= super.getGroupCount()) {
+                if (mDataValid && !mMostVisited.isClosed()) {
+                    mMostVisited.moveToPosition(childPosition);
+                    return true;
+                }
+                return false;
+            }
+            return super.moveCursorToChildPosition(groupPosition, childPosition);
+        }
+
+        @Override
         public View getChildView(int groupPosition, int childPosition, boolean isLastChild,
                 View convertView, ViewGroup parent) {
             HistoryItem item;
@@ -354,10 +461,11 @@
                 return item;
             }
 
-            item.setName(getString(HistoryQuery.INDEX_TITE));
-            String url = getString(HistoryQuery.INDEX_URL);
+            Cursor cursor = getCursor(groupPosition);
+            item.setName(cursor.getString(HistoryQuery.INDEX_TITE));
+            String url = cursor.getString(HistoryQuery.INDEX_URL);
             item.setUrl(url);
-            byte[] data = getBlob(HistoryQuery.INDEX_FAVICON);
+            byte[] data = cursor.getBlob(HistoryQuery.INDEX_FAVICON);
             if (data != null) {
                 item.setFavicon(BitmapFactory.decodeByteArray(data, 0,
                         data.length));
diff --git a/src/com/android/browser/Controller.java b/src/com/android/browser/Controller.java
index 7d183f6..caaa2c2 100644
--- a/src/com/android/browser/Controller.java
+++ b/src/com/android/browser/Controller.java
@@ -1542,6 +1542,11 @@
     }
 
     public boolean onContextItemSelected(MenuItem item) {
+        // Let the History and Bookmark fragments handle menus they created.
+        if (item.getGroupId() == R.id.CONTEXT_MENU) {
+            return false;
+        }
+
         // chording is not an issue with context menus, but we use the same
         // options selector, so set mCanChord to true so we can access them.
         mCanChord = true;
diff --git a/src/com/android/browser/OpenDownloadReceiver.java b/src/com/android/browser/OpenDownloadReceiver.java
index 0f0ba70..4277ff4 100644
--- a/src/com/android/browser/OpenDownloadReceiver.java
+++ b/src/com/android/browser/OpenDownloadReceiver.java
@@ -22,6 +22,8 @@
 import android.content.Context;
 import android.content.Intent;
 import android.net.Uri;
+import android.os.Handler;
+import android.os.HandlerThread;
 
 /**
  * This {@link BroadcastReceiver} handles clicks to notifications that
@@ -30,8 +32,14 @@
  * a complete, successful download will open the file.
  */
 public class OpenDownloadReceiver extends BroadcastReceiver {
+    private static Handler sAsyncHandler;
+    static {
+        HandlerThread thr = new HandlerThread("Open browser download async");
+        thr.start();
+        sAsyncHandler = new Handler(thr.getLooper());
+    }
     @Override
-    public void onReceive(Context context, Intent intent) {
+    public void onReceive(final Context context, Intent intent) {
         String action = intent.getAction();
         if (!DownloadManager.ACTION_NOTIFICATION_CLICKED.equals(action)) {
             openDownloadsPage(context);
@@ -43,7 +51,19 @@
             openDownloadsPage(context);
             return;
         }
-        long id = ids[0];
+        final long id = ids[0];
+        final PendingResult result = goAsync();
+        Runnable worker = new Runnable() {
+            @Override
+            public void run() {
+                onReceiveAsync(context, id);
+                result.finish();
+            }
+        };
+        sAsyncHandler.post(worker);
+    }
+
+    private void onReceiveAsync(Context context, long id) {
         DownloadManager manager = (DownloadManager) context.getSystemService(
                 Context.DOWNLOAD_SERVICE);
         Uri uri = manager.getUriForDownloadedFile(id);
diff --git a/src/com/android/browser/widget/BookmarkListWidgetService.java b/src/com/android/browser/widget/BookmarkListWidgetService.java
index 1120536..14b52b7 100644
--- a/src/com/android/browser/widget/BookmarkListWidgetService.java
+++ b/src/com/android/browser/widget/BookmarkListWidgetService.java
@@ -233,7 +233,7 @@
             views.setDrawableParameters(R.id.list_item, true, 0, -1, null, -1);
             if (res.mIsFolder) {
                 if (folder != null && res.mId == folder.mId) {
-                    views.setDrawableParameters(R.id.list_item, true, 140, -1, null, -1);
+                    views.setDrawableParameters(R.id.list_item, true, 255, -1, null, -1);
                     views.setImageViewResource(R.id.thumb, R.drawable.ic_back_normal);
                 } else {
                     views.setImageViewResource(R.id.thumb, R.drawable.ic_folder);