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