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