Cleaning up Presence API
diff --git a/src/com/android/providers/contacts/ContactsProvider2.java b/src/com/android/providers/contacts/ContactsProvider2.java
index 951764b..4ceca6f 100644
--- a/src/com/android/providers/contacts/ContactsProvider2.java
+++ b/src/com/android/providers/contacts/ContactsProvider2.java
@@ -28,6 +28,7 @@
import com.android.providers.contacts.OpenHelper.PackagesColumns;
import com.android.providers.contacts.OpenHelper.PhoneColumns;
import com.android.providers.contacts.OpenHelper.PhoneLookupColumns;
+import com.android.providers.contacts.OpenHelper.PresenceColumns;
import com.android.providers.contacts.OpenHelper.RawContactsColumns;
import com.android.providers.contacts.OpenHelper.Tables;
import com.google.android.collect.Lists;
@@ -583,11 +584,12 @@
columns = new HashMap<String, String>();
columns.put(Presence._ID, Presence._ID);
- columns.put(Presence.RAW_CONTACT_ID, Presence.RAW_CONTACT_ID);
+ columns.put(PresenceColumns.RAW_CONTACT_ID, PresenceColumns.RAW_CONTACT_ID);
columns.put(Presence.DATA_ID, Presence.DATA_ID);
columns.put(Presence.IM_ACCOUNT, Presence.IM_ACCOUNT);
columns.put(Presence.IM_HANDLE, Presence.IM_HANDLE);
- columns.put(Presence.IM_PROTOCOL, Presence.IM_PROTOCOL);
+ columns.put(Presence.PROTOCOL, Presence.PROTOCOL);
+ columns.put(Presence.CUSTOM_PROTOCOL, Presence.CUSTOM_PROTOCOL);
columns.put(Presence.PRESENCE_STATUS, Presence.PRESENCE_STATUS);
columns.put(Presence.PRESENCE_CUSTOM_STATUS, Presence.PRESENCE_CUSTOM_STATUS);
sPresenceProjectionMap = columns;
@@ -1540,23 +1542,51 @@
*/
public long insertPresence(ContentValues values) {
final String handle = values.getAsString(Presence.IM_HANDLE);
- final String protocol = values.getAsString(Presence.IM_PROTOCOL);
- if (TextUtils.isEmpty(handle) || TextUtils.isEmpty(protocol)) {
- throw new IllegalArgumentException("IM_PROTOCOL and IM_HANDLE are required");
+ if (TextUtils.isEmpty(handle) || !values.containsKey(Presence.PROTOCOL)) {
+ throw new IllegalArgumentException("PROTOCOL and IM_HANDLE are required");
+ }
+
+ final long protocol = values.getAsLong(Presence.PROTOCOL);
+ String customProtocol = null;
+
+ if (protocol == Im.PROTOCOL_CUSTOM) {
+ customProtocol = values.getAsString(Presence.CUSTOM_PROTOCOL);
+ if (TextUtils.isEmpty(customProtocol)) {
+ throw new IllegalArgumentException(
+ "CUSTOM_PROTOCOL is required when PROTOCOL=PROTOCOL_CUSTOM");
+ }
}
// TODO: generalize to allow other providers to match against email
- boolean matchEmail = Im.PROTOCOL_GOOGLE_TALK == Integer.parseInt(protocol);
+ boolean matchEmail = Im.PROTOCOL_GOOGLE_TALK == protocol;
StringBuilder selection = new StringBuilder();
String[] selectionArgs;
if (matchEmail) {
- selection.append("(" + Clauses.WHERE_IM_MATCHES + ") OR ("
- + Clauses.WHERE_EMAIL_MATCHES + ")");
- selectionArgs = new String[] { protocol, handle, handle };
+ selection.append(
+ "((" + MimetypesColumns.MIMETYPE + "='" + Im.CONTENT_ITEM_TYPE + "'"
+ + " AND " + Im.PROTOCOL + "=?"
+ + " AND " + Im.DATA + "=?");
+ if (customProtocol != null) {
+ selection.append(" AND " + Im.CUSTOM_PROTOCOL + "=");
+ DatabaseUtils.appendEscapedSQLString(selection, customProtocol);
+ }
+ selection.append(") OR ("
+ + MimetypesColumns.MIMETYPE + "='" + Email.CONTENT_ITEM_TYPE + "'"
+ + " AND " + Email.DATA + "=?"
+ + "))");
+ selectionArgs = new String[] { String.valueOf(protocol), handle, handle };
} else {
- selection.append(Clauses.WHERE_IM_MATCHES);
- selectionArgs = new String[] { protocol, handle };
+ selection.append(
+ MimetypesColumns.MIMETYPE + "='" + Im.CONTENT_ITEM_TYPE + "'"
+ + " AND " + Im.PROTOCOL + "=?"
+ + " AND " + Im.DATA + "=?");
+ if (customProtocol != null) {
+ selection.append(" AND " + Im.CUSTOM_PROTOCOL + "=");
+ DatabaseUtils.appendEscapedSQLString(selection, customProtocol);
+ }
+
+ selectionArgs = new String[] { String.valueOf(protocol), handle };
}
if (values.containsKey(Presence.DATA_ID)) {
@@ -1564,12 +1594,6 @@
.append(values.getAsLong(Presence.DATA_ID));
}
- // TODO remove this capability
- if (values.containsKey(Presence.RAW_CONTACT_ID)) {
- selection.append(" AND " + DataColumns.CONCRETE_RAW_CONTACT_ID + "=")
- .append(values.getAsLong(Presence.RAW_CONTACT_ID));
- }
-
selection.append(" AND ").append(getContactsRestrictions());
long dataId = -1;
@@ -1595,7 +1619,7 @@
}
values.put(Presence.DATA_ID, dataId);
- values.put(Presence.RAW_CONTACT_ID, rawContactId);
+ values.put(PresenceColumns.RAW_CONTACT_ID, rawContactId);
// Insert the presence update
long presenceId = mDb.replace(Tables.PRESENCE, null, values);
diff --git a/src/com/android/providers/contacts/OpenHelper.java b/src/com/android/providers/contacts/OpenHelper.java
index e2ff79b..006a978 100644
--- a/src/com/android/providers/contacts/OpenHelper.java
+++ b/src/com/android/providers/contacts/OpenHelper.java
@@ -195,12 +195,6 @@
}
public interface Clauses {
- public static final String WHERE_IM_MATCHES = MimetypesColumns.MIMETYPE + "='"
- + Im.CONTENT_ITEM_TYPE + "' AND " + Im.PROTOCOL + "=? AND " + Im.DATA + "=?";
-
- public static final String WHERE_EMAIL_MATCHES = MimetypesColumns.MIMETYPE + "='"
- + Email.CONTENT_ITEM_TYPE + "' AND " + Email.DATA + "=?";
-
public static final String MIMETYPE_IS_GROUP_MEMBERSHIP = MimetypesColumns.CONCRETE_MIMETYPE
+ "='" + GroupMembership.CONTENT_ITEM_TYPE + "'";
@@ -382,6 +376,10 @@
public static final String CLUSTER = "cluster";
}
+ public interface PresenceColumns {
+ String RAW_CONTACT_ID = "presence_raw_contact_id";
+ }
+
public interface AggregatedPresenceColumns {
String CONTACT_ID = "presence_contact_id";
}
@@ -489,19 +487,20 @@
db.execSQL("ATTACH DATABASE ':memory:' AS " + DATABASE_PRESENCE + ";");
db.execSQL("CREATE TABLE IF NOT EXISTS " + DATABASE_PRESENCE + "." + Tables.PRESENCE + " ("+
Presence._ID + " INTEGER PRIMARY KEY," +
- Presence.RAW_CONTACT_ID + " INTEGER REFERENCES raw_contacts(_id)," +
+ PresenceColumns.RAW_CONTACT_ID + " INTEGER REFERENCES raw_contacts(_id)," +
Presence.DATA_ID + " INTEGER REFERENCES data(_id)," +
- Presence.IM_PROTOCOL + " TEXT," +
+ Presence.PROTOCOL + " INTEGER NOT NULL," +
+ Presence.CUSTOM_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 + ")" +
+ "UNIQUE(" + Presence.PROTOCOL + ", " + Presence.CUSTOM_PROTOCOL
+ + ", " + Presence.IM_HANDLE + ", " + Presence.IM_ACCOUNT + ")" +
");");
db.execSQL("CREATE INDEX IF NOT EXISTS " + DATABASE_PRESENCE + ".presenceIndex" + " ON "
- + Tables.PRESENCE + " (" + Presence.RAW_CONTACT_ID + ");");
+ + Tables.PRESENCE + " (" + PresenceColumns.RAW_CONTACT_ID + ");");
db.execSQL("CREATE TABLE IF NOT EXISTS "
+ DATABASE_PRESENCE + "." + Tables.AGGREGATED_PRESENCE + " ("+
diff --git a/tests/src/com/android/providers/contacts/BaseContactsProvider2Test.java b/tests/src/com/android/providers/contacts/BaseContactsProvider2Test.java
index 55e288c..02564bf 100644
--- a/tests/src/com/android/providers/contacts/BaseContactsProvider2Test.java
+++ b/tests/src/com/android/providers/contacts/BaseContactsProvider2Test.java
@@ -249,9 +249,11 @@
return mResolver.insert(Data.CONTENT_URI, values);
}
- protected Uri insertPresence(int protocol, String handle, int presence, String status) {
+ protected Uri insertPresence(int protocol, String customProtocol, String handle, int presence,
+ String status) {
ContentValues values = new ContentValues();
- values.put(Presence.IM_PROTOCOL, protocol);
+ values.put(Presence.PROTOCOL, protocol);
+ values.put(Presence.CUSTOM_PROTOCOL, customProtocol);
values.put(Presence.IM_HANDLE, handle);
values.put(Presence.PRESENCE_STATUS, presence);
values.put(Presence.PRESENCE_CUSTOM_STATUS, status);
@@ -260,11 +262,13 @@
return resultUri;
}
- protected Uri insertImHandle(long rawContactId, int protocol, String handle) {
+ protected Uri insertImHandle(long rawContactId, int protocol, String customProtocol,
+ String handle) {
ContentValues values = new ContentValues();
values.put(Data.RAW_CONTACT_ID, rawContactId);
values.put(Data.MIMETYPE, Im.CONTENT_ITEM_TYPE);
values.put(Im.PROTOCOL, protocol);
+ values.put(Im.CUSTOM_PROTOCOL, customProtocol);
values.put(Im.DATA, handle);
values.put(Im.TYPE, Im.TYPE_HOME);
diff --git a/tests/src/com/android/providers/contacts/ContactsProvider2Test.java b/tests/src/com/android/providers/contacts/ContactsProvider2Test.java
index a55b182..7a8ece0 100644
--- a/tests/src/com/android/providers/contacts/ContactsProvider2Test.java
+++ b/tests/src/com/android/providers/contacts/ContactsProvider2Test.java
@@ -16,13 +16,13 @@
package com.android.providers.contacts;
import com.android.internal.util.ArrayUtils;
+import com.android.providers.contacts.OpenHelper.PresenceColumns;
import android.content.ContentUris;
import android.content.ContentValues;
import android.content.Entity;
import android.content.EntityIterator;
import android.database.Cursor;
-import android.database.DatabaseUtils;
import android.net.Uri;
import android.os.RemoteException;
import android.provider.ContactsContract;
@@ -362,8 +362,10 @@
insertEmail(rawContactId, "goog411@acme.com");
insertEmail(rawContactId, "goog412@acme.com");
- insertPresence(Im.PROTOCOL_GOOGLE_TALK, "goog411@acme.com", Presence.INVISIBLE, "Bad");
- insertPresence(Im.PROTOCOL_GOOGLE_TALK, "goog412@acme.com", Presence.AVAILABLE, "Good");
+ insertPresence(Im.PROTOCOL_GOOGLE_TALK, null, "goog411@acme.com",
+ Presence.INVISIBLE, "Bad");
+ insertPresence(Im.PROTOCOL_GOOGLE_TALK, null, "goog412@acme.com",
+ Presence.AVAILABLE, "Good");
long contactId = queryContactId(rawContactId);
Uri uri = Uri.withAppendedPath(ContactsContract.AUTHORITY_URI, "data_with_presence");
@@ -511,16 +513,58 @@
assertSendToVoicemailAndRingtone(queryContactId(rawContactId2), false, "bar");
}
+ public void testInsertPresence() {
+ long rawContactId = createRawContact();
+ insertImHandle(rawContactId, Im.PROTOCOL_AIM, null, "aim");
+ insertImHandle(rawContactId, Im.PROTOCOL_CUSTOM, "my_im_proto", "my_im");
+ insertEmail(rawContactId, "acme123@acme.com");
+
+ // Match on IM (standard)
+ insertPresence(Im.PROTOCOL_AIM, null, "aim", Presence.AVAILABLE, "Available");
+
+ // Match on IM (custom)
+ insertPresence(Im.PROTOCOL_CUSTOM, "my_im_proto", "my_im", Presence.IDLE, "Idle");
+
+ // Match on Email
+ insertPresence(Im.PROTOCOL_GOOGLE_TALK, null, "acme123@acme.com", Presence.AWAY, "Away");
+
+ // No match
+ insertPresence(Im.PROTOCOL_ICQ, null, "12345", Presence.DO_NOT_DISTURB, "Go away");
+
+ Cursor c = mResolver.query(Presence.CONTENT_URI, new String[] {
+ Presence.DATA_ID, Presence.PROTOCOL, Presence.CUSTOM_PROTOCOL,
+ Presence.PRESENCE_STATUS, Presence.PRESENCE_CUSTOM_STATUS},
+ PresenceColumns.RAW_CONTACT_ID + "=" + rawContactId, null, Presence.DATA_ID);
+ assertTrue(c.moveToNext());
+ assertPresence(c, Im.PROTOCOL_AIM, null, Presence.AVAILABLE, "Available");
+ assertTrue(c.moveToNext());
+ assertPresence(c, Im.PROTOCOL_CUSTOM, "my_im_proto", Presence.IDLE, "Idle");
+ assertTrue(c.moveToNext());
+ assertPresence(c, Im.PROTOCOL_GOOGLE_TALK, null, Presence.AWAY, "Away");
+ assertFalse(c.moveToNext());
+ c.close();
+ }
+
+ private void assertPresence(Cursor c, int protocol, String customProtocol, int status,
+ String customStatus) {
+ ContentValues values = new ContentValues();
+ values.put(Presence.PROTOCOL, protocol);
+ values.put(Presence.CUSTOM_PROTOCOL, customProtocol);
+ values.put(Presence.PRESENCE_STATUS, status);
+ values.put(Presence.PRESENCE_CUSTOM_STATUS, customStatus);
+ assertCursorValues(c, values);
+ }
+
public void testSinglePresenceRowPerContact() {
int protocol1 = Im.PROTOCOL_GOOGLE_TALK;
String handle1 = "test@gmail.com";
long rawContactId1 = createRawContact();
- insertImHandle(rawContactId1, protocol1, handle1);
+ insertImHandle(rawContactId1, protocol1, null, handle1);
- insertPresence(protocol1, handle1, Presence.AVAILABLE, "Green");
- insertPresence(protocol1, handle1, Presence.AWAY, "Yellow");
- insertPresence(protocol1, handle1, Presence.INVISIBLE, "Red");
+ insertPresence(protocol1, null, handle1, Presence.AVAILABLE, "Green");
+ insertPresence(protocol1, null, handle1, Presence.AWAY, "Yellow");
+ insertPresence(protocol1, null, handle1, Presence.INVISIBLE, "Red");
Cursor c = queryContactSummary(queryContactId(rawContactId1),
new String[] {Presence.PRESENCE_STATUS, Presence.PRESENCE_CUSTOM_STATUS});
@@ -747,12 +791,12 @@
long rawContactId = createRawContact();
Uri uri = ContentUris.withAppendedId(RawContacts.CONTENT_URI, rawContactId);
- insertImHandle(rawContactId, Im.PROTOCOL_GOOGLE_TALK, "deleteme@android.com");
- insertPresence(Im.PROTOCOL_GOOGLE_TALK, "deleteme@android.com", Presence.AVAILABLE, null);
+ insertImHandle(rawContactId, Im.PROTOCOL_GOOGLE_TALK, null, "deleteme@android.com");
+ insertPresence(Im.PROTOCOL_GOOGLE_TALK, null, "deleteme@android.com", Presence.AVAILABLE, null);
assertEquals(1, getCount(Uri.withAppendedPath(uri, RawContacts.Data.CONTENT_DIRECTORY),
null, null));
- assertEquals(1, getCount(Presence.CONTENT_URI, Presence.RAW_CONTACT_ID + "=" + rawContactId,
- null));
+ assertEquals(1, getCount(Presence.CONTENT_URI, PresenceColumns.RAW_CONTACT_ID + "="
+ + rawContactId, null));
mResolver.delete(uri, null, null);
@@ -764,8 +808,8 @@
assertEquals(0, getCount(uri, null, null));
assertEquals(0, getCount(Uri.withAppendedPath(uri, RawContacts.Data.CONTENT_DIRECTORY),
null, null));
- assertEquals(0, getCount(Presence.CONTENT_URI, Presence.RAW_CONTACT_ID + "=" + rawContactId,
- null));
+ assertEquals(0, getCount(Presence.CONTENT_URI, PresenceColumns.RAW_CONTACT_ID + "="
+ + rawContactId, null));
}
public void testMarkAsDirtyParameter() {
@@ -881,7 +925,7 @@
insertPhoneNumber(rawContactId, phoneNumber);
insertEmail(rawContactId, email);
- insertPresence(Im.PROTOCOL_GOOGLE_TALK, email, presenceStatus, "hacking");
+ insertPresence(Im.PROTOCOL_GOOGLE_TALK, null, email, presenceStatus, "hacking");
if (groupId != 0) {
insertGroupMembership(rawContactId, groupId);