Add RTT transcript screen.

Bug: 67596257
Test: CallDetailsCursorLoaderTest
PiperOrigin-RevId: 193259769
Change-Id: I8c6a8eb9a6bf06e9c1c25c45fc035f8db8ae5a65
diff --git a/java/com/android/dialer/app/calllog/CallLogAdapter.java b/java/com/android/dialer/app/calllog/CallLogAdapter.java
index d25a2f3..2f0c9b2 100644
--- a/java/com/android/dialer/app/calllog/CallLogAdapter.java
+++ b/java/com/android/dialer/app/calllog/CallLogAdapter.java
@@ -1008,7 +1008,10 @@
               .setDataUsage(cursor.getLong(CallLogQuery.DATA_USAGE))
               .setDate(cursor.getLong(CallLogQuery.DATE))
               .setDuration(cursor.getLong(CallLogQuery.DURATION))
-              .setFeatures(cursor.getInt(CallLogQuery.FEATURES));
+              .setFeatures(cursor.getInt(CallLogQuery.FEATURES))
+
+              .setCallMappingId(String.valueOf(cursor.getLong(CallLogQuery.DATE)));
+
 
       String phoneAccountComponentName = cursor.getString(CallLogQuery.ACCOUNT_COMPONENT_NAME);
       if (DuoConstants.PHONE_ACCOUNT_COMPONENT_NAME
diff --git a/java/com/android/dialer/calldetails/CallDetailsActivity.java b/java/com/android/dialer/calldetails/CallDetailsActivity.java
index 4fab7fd..f1d0d84 100644
--- a/java/com/android/dialer/calldetails/CallDetailsActivity.java
+++ b/java/com/android/dialer/calldetails/CallDetailsActivity.java
@@ -23,6 +23,7 @@
 import android.database.Cursor;
 import android.os.Bundle;
 import com.android.dialer.CoalescedIds;
+import com.android.dialer.calldetails.CallDetailsEntryViewHolder.CallDetailsEntryListener;
 import com.android.dialer.calldetails.CallDetailsFooterViewHolder.DeleteCallDetailsListener;
 import com.android.dialer.calldetails.CallDetailsFooterViewHolder.ReportCallIdListener;
 import com.android.dialer.calldetails.CallDetailsHeaderViewHolder.CallDetailsHeaderListener;
@@ -89,6 +90,7 @@
 
   @Override
   protected CallDetailsAdapterCommon createAdapter(
+      CallDetailsEntryListener callDetailsEntryListener,
       CallDetailsHeaderListener callDetailsHeaderListener,
       ReportCallIdListener reportCallIdListener,
       DeleteCallDetailsListener deleteCallDetailsListener) {
@@ -96,6 +98,7 @@
         this,
         headerInfo,
         getCallDetailsEntries(),
+        callDetailsEntryListener,
         callDetailsHeaderListener,
         reportCallIdListener,
         deleteCallDetailsListener);
diff --git a/java/com/android/dialer/calldetails/CallDetailsActivityCommon.java b/java/com/android/dialer/calldetails/CallDetailsActivityCommon.java
index 15a010e..dec1230 100644
--- a/java/com/android/dialer/calldetails/CallDetailsActivityCommon.java
+++ b/java/com/android/dialer/calldetails/CallDetailsActivityCommon.java
@@ -55,12 +55,14 @@
 import com.android.dialer.enrichedcall.EnrichedCallComponent;
 import com.android.dialer.enrichedcall.EnrichedCallManager;
 import com.android.dialer.enrichedcall.historyquery.proto.HistoryResult;
+import com.android.dialer.glidephotomanager.PhotoInfo;
 import com.android.dialer.logging.DialerImpression;
 import com.android.dialer.logging.Logger;
 import com.android.dialer.logging.UiAction;
 import com.android.dialer.performancereport.PerformanceReport;
 import com.android.dialer.postcall.PostCall;
 import com.android.dialer.precall.PreCall;
+import com.android.dialer.rtt.RttTranscriptActivity;
 import com.android.dialer.rtt.RttTranscriptUtil;
 import com.google.common.base.Preconditions;
 import com.google.common.util.concurrent.ListenableFuture;
@@ -84,6 +86,8 @@
   public static final String EXTRA_CAN_REPORT_CALLER_ID = "can_report_caller_id";
   public static final String EXTRA_CAN_SUPPORT_ASSISTED_DIALING = "can_support_assisted_dialing";
 
+  private final CallDetailsEntryViewHolder.CallDetailsEntryListener callDetailsEntryListener =
+      new CallDetailsEntryListener(this);
   private final CallDetailsHeaderViewHolder.CallDetailsHeaderListener callDetailsHeaderListener =
       new CallDetailsHeaderListener(this);
   private final CallDetailsFooterViewHolder.DeleteCallDetailsListener deleteCallDetailsListener =
@@ -106,6 +110,7 @@
 
   /** Creates an adapter for {@link OldCallDetailsActivity} or {@link CallDetailsActivity}. */
   protected abstract CallDetailsAdapterCommon createAdapter(
+      CallDetailsEntryViewHolder.CallDetailsEntryListener callDetailsEntryListener,
       CallDetailsHeaderViewHolder.CallDetailsHeaderListener callDetailsHeaderListener,
       CallDetailsFooterViewHolder.ReportCallIdListener reportCallIdListener,
       CallDetailsFooterViewHolder.DeleteCallDetailsListener deleteCallDetailsListener);
@@ -212,7 +217,11 @@
 
   private void setupRecyclerViewForEntries() {
     adapter =
-        createAdapter(callDetailsHeaderListener, reportCallIdListener, deleteCallDetailsListener);
+        createAdapter(
+            callDetailsEntryListener,
+            callDetailsHeaderListener,
+            reportCallIdListener,
+            deleteCallDetailsListener);
 
     RecyclerView recyclerView = findViewById(R.id.recycler_view);
     recyclerView.setLayoutManager(new LinearLayoutManager(this));
@@ -288,6 +297,26 @@
     }
   }
 
+  private static final class CallDetailsEntryListener
+      implements CallDetailsEntryViewHolder.CallDetailsEntryListener {
+    private final WeakReference<CallDetailsActivityCommon> activityWeakReference;
+
+    CallDetailsEntryListener(CallDetailsActivityCommon activity) {
+      this.activityWeakReference = new WeakReference<>(activity);
+    }
+
+    @Override
+    public void showRttTranscript(String transcriptId, String primaryText, PhotoInfo photoInfo) {
+      getActivity()
+          .startActivity(
+              RttTranscriptActivity.getIntent(getActivity(), transcriptId, primaryText, photoInfo));
+    }
+
+    private CallDetailsActivityCommon getActivity() {
+      return Preconditions.checkNotNull(activityWeakReference.get());
+    }
+  }
+
   private static final class CallDetailsHeaderListener
       implements CallDetailsHeaderViewHolder.CallDetailsHeaderListener {
     private final WeakReference<CallDetailsActivityCommon> activityWeakReference;
diff --git a/java/com/android/dialer/calldetails/CallDetailsAdapter.java b/java/com/android/dialer/calldetails/CallDetailsAdapter.java
index 2a4c1ef..40d856f 100644
--- a/java/com/android/dialer/calldetails/CallDetailsAdapter.java
+++ b/java/com/android/dialer/calldetails/CallDetailsAdapter.java
@@ -20,8 +20,10 @@
 import android.content.Context;
 import android.support.v7.widget.RecyclerView;
 import android.view.View;
+import com.android.dialer.calldetails.CallDetailsEntryViewHolder.CallDetailsEntryListener;
 import com.android.dialer.calldetails.CallDetailsFooterViewHolder.DeleteCallDetailsListener;
 import com.android.dialer.calldetails.CallDetailsHeaderViewHolder.CallDetailsHeaderListener;
+import com.android.dialer.glidephotomanager.PhotoInfo;
 
 /**
  * A {@link RecyclerView.Adapter} for {@link CallDetailsActivity}.
@@ -38,12 +40,14 @@
       Context context,
       CallDetailsHeaderInfo calldetailsHeaderInfo,
       CallDetailsEntries callDetailsEntries,
+      CallDetailsEntryListener callDetailsEntryListener,
       CallDetailsHeaderListener callDetailsHeaderListener,
       CallDetailsFooterViewHolder.ReportCallIdListener reportCallIdListener,
       DeleteCallDetailsListener deleteCallDetailsListener) {
     super(
         context,
         callDetailsEntries,
+        callDetailsEntryListener,
         callDetailsHeaderListener,
         reportCallIdListener,
         deleteCallDetailsListener);
@@ -72,4 +76,14 @@
   protected String getNumber() {
     return headerInfo.getDialerPhoneNumber().getNormalizedNumber();
   }
+
+  @Override
+  protected String getPrimaryText() {
+    return headerInfo.getPrimaryText();
+  }
+
+  @Override
+  protected PhotoInfo getPhotoInfo() {
+    return headerInfo.getPhotoInfo();
+  }
 }
diff --git a/java/com/android/dialer/calldetails/CallDetailsAdapterCommon.java b/java/com/android/dialer/calldetails/CallDetailsAdapterCommon.java
index a79642b..ec9263f 100644
--- a/java/com/android/dialer/calldetails/CallDetailsAdapterCommon.java
+++ b/java/com/android/dialer/calldetails/CallDetailsAdapterCommon.java
@@ -25,6 +25,7 @@
 import android.view.View;
 import android.view.ViewGroup;
 import com.android.dialer.calldetails.CallDetailsEntries.CallDetailsEntry;
+import com.android.dialer.calldetails.CallDetailsEntryViewHolder.CallDetailsEntryListener;
 import com.android.dialer.calldetails.CallDetailsFooterViewHolder.DeleteCallDetailsListener;
 import com.android.dialer.calldetails.CallDetailsFooterViewHolder.ReportCallIdListener;
 import com.android.dialer.calldetails.CallDetailsHeaderViewHolder.CallDetailsHeaderListener;
@@ -33,6 +34,7 @@
 import com.android.dialer.calllogutils.CallbackActionHelper.CallbackAction;
 import com.android.dialer.common.Assert;
 import com.android.dialer.duo.DuoComponent;
+import com.android.dialer.glidephotomanager.PhotoInfo;
 
 /**
  * Contains common logic shared between {@link OldCallDetailsAdapter} and {@link
@@ -44,6 +46,7 @@
   private static final int CALL_ENTRY_VIEW_TYPE = 2;
   private static final int FOOTER_VIEW_TYPE = 3;
 
+  private final CallDetailsEntryListener callDetailsEntryListener;
   private final CallDetailsHeaderListener callDetailsHeaderListener;
   private final ReportCallIdListener reportCallIdListener;
   private final DeleteCallDetailsListener deleteCallDetailsListener;
@@ -60,13 +63,21 @@
   /** Returns the phone number of the call details. */
   protected abstract String getNumber();
 
+  /** Returns the primary text shown on call details toolbar, usually contact name or number. */
+  protected abstract String getPrimaryText();
+
+  /** Returns {@link PhotoInfo} of the contact. */
+  protected abstract PhotoInfo getPhotoInfo();
+
   CallDetailsAdapterCommon(
       Context context,
       CallDetailsEntries callDetailsEntries,
+      CallDetailsEntryListener callDetailsEntryListener,
       CallDetailsHeaderListener callDetailsHeaderListener,
       ReportCallIdListener reportCallIdListener,
       DeleteCallDetailsListener deleteCallDetailsListener) {
     this.callDetailsEntries = callDetailsEntries;
+    this.callDetailsEntryListener = callDetailsEntryListener;
     this.callDetailsHeaderListener = callDetailsHeaderListener;
     this.reportCallIdListener = reportCallIdListener;
     this.deleteCallDetailsListener = deleteCallDetailsListener;
@@ -84,7 +95,7 @@
             inflater.inflate(R.layout.contact_container, parent, false), callDetailsHeaderListener);
       case CALL_ENTRY_VIEW_TYPE:
         return new CallDetailsEntryViewHolder(
-            inflater.inflate(R.layout.call_details_entry, parent, false));
+            inflater.inflate(R.layout.call_details_entry, parent, false), callDetailsEntryListener);
       case FOOTER_VIEW_TYPE:
         return new CallDetailsFooterViewHolder(
             inflater.inflate(R.layout.call_details_footer, parent, false),
@@ -108,6 +119,8 @@
       CallDetailsEntry entry = callDetailsEntries.getEntries(position - 1);
       viewHolder.setCallDetails(
           getNumber(),
+          getPrimaryText(),
+          getPhotoInfo(),
           entry,
           callTypeHelper,
           !entry.getHistoryResultsList().isEmpty() && position != getItemCount() - 2);
diff --git a/java/com/android/dialer/calldetails/CallDetailsCursorLoader.java b/java/com/android/dialer/calldetails/CallDetailsCursorLoader.java
index 3b8af40..c22ec73 100644
--- a/java/com/android/dialer/calldetails/CallDetailsCursorLoader.java
+++ b/java/com/android/dialer/calldetails/CallDetailsCursorLoader.java
@@ -139,7 +139,10 @@
         .setFeatures(cursor.getInt(FEATURES))
         .setDate(cursor.getLong(TIMESTAMP))
         .setDuration(cursor.getLong(DURATION))
-        .setDataUsage(cursor.getLong(DATA_USAGE));
+        .setDataUsage(cursor.getLong(DATA_USAGE))
+
+        .setCallMappingId(String.valueOf(cursor.getLong(TIMESTAMP)));
+
 
     String phoneAccountComponentName = cursor.getString(PHONE_ACCOUNT_COMPONENT_NAME);
     entry.setIsDuoCall(
diff --git a/java/com/android/dialer/calldetails/CallDetailsEntryViewHolder.java b/java/com/android/dialer/calldetails/CallDetailsEntryViewHolder.java
index 5c4a196..37b212a 100644
--- a/java/com/android/dialer/calldetails/CallDetailsEntryViewHolder.java
+++ b/java/com/android/dialer/calldetails/CallDetailsEntryViewHolder.java
@@ -37,6 +37,7 @@
 import com.android.dialer.compat.AppCompatConstants;
 import com.android.dialer.enrichedcall.historyquery.proto.HistoryResult;
 import com.android.dialer.enrichedcall.historyquery.proto.HistoryResult.Type;
+import com.android.dialer.glidephotomanager.PhotoInfo;
 import com.android.dialer.oem.MotorolaUtils;
 import com.android.dialer.util.DialerUtils;
 import com.android.dialer.util.IntentUtil;
@@ -44,6 +45,14 @@
 /** ViewHolder for call entries in {@link OldCallDetailsActivity} or {@link CallDetailsActivity}. */
 public class CallDetailsEntryViewHolder extends ViewHolder {
 
+  /** Listener for the call details header */
+  interface CallDetailsEntryListener {
+    /** Shows RTT transcript. */
+    void showRttTranscript(String transcriptId, String primaryText, PhotoInfo photoInfo);
+  }
+
+  private final CallDetailsEntryListener callDetailsEntryListener;
+
   private final CallTypeIconsView callTypeIcon;
   private final TextView callTypeText;
   private final TextView callTime;
@@ -65,7 +74,8 @@
 
   private final Context context;
 
-  public CallDetailsEntryViewHolder(View container) {
+  public CallDetailsEntryViewHolder(
+      View container, CallDetailsEntryListener callDetailsEntryListener) {
     super(container);
     context = container.getContext();
 
@@ -83,10 +93,13 @@
     multimediaAttachmentsNumber =
         (TextView) container.findViewById(R.id.multimedia_attachments_number);
     rttTranscript = container.findViewById(R.id.rtt_transcript);
+    this.callDetailsEntryListener = callDetailsEntryListener;
   }
 
   void setCallDetails(
       String number,
+      String primaryText,
+      PhotoInfo photoInfo,
       CallDetailsEntry entry,
       CallTypeHelper callTypeHelper,
       boolean showMultimediaDivider) {
@@ -133,6 +146,10 @@
         rttTranscript.setText(R.string.rtt_transcript_link);
         rttTranscript.setTextAppearance(R.style.RttTranscriptLink);
         rttTranscript.setClickable(true);
+        rttTranscript.setOnClickListener(
+            v ->
+                callDetailsEntryListener.showRttTranscript(
+                    entry.getCallMappingId(), primaryText, photoInfo));
       } else {
         rttTranscript.setText(R.string.rtt_transcript_not_available);
         rttTranscript.setTextAppearance(R.style.RttTranscriptMessage);
diff --git a/java/com/android/dialer/calldetails/OldCallDetailsActivity.java b/java/com/android/dialer/calldetails/OldCallDetailsActivity.java
index c974367..26217ab 100644
--- a/java/com/android/dialer/calldetails/OldCallDetailsActivity.java
+++ b/java/com/android/dialer/calldetails/OldCallDetailsActivity.java
@@ -18,6 +18,7 @@
 
 import android.content.Context;
 import android.content.Intent;
+import com.android.dialer.calldetails.CallDetailsEntryViewHolder.CallDetailsEntryListener;
 import com.android.dialer.calldetails.CallDetailsFooterViewHolder.DeleteCallDetailsListener;
 import com.android.dialer.calldetails.CallDetailsFooterViewHolder.ReportCallIdListener;
 import com.android.dialer.calldetails.CallDetailsHeaderViewHolder.CallDetailsHeaderListener;
@@ -76,6 +77,7 @@
 
   @Override
   protected CallDetailsAdapterCommon createAdapter(
+      CallDetailsEntryListener callDetailsEntryListener,
       CallDetailsHeaderListener callDetailsHeaderListener,
       ReportCallIdListener reportCallIdListener,
       DeleteCallDetailsListener deleteCallDetailsListener) {
@@ -83,6 +85,7 @@
         /* context = */ this,
         contact,
         getCallDetailsEntries(),
+        callDetailsEntryListener,
         callDetailsHeaderListener,
         reportCallIdListener,
         deleteCallDetailsListener);
diff --git a/java/com/android/dialer/calldetails/OldCallDetailsAdapter.java b/java/com/android/dialer/calldetails/OldCallDetailsAdapter.java
index 010f5cd..878803c 100644
--- a/java/com/android/dialer/calldetails/OldCallDetailsAdapter.java
+++ b/java/com/android/dialer/calldetails/OldCallDetailsAdapter.java
@@ -20,9 +20,12 @@
 import android.content.Context;
 import android.support.v7.widget.RecyclerView;
 import android.view.View;
+import com.android.dialer.calldetails.CallDetailsEntryViewHolder.CallDetailsEntryListener;
 import com.android.dialer.calldetails.CallDetailsFooterViewHolder.DeleteCallDetailsListener;
 import com.android.dialer.calldetails.CallDetailsHeaderViewHolder.CallDetailsHeaderListener;
 import com.android.dialer.dialercontact.DialerContact;
+import com.android.dialer.glidephotomanager.PhotoInfo;
+import com.android.dialer.lettertile.LetterTileDrawable;
 
 /**
  * A {@link RecyclerView.Adapter} for {@link OldCallDetailsActivity}.
@@ -39,12 +42,14 @@
       Context context,
       DialerContact contact,
       CallDetailsEntries callDetailsEntries,
+      CallDetailsEntryListener callDetailsEntryListener,
       CallDetailsHeaderListener callDetailsHeaderListener,
       CallDetailsFooterViewHolder.ReportCallIdListener reportCallIdListener,
       DeleteCallDetailsListener deleteCallDetailsListener) {
     super(
         context,
         callDetailsEntries,
+        callDetailsEntryListener,
         callDetailsHeaderListener,
         reportCallIdListener,
         deleteCallDetailsListener);
@@ -70,4 +75,32 @@
   protected String getNumber() {
     return contact.getNumber();
   }
+
+  @Override
+  protected String getPrimaryText() {
+    return contact.getNameOrNumber();
+  }
+
+  @Override
+  protected PhotoInfo getPhotoInfo() {
+    PhotoInfo.Builder builder =
+        PhotoInfo.newBuilder()
+            .setPhotoUri(contact.getPhotoUri())
+            .setPhotoId(contact.getPhotoId())
+            .setName(contact.getNameOrNumber())
+            .setLookupUri(contact.getContactUri());
+    switch (contact.getContactType()) {
+      case LetterTileDrawable.TYPE_VOICEMAIL:
+        builder.setIsVoicemail(true);
+        break;
+      case LetterTileDrawable.TYPE_BUSINESS:
+        builder.setIsBusiness(true);
+        break;
+      case LetterTileDrawable.TYPE_SPAM:
+        builder.setIsSpam(true);
+        break;
+      default: // fall out
+    }
+    return builder.build();
+  }
 }
diff --git a/java/com/android/dialer/calldetails/proto/call_details_entries.proto b/java/com/android/dialer/calldetails/proto/call_details_entries.proto
index e0202cd..0f11b53 100644
--- a/java/com/android/dialer/calldetails/proto/call_details_entries.proto
+++ b/java/com/android/dialer/calldetails/proto/call_details_entries.proto
@@ -20,6 +20,14 @@
     repeated enrichedcall.historyquery.proto.HistoryResult history_results = 7;
     optional bool is_duo_call = 8;
     optional bool has_rtt_transcript = 9;
+    // A unique ID that could be used to map a call log entry to a {@link
+    // android.telecom.Call}. This is different from call_id which is id of call
+    // log entry.
+    // On pre-Q this will be {@link android.provider.CallLog.Calls#DATE} which
+    // is same as {@link com.android.telecom.Call#getCreationTimeMillis()}.
+    // Starting from Q this will be a call UUID generated by system to associate
+    // a call log to a telecom call.
+    optional string call_mapping_id = 10;
   }
 
   repeated CallDetailsEntry entries = 1;
diff --git a/java/com/android/dialer/glidephotomanager/GlidePhotoManager.java b/java/com/android/dialer/glidephotomanager/GlidePhotoManager.java
index 519a394..de16c38 100644
--- a/java/com/android/dialer/glidephotomanager/GlidePhotoManager.java
+++ b/java/com/android/dialer/glidephotomanager/GlidePhotoManager.java
@@ -17,6 +17,7 @@
 package com.android.dialer.glidephotomanager;
 
 import android.support.annotation.MainThread;
+import android.widget.ImageView;
 import android.widget.QuickContactBadge;
 
 /** Class to load photo for call/contacts */
@@ -30,4 +31,13 @@
    */
   @MainThread
   void loadQuickContactBadge(QuickContactBadge badge, PhotoInfo photoInfo);
+
+  /**
+   * Load {@code photoInfo} into the {@code imageView}. The loading is performed in the background
+   * and a placeholder will be used appropriately. {@code imageView} must be already attached to an
+   * activity/fragment, and the load will be automatically canceled if the lifecycle of the activity
+   * ends.
+   */
+  @MainThread
+  void loadContactPhoto(ImageView imageView, PhotoInfo photoInfo);
 }
diff --git a/java/com/android/dialer/glidephotomanager/impl/GlidePhotoManagerImpl.java b/java/com/android/dialer/glidephotomanager/impl/GlidePhotoManagerImpl.java
index 202307a..562177c 100644
--- a/java/com/android/dialer/glidephotomanager/impl/GlidePhotoManagerImpl.java
+++ b/java/com/android/dialer/glidephotomanager/impl/GlidePhotoManagerImpl.java
@@ -25,6 +25,7 @@
 import android.support.annotation.Nullable;
 import android.telecom.TelecomManager;
 import android.text.TextUtils;
+import android.widget.ImageView;
 import android.widget.QuickContactBadge;
 import com.android.dialer.common.Assert;
 import com.android.dialer.glide.GlideApp;
@@ -54,8 +55,15 @@
             ? DefaultLookupUriGenerator.generateUri(photoInfo)
             : parseUri(photoInfo.getLookupUri()));
     badge.setOverlay(null);
-    GlideRequest<Drawable> request = buildRequest(GlideApp.with(badge), photoInfo);
-    request.into(badge);
+    loadContactPhoto(badge, photoInfo);
+  }
+
+  @MainThread
+  @Override
+  public void loadContactPhoto(ImageView imageView, PhotoInfo photoInfo) {
+    Assert.isMainThread();
+    GlideRequest<Drawable> request = buildRequest(GlideApp.with(imageView), photoInfo);
+    request.into(imageView);
   }
 
   private GlideRequest<Drawable> buildRequest(GlideRequests requestManager, PhotoInfo photoInfo) {
diff --git a/java/com/android/dialer/rtt/AndroidManifest.xml b/java/com/android/dialer/rtt/AndroidManifest.xml
new file mode 100644
index 0000000..c92fb1c
--- /dev/null
+++ b/java/com/android/dialer/rtt/AndroidManifest.xml
@@ -0,0 +1,21 @@
+<!--
+ ~ 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
+ -->
+<manifest package="com.android.dialer.rtt"
+    xmlns:android="http://schemas.android.com/apk/res/android">
+  <application>
+    <activity android:name=".RttTranscriptActivity" />
+  </application>
+</manifest>
\ No newline at end of file
diff --git a/java/com/android/dialer/rtt/RttTranscriptActivity.java b/java/com/android/dialer/rtt/RttTranscriptActivity.java
new file mode 100644
index 0000000..2087250
--- /dev/null
+++ b/java/com/android/dialer/rtt/RttTranscriptActivity.java
@@ -0,0 +1,122 @@
+/*
+ * 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.rtt;
+
+import android.content.Context;
+import android.content.Intent;
+import android.os.Bundle;
+import android.support.annotation.Nullable;
+import android.support.v7.app.ActionBar;
+import android.support.v7.app.AppCompatActivity;
+import android.support.v7.widget.LinearLayoutManager;
+import android.support.v7.widget.RecyclerView;
+import android.view.MenuItem;
+import com.android.dialer.common.Assert;
+import com.android.dialer.common.concurrent.DialerExecutorComponent;
+import com.android.dialer.common.concurrent.UiListener;
+import com.android.dialer.glidephotomanager.PhotoInfo;
+import com.android.dialer.protos.ProtoParsers;
+import com.google.common.util.concurrent.ListenableFuture;
+
+/** Activity holds RTT transcript. */
+public class RttTranscriptActivity extends AppCompatActivity {
+
+  public static final String EXTRA_TRANSCRIPT_ID = "extra_transcript_id";
+  public static final String EXTRA_PRIMARY_TEXT = "extra_primary_text";
+  public static final String EXTRA_PHOTO_INFO = "extra_photo_info";
+
+  private RttTranscriptAdapter adapter;
+  private UiListener<RttTranscript> rttTranscriptUiListener;
+
+  public static Intent getIntent(
+      Context context, String transcriptId, String primaryText, PhotoInfo photoInfo) {
+    Intent intent = new Intent(context, RttTranscriptActivity.class);
+    intent.putExtra(RttTranscriptActivity.EXTRA_TRANSCRIPT_ID, transcriptId);
+    intent.putExtra(RttTranscriptActivity.EXTRA_PRIMARY_TEXT, primaryText);
+    ProtoParsers.put(intent, RttTranscriptActivity.EXTRA_PHOTO_INFO, Assert.isNotNull(photoInfo));
+    return intent;
+  }
+
+  @Override
+  protected void onCreate(@Nullable Bundle bundle) {
+    super.onCreate(bundle);
+    setContentView(R.layout.activity_rtt_transcript);
+    ActionBar actionBar = getSupportActionBar();
+    actionBar.setDisplayShowHomeEnabled(true);
+    actionBar.setDisplayHomeAsUpEnabled(true);
+
+    RecyclerView recyclerView = findViewById(R.id.rtt_recycler_view);
+    LinearLayoutManager layoutManager = new LinearLayoutManager(this);
+    layoutManager.setStackFromEnd(true);
+    recyclerView.setLayoutManager(layoutManager);
+    recyclerView.setHasFixedSize(true);
+    adapter = new RttTranscriptAdapter(this);
+    recyclerView.setAdapter(adapter);
+
+    rttTranscriptUiListener =
+        DialerExecutorComponent.get(this)
+            .createUiListener(getFragmentManager(), "Load RTT transcript");
+    handleIntent(getIntent());
+  }
+
+  private void handleIntent(Intent intent) {
+    Assert.checkArgument(intent.hasExtra(EXTRA_TRANSCRIPT_ID));
+    Assert.checkArgument(intent.hasExtra(EXTRA_PRIMARY_TEXT));
+    Assert.checkArgument(intent.hasExtra(EXTRA_PHOTO_INFO));
+
+    String id = intent.getStringExtra(EXTRA_TRANSCRIPT_ID);
+    rttTranscriptUiListener.listen(
+        this,
+        getRttTranscript(id),
+        adapter::setRttTranscript,
+        throwable -> {
+          throw new RuntimeException(throwable);
+        });
+
+    String primaryText = intent.getStringExtra(EXTRA_PRIMARY_TEXT);
+    getSupportActionBar().setTitle(primaryText);
+
+    PhotoInfo photoInfo =
+        ProtoParsers.getTrusted(intent, EXTRA_PHOTO_INFO, PhotoInfo.getDefaultInstance());
+    // Photo shown here shouldn't have video or RTT badge.
+    PhotoInfo sanitizedPhotoInfo =
+        PhotoInfo.newBuilder().mergeFrom(photoInfo).setIsRtt(false).setIsVideo(false).build();
+    adapter.setPhotoInfo(sanitizedPhotoInfo);
+  }
+
+  @Override
+  protected void onNewIntent(Intent intent) {
+    super.onNewIntent(intent);
+    handleIntent(intent);
+  }
+
+  @Override
+  public boolean onOptionsItemSelected(MenuItem item) {
+    final int itemId = item.getItemId();
+    if (itemId == android.R.id.home) {
+      onBackPressed();
+      return true;
+    }
+    return super.onOptionsItemSelected(item);
+  }
+
+  private ListenableFuture<RttTranscript> getRttTranscript(String id) {
+    return DialerExecutorComponent.get(this)
+        .backgroundExecutor()
+        .submit(() -> new RttTranscriptUtil(this).getRttTranscript(id));
+  }
+}
diff --git a/java/com/android/dialer/rtt/RttTranscriptAdapter.java b/java/com/android/dialer/rtt/RttTranscriptAdapter.java
new file mode 100644
index 0000000..6e03034
--- /dev/null
+++ b/java/com/android/dialer/rtt/RttTranscriptAdapter.java
@@ -0,0 +1,88 @@
+/*
+ * 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.rtt;
+
+import android.content.Context;
+import android.support.v7.widget.RecyclerView;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import com.android.dialer.glidephotomanager.PhotoInfo;
+
+/** Adapter class for holding RTT chat data. */
+public class RttTranscriptAdapter extends RecyclerView.Adapter<RttTranscriptMessageViewHolder> {
+
+  private PhotoInfo photoInfo;
+
+  private final Context context;
+  private RttTranscript rttTranscript;
+
+  RttTranscriptAdapter(Context context) {
+    this.context = context;
+  }
+
+  @Override
+  public RttTranscriptMessageViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
+    LayoutInflater layoutInflater = LayoutInflater.from(context);
+    View view = layoutInflater.inflate(R.layout.rtt_transcript_list_item, parent, false);
+    return new RttTranscriptMessageViewHolder(view);
+  }
+
+  @Override
+  public int getItemViewType(int position) {
+    return super.getItemViewType(position);
+  }
+
+  @Override
+  public void onBindViewHolder(RttTranscriptMessageViewHolder rttChatMessageViewHolder, int i) {
+    boolean isSameGroup = false;
+    boolean hasMoreInSameGroup = false;
+    RttTranscriptMessage rttTranscriptMessage = rttTranscript.getMessages(i);
+    if (i > 0) {
+      isSameGroup =
+          rttTranscriptMessage.getIsRemote() == rttTranscript.getMessages(i - 1).getIsRemote();
+    }
+    if (i + 1 < getItemCount()) {
+      hasMoreInSameGroup =
+          rttTranscriptMessage.getIsRemote() == rttTranscript.getMessages(i + 1).getIsRemote();
+    }
+    rttChatMessageViewHolder.setMessage(rttTranscriptMessage, isSameGroup, photoInfo);
+    if (hasMoreInSameGroup) {
+      rttChatMessageViewHolder.hideTimestamp();
+    } else {
+      rttChatMessageViewHolder.showTimestamp(
+          rttTranscriptMessage.getTimestamp(), rttTranscriptMessage.getIsRemote(), i == 0);
+    }
+  }
+
+  @Override
+  public int getItemCount() {
+    if (rttTranscript == null) {
+      return 0;
+    }
+    return rttTranscript.getMessagesCount();
+  }
+
+  void setRttTranscript(RttTranscript rttTranscript) {
+    this.rttTranscript = rttTranscript;
+    notifyDataSetChanged();
+  }
+
+  void setPhotoInfo(PhotoInfo photoInfo) {
+    this.photoInfo = photoInfo;
+  }
+}
diff --git a/java/com/android/dialer/rtt/RttTranscriptMessageViewHolder.java b/java/com/android/dialer/rtt/RttTranscriptMessageViewHolder.java
new file mode 100644
index 0000000..daa8136
--- /dev/null
+++ b/java/com/android/dialer/rtt/RttTranscriptMessageViewHolder.java
@@ -0,0 +1,95 @@
+/*
+ * 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.rtt;
+
+import android.content.Context;
+import android.content.res.Resources;
+import android.support.v7.widget.RecyclerView.ViewHolder;
+import android.text.format.DateUtils;
+import android.view.Gravity;
+import android.view.View;
+import android.widget.ImageView;
+import android.widget.LinearLayout;
+import android.widget.LinearLayout.LayoutParams;
+import android.widget.TextView;
+import com.android.dialer.glidephotomanager.GlidePhotoManagerComponent;
+import com.android.dialer.glidephotomanager.PhotoInfo;
+
+/** ViewHolder class for RTT chat message bubble. */
+public class RttTranscriptMessageViewHolder extends ViewHolder {
+
+  private final TextView messageTextView;
+  private final Resources resources;
+  private final ImageView avatarImageView;
+  private final View container;
+  private final TextView timestampTextView;
+
+  RttTranscriptMessageViewHolder(View view) {
+    super(view);
+    container = view.findViewById(R.id.rtt_chat_message_container);
+    messageTextView = view.findViewById(R.id.rtt_chat_message);
+    avatarImageView = view.findViewById(R.id.rtt_chat_avatar);
+    timestampTextView = view.findViewById(R.id.rtt_chat_timestamp);
+    resources = view.getResources();
+  }
+
+  void setMessage(RttTranscriptMessage message, boolean isSameGroup, PhotoInfo photoInfo) {
+    messageTextView.setText(message.getContent());
+    LinearLayout.LayoutParams params = (LayoutParams) container.getLayoutParams();
+    params.gravity = message.getIsRemote() ? Gravity.START : Gravity.END;
+    params.topMargin =
+        isSameGroup
+            ? resources.getDimensionPixelSize(R.dimen.rtt_transcript_same_group_message_margin_top)
+            : resources.getDimensionPixelSize(R.dimen.rtt_transcript_message_margin_top);
+    container.setLayoutParams(params);
+    messageTextView.setEnabled(message.getIsRemote());
+    if (message.getIsRemote()) {
+      if (isSameGroup) {
+        avatarImageView.setVisibility(View.INVISIBLE);
+      } else {
+        avatarImageView.setVisibility(View.VISIBLE);
+        GlidePhotoManagerComponent.get(container.getContext())
+            .glidePhotoManager()
+            .loadContactPhoto(avatarImageView, photoInfo);
+      }
+      messageTextView.setTextAppearance(R.style.RttTranscriptBubble_Remote);
+    } else {
+      avatarImageView.setVisibility(View.GONE);
+      messageTextView.setTextAppearance(R.style.RttTranscriptBubble_Local);
+    }
+  }
+
+  void showTimestamp(long timestamp, boolean isRemote, boolean showFullDate) {
+    timestampTextView.setVisibility(View.VISIBLE);
+    timestampTextView.setText(
+        getTimestampText(timestampTextView.getContext(), timestamp, showFullDate));
+    timestampTextView.setGravity(isRemote ? Gravity.START : Gravity.END);
+  }
+
+  void hideTimestamp() {
+    timestampTextView.setVisibility(View.GONE);
+  }
+
+  private String getTimestampText(Context context, long timestamp, boolean showFullDate) {
+    return DateUtils.formatDateTime(
+        context,
+        timestamp,
+        showFullDate
+            ? DateUtils.FORMAT_SHOW_DATE | DateUtils.FORMAT_SHOW_TIME
+            : DateUtils.FORMAT_SHOW_TIME);
+  }
+}
diff --git a/java/com/android/dialer/rtt/RttTranscriptUtil.java b/java/com/android/dialer/rtt/RttTranscriptUtil.java
index e55d2ea..19b46b0 100644
--- a/java/com/android/dialer/rtt/RttTranscriptUtil.java
+++ b/java/com/android/dialer/rtt/RttTranscriptUtil.java
@@ -30,7 +30,13 @@
   private final RttTranscriptDatabaseHelper databaseHelper;
 
   public RttTranscriptUtil(Context context) {
-    databaseHelper = new RttTranscriptDatabaseHelper(context);
+    databaseHelper = new RttTranscriptDatabaseHelper(context.getApplicationContext());
+  }
+
+  @Override
+  protected void finalize() throws Throwable {
+    databaseHelper.close();
+    super.finalize();
   }
 
   /** @return true if there is RTT transcript available. */
diff --git a/java/com/android/dialer/rtt/res/color/bubble_background.xml b/java/com/android/dialer/rtt/res/color/bubble_background.xml
new file mode 100644
index 0000000..fb29ab6
--- /dev/null
+++ b/java/com/android/dialer/rtt/res/color/bubble_background.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ 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
+  -->
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+  <item android:state_enabled="false"
+      android:color="@android:color/white" />
+  <item android:color="@color/rtt_transcript_primary_color" />
+</selector>
\ No newline at end of file
diff --git a/java/com/android/dialer/rtt/res/drawable/message_bubble.xml b/java/com/android/dialer/rtt/res/drawable/message_bubble.xml
new file mode 100644
index 0000000..2b01f62
--- /dev/null
+++ b/java/com/android/dialer/rtt/res/drawable/message_bubble.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ 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
+  -->
+<shape xmlns:android="http://schemas.android.com/apk/res/android"
+    android:shape="rectangle">
+  <solid android:color="@android:color/white"/>
+  <corners android:radius="20dp"/>
+</shape>
\ No newline at end of file
diff --git a/java/com/android/dialer/rtt/res/layout/activity_rtt_transcript.xml b/java/com/android/dialer/rtt/res/layout/activity_rtt_transcript.xml
new file mode 100644
index 0000000..628a793
--- /dev/null
+++ b/java/com/android/dialer/rtt/res/layout/activity_rtt_transcript.xml
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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.
+-->
+
+<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    android:background="@color/rtt_transcript_background_color">
+
+  <android.support.v7.widget.RecyclerView
+      android:id="@+id/rtt_recycler_view"
+      android:layout_width="match_parent"
+      android:layout_height="match_parent"
+      android:paddingTop="16dp"
+      android:paddingBottom="16dp"
+      android:clipToPadding="false"/>
+
+</FrameLayout>
diff --git a/java/com/android/dialer/rtt/res/layout/rtt_transcript_list_item.xml b/java/com/android/dialer/rtt/res/layout/rtt_transcript_list_item.xml
new file mode 100644
index 0000000..d86a682
--- /dev/null
+++ b/java/com/android/dialer/rtt/res/layout/rtt_transcript_list_item.xml
@@ -0,0 +1,54 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ 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
+  -->
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="match_parent"
+    android:layout_height="wrap_content"
+    android:layout_marginEnd="8dp"
+    android:orientation="vertical">
+  <LinearLayout
+      android:id="@+id/rtt_chat_message_container"
+      android:layout_width="wrap_content"
+      android:layout_height="wrap_content"
+      android:orientation="horizontal">
+    <ImageView
+        android:id="@+id/rtt_chat_avatar"
+        android:layout_width="@dimen/rtt_transcript_avatar_size"
+        android:layout_height="@dimen/rtt_transcript_avatar_size"
+        android:layout_marginStart="8dp"
+        android:layout_marginEnd="8dp"
+        android:visibility="gone"/>
+    <TextView
+        android:id="@+id/rtt_chat_message"
+        style="@style/RttTranscriptBubble"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:paddingTop="9dp"
+        android:paddingBottom="9dp"
+        android:paddingStart="12dp"
+        android:paddingEnd="12dp"
+        android:background="@drawable/message_bubble"
+        android:backgroundTint="@color/bubble_background"
+        android:maxWidth="292dp"/>
+  </LinearLayout>
+  <TextView
+      android:id="@+id/rtt_chat_timestamp"
+      style="@style/RttTranscriptBubble.Timestamp"
+      android:paddingStart="64dp"
+      android:paddingEnd="8dp"
+      android:layout_width="match_parent"
+      android:layout_height="wrap_content"/>
+</LinearLayout>
\ No newline at end of file
diff --git a/java/com/android/dialer/rtt/res/values/colors.xml b/java/com/android/dialer/rtt/res/values/colors.xml
new file mode 100644
index 0000000..5de06f9
--- /dev/null
+++ b/java/com/android/dialer/rtt/res/values/colors.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ 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
+  -->
+<resources>
+  <color name="rtt_transcript_primary_color">#37474F</color>
+  <color name="rtt_transcript_background_color">#ECEFF1</color>
+</resources>
\ No newline at end of file
diff --git a/java/com/android/dialer/rtt/res/values/dimens.xml b/java/com/android/dialer/rtt/res/values/dimens.xml
new file mode 100644
index 0000000..a36cdd7
--- /dev/null
+++ b/java/com/android/dialer/rtt/res/values/dimens.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ 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
+  -->
+<resources>
+  <dimen name="rtt_transcript_message_margin_top">16dp</dimen>
+  <dimen name="rtt_transcript_same_group_message_margin_top">2dp</dimen>
+  <dimen name="rtt_transcript_avatar_size">40dp</dimen>
+</resources>
diff --git a/java/com/android/dialer/rtt/res/values/styles.xml b/java/com/android/dialer/rtt/res/values/styles.xml
new file mode 100644
index 0000000..d8bc245
--- /dev/null
+++ b/java/com/android/dialer/rtt/res/values/styles.xml
@@ -0,0 +1,36 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ 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
+  -->
+<resources>
+  <style name="RttTranscriptBubble">
+    <item name="android:fontFamily">sans-serif</item>
+    <item name="android:textColor">#DD000000</item>
+    <item name="android:textSize">16sp</item>
+  </style>
+
+  <style name="RttTranscriptBubble.Remote">
+    <item name="android:textColor">#FFFFFF</item>
+  </style>
+
+  <style name="RttTranscriptBubble.Local">
+    <item name="android:textColor">#DD000000</item>
+  </style>
+
+  <style name="RttTranscriptBubble.Timestamp">
+    <item name="android:textColor">#757575</item>
+    <item name="android:textSize">12sp</item>
+  </style>
+</resources>
\ No newline at end of file
diff --git a/java/com/android/incallui/RttCallPresenter.java b/java/com/android/incallui/RttCallPresenter.java
index 21e28ce..2114691 100644
--- a/java/com/android/incallui/RttCallPresenter.java
+++ b/java/com/android/incallui/RttCallPresenter.java
@@ -90,7 +90,9 @@
     LogUtil.enterBlock("RttCallPresenter.saveTranscript");
     RttTranscript.Builder builder = RttTranscript.newBuilder();
     builder
+
         .setId(String.valueOf(dialerCall.getCreationTimeMillis()))
+
         .setTimestamp(dialerCall.getCreationTimeMillis())
         .setNumber(dialerCall.getNumber())
         .addAllMessages(rttCallScreen.getRttTranscriptMessageList());
diff --git a/packages.mk b/packages.mk
index 5ccef53..f310669 100644
--- a/packages.mk
+++ b/packages.mk
@@ -53,6 +53,7 @@
 	com.android.dialer.precall.externalreceiver \
 	com.android.dialer.preferredsim.impl \
 	com.android.dialer.preferredsim.suggestion \
+	com.android.dialer.rtt \
 	com.android.dialer.searchfragment.common \
 	com.android.dialer.searchfragment.cp2 \
 	com.android.dialer.searchfragment.directories \