Implement RcsThread querying (provider)
This change does a first pass to introduce RcsThread querying. We can
now insert threads and query them back.
Test: Added unit test
Bug: 109759350
Change-Id: I73e134e8c869f255b179cd2c87d8cb013fb19a36
diff --git a/src/com/android/providers/telephony/MmsSmsDatabaseHelper.java b/src/com/android/providers/telephony/MmsSmsDatabaseHelper.java
index f7a446b..feac8f4 100644
--- a/src/com/android/providers/telephony/MmsSmsDatabaseHelper.java
+++ b/src/com/android/providers/telephony/MmsSmsDatabaseHelper.java
@@ -552,7 +552,8 @@
createCommonTables(db);
if (IS_RCS_TABLE_SCHEMA_CODE_COMPLETE) {
- RcsProviderHelper.createRcsTables(db);
+ RcsProviderThreadHelper.createThreadTables(db);
+ RcsProviderParticipantHelper.createParticipantTables(db);
}
createCommonTriggers(db);
@@ -1640,7 +1641,8 @@
if (currentVersion <= 67 || !IS_RCS_TABLE_SCHEMA_CODE_COMPLETE) {
return;
}
- RcsProviderHelper.createRcsTables(db);
+ RcsProviderThreadHelper.createThreadTables(db);
+ RcsProviderParticipantHelper.createParticipantTables(db);
return;
}
diff --git a/src/com/android/providers/telephony/RcsProvider.java b/src/com/android/providers/telephony/RcsProvider.java
index 83ff130..c0fffd0 100644
--- a/src/com/android/providers/telephony/RcsProvider.java
+++ b/src/com/android/providers/telephony/RcsProvider.java
@@ -15,9 +15,6 @@
*/
package com.android.providers.telephony;
-import static com.android.providers.telephony.RcsProviderHelper.ID;
-import static com.android.providers.telephony.RcsProviderHelper.THREAD_TABLE;
-
import android.app.AppOpsManager;
import android.content.ContentProvider;
import android.content.ContentValues;
@@ -32,19 +29,22 @@
/**
* Content provider to handle RCS messages. The functionality here is similar to SmsProvider,
* MmsProvider etc. This is not meant to be public.
+ *
* @hide
*/
public class RcsProvider extends ContentProvider {
- private final static String TAG = "RcsProvider";
+ static final String TAG = "RcsProvider";
static final String AUTHORITY = "rcs";
private static final UriMatcher URL_MATCHER = new UriMatcher(UriMatcher.NO_MATCH);
private static final int THREAD = 1;
+ private static final int PARTICIPANT = 2;
SQLiteOpenHelper mDbOpenHelper;
static {
URL_MATCHER.addURI(AUTHORITY, "thread", THREAD);
+ URL_MATCHER.addURI(AUTHORITY, "participant", PARTICIPANT);
}
@Override
@@ -64,7 +64,10 @@
switch (match) {
case THREAD:
- RcsProviderHelper.buildThreadQuery(qb);
+ RcsProviderThreadHelper.buildThreadQuery(qb);
+ break;
+ case PARTICIPANT:
+ RcsProviderParticipantHelper.buildParticipantsQuery(qb);
break;
default:
Log.e(TAG, "Invalid query: " + uri);
@@ -83,13 +86,21 @@
public Uri insert(Uri uri, ContentValues values) {
int match = URL_MATCHER.match(uri);
SQLiteDatabase writableDatabase = mDbOpenHelper.getWritableDatabase();
+ writableDatabase.beginTransaction();
- switch (match) {
- case THREAD:
- writableDatabase.insert(THREAD_TABLE, ID, values);
- break;
- default:
- Log.e(TAG, "Invalid insert: " + uri);
+ try {
+ switch (match) {
+ case THREAD:
+ RcsProviderThreadHelper.insert(writableDatabase, values);
+ break;
+ case PARTICIPANT:
+ RcsProviderParticipantHelper.insert(writableDatabase, values);
+ break;
+ default:
+ Log.e(TAG, "Invalid insert: " + uri);
+ }
+ } finally {
+ writableDatabase.endTransaction();
}
return null;
@@ -100,13 +111,23 @@
int match = URL_MATCHER.match(uri);
int deletedCount = 0;
SQLiteDatabase writableDatabase = mDbOpenHelper.getWritableDatabase();
+ writableDatabase.beginTransaction();
- switch (match) {
- case THREAD:
- deletedCount = writableDatabase.delete(THREAD_TABLE, selection, selectionArgs);
- break;
- default:
- Log.e(TAG, "Invalid delete: " + uri);
+ try {
+ switch (match) {
+ case THREAD:
+ deletedCount = RcsProviderThreadHelper.delete(writableDatabase, selection,
+ selectionArgs);
+ break;
+ case PARTICIPANT:
+ deletedCount = RcsProviderParticipantHelper.delete(writableDatabase, selection,
+ selectionArgs);
+ break;
+ default:
+ Log.e(TAG, "Invalid delete: " + uri);
+ }
+ } finally {
+ writableDatabase.endTransaction();
}
return deletedCount;
@@ -118,15 +139,23 @@
int updatedCount = 0;
SQLiteDatabase writableDatabase = mDbOpenHelper.getWritableDatabase();
- switch (match) {
- case THREAD:
- updatedCount = writableDatabase.update(
- THREAD_TABLE, values, selection, selectionArgs);
- break;
- default:
- Log.e(TAG, "Invalid update: " + uri);
+ writableDatabase.beginTransaction();
+ try {
+ switch (match) {
+ case THREAD:
+ updatedCount = RcsProviderThreadHelper.update(
+ writableDatabase, values, selection, selectionArgs);
+ break;
+ case PARTICIPANT:
+ updatedCount = RcsProviderParticipantHelper.update(
+ writableDatabase, values, selection, selectionArgs);
+ break;
+ default:
+ Log.e(TAG, "Invalid update: " + uri);
+ }
+ } finally {
+ writableDatabase.endTransaction();
}
-
return updatedCount;
}
}
diff --git a/src/com/android/providers/telephony/RcsProviderHelper.java b/src/com/android/providers/telephony/RcsProviderHelper.java
deleted file mode 100644
index 3966f53..0000000
--- a/src/com/android/providers/telephony/RcsProviderHelper.java
+++ /dev/null
@@ -1,43 +0,0 @@
-/*
- * Copyright (C) 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package com.android.providers.telephony;
-
-import android.database.sqlite.SQLiteDatabase;
-import android.database.sqlite.SQLiteQueryBuilder;
-
-import com.android.internal.annotations.VisibleForTesting;
-
-/**
- * Constants and helpers for RcsProvider to keep the code clean.
- * @hide
- */
-class RcsProviderHelper {
- static final String ID = "_id";
- static final String THREAD_TABLE = "rcs_thread";
- static final String OWNER_PARTICIPANT = "owner_participant";
-
- @VisibleForTesting
- public static void createRcsTables(SQLiteDatabase db) {
- db.execSQL("CREATE TABLE " + THREAD_TABLE + " (" +
- ID + " INTEGER PRIMARY KEY AUTOINCREMENT, " +
- OWNER_PARTICIPANT + " INTEGER " +
- ");");
- }
-
- static void buildThreadQuery(SQLiteQueryBuilder qb) {
- qb.setTables(THREAD_TABLE);
- }
-}
diff --git a/src/com/android/providers/telephony/RcsProviderParticipantHelper.java b/src/com/android/providers/telephony/RcsProviderParticipantHelper.java
new file mode 100644
index 0000000..913b8eb
--- /dev/null
+++ b/src/com/android/providers/telephony/RcsProviderParticipantHelper.java
@@ -0,0 +1,105 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.providers.telephony;
+
+import static com.android.providers.telephony.RcsProvider.TAG;
+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.
+ *
+ * @hide
+ */
+public class RcsProviderParticipantHelper {
+ static final String ID_COLUMN = "_id";
+ static final String PARTICIPANT_TABLE = "rcs_participant";
+ 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;
+
+ @VisibleForTesting
+ public static void createParticipantTables(SQLiteDatabase db) {
+ db.execSQL("CREATE TABLE " + PARTICIPANT_TABLE + " (" +
+ ID_COLUMN + " INTEGER PRIMARY KEY AUTOINCREMENT, " +
+ CANONICAL_ADDRESS_ID_COLUMN + " INTEGER ," +
+ RCS_ALIAS_COLUMN + " TEXT, " +
+ "FOREIGN KEY(" + CANONICAL_ADDRESS_ID_COLUMN + ") "
+ + "REFERENCES canonical_addresses(address)" +
+ ");");
+ }
+
+ static void buildParticipantsQuery(SQLiteQueryBuilder qb) {
+ qb.setTables(PARTICIPANT_TABLE);
+ }
+
+ static void insert(SQLiteDatabase db, ContentValues values) {
+ // TODO - implement
+ }
+
+ static int delete(SQLiteDatabase db, String selection,
+ String[] selectionArgs) {
+ int deletedRows = db.delete(PARTICIPANT_TABLE, selection, selectionArgs);
+ db.setTransactionSuccessful();
+ return deletedRows;
+ }
+
+ static int update(SQLiteDatabase db, ContentValues values,
+ String selection, String[] selectionArgs) {
+ int updatedRows = db.update(PARTICIPANT_TABLE, values, selection, selectionArgs);
+ 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
new file mode 100644
index 0000000..f993b2e
--- /dev/null
+++ b/src/com/android/providers/telephony/RcsProviderThreadHelper.java
@@ -0,0 +1,63 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.providers.telephony;
+
+import android.content.ContentValues;
+import android.database.sqlite.SQLiteDatabase;
+import android.database.sqlite.SQLiteQueryBuilder;
+
+import com.android.internal.annotations.VisibleForTesting;
+
+/**
+ * Constants and helpers related to threads for {@link RcsProvider} to keep the code clean.
+ *
+ * @hide
+ */
+class RcsProviderThreadHelper {
+ static final String ID_COLUMN = "_id";
+ static final String THREAD_TABLE = "rcs_thread";
+ static final String OWNER_PARTICIPANT = "owner_participant";
+
+ @VisibleForTesting
+ public static void createThreadTables(SQLiteDatabase db) {
+ db.execSQL("CREATE TABLE " + THREAD_TABLE + " (" +
+ ID_COLUMN + " INTEGER PRIMARY KEY AUTOINCREMENT, " +
+ OWNER_PARTICIPANT + " INTEGER " +
+ ");");
+ }
+
+ static void buildThreadQuery(SQLiteQueryBuilder qb) {
+ qb.setTables(THREAD_TABLE);
+ }
+
+ static void insert(SQLiteDatabase db, ContentValues values) {
+ db.insert(THREAD_TABLE, OWNER_PARTICIPANT, values);
+ db.setTransactionSuccessful();
+ }
+
+ static int delete(SQLiteDatabase db, String selection, String[] selectionArgs) {
+ int deletedRowCount = db.delete(THREAD_TABLE, selection, selectionArgs);
+ db.setTransactionSuccessful();
+ return deletedRowCount;
+ }
+
+ static int update(SQLiteDatabase db, ContentValues values, String selection,
+ String[] selectionArgs) {
+ int updatedRowCount = db.update(THREAD_TABLE, values, selection, selectionArgs);
+ db.setTransactionSuccessful();
+ return updatedRowCount;
+ }
+}
diff --git a/tests/Android.mk b/tests/Android.mk
index 14f528f..3505c29 100644
--- a/tests/Android.mk
+++ b/tests/Android.mk
@@ -5,7 +5,8 @@
LOCAL_STATIC_JAVA_LIBRARIES := mockito-target \
compatibility-device-util \
- android-support-test
+ android-support-test \
+ truth-prebuilt
LOCAL_JAVA_LIBRARIES := \
android.test.runner \
diff --git a/tests/src/com/android/providers/telephony/RcsProviderTest.java b/tests/src/com/android/providers/telephony/RcsProviderTest.java
index 708078f..2417f51 100644
--- a/tests/src/com/android/providers/telephony/RcsProviderTest.java
+++ b/tests/src/com/android/providers/telephony/RcsProviderTest.java
@@ -15,13 +15,13 @@
*/
package com.android.providers.telephony;
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNull;
+import static com.google.common.truth.Truth.assertThat;
import android.app.AppOpsManager;
import android.content.ContentValues;
import android.content.Context;
import android.content.pm.ProviderInfo;
+import android.database.Cursor;
import android.net.Uri;
import android.telephony.TelephonyManager;
import android.test.mock.MockContentResolver;
@@ -30,12 +30,14 @@
import org.junit.Before;
import org.junit.Test;
import org.mockito.Mockito;
+import org.mockito.MockitoAnnotations;
public class RcsProviderTest {
private MockContentResolver mContentResolver;
@Before
public void setUp() {
+ MockitoAnnotations.initMocks(this);
RcsProvider rcsProvider = new RcsProviderTestable();
MockContextWithProvider context = new MockContextWithProvider(rcsProvider);
mContentResolver = context.getContentResolver();
@@ -46,23 +48,39 @@
@Test
public void testInsertThread() {
ContentValues contentValues = new ContentValues();
- contentValues.put(RcsProviderHelper.OWNER_PARTICIPANT, 5);
+ contentValues.put(RcsProviderThreadHelper.OWNER_PARTICIPANT, 5);
Uri uri = mContentResolver.insert(Uri.parse("content://rcs/thread"), contentValues);
- assertNull(uri);
+ assertThat(uri).isNull();
}
@Test
public void testUpdateThread() {
ContentValues contentValues = new ContentValues();
- contentValues.put(RcsProviderHelper.OWNER_PARTICIPANT, 5);
+ contentValues.put(RcsProviderThreadHelper.OWNER_PARTICIPANT, 5);
mContentResolver.insert(Uri.parse("content://rcs/thread"), contentValues);
- contentValues.put(RcsProviderHelper.OWNER_PARTICIPANT, 12);
+ contentValues.put(RcsProviderThreadHelper.OWNER_PARTICIPANT, 12);
int updateCount = mContentResolver.update(Uri.parse("content://rcs/thread"),
contentValues, "owner_participant=5", null);
- assertEquals(1, updateCount);
+ assertThat(updateCount).isEqualTo(1);
+ }
+
+ @Test
+ public void testCanQueryAllThreads() {
+ // insert two threads
+ ContentValues contentValues = new ContentValues();
+ Uri threadsUri = Uri.parse("content://rcs/thread");
+ contentValues.put(RcsProviderThreadHelper.OWNER_PARTICIPANT, 7);
+ mContentResolver.insert(threadsUri, contentValues);
+
+ contentValues.put(RcsProviderThreadHelper.OWNER_PARTICIPANT, 13);
+ mContentResolver.insert(threadsUri, contentValues);
+
+ //verify two threads are inserted
+ Cursor cursor = mContentResolver.query(threadsUri, null, null, null, null);
+ assertThat(cursor.getCount()).isEqualTo(2);
}
class MockContextWithProvider extends MockContext {
@@ -95,5 +113,4 @@
}
}
}
-
}
diff --git a/tests/src/com/android/providers/telephony/RcsProviderTestable.java b/tests/src/com/android/providers/telephony/RcsProviderTestable.java
index 1e4da11..64ae3ef 100644
--- a/tests/src/com/android/providers/telephony/RcsProviderTestable.java
+++ b/tests/src/com/android/providers/telephony/RcsProviderTestable.java
@@ -39,7 +39,7 @@
@Override
public void onCreate(SQLiteDatabase db) {
- RcsProviderHelper.createRcsTables(db);
+ RcsProviderThreadHelper.createThreadTables(db);
}
@Override