Merge "Fix favicon updating to handle redirects"
diff --git a/res/values-xlarge/strings.xml b/res/values-xlarge/strings.xml
index 07b2b34..856b2b9 100644
--- a/res/values-xlarge/strings.xml
+++ b/res/values-xlarge/strings.xml
@@ -22,4 +22,7 @@
     <string name="new_incognito_tab">New incognito tab</string>
     <!-- Name of menu item which brings up a list of the currently active tabs -->
     <string name="active_tabs">Tabs</string>
+    <!-- Context Menu item to open the currently selected link in a new
+         window. [CHAR LIMIT=30] -->
+    <string name="contextmenu_openlink_newwindow">Open in new tab</string>
 </resources>
diff --git a/src/com/android/browser/provider/BrowserProvider2.java b/src/com/android/browser/provider/BrowserProvider2.java
index 849426a..1eaad25 100644
--- a/src/com/android/browser/provider/BrowserProvider2.java
+++ b/src/com/android/browser/provider/BrowserProvider2.java
@@ -96,6 +96,11 @@
             "url LIKE ? OR url LIKE ? OR url LIKE ? OR url LIKE ?"
             + " OR title LIKE ?";
 
+    private static final String IMAGE_PRUNE =
+            "url_key NOT IN (SELECT url FROM bookmarks " +
+            "WHERE url IS NOT NULL AND deleted == 0) AND url_key NOT IN " +
+            "(SELECT url FROM history WHERE url IS NOT NULL)";
+
     static final int BOOKMARKS = 1000;
     static final int BOOKMARKS_ID = 1001;
     static final int BOOKMARKS_FOLDER = 1002;
@@ -155,6 +160,9 @@
         matcher.addURI(authority, "bookmarks/folder", BOOKMARKS_FOLDER);
         matcher.addURI(authority, "bookmarks/folder/#", BOOKMARKS_FOLDER_ID);
         matcher.addURI(authority,
+                SearchManager.SUGGEST_URI_PATH_QUERY,
+                BOOKMARKS_SUGGESTIONS);
+        matcher.addURI(authority,
                 "bookmarks/" + SearchManager.SUGGEST_URI_PATH_QUERY,
                 BOOKMARKS_SUGGESTIONS);
         matcher.addURI(authority, "history", HISTORY);
@@ -174,6 +182,9 @@
         matcher.addURI(LEGACY_AUTHORITY, "bookmarks", LEGACY);
         matcher.addURI(LEGACY_AUTHORITY, "bookmarks/#", LEGACY_ID);
         matcher.addURI(LEGACY_AUTHORITY,
+                SearchManager.SUGGEST_URI_PATH_QUERY,
+                BOOKMARKS_SUGGESTIONS);
+        matcher.addURI(LEGACY_AUTHORITY,
                 "bookmarks/" + SearchManager.SUGGEST_URI_PATH_QUERY,
                 BOOKMARKS_SUGGESTIONS);
 
@@ -930,7 +941,9 @@
                 // fall through
             }
             case BOOKMARKS: {
-                return deleteBookmarks(selection, selectionArgs, callerIsSyncAdapter);
+                int deleted = deleteBookmarks(selection, selectionArgs, callerIsSyncAdapter);
+                pruneImages();
+                return deleted;
             }
 
             case HISTORY_ID: {
@@ -941,7 +954,9 @@
             }
             case HISTORY: {
                 filterSearchClient(selectionArgs);
-                return db.delete(TABLE_HISTORY, selection, selectionArgs);
+                int deleted = db.delete(TABLE_HISTORY, selection, selectionArgs);
+                pruneImages();
+                return deleted;
             }
 
             case SEARCHES_ID: {
@@ -1251,8 +1266,10 @@
                 // fall through
             }
             case BOOKMARKS: {
-                return updateBookmarksInTransaction(values, selection, selectionArgs,
+                int updated = updateBookmarksInTransaction(values, selection, selectionArgs,
                         callerIsSyncAdapter);
+                pruneImages();
+                return updated;
             }
 
             case HISTORY_ID: {
@@ -1262,7 +1279,9 @@
                 // fall through
             }
             case HISTORY: {
-                return updateHistoryInTransaction(values, selection, selectionArgs);
+                int updated = updateHistoryInTransaction(values, selection, selectionArgs);
+                pruneImages();
+                return updated;
             }
 
             case SYNCSTATE: {
@@ -1456,7 +1475,13 @@
         return imageValues;
     }
 
+    void pruneImages() {
+        final SQLiteDatabase db = mOpenHelper.getWritableDatabase();
+        db.delete(TABLE_IMAGES, IMAGE_PRUNE, null);
+    }
+
     static class SuggestionsCursor extends AbstractCursor {
+        private static final int ID_INDEX = 0;
         private static final int URL_INDEX = 1;
         private static final int TITLE_INDEX = 2;
         // shared suggestion array index, make sure to match COLUMNS
@@ -1491,7 +1516,7 @@
         @Override
         public String getString(int columnIndex) {
             switch (columnIndex) {
-            case 0:
+            case ID_INDEX:
                 return mSource.getString(columnIndex);
             case SUGGEST_COLUMN_INTENT_ACTION_ID:
                 return Intent.ACTION_VIEW;
@@ -1529,6 +1554,10 @@
 
         @Override
         public long getLong(int column) {
+            switch (column) {
+            case ID_INDEX:
+                return mSource.getLong(ID_INDEX);
+            }
             throw new UnsupportedOperationException();
         }
 
@@ -1539,7 +1568,7 @@
 
         @Override
         public boolean isNull(int column) {
-            return getString(column) == null;
+            return mSource.isNull(column);
         }
 
         @Override