blob: 9ed69fff19e7a5deea5e3c08d63b267c9c240d61 [file] [log] [blame]
/*
* Copyright (C) 2016 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.group;
import android.app.Activity;
import android.app.LoaderManager.LoaderCallbacks;
import android.content.ContentResolver;
import android.content.Context;
import android.content.CursorLoader;
import android.content.Intent;
import android.content.Loader;
import android.database.Cursor;
import android.database.CursorWrapper;
import android.graphics.PorterDuff;
import android.graphics.drawable.Drawable;
import android.net.Uri;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.provider.ContactsContract;
import android.provider.ContactsContract.Contacts;
import android.support.v4.content.ContextCompat;
import android.text.TextUtils;
import android.util.Log;
import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Button;
import android.widget.FrameLayout;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.Toast;
import com.android.contacts.ContactSaveService;
import com.android.contacts.ContactsUtils;
import com.android.contacts.GroupMetaDataLoader;
import com.android.contacts.R;
import com.android.contacts.activities.ActionBarAdapter;
import com.android.contacts.activities.PeopleActivity;
import com.android.contacts.group.GroupMembersAdapter.GroupMembersQuery;
import com.android.contacts.interactions.GroupDeletionDialogFragment;
import com.android.contacts.list.ContactsRequest;
import com.android.contacts.list.ContactsSectionIndexer;
import com.android.contacts.list.MultiSelectContactsListFragment;
import com.android.contacts.list.MultiSelectEntryContactListAdapter.DeleteContactListener;
import com.android.contacts.list.UiIntentActions;
import com.android.contacts.logging.ListEvent;
import com.android.contacts.logging.ListEvent.ListType;
import com.android.contacts.logging.Logger;
import com.android.contacts.logging.ScreenEvent;
import com.android.contacts.model.account.AccountWithDataSet;
import com.android.contacts.util.ImplicitIntentsUtil;
import com.android.contactsbind.FeedbackHelper;
import com.google.common.primitives.Longs;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
/** Displays the members of a group. */
public class GroupMembersFragment extends MultiSelectContactsListFragment<GroupMembersAdapter> {
private static final String TAG = "GroupMembers";
private static final String KEY_IS_EDIT_MODE = "editMode";
private static final String KEY_GROUP_URI = "groupUri";
private static final String KEY_GROUP_METADATA = "groupMetadata";
public static final String TAG_GROUP_NAME_EDIT_DIALOG = "groupNameEditDialog";
private static final String ARG_GROUP_URI = "groupUri";
private static final int LOADER_GROUP_METADATA = 100;
private static final int MSG_FAIL_TO_LOAD = 1;
private static final int RESULT_GROUP_ADD_MEMBER = 100;
/** Filters out duplicate contacts. */
private class FilterCursorWrapper extends CursorWrapper {
private int[] mIndex;
private int mCount = 0;
private int mPos = 0;
public FilterCursorWrapper(Cursor cursor) {
super(cursor);
mCount = super.getCount();
mIndex = new int[mCount];
final List<Integer> indicesToFilter = new ArrayList<>();
if (Log.isLoggable(TAG, Log.VERBOSE)) {
Log.v(TAG, "Group members CursorWrapper start: " + mCount);
}
final Bundle bundle = cursor.getExtras();
final String sections[] = bundle.getStringArray(Contacts
.EXTRA_ADDRESS_BOOK_INDEX_TITLES);
final int counts[] = bundle.getIntArray(Contacts.EXTRA_ADDRESS_BOOK_INDEX_COUNTS);
final ContactsSectionIndexer indexer = (sections == null || counts == null)
? null : new ContactsSectionIndexer(sections, counts);
mGroupMemberContactIds.clear();
for (int i = 0; i < mCount; i++) {
super.moveToPosition(i);
final String contactId = getString(GroupMembersQuery.CONTACT_ID);
if (!mGroupMemberContactIds.contains(contactId)) {
mIndex[mPos++] = i;
mGroupMemberContactIds.add(contactId);
} else {
indicesToFilter.add(i);
}
}
if (indexer != null && GroupUtil.needTrimming(mCount, counts, indexer.getPositions())) {
GroupUtil.updateBundle(bundle, indexer, indicesToFilter, sections, counts);
}
mCount = mPos;
mPos = 0;
super.moveToFirst();
if (Log.isLoggable(TAG, Log.VERBOSE)) {
Log.v(TAG, "Group members CursorWrapper end: " + mCount);
}
}
@Override
public boolean move(int offset) {
return moveToPosition(mPos + offset);
}
@Override
public boolean moveToNext() {
return moveToPosition(mPos + 1);
}
@Override
public boolean moveToPrevious() {
return moveToPosition(mPos - 1);
}
@Override
public boolean moveToFirst() {
return moveToPosition(0);
}
@Override
public boolean moveToLast() {
return moveToPosition(mCount - 1);
}
@Override
public boolean moveToPosition(int position) {
if (position >= mCount) {
mPos = mCount;
return false;
} else if (position < 0) {
mPos = -1;
return false;
}
mPos = mIndex[position];
return super.moveToPosition(mPos);
}
@Override
public int getCount() {
return mCount;
}
@Override
public int getPosition() {
return mPos;
}
}
private final LoaderCallbacks<Cursor> mGroupMetaDataCallbacks = new LoaderCallbacks<Cursor>() {
@Override
public CursorLoader onCreateLoader(int id, Bundle args) {
return new GroupMetaDataLoader(mActivity, mGroupUri);
}
@Override
public void onLoadFinished(Loader<Cursor> loader, Cursor cursor) {
if (cursor == null || cursor.isClosed() || !cursor.moveToNext()) {
Log.e(TAG, "Failed to load group metadata for " + mGroupUri);
Toast.makeText(getContext(), R.string.groupLoadErrorToast, Toast.LENGTH_SHORT)
.show();
mHandler.sendEmptyMessage(MSG_FAIL_TO_LOAD);
return;
}
mGroupMetaData = new GroupMetaData(getActivity(), cursor);
onGroupMetadataLoaded();
}
@Override
public void onLoaderReset(Loader<Cursor> loader) {}
};
private ActionBarAdapter mActionBarAdapter;
private PeopleActivity mActivity;
private Uri mGroupUri;
private boolean mIsEditMode;
private GroupMetaData mGroupMetaData;
private Set<String> mGroupMemberContactIds = new HashSet();
private Handler mHandler = new Handler() {
@Override
public void handleMessage(Message msg) {
if(msg.what == MSG_FAIL_TO_LOAD) {
mActivity.onBackPressed();
}
}
};
public static GroupMembersFragment newInstance(Uri groupUri) {
final Bundle args = new Bundle();
args.putParcelable(ARG_GROUP_URI, groupUri);
final GroupMembersFragment fragment = new GroupMembersFragment();
fragment.setArguments(args);
return fragment;
}
public GroupMembersFragment() {
setPhotoLoaderEnabled(true);
setSectionHeaderDisplayEnabled(true);
setHasOptionsMenu(true);
setListType(ListType.GROUP);
}
@Override
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
if (mGroupMetaData == null) {
// Hide menu options until metadata is fully loaded
return;
}
inflater.inflate(R.menu.view_group, menu);
}
@Override
public void onPrepareOptionsMenu(Menu menu) {
final boolean isSelectionMode = mActionBarAdapter.isSelectionMode();
final boolean isGroupEditable = mGroupMetaData != null && mGroupMetaData.editable;
final boolean isGroupReadOnly = mGroupMetaData != null && mGroupMetaData.readOnly;
setVisible(getContext(), menu, R.id.menu_multi_send_email, !mIsEditMode && !isGroupEmpty());
setVisible(getContext(), menu, R.id.menu_multi_send_message,
!mIsEditMode && !isGroupEmpty());
setVisible(getContext(), menu, R.id.menu_add, isGroupEditable && !isSelectionMode);
setVisible(getContext(), menu, R.id.menu_rename_group,
!isGroupReadOnly && !isSelectionMode);
setVisible(getContext(), menu, R.id.menu_delete_group,
!isGroupReadOnly && !isSelectionMode);
setVisible(getContext(), menu, R.id.menu_edit_group,
isGroupEditable && !mIsEditMode && !isSelectionMode && !isGroupEmpty());
setVisible(getContext(), menu, R.id.menu_remove_from_group,
isGroupEditable && isSelectionMode && !mIsEditMode);
}
private boolean isGroupEmpty() {
return getAdapter() != null && getAdapter().isEmpty();
}
private static void setVisible(Context context, Menu menu, int id, boolean visible) {
final MenuItem menuItem = menu.findItem(id);
if (menuItem != null) {
menuItem.setVisible(visible);
final Drawable icon = menuItem.getIcon();
if (icon != null) {
icon.mutate().setColorFilter(ContextCompat.getColor(context,
R.color.actionbar_icon_color), PorterDuff.Mode.SRC_ATOP);
}
}
}
/**
* Helper class for cp2 query used to look up all contact's emails and phone numbers.
*/
public static abstract class Query {
public static final String EMAIL_SELECTION =
ContactsContract.Data.MIMETYPE + "='"
+ ContactsContract.CommonDataKinds.Email.CONTENT_ITEM_TYPE + "'";
public static final String PHONE_SELECTION =
ContactsContract.Data.MIMETYPE + "='"
+ ContactsContract.CommonDataKinds.Phone.CONTENT_ITEM_TYPE + "'";
public static final String[] EMAIL_PROJECTION = {
ContactsContract.Data.CONTACT_ID,
ContactsContract.CommonDataKinds.Email._ID,
ContactsContract.Data.IS_SUPER_PRIMARY,
ContactsContract.Data.TIMES_USED,
ContactsContract.Data.DATA1
};
public static final String[] PHONE_PROJECTION = {
ContactsContract.Data.CONTACT_ID,
ContactsContract.CommonDataKinds.Phone._ID,
ContactsContract.Data.IS_SUPER_PRIMARY,
ContactsContract.Data.TIMES_USED,
ContactsContract.Data.DATA1
};
public static final int CONTACT_ID = 0;
public static final int ITEM_ID = 1;
public static final int PRIMARY = 2;
public static final int TIMES_USED = 3;
public static final int DATA1 = 4;
}
/**
* Helper class for managing data related to contacts and emails/phone numbers.
*/
private class ContactDataHelperClass {
private List<String> items = new ArrayList<>();
private String mostUsedItemId = null;
private int mostUsedTimes;
private String primaryItemId = null;
public void addItem(String item, int timesUsed, boolean primaryFlag) {
if (mostUsedItemId == null || timesUsed > mostUsedTimes) {
mostUsedItemId = item;
mostUsedTimes = timesUsed;
}
if (primaryFlag) {
primaryItemId = item;
}
items.add(item);
}
public boolean hasDefaultItem() {
return primaryItemId != null || items.size() == 1;
}
public String getDefaultSelectionItemId() {
return primaryItemId != null
? primaryItemId
: mostUsedItemId;
}
}
private void sendToGroup(long[] ids, String sendScheme, String title) {
if (ids == null || ids.length == 0) return;
// Get emails or phone numbers
// contactMap <contact_id, contact_data>
final Map<String, ContactDataHelperClass> contactMap = new HashMap<>();
// itemList <item_data>
final List<String> itemList = new ArrayList<>();
final String sIds = GroupUtil.convertArrayToString(ids);
final String select = (ContactsUtils.SCHEME_MAILTO.equals(sendScheme)
? Query.EMAIL_SELECTION
: Query.PHONE_SELECTION)
+ " AND " + ContactsContract.Data.CONTACT_ID + " IN (" + sIds + ")";
final ContentResolver contentResolver = getContext().getContentResolver();
final Cursor cursor = contentResolver.query(ContactsContract.Data.CONTENT_URI,
ContactsUtils.SCHEME_MAILTO.equals(sendScheme)
? Query.EMAIL_PROJECTION
: Query.PHONE_PROJECTION,
select, null, null);
if (cursor == null) {
return;
}
try {
cursor.moveToPosition(-1);
while (cursor.moveToNext()) {
final String contactId = cursor.getString(Query.CONTACT_ID);
final String itemId = cursor.getString(Query.ITEM_ID);
final boolean isPrimary = cursor.getInt(Query.PRIMARY) != 0;
final int timesUsed = cursor.getInt(Query.TIMES_USED);
final String data = cursor.getString(Query.DATA1);
if (!TextUtils.isEmpty(data)) {
final ContactDataHelperClass contact;
if (!contactMap.containsKey(contactId)) {
contact = new ContactDataHelperClass();
contactMap.put(contactId, contact);
} else {
contact = contactMap.get(contactId);
}
contact.addItem(itemId, timesUsed, isPrimary);
itemList.add(data);
}
}
} finally {
cursor.close();
}
// Start picker if a contact does not have a default
for (ContactDataHelperClass i : contactMap.values()) {
if (!i.hasDefaultItem()) {
// Build list of default selected item ids
final List<Long> defaultSelection = new ArrayList<>();
for (ContactDataHelperClass j : contactMap.values()) {
final String selectionItemId = j.getDefaultSelectionItemId();
if (selectionItemId != null) {
defaultSelection.add(Long.parseLong(selectionItemId));
}
}
final long[] defaultSelectionArray = Longs.toArray(defaultSelection);
startSendToSelectionPickerActivity(ids, defaultSelectionArray, sendScheme, title);
return;
}
}
if (itemList.size() == 0 || contactMap.size() < ids.length) {
Toast.makeText(getContext(), ContactsUtils.SCHEME_MAILTO.equals(sendScheme)
? getString(R.string.groupSomeContactsNoEmailsToast)
: getString(R.string.groupSomeContactsNoPhonesToast),
Toast.LENGTH_LONG).show();
}
if (itemList.size() == 0) {
return;
}
final String itemsString = TextUtils.join(",", itemList);
GroupUtil.startSendToSelectionActivity(this, itemsString, sendScheme, title);
}
private void startSendToSelectionPickerActivity(long[] ids, long[] defaultSelection,
String sendScheme, String title) {
startActivity(GroupUtil.createSendToSelectionPickerIntent(getContext(), ids,
defaultSelection, sendScheme, title));
}
private void startGroupAddMemberActivity() {
startActivityForResult(GroupUtil.createPickMemberIntent(getContext(), mGroupMetaData,
getMemberContactIds()), RESULT_GROUP_ADD_MEMBER);
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
final int id = item.getItemId();
if (id == android.R.id.home) {
mActivity.onBackPressed();
} else if (id == R.id.menu_add) {
startGroupAddMemberActivity();
} else if (id == R.id.menu_multi_send_email) {
final long[] ids = mActionBarAdapter.isSelectionMode()
? getAdapter().getSelectedContactIdsArray()
: GroupUtil.convertStringSetToLongArray(mGroupMemberContactIds);
sendToGroup(ids, ContactsUtils.SCHEME_MAILTO,
getString(R.string.menu_sendEmailOption));
} else if (id == R.id.menu_multi_send_message) {
final long[] ids = mActionBarAdapter.isSelectionMode()
? getAdapter().getSelectedContactIdsArray()
: GroupUtil.convertStringSetToLongArray(mGroupMemberContactIds);
sendToGroup(ids, ContactsUtils.SCHEME_SMSTO,
getString(R.string.menu_sendMessageOption));
} else if (id == R.id.menu_rename_group) {
GroupNameEditDialogFragment.newInstanceForUpdate(
new AccountWithDataSet(mGroupMetaData.accountName,
mGroupMetaData.accountType, mGroupMetaData.dataSet),
GroupUtil.ACTION_UPDATE_GROUP, mGroupMetaData.groupId,
mGroupMetaData.groupName).show(getFragmentManager(),
TAG_GROUP_NAME_EDIT_DIALOG);
} else if (id == R.id.menu_delete_group) {
deleteGroup();
} else if (id == R.id.menu_edit_group) {
mIsEditMode = true;
mActionBarAdapter.setSelectionMode(true);
displayDeleteButtons(true);
} else if (id == R.id.menu_remove_from_group) {
logListEvent();
removeSelectedContacts();
} else {
return super.onOptionsItemSelected(item);
}
return true;
}
private void removeSelectedContacts() {
final long[] contactIds = getAdapter().getSelectedContactIdsArray();
new UpdateGroupMembersAsyncTask(UpdateGroupMembersAsyncTask.TYPE_REMOVE,
getContext(), contactIds, mGroupMetaData.groupId, mGroupMetaData.accountName,
mGroupMetaData.accountType, mGroupMetaData.dataSet).execute();
mActionBarAdapter.setSelectionMode(false);
}
@Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
if (resultCode != Activity.RESULT_OK || data == null
|| requestCode != RESULT_GROUP_ADD_MEMBER) {
return;
}
long[] contactIds = data.getLongArrayExtra(
UiIntentActions.TARGET_CONTACT_IDS_EXTRA_KEY);
if (contactIds == null) {
final long contactId = data.getLongExtra(
UiIntentActions.TARGET_CONTACT_ID_EXTRA_KEY, -1);
if (contactId > -1) {
contactIds = new long[1];
contactIds[0] = contactId;
}
}
new UpdateGroupMembersAsyncTask(
UpdateGroupMembersAsyncTask.TYPE_ADD,
getContext(), contactIds, mGroupMetaData.groupId, mGroupMetaData.accountName,
mGroupMetaData.accountType, mGroupMetaData.dataSet).execute();
}
private final ActionBarAdapter.Listener mActionBarListener = new ActionBarAdapter.Listener() {
@Override
public void onAction(int action) {
switch (action) {
case ActionBarAdapter.Listener.Action.START_SELECTION_MODE:
if (mIsEditMode) {
displayDeleteButtons(true);
mActionBarAdapter.setActionBarTitle(getString(R.string.title_edit_group));
} else {
displayCheckBoxes(true);
}
mActivity.invalidateOptionsMenu();
break;
case ActionBarAdapter.Listener.Action.STOP_SEARCH_AND_SELECTION_MODE:
mActionBarAdapter.setSearchMode(false);
if (mIsEditMode) {
displayDeleteButtons(false);
} else {
displayCheckBoxes(false);
}
mActivity.invalidateOptionsMenu();
break;
case ActionBarAdapter.Listener.Action.BEGIN_STOPPING_SEARCH_AND_SELECTION_MODE:
break;
}
}
@Override
public void onUpButtonPressed() {
mActivity.onBackPressed();
}
};
private final OnCheckBoxListActionListener mCheckBoxListener =
new OnCheckBoxListActionListener() {
@Override
public void onStartDisplayingCheckBoxes() {
mActionBarAdapter.setSelectionMode(true);
}
@Override
public void onSelectedContactIdsChanged() {
if (mActionBarAdapter == null) {
return;
}
if (mIsEditMode) {
mActionBarAdapter.setActionBarTitle(getString(R.string.title_edit_group));
} else {
mActionBarAdapter.setSelectionCount(getSelectedContactIds().size());
}
}
@Override
public void onStopDisplayingCheckBoxes() {
mActionBarAdapter.setSelectionMode(false);
}
};
private void logListEvent() {
Logger.logListEvent(
ListEvent.ActionType.REMOVE_LABEL,
getListType(),
getAdapter().getCount(),
/* clickedIndex */ -1,
getAdapter().getSelectedContactIdsArray().length);
}
private void deleteGroup() {
if (getMemberCount() == 0) {
final Intent intent = ContactSaveService.createGroupDeletionIntent(
getContext(), mGroupMetaData.groupId);
getContext().startService(intent);
mActivity.switchToAllContacts();
} else {
GroupDeletionDialogFragment.show(getFragmentManager(), mGroupMetaData.groupId,
mGroupMetaData.groupName);
}
}
@Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
mActivity = (PeopleActivity) getActivity();
mActionBarAdapter = new ActionBarAdapter(mActivity, mActionBarListener,
mActivity.getSupportActionBar(), mActivity.getToolbar(),
R.string.enter_contact_name);
mActionBarAdapter.setShowHomeIcon(true);
final ContactsRequest contactsRequest = new ContactsRequest();
contactsRequest.setActionCode(ContactsRequest.ACTION_GROUP);
mActionBarAdapter.initialize(savedInstanceState, contactsRequest);
if (mGroupMetaData != null) {
mActivity.setTitle(mGroupMetaData.groupName);
if (mGroupMetaData.editable) {
setCheckBoxListListener(mCheckBoxListener);
}
}
}
@Override
public ActionBarAdapter getActionBarAdapter() {
return mActionBarAdapter;
}
public void displayDeleteButtons(boolean displayDeleteButtons) {
getAdapter().setDisplayDeleteButtons(displayDeleteButtons);
}
public ArrayList<String> getMemberContactIds() {
return new ArrayList<>(mGroupMemberContactIds);
}
public int getMemberCount() {
return mGroupMemberContactIds.size();
}
public boolean isEditMode() {
return mIsEditMode;
}
@Override
public void onCreate(Bundle savedState) {
super.onCreate(savedState);
if (savedState == null) {
mGroupUri = getArguments().getParcelable(ARG_GROUP_URI);
} else {
mIsEditMode = savedState.getBoolean(KEY_IS_EDIT_MODE);
mGroupUri = savedState.getParcelable(KEY_GROUP_URI);
mGroupMetaData = savedState.getParcelable(KEY_GROUP_METADATA);
}
maybeAttachCheckBoxListener();
}
@Override
public void onResume() {
super.onResume();
// Re-register the listener, which may have been cleared when onSaveInstanceState was
// called. See also: onSaveInstanceState
mActionBarAdapter.setListener(mActionBarListener);
}
@Override
protected void startLoading() {
if (mGroupMetaData == null || !mGroupMetaData.isValid()) {
getLoaderManager().restartLoader(LOADER_GROUP_METADATA, null, mGroupMetaDataCallbacks);
} else {
onGroupMetadataLoaded();
}
}
@Override
public void onLoadFinished(Loader<Cursor> loader, Cursor data) {
if (data != null) {
// Wait until contacts are loaded before showing the scrollbar
setVisibleScrollbarEnabled(true);
final FilterCursorWrapper cursorWrapper = new FilterCursorWrapper(data);
bindMembersCount(cursorWrapper.getCount());
super.onLoadFinished(loader, cursorWrapper);
// Update state of menu items (e.g. "Remove contacts") based on number of group members.
mActivity.invalidateOptionsMenu();
mActionBarAdapter.updateOverflowButtonColor();
}
}
private void bindMembersCount(int memberCount) {
final View accountFilterContainer = getView().findViewById(
R.id.account_filter_header_container);
final View emptyGroupView = getView().findViewById(R.id.empty_group);
if (memberCount > 0) {
final AccountWithDataSet accountWithDataSet = new AccountWithDataSet(
mGroupMetaData.accountName, mGroupMetaData.accountType, mGroupMetaData.dataSet);
bindListHeader(getContext(), getListView(), accountFilterContainer,
accountWithDataSet, memberCount);
emptyGroupView.setVisibility(View.GONE);
} else {
hideHeaderAndAddPadding(getContext(), getListView(), accountFilterContainer);
emptyGroupView.setVisibility(View.VISIBLE);
}
}
@Override
public void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
if (mActionBarAdapter != null) {
mActionBarAdapter.setListener(null);
mActionBarAdapter.onSaveInstanceState(outState);
}
outState.putBoolean(KEY_IS_EDIT_MODE, mIsEditMode);
outState.putParcelable(KEY_GROUP_URI, mGroupUri);
outState.putParcelable(KEY_GROUP_METADATA, mGroupMetaData);
}
private void onGroupMetadataLoaded() {
if (Log.isLoggable(TAG, Log.VERBOSE)) Log.v(TAG, "Loaded " + mGroupMetaData);
maybeAttachCheckBoxListener();
mActivity.setTitle(mGroupMetaData.groupName);
mActivity.invalidateOptionsMenu();
mActivity.updateDrawerGroupMenu(mGroupMetaData.groupId);
// Start loading the group members
super.startLoading();
}
private void maybeAttachCheckBoxListener() {
// Don't attach the multi select check box listener if we can't edit the group
if (mGroupMetaData != null && mGroupMetaData.editable) {
setCheckBoxListListener(mCheckBoxListener);
}
}
@Override
protected GroupMembersAdapter createListAdapter() {
final GroupMembersAdapter adapter = new GroupMembersAdapter(getContext());
adapter.setSectionHeaderDisplayEnabled(true);
adapter.setDisplayPhotos(true);
adapter.setDeleteContactListener(new DeletionListener());
return adapter;
}
@Override
protected void configureAdapter() {
super.configureAdapter();
if (mGroupMetaData != null) {
getAdapter().setGroupId(mGroupMetaData.groupId);
}
}
@Override
protected View inflateView(LayoutInflater inflater, ViewGroup container) {
final View view = inflater.inflate(R.layout.contact_list_content, /* root */ null);
final View emptyGroupView = inflater.inflate(R.layout.empty_group_view, null);
final ImageView image = (ImageView) emptyGroupView.findViewById(R.id.empty_group_image);
final LinearLayout.LayoutParams params =
(LinearLayout.LayoutParams) image.getLayoutParams();
final int screenHeight = getResources().getDisplayMetrics().heightPixels;
params.setMargins(0, screenHeight /
getResources().getInteger(R.integer.empty_group_view_image_margin_divisor), 0, 0);
params.gravity = Gravity.CENTER_HORIZONTAL;
image.setLayoutParams(params);
final FrameLayout contactListLayout = (FrameLayout) view.findViewById(R.id.contact_list);
contactListLayout.addView(emptyGroupView);
final Button addContactsButton =
(Button) emptyGroupView.findViewById(R.id.add_member_button);
addContactsButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
startActivityForResult(GroupUtil.createPickMemberIntent(getContext(),
mGroupMetaData, getMemberContactIds()), RESULT_GROUP_ADD_MEMBER);
}
});
return view;
}
@Override
protected void onItemClick(int position, long id) {
final Uri uri = getAdapter().getContactUri(position);
if (uri == null) {
return;
}
if (getAdapter().isDisplayingCheckBoxes()) {
super.onItemClick(position, id);
return;
}
final int count = getAdapter().getCount();
Logger.logListEvent(ListEvent.ActionType.CLICK, ListEvent.ListType.GROUP, count,
/* clickedIndex */ position, /* numSelected */ 0);
ImplicitIntentsUtil.startQuickContact(
getActivity(), uri, ScreenEvent.ScreenType.LIST_GROUP);
}
@Override
protected boolean onItemLongClick(int position, long id) {
if (mActivity != null && mIsEditMode) {
return true;
}
return super.onItemLongClick(position, id);
}
private final class DeletionListener implements DeleteContactListener {
@Override
public void onContactDeleteClicked(int position) {
final long contactId = getAdapter().getContactId(position);
final long[] contactIds = new long[1];
contactIds[0] = contactId;
new UpdateGroupMembersAsyncTask(UpdateGroupMembersAsyncTask.TYPE_REMOVE,
getContext(), contactIds, mGroupMetaData.groupId, mGroupMetaData.accountName,
mGroupMetaData.accountType, mGroupMetaData.dataSet).execute();
}
}
public GroupMetaData getGroupMetaData() {
return mGroupMetaData;
}
public boolean isCurrentGroup(long groupId) {
return mGroupMetaData != null && mGroupMetaData.groupId == groupId;
}
/**
* Return true if the fragment is not yet added, being removed, or detached.
*/
public boolean isInactive() {
return !isAdded() || isRemoving() || isDetached();
}
@Override
public void onDestroy() {
if (mActionBarAdapter != null) {
mActionBarAdapter.setListener(null);
}
super.onDestroy();
}
public void updateExistingGroupFragment(Uri newGroupUri, String action) {
toastForSaveAction(action);
if (isEditMode() && getGroupCount() == 1) {
// If we're deleting the last group member, exit edit mode
exitEditMode();
} else if (!GroupUtil.ACTION_REMOVE_FROM_GROUP.equals(action)) {
mGroupUri = newGroupUri;
mGroupMetaData = null; // Clear mGroupMetaData to trigger a new load.
reloadData();
mActivity.invalidateOptionsMenu();
}
}
public void toastForSaveAction(String action) {
int id = -1;
switch(action) {
case GroupUtil.ACTION_UPDATE_GROUP:
id = R.string.groupUpdatedToast;
break;
case GroupUtil.ACTION_REMOVE_FROM_GROUP:
id = R.string.groupMembersRemovedToast;
break;
case GroupUtil.ACTION_CREATE_GROUP:
id = R.string.groupCreatedToast;
break;
case GroupUtil.ACTION_ADD_TO_GROUP:
id = R.string.groupMembersAddedToast;
break;
case GroupUtil.ACTION_SWITCH_GROUP:
// No toast associated with this action.
break;
default:
FeedbackHelper.sendFeedback(getContext(), TAG,
"toastForSaveAction passed unknown action: " + action,
new IllegalArgumentException("Unhandled contact save action " + action));
}
toast(id);
}
private void toast(int resId) {
if (resId >= 0) {
Toast.makeText(getContext(), resId, Toast.LENGTH_SHORT).show();
}
}
private int getGroupCount() {
return getAdapter() != null ? getAdapter().getCount() : -1;
}
public void exitEditMode() {
mIsEditMode = false;
mActionBarAdapter.setSelectionMode(false);
displayDeleteButtons(false);
}
}