ContactsProviderpublic class ContactsProvider extends android.content.AbstractSyncableContentProvider
Fields Summary |
---|
private static final String | STREQUENT_ORDER_BY | private static final String | STREQUENT_LIMIT | private static final String | PEOPLE_PHONES_JOIN | private static final String | PEOPLE_PHONES_PHOTOS_JOIN | private static final String | GTALK_PROTOCOL_STRING | private static final String[] | ID_TYPE_PROJECTION | private static final String[] | sIsPrimaryProjectionWithoutKind | private static final String[] | sIsPrimaryProjectionWithKind | private static final String | WHERE_ID | private static final String | sGroupsJoinString | private static final String | PREFS_NAME_OWNER | private static final String | PREF_OWNER_ID | private final android.content.ContentValues | mValuesthis is suitable for use by insert/update/delete/query and may be passed
as a method call parameter. Only insert/update/delete/query should call .clear() on it | private final android.content.ContentValues | mValuesLocalthis is suitable for local use in methods and should never be passed as a parameter to
other methods (other than the DB layer) | private String[] | mAccounts | private final Object | mAccountsLock | private DatabaseUtils.InsertHelper | mDeletedPeopleInserter | private DatabaseUtils.InsertHelper | mPeopleInserter | private int | mIndexPeopleSyncId | private int | mIndexPeopleSyncTime | private int | mIndexPeopleSyncVersion | private int | mIndexPeopleSyncDirty | private int | mIndexPeopleSyncAccount | private int | mIndexPeopleName | private int | mIndexPeoplePhoneticName | private int | mIndexPeopleNotes | private DatabaseUtils.InsertHelper | mGroupsInserter | private DatabaseUtils.InsertHelper | mPhotosInserter | private int | mIndexPhotosPersonId | private int | mIndexPhotosSyncId | private int | mIndexPhotosSyncTime | private int | mIndexPhotosSyncVersion | private int | mIndexPhotosSyncDirty | private int | mIndexPhotosSyncAccount | private int | mIndexPhotosExistsOnServer | private int | mIndexPhotosSyncError | private DatabaseUtils.InsertHelper | mContactMethodsInserter | private int | mIndexContactMethodsPersonId | private int | mIndexContactMethodsLabel | private int | mIndexContactMethodsKind | private int | mIndexContactMethodsType | private int | mIndexContactMethodsData | private int | mIndexContactMethodsAuxData | private int | mIndexContactMethodsIsPrimary | private DatabaseUtils.InsertHelper | mOrganizationsInserter | private int | mIndexOrganizationsPersonId | private int | mIndexOrganizationsLabel | private int | mIndexOrganizationsType | private int | mIndexOrganizationsCompany | private int | mIndexOrganizationsTitle | private int | mIndexOrganizationsIsPrimary | private DatabaseUtils.InsertHelper | mExtensionsInserter | private int | mIndexExtensionsPersonId | private int | mIndexExtensionsName | private int | mIndexExtensionsValue | private DatabaseUtils.InsertHelper | mGroupMembershipInserter | private int | mIndexGroupMembershipPersonId | private int | mIndexGroupMembershipGroupSyncAccount | private int | mIndexGroupMembershipGroupSyncId | private DatabaseUtils.InsertHelper | mCallsInserter | private DatabaseUtils.InsertHelper | mPhonesInserter | private int | mIndexPhonesPersonId | private int | mIndexPhonesLabel | private int | mIndexPhonesType | private int | mIndexPhonesNumber | private int | mIndexPhonesNumberKey | private int | mIndexPhonesIsPrimary | protected static String | sPeopleTable | protected static android.net.Uri | sPeopleRawURL | protected static String | sDeletedPeopleTable | protected static android.net.Uri | sDeletedPeopleURL | protected static String | sGroupsTable | protected static String | sSettingsTable | protected static android.net.Uri | sGroupsURL | protected static String | sDeletedGroupsTable | protected static android.net.Uri | sDeletedGroupsURL | protected static String | sPhonesTable | protected static String | sOrganizationsTable | protected static String | sContactMethodsTable | protected static String | sGroupmembershipTable | protected static String | sPhotosTable | protected static android.net.Uri | sPhotosURL | protected static String | sExtensionsTable | protected static String | sCallsTable | private static final String | TAG | static final String | DATABASE_NAME | static final int | DATABASE_VERSION | protected static final String | CONTACTS_AUTHORITY | protected static final String | CALL_LOG_AUTHORITY | private static final int | PEOPLE_BASE | private static final int | PEOPLE | private static final int | PEOPLE_FILTER | private static final int | PEOPLE_ID | private static final int | PEOPLE_PHONES | private static final int | PEOPLE_PHONES_ID | private static final int | PEOPLE_CONTACTMETHODS | private static final int | PEOPLE_CONTACTMETHODS_ID | private static final int | PEOPLE_RAW | private static final int | PEOPLE_WITH_PHONES_FILTER | private static final int | PEOPLE_STREQUENT | private static final int | PEOPLE_STREQUENT_FILTER | private static final int | PEOPLE_ORGANIZATIONS | private static final int | PEOPLE_ORGANIZATIONS_ID | private static final int | PEOPLE_GROUPMEMBERSHIP | private static final int | PEOPLE_GROUPMEMBERSHIP_ID | private static final int | PEOPLE_PHOTO | private static final int | PEOPLE_EXTENSIONS | private static final int | PEOPLE_EXTENSIONS_ID | private static final int | PEOPLE_CONTACTMETHODS_WITH_PRESENCE | private static final int | PEOPLE_OWNER | private static final int | PEOPLE_UPDATE_CONTACT_TIME | private static final int | PEOPLE_PHONES_WITH_PRESENCE | private static final int | PEOPLE_WITH_EMAIL_OR_IM_FILTER | private static final int | DELETED_BASE | private static final int | DELETED_PEOPLE | private static final int | DELETED_GROUPS | private static final int | PHONES_BASE | private static final int | PHONES | private static final int | PHONES_ID | private static final int | PHONES_FILTER | private static final int | PHONES_FILTER_NAME | private static final int | PHONES_MOBILE_FILTER_NAME | private static final int | PHONES_WITH_PRESENCE | private static final int | CONTACTMETHODS_BASE | private static final int | CONTACTMETHODS | private static final int | CONTACTMETHODS_ID | private static final int | CONTACTMETHODS_EMAIL | private static final int | CONTACTMETHODS_EMAIL_FILTER | private static final int | CONTACTMETHODS_WITH_PRESENCE | private static final int | CALLS_BASE | private static final int | CALLS | private static final int | CALLS_ID | private static final int | CALLS_FILTER | private static final int | PRESENCE_BASE | private static final int | PRESENCE | private static final int | PRESENCE_ID | private static final int | ORGANIZATIONS_BASE | private static final int | ORGANIZATIONS | private static final int | ORGANIZATIONS_ID | private static final int | VOICE_DIALER_TIMESTAMP | private static final int | SEARCH_SUGGESTIONS | private static final int | GROUPS_BASE | private static final int | GROUPS | private static final int | GROUPS_ID | private static final int | GROUP_NAME_MEMBERS | private static final int | GROUP_NAME_MEMBERS_FILTER | private static final int | GROUP_SYSTEM_ID_MEMBERS | private static final int | GROUP_SYSTEM_ID_MEMBERS_FILTER | private static final int | GROUPMEMBERSHIP_BASE | private static final int | GROUPMEMBERSHIP | private static final int | GROUPMEMBERSHIP_ID | private static final int | GROUPMEMBERSHIP_RAW | private static final int | PHOTOS_BASE | private static final int | PHOTOS | private static final int | PHOTOS_ID | private static final int | EXTENSIONS_BASE | private static final int | EXTENSIONS | private static final int | EXTENSIONS_ID | private static final int | SETTINGS | private static final int | LIVE_FOLDERS_BASE | private static final int | LIVE_FOLDERS_PEOPLE | private static final int | LIVE_FOLDERS_PEOPLE_GROUP_NAME | private static final int | LIVE_FOLDERS_PEOPLE_WITH_PHONES | private static final int | LIVE_FOLDERS_PEOPLE_FAVORITES | private static final android.content.UriMatcher | sURIMatcher | private static final HashMap | sGroupsProjectionMap | private static final HashMap | sPeopleProjectionMap | private static final HashMap | sPeopleWithPhotoProjectionMap | private static final HashMap | sPeopleWithEmailOrImProjectionMap | private static final HashMap | sStrequentStarredProjectionMapUsed to force items to the top of a times_contacted list | private static final HashMap | sCallsProjectionMap | private static final HashMap | sPhonesProjectionMap | private static final HashMap | sPhonesWithPresenceProjectionMap | private static final HashMap | sContactMethodsProjectionMap | private static final HashMap | sContactMethodsWithPresenceProjectionMap | private static final HashMap | sPresenceProjectionMap | private static final HashMap | sEmailSearchProjectionMap | private static final HashMap | sOrganizationsProjectionMap | private static final HashMap | sSearchSuggestionsProjectionMap | private static final HashMap | sGroupMembershipProjectionMap | private static final HashMap | sPhotosProjectionMap | private static final HashMap | sExtensionsProjectionMap | private static final HashMap | sLiveFoldersProjectionMap | private static final String | sPhonesKeyOrderBy | private static final String | sContactMethodsKeyOrderBy | private static final String | sOrganizationsKeyOrderBy | private static final String | sGroupmembershipKeyOrderBy | private static final String | DISPLAY_NAME_SQL | private static final String | PHONETICALLY_SORTABLE_STRING_SQL | private static final String[] | sPhonesKeyColumns | private static final String[] | sContactMethodsKeyColumns | private static final String[] | sOrganizationsKeyColumns | private static final String[] | sGroupmembershipKeyColumns | private static final String[] | sExtensionsKeyColumns |
Constructors Summary |
---|
public ContactsProvider()
super(DATABASE_NAME, DATABASE_VERSION, Contacts.CONTENT_URI);
|
Methods Summary |
---|
private static java.lang.String | addIdToWhereClause(java.lang.String id, java.lang.String where)
if (id != null) {
StringBuilder whereSb = new StringBuilder("_id=");
whereSb.append(id);
if (!TextUtils.isEmpty(where)) {
whereSb.append(" AND (");
whereSb.append(where);
whereSb.append(')");
}
return whereSb.toString();
} else {
return where;
}
| private java.lang.String[] | appendSelectionArg(java.lang.String[] selectionArgs, java.lang.String newArg)Append a string to a selection args array
if (selectionArgs == null || selectionArgs.length == 0) {
return new String[] { newArg };
} else {
int length = selectionArgs.length;
String[] newArgs = new String[length + 1];
System.arraycopy(selectionArgs, 0, newArgs, 0, length);
newArgs[length] = newArg;
return newArgs;
}
| protected void | bootstrapDatabase(android.database.sqlite.SQLiteDatabase db)
super.bootstrapDatabase(db);
db.execSQL("CREATE TABLE people (" +
People._ID + " INTEGER PRIMARY KEY AUTOINCREMENT," +
People._SYNC_ACCOUNT + " TEXT," + // From the sync source
People._SYNC_ID + " TEXT," + // From the sync source
People._SYNC_TIME + " TEXT," + // From the sync source
People._SYNC_VERSION + " TEXT," + // From the sync source
People._SYNC_LOCAL_ID + " INTEGER," + // Used while syncing, not persistent
People._SYNC_DIRTY + " INTEGER NOT NULL DEFAULT 0," +
// if syncable, non-zero if the record
// has local, unsynced, changes
People._SYNC_MARK + " INTEGER," + // Used to filter out new rows
People.NAME + " TEXT COLLATE LOCALIZED," +
People.NOTES + " TEXT COLLATE LOCALIZED," +
People.TIMES_CONTACTED + " INTEGER NOT NULL DEFAULT 0," +
People.LAST_TIME_CONTACTED + " INTEGER," +
People.STARRED + " INTEGER NOT NULL DEFAULT 0," +
People.PRIMARY_PHONE_ID + " INTEGER REFERENCES phones(_id)," +
People.PRIMARY_ORGANIZATION_ID + " INTEGER REFERENCES organizations(_id)," +
People.PRIMARY_EMAIL_ID + " INTEGER REFERENCES contact_methods(_id)," +
People.PHOTO_VERSION + " TEXT," +
People.CUSTOM_RINGTONE + " TEXT," +
People.SEND_TO_VOICEMAIL + " INTEGER," +
People.PHONETIC_NAME + " TEXT COLLATE LOCALIZED" +
");");
db.execSQL("CREATE INDEX peopleNameIndex ON people (" + People.NAME + ");");
db.execSQL("CREATE INDEX peopleSyncDirtyIndex ON people (" + People._SYNC_DIRTY + ");");
db.execSQL("CREATE INDEX peopleSyncIdIndex ON people (" + People._SYNC_ID + ");");
db.execSQL("CREATE TRIGGER people_timesContacted UPDATE OF last_time_contacted ON people " +
"BEGIN " +
"UPDATE people SET "
+ People.TIMES_CONTACTED + " = (new." + People.TIMES_CONTACTED + " + 1)"
+ " WHERE _id = new._id;" +
"END");
// table of all the groups that exist for an account
db.execSQL("CREATE TABLE groups (" +
Groups._ID + " INTEGER PRIMARY KEY AUTOINCREMENT," +
Groups._SYNC_ACCOUNT + " TEXT," + // From the sync source
Groups._SYNC_ID + " TEXT," + // From the sync source
Groups._SYNC_TIME + " TEXT," + // From the sync source
Groups._SYNC_VERSION + " TEXT," + // From the sync source
Groups._SYNC_LOCAL_ID + " INTEGER," + // Used while syncing, not persistent
Groups._SYNC_DIRTY + " INTEGER NOT NULL DEFAULT 0," +
// if syncable, non-zero if the record
// has local, unsynced, changes
Groups._SYNC_MARK + " INTEGER," + // Used to filter out new rows
Groups.NAME + " TEXT NOT NULL," +
Groups.NOTES + " TEXT," +
Groups.SHOULD_SYNC + " INTEGER NOT NULL DEFAULT 0," +
Groups.SYSTEM_ID + " TEXT," +
"UNIQUE(" +
Groups.NAME + "," + Groups.SYSTEM_ID + "," + Groups._SYNC_ACCOUNT + ")" +
");");
db.execSQL("CREATE INDEX groupsSyncDirtyIndex ON groups (" + Groups._SYNC_DIRTY + ");");
if (!isTemporary()) {
// Add the system groups, since we always need them.
db.execSQL("INSERT INTO groups (" + Groups.NAME + ", " + Groups.SYSTEM_ID + ") VALUES "
+ "('" + Groups.GROUP_MY_CONTACTS + "', '" + Groups.GROUP_MY_CONTACTS + "')");
}
db.execSQL("CREATE TABLE peopleLookup (" +
"token TEXT," +
"source INTEGER REFERENCES people(_id)" +
");");
db.execSQL("CREATE INDEX peopleLookupIndex ON peopleLookup (" +
"token," +
"source" +
");");
db.execSQL("CREATE TABLE photos ("
+ Photos._ID + " INTEGER PRIMARY KEY AUTOINCREMENT,"
+ Photos.EXISTS_ON_SERVER + " INTEGER NOT NULL DEFAULT 0,"
+ Photos.PERSON_ID + " INTEGER REFERENCES people(_id), "
+ Photos.LOCAL_VERSION + " TEXT,"
+ Photos.DATA + " BLOB,"
+ Photos.SYNC_ERROR + " TEXT,"
+ Photos._SYNC_ACCOUNT + " TEXT,"
+ Photos._SYNC_ID + " TEXT,"
+ Photos._SYNC_TIME + " TEXT,"
+ Photos._SYNC_VERSION + " TEXT,"
+ Photos._SYNC_LOCAL_ID + " INTEGER,"
+ Photos._SYNC_DIRTY + " INTEGER NOT NULL DEFAULT 0,"
+ Photos._SYNC_MARK + " INTEGER,"
+ "UNIQUE(" + Photos.PERSON_ID + ") "
+ ")");
db.execSQL("CREATE INDEX photosSyncDirtyIndex ON photos (" + Photos._SYNC_DIRTY + ");");
db.execSQL("CREATE INDEX photoPersonIndex ON photos (person);");
// Delete the photo row when the people row is deleted
db.execSQL(""
+ " CREATE TRIGGER peopleDeleteAndPhotos DELETE ON people "
+ " BEGIN"
+ " DELETE FROM photos WHERE person=OLD._id;"
+ " END");
db.execSQL("CREATE TABLE _deleted_people (" +
"_sync_version TEXT," + // From the sync source
"_sync_id TEXT," +
(isTemporary() ? "_sync_local_id INTEGER," : "") + // Used while syncing,
"_sync_account TEXT," +
"_sync_mark INTEGER)"); // Used to filter out new rows
db.execSQL("CREATE TABLE _deleted_groups (" +
"_sync_version TEXT," + // From the sync source
"_sync_id TEXT," +
(isTemporary() ? "_sync_local_id INTEGER," : "") + // Used while syncing,
"_sync_account TEXT," +
"_sync_mark INTEGER)"); // Used to filter out new rows
db.execSQL("CREATE TABLE phones (" +
"_id INTEGER PRIMARY KEY AUTOINCREMENT," +
"person INTEGER REFERENCES people(_id)," +
"type INTEGER NOT NULL," + // kind specific (home, work, etc)
"number TEXT," +
"number_key TEXT," +
"label TEXT," +
"isprimary INTEGER NOT NULL DEFAULT 0" +
");");
db.execSQL("CREATE INDEX phonesIndex1 ON phones (person);");
db.execSQL("CREATE INDEX phonesIndex2 ON phones (number_key);");
db.execSQL("CREATE TABLE contact_methods (" +
"_id INTEGER PRIMARY KEY AUTOINCREMENT," +
"person INTEGER REFERENCES people(_id)," +
"kind INTEGER NOT NULL," + // the kind of contact method
"data TEXT," +
"aux_data TEXT," +
"type INTEGER NOT NULL," + // kind specific (home, work, etc)
"label TEXT," +
"isprimary INTEGER NOT NULL DEFAULT 0" +
");");
db.execSQL("CREATE INDEX contactMethodsPeopleIndex "
+ "ON contact_methods (person);");
// The table for recent calls is here so we can do table joins
// on people, phones, and calls all in one place.
db.execSQL("CREATE TABLE calls (" +
"_id INTEGER PRIMARY KEY AUTOINCREMENT," +
"number TEXT," +
"date INTEGER," +
"duration INTEGER," +
"type INTEGER," +
"new INTEGER," +
"name TEXT," +
"numbertype INTEGER," +
"numberlabel TEXT" +
");");
// Various settings for the contacts sync adapter. The _sync_account column may
// be null, but it must not be the empty string.
db.execSQL("CREATE TABLE settings (" +
"_id INTEGER PRIMARY KEY," +
"_sync_account TEXT," +
"key STRING NOT NULL," +
"value STRING " +
");");
// The table for the organizations of a person.
db.execSQL("CREATE TABLE organizations (" +
"_id INTEGER PRIMARY KEY AUTOINCREMENT," +
"company TEXT," +
"title TEXT," +
"isprimary INTEGER NOT NULL DEFAULT 0," +
"type INTEGER NOT NULL," + // kind specific (home, work, etc)
"label TEXT," +
"person INTEGER REFERENCES people(_id)" +
");");
db.execSQL("CREATE INDEX organizationsIndex1 ON organizations (person);");
// The table for the extensions of a person.
db.execSQL("CREATE TABLE extensions (" +
"_id INTEGER PRIMARY KEY AUTOINCREMENT," +
"name TEXT NOT NULL," +
"value TEXT NOT NULL," +
"person INTEGER REFERENCES people(_id)," +
"UNIQUE(person, name)" +
");");
db.execSQL("CREATE INDEX extensionsIndex1 ON extensions (person, name);");
// The table for the groups of a person.
db.execSQL("CREATE TABLE groupmembership (" +
"_id INTEGER PRIMARY KEY," +
"person INTEGER REFERENCES people(_id)," +
"group_id INTEGER REFERENCES groups(_id)," +
"group_sync_account STRING," +
"group_sync_id STRING" +
");");
db.execSQL("CREATE INDEX groupmembershipIndex1 ON groupmembership (person, group_id);");
db.execSQL("CREATE INDEX groupmembershipIndex2 ON groupmembership (group_id, person);");
db.execSQL("CREATE INDEX groupmembershipIndex3 ON groupmembership "
+ "(group_sync_account, group_sync_id);");
// Trigger to completely remove a contacts data when they're deleted
db.execSQL("CREATE TRIGGER contact_cleanup DELETE ON people " +
"BEGIN " +
"DELETE FROM peopleLookup WHERE source = old._id;" +
"DELETE FROM phones WHERE person = old._id;" +
"DELETE FROM contact_methods WHERE person = old._id;" +
"DELETE FROM organizations WHERE person = old._id;" +
"DELETE FROM groupmembership WHERE person = old._id;" +
"DELETE FROM extensions WHERE person = old._id;" +
"END");
// Trigger to disassociate the groupmembership from the groups when an
// groups entry is deleted
db.execSQL("CREATE TRIGGER groups_cleanup DELETE ON groups " +
"BEGIN " +
"UPDATE groupmembership SET group_id = null WHERE group_id = old._id;" +
"END");
// Trigger to move an account_people row to _deleted_account_people when it is deleted
db.execSQL("CREATE TRIGGER groups_to_deleted DELETE ON groups " +
"WHEN old._sync_id is not null " +
"BEGIN " +
"INSERT INTO _deleted_groups " +
"(_sync_id, _sync_account, _sync_version) " +
"VALUES (old._sync_id, old._sync_account, " +
"old._sync_version);" +
"END");
// Triggers to keep the peopleLookup table up to date
db.execSQL("CREATE TRIGGER peopleLookup_update UPDATE OF name ON people " +
"BEGIN " +
"DELETE FROM peopleLookup WHERE source = new._id;" +
"SELECT _TOKENIZE('peopleLookup', new._id, new.name, ' ');" +
"END");
db.execSQL("CREATE TRIGGER peopleLookup_insert AFTER INSERT ON people " +
"BEGIN " +
"SELECT _TOKENIZE('peopleLookup', new._id, new.name, ' ');" +
"END");
// Triggers to set the _sync_dirty flag when a phone is changed,
// inserted or deleted
db.execSQL("CREATE TRIGGER phones_update UPDATE ON phones " +
"BEGIN " +
"UPDATE people SET _sync_dirty=1 WHERE people._id=old.person;" +
"END");
db.execSQL("CREATE TRIGGER phones_insert INSERT ON phones " +
"BEGIN " +
"UPDATE people SET _sync_dirty=1 WHERE people._id=new.person;" +
"END");
db.execSQL("CREATE TRIGGER phones_delete DELETE ON phones " +
"BEGIN " +
"UPDATE people SET _sync_dirty=1 WHERE people._id=old.person;" +
"END");
// Triggers to set the _sync_dirty flag when a contact_method is
// changed, inserted or deleted
db.execSQL("CREATE TRIGGER contact_methods_update UPDATE ON contact_methods " +
"BEGIN " +
"UPDATE people SET _sync_dirty=1 WHERE people._id=old.person;" +
"END");
db.execSQL("CREATE TRIGGER contact_methods_insert INSERT ON contact_methods " +
"BEGIN " +
"UPDATE people SET _sync_dirty=1 WHERE people._id=new.person;" +
"END");
db.execSQL("CREATE TRIGGER contact_methods_delete DELETE ON contact_methods " +
"BEGIN " +
"UPDATE people SET _sync_dirty=1 WHERE people._id=old.person;" +
"END");
// Triggers for when an organization is changed, inserted or deleted
db.execSQL("CREATE TRIGGER organizations_update AFTER UPDATE ON organizations " +
"BEGIN " +
"UPDATE people SET _sync_dirty=1 WHERE people._id=old.person; " +
"END");
db.execSQL("CREATE TRIGGER organizations_insert INSERT ON organizations " +
"BEGIN " +
"UPDATE people SET _sync_dirty=1 WHERE people._id=new.person; " +
"END");
db.execSQL("CREATE TRIGGER organizations_delete DELETE ON organizations " +
"BEGIN " +
"UPDATE people SET _sync_dirty=1 WHERE people._id=old.person;" +
"END");
// Triggers for when an groupmembership is changed, inserted or deleted
db.execSQL("CREATE TRIGGER groupmembership_update AFTER UPDATE ON groupmembership " +
"BEGIN " +
"UPDATE people SET _sync_dirty=1 WHERE people._id=old.person; " +
"END");
db.execSQL("CREATE TRIGGER groupmembership_insert INSERT ON groupmembership " +
"BEGIN " +
"UPDATE people SET _sync_dirty=1 WHERE people._id=new.person; " +
"END");
db.execSQL("CREATE TRIGGER groupmembership_delete DELETE ON groupmembership " +
"BEGIN " +
"UPDATE people SET _sync_dirty=1 WHERE people._id=old.person;" +
"END");
// Triggers for when an extension is changed, inserted or deleted
db.execSQL("CREATE TRIGGER extensions_update AFTER UPDATE ON extensions " +
"BEGIN " +
"UPDATE people SET _sync_dirty=1 WHERE people._id=old.person; " +
"END");
db.execSQL("CREATE TRIGGER extensions_insert INSERT ON extensions " +
"BEGIN " +
"UPDATE people SET _sync_dirty=1 WHERE people._id=new.person; " +
"END");
db.execSQL("CREATE TRIGGER extensions_delete DELETE ON extensions " +
"BEGIN " +
"UPDATE people SET _sync_dirty=1 WHERE people._id=old.person;" +
"END");
createTypeLabelTrigger(db, sPhonesTable, "INSERT");
createTypeLabelTrigger(db, sPhonesTable, "UPDATE");
createTypeLabelTrigger(db, sOrganizationsTable, "INSERT");
createTypeLabelTrigger(db, sOrganizationsTable, "UPDATE");
createTypeLabelTrigger(db, sContactMethodsTable, "INSERT");
createTypeLabelTrigger(db, sContactMethodsTable, "UPDATE");
// Temporary table that holds a time stamp of the last time data the voice
// dialer is interested in has changed so the grammar won't need to be
// recompiled when unused data is changed.
db.execSQL("CREATE TABLE voice_dialer_timestamp (" +
"_id INTEGER PRIMARY KEY," +
"timestamp INTEGER" +
");");
db.execSQL("INSERT INTO voice_dialer_timestamp (_id, timestamp) VALUES " +
"(1, strftime('%s', 'now'));");
db.execSQL("CREATE TRIGGER timestamp_trigger1 AFTER UPDATE ON phones " +
"BEGIN " +
"UPDATE voice_dialer_timestamp SET timestamp=strftime('%s', 'now') "+
"WHERE _id=1;" +
"END");
db.execSQL("CREATE TRIGGER timestamp_trigger2 AFTER UPDATE OF name ON people " +
"BEGIN " +
"UPDATE voice_dialer_timestamp SET timestamp=strftime('%s', 'now') " +
"WHERE _id=1;" +
"END");
| private static java.lang.String | buildOrderBy(java.lang.String table, java.lang.String columns)
StringBuilder sb = null;
for (String column : columns) {
if (sb == null) {
sb = new StringBuilder();
} else {
sb.append(", ");
}
sb.append(table);
sb.append('.");
sb.append(column);
}
return (sb == null) ? "" : sb.toString();
| private java.lang.String | buildPeopleLookupWhereClause(java.lang.String filterParam)
StringBuilder filter = new StringBuilder(
"people._id IN (SELECT source FROM peopleLookup WHERE token GLOB ");
// NOTE: Query parameters won't work here since the SQL compiler
// needs to parse the actual string to know that it can use the
// index to do a prefix scan.
DatabaseUtils.appendEscapedSQLString(filter,
DatabaseUtils.getHexCollationKey(filterParam) + "*");
filter.append(')");
return filter.toString();
| public boolean | changeRequiresLocalSync(android.net.Uri uri)
final int match = sURIMatcher.match(uri);
switch (match) {
// Changes to these URIs cannot cause syncable data to be changed, so don't
// bother trying to sync them.
case CALLS:
case CALLS_FILTER:
case CALLS_ID:
case PRESENCE:
case PRESENCE_ID:
case PEOPLE_UPDATE_CONTACT_TIME:
return false;
default:
return true;
}
| private void | clearOtherIsPrimary(int kind, java.lang.Long personId, java.lang.Long itemId)Clears the isprimary flag for all rows other than the itemId.
final String table = kindToTable(kind);
if (personId == null) throw new IllegalArgumentException("personId must not be null");
StringBuilder sb = new StringBuilder();
sb.append("person=");
sb.append(personId);
if (itemId != null) {
sb.append(" and _id!=");
sb.append(itemId);
}
if (sContactMethodsTable.equals(table)) {
sb.append(" and ");
sb.append(ContactMethods.KIND);
sb.append("=");
sb.append(kind);
}
mValuesLocal.clear();
mValuesLocal.put("isprimary", 0);
getDatabase().update(table, mValuesLocal, sb.toString(), null);
| private void | createTypeLabelTrigger(android.database.sqlite.SQLiteDatabase db, java.lang.String table, java.lang.String operation)
final String name = table + "_" + operation + "_typeAndLabel";
db.execSQL("CREATE TRIGGER " + name + " AFTER " + operation + " ON " + table
+ " WHEN (NEW.type != 0 AND NEW.label IS NOT NULL) OR "
+ " (NEW.type = 0 AND NEW.label IS NULL)"
+ " BEGIN "
+ " SELECT RAISE (ABORT, 'exactly one of type or label must be set'); "
+ " END");
| private int | deleteFromGroupMembership(long rowId, java.lang.String where, java.lang.String[] whereArgs)
SQLiteQueryBuilder qb = new SQLiteQueryBuilder();
qb.setTables("groups, groupmembership");
qb.setProjectionMap(sGroupMembershipProjectionMap);
qb.appendWhere(sGroupsJoinString);
qb.appendWhere(" AND groupmembership._id=" + rowId);
Cursor cursor = qb.query(getDatabase(), null, where, whereArgs, null, null, null);
try {
final int indexPersonId = cursor.getColumnIndexOrThrow(GroupMembership.PERSON_ID);
final int indexName = cursor.getColumnIndexOrThrow(GroupMembership.NAME);
while (cursor.moveToNext()) {
if (Groups.GROUP_ANDROID_STARRED.equals(cursor.getString(indexName))) {
fixupPeopleStarred(cursor.getLong(indexPersonId), false);
}
}
} finally {
cursor.close();
}
return mDb.delete(sGroupmembershipTable,
addIdToWhereClause(String.valueOf(rowId), where),
whereArgs);
| private int | deleteFromGroups(java.lang.String where, java.lang.String[] whereArgs)
HashSet<String> modifiedAccounts = Sets.newHashSet();
Cursor cursor = getDatabase().query(sGroupsTable, null, where, whereArgs,
null, null, null);
try {
final int indexName = cursor.getColumnIndexOrThrow(Groups.NAME);
final int indexSyncAccount = cursor.getColumnIndexOrThrow(Groups._SYNC_ACCOUNT);
final int indexSyncId = cursor.getColumnIndexOrThrow(Groups._SYNC_ID);
final int indexId = cursor.getColumnIndexOrThrow(Groups._ID);
final int indexShouldSync = cursor.getColumnIndexOrThrow(Groups.SHOULD_SYNC);
while (cursor.moveToNext()) {
String oldName = cursor.getString(indexName);
String syncAccount = cursor.getString(indexSyncAccount);
String syncId = cursor.getString(indexSyncId);
boolean shouldSync = cursor.getLong(indexShouldSync) != 0;
long id = cursor.getLong(indexId);
fixupPeopleStarredOnGroupRename(oldName, null, id);
if (!TextUtils.isEmpty(syncAccount) && !TextUtils.isEmpty(syncId)) {
fixupPeopleStarredOnGroupRename(oldName, null, syncAccount, syncId);
}
if (!TextUtils.isEmpty(syncAccount) && shouldSync) {
modifiedAccounts.add(syncAccount);
}
}
} finally {
cursor.close();
}
int numRows = mDb.delete(sGroupsTable, where, whereArgs);
if (numRows > 0) {
if (!isTemporary()) {
final ContentResolver cr = getContext().getContentResolver();
for (String account : modifiedAccounts) {
onLocalChangesForAccount(cr, account, true);
}
}
}
return numRows;
| private int | deleteFromPeople(java.lang.String rowId, java.lang.String where, java.lang.String[] whereArgs)
final SQLiteDatabase db = getDatabase();
where = addIdToWhereClause(rowId, where);
Cursor cursor = db.query(sPeopleTable, null, where, whereArgs, null, null, null);
try {
final int idxSyncId = cursor.getColumnIndexOrThrow(People._SYNC_ID);
final int idxSyncAccount = cursor.getColumnIndexOrThrow(People._SYNC_ACCOUNT);
final int idxSyncVersion = cursor.getColumnIndexOrThrow(People._SYNC_VERSION);
final int dstIdxSyncId = mDeletedPeopleInserter.getColumnIndex(SyncConstValue._SYNC_ID);
final int dstIdxSyncAccount =
mDeletedPeopleInserter.getColumnIndex(SyncConstValue._SYNC_ACCOUNT);
final int dstIdxSyncVersion =
mDeletedPeopleInserter.getColumnIndex(SyncConstValue._SYNC_VERSION);
while (cursor.moveToNext()) {
final String syncId = cursor.getString(idxSyncId);
if (TextUtils.isEmpty(syncId)) continue;
// insert into deleted table
mDeletedPeopleInserter.prepareForInsert();
mDeletedPeopleInserter.bind(dstIdxSyncId, syncId);
mDeletedPeopleInserter.bind(dstIdxSyncAccount, cursor.getString(idxSyncAccount));
mDeletedPeopleInserter.bind(dstIdxSyncVersion, cursor.getString(idxSyncVersion));
mDeletedPeopleInserter.execute();
}
} finally {
cursor.close();
}
// perform the actual delete
return db.delete(sPeopleTable, where, whereArgs);
| public int | deleteInternal(android.net.Uri url, java.lang.String userWhere, java.lang.String[] whereArgs)
String tableToChange;
String changedItemId;
final int matchedUriId = sURIMatcher.match(url);
switch (matchedUriId) {
case GROUPMEMBERSHIP_ID:
return deleteFromGroupMembership(Long.parseLong(url.getPathSegments().get(1)),
userWhere, whereArgs);
case GROUPS:
return deleteFromGroups(userWhere, whereArgs);
case GROUPS_ID:
changedItemId = url.getPathSegments().get(1);
return deleteFromGroups(addIdToWhereClause(changedItemId, userWhere), whereArgs);
case EXTENSIONS:
tableToChange = sExtensionsTable;
changedItemId = null;
break;
case EXTENSIONS_ID:
tableToChange = sExtensionsTable;
changedItemId = url.getPathSegments().get(1);
break;
case PEOPLE_RAW:
case PEOPLE:
return deleteFromPeople(null, userWhere, whereArgs);
case PEOPLE_ID:
return deleteFromPeople(url.getPathSegments().get(1), userWhere, whereArgs);
case PEOPLE_PHONES_ID:
tableToChange = sPhonesTable;
changedItemId = url.getPathSegments().get(3);
break;
case PEOPLE_CONTACTMETHODS_ID:
tableToChange = sContactMethodsTable;
changedItemId = url.getPathSegments().get(3);
break;
case PHONES_ID:
tableToChange = sPhonesTable;
changedItemId = url.getPathSegments().get(1);
break;
case ORGANIZATIONS_ID:
tableToChange = sOrganizationsTable;
changedItemId = url.getPathSegments().get(1);
break;
case CONTACTMETHODS_ID:
tableToChange = sContactMethodsTable;
changedItemId = url.getPathSegments().get(1);
break;
case PRESENCE:
tableToChange = "presence";
changedItemId = null;
break;
case CALLS:
tableToChange = "calls";
changedItemId = null;
break;
default:
throw new UnsupportedOperationException("Cannot delete that URL: " + url);
}
String where = addIdToWhereClause(changedItemId, userWhere);
IsPrimaryInfo oldPrimaryInfo = null;
switch (matchedUriId) {
case PEOPLE_PHONES_ID:
case PHONES_ID:
case ORGANIZATIONS_ID:
oldPrimaryInfo = lookupIsPrimaryInfo(tableToChange,
sIsPrimaryProjectionWithoutKind, where, whereArgs);
break;
case PEOPLE_CONTACTMETHODS_ID:
case CONTACTMETHODS_ID:
oldPrimaryInfo = lookupIsPrimaryInfo(tableToChange,
sIsPrimaryProjectionWithKind, where, whereArgs);
break;
}
final SQLiteDatabase db = getDatabase();
int count = db.delete(tableToChange, where, whereArgs);
if (count > 0) {
if (oldPrimaryInfo != null && oldPrimaryInfo.isPrimary) {
fixupPrimaryAfterDelete(oldPrimaryInfo.kind,
oldPrimaryInfo.id, oldPrimaryInfo.person);
}
}
return count;
| protected void | dropTables(android.database.sqlite.SQLiteDatabase db)
db.execSQL("DROP TABLE IF EXISTS people");
db.execSQL("DROP TABLE IF EXISTS peopleLookup");
db.execSQL("DROP TABLE IF EXISTS _deleted_people");
db.execSQL("DROP TABLE IF EXISTS phones");
db.execSQL("DROP TABLE IF EXISTS contact_methods");
db.execSQL("DROP TABLE IF EXISTS calls");
db.execSQL("DROP TABLE IF EXISTS organizations");
db.execSQL("DROP TABLE IF EXISTS voice_dialer_timestamp");
db.execSQL("DROP TABLE IF EXISTS groups");
db.execSQL("DROP TABLE IF EXISTS _deleted_groups");
db.execSQL("DROP TABLE IF EXISTS groupmembership");
db.execSQL("DROP TABLE IF EXISTS photos");
db.execSQL("DROP TABLE IF EXISTS extensions");
db.execSQL("DROP TABLE IF EXISTS settings");
| private void | ensureSyncAccountIsSet(android.content.ContentValues values)
synchronized (mAccountsLock) {
String account = values.getAsString(SyncConstValue._SYNC_ACCOUNT);
if (account == null && mAccounts.length > 0) {
values.put(SyncConstValue._SYNC_ACCOUNT, mAccounts[0]);
}
}
| private java.lang.Long | findNewPrimary(int kind, java.lang.Long personId, java.lang.Long itemId)Determines which of the rows in table for the personId should be picked as the primary
row based on the rank of the row's type.
final String table = kindToTable(kind);
if (personId == null) throw new IllegalArgumentException("personId must not be null");
StringBuilder sb = new StringBuilder();
sb.append("person=");
sb.append(personId);
if (itemId != null) {
sb.append(" and _id!=");
sb.append(itemId);
}
if (sContactMethodsTable.equals(table)) {
sb.append(" and ");
sb.append(ContactMethods.KIND);
sb.append("=");
sb.append(kind);
}
Cursor cursor = getDatabase().query(table, ID_TYPE_PROJECTION, sb.toString(),
null, null, null, null);
try {
Long newPrimaryId = null;
int bestRank = -1;
while (cursor.moveToNext()) {
final int rank = getRankOfType(table, cursor.getInt(1));
if (bestRank == -1 || rank < bestRank) {
newPrimaryId = cursor.getLong(0);
bestRank = rank;
}
}
return newPrimaryId;
} finally {
cursor.close();
}
| private void | fixupGroupMembershipAfterPeopleUpdate(java.lang.String account, long personId, boolean makeStarred)
ContentValues starredGroupInfo = queryAndroidStarredGroupId(account);
if (makeStarred) {
if (starredGroupInfo == null) {
// we need to add the starred group
mValuesLocal.clear();
mValuesLocal.put(Groups.NAME, Groups.GROUP_ANDROID_STARRED);
mValuesLocal.put(Groups._SYNC_DIRTY, 1);
mValuesLocal.put(Groups._SYNC_ACCOUNT, account);
long groupId = mGroupsInserter.insert(mValuesLocal);
starredGroupInfo = new ContentValues();
starredGroupInfo.put(Groups._ID, groupId);
starredGroupInfo.put(Groups._SYNC_ACCOUNT, account);
// don't put the _SYNC_ID in here since we don't know it yet
}
final Long groupId = starredGroupInfo.getAsLong(Groups._ID);
final String syncId = starredGroupInfo.getAsString(Groups._SYNC_ID);
final String syncAccount = starredGroupInfo.getAsString(Groups._SYNC_ACCOUNT);
// check that either groupId is set or the syncId/Account is set
final boolean hasSyncId = !TextUtils.isEmpty(syncId);
final boolean hasGroupId = groupId != null;
if (!hasGroupId && !hasSyncId) {
throw new IllegalStateException("at least one of the groupId or "
+ "the syncId must be set, " + starredGroupInfo);
}
// now add this person to the group
mValuesLocal.clear();
mValuesLocal.put(GroupMembership.PERSON_ID, personId);
mValuesLocal.put(GroupMembership.GROUP_ID, groupId);
mValuesLocal.put(GroupMembership.GROUP_SYNC_ID, syncId);
mValuesLocal.put(GroupMembership.GROUP_SYNC_ACCOUNT, syncAccount);
mGroupMembershipInserter.insert(mValuesLocal);
} else {
if (starredGroupInfo != null) {
// delete the groupmembership rows for this person that match the starred group id
String syncAccount = starredGroupInfo.getAsString(Groups._SYNC_ACCOUNT);
String syncId = starredGroupInfo.getAsString(Groups._SYNC_ID);
if (!TextUtils.isEmpty(syncId)) {
mDb.delete(sGroupmembershipTable,
"person=? AND group_sync_id=? AND group_sync_account=?",
new String[]{String.valueOf(personId), syncId, syncAccount});
} else {
mDb.delete(sGroupmembershipTable, "person=? AND group_id=?",
new String[]{
Long.toString(personId),
Long.toString(starredGroupInfo.getAsLong(Groups._ID))});
}
}
}
| private int | fixupPeopleStarred(long personId, boolean inStarredGroup)
mValuesLocal.clear();
mValuesLocal.put(People.STARRED, inStarredGroup ? 1 : 0);
return getDatabase().update(sPeopleTable, mValuesLocal, WHERE_ID,
new String[]{String.valueOf(personId)});
| void | fixupPeopleStarredOnGroupRename(java.lang.String oldName, java.lang.String newName, java.lang.String where, java.lang.String[] whereArgs)
if (TextUtils.equals(oldName, newName)) return;
int starredValue;
if (Groups.GROUP_ANDROID_STARRED.equals(newName)) {
starredValue = 1;
} else if (Groups.GROUP_ANDROID_STARRED.equals(oldName)) {
starredValue = 0;
} else {
return;
}
getDatabase().execSQL("UPDATE people SET starred=" + starredValue + " WHERE _id in ("
+ "SELECT person "
+ "FROM groups, groupmembership "
+ "WHERE " + where + " AND " + sGroupsJoinString + ")",
whereArgs);
| void | fixupPeopleStarredOnGroupRename(java.lang.String oldName, java.lang.String newName, java.lang.String syncAccount, java.lang.String syncId)
fixupPeopleStarredOnGroupRename(oldName, newName, "_sync_account=? AND _sync_id=?",
new String[]{syncAccount, syncId});
| void | fixupPeopleStarredOnGroupRename(java.lang.String oldName, java.lang.String newName, long groupId)
fixupPeopleStarredOnGroupRename(oldName, newName, "group_id=?",
new String[]{String.valueOf(groupId)});
| private void | fixupPrimaryAfterDelete(int kind, java.lang.Long itemId, java.lang.Long personId)
final String table = kindToTable(kind);
// when you delete an item with isPrimary,
// select a new one as isPrimary and clear the primary if no more items
Long newPrimaryId = findNewPrimary(kind, personId, itemId);
// we found a new primary, set its isprimary flag
if (newPrimaryId != null) {
mValuesLocal.clear();
mValuesLocal.put("isprimary", 1);
if (getDatabase().update(table, mValuesLocal, "_id=" + newPrimaryId, null) != 1) {
throw new RuntimeException("error updating " + table + ", _id "
+ newPrimaryId + ", values " + mValuesLocal);
}
}
// if this kind's primary status should be reflected in the people row, update it
if (kind == Contacts.KIND_PHONE) {
updatePeoplePrimary(personId, People.PRIMARY_PHONE_ID, newPrimaryId);
} else if (kind == Contacts.KIND_EMAIL) {
updatePeoplePrimary(personId, People.PRIMARY_EMAIL_ID, newPrimaryId);
} else if (kind == Contacts.KIND_ORGANIZATION) {
updatePeoplePrimary(personId, People.PRIMARY_ORGANIZATION_ID, newPrimaryId);
}
| private void | fixupPrimaryAfterUpdate(int kind, java.lang.Long personId, java.lang.Long changedItemId, java.lang.Integer isPrimaryValue)
final String table = kindToTable(kind);
// - when you update isPrimary to true,
// make the changed item the primary, clear others
// - when you update isPrimary to false,
// select a new one as isPrimary, clear the primary if no more phones
if (isPrimaryValue != null) {
if (personId == null) {
personId = lookupPerson(table, changedItemId);
}
boolean isPrimary = isPrimaryValue != 0;
Long newPrimary = changedItemId;
if (!isPrimary) {
newPrimary = findNewPrimary(kind, personId, changedItemId);
}
clearOtherIsPrimary(kind, personId, changedItemId);
if (kind == Contacts.KIND_PHONE) {
updatePeoplePrimary(personId, People.PRIMARY_PHONE_ID, newPrimary);
} else if (kind == Contacts.KIND_EMAIL) {
updatePeoplePrimary(personId, People.PRIMARY_EMAIL_ID, newPrimary);
} else if (kind == Contacts.KIND_ORGANIZATION) {
updatePeoplePrimary(personId, People.PRIMARY_ORGANIZATION_ID, newPrimary);
}
}
| private java.lang.String | getContactMethodType(android.net.Uri url)
String mime = null;
Cursor c = query(url, new String[] {ContactMethods.KIND}, null, null, null);
if (c != null) {
try {
if (c.moveToFirst()) {
int kind = c.getInt(0);
switch (kind) {
case Contacts.KIND_EMAIL:
mime = "vnd.android.cursor.item/email";
break;
case Contacts.KIND_IM:
mime = "vnd.android.cursor.item/jabber-im";
break;
case Contacts.KIND_POSTAL:
mime = "vnd.android.cursor.item/postal-address";
break;
}
}
} finally {
c.close();
}
}
return mime;
| protected java.lang.Iterable | getMergers()
ArrayList<AbstractTableMerger> list = new ArrayList<AbstractTableMerger> ();
list.add(new PersonMerger());
list.add(new GroupMerger());
list.add(new PhotoMerger());
return list;
| private int | getRankOfType(java.lang.String table, int type)Returns the rank of the table-specific type, used when deciding which row
should be primary when none are primary. The lower the rank the better the type.
if (table.equals(sPhonesTable)) {
switch (type) {
case Contacts.Phones.TYPE_MOBILE: return 0;
case Contacts.Phones.TYPE_WORK: return 1;
case Contacts.Phones.TYPE_HOME: return 2;
case Contacts.Phones.TYPE_PAGER: return 3;
case Contacts.Phones.TYPE_CUSTOM: return 4;
case Contacts.Phones.TYPE_OTHER: return 5;
case Contacts.Phones.TYPE_FAX_WORK: return 6;
case Contacts.Phones.TYPE_FAX_HOME: return 7;
default: return 1000;
}
}
if (table.equals(sContactMethodsTable)) {
switch (type) {
case Contacts.ContactMethods.TYPE_HOME: return 0;
case Contacts.ContactMethods.TYPE_WORK: return 1;
case Contacts.ContactMethods.TYPE_CUSTOM: return 2;
case Contacts.ContactMethods.TYPE_OTHER: return 3;
default: return 1000;
}
}
if (table.equals(sOrganizationsTable)) {
switch (type) {
case Organizations.TYPE_WORK: return 0;
case Organizations.TYPE_CUSTOM: return 1;
case Organizations.TYPE_OTHER: return 2;
default: return 1000;
}
}
throw new IllegalArgumentException("unexpected table, " + table);
| public java.lang.String | getType(android.net.Uri url)
int match = sURIMatcher.match(url);
switch (match) {
case EXTENSIONS:
case PEOPLE_EXTENSIONS:
return Extensions.CONTENT_TYPE;
case EXTENSIONS_ID:
case PEOPLE_EXTENSIONS_ID:
return Extensions.CONTENT_ITEM_TYPE;
case PEOPLE:
return "vnd.android.cursor.dir/person";
case PEOPLE_ID:
return "vnd.android.cursor.item/person";
case PEOPLE_PHONES:
return "vnd.android.cursor.dir/phone";
case PEOPLE_PHONES_ID:
return "vnd.android.cursor.item/phone";
case PEOPLE_CONTACTMETHODS:
return "vnd.android.cursor.dir/contact-methods";
case PEOPLE_CONTACTMETHODS_ID:
return getContactMethodType(url);
case PHONES:
return "vnd.android.cursor.dir/phone";
case PHONES_ID:
return "vnd.android.cursor.item/phone";
case PHONES_FILTER:
case PHONES_FILTER_NAME:
case PHONES_MOBILE_FILTER_NAME:
return "vnd.android.cursor.dir/phone";
case CONTACTMETHODS:
return "vnd.android.cursor.dir/contact-methods";
case CONTACTMETHODS_ID:
return getContactMethodType(url);
case CONTACTMETHODS_EMAIL:
case CONTACTMETHODS_EMAIL_FILTER:
return "vnd.android.cursor.dir/email";
case CALLS:
return "vnd.android.cursor.dir/calls";
case CALLS_ID:
return "vnd.android.cursor.item/calls";
case ORGANIZATIONS:
return "vnd.android.cursor.dir/organizations";
case ORGANIZATIONS_ID:
return "vnd.android.cursor.item/organization";
case CALLS_FILTER:
return "vnd.android.cursor.dir/calls";
default:
throw new IllegalArgumentException("Unknown URL");
}
| private android.database.Cursor | handleSearchSuggestionsQuery(android.net.Uri url, android.database.sqlite.SQLiteQueryBuilder qb)Either sets up the query builder so we can run the proper query against the database
and returns null, or returns a cursor with the results already in it.
qb.setTables("people");
qb.setProjectionMap(sSearchSuggestionsProjectionMap);
if (url.getPathSegments().size() > 1) {
// A search term was entered, use it to filter
final String searchClause = url.getLastPathSegment();
if (!TextUtils.isDigitsOnly(searchClause)) {
qb.appendWhere(buildPeopleLookupWhereClause(searchClause));
} else {
final String[] columnNames = new String[] {
SearchManager.SUGGEST_COLUMN_TEXT_1,
SearchManager.SUGGEST_COLUMN_TEXT_2,
SearchManager.SUGGEST_COLUMN_INTENT_DATA,
SearchManager.SUGGEST_COLUMN_INTENT_ACTION,
};
Resources r = getContext().getResources();
String s;
int i;
ArrayList dialNumber = new ArrayList();
s = r.getString(com.android.internal.R.string.dial_number_using, searchClause);
i = s.indexOf('\n");
if (i < 0) {
dialNumber.add(s);
dialNumber.add("");
} else {
dialNumber.add(s.substring(0, i));
dialNumber.add(s.substring(i + 1));
}
dialNumber.add("tel:" + searchClause);
dialNumber.add(Intents.SEARCH_SUGGESTION_DIAL_NUMBER_CLICKED);
ArrayList createContact = new ArrayList();
s = r.getString(com.android.internal.R.string.create_contact_using, searchClause);
i = s.indexOf('\n");
if (i < 0) {
createContact.add(s);
createContact.add("");
} else {
createContact.add(s.substring(0, i));
createContact.add(s.substring(i + 1));
}
createContact.add("tel:" + searchClause);
createContact.add(Intents.SEARCH_SUGGESTION_CREATE_CONTACT_CLICKED);
ArrayList<ArrayList> rows = new ArrayList<ArrayList>();
rows.add(dialNumber);
rows.add(createContact);
ArrayListCursor cursor = new ArrayListCursor(columnNames, rows);
return cursor;
}
}
return null;
| private long | insertAndFixupPrimary(int kind, android.content.ContentValues values)
final String table = kindToTable(kind);
boolean isPrimary = false;
Long personId = null;
if (!isTemporary()) {
// when you add a item, if isPrimary or if there is no primary,
// make this it, set the isPrimary flag, and clear other primary flags
isPrimary = values.containsKey("isprimary")
&& (values.getAsInteger("isprimary") != 0);
personId = values.getAsLong("person");
if (!isPrimary) {
// make it primary anyway if this person doesn't have any rows of this type yet
StringBuilder sb = new StringBuilder("person=" + personId);
if (sContactMethodsTable.equals(table)) {
sb.append(" AND kind=");
sb.append(kind);
}
final boolean isFirstRowOfType = DatabaseUtils.longForQuery(getDatabase(),
"SELECT count(*) FROM " + table + " where " + sb.toString(), null) == 0;
isPrimary = isFirstRowOfType;
}
values.put("isprimary", isPrimary ? 1 : 0);
}
// do the actual insert
long newRowId = kindToInserter(kind).insert(values);
if (newRowId <= 0) {
throw new RuntimeException("error while inserting into " + table + ", " + values);
}
if (!isTemporary()) {
// If this row was made the primary then clear the other isprimary flags and update
// corresponding people row, if necessary.
if (isPrimary) {
clearOtherIsPrimary(kind, personId, newRowId);
if (kind == Contacts.KIND_PHONE) {
updatePeoplePrimary(personId, People.PRIMARY_PHONE_ID, newRowId);
} else if (kind == Contacts.KIND_EMAIL) {
updatePeoplePrimary(personId, People.PRIMARY_EMAIL_ID, newRowId);
} else if (kind == Contacts.KIND_ORGANIZATION) {
updatePeoplePrimary(personId, People.PRIMARY_ORGANIZATION_ID, newRowId);
}
}
}
return newRowId;
| public android.net.Uri | insertInternal(android.net.Uri url, android.content.ContentValues initialValues)
Uri resultUri = null;
long rowID;
final SQLiteDatabase db = getDatabase();
int match = sURIMatcher.match(url);
switch (match) {
case PEOPLE_GROUPMEMBERSHIP:
case GROUPMEMBERSHIP: {
mValues.clear();
mValues.putAll(initialValues);
if (match == PEOPLE_GROUPMEMBERSHIP) {
mValues.put(GroupMembership.PERSON_ID,
Long.valueOf(url.getPathSegments().get(1)));
}
resultUri = insertIntoGroupmembership(mValues);
}
break;
case PEOPLE_OWNER:
return insertOwner(initialValues);
case PEOPLE_EXTENSIONS:
case EXTENSIONS: {
ContentValues newMap = new ContentValues(initialValues);
if (match == PEOPLE_EXTENSIONS) {
newMap.put(Extensions.PERSON_ID,
Long.valueOf(url.getPathSegments().get(1)));
}
rowID = mExtensionsInserter.insert(newMap);
if (rowID > 0) {
resultUri = ContentUris.withAppendedId(Extensions.CONTENT_URI, rowID);
}
}
break;
case PHOTOS: {
if (!isTemporary()) {
throw new UnsupportedOperationException();
}
rowID = mPhotosInserter.insert(initialValues);
if (rowID > 0) {
resultUri = ContentUris.withAppendedId(Photos.CONTENT_URI, rowID);
}
}
break;
case GROUPS: {
ContentValues newMap = new ContentValues(initialValues);
ensureSyncAccountIsSet(newMap);
newMap.put(Groups._SYNC_DIRTY, 1);
// Insert into the groups table
rowID = mGroupsInserter.insert(newMap);
if (rowID > 0) {
resultUri = ContentUris.withAppendedId(Groups.CONTENT_URI, rowID);
if (!isTemporary() && newMap.containsKey(Groups.SHOULD_SYNC)) {
final String account = newMap.getAsString(Groups._SYNC_ACCOUNT);
if (!TextUtils.isEmpty(account)) {
final ContentResolver cr = getContext().getContentResolver();
onLocalChangesForAccount(cr, account, false);
}
}
}
}
break;
case PEOPLE_RAW:
case PEOPLE: {
mValues.clear();
mValues.putAll(initialValues);
ensureSyncAccountIsSet(mValues);
mValues.put(People._SYNC_DIRTY, 1);
// Insert into the people table
rowID = mPeopleInserter.insert(mValues);
if (rowID > 0) {
resultUri = ContentUris.withAppendedId(People.CONTENT_URI, rowID);
if (!isTemporary()) {
String account = mValues.getAsString(People._SYNC_ACCOUNT);
Long starredValue = mValues.getAsLong(People.STARRED);
final String syncId = mValues.getAsString(People._SYNC_ID);
boolean isStarred = starredValue != null && starredValue != 0;
fixupGroupMembershipAfterPeopleUpdate(account, rowID, isStarred);
// create a photo row for this person
mDb.delete(sPhotosTable, "person=" + rowID, null);
mValues.clear();
mValues.put(Photos.PERSON_ID, rowID);
mValues.put(Photos._SYNC_ACCOUNT, account);
mValues.put(Photos._SYNC_ID, syncId);
mValues.put(Photos._SYNC_DIRTY, 0);
mPhotosInserter.insert(mValues);
}
}
}
break;
case DELETED_PEOPLE: {
if (isTemporary()) {
// Insert into the people table
rowID = db.insert("_deleted_people", "_sync_id", initialValues);
if (rowID > 0) {
resultUri = Uri.parse("content://contacts/_deleted_people/" + rowID);
}
} else {
throw new UnsupportedOperationException();
}
}
break;
case DELETED_GROUPS: {
if (isTemporary()) {
rowID = db.insert(sDeletedGroupsTable, Groups._SYNC_ID,
initialValues);
if (rowID > 0) {
resultUri =ContentUris.withAppendedId(
Groups.DELETED_CONTENT_URI, rowID);
}
} else {
throw new UnsupportedOperationException();
}
}
break;
case PEOPLE_PHONES:
case PHONES: {
mValues.clear();
mValues.putAll(initialValues);
if (match == PEOPLE_PHONES) {
mValues.put(Contacts.Phones.PERSON_ID,
Long.valueOf(url.getPathSegments().get(1)));
}
String number = mValues.getAsString(Contacts.Phones.NUMBER);
if (number != null) {
mValues.put("number_key", PhoneNumberUtils.getStrippedReversed(number));
}
rowID = insertAndFixupPrimary(Contacts.KIND_PHONE, mValues);
resultUri = ContentUris.withAppendedId(Phones.CONTENT_URI, rowID);
}
break;
case CONTACTMETHODS:
case PEOPLE_CONTACTMETHODS: {
mValues.clear();
mValues.putAll(initialValues);
if (match == PEOPLE_CONTACTMETHODS) {
mValues.put("person", url.getPathSegments().get(1));
}
Integer kind = mValues.getAsInteger(ContactMethods.KIND);
if (kind == null) {
throw new IllegalArgumentException("you must specify the ContactMethods.KIND");
}
rowID = insertAndFixupPrimary(kind, mValues);
if (rowID > 0) {
resultUri = ContentUris.withAppendedId(ContactMethods.CONTENT_URI, rowID);
}
}
break;
case CALLS: {
rowID = mCallsInserter.insert(initialValues);
if (rowID > 0) {
resultUri = Uri.parse("content://call_log/calls/" + rowID);
}
}
break;
case PRESENCE: {
final String handle = initialValues.getAsString(Presence.IM_HANDLE);
final String protocol = initialValues.getAsString(Presence.IM_PROTOCOL);
if (TextUtils.isEmpty(handle) || TextUtils.isEmpty(protocol)) {
throw new IllegalArgumentException("IM_PROTOCOL and IM_HANDLE are required");
}
// Look for the contact for this presence update
StringBuilder query = new StringBuilder("SELECT ");
query.append(ContactMethods.PERSON_ID);
query.append(" FROM contact_methods WHERE (kind=");
query.append(Contacts.KIND_IM);
query.append(" AND ");
query.append(ContactMethods.DATA);
query.append("=? AND ");
query.append(ContactMethods.AUX_DATA);
query.append("=?)");
String[] selectionArgs;
if (GTALK_PROTOCOL_STRING.equals(protocol)) {
// For gtalk accounts we usually don't have an explicit IM
// entry, so also look for the email address as well
query.append(" OR (");
query.append("kind=");
query.append(Contacts.KIND_EMAIL);
query.append(" AND ");
query.append(ContactMethods.DATA);
query.append("=?)");
selectionArgs = new String[] { handle, protocol, handle };
} else {
selectionArgs = new String[] { handle, protocol };
}
Cursor c = db.rawQueryWithFactory(null, query.toString(), selectionArgs, null);
long personId = 0;
try {
if (c.moveToFirst()) {
personId = c.getLong(0);
} else {
// No contact found, return a null URI
return null;
}
} finally {
c.close();
}
mValues.clear();
mValues.putAll(initialValues);
mValues.put(Presence.PERSON_ID, personId);
// Insert the presence update
rowID = db.replace("presence", null, mValues);
if (rowID > 0) {
resultUri = Uri.parse("content://contacts/presence/" + rowID);
}
}
break;
case PEOPLE_ORGANIZATIONS:
case ORGANIZATIONS: {
ContentValues newMap = new ContentValues(initialValues);
if (match == PEOPLE_ORGANIZATIONS) {
newMap.put(Contacts.Phones.PERSON_ID,
Long.valueOf(url.getPathSegments().get(1)));
}
rowID = insertAndFixupPrimary(Contacts.KIND_ORGANIZATION, newMap);
if (rowID > 0) {
resultUri = Uri.parse("content://contacts/organizations/" + rowID);
}
}
break;
default:
throw new UnsupportedOperationException("Cannot insert into URL: " + url);
}
return resultUri;
| private android.net.Uri | insertIntoGroupmembership(android.content.ContentValues values)
String groupSyncAccount = values.getAsString(GroupMembership.GROUP_SYNC_ACCOUNT);
String groupSyncId = values.getAsString(GroupMembership.GROUP_SYNC_ID);
final Long personId = values.getAsLong(GroupMembership.PERSON_ID);
if (!values.containsKey(GroupMembership.GROUP_ID)) {
if (TextUtils.isEmpty(groupSyncAccount) || TextUtils.isEmpty(groupSyncId)) {
throw new IllegalArgumentException(
"insertIntoGroupmembership: no GROUP_ID wasn't specified and non-empty "
+ "GROUP_SYNC_ID and GROUP_SYNC_ACCOUNT fields weren't specifid, "
+ values);
}
if (0 != DatabaseUtils.longForQuery(getDatabase(), ""
+ "SELECT COUNT(*) "
+ "FROM groupmembership "
+ "WHERE group_sync_id=? AND person=?",
new String[]{groupSyncId, String.valueOf(personId)})) {
final String errorMessage =
"insertIntoGroupmembership: a row with this server key already exists, "
+ values;
if (Config.LOGD) Log.d(TAG, errorMessage);
return null;
}
} else {
long groupId = values.getAsLong(GroupMembership.GROUP_ID);
if (!TextUtils.isEmpty(groupSyncAccount) || !TextUtils.isEmpty(groupSyncId)) {
throw new IllegalArgumentException(
"insertIntoGroupmembership: GROUP_ID was specified but "
+ "GROUP_SYNC_ID and GROUP_SYNC_ACCOUNT fields were also specifid, "
+ values);
}
if (0 != DatabaseUtils.longForQuery(getDatabase(),
"SELECT COUNT(*) FROM groupmembership where group_id=? AND person=?",
new String[]{String.valueOf(groupId), String.valueOf(personId)})) {
final String errorMessage =
"insertIntoGroupmembership: a row with this local key already exists, "
+ values;
if (Config.LOGD) Log.d(TAG, errorMessage);
return null;
}
}
long rowId = mGroupMembershipInserter.insert(values);
if (rowId <= 0) {
final String errorMessage = "insertIntoGroupmembership: the insert failed, values are "
+ values;
if (Config.LOGD) Log.d(TAG, errorMessage);
return null;
}
// set the STARRED column in the people row if this group is the GROUP_ANDROID_STARRED
if (!isTemporary() && queryGroupMembershipContainsStarred(personId)) {
fixupPeopleStarred(personId, true);
}
return ContentUris.withAppendedId(GroupMembership.CONTENT_URI, rowId);
| private android.net.Uri | insertOwner(android.content.ContentValues values)
// Check the permissions
getContext().enforceCallingPermission("android.permission.WRITE_OWNER_DATA",
"No permission to set owner info");
// Insert the owner info
Uri uri = insertInternal(People.CONTENT_URI, values);
// Record which person is the owner
long id = ContentUris.parseId(uri);
SharedPreferences.Editor prefs = getContext().getSharedPreferences(PREFS_NAME_OWNER,
Context.MODE_PRIVATE).edit();
prefs.putLong(PREF_OWNER_ID, id);
prefs.commit();
return uri;
| private DatabaseUtils.InsertHelper | kindToInserter(int kind)
switch (kind) {
case Contacts.KIND_EMAIL: return mContactMethodsInserter;
case Contacts.KIND_POSTAL: return mContactMethodsInserter;
case Contacts.KIND_IM: return mContactMethodsInserter;
case Contacts.KIND_PHONE: return mPhonesInserter;
case Contacts.KIND_ORGANIZATION: return mOrganizationsInserter;
default: throw new IllegalArgumentException("unknown kind, " + kind);
}
| private java.lang.String | kindToTable(int kind)
switch (kind) {
case Contacts.KIND_EMAIL: return sContactMethodsTable;
case Contacts.KIND_POSTAL: return sContactMethodsTable;
case Contacts.KIND_IM: return sContactMethodsTable;
case Contacts.KIND_PHONE: return sPhonesTable;
case Contacts.KIND_ORGANIZATION: return sOrganizationsTable;
default: throw new IllegalArgumentException("unknown kind, " + kind);
}
| private com.android.providers.contacts.ContactsProvider$IsPrimaryInfo | lookupIsPrimaryInfo(java.lang.String table, java.lang.String[] projection, java.lang.String where, java.lang.String[] whereArgs)Queries the table to determine the state of the row's isprimary column and the kind.
The where and whereArgs must be sufficient to match either 0 or 1 row.
Cursor cursor = getDatabase().query(table, projection, where, whereArgs, null, null, null);
try {
if (!(cursor.getCount() <= 1)) {
throw new IllegalArgumentException("expected only zero or one rows, got "
+ DatabaseUtils.dumpCursorToString(cursor));
}
if (!cursor.moveToFirst()) return null;
IsPrimaryInfo info = new IsPrimaryInfo();
info.isPrimary = cursor.getInt(0) != 0;
info.person = cursor.getLong(1);
info.id = cursor.getLong(2);
if (projection == sIsPrimaryProjectionWithKind) {
info.kind = cursor.getInt(3);
} else {
if (sPhonesTable.equals(table)) {
info.kind = Contacts.KIND_PHONE;
} else if (sOrganizationsTable.equals(table)) {
info.kind = Contacts.KIND_ORGANIZATION;
} else {
throw new IllegalArgumentException("unexpected table, " + table);
}
}
return info;
} finally {
cursor.close();
}
| private long | lookupPerson(java.lang.String table, long id)Queries table to find the value of the person column for the row with _id. There must
be exactly one row that matches this id.
return DatabaseUtils.longForQuery(
getDatabase(),
"SELECT person FROM " + table + " where _id=" + id,
null);
| private void | maybeCreatePresenceTable(android.database.sqlite.SQLiteDatabase db)
// Load the presence table from the presence_db. Just create the table
// if we are
String cpDbName;
if (!isTemporary()) {
db.execSQL("ATTACH DATABASE ':memory:' AS presence_db;");
cpDbName = "presence_db.";
} else {
cpDbName = "";
}
db.execSQL("CREATE TABLE IF NOT EXISTS " + cpDbName + "presence ("+
Presence._ID + " INTEGER PRIMARY KEY," +
Presence.PERSON_ID + " INTEGER REFERENCES people(_id)," +
Presence.IM_PROTOCOL + " TEXT," +
Presence.IM_HANDLE + " TEXT," +
Presence.IM_ACCOUNT + " TEXT," +
Presence.PRESENCE_STATUS + " INTEGER," +
Presence.PRESENCE_CUSTOM_STATUS + " TEXT," +
"UNIQUE(" + Presence.IM_PROTOCOL + ", " + Presence.IM_HANDLE + ", "
+ Presence.IM_ACCOUNT + ")" +
");");
db.execSQL("CREATE INDEX IF NOT EXISTS " + cpDbName + "presenceIndex ON presence ("
+ Presence.PERSON_ID + ");");
| protected void | onAccountsChanged(java.lang.String[] accountsArray)
super.onAccountsChanged(accountsArray);
synchronized (mAccountsLock) {
mAccounts = new String[accountsArray.length];
System.arraycopy(accountsArray, 0, mAccounts, 0, mAccounts.length);
}
| protected void | onDatabaseOpened(android.database.sqlite.SQLiteDatabase db)
maybeCreatePresenceTable(db);
// Mark all the tables as syncable
db.markTableSyncable(sPeopleTable, sDeletedPeopleTable);
db.markTableSyncable(sPhonesTable, Phones.PERSON_ID, sPeopleTable);
db.markTableSyncable(sContactMethodsTable, ContactMethods.PERSON_ID, sPeopleTable);
db.markTableSyncable(sOrganizationsTable, Organizations.PERSON_ID, sPeopleTable);
db.markTableSyncable(sGroupmembershipTable, GroupMembership.PERSON_ID, sPeopleTable);
db.markTableSyncable(sExtensionsTable, Extensions.PERSON_ID, sPeopleTable);
db.markTableSyncable(sGroupsTable, sDeletedGroupsTable);
mDeletedPeopleInserter = new DatabaseUtils.InsertHelper(db, sDeletedPeopleTable);
mPeopleInserter = new DatabaseUtils.InsertHelper(db, sPeopleTable);
mIndexPeopleSyncId = mPeopleInserter.getColumnIndex(People._SYNC_ID);
mIndexPeopleSyncTime = mPeopleInserter.getColumnIndex(People._SYNC_TIME);
mIndexPeopleSyncVersion = mPeopleInserter.getColumnIndex(People._SYNC_VERSION);
mIndexPeopleSyncDirty = mPeopleInserter.getColumnIndex(People._SYNC_DIRTY);
mIndexPeopleSyncAccount = mPeopleInserter.getColumnIndex(People._SYNC_ACCOUNT);
mIndexPeopleName = mPeopleInserter.getColumnIndex(People.NAME);
mIndexPeoplePhoneticName = mPeopleInserter.getColumnIndex(People.PHONETIC_NAME);
mIndexPeopleNotes = mPeopleInserter.getColumnIndex(People.NOTES);
mGroupsInserter = new DatabaseUtils.InsertHelper(db, sGroupsTable);
mPhotosInserter = new DatabaseUtils.InsertHelper(db, sPhotosTable);
mIndexPhotosPersonId = mPhotosInserter.getColumnIndex(Photos.PERSON_ID);
mIndexPhotosSyncId = mPhotosInserter.getColumnIndex(Photos._SYNC_ID);
mIndexPhotosSyncTime = mPhotosInserter.getColumnIndex(Photos._SYNC_TIME);
mIndexPhotosSyncVersion = mPhotosInserter.getColumnIndex(Photos._SYNC_VERSION);
mIndexPhotosSyncDirty = mPhotosInserter.getColumnIndex(Photos._SYNC_DIRTY);
mIndexPhotosSyncAccount = mPhotosInserter.getColumnIndex(Photos._SYNC_ACCOUNT);
mIndexPhotosSyncError = mPhotosInserter.getColumnIndex(Photos.SYNC_ERROR);
mIndexPhotosExistsOnServer = mPhotosInserter.getColumnIndex(Photos.EXISTS_ON_SERVER);
mContactMethodsInserter = new DatabaseUtils.InsertHelper(db, sContactMethodsTable);
mIndexContactMethodsPersonId = mContactMethodsInserter.getColumnIndex(ContactMethods.PERSON_ID);
mIndexContactMethodsLabel = mContactMethodsInserter.getColumnIndex(ContactMethods.LABEL);
mIndexContactMethodsKind = mContactMethodsInserter.getColumnIndex(ContactMethods.KIND);
mIndexContactMethodsType = mContactMethodsInserter.getColumnIndex(ContactMethods.TYPE);
mIndexContactMethodsData = mContactMethodsInserter.getColumnIndex(ContactMethods.DATA);
mIndexContactMethodsAuxData = mContactMethodsInserter.getColumnIndex(ContactMethods.AUX_DATA);
mIndexContactMethodsIsPrimary = mContactMethodsInserter.getColumnIndex(ContactMethods.ISPRIMARY);
mOrganizationsInserter = new DatabaseUtils.InsertHelper(db, sOrganizationsTable);
mIndexOrganizationsPersonId = mOrganizationsInserter.getColumnIndex(Organizations.PERSON_ID);
mIndexOrganizationsLabel = mOrganizationsInserter.getColumnIndex(Organizations.LABEL);
mIndexOrganizationsType = mOrganizationsInserter.getColumnIndex(Organizations.TYPE);
mIndexOrganizationsCompany = mOrganizationsInserter.getColumnIndex(Organizations.COMPANY);
mIndexOrganizationsTitle = mOrganizationsInserter.getColumnIndex(Organizations.TITLE);
mIndexOrganizationsIsPrimary = mOrganizationsInserter.getColumnIndex(Organizations.ISPRIMARY);
mExtensionsInserter = new DatabaseUtils.InsertHelper(db, sExtensionsTable);
mIndexExtensionsPersonId = mExtensionsInserter.getColumnIndex(Extensions.PERSON_ID);
mIndexExtensionsName = mExtensionsInserter.getColumnIndex(Extensions.NAME);
mIndexExtensionsValue = mExtensionsInserter.getColumnIndex(Extensions.VALUE);
mGroupMembershipInserter = new DatabaseUtils.InsertHelper(db, sGroupmembershipTable);
mIndexGroupMembershipPersonId = mGroupMembershipInserter.getColumnIndex(GroupMembership.PERSON_ID);
mIndexGroupMembershipGroupSyncAccount = mGroupMembershipInserter.getColumnIndex(GroupMembership.GROUP_SYNC_ACCOUNT);
mIndexGroupMembershipGroupSyncId = mGroupMembershipInserter.getColumnIndex(GroupMembership.GROUP_SYNC_ID);
mCallsInserter = new DatabaseUtils.InsertHelper(db, sCallsTable);
mPhonesInserter = new DatabaseUtils.InsertHelper(db, sPhonesTable);
mIndexPhonesPersonId = mPhonesInserter.getColumnIndex(Phones.PERSON_ID);
mIndexPhonesLabel = mPhonesInserter.getColumnIndex(Phones.LABEL);
mIndexPhonesType = mPhonesInserter.getColumnIndex(Phones.TYPE);
mIndexPhonesNumber = mPhonesInserter.getColumnIndex(Phones.NUMBER);
mIndexPhonesNumberKey = mPhonesInserter.getColumnIndex(Phones.NUMBER_KEY);
mIndexPhonesIsPrimary = mPhonesInserter.getColumnIndex(Phones.ISPRIMARY);
| protected void | onLocalChangesForAccount(android.content.ContentResolver resolver, java.lang.String account, boolean groupsModified)Called when local changes are made, so subclasses have
an opportunity to react as they see fit.
// Do nothing
| public android.os.ParcelFileDescriptor | openFile(android.net.Uri uri, java.lang.String mode)
int match = sURIMatcher.match(uri);
switch (match) {
default:
throw new UnsupportedOperationException(uri.toString());
}
| private android.content.ContentValues | queryAndroidStarredGroupId(java.lang.String account)
String whereString;
String[] whereArgs;
if (!TextUtils.isEmpty(account)) {
whereString = "_sync_account=? AND name=?";
whereArgs = new String[]{account, Groups.GROUP_ANDROID_STARRED};
} else {
whereString = "_sync_account is null AND name=?";
whereArgs = new String[]{Groups.GROUP_ANDROID_STARRED};
}
Cursor cursor = getDatabase().query(sGroupsTable,
new String[]{Groups._ID, Groups._SYNC_ID, Groups._SYNC_ACCOUNT},
whereString, whereArgs, null, null, null);
try {
if (cursor.moveToNext()) {
ContentValues result = new ContentValues();
result.put(Groups._ID, cursor.getLong(0));
result.put(Groups._SYNC_ID, cursor.getString(1));
result.put(Groups._SYNC_ACCOUNT, cursor.getString(2));
return result;
}
return null;
} finally {
cursor.close();
}
| private boolean | queryGroupMembershipContainsStarred(long personId)
// TODO: Part 1 of 2 part hack to work around a bug in reusing SQLiteStatements
SQLiteStatement mGroupsMembershipQuery = null;
if (mGroupsMembershipQuery == null) {
String query =
"SELECT COUNT(*) FROM groups, groupmembership WHERE "
+ sGroupsJoinString + " AND person=? AND groups.name=?";
mGroupsMembershipQuery = getDatabase().compileStatement(query);
}
long result = DatabaseUtils.longForQuery(mGroupsMembershipQuery,
new String[]{String.valueOf(personId), Groups.GROUP_ANDROID_STARRED});
// TODO: Part 2 of 2 part hack to work around a bug in reusing SQLiteStatements
mGroupsMembershipQuery.close();
return result != 0;
| public android.database.Cursor | queryInternal(android.net.Uri url, java.lang.String[] projectionIn, java.lang.String selection, java.lang.String[] selectionArgs, java.lang.String sort)
SQLiteQueryBuilder qb = new SQLiteQueryBuilder();
Uri notificationUri = Contacts.CONTENT_URI;
StringBuilder whereClause;
String groupBy = null;
// Generate the body of the query
int match = sURIMatcher.match(url);
if (Config.LOGV) Log.v(TAG, "ContactsProvider.query: url=" + url + ", match is " + match);
switch (match) {
case DELETED_GROUPS:
if (!isTemporary()) {
throw new UnsupportedOperationException();
}
qb.setTables(sDeletedGroupsTable);
break;
case GROUPS_ID:
qb.appendWhere("_id=");
qb.appendWhere(url.getPathSegments().get(1));
// fall through
case GROUPS:
qb.setTables(sGroupsTable);
qb.setProjectionMap(sGroupsProjectionMap);
break;
case SETTINGS:
qb.setTables(sSettingsTable);
break;
case PEOPLE_GROUPMEMBERSHIP_ID:
qb.appendWhere("groupmembership._id=");
qb.appendWhere(url.getPathSegments().get(3));
qb.appendWhere(" AND ");
// fall through
case PEOPLE_GROUPMEMBERSHIP:
qb.appendWhere(sGroupsJoinString + " AND ");
qb.appendWhere("person=" + url.getPathSegments().get(1));
qb.setTables("groups, groupmembership");
qb.setProjectionMap(sGroupMembershipProjectionMap);
break;
case GROUPMEMBERSHIP_ID:
qb.appendWhere("groupmembership._id=");
qb.appendWhere(url.getPathSegments().get(1));
qb.appendWhere(" AND ");
// fall through
case GROUPMEMBERSHIP:
qb.setTables("groups, groupmembership");
qb.setProjectionMap(sGroupMembershipProjectionMap);
qb.appendWhere(sGroupsJoinString);
break;
case GROUPMEMBERSHIP_RAW:
qb.setTables("groupmembership");
break;
case GROUP_NAME_MEMBERS_FILTER:
if (url.getPathSegments().size() > 5) {
qb.appendWhere(buildPeopleLookupWhereClause(url.getLastPathSegment()));
qb.appendWhere(" AND ");
}
// fall through
case GROUP_NAME_MEMBERS:
qb.setTables(PEOPLE_PHONES_JOIN);
qb.setProjectionMap(sPeopleProjectionMap);
qb.appendWhere("people._id IN (SELECT person FROM groupmembership JOIN groups " +
"ON (group_id=groups._id OR " +
"(group_sync_id = groups._sync_id AND " +
"group_sync_account = groups._sync_account)) "+
"WHERE " + Groups.NAME + "="
+ DatabaseUtils.sqlEscapeString(url.getPathSegments().get(2)) + ")");
break;
case GROUP_SYSTEM_ID_MEMBERS_FILTER:
if (url.getPathSegments().size() > 5) {
qb.appendWhere(buildPeopleLookupWhereClause(url.getLastPathSegment()));
qb.appendWhere(" AND ");
}
// fall through
case GROUP_SYSTEM_ID_MEMBERS:
qb.setTables(PEOPLE_PHONES_JOIN);
qb.setProjectionMap(sPeopleProjectionMap);
qb.appendWhere("people._id IN (SELECT person FROM groupmembership JOIN groups " +
"ON (group_id=groups._id OR " +
"(group_sync_id = groups._sync_id AND " +
"group_sync_account = groups._sync_account)) "+
"WHERE " + Groups.SYSTEM_ID + "="
+ DatabaseUtils.sqlEscapeString(url.getPathSegments().get(2)) + ")");
break;
case PEOPLE:
qb.setTables(PEOPLE_PHONES_JOIN);
qb.setProjectionMap(sPeopleProjectionMap);
break;
case PEOPLE_RAW:
qb.setTables(sPeopleTable);
break;
case PEOPLE_OWNER:
return queryOwner(projectionIn);
case PEOPLE_WITH_PHONES_FILTER:
qb.appendWhere("number IS NOT NULL AND ");
// Fall through.
case PEOPLE_FILTER: {
qb.setTables(PEOPLE_PHONES_JOIN);
qb.setProjectionMap(sPeopleProjectionMap);
if (url.getPathSegments().size() > 2) {
qb.appendWhere(buildPeopleLookupWhereClause(url.getLastPathSegment()));
}
break;
}
case PEOPLE_WITH_EMAIL_OR_IM_FILTER:
String email = url.getPathSegments().get(2);
whereClause = new StringBuilder();
// Match any E-mail or IM contact methods where data exactly
// matches the provided string.
whereClause.append(ContactMethods.DATA);
whereClause.append("=");
DatabaseUtils.appendEscapedSQLString(whereClause, email);
whereClause.append(" AND (kind = " + Contacts.KIND_EMAIL +
" OR kind = " + Contacts.KIND_IM + ")");
qb.appendWhere(whereClause.toString());
qb.setTables("people INNER JOIN contact_methods on (people._id = contact_methods.person)");
qb.setProjectionMap(sPeopleWithEmailOrImProjectionMap);
// Prevent returning the same person for multiple matches
groupBy = "contact_methods.person";
qb.setDistinct(true);
break;
case PHOTOS_ID:
qb.appendWhere("_id="+url.getPathSegments().get(1));
// Fall through.
case PHOTOS:
qb.setTables(sPhotosTable);
qb.setProjectionMap(sPhotosProjectionMap);
break;
case PEOPLE_PHOTO:
qb.appendWhere("person="+url.getPathSegments().get(1));
qb.setTables(sPhotosTable);
qb.setProjectionMap(sPhotosProjectionMap);
break;
case SEARCH_SUGGESTIONS: {
// Force the default sort order, since the SearchManage doesn't ask for things
// sorted, though they should be
if (sort != null && !People.DEFAULT_SORT_ORDER.equals(sort)) {
throw new IllegalArgumentException("Sort ordering not allowed for this URI");
}
sort = SearchManager.SUGGEST_COLUMN_TEXT_1 + " COLLATE LOCALIZED ASC";
// This will either setup the query builder so we can run the proper query below
// and return null, or it will return a cursor with the results already in it.
Cursor c = handleSearchSuggestionsQuery(url, qb);
if (c != null) {
return c;
}
break;
}
case PEOPLE_STREQUENT: {
// Build the first query for starred
qb.setTables(PEOPLE_PHONES_PHOTOS_JOIN);
qb.setProjectionMap(sStrequentStarredProjectionMap);
final String starredQuery = qb.buildQuery(projectionIn, "starred = 1",
null, null, null, null,
null /* limit */);
// Build the second query for frequent
qb = new SQLiteQueryBuilder();
qb.setTables(PEOPLE_PHONES_PHOTOS_JOIN);
qb.setProjectionMap(sPeopleWithPhotoProjectionMap);
final String frequentQuery = qb.buildQuery(projectionIn,
"times_contacted > 0 AND starred = 0", null, null, null, null, null);
// Put them together
final String query = qb.buildUnionQuery(new String[] {starredQuery, frequentQuery},
STREQUENT_ORDER_BY, STREQUENT_LIMIT);
final SQLiteDatabase db = getDatabase();
Cursor c = db.rawQueryWithFactory(null, query, null, sPeopleTable);
if ((c != null) && !isTemporary()) {
c.setNotificationUri(getContext().getContentResolver(), notificationUri);
}
return c;
}
case PEOPLE_STREQUENT_FILTER: {
// Build the first query for starred
qb.setTables(PEOPLE_PHONES_PHOTOS_JOIN);
qb.setProjectionMap(sStrequentStarredProjectionMap);
if (url.getPathSegments().size() > 3) {
qb.appendWhere(buildPeopleLookupWhereClause(url.getLastPathSegment()));
}
final String starredQuery = qb.buildQuery(projectionIn, "starred = 1",
null, null, null, null,
null /* limit */);
// Build the second query for frequent
qb = new SQLiteQueryBuilder();
qb.setTables(PEOPLE_PHONES_PHOTOS_JOIN);
qb.setProjectionMap(sPeopleWithPhotoProjectionMap);
if (url.getPathSegments().size() > 3) {
qb.appendWhere(buildPeopleLookupWhereClause(url.getLastPathSegment()));
}
final String frequentQuery = qb.buildQuery(projectionIn,
"times_contacted > 0 AND starred = 0", null, null, null, null, null);
// Put them together
final String query = qb.buildUnionQuery(new String[] {starredQuery, frequentQuery},
STREQUENT_ORDER_BY, null);
final SQLiteDatabase db = getDatabase();
Cursor c = db.rawQueryWithFactory(null, query, null, sPeopleTable);
if ((c != null) && !isTemporary()) {
c.setNotificationUri(getContext().getContentResolver(), notificationUri);
}
return c;
}
case DELETED_PEOPLE:
if (isTemporary()) {
qb.setTables("_deleted_people");
break;
}
throw new UnsupportedOperationException();
case PEOPLE_ID:
qb.setTables("people LEFT OUTER JOIN phones ON people.primary_phone=phones._id "
+ "LEFT OUTER JOIN presence ON (presence." + Presence.PERSON_ID
+ "=people._id)");
qb.setProjectionMap(sPeopleProjectionMap);
qb.appendWhere("people._id=");
qb.appendWhere(url.getPathSegments().get(1));
break;
case PEOPLE_PHONES:
qb.setTables("phones, people");
qb.setProjectionMap(sPhonesProjectionMap);
qb.appendWhere("people._id = phones.person AND person=");
qb.appendWhere(url.getPathSegments().get(1));
break;
case PEOPLE_PHONES_ID:
qb.setTables("phones, people");
qb.setProjectionMap(sPhonesProjectionMap);
qb.appendWhere("people._id = phones.person AND person=");
qb.appendWhere(url.getPathSegments().get(1));
qb.appendWhere(" AND phones._id=");
qb.appendWhere(url.getPathSegments().get(3));
break;
case PEOPLE_PHONES_WITH_PRESENCE:
qb.appendWhere("people._id=?");
selectionArgs = appendSelectionArg(selectionArgs, url.getPathSegments().get(1));
// Fall through.
case PHONES_WITH_PRESENCE:
qb.setTables("phones JOIN people ON (phones.person = people._id)"
+ " LEFT OUTER JOIN presence ON (presence.person = people._id)");
qb.setProjectionMap(sPhonesWithPresenceProjectionMap);
break;
case PEOPLE_CONTACTMETHODS:
qb.setTables("contact_methods, people");
qb.setProjectionMap(sContactMethodsProjectionMap);
qb.appendWhere("people._id = contact_methods.person AND person=");
qb.appendWhere(url.getPathSegments().get(1));
break;
case PEOPLE_CONTACTMETHODS_ID:
qb.setTables("contact_methods, people");
qb.setProjectionMap(sContactMethodsProjectionMap);
qb.appendWhere("people._id = contact_methods.person AND person=");
qb.appendWhere(url.getPathSegments().get(1));
qb.appendWhere(" AND contact_methods._id=");
qb.appendWhere(url.getPathSegments().get(3));
break;
case PEOPLE_ORGANIZATIONS:
qb.setTables("organizations, people");
qb.setProjectionMap(sOrganizationsProjectionMap);
qb.appendWhere("people._id = organizations.person AND person=");
qb.appendWhere(url.getPathSegments().get(1));
break;
case PEOPLE_ORGANIZATIONS_ID:
qb.setTables("organizations, people");
qb.setProjectionMap(sOrganizationsProjectionMap);
qb.appendWhere("people._id = organizations.person AND person=");
qb.appendWhere(url.getPathSegments().get(1));
qb.appendWhere(" AND organizations._id=");
qb.appendWhere(url.getPathSegments().get(3));
break;
case PHONES:
qb.setTables("phones, people");
qb.appendWhere("people._id = phones.person");
qb.setProjectionMap(sPhonesProjectionMap);
break;
case PHONES_ID:
qb.setTables("phones, people");
qb.appendWhere("people._id = phones.person AND phones._id="
+ url.getPathSegments().get(1));
qb.setProjectionMap(sPhonesProjectionMap);
break;
case ORGANIZATIONS:
qb.setTables("organizations, people");
qb.appendWhere("people._id = organizations.person");
qb.setProjectionMap(sOrganizationsProjectionMap);
break;
case ORGANIZATIONS_ID:
qb.setTables("organizations, people");
qb.appendWhere("people._id = organizations.person AND organizations._id="
+ url.getPathSegments().get(1));
qb.setProjectionMap(sOrganizationsProjectionMap);
break;
case PHONES_MOBILE_FILTER_NAME:
qb.appendWhere("type=" + Contacts.PhonesColumns.TYPE_MOBILE + " AND ");
// Fall through.
case PHONES_FILTER_NAME:
qb.setTables("phones JOIN people ON (people._id = phones.person)");
qb.setProjectionMap(sPhonesProjectionMap);
if (url.getPathSegments().size() > 2) {
qb.appendWhere(buildPeopleLookupWhereClause(url.getLastPathSegment()));
}
break;
case PHONES_FILTER: {
String phoneNumber = url.getPathSegments().get(2);
String indexable = PhoneNumberUtils.toCallerIDMinMatch(phoneNumber);
StringBuilder subQuery = new StringBuilder();
if (TextUtils.isEmpty(sort)) {
// Default the sort order to something reasonable so we get consistent
// results when callers don't request an ordering
sort = People.DEFAULT_SORT_ORDER;
}
subQuery.append("people, (SELECT * FROM phones WHERE (phones.number_key GLOB '");
subQuery.append(indexable);
subQuery.append("*')) AS phones");
qb.setTables(subQuery.toString());
qb.appendWhere("phones.person=people._id AND PHONE_NUMBERS_EQUAL(phones.number, ");
qb.appendWhereEscapeString(phoneNumber);
qb.appendWhere(")");
qb.setProjectionMap(sPhonesProjectionMap);
break;
}
case CONTACTMETHODS:
qb.setTables("contact_methods, people");
qb.setProjectionMap(sContactMethodsProjectionMap);
qb.appendWhere("people._id = contact_methods.person");
break;
case CONTACTMETHODS_ID:
qb.setTables("contact_methods LEFT OUTER JOIN people ON contact_methods.person = people._id");
qb.setProjectionMap(sContactMethodsProjectionMap);
qb.appendWhere("contact_methods._id=");
qb.appendWhere(url.getPathSegments().get(1));
break;
case CONTACTMETHODS_EMAIL_FILTER:
String pattern = url.getPathSegments().get(2);
whereClause = new StringBuilder();
// TODO This is going to be REALLY slow. Come up with
// something faster.
whereClause.append(ContactMethods.KIND);
whereClause.append('=");
whereClause.append('\'");
whereClause.append(Contacts.KIND_EMAIL);
whereClause.append("' AND (UPPER(");
whereClause.append(ContactMethods.NAME);
whereClause.append(") GLOB ");
DatabaseUtils.appendEscapedSQLString(whereClause, pattern + "*");
whereClause.append(" OR UPPER(");
whereClause.append(ContactMethods.NAME);
whereClause.append(") GLOB ");
DatabaseUtils.appendEscapedSQLString(whereClause, "* " + pattern + "*");
whereClause.append(") AND ");
qb.appendWhere(whereClause.toString());
// Fall through.
case CONTACTMETHODS_EMAIL:
qb.setTables("contact_methods INNER JOIN people on (contact_methods.person = people._id)");
qb.setProjectionMap(sEmailSearchProjectionMap);
qb.appendWhere("kind = " + Contacts.KIND_EMAIL);
qb.setDistinct(true);
break;
case PEOPLE_CONTACTMETHODS_WITH_PRESENCE:
qb.appendWhere("people._id=?");
selectionArgs = appendSelectionArg(selectionArgs, url.getPathSegments().get(1));
// Fall through.
case CONTACTMETHODS_WITH_PRESENCE:
qb.setTables("contact_methods JOIN people ON (contact_methods.person = people._id)"
+ " LEFT OUTER JOIN presence ON "
// Match gtalk presence items
+ "((kind=" + Contacts.KIND_EMAIL +
" AND im_protocol='"
+ ContactMethods.encodePredefinedImProtocol(
ContactMethods.PROTOCOL_GOOGLE_TALK)
+ "' AND data=im_handle)"
+ " OR "
// Match IM presence items
+ "(kind=" + Contacts.KIND_IM
+ " AND data=im_handle AND aux_data=im_protocol))");
qb.setProjectionMap(sContactMethodsWithPresenceProjectionMap);
break;
case CALLS:
qb.setTables("calls");
qb.setProjectionMap(sCallsProjectionMap);
notificationUri = CallLog.CONTENT_URI;
break;
case CALLS_ID:
qb.setTables("calls");
qb.setProjectionMap(sCallsProjectionMap);
qb.appendWhere("calls._id=");
qb.appendWhere(url.getPathSegments().get(1));
notificationUri = CallLog.CONTENT_URI;
break;
case CALLS_FILTER: {
qb.setTables("calls");
qb.setProjectionMap(sCallsProjectionMap);
String phoneNumber = url.getPathSegments().get(2);
qb.appendWhere("PHONE_NUMBERS_EQUAL(number, ");
qb.appendWhereEscapeString(phoneNumber);
qb.appendWhere(")");
notificationUri = CallLog.CONTENT_URI;
break;
}
case PRESENCE:
qb.setTables("presence LEFT OUTER JOIN people on (presence." + Presence.PERSON_ID
+ "= people._id)");
qb.setProjectionMap(sPresenceProjectionMap);
break;
case PRESENCE_ID:
qb.setTables("presence LEFT OUTER JOIN people on (presence." + Presence.PERSON_ID
+ "= people._id)");
qb.appendWhere("presence._id=");
qb.appendWhere(url.getLastPathSegment());
break;
case VOICE_DIALER_TIMESTAMP:
qb.setTables("voice_dialer_timestamp");
qb.appendWhere("_id=1");
break;
case PEOPLE_EXTENSIONS_ID:
qb.appendWhere("extensions._id=" + url.getPathSegments().get(3) + " AND ");
// fall through
case PEOPLE_EXTENSIONS:
qb.appendWhere("person=" + url.getPathSegments().get(1));
qb.setTables(sExtensionsTable);
qb.setProjectionMap(sExtensionsProjectionMap);
break;
case EXTENSIONS_ID:
qb.appendWhere("extensions._id=" + url.getPathSegments().get(1));
// fall through
case EXTENSIONS:
qb.setTables(sExtensionsTable);
qb.setProjectionMap(sExtensionsProjectionMap);
break;
case LIVE_FOLDERS_PEOPLE:
qb.setTables("people LEFT OUTER JOIN photos ON (people._id = photos.person)");
qb.setProjectionMap(sLiveFoldersProjectionMap);
break;
case LIVE_FOLDERS_PEOPLE_WITH_PHONES:
qb.setTables("people LEFT OUTER JOIN photos ON (people._id = photos.person)");
qb.setProjectionMap(sLiveFoldersProjectionMap);
qb.appendWhere(People.PRIMARY_PHONE_ID + " IS NOT NULL");
break;
case LIVE_FOLDERS_PEOPLE_FAVORITES:
qb.setTables("people LEFT OUTER JOIN photos ON (people._id = photos.person)");
qb.setProjectionMap(sLiveFoldersProjectionMap);
qb.appendWhere(People.STARRED + " <> 0");
break;
case LIVE_FOLDERS_PEOPLE_GROUP_NAME:
qb.setTables("people LEFT OUTER JOIN photos ON (people._id = photos.person)");
qb.setProjectionMap(sLiveFoldersProjectionMap);
qb.appendWhere("people._id IN (SELECT person FROM groupmembership JOIN groups " +
"ON (group_id=groups._id OR " +
"(group_sync_id = groups._sync_id AND " +
"group_sync_account = groups._sync_account)) "+
"WHERE " + Groups.NAME + "="
+ DatabaseUtils.sqlEscapeString(url.getLastPathSegment()) + ")");
break;
default:
throw new IllegalArgumentException("Unknown URL " + url);
}
// run the query
final SQLiteDatabase db = getDatabase();
Cursor c = qb.query(db, projectionIn, selection, selectionArgs,
groupBy, null, sort);
if ((c != null) && !isTemporary()) {
c.setNotificationUri(getContext().getContentResolver(), notificationUri);
}
return c;
| private android.database.Cursor | queryOwner(java.lang.String[] projection)
// Check the permissions
getContext().enforceCallingPermission("android.permission.READ_OWNER_DATA",
"No permission to access owner info");
// Read the owner id
SharedPreferences prefs = getContext().getSharedPreferences(PREFS_NAME_OWNER,
Context.MODE_PRIVATE);
long ownerId = prefs.getLong(PREF_OWNER_ID, 0);
// Run the query
return queryInternal(ContentUris.withAppendedId(People.CONTENT_URI, ownerId), projection,
null, null, null);
| private void | setIsPrimary(int kind, long personId, long itemId)
final String table = kindToTable(kind);
StringBuilder sb = new StringBuilder();
sb.append("person=");
sb.append(personId);
if (sContactMethodsTable.equals(table)) {
sb.append(" and ");
sb.append(ContactMethods.KIND);
sb.append("=");
sb.append(kind);
}
final String where = sb.toString();
getDatabase().execSQL(
"UPDATE " + table + " SET isprimary=(_id=" + itemId + ") WHERE " + where);
| private int | updateGroups(android.content.ContentValues values, java.lang.String where, java.lang.String[] whereArgs)
for (Map.Entry<String, Object> entry : values.valueSet()) {
final String column = entry.getKey();
if (!Groups.NAME.equals(column) && !Groups.NOTES.equals(column)
&& !Groups.SYSTEM_ID.equals(column) && !Groups.SHOULD_SYNC.equals(column)) {
throw new IllegalArgumentException(
"you are not allowed to change column " + column);
}
}
Set<String> modifiedAccounts = Sets.newHashSet();
final SQLiteDatabase db = getDatabase();
if (values.containsKey(Groups.NAME) || values.containsKey(Groups.SHOULD_SYNC)) {
String newName = values.getAsString(Groups.NAME);
Cursor cursor = db.query(sGroupsTable, null, where, whereArgs, null, null, null);
try {
final int indexName = cursor.getColumnIndexOrThrow(Groups.NAME);
final int indexSyncAccount = cursor.getColumnIndexOrThrow(Groups._SYNC_ACCOUNT);
final int indexSyncId = cursor.getColumnIndexOrThrow(Groups._SYNC_ID);
final int indexId = cursor.getColumnIndexOrThrow(Groups._ID);
while (cursor.moveToNext()) {
String syncAccount = cursor.getString(indexSyncAccount);
if (values.containsKey(Groups.NAME)) {
String oldName = cursor.getString(indexName);
String syncId = cursor.getString(indexSyncId);
long id = cursor.getLong(indexId);
fixupPeopleStarredOnGroupRename(oldName, newName, id);
if (!TextUtils.isEmpty(syncAccount) && !TextUtils.isEmpty(syncId)) {
fixupPeopleStarredOnGroupRename(oldName, newName, syncAccount, syncId);
}
}
if (!TextUtils.isEmpty(syncAccount) && values.containsKey(Groups.SHOULD_SYNC)) {
modifiedAccounts.add(syncAccount);
}
}
} finally {
cursor.close();
}
}
int numRows = db.update(sGroupsTable, values, where, whereArgs);
if (numRows > 0) {
if (!isTemporary()) {
final ContentResolver cr = getContext().getContentResolver();
for (String account : modifiedAccounts) {
onLocalChangesForAccount(cr, account, true);
}
}
}
return numRows;
| public int | updateInternal(android.net.Uri url, android.content.ContentValues values, java.lang.String userWhere, java.lang.String[] whereArgs)
final SQLiteDatabase db = getDatabase();
String tableToChange;
String changedItemId;
final int matchedUriId = sURIMatcher.match(url);
switch (matchedUriId) {
case GROUPS_ID:
changedItemId = url.getPathSegments().get(1);
return updateGroups(values,
addIdToWhereClause(changedItemId, userWhere), whereArgs);
case PEOPLE_EXTENSIONS_ID:
tableToChange = sExtensionsTable;
changedItemId = url.getPathSegments().get(3);
break;
case EXTENSIONS_ID:
tableToChange = sExtensionsTable;
changedItemId = url.getPathSegments().get(1);
break;
case PEOPLE_UPDATE_CONTACT_TIME:
if (values.size() != 1 || !values.containsKey(People.LAST_TIME_CONTACTED)) {
throw new IllegalArgumentException(
"You may only use " + url + " to update People.LAST_TIME_CONTACTED");
}
tableToChange = sPeopleTable;
changedItemId = url.getPathSegments().get(1);
break;
case PEOPLE_ID:
mValues.clear();
mValues.putAll(values);
mValues.put(Photos._SYNC_DIRTY, 1);
values = mValues;
tableToChange = sPeopleTable;
changedItemId = url.getPathSegments().get(1);
break;
case PEOPLE_PHONES_ID:
tableToChange = sPhonesTable;
changedItemId = url.getPathSegments().get(3);
break;
case PEOPLE_CONTACTMETHODS_ID:
tableToChange = sContactMethodsTable;
changedItemId = url.getPathSegments().get(3);
break;
case PHONES_ID:
tableToChange = sPhonesTable;
changedItemId = url.getPathSegments().get(1);
break;
case PEOPLE_PHOTO:
case PHOTOS_ID:
mValues.clear();
mValues.putAll(values);
// The _SYNC_DIRTY flag should only be set if the data was modified and if
// it isn't already provided.
if (!mValues.containsKey(Photos._SYNC_DIRTY) && mValues.containsKey(Photos.DATA)) {
mValues.put(Photos._SYNC_DIRTY, 1);
}
StringBuilder where;
if (matchedUriId == PEOPLE_PHOTO) {
where = new StringBuilder("_id=" + url.getPathSegments().get(1));
} else {
where = new StringBuilder("person=" + url.getPathSegments().get(1));
}
if (!TextUtils.isEmpty(userWhere)) {
where.append(" AND (");
where.append(userWhere);
where.append(')");
}
return db.update(sPhotosTable, mValues, where.toString(), whereArgs);
case ORGANIZATIONS_ID:
tableToChange = sOrganizationsTable;
changedItemId = url.getPathSegments().get(1);
break;
case CONTACTMETHODS_ID:
tableToChange = sContactMethodsTable;
changedItemId = url.getPathSegments().get(1);
break;
case SETTINGS:
if (whereArgs != null) {
throw new IllegalArgumentException(
"you aren't allowed to specify where args when updating settings");
}
if (userWhere != null) {
throw new IllegalArgumentException(
"you aren't allowed to specify a where string when updating settings");
}
return updateSettings(values);
case CALLS:
tableToChange = "calls";
changedItemId = null;
break;
case CALLS_ID:
tableToChange = "calls";
changedItemId = url.getPathSegments().get(1);
break;
default:
throw new UnsupportedOperationException("Cannot update URL: " + url);
}
String where = addIdToWhereClause(changedItemId, userWhere);
int numRowsUpdated = db.update(tableToChange, values, where, whereArgs);
if (numRowsUpdated > 0 && changedItemId != null) {
long itemId = Long.parseLong(changedItemId);
switch (matchedUriId) {
case ORGANIZATIONS_ID:
fixupPrimaryAfterUpdate(
Contacts.KIND_ORGANIZATION, null, itemId,
values.getAsInteger(Organizations.ISPRIMARY));
break;
case PHONES_ID:
case PEOPLE_PHONES_ID:
fixupPrimaryAfterUpdate(
Contacts.KIND_PHONE, matchedUriId == PEOPLE_PHONES_ID
? Long.parseLong(url.getPathSegments().get(1))
: null, itemId,
values.getAsInteger(Phones.ISPRIMARY));
break;
case CONTACTMETHODS_ID:
case PEOPLE_CONTACTMETHODS_ID:
IsPrimaryInfo isPrimaryInfo = lookupIsPrimaryInfo(sContactMethodsTable,
sIsPrimaryProjectionWithKind, where, whereArgs);
fixupPrimaryAfterUpdate(
isPrimaryInfo.kind, isPrimaryInfo.person, itemId,
values.getAsInteger(ContactMethods.ISPRIMARY));
break;
case PEOPLE_ID:
boolean hasStarred = values.containsKey(People.STARRED);
boolean hasPrimaryPhone = values.containsKey(People.PRIMARY_PHONE_ID);
boolean hasPrimaryOrganization =
values.containsKey(People.PRIMARY_ORGANIZATION_ID);
boolean hasPrimaryEmail = values.containsKey(People.PRIMARY_EMAIL_ID);
if (hasStarred || hasPrimaryPhone || hasPrimaryOrganization
|| hasPrimaryEmail) {
Cursor c = mDb.query(sPeopleTable, null,
where, whereArgs, null, null, null);
try {
int indexAccount = c.getColumnIndexOrThrow(People._SYNC_ACCOUNT);
int indexId = c.getColumnIndexOrThrow(People._ID);
Long starredValue = values.getAsLong(People.STARRED);
Long primaryPhone = values.getAsLong(People.PRIMARY_PHONE_ID);
Long primaryOrganization =
values.getAsLong(People.PRIMARY_ORGANIZATION_ID);
Long primaryEmail = values.getAsLong(People.PRIMARY_EMAIL_ID);
while (c.moveToNext()) {
final long personId = c.getLong(indexId);
if (hasStarred) {
fixupGroupMembershipAfterPeopleUpdate(c.getString(indexAccount),
personId, starredValue != null && starredValue != 0);
}
if (hasPrimaryPhone) {
if (primaryPhone == null) {
throw new IllegalArgumentException(
"the value of PRIMARY_PHONE_ID must not be null");
}
setIsPrimary(Contacts.KIND_PHONE, personId, primaryPhone);
}
if (hasPrimaryOrganization) {
if (primaryOrganization == null) {
throw new IllegalArgumentException(
"the value of PRIMARY_ORGANIZATION_ID must "
+ "not be null");
}
setIsPrimary(Contacts.KIND_ORGANIZATION, personId,
primaryOrganization);
}
if (hasPrimaryEmail) {
if (primaryEmail == null) {
throw new IllegalArgumentException(
"the value of PRIMARY_EMAIL_ID must not be null");
}
setIsPrimary(Contacts.KIND_EMAIL, personId, primaryEmail);
}
}
} finally {
c.close();
}
}
break;
}
}
return numRowsUpdated;
| private void | updatePeoplePrimary(java.lang.Long personId, java.lang.String column, java.lang.Long primaryId)Set the specified primary column for the person. This is used to make the people
row reflect the isprimary flag in the people or contactmethods tables, which is
authoritative.
mValuesLocal.clear();
mValuesLocal.put(column, primaryId);
getDatabase().update(sPeopleTable, mValuesLocal, "_id=" + personId, null);
| private int | updateSettings(android.content.ContentValues values)
final SQLiteDatabase db = getDatabase();
final String account = values.getAsString(Contacts.Settings._SYNC_ACCOUNT);
final String key = values.getAsString(Contacts.Settings.KEY);
if (key == null) {
throw new IllegalArgumentException("you must specify the key when updating settings");
}
if (account == null) {
db.delete(sSettingsTable, "_sync_account IS NULL AND key=?", new String[]{key});
} else {
if (TextUtils.isEmpty(account)) {
throw new IllegalArgumentException("account cannot be the empty string, " + values);
}
db.delete(sSettingsTable, "_sync_account=? AND key=?", new String[]{account, key});
}
long rowId = db.insert(sSettingsTable, Contacts.Settings.KEY, values);
if (rowId < 0) {
throw new SQLException("error updating settings with " + values);
}
return 1;
| protected boolean | upgradeDatabase(android.database.sqlite.SQLiteDatabase db, int oldVersion, int newVersion)
boolean upgradeWasLossless = true;
if (oldVersion < 71) {
Log.w(TAG, "Upgrading database from version " + oldVersion + " to " +
newVersion + ", which will destroy all old data");
dropTables(db);
bootstrapDatabase(db);
return false; // this was lossy
}
if (oldVersion == 71) {
Log.i(TAG, "Upgrading contacts database from version " + oldVersion + " to " +
newVersion + ", which will preserve existing data");
db.delete("_sync_state", null, null);
mValuesLocal.clear();
mValuesLocal.putNull(Photos._SYNC_VERSION);
mValuesLocal.putNull(Photos._SYNC_TIME);
db.update(sPhotosTable, mValuesLocal, null, null);
getContext().getContentResolver().startSync(Contacts.CONTENT_URI, new Bundle());
oldVersion = 72;
}
if (oldVersion == 72) {
Log.i(TAG, "Upgrading contacts database from version " + oldVersion + " to " +
newVersion + ", which will preserve existing data");
// use new token format from 73
db.execSQL("delete from peopleLookup");
try {
DatabaseUtils.longForQuery(db,
"SELECT _TOKENIZE('peopleLookup', _id, name, ' ') from people;",
null);
} catch (SQLiteDoneException ex) {
// it is ok to throw this,
// it just means you don't have data in people table
}
oldVersion = 73;
}
// There was a bug for a while in the upgrade logic where going from 72 to 74 would skip
// the step from 73 to 74, so 74 to 75 just tries the same steps, and gracefully handles
// errors in case the device was started freshly at 74.
if (oldVersion == 73 || oldVersion == 74) {
Log.i(TAG, "Upgrading contacts database from version " + oldVersion + " to " +
newVersion + ", which will preserve existing data");
try {
db.execSQL("ALTER TABLE calls ADD name TEXT;");
db.execSQL("ALTER TABLE calls ADD numbertype INTEGER;");
db.execSQL("ALTER TABLE calls ADD numberlabel TEXT;");
} catch (SQLiteException sqle) {
// Maybe the table was altered already... Shouldn't be an issue.
}
oldVersion = 75;
}
// There were some indices added in version 76
if (oldVersion == 75) {
Log.i(TAG, "Upgrading contacts database from version " + oldVersion + " to " +
newVersion + ", which will preserve existing data");
// add the new indices
db.execSQL("CREATE INDEX IF NOT EXISTS groupsSyncDirtyIndex"
+ " ON groups (" + Groups._SYNC_DIRTY + ");");
db.execSQL("CREATE INDEX IF NOT EXISTS photosSyncDirtyIndex"
+ " ON photos (" + Photos._SYNC_DIRTY + ");");
db.execSQL("CREATE INDEX IF NOT EXISTS peopleSyncDirtyIndex"
+ " ON people (" + People._SYNC_DIRTY + ");");
oldVersion = 76;
}
if (oldVersion == 76 || oldVersion == 77) {
db.execSQL("DELETE FROM people");
db.execSQL("DELETE FROM groups");
db.execSQL("DELETE FROM photos");
db.execSQL("DELETE FROM _deleted_people");
db.execSQL("DELETE FROM _deleted_groups");
upgradeWasLossless = false;
oldVersion = 78;
}
if (oldVersion == 78) {
db.execSQL("UPDATE photos SET _sync_dirty=0 where _sync_dirty is null;");
oldVersion = 79;
}
if (oldVersion == 79) {
try {
db.execSQL("ALTER TABLE people ADD phonetic_name TEXT COLLATE LOCALIZED;");
} catch (SQLiteException sqle) {
// Maybe the table was altered already... Shouldn't be an issue.
}
oldVersion = 80;
}
return upgradeWasLossless;
|
|