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