CallLog.java revision af7b8c0a67f1f416e9156c375a940a47389ab838
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
18package android.provider;
19
20import android.content.ContentProvider;
21import android.content.ContentResolver;
22import android.content.ContentValues;
23import android.content.Context;
24import android.content.Intent;
25import android.content.pm.UserInfo;
26import android.database.Cursor;
27import android.location.Country;
28import android.location.CountryDetector;
29import android.net.Uri;
30import android.os.UserHandle;
31import android.os.UserManager;
32import android.provider.ContactsContract.CommonDataKinds.Callable;
33import android.provider.ContactsContract.CommonDataKinds.Phone;
34import android.provider.ContactsContract.Data;
35import android.provider.ContactsContract.DataUsageFeedback;
36import android.telecom.PhoneAccount;
37import android.telecom.PhoneAccountHandle;
38import android.telecom.TelecomManager;
39import android.telephony.PhoneNumberUtils;
40import android.text.TextUtils;
41import android.util.Log;
42
43import com.android.internal.telephony.CallerInfo;
44import com.android.internal.telephony.PhoneConstants;
45
46import java.util.List;
47
48/**
49 * The CallLog provider contains information about placed and received calls.
50 */
51public class CallLog {
52    private static final String LOG_TAG = "CallLog";
53    private static final boolean VERBOSE_LOG = false; // DON'T SUBMIT WITH TRUE.
54
55    public static final String AUTHORITY = "call_log";
56
57    /**
58     * The content:// style URL for this provider
59     */
60    public static final Uri CONTENT_URI =
61        Uri.parse("content://" + AUTHORITY);
62
63
64    /**
65     * The "shadow" provider stores calllog when the real calllog provider is encrypted.  The
66     * real provider will alter copy from it when it starts, and remove the entries in the shadow.
67     *
68     * <p>See the comment in {@link Calls#addCall} for the details.
69     *
70     * @hide
71     */
72    public static final String SHADOW_AUTHORITY = "call_log_shadow";
73
74    /**
75     * Contains the recent calls.
76     */
77    public static class Calls implements BaseColumns {
78        /**
79         * The content:// style URL for this table
80         */
81        public static final Uri CONTENT_URI =
82                Uri.parse("content://call_log/calls");
83
84        /** @hide */
85        public static final Uri SHADOW_CONTENT_URI =
86                Uri.parse("content://call_log_shadow/calls");
87
88        /**
89         * The content:// style URL for filtering this table on phone numbers
90         */
91        public static final Uri CONTENT_FILTER_URI =
92                Uri.parse("content://call_log/calls/filter");
93
94        /**
95         * Query parameter used to limit the number of call logs returned.
96         * <p>
97         * TYPE: integer
98         */
99        public static final String LIMIT_PARAM_KEY = "limit";
100
101        /**
102         * Query parameter used to specify the starting record to return.
103         * <p>
104         * TYPE: integer
105         */
106        public static final String OFFSET_PARAM_KEY = "offset";
107
108        /**
109         * An optional URI parameter which instructs the provider to allow the operation to be
110         * applied to voicemail records as well.
111         * <p>
112         * TYPE: Boolean
113         * <p>
114         * Using this parameter with a value of {@code true} will result in a security error if the
115         * calling package does not have appropriate permissions to access voicemails.
116         *
117         * @hide
118         */
119        public static final String ALLOW_VOICEMAILS_PARAM_KEY = "allow_voicemails";
120
121        /**
122         * An optional extra used with {@link #CONTENT_TYPE Calls.CONTENT_TYPE} and
123         * {@link Intent#ACTION_VIEW} to specify that the presented list of calls should be
124         * filtered for a particular call type.
125         *
126         * Applications implementing a call log UI should check for this extra, and display a
127         * filtered list of calls based on the specified call type. If not applicable within the
128         * application's UI, it should be silently ignored.
129         *
130         * <p>
131         * The following example brings up the call log, showing only missed calls.
132         * <pre>
133         * Intent intent = new Intent(Intent.ACTION_VIEW);
134         * intent.setType(CallLog.Calls.CONTENT_TYPE);
135         * intent.putExtra(CallLog.Calls.EXTRA_CALL_TYPE_FILTER, CallLog.Calls.MISSED_TYPE);
136         * startActivity(intent);
137         * </pre>
138         * </p>
139         */
140        public static final String EXTRA_CALL_TYPE_FILTER =
141                "android.provider.extra.CALL_TYPE_FILTER";
142
143        /**
144         * Content uri used to access call log entries, including voicemail records. You must have
145         * the READ_CALL_LOG and WRITE_CALL_LOG permissions to read and write to the call log, as
146         * well as READ_VOICEMAIL and WRITE_VOICEMAIL permissions to read and write voicemails.
147         */
148        public static final Uri CONTENT_URI_WITH_VOICEMAIL = CONTENT_URI.buildUpon()
149                .appendQueryParameter(ALLOW_VOICEMAILS_PARAM_KEY, "true")
150                .build();
151
152        /**
153         * The default sort order for this table
154         */
155        public static final String DEFAULT_SORT_ORDER = "date DESC";
156
157        /**
158         * The MIME type of {@link #CONTENT_URI} and {@link #CONTENT_FILTER_URI}
159         * providing a directory of calls.
160         */
161        public static final String CONTENT_TYPE = "vnd.android.cursor.dir/calls";
162
163        /**
164         * The MIME type of a {@link #CONTENT_URI} sub-directory of a single
165         * call.
166         */
167        public static final String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/calls";
168
169        /**
170         * The type of the call (incoming, outgoing or missed).
171         * <P>Type: INTEGER (int)</P>
172         *
173         * <p>
174         * Allowed values:
175         * <ul>
176         * <li>{@link #INCOMING_TYPE}</li>
177         * <li>{@link #OUTGOING_TYPE}</li>
178         * <li>{@link #MISSED_TYPE}</li>
179         * <li>{@link #VOICEMAIL_TYPE}</li>
180         * <li>{@link #REJECTED_TYPE}</li>
181         * <li>{@link #BLOCKED_TYPE}</li>
182         * <li>{@link #ANSWERED_EXTERNALLY_TYPE}</li>
183         * </ul>
184         * </p>
185         */
186        public static final String TYPE = "type";
187
188        /** Call log type for incoming calls. */
189        public static final int INCOMING_TYPE = 1;
190        /** Call log type for outgoing calls. */
191        public static final int OUTGOING_TYPE = 2;
192        /** Call log type for missed calls. */
193        public static final int MISSED_TYPE = 3;
194        /** Call log type for voicemails. */
195        public static final int VOICEMAIL_TYPE = 4;
196        /** Call log type for calls rejected by direct user action. */
197        public static final int REJECTED_TYPE = 5;
198        /** Call log type for calls blocked automatically. */
199        public static final int BLOCKED_TYPE = 6;
200        /**
201         * Call log type for a call which was answered on another device.  Used in situations where
202         * a call rings on multiple devices simultaneously and it ended up being answered on a
203         * device other than the current one.
204         */
205        public static final int ANSWERED_EXTERNALLY_TYPE = 7;
206
207        /**
208         * Bit-mask describing features of the call (e.g. video).
209         *
210         * <P>Type: INTEGER (int)</P>
211         */
212        public static final String FEATURES = "features";
213
214        /** Call had video. */
215        public static final int FEATURES_VIDEO = 1 << 0;
216
217        /** Call was pulled externally. */
218        public static final int FEATURES_PULLED_EXTERNALLY = 1 << 1;
219
220        /** Call was HD. */
221        public static final int FEATURES_HD_CALL = 1 << 2;
222
223        /** Call was WIFI call. */
224        public static final int FEATURES_WIFI = 1 << 3;
225
226        /**
227         * Indicates the call underwent Assisted Dialing.
228         */
229        public static final int FEATURES_ASSISTED_DIALING_USED = 1 << 4;
230
231        /** Call was on RTT at some point */
232        public static final int FEATURES_RTT = 1 << 5;
233
234        /**
235         * The phone number as the user entered it.
236         * <P>Type: TEXT</P>
237         */
238        public static final String NUMBER = "number";
239
240        /**
241         * The number presenting rules set by the network.
242         *
243         * <p>
244         * Allowed values:
245         * <ul>
246         * <li>{@link #PRESENTATION_ALLOWED}</li>
247         * <li>{@link #PRESENTATION_RESTRICTED}</li>
248         * <li>{@link #PRESENTATION_UNKNOWN}</li>
249         * <li>{@link #PRESENTATION_PAYPHONE}</li>
250         * </ul>
251         * </p>
252         *
253         * <P>Type: INTEGER</P>
254         */
255        public static final String NUMBER_PRESENTATION = "presentation";
256
257        /** Number is allowed to display for caller id. */
258        public static final int PRESENTATION_ALLOWED = 1;
259        /** Number is blocked by user. */
260        public static final int PRESENTATION_RESTRICTED = 2;
261        /** Number is not specified or unknown by network. */
262        public static final int PRESENTATION_UNKNOWN = 3;
263        /** Number is a pay phone. */
264        public static final int PRESENTATION_PAYPHONE = 4;
265
266        /**
267         * The ISO 3166-1 two letters country code of the country where the
268         * user received or made the call.
269         * <P>
270         * Type: TEXT
271         * </P>
272         */
273        public static final String COUNTRY_ISO = "countryiso";
274
275        /**
276         * The date the call occured, in milliseconds since the epoch
277         * <P>Type: INTEGER (long)</P>
278         */
279        public static final String DATE = "date";
280
281        /**
282         * The duration of the call in seconds
283         * <P>Type: INTEGER (long)</P>
284         */
285        public static final String DURATION = "duration";
286
287        /**
288         * The data usage of the call in bytes.
289         * <P>Type: INTEGER (long)</P>
290         */
291        public static final String DATA_USAGE = "data_usage";
292
293        /**
294         * Whether or not the call has been acknowledged
295         * <P>Type: INTEGER (boolean)</P>
296         */
297        public static final String NEW = "new";
298
299        /**
300         * The cached name associated with the phone number, if it exists.
301         *
302         * <p>This value is typically filled in by the dialer app for the caching purpose,
303         * so it's not guaranteed to be present, and may not be current if the contact
304         * information associated with this number has changed.
305         * <P>Type: TEXT</P>
306         */
307        public static final String CACHED_NAME = "name";
308
309        /**
310         * The cached number type (Home, Work, etc) associated with the
311         * phone number, if it exists.
312         *
313         * <p>This value is typically filled in by the dialer app for the caching purpose,
314         * so it's not guaranteed to be present, and may not be current if the contact
315         * information associated with this number has changed.
316         * <P>Type: INTEGER</P>
317         */
318        public static final String CACHED_NUMBER_TYPE = "numbertype";
319
320        /**
321         * The cached number label, for a custom number type, associated with the
322         * phone number, if it exists.
323         *
324         * <p>This value is typically filled in by the dialer app for the caching purpose,
325         * so it's not guaranteed to be present, and may not be current if the contact
326         * information associated with this number has changed.
327         * <P>Type: TEXT</P>
328         */
329        public static final String CACHED_NUMBER_LABEL = "numberlabel";
330
331        /**
332         * URI of the voicemail entry. Populated only for {@link #VOICEMAIL_TYPE}.
333         * <P>Type: TEXT</P>
334         */
335        public static final String VOICEMAIL_URI = "voicemail_uri";
336
337        /**
338         * Transcription of the call or voicemail entry. This will only be populated for call log
339         * entries of type {@link #VOICEMAIL_TYPE} that have valid transcriptions.
340         */
341        public static final String TRANSCRIPTION = "transcription";
342
343        /**
344         * State of voicemail transcription entry. This will only be populated for call log
345         * entries of type {@link #VOICEMAIL_TYPE}.
346         * @hide
347         */
348        public static final String TRANSCRIPTION_STATE = "transcription_state";
349
350        /**
351         * Whether this item has been read or otherwise consumed by the user.
352         * <p>
353         * Unlike the {@link #NEW} field, which requires the user to have acknowledged the
354         * existence of the entry, this implies the user has interacted with the entry.
355         * <P>Type: INTEGER (boolean)</P>
356         */
357        public static final String IS_READ = "is_read";
358
359        /**
360         * A geocoded location for the number associated with this call.
361         * <p>
362         * The string represents a city, state, or country associated with the number.
363         * <P>Type: TEXT</P>
364         */
365        public static final String GEOCODED_LOCATION = "geocoded_location";
366
367        /**
368         * The cached URI to look up the contact associated with the phone number, if it exists.
369         *
370         * <p>This value is typically filled in by the dialer app for the caching purpose,
371         * so it's not guaranteed to be present, and may not be current if the contact
372         * information associated with this number has changed.
373         * <P>Type: TEXT</P>
374         */
375        public static final String CACHED_LOOKUP_URI = "lookup_uri";
376
377        /**
378         * The cached phone number of the contact which matches this entry, if it exists.
379         *
380         * <p>This value is typically filled in by the dialer app for the caching purpose,
381         * so it's not guaranteed to be present, and may not be current if the contact
382         * information associated with this number has changed.
383         * <P>Type: TEXT</P>
384         */
385        public static final String CACHED_MATCHED_NUMBER = "matched_number";
386
387        /**
388         * The cached normalized(E164) version of the phone number, if it exists.
389         *
390         * <p>This value is typically filled in by the dialer app for the caching purpose,
391         * so it's not guaranteed to be present, and may not be current if the contact
392         * information associated with this number has changed.
393         * <P>Type: TEXT</P>
394         */
395        public static final String CACHED_NORMALIZED_NUMBER = "normalized_number";
396
397        /**
398         * The cached photo id of the picture associated with the phone number, if it exists.
399         *
400         * <p>This value is typically filled in by the dialer app for the caching purpose,
401         * so it's not guaranteed to be present, and may not be current if the contact
402         * information associated with this number has changed.
403         * <P>Type: INTEGER (long)</P>
404         */
405        public static final String CACHED_PHOTO_ID = "photo_id";
406
407        /**
408         * The cached photo URI of the picture associated with the phone number, if it exists.
409         *
410         * <p>This value is typically filled in by the dialer app for the caching purpose,
411         * so it's not guaranteed to be present, and may not be current if the contact
412         * information associated with this number has changed.
413         * <P>Type: TEXT (URI)</P>
414         */
415        public static final String CACHED_PHOTO_URI = "photo_uri";
416
417        /**
418         * The cached phone number, formatted with formatting rules based on the country the
419         * user was in when the call was made or received.
420         *
421         * <p>This value is typically filled in by the dialer app for the caching purpose,
422         * so it's not guaranteed to be present, and may not be current if the contact
423         * information associated with this number has changed.
424         * <P>Type: TEXT</P>
425         */
426        public static final String CACHED_FORMATTED_NUMBER = "formatted_number";
427
428        // Note: PHONE_ACCOUNT_* constant values are "subscription_*" due to a historic naming
429        // that was encoded into call log databases.
430
431        /**
432         * The component name of the account used to place or receive the call; in string form.
433         * <P>Type: TEXT</P>
434         */
435        public static final String PHONE_ACCOUNT_COMPONENT_NAME = "subscription_component_name";
436
437        /**
438         * The identifier for the account used to place or receive the call.
439         * <P>Type: TEXT</P>
440         */
441        public static final String PHONE_ACCOUNT_ID = "subscription_id";
442
443        /**
444         * The address associated with the account used to place or receive the call; in string
445         * form. For SIM-based calls, this is the user's own phone number.
446         * <P>Type: TEXT</P>
447         *
448         * @hide
449         */
450        public static final String PHONE_ACCOUNT_ADDRESS = "phone_account_address";
451
452        /**
453         * Indicates that the entry will be hidden from all queries until the associated
454         * {@link android.telecom.PhoneAccount} is registered with the system.
455         * <P>Type: INTEGER</P>
456         *
457         * @hide
458         */
459        public static final String PHONE_ACCOUNT_HIDDEN = "phone_account_hidden";
460
461        /**
462         * The subscription ID used to place this call.  This is no longer used and has been
463         * replaced with PHONE_ACCOUNT_COMPONENT_NAME/PHONE_ACCOUNT_ID.
464         * For ContactsProvider internal use only.
465         * <P>Type: INTEGER</P>
466         *
467         * @Deprecated
468         * @hide
469         */
470        public static final String SUB_ID = "sub_id";
471
472        /**
473         * The post-dial portion of a dialed number, including any digits dialed after a
474         * {@link TelecomManager#DTMF_CHARACTER_PAUSE} or a {@link
475         * TelecomManager#DTMF_CHARACTER_WAIT} and these characters themselves.
476         * <P>Type: TEXT</P>
477         */
478        public static final String POST_DIAL_DIGITS = "post_dial_digits";
479
480        /**
481         * For an incoming call, the secondary line number the call was received via.
482         * When a SIM card has multiple phone numbers associated with it, the via number indicates
483         * which of the numbers associated with the SIM was called.
484         */
485        public static final String VIA_NUMBER = "via_number";
486
487        /**
488         * Indicates that the entry will be copied from primary user to other users.
489         * <P>Type: INTEGER</P>
490         *
491         * @hide
492         */
493        public static final String ADD_FOR_ALL_USERS = "add_for_all_users";
494
495        /**
496         * The date the row is last inserted, updated, or marked as deleted, in milliseconds
497         * since the epoch. Read only.
498         * <P>Type: INTEGER (long)</P>
499         */
500        public static final String LAST_MODIFIED = "last_modified";
501
502        /**
503         * If a successful call is made that is longer than this duration, update the phone number
504         * in the ContactsProvider with the normalized version of the number, based on the user's
505         * current country code.
506         */
507        private static final int MIN_DURATION_FOR_NORMALIZED_NUMBER_UPDATE_MS = 1000 * 10;
508
509        /**
510         * Adds a call to the call log.
511         *
512         * @param ci the CallerInfo object to get the target contact from.  Can be null
513         * if the contact is unknown.
514         * @param context the context used to get the ContentResolver
515         * @param number the phone number to be added to the calls db
516         * @param presentation enum value from PhoneConstants.PRESENTATION_xxx, which
517         *        is set by the network and denotes the number presenting rules for
518         *        "allowed", "payphone", "restricted" or "unknown"
519         * @param callType enumerated values for "incoming", "outgoing", or "missed"
520         * @param features features of the call (e.g. Video).
521         * @param accountHandle The accountHandle object identifying the provider of the call
522         * @param start time stamp for the call in milliseconds
523         * @param duration call duration in seconds
524         * @param dataUsage data usage for the call in bytes, null if data usage was not tracked for
525         *                  the call.
526         * @result The URI of the call log entry belonging to the user that made or received this
527         *        call.
528         * {@hide}
529         */
530        public static Uri addCall(CallerInfo ci, Context context, String number,
531                int presentation, int callType, int features, PhoneAccountHandle accountHandle,
532                long start, int duration, Long dataUsage) {
533            return addCall(ci, context, number, /* postDialDigits =*/ "", /* viaNumber =*/ "",
534                    presentation, callType, features, accountHandle, start, duration,
535                    dataUsage, /* addForAllUsers =*/ false, /* userToBeInsertedTo =*/ null,
536                    /* is_read =*/ false);
537        }
538
539
540        /**
541         * Adds a call to the call log.
542         *
543         * @param ci the CallerInfo object to get the target contact from.  Can be null
544         * if the contact is unknown.
545         * @param context the context used to get the ContentResolver
546         * @param number the phone number to be added to the calls db
547         * @param viaNumber the secondary number that the incoming call received with. If the
548         *       call was received with the SIM assigned number, then this field must be ''.
549         * @param presentation enum value from PhoneConstants.PRESENTATION_xxx, which
550         *        is set by the network and denotes the number presenting rules for
551         *        "allowed", "payphone", "restricted" or "unknown"
552         * @param callType enumerated values for "incoming", "outgoing", or "missed"
553         * @param features features of the call (e.g. Video).
554         * @param accountHandle The accountHandle object identifying the provider of the call
555         * @param start time stamp for the call in milliseconds
556         * @param duration call duration in seconds
557         * @param dataUsage data usage for the call in bytes, null if data usage was not tracked for
558         *                  the call.
559         * @param addForAllUsers If true, the call is added to the call log of all currently
560         *        running users. The caller must have the MANAGE_USERS permission if this is true.
561         * @param userToBeInsertedTo {@link UserHandle} of user that the call is going to be
562         *                           inserted to. null if it is inserted to the current user. The
563         *                           value is ignored if @{link addForAllUsers} is true.
564         * @result The URI of the call log entry belonging to the user that made or received this
565         *        call.
566         * {@hide}
567         */
568        public static Uri addCall(CallerInfo ci, Context context, String number,
569                String postDialDigits, String viaNumber, int presentation, int callType,
570                int features, PhoneAccountHandle accountHandle, long start, int duration,
571                Long dataUsage, boolean addForAllUsers, UserHandle userToBeInsertedTo) {
572            return addCall(ci, context, number, postDialDigits, viaNumber, presentation, callType,
573                    features, accountHandle, start, duration, dataUsage, addForAllUsers,
574                    userToBeInsertedTo, /* is_read =*/ false);
575        }
576
577        /**
578         * Adds a call to the call log.
579         *
580         * @param ci the CallerInfo object to get the target contact from.  Can be null
581         * if the contact is unknown.
582         * @param context the context used to get the ContentResolver
583         * @param number the phone number to be added to the calls db
584         * @param postDialDigits the post-dial digits that were dialed after the number,
585         *        if it was outgoing. Otherwise it is ''.
586         * @param viaNumber the secondary number that the incoming call received with. If the
587         *        call was received with the SIM assigned number, then this field must be ''.
588         * @param presentation enum value from PhoneConstants.PRESENTATION_xxx, which
589         *        is set by the network and denotes the number presenting rules for
590         *        "allowed", "payphone", "restricted" or "unknown"
591         * @param callType enumerated values for "incoming", "outgoing", or "missed"
592         * @param features features of the call (e.g. Video).
593         * @param accountHandle The accountHandle object identifying the provider of the call
594         * @param start time stamp for the call in milliseconds
595         * @param duration call duration in seconds
596         * @param dataUsage data usage for the call in bytes, null if data usage was not tracked for
597         *                  the call.
598         * @param addForAllUsers If true, the call is added to the call log of all currently
599         *        running users. The caller must have the MANAGE_USERS permission if this is true.
600         * @param userToBeInsertedTo {@link UserHandle} of user that the call is going to be
601         *                           inserted to. null if it is inserted to the current user. The
602         *                           value is ignored if @{link addForAllUsers} is true.
603         * @param is_read Flag to show if the missed call log has been read by the user or not.
604         *                Used for call log restore of missed calls.
605         *
606         * @result The URI of the call log entry belonging to the user that made or received this
607         *        call.  This could be of the shadow provider.  Do not return it to non-system apps,
608         *        as they don't have permissions.
609         * {@hide}
610         */
611        public static Uri addCall(CallerInfo ci, Context context, String number,
612                String postDialDigits, String viaNumber, int presentation, int callType,
613                int features, PhoneAccountHandle accountHandle, long start, int duration,
614                Long dataUsage, boolean addForAllUsers, UserHandle userToBeInsertedTo,
615                boolean is_read) {
616            if (VERBOSE_LOG) {
617                Log.v(LOG_TAG, String.format("Add call: number=%s, user=%s, for all=%s",
618                        number, userToBeInsertedTo, addForAllUsers));
619            }
620            final ContentResolver resolver = context.getContentResolver();
621            int numberPresentation = PRESENTATION_ALLOWED;
622
623            TelecomManager tm = null;
624            try {
625                tm = TelecomManager.from(context);
626            } catch (UnsupportedOperationException e) {}
627
628            String accountAddress = null;
629            if (tm != null && accountHandle != null) {
630                PhoneAccount account = tm.getPhoneAccount(accountHandle);
631                if (account != null) {
632                    Uri address = account.getSubscriptionAddress();
633                    if (address != null) {
634                        accountAddress = address.getSchemeSpecificPart();
635                    }
636                }
637            }
638
639            // Remap network specified number presentation types
640            // PhoneConstants.PRESENTATION_xxx to calllog number presentation types
641            // Calls.PRESENTATION_xxx, in order to insulate the persistent calllog
642            // from any future radio changes.
643            // If the number field is empty set the presentation type to Unknown.
644            if (presentation == PhoneConstants.PRESENTATION_RESTRICTED) {
645                numberPresentation = PRESENTATION_RESTRICTED;
646            } else if (presentation == PhoneConstants.PRESENTATION_PAYPHONE) {
647                numberPresentation = PRESENTATION_PAYPHONE;
648            } else if (TextUtils.isEmpty(number)
649                    || presentation == PhoneConstants.PRESENTATION_UNKNOWN) {
650                numberPresentation = PRESENTATION_UNKNOWN;
651            }
652            if (numberPresentation != PRESENTATION_ALLOWED) {
653                number = "";
654                if (ci != null) {
655                    ci.name = "";
656                }
657            }
658
659            // accountHandle information
660            String accountComponentString = null;
661            String accountId = null;
662            if (accountHandle != null) {
663                accountComponentString = accountHandle.getComponentName().flattenToString();
664                accountId = accountHandle.getId();
665            }
666
667            ContentValues values = new ContentValues(6);
668
669            values.put(NUMBER, number);
670            values.put(POST_DIAL_DIGITS, postDialDigits);
671            values.put(VIA_NUMBER, viaNumber);
672            values.put(NUMBER_PRESENTATION, Integer.valueOf(numberPresentation));
673            values.put(TYPE, Integer.valueOf(callType));
674            values.put(FEATURES, features);
675            values.put(DATE, Long.valueOf(start));
676            values.put(DURATION, Long.valueOf(duration));
677            if (dataUsage != null) {
678                values.put(DATA_USAGE, dataUsage);
679            }
680            values.put(PHONE_ACCOUNT_COMPONENT_NAME, accountComponentString);
681            values.put(PHONE_ACCOUNT_ID, accountId);
682            values.put(PHONE_ACCOUNT_ADDRESS, accountAddress);
683            values.put(NEW, Integer.valueOf(1));
684            values.put(ADD_FOR_ALL_USERS, addForAllUsers ? 1 : 0);
685
686            if (callType == MISSED_TYPE) {
687                values.put(IS_READ, Integer.valueOf(is_read ? 1 : 0));
688            }
689
690            if ((ci != null) && (ci.contactIdOrZero > 0)) {
691                // Update usage information for the number associated with the contact ID.
692                // We need to use both the number and the ID for obtaining a data ID since other
693                // contacts may have the same number.
694
695                final Cursor cursor;
696
697                // We should prefer normalized one (probably coming from
698                // Phone.NORMALIZED_NUMBER column) first. If it isn't available try others.
699                if (ci.normalizedNumber != null) {
700                    final String normalizedPhoneNumber = ci.normalizedNumber;
701                    cursor = resolver.query(Phone.CONTENT_URI,
702                            new String[] { Phone._ID },
703                            Phone.CONTACT_ID + " =? AND " + Phone.NORMALIZED_NUMBER + " =?",
704                            new String[] { String.valueOf(ci.contactIdOrZero),
705                                    normalizedPhoneNumber},
706                            null);
707                } else {
708                    final String phoneNumber = ci.phoneNumber != null ? ci.phoneNumber : number;
709                    cursor = resolver.query(
710                            Uri.withAppendedPath(Callable.CONTENT_FILTER_URI,
711                                    Uri.encode(phoneNumber)),
712                            new String[] { Phone._ID },
713                            Phone.CONTACT_ID + " =?",
714                            new String[] { String.valueOf(ci.contactIdOrZero) },
715                            null);
716                }
717
718                if (cursor != null) {
719                    try {
720                        if (cursor.getCount() > 0 && cursor.moveToFirst()) {
721                            final String dataId = cursor.getString(0);
722                            updateDataUsageStatForData(resolver, dataId);
723                            if (duration >= MIN_DURATION_FOR_NORMALIZED_NUMBER_UPDATE_MS
724                                    && callType == Calls.OUTGOING_TYPE
725                                    && TextUtils.isEmpty(ci.normalizedNumber)) {
726                                updateNormalizedNumber(context, resolver, dataId, number);
727                            }
728                        }
729                    } finally {
730                        cursor.close();
731                    }
732                }
733            }
734
735            /*
736                Writing the calllog works in the following way:
737                - All user entries
738                    - if user-0 is encrypted, insert to user-0's shadow only.
739                      (other users should also be encrypted, so nothing to do for other users.)
740                    - if user-0 is decrypted, insert to user-0's real provider, as well as
741                      all other users that are running and decrypted and should have calllog.
742
743                - Single user entry.
744                    - If the target user is encryted, insert to its shadow.
745                    - Otherwise insert to its real provider.
746
747                When the (real) calllog provider starts, it copies entries that it missed from
748                elsewhere.
749                - When user-0's (real) provider starts, it copies from user-0's shadow, and clears
750                  the shadow.
751
752                - When other users (real) providers start, unless it shouldn't have calllog entries,
753                     - Copy from the user's shadow, and clears the shadow.
754                     - Copy from user-0's entries that are FOR_ALL_USERS = 1.  (and don't clear it.)
755             */
756
757            Uri result = null;
758
759            final UserManager userManager = context.getSystemService(UserManager.class);
760            final int currentUserId = userManager.getUserHandle();
761
762            if (addForAllUsers) {
763                // First, insert to the system user.
764                final Uri uriForSystem = addEntryAndRemoveExpiredEntries(
765                        context, userManager, UserHandle.SYSTEM, values);
766                if (uriForSystem == null
767                        || SHADOW_AUTHORITY.equals(uriForSystem.getAuthority())) {
768                    // This means the system user is still encrypted and the entry has inserted
769                    // into the shadow.  This means other users are still all encrypted.
770                    // Nothing further to do; just return null.
771                    return null;
772                }
773                if (UserHandle.USER_SYSTEM == currentUserId) {
774                    result = uriForSystem;
775                }
776
777                // Otherwise, insert to all other users that are running and unlocked.
778
779                final List<UserInfo> users = userManager.getUsers(true);
780
781                final int count = users.size();
782                for (int i = 0; i < count; i++) {
783                    final UserInfo userInfo = users.get(i);
784                    final UserHandle userHandle = userInfo.getUserHandle();
785                    final int userId = userHandle.getIdentifier();
786
787                    if (userHandle.isSystem()) {
788                        // Already written.
789                        continue;
790                    }
791
792                    if (!shouldHaveSharedCallLogEntries(context, userManager, userId)) {
793                        // Shouldn't have calllog entries.
794                        continue;
795                    }
796
797                    // For other users, we write only when they're running *and* decrypted.
798                    // Other providers will copy from the system user's real provider, when they
799                    // start.
800                    if (userManager.isUserRunning(userHandle)
801                            && userManager.isUserUnlocked(userHandle)) {
802                        final Uri uri = addEntryAndRemoveExpiredEntries(context, userManager,
803                                userHandle, values);
804                        if (userId == currentUserId) {
805                            result = uri;
806                        }
807                    }
808                }
809            } else {
810                // Single-user entry. Just write to that user, assuming it's running.  If the
811                // user is encrypted, we write to the shadow calllog.
812
813                final UserHandle targetUserHandle = userToBeInsertedTo != null
814                        ? userToBeInsertedTo
815                        : UserHandle.of(currentUserId);
816                result = addEntryAndRemoveExpiredEntries(context, userManager, targetUserHandle,
817                        values);
818            }
819            return result;
820        }
821
822        /** @hide */
823        public static boolean shouldHaveSharedCallLogEntries(Context context,
824                UserManager userManager, int userId) {
825            if (userManager.hasUserRestriction(UserManager.DISALLOW_OUTGOING_CALLS,
826                    UserHandle.of(userId))) {
827                return false;
828            }
829            final UserInfo userInfo = userManager.getUserInfo(userId);
830            return userInfo != null && !userInfo.isManagedProfile();
831        }
832
833        /**
834         * Query the call log database for the last dialed number.
835         * @param context Used to get the content resolver.
836         * @return The last phone number dialed (outgoing) or an empty
837         * string if none exist yet.
838         */
839        public static String getLastOutgoingCall(Context context) {
840            final ContentResolver resolver = context.getContentResolver();
841            Cursor c = null;
842            try {
843                c = resolver.query(
844                    CONTENT_URI,
845                    new String[] {NUMBER},
846                    TYPE + " = " + OUTGOING_TYPE,
847                    null,
848                    DEFAULT_SORT_ORDER + " LIMIT 1");
849                if (c == null || !c.moveToFirst()) {
850                    return "";
851                }
852                return c.getString(0);
853            } finally {
854                if (c != null) c.close();
855            }
856        }
857
858        private static Uri addEntryAndRemoveExpiredEntries(Context context, UserManager userManager,
859                UserHandle user, ContentValues values) {
860            final ContentResolver resolver = context.getContentResolver();
861
862            // Since we're doing this operation on behalf of an app, we only
863            // want to use the actual "unlocked" state.
864            final Uri uri = ContentProvider.maybeAddUserId(
865                    userManager.isUserUnlocked(user) ? CONTENT_URI : SHADOW_CONTENT_URI,
866                    user.getIdentifier());
867
868            if (VERBOSE_LOG) {
869                Log.v(LOG_TAG, String.format("Inserting to %s", uri));
870            }
871
872            try {
873                // When cleaning up the call log, try to delete older call long entries on a per
874                // PhoneAccount basis first.  There can be multiple ConnectionServices causing
875                // the addition of entries in the call log.  With the introduction of Self-Managed
876                // ConnectionServices, we want to ensure that a misbehaving self-managed CS cannot
877                // spam the call log with its own entries, causing entries from Telephony to be
878                // removed.
879                final Uri result = resolver.insert(uri, values);
880                if (values.containsKey(PHONE_ACCOUNT_ID)
881                        && !TextUtils.isEmpty(values.getAsString(PHONE_ACCOUNT_ID))
882                        && values.containsKey(PHONE_ACCOUNT_COMPONENT_NAME)
883                        && !TextUtils.isEmpty(values.getAsString(PHONE_ACCOUNT_COMPONENT_NAME))) {
884                    // Only purge entries for the same phone account.
885                    resolver.delete(uri, "_id IN " +
886                            "(SELECT _id FROM calls"
887                            + " WHERE " + PHONE_ACCOUNT_COMPONENT_NAME + " = ?"
888                            + " AND " + PHONE_ACCOUNT_ID + " = ?"
889                            + " ORDER BY " + DEFAULT_SORT_ORDER
890                            + " LIMIT -1 OFFSET 500)", new String[] {
891                            values.getAsString(PHONE_ACCOUNT_COMPONENT_NAME),
892                            values.getAsString(PHONE_ACCOUNT_ID)
893                    });
894                } else {
895                    // No valid phone account specified, so default to the old behavior.
896                    resolver.delete(uri, "_id IN " +
897                            "(SELECT _id FROM calls ORDER BY " + DEFAULT_SORT_ORDER
898                            + " LIMIT -1 OFFSET 500)", null);
899                }
900
901                return result;
902            } catch (IllegalArgumentException e) {
903                Log.w(LOG_TAG, "Failed to insert calllog", e);
904                // Even though we make sure the target user is running and decrypted before calling
905                // this method, there's a chance that the user just got shut down, in which case
906                // we'll still get "IllegalArgumentException: Unknown URL content://call_log/calls".
907                return null;
908            }
909        }
910
911        private static void updateDataUsageStatForData(ContentResolver resolver, String dataId) {
912            final Uri feedbackUri = DataUsageFeedback.FEEDBACK_URI.buildUpon()
913                    .appendPath(dataId)
914                    .appendQueryParameter(DataUsageFeedback.USAGE_TYPE,
915                                DataUsageFeedback.USAGE_TYPE_CALL)
916                    .build();
917            resolver.update(feedbackUri, new ContentValues(), null, null);
918        }
919
920        /*
921         * Update the normalized phone number for the given dataId in the ContactsProvider, based
922         * on the user's current country.
923         */
924        private static void updateNormalizedNumber(Context context, ContentResolver resolver,
925                String dataId, String number) {
926            if (TextUtils.isEmpty(number) || TextUtils.isEmpty(dataId)) {
927                return;
928            }
929            final String countryIso = getCurrentCountryIso(context);
930            if (TextUtils.isEmpty(countryIso)) {
931                return;
932            }
933            final String normalizedNumber = PhoneNumberUtils.formatNumberToE164(number,
934                    getCurrentCountryIso(context));
935            if (TextUtils.isEmpty(normalizedNumber)) {
936                return;
937            }
938            final ContentValues values = new ContentValues();
939            values.put(Phone.NORMALIZED_NUMBER, normalizedNumber);
940            resolver.update(Data.CONTENT_URI, values, Data._ID + "=?", new String[] {dataId});
941        }
942
943        private static String getCurrentCountryIso(Context context) {
944            String countryIso = null;
945            final CountryDetector detector = (CountryDetector) context.getSystemService(
946                    Context.COUNTRY_DETECTOR);
947            if (detector != null) {
948                final Country country = detector.detectCountry();
949                if (country != null) {
950                    countryIso = country.getCountryIso();
951                }
952            }
953            return countryIso;
954        }
955    }
956}
957