1dc653a5c1bed274512ce41e4a6129a65d2b0eeacMakoto Onuki/* 2dc653a5c1bed274512ce41e4a6129a65d2b0eeacMakoto Onuki * Copyright (C) 2015 The Android Open Source Project 3dc653a5c1bed274512ce41e4a6129a65d2b0eeacMakoto Onuki * 4dc653a5c1bed274512ce41e4a6129a65d2b0eeacMakoto Onuki * Licensed under the Apache License, Version 2.0 (the "License"); 5dc653a5c1bed274512ce41e4a6129a65d2b0eeacMakoto Onuki * you may not use this file except in compliance with the License. 6dc653a5c1bed274512ce41e4a6129a65d2b0eeacMakoto Onuki * You may obtain a copy of the License at 7dc653a5c1bed274512ce41e4a6129a65d2b0eeacMakoto Onuki * 8dc653a5c1bed274512ce41e4a6129a65d2b0eeacMakoto Onuki * http://www.apache.org/licenses/LICENSE-2.0 9dc653a5c1bed274512ce41e4a6129a65d2b0eeacMakoto Onuki * 10dc653a5c1bed274512ce41e4a6129a65d2b0eeacMakoto Onuki * Unless required by applicable law or agreed to in writing, software 11dc653a5c1bed274512ce41e4a6129a65d2b0eeacMakoto Onuki * distributed under the License is distributed on an "AS IS" BASIS, 12dc653a5c1bed274512ce41e4a6129a65d2b0eeacMakoto Onuki * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13dc653a5c1bed274512ce41e4a6129a65d2b0eeacMakoto Onuki * See the License for the specific language governing permissions and 14dc653a5c1bed274512ce41e4a6129a65d2b0eeacMakoto Onuki * limitations under the License 15dc653a5c1bed274512ce41e4a6129a65d2b0eeacMakoto Onuki */ 16dc653a5c1bed274512ce41e4a6129a65d2b0eeacMakoto Onukipackage com.android.providers.contacts; 17dc653a5c1bed274512ce41e4a6129a65d2b0eeacMakoto Onuki 18dc653a5c1bed274512ce41e4a6129a65d2b0eeacMakoto Onukiimport android.annotation.Nullable; 19dc653a5c1bed274512ce41e4a6129a65d2b0eeacMakoto Onukiimport android.content.ContentValues; 20dc653a5c1bed274512ce41e4a6129a65d2b0eeacMakoto Onukiimport android.content.Context; 21dc653a5c1bed274512ce41e4a6129a65d2b0eeacMakoto Onukiimport android.database.Cursor; 22dc653a5c1bed274512ce41e4a6129a65d2b0eeacMakoto Onukiimport android.database.DatabaseUtils; 23dc653a5c1bed274512ce41e4a6129a65d2b0eeacMakoto Onukiimport android.database.sqlite.SQLiteDatabase; 24dc653a5c1bed274512ce41e4a6129a65d2b0eeacMakoto Onukiimport android.database.sqlite.SQLiteOpenHelper; 25dc653a5c1bed274512ce41e4a6129a65d2b0eeacMakoto Onukiimport android.provider.CallLog.Calls; 26dc653a5c1bed274512ce41e4a6129a65d2b0eeacMakoto Onukiimport android.provider.VoicemailContract; 2721c692d49ce7ad6f9414d46ac2410d3f2e4c4d20Ta-wei Yenimport android.provider.VoicemailContract.Status; 28dc653a5c1bed274512ce41e4a6129a65d2b0eeacMakoto Onukiimport android.provider.VoicemailContract.Voicemails; 29dc653a5c1bed274512ce41e4a6129a65d2b0eeacMakoto Onukiimport android.util.Log; 30dc653a5c1bed274512ce41e4a6129a65d2b0eeacMakoto Onuki 31dc653a5c1bed274512ce41e4a6129a65d2b0eeacMakoto Onukiimport com.android.internal.annotations.VisibleForTesting; 32dc653a5c1bed274512ce41e4a6129a65d2b0eeacMakoto Onukiimport com.android.providers.contacts.util.PropertyUtils; 33dc653a5c1bed274512ce41e4a6129a65d2b0eeacMakoto Onuki 34dc653a5c1bed274512ce41e4a6129a65d2b0eeacMakoto Onuki/** 35dc653a5c1bed274512ce41e4a6129a65d2b0eeacMakoto Onuki * SQLite database (helper) for {@link CallLogProvider} and {@link VoicemailContentProvider}. 36dc653a5c1bed274512ce41e4a6129a65d2b0eeacMakoto Onuki */ 37dc653a5c1bed274512ce41e4a6129a65d2b0eeacMakoto Onukipublic class CallLogDatabaseHelper { 38dc653a5c1bed274512ce41e4a6129a65d2b0eeacMakoto Onuki private static final String TAG = "CallLogDatabaseHelper"; 39dc653a5c1bed274512ce41e4a6129a65d2b0eeacMakoto Onuki 4021c692d49ce7ad6f9414d46ac2410d3f2e4c4d20Ta-wei Yen private static final int DATABASE_VERSION = 3; 41dc653a5c1bed274512ce41e4a6129a65d2b0eeacMakoto Onuki 42dc653a5c1bed274512ce41e4a6129a65d2b0eeacMakoto Onuki private static final boolean DEBUG = false; // DON'T SUBMIT WITH TRUE 43dc653a5c1bed274512ce41e4a6129a65d2b0eeacMakoto Onuki 44dc653a5c1bed274512ce41e4a6129a65d2b0eeacMakoto Onuki private static final String DATABASE_NAME = "calllog.db"; 45dc653a5c1bed274512ce41e4a6129a65d2b0eeacMakoto Onuki 46f3bd980c0ec03db2538e86cadee2c1559f02c85bMakoto Onuki private static final String SHADOW_DATABASE_NAME = "calllog_shadow.db"; 47f3bd980c0ec03db2538e86cadee2c1559f02c85bMakoto Onuki 48dc653a5c1bed274512ce41e4a6129a65d2b0eeacMakoto Onuki private static CallLogDatabaseHelper sInstance; 49dc653a5c1bed274512ce41e4a6129a65d2b0eeacMakoto Onuki 50f3bd980c0ec03db2538e86cadee2c1559f02c85bMakoto Onuki /** Instance for the "shadow" provider. */ 51f3bd980c0ec03db2538e86cadee2c1559f02c85bMakoto Onuki private static CallLogDatabaseHelper sInstanceForShadow; 52f3bd980c0ec03db2538e86cadee2c1559f02c85bMakoto Onuki 53dc653a5c1bed274512ce41e4a6129a65d2b0eeacMakoto Onuki private final Context mContext; 54dc653a5c1bed274512ce41e4a6129a65d2b0eeacMakoto Onuki 55dc653a5c1bed274512ce41e4a6129a65d2b0eeacMakoto Onuki private final OpenHelper mOpenHelper; 56dc653a5c1bed274512ce41e4a6129a65d2b0eeacMakoto Onuki 57dc653a5c1bed274512ce41e4a6129a65d2b0eeacMakoto Onuki public interface Tables { 58dc653a5c1bed274512ce41e4a6129a65d2b0eeacMakoto Onuki String CALLS = "calls"; 59dc653a5c1bed274512ce41e4a6129a65d2b0eeacMakoto Onuki String VOICEMAIL_STATUS = "voicemail_status"; 60dc653a5c1bed274512ce41e4a6129a65d2b0eeacMakoto Onuki } 61dc653a5c1bed274512ce41e4a6129a65d2b0eeacMakoto Onuki 62dc653a5c1bed274512ce41e4a6129a65d2b0eeacMakoto Onuki public interface DbProperties { 63dc653a5c1bed274512ce41e4a6129a65d2b0eeacMakoto Onuki String CALL_LOG_LAST_SYNCED = "call_log_last_synced"; 64f3bd980c0ec03db2538e86cadee2c1559f02c85bMakoto Onuki String CALL_LOG_LAST_SYNCED_FOR_SHADOW = "call_log_last_synced_for_shadow"; 65dc653a5c1bed274512ce41e4a6129a65d2b0eeacMakoto Onuki String DATA_MIGRATED = "migrated"; 66dc653a5c1bed274512ce41e4a6129a65d2b0eeacMakoto Onuki } 67dc653a5c1bed274512ce41e4a6129a65d2b0eeacMakoto Onuki 68dc653a5c1bed274512ce41e4a6129a65d2b0eeacMakoto Onuki /** 69dc653a5c1bed274512ce41e4a6129a65d2b0eeacMakoto Onuki * Constants used in the contacts DB helper, which are needed for migration. 70dc653a5c1bed274512ce41e4a6129a65d2b0eeacMakoto Onuki * 71dc653a5c1bed274512ce41e4a6129a65d2b0eeacMakoto Onuki * DO NOT CHANCE ANY OF THE CONSTANTS. 72dc653a5c1bed274512ce41e4a6129a65d2b0eeacMakoto Onuki */ 73dc653a5c1bed274512ce41e4a6129a65d2b0eeacMakoto Onuki private interface LegacyConstants { 74dc653a5c1bed274512ce41e4a6129a65d2b0eeacMakoto Onuki /** Table name used in the contacts DB.*/ 75dc653a5c1bed274512ce41e4a6129a65d2b0eeacMakoto Onuki String CALLS_LEGACY = "calls"; 76dc653a5c1bed274512ce41e4a6129a65d2b0eeacMakoto Onuki 77dc653a5c1bed274512ce41e4a6129a65d2b0eeacMakoto Onuki /** Table name used in the contacts DB.*/ 78dc653a5c1bed274512ce41e4a6129a65d2b0eeacMakoto Onuki String VOICEMAIL_STATUS_LEGACY = "voicemail_status"; 79dc653a5c1bed274512ce41e4a6129a65d2b0eeacMakoto Onuki 80dc653a5c1bed274512ce41e4a6129a65d2b0eeacMakoto Onuki /** Prop name used in the contacts DB.*/ 81dc653a5c1bed274512ce41e4a6129a65d2b0eeacMakoto Onuki String CALL_LOG_LAST_SYNCED_LEGACY = "call_log_last_synced"; 82dc653a5c1bed274512ce41e4a6129a65d2b0eeacMakoto Onuki } 83dc653a5c1bed274512ce41e4a6129a65d2b0eeacMakoto Onuki 84dc653a5c1bed274512ce41e4a6129a65d2b0eeacMakoto Onuki private final class OpenHelper extends SQLiteOpenHelper { 85dc653a5c1bed274512ce41e4a6129a65d2b0eeacMakoto Onuki public OpenHelper(Context context, String name, SQLiteDatabase.CursorFactory factory, 86dc653a5c1bed274512ce41e4a6129a65d2b0eeacMakoto Onuki int version) { 87dc653a5c1bed274512ce41e4a6129a65d2b0eeacMakoto Onuki super(context, name, factory, version); 88dc653a5c1bed274512ce41e4a6129a65d2b0eeacMakoto Onuki } 89dc653a5c1bed274512ce41e4a6129a65d2b0eeacMakoto Onuki 90dc653a5c1bed274512ce41e4a6129a65d2b0eeacMakoto Onuki @Override 91dc653a5c1bed274512ce41e4a6129a65d2b0eeacMakoto Onuki public void onCreate(SQLiteDatabase db) { 92dc653a5c1bed274512ce41e4a6129a65d2b0eeacMakoto Onuki if (DEBUG) { 93dc653a5c1bed274512ce41e4a6129a65d2b0eeacMakoto Onuki Log.d(TAG, "onCreate"); 94dc653a5c1bed274512ce41e4a6129a65d2b0eeacMakoto Onuki } 95dc653a5c1bed274512ce41e4a6129a65d2b0eeacMakoto Onuki 96dc653a5c1bed274512ce41e4a6129a65d2b0eeacMakoto Onuki PropertyUtils.createPropertiesTable(db); 97dc653a5c1bed274512ce41e4a6129a65d2b0eeacMakoto Onuki 98dc653a5c1bed274512ce41e4a6129a65d2b0eeacMakoto Onuki // *** NOTE ABOUT CHANGING THE DB SCHEMA *** 99dc653a5c1bed274512ce41e4a6129a65d2b0eeacMakoto Onuki // 100dc653a5c1bed274512ce41e4a6129a65d2b0eeacMakoto Onuki // The CALLS and VOICEMAIL_STATUS table used to be in the contacts2.db. So we need to 101dc653a5c1bed274512ce41e4a6129a65d2b0eeacMakoto Onuki // migrate from these legacy tables, if exist, after creating the calllog DB, which is 102dc653a5c1bed274512ce41e4a6129a65d2b0eeacMakoto Onuki // done in migrateFromLegacyTables(). 103dc653a5c1bed274512ce41e4a6129a65d2b0eeacMakoto Onuki // 104dc653a5c1bed274512ce41e4a6129a65d2b0eeacMakoto Onuki // This migration is slightly different from a regular upgrade step, because it's always 105dc653a5c1bed274512ce41e4a6129a65d2b0eeacMakoto Onuki // performed from the legacy schema (of the latest version -- because the migration 106dc653a5c1bed274512ce41e4a6129a65d2b0eeacMakoto Onuki // source is always the latest DB after all the upgrade steps) to the *latest* schema 107dc653a5c1bed274512ce41e4a6129a65d2b0eeacMakoto Onuki // at once. 108dc653a5c1bed274512ce41e4a6129a65d2b0eeacMakoto Onuki // 109dc653a5c1bed274512ce41e4a6129a65d2b0eeacMakoto Onuki // This means certain kind of changes are not doable without changing the 110dc653a5c1bed274512ce41e4a6129a65d2b0eeacMakoto Onuki // migration logic. For example, if you rename a column in the DB, the migration step 111dc653a5c1bed274512ce41e4a6129a65d2b0eeacMakoto Onuki // will need to be updated to handle the column name change. 112dc653a5c1bed274512ce41e4a6129a65d2b0eeacMakoto Onuki 113dc653a5c1bed274512ce41e4a6129a65d2b0eeacMakoto Onuki db.execSQL("CREATE TABLE " + Tables.CALLS + " (" + 114dc653a5c1bed274512ce41e4a6129a65d2b0eeacMakoto Onuki Calls._ID + " INTEGER PRIMARY KEY AUTOINCREMENT," + 115dc653a5c1bed274512ce41e4a6129a65d2b0eeacMakoto Onuki Calls.NUMBER + " TEXT," + 116dc653a5c1bed274512ce41e4a6129a65d2b0eeacMakoto Onuki Calls.NUMBER_PRESENTATION + " INTEGER NOT NULL DEFAULT " + 117dc653a5c1bed274512ce41e4a6129a65d2b0eeacMakoto Onuki Calls.PRESENTATION_ALLOWED + "," + 118dc653a5c1bed274512ce41e4a6129a65d2b0eeacMakoto Onuki Calls.POST_DIAL_DIGITS + " TEXT NOT NULL DEFAULT ''," + 119c8ad9ce59d7ca2c10f4652ee3a0ef4e5d003f767Brad Ebinger Calls.VIA_NUMBER + " TEXT NOT NULL DEFAULT ''," + 120dc653a5c1bed274512ce41e4a6129a65d2b0eeacMakoto Onuki Calls.DATE + " INTEGER," + 121dc653a5c1bed274512ce41e4a6129a65d2b0eeacMakoto Onuki Calls.DURATION + " INTEGER," + 122dc653a5c1bed274512ce41e4a6129a65d2b0eeacMakoto Onuki Calls.DATA_USAGE + " INTEGER," + 123dc653a5c1bed274512ce41e4a6129a65d2b0eeacMakoto Onuki Calls.TYPE + " INTEGER," + 124dc653a5c1bed274512ce41e4a6129a65d2b0eeacMakoto Onuki Calls.FEATURES + " INTEGER NOT NULL DEFAULT 0," + 125dc653a5c1bed274512ce41e4a6129a65d2b0eeacMakoto Onuki Calls.PHONE_ACCOUNT_COMPONENT_NAME + " TEXT," + 126dc653a5c1bed274512ce41e4a6129a65d2b0eeacMakoto Onuki Calls.PHONE_ACCOUNT_ID + " TEXT," + 127dc653a5c1bed274512ce41e4a6129a65d2b0eeacMakoto Onuki Calls.PHONE_ACCOUNT_ADDRESS + " TEXT," + 128dc653a5c1bed274512ce41e4a6129a65d2b0eeacMakoto Onuki Calls.PHONE_ACCOUNT_HIDDEN + " INTEGER NOT NULL DEFAULT 0," + 129dc653a5c1bed274512ce41e4a6129a65d2b0eeacMakoto Onuki Calls.SUB_ID + " INTEGER DEFAULT -1," + 130dc653a5c1bed274512ce41e4a6129a65d2b0eeacMakoto Onuki Calls.NEW + " INTEGER," + 131dc653a5c1bed274512ce41e4a6129a65d2b0eeacMakoto Onuki Calls.CACHED_NAME + " TEXT," + 132dc653a5c1bed274512ce41e4a6129a65d2b0eeacMakoto Onuki Calls.CACHED_NUMBER_TYPE + " INTEGER," + 133dc653a5c1bed274512ce41e4a6129a65d2b0eeacMakoto Onuki Calls.CACHED_NUMBER_LABEL + " TEXT," + 134dc653a5c1bed274512ce41e4a6129a65d2b0eeacMakoto Onuki Calls.COUNTRY_ISO + " TEXT," + 135dc653a5c1bed274512ce41e4a6129a65d2b0eeacMakoto Onuki Calls.VOICEMAIL_URI + " TEXT," + 136dc653a5c1bed274512ce41e4a6129a65d2b0eeacMakoto Onuki Calls.IS_READ + " INTEGER," + 137dc653a5c1bed274512ce41e4a6129a65d2b0eeacMakoto Onuki Calls.GEOCODED_LOCATION + " TEXT," + 138dc653a5c1bed274512ce41e4a6129a65d2b0eeacMakoto Onuki Calls.CACHED_LOOKUP_URI + " TEXT," + 139dc653a5c1bed274512ce41e4a6129a65d2b0eeacMakoto Onuki Calls.CACHED_MATCHED_NUMBER + " TEXT," + 140dc653a5c1bed274512ce41e4a6129a65d2b0eeacMakoto Onuki Calls.CACHED_NORMALIZED_NUMBER + " TEXT," + 141dc653a5c1bed274512ce41e4a6129a65d2b0eeacMakoto Onuki Calls.CACHED_PHOTO_ID + " INTEGER NOT NULL DEFAULT 0," + 142dc653a5c1bed274512ce41e4a6129a65d2b0eeacMakoto Onuki Calls.CACHED_PHOTO_URI + " TEXT," + 143dc653a5c1bed274512ce41e4a6129a65d2b0eeacMakoto Onuki Calls.CACHED_FORMATTED_NUMBER + " TEXT," + 144dc653a5c1bed274512ce41e4a6129a65d2b0eeacMakoto Onuki Calls.ADD_FOR_ALL_USERS + " INTEGER NOT NULL DEFAULT 1," + 145dc653a5c1bed274512ce41e4a6129a65d2b0eeacMakoto Onuki Calls.LAST_MODIFIED + " INTEGER DEFAULT 0," + 146dc653a5c1bed274512ce41e4a6129a65d2b0eeacMakoto Onuki Voicemails._DATA + " TEXT," + 147dc653a5c1bed274512ce41e4a6129a65d2b0eeacMakoto Onuki Voicemails.HAS_CONTENT + " INTEGER," + 148dc653a5c1bed274512ce41e4a6129a65d2b0eeacMakoto Onuki Voicemails.MIME_TYPE + " TEXT," + 149dc653a5c1bed274512ce41e4a6129a65d2b0eeacMakoto Onuki Voicemails.SOURCE_DATA + " TEXT," + 150dc653a5c1bed274512ce41e4a6129a65d2b0eeacMakoto Onuki Voicemails.SOURCE_PACKAGE + " TEXT," + 151dc653a5c1bed274512ce41e4a6129a65d2b0eeacMakoto Onuki Voicemails.TRANSCRIPTION + " TEXT," + 152dc653a5c1bed274512ce41e4a6129a65d2b0eeacMakoto Onuki Voicemails.STATE + " INTEGER," + 153dc653a5c1bed274512ce41e4a6129a65d2b0eeacMakoto Onuki Voicemails.DIRTY + " INTEGER NOT NULL DEFAULT 0," + 154dc653a5c1bed274512ce41e4a6129a65d2b0eeacMakoto Onuki Voicemails.DELETED + " INTEGER NOT NULL DEFAULT 0" + 155dc653a5c1bed274512ce41e4a6129a65d2b0eeacMakoto Onuki ");"); 156dc653a5c1bed274512ce41e4a6129a65d2b0eeacMakoto Onuki 157dc653a5c1bed274512ce41e4a6129a65d2b0eeacMakoto Onuki db.execSQL("CREATE TABLE " + Tables.VOICEMAIL_STATUS + " (" + 158dc653a5c1bed274512ce41e4a6129a65d2b0eeacMakoto Onuki VoicemailContract.Status._ID + " INTEGER PRIMARY KEY AUTOINCREMENT," + 159dc653a5c1bed274512ce41e4a6129a65d2b0eeacMakoto Onuki VoicemailContract.Status.SOURCE_PACKAGE + " TEXT NOT NULL," + 160dc653a5c1bed274512ce41e4a6129a65d2b0eeacMakoto Onuki VoicemailContract.Status.PHONE_ACCOUNT_COMPONENT_NAME + " TEXT," + 161dc653a5c1bed274512ce41e4a6129a65d2b0eeacMakoto Onuki VoicemailContract.Status.PHONE_ACCOUNT_ID + " TEXT," + 162dc653a5c1bed274512ce41e4a6129a65d2b0eeacMakoto Onuki VoicemailContract.Status.SETTINGS_URI + " TEXT," + 163dc653a5c1bed274512ce41e4a6129a65d2b0eeacMakoto Onuki VoicemailContract.Status.VOICEMAIL_ACCESS_URI + " TEXT," + 164dc653a5c1bed274512ce41e4a6129a65d2b0eeacMakoto Onuki VoicemailContract.Status.CONFIGURATION_STATE + " INTEGER," + 165dc653a5c1bed274512ce41e4a6129a65d2b0eeacMakoto Onuki VoicemailContract.Status.DATA_CHANNEL_STATE + " INTEGER," + 166dc653a5c1bed274512ce41e4a6129a65d2b0eeacMakoto Onuki VoicemailContract.Status.NOTIFICATION_CHANNEL_STATE + " INTEGER," + 167dc653a5c1bed274512ce41e4a6129a65d2b0eeacMakoto Onuki VoicemailContract.Status.QUOTA_OCCUPIED + " INTEGER DEFAULT -1," + 16821c692d49ce7ad6f9414d46ac2410d3f2e4c4d20Ta-wei Yen VoicemailContract.Status.QUOTA_TOTAL + " INTEGER DEFAULT -1," + 16921c692d49ce7ad6f9414d46ac2410d3f2e4c4d20Ta-wei Yen VoicemailContract.Status.SOURCE_TYPE + " TEXT" + 170dc653a5c1bed274512ce41e4a6129a65d2b0eeacMakoto Onuki ");"); 171dc653a5c1bed274512ce41e4a6129a65d2b0eeacMakoto Onuki 172dc653a5c1bed274512ce41e4a6129a65d2b0eeacMakoto Onuki migrateFromLegacyTables(db); 173dc653a5c1bed274512ce41e4a6129a65d2b0eeacMakoto Onuki } 174dc653a5c1bed274512ce41e4a6129a65d2b0eeacMakoto Onuki 175dc653a5c1bed274512ce41e4a6129a65d2b0eeacMakoto Onuki @Override 176dc653a5c1bed274512ce41e4a6129a65d2b0eeacMakoto Onuki public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) { 177dc653a5c1bed274512ce41e4a6129a65d2b0eeacMakoto Onuki if (DEBUG) { 178dc653a5c1bed274512ce41e4a6129a65d2b0eeacMakoto Onuki Log.d(TAG, "onUpgrade"); 179dc653a5c1bed274512ce41e4a6129a65d2b0eeacMakoto Onuki } 180dc653a5c1bed274512ce41e4a6129a65d2b0eeacMakoto Onuki 181c8ad9ce59d7ca2c10f4652ee3a0ef4e5d003f767Brad Ebinger if (oldVersion < 2) { 182c8ad9ce59d7ca2c10f4652ee3a0ef4e5d003f767Brad Ebinger upgradeToVersion2(db); 183c8ad9ce59d7ca2c10f4652ee3a0ef4e5d003f767Brad Ebinger } 18421c692d49ce7ad6f9414d46ac2410d3f2e4c4d20Ta-wei Yen 18521c692d49ce7ad6f9414d46ac2410d3f2e4c4d20Ta-wei Yen if (oldVersion < 3) { 18621c692d49ce7ad6f9414d46ac2410d3f2e4c4d20Ta-wei Yen upgradeToVersion3(db); 18721c692d49ce7ad6f9414d46ac2410d3f2e4c4d20Ta-wei Yen } 188dc653a5c1bed274512ce41e4a6129a65d2b0eeacMakoto Onuki } 189dc653a5c1bed274512ce41e4a6129a65d2b0eeacMakoto Onuki } 190dc653a5c1bed274512ce41e4a6129a65d2b0eeacMakoto Onuki 191dc653a5c1bed274512ce41e4a6129a65d2b0eeacMakoto Onuki @VisibleForTesting 192dc653a5c1bed274512ce41e4a6129a65d2b0eeacMakoto Onuki CallLogDatabaseHelper(Context context, String databaseName) { 193dc653a5c1bed274512ce41e4a6129a65d2b0eeacMakoto Onuki mContext = context; 194dc653a5c1bed274512ce41e4a6129a65d2b0eeacMakoto Onuki mOpenHelper = new OpenHelper(mContext, databaseName, /* factory=*/ null, DATABASE_VERSION); 195dc653a5c1bed274512ce41e4a6129a65d2b0eeacMakoto Onuki } 196dc653a5c1bed274512ce41e4a6129a65d2b0eeacMakoto Onuki 197dc653a5c1bed274512ce41e4a6129a65d2b0eeacMakoto Onuki public static synchronized CallLogDatabaseHelper getInstance(Context context) { 198dc653a5c1bed274512ce41e4a6129a65d2b0eeacMakoto Onuki if (sInstance == null) { 199dc653a5c1bed274512ce41e4a6129a65d2b0eeacMakoto Onuki sInstance = new CallLogDatabaseHelper(context, DATABASE_NAME); 200dc653a5c1bed274512ce41e4a6129a65d2b0eeacMakoto Onuki } 201dc653a5c1bed274512ce41e4a6129a65d2b0eeacMakoto Onuki return sInstance; 202dc653a5c1bed274512ce41e4a6129a65d2b0eeacMakoto Onuki } 203dc653a5c1bed274512ce41e4a6129a65d2b0eeacMakoto Onuki 204f3bd980c0ec03db2538e86cadee2c1559f02c85bMakoto Onuki public static synchronized CallLogDatabaseHelper getInstanceForShadow(Context context) { 205f3bd980c0ec03db2538e86cadee2c1559f02c85bMakoto Onuki if (sInstanceForShadow == null) { 206f3bd980c0ec03db2538e86cadee2c1559f02c85bMakoto Onuki // Shadow provider is always encryption-aware. 207f3bd980c0ec03db2538e86cadee2c1559f02c85bMakoto Onuki sInstanceForShadow = new CallLogDatabaseHelper( 2086364dc89b6c90dab11997bd360a1e80d9bf282caJeff Sharkey context.createDeviceProtectedStorageContext(), SHADOW_DATABASE_NAME); 209f3bd980c0ec03db2538e86cadee2c1559f02c85bMakoto Onuki } 210f3bd980c0ec03db2538e86cadee2c1559f02c85bMakoto Onuki return sInstanceForShadow; 211f3bd980c0ec03db2538e86cadee2c1559f02c85bMakoto Onuki } 212f3bd980c0ec03db2538e86cadee2c1559f02c85bMakoto Onuki 213dc653a5c1bed274512ce41e4a6129a65d2b0eeacMakoto Onuki public SQLiteDatabase getReadableDatabase() { 214dc653a5c1bed274512ce41e4a6129a65d2b0eeacMakoto Onuki return mOpenHelper.getReadableDatabase(); 215dc653a5c1bed274512ce41e4a6129a65d2b0eeacMakoto Onuki } 216dc653a5c1bed274512ce41e4a6129a65d2b0eeacMakoto Onuki 217dc653a5c1bed274512ce41e4a6129a65d2b0eeacMakoto Onuki public SQLiteDatabase getWritableDatabase() { 218dc653a5c1bed274512ce41e4a6129a65d2b0eeacMakoto Onuki return mOpenHelper.getWritableDatabase(); 219dc653a5c1bed274512ce41e4a6129a65d2b0eeacMakoto Onuki } 220dc653a5c1bed274512ce41e4a6129a65d2b0eeacMakoto Onuki 221dc653a5c1bed274512ce41e4a6129a65d2b0eeacMakoto Onuki public String getProperty(String key, String defaultValue) { 222dc653a5c1bed274512ce41e4a6129a65d2b0eeacMakoto Onuki return PropertyUtils.getProperty(getReadableDatabase(), key, defaultValue); 223dc653a5c1bed274512ce41e4a6129a65d2b0eeacMakoto Onuki } 224dc653a5c1bed274512ce41e4a6129a65d2b0eeacMakoto Onuki 225dc653a5c1bed274512ce41e4a6129a65d2b0eeacMakoto Onuki public void setProperty(String key, String value) { 226dc653a5c1bed274512ce41e4a6129a65d2b0eeacMakoto Onuki PropertyUtils.setProperty(getWritableDatabase(), key, value); 227dc653a5c1bed274512ce41e4a6129a65d2b0eeacMakoto Onuki } 228dc653a5c1bed274512ce41e4a6129a65d2b0eeacMakoto Onuki 229dc653a5c1bed274512ce41e4a6129a65d2b0eeacMakoto Onuki /** 230c8ad9ce59d7ca2c10f4652ee3a0ef4e5d003f767Brad Ebinger * Add the {@link Calls.VIA_NUMBER} Column to the CallLog Database. 231c8ad9ce59d7ca2c10f4652ee3a0ef4e5d003f767Brad Ebinger */ 232c8ad9ce59d7ca2c10f4652ee3a0ef4e5d003f767Brad Ebinger private void upgradeToVersion2(SQLiteDatabase db) { 233c8ad9ce59d7ca2c10f4652ee3a0ef4e5d003f767Brad Ebinger db.execSQL("ALTER TABLE " + Tables.CALLS + " ADD " + Calls.VIA_NUMBER + 234c8ad9ce59d7ca2c10f4652ee3a0ef4e5d003f767Brad Ebinger " TEXT NOT NULL DEFAULT ''"); 235c8ad9ce59d7ca2c10f4652ee3a0ef4e5d003f767Brad Ebinger } 236c8ad9ce59d7ca2c10f4652ee3a0ef4e5d003f767Brad Ebinger 237c8ad9ce59d7ca2c10f4652ee3a0ef4e5d003f767Brad Ebinger /** 23821c692d49ce7ad6f9414d46ac2410d3f2e4c4d20Ta-wei Yen * Add the {@link Status.SOURCE_TYPE} Column to the VoicemailStatus Database. 23921c692d49ce7ad6f9414d46ac2410d3f2e4c4d20Ta-wei Yen */ 24021c692d49ce7ad6f9414d46ac2410d3f2e4c4d20Ta-wei Yen private void upgradeToVersion3(SQLiteDatabase db) { 24121c692d49ce7ad6f9414d46ac2410d3f2e4c4d20Ta-wei Yen db.execSQL("ALTER TABLE " + Tables.VOICEMAIL_STATUS + " ADD " + Status.SOURCE_TYPE + 24221c692d49ce7ad6f9414d46ac2410d3f2e4c4d20Ta-wei Yen " TEXT"); 24321c692d49ce7ad6f9414d46ac2410d3f2e4c4d20Ta-wei Yen } 24421c692d49ce7ad6f9414d46ac2410d3f2e4c4d20Ta-wei Yen 24521c692d49ce7ad6f9414d46ac2410d3f2e4c4d20Ta-wei Yen /** 246dc653a5c1bed274512ce41e4a6129a65d2b0eeacMakoto Onuki * Perform the migration from the contacts2.db (of the latest version) to the current calllog/ 247dc653a5c1bed274512ce41e4a6129a65d2b0eeacMakoto Onuki * voicemail status tables. 248dc653a5c1bed274512ce41e4a6129a65d2b0eeacMakoto Onuki */ 249dc653a5c1bed274512ce41e4a6129a65d2b0eeacMakoto Onuki private void migrateFromLegacyTables(SQLiteDatabase calllog) { 250dc653a5c1bed274512ce41e4a6129a65d2b0eeacMakoto Onuki final SQLiteDatabase contacts = getContactsWritableDatabaseForMigration(); 251dc653a5c1bed274512ce41e4a6129a65d2b0eeacMakoto Onuki 252dc653a5c1bed274512ce41e4a6129a65d2b0eeacMakoto Onuki if (contacts == null) { 253dc653a5c1bed274512ce41e4a6129a65d2b0eeacMakoto Onuki Log.w(TAG, "Contacts DB == null, skipping migration. (running tests?)"); 254dc653a5c1bed274512ce41e4a6129a65d2b0eeacMakoto Onuki return; 255dc653a5c1bed274512ce41e4a6129a65d2b0eeacMakoto Onuki } 256dc653a5c1bed274512ce41e4a6129a65d2b0eeacMakoto Onuki if (DEBUG) { 257dc653a5c1bed274512ce41e4a6129a65d2b0eeacMakoto Onuki Log.d(TAG, "migrateFromLegacyTables"); 258dc653a5c1bed274512ce41e4a6129a65d2b0eeacMakoto Onuki } 259dc653a5c1bed274512ce41e4a6129a65d2b0eeacMakoto Onuki 260dc653a5c1bed274512ce41e4a6129a65d2b0eeacMakoto Onuki if ("1".equals(PropertyUtils.getProperty(calllog, DbProperties.DATA_MIGRATED, ""))) { 261dc653a5c1bed274512ce41e4a6129a65d2b0eeacMakoto Onuki return; 262dc653a5c1bed274512ce41e4a6129a65d2b0eeacMakoto Onuki } 263dc653a5c1bed274512ce41e4a6129a65d2b0eeacMakoto Onuki 264dc653a5c1bed274512ce41e4a6129a65d2b0eeacMakoto Onuki Log.i(TAG, "Migrating from old tables..."); 265dc653a5c1bed274512ce41e4a6129a65d2b0eeacMakoto Onuki 266dc653a5c1bed274512ce41e4a6129a65d2b0eeacMakoto Onuki contacts.beginTransaction(); 267dc653a5c1bed274512ce41e4a6129a65d2b0eeacMakoto Onuki try { 268dc653a5c1bed274512ce41e4a6129a65d2b0eeacMakoto Onuki if (!tableExists(contacts, LegacyConstants.CALLS_LEGACY) 269dc653a5c1bed274512ce41e4a6129a65d2b0eeacMakoto Onuki || !tableExists(contacts, LegacyConstants.VOICEMAIL_STATUS_LEGACY)) { 270dc653a5c1bed274512ce41e4a6129a65d2b0eeacMakoto Onuki // This is fine on new devices. (or after a "clear data".) 271dc653a5c1bed274512ce41e4a6129a65d2b0eeacMakoto Onuki Log.i(TAG, "Source tables don't exist."); 272dc653a5c1bed274512ce41e4a6129a65d2b0eeacMakoto Onuki return; 273dc653a5c1bed274512ce41e4a6129a65d2b0eeacMakoto Onuki } 274dc653a5c1bed274512ce41e4a6129a65d2b0eeacMakoto Onuki calllog.beginTransaction(); 275dc653a5c1bed274512ce41e4a6129a65d2b0eeacMakoto Onuki try { 276dc653a5c1bed274512ce41e4a6129a65d2b0eeacMakoto Onuki 277dc653a5c1bed274512ce41e4a6129a65d2b0eeacMakoto Onuki final ContentValues cv = new ContentValues(); 278dc653a5c1bed274512ce41e4a6129a65d2b0eeacMakoto Onuki 279dc653a5c1bed274512ce41e4a6129a65d2b0eeacMakoto Onuki try (Cursor source = contacts.rawQuery( 280dc653a5c1bed274512ce41e4a6129a65d2b0eeacMakoto Onuki "SELECT * FROM " + LegacyConstants.CALLS_LEGACY, null)) { 281dc653a5c1bed274512ce41e4a6129a65d2b0eeacMakoto Onuki while (source.moveToNext()) { 282dc653a5c1bed274512ce41e4a6129a65d2b0eeacMakoto Onuki cv.clear(); 283dc653a5c1bed274512ce41e4a6129a65d2b0eeacMakoto Onuki 284dc653a5c1bed274512ce41e4a6129a65d2b0eeacMakoto Onuki DatabaseUtils.cursorRowToContentValues(source, cv); 285dc653a5c1bed274512ce41e4a6129a65d2b0eeacMakoto Onuki 286dc653a5c1bed274512ce41e4a6129a65d2b0eeacMakoto Onuki calllog.insertOrThrow(Tables.CALLS, null, cv); 287dc653a5c1bed274512ce41e4a6129a65d2b0eeacMakoto Onuki } 288dc653a5c1bed274512ce41e4a6129a65d2b0eeacMakoto Onuki } 289dc653a5c1bed274512ce41e4a6129a65d2b0eeacMakoto Onuki 290dc653a5c1bed274512ce41e4a6129a65d2b0eeacMakoto Onuki try (Cursor source = contacts.rawQuery("SELECT * FROM " + 291dc653a5c1bed274512ce41e4a6129a65d2b0eeacMakoto Onuki LegacyConstants.VOICEMAIL_STATUS_LEGACY, null)) { 292dc653a5c1bed274512ce41e4a6129a65d2b0eeacMakoto Onuki while (source.moveToNext()) { 293dc653a5c1bed274512ce41e4a6129a65d2b0eeacMakoto Onuki cv.clear(); 294dc653a5c1bed274512ce41e4a6129a65d2b0eeacMakoto Onuki 295dc653a5c1bed274512ce41e4a6129a65d2b0eeacMakoto Onuki DatabaseUtils.cursorRowToContentValues(source, cv); 296dc653a5c1bed274512ce41e4a6129a65d2b0eeacMakoto Onuki 297dc653a5c1bed274512ce41e4a6129a65d2b0eeacMakoto Onuki calllog.insertOrThrow(Tables.VOICEMAIL_STATUS, null, cv); 298dc653a5c1bed274512ce41e4a6129a65d2b0eeacMakoto Onuki } 299dc653a5c1bed274512ce41e4a6129a65d2b0eeacMakoto Onuki } 300dc653a5c1bed274512ce41e4a6129a65d2b0eeacMakoto Onuki 301dc653a5c1bed274512ce41e4a6129a65d2b0eeacMakoto Onuki contacts.execSQL("DROP TABLE " + LegacyConstants.CALLS_LEGACY + ";"); 302dc653a5c1bed274512ce41e4a6129a65d2b0eeacMakoto Onuki contacts.execSQL("DROP TABLE " + LegacyConstants.VOICEMAIL_STATUS_LEGACY + ";"); 303dc653a5c1bed274512ce41e4a6129a65d2b0eeacMakoto Onuki 304dc653a5c1bed274512ce41e4a6129a65d2b0eeacMakoto Onuki // Also copy the last sync time. 305dc653a5c1bed274512ce41e4a6129a65d2b0eeacMakoto Onuki PropertyUtils.setProperty(calllog, DbProperties.CALL_LOG_LAST_SYNCED, 306dc653a5c1bed274512ce41e4a6129a65d2b0eeacMakoto Onuki PropertyUtils.getProperty(contacts, 307dc653a5c1bed274512ce41e4a6129a65d2b0eeacMakoto Onuki LegacyConstants.CALL_LOG_LAST_SYNCED_LEGACY, null)); 308dc653a5c1bed274512ce41e4a6129a65d2b0eeacMakoto Onuki 309dc653a5c1bed274512ce41e4a6129a65d2b0eeacMakoto Onuki Log.i(TAG, "Migration completed."); 310dc653a5c1bed274512ce41e4a6129a65d2b0eeacMakoto Onuki 311dc653a5c1bed274512ce41e4a6129a65d2b0eeacMakoto Onuki calllog.setTransactionSuccessful(); 312dc653a5c1bed274512ce41e4a6129a65d2b0eeacMakoto Onuki } finally { 313dc653a5c1bed274512ce41e4a6129a65d2b0eeacMakoto Onuki calllog.endTransaction(); 314dc653a5c1bed274512ce41e4a6129a65d2b0eeacMakoto Onuki } 315dc653a5c1bed274512ce41e4a6129a65d2b0eeacMakoto Onuki 316dc653a5c1bed274512ce41e4a6129a65d2b0eeacMakoto Onuki contacts.setTransactionSuccessful(); 317dc653a5c1bed274512ce41e4a6129a65d2b0eeacMakoto Onuki } catch (RuntimeException e) { 318dc653a5c1bed274512ce41e4a6129a65d2b0eeacMakoto Onuki // We don't want to be stuck here, so we just swallow exceptions... 319dc653a5c1bed274512ce41e4a6129a65d2b0eeacMakoto Onuki Log.w(TAG, "Exception caught during migration", e); 320dc653a5c1bed274512ce41e4a6129a65d2b0eeacMakoto Onuki } finally { 321dc653a5c1bed274512ce41e4a6129a65d2b0eeacMakoto Onuki contacts.endTransaction(); 322dc653a5c1bed274512ce41e4a6129a65d2b0eeacMakoto Onuki } 323dc653a5c1bed274512ce41e4a6129a65d2b0eeacMakoto Onuki PropertyUtils.setProperty(calllog, DbProperties.DATA_MIGRATED, "1"); 324dc653a5c1bed274512ce41e4a6129a65d2b0eeacMakoto Onuki } 325dc653a5c1bed274512ce41e4a6129a65d2b0eeacMakoto Onuki 326dc653a5c1bed274512ce41e4a6129a65d2b0eeacMakoto Onuki @VisibleForTesting 327dc653a5c1bed274512ce41e4a6129a65d2b0eeacMakoto Onuki static boolean tableExists(SQLiteDatabase db, String table) { 328dc653a5c1bed274512ce41e4a6129a65d2b0eeacMakoto Onuki return DatabaseUtils.longForQuery(db, 329dc653a5c1bed274512ce41e4a6129a65d2b0eeacMakoto Onuki "select count(*) from sqlite_master where type='table' and name=?", 330dc653a5c1bed274512ce41e4a6129a65d2b0eeacMakoto Onuki new String[] {table}) > 0; 331dc653a5c1bed274512ce41e4a6129a65d2b0eeacMakoto Onuki } 332dc653a5c1bed274512ce41e4a6129a65d2b0eeacMakoto Onuki 333dc653a5c1bed274512ce41e4a6129a65d2b0eeacMakoto Onuki @VisibleForTesting 334dc653a5c1bed274512ce41e4a6129a65d2b0eeacMakoto Onuki @Nullable // We return null during tests when migration is not needed. 335dc653a5c1bed274512ce41e4a6129a65d2b0eeacMakoto Onuki SQLiteDatabase getContactsWritableDatabaseForMigration() { 336dc653a5c1bed274512ce41e4a6129a65d2b0eeacMakoto Onuki return ContactsDatabaseHelper.getInstance(mContext).getWritableDatabase(); 337dc653a5c1bed274512ce41e4a6129a65d2b0eeacMakoto Onuki } 338dc653a5c1bed274512ce41e4a6129a65d2b0eeacMakoto Onuki 339dc653a5c1bed274512ce41e4a6129a65d2b0eeacMakoto Onuki @VisibleForTesting 340dc653a5c1bed274512ce41e4a6129a65d2b0eeacMakoto Onuki void closeForTest() { 341dc653a5c1bed274512ce41e4a6129a65d2b0eeacMakoto Onuki mOpenHelper.close(); 342dc653a5c1bed274512ce41e4a6129a65d2b0eeacMakoto Onuki } 343dc653a5c1bed274512ce41e4a6129a65d2b0eeacMakoto Onuki 344dc653a5c1bed274512ce41e4a6129a65d2b0eeacMakoto Onuki public void wipeForTest() { 345dc653a5c1bed274512ce41e4a6129a65d2b0eeacMakoto Onuki getWritableDatabase().execSQL("DELETE FROM " + Tables.CALLS); 346dc653a5c1bed274512ce41e4a6129a65d2b0eeacMakoto Onuki } 347dc653a5c1bed274512ce41e4a6129a65d2b0eeacMakoto Onuki} 348