Merge "SelectAccountDialogFragment: Handle orientation changes"
diff --git a/src/com/android/contacts/detail/ContactDetailFragment.java b/src/com/android/contacts/detail/ContactDetailFragment.java
index 767d366..aaeacab 100644
--- a/src/com/android/contacts/detail/ContactDetailFragment.java
+++ b/src/com/android/contacts/detail/ContactDetailFragment.java
@@ -36,6 +36,7 @@
 import com.android.contacts.model.EntityDelta.ValuesDelta;
 import com.android.contacts.model.EntityDeltaList;
 import com.android.contacts.model.EntityModifier;
+import com.android.contacts.util.AccountsListAdapter.AccountListFilter;
 import com.android.contacts.util.Constants;
 import com.android.contacts.util.DataStatus;
 import com.android.contacts.util.DateUtils;
@@ -1754,7 +1755,7 @@
     }
 
     @Override
-    public void onAccountChosen(int requestCode, AccountWithDataSet account) {
+    public void onAccountChosen(AccountWithDataSet account, Bundle extraArgs) {
         createCopy(account);
     }
 
@@ -2049,9 +2050,9 @@
                         return;  // Don't show a dialog.
                     }
 
-                    final SelectAccountDialogFragment dialog = new SelectAccountDialogFragment();
-                    dialog.setTargetFragment(ContactDetailFragment.this, 0);
-                    dialog.show(getFragmentManager(), SelectAccountDialogFragment.TAG);
+                    SelectAccountDialogFragment.show(getFragmentManager(),
+                            ContactDetailFragment.this, R.string.dialog_new_contact_account,
+                            AccountListFilter.ACCOUNTS_CONTACT_WRITABLE, null);
                     break;
                 }
             }
diff --git a/src/com/android/contacts/editor/SelectAccountDialogFragment.java b/src/com/android/contacts/editor/SelectAccountDialogFragment.java
index 3a8681a..42ac170 100644
--- a/src/com/android/contacts/editor/SelectAccountDialogFragment.java
+++ b/src/com/android/contacts/editor/SelectAccountDialogFragment.java
@@ -16,7 +16,6 @@
 
 package com.android.contacts.editor;
 
-import com.android.contacts.R;
 import com.android.contacts.model.AccountWithDataSet;
 import com.android.contacts.util.AccountsListAdapter;
 import com.android.contacts.util.AccountsListAdapter.AccountListFilter;
@@ -25,39 +24,58 @@
 import android.app.Dialog;
 import android.app.DialogFragment;
 import android.app.Fragment;
+import android.app.FragmentManager;
 import android.content.DialogInterface;
 import android.os.Bundle;
 
 /**
  * Shows a dialog asking the user which account to chose.
- * The result is passed back to the Fragment that is configured by
- * {@link Fragment#setTargetFragment(Fragment, int)}, which has to implement
- * {@link SelectAccountDialogFragment.Listener}.
- * Does not perform any action by itself.
+ *
+ * The result is passed to {@code targetFragment} passed to {@link #show}.
  */
-public class SelectAccountDialogFragment extends DialogFragment {
+public final class SelectAccountDialogFragment extends DialogFragment {
     public static final String TAG = "SelectAccountDialogFragment";
 
-    // TODO: This dialog is used in the context of group editing by default, but should be generic
-    // to work for contact editing as well. Save/restore the resource ID and account list filter
-    // that are passed in as parameters on device rotation. Bug: 5369853
-    private int mTitleResourceId = R.string.dialog_new_group_account;
-    private AccountListFilter mAccountListFilter = AccountListFilter.ACCOUNTS_GROUP_WRITABLE;
+    private static final String KEY_TITLE_RES_ID = "title_res_id";
+    private static final String KEY_LIST_FILTER = "list_filter";
+    private static final String KEY_EXTRA_ARGS = "extra_args";
 
-    public SelectAccountDialogFragment() {
+    public SelectAccountDialogFragment() { // All fragments must have a public default constructor.
     }
 
-    public SelectAccountDialogFragment(int titleResourceId, AccountListFilter accountListFilter) {
-        mTitleResourceId = titleResourceId;
-        mAccountListFilter = accountListFilter;
+    /**
+     * Show the dialog.
+     *
+     * @param fragmentManager {@link FragmentManager}.
+     * @param targetFragment {@link Fragment} that implements {@link Listener}.
+     * @param titleResourceId resource ID to use as the title.
+     * @param accountListFilter account filter.
+     * @param extraArgs Extra arguments, which will later be passed to
+     *     {@link Listener#onAccountChosen}.  {@code null} will be converted to
+     *     {@link Bundle#EMPTY}.
+     */
+    public static <F extends Fragment & Listener> void show(FragmentManager fragmentManager,
+            F targetFragment, int titleResourceId,
+            AccountListFilter accountListFilter, Bundle extraArgs) {
+        final Bundle args = new Bundle();
+        args.putInt(KEY_TITLE_RES_ID, titleResourceId);
+        args.putSerializable(KEY_LIST_FILTER, accountListFilter);
+        args.putBundle(KEY_EXTRA_ARGS, (extraArgs == null) ? Bundle.EMPTY : extraArgs);
+
+        final SelectAccountDialogFragment instance = new SelectAccountDialogFragment();
+        instance.setArguments(args);
+        instance.setTargetFragment(targetFragment, 0);
+        instance.show(fragmentManager, null);
     }
 
     @Override
     public Dialog onCreateDialog(Bundle savedInstanceState) {
         final AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
+        final Bundle args = getArguments();
 
+        final AccountListFilter filter = (AccountListFilter) args.getSerializable(KEY_LIST_FILTER);
         final AccountsListAdapter accountAdapter = new AccountsListAdapter(builder.getContext(),
-                mAccountListFilter);
+                filter);
 
         final DialogInterface.OnClickListener clickListener =
                 new DialogInterface.OnClickListener() {
@@ -69,7 +87,7 @@
             }
         };
 
-        builder.setTitle(mTitleResourceId);
+        builder.setTitle(args.getInt(KEY_TITLE_RES_ID));
         builder.setSingleChoiceItems(accountAdapter, 0, clickListener);
         final AlertDialog result = builder.create();
         return result;
@@ -86,19 +104,18 @@
     }
 
     /**
-     * Calls {@link Listener#onAccountChosen(int, AccountWithDataSet)} if the target fragment is
-     * castable to {@link Listener}. Subclasses can also overide to directly perform an operation.
+     * Calls {@link Listener#onAccountChosen} of {@code targetFragment}.
      */
-    protected void onAccountSelected(AccountWithDataSet account) {
+    private void onAccountSelected(AccountWithDataSet account) {
         final Fragment targetFragment = getTargetFragment();
         if (targetFragment != null && targetFragment instanceof Listener) {
             final Listener target = (Listener) targetFragment;
-            target.onAccountChosen(getTargetRequestCode(), account);
+            target.onAccountChosen(account, getArguments().getBundle(KEY_EXTRA_ARGS));
         }
     }
 
     public interface Listener {
-        void onAccountChosen(int requestCode, AccountWithDataSet account);
+        void onAccountChosen(AccountWithDataSet account, Bundle extraArgs);
         void onAccountSelectorCancelled();
     }
 }
diff --git a/src/com/android/contacts/group/GroupEditorFragment.java b/src/com/android/contacts/group/GroupEditorFragment.java
index 1d1237e..bb56b6e 100644
--- a/src/com/android/contacts/group/GroupEditorFragment.java
+++ b/src/com/android/contacts/group/GroupEditorFragment.java
@@ -332,14 +332,13 @@
         }
 
         mStatus = Status.SELECTING_ACCOUNT;
-        final SelectAccountDialogFragment dialog = new SelectAccountDialogFragment(
-                R.string.dialog_new_group_account, AccountListFilter.ACCOUNTS_GROUP_WRITABLE);
-        dialog.setTargetFragment(this, 0);
-        dialog.show(getFragmentManager(), SelectAccountDialogFragment.TAG);
+        SelectAccountDialogFragment.show(getFragmentManager(), this,
+                R.string.dialog_new_group_account, AccountListFilter.ACCOUNTS_GROUP_WRITABLE,
+                null);
     }
 
     @Override
-    public void onAccountChosen(int requestCode, AccountWithDataSet account) {
+    public void onAccountChosen(AccountWithDataSet account, Bundle extraArgs) {
         mAccountName = account.name;
         mAccountType = account.type;
         mDataSet = account.dataSet;
diff --git a/src/com/android/contacts/interactions/ImportExportDialogFragment.java b/src/com/android/contacts/interactions/ImportExportDialogFragment.java
index e0b617c..2eedfb3 100644
--- a/src/com/android/contacts/interactions/ImportExportDialogFragment.java
+++ b/src/com/android/contacts/interactions/ImportExportDialogFragment.java
@@ -21,6 +21,7 @@
 import com.android.contacts.model.AccountTypeManager;
 import com.android.contacts.model.AccountWithDataSet;
 import com.android.contacts.util.AccountSelectionUtil;
+import com.android.contacts.util.AccountsListAdapter.AccountListFilter;
 import com.android.contacts.vcard.ExportVCardActivity;
 
 import android.app.AlertDialog;
@@ -49,9 +50,12 @@
 /**
  * An dialog invoked to import/export contacts.
  */
-public class ImportExportDialogFragment extends DialogFragment {
+public class ImportExportDialogFragment extends DialogFragment
+        implements SelectAccountDialogFragment.Listener {
     public static final String TAG = "ImportExportDialogFragment";
 
+    private static final String KEY_RES_ID = "resourceId";
+
     private final String[] LOOKUP_PROJECTION = new String[] {
             Contacts.LOOKUP_KEY
     };
@@ -100,29 +104,34 @@
                 new DialogInterface.OnClickListener() {
             @Override
             public void onClick(DialogInterface dialog, int which) {
-                dialog.dismiss();
-
+                boolean dismissDialog;
                 final int resId = adapter.getItem(which);
                 switch (resId) {
                     case R.string.import_from_sim:
                     case R.string.import_from_sdcard: {
-                        handleImportRequest(resId);
+                        dismissDialog = handleImportRequest(resId);
                         break;
                     }
                     case R.string.export_to_sdcard: {
+                        dismissDialog = true;
                         Intent exportIntent = new Intent(getActivity(), ExportVCardActivity.class);
                         getActivity().startActivity(exportIntent);
                         break;
                     }
                     case R.string.share_visible_contacts: {
+                        dismissDialog = true;
                         doShareVisibleContacts();
                         break;
                     }
                     default: {
+                        dismissDialog = true;
                         Log.e(TAG, "Unexpected resource: "
                                 + getActivity().getResources().getResourceEntryName(resId));
                     }
                 }
+                if (dismissDialog) {
+                    dialog.dismiss();
+                }
             }
         };
         return new AlertDialog.Builder(getActivity())
@@ -164,7 +173,12 @@
         }
     }
 
-    private void handleImportRequest(int resId) {
+    /**
+     * Handle "import from SIM" and "import from SD".
+     *
+     * @return {@code true} if the dialog show be closed.  {@code false} otherwise.
+     */
+    private boolean handleImportRequest(int resId) {
         // There are three possibilities:
         // - more than one accounts -> ask the user
         // - just one account -> use the account without asking the user
@@ -174,32 +188,39 @@
         final int size = accountList.size();
         if (size > 1) {
             // Send over to the account selector
-            ImportExportAccountSelectorDialog.show(getFragmentManager(), resId);
-            return;
+            final Bundle args = new Bundle();
+            args.putInt(KEY_RES_ID, resId);
+            SelectAccountDialogFragment.show(
+                    getFragmentManager(), this,
+                    R.string.dialog_new_contact_account,
+                    AccountListFilter.ACCOUNTS_CONTACT_WRITABLE, args);
+
+            // In this case, because this DialogFragment is used as a target fragment to
+            // SelectAccountDialogFragment, we can't close it yet.  We close the dialog when
+            // we get a callback from it.
+            return false;
         }
 
         AccountSelectionUtil.doImport(getActivity(), resId,
                 (size == 1 ? accountList.get(0) : null));
+        return true; // Close the dialog.
     }
 
-    /** Sub-Dialog for showing an account selector in case there are several accounts */
-    public static class ImportExportAccountSelectorDialog extends SelectAccountDialogFragment {
-        private static final String SELECTOR_TAG = "ImportExportAccountSelectorDialog";
-        private static final String BUNDLE_RES_ID = "resourceId";
+    /**
+     * Called when an account is selected on {@link SelectAccountDialogFragment}.
+     */
+    @Override
+    public void onAccountChosen(AccountWithDataSet account, Bundle extraArgs) {
+        AccountSelectionUtil.doImport(getActivity(), extraArgs.getInt(KEY_RES_ID), account);
 
-        public static void show(FragmentManager manager, int resId) {
-            final ImportExportAccountSelectorDialog dialog =
-                new ImportExportAccountSelectorDialog();
-            final Bundle bundle = new Bundle();
-            bundle.putInt(BUNDLE_RES_ID, resId);
-            dialog.setArguments(bundle);
-            dialog.show(manager, SELECTOR_TAG);
-        }
+        // At this point the dialog is still showing (which is why we can use getActivity() above)
+        // So close it.
+        dismiss();
+    }
 
-        @Override
-        protected void onAccountSelected(AccountWithDataSet account) {
-            final int resourceId = getArguments().getInt(BUNDLE_RES_ID);
-            AccountSelectionUtil.doImport(getActivity(), resourceId, account);
-        }
+    @Override
+    public void onAccountSelectorCancelled() {
+        // See onAccountChosen() -- at this point the dialog is still showing.  Close it.
+        dismiss();
     }
 }