Implement RcsParticipant (provider)
This change adds the tables, APIs and provider for RcsParticipants. It
is now possible to add/update/query participants.
Test: Added unit tests
Bug: 109759350
Change-Id: Ibe9af508aaf6c3747f3121a3a50247d08bdf25eb
diff --git a/src/com/android/providers/telephony/MmsSmsProvider.java b/src/com/android/providers/telephony/MmsSmsProvider.java
index 1653cd9..e2e9a1c 100644
--- a/src/com/android/providers/telephony/MmsSmsProvider.java
+++ b/src/com/android/providers/telephony/MmsSmsProvider.java
@@ -1272,10 +1272,15 @@
@Override
public Uri insert(Uri uri, ContentValues values) {
- if (URI_MATCHER.match(uri) == URI_PENDING_MSG) {
- SQLiteDatabase db = mOpenHelper.getWritableDatabase();
+ SQLiteDatabase db = mOpenHelper.getWritableDatabase();
+ int matchIndex = URI_MATCHER.match(uri);
+
+ if (matchIndex == URI_PENDING_MSG) {
long rowId = db.insert(TABLE_PENDING_MSG, null, values);
- return Uri.parse(uri + "/" + rowId);
+ return uri.buildUpon().appendPath(Long.toString(rowId)).build();
+ } else if (matchIndex == URI_CANONICAL_ADDRESS) {
+ long rowId = db.insert(TABLE_CANONICAL_ADDRESSES, null, values);
+ return uri.buildUpon().appendPath(Long.toString(rowId)).build();
}
throw new UnsupportedOperationException(NO_DELETES_INSERTS_OR_UPDATES + uri);
}
diff --git a/src/com/android/providers/telephony/RcsProvider.java b/src/com/android/providers/telephony/RcsProvider.java
index c0fffd0..af9212e 100644
--- a/src/com/android/providers/telephony/RcsProvider.java
+++ b/src/com/android/providers/telephony/RcsProvider.java
@@ -35,8 +35,12 @@
public class RcsProvider extends ContentProvider {
static final String TAG = "RcsProvider";
static final String AUTHORITY = "rcs";
- private static final UriMatcher URL_MATCHER = new UriMatcher(UriMatcher.NO_MATCH);
+ private static final Uri THREAD_URI_PREFIX = Uri.parse("content://" + AUTHORITY + "/thread");
+ private static final Uri PARTICIPANT_URI_PREFIX = Uri.parse(
+ "content://" + AUTHORITY + "/participant");
+
+ private static final UriMatcher URL_MATCHER = new UriMatcher(UriMatcher.NO_MATCH);
private static final int THREAD = 1;
private static final int PARTICIPANT = 2;
@@ -88,13 +92,20 @@
SQLiteDatabase writableDatabase = mDbOpenHelper.getWritableDatabase();
writableDatabase.beginTransaction();
+ Uri returnUri = null;
+ long rowId;
+
try {
switch (match) {
case THREAD:
- RcsProviderThreadHelper.insert(writableDatabase, values);
+ rowId = RcsProviderThreadHelper.insert(writableDatabase, values);
+ returnUri = THREAD_URI_PREFIX.buildUpon().appendPath(
+ Long.toString(rowId)).build();
break;
case PARTICIPANT:
- RcsProviderParticipantHelper.insert(writableDatabase, values);
+ rowId = RcsProviderParticipantHelper.insert(writableDatabase, values);
+ returnUri = PARTICIPANT_URI_PREFIX.buildUpon().appendPath(
+ Long.toString(rowId)).build();
break;
default:
Log.e(TAG, "Invalid insert: " + uri);
@@ -103,7 +114,7 @@
writableDatabase.endTransaction();
}
- return null;
+ return returnUri;
}
@Override
diff --git a/src/com/android/providers/telephony/RcsProviderParticipantHelper.java b/src/com/android/providers/telephony/RcsProviderParticipantHelper.java
index 913b8eb..d6ae4f7 100644
--- a/src/com/android/providers/telephony/RcsProviderParticipantHelper.java
+++ b/src/com/android/providers/telephony/RcsProviderParticipantHelper.java
@@ -15,15 +15,14 @@
*/
package com.android.providers.telephony;
-import static com.android.providers.telephony.RcsProvider.TAG;
+import static com.android.providers.telephony.RcsProviderThreadHelper.RCS_THREAD_ID_COLUMN;
+import static com.android.providers.telephony.RcsProviderThreadHelper.THREAD_TABLE;
+
import android.content.ContentValues;
-import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteQueryBuilder;
-import android.util.Log;
import com.android.internal.annotations.VisibleForTesting;
-import com.android.internal.telephony.ims.RcsMessageStoreController;
/**
* Constants and helpers related to participants for {@link RcsProvider} to keep the code clean.
@@ -36,10 +35,8 @@
static final String CANONICAL_ADDRESS_ID_COLUMN = "canonical_address_id";
static final String RCS_ALIAS_COLUMN = "rcs_alias";
- static final String CANONICAL_ADDRESSES_TABLE = "canonical_addresses";
- static final String ADDRESS_COLUMN = "address";
-
- private static final int NO_EXISTING_ADDRESS = Integer.MIN_VALUE;
+ static final String PARTICIPANT_THREAD_JUNCTION_TABLE = "rcs_thread_participant";
+ static final String RCS_PARTICIPANT_ID_COLUMN = "rcs_participant_id";
@VisibleForTesting
public static void createParticipantTables(SQLiteDatabase db) {
@@ -50,14 +47,26 @@
"FOREIGN KEY(" + CANONICAL_ADDRESS_ID_COLUMN + ") "
+ "REFERENCES canonical_addresses(address)" +
");");
+
+ db.execSQL("CREATE TABLE " + PARTICIPANT_THREAD_JUNCTION_TABLE + " (" +
+ RCS_THREAD_ID_COLUMN + " INTEGER, " +
+ RCS_PARTICIPANT_ID_COLUMN + " INTEGER, " +
+ "CONSTRAINT thread_participant PRIMARY KEY("
+ + RCS_THREAD_ID_COLUMN + ", " + RCS_PARTICIPANT_ID_COLUMN + "), " +
+ "FOREIGN KEY(" + RCS_THREAD_ID_COLUMN
+ + ") REFERENCES " + THREAD_TABLE + "(" + ID_COLUMN + "), " +
+ "FOREIGN KEY(" + RCS_PARTICIPANT_ID_COLUMN
+ + ") REFERENCES " + PARTICIPANT_TABLE + "(" + ID_COLUMN + "))");
}
static void buildParticipantsQuery(SQLiteQueryBuilder qb) {
qb.setTables(PARTICIPANT_TABLE);
}
- static void insert(SQLiteDatabase db, ContentValues values) {
- // TODO - implement
+ static long insert(SQLiteDatabase db, ContentValues values) {
+ long rowId = db.insert(PARTICIPANT_TABLE, ID_COLUMN, values);
+ db.setTransactionSuccessful();
+ return rowId;
}
static int delete(SQLiteDatabase db, String selection,
@@ -73,33 +82,4 @@
db.setTransactionSuccessful();
return updatedRows;
}
-
- private static int getCanonicalAddressId(SQLiteDatabase db, ContentValues values) {
- String address = values.getAsString(RcsMessageStoreController.PARTICIPANT_ADDRESS_KEY);
-
- // see if the address already exists
- // TODO(sahinc) - refine this to match phone number formats in canonical addresses, or find
- // TODO(sahinc) - another solution.
- Cursor existingCanonicalAddressAsCursor = db.query(CANONICAL_ADDRESSES_TABLE,
- new String[]{ID_COLUMN}, ADDRESS_COLUMN + "=" + address,
- null, null, null, null);
- long canonicalAddressId = NO_EXISTING_ADDRESS;
-
- if (existingCanonicalAddressAsCursor != null
- && existingCanonicalAddressAsCursor.moveToFirst()) {
- canonicalAddressId = existingCanonicalAddressAsCursor.getLong(0);
- existingCanonicalAddressAsCursor.close();
- }
-
- // If there is no existing canonical address, add one.
- if (canonicalAddressId == NO_EXISTING_ADDRESS) {
- canonicalAddressId = db.insert(CANONICAL_ADDRESSES_TABLE, ADDRESS_COLUMN, values);
- }
-
- if (canonicalAddressId == NO_EXISTING_ADDRESS) {
- Log.e(TAG, "Could not create an entry in canonical addresses");
- }
-
- return (int) canonicalAddressId;
- }
}
diff --git a/src/com/android/providers/telephony/RcsProviderThreadHelper.java b/src/com/android/providers/telephony/RcsProviderThreadHelper.java
index f993b2e..e643136 100644
--- a/src/com/android/providers/telephony/RcsProviderThreadHelper.java
+++ b/src/com/android/providers/telephony/RcsProviderThreadHelper.java
@@ -31,21 +31,48 @@
static final String THREAD_TABLE = "rcs_thread";
static final String OWNER_PARTICIPANT = "owner_participant";
+ static final String RCS_1_TO_1_THREAD_TABLE = "rcs_1_to_1_thread";
+ static final String RCS_THREAD_ID_COLUMN = "rcs_thread_id";
+ static final String FALLBACK_THREAD_ID_COLUMN = "rcs_fallback_thread_id";
+
+ static final String RCS_GROUP_THREAD_TABLE = "rcs_group_thread";
+ static final String GROUP_NAME_COLUMN = "group_name";
+ static final String ICON_COLUMN = "icon";
+ static final String CONFERENCE_URI_COLUMN = "conference_uri";
+
@VisibleForTesting
public static void createThreadTables(SQLiteDatabase db) {
db.execSQL("CREATE TABLE " + THREAD_TABLE + " (" +
ID_COLUMN + " INTEGER PRIMARY KEY AUTOINCREMENT, " +
OWNER_PARTICIPANT + " INTEGER " +
");");
+
+ db.execSQL("CREATE TABLE " + RCS_1_TO_1_THREAD_TABLE + " (" +
+ RCS_THREAD_ID_COLUMN + " INTEGER PRIMARY KEY, " +
+ FALLBACK_THREAD_ID_COLUMN + " INTEGER, " +
+ "FOREIGN KEY(" + RCS_THREAD_ID_COLUMN
+ + ") REFERENCES " + THREAD_TABLE + "(" + ID_COLUMN + ")," +
+ "FOREIGN KEY(" + FALLBACK_THREAD_ID_COLUMN
+ + ") REFERENCES threads( " + ID_COLUMN + "))" );
+
+ db.execSQL("CREATE TABLE " + RCS_GROUP_THREAD_TABLE + " (" +
+ RCS_THREAD_ID_COLUMN + " INTEGER PRIMARY KEY, " +
+ GROUP_NAME_COLUMN + " TEXT, " +
+ ICON_COLUMN + " TEXT, " +
+ CONFERENCE_URI_COLUMN + " TEXT, " +
+ "FOREIGN KEY(" + RCS_THREAD_ID_COLUMN
+ + ") REFERENCES " + THREAD_TABLE + "(" + ID_COLUMN + "))" );
+
}
static void buildThreadQuery(SQLiteQueryBuilder qb) {
qb.setTables(THREAD_TABLE);
}
- static void insert(SQLiteDatabase db, ContentValues values) {
- db.insert(THREAD_TABLE, OWNER_PARTICIPANT, values);
+ static long insert(SQLiteDatabase db, ContentValues values) {
+ long rowId = db.insert(THREAD_TABLE, OWNER_PARTICIPANT, values);
db.setTransactionSuccessful();
+ return rowId;
}
static int delete(SQLiteDatabase db, String selection, String[] selectionArgs) {
diff --git a/tests/src/com/android/providers/telephony/RcsProviderTest.java b/tests/src/com/android/providers/telephony/RcsProviderTest.java
index 2417f51..4074e77 100644
--- a/tests/src/com/android/providers/telephony/RcsProviderTest.java
+++ b/tests/src/com/android/providers/telephony/RcsProviderTest.java
@@ -15,6 +15,10 @@
*/
package com.android.providers.telephony;
+import static com.android.providers.telephony.RcsProviderParticipantHelper.CANONICAL_ADDRESS_ID_COLUMN;
+import static com.android.providers.telephony.RcsProviderParticipantHelper.RCS_ALIAS_COLUMN;
+import static com.android.providers.telephony.RcsProviderThreadHelper.OWNER_PARTICIPANT;
+
import static com.google.common.truth.Truth.assertThat;
import android.app.AppOpsManager;
@@ -48,19 +52,19 @@
@Test
public void testInsertThread() {
ContentValues contentValues = new ContentValues();
- contentValues.put(RcsProviderThreadHelper.OWNER_PARTICIPANT, 5);
+ contentValues.put(OWNER_PARTICIPANT, 5);
Uri uri = mContentResolver.insert(Uri.parse("content://rcs/thread"), contentValues);
- assertThat(uri).isNull();
+ assertThat(uri).isEqualTo(Uri.parse("content://rcs/thread/1"));
}
@Test
public void testUpdateThread() {
ContentValues contentValues = new ContentValues();
- contentValues.put(RcsProviderThreadHelper.OWNER_PARTICIPANT, 5);
+ contentValues.put(OWNER_PARTICIPANT, 5);
mContentResolver.insert(Uri.parse("content://rcs/thread"), contentValues);
- contentValues.put(RcsProviderThreadHelper.OWNER_PARTICIPANT, 12);
+ contentValues.put(OWNER_PARTICIPANT, 12);
int updateCount = mContentResolver.update(Uri.parse("content://rcs/thread"),
contentValues, "owner_participant=5", null);
@@ -72,10 +76,10 @@
// insert two threads
ContentValues contentValues = new ContentValues();
Uri threadsUri = Uri.parse("content://rcs/thread");
- contentValues.put(RcsProviderThreadHelper.OWNER_PARTICIPANT, 7);
+ contentValues.put(OWNER_PARTICIPANT, 7);
mContentResolver.insert(threadsUri, contentValues);
- contentValues.put(RcsProviderThreadHelper.OWNER_PARTICIPANT, 13);
+ contentValues.put(OWNER_PARTICIPANT, 13);
mContentResolver.insert(threadsUri, contentValues);
//verify two threads are inserted
@@ -83,6 +87,58 @@
assertThat(cursor.getCount()).isEqualTo(2);
}
+ @Test
+ public void testInsertParticipant() {
+ ContentValues contentValues = new ContentValues();
+ contentValues.put(CANONICAL_ADDRESS_ID_COLUMN, 6);
+ contentValues.put(RCS_ALIAS_COLUMN, "Alias");
+
+ Uri uri = mContentResolver.insert(Uri.parse("content://rcs/participant"), contentValues);
+ assertThat(uri).isEqualTo(Uri.parse("content://rcs/participant/1"));
+ }
+
+ @Test
+ public void testUpdateParticipant() {
+ // insert a participant
+ Uri participantUri = Uri.parse("content://rcs/participant");
+ ContentValues contentValues = new ContentValues();
+ contentValues.put(CANONICAL_ADDRESS_ID_COLUMN, 11);
+ contentValues.put(RCS_ALIAS_COLUMN, "Alias 1");
+
+ mContentResolver.insert(participantUri, contentValues);
+
+ // update the participant
+ contentValues.clear();
+ contentValues.put(RCS_ALIAS_COLUMN, "Alias 2");
+
+ int updatedRowCount = mContentResolver.update(participantUri, contentValues, "rcs_alias=?",
+ new String[]{"Alias 1"});
+ assertThat(updatedRowCount).isEqualTo(1);
+
+ // verify participant is actually updated
+ Cursor cursor = mContentResolver.query(participantUri, new String[]{RCS_ALIAS_COLUMN},
+ "rcs_alias=?", new String[]{"Alias 2"}, null);
+ cursor.moveToNext();
+ assertThat(cursor.getString(0)).isEqualTo("Alias 2");
+ }
+
+ @Test
+ public void testQueryParticipant() {
+ // insert a participant
+ Uri participantUri = Uri.parse("content://rcs/participant");
+ ContentValues contentValues = new ContentValues();
+ contentValues.put(CANONICAL_ADDRESS_ID_COLUMN, 99);
+ contentValues.put(RCS_ALIAS_COLUMN, "Some alias");
+
+ mContentResolver.insert(participantUri, contentValues);
+
+ // Query the participant back
+ Cursor cursor = mContentResolver.query(Uri.parse("content://rcs/participant"),
+ new String[]{RCS_ALIAS_COLUMN}, null, null, null);
+ cursor.moveToNext();
+ assertThat(cursor.getString(0)).isEqualTo("Some alias");
+ }
+
class MockContextWithProvider extends MockContext {
private final MockContentResolver mResolver;
diff --git a/tests/src/com/android/providers/telephony/RcsProviderTestable.java b/tests/src/com/android/providers/telephony/RcsProviderTestable.java
index 64ae3ef..397d656 100644
--- a/tests/src/com/android/providers/telephony/RcsProviderTestable.java
+++ b/tests/src/com/android/providers/telephony/RcsProviderTestable.java
@@ -31,7 +31,7 @@
static class InMemoryRcsDatabase extends SQLiteOpenHelper {
InMemoryRcsDatabase() {
- super(null, // no context is needed for in-memory db
+ super(null, // no context is needed for in-memory db
null, // db file name is null for in-memory db
null, // CursorFactory is null by default
1); // db version is no-op for tests
@@ -40,6 +40,7 @@
@Override
public void onCreate(SQLiteDatabase db) {
RcsProviderThreadHelper.createThreadTables(db);
+ RcsProviderParticipantHelper.createParticipantTables(db);
}
@Override