| /* |
| * Copyright (C) 2009 The Android Open Source Project |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| |
| package com.android.providers.contacts; |
| |
| import com.android.providers.contacts.ContactsDatabaseHelper.DataColumns; |
| import com.android.providers.contacts.ContactsDatabaseHelper.PhoneColumns; |
| import com.android.providers.contacts.ContactsDatabaseHelper.PhoneLookupColumns; |
| import com.android.providers.contacts.ContactsDatabaseHelper.RawContactsColumns; |
| import com.android.providers.contacts.ContactsDatabaseHelper.Tables; |
| |
| import android.content.ContentResolver; |
| import android.content.ContentValues; |
| import android.content.Context; |
| import android.database.Cursor; |
| import android.database.DatabaseUtils; |
| import android.database.sqlite.SQLiteDatabase; |
| import android.database.sqlite.SQLiteException; |
| import android.database.sqlite.SQLiteStatement; |
| import android.provider.CallLog.Calls; |
| import android.provider.ContactsContract.Contacts; |
| import android.provider.ContactsContract.Data; |
| import android.provider.ContactsContract.Groups; |
| import android.provider.ContactsContract.RawContacts; |
| import android.provider.ContactsContract.CommonDataKinds.Email; |
| import android.provider.ContactsContract.CommonDataKinds.GroupMembership; |
| import android.provider.ContactsContract.CommonDataKinds.Im; |
| import android.provider.ContactsContract.CommonDataKinds.Note; |
| import android.provider.ContactsContract.CommonDataKinds.Organization; |
| import android.provider.ContactsContract.CommonDataKinds.Phone; |
| import android.provider.ContactsContract.CommonDataKinds.Photo; |
| import android.provider.ContactsContract.CommonDataKinds.StructuredName; |
| import android.provider.ContactsContract.CommonDataKinds.StructuredPostal; |
| import android.telephony.PhoneNumberUtils; |
| import android.text.TextUtils; |
| import android.util.Log; |
| |
| import java.io.File; |
| |
| public class LegacyContactImporter { |
| |
| public static final String TAG = "LegacyContactImporter"; |
| |
| private static final int MAX_ATTEMPTS = 5; |
| private static final int DELAY_BETWEEN_ATTEMPTS = 2000; |
| |
| public static final String DEFAULT_ACCOUNT_TYPE = "com.google"; |
| private static final String DATABASE_NAME = "contacts.db"; |
| |
| private static final int INSERT_BATCH_SIZE = 200; |
| |
| /** |
| * Estimated increase in database size after import. |
| */ |
| private static final long DATABASE_SIZE_MULTIPLIER = 4; |
| |
| /** |
| * Estimated minimum database size in megabytes. |
| */ |
| private static final long DATABASE_MIN_SIZE = 5; |
| |
| private final Context mContext; |
| private final ContactsProvider2 mContactsProvider; |
| private ContactsDatabaseHelper mDbHelper; |
| private ContentValues mValues = new ContentValues(); |
| private ContentResolver mResolver; |
| private boolean mPhoneticNameAvailable = true; |
| |
| private SQLiteDatabase mSourceDb; |
| private SQLiteDatabase mTargetDb; |
| |
| private NameSplitter mNameSplitter; |
| private int mBatchCounter; |
| |
| private int mContactCount; |
| |
| private long mStructuredNameMimetypeId; |
| private long mNoteMimetypeId; |
| private long mOrganizationMimetypeId; |
| private long mPhoneMimetypeId; |
| private long mEmailMimetypeId; |
| private long mImMimetypeId; |
| private long mPostalMimetypeId; |
| private long mPhotoMimetypeId; |
| private long mGroupMembershipMimetypeId; |
| |
| private long mEstimatedStorageRequirement = DATABASE_MIN_SIZE; |
| |
| public LegacyContactImporter(Context context, ContactsProvider2 contactsProvider) { |
| mContext = context; |
| mContactsProvider = contactsProvider; |
| mResolver = mContactsProvider.getContext().getContentResolver(); |
| } |
| |
| public boolean importContacts() throws Exception { |
| String path = mContext.getDatabasePath(DATABASE_NAME).getPath(); |
| File file = new File(path); |
| if (!file.exists()) { |
| Log.i(TAG, "Legacy contacts database does not exist at " + path); |
| return true; |
| } |
| |
| Log.w(TAG, "Importing contacts from " + path); |
| |
| for (int i = 0; i < MAX_ATTEMPTS; i++) { |
| try { |
| mSourceDb = SQLiteDatabase.openDatabase(path, null, SQLiteDatabase.OPEN_READONLY); |
| importContactsFromLegacyDb(); |
| Log.i(TAG, "Imported legacy contacts: " + mContactCount); |
| mContactsProvider.notifyChange(); |
| return true; |
| |
| } catch (SQLiteException e) { |
| Log.e(TAG, "Database import exception. Will retry in " + DELAY_BETWEEN_ATTEMPTS |
| + "ms", e); |
| |
| // We could get a "database locked" exception here, in which |
| // case we should retry |
| Thread.sleep(DELAY_BETWEEN_ATTEMPTS); |
| |
| } finally { |
| if (mSourceDb != null) { |
| mSourceDb.close(); |
| } |
| } |
| } |
| |
| long oldDatabaseSize = file.length(); |
| mEstimatedStorageRequirement = oldDatabaseSize * DATABASE_SIZE_MULTIPLIER / 1024 / 1024; |
| if (mEstimatedStorageRequirement < DATABASE_MIN_SIZE) { |
| mEstimatedStorageRequirement = DATABASE_MIN_SIZE; |
| } |
| |
| return false; |
| } |
| |
| public long getEstimatedStorageRequirement() { |
| return mEstimatedStorageRequirement; |
| } |
| |
| private void importContactsFromLegacyDb() { |
| int version = mSourceDb.getVersion(); |
| |
| // Upgrade to version 78 was the latest that wiped out data. Might as well follow suit |
| // and ignore earlier versions. |
| if (version < 78) { |
| return; |
| } |
| |
| if (version < 80) { |
| mPhoneticNameAvailable = false; |
| } |
| |
| mDbHelper = (ContactsDatabaseHelper)mContactsProvider.getDatabaseHelper(); |
| mTargetDb = mDbHelper.getWritableDatabase(); |
| |
| mStructuredNameMimetypeId = mDbHelper.getMimeTypeId(StructuredName.CONTENT_ITEM_TYPE); |
| mNoteMimetypeId = mDbHelper.getMimeTypeId(Note.CONTENT_ITEM_TYPE); |
| mOrganizationMimetypeId = mDbHelper.getMimeTypeId(Organization.CONTENT_ITEM_TYPE); |
| mPhoneMimetypeId = mDbHelper.getMimeTypeId(Phone.CONTENT_ITEM_TYPE); |
| mEmailMimetypeId = mDbHelper.getMimeTypeId(Email.CONTENT_ITEM_TYPE); |
| mImMimetypeId = mDbHelper.getMimeTypeId(Im.CONTENT_ITEM_TYPE); |
| mPostalMimetypeId = mDbHelper.getMimeTypeId(StructuredPostal.CONTENT_ITEM_TYPE); |
| mPhotoMimetypeId = mDbHelper.getMimeTypeId(Photo.CONTENT_ITEM_TYPE); |
| mGroupMembershipMimetypeId = |
| mDbHelper.getMimeTypeId(GroupMembership.CONTENT_ITEM_TYPE); |
| |
| mNameSplitter = mContactsProvider.getNameSplitter(); |
| |
| mTargetDb.beginTransaction(); |
| try { |
| checkForImportFailureTest(); |
| |
| /* |
| * At this point there should be no data in the contacts provider, but in case |
| * some was inserted by mistake, we should remove it. The main reason for this |
| * is that we will be preserving original contact IDs and don't want to run into |
| * any collisions. |
| */ |
| mContactsProvider.wipeData(); |
| |
| importGroups(); |
| importPeople(); |
| importOrganizations(); |
| importPhones(); |
| importContactMethods(); |
| importPhotos(); |
| importGroupMemberships(); |
| updateDisplayNamesAndLookupKeys(); |
| |
| // Deleted contacts should be inserted after everything else, because |
| // the legacy table does not provide an _ID field - the _ID field |
| // will be autoincremented |
| importDeletedPeople(); |
| |
| mDbHelper.updateAllVisible(); |
| |
| mTargetDb.setTransactionSuccessful(); |
| } finally { |
| mTargetDb.endTransaction(); |
| } |
| |
| importCalls(); |
| } |
| |
| /** |
| * This is used for simulating an import failure. Insert a row into the "settings" |
| * table with key='TEST' and then proceed with the upgrade. Remove the record |
| * after verifying the failure handling. |
| */ |
| private void checkForImportFailureTest() { |
| long isTest = DatabaseUtils.longForQuery(mSourceDb, |
| "SELECT COUNT(*) FROM settings WHERE key='TEST'", null); |
| if (isTest != 0) { |
| throw new SQLiteException("Testing import failure."); |
| } |
| } |
| |
| private interface GroupsQuery { |
| String TABLE = "groups"; |
| |
| String[] COLUMNS = { |
| "_id", "name", "notes", "should_sync", "system_id", "_sync_account", "_sync_id", |
| "_sync_dirty", |
| }; |
| |
| static int ID = 0; |
| static int NAME = 1; |
| static int NOTES = 2; |
| static int SHOULD_SYNC = 3; // TODO add this feature to Groups |
| static int SYSTEM_ID = 4; |
| |
| static int _SYNC_ACCOUNT = 5; |
| static int _SYNC_ID = 6; |
| static int _SYNC_DIRTY = 7; |
| } |
| |
| private interface GroupsInsert { |
| String INSERT_SQL = "INSERT INTO " + Tables.GROUPS + "(" + |
| Groups._ID + "," + |
| Groups.TITLE + "," + |
| Groups.NOTES + "," + |
| Groups.SYSTEM_ID + "," + |
| Groups.DIRTY + "," + |
| Groups.GROUP_VISIBLE + "," + |
| Groups.ACCOUNT_NAME + "," + |
| Groups.ACCOUNT_TYPE + "," + |
| Groups.SOURCE_ID + |
| ") VALUES (?,?,?,?,?,?,?,?,?)"; |
| |
| int ID = 1; |
| int TITLE = 2; |
| int NOTES = 3; |
| int SYSTEM_ID = 4; |
| int DIRTY = 5; |
| int GROUP_VISIBLE = 6; |
| int ACCOUNT_NAME = 7; |
| int ACCOUNT_TYPE = 8; |
| int SOURCE_ID = 9; |
| } |
| |
| private void importGroups() { |
| SQLiteStatement insert = mTargetDb.compileStatement(GroupsInsert.INSERT_SQL); |
| Cursor c = mSourceDb.query(GroupsQuery.TABLE, GroupsQuery.COLUMNS, null, null, |
| null, null, null); |
| try { |
| while (c.moveToNext()) { |
| insertGroup(c, insert); |
| } |
| } finally { |
| c.close(); |
| insert.close(); |
| } |
| } |
| |
| private void insertGroup(Cursor c, SQLiteStatement insert) { |
| long id = c.getLong(GroupsQuery.ID); |
| |
| insert.bindLong(GroupsInsert.ID, id); |
| bindString(insert, GroupsInsert.TITLE, c.getString(GroupsQuery.NAME)); |
| bindString(insert, GroupsInsert.NOTES, c.getString(GroupsQuery.NOTES)); |
| bindString(insert, GroupsInsert.SYSTEM_ID, c.getString(GroupsQuery.SYSTEM_ID)); |
| insert.bindLong(GroupsInsert.DIRTY, c.getLong(GroupsQuery._SYNC_DIRTY)); |
| insert.bindLong(GroupsInsert.GROUP_VISIBLE, 1); |
| |
| String account = c.getString(GroupsQuery._SYNC_ACCOUNT); |
| if (!TextUtils.isEmpty(account)) { |
| bindString(insert, GroupsInsert.ACCOUNT_NAME, account); |
| bindString(insert, GroupsInsert.ACCOUNT_TYPE, DEFAULT_ACCOUNT_TYPE); |
| bindString(insert, GroupsInsert.SOURCE_ID, c.getString(GroupsQuery._SYNC_ID)); |
| } else { |
| insert.bindNull(GroupsInsert.ACCOUNT_NAME); |
| insert.bindNull(GroupsInsert.ACCOUNT_TYPE); |
| insert.bindNull(GroupsInsert.SOURCE_ID); |
| } |
| insert(insert); |
| } |
| |
| private interface PeopleQuery { |
| String TABLE = "people"; |
| |
| String NAME_SQL = |
| "(CASE WHEN (name IS NOT NULL AND name != '') " |
| + "THEN name " |
| + "ELSE " |
| + "(CASE WHEN primary_organization is NOT NULL THEN " |
| + "(SELECT company FROM organizations WHERE " |
| + "organizations._id = primary_organization) " |
| + "ELSE " |
| + "(CASE WHEN primary_phone IS NOT NULL THEN " |
| +"(SELECT number FROM phones WHERE phones._id = primary_phone) " |
| + "ELSE " |
| + "(CASE WHEN primary_email IS NOT NULL THEN " |
| + "(SELECT data FROM contact_methods WHERE " |
| + "contact_methods._id = primary_email) " |
| + "ELSE " |
| + "null " |
| + "END) " |
| + "END) " |
| + "END) " |
| + "END) "; |
| |
| |
| String[] COLUMNS_WITH_DISPLAY_NAME_WITHOUT_PHONETIC_NAME = { |
| "_id", NAME_SQL, "notes", "times_contacted", "last_time_contacted", "starred", |
| "primary_phone", "primary_organization", "primary_email", "custom_ringtone", |
| "send_to_voicemail", "_sync_account", "_sync_id", "_sync_time", "_sync_local_id", |
| "_sync_dirty", |
| }; |
| |
| String[] COLUMNS_WITH_DISPLAY_NAME_WITH_PHONETIC_NAME = { |
| "_id", NAME_SQL, "notes", "times_contacted", "last_time_contacted", "starred", |
| "primary_phone", "primary_organization", "primary_email", "custom_ringtone", |
| "send_to_voicemail", "_sync_account", "_sync_id", "_sync_time", "_sync_local_id", |
| "_sync_dirty", "phonetic_name", |
| }; |
| |
| String[] COLUMNS_WITHOUT_PHONETIC_NAME = { |
| "_id", "name", "notes", "times_contacted", "last_time_contacted", "starred", |
| "primary_phone", "primary_organization", "primary_email", "custom_ringtone", |
| "send_to_voicemail", "_sync_account", "_sync_id", "_sync_time", "_sync_local_id", |
| "_sync_dirty", |
| }; |
| |
| String[] COLUMNS_WITH_PHONETIC_NAME = { |
| "_id", "name", "notes", "times_contacted", "last_time_contacted", "starred", |
| "primary_phone", "primary_organization", "primary_email", "custom_ringtone", |
| "send_to_voicemail", "_sync_account", "_sync_id", "_sync_time", "_sync_local_id", |
| "_sync_dirty", "phonetic_name", |
| }; |
| |
| static int _ID = 0; |
| static int NAME = 1; |
| static int NOTES = 2; |
| static int TIMES_CONTACTED = 3; |
| static int LAST_TIME_CONTACTED = 4; |
| static int STARRED = 5; |
| static int PRIMARY_PHONE = 6; |
| static int PRIMARY_ORGANIZATION = 7; |
| static int PRIMARY_EMAIL = 8; |
| static int CUSTOM_RINGTONE = 9; |
| static int SEND_TO_VOICEMAIL = 10; |
| |
| static int _SYNC_ACCOUNT = 11; |
| static int _SYNC_ID = 12; |
| static int _SYNC_TIME = 13; |
| static int _SYNC_LOCAL_ID = 14; |
| static int _SYNC_DIRTY = 15; |
| |
| static int PHONETIC_NAME = 16; |
| } |
| |
| |
| private interface RawContactsInsert { |
| String INSERT_SQL = "INSERT INTO " + Tables.RAW_CONTACTS + "(" + |
| RawContacts._ID + "," + |
| RawContacts.CONTACT_ID + "," + |
| RawContacts.CUSTOM_RINGTONE + "," + |
| RawContacts.DIRTY + "," + |
| RawContacts.LAST_TIME_CONTACTED + "," + |
| RawContacts.SEND_TO_VOICEMAIL + "," + |
| RawContacts.STARRED + "," + |
| RawContacts.TIMES_CONTACTED + "," + |
| RawContacts.SYNC1 + "," + |
| RawContacts.SYNC2 + "," + |
| RawContacts.ACCOUNT_NAME + "," + |
| RawContacts.ACCOUNT_TYPE + "," + |
| RawContacts.SOURCE_ID + "," + |
| RawContactsColumns.DISPLAY_NAME + "," + |
| RawContactsColumns.CONTACT_IN_VISIBLE_GROUP + |
| ") VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)"; |
| |
| int ID = 1; |
| int CONTACT_ID = 2; |
| int CUSTOM_RINGTONE = 3; |
| int DIRTY = 4; |
| int LAST_TIME_CONTACTED = 5; |
| int SEND_TO_VOICEMAIL = 6; |
| int STARRED = 7; |
| int TIMES_CONTACTED = 8; |
| int SYNC1 = 9; |
| int SYNC2 = 10; |
| int ACCOUNT_NAME = 11; |
| int ACCOUNT_TYPE = 12; |
| int SOURCE_ID = 13; |
| int DISPLAY_NAME = 14; |
| int CONTACT_IN_VISIBLE_GROUP = 15; |
| } |
| |
| private interface ContactsInsert { |
| String INSERT_SQL = "INSERT INTO " + Tables.CONTACTS + "(" + |
| Contacts._ID + "," + |
| Contacts.CUSTOM_RINGTONE + "," + |
| Contacts.LAST_TIME_CONTACTED + "," + |
| Contacts.SEND_TO_VOICEMAIL + "," + |
| Contacts.STARRED + "," + |
| Contacts.TIMES_CONTACTED + "," + |
| Contacts.NAME_RAW_CONTACT_ID + "," + |
| Contacts.IN_VISIBLE_GROUP + |
| ") VALUES (?,?,?,?,?,?,?,?)"; |
| |
| int ID = 1; |
| int CUSTOM_RINGTONE = 2; |
| int LAST_TIME_CONTACTED = 3; |
| int SEND_TO_VOICEMAIL = 4; |
| int STARRED = 5; |
| int TIMES_CONTACTED = 6; |
| int NAME_RAW_CONTACT_ID = 7; |
| int IN_VISIBLE_GROUP = 8; |
| } |
| |
| private interface StructuredNameInsert { |
| String INSERT_SQL = "INSERT INTO " + Tables.DATA + "(" + |
| Data.RAW_CONTACT_ID + "," + |
| DataColumns.MIMETYPE_ID + "," + |
| StructuredName.DISPLAY_NAME + "," + |
| StructuredName.PREFIX + "," + |
| StructuredName.GIVEN_NAME + "," + |
| StructuredName.MIDDLE_NAME + "," + |
| StructuredName.FAMILY_NAME + "," + |
| StructuredName.SUFFIX + "," + |
| StructuredName.FULL_NAME_STYLE + "," + |
| StructuredName.PHONETIC_FAMILY_NAME + "," + |
| StructuredName.PHONETIC_MIDDLE_NAME + "," + |
| StructuredName.PHONETIC_GIVEN_NAME + "," + |
| StructuredName.PHONETIC_NAME_STYLE + |
| ") VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?)"; |
| |
| int RAW_CONTACT_ID = 1; |
| int MIMETYPE_ID = 2; |
| int DISPLAY_NAME = 3; |
| int PREFIX = 4; |
| int GIVEN_NAME = 5; |
| int MIDDLE_NAME = 6; |
| int FAMILY_NAME = 7; |
| int SUFFIX = 8; |
| int FULL_NAME_STYLE = 9; |
| int PHONETIC_FAMILY_NAME = 10; |
| int PHONETIC_MIDDLE_NAME = 11; |
| int PHONETIC_GIVEN_NAME = 12; |
| int PHONETIC_NAME_STYLE = 13; |
| } |
| |
| private interface NoteInsert { |
| String INSERT_SQL = "INSERT INTO " + Tables.DATA + "(" + |
| Data.RAW_CONTACT_ID + "," + |
| DataColumns.MIMETYPE_ID + "," + |
| Note.NOTE + |
| ") VALUES (?,?,?)"; |
| |
| int RAW_CONTACT_ID = 1; |
| int MIMETYPE_ID = 2; |
| int NOTE = 3; |
| } |
| |
| private void importPeople() { |
| SQLiteStatement rawContactInsert = mTargetDb.compileStatement(RawContactsInsert.INSERT_SQL); |
| SQLiteStatement contactInsert = mTargetDb.compileStatement(ContactsInsert.INSERT_SQL); |
| SQLiteStatement structuredNameInsert = |
| mTargetDb.compileStatement(StructuredNameInsert.INSERT_SQL); |
| SQLiteStatement noteInsert = mTargetDb.compileStatement(NoteInsert.INSERT_SQL); |
| try { |
| String[] columns = mPhoneticNameAvailable |
| ? PeopleQuery.COLUMNS_WITH_DISPLAY_NAME_WITH_PHONETIC_NAME |
| : PeopleQuery.COLUMNS_WITH_DISPLAY_NAME_WITHOUT_PHONETIC_NAME; |
| Cursor c = mSourceDb.query(PeopleQuery.TABLE, columns, "name IS NULL", null, null, |
| null, null); |
| try { |
| while (c.moveToNext()) { |
| insertRawContact(c, rawContactInsert); |
| insertContact(c, contactInsert); |
| insertNote(c, noteInsert); |
| mContactCount++; |
| } |
| } finally { |
| c.close(); |
| } |
| |
| columns = mPhoneticNameAvailable |
| ? PeopleQuery.COLUMNS_WITH_PHONETIC_NAME |
| : PeopleQuery.COLUMNS_WITHOUT_PHONETIC_NAME; |
| c = mSourceDb.query(PeopleQuery.TABLE, columns, "name IS NOT NULL", null, null, null, |
| null); |
| try { |
| while (c.moveToNext()) { |
| long id = insertRawContact(c, rawContactInsert); |
| insertContact(c, contactInsert); |
| insertStructuredName(c, structuredNameInsert); |
| insertNote(c, noteInsert); |
| mContactCount++; |
| } |
| } finally { |
| c.close(); |
| } |
| } finally { |
| rawContactInsert.close(); |
| contactInsert.close(); |
| structuredNameInsert.close(); |
| noteInsert.close(); |
| } |
| } |
| |
| private long insertRawContact(Cursor c, SQLiteStatement insert) { |
| long id = c.getLong(PeopleQuery._ID); |
| insert.bindLong(RawContactsInsert.ID, id); |
| insert.bindLong(RawContactsInsert.CONTACT_ID, id); |
| bindString(insert, RawContactsInsert.CUSTOM_RINGTONE, |
| c.getString(PeopleQuery.CUSTOM_RINGTONE)); |
| bindString(insert, RawContactsInsert.DIRTY, |
| c.getString(PeopleQuery._SYNC_DIRTY)); |
| insert.bindLong(RawContactsInsert.LAST_TIME_CONTACTED, |
| c.getLong(PeopleQuery.LAST_TIME_CONTACTED)); |
| insert.bindLong(RawContactsInsert.SEND_TO_VOICEMAIL, |
| c.getLong(PeopleQuery.SEND_TO_VOICEMAIL)); |
| insert.bindLong(RawContactsInsert.STARRED, |
| c.getLong(PeopleQuery.STARRED)); |
| insert.bindLong(RawContactsInsert.TIMES_CONTACTED, |
| c.getLong(PeopleQuery.TIMES_CONTACTED)); |
| bindString(insert, RawContactsInsert.SYNC1, |
| c.getString(PeopleQuery._SYNC_TIME)); |
| bindString(insert, RawContactsInsert.SYNC2, |
| c.getString(PeopleQuery._SYNC_LOCAL_ID)); |
| bindString(insert, RawContactsInsert.DISPLAY_NAME, |
| c.getString(PeopleQuery.NAME)); |
| insert.bindLong(RawContactsInsert.CONTACT_IN_VISIBLE_GROUP, 1); |
| |
| String account = c.getString(PeopleQuery._SYNC_ACCOUNT); |
| if (!TextUtils.isEmpty(account)) { |
| bindString(insert, RawContactsInsert.ACCOUNT_NAME, account); |
| bindString(insert, RawContactsInsert.ACCOUNT_TYPE, DEFAULT_ACCOUNT_TYPE); |
| bindString(insert, RawContactsInsert.SOURCE_ID, c.getString(PeopleQuery._SYNC_ID)); |
| } else { |
| insert.bindNull(RawContactsInsert.ACCOUNT_NAME); |
| insert.bindNull(RawContactsInsert.ACCOUNT_TYPE); |
| insert.bindNull(RawContactsInsert.SOURCE_ID); |
| } |
| insert(insert); |
| return id; |
| } |
| |
| private void insertContact(Cursor c, SQLiteStatement insert) { |
| long id = c.getLong(PeopleQuery._ID); |
| insert.bindLong(ContactsInsert.ID, id); |
| bindString(insert, ContactsInsert.CUSTOM_RINGTONE, |
| c.getString(PeopleQuery.CUSTOM_RINGTONE)); |
| insert.bindLong(ContactsInsert.LAST_TIME_CONTACTED, |
| c.getLong(PeopleQuery.LAST_TIME_CONTACTED)); |
| insert.bindLong(ContactsInsert.SEND_TO_VOICEMAIL, |
| c.getLong(PeopleQuery.SEND_TO_VOICEMAIL)); |
| insert.bindLong(ContactsInsert.STARRED, |
| c.getLong(PeopleQuery.STARRED)); |
| insert.bindLong(ContactsInsert.TIMES_CONTACTED, |
| c.getLong(PeopleQuery.TIMES_CONTACTED)); |
| insert.bindLong(ContactsInsert.NAME_RAW_CONTACT_ID, id); |
| insert.bindLong(ContactsInsert.IN_VISIBLE_GROUP, 1); |
| |
| insert(insert); |
| } |
| |
| private void insertStructuredName(Cursor c, SQLiteStatement insert) { |
| String name = c.getString(PeopleQuery.NAME); |
| if (TextUtils.isEmpty(name)) { |
| return; |
| } |
| |
| long id = c.getLong(PeopleQuery._ID); |
| |
| insert.bindLong(StructuredNameInsert.RAW_CONTACT_ID, id); |
| insert.bindLong(StructuredNameInsert.MIMETYPE_ID, mStructuredNameMimetypeId); |
| bindString(insert, StructuredNameInsert.DISPLAY_NAME, name); |
| |
| NameSplitter.Name splitName = new NameSplitter.Name(); |
| mNameSplitter.split(splitName, name); |
| |
| bindString(insert, StructuredNameInsert.PREFIX, |
| splitName.getPrefix()); |
| bindString(insert, StructuredNameInsert.GIVEN_NAME, |
| splitName.getGivenNames()); |
| bindString(insert, StructuredNameInsert.MIDDLE_NAME, |
| splitName.getMiddleName()); |
| bindString(insert, StructuredNameInsert.FAMILY_NAME, |
| splitName.getFamilyName()); |
| bindString(insert, StructuredNameInsert.SUFFIX, |
| splitName.getSuffix()); |
| final String joined = mNameSplitter.join(splitName, true); |
| bindString(insert, StructuredNameInsert.DISPLAY_NAME, joined); |
| |
| if (mPhoneticNameAvailable) { |
| String phoneticName = c.getString(PeopleQuery.PHONETIC_NAME); |
| if (phoneticName != null) { |
| int index = phoneticName.indexOf(' '); |
| if (index == -1) { |
| splitName.phoneticFamilyName = phoneticName; |
| } else { |
| splitName.phoneticFamilyName = phoneticName.substring(0, index).trim(); |
| splitName.phoneticGivenName = phoneticName.substring(index + 1).trim(); |
| } |
| } |
| } |
| |
| mNameSplitter.guessNameStyle(splitName); |
| |
| int fullNameStyle = splitName.getFullNameStyle(); |
| insert.bindLong(StructuredNameInsert.FULL_NAME_STYLE, |
| fullNameStyle); |
| bindString(insert, StructuredNameInsert.PHONETIC_FAMILY_NAME, |
| splitName.phoneticFamilyName); |
| bindString(insert, StructuredNameInsert.PHONETIC_MIDDLE_NAME, |
| splitName.phoneticMiddleName); |
| bindString(insert, StructuredNameInsert.PHONETIC_GIVEN_NAME, |
| splitName.phoneticGivenName); |
| insert.bindLong(StructuredNameInsert.PHONETIC_NAME_STYLE, |
| splitName.phoneticNameStyle); |
| |
| long dataId = insert(insert); |
| |
| mContactsProvider.insertNameLookupForStructuredName(id, dataId, name, |
| mNameSplitter.getAdjustedFullNameStyle(fullNameStyle)); |
| if (splitName.phoneticFamilyName != null |
| || splitName.phoneticMiddleName != null |
| || splitName.phoneticGivenName != null) { |
| mContactsProvider.insertNameLookupForPhoneticName(id, dataId, |
| splitName.phoneticFamilyName, |
| splitName.phoneticMiddleName, |
| splitName.phoneticGivenName); |
| } |
| } |
| |
| private void insertNote(Cursor c, SQLiteStatement insert) { |
| String notes = c.getString(PeopleQuery.NOTES); |
| |
| if (TextUtils.isEmpty(notes)) { |
| return; |
| } |
| |
| long id = c.getLong(PeopleQuery._ID); |
| insert.bindLong(NoteInsert.RAW_CONTACT_ID, id); |
| insert.bindLong(NoteInsert.MIMETYPE_ID, mNoteMimetypeId); |
| bindString(insert, NoteInsert.NOTE, notes); |
| insert(insert); |
| } |
| |
| private interface OrganizationsQuery { |
| String TABLE = "organizations"; |
| |
| String[] COLUMNS = { |
| "person", "company", "title", "isprimary", "type", "label", |
| }; |
| |
| static int PERSON = 0; |
| static int COMPANY = 1; |
| static int TITLE = 2; |
| static int ISPRIMARY = 3; |
| static int TYPE = 4; |
| static int LABEL = 5; |
| } |
| |
| private interface OrganizationInsert { |
| String INSERT_SQL = "INSERT INTO " + Tables.DATA + "(" + |
| Data.RAW_CONTACT_ID + "," + |
| DataColumns.MIMETYPE_ID + "," + |
| Data.IS_PRIMARY + "," + |
| Data.IS_SUPER_PRIMARY + "," + |
| Organization.COMPANY + "," + |
| Organization.TITLE + "," + |
| Organization.TYPE + "," + |
| Organization.LABEL + |
| ") VALUES (?,?,?,?,?,?,?,?)"; |
| |
| int RAW_CONTACT_ID = 1; |
| int MIMETYPE_ID = 2; |
| int IS_PRIMARY = 3; |
| int IS_SUPER_PRIMARY = 4; |
| int COMPANY = 5; |
| int TITLE = 6; |
| int TYPE = 7; |
| int LABEL = 8; |
| } |
| |
| private void importOrganizations() { |
| SQLiteStatement insert = mTargetDb.compileStatement(OrganizationInsert.INSERT_SQL); |
| Cursor c = mSourceDb.query(OrganizationsQuery.TABLE, OrganizationsQuery.COLUMNS, null, null, |
| null, null, null); |
| try { |
| while (c.moveToNext()) { |
| insertOrganization(c, insert); |
| } |
| } finally { |
| c.close(); |
| insert.close(); |
| } |
| } |
| |
| private void insertOrganization(Cursor c, SQLiteStatement insert) { |
| long id = c.getLong(OrganizationsQuery.PERSON); |
| insert.bindLong(OrganizationInsert.RAW_CONTACT_ID, id); |
| insert.bindLong(OrganizationInsert.MIMETYPE_ID, mOrganizationMimetypeId); |
| bindString(insert, OrganizationInsert.IS_PRIMARY, c.getString(OrganizationsQuery.ISPRIMARY)); |
| bindString(insert, OrganizationInsert.IS_SUPER_PRIMARY, |
| c.getString(OrganizationsQuery.ISPRIMARY)); |
| bindString(insert, OrganizationInsert.COMPANY, c.getString(OrganizationsQuery.COMPANY)); |
| bindString(insert, OrganizationInsert.TITLE, c.getString(OrganizationsQuery.TITLE)); |
| bindString(insert, OrganizationInsert.TYPE, c.getString(OrganizationsQuery.TYPE)); |
| bindString(insert, OrganizationInsert.LABEL, c.getString(OrganizationsQuery.LABEL)); |
| insert(insert); |
| } |
| |
| private interface ContactMethodsQuery { |
| String TABLE = "contact_methods"; |
| |
| String[] COLUMNS = { |
| "person", "kind", "data", "aux_data", "type", "label", "isprimary", |
| }; |
| |
| static int PERSON = 0; |
| static int KIND = 1; |
| static int DATA = 2; |
| static int AUX_DATA = 3; |
| static int TYPE = 4; |
| static int LABEL = 5; |
| static int ISPRIMARY = 6; |
| } |
| |
| private interface EmailInsert { |
| String INSERT_SQL = "INSERT INTO " + Tables.DATA + "(" + |
| Data.RAW_CONTACT_ID + "," + |
| DataColumns.MIMETYPE_ID + "," + |
| Data.IS_PRIMARY + "," + |
| Data.IS_SUPER_PRIMARY + "," + |
| Email.DATA + "," + |
| Email.TYPE + "," + |
| Email.LABEL + "," + |
| Data.DATA14 + |
| ") VALUES (?,?,?,?,?,?,?,?)"; |
| |
| int RAW_CONTACT_ID = 1; |
| int MIMETYPE_ID = 2; |
| int IS_PRIMARY = 3; |
| int IS_SUPER_PRIMARY = 4; |
| int DATA = 5; |
| int TYPE = 6; |
| int LABEL = 7; |
| int AUX_DATA = 8; |
| } |
| |
| private interface ImInsert { |
| String INSERT_SQL = "INSERT INTO " + Tables.DATA + "(" + |
| Data.RAW_CONTACT_ID + "," + |
| DataColumns.MIMETYPE_ID + "," + |
| Data.IS_PRIMARY + "," + |
| Data.IS_SUPER_PRIMARY + "," + |
| Im.DATA + "," + |
| Im.TYPE + "," + |
| Im.LABEL + "," + |
| Data.DATA14 + |
| ") VALUES (?,?,?,?,?,?,?,?)"; |
| |
| int RAW_CONTACT_ID = 1; |
| int MIMETYPE_ID = 2; |
| int IS_PRIMARY = 3; |
| int IS_SUPER_PRIMARY = 4; |
| int DATA = 5; |
| int TYPE = 6; |
| int LABEL = 7; |
| int AUX_DATA = 8; |
| } |
| |
| private interface PostalInsert { |
| String INSERT_SQL = "INSERT INTO " + Tables.DATA + "(" + |
| Data.RAW_CONTACT_ID + "," + |
| DataColumns.MIMETYPE_ID + "," + |
| Data.IS_PRIMARY + "," + |
| Data.IS_SUPER_PRIMARY + "," + |
| StructuredPostal.FORMATTED_ADDRESS + "," + |
| StructuredPostal.TYPE + "," + |
| StructuredPostal.LABEL + "," + |
| Data.DATA14 + |
| ") VALUES (?,?,?,?,?,?,?,?)"; |
| |
| int RAW_CONTACT_ID = 1; |
| int MIMETYPE_ID = 2; |
| int IS_PRIMARY = 3; |
| int IS_SUPER_PRIMARY = 4; |
| int DATA = 5; |
| int TYPE = 6; |
| int LABEL = 7; |
| int AUX_DATA = 8; |
| } |
| |
| private void importContactMethods() { |
| SQLiteStatement emailInsert = mTargetDb.compileStatement(EmailInsert.INSERT_SQL); |
| SQLiteStatement imInsert = mTargetDb.compileStatement(ImInsert.INSERT_SQL); |
| SQLiteStatement postalInsert = mTargetDb.compileStatement(PostalInsert.INSERT_SQL); |
| Cursor c = mSourceDb.query(ContactMethodsQuery.TABLE, ContactMethodsQuery.COLUMNS, null, |
| null, null, null, null); |
| try { |
| while (c.moveToNext()) { |
| int kind = c.getInt(ContactMethodsQuery.KIND); |
| switch (kind) { |
| case android.provider.Contacts.KIND_EMAIL: |
| insertEmail(c, emailInsert); |
| break; |
| |
| case android.provider.Contacts.KIND_IM: |
| insertIm(c, imInsert); |
| break; |
| |
| case android.provider.Contacts.KIND_POSTAL: |
| insertPostal(c, postalInsert); |
| break; |
| } |
| } |
| } finally { |
| c.close(); |
| emailInsert.close(); |
| imInsert.close(); |
| postalInsert.close(); |
| } |
| |
| } |
| |
| private void insertEmail(Cursor c, SQLiteStatement insert) { |
| long personId = c.getLong(ContactMethodsQuery.PERSON); |
| String email = c.getString(ContactMethodsQuery.DATA); |
| |
| insert.bindLong(EmailInsert.RAW_CONTACT_ID, personId); |
| insert.bindLong(EmailInsert.MIMETYPE_ID, mEmailMimetypeId); |
| bindString(insert, EmailInsert.IS_PRIMARY, c.getString(ContactMethodsQuery.ISPRIMARY)); |
| bindString(insert, EmailInsert.IS_SUPER_PRIMARY, c.getString(ContactMethodsQuery.ISPRIMARY)); |
| bindString(insert, EmailInsert.DATA, email); |
| bindString(insert, EmailInsert.AUX_DATA, c.getString(ContactMethodsQuery.AUX_DATA)); |
| bindString(insert, EmailInsert.TYPE, c.getString(ContactMethodsQuery.TYPE)); |
| bindString(insert, EmailInsert.LABEL, c.getString(ContactMethodsQuery.LABEL)); |
| |
| long dataId = insert(insert); |
| mContactsProvider.insertNameLookupForEmail(personId, dataId, email); |
| } |
| |
| private void insertIm(Cursor c, SQLiteStatement insert) { |
| long personId = c.getLong(ContactMethodsQuery.PERSON); |
| |
| insert.bindLong(ImInsert.RAW_CONTACT_ID, personId); |
| insert.bindLong(ImInsert.MIMETYPE_ID, mImMimetypeId); |
| bindString(insert, ImInsert.IS_PRIMARY, c.getString(ContactMethodsQuery.ISPRIMARY)); |
| bindString(insert, ImInsert.IS_SUPER_PRIMARY, c.getString(ContactMethodsQuery.ISPRIMARY)); |
| bindString(insert, ImInsert.DATA, c.getString(ContactMethodsQuery.DATA)); |
| bindString(insert, ImInsert.AUX_DATA, c.getString(ContactMethodsQuery.AUX_DATA)); |
| bindString(insert, ImInsert.TYPE, c.getString(ContactMethodsQuery.TYPE)); |
| bindString(insert, ImInsert.LABEL, c.getString(ContactMethodsQuery.LABEL)); |
| insert(insert); |
| } |
| |
| private void insertPostal(Cursor c, SQLiteStatement insert) { |
| long personId = c.getLong(ContactMethodsQuery.PERSON); |
| |
| insert.bindLong(PostalInsert.RAW_CONTACT_ID, personId); |
| insert.bindLong(PostalInsert.MIMETYPE_ID, mPostalMimetypeId); |
| bindString(insert, PostalInsert.IS_PRIMARY, c.getString(ContactMethodsQuery.ISPRIMARY)); |
| bindString(insert, PostalInsert.IS_SUPER_PRIMARY, |
| c.getString(ContactMethodsQuery.ISPRIMARY)); |
| bindString(insert, PostalInsert.DATA, c.getString(ContactMethodsQuery.DATA)); |
| bindString(insert, PostalInsert.AUX_DATA, c.getString(ContactMethodsQuery.AUX_DATA)); |
| bindString(insert, PostalInsert.TYPE, c.getString(ContactMethodsQuery.TYPE)); |
| bindString(insert, PostalInsert.LABEL, c.getString(ContactMethodsQuery.LABEL)); |
| insert(insert); |
| } |
| |
| private interface PhonesQuery { |
| String TABLE = "phones"; |
| |
| String[] COLUMNS = { |
| "person", "type", "number", "label", "isprimary", |
| }; |
| |
| static int PERSON = 0; |
| static int TYPE = 1; |
| static int NUMBER = 2; |
| static int LABEL = 3; |
| static int ISPRIMARY = 4; |
| } |
| |
| private interface PhoneInsert { |
| String INSERT_SQL = "INSERT INTO " + Tables.DATA + "(" + |
| Data.RAW_CONTACT_ID + "," + |
| DataColumns.MIMETYPE_ID + "," + |
| Data.IS_PRIMARY + "," + |
| Data.IS_SUPER_PRIMARY + "," + |
| Phone.NUMBER + "," + |
| Phone.TYPE + "," + |
| Phone.LABEL + "," + |
| PhoneColumns.NORMALIZED_NUMBER + |
| ") VALUES (?,?,?,?,?,?,?,?)"; |
| |
| int RAW_CONTACT_ID = 1; |
| int MIMETYPE_ID = 2; |
| int IS_PRIMARY = 3; |
| int IS_SUPER_PRIMARY = 4; |
| int NUMBER = 5; |
| int TYPE = 6; |
| int LABEL = 7; |
| int NORMALIZED_NUMBER = 8; |
| } |
| |
| private interface PhoneLookupInsert { |
| String INSERT_SQL = "INSERT INTO " + Tables.PHONE_LOOKUP + "(" + |
| PhoneLookupColumns.RAW_CONTACT_ID + "," + |
| PhoneLookupColumns.DATA_ID + "," + |
| PhoneLookupColumns.NORMALIZED_NUMBER + "," + |
| PhoneLookupColumns.MIN_MATCH + |
| ") VALUES (?,?,?,?)"; |
| |
| int RAW_CONTACT_ID = 1; |
| int DATA_ID = 2; |
| int NORMALIZED_NUMBER = 3; |
| int MIN_MATCH = 4; |
| } |
| |
| private interface HasPhoneNumberUpdate { |
| String UPDATE_SQL = "UPDATE " + Tables.CONTACTS + |
| " SET " + Contacts.HAS_PHONE_NUMBER + "=1 WHERE " + Contacts._ID + "=?"; |
| |
| int CONTACT_ID = 1; |
| } |
| |
| private void importPhones() { |
| SQLiteStatement phoneInsert = mTargetDb.compileStatement(PhoneInsert.INSERT_SQL); |
| SQLiteStatement phoneLookupInsert = |
| mTargetDb.compileStatement(PhoneLookupInsert.INSERT_SQL); |
| SQLiteStatement hasPhoneUpdate = |
| mTargetDb.compileStatement(HasPhoneNumberUpdate.UPDATE_SQL); |
| Cursor c = mSourceDb.query(PhonesQuery.TABLE, PhonesQuery.COLUMNS, null, null, |
| null, null, null); |
| try { |
| while (c.moveToNext()) { |
| insertPhone(c, phoneInsert, phoneLookupInsert, hasPhoneUpdate); |
| } |
| } finally { |
| c.close(); |
| phoneInsert.close(); |
| phoneLookupInsert.close(); |
| hasPhoneUpdate.close(); |
| } |
| } |
| |
| private void insertPhone(Cursor c, SQLiteStatement phoneInsert, |
| SQLiteStatement phoneLookupInsert, SQLiteStatement hasPhoneUpdate) { |
| long lastUpdatedContact = -1; |
| long id = c.getLong(PhonesQuery.PERSON); |
| String number = c.getString(PhonesQuery.NUMBER); |
| String normalizedNumber = null; |
| if (number != null) { |
| normalizedNumber = PhoneNumberUtils.getStrippedReversed(number); |
| } |
| phoneInsert.bindLong(PhoneInsert.RAW_CONTACT_ID, id); |
| phoneInsert.bindLong(PhoneInsert.MIMETYPE_ID, mPhoneMimetypeId); |
| bindString(phoneInsert, PhoneInsert.IS_PRIMARY, c.getString(PhonesQuery.ISPRIMARY)); |
| bindString(phoneInsert, PhoneInsert.IS_SUPER_PRIMARY, c.getString(PhonesQuery.ISPRIMARY)); |
| bindString(phoneInsert, PhoneInsert.NUMBER, number); |
| bindString(phoneInsert, PhoneInsert.TYPE, c.getString(PhonesQuery.TYPE)); |
| bindString(phoneInsert, PhoneInsert.LABEL, c.getString(PhonesQuery.LABEL)); |
| bindString(phoneInsert, PhoneInsert.NORMALIZED_NUMBER, normalizedNumber); |
| |
| long dataId = insert(phoneInsert); |
| if (normalizedNumber != null) { |
| phoneLookupInsert.bindLong(PhoneLookupInsert.RAW_CONTACT_ID, id); |
| phoneLookupInsert.bindLong(PhoneLookupInsert.DATA_ID, dataId); |
| phoneLookupInsert.bindString(PhoneLookupInsert.NORMALIZED_NUMBER, normalizedNumber); |
| phoneLookupInsert.bindString(PhoneLookupInsert.MIN_MATCH, |
| PhoneNumberUtils.toCallerIDMinMatch(number)); |
| insert(phoneLookupInsert); |
| |
| if (lastUpdatedContact != id) { |
| lastUpdatedContact = id; |
| hasPhoneUpdate.bindLong(HasPhoneNumberUpdate.CONTACT_ID, id); |
| hasPhoneUpdate.execute(); |
| } |
| } |
| } |
| |
| private interface PhotosQuery { |
| String TABLE = "photos"; |
| |
| String[] COLUMNS = { |
| "person", "data", "_sync_id", "_sync_account" |
| }; |
| |
| static int PERSON = 0; |
| static int DATA = 1; |
| static int _SYNC_ID = 2; |
| static int _SYNC_ACCOUNT = 3; |
| } |
| |
| private interface PhotoInsert { |
| String INSERT_SQL = "INSERT INTO " + Tables.DATA + "(" + |
| Data.RAW_CONTACT_ID + "," + |
| DataColumns.MIMETYPE_ID + "," + |
| Photo.PHOTO + "," + |
| Data.SYNC1 + |
| ") VALUES (?,?,?,?)"; |
| |
| int RAW_CONTACT_ID = 1; |
| int MIMETYPE_ID = 2; |
| int PHOTO = 3; |
| int SYNC1 = 4; |
| } |
| |
| private interface PhotoIdUpdate { |
| String UPDATE_SQL = "UPDATE " + Tables.CONTACTS + |
| " SET " + Contacts.PHOTO_ID + "=? WHERE " + Contacts._ID + "=?"; |
| |
| int PHOTO_ID = 1; |
| int CONTACT_ID = 2; |
| } |
| |
| private void importPhotos() { |
| SQLiteStatement insert = mTargetDb.compileStatement(PhotoInsert.INSERT_SQL); |
| SQLiteStatement photoIdUpdate = mTargetDb.compileStatement(PhotoIdUpdate.UPDATE_SQL); |
| Cursor c = mSourceDb.query(PhotosQuery.TABLE, PhotosQuery.COLUMNS, null, null, |
| null, null, null); |
| try { |
| while (c.moveToNext()) { |
| insertPhoto(c, insert, photoIdUpdate); |
| } |
| } finally { |
| c.close(); |
| insert.close(); |
| photoIdUpdate.close(); |
| } |
| } |
| |
| private void insertPhoto(Cursor c, SQLiteStatement insert, SQLiteStatement photoIdUpdate) { |
| if (c.isNull(PhotosQuery.DATA)) { |
| return; |
| } |
| |
| long personId = c.getLong(PhotosQuery.PERSON); |
| |
| insert.bindLong(PhotoInsert.RAW_CONTACT_ID, personId); |
| insert.bindLong(PhotoInsert.MIMETYPE_ID, mPhotoMimetypeId); |
| insert.bindBlob(PhotoInsert.PHOTO, c.getBlob(PhotosQuery.DATA)); |
| |
| String account = c.getString(PhotosQuery._SYNC_ACCOUNT); |
| if (!TextUtils.isEmpty(account)) { |
| bindString(insert, PhotoInsert.SYNC1, c.getString(PhotosQuery._SYNC_ID)); |
| } else { |
| insert.bindNull(PhotoInsert.SYNC1); |
| } |
| |
| long rowId = insert(insert); |
| photoIdUpdate.bindLong(PhotoIdUpdate.PHOTO_ID, rowId); |
| photoIdUpdate.bindLong(PhotoIdUpdate.CONTACT_ID, personId); |
| photoIdUpdate.execute(); |
| } |
| |
| private interface GroupMembershipQuery { |
| String TABLE = "groupmembership"; |
| |
| String[] COLUMNS = { |
| "person", "group_id", "group_sync_account", "group_sync_id" |
| }; |
| |
| static int PERSON_ID = 0; |
| static int GROUP_ID = 1; |
| static int GROUP_SYNC_ACCOUNT = 2; |
| static int GROUP_SYNC_ID = 3; |
| } |
| |
| private interface GroupMembershipInsert { |
| String INSERT_SQL = "INSERT INTO " + Tables.DATA + "(" + |
| Data.RAW_CONTACT_ID + "," + |
| DataColumns.MIMETYPE_ID + "," + |
| GroupMembership.GROUP_ROW_ID + |
| ") VALUES (?,?,?)"; |
| |
| int RAW_CONTACT_ID = 1; |
| int MIMETYPE_ID = 2; |
| int GROUP_ROW_ID = 3; |
| } |
| |
| private void importGroupMemberships() { |
| SQLiteStatement insert = mTargetDb.compileStatement(GroupMembershipInsert.INSERT_SQL); |
| Cursor c = mSourceDb.query(GroupMembershipQuery.TABLE, GroupMembershipQuery.COLUMNS, null, |
| null, null, null, null); |
| try { |
| while (c.moveToNext()) { |
| insertGroupMembership(c, insert); |
| } |
| } finally { |
| c.close(); |
| insert.close(); |
| } |
| } |
| |
| private void insertGroupMembership(Cursor c, SQLiteStatement insert) { |
| long personId = c.getLong(GroupMembershipQuery.PERSON_ID); |
| |
| long groupId = 0; |
| if (c.isNull(GroupMembershipQuery.GROUP_ID)) { |
| String account = c.getString(GroupMembershipQuery.GROUP_SYNC_ACCOUNT); |
| if (!TextUtils.isEmpty(account)) { |
| String syncId = c.getString(GroupMembershipQuery.GROUP_SYNC_ID); |
| |
| Cursor cursor = mTargetDb.query(Tables.GROUPS, |
| new String[]{Groups._ID}, Groups.SOURCE_ID + "=?", new String[]{syncId}, |
| null, null, null); |
| try { |
| if (cursor.moveToFirst()) { |
| groupId = cursor.getLong(0); |
| } |
| } finally { |
| cursor.close(); |
| } |
| |
| if (groupId == 0) { |
| ContentValues values = new ContentValues(); |
| values.put(Groups.ACCOUNT_NAME, account); |
| values.put(Groups.ACCOUNT_TYPE, DEFAULT_ACCOUNT_TYPE); |
| values.put(Groups.GROUP_VISIBLE, true); |
| values.put(Groups.SOURCE_ID, syncId); |
| groupId = mTargetDb.insert(Tables.GROUPS, null, values); |
| } |
| } |
| } else { |
| groupId = c.getLong(GroupMembershipQuery.GROUP_ID); |
| } |
| |
| insert.bindLong(GroupMembershipInsert.RAW_CONTACT_ID, personId); |
| insert.bindLong(GroupMembershipInsert.MIMETYPE_ID, mGroupMembershipMimetypeId); |
| insert.bindLong(GroupMembershipInsert.GROUP_ROW_ID, groupId); |
| insert(insert); |
| } |
| |
| private interface CallsQuery { |
| String TABLE = "calls"; |
| |
| String[] COLUMNS = { |
| "_id", "number", "date", "duration", "type", "new", "name", "numbertype", |
| "numberlabel" |
| }; |
| |
| static int ID = 0; |
| static int NUMBER = 1; |
| static int DATE = 2; |
| static int DURATION = 3; |
| static int TYPE = 4; |
| static int NEW = 5; |
| static int NAME = 6; |
| static int NUMBER_TYPE = 7; |
| static int NUMBER_LABEL = 8; |
| } |
| |
| private void importCalls() { |
| Cursor c = mSourceDb.query(CallsQuery.TABLE, CallsQuery.COLUMNS, null, null, |
| null, null, null); |
| try { |
| while (c.moveToNext()) { |
| insertCall(c); |
| } |
| } finally { |
| c.close(); |
| } |
| } |
| |
| private void insertCall(Cursor c) { |
| |
| // Cannot use batch operations here, because call log is serviced by a separate provider |
| mValues.clear(); |
| mValues.put(Calls._ID, c.getLong(CallsQuery.ID)); |
| mValues.put(Calls.NUMBER, c.getString(CallsQuery.NUMBER)); |
| mValues.put(Calls.DATE, c.getLong(CallsQuery.DATE)); |
| mValues.put(Calls.DURATION, c.getLong(CallsQuery.DURATION)); |
| mValues.put(Calls.NEW, c.getLong(CallsQuery.NEW)); |
| mValues.put(Calls.TYPE, c.getLong(CallsQuery.TYPE)); |
| mValues.put(Calls.CACHED_NAME, c.getString(CallsQuery.NAME)); |
| mValues.put(Calls.CACHED_NUMBER_LABEL, c.getString(CallsQuery.NUMBER_LABEL)); |
| mValues.put(Calls.CACHED_NUMBER_TYPE, c.getString(CallsQuery.NUMBER_TYPE)); |
| |
| // TODO: confirm that we can use the CallLogProvider at this point, that it is guaranteed |
| // to have been registered. |
| mResolver.insert(Calls.CONTENT_URI, mValues); |
| } |
| |
| private void updateDisplayNamesAndLookupKeys() { |
| // Compute display names, sort keys, lookup key, etc. for all Raw Cont |
| Cursor cursor = mResolver.query(RawContacts.CONTENT_URI, |
| new String[] { RawContacts._ID }, null, null, null); |
| try { |
| while (cursor.moveToNext()) { |
| long rawContactId = cursor.getLong(0); |
| mContactsProvider.updateRawContactDisplayName(mTargetDb, rawContactId); |
| mContactsProvider.updateLookupKeyForRawContact(mTargetDb, rawContactId); |
| } |
| } finally { |
| cursor.close(); |
| } |
| } |
| |
| private interface DeletedPeopleQuery { |
| String TABLE = "_deleted_people"; |
| |
| String[] COLUMNS = { |
| "_sync_id", "_sync_account" |
| }; |
| |
| static int _SYNC_ID = 0; |
| static int _SYNC_ACCOUNT = 1; |
| } |
| |
| private interface DeletedRawContactInsert { |
| String INSERT_SQL = "INSERT INTO " + Tables.RAW_CONTACTS + "(" + |
| RawContacts.ACCOUNT_NAME + "," + |
| RawContacts.ACCOUNT_TYPE + "," + |
| RawContacts.SOURCE_ID + "," + |
| RawContacts.DELETED + "," + |
| RawContacts.AGGREGATION_MODE + |
| ") VALUES (?,?,?,?,?)"; |
| |
| |
| int ACCOUNT_NAME = 1; |
| int ACCOUNT_TYPE = 2; |
| int SOURCE_ID = 3; |
| int DELETED = 4; |
| int AGGREGATION_MODE = 5; |
| } |
| |
| private void importDeletedPeople() { |
| SQLiteStatement insert = mTargetDb.compileStatement(DeletedRawContactInsert.INSERT_SQL); |
| Cursor c = mSourceDb.query(DeletedPeopleQuery.TABLE, DeletedPeopleQuery.COLUMNS, null, null, |
| null, null, null); |
| try { |
| while (c.moveToNext()) { |
| insertDeletedPerson(c, insert); |
| } |
| } finally { |
| c.close(); |
| insert.close(); |
| } |
| } |
| |
| private void insertDeletedPerson(Cursor c, SQLiteStatement insert) { |
| String account = c.getString(DeletedPeopleQuery._SYNC_ACCOUNT); |
| if (account == null) { |
| return; |
| } |
| |
| insert.bindString(DeletedRawContactInsert.ACCOUNT_NAME, account); |
| insert.bindString(DeletedRawContactInsert.ACCOUNT_TYPE, DEFAULT_ACCOUNT_TYPE); |
| bindString(insert, DeletedRawContactInsert.SOURCE_ID, |
| c.getString(DeletedPeopleQuery._SYNC_ID)); |
| insert.bindLong(DeletedRawContactInsert.DELETED, 1); |
| insert.bindLong(DeletedRawContactInsert.AGGREGATION_MODE, |
| RawContacts.AGGREGATION_MODE_DISABLED); |
| insert(insert); |
| } |
| |
| private void bindString(SQLiteStatement insert, int index, String string) { |
| if (string == null) { |
| insert.bindNull(index); |
| } else { |
| insert.bindString(index, string); |
| } |
| } |
| |
| private long insert(SQLiteStatement insertStatement) { |
| long rowId = insertStatement.executeInsert(); |
| if (rowId == 0) { |
| throw new RuntimeException("Insert failed"); |
| } |
| |
| mBatchCounter++; |
| if (mBatchCounter >= INSERT_BATCH_SIZE) { |
| mTargetDb.setTransactionSuccessful(); |
| mTargetDb.endTransaction(); |
| mTargetDb.beginTransaction(); |
| mBatchCounter = 0; |
| } |
| return rowId; |
| } |
| } |