CallerInfo.java revision 2563a3ac05dd3cf8a07203ae682c243f2e793137
1/* 2 * Copyright (C) 2006 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.internal.telephony; 18 19import android.content.Context; 20import android.database.Cursor; 21import android.graphics.drawable.Drawable; 22import android.net.Uri; 23import android.provider.Contacts; 24import android.provider.Contacts.People; 25import android.provider.Contacts.Phones; 26import android.text.TextUtils; 27import android.telephony.TelephonyManager; 28import android.telephony.PhoneNumberUtils; 29import android.util.Config; 30import android.util.Log; 31 32/** 33 * Looks up caller information for the given phone number. 34 * 35 * {@hide} 36 */ 37public class CallerInfo { 38 private static final String TAG = "CallerInfo"; 39 40 public static final String UNKNOWN_NUMBER = "-1"; 41 public static final String PRIVATE_NUMBER = "-2"; 42 public static final String PAYPHONE_NUMBER = "-3"; 43 44 /** 45 * Please note that, any one of these member variables can be null, 46 * and any accesses to them should be prepared to handle such a case. 47 * 48 * Also, it is implied that phoneNumber is more often populated than 49 * name is, (think of calls being dialed/received using numbers where 50 * names are not known to the device), so phoneNumber should serve as 51 * a dependable fallback when name is unavailable. 52 * 53 * One other detail here is that this CallerInfo object reflects 54 * information found on a connection, it is an OUTPUT that serves 55 * mainly to display information to the user. In no way is this object 56 * used as input to make a connection, so we can choose to display 57 * whatever human-readable text makes sense to the user for a 58 * connection. This is especially relevant for the phone number field, 59 * since it is the one field that is most likely exposed to the user. 60 * 61 * As an example: 62 * 1. User dials "911" 63 * 2. Device recognizes that this is an emergency number 64 * 3. We use the "Emergency Number" string instead of "911" in the 65 * phoneNumber field. 66 * 67 * What we're really doing here is treating phoneNumber as an essential 68 * field here, NOT name. We're NOT always guaranteed to have a name 69 * for a connection, but the number should be displayable. 70 */ 71 public String name; 72 public String phoneNumber; 73 74 public String cnapName; 75 public int numberPresentation; 76 public int namePresentation; 77 public boolean contactExists; 78 79 public String phoneLabel; 80 /* Split up the phoneLabel into number type and label name */ 81 public int numberType; 82 public String numberLabel; 83 84 public int photoResource; 85 public long person_id; 86 public boolean needUpdate; 87 public Uri contactRefUri; 88 89 // fields to hold individual contact preference data, 90 // including the send to voicemail flag and the ringtone 91 // uri reference. 92 public Uri contactRingtoneUri; 93 public boolean shouldSendToVoicemail; 94 95 /** 96 * Drawable representing the caller image. This is essentially 97 * a cache for the image data tied into the connection / 98 * callerinfo object. The isCachedPhotoCurrent flag indicates 99 * if the image data needs to be reloaded. 100 */ 101 public Drawable cachedPhoto; 102 public boolean isCachedPhotoCurrent; 103 104 // Don't keep checking VM if it's going to throw an exception for this proc. 105 private static boolean sSkipVmCheck = false; 106 107 public CallerInfo() { 108 } 109 110 /** 111 * getCallerInfo given a Cursor. 112 * @param context the context used to retrieve string constants 113 * @param contactRef the URI to attach to this CallerInfo object 114 * @param cursor the first object in the cursor is used to build the CallerInfo object. 115 * @return the CallerInfo which contains the caller id for the given 116 * number. The returned CallerInfo is null if no number is supplied. 117 */ 118 public static CallerInfo getCallerInfo(Context context, Uri contactRef, Cursor cursor) { 119 120 CallerInfo info = new CallerInfo(); 121 info.photoResource = 0; 122 info.phoneLabel = null; 123 info.numberType = 0; 124 info.numberLabel = null; 125 info.cachedPhoto = null; 126 info.isCachedPhotoCurrent = false; 127 info.contactExists = false; 128 129 if (Config.LOGV) Log.v(TAG, "construct callerInfo from cursor"); 130 131 if (cursor != null) { 132 if (cursor.moveToFirst()) { 133 134 int columnIndex; 135 136 // Look for the name 137 columnIndex = cursor.getColumnIndex(People.NAME); 138 if (columnIndex != -1) { 139 info.name = cursor.getString(columnIndex); 140 } 141 142 // Look for the number 143 columnIndex = cursor.getColumnIndex(Phones.NUMBER); 144 if (columnIndex != -1) { 145 info.phoneNumber = cursor.getString(columnIndex); 146 } 147 148 // Look for the label/type combo 149 columnIndex = cursor.getColumnIndex(Phones.LABEL); 150 if (columnIndex != -1) { 151 int typeColumnIndex = cursor.getColumnIndex(Phones.TYPE); 152 if (typeColumnIndex != -1) { 153 info.numberType = cursor.getInt(typeColumnIndex); 154 info.numberLabel = cursor.getString(columnIndex); 155 info.phoneLabel = Contacts.Phones.getDisplayLabel(context, 156 info.numberType, info.numberLabel) 157 .toString(); 158 } 159 } 160 161 // Look for the person ID 162 columnIndex = cursor.getColumnIndex(Phones.PERSON_ID); 163 if (columnIndex != -1) { 164 info.person_id = cursor.getLong(columnIndex); 165 } else { 166 columnIndex = cursor.getColumnIndex(People._ID); 167 if (columnIndex != -1) { 168 info.person_id = cursor.getLong(columnIndex); 169 } 170 } 171 172 // look for the custom ringtone, create from the string stored 173 // in the database. 174 columnIndex = cursor.getColumnIndex(People.CUSTOM_RINGTONE); 175 if ((columnIndex != -1) && (cursor.getString(columnIndex) != null)) { 176 info.contactRingtoneUri = Uri.parse(cursor.getString(columnIndex)); 177 } else { 178 info.contactRingtoneUri = null; 179 } 180 181 // look for the send to voicemail flag, set it to true only 182 // under certain circumstances. 183 columnIndex = cursor.getColumnIndex(People.SEND_TO_VOICEMAIL); 184 info.shouldSendToVoicemail = (columnIndex != -1) && 185 ((cursor.getInt(columnIndex)) == 1); 186 info.contactExists = true; 187 } 188 cursor.close(); 189 } 190 191 info.needUpdate = false; 192 info.name = normalize(info.name); 193 info.contactRefUri = contactRef; 194 195 return info; 196 } 197 198 /** 199 * getCallerInfo given a URI, look up in the call-log database 200 * for the uri unique key. 201 * @param context the context used to get the ContentResolver 202 * @param contactRef the URI used to lookup caller id 203 * @return the CallerInfo which contains the caller id for the given 204 * number. The returned CallerInfo is null if no number is supplied. 205 */ 206 public static CallerInfo getCallerInfo(Context context, Uri contactRef) { 207 208 return getCallerInfo(context, contactRef, 209 context.getContentResolver().query(contactRef, null, null, null, null)); 210 } 211 212 /** 213 * getCallerInfo given a phone number, look up in the call-log database 214 * for the matching caller id info. 215 * @param context the context used to get the ContentResolver 216 * @param number the phone number used to lookup caller id 217 * @return the CallerInfo which contains the caller id for the given 218 * number. The returned CallerInfo is null if no number is supplied. If 219 * a matching number is not found, then a generic caller info is returned, 220 * with all relevant fields empty or null. 221 */ 222 public static CallerInfo getCallerInfo(Context context, String number) { 223 if (TextUtils.isEmpty(number)) { 224 return null; 225 } else { 226 // Change the callerInfo number ONLY if it is an emergency number 227 // or if it is the voicemail number. If it is either, take a 228 // shortcut and skip the query. 229 if (PhoneNumberUtils.isEmergencyNumber(number)) { 230 CallerInfo ci = new CallerInfo(); 231 232 // Note we're setting the phone number here (refer to javadoc 233 // comments at the top of CallerInfo class). 234 ci.phoneNumber = context.getString( 235 com.android.internal.R.string.emergency_call_dialog_number_for_display); 236 return ci; 237 } else { 238 try { 239 if (!sSkipVmCheck && PhoneNumberUtils.compare(number, 240 TelephonyManager.getDefault().getVoiceMailNumber())) { 241 CallerInfo ci = new CallerInfo(); 242 243 // Note we're setting the phone number here (refer to javadoc 244 // comments at the top of CallerInfo class). 245 ci.phoneNumber = TelephonyManager.getDefault().getVoiceMailAlphaTag(); 246 // TODO: FIND ANOTHER ICON 247 //info.photoResource = android.R.drawable.badge_voicemail; 248 return ci; 249 } 250 } catch (SecurityException ex) { 251 // Don't crash if this process doesn't have permission to 252 // retrieve VM number. It's still allowed to look up caller info. 253 // But don't try it again. 254 sSkipVmCheck = true; 255 } 256 } 257 } 258 259 Uri contactUri = Uri.withAppendedPath(Contacts.Phones.CONTENT_FILTER_URL, 260 Uri.encode(number)); 261 262 CallerInfo info = getCallerInfo(context, contactUri); 263 264 // if no query results were returned with a viable number, 265 // fill in the original number value we used to query with. 266 if (TextUtils.isEmpty(info.phoneNumber)) { 267 info.phoneNumber = number; 268 } 269 270 return info; 271 } 272 273 /** 274 * getCallerId: a convenience method to get the caller id for a given 275 * number. 276 * 277 * @param context the context used to get the ContentResolver. 278 * @param number a phone number. 279 * @return if the number belongs to a contact, the contact's name is 280 * returned; otherwise, the number itself is returned. 281 * 282 * TODO NOTE: This MAY need to refer to the Asynchronous Query API 283 * [startQuery()], instead of getCallerInfo, but since it looks like 284 * it is only being used by the provider calls in the messaging app: 285 * 1. android.provider.Telephony.Mms.getDisplayAddress() 286 * 2. android.provider.Telephony.Sms.getDisplayAddress() 287 * We may not need to make the change. 288 */ 289 public static String getCallerId(Context context, String number) { 290 CallerInfo info = getCallerInfo(context, number); 291 String callerID = null; 292 293 if (info != null) { 294 String name = info.name; 295 296 if (!TextUtils.isEmpty(name)) { 297 callerID = name; 298 } else { 299 callerID = number; 300 } 301 } 302 303 return callerID; 304 } 305 306 private static String normalize(String s) { 307 if (s == null || s.length() > 0) { 308 return s; 309 } else { 310 return null; 311 } 312 } 313} 314