Merge changes If1ae5505,I65e9c6ac,I1a72ca86,I417b46ed,I60f97924

* changes:
  Better support for multi call.
  Migrate RTT chat history to use proto buffer.
  Disable RTT request button when the call is not active yet.
  Use the default phone account for a voice call when the call log item is for Duo.
  Explicitly hide the badge in ContactPhotoView when it shouldn't be shown.
diff --git a/java/com/android/dialer/calllog/ui/menu/Modules.java b/java/com/android/dialer/calllog/ui/menu/Modules.java
index e316f66..e0a69ca 100644
--- a/java/com/android/dialer/calllog/ui/menu/Modules.java
+++ b/java/com/android/dialer/calllog/ui/menu/Modules.java
@@ -18,6 +18,7 @@
 
 import android.content.Context;
 import android.provider.CallLog.Calls;
+import android.telecom.PhoneAccount;
 import android.telecom.PhoneAccountHandle;
 import android.text.TextUtils;
 import com.android.dialer.blockreportspam.BlockReportSpamDialogInfo;
@@ -123,10 +124,21 @@
       return Collections.emptyList();
     }
 
-    List<HistoryItemActionModule> modules = new ArrayList<>();
+    boolean isDuoCall =
+        DuoConstants.PHONE_ACCOUNT_COMPONENT_NAME
+            .flattenToString()
+            .equals(row.getPhoneAccountComponentName());
+
+    // Obtain a PhoneAccountHandle that will be used to start carrier voice/video calls.
+    // If the row is for a Duo call, we should use the default phone account as the one included in
+    // the row is for Duo only.
     PhoneAccountHandle phoneAccountHandle =
-        TelecomUtil.composePhoneAccountHandle(
-            row.getPhoneAccountComponentName(), row.getPhoneAccountId());
+        isDuoCall
+            ? TelecomUtil.getDefaultOutgoingPhoneAccount(context, PhoneAccount.SCHEME_TEL)
+            : TelecomUtil.composePhoneAccountHandle(
+                row.getPhoneAccountComponentName(), row.getPhoneAccountId());
+
+    List<HistoryItemActionModule> modules = new ArrayList<>();
 
     // Add an audio call item
     modules.add(
@@ -136,10 +148,6 @@
     // Add a video item if (1) the call log entry is for a video call, and (2) the call is not spam.
     if ((row.getFeatures() & Calls.FEATURES_VIDEO) == Calls.FEATURES_VIDEO
         && !row.getNumberAttributes().getIsSpam()) {
-      boolean isDuoCall =
-          DuoConstants.PHONE_ACCOUNT_COMPONENT_NAME
-              .flattenToString()
-              .equals(row.getPhoneAccountComponentName());
       modules.add(
           isDuoCall
               ? new DuoCallModule(context, normalizedNumber, CallInitiationType.Type.CALL_LOG)
diff --git a/java/com/android/dialer/rtt/rtt_transcript.proto b/java/com/android/dialer/rtt/rtt_transcript.proto
new file mode 100644
index 0000000..a580b0d
--- /dev/null
+++ b/java/com/android/dialer/rtt/rtt_transcript.proto
@@ -0,0 +1,30 @@
+syntax = "proto2";
+
+option java_package = "com.android.dialer.rtt";
+option java_multiple_files = true;
+option optimize_for = LITE_RUNTIME;
+
+
+package com.android.dialer.rtt;
+
+// RTT transcript which contains chat history of a RTT call.
+message RttTranscript {
+  // Unique ID used for database.
+  optional string id = 1;
+  // Phone number of RTT call.
+  optional string number = 2;
+  // Timestamp when the RTT call is created.
+  optional int64 timestamp = 3;
+  // Chat messages.
+  repeated RttTranscriptMessage messages = 4;
+}
+
+// Single chat message inside a RTT call.
+message RttTranscriptMessage {
+  optional string content = 1;
+  optional int64 timestamp = 2;
+  // Whether this message is sent from local device or received from remote
+  // party.
+  optional bool is_remote = 3;
+  optional bool is_finished = 4;
+}
\ No newline at end of file
diff --git a/java/com/android/dialer/widget/ContactPhotoView.java b/java/com/android/dialer/widget/ContactPhotoView.java
index 6fcc89a..5020875 100644
--- a/java/com/android/dialer/widget/ContactPhotoView.java
+++ b/java/com/android/dialer/widget/ContactPhotoView.java
@@ -86,12 +86,15 @@
   private void setBadge(PhotoInfo photoInfo) {
     // No badge for spam numbers.
     if (photoInfo.getIsSpam()) {
+      hideBadge();
       return;
     }
 
     if (photoInfo.getIsVideo()) {
       contactBadgeContainer.setVisibility(View.VISIBLE);
       videoCallBadge.setVisibility(View.VISIBLE);
+    } else {
+      hideBadge();
     }
   }
 }
diff --git a/java/com/android/incallui/CallButtonPresenter.java b/java/com/android/incallui/CallButtonPresenter.java
index 8334603..7e05bad 100644
--- a/java/com/android/incallui/CallButtonPresenter.java
+++ b/java/com/android/incallui/CallButtonPresenter.java
@@ -42,6 +42,7 @@
 import com.android.incallui.call.CallList;
 import com.android.incallui.call.DialerCall;
 import com.android.incallui.call.DialerCall.CameraDirection;
+import com.android.incallui.call.DialerCall.State;
 import com.android.incallui.call.TelecomAdapter;
 import com.android.incallui.incall.protocol.InCallButtonIds;
 import com.android.incallui.incall.protocol.InCallButtonUi;
@@ -480,6 +481,7 @@
             && InCallPresenter.getInstance().getCallList().getAllCalls().size() == 1;
 
     boolean showUpgradeToRtt = call.canUpgradeToRttCall();
+    boolean enableUpgradeToRtt = showUpgradeToRtt && call.getState() == State.ACTIVE;
 
     inCallButtonUi.showButton(InCallButtonIds.BUTTON_AUDIO, true);
     inCallButtonUi.showButton(InCallButtonIds.BUTTON_SWAP, showSwap);
@@ -491,6 +493,7 @@
     inCallButtonUi.enableButton(InCallButtonIds.BUTTON_ADD_CALL, showAddCall);
     inCallButtonUi.showButton(InCallButtonIds.BUTTON_UPGRADE_TO_VIDEO, showUpgradeToVideo);
     inCallButtonUi.showButton(InCallButtonIds.BUTTON_UPGRADE_TO_RTT, showUpgradeToRtt);
+    inCallButtonUi.enableButton(InCallButtonIds.BUTTON_UPGRADE_TO_RTT, enableUpgradeToRtt);
     inCallButtonUi.showButton(InCallButtonIds.BUTTON_DOWNGRADE_TO_AUDIO, showDowngradeToAudio);
     inCallButtonUi.showButton(
         InCallButtonIds.BUTTON_SWITCH_CAMERA,
diff --git a/java/com/android/incallui/InCallActivity.java b/java/com/android/incallui/InCallActivity.java
index 65ef323..44d8667 100644
--- a/java/com/android/incallui/InCallActivity.java
+++ b/java/com/android/incallui/InCallActivity.java
@@ -151,6 +151,7 @@
   private boolean didShowVideoCallScreen;
   private boolean didShowRttCallScreen;
   private boolean didShowSpeakEasyScreen;
+  private String lastShownSpeakEasyScreenUniqueCallid = "";
   private boolean dismissKeyguard;
   private boolean isInShowMainInCallFragment;
   private boolean isRecreating; // whether the activity is going to be recreated
@@ -1353,15 +1354,18 @@
 
   private boolean showSpeakEasyFragment(FragmentTransaction transaction, DialerCall call) {
 
-    // TODO(erfanian): Support multiple speakeasy screens.
     if (didShowSpeakEasyScreen) {
-      return false;
+      if (lastShownSpeakEasyScreenUniqueCallid.equals(call.getUniqueCallId())) {
+        return false;
+      }
+      hideSpeakEasyFragment(transaction);
     }
 
     Optional<Fragment> speakEasyFragment = speakEasyCallManager.getSpeakEasyFragment(call);
     if (speakEasyFragment.isPresent()) {
       transaction.add(R.id.main, speakEasyFragment.get(), Tags.SPEAK_EASY_SCREEN);
       didShowSpeakEasyScreen = true;
+      lastShownSpeakEasyScreenUniqueCallid = call.getUniqueCallId();
       return true;
     }
     return false;
diff --git a/java/com/android/incallui/RttCallPresenter.java b/java/com/android/incallui/RttCallPresenter.java
index 939c9d0..5e83907 100644
--- a/java/com/android/incallui/RttCallPresenter.java
+++ b/java/com/android/incallui/RttCallPresenter.java
@@ -23,6 +23,7 @@
 import android.telecom.Call.RttCall;
 import com.android.dialer.common.LogUtil;
 import com.android.dialer.common.concurrent.ThreadUtil;
+import com.android.dialer.rtt.RttTranscript;
 import com.android.incallui.InCallPresenter.InCallState;
 import com.android.incallui.InCallPresenter.InCallStateListener;
 import com.android.incallui.call.CallList;
@@ -62,6 +63,10 @@
     LogUtil.enterBlock("RttCallPresenter.onRttCallScreenUiReady");
     InCallPresenter.getInstance().addListener(this);
     startListenOnRemoteMessage();
+    DialerCall call = CallList.getInstance().getActiveCall();
+    if (call != null) {
+      rttCallScreen.onRestoreRttChat(call.getRttTranscript());
+    }
   }
 
   @Override
@@ -69,6 +74,21 @@
     LogUtil.enterBlock("RttCallPresenter.onRttCallScreenUiUnready");
     InCallPresenter.getInstance().removeListener(this);
     stopListenOnRemoteMessage();
+    DialerCall call = CallList.getInstance().getActiveCall();
+    if (call != null) {
+      saveTranscript(call);
+    }
+  }
+
+  private void saveTranscript(DialerCall dialerCall) {
+    LogUtil.enterBlock("RttCallPresenter.saveTranscript");
+    RttTranscript.Builder builder = RttTranscript.newBuilder();
+    builder
+        .setId(dialerCall.getNumber() + dialerCall.getCreationTimeMillis())
+        .setTimestamp(dialerCall.getCreationTimeMillis())
+        .setNumber(dialerCall.getNumber())
+        .addAllMessages(rttCallScreen.getRttTranscriptMessageList());
+    dialerCall.setRttTranscript(builder.build());
   }
 
   @Override
@@ -82,7 +102,7 @@
   private void startListenOnRemoteMessage() {
     DialerCall call = CallList.getInstance().getActiveCall();
     if (call == null) {
-      LogUtil.i("RttCallPresenter.startListenOnRemoteMessage", "call is active yet");
+      LogUtil.i("RttCallPresenter.startListenOnRemoteMessage", "call is not active yet");
       return;
     }
     rttCall = call.getRttCall();
diff --git a/java/com/android/incallui/call/DialerCall.java b/java/com/android/incallui/call/DialerCall.java
index 35f9481..3372c03 100644
--- a/java/com/android/incallui/call/DialerCall.java
+++ b/java/com/android/incallui/call/DialerCall.java
@@ -73,6 +73,7 @@
 import com.android.dialer.logging.DialerImpression;
 import com.android.dialer.logging.Logger;
 import com.android.dialer.preferredsim.PreferredAccountRecorder;
+import com.android.dialer.rtt.RttTranscript;
 import com.android.dialer.telecom.TelecomCallUtil;
 import com.android.dialer.telecom.TelecomUtil;
 import com.android.dialer.theme.R;
@@ -206,6 +207,16 @@
    */
   private boolean isCallSubjectSupported;
 
+  public RttTranscript getRttTranscript() {
+    return rttTranscript;
+  }
+
+  public void setRttTranscript(RttTranscript rttTranscript) {
+    this.rttTranscript = rttTranscript;
+  }
+
+  private RttTranscript rttTranscript;
+
   private final Call.Callback telecomCallCallback =
       new Call.Callback() {
         @Override
@@ -951,6 +962,16 @@
     return telecomCall.getDetails().getConnectTimeMillis();
   }
 
+  /**
+   * Gets the time when the call is created (see {@link Details#getCreationTimeMillis()}). This is
+   * the same time that is logged as the start time in the Call Log (see {@link
+   * android.provider.CallLog.Calls#DATE}).
+   */
+  @TargetApi(26)
+  public long getCreationTimeMillis() {
+    return telecomCall.getDetails().getCreationTimeMillis();
+  }
+
   public boolean isConferenceCall() {
     return hasProperty(Call.Details.PROPERTY_CONFERENCE);
   }
diff --git a/java/com/android/incallui/rtt/impl/RttChatAdapter.java b/java/com/android/incallui/rtt/impl/RttChatAdapter.java
index fb73d19..6922663 100644
--- a/java/com/android/incallui/rtt/impl/RttChatAdapter.java
+++ b/java/com/android/incallui/rtt/impl/RttChatAdapter.java
@@ -18,8 +18,6 @@
 
 import android.content.Context;
 import android.graphics.drawable.Drawable;
-import android.os.Bundle;
-import android.support.annotation.NonNull;
 import android.support.annotation.Nullable;
 import android.support.v7.widget.RecyclerView;
 import android.text.TextUtils;
@@ -27,6 +25,8 @@
 import android.view.View;
 import android.view.ViewGroup;
 import com.android.dialer.common.LogUtil;
+import com.android.dialer.rtt.RttTranscript;
+import com.android.dialer.rtt.RttTranscriptMessage;
 import java.util.ArrayList;
 import java.util.List;
 
@@ -41,23 +41,14 @@
     void onUpdateLocalMessage(int position);
   }
 
-  private static final String KEY_MESSAGE_DATA = "key_message_data";
-  private static final String KEY_LAST_LOCAL_MESSAGE = "key_last_local_message";
-
   private final Context context;
-  private final List<RttChatMessage> rttMessages;
+  private List<RttChatMessage> rttMessages = new ArrayList<>();
   private int lastIndexOfLocalMessage = -1;
   private final MessageListener messageListener;
 
-  RttChatAdapter(Context context, MessageListener listener, @Nullable Bundle savedInstanceState) {
+  RttChatAdapter(Context context, MessageListener listener) {
     this.context = context;
     this.messageListener = listener;
-    if (savedInstanceState == null) {
-      rttMessages = new ArrayList<>();
-    } else {
-      rttMessages = savedInstanceState.getParcelableArrayList(KEY_MESSAGE_DATA);
-      lastIndexOfLocalMessage = savedInstanceState.getInt(KEY_LAST_LOCAL_MESSAGE);
-    }
   }
 
   @Override
@@ -168,12 +159,35 @@
     }
   }
 
-  void onSaveInstanceState(@NonNull Bundle bundle) {
-    bundle.putParcelableArrayList(KEY_MESSAGE_DATA, (ArrayList<RttChatMessage>) rttMessages);
-    bundle.putInt(KEY_LAST_LOCAL_MESSAGE, lastIndexOfLocalMessage);
-  }
-
   void setAvatarDrawable(Drawable drawable) {
     avatarDrawable = drawable;
   }
+
+  /**
+   * Restores RTT chat history from {@code RttTranscript}.
+   *
+   * @param rttTranscript transcript saved previously.
+   * @return last unfinished local message, return null if there is no current editing local
+   *     message.
+   */
+  @Nullable
+  String onRestoreRttChat(RttTranscript rttTranscript) {
+    LogUtil.enterBlock("RttChatAdapater.onRestoreRttChat");
+    rttMessages = RttChatMessage.fromTranscript(rttTranscript);
+    lastIndexOfLocalMessage = RttChatMessage.getLastIndexLocalMessage(rttMessages);
+    notifyDataSetChanged();
+    if (lastIndexOfLocalMessage < 0) {
+      return null;
+    }
+    RttChatMessage message = rttMessages.get(lastIndexOfLocalMessage);
+    if (!message.isFinished()) {
+      return message.getContent();
+    } else {
+      return null;
+    }
+  }
+
+  List<RttTranscriptMessage> getRttTranscriptMessageList() {
+    return RttChatMessage.toTranscriptMessageList(rttMessages);
+  }
 }
diff --git a/java/com/android/incallui/rtt/impl/RttChatFragment.java b/java/com/android/incallui/rtt/impl/RttChatFragment.java
index a889408..53ad582 100644
--- a/java/com/android/incallui/rtt/impl/RttChatFragment.java
+++ b/java/com/android/incallui/rtt/impl/RttChatFragment.java
@@ -49,6 +49,8 @@
 import com.android.dialer.common.LogUtil;
 import com.android.dialer.common.UiUtil;
 import com.android.dialer.lettertile.LetterTileDrawable;
+import com.android.dialer.rtt.RttTranscript;
+import com.android.dialer.rtt.RttTranscriptMessage;
 import com.android.dialer.util.DrawableConverter;
 import com.android.incallui.audioroute.AudioRouteSelectorDialogFragment.AudioRouteSelectorPresenter;
 import com.android.incallui.call.DialerCall.State;
@@ -69,6 +71,7 @@
 import com.android.incallui.rtt.protocol.RttCallScreen;
 import com.android.incallui.rtt.protocol.RttCallScreenDelegate;
 import com.android.incallui.rtt.protocol.RttCallScreenDelegateFactory;
+import java.util.List;
 
 /** RTT chat fragment to show chat bubbles. */
 public class RttChatFragment extends Fragment
@@ -150,6 +153,11 @@
     inCallButtonUiDelegate.onInCallButtonUiReady(this);
   }
 
+  @Override
+  public List<RttTranscriptMessage> getRttTranscriptMessageList() {
+    return adapter.getRttTranscriptMessageList();
+  }
+
   @Nullable
   @Override
   public View onCreateView(
@@ -172,10 +180,7 @@
           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;
+              resumeInput(lastMessage);
               rttCallScreenDelegate.onLocalMessage("\b");
               return true;
             }
@@ -188,7 +193,7 @@
     layoutManager.setStackFromEnd(true);
     recyclerView.setLayoutManager(layoutManager);
     recyclerView.setHasFixedSize(false);
-    adapter = new RttChatAdapter(getContext(), this, savedInstanceState);
+    adapter = new RttChatAdapter(getContext(), this);
     recyclerView.setAdapter(adapter);
     recyclerView.addOnScrollListener(
         new OnScrollListener() {
@@ -215,9 +220,7 @@
     submitButton.setOnClickListener(
         v -> {
           adapter.submitLocalMessage();
-          isClearingInput = true;
-          editText.setText("");
-          isClearingInput = false;
+          resumeInput("");
           rttCallScreenDelegate.onLocalMessage(Constants.BUBBLE_BREAKER);
           // Auto scrolling for new messages should be resumed since user has submit current
           // message.
@@ -314,6 +317,21 @@
   }
 
   @Override
+  public void onRestoreRttChat(RttTranscript rttTranscript) {
+    String unfinishedLocalMessage = adapter.onRestoreRttChat(rttTranscript);
+    if (unfinishedLocalMessage != null) {
+      resumeInput(unfinishedLocalMessage);
+    }
+  }
+
+  private void resumeInput(String input) {
+    isClearingInput = true;
+    editText.setText(input);
+    editText.setSelection(input.length());
+    isClearingInput = false;
+  }
+
+  @Override
   public void onStart() {
     LogUtil.enterBlock("RttChatFragment.onStart");
     super.onStart();
@@ -324,7 +342,6 @@
   @Override
   public void onSaveInstanceState(@NonNull Bundle bundle) {
     super.onSaveInstanceState(bundle);
-    adapter.onSaveInstanceState(bundle);
   }
 
   @Override
diff --git a/java/com/android/incallui/rtt/impl/RttChatMessage.java b/java/com/android/incallui/rtt/impl/RttChatMessage.java
index 0060b1b..2f3933a 100644
--- a/java/com/android/incallui/rtt/impl/RttChatMessage.java
+++ b/java/com/android/incallui/rtt/impl/RttChatMessage.java
@@ -16,22 +16,23 @@
 
 package com.android.incallui.rtt.impl;
 
-import android.os.Parcel;
-import android.os.Parcelable;
 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.android.incallui.rtt.protocol.Constants;
 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. */
-final class RttChatMessage implements Parcelable {
+final class RttChatMessage {
 
   private static final Splitter SPLITTER = Splitter.on(Constants.BUBBLE_BREAKER);
 
   boolean isRemote;
-  public boolean hasAvatar;
+  long timstamp;
   private final StringBuilder content = new StringBuilder();
   private boolean isFinished;
 
@@ -178,40 +179,39 @@
     return i;
   }
 
-  @Override
-  public int describeContents() {
-    return 0;
+  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;
   }
 
-  @Override
-  public void writeToParcel(Parcel dest, int flags) {
-    dest.writeString(getContent());
-    boolean[] values = new boolean[2];
-    values[0] = isRemote;
-    values[1] = isFinished;
-    dest.writeBooleanArray(values);
+  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 static final Parcelable.Creator<RttChatMessage> CREATOR =
-      new Parcelable.Creator<RttChatMessage>() {
-        @Override
-        public RttChatMessage createFromParcel(Parcel in) {
-          return new RttChatMessage(in);
-        }
-
-        @Override
-        public RttChatMessage[] newArray(int size) {
-          return new RttChatMessage[size];
-        }
-      };
-
-  private RttChatMessage(Parcel in) {
-    content.append(in.readString());
-    boolean[] values = new boolean[2];
-    in.readBooleanArray(values);
-    isRemote = values[0];
-    isFinished = values[1];
+  RttChatMessage() {
+    timstamp = System.currentTimeMillis();
   }
-
-  RttChatMessage() {}
 }
diff --git a/java/com/android/incallui/rtt/protocol/RttCallScreen.java b/java/com/android/incallui/rtt/protocol/RttCallScreen.java
index 531b18d..420274c 100644
--- a/java/com/android/incallui/rtt/protocol/RttCallScreen.java
+++ b/java/com/android/incallui/rtt/protocol/RttCallScreen.java
@@ -17,7 +17,10 @@
 package com.android.incallui.rtt.protocol;
 
 import android.support.v4.app.Fragment;
+import com.android.dialer.rtt.RttTranscript;
+import com.android.dialer.rtt.RttTranscriptMessage;
 import com.android.incallui.incall.protocol.InCallScreen;
+import java.util.List;
 
 /** Interface for call RTT call module. */
 public interface RttCallScreen extends InCallScreen {
@@ -28,6 +31,10 @@
 
   void onRemoteMessage(String message);
 
+  void onRestoreRttChat(RttTranscript rttTranscript);
+
+  List<RttTranscriptMessage> getRttTranscriptMessageList();
+
   Fragment getRttCallScreenFragment();
 
   String getCallId();