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

Commit 173e2d52 authored by Gary Mai's avatar Gary Mai Committed by Android (Google) Code Review
Browse files

Merge "Change aggregation suggestions to be raw contacts" into ub-contactsdialer-h-dev

parents b3705bc6 678108eb
Loading
Loading
Loading
Loading
+4 −4
Original line number Diff line number Diff line
@@ -304,10 +304,10 @@ public class ContactEditorActivity extends ContactsActivity implements
                }

                @Override
                public void onEditOtherContactRequested(
                        Uri contactLookupUri, ArrayList<ContentValues> values) {
                    final Intent intent = EditorIntents.createEditOtherContactIntent(
                            ContactEditorActivity.this, contactLookupUri, values);
                public void onEditOtherRawContactRequested(
                        Uri contactLookupUri, long rawContactId, ArrayList<ContentValues> values) {
                    final Intent intent = EditorIntents.createEditOtherRawContactIntent(
                            ContactEditorActivity.this, contactLookupUri, rawContactId, values);
                    ImplicitIntentsUtil.startActivityInApp(
                            ContactEditorActivity.this, intent);
                    finish();
+66 −145
Original line number Diff line number Diff line
@@ -29,7 +29,6 @@ import android.os.Process;
import android.provider.ContactsContract.CommonDataKinds.Email;
import android.provider.ContactsContract.CommonDataKinds.Nickname;
import android.provider.ContactsContract.CommonDataKinds.Phone;
import android.provider.ContactsContract.CommonDataKinds.Photo;
import android.provider.ContactsContract.CommonDataKinds.StructuredName;
import android.provider.ContactsContract.Contacts;
import android.provider.ContactsContract.Contacts.AggregationSuggestions;
@@ -41,6 +40,8 @@ import android.text.TextUtils;
import com.android.contacts.common.model.ValuesDelta;
import com.android.contacts.common.model.account.AccountWithDataSet;
import com.android.contacts.compat.AggregationSuggestionsCompat;

import com.google.common.base.Objects;
import com.google.common.collect.Lists;

import java.util.ArrayList;
@@ -57,36 +58,26 @@ public class AggregationSuggestionEngine extends HandlerThread {
        void onAggregationSuggestionChange();
    }

    public static final class RawContact {
        public long rawContactId;
        public String accountType;
        public String accountName;
        public String dataSet;

        @Override
        public String toString() {
            return "ID: " + rawContactId + " account: " + accountType + "/" + accountName
                    + " dataSet: " + dataSet;
        }
    }

    public static final class Suggestion {

        public long contactId;
        public long photoId;
        public String lookupKey;
        public String contactLookupKey;
        public long rawContactId;
        public String name;
        public String phoneNumber;
        public String emailAddress;
        public String nickname;
        public byte[] photo;
        public List<RawContact> rawContacts;

        @Override
        public String toString() {
            return "ID: " + contactId + " rawContacts: " + rawContacts + " name: " + name
            + " phone: " + phoneNumber + " email: " + emailAddress + " nickname: "
            + nickname + (photo != null ? " [has photo]" : "");
            return Objects.toStringHelper(Suggestion.class)
                    .add("contactId", contactId)
                    .add("contactLookupKey", contactLookupKey)
                    .add("rawContactId", rawContactId)
                    .add("name", name)
                    .add("phoneNumber", phoneNumber)
                    .add("emailAddress", emailAddress)
                    .add("nickname", nickname)
                    .toString();
        }
    }

@@ -107,10 +98,11 @@ public class AggregationSuggestionEngine extends HandlerThread {

    private static final long SUGGESTION_LOOKUP_DELAY_MILLIS = 300;

    private static final int SUGGESTIONS_LIMIT = 3;

    private final Context mContext;

    private long[] mSuggestedContactIds = new long[0];

    private Handler mMainHandler;
    private Handler mHandler;
    private long mContactId;
@@ -119,8 +111,6 @@ public class AggregationSuggestionEngine extends HandlerThread {
    private Cursor mDataCursor;
    private ContentObserver mContentObserver;
    private Uri mSuggestionsUri;
    private int mSuggestionsLimit = 3;
    private boolean mPruneInvisibleContacts = false;

    public AggregationSuggestionEngine(Context context) {
        super("AggregationSuggestions", Process.THREAD_PRIORITY_BACKGROUND);
@@ -156,14 +146,6 @@ public class AggregationSuggestionEngine extends HandlerThread {
        mAccountFilter = account;
    }

    public void setSuggestionsLimit(int suggestionsLimit) {
        mSuggestionsLimit = suggestionsLimit;
    }

    public void setPruneInvisibleContacts (boolean pruneInvisibleContacts) {
        mPruneInvisibleContacts = pruneInvisibleContacts;
    }

    public void setListener(Listener listener) {
        mListener = listener;
    }
@@ -238,7 +220,7 @@ public class AggregationSuggestionEngine extends HandlerThread {
        // AggregationSuggestions.Builder() became visible in API level 23, so use it if applicable.
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
            final Builder uriBuilder = new AggregationSuggestions.Builder()
                    .setLimit(mSuggestionsLimit)
                    .setLimit(SUGGESTIONS_LIMIT)
                    .setContactId(mContactId);
            if (nameSb.length() != 0) {
                uriBuilder.addNameParameter(nameSb.toString());
@@ -252,7 +234,7 @@ public class AggregationSuggestionEngine extends HandlerThread {
        // For previous SDKs, use the backup plan.
        final AggregationSuggestionsCompat.Builder uriBuilder =
                new AggregationSuggestionsCompat.Builder()
                .setLimit(mSuggestionsLimit)
                .setLimit(SUGGESTIONS_LIMIT)
                .setContactId(mContactId);
        if (nameSb.length() != 0) {
            uriBuilder.addNameParameter(nameSb.toString());
@@ -291,39 +273,30 @@ public class AggregationSuggestionEngine extends HandlerThread {
                        + Phone.CONTENT_ITEM_TYPE + "','"
                        + Email.CONTENT_ITEM_TYPE + "','"
                        + StructuredName.CONTENT_ITEM_TYPE + "','"
                    + Nickname.CONTENT_ITEM_TYPE + "','"
                    + Photo.CONTENT_ITEM_TYPE + "')"
                        + Nickname.CONTENT_ITEM_TYPE + "')"
                        + " AND " + Data.CONTACT_ID + " IN (";

        public static final String[] COLUMNS = {
            Data._ID,
                Data.CONTACT_ID,
                Data.LOOKUP_KEY,
            Data.PHOTO_ID,
            Data.DISPLAY_NAME,
                Data.RAW_CONTACT_ID,
                Data.MIMETYPE,
                Data.DATA1,
                Data.IS_SUPER_PRIMARY,
            Photo.PHOTO,
                RawContacts.ACCOUNT_TYPE,
                RawContacts.ACCOUNT_NAME,
                RawContacts.DATA_SET
        };

        public static final int ID = 0;
        public static final int CONTACT_ID = 1;
        public static final int LOOKUP_KEY = 2;
        public static final int PHOTO_ID = 3;
        public static final int DISPLAY_NAME = 4;
        public static final int RAW_CONTACT_ID = 5;
        public static final int MIMETYPE = 6;
        public static final int DATA1 = 7;
        public static final int IS_SUPERPRIMARY = 8;
        public static final int PHOTO = 9;
        public static final int ACCOUNT_TYPE = 10;
        public static final int ACCOUNT_NAME = 11;
        public static final int DATA_SET = 12;
        public static final int CONTACT_ID = 0;
        public static final int LOOKUP_KEY = 1;
        public static final int RAW_CONTACT_ID = 2;
        public static final int MIMETYPE = 3;
        public static final int DATA1 = 4;
        public static final int IS_SUPERPRIMARY = 5;
        public static final int ACCOUNT_TYPE = 6;
        public static final int ACCOUNT_NAME = 7;
        public static final int DATA_SET = 8;
    }

    private void loadAggregationSuggestions(Uri uri) {
@@ -352,12 +325,12 @@ public class AggregationSuggestionEngine extends HandlerThread {
                sb.append(mSuggestedContactIds[i]);
            }
            sb.append(')');
            sb.toString();

            Cursor dataCursor = contentResolver.query(Data.CONTENT_URI,
                    DataQuery.COLUMNS, sb.toString(), null, Data.CONTACT_ID);
            if (dataCursor != null) {
                mMainHandler.sendMessage(mMainHandler.obtainMessage(MESSAGE_DATA_CURSOR, dataCursor));
                mMainHandler.sendMessage(
                        mMainHandler.obtainMessage(MESSAGE_DATA_CURSOR, dataCursor));
            }
        } finally {
            cursor.close();
@@ -370,8 +343,7 @@ public class AggregationSuggestionEngine extends HandlerThread {
        final ArrayList<Long> newIds = new ArrayList<Long>(count);
        while (cursor.moveToNext()) {
            final long contactId = cursor.getLong(0);
            if (!changed &&
                    Arrays.binarySearch(mSuggestedContactIds, contactId) < 0) {
            if (!changed && Arrays.binarySearch(mSuggestedContactIds, contactId) < 0) {
                changed = true;
            }
            newIds.add(contactId);
@@ -404,110 +376,59 @@ public class AggregationSuggestionEngine extends HandlerThread {
    }

    public List<Suggestion> getSuggestions() {
        final ArrayList<Long> visibleContacts = new ArrayList<>();
        if (mPruneInvisibleContacts) {
            final Uri contactFilterUri = Data.CONTENT_URI.buildUpon()
                    .appendQueryParameter(Data.VISIBLE_CONTACTS_ONLY, "true")
                    .build();
            final ContentResolver contentResolver = mContext.getContentResolver();
            final Cursor contactCursor = contentResolver.query(contactFilterUri,
                    new String[]{Data.CONTACT_ID}, null, null, null);
            try {
                if (contactCursor != null) {
                    while (contactCursor.moveToNext()) {
                        final long contactId = contactCursor.getLong(0);
                        visibleContacts.add(contactId);
                    }
                }
            } finally {
                contactCursor.close();
            }

        }
        final ArrayList<Suggestion> list = Lists.newArrayList();

        ArrayList<Suggestion> list = Lists.newArrayList();
        if (mDataCursor != null) {
        if (mDataCursor != null && mAccountFilter != null) {
            Suggestion suggestion = null;
            long currentContactId = -1;
            long currentRawContactId = -1;
            mDataCursor.moveToPosition(-1);
            while (mDataCursor.moveToNext()) {
                long contactId = mDataCursor.getLong(DataQuery.CONTACT_ID);
                if (mPruneInvisibleContacts && !visibleContacts.contains(contactId)) {
                    continue;
                }
                if (contactId != currentContactId) {
                final long rawContactId = mDataCursor.getLong(DataQuery.RAW_CONTACT_ID);
                if (rawContactId != currentRawContactId) {
                    suggestion = new Suggestion();
                    suggestion.contactId = contactId;
                    suggestion.name = mDataCursor.getString(DataQuery.DISPLAY_NAME);
                    suggestion.lookupKey = mDataCursor.getString(DataQuery.LOOKUP_KEY);
                    suggestion.rawContacts = Lists.newArrayList();
                    // No restriction, add all suggestions.
                    if (mAccountFilter == null) {
                        list.add(suggestion);
                    }
                    currentContactId = contactId;
                }

                long rawContactId = mDataCursor.getLong(DataQuery.RAW_CONTACT_ID);
                if (!containsRawContact(suggestion, rawContactId)) {
                    RawContact rawContact = new RawContact();
                    rawContact.rawContactId = rawContactId;
                    rawContact.accountName = mDataCursor.getString(DataQuery.ACCOUNT_NAME);
                    rawContact.accountType = mDataCursor.getString(DataQuery.ACCOUNT_TYPE);
                    rawContact.dataSet = mDataCursor.getString(DataQuery.DATA_SET);
                    suggestion.rawContactId = rawContactId;
                    suggestion.contactId = mDataCursor.getLong(DataQuery.CONTACT_ID);
                    suggestion.contactLookupKey = mDataCursor.getString(DataQuery.LOOKUP_KEY);
                    final String accountName = mDataCursor.getString(DataQuery.ACCOUNT_NAME);
                    final String accountType = mDataCursor.getString(DataQuery.ACCOUNT_TYPE);
                    final String dataSet = mDataCursor.getString(DataQuery.DATA_SET);
                    final AccountWithDataSet account = new AccountWithDataSet(
                            rawContact.accountName, rawContact.accountType, rawContact.dataSet);
                    // If we're restricting to a certain account, only add the suggestion if
                    // it has a raw contact from that account.
                    if (mAccountFilter != null && mAccountFilter.equals(account)
                            && !list.contains(suggestion)) {
                            accountName, accountType, dataSet);
                    if (mAccountFilter.equals(account)) {
                        list.add(suggestion);
                    }
                    suggestion.rawContacts.add(rawContact);
                    currentRawContactId = rawContactId;
                }

                String mimetype = mDataCursor.getString(DataQuery.MIMETYPE);
                final String mimetype = mDataCursor.getString(DataQuery.MIMETYPE);
                if (Phone.CONTENT_ITEM_TYPE.equals(mimetype)) {
                    String data = mDataCursor.getString(DataQuery.DATA1);
                    final String data = mDataCursor.getString(DataQuery.DATA1);
                    int superprimary = mDataCursor.getInt(DataQuery.IS_SUPERPRIMARY);
                    if (!TextUtils.isEmpty(data)
                            && (superprimary != 0 || suggestion.phoneNumber == null)) {
                        suggestion.phoneNumber = data;
                    }
                } else if (Email.CONTENT_ITEM_TYPE.equals(mimetype)) {
                    String data = mDataCursor.getString(DataQuery.DATA1);
                    final String data = mDataCursor.getString(DataQuery.DATA1);
                    int superprimary = mDataCursor.getInt(DataQuery.IS_SUPERPRIMARY);
                    if (!TextUtils.isEmpty(data)
                            && (superprimary != 0 || suggestion.emailAddress == null)) {
                        suggestion.emailAddress = data;
                    }
                } else if (Nickname.CONTENT_ITEM_TYPE.equals(mimetype)) {
                    String data = mDataCursor.getString(DataQuery.DATA1);
                    final String data = mDataCursor.getString(DataQuery.DATA1);
                    if (!TextUtils.isEmpty(data)) {
                        suggestion.nickname = data;
                    }
                } else if (Photo.CONTENT_ITEM_TYPE.equals(mimetype)) {
                    long dataId = mDataCursor.getLong(DataQuery.ID);
                    long photoId = mDataCursor.getLong(DataQuery.PHOTO_ID);
                    if (dataId == photoId && !mDataCursor.isNull(DataQuery.PHOTO)) {
                        suggestion.photo = mDataCursor.getBlob(DataQuery.PHOTO);
                        suggestion.photoId = photoId;
                } else if (StructuredName.CONTENT_ITEM_TYPE.equals(mimetype)) {
                    // DATA1 stores the display name for the raw contact.
                    final String data = mDataCursor.getString(DataQuery.DATA1);
                    if (!TextUtils.isEmpty(data) && suggestion.name == null) {
                        suggestion.name = data;
                    }
                }
            }
        }
        return list;
    }

    public boolean containsRawContact(Suggestion suggestion, long rawContactId) {
        if (suggestion.rawContacts != null) {
            int count = suggestion.rawContacts.size();
            for (int i = 0; i < count; i++) {
                if (suggestion.rawContacts.get(i).rawContactId == rawContactId) {
                    return true;
                }
            }
        }
        return false;
    }
}
+26 −74
Original line number Diff line number Diff line
@@ -16,9 +16,10 @@

package com.android.contacts.editor;

import android.content.ContentUris;
import android.content.Context;
import android.graphics.BitmapFactory;
import android.net.Uri;
import android.provider.ContactsContract;
import android.provider.ContactsContract.Contacts;
import android.text.TextUtils;
import android.util.AttributeSet;
@@ -28,16 +29,8 @@ import android.widget.LinearLayout;
import android.widget.TextView;

import com.android.contacts.R;
import com.android.contacts.editor.AggregationSuggestionEngine.RawContact;
import com.android.contacts.editor.AggregationSuggestionEngine.Suggestion;
import com.android.contacts.common.ContactPhotoManager;
import com.android.contacts.common.model.AccountTypeManager;
import com.android.contacts.common.model.account.AccountType;

import com.google.common.collect.Lists;

import java.util.ArrayList;
import java.util.List;
import com.android.contacts.editor.AggregationSuggestionEngine.Suggestion;

/**
 * A view that contains a name, picture and other data for a contact aggregation suggestion.
@@ -45,25 +38,15 @@ import java.util.List;
public class AggregationSuggestionView extends LinearLayout {

    public interface Listener {

        /**
         * Callback that passes the contact ID to join with and, for convenience,
         * also the list of constituent raw contact IDs to avoid a separate query
         * for those.
         */
        public void onJoinAction(long contactId, List<Long> rawContacIds);

        /**
         * Callback that passes the contact ID to edit instead of the current contact.
         * Callback that passes the contact URI and raw contact ID to edit instead of the
         * current contact.
         */
        public void onEditAction(Uri contactLookupUri);
        void onEditAction(Uri contactLookupUri, long rawContactId);
    }

    private Listener mListener;
    private long mContactId;
    private String mLookupKey;
    private List<RawContact> mRawContacts = Lists.newArrayList();
    private boolean mNewContact;
    private Suggestion mSuggestion;

    public AggregationSuggestionView(Context context) {
        super(context);
@@ -77,22 +60,21 @@ public class AggregationSuggestionView extends LinearLayout {
        super(context, attrs, defStyle);
    }

    public void setNewContact(boolean flag) {
        mNewContact = flag;
    }

    public void bindSuggestion(Suggestion suggestion) {
        mContactId = suggestion.contactId;
        mLookupKey = suggestion.lookupKey;
        mRawContacts = suggestion.rawContacts;
        ImageView photo = (ImageView) findViewById(R.id.aggregation_suggestion_photo);
        if (suggestion.photo != null) {
            photo.setImageBitmap(BitmapFactory.decodeByteArray(
                    suggestion.photo, 0, suggestion.photo.length));
        } else {
            photo.setImageDrawable(ContactPhotoManager.getDefaultAvatarDrawableForContact(
                    getResources(), false, null));
        }
        mSuggestion = suggestion;
        final ContactPhotoManager.DefaultImageRequest
                request = new ContactPhotoManager.DefaultImageRequest(
                suggestion.name, String.valueOf(suggestion.rawContactId), /* isCircular = */ false);
        final Uri photoUri = Uri.withAppendedPath(ContentUris.withAppendedId(
                ContactsContract.RawContacts.CONTENT_URI, suggestion.rawContactId),
                ContactsContract.RawContacts.DisplayPhoto.CONTENT_DIRECTORY);
        final ImageView photoView = (ImageView) findViewById(
                R.id.aggregation_suggestion_photo);
        ContactPhotoManager.getInstance(getContext()).loadDirectoryPhoto(photoView,
                photoUri,
                /* darkTheme = */ false,
                /* isCircular = */ false,
                request);

        TextView name = (TextView) findViewById(R.id.aggregation_suggestion_name);
        name.setText(suggestion.name);
@@ -111,48 +93,18 @@ public class AggregationSuggestionView extends LinearLayout {
        data.setText(dataText);
    }

    /**
     * Returns true if the suggested contact can be edited.
     */
    private boolean canEditSuggestedContact() {
        if (!mNewContact) {
            return false;
        }

        AccountTypeManager accountTypes = AccountTypeManager.getInstance(getContext());
        for (RawContact rawContact : mRawContacts) {
            String accountType = rawContact.accountType;
            String dataSet = rawContact.dataSet;
            if (accountType == null) {
                return true;
            }
            AccountType type = accountTypes.getAccountType(accountType, dataSet);
            if (type.areContactsWritable()) {
                return true;
            }
        }

        return false;
    }

    public void setListener(Listener listener) {
        mListener = listener;
    }

    public boolean handleItemClickEvent() {
        if (mListener != null && isEnabled()) {
            if (canEditSuggestedContact()) {
                if (TextUtils.isEmpty(mLookupKey)) {
            if (TextUtils.isEmpty(mSuggestion.contactLookupKey)) {
                return false;
            }
                mListener.onEditAction(Contacts.getLookupUri(mContactId, mLookupKey));
            } else {
                ArrayList<Long> rawContactIds = Lists.newArrayList();
                for (RawContact rawContact : mRawContacts) {
                    rawContactIds.add(rawContact.rawContactId);
                }
                mListener.onJoinAction(mContactId, rawContactIds);
            }
            mListener.onEditAction(
                    Contacts.getLookupUri(mSuggestion.contactId, mSuggestion.contactLookupKey),
                    mSuggestion.rawContactId);
            return true;
        }
        return false;
Loading