summaryrefslogtreecommitdiff
path: root/java/com/android/incallui/rtt/protocol/RttChatMessage.java
diff options
context:
space:
mode:
Diffstat (limited to 'java/com/android/incallui/rtt/protocol/RttChatMessage.java')
-rw-r--r--java/com/android/incallui/rtt/protocol/RttChatMessage.java230
1 files changed, 230 insertions, 0 deletions
diff --git a/java/com/android/incallui/rtt/protocol/RttChatMessage.java b/java/com/android/incallui/rtt/protocol/RttChatMessage.java
new file mode 100644
index 000000000..5680529ee
--- /dev/null
+++ b/java/com/android/incallui/rtt/protocol/RttChatMessage.java
@@ -0,0 +1,230 @@
+/*
+ * 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.incallui.rtt.protocol;
+
+import android.support.annotation.NonNull;
+import com.android.dialer.common.Assert;
+import com.android.dialer.rtt.RttTranscript;
+import com.android.dialer.rtt.RttTranscriptMessage;
+import com.google.common.base.Splitter;
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+
+/** Message class that holds one RTT chat content. */
+public final class RttChatMessage {
+
+ private static final Splitter SPLITTER = Splitter.on(Constants.BUBBLE_BREAKER);
+
+ public boolean isRemote;
+ private long timstamp;
+ private final StringBuilder content = new StringBuilder();
+ private boolean isFinished;
+
+ public boolean isFinished() {
+ return isFinished;
+ }
+
+ public void finish() {
+ isFinished = true;
+ }
+
+ public void unfinish() {
+ isFinished = false;
+ }
+
+ public void append(String text) {
+ for (int i = 0; i < text.length(); i++) {
+ char c = text.charAt(i);
+ if (c == '\b' && content.length() > 0 && content.charAt(content.length() - 1) != '\b') {
+ content.deleteCharAt(content.length() - 1);
+ } else {
+ content.append(c);
+ }
+ }
+ }
+
+ public String getContent() {
+ return content.toString();
+ }
+
+ /**
+ * Computes delta change of two string.
+ *
+ * <p>e.g. "hello world" -> "hello" : "\b\b\b\b\b\b"
+ *
+ * <p>"hello world" -> "hello mom!" : "\b\b\b\b\bmom!"
+ *
+ * <p>"hello world" -> "hello d" : "\b\b\b\b\bd"
+ *
+ * <p>"hello world" -> "hello new world" : "\b\b\b\b\bnew world"
+ */
+ public static String computeChangedString(String oldMessage, String newMesssage) {
+ StringBuilder modify = new StringBuilder();
+ int indexChangeStart = 0;
+ while (indexChangeStart < oldMessage.length()
+ && indexChangeStart < newMesssage.length()
+ && oldMessage.charAt(indexChangeStart) == newMesssage.charAt(indexChangeStart)) {
+ indexChangeStart++;
+ }
+ for (int i = indexChangeStart; i < oldMessage.length(); i++) {
+ modify.append('\b');
+ }
+ for (int i = indexChangeStart; i < newMesssage.length(); i++) {
+ modify.append(newMesssage.charAt(i));
+ }
+ return modify.toString();
+ }
+
+ public static RttTranscript getRttTranscriptWithNewRemoteMessage(
+ RttTranscript rttTranscript, @NonNull String text) {
+ List<RttChatMessage> messageList = fromTranscript(rttTranscript);
+ updateRemoteRttChatMessage(messageList, text);
+ return RttTranscript.newBuilder()
+ .setId(rttTranscript.getId())
+ .setNumber(rttTranscript.getNumber())
+ .setTimestamp(rttTranscript.getTimestamp())
+ .addAllMessages(toTranscriptMessageList(messageList))
+ .build();
+ }
+
+ /** Update list of {@code RttChatMessage} based on given remote text. */
+ public static void updateRemoteRttChatMessage(
+ List<RttChatMessage> messageList, @NonNull String text) {
+ Assert.isNotNull(messageList);
+ Iterator<String> splitText = SPLITTER.split(text).iterator();
+
+ while (splitText.hasNext()) {
+ String singleMessageContent = splitText.next();
+ RttChatMessage message;
+ int index = getLastIndexUnfinishedRemoteMessage(messageList);
+ if (index < 0) {
+ message = new RttChatMessage();
+ message.append(singleMessageContent);
+ message.isRemote = true;
+ if (splitText.hasNext()) {
+ message.finish();
+ }
+ if (message.content.length() != 0) {
+ messageList.add(message);
+ }
+ } else {
+ message = messageList.get(index);
+ message.append(singleMessageContent);
+ if (splitText.hasNext()) {
+ message.finish();
+ }
+ if (message.content.length() == 0) {
+ messageList.remove(index);
+ }
+ }
+ StringBuilder content = message.content;
+ // Delete previous messages.
+ while (content.length() > 0 && content.charAt(0) == '\b') {
+ messageList.remove(message);
+ content.delete(0, 1);
+ int previous = getLastIndexRemoteMessage(messageList);
+ // There are more backspaces than existing characters.
+ if (previous < 0) {
+ while (content.length() > 0 && content.charAt(0) == '\b') {
+ content.deleteCharAt(0);
+ }
+ // Add message if there are still characters after backspaces.
+ if (content.length() > 0) {
+ message = new RttChatMessage();
+ message.append(content.toString());
+ message.isRemote = true;
+ if (splitText.hasNext()) {
+ message.finish();
+ }
+ messageList.add(message);
+ }
+ break;
+ }
+ message = messageList.get(previous);
+ message.unfinish();
+ message.append(content.toString());
+ content = message.content;
+ }
+ }
+ if (text.endsWith(Constants.BUBBLE_BREAKER)) {
+ int lastIndexRemoteMessage = getLastIndexRemoteMessage(messageList);
+ messageList.get(lastIndexRemoteMessage).finish();
+ }
+ }
+
+ private static int getLastIndexUnfinishedRemoteMessage(List<RttChatMessage> messageList) {
+ int i = messageList.size() - 1;
+ while (i >= 0 && (!messageList.get(i).isRemote || messageList.get(i).isFinished)) {
+ i--;
+ }
+ return i;
+ }
+
+ public static int getLastIndexRemoteMessage(List<RttChatMessage> messageList) {
+ int i = messageList.size() - 1;
+ while (i >= 0 && !messageList.get(i).isRemote) {
+ i--;
+ }
+ return i;
+ }
+
+ public static int getLastIndexLocalMessage(List<RttChatMessage> messageList) {
+ int i = messageList.size() - 1;
+ while (i >= 0 && messageList.get(i).isRemote) {
+ i--;
+ }
+ return i;
+ }
+
+ public static List<RttTranscriptMessage> toTranscriptMessageList(
+ List<RttChatMessage> messageList) {
+ List<RttTranscriptMessage> transcriptMessageList = new ArrayList<>();
+ for (RttChatMessage message : messageList) {
+ transcriptMessageList.add(
+ RttTranscriptMessage.newBuilder()
+ .setContent(message.getContent())
+ .setTimestamp(message.timstamp)
+ .setIsRemote(message.isRemote)
+ .setIsFinished(message.isFinished)
+ .build());
+ }
+ return transcriptMessageList;
+ }
+
+ public static List<RttChatMessage> fromTranscript(RttTranscript rttTranscript) {
+ List<RttChatMessage> messageList = new ArrayList<>();
+ if (rttTranscript == null) {
+ return messageList;
+ }
+ for (RttTranscriptMessage message : rttTranscript.getMessagesList()) {
+ RttChatMessage chatMessage = new RttChatMessage();
+ chatMessage.append(message.getContent());
+ chatMessage.timstamp = message.getTimestamp();
+ chatMessage.isRemote = message.getIsRemote();
+ if (message.getIsFinished()) {
+ chatMessage.finish();
+ }
+ messageList.add(chatMessage);
+ }
+ return messageList;
+ }
+
+ public RttChatMessage() {
+ timstamp = System.currentTimeMillis();
+ }
+}