Adding "Create new group" functionality
Change-Id: I2d0c28fcf3e9b3099c8889560a149f18f0f74c38
diff --git a/res/values/strings.xml b/res/values/strings.xml
index 1374ba9..52b28df 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -1407,6 +1407,12 @@
Initiates a contact import dialog [CHAR LIMIT=128] -->
<string name="contacts_unavailable_import_contacts">Import contacts from a file</string>
+ <!-- Title of the dialog that allows creation of a contact group [CHAR LIMIT=128] -->
+ <string name="create_group_dialog_title">Create new group</string>
+
+ <!-- An item in the popup list of groups that triggers creation of a contact group [CHAR LIMIT=128] -->
+ <string name="create_group_item_label">[Create new group]</string>
+
<!-- Title of the dialog that allows renaming of a contact group [CHAR LIMIT=128] -->
<string name="rename_group_dialog_title">Rename group</string>
diff --git a/src/com/android/contacts/activities/ContactEditorActivity.java b/src/com/android/contacts/activities/ContactEditorActivity.java
index 0b6213f..2b22b4b 100644
--- a/src/com/android/contacts/activities/ContactEditorActivity.java
+++ b/src/com/android/contacts/activities/ContactEditorActivity.java
@@ -28,7 +28,7 @@
import android.content.Intent;
import android.net.Uri;
import android.os.Bundle;
-import android.provider.ContactsContract.Intents.Insert;
+import android.provider.ContactsContract;
import android.util.Log;
import android.view.View;
import android.view.View.OnClickListener;
@@ -78,6 +78,15 @@
}
@Override
+ protected void onNewIntent(Intent intent) {
+ super.onNewIntent(intent);
+
+ if (Intent.ACTION_EDIT.equals(intent.getAction()) && mFragment != null){
+ mFragment.setIntentExtras(intent.getExtras());
+ }
+ }
+
+ @Override
protected Dialog onCreateDialog(int id, Bundle args) {
if (DialogManager.isManagedId(id)) return mDialogManager.onCreateDialog(id, args);
@@ -168,7 +177,7 @@
// Pass on all the data that has been entered so far
if (values != null && values.size() != 0) {
- intent.putParcelableArrayListExtra(Insert.DATA, values);
+ intent.putParcelableArrayListExtra(ContactsContract.Intents.Insert.DATA, values);
}
startActivity(intent);
diff --git a/src/com/android/contacts/interactions/GroupCreationDialogFragment.java b/src/com/android/contacts/interactions/GroupCreationDialogFragment.java
new file mode 100644
index 0000000..9f1ad15
--- /dev/null
+++ b/src/com/android/contacts/interactions/GroupCreationDialogFragment.java
@@ -0,0 +1,61 @@
+/*
+ * Copyright (C) 2010 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.contacts.interactions;
+
+import com.android.contacts.R;
+import com.android.contacts.views.ContactSaveService;
+
+import android.accounts.Account;
+import android.app.FragmentManager;
+import android.os.Bundle;
+import android.widget.EditText;
+
+/**
+ * A dialog for creating a new group.
+ */
+public class GroupCreationDialogFragment extends GroupNameDialogFragment {
+ private static final String ARG_ACCOUNT_TYPE = "accountType";
+ private static final String ARG_ACCOUNT_NAME = "accountName";
+
+ public static void show(
+ FragmentManager fragmentManager, String accountType, String accountName) {
+ GroupCreationDialogFragment dialog = new GroupCreationDialogFragment();
+ Bundle args = new Bundle();
+ args.putString(ARG_ACCOUNT_TYPE, accountType);
+ args.putString(ARG_ACCOUNT_NAME, accountName);
+ dialog.setArguments(args);
+ dialog.show(fragmentManager, "createGroup");
+ }
+
+ @Override
+ protected void initializeGroupLabelEditText(EditText editText) {
+ }
+
+ @Override
+ protected int getTitleResourceId() {
+ return R.string.create_group_dialog_title;
+ }
+
+ @Override
+ protected void onCompleted(String groupLabel) {
+ Bundle arguments = getArguments();
+ String accountType = arguments.getString(ARG_ACCOUNT_TYPE);
+ String accountName = arguments.getString(ARG_ACCOUNT_NAME);
+
+ getActivity().startService(ContactSaveService.createNewGroupIntent(
+ getActivity(), new Account(accountName, accountType), groupLabel));
+ }
+}
diff --git a/src/com/android/contacts/interactions/GroupNameDialogFragment.java b/src/com/android/contacts/interactions/GroupNameDialogFragment.java
new file mode 100644
index 0000000..d390385
--- /dev/null
+++ b/src/com/android/contacts/interactions/GroupNameDialogFragment.java
@@ -0,0 +1,92 @@
+/*
+ * Copyright (C) 2010 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.contacts.interactions;
+
+import com.android.contacts.R;
+
+import android.app.AlertDialog;
+import android.app.Dialog;
+import android.app.DialogFragment;
+import android.content.DialogInterface;
+import android.content.DialogInterface.OnShowListener;
+import android.os.Bundle;
+import android.text.Editable;
+import android.text.TextUtils;
+import android.text.TextWatcher;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.widget.Button;
+import android.widget.EditText;
+
+/**
+ * A common superclass for creating and renaming groups.
+ */
+public abstract class GroupNameDialogFragment extends DialogFragment
+ implements TextWatcher, OnShowListener {
+ private EditText mEdit;
+
+ protected abstract int getTitleResourceId();
+ protected abstract void initializeGroupLabelEditText(EditText editText);
+ protected abstract void onCompleted(String groupLabel);
+
+ @Override
+ public Dialog onCreateDialog(Bundle savedInstanceState) {
+ View view = LayoutInflater.from(getActivity()).inflate(R.layout.group_name_dialog, null);
+ mEdit = (EditText) view.findViewById(R.id.group_label);
+ mEdit.addTextChangedListener(this);
+
+ AlertDialog dialog = new AlertDialog.Builder(getActivity())
+ .setIcon(android.R.drawable.ic_dialog_alert)
+ .setTitle(getTitleResourceId())
+ .setView(view)
+ .setPositiveButton(android.R.string.ok,
+ new DialogInterface.OnClickListener() {
+ @Override
+ public void onClick(DialogInterface dialog, int whichButton) {
+ onCompleted(mEdit.getText().toString().trim());
+ }
+ }
+ )
+ .setNegativeButton(android.R.string.cancel, null)
+ .create();
+
+ dialog.setOnShowListener(this);
+ return dialog;
+ }
+
+ public void onShow(DialogInterface dialog) {
+ updateOkButtonState((AlertDialog) dialog);
+ }
+
+ @Override
+ public void afterTextChanged(Editable s) {
+ AlertDialog dialog = (AlertDialog) getDialog();
+ updateOkButtonState(dialog);
+ }
+
+ private void updateOkButtonState(AlertDialog dialog) {
+ Button okButton = dialog.getButton(AlertDialog.BUTTON_POSITIVE);
+ okButton.setEnabled(!TextUtils.isEmpty(mEdit.getText().toString().trim()));
+ }
+
+ @Override
+ public void beforeTextChanged(CharSequence s, int start, int count, int after) {
+ }
+
+ @Override
+ public void onTextChanged(CharSequence s, int start, int before, int count) {
+ }
+}
diff --git a/src/com/android/contacts/interactions/GroupRenamingDialogFragment.java b/src/com/android/contacts/interactions/GroupRenamingDialogFragment.java
index 6339e79..223391e 100644
--- a/src/com/android/contacts/interactions/GroupRenamingDialogFragment.java
+++ b/src/com/android/contacts/interactions/GroupRenamingDialogFragment.java
@@ -18,26 +18,18 @@
import com.android.contacts.R;
import com.android.contacts.views.ContactSaveService;
-import android.app.AlertDialog;
-import android.app.Dialog;
-import android.app.DialogFragment;
import android.app.FragmentManager;
-import android.content.DialogInterface;
import android.os.Bundle;
-import android.view.LayoutInflater;
-import android.view.View;
import android.widget.EditText;
/**
* A dialog for renaming a group.
*/
-public class GroupRenamingDialogFragment extends DialogFragment {
+public class GroupRenamingDialogFragment extends GroupNameDialogFragment {
private static final String ARG_GROUP_ID = "groupId";
private static final String ARG_LABEL = "label";
- private EditText mEdit;
-
public static void show(FragmentManager fragmentManager, long groupId, String label) {
GroupRenamingDialogFragment dialog = new GroupRenamingDialogFragment();
Bundle args = new Bundle();
@@ -48,38 +40,25 @@
}
@Override
- public Dialog onCreateDialog(Bundle savedInstanceState) {
- View view = LayoutInflater.from(getActivity()).inflate(R.layout.group_name_dialog, null);
- mEdit = (EditText) view.findViewById(R.id.group_label);
+ protected void initializeGroupLabelEditText(EditText editText) {
String label = getArguments().getString(ARG_LABEL);
- mEdit.setText(label);
+ editText.setText(label);
if (label != null) {
- mEdit.setSelection(label.length());
+ editText.setSelection(label.length());
}
-
- return new AlertDialog.Builder(getActivity())
- .setIcon(android.R.drawable.ic_dialog_alert)
- .setTitle(R.string.rename_group_dialog_title)
- .setView(view)
- .setPositiveButton(android.R.string.ok,
- new DialogInterface.OnClickListener() {
- @Override
- public void onClick(DialogInterface dialog, int whichButton) {
- saveGroupLabel();
- }
- }
- )
- .setNegativeButton(android.R.string.cancel, null)
- .create();
}
- protected void saveGroupLabel() {
- String newLabel = mEdit.getText().toString();
+ @Override
+ protected int getTitleResourceId() {
+ return R.string.rename_group_dialog_title;
+ }
+ @Override
+ protected void onCompleted(String groupLabel) {
Bundle arguments = getArguments();
long groupId = arguments.getLong(ARG_GROUP_ID);
getActivity().startService(ContactSaveService.createGroupRenameIntent(
- getActivity(), groupId, newLabel));
+ getActivity(), groupId, groupLabel));
}
}
diff --git a/src/com/android/contacts/views/ContactSaveService.java b/src/com/android/contacts/views/ContactSaveService.java
index 04ab43a..4083a4e 100644
--- a/src/com/android/contacts/views/ContactSaveService.java
+++ b/src/com/android/contacts/views/ContactSaveService.java
@@ -16,6 +16,7 @@
package com.android.contacts.views;
+import com.google.android.collect.Lists;
import com.google.android.collect.Sets;
import android.accounts.Account;
@@ -32,6 +33,7 @@
import android.os.Parcelable;
import android.os.RemoteException;
import android.provider.ContactsContract;
+import android.provider.ContactsContract.CommonDataKinds.GroupMembership;
import android.provider.ContactsContract.Data;
import android.provider.ContactsContract.Groups;
import android.provider.ContactsContract.RawContacts;
@@ -53,6 +55,7 @@
public static final String EXTRA_OPERATIONS = "Operations";
+ public static final String ACTION_CREATE_GROUP = "createGroup";
public static final String ACTION_RENAME_GROUP = "renameGroup";
public static final String ACTION_DELETE_GROUP = "deleteGroup";
public static final String EXTRA_GROUP_ID = "groupId";
@@ -88,6 +91,8 @@
String action = intent.getAction();
if (ACTION_NEW_RAW_CONTACT.equals(action)) {
createRawContact(intent);
+ } else if (ACTION_CREATE_GROUP.equals(action)) {
+ createGroup(intent);
} else if (ACTION_RENAME_GROUP.equals(action)) {
renameGroup(intent);
} else if (ACTION_DELETE_GROUP.equals(action)) {
@@ -127,7 +132,6 @@
throw new RuntimeException("Failed to store new contact", e);
}
- Uri result = ContactsContract.Directory.CONTENT_URI;
Uri rawContactUri = results[0].uri;
callbackIntent.setData(RawContacts.getContactLookupUri(resolver, rawContactUri));
@@ -180,6 +184,52 @@
return serviceIntent;
}
+ private void createGroup(Intent intent) {
+ String accountType = intent.getStringExtra(EXTRA_ACCOUNT_TYPE);
+ String accountName = intent.getStringExtra(EXTRA_ACCOUNT_NAME);
+ String label = intent.getStringExtra(EXTRA_GROUP_LABEL);
+
+ ContentValues values = new ContentValues();
+ values.put(Groups.ACCOUNT_TYPE, accountType);
+ values.put(Groups.ACCOUNT_NAME, accountName);
+ values.put(Groups.TITLE, label);
+
+ Uri groupUri = getContentResolver().insert(Groups.CONTENT_URI, values);
+ if (groupUri == null) {
+ return;
+ }
+
+ values.clear();
+ values.put(Data.MIMETYPE, GroupMembership.CONTENT_ITEM_TYPE);
+ values.put(GroupMembership.GROUP_ROW_ID, ContentUris.parseId(groupUri));
+
+ Intent callbackIntent = intent.getParcelableExtra(EXTRA_CALLBACK_INTENT);
+ callbackIntent.putExtra(ContactsContract.Intents.Insert.DATA, Lists.newArrayList(values));
+
+ startActivity(callbackIntent);
+ }
+
+ /**
+ * Creates an intent that can be sent to this service to create a new group.
+ */
+ public static Intent createNewGroupIntent(Activity activity, Account account, String label) {
+ Intent serviceIntent = new Intent(activity, ContactSaveService.class);
+ serviceIntent.setAction(ContactSaveService.ACTION_CREATE_GROUP);
+ serviceIntent.putExtra(ContactSaveService.EXTRA_ACCOUNT_TYPE, account.type);
+ serviceIntent.putExtra(ContactSaveService.EXTRA_ACCOUNT_NAME, account.name);
+ serviceIntent.putExtra(ContactSaveService.EXTRA_GROUP_LABEL, label);
+
+ // Callback intent will be invoked by the service once the new group is
+ // created. The service will put a group membership row in the extras
+ // of the callback intent.
+ Intent callbackIntent = new Intent(activity, activity.getClass());
+ callbackIntent.setAction(Intent.ACTION_EDIT);
+ callbackIntent.setFlags(
+ Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_SINGLE_TOP);
+ serviceIntent.putExtra(ContactSaveService.EXTRA_CALLBACK_INTENT, callbackIntent);
+ return serviceIntent;
+ }
+
private void renameGroup(Intent intent) {
long groupId = intent.getLongExtra(EXTRA_GROUP_ID, -1);
String label = intent.getStringExtra(EXTRA_GROUP_LABEL);
diff --git a/src/com/android/contacts/views/editor/ContactEditorFragment.java b/src/com/android/contacts/views/editor/ContactEditorFragment.java
index a2679b5..df329f9 100644
--- a/src/com/android/contacts/views/editor/ContactEditorFragment.java
+++ b/src/com/android/contacts/views/editor/ContactEditorFragment.java
@@ -366,26 +366,33 @@
sb.append(")");
mQuerySelection = sb.toString();
mState = EntityDeltaList.fromIterator(entities.iterator());
-
- // Merge in Extras from Intent
- if (mIntentExtras != null && mIntentExtras.size() > 0) {
- final AccountTypes sources = AccountTypes.getInstance(mContext);
- for (EntityDelta state : mState) {
- final String accountType = state.getValues().getAsString(RawContacts.ACCOUNT_TYPE);
- final AccountType source = sources.getInflatedSource(accountType,
- AccountType.LEVEL_CONSTRAINTS);
- if (!source.readOnly) {
- // Apply extras to the first writable raw contact only
- EntityModifier.parseExtras(mContext, source, state, mIntentExtras);
- mIntentExtras = null;
- break;
- }
- }
- }
+ setIntentExtras(mIntentExtras);
+ mIntentExtras = null;
bindEditors();
}
+ /**
+ * Merges extras from the intent.
+ */
+ public void setIntentExtras(Bundle extras) {
+ if (extras == null || extras.size() == 0) {
+ return;
+ }
+
+ final AccountTypes sources = AccountTypes.getInstance(mContext);
+ for (EntityDelta state : mState) {
+ final String accountType = state.getValues().getAsString(RawContacts.ACCOUNT_TYPE);
+ final AccountType source = sources.getInflatedSource(accountType,
+ AccountType.LEVEL_CONSTRAINTS);
+ if (!source.readOnly) {
+ // Apply extras to the first writable raw contact only
+ EntityModifier.parseExtras(mContext, source, state, extras);
+ break;
+ }
+ }
+ }
+
private void selectAccountAndCreateContact(boolean isNewContact) {
final ArrayList<Account> accounts = AccountTypes.getInstance(mContext).getAccounts(true);
// No Accounts available. Create a phone-local contact.
diff --git a/src/com/android/contacts/views/editor/GroupMembershipView.java b/src/com/android/contacts/views/editor/GroupMembershipView.java
index 60d1801..5705561 100644
--- a/src/com/android/contacts/views/editor/GroupMembershipView.java
+++ b/src/com/android/contacts/views/editor/GroupMembershipView.java
@@ -17,12 +17,14 @@
package com.android.contacts.views.editor;
import com.android.contacts.R;
+import com.android.contacts.interactions.GroupCreationDialogFragment;
import com.android.contacts.model.AccountType.DataKind;
import com.android.contacts.model.EntityDelta;
import com.android.contacts.model.EntityDelta.ValuesDelta;
import com.android.contacts.model.EntityModifier;
import com.android.contacts.views.GroupMetaDataLoader;
+import android.app.Activity;
import android.content.Context;
import android.database.Cursor;
import android.provider.ContactsContract.CommonDataKinds.GroupMembership;
@@ -47,6 +49,8 @@
public class GroupMembershipView extends LinearLayout
implements OnClickListener, OnItemClickListener {
+ private static final int CREATE_NEW_GROUP_GROUP_ID = 133;
+
public static final class GroupSelectionItem {
private final long mGroupId;
private final String mTitle;
@@ -203,6 +207,9 @@
}
}
+ mAdapter.add(new GroupSelectionItem(CREATE_NEW_GROUP_GROUP_ID,
+ getContext().getString(R.string.create_group_item_label), false));
+
mPopup = new ListPopupWindow(getContext(), null);
mPopup.setAnchorView(mGroupList);
mPopup.setAdapter(mAdapter);
@@ -224,6 +231,7 @@
super.onDetachedFromWindow();
if (mPopup != null) {
mPopup.dismiss();
+ mPopup = null;
}
}
@@ -231,6 +239,13 @@
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
ListView list = (ListView) parent;
int count = mAdapter.getCount();
+
+ if (list.isItemChecked(count - 1)) {
+ list.setItemChecked(count - 1, false);
+ createNewGroup();
+ return;
+ }
+
for (int i = 0; i < count; i++) {
mAdapter.getItem(i).setChecked(list.isItemChecked(i));
}
@@ -292,4 +307,14 @@
}
return false;
}
+
+ private void createNewGroup() {
+ if (mPopup != null) {
+ mPopup.dismiss();
+ mPopup = null;
+ }
+
+ GroupCreationDialogFragment.show(
+ ((Activity) getContext()).getFragmentManager(), mAccountType, mAccountName);
+ }
}