CallLog.java revision 9ef78f00d2950ab7f31a22beaa54bf6ad4206886
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 android.provider; 18 19import com.android.internal.telephony.CallerInfo; 20import com.android.internal.telephony.Connection; 21 22import android.content.ContentResolver; 23import android.content.ContentValues; 24import android.content.Context; 25import android.database.Cursor; 26import android.net.Uri; 27import android.provider.ContactsContract.CommonDataKinds.Phone; 28import android.provider.ContactsContract.DataUsageFeedback; 29import android.text.TextUtils; 30 31/** 32 * The CallLog provider contains information about placed and received calls. 33 */ 34public class CallLog { 35 public static final String AUTHORITY = "call_log"; 36 37 /** 38 * The content:// style URL for this provider 39 */ 40 public static final Uri CONTENT_URI = 41 Uri.parse("content://" + AUTHORITY); 42 43 /** 44 * Contains the recent calls. 45 */ 46 public static class Calls implements BaseColumns { 47 /** 48 * The content:// style URL for this table 49 */ 50 public static final Uri CONTENT_URI = 51 Uri.parse("content://call_log/calls"); 52 53 /** 54 * The content:// style URL for filtering this table on phone numbers 55 */ 56 public static final Uri CONTENT_FILTER_URI = 57 Uri.parse("content://call_log/calls/filter"); 58 59 /** 60 * An optional URI parameter which instructs the provider to allow the operation to be 61 * applied to voicemail records as well. 62 * <p> 63 * TYPE: Boolean 64 * <p> 65 * Using this parameter with a value of {@code true} will result in a security error if the 66 * calling package does not have appropriate permissions to access voicemails. 67 * 68 * @hide 69 */ 70 public static final String ALLOW_VOICEMAILS_PARAM_KEY = "allow_voicemails"; 71 72 /** 73 * Content uri with {@link #ALLOW_VOICEMAILS_PARAM_KEY} set. This can directly be used to 74 * access call log entries that includes voicemail records. 75 * 76 * @hide 77 */ 78 public static final Uri CONTENT_URI_WITH_VOICEMAIL = CONTENT_URI.buildUpon() 79 .appendQueryParameter(ALLOW_VOICEMAILS_PARAM_KEY, "true") 80 .build(); 81 82 /** 83 * The default sort order for this table 84 */ 85 public static final String DEFAULT_SORT_ORDER = "date DESC"; 86 87 /** 88 * The MIME type of {@link #CONTENT_URI} and {@link #CONTENT_FILTER_URI} 89 * providing a directory of calls. 90 */ 91 public static final String CONTENT_TYPE = "vnd.android.cursor.dir/calls"; 92 93 /** 94 * The MIME type of a {@link #CONTENT_URI} sub-directory of a single 95 * call. 96 */ 97 public static final String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/calls"; 98 99 /** 100 * The type of the call (incoming, outgoing or missed). 101 * <P>Type: INTEGER (int)</P> 102 */ 103 public static final String TYPE = "type"; 104 105 /** Call log type for incoming calls. */ 106 public static final int INCOMING_TYPE = 1; 107 /** Call log type for outgoing calls. */ 108 public static final int OUTGOING_TYPE = 2; 109 /** Call log type for missed calls. */ 110 public static final int MISSED_TYPE = 3; 111 /** 112 * Call log type for voicemails. 113 * @hide 114 */ 115 public static final int VOICEMAIL_TYPE = 4; 116 117 /** 118 * The phone number as the user entered it. 119 * <P>Type: TEXT</P> 120 */ 121 public static final String NUMBER = "number"; 122 123 /** 124 * The ISO 3166-1 two letters country code of the country where the 125 * user received or made the call. 126 * <P> 127 * Type: TEXT 128 * </P> 129 * 130 * @hide 131 */ 132 public static final String COUNTRY_ISO = "countryiso"; 133 134 /** 135 * The date the call occured, in milliseconds since the epoch 136 * <P>Type: INTEGER (long)</P> 137 */ 138 public static final String DATE = "date"; 139 140 /** 141 * The duration of the call in seconds 142 * <P>Type: INTEGER (long)</P> 143 */ 144 public static final String DURATION = "duration"; 145 146 /** 147 * Whether or not the call has been acknowledged 148 * <P>Type: INTEGER (boolean)</P> 149 */ 150 public static final String NEW = "new"; 151 152 /** 153 * The cached name associated with the phone number, if it exists. 154 * This value is not guaranteed to be current, if the contact information 155 * associated with this number has changed. 156 * <P>Type: TEXT</P> 157 */ 158 public static final String CACHED_NAME = "name"; 159 160 /** 161 * The cached number type (Home, Work, etc) associated with the 162 * phone number, if it exists. 163 * This value is not guaranteed to be current, if the contact information 164 * associated with this number has changed. 165 * <P>Type: INTEGER</P> 166 */ 167 public static final String CACHED_NUMBER_TYPE = "numbertype"; 168 169 /** 170 * The cached number label, for a custom number type, associated with the 171 * phone number, if it exists. 172 * This value is not guaranteed to be current, if the contact information 173 * associated with this number has changed. 174 * <P>Type: TEXT</P> 175 */ 176 public static final String CACHED_NUMBER_LABEL = "numberlabel"; 177 178 /** 179 * URI of the voicemail entry. Populated only for {@link #VOICEMAIL_TYPE}. 180 * <P>Type: TEXT</P> 181 * @hide 182 */ 183 public static final String VOICEMAIL_URI = "voicemail_uri"; 184 185 /** 186 * Adds a call to the call log. 187 * 188 * @param ci the CallerInfo object to get the target contact from. Can be null 189 * if the contact is unknown. 190 * @param context the context used to get the ContentResolver 191 * @param number the phone number to be added to the calls db 192 * @param presentation the number presenting rules set by the network for 193 * "allowed", "payphone", "restricted" or "unknown" 194 * @param callType enumerated values for "incoming", "outgoing", or "missed" 195 * @param start time stamp for the call in milliseconds 196 * @param duration call duration in seconds 197 * 198 * {@hide} 199 */ 200 public static Uri addCall(CallerInfo ci, Context context, String number, 201 int presentation, int callType, long start, int duration) { 202 final ContentResolver resolver = context.getContentResolver(); 203 204 // If this is a private number then set the number to Private, otherwise check 205 // if the number field is empty and set the number to Unavailable 206 if (presentation == Connection.PRESENTATION_RESTRICTED) { 207 number = CallerInfo.PRIVATE_NUMBER; 208 if (ci != null) ci.name = ""; 209 } else if (presentation == Connection.PRESENTATION_PAYPHONE) { 210 number = CallerInfo.PAYPHONE_NUMBER; 211 if (ci != null) ci.name = ""; 212 } else if (TextUtils.isEmpty(number) 213 || presentation == Connection.PRESENTATION_UNKNOWN) { 214 number = CallerInfo.UNKNOWN_NUMBER; 215 if (ci != null) ci.name = ""; 216 } 217 218 ContentValues values = new ContentValues(5); 219 220 values.put(NUMBER, number); 221 values.put(TYPE, Integer.valueOf(callType)); 222 values.put(DATE, Long.valueOf(start)); 223 values.put(DURATION, Long.valueOf(duration)); 224 values.put(NEW, Integer.valueOf(1)); 225 if (ci != null) { 226 values.put(CACHED_NAME, ci.name); 227 values.put(CACHED_NUMBER_TYPE, ci.numberType); 228 values.put(CACHED_NUMBER_LABEL, ci.numberLabel); 229 } 230 231 if ((ci != null) && (ci.person_id > 0)) { 232 // Update usage information for the number associated with the contact ID. 233 // We need to use both the number and the ID for obtaining a data ID since other 234 // contacts may have the same number. 235 236 final Cursor cursor; 237 238 // We should prefer normalized one (probably coming from 239 // Phone.NORMALIZED_NUMBER column) first. If it isn't available try others. 240 if (ci.normalizedNumber != null) { 241 final String normalizedPhoneNumber = ci.normalizedNumber; 242 cursor = resolver.query(Phone.CONTENT_URI, 243 new String[] { Phone._ID }, 244 Phone.CONTACT_ID + " =? AND " + Phone.NORMALIZED_NUMBER + " =?", 245 new String[] { String.valueOf(ci.person_id), normalizedPhoneNumber}, 246 null); 247 } else { 248 final String phoneNumber = ci.phoneNumber != null ? ci.phoneNumber : number; 249 cursor = resolver.query(Phone.CONTENT_URI, 250 new String[] { Phone._ID }, 251 Phone.CONTACT_ID + " =? AND " + Phone.NUMBER + " =?", 252 new String[] { String.valueOf(ci.person_id), phoneNumber}, 253 null); 254 } 255 256 if (cursor != null) { 257 try { 258 if (cursor.getCount() > 0 && cursor.moveToFirst()) { 259 final Uri feedbackUri = DataUsageFeedback.FEEDBACK_URI.buildUpon() 260 .appendPath(cursor.getString(0)) 261 .appendQueryParameter(DataUsageFeedback.USAGE_TYPE, 262 DataUsageFeedback.USAGE_TYPE_CALL) 263 .build(); 264 resolver.update(feedbackUri, new ContentValues(), null, null); 265 } 266 } finally { 267 cursor.close(); 268 } 269 } 270 } 271 272 Uri result = resolver.insert(CONTENT_URI, values); 273 274 removeExpiredEntries(context); 275 276 return result; 277 } 278 279 /** 280 * Query the call log database for the last dialed number. 281 * @param context Used to get the content resolver. 282 * @return The last phone number dialed (outgoing) or an empty 283 * string if none exist yet. 284 */ 285 public static String getLastOutgoingCall(Context context) { 286 final ContentResolver resolver = context.getContentResolver(); 287 Cursor c = null; 288 try { 289 c = resolver.query( 290 CONTENT_URI, 291 new String[] {NUMBER}, 292 TYPE + " = " + OUTGOING_TYPE, 293 null, 294 DEFAULT_SORT_ORDER + " LIMIT 1"); 295 if (c == null || !c.moveToFirst()) { 296 return ""; 297 } 298 return c.getString(0); 299 } finally { 300 if (c != null) c.close(); 301 } 302 } 303 304 private static void removeExpiredEntries(Context context) { 305 final ContentResolver resolver = context.getContentResolver(); 306 resolver.delete(CONTENT_URI, "_id IN " + 307 "(SELECT _id FROM calls ORDER BY " + DEFAULT_SORT_ORDER 308 + " LIMIT -1 OFFSET 500)", null); 309 } 310 } 311} 312