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

Commit d70e5ad6 authored by Flavio Lerda's avatar Flavio Lerda
Browse files

Use ContactsContract.PhoneLookup to look up SIP addresses.

We recently added support for looking up contacts with a given SIP
address using ContactContracts.PhoneLookup instead of a generic,
expensive ContactsContract.Data query.

Use this new look-up mechanism in the call log and call details.

Bug: 5529690
Change-Id: I6a10cfa5038ceca96669cf07ed20d7d47bd25427
parent 504ebb9f
Loading
Loading
Loading
Loading
+53 −109
Original line number Original line Diff line number Diff line
@@ -21,9 +21,7 @@ import com.android.contacts.util.UriUtils;
import android.content.Context;
import android.content.Context;
import android.database.Cursor;
import android.database.Cursor;
import android.net.Uri;
import android.net.Uri;
import android.provider.ContactsContract.CommonDataKinds.SipAddress;
import android.provider.ContactsContract.Contacts;
import android.provider.ContactsContract.Contacts;
import android.provider.ContactsContract.Data;
import android.provider.ContactsContract.PhoneLookup;
import android.provider.ContactsContract.PhoneLookup;
import android.telephony.PhoneNumberUtils;
import android.telephony.PhoneNumberUtils;
import android.text.TextUtils;
import android.text.TextUtils;
@@ -96,87 +94,42 @@ public class ContactInfoHelper {
    }
    }


    /**
    /**
     * Determines the contact information for the given SIP address.
     * Looks up a contact using the given URI.
     * <p>
     * <p>
     * It returns the contact info if found.
     * It returns null if an error occurs, {@link ContactInfo#EMPTY} if no matching contact is
     * found, or the {@link ContactInfo} for the given contact.
     * <p>
     * <p>
     * If no contact corresponds to the given SIP address, returns {@link ContactInfo#EMPTY}.
     * The {@link ContactInfo#formattedNumber} field is always set to {@code null} in the returned
     * <p>
     * value.
     * If the lookup fails for some other reason, it returns null.
     */
     */
    private ContactInfo queryContactInfoForSipAddress(String sipAddress) {
    private ContactInfo lookupContactFromUri(Uri uri) {
        final ContactInfo info;
        final ContactInfo info;

        Cursor phonesCursor =
        // TODO: This code is duplicated from the
        // CallerInfoAsyncQuery class.  To avoid that, could the
        // code here just use CallerInfoAsyncQuery, rather than
        // manually running ContentResolver.query() itself?

        // We look up SIP addresses directly in the Data table:
        Uri contactRef = Data.CONTENT_URI;

        // Note Data.DATA1 and SipAddress.SIP_ADDRESS are equivalent.
        //
        // Also note we use "upper(data1)" in the WHERE clause, and
        // uppercase the incoming SIP address, in order to do a
        // case-insensitive match.
        //
        // TODO: SIP URIs are defined as being case sensitive for the user part (before the '@')
        // and case insensitive everywhere else. We should change the code to handle this
        // accordingly.
        //
        // TODO: May also need to normalize by adding "sip:" as a
        // prefix, if we start storing SIP addresses that way in the
        // database.
        String selection = "upper(" + Data.DATA1 + ")=?"
                + " AND "
                + Data.MIMETYPE + "='" + SipAddress.CONTENT_ITEM_TYPE + "'";
        String[] selectionArgs = new String[] { sipAddress.toUpperCase() };

        Cursor dataTableCursor =
                mContext.getContentResolver().query(
                mContext.getContentResolver().query(
                        contactRef,
                        uri, PhoneQuery._PROJECTION, null, null, null);
                        null,  // projection
                        selection,  // selection
                        selectionArgs,  // selectionArgs
                        null);  // sortOrder


        if (dataTableCursor != null) {
        if (phonesCursor != null) {
            if (dataTableCursor.moveToFirst()) {
            try {
                if (phonesCursor.moveToFirst()) {
                    info = new ContactInfo();
                    info = new ContactInfo();

                    long contactId = phonesCursor.getLong(PhoneQuery.PERSON_ID);
                // TODO: we could slightly speed this up using an
                    String lookupKey = phonesCursor.getString(PhoneQuery.LOOKUP_KEY);
                // explicit projection (and thus not have to do
                // those getColumnIndex() calls) but the benefit is
                // very minimal.

                // Note the Data.CONTACT_ID column here is
                // equivalent to the PERSON_ID_COLUMN_INDEX column
                // we use with "phonesCursor" below.
                long contactId = dataTableCursor.getLong(
                        dataTableCursor.getColumnIndex(Data.CONTACT_ID));
                String lookupKey = dataTableCursor.getString(
                        dataTableCursor.getColumnIndex(Data.LOOKUP_KEY));
                    info.lookupUri = Contacts.getLookupUri(contactId, lookupKey);
                    info.lookupUri = Contacts.getLookupUri(contactId, lookupKey);
                info.name = dataTableCursor.getString(
                    info.name = phonesCursor.getString(PhoneQuery.NAME);
                        dataTableCursor.getColumnIndex(Data.DISPLAY_NAME));
                    info.type = phonesCursor.getInt(PhoneQuery.PHONE_TYPE);
                // "type" and "label" are currently unused for SIP addresses
                    info.label = phonesCursor.getString(PhoneQuery.LABEL);
                info.type = SipAddress.TYPE_OTHER;
                    info.number = phonesCursor.getString(PhoneQuery.MATCHED_NUMBER);
                info.label = null;
                    info.normalizedNumber = phonesCursor.getString(PhoneQuery.NORMALIZED_NUMBER);

                    info.photoId = phonesCursor.getLong(PhoneQuery.PHOTO_ID);
                // And "number" is the SIP address.
                    info.photoUri =
                // Note Data.DATA1 and SipAddress.SIP_ADDRESS are equivalent.
                            UriUtils.parseUriOrNull(phonesCursor.getString(PhoneQuery.PHOTO_URI));
                info.number = dataTableCursor.getString(dataTableCursor.getColumnIndex(Data.DATA1));
                    info.formattedNumber = null;
                info.normalizedNumber = null;  // meaningless for SIP addresses
                info.photoId = dataTableCursor.getLong(
                        dataTableCursor.getColumnIndex(Data.PHOTO_ID));
                info.photoUri = UriUtils.parseUriOrNull(dataTableCursor.getString(
                        dataTableCursor.getColumnIndex(Data.PHOTO_URI)));
                info.formattedNumber = null;  // meaningless for SIP addresses
                } else {
                } else {
                    info = ContactInfo.EMPTY;
                    info = ContactInfo.EMPTY;
                }
                }
            dataTableCursor.close();
            } finally {
                phonesCursor.close();
            }
        } else {
        } else {
            // Failed to fetch the data, ignore this request.
            // Failed to fetch the data, ignore this request.
            info = null;
            info = null;
@@ -184,6 +137,25 @@ public class ContactInfoHelper {
        return info;
        return info;
    }
    }


    /**
     * Determines the contact information for the given SIP address.
     * <p>
     * It returns the contact info if found.
     * <p>
     * If no contact corresponds to the given SIP address, returns {@link ContactInfo#EMPTY}.
     * <p>
     * If the lookup fails for some other reason, it returns null.
     */
    private ContactInfo queryContactInfoForSipAddress(String sipAddress) {
        final ContactInfo info;

        // "contactNumber" is a SIP address, so use the PhoneLookup table with the SIP parameter.
        Uri.Builder uriBuilder = PhoneLookup.CONTENT_FILTER_URI.buildUpon();
        uriBuilder.appendPath(Uri.encode(sipAddress));
        uriBuilder.appendQueryParameter(PhoneLookup.QUERY_PARAMETER_SIP_ADDRESS, "1");
        return lookupContactFromUri(uriBuilder.build());
    }

    /**
    /**
     * Determines the contact information for the given phone number.
     * Determines the contact information for the given phone number.
     * <p>
     * <p>
@@ -194,8 +166,6 @@ public class ContactInfoHelper {
     * If the lookup fails for some other reason, it returns null.
     * If the lookup fails for some other reason, it returns null.
     */
     */
    private ContactInfo queryContactInfoForPhoneNumber(String number, String countryIso) {
    private ContactInfo queryContactInfoForPhoneNumber(String number, String countryIso) {
        final ContactInfo info;

        String contactNumber = number;
        String contactNumber = number;
        if (!TextUtils.isEmpty(countryIso)) {
        if (!TextUtils.isEmpty(countryIso)) {
            // Normalize the number: this is needed because the PhoneLookup query below does not
            // Normalize the number: this is needed because the PhoneLookup query below does not
@@ -207,37 +177,11 @@ public class ContactInfoHelper {
            }
            }
        }
        }


        // "contactNumber" is a regular phone number, so use the
        // The "contactNumber" is a regular phone number, so use the PhoneLookup table.
        // PhoneLookup table:
        Uri uri = Uri.withAppendedPath(PhoneLookup.CONTENT_FILTER_URI, Uri.encode(contactNumber));
        Cursor phonesCursor =
        ContactInfo info = lookupContactFromUri(uri);
                mContext.getContentResolver().query(
        if (info != null && info != ContactInfo.EMPTY) {
                    Uri.withAppendedPath(PhoneLookup.CONTENT_FILTER_URI,
                            Uri.encode(contactNumber)),
                            PhoneQuery._PROJECTION, null, null, null);

        if (phonesCursor != null) {
            if (phonesCursor.moveToFirst()) {
                info = new ContactInfo();
                long contactId = phonesCursor.getLong(PhoneQuery.PERSON_ID);
                String lookupKey = phonesCursor.getString(PhoneQuery.LOOKUP_KEY);
                info.lookupUri = Contacts.getLookupUri(contactId, lookupKey);
                info.name = phonesCursor.getString(PhoneQuery.NAME);
                info.type = phonesCursor.getInt(PhoneQuery.PHONE_TYPE);
                info.label = phonesCursor.getString(PhoneQuery.LABEL);
                info.number = phonesCursor.getString(PhoneQuery.MATCHED_NUMBER);
                info.normalizedNumber = phonesCursor.getString(PhoneQuery.NORMALIZED_NUMBER);
                info.photoId = phonesCursor.getLong(PhoneQuery.PHOTO_ID);
                info.photoUri =
                        UriUtils.parseUriOrNull(phonesCursor.getString(PhoneQuery.PHOTO_URI));
            info.formattedNumber = formatPhoneNumber(number, null, countryIso);
            info.formattedNumber = formatPhoneNumber(number, null, countryIso);

            } else {
                info = ContactInfo.EMPTY;
            }
            phonesCursor.close();
        } else {
            // Failed to fetch the data, ignore this request.
            info = null;
        }
        }
        return info;
        return info;
    }
    }