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

Commit f7b513fe authored by Walter Jang's avatar Walter Jang Committed by Android (Google) Code Review
Browse files

Merge "Show distinct group member aggregate contacts"

parents 4a526b29 2552c11d
Loading
Loading
Loading
Loading
+4 −22
Original line number Diff line number Diff line
@@ -17,10 +17,8 @@ package com.android.contacts.activities;

import android.accounts.Account;
import android.app.FragmentManager;
import android.content.Context;
import android.app.FragmentTransaction;
import android.app.LoaderManager.LoaderCallbacks;
import android.content.CursorLoader;
import android.content.Context;
import android.content.Intent;
import android.database.Cursor;
import android.net.Uri;
@@ -30,7 +28,6 @@ import android.provider.ContactsContract;
import android.provider.ContactsContract.Intents;
import android.provider.ContactsContract.RawContacts;
import android.support.v4.view.GravityCompat;
import android.support.v7.widget.Toolbar;
import android.util.Log;
import android.view.Menu;
import android.view.MenuItem;
@@ -38,8 +35,6 @@ import android.widget.Toast;

import com.android.contacts.ContactSaveService;
import com.android.contacts.ContactsDrawerActivity;
import com.android.contacts.GroupMemberLoader;
import com.android.contacts.GroupMemberLoader.GroupEditorQuery;
import com.android.contacts.R;
import com.android.contacts.common.editor.SelectAccountDialogFragment;
import com.android.contacts.common.logging.ListEvent;
@@ -49,7 +44,6 @@ import com.android.contacts.common.model.AccountTypeManager;
import com.android.contacts.common.model.account.AccountWithDataSet;
import com.android.contacts.common.util.AccountsListAdapter.AccountListFilter;
import com.android.contacts.common.util.ImplicitIntentsUtil;
import com.android.contacts.group.GroupMembersListAdapter.GroupMembersQuery;
import com.android.contacts.group.GroupMembersListFragment;
import com.android.contacts.group.GroupMetadata;
import com.android.contacts.group.GroupNameEditDialogFragment;
@@ -59,7 +53,6 @@ import com.android.contacts.list.MultiSelectContactsListFragment;
import com.android.contacts.list.UiIntentActions;
import com.android.contacts.quickcontact.QuickContactActivity;

import java.util.ArrayList;
import java.util.List;

/**
@@ -355,7 +348,7 @@ public class GroupMembersActivity extends ContactsDrawerActivity implements

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        if (mGroupMetadata == null || mGroupMetadata.memberCount < 0) {
        if (mGroupMetadata == null) {
            // Hide menu options until metadata is fully loaded
            return false;
        }
@@ -399,7 +392,7 @@ public class GroupMembersActivity extends ContactsDrawerActivity implements
                intent.putExtra(UiIntentActions.GROUP_ACCOUNT_TYPE, mGroupMetadata.accountType);
                intent.putExtra(UiIntentActions.GROUP_ACCOUNT_DATA_SET, mGroupMetadata.dataSet);
                intent.putExtra(UiIntentActions.GROUP_CONTACT_IDS,
                        getExistingGroupMemberContactIds());
                        mMembersListFragment.getMemberContactIds());
                startActivityForResult(intent, RESULT_GROUP_ADD_MEMBER);
                return true;
            }
@@ -424,19 +417,8 @@ public class GroupMembersActivity extends ContactsDrawerActivity implements
        return super.onOptionsItemSelected(item);
    }

    private ArrayList<String> getExistingGroupMemberContactIds() {
        final ArrayList<String> contactIds = new ArrayList<>();
        final Cursor cursor = mMembersListFragment.getAdapter().getCursor(/* partition */ 0);
        if (cursor != null && cursor.moveToFirst()) {
            do {
                contactIds.add(cursor.getString(GroupMembersQuery.CONTACT_ID));
            } while (cursor.moveToNext());
        }
        return contactIds;
    }

    private void deleteGroup() {
        if (mGroupMetadata.memberCount == 0) {
        if (mMembersListFragment.getMemberCount() == 0) {
            final Intent intent = ContactSaveService.createGroupDeletionIntent(
                    this, mGroupMetadata.groupId,
                    GroupMembersActivity.class, ACTION_DELETE_GROUP);
+117 −56
Original line number Diff line number Diff line
@@ -19,25 +19,30 @@ import android.app.LoaderManager.LoaderCallbacks;
import android.content.CursorLoader;
import android.content.Loader;
import android.database.Cursor;
import android.database.CursorWrapper;
import android.net.Uri;
import android.os.Bundle;
import android.provider.ContactsContract;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;

import com.android.contacts.GroupListLoader;
import com.android.contacts.GroupMetaDataLoader;
import com.android.contacts.R;
import com.android.contacts.common.logging.ListEvent.ListType;
import com.android.contacts.common.model.AccountTypeManager;
import com.android.contacts.common.model.account.AccountType;
import com.android.contacts.group.GroupMembersListAdapter.GroupMembersQuery;
import com.android.contacts.list.MultiSelectContactsListFragment;

import java.util.ArrayList;
import java.util.HashSet;
import java.util.Set;

/** Displays the members of a group. */
public class GroupMembersListFragment extends MultiSelectContactsListFragment {
public class GroupMembersListFragment extends
        MultiSelectContactsListFragment<GroupMembersListAdapter> {

    private static final String TAG = "GroupMembers";

@@ -47,7 +52,6 @@ public class GroupMembersListFragment extends MultiSelectContactsListFragment {
    private static final String ARG_GROUP_URI = "groupUri";

    private static final int LOADER_GROUP_METADATA = 0;
    private static final int LOADER_GROUP_LIST_DETAILS = 1;

    /** Callbacks for hosts of {@link GroupMembersListFragment}. */
    public interface GroupMembersListListener {
@@ -62,7 +66,83 @@ public class GroupMembersListFragment extends MultiSelectContactsListFragment {
        void onGroupMemberListItemClicked(int position, Uri contactLookupUri);
    }

    /** Step 1 of loading group metadata. */
    /** 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];

            if (Log.isLoggable(TAG, Log.VERBOSE)) {
                Log.v(TAG, "Group members CursorWrapper start: " + mCount);
            }

            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);
                }
            }
            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 || position < 0) return false;
            return super.moveToPosition(mIndex[position]);
        }

        @Override
        public int getCount() {
            return mCount;
        }

        @Override
        public int getPosition() {
            return mPos;
        }
    }

    private final LoaderCallbacks<Cursor> mGroupMetadataCallbacks = new LoaderCallbacks<Cursor>() {

        @Override
@@ -94,39 +174,6 @@ public class GroupMembersListFragment extends MultiSelectContactsListFragment {
                    mGroupMetadata.accountType, mGroupMetadata.dataSet);
            mGroupMetadata.editable = accountType.isGroupMembershipEditable();

            getLoaderManager().restartLoader(LOADER_GROUP_LIST_DETAILS, null, mGroupListCallbacks);
        }

        @Override
        public void onLoaderReset(Loader<Cursor> loader) {}
    };

    /** Step 2 of loading group metadata. */
    private final LoaderCallbacks<Cursor> mGroupListCallbacks = new LoaderCallbacks<Cursor>() {

        @Override
        public CursorLoader onCreateLoader(int id, Bundle args) {
            final GroupListLoader groupListLoader = new GroupListLoader(getActivity());

            groupListLoader.setSelection(GroupListLoader.DEFAULT_SELECTION
                    + " AND " + ContactsContract.Groups._ID + "=?");

            final String[] selectionArgs = new String[1];
            selectionArgs[0] = Long.toString(mGroupMetadata.groupId);
            groupListLoader.setSelectionArgs(selectionArgs);

            return groupListLoader;
        }

        @Override
        public void onLoadFinished(Loader<Cursor> loader, Cursor cursor) {
            if (cursor == null || cursor.isClosed()) {
                Log.e(TAG, "Failed to load group list details");
                return;
            }
            if (cursor.moveToNext()) {
                mGroupMetadata.memberCount = cursor.getInt(GroupListLoader.MEMBER_COUNT);
            }
            onGroupMetadataLoaded();
        }

@@ -140,6 +187,8 @@ public class GroupMembersListFragment extends MultiSelectContactsListFragment {

    private GroupMetadata mGroupMetadata;

    private Set<String> mGroupMemberContactIds = new HashSet();

    public static GroupMembersListFragment newInstance(Uri groupUri) {
        final Bundle args = new Bundle();
        args.putParcelable(ARG_GROUP_URI, groupUri);
@@ -164,6 +213,14 @@ public class GroupMembersListFragment extends MultiSelectContactsListFragment {
        mListener = listener;
    }

    public ArrayList<String> getMemberContactIds() {
        return  new ArrayList<>(mGroupMemberContactIds);
    }

    public int getMemberCount() {
        return mGroupMemberContactIds.size();
    }

    @Override
    public void onCreate(Bundle savedState) {
        super.onCreate(savedState);
@@ -185,31 +242,40 @@ public class GroupMembersListFragment extends MultiSelectContactsListFragment {
    }

    @Override
    public void onSaveInstanceState(Bundle outState) {
        super.onSaveInstanceState(outState);
        outState.putParcelable(KEY_GROUP_URI, mGroupUri);
        outState.putParcelable(KEY_GROUP_METADATA, mGroupMetadata);
    public void onLoadFinished(Loader<Cursor> loader, Cursor data) {
        if (data != null) {
            final FilterCursorWrapper cursorWrapper = new FilterCursorWrapper(data);
            bindMembersCount(cursorWrapper.getCount());
            super.onLoadFinished(loader, cursorWrapper);
        }
    }

    private void onGroupMetadataLoaded() {
        if (Log.isLoggable(TAG, Log.VERBOSE)) Log.v(TAG, "Loaded " + mGroupMetadata);

        maybeAttachCheckBoxListener();

        // Bind the members count
    private void bindMembersCount(int memberCount) {
        final View accountFilterContainer = getView().findViewById(
                R.id.account_filter_header_container);
        if (mGroupMetadata.memberCount >= 0) {
        if (memberCount >= 0) {
            accountFilterContainer.setVisibility(View.VISIBLE);

            final TextView accountFilterHeader = (TextView) accountFilterContainer.findViewById(
                    R.id.account_filter_header);
            accountFilterHeader.setText(getResources().getQuantityString(
                    R.plurals.group_members_count, mGroupMetadata.memberCount,
                    mGroupMetadata.memberCount));
                    R.plurals.group_members_count, memberCount, memberCount));
        } else {
            accountFilterContainer.setVisibility(View.GONE);
        }
    }

    @Override
    public void onSaveInstanceState(Bundle outState) {
        super.onSaveInstanceState(outState);
        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();

        if (mListener != null) {
            mListener.onGroupMetadataLoaded(mGroupMetadata);
@@ -238,11 +304,6 @@ public class GroupMembersListFragment extends MultiSelectContactsListFragment {
        return adapter;
    }

    @Override
    public GroupMembersListAdapter getAdapter() {
        return (GroupMembersListAdapter) super.getAdapter();
    }

    @Override
    protected void configureAdapter() {
        super.configureAdapter();
+1 −6
Original line number Diff line number Diff line
@@ -46,7 +46,6 @@ public final class GroupMetadata implements Parcelable {
    public String groupName;
    public boolean readOnly;
    public boolean editable;
    public int memberCount = -1;

    public GroupMetadata() {
    }
@@ -64,7 +63,6 @@ public final class GroupMetadata implements Parcelable {
        groupName = source.readString();
        readOnly = source.readInt() == 1;
        editable = source.readInt() == 1;
        memberCount = source.readInt();
    }

    @Override
@@ -77,7 +75,6 @@ public final class GroupMetadata implements Parcelable {
        dest.writeString(groupName);
        dest.writeInt(readOnly ? 1 : 0);
        dest.writeInt(editable ? 1 : 0);
        dest.writeInt(memberCount);
    }

    /** Whether all metadata fields are set. */
@@ -85,8 +82,7 @@ public final class GroupMetadata implements Parcelable {
        return uri != null
                && !TextUtils.isEmpty(accountName)
                && !TextUtils.isEmpty(groupName)
                && groupId > 0
                && memberCount >= 0;
                && groupId > 0;
    }

    public AccountWithDataSet createAccountWithDataSet() {
@@ -114,7 +110,6 @@ public final class GroupMetadata implements Parcelable {
                " groupName=" + groupName +
                " readOnly=" + readOnly +
                " editable=" + editable +
                " memberCount=" + memberCount +
                " isValid=" + isValid() +
                "]";
    }
+3 −6
Original line number Diff line number Diff line
@@ -57,10 +57,7 @@ public class GroupMemberPickerFragment extends
        void onGroupMemberClicked(long contactId);
    }

    /**
     * Filters out raw contacts that are already in the group and also handles queries for contact
     * photo IDs and lookup keys which cannot be retrieved from the raw contact table directly.
     */
    /** Filters out raw contacts that are already in the group. */
    private class FilterCursorWrapper extends CursorWrapper {

        private int[] mIndex;
@@ -74,7 +71,7 @@ public class GroupMemberPickerFragment extends
            mIndex = new int[mCount];

            if (Log.isLoggable(TAG, Log.VERBOSE)) {
                Log.v(TAG, "FilterCursorWrapper starting cursor size is " + mCount);
                Log.v(TAG, "RawContacts CursorWrapper start: " + mCount);
            }

            for (int i = 0; i < mCount; i++) {
@@ -89,7 +86,7 @@ public class GroupMemberPickerFragment extends
            super.moveToFirst();

            if (Log.isLoggable(TAG, Log.VERBOSE)) {
                Log.v(TAG, "FilterCursorWrapper ending cursor size is" + mCount);
                Log.v(TAG, "RawContacts CursorWrapper end: " + mCount);
            }
        }