ContactInfoHelper.java revision 034a2b329e469bf6888fbbcf91992f974015c2a8
1/* 2 * Copyright (C) 2011 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17package com.android.dialer.calllog; 18 19import android.content.Context; 20import android.database.Cursor; 21import android.net.Uri; 22import android.provider.ContactsContract.Contacts; 23import android.provider.ContactsContract.PhoneLookup; 24import android.telephony.PhoneNumberUtils; 25import android.text.TextUtils; 26 27import com.android.contacts.common.util.UriUtils; 28import com.android.dialer.service.CachedNumberLookupService; 29import com.android.dialerbind.ServiceFactory; 30 31/** 32 * Utility class to look up the contact information for a given number. 33 */ 34public class ContactInfoHelper { 35 private final Context mContext; 36 private final String mCurrentCountryIso; 37 38 private static final CachedNumberLookupService mCachedNumberLookupService = 39 ServiceFactory.newCachedNumberLookupService(); 40 41 public ContactInfoHelper(Context context, String currentCountryIso) { 42 mContext = context; 43 mCurrentCountryIso = currentCountryIso; 44 } 45 46 /** 47 * Returns the contact information for the given number. 48 * <p> 49 * If the number does not match any contact, returns a contact info containing only the number 50 * and the formatted number. 51 * <p> 52 * If an error occurs during the lookup, it returns null. 53 * 54 * @param number the number to look up 55 * @param countryIso the country associated with this number 56 */ 57 public ContactInfo lookupNumber(String number, String countryIso) { 58 final ContactInfo info; 59 60 // Determine the contact info. 61 if (PhoneNumberUtils.isUriNumber(number)) { 62 // This "number" is really a SIP address. 63 ContactInfo sipInfo = queryContactInfoForSipAddress(number); 64 if (sipInfo == null || sipInfo == ContactInfo.EMPTY) { 65 // Check whether the "username" part of the SIP address is 66 // actually the phone number of a contact. 67 String username = PhoneNumberUtils.getUsernameFromUriNumber(number); 68 if (PhoneNumberUtils.isGlobalPhoneNumber(username)) { 69 sipInfo = queryContactInfoForPhoneNumber(username, countryIso); 70 } 71 } 72 info = sipInfo; 73 } else { 74 // Look for a contact that has the given phone number. 75 ContactInfo phoneInfo = queryContactInfoForPhoneNumber(number, countryIso); 76 77 if (phoneInfo == null || phoneInfo == ContactInfo.EMPTY) { 78 // Check whether the phone number has been saved as an "Internet call" number. 79 phoneInfo = queryContactInfoForSipAddress(number); 80 } 81 info = phoneInfo; 82 } 83 84 final ContactInfo updatedInfo; 85 if (info == null) { 86 // The lookup failed. 87 updatedInfo = null; 88 } else { 89 // If we did not find a matching contact, generate an empty contact info for the number. 90 if (info == ContactInfo.EMPTY) { 91 // Did not find a matching contact. 92 updatedInfo = new ContactInfo(); 93 updatedInfo.number = number; 94 updatedInfo.formattedNumber = formatPhoneNumber(number, null, countryIso); 95 } else { 96 updatedInfo = info; 97 } 98 } 99 return updatedInfo; 100 } 101 102 /** 103 * Looks up a contact using the given URI. 104 * <p> 105 * It returns null if an error occurs, {@link ContactInfo#EMPTY} if no matching contact is 106 * found, or the {@link ContactInfo} for the given contact. 107 * <p> 108 * The {@link ContactInfo#formattedNumber} field is always set to {@code null} in the returned 109 * value. 110 */ 111 private ContactInfo lookupContactFromUri(Uri uri) { 112 final ContactInfo info; 113 Cursor phonesCursor = 114 mContext.getContentResolver().query( 115 uri, PhoneQuery._PROJECTION, null, null, null); 116 117 if (phonesCursor != null) { 118 try { 119 if (phonesCursor.moveToFirst()) { 120 info = new ContactInfo(); 121 long contactId = phonesCursor.getLong(PhoneQuery.PERSON_ID); 122 String lookupKey = phonesCursor.getString(PhoneQuery.LOOKUP_KEY); 123 info.lookupUri = Contacts.getLookupUri(contactId, lookupKey); 124 info.name = phonesCursor.getString(PhoneQuery.NAME); 125 info.type = phonesCursor.getInt(PhoneQuery.PHONE_TYPE); 126 info.label = phonesCursor.getString(PhoneQuery.LABEL); 127 info.number = phonesCursor.getString(PhoneQuery.MATCHED_NUMBER); 128 info.normalizedNumber = phonesCursor.getString(PhoneQuery.NORMALIZED_NUMBER); 129 info.photoId = phonesCursor.getLong(PhoneQuery.PHOTO_ID); 130 info.photoUri = 131 UriUtils.parseUriOrNull(phonesCursor.getString(PhoneQuery.PHOTO_URI)); 132 info.formattedNumber = null; 133 } else { 134 info = ContactInfo.EMPTY; 135 } 136 } finally { 137 phonesCursor.close(); 138 } 139 } else { 140 // Failed to fetch the data, ignore this request. 141 info = null; 142 } 143 return info; 144 } 145 146 /** 147 * Determines the contact information for the given SIP address. 148 * <p> 149 * It returns the contact info if found. 150 * <p> 151 * If no contact corresponds to the given SIP address, returns {@link ContactInfo#EMPTY}. 152 * <p> 153 * If the lookup fails for some other reason, it returns null. 154 */ 155 private ContactInfo queryContactInfoForSipAddress(String sipAddress) { 156 final ContactInfo info; 157 158 // "contactNumber" is a SIP address, so use the PhoneLookup table with the SIP parameter. 159 Uri.Builder uriBuilder = PhoneLookup.CONTENT_FILTER_URI.buildUpon(); 160 uriBuilder.appendPath(Uri.encode(sipAddress)); 161 uriBuilder.appendQueryParameter(PhoneLookup.QUERY_PARAMETER_SIP_ADDRESS, "1"); 162 return lookupContactFromUri(uriBuilder.build()); 163 } 164 165 /** 166 * Determines the contact information for the given phone number. 167 * <p> 168 * It returns the contact info if found. 169 * <p> 170 * If no contact corresponds to the given phone number, returns {@link ContactInfo#EMPTY}. 171 * <p> 172 * If the lookup fails for some other reason, it returns null. 173 */ 174 private ContactInfo queryContactInfoForPhoneNumber(String number, String countryIso) { 175 String contactNumber = number; 176 if (!TextUtils.isEmpty(countryIso)) { 177 // Normalize the number: this is needed because the PhoneLookup query below does not 178 // accept a country code as an input. 179 String numberE164 = PhoneNumberUtils.formatNumberToE164(number, countryIso); 180 if (!TextUtils.isEmpty(numberE164)) { 181 // Only use it if the number could be formatted to E164. 182 contactNumber = numberE164; 183 } 184 } 185 186 // The "contactNumber" is a regular phone number, so use the PhoneLookup table. 187 Uri uri = Uri.withAppendedPath(PhoneLookup.CONTENT_FILTER_URI, Uri.encode(contactNumber)); 188 ContactInfo info = lookupContactFromUri(uri); 189 if (info != null && info != ContactInfo.EMPTY) { 190 info.formattedNumber = formatPhoneNumber(number, null, countryIso); 191 } else if (mCachedNumberLookupService != null) { 192 info = mCachedNumberLookupService.lookupCachedContactFromNumber(mContext, number); 193 } 194 return info; 195 } 196 197 /** 198 * Format the given phone number 199 * 200 * @param number the number to be formatted. 201 * @param normalizedNumber the normalized number of the given number. 202 * @param countryIso the ISO 3166-1 two letters country code, the country's 203 * convention will be used to format the number if the normalized 204 * phone is null. 205 * 206 * @return the formatted number, or the given number if it was formatted. 207 */ 208 private String formatPhoneNumber(String number, String normalizedNumber, 209 String countryIso) { 210 if (TextUtils.isEmpty(number)) { 211 return ""; 212 } 213 // If "number" is really a SIP address, don't try to do any formatting at all. 214 if (PhoneNumberUtils.isUriNumber(number)) { 215 return number; 216 } 217 if (TextUtils.isEmpty(countryIso)) { 218 countryIso = mCurrentCountryIso; 219 } 220 return PhoneNumberUtils.formatNumber(number, normalizedNumber, countryIso); 221 } 222} 223