Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 41893b26 authored by Wenyi Wang's avatar Wenyi Wang Committed by Android (Google) Code Review
Browse files

Merge "Let GroupMembersFragment control actionbar, menu and more."

parents c8110267 6927bf35
Loading
Loading
Loading
Loading
+6 −1
Original line number Diff line number Diff line
@@ -232,6 +232,10 @@ public abstract class ContactsDrawerActivity extends AppCompatContactsActivity i
        }
    }

    public Toolbar getToolbar() {
        return mToolbar;
    }

    private void maybeUpdateScrollPosition(int position) {
        if (mDrawer.isDrawerOpen(GravityCompat.START)) {
            if (Log.isLoggable(TAG, Log.VERBOSE)) Log.v(TAG, "Don't scroll menu when drawer open");
@@ -413,7 +417,8 @@ public abstract class ContactsDrawerActivity extends AppCompatContactsActivity i
        }
    }

    protected void updateGroupMenu(GroupMetadata groupMetadata) {
    // TODO(wenyiw) the method is public for now; we should remove it after b/30944495 is fixed.
    public void updateGroupMenu(GroupMetadata groupMetadata) {
        clearCheckedMenus();
        if (groupMetadata != null && mGroupMenuMap != null
                && mGroupMenuMap.get(groupMetadata.groupId) != null) {
+22 −427
Original line number Diff line number Diff line
@@ -17,163 +17,33 @@ package com.android.contacts.activities;

import android.app.FragmentManager;
import android.app.FragmentTransaction;
import android.content.Context;
import android.content.Intent;
import android.database.Cursor;
import android.net.Uri;
import android.os.AsyncTask;
import android.os.Bundle;
import android.provider.ContactsContract.RawContacts;
import android.support.v4.view.GravityCompat;
import android.util.Log;
import android.view.Menu;
import android.view.MenuItem;
import android.widget.Toast;

import com.android.contacts.ContactSaveService;
import com.android.contacts.ContactsDrawerActivity;
import com.android.contacts.R;
import com.android.contacts.common.GroupMetaData;
import com.android.contacts.common.logging.ListEvent;
import com.android.contacts.common.logging.Logger;
import com.android.contacts.common.logging.ScreenEvent.ScreenType;
import com.android.contacts.common.model.account.AccountWithDataSet;
import com.android.contacts.common.util.ImplicitIntentsUtil;
import com.android.contacts.group.GroupMembersFragment;
import com.android.contacts.group.GroupMetadata;
import com.android.contacts.group.GroupNameEditDialogFragment;
import com.android.contacts.group.GroupUtil;
import com.android.contacts.interactions.GroupDeletionDialogFragment;
import com.android.contacts.list.ContactsRequest;
import com.android.contacts.list.MultiSelectContactsListFragment;
import com.android.contacts.list.UiIntentActions;
import com.android.contacts.quickcontact.QuickContactActivity;

/**
 * Displays the members of a group and allows the user to edit it.
 */
public class GroupMembersActivity extends ContactsDrawerActivity implements
        ActionBarAdapter.Listener,
        MultiSelectContactsListFragment.OnCheckBoxListActionListener,
        GroupMembersFragment.GroupMembersListener {
public class GroupMembersActivity extends ContactsDrawerActivity {

    private static final String TAG = "GroupMembers";

    private static final String KEY_GROUP_URI = "groupUri";
    private static final String KEY_GROUP_METADATA = "groupMetadata";
    private static final String KEY_IS_EDIT_MODE = "editMode";

    private static final String TAG_GROUP_MEMBERS = "groupMembers";
    private static final String TAG_GROUP_NAME_EDIT_DIALOG = "groupNameEditDialog";

    private static final String ACTION_DELETE_GROUP = "deleteGroup";
    private static final String ACTION_UPDATE_GROUP = "updateGroup";
    private static final String ACTION_ADD_TO_GROUP = "addToGroup";
    private static final String ACTION_REMOVE_FROM_GROUP = "removeFromGroup";

    private static final int RESULT_GROUP_ADD_MEMBER = 100;

    /**
     * Starts an Intent to add/remove the raw contacts for the given contact IDs to/from a group.
     * Only the raw contacts that belong to the specified account are added or removed.
     */
    private static class UpdateGroupMembersAsyncTask extends AsyncTask<Void, Void, Intent> {

        static final int TYPE_ADD = 0;
        static final int TYPE_REMOVE = 1;

        private final Context mContext;
        private final int mType;
        private final long[] mContactIds;
        private final long mGroupId;
        private final String mAccountName;
        private final String mAccountType;

        private UpdateGroupMembersAsyncTask(int type, Context context, long[] contactIds,
                long groupId, String accountName, String accountType) {
            mContext = context;
            mType = type;
            mContactIds = contactIds;
            mGroupId = groupId;
            mAccountName = accountName;
            mAccountType = accountType;
        }

        @Override
        protected Intent doInBackground(Void... params) {
            final long[] rawContactIds = getRawContactIds();
            if (rawContactIds.length == 0) {
                return null;
            }
            final long[] rawContactIdsToAdd;
            final long[] rawContactIdsToRemove;
            final String action;
            if (mType == TYPE_ADD) {
                rawContactIdsToAdd = rawContactIds;
                rawContactIdsToRemove = null;
                action = GroupMembersActivity.ACTION_ADD_TO_GROUP;
            } else if (mType == TYPE_REMOVE) {
                rawContactIdsToAdd = null;
                rawContactIdsToRemove = rawContactIds;
                action = GroupMembersActivity.ACTION_REMOVE_FROM_GROUP;
            } else {
                throw new IllegalStateException("Unrecognized type " + mType);
            }
            return ContactSaveService.createGroupUpdateIntent(
                    mContext, mGroupId, /* newLabel */ null, rawContactIdsToAdd,
                    rawContactIdsToRemove, GroupMembersActivity.class, action);
        }

        // TODO(wjang): prune raw contacts that are already in the group; ContactSaveService will
        // log a warning if the raw contact is already a member and keep going but it is not ideal.
        private long[] getRawContactIds() {
            final Uri rawContactUri = RawContacts.CONTENT_URI.buildUpon()
                    .appendQueryParameter(RawContacts.ACCOUNT_NAME, mAccountName)
                    .appendQueryParameter(RawContacts.ACCOUNT_TYPE, mAccountType)
                    .build();
            final String[] projection = new String[]{RawContacts._ID};
            final StringBuilder selection = new StringBuilder();
            final String[] selectionArgs = new String[mContactIds.length];
            for (int i = 0; i < mContactIds.length; i++) {
                if (i > 0) {
                    selection.append(" OR ");
                }
                selection.append(RawContacts.CONTACT_ID).append("=?");
                selectionArgs[i] = Long.toString(mContactIds[i]);
            }
            final Cursor cursor = mContext.getContentResolver().query(
                    rawContactUri, projection, selection.toString(), selectionArgs, null, null);
            final long[] rawContactIds = new long[cursor.getCount()];
            try {
                int i = 0;
                while (cursor.moveToNext()) {
                    rawContactIds[i] = cursor.getLong(0);
                    i++;
                }
            } finally {
                cursor.close();
            }
            return rawContactIds;
        }

        @Override
        protected void onPostExecute(Intent intent) {
            if (intent == null) {
                Toast.makeText(mContext, R.string.groupSavedErrorToast, Toast.LENGTH_SHORT).show();
            } else {
                mContext.startService(intent);
            }
        }
    }

    private ActionBarAdapter mActionBarAdapter;

    private GroupMembersFragment mMembersFragment;

    private Uri mGroupUri;
    private boolean mIsEditMode;

    private GroupMetadata mGroupMetadata;

    @Override
    public void onCreate(Bundle savedState) {
@@ -182,8 +52,6 @@ public class GroupMembersActivity extends ContactsDrawerActivity implements
        // Parse the Intent
        if (savedState != null) {
            mGroupUri = savedState.getParcelable(KEY_GROUP_URI);
            mIsEditMode = savedState.getBoolean(KEY_IS_EDIT_MODE);
            mGroupMetadata = savedState.getParcelable(KEY_GROUP_METADATA);
        } else {
            mGroupUri = getIntent().getData();
            setTitle(getIntent().getStringExtra(GroupUtil.EXTRA_GROUP_NAME));
@@ -196,12 +64,6 @@ public class GroupMembersActivity extends ContactsDrawerActivity implements
        // Set up the view
        setContentView(R.layout.group_members_activity);

        // Set up the action bar
        mActionBarAdapter = new ActionBarAdapter(this, this, getSupportActionBar(),
                /* portraitTabs */ null, /* landscapeTabs */ null, mToolbar,
                R.string.enter_contact_name);
        mActionBarAdapter.setShowHomeIcon(true);

        // Add the members list fragment
        final FragmentManager fragmentManager = getFragmentManager();
        mMembersFragment = (GroupMembersFragment)
@@ -211,26 +73,12 @@ public class GroupMembersActivity extends ContactsDrawerActivity implements
            fragmentManager.beginTransaction().replace(R.id.fragment_container_inner,
                    mMembersFragment, TAG_GROUP_MEMBERS).commitAllowingStateLoss();
        }
        mMembersFragment.setListener(this);
        if (mGroupMetadata != null && mGroupMetadata.editable) {
            mMembersFragment.setCheckBoxListListener(this);
        }

        // Delay action bar initialization until after the fragment is added
        final ContactsRequest contactsRequest = new ContactsRequest();
        contactsRequest.setActionCode(ContactsRequest.ACTION_GROUP);
        mActionBarAdapter.initialize(savedState, contactsRequest);
    }

    @Override
    public void onSaveInstanceState(Bundle outState) {
        super.onSaveInstanceState(outState);
        if (mActionBarAdapter != null) {
            mActionBarAdapter.onSaveInstanceState(outState);
        }
        outState.putParcelable(KEY_GROUP_URI, mGroupUri);
        outState.putBoolean(KEY_IS_EDIT_MODE, mIsEditMode);
        outState.putParcelable(KEY_GROUP_METADATA, mGroupMetadata);
    }

    // Invoked with results from the ContactSaveService
@@ -256,14 +104,14 @@ public class GroupMembersActivity extends ContactsDrawerActivity implements

            toast(getToastMessageForSaveAction(newIntent.getAction()));

            if (mIsEditMode) {
            if (mMembersFragment.isEditMode()) {
                // If we're removing group members one at a time, don't reload the fragment so
                // the user can continue to remove group members one by one
                if (getGroupCount() == 1) {
                    // If we're deleting the last group member, exit edit mode
                    onBackPressed();
                }
            } else if (!ACTION_REMOVE_FROM_GROUP.equals(newIntent.getAction())) {
            } else if (!GroupUtil.ACTION_REMOVE_FROM_GROUP.equals(newIntent.getAction())) {
                replaceGroupMembersFragment();
                invalidateOptionsMenu();
            }
@@ -271,19 +119,20 @@ public class GroupMembersActivity extends ContactsDrawerActivity implements
    }

    private static boolean isDeleteAction(String action) {
        return ACTION_DELETE_GROUP.equals(action);
        return GroupUtil.ACTION_DELETE_GROUP.equals(action);
    }

    private static boolean isSaveAction(String action) {
        return ACTION_UPDATE_GROUP.equals(action)
                || ACTION_ADD_TO_GROUP.equals(action)
                || ACTION_REMOVE_FROM_GROUP.equals(action);
        return GroupUtil.ACTION_UPDATE_GROUP.equals(action)
                || GroupUtil.ACTION_ADD_TO_GROUP.equals(action)
                || GroupUtil.ACTION_REMOVE_FROM_GROUP.equals(action);
    }

    private static int getToastMessageForSaveAction(String action) {
        if (ACTION_UPDATE_GROUP.equals(action)) return R.string.groupUpdatedToast;
        if (ACTION_ADD_TO_GROUP.equals(action)) return R.string.groupMembersAddedToast;
        if (ACTION_REMOVE_FROM_GROUP.equals(action)) return R.string.groupMembersRemovedToast;
        if (GroupUtil.ACTION_UPDATE_GROUP.equals(action)) return R.string.groupUpdatedToast;
        if (GroupUtil.ACTION_ADD_TO_GROUP.equals(action)) return R.string.groupMembersAddedToast;
        if (GroupUtil.ACTION_REMOVE_FROM_GROUP.equals(action))
            return R.string.groupMembersRemovedToast;
        throw new IllegalArgumentException("Unhanded contact save action " + action);
    }

@@ -294,19 +143,15 @@ public class GroupMembersActivity extends ContactsDrawerActivity implements

    private void replaceGroupMembersFragment() {
        mMembersFragment = GroupMembersFragment.newInstance(mGroupUri);
        mMembersFragment.setListener(this);
        final FragmentTransaction transaction = getFragmentManager().beginTransaction();
        addGroupsAndFiltersFragments(transaction);
        transaction.replace(R.id.fragment_container_inner, mMembersFragment, TAG_GROUP_MEMBERS)
                .commitAllowingStateLoss();
        if (mGroupMetadata != null && mGroupMetadata.editable) {
            mMembersFragment.setCheckBoxListListener(this);
        }
    }

    @Override
    protected void onGroupMenuItemClicked(long groupId, String title) {
        if (mGroupMetadata.groupId != groupId) {
        if (mMembersFragment.getGroupMetadata().groupId != groupId) {
            super.onGroupMenuItemClicked(groupId, title);
        }
    }
@@ -322,129 +167,6 @@ public class GroupMembersActivity extends ContactsDrawerActivity implements
        finish();
    }

    public boolean isEditMode() {
        return mIsEditMode;
    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        if (mGroupMetadata == null) {
            // Hide menu options until metadata is fully loaded
            return false;
        }
        super.onCreateOptionsMenu(menu);
        getMenuInflater().inflate(R.menu.view_group, menu);
        return true;
    }

    @Override
    public boolean onPrepareOptionsMenu(Menu menu) {
        final boolean isSelectionMode = mActionBarAdapter.isSelectionMode();
        final boolean isGroupEditable = mGroupMetadata != null && mGroupMetadata.editable;
        final boolean isGroupReadOnly = mGroupMetadata != null && mGroupMetadata.readOnly;

        setVisible(menu, R.id.menu_add, isGroupEditable && !isSelectionMode);
        setVisible(menu, R.id.menu_rename_group, !isGroupReadOnly && !isSelectionMode);
        setVisible(menu, R.id.menu_delete_group, !isGroupReadOnly && !isSelectionMode);
        setVisible(menu, R.id.menu_edit_group, isGroupEditable && !mIsEditMode && !isSelectionMode
                && !isGroupEmpty());
        setVisible(menu, R.id.menu_remove_from_group, isGroupEditable && isSelectionMode &&
                !mIsEditMode);

        return true;
    }

    private boolean isGroupEmpty() {
        return mMembersFragment != null && mMembersFragment.getAdapter() != null &&
                mMembersFragment.getAdapter().isEmpty();
    }

    private static void setVisible(Menu menu, int id, boolean visible) {
        final MenuItem menuItem = menu.findItem(id);
        if (menuItem != null) {
            menuItem.setVisible(visible);
        }
    }

    public void startGroupAddMemberActivity() {
        startActivityForResult(GroupUtil.createPickMemberIntent(this, mGroupMetadata,
                mMembersFragment.getMemberContactIds()), RESULT_GROUP_ADD_MEMBER);
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        switch (item.getItemId()) {
            case android.R.id.home: {
                onBackPressed();
                return true;
            }
            case R.id.menu_add: {
                startGroupAddMemberActivity();
                return true;
            }
            case R.id.menu_rename_group: {
                GroupNameEditDialogFragment.newInstanceForUpdate(
                        new AccountWithDataSet(mGroupMetadata.accountName,
                                mGroupMetadata.accountType, mGroupMetadata.dataSet),
                        ACTION_UPDATE_GROUP, mGroupMetadata.groupId, mGroupMetadata.groupName)
                        .show(getFragmentManager(), TAG_GROUP_NAME_EDIT_DIALOG);
                return true;
            }
            case R.id.menu_delete_group: {
                deleteGroup();
                return true;
            }
            case R.id.menu_edit_group: {
                if (mMembersFragment == null) {
                    return false;
                }
                mIsEditMode = true;
                mActionBarAdapter.setSelectionMode(true);
                mMembersFragment.displayDeleteButtons(true);
                return true;
            }
            case R.id.menu_remove_from_group: {
                if (mMembersFragment == null) {
                    return false;
                }
                logListEvent();
                removeSelectedContacts();
                return true;
            }
        }
        return super.onOptionsItemSelected(item);
    }

    private void deleteGroup() {
        if (mMembersFragment.getMemberCount() == 0) {
            final Intent intent = ContactSaveService.createGroupDeletionIntent(this,
                    mGroupMetadata.groupId);
            startService(intent);
            finish();
        } else {
            GroupDeletionDialogFragment.show(getFragmentManager(), mGroupMetadata.groupId,
                    mGroupMetadata.groupName);
        }
    }

    private void logListEvent() {
        Logger.logListEvent(
                ListEvent.ActionType.REMOVE_LABEL,
                mMembersFragment.getListType(),
                mMembersFragment.getAdapter().getCount(),
                /* clickedIndex */ -1,
                mMembersFragment.getAdapter().getSelectedContactIdsArray().length);
    }

    private void removeSelectedContacts() {
        final long[] contactIds = mMembersFragment.getAdapter().getSelectedContactIdsArray();
        new UpdateGroupMembersAsyncTask(UpdateGroupMembersAsyncTask.TYPE_REMOVE,
                this, contactIds, mGroupMetadata.groupId, mGroupMetadata.accountName,
                mGroupMetadata.accountType).execute();

        mActionBarAdapter.setSelectionMode(false);
    }

    @Override
    public void onBackPressed() {
        if (!isSafeToCommitTransactions()) {
@@ -452,44 +174,21 @@ public class GroupMembersActivity extends ContactsDrawerActivity implements
        }
        if (mDrawer.isDrawerOpen(GravityCompat.START)) {
            mDrawer.closeDrawer(GravityCompat.START);
        } else if (mIsEditMode) {
            mIsEditMode = false;
            mActionBarAdapter.setSelectionMode(false);
            if (mMembersFragment != null) {
        } else if (mMembersFragment.isEditMode()) {
            mMembersFragment.setEditMode(false);
            mMembersFragment.getActionBarAdapter().setSelectionMode(false);
            mMembersFragment.displayDeleteButtons(false);
            }
        } else if (mActionBarAdapter.isSelectionMode()) {
            mActionBarAdapter.setSelectionMode(false);
            if (mMembersFragment != null) {
        } else if (mMembersFragment.getActionBarAdapter().isSelectionMode()) {
            mMembersFragment.getActionBarAdapter().setSelectionMode(false);
            mMembersFragment.displayCheckBoxes(false);
            }
        } else if (mActionBarAdapter.isSearchMode()) {
            mActionBarAdapter.setSearchMode(false);
        } else if (mMembersFragment.getActionBarAdapter().isSearchMode()) {
            mMembersFragment.getActionBarAdapter().setSearchMode(false);
        } else {
            switchToAllContacts();
            super.onBackPressed();
        }
    }

    @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
        if (requestCode == RESULT_GROUP_ADD_MEMBER && resultCode == RESULT_OK && data != null) {
            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,
                    this, contactIds, mGroupMetadata.groupId, mGroupMetadata.accountName,
                    mGroupMetadata.accountType).execute();
        }
    }

    private void setResultCanceledAndFinish(int resId) {
        toast(resId);
        setResult(RESULT_CANCELED);
@@ -502,112 +201,8 @@ public class GroupMembersActivity extends ContactsDrawerActivity implements
        }
    }

    // ActionBarAdapter callbacks

    @Override
    public void onAction(int action) {
        switch (action) {
            case ActionBarAdapter.Listener.Action.START_SELECTION_MODE:
                if (mMembersFragment != null) {
                    if (mIsEditMode) {
                        mMembersFragment.displayDeleteButtons(true);
                        mActionBarAdapter.setActionBarTitle(getString(R.string.title_edit_group));
                    } else {
                        mMembersFragment.displayCheckBoxes(true);
                    }
                }
                invalidateOptionsMenu();
                showFabWithAnimation(/* showFabWithAnimation = */ false);
                break;
            case ActionBarAdapter.Listener.Action.STOP_SEARCH_AND_SELECTION_MODE:
                mActionBarAdapter.setSearchMode(false);
                if (mMembersFragment != null) {
                    if (mIsEditMode) {
                        mMembersFragment.displayDeleteButtons(false);
                    } else {
                        mMembersFragment.displayCheckBoxes(false);
                    }
                }
                invalidateOptionsMenu();
                showFabWithAnimation(/* showFabWithAnimation */ true);
                break;
            case ActionBarAdapter.Listener.Action.BEGIN_STOPPING_SEARCH_AND_SELECTION_MODE:
                showFabWithAnimation(/* showFabWithAnimation */ true);
                break;
        }
    }

    private void showFabWithAnimation(boolean showFab) {
        // TODO: b/28497108
    }

    @Override
    public void onSelectedTabChanged() {
    }

    @Override
    public void onUpButtonPressed() {
        onBackPressed();
    }

    // MultiSelect checkbox callbacks

    @Override
    public void onStartDisplayingCheckBoxes() {
        mActionBarAdapter.setSelectionMode(true);
    }

    @Override
    public void onSelectedContactIdsChanged() {
        if (mIsEditMode) {
            mActionBarAdapter.setActionBarTitle(getString(R.string.title_edit_group));
        } else {
            mActionBarAdapter.setSelectionCount(mMembersFragment.getSelectedContactIds().size());
        }
    }

    @Override
    public void onStopDisplayingCheckBoxes() {
        mActionBarAdapter.setSelectionMode(false);
    }

    // GroupMembersFragment callbacks

    @Override
    public void onGroupMetadataLoaded(GroupMetadata groupMetadata) {
        mGroupMetadata = groupMetadata;
        updateGroupMenu(mGroupMetadata);
        setTitle(mGroupMetadata.groupName);
        invalidateOptionsMenu();
    }

    @Override
    public void onGroupMetadataLoadFailed() {
        setResultCanceledAndFinish(R.string.groupLoadErrorToast);
    }

    @Override
    protected GroupMetadata getGroupMetadata() {
        return mGroupMetadata;
    }

    @Override
    public void onGroupMemberListItemClicked(int position, Uri contactLookupUri) {
        final int count = mMembersFragment.getAdapter().getCount();
        Logger.logListEvent(ListEvent.ActionType.CLICK, ListEvent.ListType.GROUP, count,
                /* clickedIndex */ position, /* numSelected */ 0);
        final Intent intent = ImplicitIntentsUtil.composeQuickContactIntent(this,
                contactLookupUri, QuickContactActivity.MODE_FULLY_EXPANDED);
        intent.putExtra(QuickContactActivity.EXTRA_PREVIOUS_SCREEN_TYPE, ScreenType.LIST_GROUP);
        startActivity(intent);
    }

    @Override
    public void onGroupMemberListItemDeleted(int position, long contactId) {
        final long[] contactIds = new long[1];
        contactIds[0] = contactId;
        new UpdateGroupMembersAsyncTask(UpdateGroupMembersAsyncTask.TYPE_REMOVE,
                this, contactIds, mGroupMetadata.groupId, mGroupMetadata.accountName,
                mGroupMetadata.accountType).execute();
        return mMembersFragment.getGroupMetadata();
    }
}
+0 −3
Original line number Diff line number Diff line
@@ -113,9 +113,6 @@ public abstract class MultiSelectEntryContactListAdapter extends ContactEntryLis
     * Not guaranteed to work with all configurations of this adapter.
     */
    public void setDisplayCheckBoxes(boolean showCheckBoxes) {
        if (!mDisplayCheckBoxes && showCheckBoxes) {
            setSelectedContactIds(new TreeSet<Long>());
        }
        mDisplayCheckBoxes = showCheckBoxes;
        notifyDataSetChanged();
        if (mSelectedContactsListener != null) {
Loading