resolved conflicts for merge of 2cc7c87b to master
diff --git a/AndroidManifest.xml b/AndroidManifest.xml
index 9ff4b4b..4cde2b7 100644
--- a/AndroidManifest.xml
+++ b/AndroidManifest.xml
@@ -15,9 +15,10 @@
-->
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
- package="com.android.contacts"
- android:sharedUserId="android.uid.shared"
+ package="com.android.contacts"
+ android:sharedUserId="android.uid.shared"
>
+
<uses-permission android:name="android.permission.CALL_PRIVILEGED" />
<uses-permission android:name="android.permission.READ_CONTACTS" />
<uses-permission android:name="android.permission.WRITE_CONTACTS" />
@@ -108,7 +109,7 @@
<category android:name="android.intent.category.BROWSABLE" />
</intent-filter>
</activity>
-
+
<!-- An empty activity that presents the DialtactActivity's Contacts tab -->
<activity-alias android:name="DialtactsContactsEntryActivity"
android:targetActivity="DialtactsActivity"
@@ -126,7 +127,7 @@
<category android:name="android.intent.category.DEFAULT" />
<data android:mimeType="vnd.android.cursor.dir/person" />
</intent-filter>
-
+
<intent-filter>
<action android:name="com.android.contacts.action.FILTER_CONTACTS" />
<category android:name="android.intent.category.DEFAULT" />
@@ -144,7 +145,7 @@
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</activity-alias>
-
+
<!-- The actual list of contacts, usually embedded in ContactsActivity -->
<activity android:name="ContactsListActivity"
android:label="@string/contactsList"
@@ -179,7 +180,7 @@
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.TAB" />
</intent-filter>
-
+
<intent-filter android:label="@string/frequentList">
<action android:name="com.android.contacts.action.LIST_FREQUENT" />
<category android:name="android.intent.category.DEFAULT" />
@@ -197,14 +198,7 @@
<category android:name="android.intent.category.DEFAULT" />
<data android:mimeType="vnd.android.cursor.item/person" />
</intent-filter>
-<!--
- <intent-filter android:label="Add To Contacts">
- <action android:name="com.android.contacts.action.ADD_CONTACT" />
- <category android:name="android.intent.category.SELECTED_ALTERNATIVE" />
- <data android:scheme="mailto" />
- <data android:scheme="tel" />
- </intent-filter>
--->
+
<intent-filter>
<action android:name="android.intent.action.PICK" />
<category android:name="android.intent.category.DEFAULT" />
diff --git a/res/layout-finger/edit_contact_entry_group.xml b/res/layout-finger/edit_contact_entry_group.xml
new file mode 100644
index 0000000..b233ca8
--- /dev/null
+++ b/res/layout-finger/edit_contact_entry_group.xml
@@ -0,0 +1,69 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2008 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.
+-->
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/entry_group"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:paddingRight="?android:attr/scrollbarSize"
+ android:minHeight="?android:attr/listPreferredItemHeight"
+ android:background="@android:drawable/list_selector_background"
+ android:orientation="horizontal"
+ android:gravity="center_vertical"
+ android:focusable="true"
+ android:clickable="true"
+ >
+
+ <RelativeLayout
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginLeft="14dip"
+ android:layout_marginTop="6dip"
+ android:layout_marginBottom="6dip"
+ android:layout_weight="1"
+ android:duplicateParentState="true"
+ >
+
+ <TextView android:id="@+id/label"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:singleLine="true"
+ android:textAppearance="?android:attr/textAppearanceMedium"
+ android:ellipsize="marquee"
+ android:fadingEdge="horizontal"
+ android:duplicateParentState="true"
+ />
+
+ <TextView android:id="@+id/data"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_below="@+id/label"
+ android:layout_alignLeft="@+id/label"
+ android:textAppearance="?android:attr/textAppearanceSmall"
+ android:singleLine="true"
+ android:ellipsize="marquee"
+ android:duplicateParentState="true"
+ />
+
+ </RelativeLayout>
+
+ <ImageView
+ style="@style/MoreButton"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ />
+
+</LinearLayout>
diff --git a/res/values/config.xml b/res/values/config.xml
index 369759c..669a9d4 100644
--- a/res/values/config.xml
+++ b/res/values/config.xml
@@ -19,7 +19,7 @@
<resources>
<!-- Flag indicating whether Contacts app is allowed to import contacts from SDCard -->
- <bool name="config_allow_import_from_sdcard">false</bool>
+ <bool name="config_allow_import_from_sdcard">true</bool>
<!-- If true, all vcard files are imported from SDCard without asking a user.
If not, dialog shows to let the user to select whether all vcard files are imported or not.
If the user selects "not", then the application ask the user to select a file.-->
@@ -33,4 +33,14 @@
<!-- Flag indicating whether Contacts app is allowed to export contacts to SDCard -->
<bool name="config_allow_export_to_sdcard">false</bool>
+
+ <!-- If true, enable vibration (haptic feedback) for dialer key presses.
+ TODO: If enough users are annoyed by this, we might eventually
+ need to make it a user preference rather than a per-platform
+ resource. -->
+ <bool name="config_enable_dialer_key_vibration">true</bool>
+
+ <!-- How long to vibrate (in msec), if dialer key vibration is enabled. -->
+ <integer name="config_dialer_key_vibrate_duration">40</integer>
+
</resources>
diff --git a/res/values/strings.xml b/res/values/strings.xml
index f40a0ec..83d839e 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -145,6 +145,15 @@
<!-- The label describing the custom ringtone for a contact -->
<string name="label_ringtone">Ringtone</string>
+ <!-- The label for a list of all the groups that the contact is associated with -->
+ <string name="label_groups">Groups</string>
+
+ <!-- Provides a delimeter in a list of groups. For example, "g1, g2" has ", g2" generated using this string -->
+ <string name="group_list">, <xliff:g id="groupName">%s</xliff:g></string>
+
+ <!-- Menu item used to send user to the edit contact screen -->
+ <string name="menu_viewGroup">Edit groups</string>
+
<!-- Hint text for the contact name when editing -->
<string name="ghostData_name">First and Last</string>
@@ -172,6 +181,9 @@
<!-- Hint text for the postal address field when editing -->
<string name="ghostData_postal">Postal address</string>
+ <!-- Hint text for the group field when editing -->
+ <string name="ghostData_group">Display group</string>
+
<!-- Message displayed in a toast when you try to view the details of a contact that
for some reason doesn't exist anymore. -->
<string name="invalidContactMessage">The contact does not exist.</string>
@@ -257,7 +269,7 @@
<!-- Title for group selection dialog. The dialog contains a list of contact groups that the
user can pick from, indicating they only want to see the contacts in that group. -->
<string name="select_group_title">Groups</string>
-
+
<!-- The text displayed when the contacts list is empty while displaying a single group of contacts -->
<string name="groupEmpty">Your \"<xliff:g id="groupName">%s</xliff:g>\" group is empty.</string>
@@ -312,6 +324,9 @@
<!-- Separator in the contact details list describing that the items below are non-actionable organization information -->
<string name="listSeparatorOrganizations">Organizations</string>
+ <!-- Separator in the contact details list describing that the items below are non-actionable group information -->
+ <string name="listSeparatorGroups">Groups</string>
+
<!-- Separator in the contact details list describing that the items below are random other non-actionable information about a contact -->
<string name="listSeparatorOtherInformation">Other information</string>
@@ -360,6 +375,9 @@
<!-- The title of a dialog that displays the IMEI of the phone -->
<string name="imei">IMEI</string>
+ <!-- The title of a dialog that displays the MEID of the CDMA phone -->
+ <string name="meid">MEID</string>
+
<!-- String used for displaying calls to the voicemail number in the call log -->
<string name="voicemail">Voicemail</string>
@@ -636,7 +654,10 @@
<string name="fail_reason_io_error">I/O Error</string>
<!-- The failed reason: "Failed to parse VCard data" -->
- <string name="fail_reason_vcard_parse_error">Failed to parse VCard</string>
+ <string name="fail_reason_vcard_parse_error">Failed to parse VCard with some unexpected reason</string>
+
+ <!-- The failed reason: "The VCard is not supported right now, but may be supported in the future" -->
+ <string name="fail_reason_vcard_not_supported_error">Failed to parse VCard though it seems in valid format, since the current implementation does not support it</string>
<!-- The failed reason: "There is no VCard file" -->
<string name="fail_reason_no_vcard_file">No VCard file found on SD Card</string>
@@ -712,4 +733,4 @@
<!-- The string used to describe Contacts as a searchable item within system search settings. -->
<string name="search_settings_description">Names of your contacts</string>
-</resources>
\ No newline at end of file
+</resources>
diff --git a/src/com/android/contacts/ContactEntryAdapter.java b/src/com/android/contacts/ContactEntryAdapter.java
index c5b7ccf..b8d9fe8 100644
--- a/src/com/android/contacts/ContactEntryAdapter.java
+++ b/src/com/android/contacts/ContactEntryAdapter.java
@@ -122,7 +122,9 @@
/** Synthesized phone entry that will send an SMS instead of call the number */
public static final int KIND_SMS = -2;
/** A section separator */
- public static final int KIND_SEPARATOR = -3;
+ public static final int KIND_SEPARATOR = -3;
+ /** Signifies a group row that is stored in the group membership table */
+ public static final int KIND_GROUP = -4;
public String label;
public String data;
diff --git a/src/com/android/contacts/ContactsGroupSyncSelector.java b/src/com/android/contacts/ContactsGroupSyncSelector.java
index e1fbdf1..a94f8db 100644
--- a/src/com/android/contacts/ContactsGroupSyncSelector.java
+++ b/src/com/android/contacts/ContactsGroupSyncSelector.java
@@ -16,14 +16,15 @@
package com.android.contacts;
-import com.google.android.googlelogin.GoogleLoginServiceConstants;
-import com.google.android.googlelogin.GoogleLoginServiceHelper;
-
+import android.accounts.AccountManager;
+import android.accounts.AuthenticatorException;
+import android.accounts.Future2;
+import android.accounts.Future2Callback;
+import android.accounts.OperationCanceledException;
import android.app.ListActivity;
import android.content.ContentResolver;
import android.content.ContentUris;
import android.content.ContentValues;
-import android.content.Intent;
import android.database.Cursor;
import android.os.Bundle;
import android.provider.Contacts;
@@ -37,6 +38,9 @@
import android.widget.ListView;
import java.util.ArrayList;
+import java.io.IOException;
+
+import com.google.android.googlelogin.GoogleLoginServiceConstants;
public final class ContactsGroupSyncSelector extends ListActivity implements View.OnClickListener {
@@ -51,8 +55,6 @@
private static final int COLUMN_INDEX_SHOULD_SYNC = 2;
private static final int COLUMN_INDEX_SYSTEM_ID = 3;
- private static final int SUBACTIVITY_GET_ACCOUNT = 1;
-
ArrayList<Boolean> mChecked;
ArrayList<Long> mGroupIds;
boolean mSyncAllGroups;
@@ -160,9 +162,26 @@
// through onActivityResult().
Bundle bundle = new Bundle();
bundle.putCharSequence("optional_message", getText(R.string.contactsSyncPlug));
- GoogleLoginServiceHelper.getCredentials(this, SUBACTIVITY_GET_ACCOUNT,
- bundle, GoogleLoginServiceConstants.PREFER_HOSTED, Gmail.GMAIL_AUTH_SERVICE,
- true);
+ AccountManager.get(this).getAuthTokenByFeatures(
+ GoogleLoginServiceConstants.ACCOUNT_TYPE, Gmail.GMAIL_AUTH_SERVICE,
+ new String[]{GoogleLoginServiceConstants.FEATURE_GOOGLE_OR_DASHER}, this,
+ bundle, null /* loginOptions */, new Future2Callback() {
+ public void run(Future2 future) {
+ try {
+ // do this to check if this request succeeded or not
+ future.getResult();
+ // There is an account setup, build the group list
+ buildItems();
+ adjustChecks();
+ } catch (OperationCanceledException e) {
+ finish();
+ } catch (IOException e) {
+ finish();
+ } catch (AuthenticatorException e) {
+ finish();
+ }
+ }
+ }, null /* handler */);
}
setContentView(R.layout.sync_settings);
@@ -173,20 +192,6 @@
getListView().setChoiceMode(ListView.CHOICE_MODE_MULTIPLE);
}
- @Override
- protected void onActivityResult(int requestCode, int resultCode, Intent intent) {
- super.onActivityResult(requestCode, resultCode, intent);
- if (requestCode == SUBACTIVITY_GET_ACCOUNT) {
- if (resultCode == RESULT_OK) {
- // There is an account setup, build the group list
- buildItems();
- adjustChecks();
- } else {
- finish();
- }
- }
- }
-
private void buildItems() {
final ContentResolver resolver = getContentResolver();
Cursor cursor = resolver.query(Groups.CONTENT_URI, PROJECTION, null, null, Groups.NAME);
diff --git a/src/com/android/contacts/ContactsListActivity.java b/src/com/android/contacts/ContactsListActivity.java
index 2cc5758..922131b 100644
--- a/src/com/android/contacts/ContactsListActivity.java
+++ b/src/com/android/contacts/ContactsListActivity.java
@@ -258,12 +258,12 @@
private static final int QUERY_TOKEN = 42;
- private static final String[] GROUPS_PROJECTION = new String[] {
+ static final String[] GROUPS_PROJECTION = new String[] {
Groups.SYSTEM_ID, // 0
Groups.NAME, // 1
};
- private static final int GROUPS_COLUMN_INDEX_SYSTEM_ID = 0;
- private static final int GROUPS_COLUMN_INDEX_NAME = 1;
+ static final int GROUPS_COLUMN_INDEX_SYSTEM_ID = 0;
+ static final int GROUPS_COLUMN_INDEX_NAME = 1;
static final String GROUP_WITH_PHONES = "android_smartgroup_phone";
@@ -522,23 +522,25 @@
mQueryHandler = new QueryHandler(this);
mJustCreated = true;
- // Check to see if sync is enabled
- final ContentResolver resolver = getContentResolver();
- IContentProvider provider = resolver.acquireProvider(Contacts.CONTENT_URI);
- if (provider == null) {
- // No contacts provider, bail.
- finish();
- return;
- }
-
- try {
- ISyncAdapter sa = provider.getSyncAdapter();
- mSyncEnabled = sa != null;
- } catch (RemoteException e) {
- mSyncEnabled = false;
- } finally {
- resolver.releaseProvider(provider);
- }
+ // TODO(jham) redesign this
+ mSyncEnabled = true;
+// // Check to see if sync is enabled
+// final ContentResolver resolver = getContentResolver();
+// IContentProvider provider = resolver.acquireProvider(Contacts.CONTENT_URI);
+// if (provider == null) {
+// // No contacts provider, bail.
+// finish();
+// return;
+// }
+//
+// try {
+// ISyncAdapter sa = provider.getSyncAdapter();
+// mSyncEnabled = sa != null;
+// } catch (RemoteException e) {
+// mSyncEnabled = false;
+// } finally {
+// resolver.releaseProvider(provider);
+// }
}
private void setEmptyText() {
diff --git a/src/com/android/contacts/DialtactsActivity.java b/src/com/android/contacts/DialtactsActivity.java
index 73d702b..8f933b8 100644
--- a/src/com/android/contacts/DialtactsActivity.java
+++ b/src/com/android/contacts/DialtactsActivity.java
@@ -213,6 +213,8 @@
}
} else if (FAVORITES_ENTRY_COMPONENT.equals(componentName)) {
mTabHost.setCurrentTab(TAB_INDEX_FAVORITES);
+ } else if (Contacts.Intents.UI.FILTER_CONTACTS_ACTION.equals(intent.getAction())) {
+ mTabHost.setCurrentTab(TAB_INDEX_CONTACTS);
} else {
SharedPreferences prefs = getSharedPreferences(PREFS_DIALTACTS, MODE_PRIVATE);
boolean favoritesAsContacts = prefs.getBoolean(PREF_FAVORITES_AS_CONTACTS,
diff --git a/src/com/android/contacts/EditContactActivity.java b/src/com/android/contacts/EditContactActivity.java
index b89573b..4d5a669 100644
--- a/src/com/android/contacts/EditContactActivity.java
+++ b/src/com/android/contacts/EditContactActivity.java
@@ -44,6 +44,8 @@
import static com.android.contacts.ContactEntryAdapter.PHONES_PROJECTION;
import static com.android.contacts.ContactEntryAdapter.PHONES_TYPE_COLUMN;
+import com.android.contacts.ViewContactActivity.ViewEntry;
+
import android.app.Activity;
import android.app.AlertDialog;
import android.app.Dialog;
@@ -69,6 +71,7 @@
import android.provider.Contacts;
import android.provider.Contacts.ContactMethods;
import android.provider.Contacts.Intents.Insert;
+import android.provider.Contacts.GroupMembership;
import android.provider.Contacts.Groups;
import android.provider.Contacts.Organizations;
import android.provider.Contacts.People;
@@ -171,6 +174,20 @@
/** Flag marking this contact as changed, meaning we should write changes back. */
private boolean mContactChanged = false;
+
+ /** List of all the group names */
+ private CharSequence[] mGroups;
+
+ /** Is this contact part of the group */
+ private boolean[] mInTheGroup;
+
+ private static final String[] GROUP_ID_PROJECTION = new String[] {
+ Groups._ID,
+ };
+
+ private static final String[] GROUPMEMBERSHIP_ID_PROJECTION = new String[] {
+ GroupMembership._ID,
+ };
// These are accessed by inner classes. They're package scoped to make access more efficient.
/* package */ ContentResolver mResolver;
@@ -188,7 +205,7 @@
/* package */ static final int MSG_ADD_PHONE = 3;
/* package */ static final int MSG_ADD_EMAIL = 4;
/* package */ static final int MSG_ADD_POSTAL = 5;
-
+
private static final int[] TYPE_PRECEDENCE_PHONES = new int[] {
Phones.TYPE_MOBILE, Phones.TYPE_HOME, Phones.TYPE_WORK, Phones.TYPE_OTHER
};
@@ -222,6 +239,12 @@
break;
}
+ case R.id.entry_group: {
+ EditEntry entry = findEntryForView(v);
+ doPickGroup(entry);
+ break;
+ }
+
case R.id.entry_ringtone: {
EditEntry entry = findEntryForView(v);
doPickRingtone(entry);
@@ -716,6 +739,127 @@
setPhotoPresent(false);
}
+ private void populateGroups() {
+ // Create a list of all the groups
+ Cursor cursor = mResolver.query(Groups.CONTENT_URI, ContactsListActivity.GROUPS_PROJECTION,
+ null, null, Groups.DEFAULT_SORT_ORDER);
+ try {
+ ArrayList<Long> ids = new ArrayList<Long>();
+ ArrayList<String> items = new ArrayList<String>();
+
+ while (cursor.moveToNext()) {
+ String systemId = cursor.getString(ContactsListActivity.GROUPS_COLUMN_INDEX_SYSTEM_ID);
+ String name = cursor.getString(ContactsListActivity.GROUPS_COLUMN_INDEX_NAME);
+
+ if (systemId != null || Groups.GROUP_MY_CONTACTS.equals(systemId)) {
+ continue;
+ }
+
+ if (!TextUtils.isEmpty(name)) {
+ ids.add(new Long(cursor.getLong(ContactsListActivity.GROUPS_COLUMN_INDEX_SYSTEM_ID)));
+ items.add(name);
+ }
+ }
+
+ mGroups = items.toArray(new CharSequence[items.size()]);
+ mInTheGroup = new boolean[items.size()];
+ } finally {
+ cursor.close();
+ }
+
+ if (mGroups != null) {
+
+ // Go through the groups for this member and update the list
+ final Uri groupsUri = Uri.withAppendedPath(mUri, GroupMembership.CONTENT_DIRECTORY);
+ Cursor groupCursor = null;
+ try {
+ groupCursor = mResolver.query(groupsUri, ContactsListActivity.GROUPS_PROJECTION,
+ null, null, Groups.DEFAULT_SORT_ORDER);
+ } catch (IllegalArgumentException e) {
+ // Contact is new, so we don't need to do any work.
+ }
+
+ if (groupCursor != null) {
+ try {
+ while (groupCursor.moveToNext()) {
+ String systemId = groupCursor.getString(ContactsListActivity.GROUPS_COLUMN_INDEX_SYSTEM_ID);
+ String name = groupCursor.getString(ContactsListActivity.GROUPS_COLUMN_INDEX_NAME);
+
+ if (systemId != null || Groups.GROUP_MY_CONTACTS.equals(systemId)) {
+ continue;
+ }
+
+ if (!TextUtils.isEmpty(name)) {
+ for (int i = 0; i < mGroups.length; i++) {
+ if (name.equals(mGroups[i])) {
+ mInTheGroup[i] = true;
+ break;
+ }
+ }
+ }
+ }
+ } finally {
+ groupCursor.close();
+ }
+ }
+ }
+ }
+
+ private String generateGroupList() {
+ StringBuilder groupList = new StringBuilder();
+ for (int i = 0; mGroups != null && i < mGroups.length; i++) {
+ if (mInTheGroup[i]) {
+ if (groupList.length() == 0) {
+ groupList.append(mGroups[i]);
+ } else {
+ groupList.append(getString(R.string.group_list, mGroups[i]));
+ }
+ }
+ }
+ return groupList.length() > 0 ? groupList.toString() : null;
+ }
+
+ private void doPickGroup(EditEntry entry) {
+ if (mGroups != null) {
+ GroupDialogListener listener = new GroupDialogListener(this, entry);
+
+ new AlertDialog.Builder(EditContactActivity.this)
+ .setTitle(R.string.label_groups)
+ .setMultiChoiceItems(mGroups, mInTheGroup, listener)
+ .setPositiveButton(android.R.string.ok, listener)
+ .setNegativeButton(android.R.string.cancel, null)
+ .show();
+ }
+ }
+
+ /** Handles the clicks in the groups dialog */
+ private static final class GroupDialogListener implements DialogInterface.OnClickListener,
+ DialogInterface.OnMultiChoiceClickListener {
+
+ private EditContactActivity mEditContactActivity;
+ private EditEntry mEntry;
+ private boolean[] mInTheGroup;
+
+ public GroupDialogListener(EditContactActivity editContactActivity, EditEntry entry) {
+ mEditContactActivity = editContactActivity;
+ mEntry = entry;
+ mInTheGroup = editContactActivity.mInTheGroup.clone();
+ }
+
+ /** Called when the dialog's ok button is clicked */
+ public void onClick(DialogInterface dialog, int which) {
+ mEditContactActivity.mInTheGroup = mInTheGroup;
+ mEntry.data = mEditContactActivity.generateGroupList();
+ mEditContactActivity.updateDataView(mEntry, mEntry.data);
+ }
+
+ /** Called when each group is clicked */
+ public void onClick(DialogInterface dialog, int which, boolean isChecked) {
+ mInTheGroup[which] = isChecked;
+ }
+ }
+
+
private void doPickRingtone(EditEntry entry) {
Intent intent = new Intent(RingtoneManager.ACTION_RINGTONE_PICKER);
// Allow user to pick 'Default'
@@ -881,6 +1025,64 @@
}
finish();
}
+
+ /**
+ * Gets the group id based on group name.
+ *
+ * @param resolver the resolver to use
+ * @param groupName the name of the group to add the contact to
+ * @return the id of the group
+ * @throws IllegalStateException if the group can't be found
+ */
+ private long getGroupId(ContentResolver resolver, String groupName) {
+ long groupId = 0;
+ Cursor groupsCursor = resolver.query(Groups.CONTENT_URI, GROUP_ID_PROJECTION,
+ Groups.NAME + "=?", new String[] { groupName }, null);
+ if (groupsCursor != null) {
+ try {
+ if (groupsCursor.moveToFirst()) {
+ groupId = groupsCursor.getLong(0);
+ }
+ } finally {
+ groupsCursor.close();
+ }
+ }
+
+ if (groupId == 0) {
+ throw new IllegalStateException("Failed to find the " + groupName + "group");
+ }
+
+ return groupId;
+ }
+
+ /**
+ * Deletes group membership based on person and group ids.
+ *
+ * @param personId the person id
+ * @param groupId the group id
+ * @return the id of the group membership
+ */
+ private void deleteGroupMembership(long personId, long groupId) {
+ long groupMembershipId = 0;
+ Cursor groupsCursor = mResolver.query(GroupMembership.CONTENT_URI, GROUPMEMBERSHIP_ID_PROJECTION,
+ GroupMembership.PERSON_ID + "=? AND " + GroupMembership.GROUP_ID + "=?",
+ new String[] {String.valueOf(personId), String.valueOf(groupId)}, null);
+ if (groupsCursor != null) {
+ try {
+ if (groupsCursor.moveToFirst()) {
+ groupMembershipId = groupsCursor.getLong(0);
+ }
+ } finally {
+ groupsCursor.close();
+ }
+ }
+
+ if (groupMembershipId != 0) {
+ final Uri groupsUri = ContentUris.withAppendedId(
+ GroupMembership.CONTENT_URI,groupMembershipId);
+ mResolver.delete(groupsUri, null, null);
+ }
+ }
/**
* Save the various fields to the existing contact.
@@ -929,6 +1131,18 @@
values.put(entry.column, (String) null);
mResolver.update(entry.uri, values, null, null);
}
+ } else if (kind == EditEntry.KIND_GROUP) {
+ if (entry.id != 0) {
+ for (int g = 0; g < mGroups.length; g++) {
+ long groupId = getGroupId(mResolver, mGroups[g].toString());
+ if (mInTheGroup[g]) {
+ Contacts.People.addToGroup(mResolver, entry.id, groupId);
+ numValues++;
+ } else {
+ deleteGroupMembership(entry.id, groupId);
+ }
+ }
+ }
} else {
if (!empty) {
values.clear();
@@ -1045,7 +1259,16 @@
int entryCount = ContactEntryAdapter.countEntries(mSections, false);
for (int i = 0; i < entryCount; i++) {
EditEntry entry = ContactEntryAdapter.getEntry(mSections, i, false);
- if (entry.kind != EditEntry.KIND_CONTACT) {
+ if (entry.kind == EditEntry.KIND_GROUP) {
+ long contactId = ContentUris.parseId(contactUri);
+ for (int g = 0; g < mGroups.length; g++) {
+ if (mInTheGroup[g]) {
+ long groupId = getGroupId(mResolver, mGroups[g].toString());
+ People.addToGroup(mResolver, contactId, groupId);
+ numValues++;
+ }
+ }
+ } else if (entry.kind != EditEntry.KIND_CONTACT) {
values.clear();
if (entry.toValues(values)) {
// Only create the entry if there is data
@@ -1152,7 +1375,15 @@
mUri);
mNoteEntries.add(entry);
}
-
+
+ // Groups
+ populateGroups();
+ if (mGroups != null) {
+ entry = EditEntry.newGroupEntry(this, generateGroupList(), mUri,
+ personCursor.getLong(0));
+ mOtherEntries.add(entry);
+ }
+
// Ringtone
entry = EditEntry.newRingtoneEntry(this,
personCursor.getString(CONTACT_CUSTOM_RINGTONE_COLUMN), mUri);
@@ -1316,6 +1547,13 @@
mEmailEntries.add(entry);
}
+ // Group
+ populateGroups();
+ if (mGroups != null) {
+ entry = EditEntry.newGroupEntry(this, null, mUri, 0);
+ mOtherEntries.add(entry);
+ }
+
// Ringtone
entry = EditEntry.newRingtoneEntry(this, null, mUri);
mOtherEntries.add(entry);
@@ -1577,6 +1815,9 @@
// with some additional logic.
if (entry.kind == Contacts.KIND_ORGANIZATION) {
view = mInflater.inflate(R.layout.edit_contact_entry_org, parent, false);
+ } else if (isOtherEntry(entry, GroupMembership.GROUP_ID)) {
+ view = mInflater.inflate(R.layout.edit_contact_entry_group, parent, false);
+ view.setOnFocusChangeListener(this);
} else if (isOtherEntry(entry, People.CUSTOM_RINGTONE)) {
view = mInflater.inflate(R.layout.edit_contact_entry_ringtone, parent, false);
view.setOnFocusChangeListener(this);
@@ -1671,6 +1912,10 @@
private void fillViewData(final EditEntry entry) {
if (isOtherEntry(entry, People.CUSTOM_RINGTONE)) {
updateRingtoneView(entry);
+ } else if (isOtherEntry(entry, GroupMembership.GROUP_ID)) {
+ if (entry.data != null) {
+ updateDataView(entry, entry.data);
+ }
} else if (isOtherEntry(entry, People.SEND_TO_VOICEMAIL)) {
CheckBox checkBox = (CheckBox) entry.view.findViewById(R.id.checkbox);
boolean sendToVoicemail = false;
@@ -1846,7 +2091,9 @@
}
case Contacts.KIND_IM: {
- v.setText(getLabelsForKind(activity, kind)[type]);
+ if (type >= 0) {
+ v.setText(getLabelsForKind(activity, kind)[type]);
+ }
break;
}
@@ -2036,6 +2283,24 @@
}
/**
+ * Create a new group entry with the given data.
+ */
+ public static final EditEntry newGroupEntry(EditContactActivity activity,
+ String data, Uri uri, long personId) {
+ EditEntry entry = new EditEntry(activity);
+ entry.label = activity.getString(R.string.label_groups);
+ entry.data = data;
+ entry.uri = uri;
+ entry.id = personId;
+ entry.column = GroupMembership.GROUP_ID;
+ entry.kind = KIND_GROUP;
+ entry.isStaticLabel = true;
+ entry.syncDataWithView = false;
+ entry.lines = -1;
+ return entry;
+ }
+
+ /**
* Create a new ringtone entry with the given data.
*/
public static final EditEntry newRingtoneEntry(EditContactActivity activity,
diff --git a/src/com/android/contacts/ImportVCardActivity.java b/src/com/android/contacts/ImportVCardActivity.java
index 07eb821..b1dd11a 100644
--- a/src/com/android/contacts/ImportVCardActivity.java
+++ b/src/com/android/contacts/ImportVCardActivity.java
@@ -27,17 +27,19 @@
import android.os.Bundle;
import android.os.Handler;
import android.os.PowerManager;
-import android.syncml.pim.VBuilder;
-import android.syncml.pim.VBuilderCollection;
-import android.syncml.pim.VParser;
-import android.syncml.pim.vcard.VCardDataBuilder;
-import android.syncml.pim.vcard.VCardEntryCounter;
-import android.syncml.pim.vcard.VCardException;
-import android.syncml.pim.vcard.VCardNestedException;
-import android.syncml.pim.vcard.VCardParser_V21;
-import android.syncml.pim.vcard.VCardParser_V30;
-import android.syncml.pim.vcard.VCardSourceDetector;
-import android.syncml.pim.vcard.VCardVersionException;
+import android.pim.vcard.EntryCommitter;
+import android.pim.vcard.VCardBuilder;
+import android.pim.vcard.VCardBuilderCollection;
+import android.pim.vcard.VCardConfig;
+import android.pim.vcard.VCardDataBuilder;
+import android.pim.vcard.VCardEntryCounter;
+import android.pim.vcard.VCardParser_V21;
+import android.pim.vcard.VCardParser_V30;
+import android.pim.vcard.VCardSourceDetector;
+import android.pim.vcard.exception.VCardException;
+import android.pim.vcard.exception.VCardNestedException;
+import android.pim.vcard.exception.VCardNotSupportedException;
+import android.pim.vcard.exception.VCardVersionException;
import android.text.SpannableStringBuilder;
import android.text.Spanned;
import android.text.style.RelativeSizeSpan;
@@ -182,18 +184,19 @@
}
VCardEntryCounter counter = new VCardEntryCounter();
VCardSourceDetector detector = new VCardSourceDetector();
- VBuilderCollection builderCollection = new VBuilderCollection(
+ VCardBuilderCollection builderCollection = new VCardBuilderCollection(
Arrays.asList(counter, detector));
+
boolean result;
try {
- result = readOneVCard(mCanonicalPath,
- VParser.DEFAULT_CHARSET, builderCollection, null, true);
+ result = readOneVCardFile(mCanonicalPath,
+ VCardConfig.DEFAULT_CHARSET, builderCollection, null, true);
} catch (VCardNestedException e) {
try {
// Assume that VCardSourceDetector was able to detect the source.
// Try again with the detector.
- result = readOneVCard(mCanonicalPath,
- VParser.DEFAULT_CHARSET, counter, detector, false);
+ result = readOneVCardFile(mCanonicalPath,
+ VCardConfig.DEFAULT_CHARSET, counter, detector, false);
} catch (VCardNestedException e2) {
result = false;
Log.e(LOG_TAG, "Must not reach here. " + e2);
@@ -227,8 +230,8 @@
VCardSourceDetector detector = new VCardSourceDetector();
try {
- if (!readOneVCard(canonicalPath, VParser.DEFAULT_CHARSET, detector,
- null, true)) {
+ if (!readOneVCardFile(canonicalPath, VCardConfig.DEFAULT_CHARSET,
+ detector, null, true)) {
continue;
}
} catch (VCardNestedException e) {
@@ -248,45 +251,40 @@
private void doActuallyReadOneVCard(String charset, boolean doIncrementProgress,
VCardSourceDetector detector) {
- VCardDataBuilder builder;
final Context context = ImportVCardActivity.this;
+ VCardDataBuilder builder;
+ int nameOrderType =
+ (mLastNameComesBeforeFirstName ?
+ VCardConfig.NAME_ORDER_TYPE_JAPANESE :
+ VCardConfig.NAME_ORDER_TYPE_ENGLISH);
if (charset != null) {
- builder = new VCardDataBuilder(mResolver,
- mProgressDialog,
- context.getString(R.string.reading_vcard_message),
- mHandler,
- charset,
+ builder = new VCardDataBuilder(charset,
charset,
false,
- mLastNameComesBeforeFirstName);
+ nameOrderType);
} else {
- builder = new VCardDataBuilder(mResolver,
- mProgressDialog,
- context.getString(R.string.reading_vcard_message),
- mHandler,
- null,
+ charset = VCardConfig.DEFAULT_CHARSET;
+ builder = new VCardDataBuilder(null,
null,
false,
- mLastNameComesBeforeFirstName);
- charset = VParser.DEFAULT_CHARSET;
+ nameOrderType);
}
- if (doIncrementProgress) {
- builder.setOnProgressRunnable(new Runnable() {
- public void run() {
- mProgressDialog.incrementProgressBy(1);
- }
- });
- }
+ builder.addEntryHandler(new EntryCommitter(mResolver));
+ builder.addEntryHandler(new ProgressShower(mProgressDialog,
+ context.getString(R.string.reading_vcard_message),
+ mHandler,
+ doIncrementProgress));
+
try {
- readOneVCard(mCanonicalPath, charset, builder, detector, false);
+ readOneVCardFile(mCanonicalPath, charset, builder, detector, false);
} catch (VCardNestedException e) {
- Log.e(LOG_TAG, "Must not reach here.");
+ Log.e(LOG_TAG, "Never reach here.");
}
- builder.showDebugInfo();
}
- private boolean readOneVCard(String canonicalPath, String charset, VBuilder builder,
- VCardSourceDetector detector, boolean throwNestedException)
+ private boolean readOneVCardFile(String canonicalPath, String charset,
+ VCardBuilder builder, VCardSourceDetector detector,
+ boolean throwNestedException)
throws VCardNestedException {
FileInputStream is;
try {
@@ -316,9 +314,8 @@
}
}
}
- mVCardParser.showDebugInfo();
} catch (IOException e) {
- Log.e(LOG_TAG, "IOException was emitted: " + e);
+ Log.e(LOG_TAG, "IOException was emitted: " + e.getMessage());
mProgressDialog.dismiss();
@@ -326,19 +323,15 @@
getString(R.string.fail_reason_io_error) +
" (" + e.getMessage() + ")"));
return false;
- } catch (VCardNestedException e) {
- if (throwNestedException) {
- throw e;
- } else {
- Log.e(LOG_TAG, "VCardNestedException was emitted: " + e);
- mHandler.post(new ErrorDisplayer(
- getString(R.string.fail_reason_vcard_parse_error) +
- " (" + e.getMessage() + ")"));
- return false;
+ } catch (VCardNotSupportedException e) {
+ if ((e instanceof VCardNestedException) && throwNestedException) {
+ throw (VCardNestedException)e;
}
+ mHandler.post(new ErrorDisplayer(
+ getString(R.string.fail_reason_vcard_not_supported_error) +
+ " (" + e.getMessage() + ")"));
+ return false;
} catch (VCardException e) {
- Log.e(LOG_TAG, "VCardException was emitted: " + e);
-
mHandler.post(new ErrorDisplayer(
getString(R.string.fail_reason_vcard_parse_error) +
" (" + e.getMessage() + ")"));
diff --git a/src/com/android/contacts/ProgressShower.java b/src/com/android/contacts/ProgressShower.java
new file mode 100644
index 0000000..9498569
--- /dev/null
+++ b/src/com/android/contacts/ProgressShower.java
@@ -0,0 +1,84 @@
+/*
+ * Copyright (C) 2009 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;
+
+import android.app.ProgressDialog;
+import android.os.Handler;
+import android.pim.vcard.ContactStruct;
+import android.pim.vcard.EntryHandler;
+import android.pim.vcard.VCardConfig;
+import android.util.Log;
+
+public class ProgressShower implements EntryHandler {
+ public static final String LOG_TAG = "vcard.ProgressShower";
+
+ private final Handler mHandler;
+ private final ProgressDialog mProgressDialog;
+ private final String mProgressMessage;
+ private final boolean mIncrementProgress;
+
+ private long mTime;
+
+ private class ShowProgressRunnable implements Runnable {
+ private ContactStruct mContact;
+
+ public ShowProgressRunnable(ContactStruct contact) {
+ mContact = contact;
+ }
+
+ public void run() {
+ mProgressDialog.setMessage(mProgressMessage + "\n" +
+ mContact.displayString());
+ if (mIncrementProgress) {
+ mProgressDialog.incrementProgressBy(1);
+ }
+ }
+ }
+
+ public ProgressShower(ProgressDialog progressDialog,
+ String progressMessage,
+ Handler handler,
+ boolean incrementProgress) {
+ mHandler = handler;
+ mProgressDialog = progressDialog;
+ mProgressMessage = progressMessage;
+ mIncrementProgress = incrementProgress;
+ }
+
+ public void onEntryCreated(ContactStruct contactStruct) {
+ long start = System.currentTimeMillis();
+
+ if (!contactStruct.isIgnorable()) {
+ if (mProgressDialog != null && mProgressMessage != null) {
+ if (mHandler != null) {
+ mHandler.post(new ShowProgressRunnable(contactStruct));
+ } else {
+ mProgressDialog.setMessage(mProgressMessage + "\n" +
+ contactStruct.displayString());
+ }
+ }
+ }
+
+ mTime += System.currentTimeMillis() - start;
+ }
+
+ public void onFinal() {
+ if (VCardConfig.showPerformanceLog()) {
+ Log.d(LOG_TAG,
+ String.format("Time to progress a dialog: %ld ms", mTime));
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/com/android/contacts/ShowOrCreateActivity.java b/src/com/android/contacts/ShowOrCreateActivity.java
index 0732ffe..75af4ae 100755
--- a/src/com/android/contacts/ShowOrCreateActivity.java
+++ b/src/com/android/contacts/ShowOrCreateActivity.java
@@ -41,6 +41,7 @@
* connected with a specific E-mail address or phone number. Will search based
* on incoming {@link Intent#getData()} as described by
* {@link Intents#SHOW_OR_CREATE_CONTACT}.
+ *
* <ul>
* <li>If no matching contacts found, will prompt user with dialog to add to a
* contact, then will use {@link Intent#ACTION_INSERT_OR_EDIT} to let create new
diff --git a/src/com/android/contacts/SpecialCharSequenceMgr.java b/src/com/android/contacts/SpecialCharSequenceMgr.java
index 999e141..3f2c304 100644
--- a/src/com/android/contacts/SpecialCharSequenceMgr.java
+++ b/src/com/android/contacts/SpecialCharSequenceMgr.java
@@ -181,12 +181,19 @@
if (input.equals(MMI_IMEI_DISPLAY)) {
int networkType = ((TelephonyManager)context.getSystemService(
Context.TELEPHONY_SERVICE)).getNetworkType();
- // check for GSM
- if(networkType == TelephonyManager.NETWORK_TYPE_GPRS ||
- networkType == TelephonyManager.NETWORK_TYPE_EDGE ||
- networkType == TelephonyManager.NETWORK_TYPE_UMTS ) {
- showIMEIPanel(context, useSystemWindow);
+ if (networkType == TelephonyManager.NETWORK_TYPE_GPRS ||
+ networkType == TelephonyManager.NETWORK_TYPE_EDGE ||
+ networkType == TelephonyManager.NETWORK_TYPE_UMTS) {
+
+ showIMEIPanel(context, useSystemWindow);
+ return true;
+ } else if (networkType == TelephonyManager.NETWORK_TYPE_CDMA ||
+ networkType == TelephonyManager.NETWORK_TYPE_EVDO_0 ||
+ networkType == TelephonyManager.NETWORK_TYPE_EVDO_A ||
+ networkType == TelephonyManager.NETWORK_TYPE_1xRTT) {
+
+ showMEIDPanel(context, useSystemWindow);
return true;
}
}
@@ -207,6 +214,19 @@
alert.getWindow().setType(WindowManager.LayoutParams.TYPE_PRIORITY_PHONE);
}
+ static void showMEIDPanel(Context context, boolean useSystemWindow) {
+ String meidStr = ((TelephonyManager)context.getSystemService(Context.TELEPHONY_SERVICE))
+ .getDeviceId();
+
+ AlertDialog alert = new AlertDialog.Builder(context)
+ .setTitle(R.string.meid)
+ .setMessage(meidStr)
+ .setPositiveButton(android.R.string.ok, null)
+ .setCancelable(false)
+ .show();
+ alert.getWindow().setType(WindowManager.LayoutParams.TYPE_PRIORITY_PHONE);
+ }
+
/*******
* This code is used to handle SIM Contact queries
*******/
diff --git a/src/com/android/contacts/TwelveKeyDialer.java b/src/com/android/contacts/TwelveKeyDialer.java
index 152ff30..9284e05 100644
--- a/src/com/android/contacts/TwelveKeyDialer.java
+++ b/src/com/android/contacts/TwelveKeyDialer.java
@@ -34,6 +34,7 @@
import android.os.RemoteException;
import android.os.ServiceManager;
import android.os.SystemClock;
+import android.os.Vibrator;
import android.provider.Contacts.Intents.Insert;
import android.provider.Contacts.People;
import android.provider.Contacts.Phones;
@@ -98,7 +99,12 @@
// determines if we want to playback local DTMF tones.
private boolean mDTMFToneEnabled;
-
+
+ // Vibration (haptic feedback) for dialer key presses.
+ private Vibrator mVibrator;
+ private boolean mVibrateOn;
+ private long mVibrateDuration;
+
/** Identifier for the "Add Call" intent extra. */
static final String ADD_CALL_MODE_KEY = "add_call_mode";
/** Indicates if we are opening this dialer to add a call from the InCallScreen. */
@@ -215,6 +221,13 @@
}
}
}
+
+ // Initialize vibration parameters.
+ // TODO: We might eventually need to make mVibrateOn come from a
+ // user preference rather than a per-platform resource, in which
+ // case we would need to update it in onResume() rather than here.
+ mVibrateOn = r.getBoolean(R.bool.config_enable_dialer_key_vibration);
+ mVibrateDuration = (long) r.getInteger(R.integer.config_dialer_key_vibrate_duration);
}
@Override
@@ -371,7 +384,7 @@
@Override
protected void onResume() {
super.onResume();
-
+
// retrieve the DTMF tone play back setting.
mDTMFToneEnabled = Settings.System.getInt(getContentResolver(),
Settings.System.DTMF_TONE_WHEN_DIALING, 1) == 1;
@@ -534,6 +547,7 @@
}
private void keyPressed(int keyCode) {
+ vibrate();
KeyEvent event = new KeyEvent(KeyEvent.ACTION_DOWN, keyCode);
mDigits.onKeyDown(keyCode, event);
}
@@ -617,6 +631,7 @@
return;
}
case R.id.digits: {
+ vibrate(); // Vibrate here too, just like we do for the regular keys
placeCall();
return;
}
@@ -939,4 +954,17 @@
}
return phoneInUse;
}
+
+ /**
+ * Triggers haptic feedback (if enabled) for dialer key presses.
+ */
+ private synchronized void vibrate() {
+ if (!mVibrateOn) {
+ return;
+ }
+ if (mVibrator == null) {
+ mVibrator = new Vibrator();
+ }
+ mVibrator.vibrate(mVibrateDuration);
+ }
}
diff --git a/src/com/android/contacts/ViewContactActivity.java b/src/com/android/contacts/ViewContactActivity.java
index 28a82b4..e5afdc2 100644
--- a/src/com/android/contacts/ViewContactActivity.java
+++ b/src/com/android/contacts/ViewContactActivity.java
@@ -73,6 +73,8 @@
import android.provider.Contacts;
import android.provider.Im;
import android.provider.Contacts.ContactMethods;
+import android.provider.Contacts.Groups;
+import android.provider.Contacts.GroupMembership;
import android.provider.Contacts.Organizations;
import android.provider.Contacts.People;
import android.provider.Contacts.Phones;
@@ -136,6 +138,7 @@
/* package */ ArrayList<ViewEntry> mPostalEntries = new ArrayList<ViewEntry>();
/* package */ ArrayList<ViewEntry> mImEntries = new ArrayList<ViewEntry>();
/* package */ ArrayList<ViewEntry> mOrganizationEntries = new ArrayList<ViewEntry>();
+ /* package */ ArrayList<ViewEntry> mGroupEntries = new ArrayList<ViewEntry>();
/* package */ ArrayList<ViewEntry> mOtherEntries = new ArrayList<ViewEntry>();
/* package */ ArrayList<ArrayList<ViewEntry>> mSections = new ArrayList<ArrayList<ViewEntry>>();
@@ -229,6 +232,7 @@
mSections.add(mImEntries);
mSections.add(mPostalEntries);
mSections.add(mOrganizationEntries);
+ mSections.add(mGroupEntries);
mSections.add(mOtherEntries);
//TODO Read this value from a preference
@@ -395,6 +399,11 @@
menu.add(0, 0, 0, R.string.menu_viewAddress).setIntent(entry.intent);
break;
}
+
+ case ContactEntryAdapter.Entry.KIND_GROUP: {
+ menu.add(0, 0, 0, R.string.menu_viewGroup).setIntent(entry.intent);
+ break;
+ }
}
}
@@ -579,6 +588,11 @@
separator = new ViewEntry();
separator.kind = ViewEntry.KIND_SEPARATOR;
+ separator.data = getString(R.string.listSeparatorGroups);
+ mGroupEntries.add(separator);
+
+ separator = new ViewEntry();
+ separator.kind = ViewEntry.KIND_SEPARATOR;
separator.data = getString(R.string.listSeparatorOtherInformation);
mOtherEntries.add(separator);
}
@@ -716,7 +730,7 @@
case Contacts.KIND_IM: {
Object protocolObj = ContactMethods.decodeImProtocol(
methodsCursor.getString(METHODS_AUX_DATA_COLUMN));
- String host;
+ String host = null;
if (protocolObj instanceof Number) {
int protocol = ((Number) protocolObj).intValue();
entry.label = buildActionString(R.string.actionChat,
@@ -726,7 +740,7 @@
|| protocol == ContactMethods.PROTOCOL_MSN) {
entry.maxLabelLines = 2;
}
- } else {
+ } else if (protocolObj != null) {
String providerName = (String) protocolObj;
entry.label = buildActionString(R.string.actionChat,
providerName, false);
@@ -848,7 +862,6 @@
organizationsCursor.close();
}
-
// Build the other entries
String note = personCursor.getString(CONTACT_NOTES_COLUMN);
if (!TextUtils.isEmpty(note)) {
@@ -863,7 +876,49 @@
entry.actionIcon = R.drawable.sym_note;
mOtherEntries.add(entry);
}
-
+
+ // Build the group entries
+ final Uri groupsUri = Uri.withAppendedPath(mUri, GroupMembership.CONTENT_DIRECTORY);
+ Cursor groupCursor = mResolver.query(groupsUri, ContactsListActivity.GROUPS_PROJECTION,
+ null, null, Groups.DEFAULT_SORT_ORDER);
+ if (groupCursor != null) {
+ try {
+ StringBuilder sb = new StringBuilder();
+
+ while (groupCursor.moveToNext()) {
+ String systemId = groupCursor.getString(
+ ContactsListActivity.GROUPS_COLUMN_INDEX_SYSTEM_ID);
+
+ if (systemId != null || Groups.GROUP_MY_CONTACTS.equals(systemId)) {
+ continue;
+ }
+
+ String name = groupCursor.getString(ContactsListActivity.GROUPS_COLUMN_INDEX_NAME);
+ if (!TextUtils.isEmpty(name)) {
+ if (sb.length() == 0) {
+ sb.append(name);
+ } else {
+ sb.append(getString(R.string.group_list, name));
+ }
+ }
+ }
+
+ if (sb.length() > 0) {
+ ViewEntry entry = new ViewEntry();
+ entry.kind = ContactEntryAdapter.Entry.KIND_GROUP;
+ entry.label = getString(R.string.label_groups);
+ entry.data = sb.toString();
+ entry.intent = new Intent(Intent.ACTION_EDIT, mUri);
+
+ // TODO: Add an icon for the groups item.
+
+ mGroupEntries.add(entry);
+ }
+ } finally {
+ groupCursor.close();
+ }
+ }
+
// Build the ringtone entry
String ringtoneStr = personCursor.getString(CONTACT_CUSTOM_RINGTONE_COLUMN);
if (!TextUtils.isEmpty(ringtoneStr)) {