Integrate in cl/356241895 into testRcsApp
Add support for incoming MSRP sessions using code in cl/356241895
Fixes: 178469888
Test: manual
Change-Id: I4e39964e7577c566d19f28aa60b8015e4a867d7a
diff --git a/testapps/TestRcsApp/TestApp/AndroidManifest.xml b/testapps/TestRcsApp/TestApp/AndroidManifest.xml
index 6e52949..d57ec94 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="3"
- android:versionName="1.0.2_UP1.0">
+ android:versionCode="4"
+ android:versionName="1.0.3">
<uses-sdk
android:minSdkVersion="30"
diff --git a/testapps/TestRcsApp/aosp_test_rcsclient/javatests/com/android/libraries/rcs/simpleclient/protocol/cpim/SimpleCpimMessageTest.java b/testapps/TestRcsApp/aosp_test_rcsclient/javatests/com/android/libraries/rcs/simpleclient/protocol/cpim/SimpleCpimMessageTest.java
new file mode 100644
index 0000000..2dda33f
--- /dev/null
+++ b/testapps/TestRcsApp/aosp_test_rcsclient/javatests/com/android/libraries/rcs/simpleclient/protocol/cpim/SimpleCpimMessageTest.java
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) 2021 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.libraries.rcs.simpleclient.protocol.cpim;
+
+import static com.google.common.truth.Truth.assertThat;
+import static java.nio.charset.StandardCharsets.UTF_8;
+
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@RunWith(AndroidJUnit4.class)
+public class SimpleCpimMessageTest {
+ private static final String SAMPLE_CPIM =
+ "From: MR SANDERS <im:[email protected]>\r\n"
+ + "To: Depressed Donkey <im:[email protected]>\r\n"
+ + "DateTime: 2000-12-13T13:40:00-08:00\r\n"
+ + "Subject: the weather will be fine today\r\n"
+ + "Subject:;lang=fr beau temps prevu pour aujourd'hui\r\n"
+ + "NS: MyFeatures <mid:[email protected]>\r\n"
+ + "Require: MyFeatures.VitalMessageOption\r\n"
+ + "MyFeatures.VitalMessageOption: Confirmation-requested\r\n"
+ + "MyFeatures.WackyMessageOption: Use-silly-font\r\n"
+ + "\r\n"
+ + "Content-type: text/plain; charset=utf-8\r\n"
+ + "Content-ID: <[email protected]>\r\n"
+ + "\r\n"
+ + "body";
+
+ @Test
+ public void parse_successful() throws Exception {
+ SimpleCpimMessage cpim = SimpleCpimMessage.parse(SAMPLE_CPIM.getBytes(UTF_8));
+
+ assertThat(cpim.namespaces()).containsEntry("MyFeatures", "mid:[email protected]");
+ assertThat(cpim.headers()).containsEntry("Require", "MyFeatures.VitalMessageOption");
+ assertThat(cpim.contentType()).isEqualTo("text/plain; charset=utf-8");
+ assertThat(cpim.content()).isEqualTo("body");
+ }
+}
diff --git a/testapps/TestRcsApp/aosp_test_rcsclient/src/com/android/libraries/rcs/simpleclient/protocol/cpim/SimpleCpimMessage.java b/testapps/TestRcsApp/aosp_test_rcsclient/src/com/android/libraries/rcs/simpleclient/protocol/cpim/SimpleCpimMessage.java
index aeb6b11..ad5f1f5 100644
--- a/testapps/TestRcsApp/aosp_test_rcsclient/src/com/android/libraries/rcs/simpleclient/protocol/cpim/SimpleCpimMessage.java
+++ b/testapps/TestRcsApp/aosp_test_rcsclient/src/com/android/libraries/rcs/simpleclient/protocol/cpim/SimpleCpimMessage.java
@@ -16,11 +16,19 @@
package com.android.libraries.rcs.simpleclient.protocol.cpim;
+import android.text.TextUtils;
import com.google.auto.value.AutoValue;
+import com.google.common.base.Ascii;
import com.google.common.base.Utf8;
import com.google.common.collect.ImmutableMap;
-
+import com.google.common.io.CharStreams;
+import java.io.BufferedReader;
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.io.InputStreamReader;
import java.util.Map;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
/**
* The CPIM implementation as per RFC 3862. This class supports minimal fields that is required to
@@ -30,10 +38,9 @@
public abstract class SimpleCpimMessage {
private static final String CRLF = "\r\n";
private static final String COLSP = ": ";
-
- public static SimpleCpimMessage.Builder newBuilder() {
- return new AutoValue_SimpleCpimMessage.Builder();
- }
+ private static final Pattern NAMESPACE_HEADER_PATTERN =
+ Pattern.compile("NS:\\s+(\\S+)\\s+<(.+)>");
+ private static final Pattern HEADER_PATTERN = Pattern.compile("([^\\s:]+):\\s+(.+)");
public abstract ImmutableMap<String, String> namespaces();
@@ -68,6 +75,42 @@
return builder.toString();
}
+ public static SimpleCpimMessage parse(byte[] content) throws IOException {
+ BufferedReader reader =
+ new BufferedReader(new InputStreamReader(new ByteArrayInputStream(content)));
+ Builder builder = newBuilder();
+
+ String line = reader.readLine();
+ while (!TextUtils.isEmpty(line)) {
+ Matcher namespaceMatcher = NAMESPACE_HEADER_PATTERN.matcher(line);
+ Matcher headerMatcher = HEADER_PATTERN.matcher(line);
+ if (namespaceMatcher.matches()) {
+ builder.addNamespace(namespaceMatcher.group(1), namespaceMatcher.group(2));
+ } else if (headerMatcher.matches()) {
+ builder.addHeader(headerMatcher.group(1), headerMatcher.group(2));
+ }
+
+ line = reader.readLine();
+ }
+
+ line = reader.readLine();
+ while (!TextUtils.isEmpty(line)) {
+ Matcher headerMatcher = HEADER_PATTERN.matcher(line);
+ if (headerMatcher.matches()) {
+ if (Ascii.equalsIgnoreCase("content-type", headerMatcher.group(1))) {
+ builder.setContentType(headerMatcher.group(2));
+ }
+ }
+
+ line = reader.readLine();
+ }
+
+ String body = CharStreams.toString(reader);
+ builder.setContent(body);
+
+ return builder.build();
+ }
+
@AutoValue.Builder
public abstract static class Builder {
public abstract ImmutableMap.Builder<String, String> namespacesBuilder();
@@ -90,4 +133,8 @@
return this;
}
}
+
+ public static SimpleCpimMessage.Builder newBuilder() {
+ return new AutoValue_SimpleCpimMessage.Builder();
+ }
}
diff --git a/testapps/TestRcsApp/aosp_test_rcsclient/src/com/android/libraries/rcs/simpleclient/service/chat/SimpleChatSession.java b/testapps/TestRcsApp/aosp_test_rcsclient/src/com/android/libraries/rcs/simpleclient/service/chat/SimpleChatSession.java
index 74472d7..29c5176 100644
--- a/testapps/TestRcsApp/aosp_test_rcsclient/src/com/android/libraries/rcs/simpleclient/service/chat/SimpleChatSession.java
+++ b/testapps/TestRcsApp/aosp_test_rcsclient/src/com/android/libraries/rcs/simpleclient/service/chat/SimpleChatSession.java
@@ -31,6 +31,7 @@
import com.android.libraries.rcs.simpleclient.protocol.cpim.SimpleCpimMessage;
import com.android.libraries.rcs.simpleclient.protocol.msrp.MsrpChunk;
import com.android.libraries.rcs.simpleclient.protocol.msrp.MsrpChunk.Continuation;
+import com.android.libraries.rcs.simpleclient.protocol.msrp.MsrpChunkHeader;
import com.android.libraries.rcs.simpleclient.protocol.msrp.MsrpConstants;
import com.android.libraries.rcs.simpleclient.protocol.msrp.MsrpManager;
import com.android.libraries.rcs.simpleclient.protocol.msrp.MsrpSession;
@@ -408,11 +409,29 @@
private void receiveMsrpChunk(MsrpChunk chunk) {
Log.d(TAG, "Received msrp= " + chunk + " conversation=" + mConversationId);
- if (mListener != null) {
- // TODO(b/173186571): Parse CPIM and invoke onMessageReceived()
+
+ MsrpChunkHeader contentTypeHeader = chunk.header("Content-Type");
+ if (chunk.content().length == 0 || contentTypeHeader == null) {
+ Log.i(TAG, "No content or Content-Type header, drop it");
+ return;
+ }
+
+ String contentType = contentTypeHeader.value();
+ if ("message/cpim".equals(contentType)) {
+ try {
+ SimpleCpimMessage cpim = SimpleCpimMessage.parse(chunk.content());
+ if (mListener != null) {
+ mListener.onMessageReceived(cpim);
+ }
+ } catch (Exception e) {
+ Log.e(TAG, "Error while parsing cpim message.", e);
+ }
+ } else {
+ Log.w(TAG, contentType + " is not supported.");
}
}
+
/** Set new listener for this session. */
public void setListener(@Nullable ChatSessionListener listener) {
mListener = listener;