diff options
Diffstat (limited to 'src/com/android/dialer/calllog/ContactInfoHelper.java')
-rw-r--r-- | src/com/android/dialer/calllog/ContactInfoHelper.java | 499 |
1 files changed, 0 insertions, 499 deletions
diff --git a/src/com/android/dialer/calllog/ContactInfoHelper.java b/src/com/android/dialer/calllog/ContactInfoHelper.java deleted file mode 100644 index d9898ab94..000000000 --- a/src/com/android/dialer/calllog/ContactInfoHelper.java +++ /dev/null @@ -1,499 +0,0 @@ -/* - * Copyright (C) 2011 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.dialer.calllog; - -import com.google.common.primitives.Longs; - -import android.content.ContentValues; -import android.content.Context; -import android.database.Cursor; -import android.database.sqlite.SQLiteFullException; -import android.net.Uri; -import android.provider.CallLog.Calls; -import android.provider.ContactsContract; -import android.provider.ContactsContract.CommonDataKinds.Phone; -import android.provider.ContactsContract.Contacts; -import android.provider.ContactsContract.DisplayNameSources; -import android.provider.ContactsContract.PhoneLookup; -import android.support.annotation.Nullable; -import android.telephony.PhoneNumberUtils; -import android.text.TextUtils; -import android.util.Log; - -import com.android.contacts.common.ContactsUtils; -import com.android.contacts.common.ContactsUtils.UserType; -import com.android.contacts.common.compat.CompatUtils; -import com.android.contacts.common.compat.DirectoryCompat; -import com.android.contacts.common.util.Constants; -import com.android.contacts.common.util.PermissionsUtil; -import com.android.contacts.common.util.PhoneNumberHelper; -import com.android.contacts.common.util.UriUtils; -import com.android.dialer.compat.DialerCompatUtils; -import com.android.dialer.service.CachedNumberLookupService; -import com.android.dialer.service.CachedNumberLookupService.CachedContactInfo; -import com.android.dialer.util.TelecomUtil; -import com.android.dialerbind.ObjectFactory; - -import org.json.JSONException; -import org.json.JSONObject; - -/** - * Utility class to look up the contact information for a given number. - */ -public class ContactInfoHelper { - private static final String TAG = ContactInfoHelper.class.getSimpleName(); - - private final Context mContext; - private final String mCurrentCountryIso; - - private static final CachedNumberLookupService mCachedNumberLookupService = - ObjectFactory.newCachedNumberLookupService(); - - public ContactInfoHelper(Context context, String currentCountryIso) { - mContext = context; - mCurrentCountryIso = currentCountryIso; - } - - /** - * Returns the contact information for the given number. - * <p> - * If the number does not match any contact, returns a contact info containing only the number - * and the formatted number. - * <p> - * If an error occurs during the lookup, it returns null. - * - * @param number the number to look up - * @param countryIso the country associated with this number - */ - @Nullable - public ContactInfo lookupNumber(String number, String countryIso) { - if (TextUtils.isEmpty(number)) { - return null; - } - - ContactInfo info; - - if (PhoneNumberHelper.isUriNumber(number)) { - // The number is a SIP address.. - info = lookupContactFromUri(getContactInfoLookupUri(number), true); - if (info == null || info == ContactInfo.EMPTY) { - // If lookup failed, check if the "username" of the SIP address is a phone number. - String username = PhoneNumberHelper.getUsernameFromUriNumber(number); - if (PhoneNumberUtils.isGlobalPhoneNumber(username)) { - info = queryContactInfoForPhoneNumber(username, countryIso, true); - } - } - } else { - // Look for a contact that has the given phone number. - info = queryContactInfoForPhoneNumber(number, countryIso, false); - } - - final ContactInfo updatedInfo; - if (info == null) { - // The lookup failed. - updatedInfo = null; - } else { - // If we did not find a matching contact, generate an empty contact info for the number. - if (info == ContactInfo.EMPTY) { - // Did not find a matching contact. - updatedInfo = new ContactInfo(); - updatedInfo.number = number; - updatedInfo.formattedNumber = formatPhoneNumber(number, null, countryIso); - updatedInfo.normalizedNumber = PhoneNumberUtils.formatNumberToE164( - number, countryIso); - updatedInfo.lookupUri = createTemporaryContactUri(updatedInfo.formattedNumber); - } else { - updatedInfo = info; - } - } - return updatedInfo; - } - - /** - * Creates a JSON-encoded lookup uri for a unknown number without an associated contact - * - * @param number - Unknown phone number - * @return JSON-encoded URI that can be used to perform a lookup when clicking on the quick - * contact card. - */ - private static Uri createTemporaryContactUri(String number) { - try { - final JSONObject contactRows = new JSONObject().put(Phone.CONTENT_ITEM_TYPE, - new JSONObject().put(Phone.NUMBER, number).put(Phone.TYPE, Phone.TYPE_CUSTOM)); - - final String jsonString = new JSONObject().put(Contacts.DISPLAY_NAME, number) - .put(Contacts.DISPLAY_NAME_SOURCE, DisplayNameSources.PHONE) - .put(Contacts.CONTENT_ITEM_TYPE, contactRows).toString(); - - return Contacts.CONTENT_LOOKUP_URI - .buildUpon() - .appendPath(Constants.LOOKUP_URI_ENCODED) - .appendQueryParameter(ContactsContract.DIRECTORY_PARAM_KEY, - String.valueOf(Long.MAX_VALUE)) - .encodedFragment(jsonString) - .build(); - } catch (JSONException e) { - return null; - } - } - - /** - * Looks up a contact using the given URI. - * <p> - * 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> - * The {@link ContactInfo#formattedNumber} field is always set to {@code null} in the returned - * value. - */ - ContactInfo lookupContactFromUri(Uri uri, boolean isSip) { - if (uri == null) { - return null; - } - if (!PermissionsUtil.hasContactsPermissions(mContext)) { - return ContactInfo.EMPTY; - } - - final String directory = uri.getQueryParameter(ContactsContract.DIRECTORY_PARAM_KEY); - final Long directoryId = directory == null ? null : Longs.tryParse(directory); - - Cursor phoneLookupCursor = null; - try { - String[] projection = PhoneQuery.getPhoneLookupProjection(uri); - phoneLookupCursor = mContext.getContentResolver().query(uri, projection, null, null, - null); - } catch (NullPointerException e) { - // Trap NPE from pre-N CP2 - return null; - } - if (phoneLookupCursor == null) { - return null; - } - - try { - if (!phoneLookupCursor.moveToFirst()) { - return ContactInfo.EMPTY; - } - String lookupKey = phoneLookupCursor.getString(PhoneQuery.LOOKUP_KEY); - ContactInfo contactInfo = createPhoneLookupContactInfo(phoneLookupCursor, lookupKey); - contactInfo.nameAlternative = lookUpDisplayNameAlternative(mContext, lookupKey, - contactInfo.userType, directoryId); - return contactInfo; - } finally { - phoneLookupCursor.close(); - } - } - - private ContactInfo createPhoneLookupContactInfo(Cursor phoneLookupCursor, String lookupKey) { - ContactInfo info = new ContactInfo(); - info.lookupKey = lookupKey; - info.lookupUri = Contacts.getLookupUri(phoneLookupCursor.getLong(PhoneQuery.PERSON_ID), - lookupKey); - info.name = phoneLookupCursor.getString(PhoneQuery.NAME); - info.type = phoneLookupCursor.getInt(PhoneQuery.PHONE_TYPE); - info.label = phoneLookupCursor.getString(PhoneQuery.LABEL); - info.number = phoneLookupCursor.getString(PhoneQuery.MATCHED_NUMBER); - info.normalizedNumber = phoneLookupCursor.getString(PhoneQuery.NORMALIZED_NUMBER); - info.photoId = phoneLookupCursor.getLong(PhoneQuery.PHOTO_ID); - info.photoUri = UriUtils.parseUriOrNull(phoneLookupCursor.getString(PhoneQuery.PHOTO_URI)); - info.formattedNumber = null; - info.userType = ContactsUtils.determineUserType(null, - phoneLookupCursor.getLong(PhoneQuery.PERSON_ID)); - - return info; - } - - public static String lookUpDisplayNameAlternative(Context context, String lookupKey, - @UserType long userType, @Nullable Long directoryId) { - // Query {@link Contacts#CONTENT_LOOKUP_URI} directly with work lookup key is not allowed. - if (lookupKey == null || userType == ContactsUtils.USER_TYPE_WORK) { - return null; - } - - if (directoryId != null) { - // Query {@link Contacts#CONTENT_LOOKUP_URI} with work lookup key is not allowed. - if (DirectoryCompat.isEnterpriseDirectoryId(directoryId)) { - return null; - } - - // Skip this to avoid an extra remote network call for alternative name - if (DirectoryCompat.isRemoteDirectoryId(directoryId)) { - return null; - } - } - - final Uri uri = Uri.withAppendedPath(Contacts.CONTENT_LOOKUP_URI, lookupKey); - Cursor cursor = null; - try { - cursor = context.getContentResolver().query(uri, - PhoneQuery.DISPLAY_NAME_ALTERNATIVE_PROJECTION, null, null, null); - - if (cursor != null && cursor.moveToFirst()) { - return cursor.getString(PhoneQuery.NAME_ALTERNATIVE); - } - } catch (IllegalArgumentException e) { - // Avoid dialer crash when lookup key is not valid - Log.e(TAG, "IllegalArgumentException in lookUpDisplayNameAlternative", e); - } finally { - if (cursor != null) { - cursor.close(); - } - } - - return null; - } - - /** - * Determines the contact information for the given phone number. - * <p> - * It returns the contact info if found. - * <p> - * If no contact corresponds to the given phone number, returns {@link ContactInfo#EMPTY}. - * <p> - * If the lookup fails for some other reason, it returns null. - */ - private ContactInfo queryContactInfoForPhoneNumber(String number, String countryIso, - boolean isSip) { - if (TextUtils.isEmpty(number)) { - return null; - } - - ContactInfo info = lookupContactFromUri(getContactInfoLookupUri(number), isSip); - if (info != null && info != ContactInfo.EMPTY) { - info.formattedNumber = formatPhoneNumber(number, null, countryIso); - } else if (mCachedNumberLookupService != null) { - CachedContactInfo cacheInfo = - mCachedNumberLookupService.lookupCachedContactFromNumber(mContext, number); - if (cacheInfo != null) { - info = cacheInfo.getContactInfo().isBadData ? null : cacheInfo.getContactInfo(); - } else { - info = null; - } - } - return info; - } - - /** - * Format the given phone number - * - * @param number the number to be formatted. - * @param normalizedNumber the normalized number of the given number. - * @param countryIso the ISO 3166-1 two letters country code, the country's convention will be - * used to format the number if the normalized phone is null. - * - * @return the formatted number, or the given number if it was formatted. - */ - private String formatPhoneNumber(String number, String normalizedNumber, String countryIso) { - if (TextUtils.isEmpty(number)) { - return ""; - } - // If "number" is really a SIP address, don't try to do any formatting at all. - if (PhoneNumberHelper.isUriNumber(number)) { - return number; - } - if (TextUtils.isEmpty(countryIso)) { - countryIso = mCurrentCountryIso; - } - return PhoneNumberUtils.formatNumber(number, normalizedNumber, countryIso); - } - - /** - * Stores differences between the updated contact info and the current call log contact info. - * - * @param number The number of the contact. - * @param countryIso The country associated with this number. - * @param updatedInfo The updated contact info. - * @param callLogInfo The call log entry's current contact info. - */ - public void updateCallLogContactInfo(String number, String countryIso, ContactInfo updatedInfo, - ContactInfo callLogInfo) { - if (!PermissionsUtil.hasPermission(mContext, android.Manifest.permission.WRITE_CALL_LOG)) { - return; - } - - final ContentValues values = new ContentValues(); - boolean needsUpdate = false; - - if (callLogInfo != null) { - if (!TextUtils.equals(updatedInfo.name, callLogInfo.name)) { - values.put(Calls.CACHED_NAME, updatedInfo.name); - needsUpdate = true; - } - - if (updatedInfo.type != callLogInfo.type) { - values.put(Calls.CACHED_NUMBER_TYPE, updatedInfo.type); - needsUpdate = true; - } - - if (!TextUtils.equals(updatedInfo.label, callLogInfo.label)) { - values.put(Calls.CACHED_NUMBER_LABEL, updatedInfo.label); - needsUpdate = true; - } - - if (!UriUtils.areEqual(updatedInfo.lookupUri, callLogInfo.lookupUri)) { - values.put(Calls.CACHED_LOOKUP_URI, UriUtils.uriToString(updatedInfo.lookupUri)); - needsUpdate = true; - } - - // Only replace the normalized number if the new updated normalized number isn't empty. - if (!TextUtils.isEmpty(updatedInfo.normalizedNumber) && - !TextUtils.equals(updatedInfo.normalizedNumber, callLogInfo.normalizedNumber)) { - values.put(Calls.CACHED_NORMALIZED_NUMBER, updatedInfo.normalizedNumber); - needsUpdate = true; - } - - if (!TextUtils.equals(updatedInfo.number, callLogInfo.number)) { - values.put(Calls.CACHED_MATCHED_NUMBER, updatedInfo.number); - needsUpdate = true; - } - - if (updatedInfo.photoId != callLogInfo.photoId) { - values.put(Calls.CACHED_PHOTO_ID, updatedInfo.photoId); - needsUpdate = true; - } - - final Uri updatedPhotoUriContactsOnly = - UriUtils.nullForNonContactsUri(updatedInfo.photoUri); - if (DialerCompatUtils.isCallsCachedPhotoUriCompatible() && - !UriUtils.areEqual(updatedPhotoUriContactsOnly, callLogInfo.photoUri)) { - values.put(Calls.CACHED_PHOTO_URI, - UriUtils.uriToString(updatedPhotoUriContactsOnly)); - needsUpdate = true; - } - - if (!TextUtils.equals(updatedInfo.formattedNumber, callLogInfo.formattedNumber)) { - values.put(Calls.CACHED_FORMATTED_NUMBER, updatedInfo.formattedNumber); - needsUpdate = true; - } - } else { - // No previous values, store all of them. - values.put(Calls.CACHED_NAME, updatedInfo.name); - values.put(Calls.CACHED_NUMBER_TYPE, updatedInfo.type); - values.put(Calls.CACHED_NUMBER_LABEL, updatedInfo.label); - values.put(Calls.CACHED_LOOKUP_URI, UriUtils.uriToString(updatedInfo.lookupUri)); - values.put(Calls.CACHED_MATCHED_NUMBER, updatedInfo.number); - values.put(Calls.CACHED_NORMALIZED_NUMBER, updatedInfo.normalizedNumber); - values.put(Calls.CACHED_PHOTO_ID, updatedInfo.photoId); - if (DialerCompatUtils.isCallsCachedPhotoUriCompatible()) { - values.put(Calls.CACHED_PHOTO_URI, UriUtils.uriToString( - UriUtils.nullForNonContactsUri(updatedInfo.photoUri))); - } - values.put(Calls.CACHED_FORMATTED_NUMBER, updatedInfo.formattedNumber); - needsUpdate = true; - } - - if (!needsUpdate) { - return; - } - - try { - if (countryIso == null) { - mContext.getContentResolver().update( - TelecomUtil.getCallLogUri(mContext), - values, - Calls.NUMBER + " = ? AND " + Calls.COUNTRY_ISO + " IS NULL", - new String[]{ number }); - } else { - mContext.getContentResolver().update( - TelecomUtil.getCallLogUri(mContext), - values, - Calls.NUMBER + " = ? AND " + Calls.COUNTRY_ISO + " = ?", - new String[]{ number, countryIso }); - } - } catch (SQLiteFullException e) { - Log.e(TAG, "Unable to update contact info in call log db", e); - } - } - - public static Uri getContactInfoLookupUri(String number) { - return getContactInfoLookupUri(number, -1); - } - - public static Uri getContactInfoLookupUri(String number, long directoryId) { - // Get URI for the number in the PhoneLookup table, with a parameter to indicate whether - // the number is a SIP number. - Uri uri = PhoneLookup.ENTERPRISE_CONTENT_FILTER_URI; - if (!ContactsUtils.FLAG_N_FEATURE) { - if (directoryId != -1) { - // ENTERPRISE_CONTENT_FILTER_URI in M doesn't support directory lookup - uri = PhoneLookup.CONTENT_FILTER_URI; - } else { - // b/25900607 in M. PhoneLookup.ENTERPRISE_CONTENT_FILTER_URI, encodes twice. - number = Uri.encode(number); - } - } - Uri.Builder builder = uri.buildUpon() - .appendPath(number) - .appendQueryParameter(PhoneLookup.QUERY_PARAMETER_SIP_ADDRESS, - String.valueOf(PhoneNumberHelper.isUriNumber(number))); - if (directoryId != -1) { - builder.appendQueryParameter(ContactsContract.DIRECTORY_PARAM_KEY, - String.valueOf(directoryId)); - } - return builder.build(); - } - - /** - * Returns the contact information stored in an entry of the call log. - * - * @param c A cursor pointing to an entry in the call log. - */ - public static ContactInfo getContactInfo(Cursor c) { - ContactInfo info = new ContactInfo(); - info.lookupUri = UriUtils.parseUriOrNull(c.getString(CallLogQuery.CACHED_LOOKUP_URI)); - info.name = c.getString(CallLogQuery.CACHED_NAME); - info.type = c.getInt(CallLogQuery.CACHED_NUMBER_TYPE); - info.label = c.getString(CallLogQuery.CACHED_NUMBER_LABEL); - String matchedNumber = c.getString(CallLogQuery.CACHED_MATCHED_NUMBER); - String postDialDigits = CompatUtils.isNCompatible() - ? c.getString(CallLogQuery.POST_DIAL_DIGITS) : ""; - info.number = (matchedNumber == null) ? - c.getString(CallLogQuery.NUMBER) + postDialDigits : matchedNumber; - - info.normalizedNumber = c.getString(CallLogQuery.CACHED_NORMALIZED_NUMBER); - info.photoId = c.getLong(CallLogQuery.CACHED_PHOTO_ID); - info.photoUri = DialerCompatUtils.isCallsCachedPhotoUriCompatible() ? - UriUtils.nullForNonContactsUri( - UriUtils.parseUriOrNull(c.getString(CallLogQuery.CACHED_PHOTO_URI))) - : null; - info.formattedNumber = c.getString(CallLogQuery.CACHED_FORMATTED_NUMBER); - - return info; - } - - /** - * Given a contact's sourceType, return true if the contact is a business - * - * @param sourceType sourceType of the contact. This is usually populated by - * {@link #mCachedNumberLookupService}. - */ - public boolean isBusiness(int sourceType) { - return mCachedNumberLookupService != null - && mCachedNumberLookupService.isBusiness(sourceType); - } - - /** - * This function looks at a contact's source and determines if the user can - * mark caller ids from this source as invalid. - * - * @param sourceType The source type to be checked - * @param objectId The ID of the Contact object. - * @return true if contacts from this source can be marked with an invalid caller id - */ - public boolean canReportAsInvalid(int sourceType, String objectId) { - return mCachedNumberLookupService != null - && mCachedNumberLookupService.canReportAsInvalid(sourceType, objectId); - } -} |