OSDN Git Service

am e726495a: am fe5e7e92: Merge "docs: Fix issue with onCreate() method declaration...
[android-x86/frameworks-base.git] / core / java / android / provider / CallLog.java
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
17
18 package android.provider;
19
20 import android.content.ContentProvider;
21 import android.content.ContentResolver;
22 import android.content.ContentValues;
23 import android.content.Context;
24 import android.content.Intent;
25 import android.content.pm.UserInfo;
26 import android.database.Cursor;
27 import android.net.Uri;
28 import android.os.UserHandle;
29 import android.os.UserManager;
30 import android.provider.ContactsContract.CommonDataKinds.Callable;
31 import android.provider.ContactsContract.CommonDataKinds.Phone;
32 import android.provider.ContactsContract.DataUsageFeedback;
33 import android.telecom.PhoneAccountHandle;
34 import android.text.TextUtils;
35
36 import com.android.internal.telephony.CallerInfo;
37 import com.android.internal.telephony.PhoneConstants;
38
39 import java.util.List;
40
41 /**
42  * The CallLog provider contains information about placed and received calls.
43  */
44 public class CallLog {
45     public static final String AUTHORITY = "call_log";
46
47     /**
48      * The content:// style URL for this provider
49      */
50     public static final Uri CONTENT_URI =
51         Uri.parse("content://" + AUTHORITY);
52
53     /**
54      * Contains the recent calls.
55      */
56     public static class Calls implements BaseColumns {
57         /**
58          * The content:// style URL for this table
59          */
60         public static final Uri CONTENT_URI =
61                 Uri.parse("content://call_log/calls");
62
63         /**
64          * The content:// style URL for filtering this table on phone numbers
65          */
66         public static final Uri CONTENT_FILTER_URI =
67                 Uri.parse("content://call_log/calls/filter");
68
69         /**
70          * Query parameter used to limit the number of call logs returned.
71          * <p>
72          * TYPE: integer
73          */
74         public static final String LIMIT_PARAM_KEY = "limit";
75
76         /**
77          * Query parameter used to specify the starting record to return.
78          * <p>
79          * TYPE: integer
80          */
81         public static final String OFFSET_PARAM_KEY = "offset";
82
83         /**
84          * An optional URI parameter which instructs the provider to allow the operation to be
85          * applied to voicemail records as well.
86          * <p>
87          * TYPE: Boolean
88          * <p>
89          * Using this parameter with a value of {@code true} will result in a security error if the
90          * calling package does not have appropriate permissions to access voicemails.
91          *
92          * @hide
93          */
94         public static final String ALLOW_VOICEMAILS_PARAM_KEY = "allow_voicemails";
95
96         /**
97          * An optional extra used with {@link #CONTENT_TYPE Calls.CONTENT_TYPE} and
98          * {@link Intent#ACTION_VIEW} to specify that the presented list of calls should be
99          * filtered for a particular call type.
100          *
101          * Applications implementing a call log UI should check for this extra, and display a
102          * filtered list of calls based on the specified call type. If not applicable within the
103          * application's UI, it should be silently ignored.
104          *
105          * <p>
106          * The following example brings up the call log, showing only missed calls.
107          * <pre>
108          * Intent intent = new Intent(Intent.ACTION_VIEW);
109          * intent.setType(CallLog.Calls.CONTENT_TYPE);
110          * intent.putExtra(CallLog.Calls.EXTRA_CALL_TYPE_FILTER, CallLog.Calls.MISSED_TYPE);
111          * startActivity(intent);
112          * </pre>
113          * </p>
114          */
115         public static final String EXTRA_CALL_TYPE_FILTER =
116                 "android.provider.extra.CALL_TYPE_FILTER";
117
118         /**
119          * Content uri used to access call log entries, including voicemail records. You must have
120          * the READ_CALL_LOG and WRITE_CALL_LOG permissions to read and write to the call log, as
121          * well as READ_VOICEMAIL and WRITE_VOICEMAIL permissions to read and write voicemails.
122          */
123         public static final Uri CONTENT_URI_WITH_VOICEMAIL = CONTENT_URI.buildUpon()
124                 .appendQueryParameter(ALLOW_VOICEMAILS_PARAM_KEY, "true")
125                 .build();
126
127         /**
128          * The default sort order for this table
129          */
130         public static final String DEFAULT_SORT_ORDER = "date DESC";
131
132         /**
133          * The MIME type of {@link #CONTENT_URI} and {@link #CONTENT_FILTER_URI}
134          * providing a directory of calls.
135          */
136         public static final String CONTENT_TYPE = "vnd.android.cursor.dir/calls";
137
138         /**
139          * The MIME type of a {@link #CONTENT_URI} sub-directory of a single
140          * call.
141          */
142         public static final String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/calls";
143
144         /**
145          * The type of the call (incoming, outgoing or missed).
146          * <P>Type: INTEGER (int)</P>
147          */
148         public static final String TYPE = "type";
149
150         /** Call log type for incoming calls. */
151         public static final int INCOMING_TYPE = 1;
152         /** Call log type for outgoing calls. */
153         public static final int OUTGOING_TYPE = 2;
154         /** Call log type for missed calls. */
155         public static final int MISSED_TYPE = 3;
156         /** Call log type for voicemails. */
157         public static final int VOICEMAIL_TYPE = 4;
158
159         /**
160          * Bit-mask describing features of the call (e.g. video).
161          *
162          * <P>Type: INTEGER (int)</P>
163          */
164         public static final String FEATURES = "features";
165
166         /** Call had video. */
167         public static final int FEATURES_VIDEO = 0x1;
168
169         /**
170          * The phone number as the user entered it.
171          * <P>Type: TEXT</P>
172          */
173         public static final String NUMBER = "number";
174
175         /**
176          * The number presenting rules set by the network.
177          *
178          * <p>
179          * Allowed values:
180          * <ul>
181          * <li>{@link #PRESENTATION_ALLOWED}</li>
182          * <li>{@link #PRESENTATION_RESTRICTED}</li>
183          * <li>{@link #PRESENTATION_UNKNOWN}</li>
184          * <li>{@link #PRESENTATION_PAYPHONE}</li>
185          * </ul>
186          * </p>
187          *
188          * <P>Type: INTEGER</P>
189          */
190         public static final String NUMBER_PRESENTATION = "presentation";
191
192         /** Number is allowed to display for caller id. */
193         public static final int PRESENTATION_ALLOWED = 1;
194         /** Number is blocked by user. */
195         public static final int PRESENTATION_RESTRICTED = 2;
196         /** Number is not specified or unknown by network. */
197         public static final int PRESENTATION_UNKNOWN = 3;
198         /** Number is a pay phone. */
199         public static final int PRESENTATION_PAYPHONE = 4;
200
201         /**
202          * The ISO 3166-1 two letters country code of the country where the
203          * user received or made the call.
204          * <P>
205          * Type: TEXT
206          * </P>
207          */
208         public static final String COUNTRY_ISO = "countryiso";
209
210         /**
211          * The date the call occured, in milliseconds since the epoch
212          * <P>Type: INTEGER (long)</P>
213          */
214         public static final String DATE = "date";
215
216         /**
217          * The duration of the call in seconds
218          * <P>Type: INTEGER (long)</P>
219          */
220         public static final String DURATION = "duration";
221
222         /**
223          * The data usage of the call in bytes.
224          * <P>Type: INTEGER (long)</P>
225          */
226         public static final String DATA_USAGE = "data_usage";
227
228         /**
229          * Whether or not the call has been acknowledged
230          * <P>Type: INTEGER (boolean)</P>
231          */
232         public static final String NEW = "new";
233
234         /**
235          * The cached name associated with the phone number, if it exists.
236          * This value is not guaranteed to be current, if the contact information
237          * associated with this number has changed.
238          * <P>Type: TEXT</P>
239          */
240         public static final String CACHED_NAME = "name";
241
242         /**
243          * The cached number type (Home, Work, etc) associated with the
244          * phone number, if it exists.
245          * This value is not guaranteed to be current, if the contact information
246          * associated with this number has changed.
247          * <P>Type: INTEGER</P>
248          */
249         public static final String CACHED_NUMBER_TYPE = "numbertype";
250
251         /**
252          * The cached number label, for a custom number type, associated with the
253          * phone number, if it exists.
254          * This value is not guaranteed to be current, if the contact information
255          * associated with this number has changed.
256          * <P>Type: TEXT</P>
257          */
258         public static final String CACHED_NUMBER_LABEL = "numberlabel";
259
260         /**
261          * URI of the voicemail entry. Populated only for {@link #VOICEMAIL_TYPE}.
262          * <P>Type: TEXT</P>
263          */
264         public static final String VOICEMAIL_URI = "voicemail_uri";
265
266         /**
267          * Transcription of the call or voicemail entry. This will only be populated for call log
268          * entries of type {@link #VOICEMAIL_TYPE} that have valid transcriptions.
269          */
270         public static final String TRANSCRIPTION = "transcription";
271
272         /**
273          * Whether this item has been read or otherwise consumed by the user.
274          * <p>
275          * Unlike the {@link #NEW} field, which requires the user to have acknowledged the
276          * existence of the entry, this implies the user has interacted with the entry.
277          * <P>Type: INTEGER (boolean)</P>
278          */
279         public static final String IS_READ = "is_read";
280
281         /**
282          * A geocoded location for the number associated with this call.
283          * <p>
284          * The string represents a city, state, or country associated with the number.
285          * <P>Type: TEXT</P>
286          */
287         public static final String GEOCODED_LOCATION = "geocoded_location";
288
289         /**
290          * The cached URI to look up the contact associated with the phone number, if it exists.
291          * This value may not be current if the contact information associated with this number
292          * has changed.
293          * <P>Type: TEXT</P>
294          */
295         public static final String CACHED_LOOKUP_URI = "lookup_uri";
296
297         /**
298          * The cached phone number of the contact which matches this entry, if it exists.
299          * This value may not be current if the contact information associated with this number
300          * has changed.
301          * <P>Type: TEXT</P>
302          */
303         public static final String CACHED_MATCHED_NUMBER = "matched_number";
304
305         /**
306          * The cached normalized(E164) version of the phone number, if it exists.
307          * This value may not be current if the contact information associated with this number
308          * has changed.
309          * <P>Type: TEXT</P>
310          */
311         public static final String CACHED_NORMALIZED_NUMBER = "normalized_number";
312
313         /**
314          * The cached photo id of the picture associated with the phone number, if it exists.
315          * This value may not be current if the contact information associated with this number
316          * has changed.
317          * <P>Type: INTEGER (long)</P>
318          */
319         public static final String CACHED_PHOTO_ID = "photo_id";
320
321         /**
322          * The cached phone number, formatted with formatting rules based on the country the
323          * user was in when the call was made or received.
324          * This value is not guaranteed to be present, and may not be current if the contact
325          * information associated with this number
326          * has changed.
327          * <P>Type: TEXT</P>
328          */
329         public static final String CACHED_FORMATTED_NUMBER = "formatted_number";
330
331         // Note: PHONE_ACCOUNT_* constant values are "subscription_*" due to a historic naming
332         // that was encoded into call log databases.
333
334         /**
335          * The component name of the account in string form.
336          * <P>Type: TEXT</P>
337          */
338         public static final String PHONE_ACCOUNT_COMPONENT_NAME = "subscription_component_name";
339
340         /**
341          * The identifier of a account that is unique to a specified component.
342          * <P>Type: TEXT</P>
343          */
344         public static final String PHONE_ACCOUNT_ID = "subscription_id";
345
346         /**
347          * The identifier of a account that is unique to a specified component. Equivalent value
348          * to {@link #PHONE_ACCOUNT_ID}. For ContactsProvider internal use only.
349          * <P>Type: INTEGER</P>
350          *
351          * @hide
352          */
353         public static final String SUB_ID = "sub_id";
354
355         /**
356          * If a successful call is made that is longer than this duration, update the phone number
357          * in the ContactsProvider with the normalized version of the number, based on the user's
358          * current country code.
359          */
360         private static final int MIN_DURATION_FOR_NORMALIZED_NUMBER_UPDATE_MS = 1000 * 10;
361
362         /**
363          * Adds a call to the call log.
364          *
365          * @param ci the CallerInfo object to get the target contact from.  Can be null
366          * if the contact is unknown.
367          * @param context the context used to get the ContentResolver
368          * @param number the phone number to be added to the calls db
369          * @param presentation enum value from PhoneConstants.PRESENTATION_xxx, which
370          *        is set by the network and denotes the number presenting rules for
371          *        "allowed", "payphone", "restricted" or "unknown"
372          * @param callType enumerated values for "incoming", "outgoing", or "missed"
373          * @param features features of the call (e.g. Video).
374          * @param accountHandle The accountHandle object identifying the provider of the call
375          * @param start time stamp for the call in milliseconds
376          * @param duration call duration in seconds
377          * @param dataUsage data usage for the call in bytes, null if data usage was not tracked for
378          *                  the call.
379          * @result The URI of the call log entry belonging to the user that made or received this
380          *        call.
381          * {@hide}
382          */
383         public static Uri addCall(CallerInfo ci, Context context, String number,
384                 int presentation, int callType, int features, PhoneAccountHandle accountHandle,
385                 long start, int duration, Long dataUsage) {
386             // FIXME using -1 as subId instead of SubscriptionManager.INVALID_SUB_ID
387             return addCall(ci, context, number, presentation, callType, features, accountHandle,
388                     start, duration, dataUsage, false);
389         }
390
391
392         /**
393          * Adds a call to the call log.
394          *
395          * @param ci the CallerInfo object to get the target contact from.  Can be null
396          * if the contact is unknown.
397          * @param context the context used to get the ContentResolver
398          * @param number the phone number to be added to the calls db
399          * @param presentation enum value from PhoneConstants.PRESENTATION_xxx, which
400          *        is set by the network and denotes the number presenting rules for
401          *        "allowed", "payphone", "restricted" or "unknown"
402          * @param callType enumerated values for "incoming", "outgoing", or "missed"
403          * @param features features of the call (e.g. Video).
404          * @param accountHandle The accountHandle object identifying the provider of the call
405          * @param start time stamp for the call in milliseconds
406          * @param duration call duration in seconds
407          * @param subId the subscription id.
408          * @param dataUsage data usage for the call in bytes, null if data usage was not tracked for
409          *                  the call.
410          * @param addForAllUsers If true, the call is added to the call log of all currently
411          *        running users. The caller must have the MANAGE_USERS permission if this is true.
412          *
413          * @result The URI of the call log entry belonging to the user that made or received this
414          *        call.
415          * {@hide}
416          */
417         public static Uri addCall(CallerInfo ci, Context context, String number,
418                 int presentation, int callType, int features, PhoneAccountHandle accountHandle,
419                 long start, int duration, Long dataUsage, boolean addForAllUsers) {
420             final ContentResolver resolver = context.getContentResolver();
421             int numberPresentation = PRESENTATION_ALLOWED;
422
423             // Remap network specified number presentation types
424             // PhoneConstants.PRESENTATION_xxx to calllog number presentation types
425             // Calls.PRESENTATION_xxx, in order to insulate the persistent calllog
426             // from any future radio changes.
427             // If the number field is empty set the presentation type to Unknown.
428             if (presentation == PhoneConstants.PRESENTATION_RESTRICTED) {
429                 numberPresentation = PRESENTATION_RESTRICTED;
430             } else if (presentation == PhoneConstants.PRESENTATION_PAYPHONE) {
431                 numberPresentation = PRESENTATION_PAYPHONE;
432             } else if (TextUtils.isEmpty(number)
433                     || presentation == PhoneConstants.PRESENTATION_UNKNOWN) {
434                 numberPresentation = PRESENTATION_UNKNOWN;
435             }
436             if (numberPresentation != PRESENTATION_ALLOWED) {
437                 number = "";
438                 if (ci != null) {
439                     ci.name = "";
440                 }
441             }
442
443             // accountHandle information
444             String accountComponentString = null;
445             String accountId = null;
446             if (accountHandle != null) {
447                 accountComponentString = accountHandle.getComponentName().flattenToString();
448                 accountId = accountHandle.getId();
449             }
450
451             ContentValues values = new ContentValues(6);
452
453             values.put(NUMBER, number);
454             values.put(NUMBER_PRESENTATION, Integer.valueOf(numberPresentation));
455             values.put(TYPE, Integer.valueOf(callType));
456             values.put(FEATURES, features);
457             values.put(DATE, Long.valueOf(start));
458             values.put(DURATION, Long.valueOf(duration));
459             if (dataUsage != null) {
460                 values.put(DATA_USAGE, dataUsage);
461             }
462             values.put(PHONE_ACCOUNT_COMPONENT_NAME, accountComponentString);
463             values.put(PHONE_ACCOUNT_ID, accountId);
464             values.put(NEW, Integer.valueOf(1));
465
466             if (callType == MISSED_TYPE) {
467                 values.put(IS_READ, Integer.valueOf(0));
468             }
469             if (ci != null) {
470                 values.put(CACHED_NAME, ci.name);
471                 values.put(CACHED_NUMBER_TYPE, ci.numberType);
472                 values.put(CACHED_NUMBER_LABEL, ci.numberLabel);
473             }
474
475             if ((ci != null) && (ci.contactIdOrZero > 0)) {
476                 // Update usage information for the number associated with the contact ID.
477                 // We need to use both the number and the ID for obtaining a data ID since other
478                 // contacts may have the same number.
479
480                 final Cursor cursor;
481
482                 // We should prefer normalized one (probably coming from
483                 // Phone.NORMALIZED_NUMBER column) first. If it isn't available try others.
484                 if (ci.normalizedNumber != null) {
485                     final String normalizedPhoneNumber = ci.normalizedNumber;
486                     cursor = resolver.query(Phone.CONTENT_URI,
487                             new String[] { Phone._ID },
488                             Phone.CONTACT_ID + " =? AND " + Phone.NORMALIZED_NUMBER + " =?",
489                             new String[] { String.valueOf(ci.contactIdOrZero),
490                                     normalizedPhoneNumber},
491                             null);
492                 } else {
493                     final String phoneNumber = ci.phoneNumber != null ? ci.phoneNumber : number;
494                     cursor = resolver.query(
495                             Uri.withAppendedPath(Callable.CONTENT_FILTER_URI,
496                                     Uri.encode(phoneNumber)),
497                             new String[] { Phone._ID },
498                             Phone.CONTACT_ID + " =?",
499                             new String[] { String.valueOf(ci.contactIdOrZero) },
500                             null);
501                 }
502
503                 if (cursor != null) {
504                     try {
505                         if (cursor.getCount() > 0 && cursor.moveToFirst()) {
506                             final Uri feedbackUri = DataUsageFeedback.FEEDBACK_URI.buildUpon()
507                                     .appendPath(cursor.getString(0))
508                                     .appendQueryParameter(DataUsageFeedback.USAGE_TYPE,
509                                                 DataUsageFeedback.USAGE_TYPE_CALL)
510                                     .build();
511                             resolver.update(feedbackUri, new ContentValues(), null, null);
512                         }
513                     } finally {
514                         cursor.close();
515                     }
516                 }
517             }
518
519             Uri result = null;
520
521             if (addForAllUsers) {
522                 // Insert the entry for all currently running users, in order to trigger any
523                 // ContentObservers currently set on the call log.
524                 final UserManager userManager = (UserManager) context.getSystemService(
525                         Context.USER_SERVICE);
526                 List<UserInfo> users = userManager.getUsers(true);
527                 final int currentUserId = userManager.getUserHandle();
528                 final int count = users.size();
529                 for (int i = 0; i < count; i++) {
530                     final UserInfo user = users.get(i);
531                     final UserHandle userHandle = user.getUserHandle();
532                     if (userManager.isUserRunning(userHandle)
533                             && !userManager.hasUserRestriction(UserManager.DISALLOW_OUTGOING_CALLS,
534                                     userHandle)
535                             && !user.isManagedProfile()) {
536                         Uri uri = addEntryAndRemoveExpiredEntries(context,
537                                 ContentProvider.maybeAddUserId(CONTENT_URI, user.id), values);
538                         if (user.id == currentUserId) {
539                             result = uri;
540                         }
541                     }
542                 }
543             } else {
544                 result = addEntryAndRemoveExpiredEntries(context, CONTENT_URI, values);
545             }
546
547             return result;
548         }
549
550         /**
551          * Query the call log database for the last dialed number.
552          * @param context Used to get the content resolver.
553          * @return The last phone number dialed (outgoing) or an empty
554          * string if none exist yet.
555          */
556         public static String getLastOutgoingCall(Context context) {
557             final ContentResolver resolver = context.getContentResolver();
558             Cursor c = null;
559             try {
560                 c = resolver.query(
561                     CONTENT_URI,
562                     new String[] {NUMBER},
563                     TYPE + " = " + OUTGOING_TYPE,
564                     null,
565                     DEFAULT_SORT_ORDER + " LIMIT 1");
566                 if (c == null || !c.moveToFirst()) {
567                     return "";
568                 }
569                 return c.getString(0);
570             } finally {
571                 if (c != null) c.close();
572             }
573         }
574
575         private static Uri addEntryAndRemoveExpiredEntries(Context context, Uri uri,
576                 ContentValues values) {
577             final ContentResolver resolver = context.getContentResolver();
578             Uri result = resolver.insert(uri, values);
579             resolver.delete(uri, "_id IN " +
580                     "(SELECT _id FROM calls ORDER BY " + DEFAULT_SORT_ORDER
581                     + " LIMIT -1 OFFSET 500)", null);
582             return result;
583         }
584     }
585 }