1e99988b266dd1263162583e81e2b408e7329b1c8Dmitri Plotnikov/*
2e99988b266dd1263162583e81e2b408e7329b1c8Dmitri Plotnikov * Copyright (C) 2009 The Android Open Source Project
3e99988b266dd1263162583e81e2b408e7329b1c8Dmitri Plotnikov *
4e99988b266dd1263162583e81e2b408e7329b1c8Dmitri Plotnikov * Licensed under the Apache License, Version 2.0 (the "License");
5e99988b266dd1263162583e81e2b408e7329b1c8Dmitri Plotnikov * you may not use this file except in compliance with the License.
6e99988b266dd1263162583e81e2b408e7329b1c8Dmitri Plotnikov * You may obtain a copy of the License at
7e99988b266dd1263162583e81e2b408e7329b1c8Dmitri Plotnikov *
8e99988b266dd1263162583e81e2b408e7329b1c8Dmitri Plotnikov *      http://www.apache.org/licenses/LICENSE-2.0
9e99988b266dd1263162583e81e2b408e7329b1c8Dmitri Plotnikov *
10e99988b266dd1263162583e81e2b408e7329b1c8Dmitri Plotnikov * Unless required by applicable law or agreed to in writing, software
11e99988b266dd1263162583e81e2b408e7329b1c8Dmitri Plotnikov * distributed under the License is distributed on an "AS IS" BASIS,
12e99988b266dd1263162583e81e2b408e7329b1c8Dmitri Plotnikov * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13e99988b266dd1263162583e81e2b408e7329b1c8Dmitri Plotnikov * See the License for the specific language governing permissions and
14e99988b266dd1263162583e81e2b408e7329b1c8Dmitri Plotnikov * limitations under the License
15e99988b266dd1263162583e81e2b408e7329b1c8Dmitri Plotnikov */
16e99988b266dd1263162583e81e2b408e7329b1c8Dmitri Plotnikov
17e99988b266dd1263162583e81e2b408e7329b1c8Dmitri Plotnikovpackage com.android.providers.contacts;
18e99988b266dd1263162583e81e2b408e7329b1c8Dmitri Plotnikov
1900e7c94b70f4b477653534dbe559d1759d796157Debashish Chatterjeeimport static com.android.providers.contacts.util.DbQueryUtils.checkForSupportedColumns;
20aafbe295d67686870c64c74a59e589d1dfb506faDebashish Chatterjeeimport static com.android.providers.contacts.util.DbQueryUtils.getEqualityClause;
21aafbe295d67686870c64c74a59e589d1dfb506faDebashish Chatterjeeimport static com.android.providers.contacts.util.DbQueryUtils.getInequalityClause;
2200e7c94b70f4b477653534dbe559d1759d796157Debashish Chatterjee
23c9626e7befd591923c6af859ad079abba8a84e41Dianne Hackbornimport android.app.AppOpsManager;
24e99988b266dd1263162583e81e2b408e7329b1c8Dmitri Plotnikovimport android.content.ContentProvider;
25f3bd980c0ec03db2538e86cadee2c1559f02c85bMakoto Onukiimport android.content.ContentResolver;
26e99988b266dd1263162583e81e2b408e7329b1c8Dmitri Plotnikovimport android.content.ContentUris;
27e99988b266dd1263162583e81e2b408e7329b1c8Dmitri Plotnikovimport android.content.ContentValues;
28e99988b266dd1263162583e81e2b408e7329b1c8Dmitri Plotnikovimport android.content.Context;
29e99988b266dd1263162583e81e2b408e7329b1c8Dmitri Plotnikovimport android.content.UriMatcher;
30e99988b266dd1263162583e81e2b408e7329b1c8Dmitri Plotnikovimport android.database.Cursor;
31e99988b266dd1263162583e81e2b408e7329b1c8Dmitri Plotnikovimport android.database.DatabaseUtils;
32e99988b266dd1263162583e81e2b408e7329b1c8Dmitri Plotnikovimport android.database.sqlite.SQLiteDatabase;
33e99988b266dd1263162583e81e2b408e7329b1c8Dmitri Plotnikovimport android.database.sqlite.SQLiteQueryBuilder;
34e99988b266dd1263162583e81e2b408e7329b1c8Dmitri Plotnikovimport android.net.Uri;
35f3bd980c0ec03db2538e86cadee2c1559f02c85bMakoto Onukiimport android.os.Binder;
363b34457a4cc0d2c55676f366ddc673091a198adbYorke Leeimport android.os.UserHandle;
373b34457a4cc0d2c55676f366ddc673091a198adbYorke Leeimport android.os.UserManager;
38e99988b266dd1263162583e81e2b408e7329b1c8Dmitri Plotnikovimport android.provider.CallLog;
39e99988b266dd1263162583e81e2b408e7329b1c8Dmitri Plotnikovimport android.provider.CallLog.Calls;
40f7076a627db99f9e845d406650d73be826091367Santos Cordonimport android.telecom.PhoneAccount;
41b39eeb4f07db680e542ccaf142136a42f9d305f8Santos Cordonimport android.telecom.PhoneAccountHandle;
42f7076a627db99f9e845d406650d73be826091367Santos Cordonimport android.telecom.TelecomManager;
43a16c2509fa398159988861a3fc8408b493fa445bChristine Chenimport android.text.TextUtils;
44517d590dc73e5efcf7c94e2431faec2473924ca2Makoto Onukiimport android.util.ArrayMap;
45663b8b8ce7a29fb2796dc6431f2cd5992934f315Makoto Onukiimport android.util.Log;
46607e7e3208b8b40633b3e2c1990cf8af2e7bf174Makoto Onuki
47687bef960a8309410ee1ba0da06a012914bef88eTa-wei Yenimport com.android.internal.annotations.VisibleForTesting;
48dc653a5c1bed274512ce41e4a6129a65d2b0eeacMakoto Onukiimport com.android.providers.contacts.CallLogDatabaseHelper.DbProperties;
49dc653a5c1bed274512ce41e4a6129a65d2b0eeacMakoto Onukiimport com.android.providers.contacts.CallLogDatabaseHelper.Tables;
5038210445730ee04c351c7cc1b3800cfe23e34325Makoto Onukiimport com.android.providers.contacts.util.SelectionBuilder;
513b34457a4cc0d2c55676f366ddc673091a198adbYorke Leeimport com.android.providers.contacts.util.UserUtils;
52607e7e3208b8b40633b3e2c1990cf8af2e7bf174Makoto Onuki
53f3bd980c0ec03db2538e86cadee2c1559f02c85bMakoto Onukiimport java.util.Arrays;
54a16c2509fa398159988861a3fc8408b493fa445bChristine Chenimport java.util.List;
553a219cc3f5045bdebfcd975bf857c6ff26886a22Yorke Leeimport java.util.concurrent.CountDownLatch;
56e99988b266dd1263162583e81e2b408e7329b1c8Dmitri Plotnikov
57e99988b266dd1263162583e81e2b408e7329b1c8Dmitri Plotnikov/**
58e99988b266dd1263162583e81e2b408e7329b1c8Dmitri Plotnikov * Call log content provider.
59e99988b266dd1263162583e81e2b408e7329b1c8Dmitri Plotnikov */
60e99988b266dd1263162583e81e2b408e7329b1c8Dmitri Plotnikovpublic class CallLogProvider extends ContentProvider {
61b95db86983d47262f670ad11b83d6f254f17f229Makoto Onuki    private static final String TAG = "CallLogProvider";
623b34457a4cc0d2c55676f366ddc673091a198adbYorke Lee
63442d7200fb77e2a6d0d3c8d1b17b3b8090581b02Makoto Onuki    public static final boolean VERBOSE_LOGGING = Log.isLoggable(TAG, Log.VERBOSE);
64f3bd980c0ec03db2538e86cadee2c1559f02c85bMakoto Onuki
653a219cc3f5045bdebfcd975bf857c6ff26886a22Yorke Lee    private static final int BACKGROUND_TASK_INITIALIZE = 0;
66b39eeb4f07db680e542ccaf142136a42f9d305f8Santos Cordon    private static final int BACKGROUND_TASK_ADJUST_PHONE_ACCOUNT = 1;
673a219cc3f5045bdebfcd975bf857c6ff26886a22Yorke Lee
683b34457a4cc0d2c55676f366ddc673091a198adbYorke Lee    /** Selection clause for selecting all calls that were made after a certain time */
693b34457a4cc0d2c55676f366ddc673091a198adbYorke Lee    private static final String MORE_RECENT_THAN_SELECTION = Calls.DATE + "> ?";
70aafbe295d67686870c64c74a59e589d1dfb506faDebashish Chatterjee    /** Selection clause to use to exclude voicemail records.  */
71aafbe295d67686870c64c74a59e589d1dfb506faDebashish Chatterjee    private static final String EXCLUDE_VOICEMAIL_SELECTION = getInequalityClause(
729978b26dd17bb2b20b91101f1e4682604336b5f6Flavio Lerda            Calls.TYPE, Calls.VOICEMAIL_TYPE);
73b39eeb4f07db680e542ccaf142136a42f9d305f8Santos Cordon    /** Selection clause to exclude hidden records. */
74b39eeb4f07db680e542ccaf142136a42f9d305f8Santos Cordon    private static final String EXCLUDE_HIDDEN_SELECTION = getEqualityClause(
75b39eeb4f07db680e542ccaf142136a42f9d305f8Santos Cordon            Calls.PHONE_ACCOUNT_HIDDEN, 0);
76aafbe295d67686870c64c74a59e589d1dfb506faDebashish Chatterjee
773b34457a4cc0d2c55676f366ddc673091a198adbYorke Lee    @VisibleForTesting
783b34457a4cc0d2c55676f366ddc673091a198adbYorke Lee    static final String[] CALL_LOG_SYNC_PROJECTION = new String[] {
793b34457a4cc0d2c55676f366ddc673091a198adbYorke Lee        Calls.NUMBER,
803b34457a4cc0d2c55676f366ddc673091a198adbYorke Lee        Calls.NUMBER_PRESENTATION,
813b34457a4cc0d2c55676f366ddc673091a198adbYorke Lee        Calls.TYPE,
823b34457a4cc0d2c55676f366ddc673091a198adbYorke Lee        Calls.FEATURES,
833b34457a4cc0d2c55676f366ddc673091a198adbYorke Lee        Calls.DATE,
843b34457a4cc0d2c55676f366ddc673091a198adbYorke Lee        Calls.DURATION,
853b34457a4cc0d2c55676f366ddc673091a198adbYorke Lee        Calls.DATA_USAGE,
863b34457a4cc0d2c55676f366ddc673091a198adbYorke Lee        Calls.PHONE_ACCOUNT_COMPONENT_NAME,
878bb52d886082c2c331bc513ce9f15c93ebf558ccTony Mak        Calls.PHONE_ACCOUNT_ID,
888bb52d886082c2c331bc513ce9f15c93ebf558ccTony Mak        Calls.ADD_FOR_ALL_USERS
893b34457a4cc0d2c55676f366ddc673091a198adbYorke Lee    };
903b34457a4cc0d2c55676f366ddc673091a198adbYorke Lee
91f7076a627db99f9e845d406650d73be826091367Santos Cordon    static final String[] MINIMAL_PROJECTION = new String[] { Calls._ID };
92f7076a627db99f9e845d406650d73be826091367Santos Cordon
93e99988b266dd1263162583e81e2b408e7329b1c8Dmitri Plotnikov    private static final int CALLS = 1;
94e99988b266dd1263162583e81e2b408e7329b1c8Dmitri Plotnikov
95e99988b266dd1263162583e81e2b408e7329b1c8Dmitri Plotnikov    private static final int CALLS_ID = 2;
96e99988b266dd1263162583e81e2b408e7329b1c8Dmitri Plotnikov
97e99988b266dd1263162583e81e2b408e7329b1c8Dmitri Plotnikov    private static final int CALLS_FILTER = 3;
98e99988b266dd1263162583e81e2b408e7329b1c8Dmitri Plotnikov
99f7076a627db99f9e845d406650d73be826091367Santos Cordon    private static final String UNHIDE_BY_PHONE_ACCOUNT_QUERY =
100b39eeb4f07db680e542ccaf142136a42f9d305f8Santos Cordon            "UPDATE " + Tables.CALLS + " SET " + Calls.PHONE_ACCOUNT_HIDDEN + "=0 WHERE " +
101b39eeb4f07db680e542ccaf142136a42f9d305f8Santos Cordon            Calls.PHONE_ACCOUNT_COMPONENT_NAME + "=? AND " + Calls.PHONE_ACCOUNT_ID + "=?;";
102b39eeb4f07db680e542ccaf142136a42f9d305f8Santos Cordon
103f7076a627db99f9e845d406650d73be826091367Santos Cordon    private static final String UNHIDE_BY_ADDRESS_QUERY =
104f7076a627db99f9e845d406650d73be826091367Santos Cordon            "UPDATE " + Tables.CALLS + " SET " + Calls.PHONE_ACCOUNT_HIDDEN + "=0 WHERE " +
105f7076a627db99f9e845d406650d73be826091367Santos Cordon            Calls.PHONE_ACCOUNT_ADDRESS + "=?;";
106f7076a627db99f9e845d406650d73be826091367Santos Cordon
107e99988b266dd1263162583e81e2b408e7329b1c8Dmitri Plotnikov    private static final UriMatcher sURIMatcher = new UriMatcher(UriMatcher.NO_MATCH);
108e99988b266dd1263162583e81e2b408e7329b1c8Dmitri Plotnikov    static {
109e99988b266dd1263162583e81e2b408e7329b1c8Dmitri Plotnikov        sURIMatcher.addURI(CallLog.AUTHORITY, "calls", CALLS);
110e99988b266dd1263162583e81e2b408e7329b1c8Dmitri Plotnikov        sURIMatcher.addURI(CallLog.AUTHORITY, "calls/#", CALLS_ID);
111e99988b266dd1263162583e81e2b408e7329b1c8Dmitri Plotnikov        sURIMatcher.addURI(CallLog.AUTHORITY, "calls/filter/*", CALLS_FILTER);
112f3bd980c0ec03db2538e86cadee2c1559f02c85bMakoto Onuki
113f3bd980c0ec03db2538e86cadee2c1559f02c85bMakoto Onuki        // Shadow provider only supports "/calls".
114f3bd980c0ec03db2538e86cadee2c1559f02c85bMakoto Onuki        sURIMatcher.addURI(CallLog.SHADOW_AUTHORITY, "calls", CALLS);
115e99988b266dd1263162583e81e2b408e7329b1c8Dmitri Plotnikov    }
116e99988b266dd1263162583e81e2b408e7329b1c8Dmitri Plotnikov
117517d590dc73e5efcf7c94e2431faec2473924ca2Makoto Onuki    private static final ArrayMap<String, String> sCallsProjectionMap;
118e99988b266dd1263162583e81e2b408e7329b1c8Dmitri Plotnikov    static {
119e99988b266dd1263162583e81e2b408e7329b1c8Dmitri Plotnikov
120e99988b266dd1263162583e81e2b408e7329b1c8Dmitri Plotnikov        // Calls projection map
121517d590dc73e5efcf7c94e2431faec2473924ca2Makoto Onuki        sCallsProjectionMap = new ArrayMap<>();
122e99988b266dd1263162583e81e2b408e7329b1c8Dmitri Plotnikov        sCallsProjectionMap.put(Calls._ID, Calls._ID);
123e99988b266dd1263162583e81e2b408e7329b1c8Dmitri Plotnikov        sCallsProjectionMap.put(Calls.NUMBER, Calls.NUMBER);
12417f41872cac002cf4aa7d0e27ebfcc9d782c7873Hall Liu        sCallsProjectionMap.put(Calls.POST_DIAL_DIGITS, Calls.POST_DIAL_DIGITS);
125c8ad9ce59d7ca2c10f4652ee3a0ef4e5d003f767Brad Ebinger        sCallsProjectionMap.put(Calls.VIA_NUMBER, Calls.VIA_NUMBER);
126e31bbc395fc04e9c5f841e8e76475d98c8332271Jay Shrauner        sCallsProjectionMap.put(Calls.NUMBER_PRESENTATION, Calls.NUMBER_PRESENTATION);
127e99988b266dd1263162583e81e2b408e7329b1c8Dmitri Plotnikov        sCallsProjectionMap.put(Calls.DATE, Calls.DATE);
128e99988b266dd1263162583e81e2b408e7329b1c8Dmitri Plotnikov        sCallsProjectionMap.put(Calls.DURATION, Calls.DURATION);
129a315de3cb1c62569f7de1f25ec5b4ad425ebdf07Tyler Gunn        sCallsProjectionMap.put(Calls.DATA_USAGE, Calls.DATA_USAGE);
130e99988b266dd1263162583e81e2b408e7329b1c8Dmitri Plotnikov        sCallsProjectionMap.put(Calls.TYPE, Calls.TYPE);
131a315de3cb1c62569f7de1f25ec5b4ad425ebdf07Tyler Gunn        sCallsProjectionMap.put(Calls.FEATURES, Calls.FEATURES);
132b078d625665a07e1349bcf7b3c6eff56400f9917Ihab Awad        sCallsProjectionMap.put(Calls.PHONE_ACCOUNT_COMPONENT_NAME, Calls.PHONE_ACCOUNT_COMPONENT_NAME);
133b078d625665a07e1349bcf7b3c6eff56400f9917Ihab Awad        sCallsProjectionMap.put(Calls.PHONE_ACCOUNT_ID, Calls.PHONE_ACCOUNT_ID);
134423f9bc8fed50e2caacd6f99f3160494f15c0a67Santos Cordon        sCallsProjectionMap.put(Calls.PHONE_ACCOUNT_ADDRESS, Calls.PHONE_ACCOUNT_ADDRESS);
135e99988b266dd1263162583e81e2b408e7329b1c8Dmitri Plotnikov        sCallsProjectionMap.put(Calls.NEW, Calls.NEW);
13659f6477e10203617f504857f7e9aee2fda393f4fDebashish Chatterjee        sCallsProjectionMap.put(Calls.VOICEMAIL_URI, Calls.VOICEMAIL_URI);
1371d69b2f3576af29b1653ccb372142e04e3e158e9Yorke Lee        sCallsProjectionMap.put(Calls.TRANSCRIPTION, Calls.TRANSCRIPTION);
138bcec6b7482ad50f2ca9025b3b20624dd89b7c000mike dooley        sCallsProjectionMap.put(Calls.TRANSCRIPTION_STATE, Calls.TRANSCRIPTION_STATE);
139b2197b235e3d96e7f70c24d548b7dac52dab88d8Flavio Lerda        sCallsProjectionMap.put(Calls.IS_READ, Calls.IS_READ);
140e99988b266dd1263162583e81e2b408e7329b1c8Dmitri Plotnikov        sCallsProjectionMap.put(Calls.CACHED_NAME, Calls.CACHED_NAME);
141e99988b266dd1263162583e81e2b408e7329b1c8Dmitri Plotnikov        sCallsProjectionMap.put(Calls.CACHED_NUMBER_TYPE, Calls.CACHED_NUMBER_TYPE);
142e99988b266dd1263162583e81e2b408e7329b1c8Dmitri Plotnikov        sCallsProjectionMap.put(Calls.CACHED_NUMBER_LABEL, Calls.CACHED_NUMBER_LABEL);
1432530512f639c4979fd7371c7dd25dd67e8118124Bai Tao        sCallsProjectionMap.put(Calls.COUNTRY_ISO, Calls.COUNTRY_ISO);
144aeaba441ddb05dede8bd86291ca78f42d670d54cFlavio Lerda        sCallsProjectionMap.put(Calls.GEOCODED_LOCATION, Calls.GEOCODED_LOCATION);
1457a24e1c1476b57a6268de8d57e5ef4a2d5f46794Flavio Lerda        sCallsProjectionMap.put(Calls.CACHED_LOOKUP_URI, Calls.CACHED_LOOKUP_URI);
1467a24e1c1476b57a6268de8d57e5ef4a2d5f46794Flavio Lerda        sCallsProjectionMap.put(Calls.CACHED_MATCHED_NUMBER, Calls.CACHED_MATCHED_NUMBER);
1477a24e1c1476b57a6268de8d57e5ef4a2d5f46794Flavio Lerda        sCallsProjectionMap.put(Calls.CACHED_NORMALIZED_NUMBER, Calls.CACHED_NORMALIZED_NUMBER);
1487a24e1c1476b57a6268de8d57e5ef4a2d5f46794Flavio Lerda        sCallsProjectionMap.put(Calls.CACHED_PHOTO_ID, Calls.CACHED_PHOTO_ID);
149693406016fa0b02b4af4188fd9668a3d74881652Makoto Onuki        sCallsProjectionMap.put(Calls.CACHED_PHOTO_URI, Calls.CACHED_PHOTO_URI);
15013ed28505ed1af4f0b4a6297c4c6840d91f10c8cFlavio Lerda        sCallsProjectionMap.put(Calls.CACHED_FORMATTED_NUMBER, Calls.CACHED_FORMATTED_NUMBER);
1518bb52d886082c2c331bc513ce9f15c93ebf558ccTony Mak        sCallsProjectionMap.put(Calls.ADD_FOR_ALL_USERS, Calls.ADD_FOR_ALL_USERS);
15252cb1f8391fdf93ad90d675585a9c7e385e4a8d6Ta-wei Yen        sCallsProjectionMap.put(Calls.LAST_MODIFIED, Calls.LAST_MODIFIED);
153e99988b266dd1263162583e81e2b408e7329b1c8Dmitri Plotnikov    }
154e99988b266dd1263162583e81e2b408e7329b1c8Dmitri Plotnikov
155687bef960a8309410ee1ba0da06a012914bef88eTa-wei Yen    private static final String ALLOWED_PACKAGE_FOR_TESTING = "com.android.providers.contacts";
156687bef960a8309410ee1ba0da06a012914bef88eTa-wei Yen
157687bef960a8309410ee1ba0da06a012914bef88eTa-wei Yen    @VisibleForTesting
158687bef960a8309410ee1ba0da06a012914bef88eTa-wei Yen    static final String PARAM_KEY_QUERY_FOR_TESTING = "query_for_testing";
159687bef960a8309410ee1ba0da06a012914bef88eTa-wei Yen
160687bef960a8309410ee1ba0da06a012914bef88eTa-wei Yen    /**
161687bef960a8309410ee1ba0da06a012914bef88eTa-wei Yen     * A long to override the clock used for timestamps, or "null" to reset to the system clock.
162687bef960a8309410ee1ba0da06a012914bef88eTa-wei Yen     */
163687bef960a8309410ee1ba0da06a012914bef88eTa-wei Yen    @VisibleForTesting
164687bef960a8309410ee1ba0da06a012914bef88eTa-wei Yen    static final String PARAM_KEY_SET_TIME_FOR_TESTING = "set_time_for_testing";
165687bef960a8309410ee1ba0da06a012914bef88eTa-wei Yen
166687bef960a8309410ee1ba0da06a012914bef88eTa-wei Yen    private static Long sTimeForTestMillis;
167687bef960a8309410ee1ba0da06a012914bef88eTa-wei Yen
168607e7e3208b8b40633b3e2c1990cf8af2e7bf174Makoto Onuki    private ContactsTaskScheduler mTaskScheduler;
169607e7e3208b8b40633b3e2c1990cf8af2e7bf174Makoto Onuki
1703a219cc3f5045bdebfcd975bf857c6ff26886a22Yorke Lee    private volatile CountDownLatch mReadAccessLatch;
1713a219cc3f5045bdebfcd975bf857c6ff26886a22Yorke Lee
172dc653a5c1bed274512ce41e4a6129a65d2b0eeacMakoto Onuki    private CallLogDatabaseHelper mDbHelper;
173e99988b266dd1263162583e81e2b408e7329b1c8Dmitri Plotnikov    private DatabaseUtils.InsertHelper mCallsInserter;
1743a6a49cfb06272e3e25f3c390a9cf4002da6e34dDaisuke Miyakawa    private boolean mUseStrictPhoneNumberComparation;
175aafbe295d67686870c64c74a59e589d1dfb506faDebashish Chatterjee    private VoicemailPermissions mVoicemailPermissions;
176aeaba441ddb05dede8bd86291ca78f42d670d54cFlavio Lerda    private CallLogInsertionHelper mCallLogInsertionHelper;
177e99988b266dd1263162583e81e2b408e7329b1c8Dmitri Plotnikov
178f3bd980c0ec03db2538e86cadee2c1559f02c85bMakoto Onuki    protected boolean isShadow() {
179f3bd980c0ec03db2538e86cadee2c1559f02c85bMakoto Onuki        return false;
180f3bd980c0ec03db2538e86cadee2c1559f02c85bMakoto Onuki    }
181f3bd980c0ec03db2538e86cadee2c1559f02c85bMakoto Onuki
182f3bd980c0ec03db2538e86cadee2c1559f02c85bMakoto Onuki    protected final String getProviderName() {
183f3bd980c0ec03db2538e86cadee2c1559f02c85bMakoto Onuki        return this.getClass().getSimpleName();
184f3bd980c0ec03db2538e86cadee2c1559f02c85bMakoto Onuki    }
185f3bd980c0ec03db2538e86cadee2c1559f02c85bMakoto Onuki
186e99988b266dd1263162583e81e2b408e7329b1c8Dmitri Plotnikov    @Override
187e99988b266dd1263162583e81e2b408e7329b1c8Dmitri Plotnikov    public boolean onCreate() {
188b95db86983d47262f670ad11b83d6f254f17f229Makoto Onuki        if (VERBOSE_LOGGING) {
189b95db86983d47262f670ad11b83d6f254f17f229Makoto Onuki            Log.v(TAG, "onCreate: " + this.getClass().getSimpleName()
190b95db86983d47262f670ad11b83d6f254f17f229Makoto Onuki                    + " user=" + android.os.Process.myUserHandle().getIdentifier());
191b95db86983d47262f670ad11b83d6f254f17f229Makoto Onuki        }
192b95db86983d47262f670ad11b83d6f254f17f229Makoto Onuki
193c9626e7befd591923c6af859ad079abba8a84e41Dianne Hackborn        setAppOps(AppOpsManager.OP_READ_CALL_LOG, AppOpsManager.OP_WRITE_CALL_LOG);
194663b8b8ce7a29fb2796dc6431f2cd5992934f315Makoto Onuki        if (Log.isLoggable(Constants.PERFORMANCE_TAG, Log.DEBUG)) {
195f3bd980c0ec03db2538e86cadee2c1559f02c85bMakoto Onuki            Log.d(Constants.PERFORMANCE_TAG, getProviderName() + ".onCreate start");
196663b8b8ce7a29fb2796dc6431f2cd5992934f315Makoto Onuki        }
197e99988b266dd1263162583e81e2b408e7329b1c8Dmitri Plotnikov        final Context context = getContext();
198b38ed2c5ffeb20efc677b4a9229db4a00603aa8dDmitri Plotnikov        mDbHelper = getDatabaseHelper(context);
1993a6a49cfb06272e3e25f3c390a9cf4002da6e34dDaisuke Miyakawa        mUseStrictPhoneNumberComparation =
2003a6a49cfb06272e3e25f3c390a9cf4002da6e34dDaisuke Miyakawa            context.getResources().getBoolean(
2013a6a49cfb06272e3e25f3c390a9cf4002da6e34dDaisuke Miyakawa                    com.android.internal.R.bool.config_use_strict_phone_number_comparation);
202aafbe295d67686870c64c74a59e589d1dfb506faDebashish Chatterjee        mVoicemailPermissions = new VoicemailPermissions(context);
203aeaba441ddb05dede8bd86291ca78f42d670d54cFlavio Lerda        mCallLogInsertionHelper = createCallLogInsertionHelper(context);
2043a219cc3f5045bdebfcd975bf857c6ff26886a22Yorke Lee
205607e7e3208b8b40633b3e2c1990cf8af2e7bf174Makoto Onuki        mReadAccessLatch = new CountDownLatch(1);
206607e7e3208b8b40633b3e2c1990cf8af2e7bf174Makoto Onuki
207607e7e3208b8b40633b3e2c1990cf8af2e7bf174Makoto Onuki        mTaskScheduler = new ContactsTaskScheduler(getClass().getSimpleName()) {
2083a219cc3f5045bdebfcd975bf857c6ff26886a22Yorke Lee            @Override
209607e7e3208b8b40633b3e2c1990cf8af2e7bf174Makoto Onuki            public void onPerformTask(int taskId, Object arg) {
210607e7e3208b8b40633b3e2c1990cf8af2e7bf174Makoto Onuki                performBackgroundTask(taskId, arg);
2113a219cc3f5045bdebfcd975bf857c6ff26886a22Yorke Lee            }
2123a219cc3f5045bdebfcd975bf857c6ff26886a22Yorke Lee        };
2133a219cc3f5045bdebfcd975bf857c6ff26886a22Yorke Lee
214607e7e3208b8b40633b3e2c1990cf8af2e7bf174Makoto Onuki        mTaskScheduler.scheduleTask(BACKGROUND_TASK_INITIALIZE, null);
2153b34457a4cc0d2c55676f366ddc673091a198adbYorke Lee
216663b8b8ce7a29fb2796dc6431f2cd5992934f315Makoto Onuki        if (Log.isLoggable(Constants.PERFORMANCE_TAG, Log.DEBUG)) {
217f3bd980c0ec03db2538e86cadee2c1559f02c85bMakoto Onuki            Log.d(Constants.PERFORMANCE_TAG, getProviderName() + ".onCreate finish");
218663b8b8ce7a29fb2796dc6431f2cd5992934f315Makoto Onuki        }
219e99988b266dd1263162583e81e2b408e7329b1c8Dmitri Plotnikov        return true;
220e99988b266dd1263162583e81e2b408e7329b1c8Dmitri Plotnikov    }
221e99988b266dd1263162583e81e2b408e7329b1c8Dmitri Plotnikov
222aeaba441ddb05dede8bd86291ca78f42d670d54cFlavio Lerda    @VisibleForTesting
223aeaba441ddb05dede8bd86291ca78f42d670d54cFlavio Lerda    protected CallLogInsertionHelper createCallLogInsertionHelper(final Context context) {
224c4144727cd740079f47e74ae5078d1613874f72aMakoto Onuki        return DefaultCallLogInsertionHelper.getInstance(context);
225aeaba441ddb05dede8bd86291ca78f42d670d54cFlavio Lerda    }
226aeaba441ddb05dede8bd86291ca78f42d670d54cFlavio Lerda
227dc653a5c1bed274512ce41e4a6129a65d2b0eeacMakoto Onuki    protected CallLogDatabaseHelper getDatabaseHelper(final Context context) {
228dc653a5c1bed274512ce41e4a6129a65d2b0eeacMakoto Onuki        return CallLogDatabaseHelper.getInstance(context);
229e99988b266dd1263162583e81e2b408e7329b1c8Dmitri Plotnikov    }
230e99988b266dd1263162583e81e2b408e7329b1c8Dmitri Plotnikov
231e99988b266dd1263162583e81e2b408e7329b1c8Dmitri Plotnikov    @Override
232e99988b266dd1263162583e81e2b408e7329b1c8Dmitri Plotnikov    public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs,
233e99988b266dd1263162583e81e2b408e7329b1c8Dmitri Plotnikov            String sortOrder) {
234f3bd980c0ec03db2538e86cadee2c1559f02c85bMakoto Onuki        if (VERBOSE_LOGGING) {
235f3bd980c0ec03db2538e86cadee2c1559f02c85bMakoto Onuki            Log.v(TAG, "query: uri=" + uri + "  projection=" + Arrays.toString(projection) +
236f3bd980c0ec03db2538e86cadee2c1559f02c85bMakoto Onuki                    "  selection=[" + selection + "]  args=" + Arrays.toString(selectionArgs) +
237f3bd980c0ec03db2538e86cadee2c1559f02c85bMakoto Onuki                    "  order=[" + sortOrder + "] CPID=" + Binder.getCallingPid() +
238f3bd980c0ec03db2538e86cadee2c1559f02c85bMakoto Onuki                    " User=" + UserUtils.getCurrentUserHandle(getContext()));
239f3bd980c0ec03db2538e86cadee2c1559f02c85bMakoto Onuki        }
240687bef960a8309410ee1ba0da06a012914bef88eTa-wei Yen
241687bef960a8309410ee1ba0da06a012914bef88eTa-wei Yen        queryForTesting(uri);
242687bef960a8309410ee1ba0da06a012914bef88eTa-wei Yen
2433a219cc3f5045bdebfcd975bf857c6ff26886a22Yorke Lee        waitForAccess(mReadAccessLatch);
244143bb522fcfb4a08c7f112876f3fac1cf47cf5aeChiao Cheng        final SQLiteQueryBuilder qb = new SQLiteQueryBuilder();
24559f6477e10203617f504857f7e9aee2fda393f4fDebashish Chatterjee        qb.setTables(Tables.CALLS);
24659f6477e10203617f504857f7e9aee2fda393f4fDebashish Chatterjee        qb.setProjectionMap(sCallsProjectionMap);
24759f6477e10203617f504857f7e9aee2fda393f4fDebashish Chatterjee        qb.setStrict(true);
24859f6477e10203617f504857f7e9aee2fda393f4fDebashish Chatterjee
249143bb522fcfb4a08c7f112876f3fac1cf47cf5aeChiao Cheng        final SelectionBuilder selectionBuilder = new SelectionBuilder(selection);
2503ccaf5590a7ed2fca780f9b7fc46328d0f78a2eefafaisland        checkVoicemailPermissionAndAddRestriction(uri, selectionBuilder, true /*isQuery*/);
251b39eeb4f07db680e542ccaf142136a42f9d305f8Santos Cordon        selectionBuilder.addClause(EXCLUDE_HIDDEN_SELECTION);
252aafbe295d67686870c64c74a59e589d1dfb506faDebashish Chatterjee
253143bb522fcfb4a08c7f112876f3fac1cf47cf5aeChiao Cheng        final int match = sURIMatcher.match(uri);
254e99988b266dd1263162583e81e2b408e7329b1c8Dmitri Plotnikov        switch (match) {
25559f6477e10203617f504857f7e9aee2fda393f4fDebashish Chatterjee            case CALLS:
256e99988b266dd1263162583e81e2b408e7329b1c8Dmitri Plotnikov                break;
257e99988b266dd1263162583e81e2b408e7329b1c8Dmitri Plotnikov
258e99988b266dd1263162583e81e2b408e7329b1c8Dmitri Plotnikov            case CALLS_ID: {
259aafbe295d67686870c64c74a59e589d1dfb506faDebashish Chatterjee                selectionBuilder.addClause(getEqualityClause(Calls._ID,
260aafbe295d67686870c64c74a59e589d1dfb506faDebashish Chatterjee                        parseCallIdFromUri(uri)));
261e99988b266dd1263162583e81e2b408e7329b1c8Dmitri Plotnikov                break;
262e99988b266dd1263162583e81e2b408e7329b1c8Dmitri Plotnikov            }
263e99988b266dd1263162583e81e2b408e7329b1c8Dmitri Plotnikov
264e99988b266dd1263162583e81e2b408e7329b1c8Dmitri Plotnikov            case CALLS_FILTER: {
265a16c2509fa398159988861a3fc8408b493fa445bChristine Chen                List<String> pathSegments = uri.getPathSegments();
266a16c2509fa398159988861a3fc8408b493fa445bChristine Chen                String phoneNumber = pathSegments.size() >= 2 ? pathSegments.get(2) : null;
267a16c2509fa398159988861a3fc8408b493fa445bChristine Chen                if (!TextUtils.isEmpty(phoneNumber)) {
268a16c2509fa398159988861a3fc8408b493fa445bChristine Chen                    qb.appendWhere("PHONE_NUMBERS_EQUAL(number, ");
269a16c2509fa398159988861a3fc8408b493fa445bChristine Chen                    qb.appendWhereEscapeString(phoneNumber);
270a16c2509fa398159988861a3fc8408b493fa445bChristine Chen                    qb.appendWhere(mUseStrictPhoneNumberComparation ? ", 1)" : ", 0)");
271a16c2509fa398159988861a3fc8408b493fa445bChristine Chen                } else {
272a16c2509fa398159988861a3fc8408b493fa445bChristine Chen                    qb.appendWhere(Calls.NUMBER_PRESENTATION + "!="
273a16c2509fa398159988861a3fc8408b493fa445bChristine Chen                            + Calls.PRESENTATION_ALLOWED);
274a16c2509fa398159988861a3fc8408b493fa445bChristine Chen                }
275e99988b266dd1263162583e81e2b408e7329b1c8Dmitri Plotnikov                break;
276e99988b266dd1263162583e81e2b408e7329b1c8Dmitri Plotnikov            }
277e99988b266dd1263162583e81e2b408e7329b1c8Dmitri Plotnikov
278e99988b266dd1263162583e81e2b408e7329b1c8Dmitri Plotnikov            default:
279e99988b266dd1263162583e81e2b408e7329b1c8Dmitri Plotnikov                throw new IllegalArgumentException("Unknown URL " + uri);
280e99988b266dd1263162583e81e2b408e7329b1c8Dmitri Plotnikov        }
281e99988b266dd1263162583e81e2b408e7329b1c8Dmitri Plotnikov
282143bb522fcfb4a08c7f112876f3fac1cf47cf5aeChiao Cheng        final int limit = getIntParam(uri, Calls.LIMIT_PARAM_KEY, 0);
283143bb522fcfb4a08c7f112876f3fac1cf47cf5aeChiao Cheng        final int offset = getIntParam(uri, Calls.OFFSET_PARAM_KEY, 0);
284143bb522fcfb4a08c7f112876f3fac1cf47cf5aeChiao Cheng        String limitClause = null;
285143bb522fcfb4a08c7f112876f3fac1cf47cf5aeChiao Cheng        if (limit > 0) {
286143bb522fcfb4a08c7f112876f3fac1cf47cf5aeChiao Cheng            limitClause = offset + "," + limit;
287143bb522fcfb4a08c7f112876f3fac1cf47cf5aeChiao Cheng        }
288143bb522fcfb4a08c7f112876f3fac1cf47cf5aeChiao Cheng
289b38ed2c5ffeb20efc677b4a9229db4a00603aa8dDmitri Plotnikov        final SQLiteDatabase db = mDbHelper.getReadableDatabase();
290143bb522fcfb4a08c7f112876f3fac1cf47cf5aeChiao Cheng        final Cursor c = qb.query(db, projection, selectionBuilder.build(), selectionArgs, null,
291143bb522fcfb4a08c7f112876f3fac1cf47cf5aeChiao Cheng                null, sortOrder, limitClause);
292e99988b266dd1263162583e81e2b408e7329b1c8Dmitri Plotnikov        if (c != null) {
293e99988b266dd1263162583e81e2b408e7329b1c8Dmitri Plotnikov            c.setNotificationUri(getContext().getContentResolver(), CallLog.CONTENT_URI);
294e99988b266dd1263162583e81e2b408e7329b1c8Dmitri Plotnikov        }
295e99988b266dd1263162583e81e2b408e7329b1c8Dmitri Plotnikov        return c;
296e99988b266dd1263162583e81e2b408e7329b1c8Dmitri Plotnikov    }
297e99988b266dd1263162583e81e2b408e7329b1c8Dmitri Plotnikov
298687bef960a8309410ee1ba0da06a012914bef88eTa-wei Yen    private void queryForTesting(Uri uri) {
299687bef960a8309410ee1ba0da06a012914bef88eTa-wei Yen        if (!uri.getBooleanQueryParameter(PARAM_KEY_QUERY_FOR_TESTING, false)) {
300687bef960a8309410ee1ba0da06a012914bef88eTa-wei Yen            return;
301687bef960a8309410ee1ba0da06a012914bef88eTa-wei Yen        }
302687bef960a8309410ee1ba0da06a012914bef88eTa-wei Yen        if (!getCallingPackage().equals(ALLOWED_PACKAGE_FOR_TESTING)) {
303687bef960a8309410ee1ba0da06a012914bef88eTa-wei Yen            throw new IllegalArgumentException("query_for_testing set from foreign package "
304687bef960a8309410ee1ba0da06a012914bef88eTa-wei Yen                    + getCallingPackage());
305687bef960a8309410ee1ba0da06a012914bef88eTa-wei Yen        }
306687bef960a8309410ee1ba0da06a012914bef88eTa-wei Yen
307687bef960a8309410ee1ba0da06a012914bef88eTa-wei Yen        String timeString = uri.getQueryParameter(PARAM_KEY_SET_TIME_FOR_TESTING);
308687bef960a8309410ee1ba0da06a012914bef88eTa-wei Yen        if (timeString != null) {
309687bef960a8309410ee1ba0da06a012914bef88eTa-wei Yen            if (timeString.equals("null")) {
310687bef960a8309410ee1ba0da06a012914bef88eTa-wei Yen                sTimeForTestMillis = null;
311687bef960a8309410ee1ba0da06a012914bef88eTa-wei Yen            } else {
312687bef960a8309410ee1ba0da06a012914bef88eTa-wei Yen                sTimeForTestMillis = Long.parseLong(timeString);
313687bef960a8309410ee1ba0da06a012914bef88eTa-wei Yen            }
314687bef960a8309410ee1ba0da06a012914bef88eTa-wei Yen        }
315687bef960a8309410ee1ba0da06a012914bef88eTa-wei Yen    }
316687bef960a8309410ee1ba0da06a012914bef88eTa-wei Yen
317687bef960a8309410ee1ba0da06a012914bef88eTa-wei Yen    @VisibleForTesting
318687bef960a8309410ee1ba0da06a012914bef88eTa-wei Yen    static Long getTimeForTestMillis() {
319687bef960a8309410ee1ba0da06a012914bef88eTa-wei Yen        return sTimeForTestMillis;
320687bef960a8309410ee1ba0da06a012914bef88eTa-wei Yen    }
321687bef960a8309410ee1ba0da06a012914bef88eTa-wei Yen
322143bb522fcfb4a08c7f112876f3fac1cf47cf5aeChiao Cheng    /**
323143bb522fcfb4a08c7f112876f3fac1cf47cf5aeChiao Cheng     * Gets an integer query parameter from a given uri.
324143bb522fcfb4a08c7f112876f3fac1cf47cf5aeChiao Cheng     *
325143bb522fcfb4a08c7f112876f3fac1cf47cf5aeChiao Cheng     * @param uri The uri to extract the query parameter from.
326143bb522fcfb4a08c7f112876f3fac1cf47cf5aeChiao Cheng     * @param key The query parameter key.
327143bb522fcfb4a08c7f112876f3fac1cf47cf5aeChiao Cheng     * @param defaultValue A default value to return if the query parameter does not exist.
328143bb522fcfb4a08c7f112876f3fac1cf47cf5aeChiao Cheng     * @return The value from the query parameter in the Uri.  Or the default value if the parameter
329143bb522fcfb4a08c7f112876f3fac1cf47cf5aeChiao Cheng     * does not exist in the uri.
330143bb522fcfb4a08c7f112876f3fac1cf47cf5aeChiao Cheng     * @throws IllegalArgumentException when the value in the query parameter is not an integer.
331143bb522fcfb4a08c7f112876f3fac1cf47cf5aeChiao Cheng     */
332143bb522fcfb4a08c7f112876f3fac1cf47cf5aeChiao Cheng    private int getIntParam(Uri uri, String key, int defaultValue) {
333143bb522fcfb4a08c7f112876f3fac1cf47cf5aeChiao Cheng        String valueString = uri.getQueryParameter(key);
334143bb522fcfb4a08c7f112876f3fac1cf47cf5aeChiao Cheng        if (valueString == null) {
335143bb522fcfb4a08c7f112876f3fac1cf47cf5aeChiao Cheng            return defaultValue;
336143bb522fcfb4a08c7f112876f3fac1cf47cf5aeChiao Cheng        }
337143bb522fcfb4a08c7f112876f3fac1cf47cf5aeChiao Cheng
338143bb522fcfb4a08c7f112876f3fac1cf47cf5aeChiao Cheng        try {
339143bb522fcfb4a08c7f112876f3fac1cf47cf5aeChiao Cheng            return Integer.parseInt(valueString);
340143bb522fcfb4a08c7f112876f3fac1cf47cf5aeChiao Cheng        } catch (NumberFormatException e) {
341143bb522fcfb4a08c7f112876f3fac1cf47cf5aeChiao Cheng            String msg = "Integer required for " + key + " parameter but value '" + valueString +
342143bb522fcfb4a08c7f112876f3fac1cf47cf5aeChiao Cheng                    "' was found instead.";
343143bb522fcfb4a08c7f112876f3fac1cf47cf5aeChiao Cheng            throw new IllegalArgumentException(msg, e);
344143bb522fcfb4a08c7f112876f3fac1cf47cf5aeChiao Cheng        }
345143bb522fcfb4a08c7f112876f3fac1cf47cf5aeChiao Cheng    }
346143bb522fcfb4a08c7f112876f3fac1cf47cf5aeChiao Cheng
347e99988b266dd1263162583e81e2b408e7329b1c8Dmitri Plotnikov    @Override
348e99988b266dd1263162583e81e2b408e7329b1c8Dmitri Plotnikov    public String getType(Uri uri) {
349e99988b266dd1263162583e81e2b408e7329b1c8Dmitri Plotnikov        int match = sURIMatcher.match(uri);
350e99988b266dd1263162583e81e2b408e7329b1c8Dmitri Plotnikov        switch (match) {
351e99988b266dd1263162583e81e2b408e7329b1c8Dmitri Plotnikov            case CALLS:
352e99988b266dd1263162583e81e2b408e7329b1c8Dmitri Plotnikov                return Calls.CONTENT_TYPE;
353e99988b266dd1263162583e81e2b408e7329b1c8Dmitri Plotnikov            case CALLS_ID:
354e99988b266dd1263162583e81e2b408e7329b1c8Dmitri Plotnikov                return Calls.CONTENT_ITEM_TYPE;
355e99988b266dd1263162583e81e2b408e7329b1c8Dmitri Plotnikov            case CALLS_FILTER:
356e99988b266dd1263162583e81e2b408e7329b1c8Dmitri Plotnikov                return Calls.CONTENT_TYPE;
357e99988b266dd1263162583e81e2b408e7329b1c8Dmitri Plotnikov            default:
358e99988b266dd1263162583e81e2b408e7329b1c8Dmitri Plotnikov                throw new IllegalArgumentException("Unknown URI: " + uri);
359e99988b266dd1263162583e81e2b408e7329b1c8Dmitri Plotnikov        }
360e99988b266dd1263162583e81e2b408e7329b1c8Dmitri Plotnikov    }
361e99988b266dd1263162583e81e2b408e7329b1c8Dmitri Plotnikov
362e99988b266dd1263162583e81e2b408e7329b1c8Dmitri Plotnikov    @Override
363e99988b266dd1263162583e81e2b408e7329b1c8Dmitri Plotnikov    public Uri insert(Uri uri, ContentValues values) {
364f3bd980c0ec03db2538e86cadee2c1559f02c85bMakoto Onuki        if (VERBOSE_LOGGING) {
365f3bd980c0ec03db2538e86cadee2c1559f02c85bMakoto Onuki            Log.v(TAG, "insert: uri=" + uri + "  values=[" + values + "]" +
366f3bd980c0ec03db2538e86cadee2c1559f02c85bMakoto Onuki                    " CPID=" + Binder.getCallingPid());
367f3bd980c0ec03db2538e86cadee2c1559f02c85bMakoto Onuki        }
3683a219cc3f5045bdebfcd975bf857c6ff26886a22Yorke Lee        waitForAccess(mReadAccessLatch);
36900e7c94b70f4b477653534dbe559d1759d796157Debashish Chatterjee        checkForSupportedColumns(sCallsProjectionMap, values);
370aafbe295d67686870c64c74a59e589d1dfb506faDebashish Chatterjee        // Inserting a voicemail record through call_log requires the voicemail
371aafbe295d67686870c64c74a59e589d1dfb506faDebashish Chatterjee        // permission and also requires the additional voicemail param set.
372aafbe295d67686870c64c74a59e589d1dfb506faDebashish Chatterjee        if (hasVoicemailValue(values)) {
373aafbe295d67686870c64c74a59e589d1dfb506faDebashish Chatterjee            checkIsAllowVoicemailRequest(uri);
37477b65aa3d1c2db02ce664c4b31e10370efe645cbYorke Lee            mVoicemailPermissions.checkCallerHasWriteAccess(getCallingPackage());
375aafbe295d67686870c64c74a59e589d1dfb506faDebashish Chatterjee        }
37637c85b89cc989308749ea22b1ce29c59a47158acDmitri Plotnikov        if (mCallsInserter == null) {
37737c85b89cc989308749ea22b1ce29c59a47158acDmitri Plotnikov            SQLiteDatabase db = mDbHelper.getWritableDatabase();
37837c85b89cc989308749ea22b1ce29c59a47158acDmitri Plotnikov            mCallsInserter = new DatabaseUtils.InsertHelper(db, Tables.CALLS);
37937c85b89cc989308749ea22b1ce29c59a47158acDmitri Plotnikov        }
380f402aaf776fee29d8044d97979b16695f24086ddFlavio Lerda
381f402aaf776fee29d8044d97979b16695f24086ddFlavio Lerda        ContentValues copiedValues = new ContentValues(values);
382f402aaf776fee29d8044d97979b16695f24086ddFlavio Lerda
383f402aaf776fee29d8044d97979b16695f24086ddFlavio Lerda        // Add the computed fields to the copied values.
384f402aaf776fee29d8044d97979b16695f24086ddFlavio Lerda        mCallLogInsertionHelper.addComputedValues(copiedValues);
385f402aaf776fee29d8044d97979b16695f24086ddFlavio Lerda
386f402aaf776fee29d8044d97979b16695f24086ddFlavio Lerda        long rowId = getDatabaseModifier(mCallsInserter).insert(copiedValues);
387e99988b266dd1263162583e81e2b408e7329b1c8Dmitri Plotnikov        if (rowId > 0) {
388e99988b266dd1263162583e81e2b408e7329b1c8Dmitri Plotnikov            return ContentUris.withAppendedId(uri, rowId);
389e99988b266dd1263162583e81e2b408e7329b1c8Dmitri Plotnikov        }
390e99988b266dd1263162583e81e2b408e7329b1c8Dmitri Plotnikov        return null;
391e99988b266dd1263162583e81e2b408e7329b1c8Dmitri Plotnikov    }
392e99988b266dd1263162583e81e2b408e7329b1c8Dmitri Plotnikov
393e99988b266dd1263162583e81e2b408e7329b1c8Dmitri Plotnikov    @Override
394aafbe295d67686870c64c74a59e589d1dfb506faDebashish Chatterjee    public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) {
395f3bd980c0ec03db2538e86cadee2c1559f02c85bMakoto Onuki        if (VERBOSE_LOGGING) {
396f3bd980c0ec03db2538e86cadee2c1559f02c85bMakoto Onuki            Log.v(TAG, "update: uri=" + uri +
397f3bd980c0ec03db2538e86cadee2c1559f02c85bMakoto Onuki                    "  selection=[" + selection + "]  args=" + Arrays.toString(selectionArgs) +
398f3bd980c0ec03db2538e86cadee2c1559f02c85bMakoto Onuki                    "  values=[" + values + "] CPID=" + Binder.getCallingPid() +
399f3bd980c0ec03db2538e86cadee2c1559f02c85bMakoto Onuki                    " User=" + UserUtils.getCurrentUserHandle(getContext()));
400f3bd980c0ec03db2538e86cadee2c1559f02c85bMakoto Onuki        }
4013a219cc3f5045bdebfcd975bf857c6ff26886a22Yorke Lee        waitForAccess(mReadAccessLatch);
40200e7c94b70f4b477653534dbe559d1759d796157Debashish Chatterjee        checkForSupportedColumns(sCallsProjectionMap, values);
403aafbe295d67686870c64c74a59e589d1dfb506faDebashish Chatterjee        // Request that involves changing record type to voicemail requires the
404aafbe295d67686870c64c74a59e589d1dfb506faDebashish Chatterjee        // voicemail param set in the uri.
405aafbe295d67686870c64c74a59e589d1dfb506faDebashish Chatterjee        if (hasVoicemailValue(values)) {
406aafbe295d67686870c64c74a59e589d1dfb506faDebashish Chatterjee            checkIsAllowVoicemailRequest(uri);
407aafbe295d67686870c64c74a59e589d1dfb506faDebashish Chatterjee        }
408aafbe295d67686870c64c74a59e589d1dfb506faDebashish Chatterjee
409aafbe295d67686870c64c74a59e589d1dfb506faDebashish Chatterjee        SelectionBuilder selectionBuilder = new SelectionBuilder(selection);
4103ccaf5590a7ed2fca780f9b7fc46328d0f78a2eefafaisland        checkVoicemailPermissionAndAddRestriction(uri, selectionBuilder, false /*isQuery*/);
411aafbe295d67686870c64c74a59e589d1dfb506faDebashish Chatterjee
412b38ed2c5ffeb20efc677b4a9229db4a00603aa8dDmitri Plotnikov        final SQLiteDatabase db = mDbHelper.getWritableDatabase();
413aafbe295d67686870c64c74a59e589d1dfb506faDebashish Chatterjee        final int matchedUriId = sURIMatcher.match(uri);
414e99988b266dd1263162583e81e2b408e7329b1c8Dmitri Plotnikov        switch (matchedUriId) {
415e99988b266dd1263162583e81e2b408e7329b1c8Dmitri Plotnikov            case CALLS:
416e99988b266dd1263162583e81e2b408e7329b1c8Dmitri Plotnikov                break;
417e99988b266dd1263162583e81e2b408e7329b1c8Dmitri Plotnikov
418e99988b266dd1263162583e81e2b408e7329b1c8Dmitri Plotnikov            case CALLS_ID:
419aafbe295d67686870c64c74a59e589d1dfb506faDebashish Chatterjee                selectionBuilder.addClause(getEqualityClause(Calls._ID, parseCallIdFromUri(uri)));
420e99988b266dd1263162583e81e2b408e7329b1c8Dmitri Plotnikov                break;
421e99988b266dd1263162583e81e2b408e7329b1c8Dmitri Plotnikov
422e99988b266dd1263162583e81e2b408e7329b1c8Dmitri Plotnikov            default:
423aafbe295d67686870c64c74a59e589d1dfb506faDebashish Chatterjee                throw new UnsupportedOperationException("Cannot update URL: " + uri);
424e99988b266dd1263162583e81e2b408e7329b1c8Dmitri Plotnikov        }
425e99988b266dd1263162583e81e2b408e7329b1c8Dmitri Plotnikov
426a0722de4886cdc06acf344052b70954415d25d80Ta-wei Yen        return getDatabaseModifier(db).update(uri, Tables.CALLS, values, selectionBuilder.build(),
4272e757d904e62dbf5bc0b028626fa9319ccc38c45Debashish Chatterjee                selectionArgs);
428e99988b266dd1263162583e81e2b408e7329b1c8Dmitri Plotnikov    }
429e99988b266dd1263162583e81e2b408e7329b1c8Dmitri Plotnikov
430e99988b266dd1263162583e81e2b408e7329b1c8Dmitri Plotnikov    @Override
431e99988b266dd1263162583e81e2b408e7329b1c8Dmitri Plotnikov    public int delete(Uri uri, String selection, String[] selectionArgs) {
432f3bd980c0ec03db2538e86cadee2c1559f02c85bMakoto Onuki        if (VERBOSE_LOGGING) {
433f3bd980c0ec03db2538e86cadee2c1559f02c85bMakoto Onuki            Log.v(TAG, "delete: uri=" + uri +
434f3bd980c0ec03db2538e86cadee2c1559f02c85bMakoto Onuki                    "  selection=[" + selection + "]  args=" + Arrays.toString(selectionArgs) +
435f3bd980c0ec03db2538e86cadee2c1559f02c85bMakoto Onuki                    " CPID=" + Binder.getCallingPid() +
436f3bd980c0ec03db2538e86cadee2c1559f02c85bMakoto Onuki                    " User=" + UserUtils.getCurrentUserHandle(getContext()));
437f3bd980c0ec03db2538e86cadee2c1559f02c85bMakoto Onuki        }
4383a219cc3f5045bdebfcd975bf857c6ff26886a22Yorke Lee        waitForAccess(mReadAccessLatch);
439aafbe295d67686870c64c74a59e589d1dfb506faDebashish Chatterjee        SelectionBuilder selectionBuilder = new SelectionBuilder(selection);
4403ccaf5590a7ed2fca780f9b7fc46328d0f78a2eefafaisland        checkVoicemailPermissionAndAddRestriction(uri, selectionBuilder, false /*isQuery*/);
441e99988b266dd1263162583e81e2b408e7329b1c8Dmitri Plotnikov
442aafbe295d67686870c64c74a59e589d1dfb506faDebashish Chatterjee        final SQLiteDatabase db = mDbHelper.getWritableDatabase();
443e99988b266dd1263162583e81e2b408e7329b1c8Dmitri Plotnikov        final int matchedUriId = sURIMatcher.match(uri);
444e99988b266dd1263162583e81e2b408e7329b1c8Dmitri Plotnikov        switch (matchedUriId) {
445e99988b266dd1263162583e81e2b408e7329b1c8Dmitri Plotnikov            case CALLS:
446f3bd980c0ec03db2538e86cadee2c1559f02c85bMakoto Onuki                // TODO: Special case - We may want to forward the delete request on user 0 to the
447f3bd980c0ec03db2538e86cadee2c1559f02c85bMakoto Onuki                // shadow provider too.
4482e757d904e62dbf5bc0b028626fa9319ccc38c45Debashish Chatterjee                return getDatabaseModifier(db).delete(Tables.CALLS,
449929a04e2830e30718930d96335dfb0a729b6ab91Debashish Chatterjee                        selectionBuilder.build(), selectionArgs);
450e99988b266dd1263162583e81e2b408e7329b1c8Dmitri Plotnikov            default:
451e99988b266dd1263162583e81e2b408e7329b1c8Dmitri Plotnikov                throw new UnsupportedOperationException("Cannot delete that URL: " + uri);
452e99988b266dd1263162583e81e2b408e7329b1c8Dmitri Plotnikov        }
453e99988b266dd1263162583e81e2b408e7329b1c8Dmitri Plotnikov    }
4546f157d1cfb219f80d375c1357bfbdc5bf599d91aDmitri Plotnikov
455b39eeb4f07db680e542ccaf142136a42f9d305f8Santos Cordon    void adjustForNewPhoneAccount(PhoneAccountHandle handle) {
456607e7e3208b8b40633b3e2c1990cf8af2e7bf174Makoto Onuki        mTaskScheduler.scheduleTask(BACKGROUND_TASK_ADJUST_PHONE_ACCOUNT, handle);
457b39eeb4f07db680e542ccaf142136a42f9d305f8Santos Cordon    }
458b39eeb4f07db680e542ccaf142136a42f9d305f8Santos Cordon
4592e757d904e62dbf5bc0b028626fa9319ccc38c45Debashish Chatterjee    /**
4602e757d904e62dbf5bc0b028626fa9319ccc38c45Debashish Chatterjee     * Returns a {@link DatabaseModifier} that takes care of sending necessary notifications
4612e757d904e62dbf5bc0b028626fa9319ccc38c45Debashish Chatterjee     * after the operation is performed.
4622e757d904e62dbf5bc0b028626fa9319ccc38c45Debashish Chatterjee     */
463929a04e2830e30718930d96335dfb0a729b6ab91Debashish Chatterjee    private DatabaseModifier getDatabaseModifier(SQLiteDatabase db) {
464dc653a5c1bed274512ce41e4a6129a65d2b0eeacMakoto Onuki        return new DbModifierWithNotification(Tables.CALLS, db, getContext());
465929a04e2830e30718930d96335dfb0a729b6ab91Debashish Chatterjee    }
466929a04e2830e30718930d96335dfb0a729b6ab91Debashish Chatterjee
4672e757d904e62dbf5bc0b028626fa9319ccc38c45Debashish Chatterjee    /**
4682e757d904e62dbf5bc0b028626fa9319ccc38c45Debashish Chatterjee     * Same as {@link #getDatabaseModifier(SQLiteDatabase)} but used for insert helper operations
4692e757d904e62dbf5bc0b028626fa9319ccc38c45Debashish Chatterjee     * only.
4702e757d904e62dbf5bc0b028626fa9319ccc38c45Debashish Chatterjee     */
471929a04e2830e30718930d96335dfb0a729b6ab91Debashish Chatterjee    private DatabaseModifier getDatabaseModifier(DatabaseUtils.InsertHelper insertHelper) {
472dc653a5c1bed274512ce41e4a6129a65d2b0eeacMakoto Onuki        return new DbModifierWithNotification(Tables.CALLS, insertHelper, getContext());
473929a04e2830e30718930d96335dfb0a729b6ab91Debashish Chatterjee    }
474929a04e2830e30718930d96335dfb0a729b6ab91Debashish Chatterjee
475ee1267f05b98218d26f39875949cbc66a8a9b71dJay Shrauner    private static final Integer VOICEMAIL_TYPE = new Integer(Calls.VOICEMAIL_TYPE);
476aafbe295d67686870c64c74a59e589d1dfb506faDebashish Chatterjee    private boolean hasVoicemailValue(ContentValues values) {
477ee1267f05b98218d26f39875949cbc66a8a9b71dJay Shrauner        return VOICEMAIL_TYPE.equals(values.getAsInteger(Calls.TYPE));
478aafbe295d67686870c64c74a59e589d1dfb506faDebashish Chatterjee    }
479aafbe295d67686870c64c74a59e589d1dfb506faDebashish Chatterjee
480aafbe295d67686870c64c74a59e589d1dfb506faDebashish Chatterjee    /**
481aafbe295d67686870c64c74a59e589d1dfb506faDebashish Chatterjee     * Checks if the supplied uri requests to include voicemails and take appropriate
482aafbe295d67686870c64c74a59e589d1dfb506faDebashish Chatterjee     * action.
483aafbe295d67686870c64c74a59e589d1dfb506faDebashish Chatterjee     * <p> If voicemail is requested, then check for voicemail permissions. Otherwise
484aafbe295d67686870c64c74a59e589d1dfb506faDebashish Chatterjee     * modify the selection to restrict to non-voicemail entries only.
485aafbe295d67686870c64c74a59e589d1dfb506faDebashish Chatterjee     */
486aafbe295d67686870c64c74a59e589d1dfb506faDebashish Chatterjee    private void checkVoicemailPermissionAndAddRestriction(Uri uri,
4873ccaf5590a7ed2fca780f9b7fc46328d0f78a2eefafaisland            SelectionBuilder selectionBuilder, boolean isQuery) {
488aafbe295d67686870c64c74a59e589d1dfb506faDebashish Chatterjee        if (isAllowVoicemailRequest(uri)) {
489ab2ec1d4316770e2ce8dc47dd1ae71430cd70e36Yorke Lee            if (isQuery) {
49077b65aa3d1c2db02ce664c4b31e10370efe645cbYorke Lee                mVoicemailPermissions.checkCallerHasReadAccess(getCallingPackage());
491ab2ec1d4316770e2ce8dc47dd1ae71430cd70e36Yorke Lee            } else {
49277b65aa3d1c2db02ce664c4b31e10370efe645cbYorke Lee                mVoicemailPermissions.checkCallerHasWriteAccess(getCallingPackage());
4933ccaf5590a7ed2fca780f9b7fc46328d0f78a2eefafaisland            }
494aafbe295d67686870c64c74a59e589d1dfb506faDebashish Chatterjee        } else {
495aafbe295d67686870c64c74a59e589d1dfb506faDebashish Chatterjee            selectionBuilder.addClause(EXCLUDE_VOICEMAIL_SELECTION);
496aafbe295d67686870c64c74a59e589d1dfb506faDebashish Chatterjee        }
497aafbe295d67686870c64c74a59e589d1dfb506faDebashish Chatterjee    }
498aafbe295d67686870c64c74a59e589d1dfb506faDebashish Chatterjee
499aafbe295d67686870c64c74a59e589d1dfb506faDebashish Chatterjee    /**
500aafbe295d67686870c64c74a59e589d1dfb506faDebashish Chatterjee     * Determines if the supplied uri has the request to allow voicemails to be
501aafbe295d67686870c64c74a59e589d1dfb506faDebashish Chatterjee     * included.
502aafbe295d67686870c64c74a59e589d1dfb506faDebashish Chatterjee     */
503aafbe295d67686870c64c74a59e589d1dfb506faDebashish Chatterjee    private boolean isAllowVoicemailRequest(Uri uri) {
50492d97071e56110e0df7f25e6ebc92ff4ebf74a88Flavio Lerda        return uri.getBooleanQueryParameter(Calls.ALLOW_VOICEMAILS_PARAM_KEY, false);
505aafbe295d67686870c64c74a59e589d1dfb506faDebashish Chatterjee    }
506aafbe295d67686870c64c74a59e589d1dfb506faDebashish Chatterjee
507aafbe295d67686870c64c74a59e589d1dfb506faDebashish Chatterjee    /**
508aafbe295d67686870c64c74a59e589d1dfb506faDebashish Chatterjee     * Checks to ensure that the given uri has allow_voicemail set. Used by
509aafbe295d67686870c64c74a59e589d1dfb506faDebashish Chatterjee     * insert and update operations to check that ContentValues with voicemail
510aafbe295d67686870c64c74a59e589d1dfb506faDebashish Chatterjee     * call type must use the voicemail uri.
511aafbe295d67686870c64c74a59e589d1dfb506faDebashish Chatterjee     * @throws IllegalArgumentException if allow_voicemail is not set.
512aafbe295d67686870c64c74a59e589d1dfb506faDebashish Chatterjee     */
513aafbe295d67686870c64c74a59e589d1dfb506faDebashish Chatterjee    private void checkIsAllowVoicemailRequest(Uri uri) {
514aafbe295d67686870c64c74a59e589d1dfb506faDebashish Chatterjee        if (!isAllowVoicemailRequest(uri)) {
515aafbe295d67686870c64c74a59e589d1dfb506faDebashish Chatterjee            throw new IllegalArgumentException(
516aafbe295d67686870c64c74a59e589d1dfb506faDebashish Chatterjee                    String.format("Uri %s cannot be used for voicemail record." +
51792d97071e56110e0df7f25e6ebc92ff4ebf74a88Flavio Lerda                            " Please set '%s=true' in the uri.", uri,
51892d97071e56110e0df7f25e6ebc92ff4ebf74a88Flavio Lerda                            Calls.ALLOW_VOICEMAILS_PARAM_KEY));
519aafbe295d67686870c64c74a59e589d1dfb506faDebashish Chatterjee        }
520aafbe295d67686870c64c74a59e589d1dfb506faDebashish Chatterjee    }
521aafbe295d67686870c64c74a59e589d1dfb506faDebashish Chatterjee
522aafbe295d67686870c64c74a59e589d1dfb506faDebashish Chatterjee   /**
523aafbe295d67686870c64c74a59e589d1dfb506faDebashish Chatterjee    * Parses the call Id from the given uri, assuming that this is a uri that
524aafbe295d67686870c64c74a59e589d1dfb506faDebashish Chatterjee    * matches CALLS_ID. For other uri types the behaviour is undefined.
525aafbe295d67686870c64c74a59e589d1dfb506faDebashish Chatterjee    * @throws IllegalArgumentException if the id included in the Uri is not a valid long value.
526aafbe295d67686870c64c74a59e589d1dfb506faDebashish Chatterjee    */
5279978b26dd17bb2b20b91101f1e4682604336b5f6Flavio Lerda    private long parseCallIdFromUri(Uri uri) {
528aafbe295d67686870c64c74a59e589d1dfb506faDebashish Chatterjee        try {
5299978b26dd17bb2b20b91101f1e4682604336b5f6Flavio Lerda            return Long.parseLong(uri.getPathSegments().get(1));
530aafbe295d67686870c64c74a59e589d1dfb506faDebashish Chatterjee        } catch (NumberFormatException e) {
531aafbe295d67686870c64c74a59e589d1dfb506faDebashish Chatterjee            throw new IllegalArgumentException("Invalid call id in uri: " + uri, e);
532aafbe295d67686870c64c74a59e589d1dfb506faDebashish Chatterjee        }
533aafbe295d67686870c64c74a59e589d1dfb506faDebashish Chatterjee    }
5343b34457a4cc0d2c55676f366ddc673091a198adbYorke Lee
5353b34457a4cc0d2c55676f366ddc673091a198adbYorke Lee    /**
536f3bd980c0ec03db2538e86cadee2c1559f02c85bMakoto Onuki     * Sync all calllog entries that were inserted
5373b34457a4cc0d2c55676f366ddc673091a198adbYorke Lee     */
538f3bd980c0ec03db2538e86cadee2c1559f02c85bMakoto Onuki    private void syncEntries() {
539f3bd980c0ec03db2538e86cadee2c1559f02c85bMakoto Onuki        if (isShadow()) {
540f3bd980c0ec03db2538e86cadee2c1559f02c85bMakoto Onuki            return; // It's the shadow provider itself.  No copying.
541f3bd980c0ec03db2538e86cadee2c1559f02c85bMakoto Onuki        }
542f3bd980c0ec03db2538e86cadee2c1559f02c85bMakoto Onuki
543f3bd980c0ec03db2538e86cadee2c1559f02c85bMakoto Onuki        final UserManager userManager = UserUtils.getUserManager(getContext());
544f3bd980c0ec03db2538e86cadee2c1559f02c85bMakoto Onuki
5456e9c8b7b8406f35dd3a1a2d6d163447d243933f6Xiaohui Chen        // TODO: http://b/24944959
546f3bd980c0ec03db2538e86cadee2c1559f02c85bMakoto Onuki        if (!Calls.shouldHaveSharedCallLogEntries(getContext(), userManager,
547f3bd980c0ec03db2538e86cadee2c1559f02c85bMakoto Onuki                userManager.getUserHandle())) {
5483b34457a4cc0d2c55676f366ddc673091a198adbYorke Lee            return;
5493b34457a4cc0d2c55676f366ddc673091a198adbYorke Lee        }
5503b34457a4cc0d2c55676f366ddc673091a198adbYorke Lee
551f3bd980c0ec03db2538e86cadee2c1559f02c85bMakoto Onuki        final int myUserId = userManager.getUserHandle();
552f3bd980c0ec03db2538e86cadee2c1559f02c85bMakoto Onuki
553f3bd980c0ec03db2538e86cadee2c1559f02c85bMakoto Onuki        // See the comment in Calls.addCall() for the logic.
554f3bd980c0ec03db2538e86cadee2c1559f02c85bMakoto Onuki
555f3bd980c0ec03db2538e86cadee2c1559f02c85bMakoto Onuki        if (userManager.isSystemUser()) {
556f3bd980c0ec03db2538e86cadee2c1559f02c85bMakoto Onuki            // If it's the system user, just copy from shadow.
557f3bd980c0ec03db2538e86cadee2c1559f02c85bMakoto Onuki            syncEntriesFrom(UserHandle.USER_SYSTEM, /* sourceIsShadow = */ true,
558f3bd980c0ec03db2538e86cadee2c1559f02c85bMakoto Onuki                    /* forAllUsersOnly =*/ false);
559f3bd980c0ec03db2538e86cadee2c1559f02c85bMakoto Onuki        } else {
560f3bd980c0ec03db2538e86cadee2c1559f02c85bMakoto Onuki            // Otherwise, copy from system's real provider, as well as self's shadow.
561f3bd980c0ec03db2538e86cadee2c1559f02c85bMakoto Onuki            syncEntriesFrom(UserHandle.USER_SYSTEM, /* sourceIsShadow = */ false,
562f3bd980c0ec03db2538e86cadee2c1559f02c85bMakoto Onuki                    /* forAllUsersOnly =*/ true);
563f3bd980c0ec03db2538e86cadee2c1559f02c85bMakoto Onuki            syncEntriesFrom(myUserId, /* sourceIsShadow = */ true,
564f3bd980c0ec03db2538e86cadee2c1559f02c85bMakoto Onuki                    /* forAllUsersOnly =*/ false);
565f3bd980c0ec03db2538e86cadee2c1559f02c85bMakoto Onuki        }
566f3bd980c0ec03db2538e86cadee2c1559f02c85bMakoto Onuki    }
567f3bd980c0ec03db2538e86cadee2c1559f02c85bMakoto Onuki
568f3bd980c0ec03db2538e86cadee2c1559f02c85bMakoto Onuki    private void syncEntriesFrom(int sourceUserId, boolean sourceIsShadow,
569f3bd980c0ec03db2538e86cadee2c1559f02c85bMakoto Onuki            boolean forAllUsersOnly) {
570f3bd980c0ec03db2538e86cadee2c1559f02c85bMakoto Onuki
571f3bd980c0ec03db2538e86cadee2c1559f02c85bMakoto Onuki        final Uri sourceUri = sourceIsShadow ? Calls.SHADOW_CONTENT_URI : Calls.CONTENT_URI;
572f3bd980c0ec03db2538e86cadee2c1559f02c85bMakoto Onuki
573f3bd980c0ec03db2538e86cadee2c1559f02c85bMakoto Onuki        final long lastSyncTime = getLastSyncTime(sourceIsShadow);
574f3bd980c0ec03db2538e86cadee2c1559f02c85bMakoto Onuki
575f3bd980c0ec03db2538e86cadee2c1559f02c85bMakoto Onuki        final Uri uri = ContentProvider.maybeAddUserId(sourceUri, sourceUserId);
576f3bd980c0ec03db2538e86cadee2c1559f02c85bMakoto Onuki        final long newestTimeStamp;
577f3bd980c0ec03db2538e86cadee2c1559f02c85bMakoto Onuki        final ContentResolver cr = getContext().getContentResolver();
578f3bd980c0ec03db2538e86cadee2c1559f02c85bMakoto Onuki
579f3bd980c0ec03db2538e86cadee2c1559f02c85bMakoto Onuki        final StringBuilder selection = new StringBuilder();
580f3bd980c0ec03db2538e86cadee2c1559f02c85bMakoto Onuki
581f3bd980c0ec03db2538e86cadee2c1559f02c85bMakoto Onuki        selection.append(
582f3bd980c0ec03db2538e86cadee2c1559f02c85bMakoto Onuki                "(" + EXCLUDE_VOICEMAIL_SELECTION + ") AND (" + MORE_RECENT_THAN_SELECTION + ")");
583f3bd980c0ec03db2538e86cadee2c1559f02c85bMakoto Onuki
584f3bd980c0ec03db2538e86cadee2c1559f02c85bMakoto Onuki        if (forAllUsersOnly) {
585f3bd980c0ec03db2538e86cadee2c1559f02c85bMakoto Onuki            selection.append(" AND (" + Calls.ADD_FOR_ALL_USERS + "=1)");
586f3bd980c0ec03db2538e86cadee2c1559f02c85bMakoto Onuki        }
587f3bd980c0ec03db2538e86cadee2c1559f02c85bMakoto Onuki
588f3bd980c0ec03db2538e86cadee2c1559f02c85bMakoto Onuki        final Cursor cursor = cr.query(
5893b34457a4cc0d2c55676f366ddc673091a198adbYorke Lee                uri,
5903b34457a4cc0d2c55676f366ddc673091a198adbYorke Lee                CALL_LOG_SYNC_PROJECTION,
591f3bd980c0ec03db2538e86cadee2c1559f02c85bMakoto Onuki                selection.toString(),
5923b34457a4cc0d2c55676f366ddc673091a198adbYorke Lee                new String[] {String.valueOf(lastSyncTime)},
593f3bd980c0ec03db2538e86cadee2c1559f02c85bMakoto Onuki                Calls.DATE + " ASC");
5943b34457a4cc0d2c55676f366ddc673091a198adbYorke Lee        if (cursor == null) {
5953b34457a4cc0d2c55676f366ddc673091a198adbYorke Lee            return;
5963b34457a4cc0d2c55676f366ddc673091a198adbYorke Lee        }
5973b34457a4cc0d2c55676f366ddc673091a198adbYorke Lee        try {
598f3bd980c0ec03db2538e86cadee2c1559f02c85bMakoto Onuki            newestTimeStamp = copyEntriesFromCursor(cursor, lastSyncTime, sourceIsShadow);
5993b34457a4cc0d2c55676f366ddc673091a198adbYorke Lee        } finally {
6003b34457a4cc0d2c55676f366ddc673091a198adbYorke Lee            cursor.close();
6013b34457a4cc0d2c55676f366ddc673091a198adbYorke Lee        }
602f3bd980c0ec03db2538e86cadee2c1559f02c85bMakoto Onuki        if (sourceIsShadow) {
603f3bd980c0ec03db2538e86cadee2c1559f02c85bMakoto Onuki            // delete all entries in shadow.
604f3bd980c0ec03db2538e86cadee2c1559f02c85bMakoto Onuki            cr.delete(uri, Calls.DATE + "<= ?", new String[] {String.valueOf(newestTimeStamp)});
605f3bd980c0ec03db2538e86cadee2c1559f02c85bMakoto Onuki        }
6063b34457a4cc0d2c55676f366ddc673091a198adbYorke Lee    }
6073b34457a4cc0d2c55676f366ddc673091a198adbYorke Lee
6083b34457a4cc0d2c55676f366ddc673091a198adbYorke Lee    /**
609b39eeb4f07db680e542ccaf142136a42f9d305f8Santos Cordon     * Un-hides any hidden call log entries that are associated with the specified handle.
610b39eeb4f07db680e542ccaf142136a42f9d305f8Santos Cordon     *
611b39eeb4f07db680e542ccaf142136a42f9d305f8Santos Cordon     * @param handle The handle to the newly registered {@link android.telecom.PhoneAccount}.
612b39eeb4f07db680e542ccaf142136a42f9d305f8Santos Cordon     */
613b39eeb4f07db680e542ccaf142136a42f9d305f8Santos Cordon    private void adjustForNewPhoneAccountInternal(PhoneAccountHandle handle) {
614f7076a627db99f9e845d406650d73be826091367Santos Cordon        String[] handleArgs =
615f7076a627db99f9e845d406650d73be826091367Santos Cordon                new String[] { handle.getComponentName().flattenToString(), handle.getId() };
616f7076a627db99f9e845d406650d73be826091367Santos Cordon
617f7076a627db99f9e845d406650d73be826091367Santos Cordon        // Check to see if any entries exist for this handle. If so (not empty), run the un-hiding
618f7076a627db99f9e845d406650d73be826091367Santos Cordon        // update. If not, then try to identify the call from the phone number.
619f7076a627db99f9e845d406650d73be826091367Santos Cordon        Cursor cursor = query(Calls.CONTENT_URI, MINIMAL_PROJECTION,
620f7076a627db99f9e845d406650d73be826091367Santos Cordon                Calls.PHONE_ACCOUNT_COMPONENT_NAME + " =? AND " + Calls.PHONE_ACCOUNT_ID + " =?",
621f7076a627db99f9e845d406650d73be826091367Santos Cordon                handleArgs, null);
622f7076a627db99f9e845d406650d73be826091367Santos Cordon
623f7076a627db99f9e845d406650d73be826091367Santos Cordon        if (cursor != null) {
624f7076a627db99f9e845d406650d73be826091367Santos Cordon            try {
625f7076a627db99f9e845d406650d73be826091367Santos Cordon                if (cursor.getCount() >= 1) {
626f7076a627db99f9e845d406650d73be826091367Santos Cordon                    // run un-hiding process based on phone account
627f7076a627db99f9e845d406650d73be826091367Santos Cordon                    mDbHelper.getWritableDatabase().execSQL(
628f7076a627db99f9e845d406650d73be826091367Santos Cordon                            UNHIDE_BY_PHONE_ACCOUNT_QUERY, handleArgs);
629f7076a627db99f9e845d406650d73be826091367Santos Cordon                } else {
630f7076a627db99f9e845d406650d73be826091367Santos Cordon                    TelecomManager tm = TelecomManager.from(getContext());
631f7076a627db99f9e845d406650d73be826091367Santos Cordon                    if (tm != null) {
632f7076a627db99f9e845d406650d73be826091367Santos Cordon
633f7076a627db99f9e845d406650d73be826091367Santos Cordon                        PhoneAccount account = tm.getPhoneAccount(handle);
63464605820a3c27ca1d1bf2499aea8418bb80621d0Yorke Lee                        if (account != null && account.getAddress() != null) {
635f7076a627db99f9e845d406650d73be826091367Santos Cordon                            // We did not find any items for the specific phone account, so run the
636f7076a627db99f9e845d406650d73be826091367Santos Cordon                            // query based on the phone number instead.
637f7076a627db99f9e845d406650d73be826091367Santos Cordon                            mDbHelper.getWritableDatabase().execSQL(UNHIDE_BY_ADDRESS_QUERY,
638f7076a627db99f9e845d406650d73be826091367Santos Cordon                                    new String[] { account.getAddress().toString() });
639f7076a627db99f9e845d406650d73be826091367Santos Cordon                        }
640f7076a627db99f9e845d406650d73be826091367Santos Cordon
641f7076a627db99f9e845d406650d73be826091367Santos Cordon                    }
642f7076a627db99f9e845d406650d73be826091367Santos Cordon                }
643f7076a627db99f9e845d406650d73be826091367Santos Cordon            } finally {
644f7076a627db99f9e845d406650d73be826091367Santos Cordon                cursor.close();
645f7076a627db99f9e845d406650d73be826091367Santos Cordon            }
646f7076a627db99f9e845d406650d73be826091367Santos Cordon        }
647f7076a627db99f9e845d406650d73be826091367Santos Cordon
648b39eeb4f07db680e542ccaf142136a42f9d305f8Santos Cordon    }
649b39eeb4f07db680e542ccaf142136a42f9d305f8Santos Cordon
650b39eeb4f07db680e542ccaf142136a42f9d305f8Santos Cordon    /**
6513b34457a4cc0d2c55676f366ddc673091a198adbYorke Lee     * @param cursor to copy call log entries from
6523b34457a4cc0d2c55676f366ddc673091a198adbYorke Lee     */
6533b34457a4cc0d2c55676f366ddc673091a198adbYorke Lee    @VisibleForTesting
654f3bd980c0ec03db2538e86cadee2c1559f02c85bMakoto Onuki    long copyEntriesFromCursor(Cursor cursor, long lastSyncTime, boolean forShadow) {
655f3bd980c0ec03db2538e86cadee2c1559f02c85bMakoto Onuki        long latestTimestamp = 0;
6563b34457a4cc0d2c55676f366ddc673091a198adbYorke Lee        final ContentValues values = new ContentValues();
6573b34457a4cc0d2c55676f366ddc673091a198adbYorke Lee        final SQLiteDatabase db = mDbHelper.getWritableDatabase();
6583b34457a4cc0d2c55676f366ddc673091a198adbYorke Lee        db.beginTransaction();
6593b34457a4cc0d2c55676f366ddc673091a198adbYorke Lee        try {
6603b34457a4cc0d2c55676f366ddc673091a198adbYorke Lee            final String[] args = new String[2];
6613b34457a4cc0d2c55676f366ddc673091a198adbYorke Lee            cursor.moveToPosition(-1);
6623b34457a4cc0d2c55676f366ddc673091a198adbYorke Lee            while (cursor.moveToNext()) {
6633b34457a4cc0d2c55676f366ddc673091a198adbYorke Lee                values.clear();
6643b34457a4cc0d2c55676f366ddc673091a198adbYorke Lee                DatabaseUtils.cursorRowToContentValues(cursor, values);
6658bb52d886082c2c331bc513ce9f15c93ebf558ccTony Mak
6663b34457a4cc0d2c55676f366ddc673091a198adbYorke Lee                final String startTime = values.getAsString(Calls.DATE);
6673b34457a4cc0d2c55676f366ddc673091a198adbYorke Lee                final String number = values.getAsString(Calls.NUMBER);
6683b34457a4cc0d2c55676f366ddc673091a198adbYorke Lee
6693b34457a4cc0d2c55676f366ddc673091a198adbYorke Lee                if (startTime == null || number == null) {
6703b34457a4cc0d2c55676f366ddc673091a198adbYorke Lee                    continue;
6713b34457a4cc0d2c55676f366ddc673091a198adbYorke Lee                }
6723b34457a4cc0d2c55676f366ddc673091a198adbYorke Lee
6733b34457a4cc0d2c55676f366ddc673091a198adbYorke Lee                if (cursor.isLast()) {
6743b34457a4cc0d2c55676f366ddc673091a198adbYorke Lee                    try {
675f3bd980c0ec03db2538e86cadee2c1559f02c85bMakoto Onuki                        latestTimestamp = Long.valueOf(startTime);
6763b34457a4cc0d2c55676f366ddc673091a198adbYorke Lee                    } catch (NumberFormatException e) {
6773b34457a4cc0d2c55676f366ddc673091a198adbYorke Lee                        Log.e(TAG, "Call log entry does not contain valid start time: "
6783b34457a4cc0d2c55676f366ddc673091a198adbYorke Lee                                + startTime);
6793b34457a4cc0d2c55676f366ddc673091a198adbYorke Lee                    }
6803b34457a4cc0d2c55676f366ddc673091a198adbYorke Lee                }
6813b34457a4cc0d2c55676f366ddc673091a198adbYorke Lee
6823b34457a4cc0d2c55676f366ddc673091a198adbYorke Lee                // Avoid duplicating an already existing entry (which is uniquely identified by
6833b34457a4cc0d2c55676f366ddc673091a198adbYorke Lee                // the number, and the start time)
6843b34457a4cc0d2c55676f366ddc673091a198adbYorke Lee                args[0] = startTime;
6853b34457a4cc0d2c55676f366ddc673091a198adbYorke Lee                args[1] = number;
6863b34457a4cc0d2c55676f366ddc673091a198adbYorke Lee                if (DatabaseUtils.queryNumEntries(db, Tables.CALLS,
6873b34457a4cc0d2c55676f366ddc673091a198adbYorke Lee                        Calls.DATE + " = ? AND " + Calls.NUMBER + " = ?", args) > 0) {
6883b34457a4cc0d2c55676f366ddc673091a198adbYorke Lee                    continue;
6893b34457a4cc0d2c55676f366ddc673091a198adbYorke Lee                }
6903b34457a4cc0d2c55676f366ddc673091a198adbYorke Lee
6913b34457a4cc0d2c55676f366ddc673091a198adbYorke Lee                db.insert(Tables.CALLS, null, values);
6923b34457a4cc0d2c55676f366ddc673091a198adbYorke Lee            }
693f3bd980c0ec03db2538e86cadee2c1559f02c85bMakoto Onuki
694f3bd980c0ec03db2538e86cadee2c1559f02c85bMakoto Onuki            if (latestTimestamp > lastSyncTime) {
695f3bd980c0ec03db2538e86cadee2c1559f02c85bMakoto Onuki                setLastTimeSynced(latestTimestamp, forShadow);
696f3bd980c0ec03db2538e86cadee2c1559f02c85bMakoto Onuki            }
697f3bd980c0ec03db2538e86cadee2c1559f02c85bMakoto Onuki
6983b34457a4cc0d2c55676f366ddc673091a198adbYorke Lee            db.setTransactionSuccessful();
6993b34457a4cc0d2c55676f366ddc673091a198adbYorke Lee        } finally {
7003b34457a4cc0d2c55676f366ddc673091a198adbYorke Lee            db.endTransaction();
7013b34457a4cc0d2c55676f366ddc673091a198adbYorke Lee        }
702f3bd980c0ec03db2538e86cadee2c1559f02c85bMakoto Onuki        return latestTimestamp;
703f3bd980c0ec03db2538e86cadee2c1559f02c85bMakoto Onuki    }
704f3bd980c0ec03db2538e86cadee2c1559f02c85bMakoto Onuki
705f3bd980c0ec03db2538e86cadee2c1559f02c85bMakoto Onuki    private static String getLastSyncTimePropertyName(boolean forShadow) {
706f3bd980c0ec03db2538e86cadee2c1559f02c85bMakoto Onuki        return forShadow
707f3bd980c0ec03db2538e86cadee2c1559f02c85bMakoto Onuki                ? DbProperties.CALL_LOG_LAST_SYNCED_FOR_SHADOW
708f3bd980c0ec03db2538e86cadee2c1559f02c85bMakoto Onuki                : DbProperties.CALL_LOG_LAST_SYNCED;
7093b34457a4cc0d2c55676f366ddc673091a198adbYorke Lee    }
7103b34457a4cc0d2c55676f366ddc673091a198adbYorke Lee
711f3bd980c0ec03db2538e86cadee2c1559f02c85bMakoto Onuki    @VisibleForTesting
712f3bd980c0ec03db2538e86cadee2c1559f02c85bMakoto Onuki    long getLastSyncTime(boolean forShadow) {
7133b34457a4cc0d2c55676f366ddc673091a198adbYorke Lee        try {
714f3bd980c0ec03db2538e86cadee2c1559f02c85bMakoto Onuki            return Long.valueOf(mDbHelper.getProperty(getLastSyncTimePropertyName(forShadow), "0"));
7153b34457a4cc0d2c55676f366ddc673091a198adbYorke Lee        } catch (NumberFormatException e) {
7163b34457a4cc0d2c55676f366ddc673091a198adbYorke Lee            return 0;
7173b34457a4cc0d2c55676f366ddc673091a198adbYorke Lee        }
7183b34457a4cc0d2c55676f366ddc673091a198adbYorke Lee    }
7193b34457a4cc0d2c55676f366ddc673091a198adbYorke Lee
720f3bd980c0ec03db2538e86cadee2c1559f02c85bMakoto Onuki    private void setLastTimeSynced(long time, boolean forShadow) {
721f3bd980c0ec03db2538e86cadee2c1559f02c85bMakoto Onuki        mDbHelper.setProperty(getLastSyncTimePropertyName(forShadow), String.valueOf(time));
7223b34457a4cc0d2c55676f366ddc673091a198adbYorke Lee    }
7233a219cc3f5045bdebfcd975bf857c6ff26886a22Yorke Lee
7243a219cc3f5045bdebfcd975bf857c6ff26886a22Yorke Lee    private static void waitForAccess(CountDownLatch latch) {
7253a219cc3f5045bdebfcd975bf857c6ff26886a22Yorke Lee        if (latch == null) {
7263a219cc3f5045bdebfcd975bf857c6ff26886a22Yorke Lee            return;
7273a219cc3f5045bdebfcd975bf857c6ff26886a22Yorke Lee        }
7283a219cc3f5045bdebfcd975bf857c6ff26886a22Yorke Lee
7293a219cc3f5045bdebfcd975bf857c6ff26886a22Yorke Lee        while (true) {
7303a219cc3f5045bdebfcd975bf857c6ff26886a22Yorke Lee            try {
7313a219cc3f5045bdebfcd975bf857c6ff26886a22Yorke Lee                latch.await();
7323a219cc3f5045bdebfcd975bf857c6ff26886a22Yorke Lee                return;
7333a219cc3f5045bdebfcd975bf857c6ff26886a22Yorke Lee            } catch (InterruptedException e) {
7343a219cc3f5045bdebfcd975bf857c6ff26886a22Yorke Lee                Thread.currentThread().interrupt();
7353a219cc3f5045bdebfcd975bf857c6ff26886a22Yorke Lee            }
7363a219cc3f5045bdebfcd975bf857c6ff26886a22Yorke Lee        }
7373a219cc3f5045bdebfcd975bf857c6ff26886a22Yorke Lee    }
7383a219cc3f5045bdebfcd975bf857c6ff26886a22Yorke Lee
739b39eeb4f07db680e542ccaf142136a42f9d305f8Santos Cordon    private void performBackgroundTask(int task, Object arg) {
7403a219cc3f5045bdebfcd975bf857c6ff26886a22Yorke Lee        if (task == BACKGROUND_TASK_INITIALIZE) {
7413a219cc3f5045bdebfcd975bf857c6ff26886a22Yorke Lee            try {
742f3bd980c0ec03db2538e86cadee2c1559f02c85bMakoto Onuki                syncEntries();
7433a219cc3f5045bdebfcd975bf857c6ff26886a22Yorke Lee            } finally {
7443a219cc3f5045bdebfcd975bf857c6ff26886a22Yorke Lee                mReadAccessLatch.countDown();
7453a219cc3f5045bdebfcd975bf857c6ff26886a22Yorke Lee                mReadAccessLatch = null;
7463a219cc3f5045bdebfcd975bf857c6ff26886a22Yorke Lee            }
747b39eeb4f07db680e542ccaf142136a42f9d305f8Santos Cordon        } else if (task == BACKGROUND_TASK_ADJUST_PHONE_ACCOUNT) {
748b39eeb4f07db680e542ccaf142136a42f9d305f8Santos Cordon            adjustForNewPhoneAccountInternal((PhoneAccountHandle) arg);
7493a219cc3f5045bdebfcd975bf857c6ff26886a22Yorke Lee        }
7503a219cc3f5045bdebfcd975bf857c6ff26886a22Yorke Lee    }
7510220fa1c7b231796c250af2d9dd5750ae84771f6Makoto Onuki
7520220fa1c7b231796c250af2d9dd5750ae84771f6Makoto Onuki    @Override
7530220fa1c7b231796c250af2d9dd5750ae84771f6Makoto Onuki    public void shutdown() {
754607e7e3208b8b40633b3e2c1990cf8af2e7bf174Makoto Onuki        mTaskScheduler.shutdownForTest();
7550220fa1c7b231796c250af2d9dd5750ae84771f6Makoto Onuki    }
756e99988b266dd1263162583e81e2b408e7329b1c8Dmitri Plotnikov}
757