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