Snap for 4632767 from f2874ff76230a05421c653e1aed6e288062d82cf to pi-release

Change-Id: I0f473726a9ab6e894c265e50224ac64bde8bcabe
diff --git a/assets/quantum/res/drawable/quantum_ic_add_call_vd_theme_24.xml b/assets/quantum/res/drawable/quantum_ic_add_call_vd_theme_24.xml
new file mode 100644
index 0000000..b7d3a09
--- /dev/null
+++ b/assets/quantum/res/drawable/quantum_ic_add_call_vd_theme_24.xml
@@ -0,0 +1,25 @@
+<!--
+  ~ 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
+  -->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="24dp"
+    android:height="24dp"
+    android:viewportWidth="24.0"
+    android:viewportHeight="24.0"
+    android:tint="?attr/colorControlNormal">
+  <path
+      android:fillColor="@android:color/white"
+      android:pathData="M20,15.5c-1.25,0 -2.45,-0.2 -3.57,-0.57 -0.35,-0.11 -0.74,-0.03 -1.02,0.24l-2.2,2.2c-2.83,-1.44 -5.15,-3.75 -6.59,-6.59l2.2,-2.21c0.28,-0.26 0.36,-0.65 0.25,-1C8.7,6.45 8.5,5.25 8.5,4c0,-0.55 -0.45,-1 -1,-1H4c-0.55,0 -1,0.45 -1,1 0,9.39 7.61,17 17,17 0.55,0 1,-0.45 1,-1v-3.5c0,-0.55 -0.45,-1 -1,-1zM21,6h-3V3h-2v3h-3v2h3v3h2V8h3z"/>
+</vector>
\ No newline at end of file
diff --git a/assets/quantum/res/drawable/quantum_ic_dialpad_vd_theme_24.xml b/assets/quantum/res/drawable/quantum_ic_dialpad_vd_theme_24.xml
new file mode 100644
index 0000000..4e340ed
--- /dev/null
+++ b/assets/quantum/res/drawable/quantum_ic_dialpad_vd_theme_24.xml
@@ -0,0 +1,25 @@
+<!--
+  ~ 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
+  -->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="24dp"
+    android:height="24dp"
+    android:viewportWidth="24.0"
+    android:viewportHeight="24.0"
+    android:tint="?attr/colorControlNormal">
+  <path
+      android:fillColor="@android:color/white"
+      android:pathData="M12,19c-1.1,0 -2,0.9 -2,2s0.9,2 2,2 2,-0.9 2,-2 -0.9,-2 -2,-2zM6,1c-1.1,0 -2,0.9 -2,2s0.9,2 2,2 2,-0.9 2,-2 -0.9,-2 -2,-2zM6,7c-1.1,0 -2,0.9 -2,2s0.9,2 2,2 2,-0.9 2,-2 -0.9,-2 -2,-2zM6,13c-1.1,0 -2,0.9 -2,2s0.9,2 2,2 2,-0.9 2,-2 -0.9,-2 -2,-2zM18,5c1.1,0 2,-0.9 2,-2s-0.9,-2 -2,-2 -2,0.9 -2,2 0.9,2 2,2zM12,13c-1.1,0 -2,0.9 -2,2s0.9,2 2,2 2,-0.9 2,-2 -0.9,-2 -2,-2zM18,13c-1.1,0 -2,0.9 -2,2s0.9,2 2,2 2,-0.9 2,-2 -0.9,-2 -2,-2zM18,7c-1.1,0 -2,0.9 -2,2s0.9,2 2,2 2,-0.9 2,-2 -0.9,-2 -2,-2zM12,7c-1.1,0 -2,0.9 -2,2s0.9,2 2,2 2,-0.9 2,-2 -0.9,-2 -2,-2zM12,1c-1.1,0 -2,0.9 -2,2s0.9,2 2,2 2,-0.9 2,-2 -0.9,-2 -2,-2z"/>
+</vector>
\ No newline at end of file
diff --git a/assets/quantum/res/drawable/quantum_ic_rtt_vd_theme_24.xml b/assets/quantum/res/drawable/quantum_ic_rtt_vd_theme_24.xml
new file mode 100644
index 0000000..90e1f84
--- /dev/null
+++ b/assets/quantum/res/drawable/quantum_ic_rtt_vd_theme_24.xml
@@ -0,0 +1,25 @@
+<!--
+  ~ 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
+  -->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="24dp"
+    android:height="24dp"
+    android:viewportWidth="24.0"
+    android:viewportHeight="24.0"
+    android:tint="?attr/colorControlNormal">
+  <path
+      android:fillColor="@android:color/white"
+      android:pathData="M9.03,3l-1.11,7.07h2.62l0.7,-4.5h2.58L11.8,18.43L9.47,18.43L9.06,21h7.27l0.4,-2.57h-2.35l2,-12.86h2.58l-0.71,4.5h2.65L22,3L9.03,3zM8,5L4,5l-0.31,2h4L8,5zM7.39,9h-4l-0.31,2h4l0.31,-2zM8.31,17h-6L2,19h6l0.31,-2zM8.93,13h-6l-0.31,2h6.01l0.3,-2z"/>
+</vector>
\ No newline at end of file
diff --git a/java/com/android/contacts/common/compat/PhoneNumberUtilsCompat.java b/java/com/android/contacts/common/compat/PhoneNumberUtilsCompat.java
deleted file mode 100644
index a6cfe07..0000000
--- a/java/com/android/contacts/common/compat/PhoneNumberUtilsCompat.java
+++ /dev/null
@@ -1,46 +0,0 @@
-/*
- * Copyright (C) 2015 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.contacts.common.compat;
-
-import android.telephony.PhoneNumberUtils;
-import android.text.style.TtsSpan;
-
-/**
- * This class contains static utility methods extracted from PhoneNumberUtils, and the methods were
- * added in API level 23. In this way, we could enable the corresponding functionality for pre-M
- * devices. We need maintain this class and keep it synced with PhoneNumberUtils. Another thing to
- * keep in mind is that we use com.google.i18n rather than com.android.i18n in here, so we need make
- * sure the application behavior is preserved.
- */
-public class PhoneNumberUtilsCompat {
-
-  /** Not instantiable. */
-  private PhoneNumberUtilsCompat() {}
-
-  public static String formatNumber(
-      String phoneNumber, String phoneNumberE164, String defaultCountryIso) {
-      return PhoneNumberUtils.formatNumber(phoneNumber, phoneNumberE164, defaultCountryIso);
-  }
-
-  public static CharSequence createTtsSpannable(CharSequence phoneNumber) {
-    return PhoneNumberUtils.createTtsSpannable(phoneNumber);
-  }
-
-  public static TtsSpan createTtsSpan(String phoneNumber) {
-    return PhoneNumberUtils.createTtsSpan(phoneNumber);
-  }
-}
diff --git a/java/com/android/contacts/common/list/ContactListItemView.java b/java/com/android/contacts/common/list/ContactListItemView.java
index 0a5bf09..409aa1b 100644
--- a/java/com/android/contacts/common/list/ContactListItemView.java
+++ b/java/com/android/contacts/common/list/ContactListItemView.java
@@ -32,6 +32,7 @@
 import android.support.annotation.IntDef;
 import android.support.annotation.NonNull;
 import android.support.v4.content.ContextCompat;
+import android.telephony.PhoneNumberUtils;
 import android.text.Spannable;
 import android.text.SpannableString;
 import android.text.TextUtils;
@@ -50,7 +51,6 @@
 import com.android.contacts.common.ContactPresenceIconUtil;
 import com.android.contacts.common.ContactStatusUtil;
 import com.android.contacts.common.R;
-import com.android.contacts.common.compat.PhoneNumberUtilsCompat;
 import com.android.contacts.common.format.TextHighlighter;
 import com.android.contacts.common.list.PhoneNumberListAdapter.Listener;
 import com.android.contacts.common.util.ContactDisplayUtils;
@@ -1111,7 +1111,7 @@
       mSnippetView.setVisibility(VISIBLE);
       if (ContactDisplayUtils.isPossiblePhoneNumber(text)) {
         // Give the text-to-speech engine a hint that it's a phone number
-        mSnippetView.setContentDescription(PhoneNumberUtilsCompat.createTtsSpannable(text));
+        mSnippetView.setContentDescription(PhoneNumberUtils.createTtsSpannable(text));
       } else {
         mSnippetView.setContentDescription(null);
       }
@@ -1232,8 +1232,7 @@
     if (ContactDisplayUtils.isPossiblePhoneNumber(name)) {
       // Give the text-to-speech engine a hint that it's a phone number
       mNameTextView.setTextDirection(View.TEXT_DIRECTION_LTR);
-      mNameTextView.setContentDescription(
-          PhoneNumberUtilsCompat.createTtsSpannable(name.toString()));
+      mNameTextView.setContentDescription(PhoneNumberUtils.createTtsSpannable(name.toString()));
     } else {
       // Remove span tags of highlighting for talkback to avoid reading highlighting and rest
       // of the name into two separate parts.
diff --git a/java/com/android/contacts/common/model/ContactLoader.java b/java/com/android/contacts/common/model/ContactLoader.java
index 51b8e3e..12cca4f 100644
--- a/java/com/android/contacts/common/model/ContactLoader.java
+++ b/java/com/android/contacts/common/model/ContactLoader.java
@@ -669,7 +669,7 @@
         final DataItem dataItem = dataItems.get(dataIndex);
         if (dataItem instanceof PhoneDataItem) {
           final PhoneDataItem phoneDataItem = (PhoneDataItem) dataItem;
-          phoneDataItem.computeFormattedPhoneNumber(countryIso);
+          phoneDataItem.computeFormattedPhoneNumber(getContext(), countryIso);
         }
       }
     }
diff --git a/java/com/android/contacts/common/model/dataitem/PhoneDataItem.java b/java/com/android/contacts/common/model/dataitem/PhoneDataItem.java
index e1f5645..ed32124 100644
--- a/java/com/android/contacts/common/model/dataitem/PhoneDataItem.java
+++ b/java/com/android/contacts/common/model/dataitem/PhoneDataItem.java
@@ -19,15 +19,15 @@
 import android.content.ContentValues;
 import android.content.Context;
 import android.provider.ContactsContract.CommonDataKinds.Phone;
-import com.android.contacts.common.compat.PhoneNumberUtilsCompat;
+import com.android.dialer.phonenumberutil.PhoneNumberHelper;
 
 /**
  * Represents a phone data item, wrapping the columns in {@link
- * ContactsContract.CommonDataKinds.Phone}.
+ * android.provider.ContactsContract.CommonDataKinds.Phone}.
  */
 public class PhoneDataItem extends DataItem {
 
-  public static final String KEY_FORMATTED_PHONE_NUMBER = "formattedPhoneNumber";
+  private static final String KEY_FORMATTED_PHONE_NUMBER = "formattedPhoneNumber";
 
   /* package */ PhoneDataItem(ContentValues values) {
     super(values);
@@ -50,12 +50,12 @@
     return getContentValues().getAsString(Phone.LABEL);
   }
 
-  public void computeFormattedPhoneNumber(String defaultCountryIso) {
+  public void computeFormattedPhoneNumber(Context context, String defaultCountryIso) {
     final String phoneNumber = getNumber();
     if (phoneNumber != null) {
       final String formattedPhoneNumber =
-          PhoneNumberUtilsCompat.formatNumber(
-              phoneNumber, getNormalizedNumber(), defaultCountryIso);
+          PhoneNumberHelper.formatNumber(
+              context, phoneNumber, getNormalizedNumber(), defaultCountryIso);
       getContentValues().put(KEY_FORMATTED_PHONE_NUMBER, formattedPhoneNumber);
     }
   }
diff --git a/java/com/android/contacts/common/util/ContactDisplayUtils.java b/java/com/android/contacts/common/util/ContactDisplayUtils.java
index a45394f..7d428e1 100644
--- a/java/com/android/contacts/common/util/ContactDisplayUtils.java
+++ b/java/com/android/contacts/common/util/ContactDisplayUtils.java
@@ -21,13 +21,13 @@
 import android.provider.ContactsContract.CommonDataKinds.Phone;
 import android.support.annotation.NonNull;
 import android.support.annotation.Nullable;
+import android.telephony.PhoneNumberUtils;
 import android.text.Spannable;
 import android.text.SpannableString;
 import android.text.TextUtils;
 import android.text.style.TtsSpan;
 import android.util.Patterns;
 import com.android.contacts.common.R;
-import com.android.contacts.common.compat.PhoneNumberUtilsCompat;
 import com.android.contacts.common.preference.ContactsPreferences;
 import com.android.dialer.common.LogUtil;
 import java.util.Objects;
@@ -219,7 +219,7 @@
     int start = TextUtils.isEmpty(phoneNumber) ? -1 : message.indexOf(phoneNumber);
     while (start >= 0) {
       final int end = start + phoneNumber.length();
-      final TtsSpan ttsSpan = PhoneNumberUtilsCompat.createTtsSpan(phoneNumber);
+      final TtsSpan ttsSpan = PhoneNumberUtils.createTtsSpan(phoneNumber);
       spannable.setSpan(
           ttsSpan,
           start,
diff --git a/java/com/android/contacts/common/widget/SelectPhoneAccountDialogFragment.java b/java/com/android/contacts/common/widget/SelectPhoneAccountDialogFragment.java
index 07891a0..295aa96 100644
--- a/java/com/android/contacts/common/widget/SelectPhoneAccountDialogFragment.java
+++ b/java/com/android/contacts/common/widget/SelectPhoneAccountDialogFragment.java
@@ -325,6 +325,7 @@
         holder.numberTextView.setVisibility(View.VISIBLE);
         holder.numberTextView.setText(
             PhoneNumberHelper.formatNumberForDisplay(
+                getContext(),
                 account.getAddress().getSchemeSpecificPart(),
                 getCountryIso(getContext(), accountHandle)));
       }
diff --git a/java/com/android/dialer/app/calllog/CallLogAdapter.java b/java/com/android/dialer/app/calllog/CallLogAdapter.java
index baca590..4b860fe 100644
--- a/java/com/android/dialer/app/calllog/CallLogAdapter.java
+++ b/java/com/android/dialer/app/calllog/CallLogAdapter.java
@@ -52,7 +52,6 @@
 import android.view.View;
 import android.view.ViewGroup;
 import com.android.contacts.common.ContactsUtils;
-import com.android.contacts.common.compat.PhoneNumberUtilsCompat;
 import com.android.contacts.common.preference.ContactsPreferences;
 import com.android.dialer.app.DialtactsActivity;
 import com.android.dialer.app.R;
@@ -1057,7 +1056,7 @@
     CharSequence formattedNumber =
         info.formattedNumber == null
             ? null
-            : PhoneNumberUtilsCompat.createTtsSpannable(info.formattedNumber);
+            : PhoneNumberUtils.createTtsSpannable(info.formattedNumber);
     details.updateDisplayNumber(activity, formattedNumber, isVoicemailNumber);
 
     views.displayNumber = details.displayNumber;
diff --git a/java/com/android/dialer/app/calllog/CallLogListItemViewHolder.java b/java/com/android/dialer/app/calllog/CallLogListItemViewHolder.java
index 5c94111..4c187fa 100644
--- a/java/com/android/dialer/app/calllog/CallLogListItemViewHolder.java
+++ b/java/com/android/dialer/app/calllog/CallLogListItemViewHolder.java
@@ -52,7 +52,6 @@
 import android.widget.ImageView;
 import android.widget.TextView;
 import android.widget.Toast;
-import com.android.contacts.common.compat.PhoneNumberUtilsCompat;
 import com.android.contacts.common.dialog.CallSubjectDialog;
 import com.android.dialer.app.DialtactsActivity;
 import com.android.dialer.app.R;
@@ -1222,7 +1221,7 @@
       menu.setHeaderTitle(context.getResources().getText(R.string.voicemail));
     } else {
       menu.setHeaderTitle(
-          PhoneNumberUtilsCompat.createTtsSpannable(
+          PhoneNumberUtils.createTtsSpannable(
               BidiFormatter.getInstance().unicodeWrap(number, TextDirectionHeuristics.LTR)));
     }
 
diff --git a/java/com/android/dialer/app/calllog/CallLogNotificationsQueryHelper.java b/java/com/android/dialer/app/calllog/CallLogNotificationsQueryHelper.java
index d20ddd0..3afb6bb 100644
--- a/java/com/android/dialer/app/calllog/CallLogNotificationsQueryHelper.java
+++ b/java/com/android/dialer/app/calllog/CallLogNotificationsQueryHelper.java
@@ -43,6 +43,7 @@
 import com.android.dialer.location.GeoUtil;
 import com.android.dialer.phonenumbercache.ContactInfo;
 import com.android.dialer.phonenumbercache.ContactInfoHelper;
+import com.android.dialer.phonenumberutil.PhoneNumberHelper;
 import com.android.dialer.util.PermissionsUtil;
 import java.util.ArrayList;
 import java.util.Arrays;
@@ -199,7 +200,7 @@
     number = (number == null) ? "" : number;
     ContactInfo contactInfo = new ContactInfo();
     contactInfo.number = number;
-    contactInfo.formattedNumber = PhoneNumberUtils.formatNumber(number, countryIso);
+    contactInfo.formattedNumber = PhoneNumberHelper.formatNumber(context, number, countryIso);
     // contactInfo.normalizedNumber is not PhoneNumberUtils.normalizeNumber. Read ContactInfo.
     contactInfo.normalizedNumber = PhoneNumberUtils.formatNumberToE164(number, countryIso);
 
diff --git a/java/com/android/dialer/app/calllog/LegacyVoicemailNotifier.java b/java/com/android/dialer/app/calllog/LegacyVoicemailNotifier.java
index 0ddfb9f..7b1536b 100644
--- a/java/com/android/dialer/app/calllog/LegacyVoicemailNotifier.java
+++ b/java/com/android/dialer/app/calllog/LegacyVoicemailNotifier.java
@@ -27,14 +27,15 @@
 import android.telecom.PhoneAccountHandle;
 import android.telecom.TelecomManager;
 import android.telephony.CarrierConfigManager;
-import android.telephony.PhoneNumberUtils;
 import android.telephony.TelephonyManager;
 import android.text.TextUtils;
 import com.android.dialer.app.R;
 import com.android.dialer.common.Assert;
 import com.android.dialer.common.LogUtil;
+import com.android.dialer.location.GeoUtil;
 import com.android.dialer.notification.DialerNotificationManager;
 import com.android.dialer.notification.NotificationChannelManager;
+import com.android.dialer.phonenumberutil.PhoneNumberHelper;
 import com.android.dialer.telecom.TelecomUtil;
 
 /** Shows a notification in the status bar for legacy vociemail. */
@@ -144,7 +145,8 @@
     } else {
       return String.format(
           context.getString(R.string.notification_voicemail_text_format),
-          PhoneNumberUtils.formatNumber(voicemailNumber));
+          PhoneNumberHelper.formatNumber(
+              context, voicemailNumber, GeoUtil.getCurrentCountryIso(context)));
     }
   }
 
diff --git a/java/com/android/dialer/app/calllog/MissedCallNotifier.java b/java/com/android/dialer/app/calllog/MissedCallNotifier.java
index 14bbdfa..80901ce 100644
--- a/java/com/android/dialer/app/calllog/MissedCallNotifier.java
+++ b/java/com/android/dialer/app/calllog/MissedCallNotifier.java
@@ -36,12 +36,12 @@
 import android.telecom.PhoneAccount;
 import android.telecom.PhoneAccountHandle;
 import android.telecom.TelecomManager;
+import android.telephony.PhoneNumberUtils;
 import android.text.BidiFormatter;
 import android.text.TextDirectionHeuristics;
 import android.text.TextUtils;
 import android.util.ArraySet;
 import com.android.contacts.common.ContactsUtils;
-import com.android.contacts.common.compat.PhoneNumberUtilsCompat;
 import com.android.dialer.app.DialtactsActivity;
 import com.android.dialer.app.MainComponent;
 import com.android.dialer.app.R;
@@ -171,7 +171,7 @@
       if (TextUtils.equals(contactInfo.name, contactInfo.formattedNumber)
           || TextUtils.equals(contactInfo.name, contactInfo.number)) {
         expandedText =
-            PhoneNumberUtilsCompat.createTtsSpannable(
+            PhoneNumberUtils.createTtsSpannable(
                 BidiFormatter.getInstance()
                     .unicodeWrap(contactInfo.name, TextDirectionHeuristics.LTR));
       } else {
@@ -328,7 +328,7 @@
     if (TextUtils.equals(contactInfo.name, contactInfo.formattedNumber)
         || TextUtils.equals(contactInfo.name, contactInfo.number)) {
       expandedText =
-          PhoneNumberUtilsCompat.createTtsSpannable(
+          PhoneNumberUtils.createTtsSpannable(
               BidiFormatter.getInstance()
                   .unicodeWrap(contactInfo.name, TextDirectionHeuristics.LTR));
     } else {
diff --git a/java/com/android/dialer/app/filterednumber/BlockedNumbersAdapter.java b/java/com/android/dialer/app/filterednumber/BlockedNumbersAdapter.java
index 4f8bc66..603c06f 100644
--- a/java/com/android/dialer/app/filterednumber/BlockedNumbersAdapter.java
+++ b/java/com/android/dialer/app/filterednumber/BlockedNumbersAdapter.java
@@ -18,7 +18,6 @@
 import android.app.FragmentManager;
 import android.content.Context;
 import android.database.Cursor;
-import android.telephony.PhoneNumberUtils;
 import android.view.View;
 import com.android.dialer.app.R;
 import com.android.dialer.blocking.BlockNumberDialogFragment;
@@ -28,6 +27,7 @@
 import com.android.dialer.logging.InteractionEvent;
 import com.android.dialer.logging.Logger;
 import com.android.dialer.phonenumbercache.ContactInfoHelper;
+import com.android.dialer.phonenumberutil.PhoneNumberHelper;
 
 /** TODO(calderwoodra): documentation */
 public class BlockedNumbersAdapter extends NumbersAdapter {
@@ -66,7 +66,7 @@
                 id,
                 number,
                 countryIso,
-                PhoneNumberUtils.formatNumber(number, countryIso),
+                PhoneNumberHelper.formatNumber(getContext(), number, countryIso),
                 R.id.blocked_numbers_activity_container,
                 getFragmentManager(),
                 new BlockNumberDialogFragment.Callback() {
diff --git a/java/com/android/dialer/app/list/BlockedListSearchFragment.java b/java/com/android/dialer/app/list/BlockedListSearchFragment.java
index de9dbae..ce812af 100644
--- a/java/com/android/dialer/app/list/BlockedListSearchFragment.java
+++ b/java/com/android/dialer/app/list/BlockedListSearchFragment.java
@@ -19,7 +19,6 @@
 import android.os.Bundle;
 import android.support.v7.app.ActionBar;
 import android.support.v7.app.AppCompatActivity;
-import android.telephony.PhoneNumberUtils;
 import android.text.Editable;
 import android.text.TextUtils;
 import android.text.TextWatcher;
@@ -39,6 +38,7 @@
 import com.android.dialer.location.GeoUtil;
 import com.android.dialer.logging.InteractionEvent;
 import com.android.dialer.logging.Logger;
+import com.android.dialer.phonenumberutil.PhoneNumberHelper;
 
 /** TODO(calderwoodra): documentation */
 public class BlockedListSearchFragment extends RegularSearchFragment
@@ -174,7 +174,7 @@
                   id,
                   number,
                   countryIso,
-                  PhoneNumberUtils.formatNumber(number, countryIso),
+                  PhoneNumberHelper.formatNumber(getContext(), number, countryIso),
                   R.id.blocked_numbers_activity_container,
                   getFragmentManager(),
                   BlockedListSearchFragment.this);
diff --git a/java/com/android/dialer/app/list/DialerPhoneNumberListAdapter.java b/java/com/android/dialer/app/list/DialerPhoneNumberListAdapter.java
index 3711e6e..d5609b8 100644
--- a/java/com/android/dialer/app/list/DialerPhoneNumberListAdapter.java
+++ b/java/com/android/dialer/app/list/DialerPhoneNumberListAdapter.java
@@ -31,6 +31,7 @@
 import com.android.contacts.common.util.ContactDisplayUtils;
 import com.android.dialer.app.R;
 import com.android.dialer.location.GeoUtil;
+import com.android.dialer.phonenumberutil.PhoneNumberHelper;
 
 /**
  * {@link PhoneNumberListAdapter} with the following added shortcuts, that are displayed as list
@@ -228,7 +229,8 @@
   @Override
   public void setQueryString(String queryString) {
     formattedQueryString =
-        PhoneNumberUtils.formatNumber(PhoneNumberUtils.normalizeNumber(queryString), countryIso);
+        PhoneNumberHelper.formatNumber(
+            getContext(), PhoneNumberUtils.normalizeNumber(queryString), countryIso);
     super.setQueryString(queryString);
   }
 }
diff --git a/java/com/android/dialer/app/list/PhoneFavoriteTileView.java b/java/com/android/dialer/app/list/PhoneFavoriteTileView.java
index 3739588..30b8464 100644
--- a/java/com/android/dialer/app/list/PhoneFavoriteTileView.java
+++ b/java/com/android/dialer/app/list/PhoneFavoriteTileView.java
@@ -199,9 +199,12 @@
    */
   private void sendViewNotification(Context context, Uri contactUri) {
     if (loader != null) {
-      loader.cancelLoad();
+      // Cancels the current load if it's running and clears up any memory if it's using any.
+      loader.reset();
     }
     loader = new ContactLoader(context, contactUri, true /* postViewNotification */);
+    // Immediately release anything we're holding in memory
+    loader.registerListener(0, (loader1, contact) -> loader.reset());
     loader.startLoading();
   }
 }
diff --git a/java/com/android/dialer/app/settings/DialerSettingsActivity.java b/java/com/android/dialer/app/settings/DialerSettingsActivity.java
index cbd9e79..24e5fe8 100644
--- a/java/com/android/dialer/app/settings/DialerSettingsActivity.java
+++ b/java/com/android/dialer/app/settings/DialerSettingsActivity.java
@@ -102,7 +102,6 @@
 
     Header soundSettingsHeader = new Header();
     soundSettingsHeader.titleRes = R.string.sounds_and_vibration_title;
-    soundSettingsHeader.fragment = SoundSettingsFragment.class.getName();
     soundSettingsHeader.id = R.id.settings_header_sounds_and_vibration;
     target.add(soundSettingsHeader);
 
@@ -271,22 +270,32 @@
         && getResources().getBoolean(R.bool.config_sort_order_user_changeable);
   }
 
+  /**
+   * For the "sounds and vibration" setting, we go directly to the system sound settings fragment.
+   * This helps since:
+   * <li>We don't need a separate Dialer sounds and vibrations fragment, as everything we need is
+   *     present in the system sounds fragment.
+   * <li>OEM's e.g Moto that support dual sim ring-tones no longer need to update the dialer sound
+   *     and settings fragment.
+   *
+   *     <p>For all other settings, we launch our our preferences fragment.
+   */
   @Override
   public void onHeaderClick(Header header, int position) {
     if (header.id == R.id.settings_header_sounds_and_vibration) {
-      // If we don't have the permission to write to system settings, go to system sound
-      // settings instead. Otherwise, perform the super implementation (which launches our
-      // own preference fragment.
+
       if (!Settings.System.canWrite(this)) {
         Toast.makeText(
                 this,
                 getResources().getString(R.string.toast_cannot_write_system_settings),
                 Toast.LENGTH_SHORT)
             .show();
-        startActivity(new Intent(Settings.ACTION_SOUND_SETTINGS));
-        return;
       }
+
+      startActivity(new Intent(Settings.ACTION_SOUND_SETTINGS));
+      return;
     }
+
     super.onHeaderClick(header, position);
   }
 
diff --git a/java/com/android/dialer/app/settings/SoundSettingsFragment.java b/java/com/android/dialer/app/settings/SoundSettingsFragment.java
deleted file mode 100644
index 19cddbc..0000000
--- a/java/com/android/dialer/app/settings/SoundSettingsFragment.java
+++ /dev/null
@@ -1,242 +0,0 @@
-/*
- * Copyright (C) 2014 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.app.settings;
-
-import android.content.Context;
-import android.media.RingtoneManager;
-import android.os.Build;
-import android.os.Bundle;
-import android.os.Handler;
-import android.os.Message;
-import android.os.Vibrator;
-import android.preference.ListPreference;
-import android.preference.Preference;
-import android.preference.PreferenceFragment;
-import android.preference.PreferenceScreen;
-import android.preference.SwitchPreference;
-import android.provider.Settings;
-import android.telephony.CarrierConfigManager;
-import android.telephony.TelephonyManager;
-import android.widget.Toast;
-import com.android.dialer.app.R;
-import com.android.dialer.compat.SdkVersionOverride;
-import com.android.dialer.util.SettingsUtil;
-
-public class SoundSettingsFragment extends PreferenceFragment
-    implements Preference.OnPreferenceChangeListener {
-
-  private static final int NO_DTMF_TONE = 0;
-  private static final int PLAY_DTMF_TONE = 1;
-
-  private static final int NO_VIBRATION_FOR_CALLS = 0;
-  private static final int DO_VIBRATION_FOR_CALLS = 1;
-
-  private static final int DTMF_TONE_TYPE_NORMAL = 0;
-
-  private static final int MSG_UPDATE_RINGTONE_SUMMARY = 1;
-
-  private Preference ringtonePreference;
-  private final Handler ringtoneLookupComplete =
-      new Handler() {
-        @Override
-        public void handleMessage(Message msg) {
-          switch (msg.what) {
-            case MSG_UPDATE_RINGTONE_SUMMARY:
-              ringtonePreference.setSummary((CharSequence) msg.obj);
-              break;
-          }
-        }
-      };
-  private final Runnable ringtoneLookupRunnable =
-      new Runnable() {
-        @Override
-        public void run() {
-          updateRingtonePreferenceSummary();
-        }
-      };
-  private SwitchPreference vibrateWhenRinging;
-  private SwitchPreference playDtmfTone;
-  private ListPreference dtmfToneLength;
-
-  @Override
-  public Context getContext() {
-    return getActivity();
-  }
-
-  @Override
-  public void onCreate(Bundle savedInstanceState) {
-    super.onCreate(savedInstanceState);
-
-    addPreferencesFromResource(R.xml.sound_settings);
-
-    Context context = getActivity();
-
-    ringtonePreference = findPreference(context.getString(R.string.ringtone_preference_key));
-    vibrateWhenRinging =
-        (SwitchPreference) findPreference(context.getString(R.string.vibrate_on_preference_key));
-    playDtmfTone =
-        (SwitchPreference) findPreference(context.getString(R.string.play_dtmf_preference_key));
-    dtmfToneLength =
-        (ListPreference)
-            findPreference(context.getString(R.string.dtmf_tone_length_preference_key));
-
-    if (hasVibrator()) {
-      vibrateWhenRinging.setOnPreferenceChangeListener(this);
-    } else {
-      getPreferenceScreen().removePreference(vibrateWhenRinging);
-      vibrateWhenRinging = null;
-    }
-
-    playDtmfTone.setOnPreferenceChangeListener(this);
-    playDtmfTone.setChecked(shouldPlayDtmfTone());
-
-    TelephonyManager telephonyManager =
-        (TelephonyManager) getActivity().getSystemService(Context.TELEPHONY_SERVICE);
-    if (SdkVersionOverride.getSdkVersion(Build.VERSION_CODES.M) >= Build.VERSION_CODES.M
-        && telephonyManager.canChangeDtmfToneLength()
-        && (telephonyManager.isWorldPhone() || !shouldHideCarrierSettings())) {
-      dtmfToneLength.setOnPreferenceChangeListener(this);
-      dtmfToneLength.setValueIndex(
-          Settings.System.getInt(
-              context.getContentResolver(),
-              Settings.System.DTMF_TONE_TYPE_WHEN_DIALING,
-              DTMF_TONE_TYPE_NORMAL));
-    } else {
-      getPreferenceScreen().removePreference(dtmfToneLength);
-      dtmfToneLength = null;
-    }
-  }
-
-  @Override
-  public void onResume() {
-    super.onResume();
-
-    if (!Settings.System.canWrite(getContext())) {
-      // If the user launches this setting fragment, then toggles the WRITE_SYSTEM_SETTINGS
-      // AppOp, then close the fragment since there is nothing useful to do.
-      getActivity().onBackPressed();
-      return;
-    }
-
-    if (vibrateWhenRinging != null) {
-      vibrateWhenRinging.setChecked(shouldVibrateWhenRinging());
-    }
-
-    // Lookup the ringtone name asynchronously.
-    new Thread(ringtoneLookupRunnable).start();
-  }
-
-  /**
-   * Supports onPreferenceChangeListener to look for preference changes.
-   *
-   * @param preference The preference to be changed
-   * @param objValue The value of the selection, NOT its localized display value.
-   */
-  @Override
-  public boolean onPreferenceChange(Preference preference, Object objValue) {
-    if (!Settings.System.canWrite(getContext())) {
-      // A user shouldn't be able to get here, but this protects against monkey crashes.
-      Toast.makeText(
-              getContext(),
-              getResources().getString(R.string.toast_cannot_write_system_settings),
-              Toast.LENGTH_SHORT)
-          .show();
-      return true;
-    }
-    if (preference == vibrateWhenRinging) {
-      boolean doVibrate = (Boolean) objValue;
-      Settings.System.putInt(
-          getActivity().getContentResolver(),
-          Settings.System.VIBRATE_WHEN_RINGING,
-          doVibrate ? DO_VIBRATION_FOR_CALLS : NO_VIBRATION_FOR_CALLS);
-    } else if (preference == dtmfToneLength) {
-      int index = dtmfToneLength.findIndexOfValue((String) objValue);
-      Settings.System.putInt(
-          getActivity().getContentResolver(), Settings.System.DTMF_TONE_TYPE_WHEN_DIALING, index);
-    }
-    return true;
-  }
-
-  /** Click listener for toggle events. */
-  @Override
-  public boolean onPreferenceTreeClick(PreferenceScreen preferenceScreen, Preference preference) {
-    if (!Settings.System.canWrite(getContext())) {
-      Toast.makeText(
-              getContext(),
-              getResources().getString(R.string.toast_cannot_write_system_settings),
-              Toast.LENGTH_SHORT)
-          .show();
-      return true;
-    }
-    if (preference == playDtmfTone) {
-      Settings.System.putInt(
-          getActivity().getContentResolver(),
-          Settings.System.DTMF_TONE_WHEN_DIALING,
-          playDtmfTone.isChecked() ? PLAY_DTMF_TONE : NO_DTMF_TONE);
-    }
-    return true;
-  }
-
-  /** Updates the summary text on the ringtone preference with the name of the ringtone. */
-  private void updateRingtonePreferenceSummary() {
-    SettingsUtil.updateRingtoneName(
-        getActivity(),
-        ringtoneLookupComplete,
-        RingtoneManager.TYPE_RINGTONE,
-        ringtonePreference.getKey(),
-        MSG_UPDATE_RINGTONE_SUMMARY);
-  }
-
-  /**
-   * Obtain the value for "vibrate when ringing" setting. The default value is false.
-   *
-   * <p>Watch out: if the setting is missing in the device, this will try obtaining the old "vibrate
-   * on ring" setting from AudioManager, and save the previous setting to the new one.
-   */
-  private boolean shouldVibrateWhenRinging() {
-    int vibrateWhenRingingSetting =
-        Settings.System.getInt(
-            getActivity().getContentResolver(),
-            Settings.System.VIBRATE_WHEN_RINGING,
-            NO_VIBRATION_FOR_CALLS);
-    return hasVibrator() && (vibrateWhenRingingSetting == DO_VIBRATION_FOR_CALLS);
-  }
-
-  /** Obtains the value for dialpad/DTMF tones. The default value is true. */
-  private boolean shouldPlayDtmfTone() {
-    int dtmfToneSetting =
-        Settings.System.getInt(
-            getActivity().getContentResolver(),
-            Settings.System.DTMF_TONE_WHEN_DIALING,
-            PLAY_DTMF_TONE);
-    return dtmfToneSetting == PLAY_DTMF_TONE;
-  }
-
-  /** Whether the device hardware has a vibrator. */
-  private boolean hasVibrator() {
-    Vibrator vibrator = (Vibrator) getActivity().getSystemService(Context.VIBRATOR_SERVICE);
-    return vibrator != null && vibrator.hasVibrator();
-  }
-
-  private boolean shouldHideCarrierSettings() {
-    CarrierConfigManager configManager =
-        (CarrierConfigManager) getActivity().getSystemService(Context.CARRIER_CONFIG_SERVICE);
-    return configManager
-        .getConfig()
-        .getBoolean(CarrierConfigManager.KEY_HIDE_CARRIER_NETWORK_SETTINGS_BOOL);
-  }
-}
diff --git a/java/com/android/dialer/assisteddialing/ConcreteCreator.java b/java/com/android/dialer/assisteddialing/ConcreteCreator.java
index 2561e28..dfd28a6 100644
--- a/java/com/android/dialer/assisteddialing/ConcreteCreator.java
+++ b/java/com/android/dialer/assisteddialing/ConcreteCreator.java
@@ -23,7 +23,6 @@
 import android.preference.PreferenceManager;
 import android.support.annotation.NonNull;
 import android.support.annotation.VisibleForTesting;
-import android.support.v4.os.BuildCompat;
 import android.support.v4.os.UserManagerCompat;
 import android.telephony.TelephonyManager;
 import com.android.dialer.common.LogUtil;
@@ -42,8 +41,8 @@
 
   // Floor set at N due to use of Optional.
   @VisibleForTesting public static final int BUILD_CODE_FLOOR = Build.VERSION_CODES.N;
-  // Ceiling set at O_MR1 because this feature will ship as part of the framework in P.
-  @VisibleForTesting public static final int BUILD_CODE_CEILING = Build.VERSION_CODES.O_MR1;
+  // Ceiling set at P because this feature will ship as part of the framework in Q.
+  @VisibleForTesting public static final int BUILD_CODE_CEILING = 28;
 
   /**
    * Creates a new AssistedDialingMediator
@@ -107,8 +106,7 @@
     }
 
     return (Build.VERSION.SDK_INT >= BUILD_CODE_FLOOR
-            && Build.VERSION.SDK_INT <= BUILD_CODE_CEILING
-            && !BuildCompat.isAtLeastP())
+            && Build.VERSION.SDK_INT <= BUILD_CODE_CEILING)
         && configProvider.getBoolean("assisted_dialing_enabled", false);
   }
 
diff --git a/java/com/android/dialer/calldetails/CallDetailsActivity.java b/java/com/android/dialer/calldetails/CallDetailsActivity.java
index 26b38ed..ec124df 100644
--- a/java/com/android/dialer/calldetails/CallDetailsActivity.java
+++ b/java/com/android/dialer/calldetails/CallDetailsActivity.java
@@ -32,7 +32,6 @@
 import android.support.annotation.NonNull;
 import android.support.annotation.Nullable;
 import android.support.annotation.RequiresPermission;
-import android.support.v4.os.BuildCompat;
 import android.support.v7.app.AppCompatActivity;
 import android.support.v7.widget.LinearLayoutManager;
 import android.support.v7.widget.RecyclerView;
@@ -52,7 +51,6 @@
 import com.android.dialer.common.concurrent.DialerExecutor.SuccessListener;
 import com.android.dialer.common.concurrent.DialerExecutor.Worker;
 import com.android.dialer.common.concurrent.DialerExecutorComponent;
-import com.android.dialer.compat.telephony.TelephonyManagerCompat;
 import com.android.dialer.constants.ActivityRequestCodes;
 import com.android.dialer.dialercontact.DialerContact;
 import com.android.dialer.duo.Duo;
@@ -409,14 +407,8 @@
 
     @Override
     public void openAssistedDialingSettings(View unused) {
-      if (BuildCompat.isAtLeastP()) {
-        Intent callSettingsIntent =
-            new Intent(TelephonyManagerCompat.ACTION_SHOW_ASSISTED_DIALING_SETTINGS);
-        getActivity().startActivity(callSettingsIntent);
-      } else {
         Intent intent = new Intent(getActivity(), AssistedDialingSettingActivity.class);
         getActivity().startActivity(intent);
-      }
     }
 
     @Override
diff --git a/java/com/android/dialer/calllog/RefreshAnnotatedCallLogReceiver.java b/java/com/android/dialer/calllog/RefreshAnnotatedCallLogReceiver.java
index e0bfcd8..4a7ce0b 100644
--- a/java/com/android/dialer/calllog/RefreshAnnotatedCallLogReceiver.java
+++ b/java/com/android/dialer/calllog/RefreshAnnotatedCallLogReceiver.java
@@ -21,10 +21,18 @@
 import android.content.Intent;
 import android.content.IntentFilter;
 import android.support.annotation.Nullable;
+import com.android.dialer.calllog.RefreshAnnotatedCallLogWorker.RefreshResult;
 import com.android.dialer.calllog.constants.IntentNames;
 import com.android.dialer.common.LogUtil;
-import com.android.dialer.common.concurrent.DefaultFutureCallback;
 import com.android.dialer.common.concurrent.ThreadUtil;
+import com.android.dialer.logging.DialerImpression;
+import com.android.dialer.logging.Logger;
+import com.android.dialer.logging.LoggingBindings;
+import com.android.dialer.metrics.FutureTimer;
+import com.android.dialer.metrics.Metrics;
+import com.android.dialer.metrics.MetricsComponent;
+import com.google.common.base.Function;
+import com.google.common.util.concurrent.FutureCallback;
 import com.google.common.util.concurrent.Futures;
 import com.google.common.util.concurrent.ListenableFuture;
 import com.google.common.util.concurrent.MoreExecutors;
@@ -43,6 +51,8 @@
   private static final long REFRESH_ANNOTATED_CALL_LOG_WAIT_MILLIS = 100L;
 
   private final RefreshAnnotatedCallLogWorker refreshAnnotatedCallLogWorker;
+  private final FutureTimer futureTimer;
+  private final LoggingBindings logger;
 
   @Nullable private Runnable refreshAnnotatedCallLogRunnable;
 
@@ -57,6 +67,8 @@
   public RefreshAnnotatedCallLogReceiver(Context context) {
     refreshAnnotatedCallLogWorker =
         CallLogComponent.get(context).getRefreshAnnotatedCallLogWorker();
+    futureTimer = MetricsComponent.get(context).futureTimer();
+    logger = Logger.get(context);
   }
 
   @Override
@@ -97,12 +109,29 @@
 
     refreshAnnotatedCallLogRunnable =
         () -> {
-          ListenableFuture<Void> future =
+          ListenableFuture<RefreshResult> future =
               checkDirty
                   ? refreshAnnotatedCallLogWorker.refreshWithDirtyCheck()
                   : refreshAnnotatedCallLogWorker.refreshWithoutDirtyCheck();
           Futures.addCallback(
-              future, new DefaultFutureCallback<>(), MoreExecutors.directExecutor());
+              future,
+              new FutureCallback<RefreshResult>() {
+                @Override
+                public void onSuccess(RefreshResult refreshResult) {
+                  logger.logImpression(getImpressionType(checkDirty, refreshResult));
+                }
+
+                @Override
+                public void onFailure(Throwable throwable) {
+                  ThreadUtil.getUiThreadHandler()
+                      .post(
+                          () -> {
+                            throw new RuntimeException(throwable);
+                          });
+                }
+              },
+              MoreExecutors.directExecutor());
+          futureTimer.applyTiming(future, new EventNameFromResultFunction(checkDirty));
         };
 
     ThreadUtil.getUiThreadHandler()
@@ -118,4 +147,49 @@
 
     ThreadUtil.getUiThreadHandler().removeCallbacks(refreshAnnotatedCallLogRunnable);
   }
+
+  private static class EventNameFromResultFunction implements Function<RefreshResult, String> {
+
+    private final boolean checkDirty;
+
+    private EventNameFromResultFunction(boolean checkDirty) {
+      this.checkDirty = checkDirty;
+    }
+
+    @Override
+    public String apply(RefreshResult refreshResult) {
+      switch (refreshResult) {
+        case NOT_DIRTY:
+          return Metrics.ANNOTATED_CALL_LOG_NOT_DIRTY; // NOT_DIRTY implies forceRefresh is false
+        case REBUILT_BUT_NO_CHANGES_NEEDED:
+          return checkDirty
+              ? Metrics.ANNOTATED_LOG_NO_CHANGES_NEEDED
+              : Metrics.NEW_CALL_LOG_FORCE_REFRESH_NO_CHANGES_NEEDED;
+        case REBUILT_AND_CHANGES_NEEDED:
+          return checkDirty
+              ? Metrics.ANNOTATED_CALL_LOG_CHANGES_NEEDED
+              : Metrics.ANNOTATED_CALL_LOG_FORCE_REFRESH_CHANGES_NEEDED;
+        default:
+          throw new IllegalStateException("Unsupported result: " + refreshResult);
+      }
+    }
+  }
+
+  private static DialerImpression.Type getImpressionType(
+      boolean checkDirty, RefreshResult refreshResult) {
+    switch (refreshResult) {
+      case NOT_DIRTY:
+        return DialerImpression.Type.ANNOTATED_CALL_LOG_NOT_DIRTY;
+      case REBUILT_BUT_NO_CHANGES_NEEDED:
+        return checkDirty
+            ? DialerImpression.Type.ANNOTATED_CALL_LOG_NO_CHANGES_NEEDED
+            : DialerImpression.Type.ANNOTATED_CALL_LOG_FORCE_REFRESH_NO_CHANGES_NEEDED;
+      case REBUILT_AND_CHANGES_NEEDED:
+        return checkDirty
+            ? DialerImpression.Type.ANNOTATED_CALL_LOG_CHANGES_NEEDED
+            : DialerImpression.Type.ANNOTATED_CALL_LOG_FORCE_REFRESH_CHANGES_NEEDED;
+      default:
+        throw new IllegalStateException("Unsupported result: " + refreshResult);
+    }
+  }
 }
diff --git a/java/com/android/dialer/calllog/RefreshAnnotatedCallLogWorker.java b/java/com/android/dialer/calllog/RefreshAnnotatedCallLogWorker.java
index e05b772..c399b05 100644
--- a/java/com/android/dialer/calllog/RefreshAnnotatedCallLogWorker.java
+++ b/java/com/android/dialer/calllog/RefreshAnnotatedCallLogWorker.java
@@ -79,23 +79,30 @@
     this.lightweightExecutorService = lightweightExecutorService;
   }
 
+  /** Result of refreshing the annotated call log. */
+  public enum RefreshResult {
+    NOT_DIRTY,
+    REBUILT_BUT_NO_CHANGES_NEEDED,
+    REBUILT_AND_CHANGES_NEEDED
+  }
+
   /** Checks if the annotated call log is dirty and refreshes it if necessary. */
-  ListenableFuture<Void> refreshWithDirtyCheck() {
+  ListenableFuture<RefreshResult> refreshWithDirtyCheck() {
     return refresh(true);
   }
 
   /** Refreshes the annotated call log, bypassing dirty checks. */
-  ListenableFuture<Void> refreshWithoutDirtyCheck() {
+  ListenableFuture<RefreshResult> refreshWithoutDirtyCheck() {
     return refresh(false);
   }
 
-  private ListenableFuture<Void> refresh(boolean checkDirty) {
+  private ListenableFuture<RefreshResult> refresh(boolean checkDirty) {
     LogUtil.i("RefreshAnnotatedCallLogWorker.refresh", "submitting serialized refresh request");
     return dialerFutureSerializer.submitAsync(
         () -> checkDirtyAndRebuildIfNecessary(checkDirty), lightweightExecutorService);
   }
 
-  private ListenableFuture<Void> checkDirtyAndRebuildIfNecessary(boolean checkDirty) {
+  private ListenableFuture<RefreshResult> checkDirtyAndRebuildIfNecessary(boolean checkDirty) {
     ListenableFuture<Boolean> forceRebuildFuture =
         backgroundExecutorService.submit(
             () -> {
@@ -139,7 +146,7 @@
             return Futures.transformAsync(
                 callLogState.isBuilt(), this::rebuild, MoreExecutors.directExecutor());
           }
-          return Futures.immediateFuture(null);
+          return Futures.immediateFuture(RefreshResult.NOT_DIRTY);
         },
         lightweightExecutorService);
   }
@@ -160,7 +167,7 @@
     return isDirtyFuture;
   }
 
-  private ListenableFuture<Void> rebuild(boolean isBuilt) {
+  private ListenableFuture<RefreshResult> rebuild(boolean isBuilt) {
     CallLogMutations mutations = new CallLogMutations();
 
     // Start by filling the data sources--the system call log data source must go first!
@@ -225,7 +232,9 @@
         unused -> {
           sharedPreferences.edit().putBoolean(SharedPrefKeys.FORCE_REBUILD, false).apply();
           callLogState.markBuilt();
-          return null;
+          return mutations.isEmpty()
+              ? RefreshResult.REBUILT_BUT_NO_CHANGES_NEEDED
+              : RefreshResult.REBUILT_AND_CHANGES_NEEDED;
         },
         backgroundExecutorService);
   }
diff --git a/java/com/android/dialer/calllog/database/AnnotatedCallLogContentProvider.java b/java/com/android/dialer/calllog/database/AnnotatedCallLogContentProvider.java
index 77de62e..6972273 100644
--- a/java/com/android/dialer/calllog/database/AnnotatedCallLogContentProvider.java
+++ b/java/com/android/dialer/calllog/database/AnnotatedCallLogContentProvider.java
@@ -37,6 +37,8 @@
 import com.android.dialer.calllog.database.contract.AnnotatedCallLogContract.CoalescedAnnotatedCallLog;
 import com.android.dialer.common.Assert;
 import com.android.dialer.common.LogUtil;
+import com.android.dialer.metrics.Metrics;
+import com.android.dialer.metrics.MetricsComponent;
 import java.util.ArrayList;
 import java.util.Arrays;
 
@@ -153,6 +155,7 @@
         Assert.checkArgument(
             selectionArgs == null, "selection args not supported for coalesced call log");
         Assert.checkArgument(sortOrder == null, "sort order not supported for coalesced call log");
+        MetricsComponent.get(getContext()).metrics().startTimer(Metrics.NEW_CALL_LOG_COALESCE);
         try (Cursor allAnnotatedCallLogRows =
             queryBuilder.query(
                 db,
@@ -168,6 +171,7 @@
                   .coalesce(allAnnotatedCallLogRows);
           coalescedRows.setNotificationUri(
               getContext().getContentResolver(), CoalescedAnnotatedCallLog.CONTENT_URI);
+          MetricsComponent.get(getContext()).metrics().stopTimer(Metrics.NEW_CALL_LOG_COALESCE);
           return coalescedRows;
         }
       default:
diff --git a/java/com/android/dialer/calllogutils/PhoneNumberDisplayUtil.java b/java/com/android/dialer/calllogutils/PhoneNumberDisplayUtil.java
index f0f6963..6fe3a82 100644
--- a/java/com/android/dialer/calllogutils/PhoneNumberDisplayUtil.java
+++ b/java/com/android/dialer/calllogutils/PhoneNumberDisplayUtil.java
@@ -18,10 +18,10 @@
 
 import android.content.Context;
 import android.provider.CallLog.Calls;
+import android.telephony.PhoneNumberUtils;
 import android.text.BidiFormatter;
 import android.text.TextDirectionHeuristics;
 import android.text.TextUtils;
-import com.android.contacts.common.compat.PhoneNumberUtilsCompat;
 import com.android.dialer.phonenumberutil.PhoneNumberHelper;
 import com.google.common.base.Optional;
 
@@ -86,8 +86,8 @@
   }
 
   /** Returns number annotated as phone number in LTR direction. */
-  public static CharSequence getTtsSpannableLtrNumber(CharSequence number) {
-    return PhoneNumberUtilsCompat.createTtsSpannable(
+  private static CharSequence getTtsSpannableLtrNumber(CharSequence number) {
+    return PhoneNumberUtils.createTtsSpannable(
         BidiFormatter.getInstance().unicodeWrap(number.toString(), TextDirectionHeuristics.LTR));
   }
 }
diff --git a/java/com/android/dialer/compat/telephony/TelephonyManagerCompat.java b/java/com/android/dialer/compat/telephony/TelephonyManagerCompat.java
index 669cba7..236f779 100644
--- a/java/com/android/dialer/compat/telephony/TelephonyManagerCompat.java
+++ b/java/com/android/dialer/compat/telephony/TelephonyManagerCompat.java
@@ -65,9 +65,6 @@
   public static final String ASSISTED_DIALING_EXTRAS =
       "android.telecom.extra.ASSISTED_DIALING_EXTRAS";
 
-  public static final String EXTRA_ASSISTED_DIALING_TRANSFORMATION_INFO =
-      "android.telecom.extra.ASSISTED_DIALING_TRANSFORMATION_INFO";
-
   /** Indicates the Connection/Call used assisted dialing. */
   public static final int PROPERTY_ASSISTED_DIALING_USED = 1 << 9;
 
@@ -80,10 +77,6 @@
    */
   public static final Integer FEATURES_ASSISTED_DIALING = 1 << 4;
 
-  /** The {@link android.content.Intent} action used to show the assisted dialing settings. */
-  public static final String ACTION_SHOW_ASSISTED_DIALING_SETTINGS =
-      "android.telecom.action.SHOW_ASSISTED_DIALING_SETTINGS";
-
   /**
    * Returns the number of phones available. Returns 1 for Single standby mode (Single SIM
    * functionality) Returns 2 for Dual standby mode.(Dual SIM functionality)
diff --git a/java/com/android/dialer/dialpadview/DialpadFragment.java b/java/com/android/dialer/dialpadview/DialpadFragment.java
index f093332..eeab6c4 100644
--- a/java/com/android/dialer/dialpadview/DialpadFragment.java
+++ b/java/com/android/dialer/dialpadview/DialpadFragment.java
@@ -88,6 +88,7 @@
 import com.android.dialer.logging.UiAction;
 import com.android.dialer.oem.MotorolaUtils;
 import com.android.dialer.performancereport.PerformanceReport;
+import com.android.dialer.phonenumberutil.PhoneNumberHelper;
 import com.android.dialer.precall.PreCall;
 import com.android.dialer.proguard.UsedByReflection;
 import com.android.dialer.telecom.TelecomUtil;
@@ -220,8 +221,7 @@
    * @return the provided string of digits as a formatted phone number, retaining any post-dial
    *     portion of the string.
    */
-  @VisibleForTesting
-  static String getFormattedDigits(String dialString, String normalizedNumber, String countryIso) {
+  String getFormattedDigits(String dialString, String normalizedNumber, String countryIso) {
     String number = PhoneNumberUtils.extractNetworkPortion(dialString);
     // Also retrieve the post dial portion of the provided data, so that the entire dial
     // string can be reconstituted later.
@@ -231,7 +231,7 @@
       return postDial;
     }
 
-    number = PhoneNumberUtils.formatNumber(number, normalizedNumber, countryIso);
+    number = PhoneNumberHelper.formatNumber(getContext(), number, normalizedNumber, countryIso);
 
     if (TextUtils.isEmpty(postDial)) {
       return number;
diff --git a/java/com/android/dialer/logging/dialer_impression.proto b/java/com/android/dialer/logging/dialer_impression.proto
index 635d8fd..80249f4 100644
--- a/java/com/android/dialer/logging/dialer_impression.proto
+++ b/java/com/android/dialer/logging/dialer_impression.proto
@@ -12,7 +12,7 @@
   // Event enums to be used for Impression Logging in Dialer.
   // It's perfectly acceptable for this enum to be large
   // Values should be from 1000 to 100000.
-  // Next Tag: 1341
+  // Next Tag: 1346
   enum Type {
     UNKNOWN_AOSP_EVENT_TYPE = 1000;
 
@@ -659,21 +659,32 @@
     DUO_CALL_LOG_INVITE_SHOWN = 1326;
 
     // NUI bottom navigation bar
-    NUI_SWITCH_TAB_TO_FAVORITE = 1327;
-    NUI_SWITCH_TAB_TO_CALL_LOG = 1328;
-    NUI_SWITCH_TAB_TO_CONTACTS = 1329;
-    NUI_SWITCH_TAB_TO_VOICEMAIL = 1330;
+    MAIN_SWITCH_TAB_TO_FAVORITE = 1327;
+    MAIN_SWITCH_TAB_TO_CALL_LOG = 1328;
+    MAIN_SWITCH_TAB_TO_CONTACTS = 1329;
+    MAIN_SWITCH_TAB_TO_VOICEMAIL = 1330;
     // NUI search
-    NUI_TOUCH_DIALPAD_SEARCH_LIST_TO_CLOSE_SEARCH_AND_DIALPAD = 1331;
-    NUI_TOUCH_DIALPAD_SEARCH_LIST_TO_HIDE_DIALPAD = 1332;
-    NUI_TOUCH_SEARCH_LIST_TO_CLOSE_SEARCH = 1333;
-    NUI_TOUCH_SEARCH_LIST_TO_HIDE_KEYBOARD = 1334;
-    NUI_PRESS_BACK_BUTTON_TO_CLOSE_SEARCH = 1335;
-    NUI_PRESS_BACK_BUTTON_TO_CLOSE_SEARCH_AND_DIALPAD = 1336;
-    NUI_PRESS_BACK_BUTTON_TO_HIDE_DIALPAD = 1337;
-    NUI_CLICK_SEARCH_BAR = 1338;
-    NUI_CLICK_SEARCH_BAR_VOICE_BUTTON = 1339;
+    MAIN_TOUCH_DIALPAD_SEARCH_LIST_TO_CLOSE_SEARCH_AND_DIALPAD = 1331;
+    MAIN_TOUCH_DIALPAD_SEARCH_LIST_TO_HIDE_DIALPAD = 1332;
+    MAIN_TOUCH_SEARCH_LIST_TO_CLOSE_SEARCH = 1333;
+    MAIN_TOUCH_SEARCH_LIST_TO_HIDE_KEYBOARD = 1334;
+    MAIN_PRESS_BACK_BUTTON_TO_CLOSE_SEARCH = 1335;
+    MAIN_PRESS_BACK_BUTTON_TO_CLOSE_SEARCH_AND_DIALPAD = 1336;
+    MAIN_PRESS_BACK_BUTTON_TO_HIDE_DIALPAD = 1337;
+    MAIN_CLICK_SEARCH_BAR = 1338;
+    MAIN_CLICK_SEARCH_BAR_VOICE_BUTTON = 1339;
     // NUI FAB
-    NUI_CLICK_FAB_TO_OPEN_DIALPAD = 1340;
+    MAIN_CLICK_FAB_TO_OPEN_DIALPAD = 1340;
+
+    // The call log was not dirty.
+    ANNOTATED_CALL_LOG_NOT_DIRTY = 1341;
+    // The call log was dirty but no changes were needed.
+    ANNOTATED_CALL_LOG_NO_CHANGES_NEEDED = 1342;
+    // The call log was force refreshed but no changes were needed.
+    ANNOTATED_CALL_LOG_FORCE_REFRESH_NO_CHANGES_NEEDED = 1343;
+    // The call log was dirty and changes were needed.
+    ANNOTATED_CALL_LOG_CHANGES_NEEDED = 1344;
+    // The call log was force refreshed and changes were needed.
+    ANNOTATED_CALL_LOG_FORCE_REFRESH_CHANGES_NEEDED = 1345;
   }
 }
diff --git a/java/com/android/dialer/main/impl/MainSearchController.java b/java/com/android/dialer/main/impl/MainSearchController.java
index 7d380d7..993ed3d 100644
--- a/java/com/android/dialer/main/impl/MainSearchController.java
+++ b/java/com/android/dialer/main/impl/MainSearchController.java
@@ -136,6 +136,11 @@
     }
     searchFragment.setQuery("", CallInitiationType.Type.DIALPAD);
 
+    // Split the transactions so that the dialpad fragment isn't popped off the stack when we exit
+    // search. We do this so that the dialpad actually animates down instead of just disappearing.
+    transaction.commit();
+    transaction = mainActivity.getFragmentManager().beginTransaction();
+
     // Show Dialpad
     if (getDialpadFragment() == null) {
       DialpadFragment dialpadFragment = new DialpadFragment();
@@ -228,21 +233,21 @@
       if (TextUtils.isEmpty(getDialpadFragment().getQuery())) {
         Logger.get(mainActivity)
             .logImpression(
-                DialerImpression.Type.NUI_TOUCH_DIALPAD_SEARCH_LIST_TO_CLOSE_SEARCH_AND_DIALPAD);
+                DialerImpression.Type.MAIN_TOUCH_DIALPAD_SEARCH_LIST_TO_CLOSE_SEARCH_AND_DIALPAD);
         closeSearch(true);
       } else {
         Logger.get(mainActivity)
-            .logImpression(DialerImpression.Type.NUI_TOUCH_DIALPAD_SEARCH_LIST_TO_HIDE_DIALPAD);
+            .logImpression(DialerImpression.Type.MAIN_TOUCH_DIALPAD_SEARCH_LIST_TO_HIDE_DIALPAD);
         hideDialpad(/* animate=*/ true, /* bottomNavVisible=*/ false);
       }
     } else if (isSearchVisible()) {
       if (TextUtils.isEmpty(toolbar.getQuery())) {
         Logger.get(mainActivity)
-            .logImpression(DialerImpression.Type.NUI_TOUCH_SEARCH_LIST_TO_CLOSE_SEARCH);
+            .logImpression(DialerImpression.Type.MAIN_TOUCH_SEARCH_LIST_TO_CLOSE_SEARCH);
         closeSearch(true);
       } else {
         Logger.get(mainActivity)
-            .logImpression(DialerImpression.Type.NUI_TOUCH_SEARCH_LIST_TO_HIDE_KEYBOARD);
+            .logImpression(DialerImpression.Type.MAIN_TOUCH_SEARCH_LIST_TO_HIDE_KEYBOARD);
         toolbar.hideKeyboard();
       }
     }
@@ -257,7 +262,7 @@
     if (isDialpadVisible() && !TextUtils.isEmpty(getDialpadFragment().getQuery())) {
       LogUtil.i("MainSearchController.onBackPressed", "Dialpad visible with query");
       Logger.get(mainActivity)
-          .logImpression(DialerImpression.Type.NUI_PRESS_BACK_BUTTON_TO_HIDE_DIALPAD);
+          .logImpression(DialerImpression.Type.MAIN_PRESS_BACK_BUTTON_TO_HIDE_DIALPAD);
       hideDialpad(/* animate=*/ true, /* bottomNavVisible=*/ false);
       return true;
     } else if (isSearchVisible()) {
@@ -265,8 +270,8 @@
       Logger.get(mainActivity)
           .logImpression(
               isDialpadVisible()
-                  ? DialerImpression.Type.NUI_PRESS_BACK_BUTTON_TO_CLOSE_SEARCH_AND_DIALPAD
-                  : DialerImpression.Type.NUI_PRESS_BACK_BUTTON_TO_CLOSE_SEARCH);
+                  ? DialerImpression.Type.MAIN_PRESS_BACK_BUTTON_TO_CLOSE_SEARCH_AND_DIALPAD
+                  : DialerImpression.Type.MAIN_PRESS_BACK_BUTTON_TO_CLOSE_SEARCH);
       closeSearch(true);
       return true;
     } else {
@@ -346,7 +351,7 @@
   @Override
   public void onSearchBarClicked() {
     LogUtil.enterBlock("MainSearchController.onSearchBarClicked");
-    Logger.get(mainActivity).logImpression(DialerImpression.Type.NUI_CLICK_SEARCH_BAR);
+    Logger.get(mainActivity).logImpression(DialerImpression.Type.MAIN_CLICK_SEARCH_BAR);
     openSearch(Optional.absent());
   }
 
@@ -406,7 +411,8 @@
 
   @Override
   public void onVoiceButtonClicked(VoiceSearchResultCallback voiceSearchResultCallback) {
-    Logger.get(mainActivity).logImpression(DialerImpression.Type.NUI_CLICK_SEARCH_BAR_VOICE_BUTTON);
+    Logger.get(mainActivity)
+        .logImpression(DialerImpression.Type.MAIN_CLICK_SEARCH_BAR_VOICE_BUTTON);
     try {
       Intent voiceIntent = new Intent(RecognizerIntent.ACTION_RECOGNIZE_SPEECH);
       mainActivity.startActivityForResult(voiceIntent, ActivityRequestCodes.DIALTACTS_VOICE_SEARCH);
diff --git a/java/com/android/dialer/main/impl/OldMainActivityPeer.java b/java/com/android/dialer/main/impl/OldMainActivityPeer.java
index 293ec95..e87fb0e 100644
--- a/java/com/android/dialer/main/impl/OldMainActivityPeer.java
+++ b/java/com/android/dialer/main/impl/OldMainActivityPeer.java
@@ -65,6 +65,7 @@
 import com.android.dialer.common.FragmentUtils.FragmentUtilListener;
 import com.android.dialer.common.LogUtil;
 import com.android.dialer.common.concurrent.DialerExecutorComponent;
+import com.android.dialer.common.concurrent.ThreadUtil;
 import com.android.dialer.common.concurrent.UiListener;
 import com.android.dialer.compat.CompatUtils;
 import com.android.dialer.configprovider.ConfigProviderBindings;
@@ -87,6 +88,8 @@
 import com.android.dialer.main.impl.bottomnav.BottomNavBar.OnBottomNavTabSelectedListener;
 import com.android.dialer.main.impl.bottomnav.BottomNavBar.TabIndex;
 import com.android.dialer.main.impl.toolbar.MainToolbar;
+import com.android.dialer.metrics.Metrics;
+import com.android.dialer.metrics.MetricsComponent;
 import com.android.dialer.postcall.PostCall;
 import com.android.dialer.precall.PreCall;
 import com.android.dialer.searchfragment.list.NewSearchFragment.SearchFragmentListener;
@@ -200,7 +203,7 @@
     fab.setOnClickListener(
         v -> {
           Logger.get(mainActivity)
-              .logImpression(DialerImpression.Type.NUI_CLICK_FAB_TO_OPEN_DIALPAD);
+              .logImpression(DialerImpression.Type.MAIN_CLICK_FAB_TO_OPEN_DIALPAD);
           searchController.showDialpad(true);
         });
 
@@ -404,6 +407,14 @@
     } else {
       bottomNav.setVisibility(View.VISIBLE);
     }
+
+    // add 1 sec delay to get memory snapshot so that dialer wont react slowly on resume.
+    ThreadUtil.postDelayedOnUiThread(
+        () ->
+            MetricsComponent.get(mainActivity)
+                .metrics()
+                .recordMemory(Metrics.OLD_MAIN_ACTIVITY_PEER_ON_RESUME_MEMORY_EVENT_NAME),
+        1000);
   }
 
   @Override
@@ -1095,7 +1106,7 @@
     public void onSpeedDialSelected() {
       LogUtil.enterBlock("MainBottomNavBarBottomNavTabListener.onSpeedDialSelected");
       if (selectedTab != TabIndex.SPEED_DIAL) {
-        Logger.get(context).logImpression(DialerImpression.Type.NUI_SWITCH_TAB_TO_FAVORITE);
+        Logger.get(context).logImpression(DialerImpression.Type.MAIN_SWITCH_TAB_TO_FAVORITE);
         selectedTab = TabIndex.SPEED_DIAL;
       }
       hideAllFragments();
@@ -1115,7 +1126,7 @@
     public void onCallLogSelected() {
       LogUtil.enterBlock("MainBottomNavBarBottomNavTabListener.onCallLogSelected");
       if (selectedTab != TabIndex.CALL_LOG) {
-        Logger.get(context).logImpression(DialerImpression.Type.NUI_SWITCH_TAB_TO_CALL_LOG);
+        Logger.get(context).logImpression(DialerImpression.Type.MAIN_SWITCH_TAB_TO_CALL_LOG);
         selectedTab = TabIndex.CALL_LOG;
       }
       hideAllFragments();
@@ -1135,7 +1146,7 @@
     public void onContactsSelected() {
       LogUtil.enterBlock("MainBottomNavBarBottomNavTabListener.onContactsSelected");
       if (selectedTab != TabIndex.CONTACTS) {
-        Logger.get(context).logImpression(DialerImpression.Type.NUI_SWITCH_TAB_TO_CONTACTS);
+        Logger.get(context).logImpression(DialerImpression.Type.MAIN_SWITCH_TAB_TO_CONTACTS);
         selectedTab = TabIndex.CONTACTS;
       }
       hideAllFragments();
@@ -1159,7 +1170,7 @@
     public void onVoicemailSelected() {
       LogUtil.enterBlock("MainBottomNavBarBottomNavTabListener.onVoicemailSelected");
       if (selectedTab != TabIndex.VOICEMAIL) {
-        Logger.get(context).logImpression(DialerImpression.Type.NUI_SWITCH_TAB_TO_VOICEMAIL);
+        Logger.get(context).logImpression(DialerImpression.Type.MAIN_SWITCH_TAB_TO_VOICEMAIL);
         selectedTab = TabIndex.VOICEMAIL;
       }
       hideAllFragments();
diff --git a/java/com/android/dialer/main/impl/res/layout/main_activity.xml b/java/com/android/dialer/main/impl/res/layout/main_activity.xml
index b69625e..0883ace 100644
--- a/java/com/android/dialer/main/impl/res/layout/main_activity.xml
+++ b/java/com/android/dialer/main/impl/res/layout/main_activity.xml
@@ -37,7 +37,7 @@
         android:layout_height="match_parent"
         android:layout_above="@+id/bottom_nav_bar"/>
 
-    <android.support.design.widget.FloatingActionButton
+    <com.android.dialer.widget.DialerFloatingActionButton
         android:id="@+id/fab"
         android:layout_width="wrap_content"
         android:layout_height="wrap_content"
diff --git a/java/com/android/dialer/metrics/FutureTimer.java b/java/com/android/dialer/metrics/FutureTimer.java
index f7ba3fe..a45fb38 100644
--- a/java/com/android/dialer/metrics/FutureTimer.java
+++ b/java/com/android/dialer/metrics/FutureTimer.java
@@ -21,6 +21,7 @@
 import android.support.annotation.VisibleForTesting;
 import com.android.dialer.common.LogUtil;
 import com.android.dialer.common.concurrent.Annotations.LightweightExecutor;
+import com.google.common.base.Function;
 import com.google.common.util.concurrent.FutureCallback;
 import com.google.common.util.concurrent.Futures;
 import com.google.common.util.concurrent.ListenableFuture;
@@ -72,7 +73,7 @@
    * of tracking heavyweight operations (which is what this method is intended for).
    */
   public <T> void applyTiming(ListenableFuture<T> future, String eventName) {
-    applyTiming(future, eventName, LogCatMode.DONT_LOG_VALUES);
+    applyTiming(future, unused -> eventName, LogCatMode.DONT_LOG_VALUES);
   }
 
   /**
@@ -81,14 +82,35 @@
    */
   public <T> void applyTiming(
       ListenableFuture<T> future, String eventName, @LogCatMode int logCatMode) {
+    applyTiming(future, unused -> eventName, logCatMode);
+  }
+
+  /**
+   * Overload of {@link #applyTiming(ListenableFuture, String)} that accepts a function which
+   * specifies how to compute an event name from the result of the future.
+   *
+   * <p>This is useful when the event name depends on the result of the future.
+   */
+  public <T> void applyTiming(
+      ListenableFuture<T> future, Function<T, String> eventNameFromResultFunction) {
+    applyTiming(future, eventNameFromResultFunction, LogCatMode.DONT_LOG_VALUES);
+  }
+
+  private <T> void applyTiming(
+      ListenableFuture<T> future,
+      Function<T, String> eventNameFromResultFunction,
+      @LogCatMode int logCatMode) {
     long startTime = SystemClock.elapsedRealtime();
-    metrics.startTimer(eventName);
+    Integer timerId = metrics.startUnnamedTimer();
     Futures.addCallback(
         future,
         new FutureCallback<T>() {
           @Override
           public void onSuccess(T result) {
-            metrics.stopTimer(eventName);
+            String eventName = eventNameFromResultFunction.apply(result);
+            if (timerId != null) {
+              metrics.stopUnnamedTimer(timerId, eventName);
+            }
             long operationTime = SystemClock.elapsedRealtime() - startTime;
 
             // If the operation took a long time, do some WARNING logging.
diff --git a/java/com/android/dialer/metrics/Metrics.java b/java/com/android/dialer/metrics/Metrics.java
index 383b3a3..5572658 100644
--- a/java/com/android/dialer/metrics/Metrics.java
+++ b/java/com/android/dialer/metrics/Metrics.java
@@ -17,23 +17,35 @@
 package com.android.dialer.metrics;
 
 import android.app.Application;
+import android.support.annotation.Nullable;
 
 /** Logs metrics. */
 public interface Metrics {
 
   String APPLICATION_ON_CREATE_EVENT_NAME = "Application.onCreate";
   String DIALTACTS_ON_CREATE_EVENT_NAME = "GoogleDialtactsActivity.onCreate";
+  String MAIN_ACTIVITY_ON_CREATE_EVENT_NAME = "GoogleMainActivity.onCreate";
   String ON_CALL_ADDED_TO_ON_INCALL_UI_SHOWN_INCOMING =
       "CallList.onCallAdded_To_InCallActivity.onCreate_Incoming";
   String ON_CALL_ADDED_TO_ON_INCALL_UI_SHOWN_OUTGOING =
       "CallList.onCallAdded_To_InCallActivity.onCreate_Outgoing";
   String DIALTACTS_ON_RESUME_MEMORY_EVENT_NAME = "GoogleDialtactsActivity.onResume";
+  String OLD_MAIN_ACTIVITY_PEER_ON_RESUME_MEMORY_EVENT_NAME = "OldMainActivityPeer.onResume";
   String INCALL_ACTIVITY_ON_RESUME_MEMORY_EVENT_NAME = "IncallActivity.OnResume";
   String INCALL_ACTIVITY_ON_STOP_MEMORY_EVENT_NAME = "IncallActivity.OnStop";
   String OLD_CALL_LOG_JANK_EVENT_NAME = "OldCallLog.Jank";
   String NEW_CALL_LOG_JANK_EVENT_NAME = "NewCallLog.Jank";
 
   // Events related to refreshing the annotated call log.
+  String NEW_CALL_LOG_COALESCE = "NewCallLog.Coalesce";
+  String ANNOTATED_CALL_LOG_NOT_DIRTY = "RefreshAnnotatedCallLogReceiver.NotDirty";
+  String ANNOTATED_CALL_LOG_CHANGES_NEEDED = "RefreshAnnotatedCallLogReceiver.ChangesNeeded";
+  String ANNOTATED_LOG_NO_CHANGES_NEEDED = "RefreshAnnotatedCallLogReceiver.NoChangesNeeded";
+  String ANNOTATED_CALL_LOG_FORCE_REFRESH_CHANGES_NEEDED =
+      "RefreshAnnotatedCallLogReceiver.ForceRefreshChangesNeeded";
+  String NEW_CALL_LOG_FORCE_REFRESH_NO_CHANGES_NEEDED =
+      "RefreshAnnotatedCallLogReceiver.ForceRefreshNoChangesNeeded";
+
   String INITIAL_FILL_EVENT_NAME = "RefreshAnnotatedCallLog.Initial.Fill";
   String INITIAL_ON_SUCCESSFUL_FILL_EVENT_NAME = "RefreshAnnotatedCallLog.Initial.OnSuccessfulFill";
   String INITIAL_APPLY_MUTATIONS_EVENT_NAME = "RefreshAnnotatedCallLog.Initial.ApplyMutations";
@@ -59,6 +71,23 @@
   /** Start a timer. */
   void startTimer(String timerEventName);
 
+  /**
+   * Starts a timer for which the name is not yet known.
+   *
+   * @return opaque identifier for the event which should be provided back to {@link
+   *     #stopUnnamedTimer(int, String)} to stop the timer. Null if the timer cannot be started, for
+   *     example because the user is locked.
+   */
+  @Nullable
+  Integer startUnnamedTimer();
+
+  /**
+   * Stop a timer which was started with {@link #startUnnamedTimer()}.
+   *
+   * @param timerId the value returned in the corresponding call to {@link #startUnnamedTimer()}
+   */
+  void stopUnnamedTimer(int timerId, String timerEventName);
+
   /** Stop a timer. */
   void stopTimer(String timerEventName);
 
diff --git a/java/com/android/dialer/metrics/MetricsComponent.java b/java/com/android/dialer/metrics/MetricsComponent.java
index f371297..a3570db 100644
--- a/java/com/android/dialer/metrics/MetricsComponent.java
+++ b/java/com/android/dialer/metrics/MetricsComponent.java
@@ -28,6 +28,8 @@
 
   public abstract Metrics.Initializer metricsInitializer();
 
+  public abstract FutureTimer futureTimer();
+
   public static MetricsComponent get(Context context) {
     return ((MetricsComponent.HasComponent)
             ((HasRootComponent) context.getApplicationContext()).component())
diff --git a/java/com/android/dialer/metrics/StubMetrics.java b/java/com/android/dialer/metrics/StubMetrics.java
index 99c3d76..ecd2382 100644
--- a/java/com/android/dialer/metrics/StubMetrics.java
+++ b/java/com/android/dialer/metrics/StubMetrics.java
@@ -16,26 +16,91 @@
 
 package com.android.dialer.metrics;
 
+import android.os.SystemClock;
+import com.android.dialer.common.Assert;
+import com.android.dialer.common.LogUtil;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentMap;
+import javax.annotation.concurrent.ThreadSafe;
 import javax.inject.Inject;
+import javax.inject.Singleton;
 
-/** Stub {@link Metrics}. */
+/** Stub {@link Metrics} which simply logs debug messages to logcat. */
+@ThreadSafe
+@Singleton
 public final class StubMetrics implements Metrics {
 
+  private final ConcurrentMap<String, StubTimerEvent> namedEvents = new ConcurrentHashMap<>();
+  private final ConcurrentMap<Integer, StubTimerEvent> unnamedEvents = new ConcurrentHashMap<>();
+
   @Inject
   StubMetrics() {}
 
   @Override
-  public void startTimer(String timerEventName) {}
+  public void startTimer(String timerEventName) {
+    namedEvents.put(timerEventName, new StubTimerEvent());
+  }
 
   @Override
-  public void stopTimer(String timerEventName) {}
+  public Integer startUnnamedTimer() {
+    StubTimerEvent stubTimerEvent = new StubTimerEvent();
+    int id = stubTimerEvent.hashCode();
+    LogUtil.d("StubMetrics.startUnnamedTimer", "started timer for id: %d", id);
+    unnamedEvents.put(id, stubTimerEvent);
+    return id;
+  }
 
   @Override
-  public void startJankRecorder(String eventName) {}
+  public void stopTimer(String timerEventName) {
+    StubTimerEvent stubTimerEvent = namedEvents.remove(timerEventName);
+    if (stubTimerEvent == null) {
+      return;
+    }
+
+    LogUtil.d(
+        "StubMetrics.stopTimer",
+        "%s took %dms",
+        timerEventName,
+        SystemClock.elapsedRealtime() - stubTimerEvent.startTime);
+  }
 
   @Override
-  public void stopJankRecorder(String eventName) {}
+  public void stopUnnamedTimer(int timerId, String timerEventName) {
+    long startTime =
+        Assert.isNotNull(
+                unnamedEvents.remove(timerId),
+                "no timer found for id: %d (%s)",
+                timerId,
+                timerEventName)
+            .startTime;
+
+    LogUtil.d(
+        "StubMetrics.stopUnnamedTimer",
+        "%s took %dms",
+        timerEventName,
+        SystemClock.elapsedRealtime() - startTime);
+  }
 
   @Override
-  public void recordMemory(String memoryEventName) {}
+  public void startJankRecorder(String eventName) {
+    LogUtil.d("StubMetrics.startJankRecorder", "started jank recorder for %s", eventName);
+  }
+
+  @Override
+  public void stopJankRecorder(String eventName) {
+    LogUtil.d("StubMetrics.startJankRecorder", "stopped jank recorder for %s", eventName);
+  }
+
+  @Override
+  public void recordMemory(String memoryEventName) {
+    LogUtil.d("StubMetrics.startJankRecorder", "recorded memory for %s", memoryEventName);
+  }
+
+  private static class StubTimerEvent {
+    final long startTime;
+
+    StubTimerEvent() {
+      this.startTime = SystemClock.elapsedRealtime();
+    }
+  }
 }
diff --git a/java/com/android/dialer/phonenumbercache/ContactInfoHelper.java b/java/com/android/dialer/phonenumbercache/ContactInfoHelper.java
index f094be8..01f9669 100644
--- a/java/com/android/dialer/phonenumbercache/ContactInfoHelper.java
+++ b/java/com/android/dialer/phonenumbercache/ContactInfoHelper.java
@@ -475,7 +475,7 @@
     if (TextUtils.isEmpty(countryIso)) {
       countryIso = currentCountryIso;
     }
-    return PhoneNumberUtils.formatNumber(number, normalizedNumber, countryIso);
+    return PhoneNumberHelper.formatNumber(context, number, normalizedNumber, countryIso);
   }
 
   /**
diff --git a/java/com/android/dialer/phonenumberutil/PhoneNumberHelper.java b/java/com/android/dialer/phonenumberutil/PhoneNumberHelper.java
index b58739d..f5e6346 100644
--- a/java/com/android/dialer/phonenumberutil/PhoneNumberHelper.java
+++ b/java/com/android/dialer/phonenumberutil/PhoneNumberHelper.java
@@ -35,6 +35,7 @@
 import com.android.dialer.compat.telephony.TelephonyManagerCompat;
 import com.android.dialer.phonenumbergeoutil.PhoneNumberGeoUtilComponent;
 import com.android.dialer.telecom.TelecomUtil;
+import com.google.common.base.Ascii;
 import java.util.Arrays;
 import java.util.HashSet;
 import java.util.Set;
@@ -224,28 +225,50 @@
   }
 
   /**
-   * @return Formatted phone number. e.g. 1-123-456-7890. Returns the original number if formatting
-   *     failed.
+   * An enhanced version of {@link PhoneNumberUtils#formatNumber(String, String, String)}.
+   *
+   * <p>The {@link Context} parameter allows us to tweak formatting according to device properties.
+   *
+   * <p>Returns the formatted phone number (e.g, 1-123-456-7890) or the original number if
+   * formatting fails or is intentionally ignored.
    */
-  public static String formatNumber(@Nullable String number, String countryIso) {
+  public static String formatNumber(
+      Context context, @Nullable String number, @Nullable String numberE164, String countryIso) {
     // The number can be null e.g. schema is voicemail and uri content is empty.
     if (number == null) {
       return null;
     }
-    String formattedNumber = PhoneNumberUtils.formatNumber(number, countryIso);
+
+    // Argentina phone number formats are complex and PhoneNumberUtils doesn't format all Argentina
+    // numbers correctly.
+    // To ensure consistent user experience, we disable phone number formatting for all numbers
+    // (not just Argentinian ones) for devices with Argentinian SIMs.
+    TelephonyManager telephonyManager =
+        (TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE);
+    if (telephonyManager != null
+        && "AR".equals(Ascii.toUpperCase(telephonyManager.getSimCountryIso()))) {
+      return number;
+    }
+
+    String formattedNumber = PhoneNumberUtils.formatNumber(number, numberE164, countryIso);
     return formattedNumber != null ? formattedNumber : number;
   }
 
+  /** @see #formatNumber(Context, String, String, String). */
+  public static String formatNumber(Context context, @Nullable String number, String countryIso) {
+    return formatNumber(context, number, /* numberE164 = */ null, countryIso);
+  }
+
   @Nullable
   public static CharSequence formatNumberForDisplay(
-      @Nullable String number, @NonNull String countryIso) {
+      Context context, @Nullable String number, @NonNull String countryIso) {
     if (number == null) {
       return null;
     }
 
     return PhoneNumberUtils.createTtsSpannable(
         BidiFormatter.getInstance()
-            .unicodeWrap(formatNumber(number, countryIso), TextDirectionHeuristics.LTR));
+            .unicodeWrap(formatNumber(context, number, countryIso), TextDirectionHeuristics.LTR));
   }
 
   /**
diff --git a/java/com/android/dialer/precall/impl/AssistedDialAction.java b/java/com/android/dialer/precall/impl/AssistedDialAction.java
index 15a889e..9ed37ac 100644
--- a/java/com/android/dialer/precall/impl/AssistedDialAction.java
+++ b/java/com/android/dialer/precall/impl/AssistedDialAction.java
@@ -20,7 +20,6 @@
 import android.content.Context;
 import android.os.Build;
 import android.os.Bundle;
-import android.support.v4.os.BuildCompat;
 import android.telecom.PhoneAccount;
 import android.telephony.SubscriptionInfo;
 import android.telephony.TelephonyManager;
@@ -58,9 +57,7 @@
     AssistedDialingMediator assistedDialingMediator =
         ConcreteCreator.createNewAssistedDialingMediator(
             getAssistedDialingTelephonyManager(context, builder), context);
-    if (BuildCompat.isAtLeastP()) {
-      builder.getOutgoingCallExtras().putBoolean(TelephonyManagerCompat.USE_ASSISTED_DIALING, true);
-    }
+
     // Checks the platform is N+ and meets other pre-flight checks.
     if (!assistedDialingMediator.isPlatformEligible()) {
       return;
diff --git a/java/com/android/dialer/speeddial/SuggestionViewHolder.java b/java/com/android/dialer/speeddial/SuggestionViewHolder.java
index 70df307..68c0ce4 100644
--- a/java/com/android/dialer/speeddial/SuggestionViewHolder.java
+++ b/java/com/android/dialer/speeddial/SuggestionViewHolder.java
@@ -23,7 +23,6 @@
 import android.provider.ContactsContract.CommonDataKinds.Phone;
 import android.provider.ContactsContract.Contacts;
 import android.support.v7.widget.RecyclerView;
-import android.telephony.PhoneNumberUtils;
 import android.text.TextUtils;
 import android.view.View;
 import android.view.View.OnClickListener;
@@ -32,6 +31,7 @@
 import com.android.dialer.contactphoto.ContactPhotoManager;
 import com.android.dialer.lettertile.LetterTileDrawable;
 import com.android.dialer.location.GeoUtil;
+import com.android.dialer.phonenumberutil.PhoneNumberHelper;
 
 /** ViewHolder for displaying suggested contacts in {@link SpeedDialFragment}. */
 public class SuggestionViewHolder extends RecyclerView.ViewHolder implements OnClickListener {
@@ -56,7 +56,7 @@
 
   public void bind(Context context, Cursor cursor) {
     number = cursor.getString(StrequentContactsCursorLoader.PHONE_NUMBER);
-    number = PhoneNumberUtils.formatNumber(number, GeoUtil.getCurrentCountryIso(context));
+    number = PhoneNumberHelper.formatNumber(context, number, GeoUtil.getCurrentCountryIso(context));
 
     String name = cursor.getString(StrequentContactsCursorLoader.PHONE_DISPLAY_NAME);
     String label = getLabel(context.getResources(), cursor);
diff --git a/java/com/android/dialer/voicemail/listui/NewVoicemailFragment.java b/java/com/android/dialer/voicemail/listui/NewVoicemailFragment.java
index 6d71dad..3a5e72b 100644
--- a/java/com/android/dialer/voicemail/listui/NewVoicemailFragment.java
+++ b/java/com/android/dialer/voicemail/listui/NewVoicemailFragment.java
@@ -210,7 +210,8 @@
     showView(emptyContentView);
 
     emptyContentView.setDescription((R.string.empty_voicemail_tab_text));
-    emptyContentView.setImage(R.drawable.quantum_ic_schedule_vd_theme_24);
+    emptyContentView.setImage(R.drawable.quantum_ic_voicemail_vd_theme_24);
+    emptyContentView.setImageTint(R.color.empty_voicemail_icon_tint_color, null);
   }
 
   private void showView(View view) {
diff --git a/java/com/android/dialer/voicemail/settings/VoicemailSettingsFragment.java b/java/com/android/dialer/voicemail/settings/VoicemailSettingsFragment.java
index 7f5bb79..5ae26f5 100644
--- a/java/com/android/dialer/voicemail/settings/VoicemailSettingsFragment.java
+++ b/java/com/android/dialer/voicemail/settings/VoicemailSettingsFragment.java
@@ -32,14 +32,12 @@
 import android.telecom.TelecomManager;
 import android.telephony.SubscriptionInfo;
 import android.telephony.TelephonyManager;
-import android.text.Html;
 import com.android.dialer.common.Assert;
 import com.android.dialer.common.LogUtil;
 import com.android.dialer.logging.DialerImpression;
 import com.android.dialer.logging.Logger;
 import com.android.dialer.notification.NotificationChannelManager;
 import com.android.dialer.telecom.TelecomUtil;
-import com.android.dialer.widget.TextViewPreference;
 import com.android.voicemail.VoicemailClient;
 import com.android.voicemail.VoicemailClient.ActivationStateListener;
 import com.android.voicemail.VoicemailComponent;
@@ -75,7 +73,6 @@
   private SwitchPreference donateVoicemailSwitchPreference;
   private Preference voicemailChangePinPreference;
   private PreferenceScreen advancedSettings;
-  private TextViewPreference voicemailTranscriptionInstructionText;
 
   @Override
   public void onCreate(Bundle icicle) {
@@ -212,10 +209,6 @@
             return false;
           }
         });
-
-    voicemailTranscriptionInstructionText =
-        (TextViewPreference) findPreference(getString(R.string.voicemail_transcription_text_key));
-    voicemailTranscriptionInstructionText.setTitle(getVoicemailTranscriptionInstructionsText());
   }
 
   @Override
@@ -355,20 +348,4 @@
     builder.setCancelable(true);
     builder.show();
   }
-
-  /**
-   * Builds a spannable string containing the voicemail transcription instructions text containing
-   * the appropriate "Learn More" urls.
-   *
-   * @return The voicemail transcription instructions text.
-   */
-  private CharSequence getVoicemailTranscriptionInstructionsText() {
-    String settingText =
-        getString(
-            R.string.voicemail_transcription_instruction_text,
-            getString(R.string.transcription_learn_more_url),
-            getString(R.string.donation_learn_more_url));
-    CharSequence settingSeq = Html.fromHtml(settingText);
-    return settingSeq;
-  }
 }
diff --git a/java/com/android/dialer/voicemail/settings/res/values/strings.xml b/java/com/android/dialer/voicemail/settings/res/values/strings.xml
index 3056ef6..1d2c104 100644
--- a/java/com/android/dialer/voicemail/settings/res/values/strings.xml
+++ b/java/com/android/dialer/voicemail/settings/res/values/strings.xml
@@ -125,17 +125,6 @@
   <!-- The label for the confirm-disable-voicemail button [CHAR LIMIT=16] -->
   <string name="confirm_disable_voicemail_accept_dialog_label">TURN OFF</string>
 
-  <!-- Internal preferences key for static instruction text. -->
-  <string name="voicemail_transcription_text_key" translatable="false">voicemail_transcription_text_key</string>
-
-  <!-- Additional information text and links for visual voicemail and voicemail donation setting page
-       [CHAR LIMIT=NONE] -->
-  <string name="voicemail_transcription_instruction_text">
-    Visual voicemail allows you to check voicemail messages without having to call voicemail. Transcripts provided by Google. &lt;a href="<xliff:g example="http://www.google.com" id="url1">%1$s</xliff:g>">Learn&#160;more&lt;/a>
-    &lt;br>&lt;br>
-    For voicemail transcription analysis, your voicemail messages are stored anonymously. &lt;a href="<xliff:g example="http://www.google.com" id="url2">%2$s</xliff:g>">Learn&#160;more&lt;/a>
-  </string>
-
   <string translatable="false" name="transcription_learn_more_url">https://support.google.com/phoneapp/answer/2811844?hl=en%26ref_topic=7539039</string>
   <string translatable="false" name="donation_learn_more_url">https://support.google.com/phoneapp/answer/2811844#voicemail_transcript</string>
 
diff --git a/java/com/android/dialer/voicemail/settings/res/xml/voicemail_settings.xml b/java/com/android/dialer/voicemail/settings/res/xml/voicemail_settings.xml
index 75c8cfe..e558985 100644
--- a/java/com/android/dialer/voicemail/settings/res/xml/voicemail_settings.xml
+++ b/java/com/android/dialer/voicemail/settings/res/xml/voicemail_settings.xml
@@ -44,7 +44,4 @@
     android:title="@string/voicemail_advanced_settings_title">
     </PreferenceScreen>
 
-  <com.android.dialer.widget.TextViewPreference
-    android:key="@string/voicemail_transcription_text_key"/>
-
 </PreferenceScreen>
diff --git a/java/com/android/dialer/widget/DialerFloatingActionButton.java b/java/com/android/dialer/widget/DialerFloatingActionButton.java
new file mode 100644
index 0000000..17ad907
--- /dev/null
+++ b/java/com/android/dialer/widget/DialerFloatingActionButton.java
@@ -0,0 +1,79 @@
+/*
+ * 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.support.design.widget.FloatingActionButton;
+import android.util.AttributeSet;
+import com.android.dialer.common.Assert;
+
+/**
+ * Since {@link FloatingActionButton} is possibly the worst widget supported by the framework, we
+ * need this class to work around several of it's bugs.
+ *
+ * <p>Current fixes:
+ *
+ * <ul>
+ *   <li>Being able to trigger click events twice.
+ *   <li>Banning setVisibility since 9 times out of 10, it just causes bad state.
+ * </ul>
+ *
+ * Planned fixes:
+ *
+ * <ul>
+ *   <li>Animating on first show/hide
+ *   <li>Being able to call show/hide rapidly and being in the proper state
+ *   <li>Having a proper 48x48 touch target in mini mode
+ * </ul>
+ */
+public class DialerFloatingActionButton extends FloatingActionButton {
+
+  public DialerFloatingActionButton(Context context, AttributeSet attributeSet) {
+    super(context, attributeSet);
+  }
+
+  @Override
+  public void show() {
+    super.show();
+    setClickable(true);
+  }
+
+  @Override
+  public void show(@Nullable OnVisibilityChangedListener onVisibilityChangedListener) {
+    super.show(onVisibilityChangedListener);
+    setClickable(true);
+  }
+
+  @Override
+  public void hide() {
+    super.hide();
+    setClickable(false);
+  }
+
+  @Override
+  public void hide(@Nullable OnVisibilityChangedListener onVisibilityChangedListener) {
+    super.hide(onVisibilityChangedListener);
+    setClickable(false);
+  }
+
+  @Override
+  public void setVisibility(int i) {
+    throw Assert.createUnsupportedOperationFailException(
+        "Do not call setVisibility, call show/hide instead");
+  }
+}
diff --git a/java/com/android/dialer/widget/EmptyContentView.java b/java/com/android/dialer/widget/EmptyContentView.java
index 5c2e4d5..b99657a 100644
--- a/java/com/android/dialer/widget/EmptyContentView.java
+++ b/java/com/android/dialer/widget/EmptyContentView.java
@@ -17,6 +17,10 @@
 package com.android.dialer.widget;
 
 import android.content.Context;
+import android.content.res.ColorStateList;
+import android.content.res.Resources.Theme;
+import android.support.annotation.ColorRes;
+import android.support.annotation.Nullable;
 import android.support.annotation.StringRes;
 import android.util.AttributeSet;
 import android.view.LayoutInflater;
@@ -86,6 +90,11 @@
     }
   }
 
+  public void setImageTint(@ColorRes int color, @Nullable Theme theme) {
+    imageView.setImageTintList(
+        (ColorStateList.valueOf(getContext().getResources().getColor(color, theme))));
+  }
+
   public void setActionLabel(@StringRes int resourceId) {
     actionLabel = resourceId;
     if (resourceId == NO_LABEL) {
diff --git a/java/com/android/dialer/widget/res/layout-land/empty_content_view.xml b/java/com/android/dialer/widget/res/layout-land/empty_content_view.xml
index 00344bf..3a7574f 100644
--- a/java/com/android/dialer/widget/res/layout-land/empty_content_view.xml
+++ b/java/com/android/dialer/widget/res/layout-land/empty_content_view.xml
@@ -18,7 +18,7 @@
   <ImageView
       android:id="@+id/empty_list_view_image"
       android:layout_width="match_parent"
-      android:layout_height="0dp"
+      android:layout_height="108dp"
       android:layout_weight="1"
       android:maxHeight="126dp"
       android:gravity="center_horizontal"/>
diff --git a/java/com/android/dialer/widget/res/values/colors.xml b/java/com/android/dialer/widget/res/values/colors.xml
index c974609..12a5cb9 100644
--- a/java/com/android/dialer/widget/res/values/colors.xml
+++ b/java/com/android/dialer/widget/res/values/colors.xml
@@ -1,4 +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="empty_list_text_color">#b2b2b2</color>
+  <color name="empty_voicemail_icon_tint_color">#E1E1E1</color>
 </resources>
\ No newline at end of file
diff --git a/java/com/android/incallui/CallCardPresenter.java b/java/com/android/incallui/CallCardPresenter.java
index ad92f57..8eb07c5 100644
--- a/java/com/android/incallui/CallCardPresenter.java
+++ b/java/com/android/incallui/CallCardPresenter.java
@@ -483,7 +483,7 @@
                   .setCallSubject(shouldShowCallSubject(primary) ? primary.getCallSubject() : null)
                   .setCallbackNumber(
                       PhoneNumberHelper.formatNumber(
-                          primary.getCallbackNumber(), primary.getSimCountryIso()))
+                          context, primary.getCallbackNumber(), primary.getSimCountryIso()))
                   .setIsWifi(primary.hasProperty(Details.PROPERTY_WIFI))
                   .setIsConference(
                       primary.isConferenceCall()
@@ -907,7 +907,7 @@
 
     if (secondary == null) {
       // Clear the secondary display info.
-      inCallScreen.setSecondary(SecondaryInfo.createEmptySecondaryInfo(isFullscreen));
+      inCallScreen.setSecondary(SecondaryInfo.builder().setIsFullscreen(isFullscreen).build());
       return;
     }
 
@@ -915,39 +915,39 @@
       LogUtil.i(
           "CallCardPresenter.updateSecondaryDisplayInfo",
           "secondary call is merge in process, clearing info");
-      inCallScreen.setSecondary(SecondaryInfo.createEmptySecondaryInfo(isFullscreen));
+      inCallScreen.setSecondary(SecondaryInfo.builder().setIsFullscreen(isFullscreen).build());
       return;
     }
 
     if (secondary.isConferenceCall()) {
       inCallScreen.setSecondary(
-          new SecondaryInfo(
-              true /* show */,
-              CallerInfoUtils.getConferenceString(
-                  context, secondary.hasProperty(Details.PROPERTY_GENERIC_CONFERENCE)),
-              false /* nameIsNumber */,
-              null /* label */,
-              secondary.getCallProviderLabel(),
-              true /* isConference */,
-              secondary.isVideoCall(),
-              isFullscreen));
+          SecondaryInfo.builder()
+              .setShouldShow(true)
+              .setName(
+                  CallerInfoUtils.getConferenceString(
+                      context, secondary.hasProperty(Details.PROPERTY_GENERIC_CONFERENCE)))
+              .setProviderLabel(secondary.getCallProviderLabel())
+              .setIsConference(true)
+              .setIsVideoCall(secondary.isVideoCall())
+              .setIsFullscreen(isFullscreen)
+              .build());
     } else if (secondaryContactInfo != null) {
       LogUtil.v("CallCardPresenter.updateSecondaryDisplayInfo", "" + secondaryContactInfo);
       String name = getNameForCall(secondaryContactInfo);
       boolean nameIsNumber = name != null && name.equals(secondaryContactInfo.number);
       inCallScreen.setSecondary(
-          new SecondaryInfo(
-              true /* show */,
-              secondary.updateNameIfRestricted(name),
-              nameIsNumber,
-              secondaryContactInfo.label,
-              secondary.getCallProviderLabel(),
-              false /* isConference */,
-              secondary.isVideoCall(),
-              isFullscreen));
+          SecondaryInfo.builder()
+              .setShouldShow(true)
+              .setName(secondary.updateNameIfRestricted(name))
+              .setNameIsNumber(nameIsNumber)
+              .setLabel(secondaryContactInfo.label)
+              .setProviderLabel(secondary.getCallProviderLabel())
+              .setIsVideoCall(secondary.isVideoCall())
+              .setIsFullscreen(isFullscreen)
+              .build());
     } else {
       // Clear the secondary display info.
-      inCallScreen.setSecondary(SecondaryInfo.createEmptySecondaryInfo(isFullscreen));
+      inCallScreen.setSecondary(SecondaryInfo.builder().setIsFullscreen(isFullscreen).build());
     }
   }
 
diff --git a/java/com/android/incallui/ConferenceParticipantListAdapter.java b/java/com/android/incallui/ConferenceParticipantListAdapter.java
index d4579b1..4780974 100644
--- a/java/com/android/incallui/ConferenceParticipantListAdapter.java
+++ b/java/com/android/incallui/ConferenceParticipantListAdapter.java
@@ -20,6 +20,7 @@
 import android.net.Uri;
 import android.support.annotation.Nullable;
 import android.support.v4.util.ArrayMap;
+import android.telephony.PhoneNumberUtils;
 import android.text.BidiFormatter;
 import android.text.TextDirectionHeuristics;
 import android.text.TextUtils;
@@ -32,7 +33,6 @@
 import android.widget.ImageView;
 import android.widget.ListView;
 import android.widget.TextView;
-import com.android.contacts.common.compat.PhoneNumberUtilsCompat;
 import com.android.contacts.common.preference.ContactsPreferences;
 import com.android.contacts.common.util.ContactDisplayUtils;
 import com.android.dialer.common.LogUtil;
@@ -341,7 +341,7 @@
     } else {
       numberTextView.setVisibility(View.VISIBLE);
       numberTextView.setText(
-          PhoneNumberUtilsCompat.createTtsSpannable(
+          PhoneNumberUtils.createTtsSpannable(
               BidiFormatter.getInstance().unicodeWrap(callerNumber, TextDirectionHeuristics.LTR)));
     }
   }
diff --git a/java/com/android/incallui/ContactInfoCache.java b/java/com/android/incallui/ContactInfoCache.java
index d2ae709..9051338 100644
--- a/java/com/android/incallui/ContactInfoCache.java
+++ b/java/com/android/incallui/ContactInfoCache.java
@@ -214,7 +214,7 @@
         // No name, but we do have a valid CNAP name, so use that.
         displayName = info.cnapName;
         info.name = info.cnapName;
-        displayNumber = PhoneNumberHelper.formatNumber(number, info.countryIso);
+        displayNumber = PhoneNumberHelper.formatNumber(context, number, info.countryIso);
         Log.d(
             TAG,
             "  ==> cnapName available: displayName '"
@@ -227,7 +227,7 @@
         // case when an incoming call doesn't match any contact,
         // or if you manually dial an outgoing number using the
         // dialpad.
-        displayNumber = PhoneNumberHelper.formatNumber(number, info.countryIso);
+        displayNumber = PhoneNumberHelper.formatNumber(context, number, info.countryIso);
 
         Log.d(
             TAG,
@@ -252,7 +252,7 @@
         // later determine whether to use the name or nameAlternative when presenting
         displayName = info.name;
         cce.nameAlternative = info.nameAlternative;
-        displayNumber = PhoneNumberHelper.formatNumber(number, info.countryIso);
+        displayNumber = PhoneNumberHelper.formatNumber(context, number, info.countryIso);
         label = info.phoneLabel;
         Log.d(
             TAG,
diff --git a/java/com/android/incallui/DialpadFragment.java b/java/com/android/incallui/DialpadFragment.java
index c5b9d78..44eaf21 100644
--- a/java/com/android/incallui/DialpadFragment.java
+++ b/java/com/android/incallui/DialpadFragment.java
@@ -18,6 +18,7 @@
 
 import android.content.Context;
 import android.os.Bundle;
+import android.telephony.PhoneNumberUtils;
 import android.util.ArrayMap;
 import android.util.AttributeSet;
 import android.view.KeyEvent;
@@ -29,7 +30,6 @@
 import android.widget.EditText;
 import android.widget.LinearLayout;
 import android.widget.TextView;
-import com.android.contacts.common.compat.PhoneNumberUtilsCompat;
 import com.android.dialer.common.LogUtil;
 import com.android.dialer.dialpadview.DialpadKeyButton;
 import com.android.dialer.dialpadview.DialpadKeyButton.OnPressedListener;
@@ -199,7 +199,7 @@
    * @param text Text to set Dialpad EditText to.
    */
   public void setDtmfText(String text) {
-    dtmfDialerField.setText(PhoneNumberUtilsCompat.createTtsSpannable(text));
+    dtmfDialerField.setText(PhoneNumberUtils.createTtsSpannable(text));
   }
 
   /** Starts the slide up animation for the Dialpad keys when the Dialpad is revealed. */
diff --git a/java/com/android/incallui/answer/impl/answermethod/FlingUpDownMethod.java b/java/com/android/incallui/answer/impl/answermethod/FlingUpDownMethod.java
index b5dbc0c..2eeecc3 100644
--- a/java/com/android/incallui/answer/impl/answermethod/FlingUpDownMethod.java
+++ b/java/com/android/incallui/answer/impl/answermethod/FlingUpDownMethod.java
@@ -336,7 +336,7 @@
     if (getParent().isVideoCall() || getParent().isVideoUpgradeRequest()) {
       contactPuckIcon.setImageResource(R.drawable.quantum_ic_videocam_white_24);
     } else if (getParent().isRttCall()) {
-      contactPuckIcon.setImageResource(R.drawable.quantum_ic_call_white_24);
+      contactPuckIcon.setImageResource(R.drawable.quantum_ic_rtt_vd_theme_24);
     } else {
       contactPuckIcon.setImageResource(R.drawable.quantum_ic_call_white_24);
     }
diff --git a/java/com/android/incallui/call/DialerCall.java b/java/com/android/incallui/call/DialerCall.java
index 50bc691..d36b00d 100644
--- a/java/com/android/incallui/call/DialerCall.java
+++ b/java/com/android/incallui/call/DialerCall.java
@@ -1136,7 +1136,7 @@
    */
   public boolean isAssistedDialed() {
     if (getIntentExtras() != null) {
-      // O_MR1 and below uses the existence of USE_ASSISTED_DIALING to indicate assisted dialing
+      // P and below uses the existence of USE_ASSISTED_DIALING to indicate assisted dialing
       // was used. The Dialer client is responsible for performing assisted dialing before
       // placing the outgoing call.
       //
@@ -1148,13 +1148,6 @@
       }
     }
 
-    // Starting in P+ USE_ASSISTED_DIALING indicates that the client requested the platform
-    // perform assisted dialing. PROPERTY_ASSISTED_DIALING_USED indicates assisted dialing took
-    // place.
-    if (hasProperty(TelephonyManagerCompat.PROPERTY_ASSISTED_DIALING_USED)
-        && BuildCompat.isAtLeastP()) {
-      return true;
-    }
     return false;
   }
 
@@ -1164,21 +1157,6 @@
       return null;
     }
 
-    if (BuildCompat.isAtLeastP()) {
-      if (getExtras() == null) {
-        return null;
-      }
-
-      if (getExtras()
-              .getParcelable(TelephonyManagerCompat.EXTRA_ASSISTED_DIALING_TRANSFORMATION_INFO)
-          == null) {
-        return null;
-      }
-
-      // TODO(erfanian): Use the framework transformation info when we can link against it
-      return null;
-    }
-
     if (getIntentExtras().getBundle(TelephonyManagerCompat.ASSISTED_DIALING_EXTRAS) == null) {
       return null;
     }
diff --git a/java/com/android/incallui/contactgrid/ContactGridManager.java b/java/com/android/incallui/contactgrid/ContactGridManager.java
index 1b76958..327eaf2 100644
--- a/java/com/android/incallui/contactgrid/ContactGridManager.java
+++ b/java/com/android/incallui/contactgrid/ContactGridManager.java
@@ -22,6 +22,7 @@
 import android.os.SystemClock;
 import android.support.annotation.Nullable;
 import android.support.v4.view.ViewCompat;
+import android.telephony.PhoneNumberUtils;
 import android.text.TextUtils;
 import android.view.View;
 import android.view.accessibility.AccessibilityEvent;
@@ -30,7 +31,6 @@
 import android.widget.Space;
 import android.widget.TextView;
 import android.widget.ViewAnimator;
-import com.android.contacts.common.compat.PhoneNumberUtilsCompat;
 import com.android.dialer.common.Assert;
 import com.android.dialer.common.LogUtil;
 import com.android.dialer.lettertile.LetterTileDrawable;
@@ -276,7 +276,7 @@
     } else {
       contactNameTextView.setText(
           primaryInfo.nameIsNumber()
-              ? PhoneNumberUtilsCompat.createTtsSpannable(primaryInfo.name())
+              ? PhoneNumberUtils.createTtsSpannable(primaryInfo.name())
               : primaryInfo.name());
 
       // Set direction of the name field
diff --git a/java/com/android/incallui/hold/OnHoldFragment.java b/java/com/android/incallui/hold/OnHoldFragment.java
index 33ca158..bddb9ba 100644
--- a/java/com/android/incallui/hold/OnHoldFragment.java
+++ b/java/com/android/incallui/hold/OnHoldFragment.java
@@ -59,14 +59,14 @@
 
     ((TextView) view.findViewById(R.id.hold_contact_name))
         .setText(
-            secondaryInfo.nameIsNumber
+            secondaryInfo.nameIsNumber()
                 ? PhoneNumberUtils.createTtsSpannable(
                     BidiFormatter.getInstance()
-                        .unicodeWrap(secondaryInfo.name, TextDirectionHeuristics.LTR))
-                : secondaryInfo.name);
+                        .unicodeWrap(secondaryInfo.name(), TextDirectionHeuristics.LTR))
+                : secondaryInfo.name());
     ((ImageView) view.findViewById(R.id.hold_phone_icon))
         .setImageResource(
-            secondaryInfo.isVideoCall
+            secondaryInfo.isVideoCall()
                 ? R.drawable.quantum_ic_videocam_white_18
                 : R.drawable.quantum_ic_phone_paused_vd_theme_24);
     view.addOnAttachStateChangeListener(
diff --git a/java/com/android/incallui/incall/impl/InCallFragment.java b/java/com/android/incallui/incall/impl/InCallFragment.java
index 29160ab..5f558a4 100644
--- a/java/com/android/incallui/incall/impl/InCallFragment.java
+++ b/java/com/android/incallui/incall/impl/InCallFragment.java
@@ -305,7 +305,7 @@
     savedSecondaryInfo = null;
     FragmentTransaction transaction = getChildFragmentManager().beginTransaction();
     Fragment oldBanner = getChildFragmentManager().findFragmentById(R.id.incall_on_hold_banner);
-    if (secondaryInfo.shouldShow) {
+    if (secondaryInfo.shouldShow()) {
       transaction.replace(R.id.incall_on_hold_banner, OnHoldFragment.newInstance(secondaryInfo));
     } else {
       if (oldBanner != null) {
diff --git a/java/com/android/incallui/incall/protocol/SecondaryInfo.java b/java/com/android/incallui/incall/protocol/SecondaryInfo.java
index cadfca6..2dfd220 100644
--- a/java/com/android/incallui/incall/protocol/SecondaryInfo.java
+++ b/java/com/android/incallui/incall/protocol/SecondaryInfo.java
@@ -18,41 +18,62 @@
 
 import android.os.Parcel;
 import android.os.Parcelable;
+import android.support.annotation.Nullable;
 import com.android.dialer.common.LogUtil;
+import com.google.auto.value.AutoValue;
 import java.util.Locale;
 
 /** Information about the secondary call. */
-public class SecondaryInfo implements Parcelable {
-  public final boolean shouldShow;
-  public final String name;
-  public final boolean nameIsNumber;
-  public final String label;
-  public final String providerLabel;
-  public final boolean isConference;
-  public final boolean isVideoCall;
-  public final boolean isFullscreen;
+@AutoValue
+public abstract class SecondaryInfo implements Parcelable {
+  public abstract boolean shouldShow();
 
-  public static SecondaryInfo createEmptySecondaryInfo(boolean isFullScreen) {
-    return new SecondaryInfo(false, null, false, null, null, false, false, isFullScreen);
+  @Nullable
+  public abstract String name();
+
+  public abstract boolean nameIsNumber();
+
+  @Nullable
+  public abstract String label();
+
+  @Nullable
+  public abstract String providerLabel();
+
+  public abstract boolean isConference();
+
+  public abstract boolean isVideoCall();
+
+  public abstract boolean isFullscreen();
+
+  public static Builder builder() {
+    return new AutoValue_SecondaryInfo.Builder()
+        .setShouldShow(false)
+        .setNameIsNumber(false)
+        .setIsConference(false)
+        .setIsVideoCall(false)
+        .setIsFullscreen(false);
   }
 
-  public SecondaryInfo(
-      boolean shouldShow,
-      String name,
-      boolean nameIsNumber,
-      String label,
-      String providerLabel,
-      boolean isConference,
-      boolean isVideoCall,
-      boolean isFullscreen) {
-    this.shouldShow = shouldShow;
-    this.name = name;
-    this.nameIsNumber = nameIsNumber;
-    this.label = label;
-    this.providerLabel = providerLabel;
-    this.isConference = isConference;
-    this.isVideoCall = isVideoCall;
-    this.isFullscreen = isFullscreen;
+  /** Builder class for secondary info. */
+  @AutoValue.Builder
+  public abstract static class Builder {
+    public abstract Builder setShouldShow(boolean shouldShow);
+
+    public abstract Builder setName(String name);
+
+    public abstract Builder setNameIsNumber(boolean nameIsNumber);
+
+    public abstract Builder setLabel(String label);
+
+    public abstract Builder setProviderLabel(String providerLabel);
+
+    public abstract Builder setIsConference(boolean isConference);
+
+    public abstract Builder setIsVideoCall(boolean isVideoCall);
+
+    public abstract Builder setIsFullscreen(boolean isFullscreen);
+
+    public abstract SecondaryInfo build();
   }
 
   @Override
@@ -60,28 +81,26 @@
     return String.format(
         Locale.US,
         "SecondaryInfo, show: %b, name: %s, label: %s, " + "providerLabel: %s",
-        shouldShow,
-        LogUtil.sanitizePii(name),
-        label,
-        providerLabel);
-  }
-
-  protected SecondaryInfo(Parcel in) {
-    shouldShow = in.readByte() != 0;
-    name = in.readString();
-    nameIsNumber = in.readByte() != 0;
-    label = in.readString();
-    providerLabel = in.readString();
-    isConference = in.readByte() != 0;
-    isVideoCall = in.readByte() != 0;
-    isFullscreen = in.readByte() != 0;
+        shouldShow(),
+        LogUtil.sanitizePii(name()),
+        label(),
+        providerLabel());
   }
 
   public static final Creator<SecondaryInfo> CREATOR =
       new Creator<SecondaryInfo>() {
         @Override
         public SecondaryInfo createFromParcel(Parcel in) {
-          return new SecondaryInfo(in);
+          return builder()
+              .setShouldShow(in.readByte() != 0)
+              .setName(in.readString())
+              .setNameIsNumber(in.readByte() != 0)
+              .setLabel(in.readString())
+              .setProviderLabel(in.readString())
+              .setIsConference(in.readByte() != 0)
+              .setIsVideoCall(in.readByte() != 0)
+              .setIsFullscreen(in.readByte() != 0)
+              .build();
         }
 
         @Override
@@ -97,13 +116,13 @@
 
   @Override
   public void writeToParcel(Parcel dest, int flags) {
-    dest.writeByte((byte) (shouldShow ? 1 : 0));
-    dest.writeString(name);
-    dest.writeByte((byte) (nameIsNumber ? 1 : 0));
-    dest.writeString(label);
-    dest.writeString(providerLabel);
-    dest.writeByte((byte) (isConference ? 1 : 0));
-    dest.writeByte((byte) (isVideoCall ? 1 : 0));
-    dest.writeByte((byte) (isFullscreen ? 1 : 0));
+    dest.writeByte((byte) (shouldShow() ? 1 : 0));
+    dest.writeString(name());
+    dest.writeByte((byte) (nameIsNumber() ? 1 : 0));
+    dest.writeString(label());
+    dest.writeString(providerLabel());
+    dest.writeByte((byte) (isConference() ? 1 : 0));
+    dest.writeByte((byte) (isVideoCall() ? 1 : 0));
+    dest.writeByte((byte) (isFullscreen() ? 1 : 0));
   }
 }
diff --git a/java/com/android/incallui/rtt/impl/RttChatFragment.java b/java/com/android/incallui/rtt/impl/RttChatFragment.java
index deb205c..396b89e 100644
--- a/java/com/android/incallui/rtt/impl/RttChatFragment.java
+++ b/java/com/android/incallui/rtt/impl/RttChatFragment.java
@@ -29,6 +29,7 @@
 import android.text.Editable;
 import android.text.TextUtils;
 import android.text.TextWatcher;
+import android.view.Gravity;
 import android.view.KeyEvent;
 import android.view.LayoutInflater;
 import android.view.View;
@@ -45,6 +46,8 @@
 import com.android.dialer.common.Assert;
 import com.android.dialer.common.FragmentUtils;
 import com.android.dialer.common.LogUtil;
+import com.android.incallui.audioroute.AudioRouteSelectorDialogFragment;
+import com.android.incallui.audioroute.AudioRouteSelectorDialogFragment.AudioRouteSelectorPresenter;
 import com.android.incallui.call.DialerCall.State;
 import com.android.incallui.incall.protocol.InCallButtonUi;
 import com.android.incallui.incall.protocol.InCallButtonUiDelegate;
@@ -68,7 +71,8 @@
         MessageListener,
         RttCallScreen,
         InCallScreen,
-        InCallButtonUi {
+        InCallButtonUi,
+        AudioRouteSelectorPresenter {
 
   private static final String ARG_CALL_ID = "call_id";
 
@@ -94,6 +98,7 @@
   private TextView nameTextView;
   private Chronometer chronometer;
   private boolean isTimerStarted;
+  private RttOverflowMenu overflowMenu;
 
   /**
    * Create a new instance of RttChatFragment.
@@ -173,6 +178,10 @@
           inCallButtonUiDelegate.onEndCallClicked();
         });
 
+    overflowMenu = new RttOverflowMenu(getContext(), inCallButtonUiDelegate);
+    view.findViewById(R.id.rtt_overflow_button)
+        .setOnClickListener(v -> overflowMenu.showAtLocation(v, Gravity.TOP | Gravity.RIGHT, 0, 0));
+
     nameTextView = view.findViewById(R.id.rtt_name_or_number);
     chronometer = view.findViewById(R.id.rtt_timer);
     return view;
@@ -240,6 +249,9 @@
   public void onStop() {
     LogUtil.enterBlock("RttChatFragment.onStop");
     super.onStop();
+    if (overflowMenu.isShowing()) {
+      overflowMenu.dismiss();
+    }
     onRttScreenStop();
   }
 
@@ -360,7 +372,11 @@
   public void setVideoPaused(boolean isPaused) {}
 
   @Override
-  public void setAudioState(CallAudioState audioState) {}
+  public void setAudioState(CallAudioState audioState) {
+    LogUtil.i("RttChatFragment.setAudioState", "audioState: " + audioState);
+    overflowMenu.setMuteButtonChecked(audioState.isMuted());
+    overflowMenu.setAudioState(audioState);
+  }
 
   @Override
   public void updateButtonStates() {}
@@ -374,5 +390,16 @@
   }
 
   @Override
-  public void showAudioRouteSelector() {}
+  public void showAudioRouteSelector() {
+    AudioRouteSelectorDialogFragment.newInstance(inCallButtonUiDelegate.getCurrentAudioState())
+        .show(getChildFragmentManager(), null);
+  }
+
+  @Override
+  public void onAudioRouteSelected(int audioRoute) {
+    inCallButtonUiDelegate.setAudioRoute(audioRoute);
+  }
+
+  @Override
+  public void onAudioRouteSelectorDismiss() {}
 }
diff --git a/java/com/android/incallui/rtt/impl/RttCheckableButton.java b/java/com/android/incallui/rtt/impl/RttCheckableButton.java
new file mode 100644
index 0000000..c0c8599
--- /dev/null
+++ b/java/com/android/incallui/rtt/impl/RttCheckableButton.java
@@ -0,0 +1,227 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.incallui.rtt.impl;
+
+import android.content.Context;
+import android.content.res.TypedArray;
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.util.AttributeSet;
+import android.view.SoundEffectConstants;
+import android.widget.Button;
+import android.widget.Checkable;
+
+/** Image button that maintains a checked state. */
+public class RttCheckableButton extends Button implements Checkable {
+
+  private static final int[] CHECKED_STATE_SET = {android.R.attr.state_checked};
+
+  /** Callback interface to notify when the button's checked state has changed */
+  public interface OnCheckedChangeListener {
+
+    void onCheckedChanged(RttCheckableButton button, boolean isChecked);
+  }
+
+  private boolean broadcasting;
+  private boolean isChecked;
+  private OnCheckedChangeListener onCheckedChangeListener;
+  private CharSequence contentDescriptionChecked;
+  private CharSequence contentDescriptionUnchecked;
+
+  public RttCheckableButton(Context context) {
+    this(context, null);
+  }
+
+  public RttCheckableButton(Context context, AttributeSet attrs) {
+    this(context, attrs, android.R.attr.imageButtonStyle);
+  }
+
+  public RttCheckableButton(Context context, AttributeSet attrs, int defStyleAttr) {
+    this(context, attrs, defStyleAttr, 0);
+  }
+
+  public RttCheckableButton(
+      Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
+    super(context, attrs, defStyleAttr, defStyleRes);
+    init(context, attrs);
+  }
+
+  private void init(Context context, AttributeSet attrs) {
+    TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.RttCheckableButton);
+    setChecked(typedArray.getBoolean(R.styleable.RttCheckableButton_android_checked, false));
+    contentDescriptionChecked =
+        typedArray.getText(R.styleable.RttCheckableButton_contentDescriptionChecked);
+    contentDescriptionUnchecked =
+        typedArray.getText(R.styleable.RttCheckableButton_contentDescriptionUnchecked);
+    typedArray.recycle();
+
+    updateContentDescription();
+    setClickable(true);
+    setFocusable(true);
+  }
+
+  @Override
+  public void setChecked(boolean checked) {
+    performSetChecked(checked);
+  }
+
+  /**
+   * Called when the state of the button should be updated, this should not be the result of user
+   * interaction.
+   *
+   * @param checked {@code true} if the button should be in the checked state, {@code false}
+   *     otherwise.
+   */
+  private void performSetChecked(boolean checked) {
+    if (isChecked() == checked) {
+      return;
+    }
+    isChecked = checked;
+    CharSequence contentDescription = updateContentDescription();
+    announceForAccessibility(contentDescription);
+    refreshDrawableState();
+  }
+
+  private CharSequence updateContentDescription() {
+    CharSequence contentDescription =
+        isChecked ? contentDescriptionChecked : contentDescriptionUnchecked;
+    setContentDescription(contentDescription);
+    return contentDescription;
+  }
+
+  /**
+   * Called when the user interacts with a button. This should not result in the button updating
+   * state, rather the request should be propagated to the associated listener.
+   *
+   * @param checked {@code true} if the button should be in the checked state, {@code false}
+   *     otherwise.
+   */
+  private void userRequestedSetChecked(boolean checked) {
+    if (isChecked() == checked) {
+      return;
+    }
+    if (broadcasting) {
+      return;
+    }
+    broadcasting = true;
+    if (onCheckedChangeListener != null) {
+      onCheckedChangeListener.onCheckedChanged(this, checked);
+    }
+    broadcasting = false;
+  }
+
+  @Override
+  public boolean isChecked() {
+    return isChecked;
+  }
+
+  @Override
+  public void toggle() {
+    userRequestedSetChecked(!isChecked());
+  }
+
+  @Override
+  public int[] onCreateDrawableState(int extraSpace) {
+    final int[] drawableState = super.onCreateDrawableState(extraSpace + 1);
+    if (isChecked()) {
+      mergeDrawableStates(drawableState, CHECKED_STATE_SET);
+    }
+    return drawableState;
+  }
+
+  @Override
+  protected void drawableStateChanged() {
+    super.drawableStateChanged();
+    invalidate();
+  }
+
+  public void setOnCheckedChangeListener(OnCheckedChangeListener listener) {
+    this.onCheckedChangeListener = listener;
+  }
+
+  @Override
+  public boolean performClick() {
+    if (!isCheckable()) {
+      return super.performClick();
+    }
+
+    toggle();
+    final boolean handled = super.performClick();
+    if (!handled) {
+      // View only makes a sound effect if the onClickListener was
+      // called, so we'll need to make one here instead.
+      playSoundEffect(SoundEffectConstants.CLICK);
+    }
+    return handled;
+  }
+
+  private boolean isCheckable() {
+    return onCheckedChangeListener != null;
+  }
+
+  @Override
+  public void onRestoreInstanceState(Parcelable state) {
+    SavedState savedState = (SavedState) state;
+    super.onRestoreInstanceState(savedState.getSuperState());
+    performSetChecked(savedState.isChecked);
+    requestLayout();
+  }
+
+  @Override
+  public Parcelable onSaveInstanceState() {
+    return new SavedState(isChecked(), super.onSaveInstanceState());
+  }
+
+  private static class SavedState extends BaseSavedState {
+
+    public final boolean isChecked;
+
+    private SavedState(boolean isChecked, Parcelable superState) {
+      super(superState);
+      this.isChecked = isChecked;
+    }
+
+    protected SavedState(Parcel in) {
+      super(in);
+      isChecked = in.readByte() != 0;
+    }
+
+    public static final Creator<SavedState> CREATOR =
+        new Creator<SavedState>() {
+          @Override
+          public SavedState createFromParcel(Parcel in) {
+            return new SavedState(in);
+          }
+
+          @Override
+          public SavedState[] newArray(int size) {
+            return new SavedState[size];
+          }
+        };
+
+    @Override
+    public int describeContents() {
+      return 0;
+    }
+
+    @Override
+    public void writeToParcel(Parcel dest, int flags) {
+      super.writeToParcel(dest, flags);
+      dest.writeByte((byte) (isChecked ? 1 : 0));
+    }
+  }
+}
diff --git a/java/com/android/incallui/rtt/impl/RttOverflowMenu.java b/java/com/android/incallui/rtt/impl/RttOverflowMenu.java
new file mode 100644
index 0000000..e0916be
--- /dev/null
+++ b/java/com/android/incallui/rtt/impl/RttOverflowMenu.java
@@ -0,0 +1,78 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.incallui.rtt.impl;
+
+import android.content.Context;
+import android.telecom.CallAudioState;
+import android.view.View;
+import android.widget.PopupWindow;
+import com.android.incallui.incall.protocol.InCallButtonUiDelegate;
+import com.android.incallui.rtt.impl.RttCheckableButton.OnCheckedChangeListener;
+import com.android.incallui.speakerbuttonlogic.SpeakerButtonInfo;
+import com.android.incallui.speakerbuttonlogic.SpeakerButtonInfo.IconSize;
+
+/** Overflow menu for RTT call. */
+public class RttOverflowMenu extends PopupWindow implements OnCheckedChangeListener {
+
+  private final RttCheckableButton muteButton;
+  private final RttCheckableButton speakerButton;
+  private final RttCheckableButton dialpadButton;
+  private final RttCheckableButton addCallButton;
+  private final InCallButtonUiDelegate inCallButtonUiDelegate;
+
+  RttOverflowMenu(Context context, InCallButtonUiDelegate inCallButtonUiDelegate) {
+    super(context);
+    this.inCallButtonUiDelegate = inCallButtonUiDelegate;
+    View view = View.inflate(context, R.layout.overflow_menu, null);
+    setContentView(view);
+    setOnDismissListener(this::dismiss);
+    setFocusable(true);
+    setWidth(context.getResources().getDimensionPixelSize(R.dimen.rtt_overflow_menu_width));
+    muteButton = view.findViewById(R.id.menu_mute);
+    muteButton.setOnCheckedChangeListener(this);
+    speakerButton = view.findViewById(R.id.menu_speaker);
+    speakerButton.setOnCheckedChangeListener(this);
+    dialpadButton = view.findViewById(R.id.menu_keypad);
+    dialpadButton.setOnCheckedChangeListener(this);
+    addCallButton = view.findViewById(R.id.menu_add_call);
+    addCallButton.setOnCheckedChangeListener(this);
+  }
+
+  @Override
+  public void onCheckedChanged(RttCheckableButton button, boolean isChecked) {
+    if (button == muteButton) {
+      inCallButtonUiDelegate.muteClicked(isChecked, true);
+    } else if (button == speakerButton) {
+      inCallButtonUiDelegate.toggleSpeakerphone();
+    } else if (button == dialpadButton) {
+      inCallButtonUiDelegate.showDialpadClicked(isChecked);
+    } else if (button == addCallButton) {
+      inCallButtonUiDelegate.addCallClicked();
+    }
+  }
+
+  void setMuteButtonChecked(boolean isChecked) {
+    muteButton.setChecked(isChecked);
+  }
+
+  void setAudioState(CallAudioState audioState) {
+    SpeakerButtonInfo info = new SpeakerButtonInfo(audioState, IconSize.SIZE_24_DP);
+    if (info.checkable) {
+      speakerButton.setChecked(info.isChecked);
+    }
+  }
+}
diff --git a/java/com/android/incallui/rtt/impl/res/color/rtt_checkable_button_color.xml b/java/com/android/incallui/rtt/impl/res/color/rtt_checkable_button_color.xml
new file mode 100644
index 0000000..cb3a452
--- /dev/null
+++ b/java/com/android/incallui/rtt/impl/res/color/rtt_checkable_button_color.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_checked="true"
+      android:color="@color/rtt_button_selected_color" />
+  <item android:color="@color/rtt_button_unselected_color" />
+</selector>
\ No newline at end of file
diff --git a/java/com/android/incallui/rtt/impl/res/drawable/overflow_menu_background.xml b/java/com/android/incallui/rtt/impl/res/drawable/overflow_menu_background.xml
new file mode 100644
index 0000000..6142986
--- /dev/null
+++ b/java/com/android/incallui/rtt/impl/res/drawable/overflow_menu_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
+  -->
+<shape xmlns:android="http://schemas.android.com/apk/res/android"
+    android:shape="rectangle">
+  <solid android:color="@android:color/white"/>
+  <corners android:radius="2dp"/>
+</shape>
\ No newline at end of file
diff --git a/java/com/android/incallui/rtt/impl/res/layout/overflow_menu.xml b/java/com/android/incallui/rtt/impl/res/layout/overflow_menu.xml
new file mode 100644
index 0000000..a29fad5
--- /dev/null
+++ b/java/com/android/incallui/rtt/impl/res/layout/overflow_menu.xml
@@ -0,0 +1,49 @@
+<?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"
+    xmlns:app="http://schemas.android.com/apk/res-auto"
+    android:layout_width="180dp"
+    android:layout_height="wrap_content"
+    android:paddingTop="8dp"
+    android:paddingBottom="8dp"
+    android:background="@drawable/overflow_menu_background"
+    android:orientation="vertical">
+  <com.android.incallui.rtt.impl.RttCheckableButton
+      android:id="@+id/menu_mute"
+      style="@style/RttButton"
+      android:drawableStart="@drawable/quantum_ic_mic_off_vd_theme_24"
+      android:text="@string/incall_label_mute"
+      app:contentDescriptionChecked="@string/incall_content_description_muted"
+      app:contentDescriptionUnchecked="@string/incall_content_description_unmuted"/>
+  <com.android.incallui.rtt.impl.RttCheckableButton
+      android:id="@+id/menu_speaker"
+      style="@style/RttButton"
+      android:drawableStart="@drawable/quantum_ic_volume_up_vd_theme_24"
+      android:text="@string/incall_label_speaker"
+      app:contentDescriptionChecked="@string/incall_content_description_speaker"
+      app:contentDescriptionUnchecked="@string/incall_content_description_earpiece"/>
+  <com.android.incallui.rtt.impl.RttCheckableButton
+      android:id="@+id/menu_keypad"
+      style="@style/RttButton"
+      android:drawableStart="@drawable/quantum_ic_dialpad_vd_theme_24"
+      android:text="@string/incall_label_dialpad"/>
+  <com.android.incallui.rtt.impl.RttCheckableButton
+      android:id="@+id/menu_add_call"
+      style="@style/RttButton"
+      android:drawableStart="@drawable/quantum_ic_add_call_vd_theme_24"
+      android:text="@string/incall_label_add_call"/>
+</LinearLayout>
\ No newline at end of file
diff --git a/java/com/android/incallui/rtt/impl/res/values/attrs.xml b/java/com/android/incallui/rtt/impl/res/values/attrs.xml
new file mode 100644
index 0000000..2e7d899
--- /dev/null
+++ b/java/com/android/incallui/rtt/impl/res/values/attrs.xml
@@ -0,0 +1,23 @@
+<?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>
+  <declare-styleable name="RttCheckableButton">
+    <attr name="android:checked"/>
+    <attr name="contentDescriptionChecked" format="reference|string"/>
+    <attr name="contentDescriptionUnchecked" format="reference|string"/>
+  </declare-styleable>
+</resources>
diff --git a/java/com/android/incallui/rtt/impl/res/values/colors.xml b/java/com/android/incallui/rtt/impl/res/values/colors.xml
index c25ad21..e1702cc 100644
--- a/java/com/android/incallui/rtt/impl/res/values/colors.xml
+++ b/java/com/android/incallui/rtt/impl/res/values/colors.xml
@@ -17,4 +17,6 @@
 <resources>
   <color name="rtt_status_bar_color">#03165C</color>
   <color name="rtt_navigation_bar_color">#FAFAFA</color>
+  <color name="rtt_button_unselected_color">#757575</color>
+  <color name="rtt_button_selected_color">#2A56C6</color>
 </resources>
\ No newline at end of file
diff --git a/java/com/android/incallui/rtt/impl/res/values/dimens.xml b/java/com/android/incallui/rtt/impl/res/values/dimens.xml
index a3f230c..4c3fe02 100644
--- a/java/com/android/incallui/rtt/impl/res/values/dimens.xml
+++ b/java/com/android/incallui/rtt/impl/res/values/dimens.xml
@@ -17,4 +17,5 @@
 <resources>
   <dimen name="rtt_message_margin_top">16dp</dimen>
   <dimen name="rtt_same_group_message_margin_top">2dp</dimen>
+  <dimen name="rtt_overflow_menu_width">180dp</dimen>
 </resources>
\ No newline at end of file
diff --git a/java/com/android/incallui/rtt/impl/res/values/styles.xml b/java/com/android/incallui/rtt/impl/res/values/styles.xml
index 55207a3..bbacde8 100644
--- a/java/com/android/incallui/rtt/impl/res/values/styles.xml
+++ b/java/com/android/incallui/rtt/impl/res/values/styles.xml
@@ -15,9 +15,29 @@
   ~ limitations under the License
   -->
 <resources>
+
   <style name="Dialer.Incall.TextAppearance.RttMessage" parent="Dialer.Incall.TextAppearance">
     <item name="android:fontFamily">sans-serif</item>
     <item name="android:textColor">#DD000000</item>
     <item name="android:textSize">16sp</item>
   </style>
+
+  <style name="ButtonTheme">
+    <item name="android:colorControlHighlight">#33000000</item>
+  </style>
+
+  <style name="RttButton">
+    <item name="android:layout_width">match_parent</item>
+    <item name="android:layout_height">wrap_content</item>
+    <item name="android:drawablePadding">16dp</item>
+    <item name="android:paddingLeft">16dp</item>
+    <item name="android:paddingRight">16dp</item>
+    <item name="android:paddingTop">8dp</item>
+    <item name="android:paddingBottom">8dp</item>
+    <item name="android:drawableTint">@color/rtt_checkable_button_color</item>
+    <item name="android:textSize">16sp</item>
+    <item name="android:textColor">@color/rtt_checkable_button_color</item>
+    <item name="android:theme">@style/ButtonTheme</item>
+    <item name="android:background">?attr/selectableItemBackground</item>
+  </style>
 </resources>
\ No newline at end of file
diff --git a/java/com/android/incallui/spam/SpamCallListListener.java b/java/com/android/incallui/spam/SpamCallListListener.java
index c7fa498..22b3833 100644
--- a/java/com/android/incallui/spam/SpamCallListListener.java
+++ b/java/com/android/incallui/spam/SpamCallListListener.java
@@ -34,7 +34,6 @@
 import android.telecom.DisconnectCause;
 import android.telephony.PhoneNumberUtils;
 import android.text.TextUtils;
-import com.android.contacts.common.compat.PhoneNumberUtilsCompat;
 import com.android.dialer.blocking.FilteredNumberCompat;
 import com.android.dialer.blocking.FilteredNumbersUtil;
 import com.android.dialer.common.Assert;
@@ -47,6 +46,7 @@
 import com.android.dialer.logging.Logger;
 import com.android.dialer.notification.DialerNotificationManager;
 import com.android.dialer.notification.NotificationChannelId;
+import com.android.dialer.phonenumberutil.PhoneNumberHelper;
 import com.android.dialer.spam.SpamComponent;
 import com.android.dialer.telecom.TelecomUtil;
 import com.android.dialer.util.PermissionsUtil;
@@ -267,8 +267,9 @@
 
   private CharSequence getDisplayNumber(DialerCall call) {
     String formattedNumber =
-        PhoneNumberUtils.formatNumber(call.getNumber(), GeoUtil.getCurrentCountryIso(context));
-    return PhoneNumberUtilsCompat.createTtsSpannable(formattedNumber);
+        PhoneNumberHelper.formatNumber(
+            context, call.getNumber(), GeoUtil.getCurrentCountryIso(context));
+    return PhoneNumberUtils.createTtsSpannable(formattedNumber);
   }
 
   /** Display a notification with two actions: "add contact" and "report spam". */
diff --git a/java/com/android/incallui/spam/SpamNotificationActivity.java b/java/com/android/incallui/spam/SpamNotificationActivity.java
index 6ba7c30..8919dc7 100644
--- a/java/com/android/incallui/spam/SpamNotificationActivity.java
+++ b/java/com/android/incallui/spam/SpamNotificationActivity.java
@@ -27,7 +27,6 @@
 import android.provider.ContactsContract;
 import android.support.v4.app.FragmentActivity;
 import android.telephony.PhoneNumberUtils;
-import com.android.contacts.common.compat.PhoneNumberUtilsCompat;
 import com.android.dialer.blocking.BlockedNumbersMigrator;
 import com.android.dialer.blocking.FilteredNumberAsyncQueryHandler;
 import com.android.dialer.blocking.FilteredNumberCompat;
@@ -39,6 +38,7 @@
 import com.android.dialer.logging.Logger;
 import com.android.dialer.logging.ReportingLocation;
 import com.android.dialer.notification.DialerNotificationManager;
+import com.android.dialer.phonenumberutil.PhoneNumberHelper;
 import com.android.dialer.spam.SpamComponent;
 import com.android.incallui.call.DialerCall;
 
@@ -109,8 +109,8 @@
   /** Returns the formatted version of the given number. */
   private static String getFormattedNumber(String number, Context context) {
     String formattedNumber =
-        PhoneNumberUtils.formatNumber(number, GeoUtil.getCurrentCountryIso(context));
-    return PhoneNumberUtilsCompat.createTtsSpannable(formattedNumber).toString();
+        PhoneNumberHelper.formatNumber(context, number, GeoUtil.getCurrentCountryIso(context));
+    return PhoneNumberUtils.createTtsSpannable(formattedNumber).toString();
   }
 
   private void logCallImpression(DialerImpression.Type impression) {
diff --git a/java/com/android/incallui/speakeasy/SpeakEasyCallManager.java b/java/com/android/incallui/speakeasy/SpeakEasyCallManager.java
index 4fe894a..f2721da 100644
--- a/java/com/android/incallui/speakeasy/SpeakEasyCallManager.java
+++ b/java/com/android/incallui/speakeasy/SpeakEasyCallManager.java
@@ -16,8 +16,8 @@
 
 package com.android.incallui.speakeasy;
 
-import android.app.Fragment;
 import android.support.annotation.NonNull;
+import android.support.v4.app.Fragment;
 import com.android.incallui.call.DialerCall;
 import com.google.common.base.Optional;
 
diff --git a/java/com/android/incallui/speakeasy/SpeakEasyCallManagerStub.java b/java/com/android/incallui/speakeasy/SpeakEasyCallManagerStub.java
index e84766c..9e58ce1 100644
--- a/java/com/android/incallui/speakeasy/SpeakEasyCallManagerStub.java
+++ b/java/com/android/incallui/speakeasy/SpeakEasyCallManagerStub.java
@@ -16,8 +16,8 @@
 
 package com.android.incallui.speakeasy;
 
-import android.app.Fragment;
 import android.support.annotation.Nullable;
+import android.support.v4.app.Fragment;
 import com.android.incallui.call.DialerCall;
 import com.google.common.base.Optional;
 import javax.inject.Inject;
diff --git a/java/com/android/incallui/video/impl/SurfaceViewVideoCallFragment.java b/java/com/android/incallui/video/impl/SurfaceViewVideoCallFragment.java
index 631cc1d..28ee774 100644
--- a/java/com/android/incallui/video/impl/SurfaceViewVideoCallFragment.java
+++ b/java/com/android/incallui/video/impl/SurfaceViewVideoCallFragment.java
@@ -846,7 +846,7 @@
     updateButtonStates();
     FragmentTransaction transaction = getChildFragmentManager().beginTransaction();
     Fragment oldBanner = getChildFragmentManager().findFragmentById(R.id.videocall_on_hold_banner);
-    if (secondaryInfo.shouldShow) {
+    if (secondaryInfo.shouldShow()) {
       OnHoldFragment onHoldFragment = OnHoldFragment.newInstance(secondaryInfo);
       onHoldFragment.setPadTopInset(!isInFullscreenMode);
       transaction.replace(R.id.videocall_on_hold_banner, onHoldFragment);
diff --git a/java/com/android/incallui/video/impl/SwitchOnHoldCallController.java b/java/com/android/incallui/video/impl/SwitchOnHoldCallController.java
index 372b56b..3efdfd7 100644
--- a/java/com/android/incallui/video/impl/SwitchOnHoldCallController.java
+++ b/java/com/android/incallui/video/impl/SwitchOnHoldCallController.java
@@ -74,7 +74,7 @@
   }
 
   private boolean hasSecondaryInfo() {
-    return secondaryInfo != null && secondaryInfo.shouldShow;
+    return secondaryInfo != null && secondaryInfo.shouldShow();
   }
 
   public void updateButtonState() {
diff --git a/java/com/android/incallui/video/impl/VideoCallFragment.java b/java/com/android/incallui/video/impl/VideoCallFragment.java
index 0793d18..6b5a979 100644
--- a/java/com/android/incallui/video/impl/VideoCallFragment.java
+++ b/java/com/android/incallui/video/impl/VideoCallFragment.java
@@ -887,7 +887,7 @@
     updateButtonStates();
     FragmentTransaction transaction = getChildFragmentManager().beginTransaction();
     Fragment oldBanner = getChildFragmentManager().findFragmentById(R.id.videocall_on_hold_banner);
-    if (secondaryInfo.shouldShow) {
+    if (secondaryInfo.shouldShow()) {
       OnHoldFragment onHoldFragment = OnHoldFragment.newInstance(secondaryInfo);
       onHoldFragment.setPadTopInset(!isInFullscreenMode);
       transaction.replace(R.id.videocall_on_hold_banner, onHoldFragment);