/*
* 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.
*
*
e.g. "hello world" -> "hello" : "\b\b\b\b\b\b"
*
*
"hello world" -> "hello mom!" : "\b\b\b\b\bmom!"
*
*
"hello world" -> "hello d" : "\b\b\b\b\bd"
*
*
"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 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 messageList, @NonNull String text) {
Assert.isNotNull(messageList);
Iterator 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 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 messageList) {
int i = messageList.size() - 1;
while (i >= 0 && !messageList.get(i).isRemote) {
i--;
}
return i;
}
public static int getLastIndexLocalMessage(List messageList) {
int i = messageList.size() - 1;
while (i >= 0 && messageList.get(i).isRemote) {
i--;
}
return i;
}
public static List toTranscriptMessageList(
List messageList) {
List 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 fromTranscript(RttTranscript rttTranscript) {
List 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();
}
}