Merge "Remove second url bar"
diff --git a/AndroidManifest.xml b/AndroidManifest.xml
index c32b76a..8ac2c87 100644
--- a/AndroidManifest.xml
+++ b/AndroidManifest.xml
@@ -35,6 +35,7 @@
     <uses-permission android:name="android.permission.WRITE_SETTINGS" />
     <uses-permission android:name="android.permission.READ_SYNC_SETTINGS" />
     <uses-permission android:name="android.permission.WRITE_SYNC_SETTINGS" />
+    <uses-permission android:name="android.permission.MANAGE_ACCOUNTS" />
     <uses-permission android:name="com.android.browser.permission.READ_HISTORY_BOOKMARKS"/>
     <uses-permission android:name="com.android.browser.permission.WRITE_HISTORY_BOOKMARKS"/>
     <uses-permission android:name="com.android.launcher.permission.INSTALL_SHORTCUT"/>
diff --git a/res/drawable-mdpi/bookmarks_widget_thumb_selector_focused.9.png b/res/drawable-mdpi/bookmarks_widget_thumb_selector_focused.9.png
new file mode 100644
index 0000000..5bcc7c8
--- /dev/null
+++ b/res/drawable-mdpi/bookmarks_widget_thumb_selector_focused.9.png
Binary files differ
diff --git a/res/drawable/bookmark_thumb_selector.xml b/res/drawable/bookmark_thumb_selector.xml
index 59d9405..d4a12a3 100644
--- a/res/drawable/bookmark_thumb_selector.xml
+++ b/res/drawable/bookmark_thumb_selector.xml
@@ -16,6 +16,7 @@
 
 <selector xmlns:android="http://schemas.android.com/apk/res/android"
         android:exitFadeDuration="@android:integer/config_mediumAnimTime">
+    <item android:state_focused="true" android:state_pressed="false" android:drawable="@drawable/bookmarks_widget_thumb_selector_focused" />
     <item android:state_pressed="true" android:drawable="@drawable/bookmark_thumb_selector_transition" />
     <item android:drawable="@android:color/transparent" />
 </selector>
diff --git a/res/menu-xlarge/browser.xml b/res/menu-xlarge/browser.xml
index 1b52c9a..a791cdd 100644
--- a/res/menu-xlarge/browser.xml
+++ b/res/menu-xlarge/browser.xml
@@ -44,6 +44,8 @@
             android:title="@string/menu_preferences"
             android:icon="@drawable/ic_settings_holo_dark"
             android:alphabeticShortcut="p" />
+        <item android:id="@+id/save_webarchive_menu_id"
+            android:title="@string/menu_save_webarchive" />
         <!-- followings are debug only -->
         <item android:id="@+id/dump_nav_menu_id"
             android:title="@string/dump_nav"
diff --git a/res/menu/browser.xml b/res/menu/browser.xml
index beaa8f3..7a59ffd 100644
--- a/res/menu/browser.xml
+++ b/res/menu/browser.xml
@@ -57,6 +57,8 @@
             android:title="@string/menu_preferences"
             android:icon="@drawable/ic_settings_holo_dark"
             android:alphabeticShortcut="p" />
+        <item android:id="@+id/save_webarchive_menu_id"
+            android:title="@string/menu_save_webarchive" />
         <!-- followings are debug only -->
         <item android:id="@+id/dump_nav_menu_id"
             android:title="@string/dump_nav"
diff --git a/src/com/android/browser/AddBookmarkPage.java b/src/com/android/browser/AddBookmarkPage.java
index 1444862..9a7227c 100644
--- a/src/com/android/browser/AddBookmarkPage.java
+++ b/src/com/android/browser/AddBookmarkPage.java
@@ -73,6 +73,7 @@
     // Place on an edited bookmark to remove the saved thumbnail
     public static final String REMOVE_THUMBNAIL = "remove_thumbnail";
     public static final String USER_AGENT = "user_agent";
+    public static final String CHECK_FOR_DUPE = "check_for_dupe";
 
     /* package */ static final String EXTRA_EDIT_BOOKMARK = "bookmark";
     /* package */ static final String EXTRA_IS_FOLDER = "is_folder";
@@ -86,6 +87,8 @@
     private final int LOADER_ID_ALL_FOLDERS = 1;
     private final int LOADER_ID_FIND_ROOT = 2;
     private final int LOADER_ID_CHECK_FOR_DUPE = 3;
+    private final int LOADER_ID_MOST_RECENTLY_SAVED_BOOKMARK = 4;
+    private final int LOADER_ID_FIND_FOLDER_BY_ID = 5;
 
     private EditText    mTitle;
     private EditText    mAddress;
@@ -117,6 +120,7 @@
     private Drawable mHeaderIcon;
     private View mRemoveLink;
     private View mFakeTitleHolder;
+    private FolderSpinnerAdapter mFolderAdapter;
     private static class Folder {
         String Name;
         long Id;
@@ -308,6 +312,15 @@
             case FolderSpinnerAdapter.OTHER_FOLDER:
                 switchToFolderSelector();
                 break;
+            case FolderSpinnerAdapter.RECENT_FOLDER:
+                mCurrentFolder = mFolderAdapter.recentFolderId();
+                mSaveToHomeScreen = false;
+                // In case the user decides to select OTHER_FOLDER
+                // and choose a different one, so that we will start from
+                // the correct place.
+                LoaderManager manager = getLoaderManager();
+                manager.initLoader(LOADER_ID_ALL_FOLDERS, null, this);
+                manager.restartLoader(LOADER_ID_FOLDER_CONTENTS, null, this);
             default:
                 break;
         }
@@ -412,6 +425,18 @@
                         selection,
                         selArgs,
                         null);
+            case LOADER_ID_FIND_FOLDER_BY_ID:
+                projection = new String[] {
+                        BrowserContract.Bookmarks._ID,
+                        BrowserContract.Bookmarks.TITLE
+                };
+                return new CursorLoader(this,
+                        BrowserContract.Bookmarks.CONTENT_URI,
+                        projection,
+                        BrowserContract.Bookmarks._ID + " = "
+                                + args.getLong(BrowserContract.Bookmarks._ID),
+                        null,
+                        null);
             case LOADER_ID_ALL_FOLDERS:
                 projection = new String[] {
                         BrowserContract.Bookmarks._ID,
@@ -442,6 +467,16 @@
                         where,
                         null,
                         BrowserContract.Bookmarks._ID + " ASC");
+            case LOADER_ID_MOST_RECENTLY_SAVED_BOOKMARK:
+                projection = new String[] {
+                        BrowserContract.Bookmarks.PARENT
+                };
+                return new CursorLoader(this,
+                        BrowserContract.Bookmarks.CONTENT_URI,
+                        projection,
+                        BrowserContract.Bookmarks.IS_FOLDER + " = 0",
+                        null,
+                        BrowserContract.Bookmarks.DATE_CREATED + " DESC");
             default:
                 throw new AssertionError("Asking for nonexistant loader!");
         }
@@ -484,6 +519,32 @@
             case LOADER_ID_FOLDER_CONTENTS:
                 mAdapter.changeCursor(cursor);
                 break;
+            case LOADER_ID_MOST_RECENTLY_SAVED_BOOKMARK:
+                LoaderManager manager = getLoaderManager();
+                if (cursor != null && cursor.moveToFirst()) {
+                    // Find the parent
+                    long lastUsedFolder = cursor.getLong(0);
+                    if (lastUsedFolder != mRootFolder
+                            && lastUsedFolder != mCurrentFolder
+                            && lastUsedFolder != 0) {
+                        // Find out the parent's name
+                        Bundle b = new Bundle();
+                        b.putLong(BrowserContract.Bookmarks._ID, lastUsedFolder);
+                        manager.initLoader(LOADER_ID_FIND_FOLDER_BY_ID, b, this);
+                    }
+                }
+                manager.destroyLoader(LOADER_ID_MOST_RECENTLY_SAVED_BOOKMARK);
+                break;
+            case LOADER_ID_FIND_FOLDER_BY_ID:
+                if (cursor != null && cursor.moveToFirst()) {
+                    long id = cursor.getLong(cursor.getColumnIndexOrThrow(
+                            BrowserContract.Bookmarks._ID));
+                    String title = cursor.getString(cursor.getColumnIndexOrThrow(
+                            BrowserContract.Bookmarks.TITLE));
+                    mFolderAdapter.addRecentFolder(id, title);
+                }
+                getLoaderManager().destroyLoader(LOADER_ID_FIND_FOLDER_BY_ID);
+                break;
             case LOADER_ID_ALL_FOLDERS:
                 long parent = mCurrentFolder;
                 int idIndex = cursor.getColumnIndexOrThrow(
@@ -665,7 +726,8 @@
         mCancelButton.setOnClickListener(this);
 
         mFolder = (FolderSpinner) findViewById(R.id.folder);
-        mFolder.setAdapter(new FolderSpinnerAdapter(!mEditingFolder));
+        mFolderAdapter = new FolderSpinnerAdapter(!mEditingFolder);
+        mFolder.setAdapter(mFolderAdapter);
         mFolder.setOnSetSelectionListener(this);
 
         mDefaultView = findViewById(R.id.default_view);
@@ -728,7 +790,8 @@
             mCurrentFolder = mRootFolder;
         }
         setupTopCrumb();
-        if (mEditingExisting || TextUtils.isEmpty(mOriginalUrl)) {
+        if (mEditingExisting || TextUtils.isEmpty(mOriginalUrl)
+                || !(mMap != null && mMap.getBoolean(CHECK_FOR_DUPE))) {
             onCurrentFolderFound();
         } else {
             // User is attempting to bookmark a site, rather than deliberately
@@ -757,6 +820,11 @@
             mFolder.setSelectionIgnoringSelectionChange(mEditingFolder ? 1 : 2);
         } else {
             setShowBookmarkIcon(true);
+            if (!mEditingExisting) {
+                // Find the most recently saved bookmark, so that we can include it in
+                // the list of options to save the current bookmark.
+                manager.initLoader(LOADER_ID_MOST_RECENTLY_SAVED_BOOKMARK, null, this);
+            }
             if (!mEditingFolder) {
                 // Initially the "Bookmarks" folder should be showing, rather than
                 // the home screen.  In the editing folder case, home screen is not
diff --git a/src/com/android/browser/CombinedBookmarkHistoryView.java b/src/com/android/browser/CombinedBookmarkHistoryView.java
index 173abba..686e646 100644
--- a/src/com/android/browser/CombinedBookmarkHistoryView.java
+++ b/src/com/android/browser/CombinedBookmarkHistoryView.java
@@ -324,7 +324,7 @@
             mUiController.onUrlSelected(settings.getHomePage(), false);
             return true;
         case R.id.add_bookmark:
-            mUiController.bookmarkCurrentPage(mBookmarks.getFolderId());
+            mUiController.bookmarkCurrentPage(mBookmarks.getFolderId(), false);
             return true;
         case R.id.preferences_menu_id:
             Intent intent = new Intent(mActivity, BrowserPreferencesPage.class);
diff --git a/src/com/android/browser/Controller.java b/src/com/android/browser/Controller.java
index f4588bd..745a0f4 100644
--- a/src/com/android/browser/Controller.java
+++ b/src/com/android/browser/Controller.java
@@ -43,6 +43,7 @@
 import android.net.http.SslError;
 import android.os.AsyncTask;
 import android.os.Bundle;
+import android.os.Environment;
 import android.os.Handler;
 import android.os.Message;
 import android.os.PowerManager;
@@ -77,6 +78,7 @@
 import android.webkit.WebIconDatabase;
 import android.webkit.WebSettings;
 import android.webkit.WebView;
+import android.widget.Toast;
 
 import java.io.ByteArrayOutputStream;
 import java.io.File;
@@ -1520,7 +1522,7 @@
                 break;
 
             case R.id.add_bookmark_menu_id:
-                bookmarkCurrentPage(AddBookmarkPage.DEFAULT_FOLDER_ID);
+                bookmarkCurrentPage(AddBookmarkPage.DEFAULT_FOLDER_ID, false);
                 break;
 
             case R.id.stop_reload_menu_id:
@@ -1567,6 +1569,54 @@
                 getCurrentTopWebView().showFindDialog(null, true);
                 break;
 
+            case R.id.save_webarchive_menu_id:
+                String state = Environment.getExternalStorageState();
+                if (!Environment.MEDIA_MOUNTED.equals(state)) {
+                    Log.e(LOGTAG, "External storage not mounted");
+                    Toast.makeText(mActivity, R.string.webarchive_failed,
+                            Toast.LENGTH_SHORT).show();
+                    break;
+                }
+                final String directory = Environment.getExternalStoragePublicDirectory(
+                        Environment.DIRECTORY_DOWNLOADS) + File.separator;
+                File dir = new File(directory);
+                if (!dir.exists() && !dir.mkdirs()) {
+                    Log.e(LOGTAG, "Save as Web Archive: mkdirs for " + directory + " failed!");
+                    Toast.makeText(mActivity, R.string.webarchive_failed,
+                            Toast.LENGTH_SHORT).show();
+                    break;
+                }
+                WebView topWebView = getCurrentTopWebView();
+                final String title = topWebView.getTitle();
+                topWebView.saveWebArchive(directory, true,
+                        new ValueCallback<String>() {
+                    @Override
+                    public void onReceiveValue(final String value) {
+                        if (value != null) {
+                            File file = new File(value);
+                            final long length = file.length();
+                            if (file.exists() && length > 0) {
+                                Toast.makeText(mActivity, R.string.webarchive_saved,
+                                        Toast.LENGTH_SHORT).show();
+                                final DownloadManager manager = (DownloadManager) mActivity
+                                        .getSystemService(Context.DOWNLOAD_SERVICE);
+                                new Thread("Add WebArchive to download manager") {
+                                    @Override
+                                    public void run() {
+                                        manager.completedDownload(null == title ? value : title,
+                                                value, true, "application/x-webarchive-xml",
+                                                value, length, true);
+                                    }
+                                }.start();
+                                return;
+                            }
+                        }
+                        Toast.makeText(mActivity,
+                                R.string.webarchive_failed, Toast.LENGTH_SHORT).show();
+                    }
+                });
+                break;
+
             case R.id.page_info_menu_id:
                 mPageDialogsHandler.showPageInfo(mTabControl.getCurrentTab(),
                         false);
@@ -1804,9 +1854,13 @@
     /**
      * add the current page as a bookmark to the given folder id
      * @param folderId use -1 for the default folder
+     * @param canBeAnEdit If true, check to see whether the site is already
+     *          bookmarked, and if it is, edit that bookmark.  If false, and
+     *          the site is already bookmarked, do not attempt to edit the
+     *          existing bookmark.
      */
     @Override
-    public void bookmarkCurrentPage(long folderId) {
+    public void bookmarkCurrentPage(long folderId, boolean canBeAnEdit) {
         Intent i = new Intent(mActivity,
                 AddBookmarkPage.class);
         WebView w = getCurrentTopWebView();
@@ -1827,6 +1881,9 @@
         i.putExtra(BrowserContract.Bookmarks.FAVICON, w.getFavicon());
         i.putExtra(BrowserContract.Bookmarks.PARENT,
                 folderId);
+        if (canBeAnEdit) {
+            i.putExtra(AddBookmarkPage.CHECK_FOR_DUPE, true);
+        }
         // Put the dialog at the upper right of the screen, covering the
         // star on the title bar.
         i.putExtra("gravity", Gravity.RIGHT | Gravity.TOP);
diff --git a/src/com/android/browser/TitleBar.java b/src/com/android/browser/TitleBar.java
index bdef82e..b8ad2ef 100644
--- a/src/com/android/browser/TitleBar.java
+++ b/src/com/android/browser/TitleBar.java
@@ -215,7 +215,7 @@
                         mController.stopLoading();
                     } else {
                         mController.bookmarkCurrentPage(
-                                AddBookmarkPage.DEFAULT_FOLDER_ID);
+                                AddBookmarkPage.DEFAULT_FOLDER_ID, true);
                     }
                     button.setPressed(false);
                 } else if (mTitleBg.isPressed()) {
diff --git a/src/com/android/browser/TitleBarXLarge.java b/src/com/android/browser/TitleBarXLarge.java
index 55347a0..453e1b8 100644
--- a/src/com/android/browser/TitleBarXLarge.java
+++ b/src/com/android/browser/TitleBarXLarge.java
@@ -244,7 +244,7 @@
             mUiController.getCurrentTopWebView().goForward();
         } else if (mStar == v) {
             mUiController.bookmarkCurrentPage(
-                    AddBookmarkPage.DEFAULT_FOLDER_ID);
+                    AddBookmarkPage.DEFAULT_FOLDER_ID, true);
         } else if (mAllButton == v) {
             mUiController.bookmarksOrHistoryPicker(false);
         } else if (mSearchButton == v) {
diff --git a/src/com/android/browser/UiController.java b/src/com/android/browser/UiController.java
index ae38cff..a16b44b 100644
--- a/src/com/android/browser/UiController.java
+++ b/src/com/android/browser/UiController.java
@@ -49,7 +49,7 @@
 
     void stopLoading();
 
-    void bookmarkCurrentPage(long folderId);
+    void bookmarkCurrentPage(long folderId, boolean canBeAnEdit);
 
     void bookmarksOrHistoryPicker(boolean openHistory);
 
diff --git a/src/com/android/browser/UrlHandler.java b/src/com/android/browser/UrlHandler.java
index 686ed7b..03bab9b 100644
--- a/src/com/android/browser/UrlHandler.java
+++ b/src/com/android/browser/UrlHandler.java
@@ -20,7 +20,6 @@
 import android.content.ActivityNotFoundException;
 import android.content.Intent;
 import android.content.IntentFilter;
-import android.content.pm.ActivityInfo;
 import android.content.pm.PackageManager;
 import android.content.pm.ResolveInfo;
 import android.database.Cursor;
@@ -31,6 +30,7 @@
 
 import java.net.URISyntaxException;
 import java.util.List;
+import java.util.regex.Matcher;
 
 /**
  *
@@ -156,7 +156,11 @@
       // security (only access to BROWSABLE activities).
       intent.addCategory(Intent.CATEGORY_BROWSABLE);
       intent.setComponent(null);
-      if (!isSpecializedHandlerAvailable(intent)) {
+      // Make sure webkit can handle it internally before checking for specialized
+      // handlers. If webkit can't handle it internally, we need to call
+      // startActivityIfNeeded
+      Matcher m = UrlUtils.ACCEPTED_URI_SCHEMA.matcher(url);
+      if (m.matches() && !isSpecializedHandlerAvailable(intent)) {
           return false;
       }
       try {
diff --git a/src/com/android/browser/addbookmark/FolderSpinnerAdapter.java b/src/com/android/browser/addbookmark/FolderSpinnerAdapter.java
index 0712469..261aa62 100644
--- a/src/com/android/browser/addbookmark/FolderSpinnerAdapter.java
+++ b/src/com/android/browser/addbookmark/FolderSpinnerAdapter.java
@@ -35,15 +35,27 @@
  */
 public class FolderSpinnerAdapter implements SpinnerAdapter {
     private boolean mIncludeHomeScreen;
+    private boolean mIncludesRecentFolder;
+    private long mRecentFolderId;
+    private String mRecentFolderName;
 
     public static final int HOME_SCREEN = 0;
     public static final int ROOT_FOLDER = 1;
     public static final int OTHER_FOLDER = 2;
+    public static final int RECENT_FOLDER = 3;
 
     public FolderSpinnerAdapter(boolean includeHomeScreen) {
         mIncludeHomeScreen = includeHomeScreen;
     }
 
+    public void addRecentFolder(long folderId, String folderName) {
+        mIncludesRecentFolder = true;
+        mRecentFolderId = folderId;
+        mRecentFolderName = folderName;
+    }
+
+    public long recentFolderId() { return mRecentFolderId; }
+
     @Override
     public View getDropDownView(int position, View convertView, ViewGroup parent) {
         int labelResource;
@@ -60,6 +72,8 @@
                 labelResource = R.string.add_to_bookmarks_menu_option;
                 drawableResource = R.drawable.ic_bookmarks_holo_dark;
                 break;
+            case RECENT_FOLDER:
+                // Fall through and use the same icon resource
             case OTHER_FOLDER:
                 labelResource = R.string.add_to_other_folder_menu_option;
                 drawableResource = R.drawable.ic_folder_holo_dark;
@@ -73,7 +87,11 @@
         Context context = parent.getContext();
         LayoutInflater factory = LayoutInflater.from(context);
         TextView textView = (TextView) factory.inflate(R.layout.add_to_option, null);
-        textView.setText(labelResource);
+        if (position == RECENT_FOLDER) {
+            textView.setText(mRecentFolderName);
+        } else {
+            textView.setText(labelResource);
+        }
         Drawable drawable = context.getResources().getDrawable(drawableResource);
         textView.setCompoundDrawablesWithIntrinsicBounds(drawable, null,
                 null, null);
@@ -90,7 +108,10 @@
 
     @Override
     public int getCount() {
-        return mIncludeHomeScreen ? 3 : 2;
+        int count = 2;
+        if (mIncludeHomeScreen) count++;
+        if (mIncludesRecentFolder) count++;
+        return count;
     }
 
     @Override
diff --git a/src/com/android/browser/preferences/GeneralPreferencesFragment.java b/src/com/android/browser/preferences/GeneralPreferencesFragment.java
index 33bfd9c..1c82e1c 100644
--- a/src/com/android/browser/preferences/GeneralPreferencesFragment.java
+++ b/src/com/android/browser/preferences/GeneralPreferencesFragment.java
@@ -25,6 +25,8 @@
 
 import android.accounts.Account;
 import android.accounts.AccountManager;
+import android.accounts.AccountManagerCallback;
+import android.accounts.AccountManagerFuture;
 import android.app.AlertDialog;
 import android.app.Dialog;
 import android.app.DialogFragment;
@@ -132,6 +134,40 @@
 
     };
 
+    private AccountManagerCallback<Bundle> mCallback =
+            new AccountManagerCallback<Bundle>() {
+
+        @Override
+        public void run(AccountManagerFuture<Bundle> future) {
+            try {
+                Bundle bundle = future.getResult();
+                String name = bundle.getString(AccountManager.KEY_ACCOUNT_NAME);
+                String type = bundle.getString(AccountManager.KEY_ACCOUNT_TYPE);
+                Account account = new Account(name, type);
+                Fragment frag = new ImportWizardDialog();
+                Bundle extras = mChromeSync.getExtras();
+                extras.putParcelableArray("accounts", new Account[] { account });
+                frag.setArguments(extras);
+                getFragmentManager().beginTransaction()
+                        .add(frag, null)
+                        .commit();
+            } catch (Exception ex) {
+                // Canceled or failed to login, doesn't matter to us
+            }
+        }
+    };
+
+    OnPreferenceClickListener mAddAccount = new OnPreferenceClickListener() {
+
+        @Override
+        public boolean onPreferenceClick(Preference preference) {
+            AccountManager am = AccountManager.get(getActivity());
+            am.addAccount("com.google", null, null, null, getActivity(),
+                    mCallback, null);
+            return true;
+        }
+    };
+
     private class GetAccountsTask extends AsyncTask<Void, Void, String> {
         private Context mContext;
 
@@ -146,7 +182,7 @@
             if (accounts == null || accounts.length == 0) {
                 // No Google accounts setup, don't offer Chrome sync
                 if (mChromeSync != null) {
-                    getPreferenceScreen().removePreference(mChromeSync);
+                    mChromeSync.setOnPreferenceClickListener(mAddAccount);
                 }
             } else {
                 // Google accounts are present.