summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorblong <blong@codeaurora.org>2015-08-19 14:55:56 +0800
committerblong <blong@codeaurora.org>2015-09-10 13:59:38 +0800
commit8ced6a5c88c57a892ca6cdaefa08d69907171c94 (patch)
tree84d0e04683bd33a796adaab97d74fc940addf983
parent354bdd57c9701a1562a5dee205432fe285fa0112 (diff)
downloadpackages_apps_Contacts-8ced6a5c88c57a892ca6cdaefa08d69907171c94.tar.gz
packages_apps_Contacts-8ced6a5c88c57a892ca6cdaefa08d69907171c94.tar.bz2
packages_apps_Contacts-8ced6a5c88c57a892ca6cdaefa08d69907171c94.zip
Add contacts group feature
- Restore group tab which was deleted - Add local group feature for phone account Change-Id: I298642d353492f2ff443fbc5a2f3fbf4f4eb024e
-rw-r--r--res/layout-land/group_editor_view.xml23
-rw-r--r--res/layout-sw600dp/group_editor_view.xml21
-rw-r--r--res/layout/group_browse_list_fragment.xml3
-rw-r--r--res/layout/group_editor_autocomplete_view.xml3
-rw-r--r--res/layout/group_editor_view.xml21
-rw-r--r--res/menu/people_options.xml4
-rw-r--r--res/menu/view_group.xml4
-rw-r--r--res/values-zh-rCN/strings.xml1
-rw-r--r--res/values/colors.xml4
-rw-r--r--res/values/strings.xml3
-rw-r--r--src/com/android/contacts/GroupListLoader.java4
-rw-r--r--src/com/android/contacts/GroupMetaDataLoader.java4
-rw-r--r--src/com/android/contacts/activities/ActionBarAdapter.java3
-rw-r--r--src/com/android/contacts/activities/PeopleActivity.java140
-rw-r--r--src/com/android/contacts/group/GroupBrowseListAdapter.java6
-rw-r--r--src/com/android/contacts/group/GroupDetailFragment.java21
-rw-r--r--src/com/android/contacts/group/GroupEditorFragment.java81
-rw-r--r--src/com/android/contacts/group/SuggestedMemberListAdapter.java10
-rw-r--r--src/com/android/contacts/quickcontact/QuickContactActivity.java53
19 files changed, 385 insertions, 24 deletions
diff --git a/res/layout-land/group_editor_view.xml b/res/layout-land/group_editor_view.xml
index dded4c3fc..a17b4669a 100644
--- a/res/layout-land/group_editor_view.xml
+++ b/res/layout-land/group_editor_view.xml
@@ -52,9 +52,26 @@
android:paddingStart="8dip"
android:orientation="vertical"
>
- <include
- layout="@layout/group_editor_autocomplete_view"
- android:id="@+id/add_member_field"/>
+ <LinearLayout
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:orientation="horizontal">
+ <include
+ layout="@layout/group_editor_autocomplete_view"
+ android:id="@+id/add_member_field"/>
+
+ <ImageView
+ android:id="@+id/addGroupMember"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:cropToPadding="true"
+ android:scaleType="centerCrop"
+ android:src="@drawable/ic_add_contact_holo_light"
+ android:background="?android:attr/selectableItemBackground"
+ android:gravity="start"
+ android:layout_gravity="center"/>
+ </LinearLayout>
+
<include
layout="@layout/group_editor_existing_member_list"
android:id="@android:id/list"/>
diff --git a/res/layout-sw600dp/group_editor_view.xml b/res/layout-sw600dp/group_editor_view.xml
index 717fc28f4..1541c3a92 100644
--- a/res/layout-sw600dp/group_editor_view.xml
+++ b/res/layout-sw600dp/group_editor_view.xml
@@ -63,9 +63,24 @@
layout="@layout/editor_account_header"
android:visibility="invisible"/>
- <include
- layout="@layout/group_editor_autocomplete_view"
- android:id="@+id/add_member_field"/>
+ <LinearLayout android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:orientation="horizontal">
+ <include
+ layout="@layout/group_editor_autocomplete_view"
+ android:id="@+id/add_member_field"/>
+
+ <ImageView
+ android:id="@+id/addGroupMember"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:cropToPadding="true"
+ android:scaleType="centerCrop"
+ android:src="@drawable/ic_add_contact_holo_light"
+ android:background="?android:attr/selectableItemBackground"
+ android:gravity="start"
+ android:layout_gravity="center"/>
+ </LinearLayout>
<include
layout="@layout/group_editor_existing_member_list"
diff --git a/res/layout/group_browse_list_fragment.xml b/res/layout/group_browse_list_fragment.xml
index 30c2fec3a..c7339b0b4 100644
--- a/res/layout/group_browse_list_fragment.xml
+++ b/res/layout/group_browse_list_fragment.xml
@@ -18,7 +18,8 @@
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
- android:orientation="vertical">
+ android:orientation="vertical"
+ android:background="@color/group_list_background_color">
<!-- See group_browse_list_item.xml for the reason for the transparent android:listSelector -->
<view
diff --git a/res/layout/group_editor_autocomplete_view.xml b/res/layout/group_editor_autocomplete_view.xml
index c8e716a38..4c3fc22ae 100644
--- a/res/layout/group_editor_autocomplete_view.xml
+++ b/res/layout/group_editor_autocomplete_view.xml
@@ -18,7 +18,8 @@
<AutoCompleteTextView
xmlns:android="http://schemas.android.com/apk/res/android"
- android:layout_width="match_parent"
+ android:layout_width="0dip"
+ android:layout_weight="1"
android:layout_height="wrap_content"
android:textAppearance="?android:attr/textAppearanceMedium"
android:textColor="?android:attr/textColorPrimary"
diff --git a/res/layout/group_editor_view.xml b/res/layout/group_editor_view.xml
index d94853db7..1bda19c73 100644
--- a/res/layout/group_editor_view.xml
+++ b/res/layout/group_editor_view.xml
@@ -44,9 +44,24 @@
android:paddingLeft="8dip"
android:paddingStart="8dip"/>
- <include
- layout="@layout/group_editor_autocomplete_view"
- android:id="@+id/add_member_field"/>
+ <LinearLayout android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:orientation="horizontal">
+ <include
+ layout="@layout/group_editor_autocomplete_view"
+ android:id="@+id/add_member_field"/>
+
+ <ImageView
+ android:id="@+id/addGroupMember"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:cropToPadding="true"
+ android:scaleType="centerCrop"
+ android:src="@drawable/ic_add_contact_holo_light"
+ android:background="?android:attr/selectableItemBackground"
+ android:gravity="start"
+ android:layout_gravity="center"/>
+ </LinearLayout>
<include
layout="@layout/group_editor_existing_member_list"
diff --git a/res/menu/people_options.xml b/res/menu/people_options.xml
index e561f6137..3ccf855c9 100644
--- a/res/menu/people_options.xml
+++ b/res/menu/people_options.xml
@@ -41,6 +41,10 @@
android:title="@string/menu_settings" />
<item
+ android:id="@+id/menu_add_group"
+ android:title="@string/menu_new_group_action_bar" />
+
+ <item
android:id="@+id/menu_memory_status"
android:title="@string/menu_memory_status" />
diff --git a/res/menu/view_group.xml b/res/menu/view_group.xml
index 669f401c8..eb6cf5f6a 100644
--- a/res/menu/view_group.xml
+++ b/res/menu/view_group.xml
@@ -23,4 +23,8 @@
<item
android:id="@+id/menu_delete_group"
android:title="@string/menu_deleteGroup" />
+
+ <item
+ android:id="@+id/menu_move_group_members"
+ android:title="@string/menu_moveGroupMembers" />
</menu>
diff --git a/res/values-zh-rCN/strings.xml b/res/values-zh-rCN/strings.xml
index c56218ae9..868f3e6aa 100644
--- a/res/values-zh-rCN/strings.xml
+++ b/res/values-zh-rCN/strings.xml
@@ -133,6 +133,7 @@
</plurals>
<string name="all_contacts_tab_label" msgid="6250372293594147703">"所有联系人"</string>
<string name="favorites_tab_label" msgid="1524869648904016414">"收藏"</string>
+ <string name="contacts_groups_label">"群组"</string>
<string name="callBack" msgid="5498224409038809224">"回电"</string>
<string name="callAgain" msgid="3197312117049874778">"重拨"</string>
<string name="returnCall" msgid="8171961914203617813">"回拨"</string>
diff --git a/res/values/colors.xml b/res/values/colors.xml
index a537a9554..7cc8f586a 100644
--- a/res/values/colors.xml
+++ b/res/values/colors.xml
@@ -56,6 +56,10 @@
<color name="call_arrow_green">#2aad6f</color>
<color name="call_arrow_red">#ff2e58</color>
+ <color name="contact_all_list_background_color">#FFFFFF</color>
+ <color name="contact_favorites_list_background_color">#FFFFFF</color>
+ <color name="group_list_background_color">#FFFFFF</color>
+
<!-- Background color of pinned header items. -->
<color name="list_item_pinned_header_color">@color/background_primary</color>
diff --git a/res/values/strings.xml b/res/values/strings.xml
index 20d304ee8..f4ff2cece 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -335,6 +335,9 @@
<!-- The title of "favorites" tab. [CHAR LIMIT=14] -->
<string name="favorites_tab_label">Favorites</string>
+ <!-- The title of "groups" tab. [CHAR LIMIT=14] -->
+ <string name="contacts_groups_label">Groups</string>
+
<!-- Action string for calling back a number in the call log -->
<string name="callBack">Call back</string>
diff --git a/src/com/android/contacts/GroupListLoader.java b/src/com/android/contacts/GroupListLoader.java
index 2589c9bb4..e7fd6428f 100644
--- a/src/com/android/contacts/GroupListLoader.java
+++ b/src/com/android/contacts/GroupListLoader.java
@@ -49,8 +49,6 @@ public final class GroupListLoader extends CursorLoader {
public GroupListLoader(Context context) {
super(context, GROUP_LIST_URI, COLUMNS, Groups.ACCOUNT_TYPE + " NOT NULL AND "
+ Groups.ACCOUNT_NAME + " NOT NULL AND " + Groups.AUTO_ADD + "=0 AND " +
- Groups.FAVORITES + "=0 AND " + Groups.DELETED + "=0", null,
- Groups.ACCOUNT_TYPE + ", " + Groups.ACCOUNT_NAME + ", " + Groups.DATA_SET + ", " +
- Groups.TITLE + " COLLATE LOCALIZED ASC");
+ Groups.FAVORITES + "=0 AND " + Groups.DELETED + "=0", null, "account_id");
}
}
diff --git a/src/com/android/contacts/GroupMetaDataLoader.java b/src/com/android/contacts/GroupMetaDataLoader.java
index 834404138..ea503d017 100644
--- a/src/com/android/contacts/GroupMetaDataLoader.java
+++ b/src/com/android/contacts/GroupMetaDataLoader.java
@@ -50,7 +50,9 @@ public final class GroupMetaDataLoader extends CursorLoader {
public GroupMetaDataLoader(Context context, Uri groupUri) {
super(context, ensureIsGroupUri(groupUri), COLUMNS, Groups.ACCOUNT_TYPE + " NOT NULL AND "
- + Groups.ACCOUNT_NAME + " NOT NULL", null, null);
+ + Groups.ACCOUNT_NAME + " NOT NULL AND " + Groups.DELETED + " != ?"
+ , new String[] {"1"}
+ , null);
}
/**
diff --git a/src/com/android/contacts/activities/ActionBarAdapter.java b/src/com/android/contacts/activities/ActionBarAdapter.java
index 5a95c90bc..6a81d066b 100644
--- a/src/com/android/contacts/activities/ActionBarAdapter.java
+++ b/src/com/android/contacts/activities/ActionBarAdapter.java
@@ -110,8 +110,9 @@ public class ActionBarAdapter implements OnCloseListener {
public interface TabState {
public static int FAVORITES = 0;
public static int ALL = 1;
+ public static int GROUPS = 2;
- public static int COUNT = 2;
+ public static int COUNT = 3;
public static int DEFAULT = ALL;
}
diff --git a/src/com/android/contacts/activities/PeopleActivity.java b/src/com/android/contacts/activities/PeopleActivity.java
index aa6f7dc08..daa398563 100644
--- a/src/com/android/contacts/activities/PeopleActivity.java
+++ b/src/com/android/contacts/activities/PeopleActivity.java
@@ -64,6 +64,9 @@ import com.android.contacts.common.util.ImplicitIntentsUtil;
import com.android.contacts.common.widget.FloatingActionButtonController;
import com.android.contacts.editor.EditorIntents;
import com.android.contacts.common.editor.SelectAccountDialogFragment;
+import com.android.contacts.group.GroupBrowseListFragment;
+import com.android.contacts.group.GroupBrowseListFragment.OnGroupBrowserActionListener;
+import com.android.contacts.group.GroupDetailFragment;
import com.android.contacts.interactions.ContactDeletionInteraction;
import com.android.contacts.common.interactions.ImportExportDialogFragment;
import com.android.contacts.common.interactions.ImportExportDialogFragment.ExportToSimThread;
@@ -129,7 +132,8 @@ public class PeopleActivity extends ContactsActivity implements
// These values needs to start at 2. See {@link ContactEntryListFragment}.
private static final int SUBACTIVITY_ACCOUNT_FILTER = 2;
-
+ private static final int SUBACTIVITY_NEW_GROUP = 4;
+ private static final int SUBACTIVITY_EDIT_GROUP = 5;
private final DialogManager mDialogManager = new DialogManager(this);
private ContactsIntentResolver mIntentResolver;
@@ -137,6 +141,9 @@ public class PeopleActivity extends ContactsActivity implements
private ActionBarAdapter mActionBarAdapter;
private FloatingActionButtonController mFloatingActionButtonController;
+ private GroupDetailFragment mGroupDetailFragment;
+ private final GroupDetailFragmentListener mGroupDetailFragmentListener =
+ new GroupDetailFragmentListener();
private View mFloatingActionButtonContainer;
private boolean wasLastFabAnimationScaleIn = false;
@@ -156,6 +163,7 @@ public class PeopleActivity extends ContactsActivity implements
*/
private MultiSelectContactsListFragment mAllFragment;
private ContactTileListFragment mFavoritesFragment;
+ private GroupBrowseListFragment mGroupsFragment;
/** ViewPager for swipe */
private ViewPager mTabPager;
@@ -348,6 +356,7 @@ public class PeopleActivity extends ContactsActivity implements
mTabTitles = new String[TabState.COUNT];
mTabTitles[TabState.FAVORITES] = getString(R.string.favorites_tab_label);
mTabTitles[TabState.ALL] = getString(R.string.all_contacts_tab_label);
+ mTabTitles[TabState.GROUPS] = getString(R.string.contacts_groups_label);
mTabPager = getView(R.id.tab_pager);
mTabPagerAdapter = new TabPagerAdapter();
mTabPager.setAdapter(mTabPagerAdapter);
@@ -370,6 +379,7 @@ public class PeopleActivity extends ContactsActivity implements
final String FAVORITE_TAG = "tab-pager-favorite";
final String ALL_TAG = "tab-pager-all";
+ final String GROUPS_TAG = "tab-pager-groups";
// Create the fragments and add as children of the view pager.
// The pager adapter will only change the visibility; it'll never create/destroy
@@ -381,13 +391,17 @@ public class PeopleActivity extends ContactsActivity implements
fragmentManager.findFragmentByTag(FAVORITE_TAG);
mAllFragment = (MultiSelectContactsListFragment)
fragmentManager.findFragmentByTag(ALL_TAG);
+ mGroupsFragment = (GroupBrowseListFragment)
+ fragmentManager.findFragmentByTag(GROUPS_TAG);
if (mFavoritesFragment == null) {
mFavoritesFragment = new ContactTileListFragment();
mAllFragment = new MultiSelectContactsListFragment();
+ mGroupsFragment = new GroupBrowseListFragment();
transaction.add(R.id.tab_pager, mFavoritesFragment, FAVORITE_TAG);
transaction.add(R.id.tab_pager, mAllFragment, ALL_TAG);
+ transaction.add(R.id.tab_pager, mGroupsFragment, GROUPS_TAG);
}
mFavoritesFragment.setListener(mFavoritesFragmentListener);
@@ -395,10 +409,13 @@ public class PeopleActivity extends ContactsActivity implements
mAllFragment.setOnContactListActionListener(new ContactBrowserActionListener());
mAllFragment.setCheckBoxListListener(new CheckBoxListListener());
+ mGroupsFragment.setListener(new GroupBrowserActionListener());
+
// Hide all fragments for now. We adjust visibility when we get onSelectedTabChanged()
// from ActionBarAdapter.
transaction.hide(mFavoritesFragment);
transaction.hide(mAllFragment);
+ transaction.hide(mGroupsFragment);
transaction.commitAllowingStateLoss();
fragmentManager.executePendingTransactions();
@@ -532,6 +549,9 @@ public class PeopleActivity extends ContactsActivity implements
case ContactsRequest.ACTION_VIEW_CONTACT:
tabToOpen = TabState.ALL;
break;
+ case ContactsRequest.ACTION_GROUP:
+ tabToOpen = TabState.GROUPS;
+ break;
default:
tabToOpen = -1;
break;
@@ -554,6 +574,7 @@ public class PeopleActivity extends ContactsActivity implements
}
configureContactListFragment();
+ configureGroupListFragment();
invalidateOptionsMenuIfNeeded();
}
@@ -673,6 +694,9 @@ public class PeopleActivity extends ContactsActivity implements
}
invalidateOptionsMenu();
showEmptyStateForTab(tab);
+ if (tab == TabState.GROUPS) {
+ mGroupsFragment.setAddAccountsVisibility(!areGroupWritableAccountsAvailable());
+ }
}
private void showEmptyStateForTab(int tab) {
@@ -682,6 +706,10 @@ public class PeopleActivity extends ContactsActivity implements
mContactsUnavailableFragment.setMessageText(
R.string.listTotalAllContactsZeroStarred, -1);
break;
+ case TabState.GROUPS:
+ mContactsUnavailableFragment.setMessageText(R.string.noGroups,
+ areGroupWritableAccountsAvailable() ? -1 : R.string.noAccounts);
+ break;
case TabState.ALL:
mContactsUnavailableFragment.setMessageText(R.string.noContacts, -1);
break;
@@ -730,6 +758,9 @@ public class PeopleActivity extends ContactsActivity implements
mActionBarAdapter.setCurrentTab(position, false);
mViewPagerTabs.onPageSelected(position);
showEmptyStateForTab(position);
+ if (position == TabState.GROUPS) {
+ mGroupsFragment.setAddAccountsVisibility(!areGroupWritableAccountsAvailable());
+ }
invalidateOptionsMenu();
}
}
@@ -788,6 +819,9 @@ public class PeopleActivity extends ContactsActivity implements
if (object == mAllFragment) {
return getTabPositionForTextDirection(TabState.ALL);
}
+ if (object == mGroupsFragment) {
+ return TabState.GROUPS;
+ }
}
return POSITION_NONE;
}
@@ -811,6 +845,8 @@ public class PeopleActivity extends ContactsActivity implements
return mFavoritesFragment;
} else if (position == TabState.ALL) {
return mAllFragment;
+ } else if (position == TabState.GROUPS) {
+ return mGroupsFragment;
}
}
throw new IllegalArgumentException("position: " + position);
@@ -918,6 +954,11 @@ public class PeopleActivity extends ContactsActivity implements
return TextUtils.getLayoutDirectionFromLocale(locale) == View.LAYOUT_DIRECTION_RTL;
}
+ private void configureGroupListFragment() {
+ mGroupsFragment.setVerticalScrollbarPosition(getScrollBarPosition());
+ mGroupsFragment.setSelectionVisible(false);
+ }
+
@Override
public void onProviderStatusChange() {
updateViewConfiguration(false);
@@ -1092,6 +1133,67 @@ public class PeopleActivity extends ContactsActivity implements
}
}
+ private final class GroupBrowserActionListener implements OnGroupBrowserActionListener {
+
+ GroupBrowserActionListener() {}
+
+ @Override
+ public void onViewGroupAction(Uri groupUri) {
+ Intent intent = new Intent(PeopleActivity.this, GroupDetailActivity.class);
+ intent.setData(groupUri);
+ startActivity(intent);
+ }
+ }
+
+ private class GroupDetailFragmentListener implements GroupDetailFragment.Listener {
+
+ GroupDetailFragmentListener() {}
+
+ @Override
+ public void onGroupSizeUpdated(String size) {
+ // Nothing needs to be done here because the size will be displayed in the detail
+ // fragment
+ }
+
+ @Override
+ public void onGroupTitleUpdated(String title) {
+ // Nothing needs to be done here because the title will be displayed in the detail
+ // fragment
+ }
+
+ @Override
+ public void onAccountTypeUpdated(String accountTypeString, String dataSet) {
+ // Nothing needs to be done here because the group source will be displayed in the
+ // detail fragment
+ }
+
+ @Override
+ public void onEditRequested(Uri groupUri) {
+ final Intent intent = new Intent(PeopleActivity.this, GroupEditorActivity.class);
+ intent.setData(groupUri);
+ intent.setAction(Intent.ACTION_EDIT);
+ startActivityForResult(intent, SUBACTIVITY_EDIT_GROUP);
+ }
+
+ @Override
+ public void onContactSelected(Uri contactUri) {
+ // Nothing needs to be done here because either quickcontact will be displayed
+ // or activity will take care of selection
+ }
+ }
+
+ public void startActivityAndForwardResult(final Intent intent) {
+ intent.setFlags(Intent.FLAG_ACTIVITY_FORWARD_RESULT);
+
+ // Forward extras to the new activity
+ Bundle extras = getIntent().getExtras();
+ if (extras != null) {
+ intent.putExtras(extras);
+ }
+ startActivity(intent);
+ finish();
+ }
+
@Override
public boolean onCreateOptionsMenu(Menu menu) {
if (!areContactsAvailable()) {
@@ -1121,6 +1223,10 @@ public class PeopleActivity extends ContactsActivity implements
return true;
}
+ if (mGroupDetailFragment != null && mGroupDetailFragment.isOptionsMenuChanged()) {
+ return true;
+ }
+
return false;
}
@@ -1133,12 +1239,14 @@ public class PeopleActivity extends ContactsActivity implements
// Get references to individual menu items in the menu
final MenuItem contactsFilterMenu = menu.findItem(R.id.menu_contacts_filter);
+ MenuItem addGroupMenu = menu.findItem(R.id.menu_add_group);
final MenuItem clearFrequentsMenu = menu.findItem(R.id.menu_clear_frequents);
final MenuItem helpMenu = menu.findItem(R.id.menu_help);
final boolean isSearchOrSelectionMode = mActionBarAdapter.isSearchMode()
|| mActionBarAdapter.isSelectionMode();
if (isSearchOrSelectionMode) {
+ addGroupMenu.setVisible(false);
contactsFilterMenu.setVisible(false);
clearFrequentsMenu.setVisible(false);
helpMenu.setVisible(false);
@@ -1146,13 +1254,25 @@ public class PeopleActivity extends ContactsActivity implements
} else {
switch (getTabPositionForTextDirection(mActionBarAdapter.getCurrentTab())) {
case TabState.FAVORITES:
+ addGroupMenu.setVisible(false);
contactsFilterMenu.setVisible(false);
clearFrequentsMenu.setVisible(hasFrequents());
break;
case TabState.ALL:
+ addGroupMenu.setVisible(false);
contactsFilterMenu.setVisible(true);
clearFrequentsMenu.setVisible(false);
break;
+ case TabState.GROUPS:
+ // Do not display the "new group" button if no accounts are available
+ if (areGroupWritableAccountsAvailable()) {
+ addGroupMenu.setVisible(true);
+ } else {
+ addGroupMenu.setVisible(false);
+ }
+ addGroupMenu.setVisible(true);
+ contactsFilterMenu.setVisible(false);
+ clearFrequentsMenu.setVisible(false);
}
helpMenu.setVisible(HelpUtils.isHelpAndFeedbackAvailable());
}
@@ -1243,6 +1363,10 @@ public class PeopleActivity extends ContactsActivity implements
case R.id.menu_join:
joinSelectedContacts();
return true;
+ case R.id.menu_add_group: {
+ createNewGroup();
+ return true;
+ }
case R.id.menu_delete: {
final Intent intent = new Intent(Intent.ACTION_DELETE, Contacts.CONTENT_URI);
intent.putExtra(EDITABLE_KEY, mActionBarAdapter.getQueryString());
@@ -1337,6 +1461,12 @@ public class PeopleActivity extends ContactsActivity implements
mAllFragment.getSelectedContactIds());
}
+ private void createNewGroup() {
+ final Intent intent = new Intent(this, GroupEditorActivity.class);
+ intent.setAction(Intent.ACTION_INSERT);
+ startActivityForResult(intent, SUBACTIVITY_NEW_GROUP);
+ }
+
@Override
public void onDeletionFinished() {
mActionBarAdapter.setSelectionMode(false);
@@ -1350,6 +1480,14 @@ public class PeopleActivity extends ContactsActivity implements
mContactListFilterController, resultCode, data);
break;
}
+ case SUBACTIVITY_NEW_GROUP:
+ case SUBACTIVITY_EDIT_GROUP: {
+ if (resultCode == RESULT_OK) {
+ mRequest.setActionCode(ContactsRequest.ACTION_GROUP);
+ mGroupsFragment.setSelectedUri(data.getData());
+ }
+ break;
+ }
// TODO: Using the new startActivityWithResultFromFragment API this should not be needed
// anymore
diff --git a/src/com/android/contacts/group/GroupBrowseListAdapter.java b/src/com/android/contacts/group/GroupBrowseListAdapter.java
index 48751e72d..0931f3e7a 100644
--- a/src/com/android/contacts/group/GroupBrowseListAdapter.java
+++ b/src/com/android/contacts/group/GroupBrowseListAdapter.java
@@ -30,6 +30,7 @@ import android.widget.TextView;
import com.android.contacts.GroupListLoader;
import com.android.contacts.R;
import com.android.contacts.common.model.account.AccountType;
+import com.android.contacts.common.model.account.PhoneAccountType;
import com.android.contacts.common.model.AccountTypeManager;
import com.google.common.base.Objects;
@@ -198,7 +199,10 @@ public class GroupBrowseListAdapter extends BaseAdapter {
AccountType accountType = mAccountTypeManager.getAccountType(
entry.getAccountType(), entry.getDataSet());
viewCache.accountType.setText(accountType.getDisplayLabel(mContext));
- viewCache.accountName.setText(entry.getAccountName());
+ // According to the UI SPEC, we will not show the account name for Phone account
+ if (!PhoneAccountType.ACCOUNT_TYPE.equals(entry.getAccountType())) {
+ viewCache.accountName.setText(entry.getAccountName());
+ }
}
private static Uri getGroupUriFromId(long groupId) {
diff --git a/src/com/android/contacts/group/GroupDetailFragment.java b/src/com/android/contacts/group/GroupDetailFragment.java
index c9cf6bd58..2039450e3 100644
--- a/src/com/android/contacts/group/GroupDetailFragment.java
+++ b/src/com/android/contacts/group/GroupDetailFragment.java
@@ -31,6 +31,7 @@ import android.database.Cursor;
import android.graphics.Rect;
import android.net.Uri;
import android.os.Bundle;
+import android.provider.ContactsContract.Contacts;
import android.provider.ContactsContract.Groups;
import android.text.TextUtils;
import android.util.Log;
@@ -58,6 +59,8 @@ import com.android.contacts.common.list.ContactTileView;
import com.android.contacts.list.GroupMemberTileAdapter;
import com.android.contacts.common.model.AccountTypeManager;
import com.android.contacts.common.model.account.AccountType;
+import com.android.contacts.activities.MultiPickContactActivity;
+import com.android.contacts.common.SimContactsConstants;
/**
* Displays the details of a group and shows a list of actions possible for the group.
@@ -115,6 +118,7 @@ public class GroupDetailFragment extends Fragment implements OnScrollListener {
private Uri mGroupUri;
private long mGroupId;
private String mGroupName;
+ private String mAccountNameString;
private String mAccountTypeString;
private String mDataSet;
private boolean mIsReadOnly;
@@ -286,6 +290,7 @@ public class GroupDetailFragment extends Fragment implements OnScrollListener {
Log.e(TAG, "Failed to load group members");
return;
}
+ getActivity().invalidateOptionsMenu();
updateSize(data.getCount());
mAdapter.setContactCursor(data);
mMemberListView.setEmptyView(mEmptyView);
@@ -298,6 +303,7 @@ public class GroupDetailFragment extends Fragment implements OnScrollListener {
private void bindGroupMetaData(Cursor cursor) {
cursor.moveToPosition(-1);
if (cursor.moveToNext()) {
+ mAccountNameString = cursor.getString(GroupMetaDataLoader.ACCOUNT_NAME);
mAccountTypeString = cursor.getString(GroupMetaDataLoader.ACCOUNT_TYPE);
mDataSet = cursor.getString(GroupMetaDataLoader.DATA_SET);
mGroupId = cursor.getLong(GroupMetaDataLoader.GROUP_ID);
@@ -454,6 +460,9 @@ public class GroupDetailFragment extends Fragment implements OnScrollListener {
final MenuItem deleteMenu = menu.findItem(R.id.menu_delete_group);
deleteMenu.setVisible(mOptionsMenuGroupDeletable);
+
+ final MenuItem moveMenu = menu.findItem(R.id.menu_move_group_members);
+ moveMenu.setVisible(isVisible() && mAdapter != null && mAdapter.getCount() > 0);
}
@Override
@@ -468,6 +477,18 @@ public class GroupDetailFragment extends Fragment implements OnScrollListener {
mCloseActivityAfterDelete);
return true;
}
+ case R.id.menu_move_group_members: {
+ Intent intent = new Intent(SimContactsConstants.ACTION_MULTI_PICK);
+ intent.setType(Contacts.CONTENT_TYPE);
+ intent.putExtra(SimContactsConstants.IS_CONTACT, true);
+ intent.putExtra(MultiPickContactActivity.KEY_GROUP_ID, getGroupId());
+ intent.putExtra(SimContactsConstants.ACCOUNT_TYPE, mAccountTypeString);
+ intent.putExtra(SimContactsConstants.ACCOUNT_NAME, mAccountNameString);
+ intent.putExtra(MultiPickContactActivity.ADD_MOVE_GROUP_MEMBER_KEY,
+ MultiPickContactActivity.ACTION_MOVE_GROUP_MEMBER);
+ startActivity(intent);
+ return true;
+ }
}
return false;
}
diff --git a/src/com/android/contacts/group/GroupEditorFragment.java b/src/com/android/contacts/group/GroupEditorFragment.java
index eda5d4f39..25ff4747e 100644
--- a/src/com/android/contacts/group/GroupEditorFragment.java
+++ b/src/com/android/contacts/group/GroupEditorFragment.java
@@ -63,6 +63,7 @@ import com.android.contacts.GroupMemberLoader.GroupEditorQuery;
import com.android.contacts.GroupMetaDataLoader;
import com.android.contacts.R;
import com.android.contacts.activities.GroupEditorActivity;
+import com.android.contacts.activities.MultiPickContactActivity;
import com.android.contacts.common.ContactPhotoManager;
import com.android.contacts.common.ContactPhotoManager.DefaultImageRequest;
import com.android.contacts.common.model.account.AccountType;
@@ -72,11 +73,14 @@ import com.android.contacts.group.SuggestedMemberListAdapter.SuggestedMember;
import com.android.contacts.common.model.AccountTypeManager;
import com.android.contacts.common.util.AccountsListAdapter.AccountListFilter;
import com.android.contacts.common.util.ViewUtil;
+import com.android.contacts.common.SimContactsConstants;
import com.google.common.base.Objects;
import java.util.ArrayList;
+import java.util.Iterator;
import java.util.List;
+import java.util.Set;
public class GroupEditorFragment extends Fragment implements SelectAccountDialogFragment.Listener {
private static final String TAG = "GroupEditorFragment";
@@ -98,6 +102,8 @@ public class GroupEditorFragment extends Fragment implements SelectAccountDialog
private static final String CURRENT_EDITOR_TAG = "currentEditorForAccount";
+ public static final int REQUEST_CODE_PICK_GROUP_MEM = 1001;
+
public static interface Listener {
/**
* Group metadata was not found, close the fragment now.
@@ -183,6 +189,7 @@ public class GroupEditorFragment extends Fragment implements SelectAccountDialog
private TextView mGroupNameView;
private AutoCompleteTextView mAutoCompleteTextView;
+ private ImageView mAddGroupMemberView;
private String mAccountName;
private String mAccountType;
@@ -311,8 +318,9 @@ public class GroupEditorFragment extends Fragment implements SelectAccountDialog
}
private void selectAccountAndCreateGroup() {
- final List<AccountWithDataSet> accounts =
- AccountTypeManager.getInstance(mContext).getAccounts(true /* writeable */);
+ final List<AccountWithDataSet> accounts = AccountTypeManager
+ .getInstance(mContext).getAccounts(true /* writeable */,
+ AccountTypeManager.FLAG_ALL_ACCOUNTS_WITHOUT_SIM);
// No Accounts available
if (accounts.isEmpty()) {
Log.e(TAG, "No accounts were found.");
@@ -404,6 +412,7 @@ public class GroupEditorFragment extends Fragment implements SelectAccountDialog
mGroupNameView = (TextView) editorView.findViewById(R.id.group_name);
mAutoCompleteTextView = (AutoCompleteTextView) editorView.findViewById(
R.id.add_member_field);
+ mAddGroupMemberView = (ImageView) editorView.findViewById(R.id.addGroupMember);
mListView = (ListView) editorView.findViewById(android.R.id.list);
mListView.setAdapter(mMemberListAdapter);
@@ -428,6 +437,7 @@ public class GroupEditorFragment extends Fragment implements SelectAccountDialog
if (mAutoCompleteTextView != null) {
mAutoCompleteAdapter = new SuggestedMemberListAdapter(mContext,
android.R.layout.simple_dropdown_item_1line);
+ mAutoCompleteTextView.setThreshold(1);
mAutoCompleteAdapter.setContentResolver(mContentResolver);
mAutoCompleteAdapter.setAccountType(mAccountType);
mAutoCompleteAdapter.setAccountName(mAccountName);
@@ -455,6 +465,23 @@ public class GroupEditorFragment extends Fragment implements SelectAccountDialog
mAutoCompleteAdapter.updateExistingMembersList(mListToDisplay);
}
+ if (mAddGroupMemberView != null) {
+ mAddGroupMemberView.setOnClickListener(new OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ Intent intent = new Intent(SimContactsConstants.ACTION_MULTI_PICK);
+ intent.setType(Contacts.CONTENT_TYPE);
+ intent.putExtra(SimContactsConstants.IS_CONTACT, true);
+ intent.putExtra(SimContactsConstants.ACCOUNT_NAME, mAccountName);
+ intent.putExtra(SimContactsConstants.ACCOUNT_TYPE, mAccountType);
+ intent.putExtra(MultiPickContactActivity.ADD_MOVE_GROUP_MEMBER_KEY,
+ MultiPickContactActivity.ACTION_ADD_GROUP_MEMBER);
+ intent.putExtra(MultiPickContactActivity.KEY_GROUP_ID, mGroupId);
+ startActivityForResult(intent, REQUEST_CODE_PICK_GROUP_MEM);
+ }
+ });
+ }
+
// If the group name is ready only, don't let the user focus on the field.
mGroupNameView.setFocusable(!mGroupNameIsReadOnly);
if(isNewEditor) {
@@ -463,6 +490,47 @@ public class GroupEditorFragment extends Fragment implements SelectAccountDialog
mStatus = Status.EDITING;
}
+ @Override
+ public void onActivityResult(int requestCode, int resultCode, Intent data) {
+ super.onActivityResult(requestCode, resultCode, data);
+ if (resultCode != Activity.RESULT_OK) {
+ return;
+ }
+ if (requestCode == REQUEST_CODE_PICK_GROUP_MEM) {
+ Bundle mChoiceSet = data.getExtras();
+ Set<String> keys = mChoiceSet.keySet();
+ Iterator<String> iterator = keys.iterator();
+ String key;
+ String[] info;
+ String contactId;
+ String nameRawContactId;
+ String displayName;
+ String lookupKey;
+ String photoUri;
+
+ while (iterator.hasNext()) {
+ key = iterator.next();
+ info = mChoiceSet.getStringArray(key);
+
+ contactId = info[1];
+
+ if (!mAutoCompleteAdapter.containsMember(Long.valueOf(contactId))) {
+ // Retrieve the contact data fields that will be sufficient
+ // to update
+ // the adapter with a new entry for this contact
+ lookupKey = info[0];
+ nameRawContactId = info[2];
+ photoUri= info[3];
+ displayName = info[4];
+
+ Member member = new Member(Long.valueOf(nameRawContactId), lookupKey,
+ Long.valueOf(contactId), displayName, photoUri);
+ addMember(member);
+ }
+ }
+ }
+ }
+
public void load(String action, Uri groupUri, Bundle intentExtras) {
mAction = action;
mGroupUri = groupUri;
@@ -713,8 +781,13 @@ public class GroupEditorFragment extends Fragment implements SelectAccountDialog
}
private void addMember(Member member) {
- // Update the display list
- mListMembersToAdd.add(member);
+ // If the contact was just removed during this session, remove it from
+ // the list of members to remove
+ if (mListMembersToRemove.contains(member)) {
+ mListMembersToRemove.remove(member);
+ } else {
+ mListMembersToAdd.add(member);
+ }
mListToDisplay.add(member);
mMemberListAdapter.notifyDataSetChanged();
diff --git a/src/com/android/contacts/group/SuggestedMemberListAdapter.java b/src/com/android/contacts/group/SuggestedMemberListAdapter.java
index 19ff61177..18ad34c7c 100644
--- a/src/com/android/contacts/group/SuggestedMemberListAdapter.java
+++ b/src/com/android/contacts/group/SuggestedMemberListAdapter.java
@@ -116,7 +116,13 @@ public class SuggestedMemberListAdapter extends ArrayAdapter<SuggestedMember> {
}
public void addNewMember(long contactId) {
- mExistingMemberContactIds.add(contactId);
+ if (!containsMember(contactId)) {
+ mExistingMemberContactIds.add(contactId);
+ }
+ }
+
+ public boolean containsMember(long contactId) {
+ return mExistingMemberContactIds.contains(contactId);
}
public void removeMember(long contactId) {
@@ -186,7 +192,7 @@ public class SuggestedMemberListAdapter extends ArrayAdapter<SuggestedMember> {
// and have the same account name and type as specified in this adapter
String searchQuery = prefix.toString() + "%";
String accountClause = RawContacts.ACCOUNT_NAME + "=? AND " +
- RawContacts.ACCOUNT_TYPE + "=?";
+ RawContacts.ACCOUNT_TYPE + "=? AND " + RawContacts.DELETED + "!= 1";
String[] args;
if (mDataSet == null) {
accountClause += " AND " + RawContacts.DATA_SET + " IS NULL";
diff --git a/src/com/android/contacts/quickcontact/QuickContactActivity.java b/src/com/android/contacts/quickcontact/QuickContactActivity.java
index 81a98b55f..ccfd76f44 100644
--- a/src/com/android/contacts/quickcontact/QuickContactActivity.java
+++ b/src/com/android/contacts/quickcontact/QuickContactActivity.java
@@ -97,6 +97,7 @@ import com.android.contacts.common.CallUtil;
import com.android.contacts.common.ClipboardUtils;
import com.android.contacts.common.Collapser;
import com.android.contacts.common.ContactsUtils;
+import com.android.contacts.common.GroupMetaData;
import com.android.contacts.common.activity.RequestPermissionsActivity;
import com.android.contacts.common.editor.SelectAccountDialogFragment;
import com.android.contacts.common.interactions.TouchPointManager;
@@ -113,6 +114,7 @@ import com.android.contacts.common.model.dataitem.DataItem;
import com.android.contacts.common.model.dataitem.DataKind;
import com.android.contacts.common.model.dataitem.EmailDataItem;
import com.android.contacts.common.model.dataitem.EventDataItem;
+import com.android.contacts.common.model.dataitem.GroupMembershipDataItem;
import com.android.contacts.common.model.dataitem.ImDataItem;
import com.android.contacts.common.model.dataitem.NicknameDataItem;
import com.android.contacts.common.model.dataitem.NoteDataItem;
@@ -1183,6 +1185,30 @@ public class QuickContactActivity extends ContactsActivity {
}
/**
+ * Maps group ID to the corresponding group name, collapses all synonymous groups. Ignores
+ * default groups (e.g. My Contacts) and favorites groups.
+ */
+ private static String getGroupName(List<GroupMetaData> groupMetaData, long groupId) {
+ if (groupMetaData == null) {
+ return "";
+ }
+
+ for (GroupMetaData group : groupMetaData) {
+ if (group.getGroupId() == groupId) {
+ if (!group.isDefaultGroup() && !group.isFavorites()) {
+ String title = group.getTitle();
+ if (!TextUtils.isEmpty(title)) {
+ return title;
+ }
+ }
+ break;
+ }
+ }
+
+ return "";
+ }
+
+ /**
* Create a card that shows "Add email" and "Add phone number" entries in grey.
*/
private void initializeNoContactDetailCard() {
@@ -1607,6 +1633,33 @@ public class QuickContactActivity extends ContactsActivity {
aboutCardName.value = res.getString(R.string.about_card_title);
}
}
+ } else if (dataItem instanceof GroupMembershipDataItem) {
+ GroupMembershipDataItem groupMembership =
+ (GroupMembershipDataItem) dataItem;
+ Long groupId = groupMembership.getGroupRowId();
+ if (groupId != null) {
+ return new Entry(/* viewId = */-1,
+ /* icon = */null,
+ res.getString(R.string.groupsLabel),
+ getGroupName(contactData.getGroupMetaData(),
+ groupId),
+ /* mSubHeaderIcon= */null,
+ /* text = */null,
+ /* mTextIcon= */null,
+ /* primaryContentDescription = */null,
+ /* intent = */null,
+ /* alternateIcon = */null,
+ /* alternateIntent = */null,
+ /* alternateContentDescription = */null,
+ /* shouldApplyColor = */false,
+ /* isEditable = */false,
+ /* EntryContextMenuInfo = */null,
+ /* thirdIcon = */null,
+ /* thirdIntent = */null,
+ /* thirdContentDescription = */null,
+ /* iconResourceId = */0);
+ }
+ return null;
} else {
// Custom DataItem
header = dataItem.buildDataStringForDisplay(context, kind);