• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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.location.Country;
28 import android.location.CountryDetector;
29 import android.net.Uri;
30 import android.os.UserHandle;
31 import android.os.UserManager;
32 import android.provider.ContactsContract.CommonDataKinds.Callable;
33 import android.provider.ContactsContract.CommonDataKinds.Phone;
34 import android.provider.ContactsContract.Data;
35 import android.provider.ContactsContract.DataUsageFeedback;
36 import android.telecom.PhoneAccount;
37 import android.telecom.PhoneAccountHandle;
38 import android.telecom.TelecomManager;
39 import android.telephony.PhoneNumberUtils;
40 import android.text.TextUtils;
41 import android.util.Log;
42 
43 import com.android.internal.telephony.CallerInfo;
44 import com.android.internal.telephony.PhoneConstants;
45 
46 import java.util.List;
47 
48 /**
49  * The CallLog provider contains information about placed and received calls.
50  */
51 public 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 = 0x1;
216 
217         /** Call was pulled externally. */
218         public static final int FEATURES_PULLED_EXTERNALLY = 0x2;
219 
220         /**
221          * The phone number as the user entered it.
222          * <P>Type: TEXT</P>
223          */
224         public static final String NUMBER = "number";
225 
226         /**
227          * The number presenting rules set by the network.
228          *
229          * <p>
230          * Allowed values:
231          * <ul>
232          * <li>{@link #PRESENTATION_ALLOWED}</li>
233          * <li>{@link #PRESENTATION_RESTRICTED}</li>
234          * <li>{@link #PRESENTATION_UNKNOWN}</li>
235          * <li>{@link #PRESENTATION_PAYPHONE}</li>
236          * </ul>
237          * </p>
238          *
239          * <P>Type: INTEGER</P>
240          */
241         public static final String NUMBER_PRESENTATION = "presentation";
242 
243         /** Number is allowed to display for caller id. */
244         public static final int PRESENTATION_ALLOWED = 1;
245         /** Number is blocked by user. */
246         public static final int PRESENTATION_RESTRICTED = 2;
247         /** Number is not specified or unknown by network. */
248         public static final int PRESENTATION_UNKNOWN = 3;
249         /** Number is a pay phone. */
250         public static final int PRESENTATION_PAYPHONE = 4;
251 
252         /**
253          * The ISO 3166-1 two letters country code of the country where the
254          * user received or made the call.
255          * <P>
256          * Type: TEXT
257          * </P>
258          */
259         public static final String COUNTRY_ISO = "countryiso";
260 
261         /**
262          * The date the call occured, in milliseconds since the epoch
263          * <P>Type: INTEGER (long)</P>
264          */
265         public static final String DATE = "date";
266 
267         /**
268          * The duration of the call in seconds
269          * <P>Type: INTEGER (long)</P>
270          */
271         public static final String DURATION = "duration";
272 
273         /**
274          * The data usage of the call in bytes.
275          * <P>Type: INTEGER (long)</P>
276          */
277         public static final String DATA_USAGE = "data_usage";
278 
279         /**
280          * Whether or not the call has been acknowledged
281          * <P>Type: INTEGER (boolean)</P>
282          */
283         public static final String NEW = "new";
284 
285         /**
286          * The cached name associated with the phone number, if it exists.
287          *
288          * <p>This value is typically filled in by the dialer app for the caching purpose,
289          * so it's not guaranteed to be present, and may not be current if the contact
290          * information associated with this number has changed.
291          * <P>Type: TEXT</P>
292          */
293         public static final String CACHED_NAME = "name";
294 
295         /**
296          * The cached number type (Home, Work, etc) associated with the
297          * phone number, if it exists.
298          *
299          * <p>This value is typically filled in by the dialer app for the caching purpose,
300          * so it's not guaranteed to be present, and may not be current if the contact
301          * information associated with this number has changed.
302          * <P>Type: INTEGER</P>
303          */
304         public static final String CACHED_NUMBER_TYPE = "numbertype";
305 
306         /**
307          * The cached number label, for a custom number type, associated with the
308          * phone number, if it exists.
309          *
310          * <p>This value is typically filled in by the dialer app for the caching purpose,
311          * so it's not guaranteed to be present, and may not be current if the contact
312          * information associated with this number has changed.
313          * <P>Type: TEXT</P>
314          */
315         public static final String CACHED_NUMBER_LABEL = "numberlabel";
316 
317         /**
318          * URI of the voicemail entry. Populated only for {@link #VOICEMAIL_TYPE}.
319          * <P>Type: TEXT</P>
320          */
321         public static final String VOICEMAIL_URI = "voicemail_uri";
322 
323         /**
324          * Transcription of the call or voicemail entry. This will only be populated for call log
325          * entries of type {@link #VOICEMAIL_TYPE} that have valid transcriptions.
326          */
327         public static final String TRANSCRIPTION = "transcription";
328 
329         /**
330          * Whether this item has been read or otherwise consumed by the user.
331          * <p>
332          * Unlike the {@link #NEW} field, which requires the user to have acknowledged the
333          * existence of the entry, this implies the user has interacted with the entry.
334          * <P>Type: INTEGER (boolean)</P>
335          */
336         public static final String IS_READ = "is_read";
337 
338         /**
339          * A geocoded location for the number associated with this call.
340          * <p>
341          * The string represents a city, state, or country associated with the number.
342          * <P>Type: TEXT</P>
343          */
344         public static final String GEOCODED_LOCATION = "geocoded_location";
345 
346         /**
347          * The cached URI to look up the contact associated with the phone number, if it exists.
348          *
349          * <p>This value is typically filled in by the dialer app for the caching purpose,
350          * so it's not guaranteed to be present, and may not be current if the contact
351          * information associated with this number has changed.
352          * <P>Type: TEXT</P>
353          */
354         public static final String CACHED_LOOKUP_URI = "lookup_uri";
355 
356         /**
357          * The cached phone number of the contact which matches this entry, if it exists.
358          *
359          * <p>This value is typically filled in by the dialer app for the caching purpose,
360          * so it's not guaranteed to be present, and may not be current if the contact
361          * information associated with this number has changed.
362          * <P>Type: TEXT</P>
363          */
364         public static final String CACHED_MATCHED_NUMBER = "matched_number";
365 
366         /**
367          * The cached normalized(E164) version of the phone number, if it exists.
368          *
369          * <p>This value is typically filled in by the dialer app for the caching purpose,
370          * so it's not guaranteed to be present, and may not be current if the contact
371          * information associated with this number has changed.
372          * <P>Type: TEXT</P>
373          */
374         public static final String CACHED_NORMALIZED_NUMBER = "normalized_number";
375 
376         /**
377          * The cached photo id of the picture associated with the phone number, if it exists.
378          *
379          * <p>This value is typically filled in by the dialer app for the caching purpose,
380          * so it's not guaranteed to be present, and may not be current if the contact
381          * information associated with this number has changed.
382          * <P>Type: INTEGER (long)</P>
383          */
384         public static final String CACHED_PHOTO_ID = "photo_id";
385 
386         /**
387          * The cached photo URI of the picture associated with the phone number, if it exists.
388          *
389          * <p>This value is typically filled in by the dialer app for the caching purpose,
390          * so it's not guaranteed to be present, and may not be current if the contact
391          * information associated with this number has changed.
392          * <P>Type: TEXT (URI)</P>
393          */
394         public static final String CACHED_PHOTO_URI = "photo_uri";
395 
396         /**
397          * The cached phone number, formatted with formatting rules based on the country the
398          * user was in when the call was made or received.
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: TEXT</P>
404          */
405         public static final String CACHED_FORMATTED_NUMBER = "formatted_number";
406 
407         // Note: PHONE_ACCOUNT_* constant values are "subscription_*" due to a historic naming
408         // that was encoded into call log databases.
409 
410         /**
411          * The component name of the account used to place or receive the call; in string form.
412          * <P>Type: TEXT</P>
413          */
414         public static final String PHONE_ACCOUNT_COMPONENT_NAME = "subscription_component_name";
415 
416         /**
417          * The identifier for the account used to place or receive the call.
418          * <P>Type: TEXT</P>
419          */
420         public static final String PHONE_ACCOUNT_ID = "subscription_id";
421 
422         /**
423          * The address associated with the account used to place or receive the call; in string
424          * form. For SIM-based calls, this is the user's own phone number.
425          * <P>Type: TEXT</P>
426          *
427          * @hide
428          */
429         public static final String PHONE_ACCOUNT_ADDRESS = "phone_account_address";
430 
431         /**
432          * Indicates that the entry will be hidden from all queries until the associated
433          * {@link android.telecom.PhoneAccount} is registered with the system.
434          * <P>Type: INTEGER</P>
435          *
436          * @hide
437          */
438         public static final String PHONE_ACCOUNT_HIDDEN = "phone_account_hidden";
439 
440         /**
441          * The subscription ID used to place this call.  This is no longer used and has been
442          * replaced with PHONE_ACCOUNT_COMPONENT_NAME/PHONE_ACCOUNT_ID.
443          * For ContactsProvider internal use only.
444          * <P>Type: INTEGER</P>
445          *
446          * @Deprecated
447          * @hide
448          */
449         public static final String SUB_ID = "sub_id";
450 
451         /**
452          * The post-dial portion of a dialed number, including any digits dialed after a
453          * {@link TelecomManager#DTMF_CHARACTER_PAUSE} or a {@link
454          * TelecomManager#DTMF_CHARACTER_WAIT} and these characters themselves.
455          * <P>Type: TEXT</P>
456          */
457         public static final String POST_DIAL_DIGITS = "post_dial_digits";
458 
459         /**
460          * For an incoming call, the secondary line number the call was received via.
461          * When a SIM card has multiple phone numbers associated with it, the via number indicates
462          * which of the numbers associated with the SIM was called.
463          */
464         public static final String VIA_NUMBER = "via_number";
465 
466         /**
467          * Indicates that the entry will be copied from primary user to other users.
468          * <P>Type: INTEGER</P>
469          *
470          * @hide
471          */
472         public static final String ADD_FOR_ALL_USERS = "add_for_all_users";
473 
474         /**
475          * The date the row is last inserted, updated, or marked as deleted, in milliseconds
476          * since the epoch. Read only.
477          * <P>Type: INTEGER (long)</P>
478          */
479         public static final String LAST_MODIFIED = "last_modified";
480 
481         /**
482          * If a successful call is made that is longer than this duration, update the phone number
483          * in the ContactsProvider with the normalized version of the number, based on the user's
484          * current country code.
485          */
486         private static final int MIN_DURATION_FOR_NORMALIZED_NUMBER_UPDATE_MS = 1000 * 10;
487 
488         /**
489          * Adds a call to the call log.
490          *
491          * @param ci the CallerInfo object to get the target contact from.  Can be null
492          * if the contact is unknown.
493          * @param context the context used to get the ContentResolver
494          * @param number the phone number to be added to the calls db
495          * @param presentation enum value from PhoneConstants.PRESENTATION_xxx, which
496          *        is set by the network and denotes the number presenting rules for
497          *        "allowed", "payphone", "restricted" or "unknown"
498          * @param callType enumerated values for "incoming", "outgoing", or "missed"
499          * @param features features of the call (e.g. Video).
500          * @param accountHandle The accountHandle object identifying the provider of the call
501          * @param start time stamp for the call in milliseconds
502          * @param duration call duration in seconds
503          * @param dataUsage data usage for the call in bytes, null if data usage was not tracked for
504          *                  the call.
505          * @result The URI of the call log entry belonging to the user that made or received this
506          *        call.
507          * {@hide}
508          */
addCall(CallerInfo ci, Context context, String number, int presentation, int callType, int features, PhoneAccountHandle accountHandle, long start, int duration, Long dataUsage)509         public static Uri addCall(CallerInfo ci, Context context, String number,
510                 int presentation, int callType, int features, PhoneAccountHandle accountHandle,
511                 long start, int duration, Long dataUsage) {
512             return addCall(ci, context, number, /* postDialDigits =*/ "", /* viaNumber =*/ "",
513                     presentation, callType, features, accountHandle, start, duration,
514                     dataUsage, /* addForAllUsers =*/ false, /* userToBeInsertedTo =*/ null,
515                     /* is_read =*/ false);
516         }
517 
518 
519         /**
520          * Adds a call to the call log.
521          *
522          * @param ci the CallerInfo object to get the target contact from.  Can be null
523          * if the contact is unknown.
524          * @param context the context used to get the ContentResolver
525          * @param number the phone number to be added to the calls db
526          * @param viaNumber the secondary number that the incoming call received with. If the
527          *       call was received with the SIM assigned number, then this field must be ''.
528          * @param presentation enum value from PhoneConstants.PRESENTATION_xxx, which
529          *        is set by the network and denotes the number presenting rules for
530          *        "allowed", "payphone", "restricted" or "unknown"
531          * @param callType enumerated values for "incoming", "outgoing", or "missed"
532          * @param features features of the call (e.g. Video).
533          * @param accountHandle The accountHandle object identifying the provider of the call
534          * @param start time stamp for the call in milliseconds
535          * @param duration call duration in seconds
536          * @param dataUsage data usage for the call in bytes, null if data usage was not tracked for
537          *                  the call.
538          * @param addForAllUsers If true, the call is added to the call log of all currently
539          *        running users. The caller must have the MANAGE_USERS permission if this is true.
540          * @param userToBeInsertedTo {@link UserHandle} of user that the call is going to be
541          *                           inserted to. null if it is inserted to the current user. The
542          *                           value is ignored if @{link addForAllUsers} is true.
543          * @result The URI of the call log entry belonging to the user that made or received this
544          *        call.
545          * {@hide}
546          */
addCall(CallerInfo ci, Context context, String number, String postDialDigits, String viaNumber, int presentation, int callType, int features, PhoneAccountHandle accountHandle, long start, int duration, Long dataUsage, boolean addForAllUsers, UserHandle userToBeInsertedTo)547         public static Uri addCall(CallerInfo ci, Context context, String number,
548                 String postDialDigits, String viaNumber, int presentation, int callType,
549                 int features, PhoneAccountHandle accountHandle, long start, int duration,
550                 Long dataUsage, boolean addForAllUsers, UserHandle userToBeInsertedTo) {
551             return addCall(ci, context, number, postDialDigits, viaNumber, presentation, callType,
552                     features, accountHandle, start, duration, dataUsage, addForAllUsers,
553                     userToBeInsertedTo, /* is_read =*/ false);
554         }
555 
556         /**
557          * Adds a call to the call log.
558          *
559          * @param ci the CallerInfo object to get the target contact from.  Can be null
560          * if the contact is unknown.
561          * @param context the context used to get the ContentResolver
562          * @param number the phone number to be added to the calls db
563          * @param postDialDigits the post-dial digits that were dialed after the number,
564          *        if it was outgoing. Otherwise it is ''.
565          * @param viaNumber the secondary number that the incoming call received with. If the
566          *        call was received with the SIM assigned number, then this field must be ''.
567          * @param presentation enum value from PhoneConstants.PRESENTATION_xxx, which
568          *        is set by the network and denotes the number presenting rules for
569          *        "allowed", "payphone", "restricted" or "unknown"
570          * @param callType enumerated values for "incoming", "outgoing", or "missed"
571          * @param features features of the call (e.g. Video).
572          * @param accountHandle The accountHandle object identifying the provider of the call
573          * @param start time stamp for the call in milliseconds
574          * @param duration call duration in seconds
575          * @param dataUsage data usage for the call in bytes, null if data usage was not tracked for
576          *                  the call.
577          * @param addForAllUsers If true, the call is added to the call log of all currently
578          *        running users. The caller must have the MANAGE_USERS permission if this is true.
579          * @param userToBeInsertedTo {@link UserHandle} of user that the call is going to be
580          *                           inserted to. null if it is inserted to the current user. The
581          *                           value is ignored if @{link addForAllUsers} is true.
582          * @param is_read Flag to show if the missed call log has been read by the user or not.
583          *                Used for call log restore of missed calls.
584          *
585          * @result The URI of the call log entry belonging to the user that made or received this
586          *        call.  This could be of the shadow provider.  Do not return it to non-system apps,
587          *        as they don't have permissions.
588          * {@hide}
589          */
addCall(CallerInfo ci, Context context, String number, String postDialDigits, String viaNumber, int presentation, int callType, int features, PhoneAccountHandle accountHandle, long start, int duration, Long dataUsage, boolean addForAllUsers, UserHandle userToBeInsertedTo, boolean is_read)590         public static Uri addCall(CallerInfo ci, Context context, String number,
591                 String postDialDigits, String viaNumber, int presentation, int callType,
592                 int features, PhoneAccountHandle accountHandle, long start, int duration,
593                 Long dataUsage, boolean addForAllUsers, UserHandle userToBeInsertedTo,
594                 boolean is_read) {
595             if (VERBOSE_LOG) {
596                 Log.v(LOG_TAG, String.format("Add call: number=%s, user=%s, for all=%s",
597                         number, userToBeInsertedTo, addForAllUsers));
598             }
599             final ContentResolver resolver = context.getContentResolver();
600             int numberPresentation = PRESENTATION_ALLOWED;
601 
602             TelecomManager tm = null;
603             try {
604                 tm = TelecomManager.from(context);
605             } catch (UnsupportedOperationException e) {}
606 
607             String accountAddress = null;
608             if (tm != null && accountHandle != null) {
609                 PhoneAccount account = tm.getPhoneAccount(accountHandle);
610                 if (account != null) {
611                     Uri address = account.getSubscriptionAddress();
612                     if (address != null) {
613                         accountAddress = address.getSchemeSpecificPart();
614                     }
615                 }
616             }
617 
618             // Remap network specified number presentation types
619             // PhoneConstants.PRESENTATION_xxx to calllog number presentation types
620             // Calls.PRESENTATION_xxx, in order to insulate the persistent calllog
621             // from any future radio changes.
622             // If the number field is empty set the presentation type to Unknown.
623             if (presentation == PhoneConstants.PRESENTATION_RESTRICTED) {
624                 numberPresentation = PRESENTATION_RESTRICTED;
625             } else if (presentation == PhoneConstants.PRESENTATION_PAYPHONE) {
626                 numberPresentation = PRESENTATION_PAYPHONE;
627             } else if (TextUtils.isEmpty(number)
628                     || presentation == PhoneConstants.PRESENTATION_UNKNOWN) {
629                 numberPresentation = PRESENTATION_UNKNOWN;
630             }
631             if (numberPresentation != PRESENTATION_ALLOWED) {
632                 number = "";
633                 if (ci != null) {
634                     ci.name = "";
635                 }
636             }
637 
638             // accountHandle information
639             String accountComponentString = null;
640             String accountId = null;
641             if (accountHandle != null) {
642                 accountComponentString = accountHandle.getComponentName().flattenToString();
643                 accountId = accountHandle.getId();
644             }
645 
646             ContentValues values = new ContentValues(6);
647 
648             values.put(NUMBER, number);
649             values.put(POST_DIAL_DIGITS, postDialDigits);
650             values.put(VIA_NUMBER, viaNumber);
651             values.put(NUMBER_PRESENTATION, Integer.valueOf(numberPresentation));
652             values.put(TYPE, Integer.valueOf(callType));
653             values.put(FEATURES, features);
654             values.put(DATE, Long.valueOf(start));
655             values.put(DURATION, Long.valueOf(duration));
656             if (dataUsage != null) {
657                 values.put(DATA_USAGE, dataUsage);
658             }
659             values.put(PHONE_ACCOUNT_COMPONENT_NAME, accountComponentString);
660             values.put(PHONE_ACCOUNT_ID, accountId);
661             values.put(PHONE_ACCOUNT_ADDRESS, accountAddress);
662             values.put(NEW, Integer.valueOf(1));
663             values.put(ADD_FOR_ALL_USERS, addForAllUsers ? 1 : 0);
664 
665             if (callType == MISSED_TYPE) {
666                 values.put(IS_READ, Integer.valueOf(is_read ? 1 : 0));
667             }
668 
669             if ((ci != null) && (ci.contactIdOrZero > 0)) {
670                 // Update usage information for the number associated with the contact ID.
671                 // We need to use both the number and the ID for obtaining a data ID since other
672                 // contacts may have the same number.
673 
674                 final Cursor cursor;
675 
676                 // We should prefer normalized one (probably coming from
677                 // Phone.NORMALIZED_NUMBER column) first. If it isn't available try others.
678                 if (ci.normalizedNumber != null) {
679                     final String normalizedPhoneNumber = ci.normalizedNumber;
680                     cursor = resolver.query(Phone.CONTENT_URI,
681                             new String[] { Phone._ID },
682                             Phone.CONTACT_ID + " =? AND " + Phone.NORMALIZED_NUMBER + " =?",
683                             new String[] { String.valueOf(ci.contactIdOrZero),
684                                     normalizedPhoneNumber},
685                             null);
686                 } else {
687                     final String phoneNumber = ci.phoneNumber != null ? ci.phoneNumber : number;
688                     cursor = resolver.query(
689                             Uri.withAppendedPath(Callable.CONTENT_FILTER_URI,
690                                     Uri.encode(phoneNumber)),
691                             new String[] { Phone._ID },
692                             Phone.CONTACT_ID + " =?",
693                             new String[] { String.valueOf(ci.contactIdOrZero) },
694                             null);
695                 }
696 
697                 if (cursor != null) {
698                     try {
699                         if (cursor.getCount() > 0 && cursor.moveToFirst()) {
700                             final String dataId = cursor.getString(0);
701                             updateDataUsageStatForData(resolver, dataId);
702                             if (duration >= MIN_DURATION_FOR_NORMALIZED_NUMBER_UPDATE_MS
703                                     && callType == Calls.OUTGOING_TYPE
704                                     && TextUtils.isEmpty(ci.normalizedNumber)) {
705                                 updateNormalizedNumber(context, resolver, dataId, number);
706                             }
707                         }
708                     } finally {
709                         cursor.close();
710                     }
711                 }
712             }
713 
714             /*
715                 Writing the calllog works in the following way:
716                 - All user entries
717                     - if user-0 is encrypted, insert to user-0's shadow only.
718                       (other users should also be encrypted, so nothing to do for other users.)
719                     - if user-0 is decrypted, insert to user-0's real provider, as well as
720                       all other users that are running and decrypted and should have calllog.
721 
722                 - Single user entry.
723                     - If the target user is encryted, insert to its shadow.
724                     - Otherwise insert to its real provider.
725 
726                 When the (real) calllog provider starts, it copies entries that it missed from
727                 elsewhere.
728                 - When user-0's (real) provider starts, it copies from user-0's shadow, and clears
729                   the shadow.
730 
731                 - When other users (real) providers start, unless it shouldn't have calllog entries,
732                      - Copy from the user's shadow, and clears the shadow.
733                      - Copy from user-0's entries that are FOR_ALL_USERS = 1.  (and don't clear it.)
734              */
735 
736             Uri result = null;
737 
738             final UserManager userManager = context.getSystemService(UserManager.class);
739             final int currentUserId = userManager.getUserHandle();
740 
741             if (addForAllUsers) {
742                 // First, insert to the system user.
743                 final Uri uriForSystem = addEntryAndRemoveExpiredEntries(
744                         context, userManager, UserHandle.SYSTEM, values);
745                 if (uriForSystem == null
746                         || SHADOW_AUTHORITY.equals(uriForSystem.getAuthority())) {
747                     // This means the system user is still encrypted and the entry has inserted
748                     // into the shadow.  This means other users are still all encrypted.
749                     // Nothing further to do; just return null.
750                     return null;
751                 }
752                 if (UserHandle.USER_SYSTEM == currentUserId) {
753                     result = uriForSystem;
754                 }
755 
756                 // Otherwise, insert to all other users that are running and unlocked.
757 
758                 final List<UserInfo> users = userManager.getUsers(true);
759 
760                 final int count = users.size();
761                 for (int i = 0; i < count; i++) {
762                     final UserInfo userInfo = users.get(i);
763                     final UserHandle userHandle = userInfo.getUserHandle();
764                     final int userId = userHandle.getIdentifier();
765 
766                     if (userHandle.isSystem()) {
767                         // Already written.
768                         continue;
769                     }
770 
771                     if (!shouldHaveSharedCallLogEntries(context, userManager, userId)) {
772                         // Shouldn't have calllog entries.
773                         continue;
774                     }
775 
776                     // For other users, we write only when they're running *and* decrypted.
777                     // Other providers will copy from the system user's real provider, when they
778                     // start.
779                     if (userManager.isUserRunning(userHandle)
780                             && userManager.isUserUnlocked(userHandle)) {
781                         final Uri uri = addEntryAndRemoveExpiredEntries(context, userManager,
782                                 userHandle, values);
783                         if (userId == currentUserId) {
784                             result = uri;
785                         }
786                     }
787                 }
788             } else {
789                 // Single-user entry. Just write to that user, assuming it's running.  If the
790                 // user is encrypted, we write to the shadow calllog.
791 
792                 final UserHandle targetUserHandle = userToBeInsertedTo != null
793                         ? userToBeInsertedTo
794                         : UserHandle.of(currentUserId);
795                 result = addEntryAndRemoveExpiredEntries(context, userManager, targetUserHandle,
796                         values);
797             }
798             return result;
799         }
800 
801         /** @hide */
shouldHaveSharedCallLogEntries(Context context, UserManager userManager, int userId)802         public static boolean shouldHaveSharedCallLogEntries(Context context,
803                 UserManager userManager, int userId) {
804             if (userManager.hasUserRestriction(UserManager.DISALLOW_OUTGOING_CALLS,
805                     UserHandle.of(userId))) {
806                 return false;
807             }
808             final UserInfo userInfo = userManager.getUserInfo(userId);
809             return userInfo != null && !userInfo.isManagedProfile();
810         }
811 
812         /**
813          * Query the call log database for the last dialed number.
814          * @param context Used to get the content resolver.
815          * @return The last phone number dialed (outgoing) or an empty
816          * string if none exist yet.
817          */
getLastOutgoingCall(Context context)818         public static String getLastOutgoingCall(Context context) {
819             final ContentResolver resolver = context.getContentResolver();
820             Cursor c = null;
821             try {
822                 c = resolver.query(
823                     CONTENT_URI,
824                     new String[] {NUMBER},
825                     TYPE + " = " + OUTGOING_TYPE,
826                     null,
827                     DEFAULT_SORT_ORDER + " LIMIT 1");
828                 if (c == null || !c.moveToFirst()) {
829                     return "";
830                 }
831                 return c.getString(0);
832             } finally {
833                 if (c != null) c.close();
834             }
835         }
836 
addEntryAndRemoveExpiredEntries(Context context, UserManager userManager, UserHandle user, ContentValues values)837         private static Uri addEntryAndRemoveExpiredEntries(Context context, UserManager userManager,
838                 UserHandle user, ContentValues values) {
839             final ContentResolver resolver = context.getContentResolver();
840 
841             // Since we're doing this operation on behalf of an app, we only
842             // want to use the actual "unlocked" state.
843             final Uri uri = ContentProvider.maybeAddUserId(
844                     userManager.isUserUnlocked(user) ? CONTENT_URI : SHADOW_CONTENT_URI,
845                     user.getIdentifier());
846 
847             if (VERBOSE_LOG) {
848                 Log.v(LOG_TAG, String.format("Inserting to %s", uri));
849             }
850 
851             try {
852                 final Uri result = resolver.insert(uri, values);
853                 resolver.delete(uri, "_id IN " +
854                         "(SELECT _id FROM calls ORDER BY " + DEFAULT_SORT_ORDER
855                         + " LIMIT -1 OFFSET 500)", null);
856                 return result;
857             } catch (IllegalArgumentException e) {
858                 Log.w(LOG_TAG, "Failed to insert calllog", e);
859                 // Even though we make sure the target user is running and decrypted before calling
860                 // this method, there's a chance that the user just got shut down, in which case
861                 // we'll still get "IllegalArgumentException: Unknown URL content://call_log/calls".
862                 return null;
863             }
864         }
865 
updateDataUsageStatForData(ContentResolver resolver, String dataId)866         private static void updateDataUsageStatForData(ContentResolver resolver, String dataId) {
867             final Uri feedbackUri = DataUsageFeedback.FEEDBACK_URI.buildUpon()
868                     .appendPath(dataId)
869                     .appendQueryParameter(DataUsageFeedback.USAGE_TYPE,
870                                 DataUsageFeedback.USAGE_TYPE_CALL)
871                     .build();
872             resolver.update(feedbackUri, new ContentValues(), null, null);
873         }
874 
875         /*
876          * Update the normalized phone number for the given dataId in the ContactsProvider, based
877          * on the user's current country.
878          */
updateNormalizedNumber(Context context, ContentResolver resolver, String dataId, String number)879         private static void updateNormalizedNumber(Context context, ContentResolver resolver,
880                 String dataId, String number) {
881             if (TextUtils.isEmpty(number) || TextUtils.isEmpty(dataId)) {
882                 return;
883             }
884             final String countryIso = getCurrentCountryIso(context);
885             if (TextUtils.isEmpty(countryIso)) {
886                 return;
887             }
888             final String normalizedNumber = PhoneNumberUtils.formatNumberToE164(number,
889                     getCurrentCountryIso(context));
890             if (TextUtils.isEmpty(normalizedNumber)) {
891                 return;
892             }
893             final ContentValues values = new ContentValues();
894             values.put(Phone.NORMALIZED_NUMBER, normalizedNumber);
895             resolver.update(Data.CONTENT_URI, values, Data._ID + "=?", new String[] {dataId});
896         }
897 
getCurrentCountryIso(Context context)898         private static String getCurrentCountryIso(Context context) {
899             String countryIso = null;
900             final CountryDetector detector = (CountryDetector) context.getSystemService(
901                     Context.COUNTRY_DETECTOR);
902             if (detector != null) {
903                 final Country country = detector.detectCountry();
904                 if (country != null) {
905                     countryIso = country.getCountryIso();
906                 }
907             }
908             return countryIso;
909         }
910     }
911 }
912