summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTreehugger Robot <treehugger-gerrit@google.com>2018-03-27 06:37:08 +0000
committerGerrit Code Review <noreply-gerritcodereview@google.com>2018-03-27 06:37:08 +0000
commitbc62b7254e513fb6bb190d8838be09780bf89714 (patch)
treede75b03528aae36b06fc402fa39d081250671048
parent966800d977660c8ce78d988af5284647d02d6555 (diff)
parentf4b484485a4519a99d797bd9c0c1cc902cfc7414 (diff)
Merge changes Ic7cb3be7,I412f8fbf,Ifebcbe87
* changes: Correctly display phone numbers containing whitespaces in RTL context. Add waiting for join banner to RTT outgoing call. Allow user to delete previous bubbles.
-rw-r--r--java/com/android/contacts/common/list/ContactTileView.java6
-rw-r--r--java/com/android/dialer/app/calllog/PhoneCallDetailsViews.java9
-rw-r--r--java/com/android/dialer/app/list/PhoneFavoriteSquareTileView.java10
-rw-r--r--java/com/android/dialer/app/res/layout/call_log_list_item.xml2
-rw-r--r--java/com/android/dialer/app/res/layout/phone_favorite_tile_view.xml2
-rw-r--r--java/com/android/dialer/calldetails/CallDetailsHeaderViewHolder.java3
-rw-r--r--java/com/android/dialer/calldetails/res/layout/contact_container.xml2
-rw-r--r--java/com/android/dialer/contactsfragment/ContactViewHolder.java3
-rw-r--r--java/com/android/dialer/contactsfragment/res/layout/contact_row.xml2
-rw-r--r--java/com/android/dialer/i18n/DialerBidiFormatter.java123
-rw-r--r--java/com/android/dialer/searchfragment/common/res/layout/search_contact_row.xml4
-rw-r--r--java/com/android/dialer/searchfragment/cp2/SearchContactViewHolder.java6
-rw-r--r--java/com/android/dialer/widget/BidiTextView.java40
-rw-r--r--java/com/android/incallui/rtt/impl/RttChatAdapter.java58
-rw-r--r--java/com/android/incallui/rtt/impl/RttChatFragment.java42
-rw-r--r--java/com/android/incallui/rtt/impl/RttChatMessage.java116
-rw-r--r--java/com/android/incallui/rtt/impl/res/layout/rtt_banner.xml10
-rw-r--r--java/com/android/incallui/rtt/impl/res/values/strings.xml5
18 files changed, 352 insertions, 91 deletions
diff --git a/java/com/android/contacts/common/list/ContactTileView.java b/java/com/android/contacts/common/list/ContactTileView.java
index cfd52f385..072e07dd2 100644
--- a/java/com/android/contacts/common/list/ContactTileView.java
+++ b/java/com/android/contacts/common/list/ContactTileView.java
@@ -22,7 +22,6 @@ import android.util.AttributeSet;
import android.view.View;
import android.widget.FrameLayout;
import android.widget.ImageView;
-import android.widget.TextView;
import com.android.contacts.common.MoreContactUtils;
import com.android.contacts.common.R;
import com.android.dialer.callintent.CallInitiationType;
@@ -30,6 +29,7 @@ import com.android.dialer.callintent.CallSpecificAppData;
import com.android.dialer.common.LogUtil;
import com.android.dialer.contactphoto.ContactPhotoManager;
import com.android.dialer.contactphoto.ContactPhotoManager.DefaultImageRequest;
+import com.android.dialer.widget.BidiTextView;
/** A ContactTile displays a contact's picture and name */
public abstract class ContactTileView extends FrameLayout {
@@ -38,7 +38,7 @@ public abstract class ContactTileView extends FrameLayout {
protected Listener mListener;
private Uri mLookupUri;
private ImageView mPhoto;
- private TextView mName;
+ private BidiTextView mName;
private ContactPhotoManager mPhotoManager = null;
public ContactTileView(Context context, AttributeSet attrs) {
@@ -48,7 +48,7 @@ public abstract class ContactTileView extends FrameLayout {
@Override
protected void onFinishInflate() {
super.onFinishInflate();
- mName = (TextView) findViewById(R.id.contact_tile_name);
+ mName = (BidiTextView) findViewById(R.id.contact_tile_name);
mPhoto = (ImageView) findViewById(R.id.contact_tile_image);
OnClickListener listener = createClickListener();
diff --git a/java/com/android/dialer/app/calllog/PhoneCallDetailsViews.java b/java/com/android/dialer/app/calllog/PhoneCallDetailsViews.java
index 8b7a92bd4..71cbc8c12 100644
--- a/java/com/android/dialer/app/calllog/PhoneCallDetailsViews.java
+++ b/java/com/android/dialer/app/calllog/PhoneCallDetailsViews.java
@@ -21,11 +21,12 @@ import android.view.View;
import android.widget.TextView;
import com.android.dialer.app.R;
import com.android.dialer.calllogutils.CallTypeIconsView;
+import com.android.dialer.widget.BidiTextView;
/** Encapsulates the views that are used to display the details of a phone call in the call log. */
public final class PhoneCallDetailsViews {
- public final TextView nameView;
+ public final BidiTextView nameView;
public final View callTypeView;
public final CallTypeIconsView callTypeIcons;
public final TextView callLocationAndDate;
@@ -36,7 +37,7 @@ public final class PhoneCallDetailsViews {
public final TextView callAccountLabel;
private PhoneCallDetailsViews(
- TextView nameView,
+ BidiTextView nameView,
View callTypeView,
CallTypeIconsView callTypeIcons,
TextView callLocationAndDate,
@@ -65,7 +66,7 @@ public final class PhoneCallDetailsViews {
*/
public static PhoneCallDetailsViews fromView(View view) {
return new PhoneCallDetailsViews(
- (TextView) view.findViewById(R.id.name),
+ (BidiTextView) view.findViewById(R.id.name),
view.findViewById(R.id.call_type),
(CallTypeIconsView) view.findViewById(R.id.call_type_icons),
(TextView) view.findViewById(R.id.call_location_and_date),
@@ -78,7 +79,7 @@ public final class PhoneCallDetailsViews {
public static PhoneCallDetailsViews createForTest(Context context) {
return new PhoneCallDetailsViews(
- new TextView(context),
+ new BidiTextView(context),
new View(context),
new CallTypeIconsView(context),
new TextView(context),
diff --git a/java/com/android/dialer/app/list/PhoneFavoriteSquareTileView.java b/java/com/android/dialer/app/list/PhoneFavoriteSquareTileView.java
index 330a3614c..6096ca872 100644
--- a/java/com/android/dialer/app/list/PhoneFavoriteSquareTileView.java
+++ b/java/com/android/dialer/app/list/PhoneFavoriteSquareTileView.java
@@ -28,12 +28,11 @@ import com.android.dialer.app.R;
import com.android.dialer.compat.CompatUtils;
import com.android.dialer.logging.InteractionEvent;
import com.android.dialer.logging.Logger;
+import com.android.dialer.widget.BidiTextView;
/** Displays the contact's picture overlaid with their name and number type in a tile. */
public class PhoneFavoriteSquareTileView extends PhoneFavoriteTileView {
- private static final String TAG = PhoneFavoriteSquareTileView.class.getSimpleName();
-
private final float heightToWidthRatio;
private ImageButton secondaryButton;
@@ -50,11 +49,12 @@ public class PhoneFavoriteSquareTileView extends PhoneFavoriteTileView {
@Override
protected void onFinishInflate() {
super.onFinishInflate();
- final TextView nameView = (TextView) findViewById(R.id.contact_tile_name);
+ BidiTextView nameView = findViewById(R.id.contact_tile_name);
nameView.setElegantTextHeight(false);
- final TextView phoneTypeView = (TextView) findViewById(R.id.contact_tile_phone_type);
+
+ TextView phoneTypeView = findViewById(R.id.contact_tile_phone_type);
phoneTypeView.setElegantTextHeight(false);
- secondaryButton = (ImageButton) findViewById(R.id.contact_tile_secondary_button);
+ secondaryButton = findViewById(R.id.contact_tile_secondary_button);
}
@Override
diff --git a/java/com/android/dialer/app/res/layout/call_log_list_item.xml b/java/com/android/dialer/app/res/layout/call_log_list_item.xml
index acaa82085..d1111103e 100644
--- a/java/com/android/dialer/app/res/layout/call_log_list_item.xml
+++ b/java/com/android/dialer/app/res/layout/call_log_list_item.xml
@@ -93,7 +93,7 @@
android:gravity="center_vertical"
android:layout_marginStart="@dimen/call_log_list_item_info_margin_start">
- <TextView
+ <com.android.dialer.widget.BidiTextView
android:id="@+id/name"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
diff --git a/java/com/android/dialer/app/res/layout/phone_favorite_tile_view.xml b/java/com/android/dialer/app/res/layout/phone_favorite_tile_view.xml
index d2712e9fe..3aeba98a7 100644
--- a/java/com/android/dialer/app/res/layout/phone_favorite_tile_view.xml
+++ b/java/com/android/dialer/app/res/layout/phone_favorite_tile_view.xml
@@ -63,7 +63,7 @@
android:layout_height="wrap_content"
android:gravity="center_vertical"
android:orientation="horizontal">
- <TextView
+ <com.android.dialer.widget.BidiTextView
android:id="@+id/contact_tile_name"
android:layout_width="0dp"
android:layout_height="wrap_content"
diff --git a/java/com/android/dialer/calldetails/CallDetailsHeaderViewHolder.java b/java/com/android/dialer/calldetails/CallDetailsHeaderViewHolder.java
index e4fded173..cb84a28c2 100644
--- a/java/com/android/dialer/calldetails/CallDetailsHeaderViewHolder.java
+++ b/java/com/android/dialer/calldetails/CallDetailsHeaderViewHolder.java
@@ -40,6 +40,7 @@ import com.android.dialer.dialercontact.DialerContact;
import com.android.dialer.glidephotomanager.GlidePhotoManagerComponent;
import com.android.dialer.logging.InteractionEvent;
import com.android.dialer.logging.Logger;
+import com.android.dialer.widget.BidiTextView;
/**
* ViewHolder for the header in {@link OldCallDetailsActivity} or {@link CallDetailsActivity}.
@@ -51,7 +52,7 @@ public class CallDetailsHeaderViewHolder extends RecyclerView.ViewHolder
private final CallDetailsHeaderListener callDetailsHeaderListener;
private final ImageView callbackButton;
- private final TextView nameView;
+ private final BidiTextView nameView;
private final TextView numberView;
private final TextView networkView;
private final QuickContactBadge contactPhoto;
diff --git a/java/com/android/dialer/calldetails/res/layout/contact_container.xml b/java/com/android/dialer/calldetails/res/layout/contact_container.xml
index 5f531ab43..9506183a0 100644
--- a/java/com/android/dialer/calldetails/res/layout/contact_container.xml
+++ b/java/com/android/dialer/calldetails/res/layout/contact_container.xml
@@ -44,7 +44,7 @@
android:minHeight="@dimen/call_details_contact_photo_size"
android:orientation="vertical">
- <TextView
+ <com.android.dialer.widget.BidiTextView
android:id="@+id/contact_name"
style="@style/PrimaryText"
android:layout_width="wrap_content"
diff --git a/java/com/android/dialer/contactsfragment/ContactViewHolder.java b/java/com/android/dialer/contactsfragment/ContactViewHolder.java
index 2730c0d38..e1883322c 100644
--- a/java/com/android/dialer/contactsfragment/ContactViewHolder.java
+++ b/java/com/android/dialer/contactsfragment/ContactViewHolder.java
@@ -28,12 +28,13 @@ import com.android.dialer.common.Assert;
import com.android.dialer.contactsfragment.ContactsFragment.OnContactSelectedListener;
import com.android.dialer.logging.InteractionEvent;
import com.android.dialer.logging.Logger;
+import com.android.dialer.widget.BidiTextView;
/** View holder for a contact. */
final class ContactViewHolder extends RecyclerView.ViewHolder implements OnClickListener {
private final TextView header;
- private final TextView name;
+ private final BidiTextView name;
private final QuickContactBadge photo;
private final Context context;
private final OnContactSelectedListener onContactSelectedListener;
diff --git a/java/com/android/dialer/contactsfragment/res/layout/contact_row.xml b/java/com/android/dialer/contactsfragment/res/layout/contact_row.xml
index 9e829fee4..b65a8c87f 100644
--- a/java/com/android/dialer/contactsfragment/res/layout/contact_row.xml
+++ b/java/com/android/dialer/contactsfragment/res/layout/contact_row.xml
@@ -41,7 +41,7 @@
android:layout_height="@dimen/photo_size"
android:clickable="false"/>
- <TextView
+ <com.android.dialer.widget.BidiTextView
android:id="@+id/contact_name"
android:layout_width="wrap_content"
android:layout_height="match_parent"
diff --git a/java/com/android/dialer/i18n/DialerBidiFormatter.java b/java/com/android/dialer/i18n/DialerBidiFormatter.java
new file mode 100644
index 000000000..4ebaa666c
--- /dev/null
+++ b/java/com/android/dialer/i18n/DialerBidiFormatter.java
@@ -0,0 +1,123 @@
+/*
+ * 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.dialer.i18n;
+
+import android.support.annotation.Nullable;
+import android.support.annotation.VisibleForTesting;
+import android.support.v4.text.BidiFormatter;
+import android.text.TextUtils;
+import android.util.Patterns;
+import com.android.dialer.common.Assert;
+import com.google.auto.value.AutoValue;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.regex.Matcher;
+
+/**
+ * An enhanced version of {@link BidiFormatter} that can recognize a formatted phone number
+ * containing whitespaces.
+ *
+ * <p>Formatted phone numbers usually contain one or more whitespaces (e.g., "+1 650-253-0000",
+ * "(650) 253-0000", etc). {@link BidiFormatter} mistakes such a number for tokens separated by
+ * whitespaces. Therefore, these numbers can't be correctly shown in a RTL context (e.g., "+1
+ * 650-253-0000" would be shown as "650-253-0000 1+".)
+ */
+public final class DialerBidiFormatter {
+
+ private DialerBidiFormatter() {}
+
+ /**
+ * Divides the given text into segments, applies {@link BidiFormatter#unicodeWrap(CharSequence)}
+ * to each segment, and then reassembles the text.
+ *
+ * <p>A segment of the text is either a substring matching {@link Patterns#PHONE} or one that does
+ * not.
+ *
+ * @see BidiFormatter#unicodeWrap(CharSequence)
+ */
+ public static CharSequence unicodeWrap(@Nullable CharSequence text) {
+ if (TextUtils.isEmpty(text)) {
+ return text;
+ }
+
+ List<CharSequence> segments = segmentText(text);
+
+ StringBuilder formattedText = new StringBuilder();
+ for (CharSequence segment : segments) {
+ formattedText.append(BidiFormatter.getInstance().unicodeWrap(segment));
+ }
+
+ return formattedText.toString();
+ }
+
+ /**
+ * Segments the given text using {@link Patterns#PHONE}.
+ *
+ * <p>For example, "Mobile, +1 650-253-0000, 20 seconds" will be segmented into {"Mobile, ", "+1
+ * 650-253-0000", ", 20 seconds"}.
+ */
+ @VisibleForTesting
+ static List<CharSequence> segmentText(CharSequence text) {
+ Assert.checkArgument(!TextUtils.isEmpty(text));
+
+ List<CharSequence> segments = new ArrayList<>();
+
+ // Find the start index and the end index of each segment matching the phone number pattern.
+ Matcher matcher = Patterns.PHONE.matcher(text.toString());
+ List<Range> segmentRanges = new ArrayList<>();
+ while (matcher.find()) {
+ segmentRanges.add(Range.newBuilder().setStart(matcher.start()).setEnd(matcher.end()).build());
+ }
+
+ // Segment the text.
+ int currIndex = 0;
+ for (Range segmentRange : segmentRanges) {
+ if (currIndex < segmentRange.getStart()) {
+ segments.add(text.subSequence(currIndex, segmentRange.getStart()));
+ }
+
+ segments.add(text.subSequence(segmentRange.getStart(), segmentRange.getEnd()));
+ currIndex = segmentRange.getEnd();
+ }
+ if (currIndex < text.length()) {
+ segments.add(text.subSequence(currIndex, text.length()));
+ }
+
+ return segments;
+ }
+
+ /** Represents the start index (inclusive) and the end index (exclusive) of a text segment. */
+ @AutoValue
+ abstract static class Range {
+ static Builder newBuilder() {
+ return new AutoValue_DialerBidiFormatter_Range.Builder();
+ }
+
+ abstract int getStart();
+
+ abstract int getEnd();
+
+ @AutoValue.Builder
+ abstract static class Builder {
+ abstract Builder setStart(int start);
+
+ abstract Builder setEnd(int end);
+
+ abstract Range build();
+ }
+ }
+}
diff --git a/java/com/android/dialer/searchfragment/common/res/layout/search_contact_row.xml b/java/com/android/dialer/searchfragment/common/res/layout/search_contact_row.xml
index 9be7fa046..a0d9dd274 100644
--- a/java/com/android/dialer/searchfragment/common/res/layout/search_contact_row.xml
+++ b/java/com/android/dialer/searchfragment/common/res/layout/search_contact_row.xml
@@ -39,7 +39,7 @@
android:layout_centerVertical="true"
android:layout_marginStart="8dp">
- <TextView
+ <com.android.dialer.widget.BidiTextView
android:id="@+id/primary"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
@@ -47,7 +47,7 @@
android:fontFamily="sans-serif"
style="@style/PrimaryText"/>
- <TextView
+ <com.android.dialer.widget.BidiTextView
android:id="@+id/secondary"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
diff --git a/java/com/android/dialer/searchfragment/cp2/SearchContactViewHolder.java b/java/com/android/dialer/searchfragment/cp2/SearchContactViewHolder.java
index e36df4bf7..9d18e07b1 100644
--- a/java/com/android/dialer/searchfragment/cp2/SearchContactViewHolder.java
+++ b/java/com/android/dialer/searchfragment/cp2/SearchContactViewHolder.java
@@ -30,7 +30,6 @@ import android.view.View;
import android.view.View.OnClickListener;
import android.widget.ImageView;
import android.widget.QuickContactBadge;
-import android.widget.TextView;
import com.android.dialer.common.Assert;
import com.android.dialer.contactphoto.ContactPhotoManager;
import com.android.dialer.dialercontact.DialerContact;
@@ -44,6 +43,7 @@ import com.android.dialer.searchfragment.common.QueryBoldingUtil;
import com.android.dialer.searchfragment.common.R;
import com.android.dialer.searchfragment.common.RowClickListener;
import com.android.dialer.searchfragment.common.SearchCursor;
+import com.android.dialer.widget.BidiTextView;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
@@ -67,8 +67,8 @@ public final class SearchContactViewHolder extends ViewHolder implements OnClick
private final RowClickListener listener;
private final QuickContactBadge photo;
- private final TextView nameOrNumberView;
- private final TextView numberView;
+ private final BidiTextView nameOrNumberView;
+ private final BidiTextView numberView;
private final ImageView callToActionView;
private final Context context;
diff --git a/java/com/android/dialer/widget/BidiTextView.java b/java/com/android/dialer/widget/BidiTextView.java
new file mode 100644
index 000000000..6cf1aaedf
--- /dev/null
+++ b/java/com/android/dialer/widget/BidiTextView.java
@@ -0,0 +1,40 @@
+/*
+ * 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.dialer.widget;
+
+import android.content.Context;
+import android.support.annotation.Nullable;
+import android.util.AttributeSet;
+import android.widget.TextView;
+import com.android.dialer.i18n.DialerBidiFormatter;
+
+/** A {@link TextView} that applies bidirectional formatting to its text. */
+public final class BidiTextView extends TextView {
+
+ public BidiTextView(Context context) {
+ super(context);
+ }
+
+ public BidiTextView(Context context, @Nullable AttributeSet attrs) {
+ super(context, attrs);
+ }
+
+ @Override
+ public void setText(CharSequence text, BufferType type) {
+ super.setText(DialerBidiFormatter.unicodeWrap(text), type);
+ }
+}
diff --git a/java/com/android/incallui/rtt/impl/RttChatAdapter.java b/java/com/android/incallui/rtt/impl/RttChatAdapter.java
index 7e2b571c1..8d924c9f8 100644
--- a/java/com/android/incallui/rtt/impl/RttChatAdapter.java
+++ b/java/com/android/incallui/rtt/impl/RttChatAdapter.java
@@ -37,13 +37,11 @@ public class RttChatAdapter extends RecyclerView.Adapter<RttChatMessageViewHolde
}
private static final String KEY_MESSAGE_DATA = "key_message_data";
- private static final String KEY_LAST_REMOTE_MESSAGE = "key_last_remote_message";
private static final String KEY_LAST_LOCAL_MESSAGE = "key_last_local_message";
private final Context context;
private final List<RttChatMessage> rttMessages;
private int lastIndexOfLocalMessage = -1;
- private int lastIndexOfRemoteMessage = -1;
private final MessageListener messageListener;
RttChatAdapter(Context context, MessageListener listener, @Nullable Bundle savedInstanceState) {
@@ -53,7 +51,6 @@ public class RttChatAdapter extends RecyclerView.Adapter<RttChatMessageViewHolde
rttMessages = new ArrayList<>();
} else {
rttMessages = savedInstanceState.getParcelableArrayList(KEY_MESSAGE_DATA);
- lastIndexOfRemoteMessage = savedInstanceState.getInt(KEY_LAST_REMOTE_MESSAGE);
lastIndexOfLocalMessage = savedInstanceState.getInt(KEY_LAST_LOCAL_MESSAGE);
}
}
@@ -84,33 +81,6 @@ public class RttChatAdapter extends RecyclerView.Adapter<RttChatMessageViewHolde
return rttMessages.size();
}
- private void updateCurrentRemoteMessage(String newText) {
- RttChatMessage rttChatMessage = null;
- if (lastIndexOfRemoteMessage >= 0) {
- rttChatMessage = rttMessages.get(lastIndexOfRemoteMessage);
- }
- List<RttChatMessage> newMessages =
- RttChatMessage.getRemoteRttChatMessage(rttChatMessage, newText);
-
- if (rttChatMessage == null) {
- lastIndexOfRemoteMessage = rttMessages.size();
- rttMessages.add(lastIndexOfRemoteMessage, newMessages.get(0));
- rttMessages.addAll(newMessages.subList(1, newMessages.size()));
- notifyItemRangeInserted(lastIndexOfRemoteMessage, newMessages.size());
- lastIndexOfRemoteMessage = rttMessages.size() - 1;
- } else {
- rttMessages.set(lastIndexOfRemoteMessage, newMessages.get(0));
- int lastIndex = rttMessages.size();
- rttMessages.addAll(newMessages.subList(1, newMessages.size()));
-
- notifyItemChanged(lastIndexOfRemoteMessage);
- notifyItemRangeInserted(lastIndex, newMessages.size());
- }
- if (rttMessages.get(lastIndexOfRemoteMessage).isFinished()) {
- lastIndexOfRemoteMessage = -1;
- }
- }
-
private void updateCurrentLocalMessage(String newMessage) {
RttChatMessage rttChatMessage = null;
if (lastIndexOfLocalMessage >= 0) {
@@ -128,9 +98,6 @@ public class RttChatAdapter extends RecyclerView.Adapter<RttChatMessageViewHolde
if (TextUtils.isEmpty(rttChatMessage.getContent())) {
rttMessages.remove(lastIndexOfLocalMessage);
notifyItemRemoved(lastIndexOfLocalMessage);
- if (lastIndexOfRemoteMessage > lastIndexOfLocalMessage) {
- lastIndexOfRemoteMessage -= 1;
- }
lastIndexOfLocalMessage = -1;
} else {
notifyItemChanged(lastIndexOfLocalMessage);
@@ -138,8 +105,13 @@ public class RttChatAdapter extends RecyclerView.Adapter<RttChatMessageViewHolde
}
}
+ private void updateCurrentRemoteMessage(String newMessage) {
+ RttChatMessage.updateRemoteRttChatMessage(rttMessages, newMessage);
+ lastIndexOfLocalMessage = RttChatMessage.getLastIndexLocalMessage(rttMessages);
+ notifyDataSetChanged();
+ }
+
void addLocalMessage(String message) {
- LogUtil.enterBlock("RttChatAdapater.addLocalMessage");
updateCurrentLocalMessage(message);
if (messageListener != null) {
messageListener.newMessageAdded();
@@ -166,7 +138,6 @@ public class RttChatAdapter extends RecyclerView.Adapter<RttChatMessageViewHolde
}
void addRemoteMessage(String message) {
- LogUtil.enterBlock("RttChatAdapater.addRemoteMessage");
if (TextUtils.isEmpty(message)) {
return;
}
@@ -176,9 +147,24 @@ public class RttChatAdapter extends RecyclerView.Adapter<RttChatMessageViewHolde
}
}
+ /**
+ * Retrieve last local message and update the index. This is used when deleting to previous
+ * message bubble.
+ */
+ @Nullable
+ String retrieveLastLocalMessage() {
+ lastIndexOfLocalMessage = RttChatMessage.getLastIndexLocalMessage(rttMessages);
+ if (lastIndexOfLocalMessage >= 0) {
+ RttChatMessage rttChatMessage = rttMessages.get(lastIndexOfLocalMessage);
+ rttChatMessage.unfinish();
+ return rttChatMessage.getContent();
+ } else {
+ return null;
+ }
+ }
+
void onSaveInstanceState(@NonNull Bundle bundle) {
bundle.putParcelableArrayList(KEY_MESSAGE_DATA, (ArrayList<RttChatMessage>) rttMessages);
- bundle.putInt(KEY_LAST_REMOTE_MESSAGE, lastIndexOfRemoteMessage);
bundle.putInt(KEY_LAST_LOCAL_MESSAGE, lastIndexOfLocalMessage);
}
}
diff --git a/java/com/android/incallui/rtt/impl/RttChatFragment.java b/java/com/android/incallui/rtt/impl/RttChatFragment.java
index 90bf199b2..56ac2429c 100644
--- a/java/com/android/incallui/rtt/impl/RttChatFragment.java
+++ b/java/com/android/incallui/rtt/impl/RttChatFragment.java
@@ -103,6 +103,8 @@ public class RttChatFragment extends Fragment
private boolean isTimerStarted;
private RttOverflowMenu overflowMenu;
private SecondaryInfo savedSecondaryInfo;
+ private TextView statusBanner;
+ private PrimaryInfo primaryInfo;
/**
* Create a new instance of RttChatFragment.
@@ -164,6 +166,26 @@ public class RttChatFragment extends Fragment
editText = view.findViewById(R.id.rtt_chat_input);
editText.setOnEditorActionListener(this);
editText.addTextChangedListener(this);
+
+ editText.setOnKeyListener(
+ (v, keyCode, event) -> {
+ // This is only triggered when input method doesn't handle delete key, which means the
+ // current
+ // input box is empty.
+ if (keyCode == KeyEvent.KEYCODE_DEL && event.getAction() == KeyEvent.ACTION_DOWN) {
+ String lastMessage = adapter.retrieveLastLocalMessage();
+ if (lastMessage != null) {
+ isClearingInput = true;
+ editText.setText(lastMessage);
+ editText.setSelection(lastMessage.length());
+ isClearingInput = false;
+ rttCallScreenDelegate.onLocalMessage("\b");
+ return true;
+ }
+ return false;
+ }
+ return false;
+ });
recyclerView = view.findViewById(R.id.rtt_recycler_view);
LinearLayoutManager layoutManager = new LinearLayoutManager(getContext());
layoutManager.setStackFromEnd(true);
@@ -201,13 +223,16 @@ public class RttChatFragment extends Fragment
nameTextView = view.findViewById(R.id.rtt_name_or_number);
chronometer = view.findViewById(R.id.rtt_timer);
+ statusBanner = view.findViewById(R.id.rtt_status_banner);
return view;
}
@Override
public boolean onEditorAction(TextView v, int actionId, KeyEvent event) {
if (actionId == EditorInfo.IME_ACTION_SEND) {
- submitButton.performClick();
+ if (!TextUtils.isEmpty(editText.getText())) {
+ submitButton.performClick();
+ }
return true;
}
return false;
@@ -312,6 +337,7 @@ public class RttChatFragment extends Fragment
public void setPrimary(@NonNull PrimaryInfo primaryInfo) {
LogUtil.i("RttChatFragment.setPrimary", primaryInfo.toString());
nameTextView.setText(primaryInfo.name());
+ this.primaryInfo = primaryInfo;
}
@Override
@@ -359,6 +385,20 @@ public class RttChatFragment extends Fragment
chronometer.start();
isTimerStarted = true;
}
+ if (primaryCallState.state() == State.DIALING) {
+ showWaitingForJoinBanner();
+ } else {
+ hideWaitingForJoinBanner();
+ }
+ }
+
+ private void showWaitingForJoinBanner() {
+ statusBanner.setText(getString(R.string.rtt_status_banner_text, primaryInfo.name()));
+ statusBanner.setVisibility(View.VISIBLE);
+ }
+
+ private void hideWaitingForJoinBanner() {
+ statusBanner.setVisibility(View.GONE);
}
@Override
diff --git a/java/com/android/incallui/rtt/impl/RttChatMessage.java b/java/com/android/incallui/rtt/impl/RttChatMessage.java
index fd83fb82f..cbc53ef15 100644
--- a/java/com/android/incallui/rtt/impl/RttChatMessage.java
+++ b/java/com/android/incallui/rtt/impl/RttChatMessage.java
@@ -19,10 +19,9 @@ package com.android.incallui.rtt.impl;
import android.os.Parcel;
import android.os.Parcelable;
import android.support.annotation.NonNull;
-import android.support.annotation.Nullable;
+import com.android.dialer.common.Assert;
import com.android.incallui.rtt.protocol.Constants;
import com.google.common.base.Splitter;
-import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
@@ -44,13 +43,17 @@ final class RttChatMessage implements Parcelable {
isFinished = true;
}
+ 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.append(c);
- } else if (content.length() > 0) {
+ if (c == '\b' && content.length() > 0 && content.charAt(content.length() - 1) != '\b') {
content.deleteCharAt(content.length() - 1);
+ } else {
+ content.append(c);
}
}
}
@@ -87,39 +90,92 @@ final class RttChatMessage implements Parcelable {
return modify.toString();
}
- /** Convert remote input text into an array of {@code RttChatMessage}. */
- static List<RttChatMessage> getRemoteRttChatMessage(
- @Nullable RttChatMessage currentMessage, @NonNull String text) {
+ /** Update list of {@code RttChatMessage} based on given remote text. */
+ static void updateRemoteRttChatMessage(List<RttChatMessage> messageList, @NonNull String text) {
+ Assert.isNotNull(messageList);
Iterator<String> splitText = SPLITTER.split(text).iterator();
- List<RttChatMessage> messageList = new ArrayList<>();
-
- String firstMessageContent = splitText.next();
- RttChatMessage firstMessage = currentMessage;
- if (firstMessage == null) {
- firstMessage = new RttChatMessage();
- firstMessage.isRemote = true;
- }
- firstMessage.append(firstMessageContent);
- if (splitText.hasNext() || text.endsWith(Constants.BUBBLE_BREAKER)) {
- firstMessage.finish();
- }
- messageList.add(firstMessage);
while (splitText.hasNext()) {
String singleMessageContent = splitText.next();
- if (singleMessageContent.isEmpty()) {
- continue;
+ 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);
+ }
}
- RttChatMessage message = new RttChatMessage();
- message.append(singleMessageContent);
- message.isRemote = true;
- if (splitText.hasNext()) {
- message.finish();
+ 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;
}
- messageList.add(message);
}
+ 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;
+ }
- return messageList;
+ private static int getLastIndexRemoteMessage(List<RttChatMessage> messageList) {
+ int i = messageList.size() - 1;
+ while (i >= 0 && !messageList.get(i).isRemote) {
+ i--;
+ }
+ return i;
+ }
+
+ static int getLastIndexLocalMessage(List<RttChatMessage> messageList) {
+ int i = messageList.size() - 1;
+ while (i >= 0 && messageList.get(i).isRemote) {
+ i--;
+ }
+ return i;
}
@Override
diff --git a/java/com/android/incallui/rtt/impl/res/layout/rtt_banner.xml b/java/com/android/incallui/rtt/impl/res/layout/rtt_banner.xml
index c4d3a4290..d62cf1849 100644
--- a/java/com/android/incallui/rtt/impl/res/layout/rtt_banner.xml
+++ b/java/com/android/incallui/rtt/impl/res/layout/rtt_banner.xml
@@ -83,5 +83,15 @@
android:id="@id/rtt_on_hold_banner"
android:layout_width="match_parent"
android:layout_height="wrap_content"/>
+ <TextView
+ android:id="@+id/rtt_status_banner"
+ android:layout_width="match_parent"
+ android:layout_height="48dp"
+ android:paddingStart="16dp"
+ android:paddingEnd="16dp"
+ android:background="@android:color/white"
+ android:gravity="center_vertical"
+ android:textColor="#DD000000"
+ android:textSize="14sp"/>
</LinearLayout> \ No newline at end of file
diff --git a/java/com/android/incallui/rtt/impl/res/values/strings.xml b/java/com/android/incallui/rtt/impl/res/values/strings.xml
index dce16fdda..b0ac2057e 100644
--- a/java/com/android/incallui/rtt/impl/res/values/strings.xml
+++ b/java/com/android/incallui/rtt/impl/res/values/strings.xml
@@ -14,7 +14,7 @@
~ See the License for the specific language governing permissions and
~ limitations under the License
-->
-<resources>
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<!-- Content description for submit chat input button. [CHAR LIMIT=NONE] -->
<string name="content_description_rtt_check_button">Go ahead</string>
@@ -27,4 +27,7 @@
<!-- Text for back button. [CHAR LIMIT=20] -->
<string name="rtt_button_back">Back</string>
+ <!-- Text for status banner. [CHAT LIMIT=100] -->
+ <string name="rtt_status_banner_text">Waiting for <xliff:g id="name">%s</xliff:g> to join RTT call&#8230;</string>
+
</resources> \ No newline at end of file