am 9141437c: Merge "New Bookmark Import wizard" into honeycomb-mr1

* commit '9141437ca3f1fc44051d66df1b7379466f915895':
  New Bookmark Import wizard
diff --git a/res/layout/bookmark_sync_wizard.xml b/res/layout/bookmark_sync_wizard.xml
new file mode 100644
index 0000000..3a3d9da
--- /dev/null
+++ b/res/layout/bookmark_sync_wizard.xml
@@ -0,0 +1,78 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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.
+-->
+<view class="com.android.browser.view.EventRedirectingFrameLayout"
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:id="@+id/pages"
+    android:paddingTop="6dip">
+
+    <LinearLayout
+        android:layout_width="match_parent"
+        android:layout_height="match_parent"
+        android:orientation="vertical"
+        android:background="@android:color/black">
+
+        <TextView
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:text="@string/import_bookmarks_dialog_description"
+            android:textAppearance="?android:attr/textAppearanceMedium"
+            android:textColor="?android:attr/textColorAlertDialogListItem" />
+
+        <ListView
+            android:id="@+id/add_remove_bookmarks"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:layout_marginTop="10dp"
+            android:divider="?android:attr/listDividerAlertDialog"
+            android:scrollbars="vertical"
+            android:overScrollMode="ifContentScrolls"
+            android:choiceMode="singleChoice" />
+
+    </LinearLayout>
+
+    <LinearLayout
+        android:layout_width="match_parent"
+        android:layout_height="match_parent"
+        android:orientation="vertical"
+        android:background="@android:color/black">
+
+        <TextView
+            android:id="@+id/select_account_description"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:textAppearance="?android:attr/textAppearanceMedium"
+            android:textColor="?android:attr/textColorAlertDialogListItem" />
+
+        <ListView
+            android:id="@+id/select_account"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:layout_marginTop="10dp"
+            android:divider="?android:attr/listDividerAlertDialog"
+            android:scrollbars="vertical"
+            android:overScrollMode="ifContentScrolls"
+            android:choiceMode="singleChoice" />
+
+    </LinearLayout>
+
+    <TextView
+        android:id="@+id/confirm"
+        android:layout_width="match_parent"
+        android:layout_height="match_parent"
+        android:background="@android:color/black"
+        android:textAppearance="?android:attr/textAppearanceMedium" />
+
+</view>
diff --git a/res/layout/bookmark_sync_wizard_item.xml b/res/layout/bookmark_sync_wizard_item.xml
new file mode 100644
index 0000000..91ec3de
--- /dev/null
+++ b/res/layout/bookmark_sync_wizard_item.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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.
+-->
+
+<CheckedTextView xmlns:android="http://schemas.android.com/apk/res/android"
+    android:id="@android:id/text1"
+    android:layout_width="match_parent"
+    android:layout_height="?android:attr/listPreferredItemHeight"
+    android:textAppearance="?android:attr/textAppearanceMedium"
+    android:gravity="center_vertical"
+    android:checkMark="?android:attr/listChoiceIndicatorSingle"
+    android:paddingLeft="6dip"
+    android:paddingRight="6dip"
+/>
diff --git a/src/com/android/browser/preferences/GeneralPreferencesFragment.java b/src/com/android/browser/preferences/GeneralPreferencesFragment.java
index 9c763e9..d64f062 100644
--- a/src/com/android/browser/preferences/GeneralPreferencesFragment.java
+++ b/src/com/android/browser/preferences/GeneralPreferencesFragment.java
@@ -30,35 +30,19 @@
 import android.app.AlertDialog;
 import android.app.Dialog;
 import android.app.DialogFragment;
-import android.app.Fragment;
-import android.content.ContentProviderOperation;
-import android.content.ContentResolver;
-import android.content.ContentValues;
 import android.content.Context;
 import android.content.DialogInterface;
-import android.content.OperationApplicationException;
 import android.content.SharedPreferences;
 import android.content.SharedPreferences.OnSharedPreferenceChangeListener;
-import android.database.Cursor;
 import android.os.AsyncTask;
 import android.os.Bundle;
-import android.os.RemoteException;
 import android.preference.Preference;
 import android.preference.Preference.OnPreferenceClickListener;
 import android.preference.PreferenceFragment;
 import android.preference.PreferenceManager;
 import android.preference.PreferenceScreen;
 import android.provider.BrowserContract;
-import android.provider.BrowserContract.Bookmarks;
-import android.provider.BrowserContract.ChromeSyncColumns;
 import android.util.Log;
-import android.view.LayoutInflater;
-import android.view.View;
-import android.view.View.OnClickListener;
-import android.widget.Button;
-import android.widget.LinearLayout;
-
-import java.util.ArrayList;
 
 public class GeneralPreferencesFragment extends PreferenceFragment
         implements OnPreferenceClickListener, Preference.OnPreferenceChangeListener {
@@ -69,6 +53,7 @@
     Preference mChromeSync;
     boolean mEnabled;
     SharedPreferences mSharedPrefs;
+    Account[] mAccounts;
 
     @Override
     public void onCreate(Bundle savedInstanceState) {
@@ -144,13 +129,9 @@
                 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();
+                mAccounts = new Account[] { account };
+                ImportWizard wizard = ImportWizard.newInstance(mAccounts);
+                wizard.show(getFragmentManager(), null);
             } catch (Exception ex) {
                 // Canceled or failed to login, doesn't matter to us
             }
@@ -186,6 +167,7 @@
                 }
             } else {
                 // Google accounts are present.
+                mAccounts = accounts;
                 SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(mContext);
                 Bundle args = mChromeSync.getExtras();
                 args.putParcelableArray("accounts", accounts);
@@ -226,16 +208,18 @@
 
     @Override
     public boolean onPreferenceClick(Preference preference) {
-        Fragment frag;
+        if (mAccounts == null) {
+            Log.w(TAG, "NULL accounts!");
+            return true;
+        }
+        DialogFragment frag;
         if (mEnabled) {
             frag = new AccountChooserDialog();
+            frag.setArguments(preference.getExtras());
         } else {
-            frag = new ImportWizardDialog();
+            frag = ImportWizard.newInstance(mAccounts);
         }
-        frag.setArguments(preference.getExtras());
-        getFragmentManager().beginTransaction()
-                .add(frag, null)
-                .commit();
+        frag.show(getFragmentManager(), null);
         return true;
     }
 
@@ -276,196 +260,4 @@
             dismiss();
         }
     }
-
-    public static class ImportWizardDialog extends DialogFragment implements OnClickListener {
-        View mRemoveButton;
-        View mCancelButton;
-        String mDefaultAccount;
-
-        @Override
-        public Dialog onCreateDialog(Bundle savedInstanceState) {
-            Context context = getActivity();
-            Dialog dialog = new Dialog(context);
-            dialog.setTitle(R.string.import_bookmarks_dialog_title);
-            dialog.setContentView(R.layout.import_bookmarks_dialog);
-            mRemoveButton = dialog.findViewById(R.id.remove);
-            mRemoveButton.setOnClickListener(this);
-            mCancelButton = dialog.findViewById(R.id.cancel);
-            mCancelButton.setOnClickListener(this);
-
-            LayoutInflater inflater = dialog.getLayoutInflater();
-            LinearLayout accountList = (LinearLayout) dialog.findViewById(R.id.accountList);
-            Account[] accounts = (Account[]) getArguments().getParcelableArray("accounts");
-            mDefaultAccount = accounts[0].name;
-            int length = accounts.length;
-            for (int i = 0; i < length; i++) {
-                Button button = (Button) inflater.inflate(R.layout.import_bookmarks_dialog_button,
-                        null);
-                button.setText(context.getString(R.string.import_bookmarks_dialog_import,
-                        accounts[i].name));
-                button.setTag(accounts[i].name);
-                button.setOnClickListener(this);
-                accountList.addView(button);
-            }
-
-            return dialog;
-        }
-
-        @Override
-        public void onClick(View view) {
-            if (view == mCancelButton) {
-                dismiss();
-                return;
-            }
-
-            ContentResolver resolver = getActivity().getContentResolver();
-            SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(getActivity());
-            String accountName;
-            if (view == mRemoveButton) {
-                // The user chose to remove their old bookmarks, delete them now
-                resolver.delete(Bookmarks.CONTENT_URI,
-                        Bookmarks.PARENT + "=1 AND " + Bookmarks.ACCOUNT_NAME + " IS NULL", null);
-                accountName = mDefaultAccount;
-            } else {
-                // The user chose to migrate their old bookmarks to the account they're syncing
-                accountName = view.getTag().toString();
-                migrateBookmarks(resolver, accountName);
-            }
-
-            // Record the fact that we turned on sync
-            BrowserContract.Settings.setSyncEnabled(getActivity(), true);
-            prefs.edit()
-                    .putString(BrowserBookmarksPage.PREF_ACCOUNT_TYPE, "com.google")
-                    .putString(BrowserBookmarksPage.PREF_ACCOUNT_NAME, accountName)
-                    .apply();
-
-            // Enable bookmark sync on all accounts
-            Account[] accounts = (Account[]) getArguments().getParcelableArray("accounts");
-            for (Account account : accounts) {
-                if (ContentResolver.getIsSyncable(account, BrowserContract.AUTHORITY) == 0) {
-                    // Account wasn't syncable, enable it
-                    ContentResolver.setIsSyncable(account, BrowserContract.AUTHORITY, 1);
-                    ContentResolver.setSyncAutomatically(account, BrowserContract.AUTHORITY, true);
-                }
-            }
-
-            dismiss();
-        }
-
-        /**
-         * Migrates bookmarks to the given account
-         */
-        void migrateBookmarks(ContentResolver resolver, String accountName) {
-            Cursor cursor = null;
-            try {
-                // Re-parent the bookmarks in the default root folder
-                cursor = resolver.query(Bookmarks.CONTENT_URI, new String[] { Bookmarks._ID },
-                        Bookmarks.ACCOUNT_NAME + " =? AND " +
-                            ChromeSyncColumns.SERVER_UNIQUE + " =?",
-                        new String[] { accountName,
-                            ChromeSyncColumns.FOLDER_NAME_BOOKMARKS_BAR },
-                        null);
-                ContentValues values = new ContentValues();
-                if (cursor == null || !cursor.moveToFirst()) {
-                    // The root folders don't exist for the account, create them now
-                    ArrayList<ContentProviderOperation> ops =
-                            new ArrayList<ContentProviderOperation>();
-
-                    // Chrome sync root folder
-                    values.clear();
-                    values.put(ChromeSyncColumns.SERVER_UNIQUE, ChromeSyncColumns.FOLDER_NAME_ROOT);
-                    values.put(Bookmarks.TITLE, "Google Chrome");
-                    values.put(Bookmarks.POSITION, 0);
-                    values.put(Bookmarks.IS_FOLDER, true);
-                    values.put(Bookmarks.DIRTY, true);
-                    ops.add(ContentProviderOperation.newInsert(
-                            Bookmarks.CONTENT_URI.buildUpon().appendQueryParameter(
-                                    BrowserContract.CALLER_IS_SYNCADAPTER, "true").build())
-                            .withValues(values)
-                            .build());
-
-                    // Bookmarks folder
-                    values.clear();
-                    values.put(ChromeSyncColumns.SERVER_UNIQUE,
-                            ChromeSyncColumns.FOLDER_NAME_BOOKMARKS);
-                    values.put(Bookmarks.TITLE, "Bookmarks");
-                    values.put(Bookmarks.POSITION, 0);
-                    values.put(Bookmarks.IS_FOLDER, true);
-                    values.put(Bookmarks.DIRTY, true);
-                    ops.add(ContentProviderOperation.newInsert(Bookmarks.CONTENT_URI)
-                            .withValues(values)
-                            .withValueBackReference(Bookmarks.PARENT, 0)
-                            .build());
-
-                    // Bookmarks Bar folder
-                    values.clear();
-                    values.put(ChromeSyncColumns.SERVER_UNIQUE,
-                            ChromeSyncColumns.FOLDER_NAME_BOOKMARKS_BAR);
-                    values.put(Bookmarks.TITLE, "Bookmarks Bar");
-                    values.put(Bookmarks.POSITION, 0);
-                    values.put(Bookmarks.IS_FOLDER, true);
-                    values.put(Bookmarks.DIRTY, true);
-                    ops.add(ContentProviderOperation.newInsert(Bookmarks.CONTENT_URI)
-                            .withValues(values)
-                            .withValueBackReference(Bookmarks.PARENT, 1)
-                            .build());
-
-                    // Other Bookmarks folder
-                    values.clear();
-                    values.put(ChromeSyncColumns.SERVER_UNIQUE,
-                            ChromeSyncColumns.FOLDER_NAME_OTHER_BOOKMARKS);
-                    values.put(Bookmarks.TITLE, "Other Bookmarks");
-                    values.put(Bookmarks.POSITION, 1000);
-                    values.put(Bookmarks.IS_FOLDER, true);
-                    values.put(Bookmarks.DIRTY, true);
-                    ops.add(ContentProviderOperation.newInsert(Bookmarks.CONTENT_URI)
-                            .withValues(values)
-                            .withValueBackReference(Bookmarks.PARENT, 1)
-                            .build());
-
-                    // Re-parent the existing bookmarks to the newly create bookmarks bar folder
-                    ops.add(ContentProviderOperation.newUpdate(Bookmarks.CONTENT_URI)
-                            .withValueBackReference(Bookmarks.PARENT, 2)
-                            .withSelection(Bookmarks.ACCOUNT_NAME + " IS NULL AND " +
-                                    Bookmarks.PARENT + "=?",
-                                        new String[] { Integer.toString(1) })
-                            .build());
-
-                    // Mark all non-root folder items as belonging to the new account
-                    values.clear();
-                    values.put(Bookmarks.ACCOUNT_TYPE, "com.google");
-                    values.put(Bookmarks.ACCOUNT_NAME, accountName);
-                    ops.add(ContentProviderOperation.newUpdate(Bookmarks.CONTENT_URI)
-                            .withValues(values)
-                            .withSelection(Bookmarks.ACCOUNT_NAME + " IS NULL AND " +
-                                    Bookmarks._ID + "<>1", null)
-                            .build());
-
-                    try {
-                        resolver.applyBatch(BrowserContract.AUTHORITY, ops);
-                    } catch (RemoteException e) {
-                        Log.e(TAG, "failed to create root folder for account " + accountName, e);
-                        return;
-                    } catch (OperationApplicationException e) {
-                        Log.e(TAG, "failed to create root folder for account " + accountName, e);
-                        return;
-                    }
-                } else {
-                    values.put(Bookmarks.PARENT, cursor.getLong(0));
-                    resolver.update(Bookmarks.CONTENT_URI, values, Bookmarks.PARENT + "=?",
-                            new String[] { Integer.toString(1) });
-
-                    // Mark all bookmarks at all levels as part of the new account
-                    values.clear();
-                    values.put(Bookmarks.ACCOUNT_TYPE, "com.google");
-                    values.put(Bookmarks.ACCOUNT_NAME, accountName);
-                    resolver.update(Bookmarks.CONTENT_URI, values,
-                            Bookmarks.ACCOUNT_NAME + " IS NULL AND " + Bookmarks._ID + "<>1",
-                            null);
-                }
-            } finally {
-                if (cursor != null) cursor.close();
-            }
-        }
-    }
 }
diff --git a/src/com/android/browser/preferences/ImportWizard.java b/src/com/android/browser/preferences/ImportWizard.java
new file mode 100644
index 0000000..7105f4d
--- /dev/null
+++ b/src/com/android/browser/preferences/ImportWizard.java
@@ -0,0 +1,491 @@
+/*
+ * 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.preferences;
+
+import com.android.browser.BrowserBookmarksPage;
+import com.android.browser.R;
+import com.android.browser.view.EventRedirectingFrameLayout;
+
+import android.accounts.Account;
+import android.animation.LayoutTransition;
+import android.animation.ObjectAnimator;
+import android.app.AlertDialog;
+import android.app.Dialog;
+import android.app.DialogFragment;
+import android.content.ContentProviderOperation;
+import android.content.ContentResolver;
+import android.content.ContentValues;
+import android.content.DialogInterface;
+import android.content.DialogInterface.OnKeyListener;
+import android.content.DialogInterface.OnShowListener;
+import android.content.OperationApplicationException;
+import android.content.SharedPreferences;
+import android.content.res.Resources;
+import android.database.Cursor;
+import android.os.Bundle;
+import android.os.RemoteException;
+import android.preference.PreferenceManager;
+import android.provider.BrowserContract;
+import android.provider.BrowserContract.Bookmarks;
+import android.provider.BrowserContract.ChromeSyncColumns;
+import android.util.Log;
+import android.view.KeyEvent;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.View.OnClickListener;
+import android.widget.AdapterView;
+import android.widget.AdapterView.OnItemClickListener;
+import android.widget.ArrayAdapter;
+import android.widget.Button;
+import android.widget.ListView;
+import android.widget.TextView;
+
+import java.util.ArrayList;
+
+public class ImportWizard extends DialogFragment implements OnClickListener,
+        OnItemClickListener {
+
+    static final String TAG = "BookmarkImportWizard";
+
+    static final int PAGE_IMPORT_OR_DELETE = 0;
+    static final int PAGE_SELECT_ACCOUNT = 1;
+    static final int PAGE_CONFIRMATION = 2;
+
+    static final String STATE_CURRENT_PAGE = "wizard.current_page";
+    static final String STATE_IMPORT_OR_DELETE = "wizard.import_or_delete";
+    static final String STATE_SELECTED_ACCOUNT = "wizard.selected_account";
+
+    static final String ARG_ACCOUNTS = "accounts";
+
+    AlertDialog mDialog;
+    EventRedirectingFrameLayout mPages;
+    int mCurrentPage;
+    Button mPositiveButton, mNegativeButton;
+    ListView mImportOrDelete, mSelectAccount;
+    Account[] mAccounts;
+    TextView mSelectAccountDescription, mConfirmation;
+
+    static ImportWizard newInstance(Account[] accounts) {
+        ImportWizard wizard = new ImportWizard();
+        Bundle args = new Bundle();
+        args.putParcelableArray(ARG_ACCOUNTS, accounts);
+        wizard.setArguments(args);
+        return wizard;
+    }
+
+    @Override
+    public void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        mAccounts = (Account[]) getArguments().getParcelableArray(ARG_ACCOUNTS);
+    }
+
+    @Override
+    public Dialog onCreateDialog(Bundle savedInstanceState) {
+        mDialog = new AlertDialog.Builder(getActivity())
+                .setTitle(R.string.import_bookmarks_dialog_title)
+                .setView(createView(savedInstanceState))
+                .setPositiveButton("?", null) // This is just a placeholder
+                .setNegativeButton("?", null) // Ditto
+                .setOnKeyListener(new OnKeyListener() {
+                    @Override
+                    public boolean onKey(DialogInterface arg0, int arg1, KeyEvent key) {
+                        if (key.getKeyCode() == KeyEvent.KEYCODE_BACK) {
+                            if (key.getAction() == KeyEvent.ACTION_UP
+                                    && !key.isCanceled()) {
+                                mNegativeButton.performClick();
+                            }
+                            return true;
+                        }
+                        return false;
+                    }
+                })
+                .create();
+        mDialog.setOnShowListener(new OnShowListener() {
+            @Override
+            public void onShow(DialogInterface dialog) {
+                mPositiveButton = mDialog.getButton(AlertDialog.BUTTON_POSITIVE);
+                mNegativeButton = mDialog.getButton(AlertDialog.BUTTON_NEGATIVE);
+                mPositiveButton.setOnClickListener(ImportWizard.this);
+                mNegativeButton.setOnClickListener(ImportWizard.this);
+                setupAnimations();
+                updateNavigation();
+            }
+        });
+        return mDialog;
+    }
+
+    @Override
+    public void onSaveInstanceState(Bundle outState) {
+        super.onSaveInstanceState(outState);
+        outState.putInt(STATE_CURRENT_PAGE, mCurrentPage);
+        outState.putInt(STATE_IMPORT_OR_DELETE, mImportOrDelete.getCheckedItemPosition());
+        outState.putInt(STATE_SELECTED_ACCOUNT, mSelectAccount.getCheckedItemPosition());
+    }
+
+    public View createView(Bundle savedInstanceState) {
+        LayoutInflater inflater = LayoutInflater.from(getActivity());
+        View root = inflater.inflate(R.layout.bookmark_sync_wizard, null);
+        mPages = (EventRedirectingFrameLayout) root.findViewById(R.id.pages);
+        if (mPages.getChildCount() < 1) {
+            throw new IllegalStateException("no pages in wizard!");
+        }
+        if (savedInstanceState != null) {
+            mCurrentPage = savedInstanceState.getInt(STATE_CURRENT_PAGE);
+        } else {
+            mCurrentPage = 0;
+        }
+        setupPage1(savedInstanceState);
+        setupPage2(savedInstanceState);
+        setupPage3(savedInstanceState);
+        for (int i = 0; i < mPages.getChildCount(); i++) {
+            View v = mPages.getChildAt(i);
+            if (i <= mCurrentPage) {
+                preparePage();
+                v.setVisibility(View.VISIBLE);
+            } else {
+                v.setVisibility(View.GONE);
+            }
+        }
+        mPages.setTargetChild(mCurrentPage);
+        return root;
+    }
+
+    void setupPage1(Bundle savedInstanceState) {
+        mImportOrDelete = (ListView) mPages.findViewById(R.id.add_remove_bookmarks);
+        // Add an empty header so we get a divider above the list
+        mImportOrDelete.addHeaderView(new View(getActivity()));
+        Resources res = getActivity().getResources();
+        String[] choices = new String[] {
+                res.getString(R.string.import_bookmarks_dialog_add),
+                res.getString(R.string.import_bookmarks_dialog_remove)
+        };
+        ArrayAdapter<String> adapter = new ArrayAdapter<String>(getActivity(),
+                R.layout.bookmark_sync_wizard_item, choices);
+        mImportOrDelete.setAdapter(adapter);
+        if (savedInstanceState != null) {
+            int position = savedInstanceState.getInt(STATE_IMPORT_OR_DELETE);
+            if (position == ListView.INVALID_POSITION) {
+                mImportOrDelete.clearChoices();
+            } else {
+                mImportOrDelete.setItemChecked(position, true);
+            }
+        }
+        mImportOrDelete.setOnItemClickListener(this);
+    }
+
+    void setupPage2(Bundle savedInstanceState) {
+        mSelectAccount = (ListView) mPages.findViewById(R.id.select_account);
+        mSelectAccountDescription =
+                (TextView) mPages.findViewById(R.id.select_account_description);
+        // Add an empty header so we get a divider above the list
+        mSelectAccount.addHeaderView(new View(getActivity()));
+        Resources res = getActivity().getResources();
+        String[] accountNames = new String[mAccounts.length];
+        for (int i = 0; i < mAccounts.length; i++) {
+            accountNames[i] = mAccounts[i].name;
+        }
+        ArrayAdapter<String> adapter = new ArrayAdapter<String>(getActivity(),
+                R.layout.bookmark_sync_wizard_item, accountNames);
+        mSelectAccount.setAdapter(adapter);
+        mSelectAccount.setItemChecked(mSelectAccount.getHeaderViewsCount(), true);
+        if (savedInstanceState != null) {
+            int position = savedInstanceState.getInt(STATE_SELECTED_ACCOUNT);
+            if (position != ListView.INVALID_POSITION) {
+                mSelectAccount.setItemChecked(position, true);
+            }
+        }
+        mSelectAccount.setOnItemClickListener(this);
+    }
+
+    void setupPage3(Bundle savedInstanceState) {
+        mConfirmation = (TextView) mPages.findViewById(R.id.confirm);
+    }
+
+    void preparePage() {
+        switch (mCurrentPage) {
+        case PAGE_SELECT_ACCOUNT:
+            if (shouldDeleteBookmarks()) {
+                mSelectAccountDescription.setText(
+                        R.string.import_bookmarks_dialog_delete_select_account);
+            } else {
+                mSelectAccountDescription.setText(
+                        R.string.import_bookmarks_dialog_select_add_account);
+            }
+            break;
+        case PAGE_CONFIRMATION:
+            String account = getSelectedAccount().name;
+            String confirmationMessage;
+            if (shouldDeleteBookmarks()) {
+                confirmationMessage = getActivity().getString(
+                        R.string.import_bookmarks_dialog_confirm_delete, account);
+            } else {
+                confirmationMessage = getActivity().getString(
+                        R.string.import_bookmarks_dialog_confirm_add, account);
+            }
+            mConfirmation.setText(confirmationMessage);
+            break;
+        }
+    }
+
+    int getAdjustedCheckedItemPosition(ListView list) {
+        int position = list.getCheckedItemPosition();
+        if (position != ListView.INVALID_POSITION) {
+            position -= list.getHeaderViewsCount();
+        }
+        return position;
+    }
+
+    Account getSelectedAccount() {
+        return mAccounts[getAdjustedCheckedItemPosition(mSelectAccount)];
+    }
+
+    boolean shouldDeleteBookmarks() {
+        return getAdjustedCheckedItemPosition(mImportOrDelete) == 1;
+    }
+
+    @Override
+    public void onItemClick(
+            AdapterView<?> parent, View view, int position, long id) {
+        validate();
+    }
+
+    void updateNavigation() {
+        if (mCurrentPage == 0) {
+            mNegativeButton.setText(R.string.import_bookmarks_wizard_cancel);
+        } else {
+            mNegativeButton.setText(R.string.import_bookmarks_wizard_previous);
+        }
+        if ((mCurrentPage + 1) == mPages.getChildCount()) {
+            mPositiveButton.setText(R.string.import_bookmarks_wizard_done);
+        } else {
+            mPositiveButton.setText(R.string.import_bookmarks_wizard_next);
+        }
+        validate();
+    }
+
+    void validate() {
+        switch (mCurrentPage) {
+        case PAGE_IMPORT_OR_DELETE:
+            mPositiveButton.setEnabled(
+                    mImportOrDelete.getCheckedItemPosition() != ListView.INVALID_POSITION);
+            break;
+        case PAGE_SELECT_ACCOUNT:
+            mPositiveButton.setEnabled(
+                    mSelectAccount.getCheckedItemPosition() != ListView.INVALID_POSITION);
+            break;
+        }
+    }
+
+    void setupAnimations() {
+        float animX = mPages.getMeasuredWidth();
+        final LayoutTransition transitioner = new LayoutTransition();
+        ObjectAnimator appearing = ObjectAnimator.ofFloat(this, "translationX",
+                animX, 0);
+        ObjectAnimator disappearing = ObjectAnimator.ofFloat(this, "translationX",
+                0, animX);
+        transitioner.setAnimator(LayoutTransition.APPEARING, appearing);
+        transitioner.setAnimator(LayoutTransition.DISAPPEARING, disappearing);
+        mPages.setLayoutTransition(transitioner);
+    }
+
+    boolean next() {
+        if (mCurrentPage + 1 < mPages.getChildCount()) {
+            mCurrentPage++;
+            preparePage();
+            mPages.getChildAt(mCurrentPage).setVisibility(View.VISIBLE);
+            mPages.setTargetChild(mCurrentPage);
+            return true;
+        }
+        return false;
+    }
+
+    boolean prev() {
+        if (mCurrentPage > 0) {
+            mPages.getChildAt(mCurrentPage).setVisibility(View.GONE);
+            mCurrentPage--;
+            mPages.setTargetChild(mCurrentPage);
+            return true;
+        }
+        return false;
+    }
+
+    void done() {
+        ContentResolver resolver = getActivity().getContentResolver();
+        SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(getActivity());
+        String accountName = getSelectedAccount().name;
+        if (shouldDeleteBookmarks()) {
+            // The user chose to remove their old bookmarks, delete them now
+            resolver.delete(Bookmarks.CONTENT_URI,
+                    Bookmarks.PARENT + "=1 AND " + Bookmarks.ACCOUNT_NAME + " IS NULL", null);
+        } else {
+            // The user chose to migrate their old bookmarks to the account they're syncing
+            migrateBookmarks(resolver, accountName);
+        }
+
+        // Record the fact that we turned on sync
+        BrowserContract.Settings.setSyncEnabled(getActivity(), true);
+        prefs.edit()
+                .putString(BrowserBookmarksPage.PREF_ACCOUNT_TYPE, "com.google")
+                .putString(BrowserBookmarksPage.PREF_ACCOUNT_NAME, accountName)
+                .apply();
+
+        // Enable bookmark sync on all accounts
+        Account[] accounts = (Account[]) getArguments().getParcelableArray("accounts");
+        for (Account account : accounts) {
+            if (ContentResolver.getIsSyncable(account, BrowserContract.AUTHORITY) == 0) {
+                // Account wasn't syncable, enable it
+                ContentResolver.setIsSyncable(account, BrowserContract.AUTHORITY, 1);
+                ContentResolver.setSyncAutomatically(account, BrowserContract.AUTHORITY, true);
+            }
+        }
+
+        dismiss();
+    }
+
+    @Override
+    public void onClick(View v) {
+        if (v == mNegativeButton) {
+            if (prev()) {
+                updateNavigation();
+            } else {
+                dismiss();
+            }
+        } else if (v == mPositiveButton) {
+            if (next()) {
+                updateNavigation();
+            } else {
+                done();
+            }
+        }
+    }
+
+    /**
+     * Migrates bookmarks to the given account
+     */
+    void migrateBookmarks(ContentResolver resolver, String accountName) {
+        Cursor cursor = null;
+        try {
+            // Re-parent the bookmarks in the default root folder
+            cursor = resolver.query(Bookmarks.CONTENT_URI, new String[] { Bookmarks._ID },
+                    Bookmarks.ACCOUNT_NAME + " =? AND " +
+                        ChromeSyncColumns.SERVER_UNIQUE + " =?",
+                    new String[] { accountName,
+                        ChromeSyncColumns.FOLDER_NAME_BOOKMARKS_BAR },
+                    null);
+            ContentValues values = new ContentValues();
+            if (cursor == null || !cursor.moveToFirst()) {
+                // The root folders don't exist for the account, create them now
+                ArrayList<ContentProviderOperation> ops =
+                        new ArrayList<ContentProviderOperation>();
+
+                // Chrome sync root folder
+                values.clear();
+                values.put(ChromeSyncColumns.SERVER_UNIQUE, ChromeSyncColumns.FOLDER_NAME_ROOT);
+                values.put(Bookmarks.TITLE, "Google Chrome");
+                values.put(Bookmarks.POSITION, 0);
+                values.put(Bookmarks.IS_FOLDER, true);
+                values.put(Bookmarks.DIRTY, true);
+                ops.add(ContentProviderOperation.newInsert(
+                        Bookmarks.CONTENT_URI.buildUpon().appendQueryParameter(
+                                BrowserContract.CALLER_IS_SYNCADAPTER, "true").build())
+                        .withValues(values)
+                        .build());
+
+                // Bookmarks folder
+                values.clear();
+                values.put(ChromeSyncColumns.SERVER_UNIQUE,
+                        ChromeSyncColumns.FOLDER_NAME_BOOKMARKS);
+                values.put(Bookmarks.TITLE, "Bookmarks");
+                values.put(Bookmarks.POSITION, 0);
+                values.put(Bookmarks.IS_FOLDER, true);
+                values.put(Bookmarks.DIRTY, true);
+                ops.add(ContentProviderOperation.newInsert(Bookmarks.CONTENT_URI)
+                        .withValues(values)
+                        .withValueBackReference(Bookmarks.PARENT, 0)
+                        .build());
+
+                // Bookmarks Bar folder
+                values.clear();
+                values.put(ChromeSyncColumns.SERVER_UNIQUE,
+                        ChromeSyncColumns.FOLDER_NAME_BOOKMARKS_BAR);
+                values.put(Bookmarks.TITLE, "Bookmarks Bar");
+                values.put(Bookmarks.POSITION, 0);
+                values.put(Bookmarks.IS_FOLDER, true);
+                values.put(Bookmarks.DIRTY, true);
+                ops.add(ContentProviderOperation.newInsert(Bookmarks.CONTENT_URI)
+                        .withValues(values)
+                        .withValueBackReference(Bookmarks.PARENT, 1)
+                        .build());
+
+                // Other Bookmarks folder
+                values.clear();
+                values.put(ChromeSyncColumns.SERVER_UNIQUE,
+                        ChromeSyncColumns.FOLDER_NAME_OTHER_BOOKMARKS);
+                values.put(Bookmarks.TITLE, "Other Bookmarks");
+                values.put(Bookmarks.POSITION, 1000);
+                values.put(Bookmarks.IS_FOLDER, true);
+                values.put(Bookmarks.DIRTY, true);
+                ops.add(ContentProviderOperation.newInsert(Bookmarks.CONTENT_URI)
+                        .withValues(values)
+                        .withValueBackReference(Bookmarks.PARENT, 1)
+                        .build());
+
+                // Re-parent the existing bookmarks to the newly create bookmarks bar folder
+                ops.add(ContentProviderOperation.newUpdate(Bookmarks.CONTENT_URI)
+                        .withValueBackReference(Bookmarks.PARENT, 2)
+                        .withSelection(Bookmarks.ACCOUNT_NAME + " IS NULL AND " +
+                                Bookmarks.PARENT + "=?",
+                                    new String[] { Integer.toString(1) })
+                        .build());
+
+                // Mark all non-root folder items as belonging to the new account
+                values.clear();
+                values.put(Bookmarks.ACCOUNT_TYPE, "com.google");
+                values.put(Bookmarks.ACCOUNT_NAME, accountName);
+                ops.add(ContentProviderOperation.newUpdate(Bookmarks.CONTENT_URI)
+                        .withValues(values)
+                        .withSelection(Bookmarks.ACCOUNT_NAME + " IS NULL AND " +
+                                Bookmarks._ID + "<>1", null)
+                        .build());
+
+                try {
+                    resolver.applyBatch(BrowserContract.AUTHORITY, ops);
+                } catch (RemoteException e) {
+                    Log.e(TAG, "failed to create root folder for account " + accountName, e);
+                    return;
+                } catch (OperationApplicationException e) {
+                    Log.e(TAG, "failed to create root folder for account " + accountName, e);
+                    return;
+                }
+            } else {
+                values.put(Bookmarks.PARENT, cursor.getLong(0));
+                resolver.update(Bookmarks.CONTENT_URI, values, Bookmarks.PARENT + "=?",
+                        new String[] { Integer.toString(1) });
+
+                // Mark all bookmarks at all levels as part of the new account
+                values.clear();
+                values.put(Bookmarks.ACCOUNT_TYPE, "com.google");
+                values.put(Bookmarks.ACCOUNT_NAME, accountName);
+                resolver.update(Bookmarks.CONTENT_URI, values,
+                        Bookmarks.ACCOUNT_NAME + " IS NULL AND " + Bookmarks._ID + "<>1",
+                        null);
+            }
+        } finally {
+            if (cursor != null) cursor.close();
+        }
+    }
+}
diff --git a/src/com/android/browser/view/EventRedirectingFrameLayout.java b/src/com/android/browser/view/EventRedirectingFrameLayout.java
new file mode 100644
index 0000000..901b021
--- /dev/null
+++ b/src/com/android/browser/view/EventRedirectingFrameLayout.java
@@ -0,0 +1,74 @@
+/*
+ * 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.view;
+
+import android.content.Context;
+import android.util.AttributeSet;
+import android.view.KeyEvent;
+import android.view.MotionEvent;
+import android.view.View;
+import android.widget.FrameLayout;
+
+public class EventRedirectingFrameLayout extends FrameLayout {
+
+    private int mTargetChild;
+
+    public EventRedirectingFrameLayout(Context context) {
+        super(context);
+    }
+
+    public EventRedirectingFrameLayout(Context context, AttributeSet attrs) {
+        super(context, attrs);
+    }
+
+    public EventRedirectingFrameLayout(
+            Context context, AttributeSet attrs, int defStyle) {
+        super(context, attrs, defStyle);
+    }
+
+    public void setTargetChild(int index) {
+        if (index >= 0 && index < getChildCount()) {
+            mTargetChild = index;
+            getChildAt(mTargetChild).requestFocus();
+        }
+    }
+
+    @Override
+    public boolean dispatchTouchEvent(MotionEvent ev) {
+        View child = getChildAt(mTargetChild);
+        if (child != null)
+            return child.dispatchTouchEvent(ev);
+        return false;
+    }
+
+    @Override
+    public boolean dispatchKeyEvent(KeyEvent event) {
+        View child = getChildAt(mTargetChild);
+        if (child != null)
+            return child.dispatchKeyEvent(event);
+        return false;
+    }
+
+    @Override
+    public boolean dispatchKeyEventPreIme(KeyEvent event) {
+        View child = getChildAt(mTargetChild);
+        if (child != null)
+            return child.dispatchKeyEventPreIme(event);
+        return false;
+    }
+
+}