New group disambiguation dialog

- Since switching accounts in the group editor is difficult
(i.e. we need to wipe all added group members when accounts
are switched), it's easier to just have an account disambig
dialog when you first create the group
- The disambig happens as a popupwindow anchored to the
action bar "New group" button if it's a wide screen
- Otherwise the disambig is a dialog that comes from
the GroupEditorFragment

Change-Id: Ibd75607b326e600c412f4bd04eb4cc72534aed72
diff --git a/res/layout/add_contact_menu_item.xml b/res/layout/add_group_menu_item.xml
similarity index 86%
rename from res/layout/add_contact_menu_item.xml
rename to res/layout/add_group_menu_item.xml
index 1bdbcac..b2ff678 100644
--- a/res/layout/add_contact_menu_item.xml
+++ b/res/layout/add_group_menu_item.xml
@@ -1,12 +1,12 @@
 <?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2010 The Android Open Source Project
+<!-- 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.
@@ -36,14 +36,14 @@
             android:layout_height="wrap_content"
             android:layout_gravity="center_vertical"
             android:layout_marginRight="8dip"
-            android:src="@drawable/ic_menu_add_contact_holo_light"
-            android:description="@string/menu_newContact" />
+            android:src="@drawable/ic_menu_display_all_holo_light"
+            android:description="@string/menu_new_group_action_bar" />
 
         <TextView
             android:layout_width="wrap_content"
             android:layout_height="wrap_content"
             android:layout_gravity="center_vertical"
             android:textAppearance="?android:attr/textAppearanceMedium"
-            android:text="@string/menu_new_contact_action_bar" />
+            android:text="@string/menu_new_group_action_bar" />
     </LinearLayout>
 </LinearLayout>
diff --git a/res/menu-sw580dp-w720dp/actions.xml b/res/menu-sw580dp-w720dp/actions.xml
index 60788e0..081065c 100644
--- a/res/menu-sw580dp-w720dp/actions.xml
+++ b/res/menu-sw580dp-w720dp/actions.xml
@@ -26,9 +26,9 @@
         android:showAsAction="withText|always" />
 
     <item
-        android:id="@+id/menu_add_group"
+        android:id="@+id/menu_custom_add_group"
         android:icon="@drawable/ic_menu_display_all_holo_light"
-        android:title="@string/menu_new_contact_action_bar"
+        android:title="@string/menu_new_group_action_bar"
         android:showAsAction="withText|always" />
 
     <item
diff --git a/res/menu-sw580dp/actions.xml b/res/menu-sw580dp/actions.xml
index 4fe669a..1d955c1 100644
--- a/res/menu-sw580dp/actions.xml
+++ b/res/menu-sw580dp/actions.xml
@@ -28,7 +28,7 @@
     <item
         android:id="@+id/menu_add_group"
         android:icon="@drawable/ic_menu_display_all_holo_light"
-        android:title="@string/menu_new_contact_action_bar"
+        android:title="@string/menu_new_group_action_bar"
         android:showAsAction="withText" />
 
     <item
diff --git a/res/menu/actions.xml b/res/menu/actions.xml
index 996cfef..7bd3765 100644
--- a/res/menu/actions.xml
+++ b/res/menu/actions.xml
@@ -27,7 +27,7 @@
     <item
         android:id="@+id/menu_add_group"
         android:icon="@drawable/ic_menu_display_all_holo_light"
-        android:title="@string/menu_new_contact_action_bar" />
+        android:title="@string/menu_new_group_action_bar" />
 
     <item
         android:id="@+id/menu_contacts_filter"
diff --git a/res/values/strings.xml b/res/values/strings.xml
index a2baaa2..21f42e9 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -144,6 +144,9 @@
     <!-- Menu item (in the action bar) that creates a new contacts [CHAR LIMIT=12] -->
     <string name="menu_new_contact_action_bar">New</string>
 
+    <!-- Menu item (in the action bar) that creates a new group [CHAR LIMIT=12] -->
+    <string name="menu_new_group_action_bar">New</string>
+
     <!-- Title of the confirmation dialog for separating contacts into multiple instances  -->
     <string name="splitConfirmation_title">Separate Contact</string>
 
@@ -1071,6 +1074,9 @@
 
     <string name="dialog_new_contact_account">Create contact under account</string>
 
+    <!-- Title for the disambiguation dialog that requests the user choose an account for the new group to be created under [CHAR LIMIT=NONE] -->
+    <string name="dialog_new_group_account">Create group under account</string>
+
     <string name="menu_sync_remove">Remove sync group</string>
     <string name="dialog_sync_add">Add sync group</string>
     <string name="display_more_groups">More groups\u2026</string>
diff --git a/src/com/android/contacts/activities/GroupEditorActivity.java b/src/com/android/contacts/activities/GroupEditorActivity.java
index 2a79852..e71d314 100644
--- a/src/com/android/contacts/activities/GroupEditorActivity.java
+++ b/src/com/android/contacts/activities/GroupEditorActivity.java
@@ -68,7 +68,7 @@
         mFragment.setListener(mFragmentListener);
         mFragment.setContentResolver(getContentResolver());
         Uri uri = Intent.ACTION_EDIT.equals(action) ? getIntent().getData() : null;
-        mFragment.load(action, uri);
+        mFragment.load(action, uri, getIntent().getExtras());
     }
 
     @Override
diff --git a/src/com/android/contacts/activities/PeopleActivity.java b/src/com/android/contacts/activities/PeopleActivity.java
index 4b7c360..9af426d 100644
--- a/src/com/android/contacts/activities/PeopleActivity.java
+++ b/src/com/android/contacts/activities/PeopleActivity.java
@@ -44,8 +44,10 @@
 import com.android.contacts.list.ProviderStatusLoader;
 import com.android.contacts.list.ProviderStatusLoader.ProviderStatusListener;
 import com.android.contacts.list.StrequentContactListFragment;
+import com.android.contacts.model.AccountTypeManager;
 import com.android.contacts.preference.ContactsPreferenceActivity;
 import com.android.contacts.util.AccountSelectionUtil;
+import com.android.contacts.util.AccountsListAdapter;
 import com.android.contacts.util.DialogManager;
 import com.android.contacts.widget.ContextMenuAdapter;
 
@@ -65,6 +67,7 @@
 import android.os.Bundle;
 import android.provider.ContactsContract;
 import android.provider.ContactsContract.Contacts;
+import android.provider.ContactsContract.Intents;
 import android.provider.ContactsContract.ProviderStatus;
 import android.provider.Settings;
 import android.util.Log;
@@ -73,7 +76,11 @@
 import android.view.MenuInflater;
 import android.view.MenuItem;
 import android.view.View;
+import android.view.View.OnClickListener;
 import android.view.Window;
+import android.widget.AdapterView;
+import android.widget.AdapterView.OnItemClickListener;
+import android.widget.ListPopupWindow;
 import android.widget.SearchView;
 import android.widget.Toast;
 
@@ -147,6 +154,8 @@
     private View mBrowserView;
     private View mDetailsView;
 
+    private View mAddGroupImageView;
+
     private enum TabState {
         FAVORITES, CONTACTS, GROUPS
     }
@@ -888,6 +897,23 @@
                 mActionBarAdapter.setSearchView(searchView);
             }
         }
+
+        // On narrow screens we specify a NEW group button in the {@link ActionBar}, so that
+        // it can be in the overflow menu. On wide screens, we use a custom view because we need
+        // its location for anchoring the account-selector popup.
+        final MenuItem addGroup = menu.findItem(R.id.menu_custom_add_group);
+        if (addGroup != null) {
+            mAddGroupImageView = getLayoutInflater().inflate(
+                    R.layout.add_group_menu_item, null, false);
+            View item = mAddGroupImageView.findViewById(R.id.menu_item);
+            item.setOnClickListener(new OnClickListener() {
+                @Override
+                public void onClick(View v) {
+                    createNewGroupWithAccountDisambiguation();
+                }
+            });
+            addGroup.setActionView(mAddGroupImageView);
+        }
         return true;
     }
 
@@ -924,9 +950,12 @@
             return false;
         }
 
-        final MenuItem addContactMenu = menu.findItem(R.id.menu_add_contact);
-        final MenuItem addGroupMenu = menu.findItem(R.id.menu_add_group);
         final MenuItem searchMenu = menu.findItem(R.id.menu_search);
+        final MenuItem addContactMenu = menu.findItem(R.id.menu_add_contact);
+        MenuItem addGroupMenu = menu.findItem(R.id.menu_add_group);
+        if (addGroupMenu == null) {
+            addGroupMenu = menu.findItem(R.id.menu_custom_add_group);
+        }
 
         if (mActionBarAdapter.isSearchMode()) {
             addContactMenu.setVisible(false);
@@ -983,12 +1012,7 @@
                 return true;
             }
             case R.id.menu_add_group: {
-                // TODO: Send off an intent with the groups URI, so we don't need to specify
-                // the editor activity class. Then it would be declared as:
-                // new Intent(Intent.ACTION_INSERT, Groups.CONTENT_URI)
-                final Intent intent = new Intent(this, GroupEditorActivity.class);
-                intent.setAction(Intent.ACTION_INSERT);
-                startActivityForResult(intent, SUBACTIVITY_NEW_GROUP);
+                createNewGroupWithAccountDisambiguation();
                 return true;
             }
             case R.id.menu_import_export: {
@@ -1008,6 +1032,39 @@
         return false;
     }
 
+    private void createNewGroupWithAccountDisambiguation() {
+        final ArrayList<Account> accounts =
+                AccountTypeManager.getInstance(this).getAccounts(true);
+        if (accounts.size() <= 1 || mAddGroupImageView == null) {
+            // No account to choose or no control to anchor the popup-menu to
+            // ==> just go straight to the editor which will disambig if necessary
+            final Intent intent = new Intent(this, GroupEditorActivity.class);
+            intent.setAction(Intent.ACTION_INSERT);
+            startActivityForResult(intent, SUBACTIVITY_NEW_GROUP);
+            return;
+        }
+
+        final ListPopupWindow popup = new ListPopupWindow(this, null);
+        popup.setWidth(getResources().getDimensionPixelSize(R.dimen.account_selector_popup_width));
+        popup.setAnchorView(mAddGroupImageView);
+        // Create a list adapter with all writeable accounts (assume that the writeable accounts all
+        // allow group creation).
+        final AccountsListAdapter adapter = new AccountsListAdapter(this, true);
+        popup.setAdapter(adapter);
+        popup.setOnItemClickListener(new OnItemClickListener() {
+            @Override
+            public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
+                popup.dismiss();
+                final Intent intent = new Intent(PeopleActivity.this, GroupEditorActivity.class);
+                intent.setAction(Intent.ACTION_INSERT);
+                intent.putExtra(Intents.Insert.ACCOUNT, adapter.getItem(position));
+                startActivityForResult(intent, SUBACTIVITY_NEW_GROUP);
+            }
+        });
+        popup.setModal(true);
+        popup.show();
+    }
+
     @Override
     public void startSearch(String initialQuery, boolean selectInitialQuery, Bundle appSearchData,
             boolean globalSearch) {
diff --git a/src/com/android/contacts/editor/SelectAccountDialogFragment.java b/src/com/android/contacts/editor/SelectAccountDialogFragment.java
index 65370f5..0a33f25 100644
--- a/src/com/android/contacts/editor/SelectAccountDialogFragment.java
+++ b/src/com/android/contacts/editor/SelectAccountDialogFragment.java
@@ -37,9 +37,15 @@
 public class SelectAccountDialogFragment extends DialogFragment {
     public static final String TAG = "SelectAccountDialogFragment";
 
+    private int mTitleResourceId = R.string.dialog_new_contact_account;
+
     public SelectAccountDialogFragment() {
     }
 
+    public SelectAccountDialogFragment(int titleResourceId) {
+        mTitleResourceId = titleResourceId;
+    }
+
     @Override
     public Dialog onCreateDialog(Bundle savedInstanceState) {
         final AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
@@ -57,7 +63,7 @@
             }
         };
 
-        builder.setTitle(R.string.dialog_new_contact_account);
+        builder.setTitle(mTitleResourceId);
         builder.setSingleChoiceItems(accountAdapter, 0, clickListener);
         final AlertDialog result = builder.create();
         return result;
diff --git a/src/com/android/contacts/group/GroupEditorFragment.java b/src/com/android/contacts/group/GroupEditorFragment.java
index 0394d30..07d19a7 100644
--- a/src/com/android/contacts/group/GroupEditorFragment.java
+++ b/src/com/android/contacts/group/GroupEditorFragment.java
@@ -24,6 +24,7 @@
 import com.android.contacts.R;
 import com.android.contacts.activities.GroupEditorActivity;
 import com.android.contacts.editor.ContactEditorFragment.SaveMode;
+import com.android.contacts.editor.SelectAccountDialogFragment;
 import com.android.contacts.group.SuggestedMemberListAdapter.SuggestedMember;
 import com.android.contacts.model.AccountType;
 import com.android.contacts.model.AccountTypeManager;
@@ -54,6 +55,7 @@
 import android.os.Bundle;
 import android.provider.ContactsContract.Contacts;
 import android.provider.ContactsContract.CommonDataKinds.GroupMembership;
+import android.provider.ContactsContract.Intents;
 import android.provider.ContactsContract.RawContacts;
 import android.text.TextUtils;
 import android.util.Log;
@@ -79,7 +81,7 @@
 import java.util.List;
 
 // TODO: Use savedInstanceState
-public class GroupEditorFragment extends Fragment {
+public class GroupEditorFragment extends Fragment implements SelectAccountDialogFragment.Listener {
 
     private static final String TAG = "GroupEditorFragment";
 
@@ -162,6 +164,7 @@
 
     private Context mContext;
     private String mAction;
+    private Bundle mIntentExtras;
     private Uri mGroupUri;
     private long mGroupId;
     private Listener mListener;
@@ -239,12 +242,27 @@
             if (mListener != null) {
                 mListener.onTitleLoaded(R.string.editGroup_title_insert);
             }
-            setupAccountSwitcher();
+
+            final Account account = mIntentExtras == null ? null :
+                    (Account) mIntentExtras.getParcelable(Intents.Insert.ACCOUNT);
+
+            if (account != null) {
+                // Account specified in Intent
+                mAccountName = account.name;
+                mAccountType = account.type;
+                setupAccountHeader();
+            } else {
+                // No Account specified. Let the user choose from a disambiguation dialog.
+                selectAccountAndCreateGroup();
+            }
+
             mStatus = Status.EDITING;
+
             // The user wants to create a new group, temporarily hide the "add members" text view
             // TODO: Need to allow users to add members if it's a new group. Under the current
             // approach, we can't add members because it needs a group ID in order to save,
             // and we don't have a group ID for a new group until the whole group is saved.
+            // Take this out when batch add/remove members is working.
             mAutoCompleteTextView.setVisibility(View.GONE);
         } else {
             throw new IllegalArgumentException("Unknown Action String " + mAction +
@@ -259,41 +277,50 @@
         }
     }
 
-    /**
-     * Sets up the account header for a new group by taking the first account.
-     */
-    private void setupAccountSwitcher() {
-        // TODO: Allow switching between valid accounts
-        final AccountTypeManager accountTypeManager = AccountTypeManager.getInstance(mContext);
-        final ArrayList<Account> accountsList = accountTypeManager.getAccounts(true);
-        if (accountsList.isEmpty()) {
-            return;
+    private void selectAccountAndCreateGroup() {
+        final ArrayList<Account> accounts =
+                AccountTypeManager.getInstance(mContext).getAccounts(true /* writeable */);
+        // No Accounts available
+        if (accounts.isEmpty()) {
+            throw new IllegalStateException("No accounts were found.");
         }
-        Account account = accountsList.get(0);
 
-        // Store account info for later
+        // In the common case of a single account being writable, auto-select
+        // it without showing a dialog.
+        if (accounts.size() == 1) {
+            mAccountName = accounts.get(0).name;
+            mAccountType = accounts.get(0).type;
+            setupAccountHeader();
+            return;  // Don't show a dialog.
+        }
+
+        final SelectAccountDialogFragment dialog = new SelectAccountDialogFragment(
+                R.string.dialog_new_group_account);
+        dialog.setTargetFragment(this, 0);
+        dialog.show(getFragmentManager(), SelectAccountDialogFragment.TAG);
+    }
+
+    @Override
+    public void onAccountChosen(int requestCode, Account account) {
         mAccountName = account.name;
         mAccountType = account.type;
+        setupAccountHeader();
+    }
 
-        // Display account name
-        if (!TextUtils.isEmpty(mAccountName)) {
-            mAccountNameTextView.setText(
-                    mContext.getString(R.string.from_account_format, mAccountName));
+    @Override
+    public void onAccountSelectorCancelled() {
+        if (mListener != null) {
+            // Exit the fragment because we cannot continue without selecting an account
+            mListener.onGroupNotFound();
         }
-        // Display account type
-        final AccountType type = accountTypeManager.getAccountType(mAccountType);
-        mAccountTypeTextView.setText(type.getDisplayLabel(mContext));
-
-        // Display account icon
-        mAccountIcon.setImageDrawable(type.getDisplayIcon(mContext));
     }
 
     /**
-     * Sets up the account header for an existing group.
+     * Sets up the account header.
      */
     private void setupAccountHeader() {
-        final AccountTypeManager accountTypes = AccountTypeManager.getInstance(mContext);
-        final AccountType accountType = accountTypes.getAccountType(mAccountType);
+        final AccountTypeManager accountTypeManager = AccountTypeManager.getInstance(mContext);
+        final AccountType accountType = accountTypeManager.getAccountType(mAccountType);
         CharSequence accountTypeDisplayLabel = accountType.getDisplayLabel(mContext);
         if (!TextUtils.isEmpty(mAccountName)) {
             mAccountNameTextView.setText(
@@ -303,10 +330,11 @@
         mAccountIcon.setImageDrawable(accountType.getDisplayIcon(mContext));
     }
 
-    public void load(String action, Uri groupUri) {
+    public void load(String action, Uri groupUri, Bundle intentExtras) {
         mAction = action;
         mGroupUri = groupUri;
         mGroupId = (groupUri != null) ? ContentUris.parseId(mGroupUri) : 0;
+        mIntentExtras = intentExtras;
     }
 
     private void bindGroupMetaData(Cursor cursor) {