Merge "Shared state modified in two threads without synchronization"
diff --git a/testapps/TestRcsApp/TestApp/AndroidManifest.xml b/testapps/TestRcsApp/TestApp/AndroidManifest.xml
index 485d65e..52dd427 100644
--- a/testapps/TestRcsApp/TestApp/AndroidManifest.xml
+++ b/testapps/TestRcsApp/TestApp/AndroidManifest.xml
@@ -19,8 +19,8 @@
-->
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.google.android.sample.rcsclient"
- android:versionCode="10"
- android:versionName="1.0.9">
+ android:versionCode="11"
+ android:versionName="1.0.10">
<uses-sdk
android:minSdkVersion="30"
diff --git a/testapps/TestRcsApp/TestApp/src/com/google/android/sample/rcsclient/ChatActivity.java b/testapps/TestRcsApp/TestApp/src/com/google/android/sample/rcsclient/ChatActivity.java
index 8f7e6a8..40a108d 100644
--- a/testapps/TestRcsApp/TestApp/src/com/google/android/sample/rcsclient/ChatActivity.java
+++ b/testapps/TestRcsApp/TestApp/src/com/google/android/sample/rcsclient/ChatActivity.java
@@ -21,6 +21,7 @@
import android.database.Cursor;
import android.graphics.Color;
import android.graphics.Typeface;
+import android.net.Uri;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
@@ -41,6 +42,9 @@
import com.google.android.sample.rcsclient.util.ChatManager;
import com.google.android.sample.rcsclient.util.ChatProvider;
import com.google.android.sample.rcsclient.util.NumberUtils;
+import com.google.common.util.concurrent.FutureCallback;
+import com.google.common.util.concurrent.Futures;
+import com.google.common.util.concurrent.MoreExecutors;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
@@ -176,11 +180,8 @@
if (TextUtils.isEmpty(mDestNumber)) {
Log.i(TAG, "Destination number is empty");
} else {
- ChatManager.getInstance(getApplicationContext(), mSubId).addNewMessage(
- mNewMessage.getText().toString(), ChatManager.SELF, mDestNumber);
- ChatManager.getInstance(getApplicationContext(), mSubId).sendMessage(
- mDestNumber, mNewMessage.getText().toString());
- mHandler.sendMessage(mHandler.obtainMessage(EMPTY_MSG));
+ Log.i(TAG, "send message");
+ sendChatMessage();
}
});
});
@@ -192,6 +193,34 @@
}
}
+ private void sendChatMessage() {
+ Uri result = ChatManager.getInstance(getApplicationContext(), mSubId).addNewMessage(
+ mNewMessage.getText().toString(), ChatManager.SELF, mDestNumber);
+ String chatId = result.getPathSegments().get(1);
+ Futures.addCallback(
+ ChatManager.getInstance(getApplicationContext(),
+ mSubId).sendMessage(
+ mDestNumber,
+ mNewMessage.getText().toString()),
+ new FutureCallback<Void>() {
+ @Override
+ public void onSuccess(Void param) {
+ Log.i(TAG, "send chat msg successfully");
+ ChatManager.getInstance(getApplicationContext(), mSubId).updateMsgResult(
+ chatId, true);
+ }
+
+ @Override
+ public void onFailure(Throwable t) {
+ Log.i(TAG, "fail to send chat message:" + t);
+ ChatManager.getInstance(getApplicationContext(), mSubId).updateMsgResult(
+ chatId, false);
+ }
+ },
+ MoreExecutors.directExecutor());
+ mHandler.sendMessage(mHandler.obtainMessage(EMPTY_MSG));
+ }
+
private void initChatMessageLayout(Cursor cursor) {
Log.i(TAG, "initChatMessageLayout");
RelativeLayout rl = findViewById(R.id.relative_layout);
@@ -221,7 +250,8 @@
lp.setMargins(0, MARGIN_SIZE, 0, 0);
if (messageFromSelf(cursor)) {
lp.addRule(RelativeLayout.ALIGN_PARENT_RIGHT);
- chatMsg.setBackgroundColor(Color.YELLOW);
+ int result = cursor.getInt(cursor.getColumnIndex(ChatProvider.RcsColumns.RESULT));
+ chatMsg.setBackgroundColor(result == 1 ? Color.GREEN : Color.RED);
} else {
lp.addRule(RelativeLayout.ALIGN_PARENT_LEFT);
chatMsg.setBackgroundColor(Color.LTGRAY);
@@ -243,7 +273,8 @@
Cursor cursor = getContentResolver().query(ChatProvider.CHAT_URI,
new String[]{ChatProvider.RcsColumns.SRC_PHONE_NUMBER,
ChatProvider.RcsColumns.DEST_PHONE_NUMBER,
- ChatProvider.RcsColumns.CHAT_MESSAGE},
+ ChatProvider.RcsColumns.CHAT_MESSAGE,
+ ChatProvider.RcsColumns.RESULT},
ChatProvider.RcsColumns.SRC_PHONE_NUMBER + "=? OR "
+ ChatProvider.RcsColumns.DEST_PHONE_NUMBER + "=?",
new String[]{mDestNumber, mDestNumber},
diff --git a/testapps/TestRcsApp/TestApp/src/com/google/android/sample/rcsclient/util/ChatManager.java b/testapps/TestRcsApp/TestApp/src/com/google/android/sample/rcsclient/util/ChatManager.java
index 399a860..ed22f03 100644
--- a/testapps/TestRcsApp/TestApp/src/com/google/android/sample/rcsclient/util/ChatManager.java
+++ b/testapps/TestRcsApp/TestApp/src/com/google/android/sample/rcsclient/util/ChatManager.java
@@ -19,6 +19,7 @@
import android.content.ContentValues;
import android.content.Context;
import android.database.Cursor;
+import android.net.Uri;
import android.telephony.ims.ImsManager;
import android.text.TextUtils;
import android.util.Log;
@@ -36,6 +37,7 @@
import com.google.android.sample.rcsclient.SessionStateCallback;
import com.google.common.util.concurrent.FutureCallback;
import com.google.common.util.concurrent.Futures;
+import com.google.common.util.concurrent.ListenableFuture;
import com.google.common.util.concurrent.MoreExecutors;
import gov.nist.javax.sip.address.AddressFactoryImpl;
@@ -227,13 +229,14 @@
* @param contact destination phone number.
* @param message chat message.
*/
- public void sendMessage(String contact, String message) {
+ public ListenableFuture<Void> sendMessage(String contact, String message) {
SimpleChatSession chatSession = mContactSessionMap.get(contact);
if (chatSession == null) {
Log.i(TAG, "session is unavailable for contact = " + contact);
- return;
+ return Futures.immediateFailedFuture(
+ new IllegalStateException("Chat session does not exist"));
}
- chatSession.sendMessage(message);
+ return chatSession.sendMessage(message);
}
public boolean isRegistered() {
@@ -263,7 +266,7 @@
* @param src source phone number.
* @param dest destination phone number.
*/
- public void addNewMessage(String message, String src, String dest) {
+ public Uri addNewMessage(String message, String src, String dest) {
long currentTime = Instant.now().getEpochSecond();
ContentValues contentValues = new ContentValues();
contentValues.put(ChatProvider.RcsColumns.SRC_PHONE_NUMBER, src);
@@ -272,7 +275,7 @@
contentValues.put(ChatProvider.RcsColumns.MSG_TIMESTAMP, currentTime);
contentValues.put(ChatProvider.RcsColumns.IS_READ, Boolean.TRUE);
// insert chat table
- mContext.getContentResolver().insert(ChatProvider.CHAT_URI, contentValues);
+ Uri result = mContext.getContentResolver().insert(ChatProvider.CHAT_URI, contentValues);
ContentValues summary = new ContentValues();
summary.put(ChatProvider.SummaryColumns.LATEST_MESSAGE, message);
@@ -288,6 +291,17 @@
summary.put(ChatProvider.SummaryColumns.REMOTE_PHONE_NUMBER, remoteNumber);
mContext.getContentResolver().insert(ChatProvider.SUMMARY_URI, summary);
}
+ return result;
+ }
+
+ /**
+ * Update MSRP chat message sent result.
+ */
+ public void updateMsgResult(String id, boolean success) {
+ ContentValues contentValues = new ContentValues();
+ contentValues.put(ChatProvider.RcsColumns.RESULT, success);
+ mContext.getContentResolver().update(ChatProvider.CHAT_URI, contentValues,
+ ChatProvider.RcsColumns._ID + "=?", new String[]{id});
}
/**
diff --git a/testapps/TestRcsApp/TestApp/src/com/google/android/sample/rcsclient/util/ChatProvider.java b/testapps/TestRcsApp/TestApp/src/com/google/android/sample/rcsclient/util/ChatProvider.java
index 050da1f..98f3ceb 100644
--- a/testapps/TestRcsApp/TestApp/src/com/google/android/sample/rcsclient/util/ChatProvider.java
+++ b/testapps/TestRcsApp/TestApp/src/com/google/android/sample/rcsclient/util/ChatProvider.java
@@ -23,6 +23,7 @@
import android.database.Cursor;
import android.database.SQLException;
import android.database.sqlite.SQLiteDatabase;
+import android.database.sqlite.SQLiteException;
import android.database.sqlite.SQLiteOpenHelper;
import android.database.sqlite.SQLiteQueryBuilder;
import android.net.Uri;
@@ -36,7 +37,7 @@
public static final Uri SUMMARY_URI = Uri.parse("content://rcsprovider/summary");
public static final String AUTHORITY = "rcsprovider";
private static final String TAG = "TestRcsApp.ChatProvider";
- private static final int DATABASE_VERSION = 1;
+ private static final int DATABASE_VERSION = 2;
private static final String CHAT_TABLE_NAME = "chat";
private static final String SUMMARY_TABLE_NAME = "summary";
@@ -146,9 +147,9 @@
public static final String SRC_PHONE_NUMBER = "source_phone_number";
public static final String DEST_PHONE_NUMBER = "destination_phone_number";
public static final String CHAT_MESSAGE = "chat_message";
- public static final String SUBSCRIPTION_ID = "subscription_id";
public static final String MSG_TIMESTAMP = "msg_timestamp";
public static final String IS_READ = "is_read";
+ public static final String RESULT = "result";
}
/** Define columns for the summary table. */
@@ -169,7 +170,9 @@
+ RcsColumns.DEST_PHONE_NUMBER + " Text DEFAULT NULL, "
+ RcsColumns.CHAT_MESSAGE + " Text DEFAULT NULL, "
+ RcsColumns.MSG_TIMESTAMP + " LONG DEFAULT NULL, "
- + RcsColumns.IS_READ + " BOOLEAN DEFAULT false);";
+ + RcsColumns.IS_READ + " BOOLEAN DEFAULT false, "
+ + RcsColumns.RESULT + " BOOLEAN DEFAULT true);";
+
public static final String SQL_CREATE_SUMMARY_TABLE = "CREATE TABLE "
+ SUMMARY_TABLE_NAME
+ " ("
@@ -191,8 +194,32 @@
}
@Override
- public void onUpgrade(SQLiteDatabase sqLiteDatabase, int oldVersion, int newVersion) {
+ public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
Log.d(TAG, "DB upgrade from " + oldVersion + " to " + newVersion);
+ db.beginTransaction();
+ try {
+ switch (oldVersion) {
+ case 1:
+ upgradeDatabaseToVersion2(db);
+ break;
+ default: // fall out
+ }
+ db.setTransactionSuccessful();
+ } catch (Exception ex) {
+ Log.e(TAG, ex.getMessage(), ex);
+ } finally {
+ db.endTransaction();
+ }
+ }
+
+ private static void upgradeDatabaseToVersion2(SQLiteDatabase db) {
+ try {
+ Log.d(TAG, "upgradeDatabaseToVersion2");
+ String alterTable = "ALTER TABLE " + CHAT_TABLE_NAME + " ADD COLUMN ";
+ db.execSQL(alterTable + RcsColumns.RESULT + " BOOLEAN DEFAULT true");
+ } catch (SQLiteException e) {
+ Log.w(TAG, "[upgradeDatabaseToVersion10] Exception adding column: " + e);
+ }
}
}
}