Merge pi-dev-plus-aosp-without-vendor into stage-aosp-master

Bug: 79597307
Change-Id: I032654174f91c057b36f9b9a71071bdbd2383a2a
diff --git a/Android.mk b/Android.mk
index 228e9ff..c727011 100644
--- a/Android.mk
+++ b/Android.mk
@@ -32,7 +32,16 @@
 LOCAL_USE_AAPT2 := true
 
 LOCAL_STATIC_ANDROID_LIBRARIES += \
-    android-support-v4
+    android-support-car \
+    android-arch-lifecycle-extensions \
+    android-support-constraint-layout \
+    android-support-v4 \
+    android-support-v7-cardview \
+    car-apps-common \
+
+LOCAL_STATIC_JAVA_LIBRARIES := \
+    android-support-constraint-layout-solver \
+    guava \
 
 LOCAL_PROGUARD_ENABLED := disabled
 
@@ -40,9 +49,6 @@
 
 LOCAL_DEX_PREOPT := false
 
-include packages/apps/Car/libs/car-stream-ui-lib/car-stream-ui-lib.mk
-include packages/apps/Car/libs/car-apps-common/car-apps-common.mk
-
 include $(BUILD_PACKAGE)
 
 endif
diff --git a/AndroidManifest.xml b/AndroidManifest.xml
index d420c7e..f5beec7 100644
--- a/AndroidManifest.xml
+++ b/AndroidManifest.xml
@@ -20,6 +20,7 @@
     <uses-sdk android:minSdkVersion="24" android:targetSdkVersion='24'/>
 
     <uses-permission android:name="android.permission.BLUETOOTH"/>
+    <uses-permission android:name="android.permission.BLUETOOTH_ADMIN"/>
     <uses-permission android:name="android.permission.READ_CALL_LOG"/>
     <uses-permission android:name="android.permission.READ_CONTACTS"/>
     <uses-permission android:name="android.permission.READ_PHONE_STATE"/>
diff --git a/res/drawable/button_active_state_ring.xml b/res/drawable/button_active_state_ring.xml
new file mode 100644
index 0000000..8f71717
--- /dev/null
+++ b/res/drawable/button_active_state_ring.xml
@@ -0,0 +1,22 @@
+<?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="ring"
+    android:thickness="4dp"
+    android:innerRadius="34dp"
+    android:useLevel="false">
+</shape>
\ No newline at end of file
diff --git a/res/drawable/car_card_rounded_bottom_background.xml b/res/drawable/car_card_rounded_bottom_background.xml
deleted file mode 100644
index 011f030..0000000
--- a/res/drawable/car_card_rounded_bottom_background.xml
+++ /dev/null
@@ -1,6 +0,0 @@
-<shape xmlns:android="http://schemas.android.com/apk/res/android">
-    <solid android:color="@color/car_card" />
-    <corners
-            android:bottomRightRadius="@dimen/call_log_last_card_corner_radius"
-            android:bottomLeftRadius="@dimen/call_log_last_card_corner_radius"/>
-</shape>
diff --git a/res/drawable/car_card_rounded_top_background.xml b/res/drawable/car_card_rounded_top_background.xml
deleted file mode 100644
index 9a136e0..0000000
--- a/res/drawable/car_card_rounded_top_background.xml
+++ /dev/null
@@ -1,6 +0,0 @@
-<shape xmlns:android="http://schemas.android.com/apk/res/android">
-    <solid android:color="@color/car_card" />
-    <corners
-            android:topRightRadius="@dimen/call_log_last_card_corner_radius"
-            android:topLeftRadius="@dimen/call_log_last_card_corner_radius"/>
-</shape>
diff --git a/res/drawable/car_card_rounded_top_bottom_background.xml b/res/drawable/car_card_rounded_top_bottom_background.xml
deleted file mode 100644
index cc84056..0000000
--- a/res/drawable/car_card_rounded_top_bottom_background.xml
+++ /dev/null
@@ -1,5 +0,0 @@
-<shape xmlns:android="http://schemas.android.com/apk/res/android">
-    <solid android:color="@color/car_card" />
-    <corners
-            android:radius="@dimen/call_log_last_card_corner_radius"/>
-</shape>
diff --git a/res/drawable/car_list_item_background.xml b/res/drawable/car_list_item_background.xml
new file mode 100644
index 0000000..cbc97c7
--- /dev/null
+++ b/res/drawable/car_list_item_background.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  Copyright 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.
+-->
+<ripple xmlns:android="http://schemas.android.com/apk/res/android"
+        android:color="@color/car_card_ripple_background">
+    <item android:id="@android:id/mask">
+        <color android:color="#ffffffff" />
+    </item>
+</ripple>
diff --git a/res/drawable/dialer_ripple_background.xml b/res/drawable/dialer_ripple_background.xml
index b7eff0f..c4ee229 100644
--- a/res/drawable/dialer_ripple_background.xml
+++ b/res/drawable/dialer_ripple_background.xml
@@ -14,5 +14,5 @@
 limitations under the License.
 -->
 <ripple xmlns:android="http://schemas.android.com/apk/res/android"
-        android:color="@color/car_card_ripple_light_color_background_dark">
+        android:color="@color/car_card_ripple_background_dark">
 </ripple>
diff --git a/res/drawable/ic_arrow_back.xml b/res/drawable/ic_arrow_back.xml
index fe02ea5..2c1655f 100644
--- a/res/drawable/ic_arrow_back.xml
+++ b/res/drawable/ic_arrow_back.xml
@@ -14,8 +14,8 @@
 limitations under the License.
 -->
 <vector xmlns:android="http://schemas.android.com/apk/res/android"
-        android:width="@dimen/stream_button_icon_size"
-        android:height="@dimen/stream_button_icon_size"
+        android:width="@dimen/car_primary_icon_size"
+        android:height="@dimen/car_primary_icon_size"
         android:viewportWidth="48.0"
         android:viewportHeight="48.0">
     <path
diff --git a/res/drawable/ic_arrow_down.xml b/res/drawable/ic_arrow_down.xml
new file mode 100644
index 0000000..60f49aa
--- /dev/null
+++ b/res/drawable/ic_arrow_down.xml
@@ -0,0 +1,24 @@
+<?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.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+        android:viewportWidth="24"
+        android:viewportHeight="24"
+        android:width="24dp"
+        android:height="24dp">
+    <path
+        android:pathData="M7 10l5 5 5 -5z"
+        android:fillColor="#000000" />
+</vector>
\ No newline at end of file
diff --git a/res/drawable/ic_bluetooth.xml b/res/drawable/ic_bluetooth.xml
new file mode 100644
index 0000000..01fc115
--- /dev/null
+++ b/res/drawable/ic_bluetooth.xml
@@ -0,0 +1,24 @@
+<?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.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+        android:width="44dp"
+        android:height="44dp"
+        android:viewportWidth="24.0"
+        android:viewportHeight="24.0">
+    <path
+        android:fillColor="#FF000000"
+        android:pathData="M14.24,12.01l2.32,2.32c0.28,-0.72 0.44,-1.51 0.44,-2.33 0,-0.82 -0.16,-1.59 -0.43,-2.31l-2.33,2.32zM19.53,6.71l-1.26,1.26c0.63,1.21 0.98,2.57 0.98,4.02s-0.36,2.82 -0.98,4.02l1.2,1.2c0.97,-1.54 1.54,-3.36 1.54,-5.31 -0.01,-1.89 -0.55,-3.67 -1.48,-5.19zM15.71,7.71L10,2L9,2v7.59L4.41,5 3,6.41 8.59,12 3,17.59 4.41,19 9,14.41L9,22h1l5.71,-5.71 -4.3,-4.29 4.3,-4.29zM11,5.83l1.88,1.88L11,9.59L11,5.83zM12.88,16.29L11,18.17v-3.76l1.88,1.88z"/>
+</vector>
diff --git a/res/drawable/ic_call_end.xml b/res/drawable/ic_call_end.xml
index 140482a..2b008b9 100644
--- a/res/drawable/ic_call_end.xml
+++ b/res/drawable/ic_call_end.xml
@@ -1,7 +1,7 @@
 <?xml version="1.0" encoding="utf-8"?>
 <vector xmlns:android="http://schemas.android.com/apk/res/android"
-    android:width="56dp"
-    android:height="56dp"
+    android:width="44dp"
+    android:height="44dp"
     android:viewportWidth="24"
     android:viewportHeight="24">
 
@@ -16,4 +16,4 @@
 .18 -.43 .29 -.71 .29 -.27
 0-.52-.11-.7-.28-.79-.74-1.69-1.36-2.67-1.85-.33-.16-.56-.5-.56-.9v-3.1C15.15
 9.25 13.6 9 12 9z" />
-</vector>
\ No newline at end of file
+</vector>
diff --git a/res/drawable/ic_call_state_switch.xml b/res/drawable/ic_call_state_switch.xml
new file mode 100644
index 0000000..b7142dd
--- /dev/null
+++ b/res/drawable/ic_call_state_switch.xml
@@ -0,0 +1,24 @@
+<?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_activated="true"
+        android:drawable="@drawable/ic_play" />
+    <item
+        android:state_activated="false"
+        android:drawable="@drawable/ic_pause" />
+</selector>
diff --git a/res/drawable/ic_cancel.xml b/res/drawable/ic_cancel.xml
index 2ade2e6..3574989 100644
--- a/res/drawable/ic_cancel.xml
+++ b/res/drawable/ic_cancel.xml
@@ -14,8 +14,8 @@
 limitations under the License.
 -->
 <vector xmlns:android="http://schemas.android.com/apk/res/android"
-        android:width="@dimen/stream_button_icon_size"
-        android:height="@dimen/stream_button_icon_size"
+        android:width="@dimen/car_primary_icon_size"
+        android:height="@dimen/car_primary_icon_size"
         android:viewportWidth="48.0"
         android:viewportHeight="48.0">
     <path
diff --git a/res/drawable/ic_contact.xml b/res/drawable/ic_contact.xml
new file mode 100644
index 0000000..7b54775
--- /dev/null
+++ b/res/drawable/ic_contact.xml
@@ -0,0 +1,24 @@
+<?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.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+        android:viewportWidth="48"
+        android:viewportHeight="48"
+        android:width="48dp"
+        android:height="48dp">
+    <path
+        android:pathData="M6 10l0 28c0 2.21 1.79 4 4 4l28 0c2.21 0 4 -1.79 4 -4L42 10C42 7.79 40.21 6 38 6L10 6C7.79 6 6 7.79 6 10Zm24 8c0 3.32 -2.69 6 -6 6 -3.31 0 -6 -2.68 -6 -6 0 -3.31 2.69 -6 6 -6 3.31 0 6 2.69 6 6zM12 34c0 -4 8 -6.2 12 -6.2 4 0 12 2.2 12 6.2l0 2 -24 0 0 -2z"
+        android:fillColor="#000000" />
+</vector>
\ No newline at end of file
diff --git a/res/drawable/ic_dialpad_activated.xml b/res/drawable/ic_dialpad_activated.xml
index 364ece7..42f5d8c 100644
--- a/res/drawable/ic_dialpad_activated.xml
+++ b/res/drawable/ic_dialpad_activated.xml
@@ -1,62 +1,22 @@
 <?xml version="1.0" encoding="utf-8"?>
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
-    android:width="72dp"
-    android:height="72dp"
-    android:viewportWidth="24"
-    android:viewportHeight="24">
+<!-- Copyright (C) 2018 The Android Open Source Project
 
-    <path
-        android:strokeWidth="1"
-        android:pathData="M 0 24 L 24 24 L 24 0 L 0 0 Z" />
-    <path
-        android:fillColor="#212121"
-        android:strokeWidth="1"
-        android:pathData="M12,0 C5.37257143,0 0,5.37257143 0,12 C0,18.6274286 5.37257143,24 12,24
-C18.6274286,24 24,18.6274286 24,12 C24,5.37257143 18.6274286,0 12,0
-M12,1.28571429 C17.9078571,1.28571429 22.7142857,6.09214286 22.7142857,12
-C22.7142857,17.9078571 17.9078571,22.7142857 12,22.7142857
-C6.09214286,22.7142857 1.28571429,17.9078571 1.28571429,12
-C1.28571429,6.09214286 6.09214286,1.28571429 12,1.28571429" />
-    <path
-        android:fillColor="#212121"
-        android:strokeWidth="1"
-        android:pathData="M12,16 C11.3688571,16 10.8571429,16.5117143 10.8571429,17.1428571
-C10.8571429,17.774 11.3688571,18.2857143 12,18.2857143 C12.6311429,18.2857143
-13.1428571,17.774 13.1428571,17.1428571 C13.1428571,16.5117143 12.6311429,16
-12,16 M15.4285714,12.5714286 C14.7974286,12.5714286 14.2857143,13.0831429
-14.2857143,13.7142857 C14.2857143,14.3454286 14.7974286,14.8571429
-15.4285714,14.8571429 C16.0597143,14.8571429 16.5714286,14.3454286
-16.5714286,13.7142857 C16.5714286,13.0831429 16.0597143,12.5714286
-15.4285714,12.5714286 M12,12.5714286 C11.3688571,12.5714286
-10.8571429,13.0831429 10.8571429,13.7142857 C10.8571429,14.3454286
-11.3688571,14.8571429 12,14.8571429 C12.6311429,14.8571429 13.1428571,14.3454286
-13.1428571,13.7142857 C13.1428571,13.0831429 12.6311429,12.5714286 12,12.5714286
-M8.57142857,12.5714286 C7.94028571,12.5714286 7.42857143,13.0831429
-7.42857143,13.7142857 C7.42857143,14.3454286 7.94028571,14.8571429
-8.57142857,14.8571429 C9.20257143,14.8571429 9.71428571,14.3454286
-9.71428571,13.7142857 C9.71428571,13.0831429 9.20257143,12.5714286
-8.57142857,12.5714286 M15.4285714,9.14285714 C14.7974286,9.14285714
-14.2857143,9.65457143 14.2857143,10.2857143 C14.2857143,10.9168571
-14.7974286,11.4285714 15.4285714,11.4285714 C16.0597143,11.4285714
-16.5714286,10.9168571 16.5714286,10.2857143 C16.5714286,9.65457143
-16.0597143,9.14285714 15.4285714,9.14285714 M12,9.14285714
-C11.3688571,9.14285714 10.8571429,9.65457143 10.8571429,10.2857143
-C10.8571429,10.9168571 11.3688571,11.4285714 12,11.4285714
-C12.6311429,11.4285714 13.1428571,10.9168571 13.1428571,10.2857143
-C13.1428571,9.65457143 12.6311429,9.14285714 12,9.14285714
-M8.57142857,9.14285714 C7.94028571,9.14285714 7.42857143,9.65457143
-7.42857143,10.2857143 C7.42857143,10.9168571 7.94028571,11.4285714
-8.57142857,11.4285714 C9.20257143,11.4285714 9.71428571,10.9168571
-9.71428571,10.2857143 C9.71428571,9.65457143 9.20257143,9.14285714
-8.57142857,9.14285714 M15.4285714,5.71428571 C14.7974286,5.71428571
-14.2857143,6.226 14.2857143,6.85714286 C14.2857143,7.48828571 14.7974286,8
-15.4285714,8 C16.0597143,8 16.5714286,7.48828571 16.5714286,6.85714286
-C16.5714286,6.226 16.0597143,5.71428571 15.4285714,5.71428571 M12,5.71428571
-C11.3688571,5.71428571 10.8571429,6.226 10.8571429,6.85714286
-C10.8571429,7.48828571 11.3688571,8 12,8 C12.6311429,8 13.1428571,7.48828571
-13.1428571,6.85714286 C13.1428571,6.226 12.6311429,5.71428571 12,5.71428571
-M8.57142857,5.71428571 C7.94028571,5.71428571 7.42857143,6.226
-7.42857143,6.85714286 C7.42857143,7.48828571 7.94028571,8 8.57142857,8
-C9.20257143,8 9.71428571,7.48828571 9.71428571,6.85714286 C9.71428571,6.226
-9.20257143,5.71428571 8.57142857,5.71428571" />
-</vector>
\ No newline at end of file
+     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.
+-->
+<layer-list
+    xmlns:android="http://schemas.android.com/apk/res/android" >
+    <item
+        android:drawable="@drawable/button_active_state_ring"/>
+    <item
+        android:drawable="@drawable/ic_dialpad_normal"/>
+</layer-list>
diff --git a/res/drawable/ic_dialpad_normal.xml b/res/drawable/ic_dialpad_normal.xml
index 8e628ce..be92de7 100644
--- a/res/drawable/ic_dialpad_normal.xml
+++ b/res/drawable/ic_dialpad_normal.xml
@@ -1,53 +1,21 @@
 <?xml version="1.0" encoding="utf-8"?>
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
-    android:width="72dp"
-    android:height="72dp"
-    android:viewportWidth="24"
-    android:viewportHeight="24">
+<!-- Copyright (C) 2018 The Android Open Source Project
 
-    <path
-        android:strokeWidth="1"
-        android:pathData="M 0 0 L 24 0 L 24 24 L 0 24 Z" />
-    <path
-        android:fillColor="#212121"
-        android:strokeWidth="1"
-        android:pathData="M12,16 C11.3688571,16 10.8571429,16.5117143 10.8571429,17.1428571
-C10.8571429,17.774 11.3688571,18.2857143 12,18.2857143 C12.6311429,18.2857143
-13.1428571,17.774 13.1428571,17.1428571 C13.1428571,16.5117143 12.6311429,16
-12,16 M15.4285714,12.5714286 C14.7974286,12.5714286 14.2857143,13.0831429
-14.2857143,13.7142857 C14.2857143,14.3454286 14.7974286,14.8571429
-15.4285714,14.8571429 C16.0597143,14.8571429 16.5714286,14.3454286
-16.5714286,13.7142857 C16.5714286,13.0831429 16.0597143,12.5714286
-15.4285714,12.5714286 M12,12.5714286 C11.3688571,12.5714286
-10.8571429,13.0831429 10.8571429,13.7142857 C10.8571429,14.3454286
-11.3688571,14.8571429 12,14.8571429 C12.6311429,14.8571429 13.1428571,14.3454286
-13.1428571,13.7142857 C13.1428571,13.0831429 12.6311429,12.5714286 12,12.5714286
-M8.57142857,12.5714286 C7.94028571,12.5714286 7.42857143,13.0831429
-7.42857143,13.7142857 C7.42857143,14.3454286 7.94028571,14.8571429
-8.57142857,14.8571429 C9.20257143,14.8571429 9.71428571,14.3454286
-9.71428571,13.7142857 C9.71428571,13.0831429 9.20257143,12.5714286
-8.57142857,12.5714286 M15.4285714,9.14285714 C14.7974286,9.14285714
-14.2857143,9.65457143 14.2857143,10.2857143 C14.2857143,10.9168571
-14.7974286,11.4285714 15.4285714,11.4285714 C16.0597143,11.4285714
-16.5714286,10.9168571 16.5714286,10.2857143 C16.5714286,9.65457143
-16.0597143,9.14285714 15.4285714,9.14285714 M12,9.14285714
-C11.3688571,9.14285714 10.8571429,9.65457143 10.8571429,10.2857143
-C10.8571429,10.9168571 11.3688571,11.4285714 12,11.4285714
-C12.6311429,11.4285714 13.1428571,10.9168571 13.1428571,10.2857143
-C13.1428571,9.65457143 12.6311429,9.14285714 12,9.14285714
-M8.57142857,9.14285714 C7.94028571,9.14285714 7.42857143,9.65457143
-7.42857143,10.2857143 C7.42857143,10.9168571 7.94028571,11.4285714
-8.57142857,11.4285714 C9.20257143,11.4285714 9.71428571,10.9168571
-9.71428571,10.2857143 C9.71428571,9.65457143 9.20257143,9.14285714
-8.57142857,9.14285714 M15.4285714,5.71428571 C14.7974286,5.71428571
-14.2857143,6.226 14.2857143,6.85714286 C14.2857143,7.48828571 14.7974286,8
-15.4285714,8 C16.0597143,8 16.5714286,7.48828571 16.5714286,6.85714286
-C16.5714286,6.226 16.0597143,5.71428571 15.4285714,5.71428571 M12,5.71428571
-C11.3688571,5.71428571 10.8571429,6.226 10.8571429,6.85714286
-C10.8571429,7.48828571 11.3688571,8 12,8 C12.6311429,8 13.1428571,7.48828571
-13.1428571,6.85714286 C13.1428571,6.226 12.6311429,5.71428571 12,5.71428571
-M8.57142857,5.71428571 C7.94028571,5.71428571 7.42857143,6.226
-7.42857143,6.85714286 C7.42857143,7.48828571 7.94028571,8 8.57142857,8
-C9.20257143,8 9.71428571,7.48828571 9.71428571,6.85714286 C9.71428571,6.226
-9.20257143,5.71428571 8.57142857,5.71428571" />
-</vector>
\ No newline at end of file
+     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 android:height="44dp" android:viewportHeight="48.0"
+        android:viewportWidth="48.0" android:width="44dp"
+        xmlns:android="http://schemas.android.com/apk/res/android">
+    <path android:fillColor="#000000"
+          android:pathData="M24,38c-2.21,0 -4,1.79 -4,4s1.79,4 4,4 4,-1.79 4,-4 -1.79,-4 -4,-4zM12,2C9.79,2 8,3.79 8,6s1.79,4 4,4 4,-1.79 4,-4 -1.79,-4 -4,-4zM12,14c-2.21,0 -4,1.79 -4,4s1.79,4 4,4 4,-1.79 4,-4 -1.79,-4 -4,-4zM12,26c-2.21,0 -4,1.79 -4,4s1.79,4 4,4 4,-1.79 4,-4 -1.79,-4 -4,-4zM36,10c2.21,0 4,-1.79 4,-4s-1.79,-4 -4,-4 -4,1.79 -4,4 1.79,4 4,4zM24,26c-2.21,0 -4,1.79 -4,4s1.79,4 4,4 4,-1.79 4,-4 -1.79,-4 -4,-4zM36,26c-2.21,0 -4,1.79 -4,4s1.79,4 4,4 4,-1.79 4,-4 -1.79,-4 -4,-4zM36,14c-2.21,0 -4,1.79 -4,4s1.79,4 4,4 4,-1.79 4,-4 -1.79,-4 -4,-4zM24,14c-2.21,0 -4,1.79 -4,4s1.79,4 4,4 4,-1.79 4,-4 -1.79,-4 -4,-4zM24,2c-2.21,0 -4,1.79 -4,4s1.79,4 4,4 4,-1.79 4,-4 -1.79,-4 -4,-4z"/>
+</vector>
diff --git a/res/drawable/ic_favorite.xml b/res/drawable/ic_favorite.xml
new file mode 100644
index 0000000..5c6b655
--- /dev/null
+++ b/res/drawable/ic_favorite.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+        android:width="24dp"
+        android:height="24dp"
+        android:viewportWidth="24.0"
+        android:viewportHeight="24.0">
+    <path
+        android:fillColor="#FF000000"
+        android:pathData="M12,21.35l-1.45,-1.32C5.4,15.36 2,12.28 2,8.5 2,5.42 4.42,3 7.5,3c1.74,0 3.41,0.81 4.5,2.09C13.09,3.81 14.76,3 16.5,3 19.58,3 22,5.42 22,8.5c0,3.78 -3.4,6.86 -8.55,11.54L12,21.35z"/>
+</vector>
diff --git a/res/drawable/ic_mute_call_activated.xml b/res/drawable/ic_mute_call_activated.xml
index 738854d..822c736 100644
--- a/res/drawable/ic_mute_call_activated.xml
+++ b/res/drawable/ic_mute_call_activated.xml
@@ -1,50 +1,22 @@
 <?xml version="1.0" encoding="utf-8"?>
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
-    android:width="72dp"
-    android:height="72dp"
-    android:viewportWidth="24"
-    android:viewportHeight="24">
+<!-- Copyright (C) 2018 The Android Open Source Project
 
-    <path
-        android:strokeWidth="1"
-        android:pathData="M 0 24 L 24 24 L 24 -1.13686838e-13 L 0 -1.13686838e-13 Z" />
-    <path
-        android:fillColor="#000000"
-        android:strokeWidth="1"
-        android:pathData="M14,7.57142857 C14,6.466 13.1058571,5.57142857 12.0022857,5.57142857
-C10.899,5.57142857 10.0038571,6.466 10.0038571,7.57142857 L10.0038571,7.73857143
-L14,11.7251429 C14.0038571,11.6742857 14,7.57142857 14,7.57142857" />
-    <path
-        android:fillColor="#000000"
-        android:strokeWidth="1"
-        android:pathData="M10.0039286,9.53624286 L6.72921429,6.25838571 L5.86507143,7.1021
-L10.0039286,11.2238143 L10.0039286,11.5713857 C10.0039286,12.6756714
-10.8989286,13.5713857 12.0023571,13.5713857 C12.1112143,13.5713857
-12.2172143,13.5603857 12.3213571,13.5435286 L17.1650714,18.3919571
-L18.0079286,17.5482429 L13.4299286,12.9656714 L13.4299286,12.9656714
-L10.0039286,9.53624286 Z" />
-    <path
-        android:fillColor="#000000"
-        android:strokeWidth="1"
-        android:pathData="M16.7016571,11.7142857 L15.5582286,11.7142857 C15.5582286,12.1917143
-15.4619429,12.6338571 15.2916571,13.0315714 L16.1336571,13.8744286
-C16.4940857,13.2327143 16.7016571,12.4977143 16.7016571,11.7142857" />
-    <path
-        android:fillColor="#000000"
-        android:strokeWidth="1"
-        android:pathData="M11.9969857,15.1317857 C10.1408429,15.1317857 8.4347,13.7325 8.4347,11.7142143
-L7.29227143,11.7142143 C7.29227143,14.0117857 9.08298571,15.8945
-11.2884143,16.2205 L11.2884143,18.4285 L12.7155571,18.4285 L12.7155571,16.2205
-C13.7292714,16.0705 14.6529857,15.5907857 15.3558429,14.8933571
-L14.5601286,14.0969286 C13.8944143,14.7493571 12.9665571,15.1317857
-11.9969857,15.1317857" />
-    <path
-        android:fillColor="#000000"
-        android:strokeWidth="1"
-        android:pathData="M12,0 C5.37257143,0 0,5.37257143 0,12 C0,18.6274286 5.37257143,24 12,24
-C18.6274286,24 24,18.6274286 24,12 C24,5.37257143 18.6274286,0 12,0
-M12,1.28571429 C17.9078571,1.28571429 22.7142857,6.09214286 22.7142857,12
-C22.7142857,17.9078571 17.9078571,22.7142857 12,22.7142857
-C6.09214286,22.7142857 1.28571429,17.9078571 1.28571429,12
-C1.28571429,6.09214286 6.09214286,1.28571429 12,1.28571429" />
-</vector>
\ No newline at end of file
+     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.
+-->
+<layer-list
+    xmlns:android="http://schemas.android.com/apk/res/android" >
+    <item
+        android:drawable="@drawable/button_active_state_ring"/>
+    <item
+        android:drawable="@drawable/ic_mute_call_normal"/>
+</layer-list>
diff --git a/res/drawable/ic_mute_call_normal.xml b/res/drawable/ic_mute_call_normal.xml
index 3aeebc2..7816387 100644
--- a/res/drawable/ic_mute_call_normal.xml
+++ b/res/drawable/ic_mute_call_normal.xml
@@ -1,41 +1,21 @@
 <?xml version="1.0" encoding="utf-8"?>
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
-    android:width="72dp"
-    android:height="72dp"
-    android:viewportWidth="24"
-    android:viewportHeight="24">
+<!-- Copyright (C) 2018 The Android Open Source Project
 
-    <path
-        android:strokeWidth="1"
-        android:pathData="M 0 24 L 24 24 L 24 -1.13686838e-13 L 0 -1.13686838e-13 Z" />
-    <path
-        android:fillColor="#000000"
-        android:strokeWidth="1"
-        android:pathData="M14,7.57142857 C14,6.466 13.1058571,5.57142857 12.0022857,5.57142857
-C10.899,5.57142857 10.0038571,6.466 10.0038571,7.57142857 L10.0038571,7.73857143
-L14,11.7251429 C14.0038571,11.6742857 14,7.57142857 14,7.57142857" />
-    <path
-        android:fillColor="#000000"
-        android:strokeWidth="1"
-        android:pathData="M10.0039286,9.53624286 L6.72921429,6.25838571 L5.86507143,7.1021
-L10.0039286,11.2238143 L10.0039286,11.5713857 C10.0039286,12.6756714
-10.8989286,13.5713857 12.0023571,13.5713857 C12.1112143,13.5713857
-12.2172143,13.5603857 12.3213571,13.5435286 L17.1650714,18.3919571
-L18.0079286,17.5482429 L13.4299286,12.9656714 L13.4299286,12.9656714
-L10.0039286,9.53624286 Z" />
-    <path
-        android:fillColor="#000000"
-        android:strokeWidth="1"
-        android:pathData="M16.7016571,11.7142857 L15.5582286,11.7142857 C15.5582286,12.1917143
-15.4619429,12.6338571 15.2916571,13.0315714 L16.1336571,13.8744286
-C16.4940857,13.2327143 16.7016571,12.4977143 16.7016571,11.7142857" />
-    <path
-        android:fillColor="#000000"
-        android:strokeWidth="1"
-        android:pathData="M11.9969857,15.1317857 C10.1408429,15.1317857 8.4347,13.7325 8.4347,11.7142143
-L7.29227143,11.7142143 C7.29227143,14.0117857 9.08298571,15.8945
-11.2884143,16.2205 L11.2884143,18.4285 L12.7155571,18.4285 L12.7155571,16.2205
-C13.7292714,16.0705 14.6529857,15.5907857 15.3558429,14.8933571
-L14.5601286,14.0969286 C13.8944143,14.7493571 12.9665571,15.1317857
-11.9969857,15.1317857" />
-</vector>
\ No newline at end of file
+     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 android:height="44dp" android:viewportHeight="48.0"
+        android:viewportWidth="48.0" android:width="44dp"
+        xmlns:android="http://schemas.android.com/apk/res/android">
+    <path android:fillColor="#000000"
+          android:pathData="M38,22h-3.4c0,1.49 -0.31,2.87 -0.87,4.1l2.46,2.46C37.33,26.61 38,24.38 38,22zM29.97,22.33c0,-0.11 0.03,-0.22 0.03,-0.33L30,10c0,-3.32 -2.69,-6 -6,-6s-6,2.68 -6,6v0.37l11.97,11.96zM8.55,6L6,8.55l12.02,12.02v1.44c0,3.31 2.67,6 5.98,6 0.45,0 0.88,-0.06 1.3,-0.15l3.32,3.32c-1.43,0.66 -3,1.03 -4.62,1.03 -5.52,0 -10.6,-4.2 -10.6,-10.2L10,22.01c0,6.83 5.44,12.47 12,13.44L22,42h4v-6.56c1.81,-0.27 3.53,-0.9 5.08,-1.81L39.45,42 42,39.46 8.55,6z"/>
+</vector>
diff --git a/res/drawable/ic_pause.xml b/res/drawable/ic_pause.xml
new file mode 100644
index 0000000..515720e
--- /dev/null
+++ b/res/drawable/ic_pause.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.
+-->
+<vector android:height="44dp" android:viewportHeight="48.0"
+        android:viewportWidth="48.0" android:width="44dp"
+        xmlns:android="http://schemas.android.com/apk/res/android">
+    <path android:fillColor="#000000"
+          android:pathData="M12,38h8L20,10h-8v28zM28,10v28h8L36,10h-8z"/>
+</vector>
diff --git a/res/drawable/ic_phone.xml b/res/drawable/ic_phone.xml
index 77172dc..56db064 100644
--- a/res/drawable/ic_phone.xml
+++ b/res/drawable/ic_phone.xml
@@ -1,7 +1,7 @@
 <?xml version="1.0" encoding="utf-8"?>
 <vector xmlns:android="http://schemas.android.com/apk/res/android"
-    android:width="56dp"
-    android:height="56dp"
+    android:width="44dp"
+    android:height="44dp"
     android:viewportWidth="24"
     android:viewportHeight="24">
 
diff --git a/res/drawable/ic_play.xml b/res/drawable/ic_play.xml
new file mode 100644
index 0000000..d0c77c1
--- /dev/null
+++ b/res/drawable/ic_play.xml
@@ -0,0 +1,19 @@
+<?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.
+-->
+<vector android:height="44dp" android:viewportHeight="48.0"
+    android:viewportWidth="48.0" android:width="44dp" xmlns:android="http://schemas.android.com/apk/res/android">
+    <path android:fillColor="#000000" android:pathData="M16,10v28l22,-14z"/>
+</vector>
diff --git a/res/drawable/ic_search.xml b/res/drawable/ic_search.xml
index f0cdc70..b85f8a5 100644
--- a/res/drawable/ic_search.xml
+++ b/res/drawable/ic_search.xml
@@ -14,8 +14,8 @@
 limitations under the License.
 -->
 <vector xmlns:android="http://schemas.android.com/apk/res/android"
-    android:width="@dimen/stream_button_icon_size"
-    android:height="@dimen/stream_button_icon_size"
+    android:width="@dimen/car_primary_icon_size"
+    android:height="@dimen/car_primary_icon_size"
     android:viewportWidth="48"
     android:viewportHeight="48">
 
diff --git a/res/drawable/ic_smartphone.xml b/res/drawable/ic_smartphone.xml
new file mode 100644
index 0000000..a15382d
--- /dev/null
+++ b/res/drawable/ic_smartphone.xml
@@ -0,0 +1,24 @@
+<?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.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+           android:viewportWidth="24"
+           android:viewportHeight="24"
+           android:width="44dp"
+           android:height="44dp">
+    <path
+        android:pathData="M16 1L8 1C6.34 1 5 2.34 5 4l0 16c0 1.66 1.34 3 3 3l8 0c1.66 0 3 -1.34 3 -3L19 4C19 2.34 17.66 1 16 1Zm-2 20l-4 0 0 -1 4 0 0 1zm3.25 -3l-10.5 0 0 -14 10.5 0 0 14z"
+        android:fillColor="#000000" />
+</vector>
\ No newline at end of file
diff --git a/res/drawable/ic_speaker_phone.xml b/res/drawable/ic_speaker_phone.xml
new file mode 100644
index 0000000..ed96b69
--- /dev/null
+++ b/res/drawable/ic_speaker_phone.xml
@@ -0,0 +1,24 @@
+<?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.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+        android:viewportWidth="24"
+        android:viewportHeight="24"
+        android:width="44dp"
+        android:height="44dp">
+    <path
+        android:pathData="M7 7.07L8.43 8.5C9.34 7.59 10.61 7.02 12 7.02c1.39 0 2.66 0.57 3.57 1.48L17 7.07C15.72 5.79 13.95 5 12 5 10.05 5 8.28 5.79 7 7.07ZM12 1C8.98 1 6.24 2.23 4.25 4.21L5.66 5.62C7.28 4 9.53 3 12 3c2.47 0 4.72 1 6.34 2.62L19.75 4.21C17.76 2.23 15.02 1 12 1ZM14.86 10.01L9.14 10C8.51 10 8 10.51 8 11.14l0 9.71c0 0.63 0.51 1.14 1.14 1.14l5.71 0c0.63 0 1.14 -0.51 1.14 -1.14l0 -9.71C16 10.51 15.49 10.01 14.86 10.01ZM15 20l-6 0 0 -8 6 0 0 8z"
+        android:fillColor="#000000" />
+</vector>
\ No newline at end of file
diff --git a/res/drawable/in_call_card_background.xml b/res/drawable/in_call_card_background.xml
index db61e98..f1e4540 100644
--- a/res/drawable/in_call_card_background.xml
+++ b/res/drawable/in_call_card_background.xml
@@ -1,3 +1,18 @@
+<?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">
     <solid android:color="@color/car_card" />
     <corners
diff --git a/res/drawable/ongoing_call_secondary_action_background.xml b/res/drawable/ongoing_call_secondary_action_background.xml
index c0ce13a..3b3c3ca 100644
--- a/res/drawable/ongoing_call_secondary_action_background.xml
+++ b/res/drawable/ongoing_call_secondary_action_background.xml
@@ -16,5 +16,5 @@
 <inset
     xmlns:android="http://schemas.android.com/apk/res/android"
     android:inset="32dp" >
-    <ripple android:color="@color/car_card_ripple_light_color_background" />
+    <ripple android:color="@color/car_card_ripple_background_dark" />
 </inset>
diff --git a/res/layout-h720dp/dialer_fragment.xml b/res/layout-h720dp/dialer_fragment.xml
deleted file mode 100644
index e098099..0000000
--- a/res/layout-h720dp/dialer_fragment.xml
+++ /dev/null
@@ -1,124 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- 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.
--->
-<!-- There seems to be a bug in layout inflation where it can't use a resource to inflate a view
-     group that sets layout_marginTop with a dimension. Work around by putting in a shell layout.
--->
-<FrameLayout
-    xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:card_view="http://schemas.android.com/apk/res-auto"
-    android:layout_width="match_parent"
-    android:layout_height="match_parent">
-
-    <!-- This CardView is clickable so that clicks do not fall through to the fragment that
-         is underneath the dialer_fragment. -->
-    <android.support.v7.widget.CardView
-        android:layout_width="match_parent"
-        android:layout_height="match_parent"
-        android:layout_marginTop="@dimen/lens_header_height"
-        android:clickable="true"
-        card_view:cardBackgroundColor="@color/car_card"
-        card_view:cardElevation="@dimen/dialer_card_elevation">
-
-        <RelativeLayout
-            android:layout_width="match_parent"
-            android:layout_height="match_parent">
-
-            <TextView
-                android:id="@+id/number"
-                android:layout_width="match_parent"
-                android:layout_height="@dimen/dialer_number_view_height"
-                android:paddingTop="@dimen/dialer_number_view_padding"
-                android:paddingBottom="@dimen/dialer_number_view_padding"
-                android:gravity="center"
-                android:focusable="true"
-                android:text="@string/dial_a_number"
-                android:layout_alignParentTop="true"
-                style="@style/CarBody1" />
-
-            <View
-                android:id="@+id/line_divider"
-                android:background="@color/car_list_divider"
-                android:layout_width="match_parent"
-                android:layout_height="@dimen/line_divider_height"
-                android:layout_marginLeft="@dimen/stream_content_keyline_1"
-                android:layout_marginRight="@dimen/stream_content_keyline_1"
-                android:layout_below="@id/number" />
-
-            <LinearLayout
-                android:orientation="horizontal"
-                android:layout_marginTop="@dimen/dial_container_vertical_margin"
-                android:layout_width="match_parent"
-                android:layout_height="wrap_content"
-                android:layout_below="@id/line_divider" >
-
-                <FrameLayout
-                    android:layout_width="0dp"
-                    android:layout_height="match_parent"
-                    android:layout_weight="1" >
-
-                    <ImageButton
-                        android:id="@+id/call"
-                        android:scaleType="center"
-                        android:src="@drawable/ic_phone"
-                        style="@style/DialpadCall"
-                        android:elevation="@dimen/call_fab_elevation"
-                        android:layout_gravity="center" />
-                </FrameLayout>
-
-                <include
-                    android:layout_gravity="center"
-                    android:layout_height="wrap_content"
-                    android:layout_width="wrap_content"
-                    layout="@layout/dialpad" />
-
-                <FrameLayout
-                    android:layout_width="0dp"
-                    android:layout_height="match_parent"
-                    android:layout_weight="1" >
-
-                    <ImageButton
-                        android:id="@+id/delete"
-                        android:layout_width="@dimen/bksp_button_width"
-                        android:layout_height="@dimen/bksp_button_width"
-                        android:scaleType="centerInside"
-                        android:src="@drawable/ic_backspace"
-                        android:tint="@color/car_tint"
-                        android:background="@drawable/dialpad_delete_button_background"
-                        android:layout_gravity="center" />
-                </FrameLayout>
-            </LinearLayout>
-        </RelativeLayout>
-
-        <!-- This FrameLayout ensures that the back button is centered within the
-             exit_dialer_button despite the button's touch target
-             being smaller. -->
-        <FrameLayout
-            android:layout_gravity="start|top"
-            android:layout_width="@dimen/stream_content_keyline_1"
-            android:layout_height="@dimen/stream_content_keyline_1">
-
-            <ImageView
-                android:id="@+id/exit_dialer_button"
-                android:background="@drawable/dialpad_button_background"
-                android:layout_gravity="center"
-                android:layout_width="@dimen/stream_button_size"
-                android:layout_height="@dimen/stream_button_size"
-                android:scaleType="center"
-                android:tint="@color/car_tint"
-                android:src="@drawable/ic_down_outlined" />
-        </FrameLayout>
-    </android.support.v7.widget.CardView>
-</FrameLayout>
diff --git a/res/layout-port/dialer_fragment.xml b/res/layout-port/dialer_fragment.xml
new file mode 100644
index 0000000..8b04206
--- /dev/null
+++ b/res/layout-port/dialer_fragment.xml
@@ -0,0 +1,106 @@
+<?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.
+-->
+<!-- There seems to be a bug in layout inflation where it can't use a resource to inflate a view
+     group that sets layout_marginTop with a dimension. Work around by putting in a shell layout.
+-->
+<FrameLayout
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:app="http://schemas.android.com/apk/res-auto"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    android:paddingTop="@dimen/car_app_bar_height">
+    <android.support.constraint.ConstraintLayout
+        android:id="@+id/dialer_info_fragment_container"
+        android:paddingLeft="@dimen/car_margin"
+        android:paddingRight="@dimen/car_margin"
+        android:layout_width="match_parent"
+        android:layout_height="match_parent">
+
+        <FrameLayout
+            android:id="@+id/dialpad_fragment_container"
+            android:layout_height="wrap_content"
+            android:layout_width="wrap_content"
+            app:layout_constraintBottom_toBottomOf="parent"
+            app:layout_constraintStart_toStartOf="parent"
+            app:layout_constraintEnd_toStartOf="parent"
+            app:layout_constraintTop_toTopOf="parent"/>
+
+        <TextView
+            android:id="@+id/title"
+            style="@style/TextAppearance.Car.Headline2"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:layout_marginTop="@dimen/car_padding_4"
+            android:gravity="center"
+            android:focusable="true"
+            android:maxLines="1"
+            android:text="@string/dial_a_number"
+            app:layout_constraintEnd_toEndOf="parent"
+            app:layout_constraintStart_toStartOf="parent"
+            app:layout_constraintTop_toTopOf="parent"/>
+
+        <TextView
+            android:id="@+id/body"
+            style="@style/TextAppearance.Car.Body1"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:layout_marginTop="@dimen/car_padding_3"
+            android:gravity="center"
+            android:visibility="gone"
+            android:maxLines="1"
+            app:layout_constraintEnd_toEndOf="parent"
+            app:layout_constraintStart_toStartOf="parent"
+            app:layout_constraintTop_toBottomOf="@+id/title"/>
+
+        <ImageButton
+            android:id="@+id/call_button"
+            style="@style/DialpadPrimaryButton"
+            android:src="@drawable/ic_phone"
+            android:layout_marginBottom="@dimen/car_padding_4"
+            app:layout_constraintBottom_toBottomOf="parent"
+            app:layout_constraintEnd_toStartOf="@+id/delete_button"
+            app:layout_constraintHorizontal_chainStyle="packed"
+            app:layout_constraintStart_toStartOf="parent"/>
+
+        <ImageButton
+            android:id="@+id/delete_button"
+            style="@style/DialpadSecondaryButton"
+            android:layout_marginBottom="@dimen/car_padding_4"
+            android:layout_marginStart="@dimen/car_padding_6"
+            android:src="@drawable/ic_backspace"
+            app:layout_constraintBottom_toBottomOf="parent"
+            app:layout_constraintEnd_toEndOf="parent"
+            app:layout_constraintStart_toEndOf="@+id/call_button"/>
+
+        <ImageButton
+            android:id="@+id/end_call_button"
+            style="@style/DialpadPrimaryButton"
+            android:layout_marginBottom="@dimen/car_padding_4"
+            android:visibility="gone"
+            app:layout_constraintBottom_toBottomOf="parent"
+            app:layout_constraintEnd_toStartOf="@+id/mute_button"
+            app:layout_constraintHorizontal_chainStyle="packed"
+            app:layout_constraintStart_toStartOf="parent"/>
+
+        <ImageButton
+            android:id="@+id/mute_button"
+            style="@style/DialpadSecondaryButton"
+            android:layout_marginBottom="@dimen/car_padding_4"
+            android:layout_marginStart="@dimen/car_padding_6"
+            android:src="@drawable/ic_mute_call_normal"
+            android:visibility="gone"
+            app:layout_constraintBottom_toBottomOf="parent"
+            app:layout_constraintEnd_toEndOf="parent"
+            app:layout_constraintStart_toEndOf="@+id/end_call_button"/>
+    </android.support.constraint.ConstraintLayout>
+</FrameLayout>
\ No newline at end of file
diff --git a/res/layout-port/in_call_fragment.xml b/res/layout-port/in_call_fragment.xml
new file mode 100644
index 0000000..11808a4
--- /dev/null
+++ b/res/layout-port/in_call_fragment.xml
@@ -0,0 +1,53 @@
+<?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.
+-->
+<android.support.constraint.ConstraintLayout
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:app="http://schemas.android.com/apk/res-auto"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    android:background="@color/phone_theme_secondary"
+    android:orientation="vertical">
+
+    <FrameLayout
+        android:id="@+id/dialer_container"
+        android:layout_width="match_parent"
+        android:layout_height="match_parent"
+        android:visibility="gone"
+        app:layout_constraintBottom_toBottomOf="parent"
+        app:layout_constraintTop_toTopOf="parent"
+        app:layout_constraintEnd_toEndOf="parent"
+        app:layout_constraintStart_toStartOf="parent"/>
+
+    <FrameLayout
+        android:id="@+id/user_profile_container"
+        android:layout_width="match_parent"
+        android:layout_height="0dp"
+        app:layout_constraintBottom_toTopOf="@+id/controller_bar_container"
+        app:layout_constraintTop_toTopOf="parent"
+        app:layout_constraintEnd_toEndOf="parent"
+        app:layout_constraintStart_toStartOf="parent">
+        <include layout="@layout/user_profile_large"/>
+    </FrameLayout>
+
+    <FrameLayout
+        android:id="@+id/controller_bar_container"
+        android:layout_width="match_parent"
+        android:layout_height="@dimen/car_action_bar_height"
+        app:layout_constraintBottom_toBottomOf="parent"
+        app:layout_constraintEnd_toEndOf="parent"
+        app:layout_constraintStart_toStartOf="parent"/>
+</android.support.constraint.ConstraintLayout
+>
\ No newline at end of file
diff --git a/res/layout/audio_route_list_item.xml b/res/layout/audio_route_list_item.xml
new file mode 100644
index 0000000..79d6e7c
--- /dev/null
+++ b/res/layout/audio_route_list_item.xml
@@ -0,0 +1,47 @@
+<?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.
+-->
+<android.support.constraint.ConstraintLayout
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:app="http://schemas.android.com/apk/res-auto"
+    android:layout_width="match_parent"
+    android:layout_height="@dimen/car_action_bar_height"
+    android:background="@color/phone_theme"
+    android:elevation="@dimen/in_call_card_elevation">
+    <android.support.constraint.Guideline
+        android:id="@+id/text_start"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:orientation="vertical"
+        app:layout_constraintGuide_begin="124dp"/>
+    <ImageView
+        android:id="@+id/icon"
+        android:layout_width="@dimen/car_app_icon_size"
+        android:layout_height="@dimen/car_app_icon_size"
+        android:scaleType="fitCenter"
+        android:tint="@color/primary_icon_color"
+        app:layout_constraintBottom_toBottomOf="parent"
+        app:layout_constraintStart_toStartOf="parent"
+        app:layout_constraintTop_toTopOf="parent"/>
+    <TextView
+        android:id="@+id/body"
+        android:layout_width="0dp"
+        android:layout_height="wrap_content"
+        style="@style/TextAppearance.Car.Body1"
+        app:layout_constraintBottom_toBottomOf="parent"
+        app:layout_constraintStart_toStartOf="@+id/text_start"
+        app:layout_constraintEnd_toEndOf="parent"
+        app:layout_constraintTop_toTopOf="parent"/>
+</android.support.constraint.ConstraintLayout>
diff --git a/res/layout/audio_route_switch_dialog.xml b/res/layout/audio_route_switch_dialog.xml
new file mode 100644
index 0000000..6f89ce7
--- /dev/null
+++ b/res/layout/audio_route_switch_dialog.xml
@@ -0,0 +1,33 @@
+<?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.
+-->
+<android.support.v7.widget.CardView
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:app="http://schemas.android.com/apk/res-auto"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    app:cardBackgroundColor="@color/phone_theme"
+    app:contentPadding="@dimen/car_keyline_1"
+    app:cardCornerRadius="@dimen/car_radius_3"
+    app:cardElevation="@dimen/car_action_bar_elevation">
+
+    <androidx.car.widget.PagedListView
+        android:id="@+id/list"
+        android:layout_width="match_parent"
+        android:layout_height="match_parent"
+        android:clipChildren="false"
+        app:scrollBarEnabled="false"
+        app:gutter="none"/>
+</android.support.v7.widget.CardView>
\ No newline at end of file
diff --git a/res/layout/call_history_list_item.xml b/res/layout/call_history_list_item.xml
new file mode 100644
index 0000000..812cb90
--- /dev/null
+++ b/res/layout/call_history_list_item.xml
@@ -0,0 +1,42 @@
+<?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.
+-->
+<android.support.constraint.ConstraintLayout
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:app="http://schemas.android.com/apk/res-auto"
+    android:layout_width="match_parent"
+    android:layout_height="@dimen/car_action_bar_height"
+    android:background="@color/phone_theme"
+    android:paddingRight="@dimen/car_keyline_1"
+    android:paddingLeft="@dimen/car_keyline_1"
+    android:elevation = "@dimen/in_call_card_elevation">
+
+    <android.support.constraint.Guideline
+        android:id="@+id/list_item_left_edge"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:orientation="vertical"
+        app:layout_constraintGuide_begin="@dimen/car_keyline_1" />
+
+    <ImageView
+        android:id="@+id/avatar"
+        android:layout_width="@dimen/car_avatar_size"
+        android:layout_height="@dimen/car_avatar_size"
+        android:scaleType="center"
+        app:layout_constraintBottom_toBottomOf="parent"
+        app:layout_constraintStart_toStartOf="parent"
+        app:layout_constraintEnd_toStartOf="@+id/toggle_dialpad_button"
+        app:layout_constraintTop_toTopOf="parent"/>
+</android.support.constraint.ConstraintLayout>
diff --git a/res/layout/call_list_fragment.xml b/res/layout/call_list_fragment.xml
new file mode 100644
index 0000000..30086a9
--- /dev/null
+++ b/res/layout/call_list_fragment.xml
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2017 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<FrameLayout
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:app="http://schemas.android.com/apk/res-auto"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    android:background="@color/call_list_fragment_background"
+    android:clipChildren="false">
+
+    <androidx.car.widget.PagedListView
+        android:id="@+id/list_view"
+        android:layout_width="match_parent"
+        android:layout_height="match_parent"
+        android:layout_marginTop="@dimen/car_app_bar_height"
+        android:clipChildren="false" />
+</FrameLayout>
\ No newline at end of file
diff --git a/res/layout/call_log_last_call_item_card.xml b/res/layout/call_log_last_call_item_card.xml
deleted file mode 100644
index 72d568a..0000000
--- a/res/layout/call_log_last_call_item_card.xml
+++ /dev/null
@@ -1,34 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- 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.
--->
-<!-- This FrameLayout is used to center the CardView since the CardView's container will be larger
-     than its width. -->
-<FrameLayout
-    xmlns:android="http://schemas.android.com/apk/res/android"
-    android:layout_width="match_parent"
-    android:layout_height="wrap_content"
-    android:layout_marginBottom="@dimen/call_log_last_card_bottom_margin"
-    android:focusable="true">
-
-    <com.android.car.stream.ui.StreamCardView
-        android:id="@+id/call_log_card"
-        android:foreground="@drawable/dialer_ripple_background"
-        android:layout_gravity="center"
-        android:layout_width="wrap_content"
-        android:layout_height="@dimen/call_log_item_height" >
-
-        <include layout="@layout/call_log_list_item_card_base" />
-    </com.android.car.stream.ui.StreamCardView>
-</FrameLayout>
diff --git a/res/layout/call_log_list_item_card.xml b/res/layout/call_log_list_item_card.xml
index 5da3fdf..f836fff 100644
--- a/res/layout/call_log_list_item_card.xml
+++ b/res/layout/call_log_list_item_card.xml
@@ -13,22 +13,17 @@
      See the License for the specific language governing permissions and
      limitations under the License.
 -->
-<!-- This FrameLayout is used to center the CardView since the CardView's container will be larger
-     than its width. -->
-<FrameLayout
+<android.support.v7.widget.CardView
     xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:app="http://schemas.android.com/apk/res-auto"
+    android:id="@+id/call_log_card"
+    android:foreground="@drawable/dialer_ripple_background"
+    android:layout_gravity="center"
     android:layout_width="match_parent"
-    android:layout_height="wrap_content"
-    android:layout_marginBottom="@dimen/call_log_card_overlap"
-    android:focusable="true">
+    android:layout_height="@dimen/call_log_item_height"
+    app:cardBackgroundColor="@color/phone_theme"
+    app:cardCornerRadius="@dimen/favorite_card_corner_radius"
+    app:cardElevation="@dimen/car_action_bar_elevation">
 
-    <com.android.car.stream.ui.StreamCardView
-        android:id="@+id/call_log_card"
-        android:foreground="@drawable/dialer_ripple_background"
-        android:layout_gravity="center"
-        android:layout_width="wrap_content"
-        android:layout_height="@dimen/call_log_item_height" >
-
-        <include layout="@layout/call_log_list_item_card_base" />
-    </com.android.car.stream.ui.StreamCardView>
-</FrameLayout>
+    <include layout="@layout/call_log_list_item_card_base"/>
+</android.support.v7.widget.CardView>
diff --git a/res/layout/call_log_list_item_card_base.xml b/res/layout/call_log_list_item_card_base.xml
index f7c4616..6bb77eb 100644
--- a/res/layout/call_log_list_item_card_base.xml
+++ b/res/layout/call_log_list_item_card_base.xml
@@ -18,23 +18,22 @@
     android:id="@+id/container"
     android:layout_width="match_parent"
     android:layout_height="match_parent"
-    android:background="@drawable/car_list_item_background"
     android:duplicateParentState="true"
     android:orientation="horizontal">
 
     <FrameLayout
         android:id="@+id/icon_container"
-        android:layout_width="@dimen/stream_card_keyline_2"
+        android:layout_width="@dimen/car_keyline_2"
         android:layout_height="@dimen/icon_container_height"
         android:layout_gravity="center_vertical"
-        android:layout_marginLeft="16dp"
-        android:layout_marginRight="8dp" >
+        android:layout_marginStart="16dp"
+        android:layout_marginEnd="8dp" >
         <ImageView
             android:id="@+id/icon"
             android:layout_width="@dimen/call_log_icon_size"
             android:layout_height="@dimen/call_log_icon_size"
-            android:layout_gravity="center_vertical|left"
-            android:layout_marginLeft="@dimen/stream_card_keyline_1"
+            android:layout_gravity="center_vertical|start"
+            android:layout_marginStart="@dimen/car_keyline_1"
             android:scaleType="centerCrop" />
         <ImageView
             android:id="@+id/small_icon"
@@ -42,7 +41,7 @@
             android:layout_height="28dp"
             android:padding="4dp"
             android:scaleType="centerInside"
-            android:layout_gravity="bottom|right"
+            android:layout_gravity="bottom|end"
             android:background="@drawable/strequent_small_icon_bg"
             android:visibility="gone" />
     </FrameLayout>
@@ -58,13 +57,13 @@
 
         <TextView
             android:id="@+id/title"
-            style="@style/CarBody1"
+            style="@style/TextAppearance.Car.Body1"
             android:layout_width="wrap_content"
             android:layout_height="wrap_content"
             android:layout_marginBottom="@dimen/car_text_vertical_margin"
-            android:layout_marginRight="@dimen/stream_card_keyline_1"
+            android:layout_marginEnd="@dimen/car_keyline_1"
             android:ellipsize="end"
-            android:singleLine="true" />
+            android:maxLines="1" />
 
         <LinearLayout
             android:id="@+id/call_type"
@@ -83,7 +82,7 @@
 
             <TextView
                 android:id="@+id/text"
-                style="@style/CarBody2"
+                style="@style/TextAppearance.Car.Body2"
                 android:layout_width="wrap_content"
                 android:layout_height="wrap_content"
                 android:layout_gravity="center_vertical" />
@@ -95,7 +94,7 @@
         android:layout_width="wrap_content"
         android:layout_height="wrap_content"
         android:layout_gravity="center_vertical"
-        android:layout_marginRight="@dimen/car_list_item_icon_right_margin"
+        android:layout_marginEnd="@dimen/car_padding_4"
         android:scaleType="center"
         android:visibility="gone" />
 
diff --git a/res/layout/call_log_list_item_empty.xml b/res/layout/call_log_list_item_empty.xml
new file mode 100644
index 0000000..88d1aa1
--- /dev/null
+++ b/res/layout/call_log_list_item_empty.xml
@@ -0,0 +1,45 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2017 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<LinearLayout
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:id="@+id/container"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    android:layout_marginStart="16dp"
+    android:layout_marginEnd="16dp"
+    android:focusable="false"
+    android:orientation="vertical"
+    android:background="@drawable/car_list_item_background" >
+    <FrameLayout
+        android:id="@+id/icon_container"
+        android:layout_width="match_parent"
+        android:layout_height="match_parent"
+        android:visibility="visible">
+        <ImageView
+            android:id="@+id/icon"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_gravity="center_horizontal"
+            android:layout_marginTop="48dp"
+            android:layout_marginBottom="22dp" />
+    </FrameLayout>
+    <TextView
+        android:id="@+id/title"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:gravity="center"
+        style="@style/TextAppearance.Car.Body1" />
+</LinearLayout>
diff --git a/res/layout/contact_detail_card_content.xml b/res/layout/contact_detail_card_content.xml
new file mode 100644
index 0000000..3e2d801
--- /dev/null
+++ b/res/layout/contact_detail_card_content.xml
@@ -0,0 +1,55 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2017 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<FrameLayout
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="match_parent"
+    android:layout_height="@dimen/car_single_line_list_item_height"
+    android:layout_marginStart="@dimen/car_keyline_1"
+    android:layout_marginEnd="@dimen/car_keyline_1"
+    android:focusable="true"
+    android:backgroundTint="@color/contact_detail_card_background_color"
+    android:background="@drawable/car_list_item_background">
+    <ImageView
+        android:id="@+id/icon"
+        android:layout_width="@dimen/contact_detail_image_size"
+        android:layout_height="@dimen/contact_detail_image_size"
+        android:layout_gravity="center_vertical"
+        android:scaleType="centerCrop"/>
+
+    <LinearLayout
+        android:id="@+id/text_container"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_gravity="center_vertical"
+        android:orientation="vertical"
+        android:layout_marginStart="@dimen/car_keyline_2">
+        <TextView
+            android:id="@+id/title"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_marginBottom="@dimen/car_padding_1"
+            android:ellipsize="end"
+            android:maxLines="1"
+            style="@style/TextAppearance.Car.Body1"/>
+        <TextView
+            android:id="@+id/text"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:ellipsize="end"
+            android:maxLines="1"
+            style="@style/TextAppearance.Car.Body2"/>
+    </LinearLayout>
+</FrameLayout>
diff --git a/res/layout/contact_detail_name_image.xml b/res/layout/contact_detail_name_image.xml
index dc82d58..31ff2ca 100644
--- a/res/layout/contact_detail_name_image.xml
+++ b/res/layout/contact_detail_name_image.xml
@@ -16,47 +16,59 @@
 <!-- This FrameLayout is used to center the inner layout. -->
 <FrameLayout
     xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:app="http://schemas.android.com/apk/res-auto"
     android:layout_width="match_parent"
     android:layout_height="wrap_content"
-    android:layout_marginBottom="@dimen/call_log_card_overlap"
     android:focusable="true">
 
     <!-- Wraps everything in a card -->
-    <com.android.car.stream.ui.StreamCardView
+    <androidx.car.widget.ColumnCardView
         android:id="@+id/card"
         android:layout_width="wrap_content"
         android:layout_height="wrap_content"
-        android:backgroundTint="@color/car_grey_200"
-        android:backgroundTintMode="multiply"
+        android:backgroundTint="@color/contact_detail_card_background_color"
         android:layout_gravity="center">
 
         <!-- Used to provide common margins and also allow for the textview to set its right margin
              to the width of the image to allow it to ellipsize.
         -->
-        <FrameLayout
+        <android.support.constraint.ConstraintLayout
             android:layout_width="match_parent"
-            android:layout_height="match_parent"
-            android:layout_marginLeft="@dimen/stream_card_keyline_1"
-            android:layout_marginRight="@dimen/stream_card_keyline_1"
-            android:layout_marginTop="@dimen/contact_detail_vertical_margin"
-            android:layout_marginBottom="@dimen/contact_detail_vertical_margin">
+            android:layout_height="@dimen/contact_detail_name_card_height"
+            android:layout_marginLeft="@dimen/car_keyline_1"
+            android:layout_marginRight="@dimen/car_keyline_1">
+
+            <ImageView
+                android:id="@+id/avatar"
+                android:layout_width="@dimen/contact_detail_image_size"
+                android:layout_height="@dimen/contact_detail_image_size"
+                android:background="@drawable/avatar_rounded_bg"
+                app:layout_constraintVertical_chainStyle="packed"
+                app:layout_constraintBottom_toTopOf="@+id/title"
+                app:layout_constraintStart_toStartOf="parent"
+                app:layout_constraintEnd_toEndOf="parent"
+                app:layout_constraintTop_toTopOf="parent"/>
 
             <TextView
                 android:id="@+id/title"
                 android:layout_width="wrap_content"
                 android:layout_height="wrap_content"
-                android:layout_gravity="bottom|left"
-                android:layout_marginRight="@dimen/contact_detail_image_size"
                 android:singleLine="true"
                 android:ellipsize="end"
-                style="@style/CarHeadline1" />
-
-            <ImageView
-                android:id="@+id/right_icon"
-                android:layout_width="@dimen/contact_detail_image_size"
-                android:layout_height="@dimen/contact_detail_image_size"
-                android:background="@drawable/avatar_rounded_bg"
-                android:layout_gravity="right" />
-        </FrameLayout>
-    </com.android.car.stream.ui.StreamCardView>
+                android:layout_marginTop="@dimen/car_padding_4"
+                style="@style/TextAppearance.Car.Body1"
+                app:layout_constraintBottom_toBottomOf="parent"
+                app:layout_constraintStart_toStartOf="parent"
+                app:layout_constraintEnd_toEndOf="parent"
+                app:layout_constraintTop_toBottomOf="@+id/avatar"/>
+        </android.support.constraint.ConstraintLayout>
+        <View
+            android:id="@+id/divider"
+            android:layout_width="match_parent"
+            android:layout_height="@dimen/car_list_divider_height"
+            android:layout_marginStart="@dimen/car_keyline_1"
+            android:layout_marginEnd="@dimen/car_keyline_1"
+            android:background="@color/car_list_divider"
+            android:layout_gravity="bottom"/>
+    </androidx.car.widget.ColumnCardView>
 </FrameLayout>
diff --git a/res/layout/contact_details.xml b/res/layout/contact_details.xml
index 5a85fec..602f572 100644
--- a/res/layout/contact_details.xml
+++ b/res/layout/contact_details.xml
@@ -18,13 +18,14 @@
     xmlns:app="http://schemas.android.com/apk/res-auto"
     android:layout_width="match_parent"
     android:layout_height="match_parent"
+    android:background="@color/phone_theme_secondary"
     android:clickable="true"
     android:clipChildren="false">
 
-    <com.android.car.view.PagedListView
+    <androidx.car.widget.PagedListView
         android:id="@+id/list_view"
         android:layout_width="match_parent"
         android:layout_height="match_parent"
         android:clipChildren="false"
-        app:showDivider="false" />
+        app:showPagedListViewDivider="false" />
 </FrameLayout>
diff --git a/res/layout/contact_details_number.xml b/res/layout/contact_details_number.xml
index 928d789..94c49db 100644
--- a/res/layout/contact_details_number.xml
+++ b/res/layout/contact_details_number.xml
@@ -18,21 +18,23 @@
     xmlns:android="http://schemas.android.com/apk/res/android"
     android:layout_width="match_parent"
     android:layout_height="wrap_content"
-    android:layout_marginBottom="@dimen/call_log_card_overlap"
     android:focusable="true">
 
-    <com.android.car.stream.ui.StreamCardView
+    <androidx.car.widget.ColumnCardView
         android:id="@+id/card"
         android:layout_width="wrap_content"
         android:layout_height="wrap_content"
         android:layout_gravity="center">
 
-        <include layout="@layout/car_list_item_2" />
+        <include layout="@layout/contact_detail_card_content"/>
+
         <View
+            android:id="@+id/divider"
             android:layout_width="match_parent"
-            android:layout_height="@dimen/car_divider_height"
+            android:layout_height="@dimen/car_list_divider_height"
+            android:layout_marginStart="@dimen/car_keyline_1"
+            android:layout_marginEnd="@dimen/car_keyline_1"
             android:background="@color/car_list_divider"
-            android:layout_gravity="bottom"
-            android:layout_marginLeft="@dimen/stream_card_keyline_2" />
-    </com.android.car.stream.ui.StreamCardView>
+            android:layout_gravity="bottom"/>
+    </androidx.car.widget.ColumnCardView>
 </FrameLayout>
diff --git a/res/layout/contact_list_fragment.xml b/res/layout/contact_list_fragment.xml
new file mode 100644
index 0000000..1df07e2
--- /dev/null
+++ b/res/layout/contact_list_fragment.xml
@@ -0,0 +1,74 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2018 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<FrameLayout
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:app="http://schemas.android.com/apk/res-auto"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    android:background="@color/contact_fragment_background"
+    android:clipChildren="false">
+
+    <androidx.car.widget.PagedListView
+        android:id="@+id/list_view"
+        android:layout_width="match_parent"
+        android:layout_height="match_parent"
+        android:layout_marginTop="@dimen/car_app_bar_height"
+        android:clipChildren="false"/>
+
+    <FrameLayout
+        android:id="@+id/contact_detail_container"
+        android:background="@color/contact_detail_fragment_background_color"
+        android:layout_width="match_parent"
+        android:layout_height="match_parent"
+        android:visibility="gone">
+        <android.support.constraint.ConstraintLayout
+            android:layout_width="match_parent"
+            android:layout_height="@dimen/car_app_bar_height"
+            android:background="@color/phone_theme_secondary">
+            <ImageView
+                android:id="@+id/back_button"
+                android:layout_width="@dimen/car_touch_target_size"
+                android:layout_height="@dimen/car_touch_target_size"
+                android:scaleType="center"
+                android:src="@drawable/ic_arrow_back"
+                android:tint="@color/car_tint"
+                app:layout_constraintBottom_toBottomOf="parent"
+                app:layout_constraintStart_toStartOf="parent"
+                app:layout_constraintEnd_toEndOf="@+id/margin_guideline"
+                app:layout_constraintTop_toTopOf="parent"/>
+            <android.support.constraint.Guideline
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:id="@+id/margin_guideline"
+                app:layout_constraintGuide_begin="@dimen/car_margin"
+                android:orientation="vertical"/>
+            <TextView
+                android:id="@+id/title"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                style="@style/TextAppearance.Car.Body1"
+                app:layout_constraintBottom_toBottomOf="parent"
+                app:layout_constraintStart_toEndOf="@+id/back_button"
+                app:layout_constraintTop_toTopOf="parent"/>
+        </android.support.constraint.ConstraintLayout>
+        <FrameLayout
+            android:id="@+id/contact_detail_fragment_container"
+            android:layout_marginTop="@dimen/car_app_bar_height"
+            android:background="@android:color/transparent"
+            android:layout_width="match_parent"
+            android:layout_height="match_parent"/>
+    </FrameLayout>
+</FrameLayout>
\ No newline at end of file
diff --git a/res/layout/contact_result.xml b/res/layout/contact_result.xml
index 4b5f914..ca36bb5 100644
--- a/res/layout/contact_result.xml
+++ b/res/layout/contact_result.xml
@@ -21,7 +21,7 @@
     android:layout_height="wrap_content"
     android:focusable="true">
 
-    <com.android.car.stream.ui.StreamCardView
+    <androidx.car.widget.ColumnCardView
         android:id="@+id/contact_result_card"
         android:foreground="@drawable/dialer_ripple_background"
         android:layout_gravity="center"
@@ -29,9 +29,9 @@
         android:layout_height="@dimen/contact_result_card_height" >
 
         <!-- Using this FrameLayout to center the ImageView within a width of
-             stream_card_keyline_2. -->
+            car_keyline_2. -->
         <FrameLayout
-            android:layout_width="@dimen/stream_card_keyline_2"
+            android:layout_width="@dimen/car_keyline_2"
             android:layout_height="match_parent">
 
             <ImageView
@@ -44,12 +44,12 @@
 
         <TextView
             android:id="@+id/contact_name"
-            android:layout_marginStart="@dimen/stream_card_keyline_2"
+            android:layout_marginStart="@dimen/car_keyline_2"
             android:layout_gravity="center_vertical|start"
             android:layout_width="wrap_content"
             android:layout_height="wrap_content"
             android:ellipsize="end"
             android:maxLines="2"
-            style="@style/CarBody1" />
-    </com.android.car.stream.ui.StreamCardView>
+            style="@style/TextAppearance.Car.Body1" />
+    </androidx.car.widget.ColumnCardView>
 </FrameLayout>
diff --git a/res/layout/contact_result_fragment.xml b/res/layout/contact_result_fragment.xml
index 8b537dd..3dcb87d 100644
--- a/res/layout/contact_result_fragment.xml
+++ b/res/layout/contact_result_fragment.xml
@@ -19,13 +19,12 @@
     android:layout_width="match_parent"
     android:layout_height="match_parent">
 
-    <com.android.car.view.PagedListView
+    <androidx.car.widget.PagedListView
         android:id="@+id/contact_result_list"
         android:layout_width="match_parent"
         android:layout_height="match_parent"
-        app:offsetRows="true"
-        app:showDivider="true"
-        app:dividerStartMargin="@dimen/stream_card_keyline_2"
+        app:showPagedListViewDivider="true"
+        app:dividerStartMargin="@dimen/car_keyline_2"
         app:alignDividerEndTo="@id/contact_result_card"
         app:alignDividerStartTo="@id/contact_result_card" />
 </FrameLayout>
diff --git a/res/layout/contact_search_activity.xml b/res/layout/contact_search_activity.xml
index a9584ba..b130206 100644
--- a/res/layout/contact_search_activity.xml
+++ b/res/layout/contact_search_activity.xml
@@ -33,7 +33,7 @@
         android:id="@+id/search_container"
         android:background="@color/phone_theme"
         android:layout_width="match_parent"
-        android:layout_height="@dimen/lens_header_height" >
+        android:layout_height="@dimen/car_app_bar_height" >
 
         <FrameLayout
             android:background="@color/telecom_display_scrim"
@@ -41,23 +41,23 @@
             android:layout_height="match_parent" />
 
         <!-- This FrameLayout is used to center the ImageView in a space that is the width of
-             stream_content_keyline_1. -->
+             car_keyline_1. -->
         <FrameLayout
-            android:layout_width="@dimen/stream_content_keyline_1"
+            android:layout_width="@dimen/car_keyline_1"
             android:layout_height="match_parent">
 
             <ImageView
                 android:id="@+id/back"
                 android:background="@drawable/dialer_ripple_background"
                 android:layout_gravity="center"
-                android:layout_width="@dimen/stream_button_size"
-                android:layout_height="@dimen/stream_button_size"
+                android:layout_width="@dimen/car_touch_target_size"
+                android:layout_height="@dimen/car_touch_target_size"
                 android:src="@drawable/ic_arrow_back"
                 android:scaleType="center"
                 android:tint="@color/car_grey_50" />
         </FrameLayout>
 
-        <com.android.car.stream.ui.StreamCardView
+        <androidx.car.widget.ColumnCardView
             android:layout_gravity="center"
             android:layout_width="match_parent"
             android:layout_height="@dimen/search_container_height"
@@ -67,39 +67,39 @@
 
             <ImageView
                 android:layout_gravity="start|center_vertical"
-                android:layout_width="@dimen/stream_button_size"
-                android:layout_height="@dimen/stream_button_size"
+                android:layout_width="@dimen/car_touch_target_size"
+                android:layout_height="@dimen/car_touch_target_size"
                 android:src="@drawable/ic_search"
                 android:scaleType="center"
                 android:tint="@color/search_container_controls_tint"/>
 
             <EditText
                 android:id="@+id/search_field"
-                android:layout_marginStart="@dimen/stream_button_size"
-                android:layout_marginEnd="@dimen/stream_button_size"
+                android:layout_marginStart="@dimen/car_touch_target_size"
+                android:layout_marginEnd="@dimen/car_touch_target_size"
                 android:layout_gravity="center"
                 android:layout_width="match_parent"
                 android:layout_height="wrap_content"
                 android:inputType="textPersonName|textCapWords"
                 android:hint="@string/search_hint"
                 android:textColorHint="@color/search_container_text_hint"
-                style="@style/CarBody1" />
+                style="@style/TextAppearance.Car.Body1" />
 
             <ImageView
                 android:id="@+id/clear"
                 android:background="@drawable/dialer_ripple_background"
                 android:layout_gravity="end|center_vertical"
-                android:layout_width="@dimen/stream_button_size"
-                android:layout_height="@dimen/stream_button_size"
+                android:layout_width="@dimen/car_touch_target_size"
+                android:layout_height="@dimen/car_touch_target_size"
                 android:src="@drawable/ic_cancel"
                 android:scaleType="center"
                 android:tint="@color/search_container_controls_tint"/>
-        </com.android.car.stream.ui.StreamCardView>
+        </androidx.car.widget.ColumnCardView>
     </FrameLayout>
 
     <FrameLayout
         android:id="@+id/content_fragment_container"
-        android:layout_marginTop="@dimen/lens_header_height"
+        android:layout_marginTop="@dimen/car_app_bar_height"
         android:layout_width="match_parent"
         android:layout_height="match_parent" />
 </FrameLayout>
diff --git a/res/layout/dialer_fragment.xml b/res/layout/dialer_fragment.xml
index c3c432f..495d4d3 100644
--- a/res/layout/dialer_fragment.xml
+++ b/res/layout/dialer_fragment.xml
@@ -18,100 +18,46 @@
 -->
 <FrameLayout
     xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:app="http://schemas.android.com/apk/res-auto"
     android:layout_width="match_parent"
     android:layout_height="match_parent"
-    android:paddingTop="@dimen/lens_header_height">
+    android:paddingTop="@dimen/car_app_bar_height">
 
-    <!-- This LinearLayout is clickable so that clicks do not fall through to the fragment that
-         is underneath the dialer_fragment. -->
-    <LinearLayout
-        android:background="@color/car_card"
-        android:clickable="true"
+    <android.support.constraint.ConstraintLayout
         android:layout_width="match_parent"
-        android:layout_height="match_parent"
-        android:paddingTop="@dimen/dial_container_vertical_margin"
-        android:orientation="horizontal" >
+        android:layout_height="match_parent">
 
         <FrameLayout
-            android:layout_marginTop="@dimen/dialer_dialpad_top_margin"
+            android:id="@+id/dialpad_fragment_container"
+            android:layout_height="wrap_content"
+            android:layout_width="wrap_content"
+            app:layout_constraintBottom_toBottomOf="parent"
+            app:layout_constraintStart_toStartOf="parent"
+            app:layout_constraintEnd_toStartOf="@+id/divider"
+            app:layout_constraintTop_toTopOf="parent"/>
+
+        <View
+            android:id="@+id/divider"
+            android:background="@color/car_list_divider"
+            android:layout_gravity="end|top"
+            android:layout_height="0dp"
+            android:layout_width="@dimen/line_divider_height"
+            app:layout_constraintBottom_toBottomOf="@+id/dialpad_fragment_container"
+            app:layout_constraintStart_toStartOf="parent"
+            app:layout_constraintEnd_toEndOf="parent"
+            app:layout_constraintTop_toTopOf="@+id/dialpad_fragment_container"/>
+
+        <FrameLayout
+            android:id="@+id/dialer_info_fragment_container"
+            android:layout_height="0dp"
             android:layout_width="0dp"
-            android:layout_height="match_parent"
-            android:layout_weight="1" >
-
-            <!-- This FrameLayout ensures that the back button is centered within the
-             exit_dialer_button despite the button's touch target
-             being smaller. -->
-            <FrameLayout
-                android:layout_marginTop="@dimen/dialer_back_button_top_margin"
-                android:layout_gravity="start|top"
-                android:layout_width="@dimen/stream_content_keyline_1"
-                android:layout_height="@dimen/stream_content_keyline_1">
-
-                <ImageView
-                    android:id="@+id/exit_dialer_button"
-                    android:background="@drawable/dialpad_button_background"
-                    android:layout_gravity="center"
-                    android:layout_width="@dimen/stream_button_size"
-                    android:layout_height="@dimen/stream_button_size"
-                    android:scaleType="center"
-                    android:tint="@color/car_tint"
-                    android:src="@drawable/ic_down_outlined" />
-            </FrameLayout>
-
-            <include
-                android:layout_gravity="center_horizontal"
-                android:layout_height="wrap_content"
-                android:layout_width="wrap_content"
-                layout="@layout/dialpad" />
+            android:paddingStart="@dimen/car_keyline_1"
+            android:paddingEnd="@dimen/car_keyline_1"
+            app:layout_constraintBottom_toBottomOf="@+id/dialpad_fragment_container"
+            app:layout_constraintStart_toEndOf="@+id/divider"
+            app:layout_constraintEnd_toEndOf="parent"
+            app:layout_constraintTop_toTopOf="@+id/dialpad_fragment_container">
+            <include layout="@layout/dialer_info_fragment"/>
         </FrameLayout>
-
-        <RelativeLayout
-            android:layout_width="@dimen/dialer_dialed_number_container"
-            android:layout_height="match_parent"
-            android:paddingStart="@dimen/stream_content_keyline_1"
-            android:paddingEnd="@dimen/stream_content_keyline_1"
-            android:paddingBottom="@dimen/dialer_dialed_number_bottom_padding">
-
-            <TextView
-                android:id="@+id/number"
-                android:layout_width="match_parent"
-                android:layout_height="@dimen/dialer_number_view_height"
-                android:layout_alignParentTop="true"
-                android:layout_alignParentStart="true"
-                android:paddingTop="@dimen/dialer_number_view_padding"
-                android:paddingBottom="@dimen/dialer_number_view_padding"
-                android:gravity="center"
-                android:focusable="true"
-                android:text="@string/dial_a_number"
-                style="@style/CarBody1" />
-
-            <ImageButton
-                android:id="@+id/call"
-                android:scaleType="center"
-                android:src="@drawable/ic_phone"
-                android:layout_alignParentBottom="true"
-                android:layout_centerHorizontal="true"
-                android:elevation="@dimen/call_fab_elevation"
-                style="@style/DialpadCall" />
-
-            <ImageButton
-                android:id="@+id/delete"
-                android:layout_alignParentBottom="true"
-                android:layout_width="@dimen/bksp_button_width"
-                android:layout_height="@dimen/bksp_button_width"
-                android:layout_toEndOf="@id/call"
-                android:layout_marginStart="16dp"
-                android:scaleType="centerInside"
-                android:src="@drawable/ic_backspace"
-                android:tint="@color/car_tint"
-                android:background="@drawable/dialpad_delete_button_background" />
-        </RelativeLayout>
-    </LinearLayout>
-
-    <View
-        android:background="@color/car_list_divider"
-        android:layout_gravity="end|top"
-        android:layout_height="match_parent"
-        android:layout_width="@dimen/line_divider_height"
-        android:layout_marginEnd="@dimen/dialer_dialed_number_container" />
+    </android.support.constraint.ConstraintLayout>
 </FrameLayout>
diff --git a/res/layout/dialer_info_fragment.xml b/res/layout/dialer_info_fragment.xml
new file mode 100644
index 0000000..1f900f6
--- /dev/null
+++ b/res/layout/dialer_info_fragment.xml
@@ -0,0 +1,91 @@
+<?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.
+-->
+<android.support.constraint.ConstraintLayout
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:app="http://schemas.android.com/apk/res-auto"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent">
+
+    <TextView
+        android:id="@+id/title"
+        style="@style/TextAppearance.Car.Headline2"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:paddingLeft="@dimen/car_padding_4"
+        android:paddingRight="@dimen/car_padding_4"
+        android:paddingBottom="@dimen/dialer_number_view_padding"
+        android:gravity="center"
+        android:focusable="true"
+        android:maxLines="1"
+        android:text="@string/dial_a_number"
+        app:layout_constraintEnd_toEndOf="parent"
+        app:layout_constraintStart_toStartOf="parent"
+        app:layout_constraintTop_toTopOf="parent"/>
+
+    <TextView
+        android:id="@+id/body"
+        style="@style/TextAppearance.Car.Body1"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:paddingLeft="@dimen/car_padding_4"
+        android:paddingRight="@dimen/car_padding_4"
+        android:paddingTop="@dimen/car_padding_3"
+        android:gravity="center"
+        android:visibility="gone"
+        android:maxLines="1"
+        app:layout_constraintEnd_toEndOf="parent"
+        app:layout_constraintStart_toStartOf="parent"
+        app:layout_constraintTop_toBottomOf="@+id/title"/>
+
+    <ImageButton
+        android:id="@+id/call_button"
+        style="@style/DialpadPrimaryButton"
+        android:src="@drawable/ic_phone"
+        android:backgroundTint="@color/phone_call"
+        app:layout_constraintBottom_toBottomOf="parent"
+        app:layout_constraintEnd_toStartOf="@+id/delete_button"
+        app:layout_constraintHorizontal_chainStyle="packed"
+        app:layout_constraintStart_toStartOf="parent"/>
+
+    <ImageButton
+        android:id="@+id/delete_button"
+        style="@style/DialpadSecondaryButton"
+        android:layout_marginStart="@dimen/car_padding_6"
+        android:src="@drawable/ic_backspace"
+        app:layout_constraintBottom_toBottomOf="parent"
+        app:layout_constraintEnd_toEndOf="parent"
+        app:layout_constraintStart_toEndOf="@+id/call_button"/>
+
+    <ImageButton
+        android:id="@+id/end_call_button"
+        style="@style/DialpadPrimaryButton"
+        android:src="@drawable/ic_call_end"
+        android:visibility="gone"
+        app:layout_constraintBottom_toBottomOf="parent"
+        app:layout_constraintEnd_toStartOf="@+id/mute_button"
+        app:layout_constraintHorizontal_chainStyle="packed"
+        app:layout_constraintStart_toStartOf="parent"/>
+
+    <ImageButton
+        android:id="@+id/mute_button"
+        style="@style/DialpadSecondaryButton"
+        android:layout_marginStart="@dimen/car_padding_6"
+        android:src="@drawable/ic_mute_call_normal"
+        android:visibility="gone"
+        app:layout_constraintBottom_toBottomOf="parent"
+        app:layout_constraintEnd_toEndOf="parent"
+        app:layout_constraintStart_toEndOf="@+id/end_call_button"/>
+</android.support.constraint.ConstraintLayout>
\ No newline at end of file
diff --git a/res/layout/dialpad_button.xml b/res/layout/dialpad_button.xml
index 132f5ea..993953a 100644
--- a/res/layout/dialpad_button.xml
+++ b/res/layout/dialpad_button.xml
@@ -27,7 +27,7 @@
         android:layout_height="wrap_content"
         android:layout_marginBottom="-8dp"
         android:visibility="gone"
-        style="@style/CarKey1" />
+        style="@style/TextAppearance.Car.Key1" />
 
     <TextView
         android:id="@+id/dialpad_letters"
@@ -36,7 +36,7 @@
         android:layout_height="wrap_content"
         android:textAllCaps="true"
         android:visibility="gone"
-        style="@style/CarKey2" />
+        style="@style/TextAppearance.Car.Key2" />
 
     <ImageView
         android:id="@+id/dialpad_image"
diff --git a/res/layout/in_call_fragment.xml b/res/layout/in_call_fragment.xml
new file mode 100644
index 0000000..08a39be
--- /dev/null
+++ b/res/layout/in_call_fragment.xml
@@ -0,0 +1,50 @@
+<?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="match_parent"
+    android:layout_height="match_parent"
+    android:background="@color/phone_theme_secondary"
+    android:orientation="vertical">
+
+    <FrameLayout
+        android:id="@+id/dialer_container"
+        android:layout_width="match_parent"
+        android:layout_height="0dp"
+        android:visibility="gone"
+        android:layout_weight="1"/>
+
+    <FrameLayout
+        android:id="@+id/user_profile_container"
+        android:layout_width="match_parent"
+        android:gravity="center"
+        android:layout_height="0dp"
+        android:layout_weight="1">
+        <include layout="@layout/user_profile_large"/>
+    </FrameLayout>
+
+    <android.support.v7.widget.CardView
+        android:id="@+id/controller_bar_container"
+        android:layout_width="match_parent"
+        android:layout_height="@dimen/car_action_bar_height"
+        android:background="@android:color/white"
+        android:layout_marginStart="@dimen/car_margin"
+        android:layout_marginEnd="@dimen/car_margin"
+        android:layout_marginBottom="@dimen/car_padding_1"
+        app:cardCornerRadius="@dimen/car_radius_3"
+        app:cardElevation="@dimen/car_action_bar_elevation"/>
+</LinearLayout>
\ No newline at end of file
diff --git a/res/layout/on_going_call_controller_bar_fragment.xml b/res/layout/on_going_call_controller_bar_fragment.xml
new file mode 100644
index 0000000..62a430b
--- /dev/null
+++ b/res/layout/on_going_call_controller_bar_fragment.xml
@@ -0,0 +1,100 @@
+<?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.
+-->
+<android.support.constraint.ConstraintLayout
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:app="http://schemas.android.com/apk/res-auto"
+    xmlns:tools="http://schemas.android.com/tools"
+    android:layout_width="match_parent"
+    android:layout_height="@dimen/car_action_bar_height"
+    android:background="@color/phone_theme"
+    android:elevation = "@dimen/in_call_card_elevation">
+    <ImageView
+        android:id="@+id/mute_button"
+        android:layout_width="@dimen/in_call_button_size"
+        android:layout_height="@dimen/in_call_button_size"
+        android:scaleType="center"
+        android:src="@drawable/ic_mute"
+        android:tint="@color/primary_icon_color"
+        app:layout_constraintBottom_toBottomOf="parent"
+        app:layout_constraintStart_toStartOf="parent"
+        app:layout_constraintEnd_toStartOf="@+id/toggle_dialpad_button"
+        app:layout_constraintTop_toTopOf="parent"
+        tools:src="@color/contact_badge"/>
+
+    <ImageView
+        android:id="@+id/toggle_dialpad_button"
+        android:layout_width="@dimen/in_call_button_size"
+        android:layout_height="@dimen/in_call_button_size"
+        android:scaleType="center"
+        android:src="@drawable/ic_dialpad"
+        android:tint="@color/primary_icon_color"
+        app:layout_constraintBottom_toBottomOf="parent"
+        app:layout_constraintStart_toEndOf="@+id/mute_button"
+        app:layout_constraintEnd_toStartOf="@+id/end_call_button"
+        app:layout_constraintTop_toTopOf="parent"
+        tools:src="@color/contact_badge"/>
+
+    <ImageView
+        android:id="@+id/end_call_button"
+        android:layout_width="@dimen/fab_button_size"
+        android:layout_height="@dimen/fab_button_size"
+        android:scaleType="center"
+        android:src="@drawable/ic_call_end"
+        android:tint="@color/phone_theme_light"
+        app:layout_constraintBottom_toBottomOf="parent"
+        app:layout_constraintStart_toEndOf="@+id/toggle_dialpad_button"
+        app:layout_constraintEnd_toStartOf="@+id/voice_channel_button"
+        app:layout_constraintTop_toTopOf="parent"
+        tools:src="@color/contact_badge"/>
+
+    <ImageView
+        android:id="@+id/voice_channel_button"
+        android:layout_width="@dimen/in_call_button_size"
+        android:layout_height="@dimen/in_call_button_size"
+        android:scaleType="center"
+        android:src="@drawable/ic_bluetooth"
+        android:tint="@color/primary_icon_color"
+        app:layout_constraintBottom_toBottomOf="parent"
+        app:layout_constraintStart_toEndOf="@+id/end_call_button"
+        app:layout_constraintEnd_toStartOf="@+id/pause_button"
+        app:layout_constraintTop_toTopOf="parent"
+        tools:src="@color/contact_badge"/>
+
+    <ImageView
+        android:id="@+id/voice_channel_chevron"
+        android:layout_width="@dimen/car_secondary_icon_size"
+        android:layout_height="@dimen/car_secondary_icon_size"
+        android:scaleType="fitCenter"
+        android:src="@drawable/ic_arrow_down"
+        android:tint="@color/primary_icon_color"
+        app:layout_constraintBottom_toBottomOf="parent"
+        app:layout_constraintStart_toEndOf="@+id/voice_channel_button"
+        app:layout_constraintTop_toTopOf="parent"
+        tools:src="@color/contact_badge"/>
+
+    <ImageView
+        android:id="@+id/pause_button"
+        android:layout_width="@dimen/in_call_button_size"
+        android:layout_height="@dimen/in_call_button_size"
+        android:scaleType="center"
+        android:src="@drawable/ic_call_state_switch"
+        android:tint="@color/primary_icon_color"
+        app:layout_constraintBottom_toBottomOf="parent"
+        app:layout_constraintStart_toEndOf="@+id/voice_channel_button"
+        app:layout_constraintEnd_toEndOf="parent"
+        app:layout_constraintTop_toTopOf="parent"
+        tools:src="@color/contact_badge"/>
+</android.support.constraint.ConstraintLayout>
diff --git a/res/layout/ongoing_call.xml b/res/layout/ongoing_call.xml
index 3faeca5..5d8db5a 100644
--- a/res/layout/ongoing_call.xml
+++ b/res/layout/ongoing_call.xml
@@ -52,7 +52,8 @@
             android:layout_width="match_parent"
             android:layout_height="wrap_content"
             android:maxWidth="@dimen/in_call_text_max_width"
-            style="@style/CarHeadline2.Light" />
+            android:textAppearance="@style/TextAppearance.Car.Headline2"
+            android:textColor="@color/car_headline1_light" />
         <TextView
             android:id="@+id/info_secondary"
             android:layout_width="match_parent"
@@ -61,7 +62,7 @@
             android:layout_below="@id/name_secondary"
             android:maxWidth="@dimen/in_call_text_max_width"
             android:alpha="0.6"
-            style="@style/CarBody2"
+            style="@style/TextAppearance.Car.Body2"
             android:textColor="@color/car_grey_100" />
     </RelativeLayout>
 
@@ -71,7 +72,7 @@
         android:layout_width="@dimen/in_call_card_dialpad_width"
         android:layout_height="match_parent"
         android:layout_gravity="top|start"
-        android:layout_marginTop="@dimen/lens_header_height"
+        android:layout_marginTop="@dimen/car_app_bar_height"
         app:cardBackgroundColor="@color/car_card"
         app:cardCornerRadius="@dimen/in_call_card_dialpad_corner_radius"
         app:cardElevation="@dimen/in_call_card_elevation"
@@ -85,7 +86,7 @@
         android:layout_width="match_parent"
         android:layout_height="match_parent"
         android:background="@drawable/in_call_card_background"
-        android:layout_marginTop="@dimen/lens_header_height"
+        android:layout_marginTop="@dimen/car_app_bar_height"
         android:layout_marginEnd="@dimen/in_call_card_margin_right"
         android:paddingStart="@dimen/in_call_content_card_margin_start" >
         <LinearLayout
@@ -104,7 +105,7 @@
                     android:ellipsize="end"
                     android:maxLines="2"
                     android:visibility="gone"
-                    style="@style/CarHeadline2" />
+                    style="@style/TextAppearance.Car.Headline2" />
                 <TextView
                     android:id="@+id/info"
                     android:layout_below="@id/name"
@@ -112,7 +113,7 @@
                     android:layout_height="wrap_content"
                     android:visibility="gone"
                     android:textColor="@color/car_caption"
-                    style="@style/CarBody1" />
+                    style="@style/TextAppearance.Car.Body1" />
             </RelativeLayout>
             <ImageView
                 android:id="@+id/small_contact_photo"
@@ -130,14 +131,14 @@
             android:layout_width="match_parent"
             android:layout_height="1dp"
             android:layout_gravity="bottom"
-            android:layout_marginBottom="@dimen/action_panel_height"
+            android:layout_marginBottom="@dimen/car_action_bar_height"
             android:background="@color/separator" />
 
         <!-- TODO: Consider flattening out this part and updating logic. -->
         <FrameLayout
             android:id="@+id/controls_container"
             android:layout_width="match_parent"
-            android:layout_height="@dimen/action_panel_height"
+            android:layout_height="@dimen/car_action_bar_height"
             android:layout_gravity="bottom" >
 
             <LinearLayout
@@ -148,16 +149,16 @@
                 android:visibility="gone" >
                 <ImageButton
                     android:id="@+id/answer_call_button"
-                    android:layout_width="@dimen/stream_fab_size"
-                    android:layout_height="@dimen/stream_fab_size"
+                    android:layout_width="@dimen/dialer_fab_size"
+                    android:layout_height="@dimen/dialer_fab_size"
                     android:layout_gravity="center_vertical"
                     android:scaleType="center"
                     android:elevation="8dp"
                     android:src="@drawable/ic_phone" />
                 <ImageButton
                     android:id="@+id/reject_call_button"
-                    android:layout_width="@dimen/stream_fab_size"
-                    android:layout_height="@dimen/stream_fab_size"
+                    android:layout_width="@dimen/dialer_fab_size"
+                    android:layout_height="@dimen/dialer_fab_size"
                     android:layout_marginStart="@dimen/in_call_button_spacing"
                     android:layout_gravity="center_vertical"
                     android:scaleType="center"
@@ -175,16 +176,16 @@
                 android:visibility="gone" >
                 <ImageButton
                     android:id="@+id/end_call"
-                    android:layout_width="@dimen/stream_fab_size"
-                    android:layout_height="@dimen/stream_fab_size"
+                    android:layout_width="@dimen/dialer_fab_size"
+                    android:layout_height="@dimen/dialer_fab_size"
                     android:layout_gravity="center_vertical"
                     android:scaleType="center"
                     android:elevation="8dp"
                     android:src="@drawable/ic_call_end" />
                 <ImageButton
                     android:id="@+id/unhold_call"
-                    android:layout_width="@dimen/stream_fab_size"
-                    android:layout_height="@dimen/stream_fab_size"
+                    android:layout_width="@dimen/dialer_fab_size"
+                    android:layout_height="@dimen/dialer_fab_size"
                     android:layout_gravity="center_vertical"
                     android:scaleType="center"
                     android:elevation="8dp"
@@ -192,8 +193,8 @@
                     android:visibility="gone" />
                 <ImageButton
                     android:id="@+id/mute"
-                    android:layout_width="@dimen/stream_fab_size"
-                    android:layout_height="@dimen/stream_fab_size"
+                    android:layout_width="@dimen/dialer_fab_size"
+                    android:layout_height="@dimen/dialer_fab_size"
                     android:layout_marginStart="@dimen/in_call_button_spacing"
                     android:scaleType="center"
                     android:src="@drawable/ic_mute"
@@ -201,8 +202,8 @@
                     android:background="@drawable/ongoing_call_action_background" />
                 <ImageButton
                     android:id="@+id/toggle_dialpad"
-                    android:layout_width="@dimen/stream_fab_size"
-                    android:layout_height="@dimen/stream_fab_size"
+                    android:layout_width="@dimen/dialer_fab_size"
+                    android:layout_height="@dimen/dialer_fab_size"
                     android:layout_marginStart="@dimen/in_call_button_spacing"
                     android:scaleType="center"
                     android:src="@drawable/ic_dialpad"
@@ -223,15 +224,15 @@
         android:visibility="gone" >
         <ImageButton
             android:id="@+id/swap"
-            android:layout_width="@dimen/stream_fab_size"
-            android:layout_height="@dimen/stream_fab_size"
+            android:layout_width="@dimen/dialer_fab_size"
+            android:layout_height="@dimen/dialer_fab_size"
             android:scaleType="center"
             android:src="@drawable/ic_swap_calls"
             android:background="@drawable/ongoing_call_secondary_action_background" />
         <ImageButton
             android:id="@+id/merge"
-            android:layout_width="@dimen/stream_fab_size"
-            android:layout_height="@dimen/stream_fab_size"
+            android:layout_width="@dimen/dialer_fab_size"
+            android:layout_height="@dimen/dialer_fab_size"
             android:scaleType="center"
             android:src="@drawable/ic_call_merge"
             android:background="@drawable/ongoing_call_secondary_action_background" />
diff --git a/res/layout/ringing_call_controller_bar_fragment.xml b/res/layout/ringing_call_controller_bar_fragment.xml
new file mode 100644
index 0000000..8278980
--- /dev/null
+++ b/res/layout/ringing_call_controller_bar_fragment.xml
@@ -0,0 +1,80 @@
+<?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.
+-->
+<android.support.constraint.ConstraintLayout
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:app="http://schemas.android.com/apk/res-auto"
+    android:layout_width="match_parent"
+    android:layout_height="@dimen/car_action_bar_height"
+    android:background="@color/phone_theme"
+    android:elevation = "@dimen/in_call_card_elevation">
+
+    <ImageView
+        android:id="@+id/answer_call_button"
+        android:layout_width="@dimen/car_touch_target_size"
+        android:layout_height="@dimen/car_touch_target_size"
+        android:scaleType="center"
+        android:src="@drawable/ic_phone"
+        android:tint="@color/phone_call"
+        app:layout_constraintHorizontal_chainStyle="packed"
+        app:layout_constraintBottom_toBottomOf="parent"
+        app:layout_constraintStart_toStartOf="parent"
+        app:layout_constraintEnd_toStartOf="@+id/answer_call_text"
+        app:layout_constraintTop_toTopOf="parent"/>
+
+    <TextView
+        android:id="@+id/answer_call_text"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_marginStart="@dimen/car_padding_4"
+        android:text="@string/answer_call"
+        style="@style/TextAppearance.Car.Body1"
+        app:layout_constraintBottom_toBottomOf="parent"
+        app:layout_constraintStart_toEndOf="@+id/answer_call_button"
+        app:layout_constraintEnd_toStartOf="@+id/mid_line"
+        app:layout_constraintTop_toTopOf="parent"/>
+
+    <android.support.constraint.Guideline
+        android:id="@+id/mid_line"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:orientation="vertical"
+        app:layout_constraintGuide_percent="0.5"/>
+
+    <ImageView
+        android:id="@+id/end_call_button"
+        android:layout_width="@dimen/car_touch_target_size"
+        android:layout_height="@dimen/car_touch_target_size"
+        android:scaleType="center"
+        android:src="@drawable/ic_call_end"
+        android:tint="@color/phone_end_call"
+        app:layout_constraintHorizontal_chainStyle="packed"
+        app:layout_constraintBottom_toBottomOf="parent"
+        app:layout_constraintStart_toEndOf="@+id/mid_line"
+        app:layout_constraintEnd_toStartOf="@+id/end_call_text"
+        app:layout_constraintTop_toTopOf="parent"/>
+
+    <TextView
+        android:id="@+id/end_call_text"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_marginStart="@dimen/car_padding_4"
+        android:text="@string/decline_call"
+        style="@style/TextAppearance.Car.Body1"
+        app:layout_constraintBottom_toBottomOf="parent"
+        app:layout_constraintStart_toEndOf="@+id/end_call_button"
+        app:layout_constraintEnd_toEndOf="parent"
+        app:layout_constraintTop_toTopOf="parent"/>
+</android.support.constraint.ConstraintLayout>
diff --git a/res/layout/strequents_fragment.xml b/res/layout/strequents_fragment.xml
index d56fe71..2bb5133 100644
--- a/res/layout/strequents_fragment.xml
+++ b/res/layout/strequents_fragment.xml
@@ -18,14 +18,14 @@
     xmlns:app="http://schemas.android.com/apk/res-auto"
     android:layout_width="match_parent"
     android:layout_height="match_parent"
-    android:background="@color/telecom_display_scrim"
+    android:background="@color/phone_theme_secondary"
     android:clipChildren="false" >
 
-    <com.android.car.view.PagedListView
+    <androidx.car.widget.PagedListView
         android:id="@+id/list_view"
         android:layout_width="match_parent"
         android:layout_height="match_parent"
-        android:layout_marginTop="@dimen/lens_header_height"
+        android:layout_marginTop="@dimen/car_app_bar_height"
         android:clipChildren="false"
-        app:showDivider="false" />
+        app:showPagedListViewDivider="false" />
 </FrameLayout>
diff --git a/res/layout/telecom_activity.xml b/res/layout/telecom_activity.xml
index 50f3f14..68f8381 100644
--- a/res/layout/telecom_activity.xml
+++ b/res/layout/telecom_activity.xml
@@ -16,19 +16,20 @@
 <FrameLayout
     xmlns:android="http://schemas.android.com/apk/res/android"
     android:layout_width="match_parent"
-    android:layout_height="match_parent">
+    android:layout_height="match_parent"
+    android:background="@color/telecom_activity_background_color">
 
     <FrameLayout
         android:layout_gravity="top|end"
-        android:layout_width="@dimen/stream_content_keyline_1"
-        android:layout_height="@dimen/lens_header_height">
+        android:layout_width="@dimen/car_keyline_1"
+        android:layout_height="@dimen/car_app_bar_height">
 
         <ImageView
             android:id="@+id/search"
             android:background="@drawable/dialer_ripple_background"
             android:layout_gravity="center"
-            android:layout_width="@dimen/stream_button_size"
-            android:layout_height="@dimen/stream_button_size"
+            android:layout_width="@dimen/car_touch_target_size"
+            android:layout_height="@dimen/car_touch_target_size"
             android:src="@drawable/ic_search"
             android:scaleType="center"
             android:tint="@color/car_grey_50"/>
@@ -37,6 +38,6 @@
     <FrameLayout
         android:id="@+id/content_fragment_container"
         android:layout_width="match_parent"
-        android:layout_height="match_parent" />
+        android:layout_height="match_parent"/>
 
 </FrameLayout>
diff --git a/res/layout/user_profile_large.xml b/res/layout/user_profile_large.xml
new file mode 100644
index 0000000..193b671
--- /dev/null
+++ b/res/layout/user_profile_large.xml
@@ -0,0 +1,42 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2018 The Android Open Source Project
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+  http://www.apache.org/licenses/LICENSE-2.0
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+-->
+<LinearLayout
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    android:gravity="center"
+    android:orientation="vertical">
+    <ImageView
+        android:id="@+id/avatar"
+        android:layout_width="@dimen/car_large_avatar_size"
+        android:layout_height="@dimen/car_large_avatar_size"
+        android:layout_gravity="center"
+        android:scaleType="fitCenter" />
+    <TextView
+        android:id="@+id/title"
+        style="@style/TextAppearance.Car.Headline2"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:paddingTop="@dimen/car_padding_3"
+        android:focusable="true"
+        android:maxLines="1"
+        android:gravity="center"/>
+    <TextView
+        android:id="@+id/body"
+        style="@style/TextAppearance.Car.Body2"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:paddingTop="@dimen/car_padding_3"
+        android:gravity="center"
+        android:maxLines="1"/>
+</LinearLayout>
\ No newline at end of file
diff --git a/res/values-h420dp/dimens.xml b/res/values-h420dp/dimens.xml
index d2d0678..d2e19f1 100644
--- a/res/values-h420dp/dimens.xml
+++ b/res/values-h420dp/dimens.xml
@@ -14,10 +14,8 @@
      limitations under the License.
 -->
 <resources>
-    <dimen name="call_log_item_height">152dp</dimen>
     <dimen name="in_call_controls_container_height">192dp</dimen>
-    <dimen name="in_call_button_size">188dp</dimen>
     <dimen name="in_call_info_margin_top">72dp</dimen>
-    <dimen name="in_call_card_dialpad_vertical_spacing">16dp</dimen>
+    <dimen name="in_call_card_dialpad_vertical_spacing">@dimen/car_padding_2</dimen>
     <dimen name="small_contact_photo_margin_end">72dp</dimen>
 </resources>
diff --git a/res/values-h480dp/dimens.xml b/res/values-h480dp/dimens.xml
new file mode 100644
index 0000000..eb97fb6
--- /dev/null
+++ b/res/values-h480dp/dimens.xml
@@ -0,0 +1,18 @@
+<?xml version='1.0' encoding='UTF-8'?>
+<!-- Copyright (C) 2018 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<resources>
+    <dimen name="dialer_fab_size">100dp</dimen>
+</resources>
diff --git a/res/values-h600dp/dimens.xml b/res/values-h600dp/dimens.xml
index a3024e4..8de6192 100644
--- a/res/values-h600dp/dimens.xml
+++ b/res/values-h600dp/dimens.xml
@@ -15,5 +15,6 @@
 -->
 <resources>
     <dimen name="avatar_rounded_radius">98dp</dimen>
-    <dimen name="in_call_small_contact_photo_size">196dp</dimen>
+    <dimen name="car_key1_size">50sp</dimen>
+    <dimen name="car_key2_size">22sp</dimen>
 </resources>
diff --git a/res/values-h720dp/dimens.xml b/res/values-h720dp/dimens.xml
index 8f7d091..c97e184 100644
--- a/res/values-h720dp/dimens.xml
+++ b/res/values-h720dp/dimens.xml
@@ -17,6 +17,7 @@
     <dimen name="avatar_rounded_radius">118dp</dimen>
     <dimen name="in_call_controls_container_height">236dp</dimen>
     <dimen name="in_call_info_margin_top">96dp</dimen>
-    <dimen name="in_call_small_contact_photo_size">232dp</dimen>
     <dimen name="small_contact_photo_margin_end">96dp</dimen>
+    <dimen name="in_call_card_dialpad_horizontal_spacing">@dimen/car_padding_6</dimen>
+    <dimen name="in_call_card_dialpad_vertical_spacing">@dimen/car_padding_5</dimen>
 </resources>
diff --git a/res/values-night/colors.xml b/res/values-night/colors.xml
index 8977116..09f85f7 100644
--- a/res/values-night/colors.xml
+++ b/res/values-night/colors.xml
@@ -14,8 +14,13 @@
      limitations under the License.
 -->
 <resources>
+    <color name="phone_theme">@color/phone_theme_dark</color>
+    <color name="phone_theme_secondary">@color/phone_theme_secondary_dark</color>
+
     <color name="telecom_display_scrim">#52000000</color>  <!-- 32% black -->
-    <color name="phone_status_bar_theme">#ff00457c</color>
     <color name="search_container_controls_tint">@color/car_grey_100</color>
     <color name="search_container_text_hint">@color/car_body2_light</color>
+    <color name="car_caption">@color/car_caption_light</color>
+    <color name="car_key1">@color/car_key1_light</color>
+    <color name="car_key2">@color/car_key2_light</color>
 </resources>
diff --git a/res/values-w1024dp/dimens.xml b/res/values-w1024dp/dimens.xml
index b2ed8c4..9a833b1 100644
--- a/res/values-w1024dp/dimens.xml
+++ b/res/values-w1024dp/dimens.xml
@@ -22,17 +22,14 @@
 
     <dimen name="call_fab_elevation">8dp</dimen>
     <dimen name="dial_number_call_button_width">160dp</dimen>
-    <dimen name="bksp_button_width">160dp</dimen>
 
     <dimen name="in_call_card_corner_radius">160dp</dimen>
     <dimen name="in_call_large_contact_photo_size">632dp</dimen>
     <dimen name="in_call_card_margin_right">304dp</dimen>
-    <dimen name="in_call_content_card_margin_start">@dimen/stream_content_keyline_1</dimen>
+    <dimen name="in_call_content_card_margin_start">@dimen/car_keyline_1</dimen>
     <dimen name="in_call_text_max_width">460dp</dimen>
-    <dimen name="in_call_button_size">160dp</dimen>
     <dimen name="in_call_button_spacing">48dp</dimen>
     <dimen name="in_call_card_dialpad_width">468dp</dimen>
-    <dimen name="in_call_card_dialpad_horizontal_spacing">56dp</dimen>
 
     <dimen name="car_card_view_corner_radius">0dp</dimen>
 
@@ -40,5 +37,4 @@
 
     <dimen name="call_log_icon_size">76dp</dimen>
     <dimen name="call_log_last_card_bottom_margin">@dimen/call_log_card_overlap</dimen>
-    <dimen name="call_log_last_card_corner_radius">16dp</dimen>
 </resources>
diff --git a/res/values-w748dp/dimens.xml b/res/values-w748dp/dimens.xml
index 045bff5..1a85673 100644
--- a/res/values-w748dp/dimens.xml
+++ b/res/values-w748dp/dimens.xml
@@ -16,7 +16,4 @@
 <resources>
     <!-- The max width of content in apps for adaptive responsive -->
     <dimen name="apps_max_content_width">748dp</dimen>
-
-    <!-- Touch Keyboard -->
-    <dimen name="in_call_button_size">116dp</dimen>
-</resources>
\ No newline at end of file
+</resources>
diff --git a/res/values/colors.xml b/res/values/colors.xml
index 595df7b..046bb20 100644
--- a/res/values/colors.xml
+++ b/res/values/colors.xml
@@ -16,13 +16,30 @@
 <resources>
     <!-- rail -->
     <color name="phone_theme">@color/phone_theme_light</color>
-    <color name="phone_theme_light">@color/car_light_blue_800</color>
-    <color name="phone_status_bar_theme">@color/car_light_blue_900</color>
+    <color name="phone_theme_secondary">@color/phone_theme_secondary_light</color>
+
+    <color name="phone_theme_light">@color/car_grey_50</color>
+    <color name="phone_theme_dark">@color/car_dark_blue_grey_700</color>
+    <color name="phone_theme_secondary_light">@color/car_grey_200</color>
+    <color name="phone_theme_secondary_dark">@color/car_dark_blue_grey_800</color>
+
+    <color name="primary_icon_color">@color/car_tint</color>
+
+    <color name="phone_status_bar_theme">@android:color/transparent</color>
     <color name="phone_call">@color/car_green_700</color>
     <color name="phone_end_call">@color/car_red_500a</color>
     <color name="phone_secondary_call_scrim">#990288d1</color>
     <color name="separator">#1f000000</color>
 
+    <color name="call_history_list_item_color">@color/phone_theme</color>
+    <color name="call_list_fragment_background">@color/phone_theme</color>
+
+    <color name="contact_fragment_background">@color/phone_theme</color>
+    <color name="contact_list_item_color">@color/phone_theme</color>
+
+    <color name="dialer_fragment_background_color">@color/phone_theme</color>
+    <color name="telecom_activity_background_color">@color/phone_theme</color>
+
     <!-- phone -->
     <color name="secondary_call_scrim">#990288d1</color>
 
@@ -34,7 +51,22 @@
 
     <!-- The color of the icons in the contact details page. -->
     <color name="contact_details_icon_tint">@color/search_container_controls_tint</color>
+    <color name="contact_detail_fragment_background_color">@color/phone_theme_secondary</color>
+    <color name="contact_detail_card_background_color">@color/phone_theme</color>
 
     <!-- The color of the hint text in the search field. -->
     <color name="search_container_text_hint">@color/car_grey_400</color>
+
+    <!-- TextAppearances -->
+    <color name="car_caption_light">@color/car_grey_400</color>
+    <color name="car_caption_dark">@color/car_grey_700</color>
+    <color name="car_caption">@color/car_caption_dark</color>
+
+    <color name="car_key1_light">@color/car_grey_100</color>
+    <color name="car_key1_dark">@color/car_light_blue_700</color>
+    <color name="car_key1">@color/car_key1_dark</color>
+
+    <color name="car_key2_light">@color/car_grey_400</color>
+    <color name="car_key2_dark">@color/car_grey_650</color>
+    <color name="car_key2">@color/car_key2_dark</color>
 </resources>
diff --git a/res/values/dimens.xml b/res/values/dimens.xml
index a489b87..e319b79 100644
--- a/res/values/dimens.xml
+++ b/res/values/dimens.xml
@@ -30,18 +30,19 @@
     <dimen name="in_call_text_max_width">362dp</dimen>
     <dimen name="in_call_card_dialpad_width">300dp</dimen>
     <dimen name="in_call_large_contact_photo_size">480dp</dimen>
-    <dimen name="in_call_content_card_margin_start">@dimen/stream_content_keyline_1</dimen>
+    <dimen name="in_call_content_card_margin_start">@dimen/car_keyline_1</dimen>
     <dimen name="avatar_rounded_radius">60dp</dimen>
-    <dimen name="in_call_small_contact_photo_size">120dp</dimen>
+    <dimen name="in_call_small_contact_photo_size">@dimen/car_touch_target_size</dimen>
     <dimen name="in_call_toggle_button_image_offset">30dp</dimen>
     <dimen name="in_call_info_margin_top">72dp</dimen>
     <dimen name="in_call_card_elevation">12dp</dimen>
+    <dimen name="in_call_card_height">200dp</dimen>
 
     <!-- This should be -1 * in_call_card_right_margin -->
     <dimen name="in_call_card_dialpad_translation_x">-308dp</dimen>
     <dimen name="in_call_card_dialpad_corner_radius">16dp</dimen>
-    <dimen name="in_call_card_dialpad_horizontal_spacing">24dp</dimen>
-    <dimen name="in_call_card_dialpad_vertical_spacing">0dp</dimen>
+    <dimen name="in_call_card_dialpad_horizontal_spacing">@dimen/car_padding_5</dimen>
+    <dimen name="in_call_card_dialpad_vertical_spacing">@dimen/car_padding_4</dimen>
 
     <dimen name="in_call_button_spacing">32dp</dimen>
     <dimen name="in_call_card_corner_radius">@dimen/car_card_view_corner_radius</dimen>
@@ -61,13 +62,19 @@
          in_call_card_right_margin + car_card_view_corner_radius - card_margin.  -->
     <dimen name="call_log_card_overlap">-4dp</dimen>
     <dimen name="call_log_icon_margin">4dp</dimen>
-    <dimen name="call_log_item_height">91dp</dimen>
-    <dimen name="call_log_icon_size">@dimen/car_list_item_icon_size</dimen>
+    <dimen name="call_log_item_height">@dimen/car_single_line_list_item_height</dimen>
+    <dimen name="call_log_icon_size">@dimen/car_primary_icon_size</dimen>
+    <dimen name="car_card_view_corner_radius">2dp</dimen>
+    <dimen name="favorite_card_corner_radius">@dimen/car_radius_5</dimen>
+    <dimen name="favorite_card_space">@dimen/car_padding_1</dimen>
 
-    <dimen name="icon_container_height">@dimen/car_list_item_icon_size</dimen>
+    <dimen name="icon_container_height">@dimen/car_primary_icon_size</dimen>
+    <dimen name="avatar_icon_size">@dimen/car_avatar_size</dimen>
 
-    <dimen name="contact_detail_image_size">@dimen/in_call_small_contact_photo_size</dimen>
+    <dimen name="contact_detail_image_size">@dimen/car_primary_icon_size</dimen>
     <dimen name="contact_detail_vertical_margin">16dp</dimen>
+    <dimen name="contact_detail_name_card_height">192dp</dimen>
+    <dimen name="contact_detail_card_corner_radius">@dimen/car_radius_3</dimen>
 
     <!-- The height of the container that contains the contact search field. -->
     <dimen name="search_container_height">128dp</dimen>
@@ -80,4 +87,25 @@
 
     <!-- The height of each of the cards that list the contact search results. -->
     <dimen name="contact_result_card_height">128dp</dimen>
+
+    <dimen name="call_log_last_card_bottom_margin">@dimen/call_log_card_overlap</dimen>
+
+    <dimen name="line_divider_height">1dp</dimen>
+
+    <dimen name="dialer_number_view_height">128dp</dimen>
+    <dimen name="dialer_number_view_padding">32dp</dimen>
+
+    <dimen name="dialer_fab_size">80dp</dimen>
+    <dimen name="call_fab_elevation">8dp</dimen>
+    <dimen name="bksp_button_width">@dimen/car_touch_target_size</dimen>
+    <!-- Fab button size is touch target (76dp) + stroke width (8dp) * 2-->
+    <dimen name="fab_button_size">92dp</dimen>
+
+    <dimen name="in_call_button_size">@dimen/car_touch_target_size</dimen>
+
+    <dimen name="user_profile_title_margin_top">@dimen/car_padding_3</dimen>
+    <dimen name="user_profile_body_margin_top">@dimen/car_padding_3</dimen>
+
+    <dimen name="car_key1_size">40sp</dimen>
+    <dimen name="car_key2_size">18sp</dimen>
 </resources>
diff --git a/res/values/integer.xml b/res/values/integer.xml
new file mode 100644
index 0000000..b836fe4
--- /dev/null
+++ b/res/values/integer.xml
@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="utf-8"?>
+
+<resources >
+    <integer name="favorite_fragment_grid_column">2</integer>
+</resources>
\ No newline at end of file
diff --git a/res/values/strings.xml b/res/values/strings.xml
index d432c2f..9699a4b 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -54,6 +54,11 @@
     <!-- Status label for phone state [CHAR LIMIT=20] -->
     <string name="call_state_call_ending">Disconnecting</string>
 
+    <!-- Decline an in coming call [CHAR LIMIT=20] -->
+    <string name="decline_call">Decline</string>
+    <!-- Answer an in coming call [CHAR LIMIT=20] -->
+    <string name="answer_call">Answer</string>
+
     <!-- Label for voicemail [CHAR LIMIT=30] -->
     <string name="voicemail">Voicemail</string>
     <!-- Label for current phone call [CHAR LIMIT=30] -->
@@ -66,15 +71,42 @@
     <!-- Label for when a call is a conference call [CHAR LIMIT=30] -->
     <string name="conference_call">Conference call</string>
 
+    <!-- Audio route -->
+    <!-- Label for routing phone audio to the vehicle [CHAR LIMIT=30] -->
+    <string name="audio_route_vehicle">Vehicle bluetooth</string>
+    <!-- Label for routing phone audio to the phone speaker [CHAR LIMIT=30] -->
+    <string name="audio_route_phone_speaker">Speaker phone</string>
+    <!-- Label for routing phone audio to the phone earpiece. [CHAR LIMIT=30] -->
+    <string name="audio_route_handset">Handset</string>
+
     <!-- Menu label for the call history [CHAR LIMIT=30] -->
     <string name="calllog_all">Call History</string>
     <!-- Menu label for the missed call history [CHAR LIMIT=30] -->
     <string name="calllog_missed">Missed</string>
+    <!-- Menu label for the favorites [CHAR LIMIT=30] -->
+    <string name="calllog_favorites">Favorites</string>
     <!-- Menu label for dial a number [CHAR LIMIT=30] -->
-    <string name="calllog_dial_number">Dial a number</string>
+    <string name="calllog_dial_number">Dialpad</string>
     <!-- Button label to dial a manually entered phone number -->
     <string name="dial_a_number">Dial a number</string>
 
+    <!-- Menu label for the call history [CHAR LIMIT=30] -->
+    <string name="contact_menu_label">Contact</string>
+
+    <!-- Titles -->
+    <!-- Title for the favorites [CHAR LIMIT=30] -->
+    <string name="favorites_title">Favorites</string>
+    <!-- Title for the call history [CHAR LIMIT=30] -->
+    <string name="call_history_title">Call History</string>
+    <!-- Title for the missed call history [CHAR LIMIT=30] -->
+    <string name="missed_call_title">Missed</string>
+    <!-- Title for the contacts [CHAR LIMIT=30] -->
+    <string name="contacts_title">Contacts</string>
+    <!-- Title for the dialpad [CHAR LIMIT=30] -->
+    <string name="dialpad_title">Dialpad</string>
+    <!-- Title for the in call [CHAR LIMIT=30] -->
+    <string name="in_call_title">In Call</string>
+
     <!-- TODO: we do not need to localize this, figure out how to build ignoring it -->
     <string name="one">1</string>
     <string name="two">2</string>
@@ -109,5 +141,4 @@
     <string name="type_work">Work</string>
     <string name="type_mobile">Mobile</string>
     <string name="type_other">Other</string>
-
 </resources>
diff --git a/res/values/styles.xml b/res/values/styles.xml
index 5866d20..ab9e596 100644
--- a/res/values/styles.xml
+++ b/res/values/styles.xml
@@ -14,19 +14,42 @@
      limitations under the License.
 -->
 <resources xmlns:android="http://schemas.android.com/apk/res/android">
+    <style name="TextAppearance.Car.Key1" >
+        <item name="android:textStyle">normal</item>
+        <item name="android:textSize">@dimen/car_key1_size</item>
+        <item name="android:textColor">@color/car_key1</item>
+    </style>
+
+    <style name="TextAppearance.Car.Key2" >
+        <item name="android:textStyle">normal</item>
+        <item name="android:textSize">@dimen/car_key2_size</item>
+        <item name="android:textColor">@color/car_key2</item>
+    </style>
 
     <!-- Phone -->
     <style name="DialpadKeyButtonStyle">
         <item name="android:clickable">true</item>
-        <item name="android:layout_width">@dimen/stream_button_size</item>
-        <item name="android:layout_height">@dimen/stream_button_size</item>
+        <item name="android:layout_width">wrap_content</item>
+        <item name="android:layout_height">wrap_content</item>
+        <item name="android:minWidth">@dimen/car_touch_target_size</item>
+        <item name="android:minHeight">@dimen/car_touch_target_size</item>
         <item name="android:background">@drawable/dialpad_button_background</item>
         <item name="android:focusable">true</item>
     </style>
 
-    <style name="DialpadCall">
-        <item name="android:layout_width">@dimen/dial_number_call_button_width</item>
-        <item name="android:layout_height">@dimen/dial_number_call_button_width</item>
+    <style name="DialpadPrimaryButton">
+        <item name="android:layout_width">@dimen/fab_button_size</item>
+        <item name="android:layout_height">@dimen/fab_button_size</item>
+        <item name="android:elevation">@dimen/call_fab_elevation</item>
+        <item name="android:scaleType">center</item>
+    </style>
+
+    <style name="DialpadSecondaryButton">
+        <item name="android:layout_width">@dimen/bksp_button_width</item>
+        <item name="android:layout_height">@dimen/bksp_button_width</item>
+        <item name="android:background">@drawable/dialpad_delete_button_background</item>
+        <item name="android:scaleType">centerInside</item>
+        <item name="android:tint">@color/car_tint</item>
     </style>
 
     <style name="InCallDialpad">
@@ -39,7 +62,7 @@
         <item name="android:textColor">@color/car_headline1</item>
     </style>
 
-    <style name="NoHfpText" parent="CarBody2.Light">
+    <style name="NoHfpText" parent="TextAppearance.Car.Body2">
         <item name="android:textColor">@color/car_body1_light</item>
         <item name="android:gravity">center</item>
         <item name="android:maxLines">3</item>
diff --git a/res/values/themes.xml b/res/values/themes.xml
index 9da01d8..d09bffb 100644
--- a/res/values/themes.xml
+++ b/res/values/themes.xml
@@ -15,12 +15,19 @@
 -->
 <resources>
     <!-- The theme for the TelecomActivity. -->
-    <style name="TelecomActivityTheme" parent="@style/CarDrawerActivityTheme" >
+    <style name="TelecomActivityTheme" parent="@style/Theme.Car.Light.NoActionBar.Drawer" >
         <item name="android:statusBarColor">@color/phone_status_bar_theme</item>
+        <item name="android:colorPrimary">@android:color/transparent</item>
+        <item name="android:colorPrimaryDark">@color/phone_status_bar_theme</item>
+        <item name="android:textColorPrimary">@android:color/black</item>
+        <item name="drawerHeaderColor">@color/car_title2</item>
+        <item name="drawerBackgroundColor">@color/phone_theme</item>
     </style>
 
     <!-- The theme for the contact search page. -->
     <style name="ContactSearchActivityTheme" parent="@android:style/Theme.Material.Light.NoActionBar">
         <item name="android:statusBarColor">@color/phone_status_bar_theme</item>
+        <item name="android:colorPrimary">@android:color/transparent</item>
+        <item name="android:colorPrimaryDark">@color/phone_status_bar_theme</item>
     </style>
 </resources>
diff --git a/src/com/android/car/dialer/CallListener.java b/src/com/android/car/dialer/CallListener.java
new file mode 100644
index 0000000..b09ec8d
--- /dev/null
+++ b/src/com/android/car/dialer/CallListener.java
@@ -0,0 +1,16 @@
+package com.android.car.dialer;
+
+import com.android.car.dialer.telecom.UiCall;
+
+/** Interface for listening to call state changes. */
+public interface CallListener {
+    void onAudioStateChanged(boolean isMuted, int route, int supportedRouteMask);
+
+    void onCallStateChanged(UiCall call, int state);
+
+    void onCallUpdated(UiCall call);
+
+    void onCallAdded(UiCall call);
+
+    void onCallRemoved(UiCall call);
+}
diff --git a/src/com/android/car/dialer/CallLogListingTask.java b/src/com/android/car/dialer/CallLogListingTask.java
deleted file mode 100644
index 171bf24..0000000
--- a/src/com/android/car/dialer/CallLogListingTask.java
+++ /dev/null
@@ -1,258 +0,0 @@
-/*
- * 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.car.dialer;
-
-import android.content.ContentResolver;
-import android.content.Context;
-import android.content.res.Resources;
-import android.database.Cursor;
-import android.graphics.Bitmap;
-import android.os.AsyncTask;
-import android.provider.CallLog;
-import android.support.annotation.NonNull;
-import android.telephony.PhoneNumberUtils;
-import android.text.TextUtils;
-import android.text.format.DateUtils;
-
-import com.android.car.apps.common.CircleBitmapDrawable;
-import com.android.car.apps.common.LetterTileDrawable;
-import com.android.car.dialer.telecom.PhoneLoader;
-import com.android.car.dialer.telecom.TelecomUtils;
-
-import java.util.ArrayList;
-import java.util.List;
-
-class CallLogListingTask extends AsyncTask<Void, Void, Void> {
-    static class CallLogItem {
-        final String mTitle;
-        final String mText;
-        final String mNumber;
-        final Bitmap mIcon;
-
-        public CallLogItem(String title, String text, String number, Bitmap icon) {
-            mTitle = title;
-            mText = text;
-            mNumber = number;
-            mIcon = icon;
-        }
-    }
-
-    interface LoadCompleteListener {
-        void onLoadComplete(List<CallLogItem> items);
-    }
-
-
-    // Like a constant but needs a context so not static.
-    private final String VOICEMAIL_NUMBER;
-
-    private Context mContext;
-    private Cursor mCursor;
-    private List<CallLogItem> mItems;
-    private LoadCompleteListener mListener;
-
-    CallLogListingTask(Context context, Cursor cursor,
-            @NonNull LoadCompleteListener listener) {
-        mContext = context;
-        mCursor = cursor;
-        mItems = new ArrayList<>(mCursor.getCount());
-        mListener = listener;
-        VOICEMAIL_NUMBER = TelecomUtils.getVoicemailNumber(mContext);
-    }
-
-    private String maybeAppendCount(StringBuilder sb, int count) {
-        if (count > 1) {
-            sb.append(" (").append(count).append(")");
-        }
-        return sb.toString();
-    }
-
-    private String getContactName(String cachedName, String number,
-            int count, boolean isVoicemail) {
-        if (cachedName != null) {
-            return maybeAppendCount(new StringBuilder(cachedName), count);
-        }
-
-        StringBuilder sb = new StringBuilder();
-        if (isVoicemail) {
-            sb.append(mContext.getString(R.string.voicemail));
-        } else {
-            String displayName = TelecomUtils.getDisplayName(mContext, number);
-            if (TextUtils.isEmpty(displayName)) {
-                displayName = mContext.getString(R.string.unknown);
-            }
-            sb.append(displayName);
-        }
-
-        return maybeAppendCount(sb, count);
-    }
-
-    private Bitmap getContactImage(Context context, ContentResolver contentResolver,
-            String name, String number) {
-        Resources r = context.getResources();
-        int size = r.getDimensionPixelSize(R.dimen.dialer_menu_icon_container_width);
-
-        Bitmap bitmap = TelecomUtils.getContactPhotoFromNumber(contentResolver, number);
-        if (bitmap != null) {
-            return new CircleBitmapDrawable(r, bitmap).toBitmap(size);
-        }
-
-        LetterTileDrawable letterTileDrawable = new LetterTileDrawable(r);
-        letterTileDrawable.setContactDetails(name, number);
-        letterTileDrawable.setIsCircular(true);
-        return letterTileDrawable.toBitmap(size);
-    }
-
-    private static CharSequence getRelativeTime(long millis) {
-        boolean validTimestamp = millis > 0;
-
-        return validTimestamp ? DateUtils.getRelativeTimeSpanString(
-                millis, System.currentTimeMillis(), DateUtils.MINUTE_IN_MILLIS,
-                DateUtils.FORMAT_ABBREV_RELATIVE) : null;
-    }
-
-    @Override
-    protected Void doInBackground(Void... voids) {
-        ContentResolver resolver = mContext.getContentResolver();
-
-        try {
-            if (mCursor != null) {
-                int cachedNameColumn = PhoneLoader.getNameColumnIndex(mCursor);
-                int numberColumn = PhoneLoader.getNumberColumnIndex(mCursor);
-                int dateColumn = mCursor.getColumnIndex(CallLog.Calls.DATE);
-
-                while (mCursor.moveToNext()) {
-                    int count = 1;
-                    String number = mCursor.getString(numberColumn);
-
-                    // We want to group calls to the same number into one so seek forward as many
-                    // entries as possible as long as the number is the same.
-                    int position = mCursor.getPosition();
-                    while (mCursor.moveToNext()) {
-                        String nextNumber = mCursor.getString(numberColumn);
-                        if (equalNumbers(number, nextNumber)) {
-                            count++;
-                        } else {
-                            break;
-                        }
-                    }
-                    mCursor.moveToPosition(position);
-
-                    boolean isVoicemail = number.equals(VOICEMAIL_NUMBER);
-                    String name = getContactName(mCursor.getString(cachedNameColumn),
-                            number, count, isVoicemail);
-
-                    // Not sure why this is the only column checked here but I'm assuming this was
-                    // to work around some bug on some device.
-                    long millis = dateColumn == -1 ? 0 : mCursor.getLong(dateColumn);
-
-                    StringBuffer secondaryText = new StringBuffer();
-                    CharSequence relativeDate = getRelativeTime(millis);
-
-                    // Append the type (work, mobile etc.) if it isnt voicemail.
-                    if (!isVoicemail) {
-                        CharSequence type = TelecomUtils.getTypeFromNumber(mContext, number);
-                        secondaryText.append(type);
-                        if (!TextUtils.isEmpty(type) && !TextUtils.isEmpty(relativeDate)) {
-                            secondaryText.append(", ");
-                        }
-                    }
-
-                    // Add in the timestamp.
-                    if (relativeDate != null) {
-                        secondaryText.append(relativeDate);
-                    }
-
-                    Bitmap contactImage = getContactImage(mContext, resolver, name, number);
-
-                    CallLogItem item =
-                            new CallLogItem(name, secondaryText.toString(), number, contactImage);
-                    mItems.add(item);
-
-                    // Since we deduplicated count rows, we can move all the way to that row so the
-                    // next iteration takes us to the row following the last duplicate row.
-                    if (count > 1) {
-                        mCursor.moveToPosition(position + count - 1);
-                    }
-                }
-            }
-        } finally {
-            if (mCursor != null) {
-                mCursor.close();
-            }
-        }
-        return null;
-    }
-
-    @Override
-    protected void onPostExecute(Void aVoid) {
-        mListener.onLoadComplete(mItems);
-    }
-
-    /**
-     * Determines if the specified number is actually a URI
-     * (i.e. a SIP address) rather than a regular PSTN phone number,
-     * based on whether or not the number contains an "@" character.
-     *
-     * @return true if number contains @
-     *
-     * from android.telephony.PhoneNumberUtils
-     */
-    public static boolean isUriNumber(String number) {
-        // Note we allow either "@" or "%40" to indicate a URI, in case
-        // the passed-in string is URI-escaped.  (Neither "@" nor "%40"
-        // will ever be found in a legal PSTN number.)
-        return number != null && (number.contains("@") || number.contains("%40"));
-    }
-
-    private static boolean equalNumbers(String number1, String number2) {
-        if (isUriNumber(number1) || isUriNumber(number2)) {
-            return compareSipAddresses(number1, number2);
-        } else {
-            return PhoneNumberUtils.compare(number1, number2);
-        }
-    }
-
-    private static boolean compareSipAddresses(String number1, String number2) {
-        if (number1 == null || number2 == null) {
-            return number1 == null && number2 == null;
-        }
-
-        String[] address1 = splitSipAddress(number1);
-        String[] address2 = splitSipAddress(number2);
-
-        return address1[0].equals(address2[0]) && address1[1].equals(address2[1]);
-    }
-
-    /**
-     * Splits a sip address on either side of the @ sign and returns both halves.
-     * If there is no @ sign, user info will be number and rest will be empty string
-     * @param number the sip number to split
-     * @return a string array of size 2. Element 0 is the user info (left side of @ sign) and
-     *         element 1 is the rest (right side of @ sign).
-     */
-    private static String[] splitSipAddress(String number) {
-        String[] values = new String[2];
-        int index = number.indexOf('@');
-        if (index == -1) {
-            values[0] = number;
-            values[1] = "";
-        } else {
-            values[0] = number.substring(0, index);
-            values[1] = number.substring(index);
-        }
-        return values;
-    }
-}
diff --git a/src/com/android/car/dialer/CallLogViewHolder.java b/src/com/android/car/dialer/CallLogViewHolder.java
index c4fd687..fa575ae 100644
--- a/src/com/android/car/dialer/CallLogViewHolder.java
+++ b/src/com/android/car/dialer/CallLogViewHolder.java
@@ -15,26 +15,40 @@
  */
 package com.android.car.dialer;
 
+import android.support.v7.widget.RecyclerView;
 import android.view.View;
 import android.view.ViewGroup;
+import android.widget.FrameLayout;
 import android.widget.ImageView;
 import android.widget.LinearLayout;
-import com.android.car.view.CarListItemViewHolder;
+import android.widget.TextView;
 
-public class CallLogViewHolder extends CarListItemViewHolder {
-    public View card;
-    public ViewGroup container;
-    public LinearLayout callType;
-    public CallTypeIconsView callTypeIconsView;
-    public ImageView smallIcon;
+/**
+ * A {@link android.support.v7.widget.RecyclerView.ViewHolder} that will hold layouts that
+ * are inflated by {@link StrequentsAdapter}.
+ */
+public class CallLogViewHolder extends RecyclerView.ViewHolder {
+    public final FrameLayout iconContainer;
+    public final ImageView icon;
+    public final TextView title;
+    public final TextView text;
+    public final View card;
+    public final ViewGroup container;
+    public final LinearLayout callType;
+    public final CallTypeIconsView callTypeIconsView;
+    public final ImageView smallIcon;
 
     public CallLogViewHolder(View v) {
-        super(v, R.layout.car_textview);
+        super(v);
 
+        icon = v.findViewById(R.id.icon);
+        iconContainer = v.findViewById(R.id.icon_container);
+        title = v.findViewById(R.id.title);
+        text = v.findViewById(R.id.text);
         card = v.findViewById(R.id.call_log_card);
-        callType = (LinearLayout) v.findViewById(R.id.call_type);
-        callTypeIconsView = (CallTypeIconsView) v.findViewById(R.id.call_type_icons);
-        smallIcon = (ImageView) v.findViewById(R.id.small_icon);
-        container = (ViewGroup) v.findViewById(R.id.container);
+        callType = v.findViewById(R.id.call_type);
+        callTypeIconsView = v.findViewById(R.id.call_type_icons);
+        smallIcon = v.findViewById(R.id.small_icon);
+        container = v.findViewById(R.id.container);
     }
 }
diff --git a/src/com/android/car/dialer/ContactDetailsFragment.java b/src/com/android/car/dialer/ContactDetailsFragment.java
index 9470c19..bb3b1b5 100644
--- a/src/com/android/car/dialer/ContactDetailsFragment.java
+++ b/src/com/android/car/dialer/ContactDetailsFragment.java
@@ -15,17 +15,17 @@
  */
 package com.android.car.dialer;
 
-import android.app.Fragment;
-import android.app.LoaderManager;
-import android.content.CursorLoader;
 import android.content.Intent;
-import android.content.Loader;
 import android.database.Cursor;
 import android.net.Uri;
 import android.os.Bundle;
 import android.provider.ContactsContract;
 import android.support.annotation.ColorInt;
 import android.support.annotation.Nullable;
+import android.support.v4.app.Fragment;
+import android.support.v4.app.LoaderManager;
+import android.support.v4.content.CursorLoader;
+import android.support.v4.content.Loader;
 import android.support.v7.widget.RecyclerView;
 import android.util.Log;
 import android.util.Pair;
@@ -36,11 +36,14 @@
 import android.widget.TextView;
 
 import com.android.car.dialer.telecom.TelecomUtils;
-import com.android.car.view.PagedListView;
 
 import java.util.ArrayList;
 import java.util.List;
 
+import androidx.car.utils.ListItemBackgroundResolver;
+import androidx.car.widget.DayNightStyle;
+import androidx.car.widget.PagedListView;
+
 /**
  * A fragment that shows the name of the contact, the photo and all listed phone numbers. It is
  * primarily used to respond to the results of search queries but supplyig it with the content://
@@ -57,10 +60,10 @@
     private static final String KEY_URI = "uri";
 
     private static final String[] CONTACT_DETAILS_PROJECTION = {
-        ContactsContract.Contacts._ID,
-        ContactsContract.Contacts.DISPLAY_NAME,
-        ContactsContract.Contacts.PHOTO_URI,
-        ContactsContract.Contacts.HAS_PHONE_NUMBER
+            ContactsContract.Contacts._ID,
+            ContactsContract.Contacts.DISPLAY_NAME,
+            ContactsContract.Contacts.PHOTO_URI,
+            ContactsContract.Contacts.HAS_PHONE_NUMBER
     };
 
     private PagedListView mListView;
@@ -69,7 +72,9 @@
     public static ContactDetailsFragment newInstance(Uri uri,
             @Nullable RecyclerView.OnScrollListener listener) {
         ContactDetailsFragment fragment = new ContactDetailsFragment();
-        fragment.addOnScrollListener(listener);
+        if (listener != null) {
+            fragment.addOnScrollListener(listener);
+        }
 
         Bundle args = new Bundle();
         args.putParcelable(KEY_URI, uri);
@@ -87,7 +92,7 @@
     @Override
     public void onViewCreated(View view, Bundle savedInstanceState) {
         mListView = view.findViewById(R.id.list_view);
-        mListView.setLightMode();
+        mListView.setDayNightStyle(DayNightStyle.ALWAYS_LIGHT);
 
         RecyclerView recyclerView = mListView.getRecyclerView();
         for (RecyclerView.OnScrollListener listener : mOnScrollListeners) {
@@ -153,7 +158,8 @@
     }
 
     @Override
-    public void onLoaderReset(Loader loader) {  }
+    public void onLoaderReset(Loader loader) {
+    }
 
     private boolean vdebug() {
         return Log.isLoggable(TAG, Log.DEBUG);
@@ -164,7 +170,8 @@
         public ImageView leftIcon;
         public TextView title;
         public TextView text;
-        public ImageView rightIcon;
+        public ImageView avatar;
+        public View divier;
 
         public ContactDetailViewHolder(View v) {
             super(v);
@@ -172,7 +179,8 @@
             leftIcon = v.findViewById(R.id.icon);
             title = v.findViewById(R.id.title);
             text = v.findViewById(R.id.text);
-            rightIcon = v.findViewById(R.id.right_icon);
+            avatar = v.findViewById(R.id.avatar);
+            divier = v.findViewById(R.id.divider);
         }
     }
 
@@ -183,7 +191,8 @@
         private static final int ID_CONTENT = 2;
 
         private final String mContactName;
-        @ColorInt private int mIconTint;
+        @ColorInt
+        private int mIconTint;
 
         private List<Pair<String, String>> mPhoneNumbers = new ArrayList<>();
 
@@ -204,7 +213,8 @@
             }
 
             // Fetch the phone number from the contacts db using another loader.
-            getLoaderManager().initLoader(PHONE_LOADER_QUERY_ID, null,
+            LoaderManager.getInstance(ContactDetailsFragment.this).initLoader(PHONE_LOADER_QUERY_ID,
+                    null,
                     new LoaderManager.LoaderCallbacks<Cursor>() {
                         @Override
                         public Loader<Cursor> onCreateLoader(int id, Bundle args) {
@@ -212,7 +222,7 @@
                                     ContactsContract.CommonDataKinds.Phone.CONTENT_URI,
                                     null, /* All columns **/
                                     ContactsContract.CommonDataKinds.Phone.CONTACT_ID + " = ?",
-                                    new String[] { contactId },
+                                    new String[]{contactId},
                                     null /* sortOrder */);
                         }
 
@@ -245,35 +255,11 @@
                             notifyDataSetChanged();
                         }
 
-                        public void onLoaderReset(Loader loader) {  }
+                        public void onLoaderReset(Loader loader) {
+                        }
                     });
         }
 
-        /**
-         * Appropriately sets the background for the View that is being bound. This method will
-         * allow for rounded corners on either the top or bottom of a card.
-         */
-        private void setBackground(ContactDetailViewHolder viewHolder) {
-            int itemCount = getItemCount();
-            int adapterPosition = viewHolder.getAdapterPosition();
-
-            if (itemCount == 1) {
-                // Only element - all corners are rounded
-                viewHolder.card.setBackgroundResource(
-                        R.drawable.car_card_rounded_top_bottom_background);
-            } else if (adapterPosition == 0) {
-                // First element gets rounded top
-                viewHolder.card.setBackgroundResource(R.drawable.car_card_rounded_top_background);
-            } else if (adapterPosition == itemCount - 1) {
-                // Last one has a rounded bottom
-                viewHolder.card.setBackgroundResource(
-                        R.drawable.car_card_rounded_bottom_background);
-            } else {
-                // Middle have no rounded corners
-                viewHolder.card.setBackgroundResource(R.color.car_card);
-            }
-        }
-
         @Override
         public int getItemViewType(int position) {
             return position == 0 ? ID_HEADER : ID_CONTENT;
@@ -304,7 +290,8 @@
                     return null;
             }
 
-            View view = LayoutInflater.from(parent.getContext()).inflate(layoutResId, null);
+            View view = LayoutInflater.from(parent.getContext()).inflate(layoutResId, parent,
+                    false);
             return new ContactDetailViewHolder(view);
         }
 
@@ -315,7 +302,7 @@
                     viewHolder.title.setText(mContactName);
                     if (!mPhoneNumbers.isEmpty()) {
                         String firstNumber = mPhoneNumbers.get(0).second;
-                        TelecomUtils.setContactBitmapAsync(getContext(), viewHolder.rightIcon,
+                        TelecomUtils.setContactBitmapAsync(getContext(), viewHolder.avatar,
                                 mContactName, firstNumber);
                     }
                     // Just in case a viewholder object gets recycled.
@@ -323,8 +310,8 @@
                     break;
                 case ID_CONTENT:
                     Pair<String, String> data = mPhoneNumbers.get(position - 1);
-                    viewHolder.title.setText(data.first);  // Type.
-                    viewHolder.text.setText(data.second);  // Number.
+                    viewHolder.title.setText(data.second);  // Type.
+                    viewHolder.text.setText(data.first);  // Number.
                     viewHolder.leftIcon.setImageResource(R.drawable.ic_phone);
                     viewHolder.leftIcon.setColorFilter(mIconTint);
                     viewHolder.card.setOnClickListener(v -> {
@@ -337,7 +324,15 @@
                     Log.e(TAG, "Unknown view type " + viewHolder.getItemViewType());
                     return;
             }
-            setBackground(viewHolder);
+
+            if (position == (getItemCount() - 1)) {
+                // hide divider for last item.
+                viewHolder.divier.setVisibility(View.GONE);
+            } else {
+                viewHolder.divier.setVisibility(View.VISIBLE);
+            }
+            ListItemBackgroundResolver.setBackground(viewHolder.card,
+                    viewHolder.getAdapterPosition(), getItemCount());
         }
     }
 }
diff --git a/src/com/android/car/dialer/ContactEntry.java b/src/com/android/car/dialer/ContactEntry.java
index 34db70f..27e4377 100644
--- a/src/com/android/car/dialer/ContactEntry.java
+++ b/src/com/android/car/dialer/ContactEntry.java
@@ -20,43 +20,108 @@
 import android.provider.ContactsContract;
 import android.support.annotation.Nullable;
 import android.text.TextUtils;
+import android.util.Log;
+
 import com.android.car.dialer.telecom.PhoneLoader;
 import com.android.car.dialer.telecom.TelecomUtils;
 
 /**
  * Encapsulates data about a phone Contact entry. Typically loaded from the local Contact store.
  */
+// TODO: Refactor to use Builder design pattern.
 public class ContactEntry implements Comparable<ContactEntry> {
     private final Context mContext;
 
+    /**
+     * An unique primary key for searching an entry.
+     */
+    private int mId;
+
+    /**
+     * Whether this contact entry is starred by user.
+     */
+    private boolean mIsStarred;
+
+    /**
+     * Contact-specific information about whether or not a contact has been pinned by the user at
+     * a particular position within the system contact application's user interface.
+     */
+    private int mPinnedPosition;
+
+    /**
+     * Phone number.
+     */
+    private String mNumber;
+
+    /**
+     * The display name.
+     */
     @Nullable
-    public String name;
-    public String number;
-    public boolean isStarred;
-    public int pinnedPosition;
+    private String mDisplayName;
+
+    /**
+     * A URI that can be used to retrieve a thumbnail of the contact's photo.
+     */
+    private String mAvatarThumbnailUri;
+
+    /**
+     * A URI that can be used to retrieve the contact's full-size photo.
+     */
+    private String mAvatarUri;
+
+    /**
+     * An opaque value that contains hints on how to find the contact if its row id changed
+     * as a result of a sync or aggregation
+     */
+    private String mLookupKey;
+
+    /**
+     * The type of data, for example Home or Work.
+     */
+    private int mType;
+
+    /**
+     * The user defined label for the the contact method.
+     */
+    private String mLabel;
 
     /**
      * Parses a Contact entry for a Cursor loaded from the OS Strequents DB.
      */
     public static ContactEntry fromCursor(Cursor cursor, Context context) {
-        int nameColumn = cursor.getColumnIndex(ContactsContract.Contacts.DISPLAY_NAME);
+        int idColumnIndex = PhoneLoader.getIdColumnIndex(cursor);
         int starredColumn = cursor.getColumnIndex(ContactsContract.Contacts.STARRED);
         int pinnedColumn = cursor.getColumnIndex("pinned");
+        int displayNameColumnIndex = cursor.getColumnIndex(ContactsContract.Contacts.DISPLAY_NAME);
+        int avatarUriColumnIndex = cursor.getColumnIndex(ContactsContract.Contacts.PHOTO_URI);
+        int avatarThumbnailColumnIndex = cursor.getColumnIndex(
+                ContactsContract.Contacts.PHOTO_THUMBNAIL_URI);
+        int lookupKeyColumnIndex = cursor.getColumnIndex(ContactsContract.Contacts.LOOKUP_KEY);
+        int typeColumnIndex = cursor.getColumnIndex(ContactsContract.CommonDataKinds.Phone.DATA2);
+        int labelColumnIndex = cursor.getColumnIndex(ContactsContract.CommonDataKinds.Phone.DATA3);
 
-        String name = cursor.getString(nameColumn);
+        String name = cursor.getString(displayNameColumnIndex);
         String number = PhoneLoader.getPhoneNumber(cursor, context.getContentResolver());
         int starred = cursor.getInt(starredColumn);
         int pinnedPosition = cursor.getInt(pinnedColumn);
-        return new ContactEntry(context, name, number, starred > 0, pinnedPosition);
+        ContactEntry contactEntry = new ContactEntry(context, name, number, starred > 0,
+                pinnedPosition);
+        contactEntry.setId(cursor.getInt(idColumnIndex));
+        contactEntry.setAvatarUri(cursor.getString(avatarUriColumnIndex));
+        contactEntry.setAvatarThumbnailUri(cursor.getString(avatarThumbnailColumnIndex));
+        contactEntry.setLookupKey(cursor.getString(lookupKeyColumnIndex));
+        contactEntry.setType(cursor.getInt(typeColumnIndex));
+        contactEntry.setLabel(cursor.getString(labelColumnIndex));
+        return contactEntry;
     }
 
     public ContactEntry(
             Context context, String name, String number, boolean isStarred, int pinnedPosition) {
         mContext = context;
-        this.name = name;
-        this.number = number;
-        this.isStarred = isStarred;
-        this.pinnedPosition = pinnedPosition;
+        this.mDisplayName = name;
+        this.mNumber = number;
+        this.mIsStarred = isStarred;
+        this.mPinnedPosition = pinnedPosition;
     }
 
     /**
@@ -64,13 +129,13 @@
      * It takes into account the number associated with a name for fail cases.
      */
     public String getDisplayName() {
-        if (!TextUtils.isEmpty(name)) {
-            return name;
+        if (!TextUtils.isEmpty(mDisplayName)) {
+            return mDisplayName;
         }
         if (isVoicemail()) {
             return mContext.getResources().getString(R.string.voicemail);
         } else {
-            String displayName = TelecomUtils.getFormattedNumber(mContext, number);
+            String displayName = TelecomUtils.getFormattedNumber(mContext, mNumber);
             if (TextUtils.isEmpty(displayName)) {
                 displayName = mContext.getString(R.string.unknown);
             }
@@ -79,23 +144,23 @@
     }
 
     public boolean isVoicemail() {
-        return number.equals(TelecomUtils.getVoicemailNumber(mContext));
+        return mNumber.equals(TelecomUtils.getVoicemailNumber(mContext));
     }
 
     @Override
     public int compareTo(ContactEntry strequentContactEntry) {
-        if (isStarred == strequentContactEntry.isStarred) {
-            if (pinnedPosition == strequentContactEntry.pinnedPosition) {
-                if (name == strequentContactEntry.name) {
-                    return compare(number, strequentContactEntry.number);
+        if (mIsStarred == strequentContactEntry.mIsStarred) {
+            if (mPinnedPosition == strequentContactEntry.mPinnedPosition) {
+                if (mDisplayName == strequentContactEntry.mDisplayName) {
+                    return compare(mNumber, strequentContactEntry.mNumber);
                 }
-                return compare(name, strequentContactEntry.name);
+                return compare(mDisplayName, strequentContactEntry.mDisplayName);
             } else {
-                if (pinnedPosition > 0 && strequentContactEntry.pinnedPosition > 0) {
-                    return pinnedPosition - strequentContactEntry.pinnedPosition;
+                if (mPinnedPosition > 0 && strequentContactEntry.mPinnedPosition > 0) {
+                    return mPinnedPosition - strequentContactEntry.mPinnedPosition;
                 }
 
-                if (pinnedPosition > 0) {
+                if (mPinnedPosition > 0) {
                     return -1;
                 }
 
@@ -103,7 +168,7 @@
             }
         }
 
-        if (isStarred) {
+        if (mIsStarred) {
             return -1;
         }
 
@@ -114,10 +179,10 @@
     public boolean equals(Object obj) {
         if (obj instanceof ContactEntry) {
             ContactEntry other = (ContactEntry) obj;
-            if (compare(name, other.name) == 0
-                    && compare(number, other.number) == 0
-                    && isStarred == other.isStarred
-                    && pinnedPosition == other.pinnedPosition) {
+            if (compare(mDisplayName, other.mDisplayName) == 0
+                    && compare(mNumber, other.mNumber) == 0
+                    && mIsStarred == other.mIsStarred
+                    && mPinnedPosition == other.mPinnedPosition) {
                 return true;
             }
         }
@@ -127,10 +192,10 @@
     @Override
     public int hashCode() {
         int result = 17;
-        result = 31 * result + (isStarred ? 1 : 0);
-        result = 31 * result + pinnedPosition;
-        result = 31 * result + (name == null ? 0 : name.hashCode());
-        result = 31 * result + (number == null ? 0 : number.hashCode());
+        result = 31 * result + (mIsStarred ? 1 : 0);
+        result = 31 * result + mPinnedPosition;
+        result = 31 * result + (mDisplayName == null ? 0 : mDisplayName.hashCode());
+        result = 31 * result + (mNumber == null ? 0 : mNumber.hashCode());
         return result;
     }
 
@@ -145,4 +210,65 @@
 
         return one.compareTo(two);
     }
+
+    public int getId() {
+        return mId;
+    }
+
+    private void setId(int id) {
+        mId = id;
+    }
+
+    public String getAvatarUri() {
+        return mAvatarUri;
+    }
+
+    private void setAvatarUri(String avatarUri) {
+        mAvatarUri = avatarUri;
+    }
+
+    public String getLookupKey() {
+        return mLookupKey;
+    }
+
+    private void setLookupKey(String lookupKey) {
+        mLookupKey = lookupKey;
+    }
+
+    public int getType() {
+        return mType;
+    }
+
+    private void setType(int type) {
+        mType = type;
+    }
+
+    public String getLabel() {
+        return mLabel;
+    }
+
+    private void setLabel(String label) {
+        mLabel = label;
+    }
+
+    public String getAvatarThumbnailUri() {
+        return mAvatarThumbnailUri;
+    }
+
+    private void setAvatarThumbnailUri(String avatarThumbnailUri) {
+        mAvatarThumbnailUri = avatarThumbnailUri;
+    }
+
+    public String getNumber() {
+        return mNumber;
+    }
+
+    public boolean isStarred() {
+        return mIsStarred;
+    }
+
+    public int getPinnedPosition() {
+        return mPinnedPosition;
+    }
+
 }
diff --git a/src/com/android/car/dialer/ContactResultViewHolder.java b/src/com/android/car/dialer/ContactResultViewHolder.java
index df8e2df..00766e1 100644
--- a/src/com/android/car/dialer/ContactResultViewHolder.java
+++ b/src/com/android/car/dialer/ContactResultViewHolder.java
@@ -27,8 +27,10 @@
 import android.widget.ImageView;
 import android.widget.TextView;
 
-import com.android.car.apps.common.CircleBitmapDrawable;
+import androidx.car.utils.ListItemBackgroundResolver;
+
 import com.android.car.apps.common.LetterTileDrawable;
+import com.android.car.dialer.ui.CircleBitmapDrawable;
 
 import java.io.FileNotFoundException;
 import java.io.InputStream;
@@ -56,7 +58,7 @@
      * provided {@link ContactDetails}.
      */
     public void bind(ContactDetails details, int itemCount) {
-        updateBackground(itemCount);
+        ListItemBackgroundResolver.setBackground(mContactCard, getAdapterPosition(), itemCount);
 
         mContactCard.setOnClickListener(v -> {
             Intent intent = new Intent();
@@ -95,32 +97,6 @@
     }
 
     /**
-     * Sets the appropriate background on the card containing the preset information. The cards
-     * need to have rounded corners depending on its position in the list and the number of items
-     * in the list.
-     */
-    private void updateBackground(int itemCount) {
-        int position = getAdapterPosition();
-
-        // Correctly set the background for each card. Only the top and last card should
-        // have rounded corners.
-        if (itemCount == 1) {
-            // One card - all corners are rounded
-            mContactCard.setBackgroundResource(
-                    R.drawable.car_card_rounded_top_bottom_background);
-        } else if (position == 0) {
-            // First card gets rounded top
-            mContactCard.setBackgroundResource(R.drawable.car_card_rounded_top_background);
-        } else if (position == itemCount - 1) {
-            // Last one has a rounded bottom
-            mContactCard.setBackgroundResource(R.drawable.car_card_rounded_bottom_background);
-        } else {
-            // Middle has no rounded corners
-            mContactCard.setBackgroundResource(R.color.car_card);
-        }
-    }
-
-    /**
      * Retrieves the picture that is specified by the given {@link Uri}.
      */
     @Nullable
diff --git a/src/com/android/car/dialer/ContactResultsAdapter.java b/src/com/android/car/dialer/ContactResultsAdapter.java
index d637f9d..07c6351 100644
--- a/src/com/android/car/dialer/ContactResultsAdapter.java
+++ b/src/com/android/car/dialer/ContactResultsAdapter.java
@@ -24,11 +24,11 @@
 import android.view.View;
 import android.view.ViewGroup;
 
-import com.android.car.view.PagedListView;
-
 import java.util.ArrayList;
 import java.util.List;
 
+import androidx.car.widget.PagedListView;
+
 /**
  *  An adapter that will parse a list of contacts given by a {@link Cursor} that display the
  *  results as a list.
diff --git a/src/com/android/car/dialer/ContactResultsFragment.java b/src/com/android/car/dialer/ContactResultsFragment.java
index 062c8b2..417581d 100644
--- a/src/com/android/car/dialer/ContactResultsFragment.java
+++ b/src/com/android/car/dialer/ContactResultsFragment.java
@@ -16,14 +16,14 @@
 
 package com.android.car.dialer;
 
-import android.app.Fragment;
-import android.app.LoaderManager;
-import android.content.CursorLoader;
-import android.content.Loader;
 import android.database.Cursor;
 import android.os.Bundle;
 import android.provider.ContactsContract.Contacts;
 import android.support.annotation.Nullable;
+import android.support.v4.app.Fragment;
+import android.support.v4.app.LoaderManager;
+import android.support.v4.content.CursorLoader;
+import android.support.v4.content.Loader;
 import android.support.v7.widget.RecyclerView;
 import android.text.TextUtils;
 import android.util.Log;
@@ -32,11 +32,12 @@
 import android.view.ViewGroup;
 import android.net.Uri;
 
-import com.android.car.view.PagedListView;
-
 import java.util.ArrayList;
 import java.util.List;
 
+import androidx.car.widget.DayNightStyle;
+import androidx.car.widget.PagedListView;
+
 /**
  * A fragment that will take a search query, look up contacts that match and display those
  * results as a list.
@@ -79,9 +80,8 @@
     @Override
     public void onViewCreated(View view, Bundle savedInstanceState) {
         mContactResultList = view.findViewById(R.id.contact_result_list);
-        mContactResultList.setLightMode();
+        mContactResultList.setDayNightStyle(DayNightStyle.ALWAYS_LIGHT);
         mContactResultList.setAdapter(mAdapter);
-        mContactResultList.getLayoutManager().setOffsetRows(false);
 
         RecyclerView recyclerView = mContactResultList.getRecyclerView();
         for (RecyclerView.OnScrollListener listener : mOnScrollListeners) {
@@ -124,7 +124,7 @@
         if (!TextUtils.isEmpty(mSearchQuery)) {
             // Calling restartLoader so that the loader is always re-created with the new
             // search query.
-            getLoaderManager().restartLoader(0, null /* args */, this /* callback */);
+            LoaderManager.getInstance(this).restartLoader(0, null /* args */, this /* callback */);
         }
     }
 
@@ -161,7 +161,8 @@
     }
 
     @Override
-    public void onLoaderReset(Loader<Cursor> loader) {}
+    public void onLoaderReset(Loader<Cursor> loader) {
+    }
 
     @Override
     public void onDestroy() {
@@ -173,8 +174,9 @@
     /**
      * Creates a new instance of the {@link ContactResultsFragment}.
      *
-     * @param listener A scroll listener that will be notified when the list of search results has
-     *                 been scrolled.
+     * @param listener           A scroll listener that will be notified when the list of search
+     *                           results has
+     *                           been scrolled.
      * @param initialSearchQuery An optional search query that will be inputted when the fragment
      *                           starts up.
      */
diff --git a/src/com/android/car/dialer/ContactSearchActivity.java b/src/com/android/car/dialer/ContactSearchActivity.java
index 30a9cd7..03243f3 100644
--- a/src/com/android/car/dialer/ContactSearchActivity.java
+++ b/src/com/android/car/dialer/ContactSearchActivity.java
@@ -18,13 +18,15 @@
 
 import android.animation.ValueAnimator;
 import android.app.Activity;
-import android.app.Fragment;
 import android.app.SearchManager;
 import android.content.Intent;
 import android.net.Uri;
 import android.os.Bundle;
 import android.os.Handler;
 import android.support.annotation.Nullable;
+import android.support.v4.app.Fragment;
+import android.support.v4.app.FragmentActivity;
+import android.support.v7.widget.LinearLayoutManager;
 import android.support.v7.widget.RecyclerView;
 import android.text.Editable;
 import android.text.TextWatcher;
@@ -32,13 +34,11 @@
 import android.view.inputmethod.InputMethodManager;
 import android.widget.EditText;
 
-import com.android.car.view.CarLayoutManager;
-
 /**
  * An activity that manages contact searching. This activity will display the result of a search
  * as well as show the details of a contact when that contact is clicked.
  */
-public class ContactSearchActivity extends Activity {
+public class ContactSearchActivity extends FragmentActivity {
     private static final String CONTENT_FRAGMENT_TAG = "CONTENT_FRAGMENT_TAG";
     private static final int ANIMATION_DURATION_MS = 100;
 
@@ -76,10 +76,12 @@
 
         mSearchField.addTextChangedListener(new TextWatcher() {
             @Override
-            public void beforeTextChanged(CharSequence s, int start, int count, int after) {}
+            public void beforeTextChanged(CharSequence s, int start, int count, int after) {
+            }
 
             @Override
-            public void onTextChanged(CharSequence s, int start, int before, int count) {}
+            public void onTextChanged(CharSequence s, int start, int before, int count) {
+            }
 
             @Override
             public void afterTextChanged(Editable s) {
@@ -187,7 +189,7 @@
         // changes since any lists in it will be reset to the top.
         resetSearchPanelElevation();
 
-        getFragmentManager().beginTransaction()
+        getSupportFragmentManager().beginTransaction()
                 .setCustomAnimations(R.animator.fade_in, R.animator.fade_out)
                 .replace(R.id.content_fragment_container, fragment, CONTENT_FRAGMENT_TAG)
                 .commitNow();
@@ -198,7 +200,7 @@
      */
     @Nullable
     private Fragment getCurrentFragment() {
-        return getFragmentManager().findFragmentByTag(CONTENT_FRAGMENT_TAG);
+        return getSupportFragmentManager().findFragmentByTag(CONTENT_FRAGMENT_TAG);
     }
 
     @Override
@@ -254,11 +256,12 @@
     public class ContactScrollListener extends RecyclerView.OnScrollListener {
         @Override
         public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
-            // Assuming CarLayoutManager is the layout manager as all car applications should be
-            // using a PagedListView.
-            CarLayoutManager layoutManager = (CarLayoutManager) recyclerView.getLayoutManager();
+            // The default LayoutManager for PagedListView is a LinearLayoutManager. Dialer does
+            // not change this.
+            LinearLayoutManager layoutManager =
+                    (LinearLayoutManager) recyclerView.getLayoutManager();
 
-            if (layoutManager.isAtTop()) {
+            if (layoutManager.findFirstCompletelyVisibleItemPosition() == 0) {
                 resetSearchPanelElevation();
             } else {
                 // No animation needed when adding the elevation because the scroll masks the adding
diff --git a/src/com/android/car/dialer/DialerFragment.java b/src/com/android/car/dialer/DialerFragment.java
index 642bf19..86bd97f 100644
--- a/src/com/android/car/dialer/DialerFragment.java
+++ b/src/com/android/car/dialer/DialerFragment.java
@@ -15,102 +15,37 @@
  */
 package com.android.car.dialer;
 
-import android.content.Context;
-import android.media.AudioManager;
-import android.media.ToneGenerator;
 import android.os.Bundle;
 import android.support.annotation.Nullable;
 import android.support.v4.app.Fragment;
 import android.text.TextUtils;
-import android.util.Log;
-import android.util.SparseArray;
-import android.util.SparseIntArray;
-import android.view.KeyEvent;
 import android.view.LayoutInflater;
 import android.view.View;
 import android.view.ViewGroup;
-import android.widget.TextView;
 
-import com.android.car.apps.common.FabDrawable;
-import com.android.car.dialer.telecom.TelecomUtils;
+import com.android.car.dialer.log.L;
 import com.android.car.dialer.telecom.UiCallManager;
-import com.android.car.dialer.telecom.UiCallManager.CallListener;
+import com.android.car.dialer.ui.DialerInfoController;
+import com.android.car.dialer.ui.DialpadFragment;
 
 /**
  * Fragment that controls the dialpad.
  */
-public class DialerFragment extends Fragment {
+public class DialerFragment extends Fragment implements DialpadFragment.DialpadCallback {
     private static final String TAG = "Em.DialerFragment";
-    private static final String INPUT_ACTIVE_KEY = "INPUT_ACTIVE_KEY";
+
     private static final String DIAL_NUMBER_KEY = "DIAL_NUMBER_KEY";
+    private static final String PLUS_DIGIT = "+";
 
-    private static final int TONE_LENGTH_MS = 150;
-    private static final int TONE_RELATIVE_VOLUME = 80;
-    private static final int MAX_DIAL_NUMBER = 20;
-
-    private static final SparseIntArray mToneMap = new SparseIntArray();
-    private static final SparseArray<String> mDialValueMap = new SparseArray<>();
-
-    static {
-        mToneMap.put(KeyEvent.KEYCODE_1, ToneGenerator.TONE_DTMF_1);
-        mToneMap.put(KeyEvent.KEYCODE_2, ToneGenerator.TONE_DTMF_2);
-        mToneMap.put(KeyEvent.KEYCODE_3, ToneGenerator.TONE_DTMF_3);
-        mToneMap.put(KeyEvent.KEYCODE_4, ToneGenerator.TONE_DTMF_4);
-        mToneMap.put(KeyEvent.KEYCODE_5, ToneGenerator.TONE_DTMF_5);
-        mToneMap.put(KeyEvent.KEYCODE_6, ToneGenerator.TONE_DTMF_6);
-        mToneMap.put(KeyEvent.KEYCODE_7, ToneGenerator.TONE_DTMF_7);
-        mToneMap.put(KeyEvent.KEYCODE_8, ToneGenerator.TONE_DTMF_8);
-        mToneMap.put(KeyEvent.KEYCODE_9, ToneGenerator.TONE_DTMF_9);
-        mToneMap.put(KeyEvent.KEYCODE_0, ToneGenerator.TONE_DTMF_0);
-        mToneMap.put(KeyEvent.KEYCODE_STAR, ToneGenerator.TONE_DTMF_S);
-        mToneMap.put(KeyEvent.KEYCODE_POUND, ToneGenerator.TONE_DTMF_P);
-
-        mDialValueMap.put(KeyEvent.KEYCODE_1, "1");
-        mDialValueMap.put(KeyEvent.KEYCODE_2, "2");
-        mDialValueMap.put(KeyEvent.KEYCODE_3, "3");
-        mDialValueMap.put(KeyEvent.KEYCODE_4, "4");
-        mDialValueMap.put(KeyEvent.KEYCODE_5, "5");
-        mDialValueMap.put(KeyEvent.KEYCODE_6, "6");
-        mDialValueMap.put(KeyEvent.KEYCODE_7, "7");
-        mDialValueMap.put(KeyEvent.KEYCODE_8, "8");
-        mDialValueMap.put(KeyEvent.KEYCODE_9, "9");
-        mDialValueMap.put(KeyEvent.KEYCODE_0, "0");
-        mDialValueMap.put(KeyEvent.KEYCODE_STAR, "*");
-        mDialValueMap.put(KeyEvent.KEYCODE_POUND, "#");
-    }
-
-    private Context mContext;
-    private UiCallManager mUiCallManager;
-    private final StringBuffer mNumber = new StringBuffer(MAX_DIAL_NUMBER);
-    private ToneGenerator mToneGenerator;
-    private final Object mToneGeneratorLock = new Object();
-    private TextView mNumberView;
-    private boolean mShowInput = true;
-    private Runnable mPendingRunnable;
-
-    private DialerBackButtonListener mBackListener;
-
-    /**
-     * Interface for a class that will be notified when the back button of the dialer has been
-     * clicked.
-     */
-    public interface DialerBackButtonListener {
-        /**
-         * Called when the back button has been clicked on the dialer. This action should dismiss
-         * the dialer fragment.
-         */
-        void onDialerBackClick();
-    }
+    private DialerInfoController mDialerInfoController;
+    private L logger = L.logger(TAG);
 
     /**
      * Creates a new instance of the {@link DialerFragment} and display the given number as the one
      * to dial.
      */
-    static DialerFragment newInstance(UiCallManager callManager,
-            DialerBackButtonListener listener, @Nullable String dialNumber) {
+    static DialerFragment newInstance(@Nullable String dialNumber) {
         DialerFragment fragment = new DialerFragment();
-        fragment.mUiCallManager = callManager;
-        fragment.mBackListener = listener;
 
         if (!TextUtils.isEmpty(dialNumber)) {
             Bundle args = new Bundle();
@@ -122,211 +57,36 @@
     }
 
     @Override
-    public void onCreate(Bundle savedInstanceState) {
-        super.onCreate(savedInstanceState);
-        if (savedInstanceState != null && savedInstanceState.containsKey(INPUT_ACTIVE_KEY)) {
-            mShowInput = savedInstanceState.getBoolean(INPUT_ACTIVE_KEY);
-        }
-
-        Bundle args = getArguments();
-        if (args != null) {
-            setDialNumber(args.getString(DIAL_NUMBER_KEY));
-        }
-    }
-
-    @Override
     public View onCreateView(LayoutInflater inflater, ViewGroup container,
             Bundle savedInstanceState) {
-        if (Log.isLoggable(TAG, Log.DEBUG)) {
-            Log.d(TAG, "onCreateView");
-        }
-
-        mContext = getContext();
+        logger.d("onCreateView");
         View view = inflater.inflate(R.layout.dialer_fragment, container, false);
 
-        if (Log.isLoggable(TAG, Log.VERBOSE)) {
-            Log.v(TAG, "onCreateView: inflated successfully");
+        Fragment dialpadFragment = DialpadFragment.newInstance();
+        getChildFragmentManager().beginTransaction()
+                .replace(R.id.dialpad_fragment_container, dialpadFragment)
+                .commit();
+
+        View dialerInfoContainer = view.findViewById(R.id.dialer_info_fragment_container);
+        mDialerInfoController = new DialerInfoController(getContext(), dialerInfoContainer);
+
+        if (getArguments() != null) {
+            mDialerInfoController.appendDialedNumber(getArguments().getString(DIAL_NUMBER_KEY));
         }
 
-        view.findViewById(R.id.exit_dialer_button).setOnClickListener(v -> {
-            if (mBackListener != null) {
-                mBackListener.onDialerBackClick();
-            }
-        });
-
-        mNumberView = (TextView) view.findViewById(R.id.number);
-
-        if (Log.isLoggable(TAG, Log.VERBOSE)) {
-            Log.v(TAG, "mShowInput: " + mShowInput);
-        }
-
-        FabDrawable answerCallDrawable = new FabDrawable(mContext);
-        answerCallDrawable.setFabAndStrokeColor(getContext().getColor(R.color.phone_call));
-
-        View callButton = view.findViewById(R.id.call);
-        callButton.setBackground(answerCallDrawable);
-        callButton.setVisibility(View.VISIBLE);
-        callButton.setOnClickListener((unusedView) -> {
-            if (Log.isLoggable(TAG, Log.DEBUG)) {
-                Log.d(TAG, "Call button clicked, placing a call: " + mNumber.toString());
-            }
-
-            if (!TextUtils.isEmpty(mNumber.toString())) {
-                mUiCallManager.safePlaceCall(mNumber.toString(), false);
-            }
-        });
-
-        View deleteButton = view.findViewById(R.id.delete);
-        deleteButton.setVisibility(View.VISIBLE);
-        deleteButton.setOnClickListener(v -> {
-            if (mNumber.length() != 0) {
-                mNumber.deleteCharAt(mNumber.length() - 1);
-                mNumberView.setText(getFormattedNumber(mNumber.toString()));
-            }
-        });
-
-        setupKeypadClickListeners(view);
-
         return view;
     }
 
-    /**
-     * The default click listener for all dialpad buttons. This click listener will append its
-     * associated value to {@link #mNumber}.
-     */
-    private class DialpadClickListener implements View.OnClickListener {
-        private final int mTone;
-        private final String mValue;
-
-        DialpadClickListener(int keyCode) {
-            mTone = mToneMap.get(keyCode);
-            mValue = mDialValueMap.get(keyCode);
-        }
-
-        @Override
-        public void onClick(View v) {
-            mNumber.append(mValue);
-            mNumberView.setText(getFormattedNumber(mNumber.toString()));
-            playTone(mTone);
-        }
-    }
-
-    private void setupKeypadClickListeners(View parent) {
-        parent.findViewById(R.id.zero).setOnClickListener(
-                new DialpadClickListener(KeyEvent.KEYCODE_0));
-        parent.findViewById(R.id.one).setOnClickListener(
-                new DialpadClickListener(KeyEvent.KEYCODE_1));
-        parent.findViewById(R.id.two).setOnClickListener(
-                new DialpadClickListener(KeyEvent.KEYCODE_2));
-        parent.findViewById(R.id.three).setOnClickListener(
-                new DialpadClickListener(KeyEvent.KEYCODE_3));
-        parent.findViewById(R.id.four).setOnClickListener(
-                new DialpadClickListener(KeyEvent.KEYCODE_4));
-        parent.findViewById(R.id.five).setOnClickListener(
-                new DialpadClickListener(KeyEvent.KEYCODE_5));
-        parent.findViewById(R.id.six).setOnClickListener(
-                new DialpadClickListener(KeyEvent.KEYCODE_6));
-        parent.findViewById(R.id.seven).setOnClickListener(
-                new DialpadClickListener(KeyEvent.KEYCODE_7));
-        parent.findViewById(R.id.eight).setOnClickListener(
-                new DialpadClickListener(KeyEvent.KEYCODE_8));
-        parent.findViewById(R.id.nine).setOnClickListener(
-                new DialpadClickListener(KeyEvent.KEYCODE_9));
-        parent.findViewById(R.id.star).setOnClickListener(
-                new DialpadClickListener(KeyEvent.KEYCODE_STAR));
-        parent.findViewById(R.id.pound).setOnClickListener(
-                new DialpadClickListener(KeyEvent.KEYCODE_POUND));
+    @Override
+    public void onDialVoiceMail() {
+        UiCallManager.get().callVoicemail();
     }
 
     @Override
-    public void onResume() {
-        super.onResume();
-        synchronized (mToneGeneratorLock) {
-            if (mToneGenerator == null) {
-                mToneGenerator = new ToneGenerator(AudioManager.STREAM_MUSIC, TONE_RELATIVE_VOLUME);
-            }
+    public void onAppendDigit(String digit) {
+        if (PLUS_DIGIT.equals(digit)) {
+            mDialerInfoController.removeLastDigit();
         }
-        mUiCallManager.addListener(mCallListener);
-
-        if (mPendingRunnable != null) {
-            mPendingRunnable.run();
-            mPendingRunnable = null;
-        }
+        mDialerInfoController.appendDialedNumber(digit);
     }
-
-    @Override
-    public void onPause() {
-        super.onPause();
-        mUiCallManager.removeListener(mCallListener);
-        stopTone();
-        synchronized (mToneGeneratorLock) {
-            if (mToneGenerator != null) {
-                mToneGenerator.release();
-                mToneGenerator = null;
-            }
-        }
-    }
-
-    @Override
-    public void onDestroyView() {
-        super.onDestroyView();
-        mContext = null;
-        mNumberView = null;
-    }
-
-    private void setDialNumber(final String number) {
-        if (TextUtils.isEmpty(number)) {
-            return;
-        }
-
-        if (mContext != null && mNumberView != null) {
-            setDialNumberInternal(number);
-        } else {
-            mPendingRunnable = () -> setDialNumberInternal(number);
-        }
-    }
-
-    private void setDialNumberInternal(final String number) {
-        // Clear existing content in mNumber.
-        mNumber.setLength(0);
-        mNumber.append(number);
-        mNumberView.setText(getFormattedNumber(mNumber.toString()));
-    }
-
-    private void playTone(int tone) {
-        synchronized (mToneGeneratorLock) {
-            if (mToneGenerator == null) {
-                Log.w(TAG, "playTone: mToneGenerator == null, tone: " + tone);
-                return;
-            }
-
-            // Start the new tone (will stop any playing tone)
-            mToneGenerator.startTone(tone, TONE_LENGTH_MS);
-        }
-    }
-
-    private void stopTone() {
-        synchronized (mToneGeneratorLock) {
-            if (mToneGenerator == null) {
-                Log.w(TAG, "stopTone: mToneGenerator == null");
-                return;
-            }
-            mToneGenerator.stopTone();
-        }
-    }
-
-    private String getFormattedNumber(String number) {
-        return TelecomUtils.getFormattedNumber(mContext, number);
-    }
-
-    private final CallListener mCallListener = new CallListener() {
-        @Override
-        public void dispatchPhoneKeyEvent(KeyEvent event) {
-            if (event.getKeyCode() == KeyEvent.KEYCODE_CALL &&
-                    event.getAction() == KeyEvent.ACTION_UP &&
-                    !TextUtils.isEmpty(mNumber.toString())) {
-                mUiCallManager.safePlaceCall(mNumber.toString(), false);
-            }
-        }
-    };
 }
diff --git a/src/com/android/car/dialer/OngoingCallFragment.java b/src/com/android/car/dialer/OngoingCallFragment.java
index 87d4ebb..1c6445a 100644
--- a/src/com/android/car/dialer/OngoingCallFragment.java
+++ b/src/com/android/car/dialer/OngoingCallFragment.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2015 The Android Open Source Project
+ * 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.
@@ -38,15 +38,13 @@
 import android.view.animation.Transformation;
 import android.widget.ImageButton;
 import android.widget.ImageView;
-import android.widget.LinearLayout;
 import android.widget.TextView;
 
-import com.android.car.apps.common.CircleBitmapDrawable;
 import com.android.car.apps.common.FabDrawable;
 import com.android.car.dialer.telecom.TelecomUtils;
 import com.android.car.dialer.telecom.UiCall;
 import com.android.car.dialer.telecom.UiCallManager;
-import com.android.car.dialer.telecom.UiCallManager.CallListener;
+import com.android.car.dialer.ui.CircleBitmapDrawable;
 
 import java.util.Arrays;
 import java.util.List;
@@ -55,7 +53,8 @@
 /**
  * A fragment that displays information about an on-going call with options to hang up.
  */
-public class OngoingCallFragment extends Fragment {
+@Deprecated
+public class OngoingCallFragment extends Fragment implements CallListener {
     private static final String TAG = "OngoingCall";
     private static final SparseArray<Character> mDialpadButtonMap = new SparseArray<>();
 
@@ -150,8 +149,6 @@
             dialpadView.setOnKeyListener(mDialpadKeyListener);
         }
 
-        mUiCallManager.addListener(mCallListener);
-
         updateCalls();
 
         return view;
@@ -268,7 +265,6 @@
     @Override
     public void onDestroyView() {
         super.onDestroyView();
-        mUiCallManager.removeListener(mCallListener);
     }
 
     @Override
@@ -580,6 +576,51 @@
     private final Runnable mStopDtmfToneRunnable =
             () -> mUiCallManager.stopDtmfTone(mUiCallManager.getPrimaryCall());
 
+    @Override
+    public void onAudioStateChanged(boolean isMuted, int route, int supportedRouteMask) {
+        if (Log.isLoggable(TAG, Log.DEBUG)) {
+            Log.d(TAG, String.format(
+                "onAudioStateChanged(); isMuted: %b, audioRoute: %d, supportedAudioRouteMask: %d",
+                isMuted, route, supportedRouteMask));
+        }
+        mMuteButton.setActivated(isMuted);
+        trySpeakerAudioRouteIfNecessary();
+    }
+
+    @Override
+    public void onCallStateChanged(UiCall call, int state) {
+        if (Log.isLoggable(TAG, Log.DEBUG)) {
+            Log.d(TAG, String.format("onCallStateChanged(); call: %s, state: %s", call, state));
+        }
+        updateCalls();
+    }
+
+    @Override
+    public void onCallUpdated(UiCall call) {
+        if (Log.isLoggable(TAG, Log.DEBUG)) {
+            Log.d(TAG, "onCallUpdated(); call: " + call);
+        }
+        updateCalls();
+    }
+
+    @Override
+    public void onCallAdded(UiCall call) {
+        if (Log.isLoggable(TAG, Log.DEBUG)) {
+            Log.d(TAG, "onCallAdded(); call: " + call);
+        }
+        updateCalls();
+        trySpeakerAudioRouteIfNecessary();
+    }
+
+    @Override
+    public void onCallRemoved(UiCall call) {
+        if (Log.isLoggable(TAG, Log.DEBUG)) {
+            Log.d(TAG, "onCallRemoved(); call: " + call);
+        }
+        mLastRemovedCall = call;
+        updateCalls();
+    }
+
     private final class DialpadAnimation extends Animation {
         private static final int DURATION = 300;
         private static final float MAX_SCRIM_ALPHA = 0.6f;
@@ -622,52 +663,4 @@
             mSecondaryStateTextView.setAlpha(1f - interpolatedTime);
         }
     }
-
-    private final CallListener mCallListener = new CallListener() {
-        @Override
-        public void onCallAdded(UiCall call) {
-            if (Log.isLoggable(TAG, Log.DEBUG)) {
-                Log.d(TAG, "onCallAdded(); call: " + call);
-            }
-            updateCalls();
-            trySpeakerAudioRouteIfNecessary();
-        }
-
-        @Override
-        public void onCallRemoved(UiCall call) {
-            if (Log.isLoggable(TAG, Log.DEBUG)) {
-                Log.d(TAG, "onCallRemoved(); call: " + call);
-            }
-            mLastRemovedCall = call;
-            updateCalls();
-        }
-
-        @Override
-        public void onAudioStateChanged(boolean isMuted, int audioRoute,
-                int supportedAudioRouteMask) {
-            if (Log.isLoggable(TAG, Log.DEBUG)) {
-                Log.d(TAG, String.format("onAudioStateChanged(); isMuted: %b, audioRoute: %d, "
-                        + " supportedAudioRouteMask: %d", isMuted, audioRoute,
-                        supportedAudioRouteMask));
-            }
-            mMuteButton.setActivated(isMuted);
-            trySpeakerAudioRouteIfNecessary();
-        }
-
-        @Override
-        public void onStateChanged(UiCall call, int state) {
-            if (Log.isLoggable(TAG, Log.DEBUG)) {
-                Log.d(TAG, "onStateChanged(); call: " + call + ", state: " + state);
-            }
-            updateCalls();
-        }
-
-        @Override
-        public void onCallUpdated(UiCall call) {
-            if (Log.isLoggable(TAG, Log.DEBUG)) {
-                Log.d(TAG, "onCallUpdated(); call: " + call);
-            }
-            updateCalls();
-        }
-    };
 }
diff --git a/src/com/android/car/dialer/StrequentsAdapter.java b/src/com/android/car/dialer/StrequentsAdapter.java
index 1bf11b5..da07b23 100644
--- a/src/com/android/car/dialer/StrequentsAdapter.java
+++ b/src/com/android/car/dialer/StrequentsAdapter.java
@@ -19,6 +19,7 @@
 import android.content.Context;
 import android.database.Cursor;
 import android.graphics.PorterDuff;
+import android.os.Handler;
 import android.provider.CallLog;
 import android.support.annotation.Nullable;
 import android.support.v7.widget.RecyclerView;
@@ -28,10 +29,11 @@
 import android.view.View;
 import android.view.ViewGroup;
 
+import androidx.car.widget.PagedListView;
+
 import com.android.car.dialer.telecom.PhoneLoader;
 import com.android.car.dialer.telecom.TelecomUtils;
 import com.android.car.dialer.telecom.UiCallManager;
-import com.android.car.view.PagedListView;
 
 import java.util.ArrayList;
 import java.util.Collections;
@@ -43,8 +45,8 @@
  * It handles two types of contacts:
  * <p>
  * <ul>
- *     <li>Strequent contacts (starred and/or frequent)
- *     <li>Last call contact
+ * <li>Strequent contacts (starred and/or frequent)
+ * <li>Last call contact
  * </ul>
  */
 public class StrequentsAdapter extends RecyclerView.Adapter<CallLogViewHolder>
@@ -53,12 +55,16 @@
     private static final int VIEW_TYPE_EMPTY = 0;
     private static final int VIEW_TYPE_LASTCALL = 1;
     private static final int VIEW_TYPE_STREQUENT = 2;
+    private static final long LAST_CALL_REFRESH_INTERVAL_MILLIS = 60 * 1000L;
 
     private final Context mContext;
     private final UiCallManager mUiCallManager;
     private List<ContactEntry> mData;
+    private Handler mMainThreadHandler = new Handler();
 
     private LastCallData mLastCallData;
+    private Cursor mLastCallCursor;
+    private LastCallPeriodicalUpdater mLastCallPeriodicalUpdater = new LastCallPeriodicalUpdater();
 
     private final ContentResolver mContentResolver;
 
@@ -84,7 +90,15 @@
     }
 
     public void setLastCallCursor(@Nullable Cursor cursor) {
+        mLastCallCursor = cursor;
         mLastCallData = convertLastCallCursor(cursor);
+        if (cursor != null) {
+            mMainThreadHandler.postDelayed(mLastCallPeriodicalUpdater,
+                    LAST_CALL_REFRESH_INTERVAL_MILLIS);
+        } else {
+            mMainThreadHandler.removeCallbacks(mLastCallPeriodicalUpdater);
+        }
+
         notifyDataSetChanged();
     }
 
@@ -138,16 +152,12 @@
     public CallLogViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
         View view;
         switch (viewType) {
-            case VIEW_TYPE_LASTCALL:
-                view = LayoutInflater.from(parent.getContext())
-                        .inflate(R.layout.call_log_last_call_item_card, parent, false);
-                return new CallLogViewHolder(view);
-
             case VIEW_TYPE_EMPTY:
                 view = LayoutInflater.from(parent.getContext())
-                        .inflate(R.layout.car_list_item_empty, parent, false);
+                        .inflate(R.layout.call_log_list_item_empty, parent, false);
                 return new CallLogViewHolder(view);
 
+            case VIEW_TYPE_LASTCALL:
             case VIEW_TYPE_STREQUENT:
             default:
                 view = LayoutInflater.from(parent.getContext())
@@ -235,24 +245,26 @@
         String primaryText = mLastCallData.getPrimaryText();
         String number = mLastCallData.getNumber();
 
-        viewHolder.title.setText(mLastCallData.getPrimaryText());
-        viewHolder.text.setText(mLastCallData.getSecondaryText());
-        viewHolder.itemView.setTag(number);
-        viewHolder.callTypeIconsView.clear();
-        viewHolder.callTypeIconsView.setVisibility(View.VISIBLE);
+        if (!number.equals(viewHolder.itemView.getTag())) {
+            viewHolder.title.setText(mLastCallData.getPrimaryText());
+            viewHolder.itemView.setTag(number);
+            viewHolder.callTypeIconsView.clear();
+            viewHolder.callTypeIconsView.setVisibility(View.VISIBLE);
 
-        // mHasFirstItem is true only in main screen, or else it is in drawer, then we need to add
-        // call type icons for call history items.
-        viewHolder.smallIcon.setVisibility(View.GONE);
-        int[] callTypes = mLastCallData.getCallTypes();
-        int icons = Math.min(callTypes.length, CallTypeIconsView.MAX_CALL_TYPE_ICONS);
-        for (int i = 0; i < icons; i++) {
-            viewHolder.callTypeIconsView.add(callTypes[i]);
+            // mHasFirstItem is true only in main screen, or else it is in drawer, then we need
+            // to add
+            // call type icons for call history items.
+            viewHolder.smallIcon.setVisibility(View.GONE);
+            int[] callTypes = mLastCallData.getCallTypes();
+            int icons = Math.min(callTypes.length, CallTypeIconsView.MAX_CALL_TYPE_ICONS);
+            for (int i = 0; i < icons; i++) {
+                viewHolder.callTypeIconsView.add(callTypes[i]);
+            }
+
+            TelecomUtils.setContactBitmapAsync(mContext, viewHolder.icon, primaryText, number);
         }
 
-        setBackground(viewHolder);
-
-        TelecomUtils.setContactBitmapAsync(mContext, viewHolder.icon, primaryText, number);
+        viewHolder.text.setText(mLastCallData.getSecondaryText());
     }
 
     /**
@@ -321,10 +333,9 @@
     private void onBindView(final CallLogViewHolder viewHolder, final ContactEntry entry) {
         viewHolder.itemView.setOnClickListener(v -> onViewClicked(viewHolder));
 
-        final String number = entry.number;
-        // TODO(mcrico): Why is being a voicemail related to not having a name?
-        boolean isVoicemail = (entry.name == null)
-                && (number.equals(TelecomUtils.getVoicemailNumber(mContext)));
+        final String number = entry.getNumber();
+        // TODO: Why is being a voicemail related to not having a name?
+        boolean isVoicemail = entry.isVoicemail();
         String secondaryText = "";
         if (!isVoicemail) {
             secondaryText = String.valueOf(TelecomUtils.getTypeFromNumber(mContext, number));
@@ -339,7 +350,7 @@
 
         TelecomUtils.setContactBitmapAsync(mContext, viewHolder.icon, displayName, number);
 
-        if (entry.isStarred) {
+        if (entry.isStarred()) {
             viewHolder.smallIcon.setVisibility(View.VISIBLE);
             final int iconColor = mContext.getColor(android.R.color.white);
             viewHolder.smallIcon.setColorFilter(iconColor, PorterDuff.Mode.SRC_IN);
@@ -348,31 +359,6 @@
             viewHolder.smallIcon.setVisibility(View.GONE);
         }
 
-        setBackground(viewHolder);
-    }
-
-    /**
-     * Appropriately sets the background for the View that is being bound. This method will allow
-     * for rounded corners on either the top or bottom of a card.
-     */
-    private void setBackground(CallLogViewHolder viewHolder) {
-        int itemCount = getItemCount();
-        int adapterPosition = viewHolder.getAdapterPosition();
-
-        if (itemCount == 1) {
-            // Only element - all corners are rounded
-            viewHolder.card.setBackgroundResource(
-                    R.drawable.car_card_rounded_top_bottom_background);
-        } else if (adapterPosition == 0) {
-            // First element gets rounded top
-            viewHolder.card.setBackgroundResource(R.drawable.car_card_rounded_top_background);
-        } else if (adapterPosition == itemCount - 1) {
-            // Last one has a rounded bottom
-            viewHolder.card.setBackgroundResource(R.drawable.car_card_rounded_bottom_background);
-        } else {
-            // Middle have no rounded corners
-            viewHolder.card.setBackgroundResource(R.color.car_card);
-        }
     }
 
     /**
@@ -422,4 +408,14 @@
             return mCallTypes;
         }
     }
+
+    private class LastCallPeriodicalUpdater implements Runnable {
+
+        @Override
+        public void run() {
+            mLastCallData = convertLastCallCursor(mLastCallCursor);
+            notifyItemChanged(0);
+            mMainThreadHandler.postDelayed(this, LAST_CALL_REFRESH_INTERVAL_MILLIS);
+        }
+    }
 }
diff --git a/src/com/android/car/dialer/StrequentsFragment.java b/src/com/android/car/dialer/StrequentsFragment.java
index f6f94ee..7bd8d4a 100644
--- a/src/com/android/car/dialer/StrequentsFragment.java
+++ b/src/com/android/car/dialer/StrequentsFragment.java
@@ -18,26 +18,27 @@
 import android.content.ContentResolver;
 import android.content.Context;
 import android.content.CursorLoader;
-import android.content.res.Resources;
 import android.database.ContentObserver;
 import android.database.Cursor;
-import android.graphics.Canvas;
-import android.graphics.Paint;
+import android.graphics.Rect;
 import android.net.Uri;
 import android.os.Bundle;
 import android.os.Handler;
+import android.support.annotation.NonNull;
 import android.support.annotation.Nullable;
 import android.support.v4.app.Fragment;
+import android.support.v7.widget.GridLayoutManager;
 import android.support.v7.widget.RecyclerView;
 import android.util.Log;
 import android.view.LayoutInflater;
 import android.view.View;
 import android.view.ViewGroup;
-import android.widget.LinearLayout;
+
+import androidx.car.widget.DayNightStyle;
+import androidx.car.widget.PagedListView;
 
 import com.android.car.dialer.telecom.PhoneLoader;
 import com.android.car.dialer.telecom.UiCallManager;
-import com.android.car.view.PagedListView;
 
 /**
  * Contains a list of contacts. The call types can be any of the CALL_TYPE_* fields from
@@ -59,10 +60,8 @@
     private Cursor mCallLogCursor;
     private boolean mHasLoadedData;
 
-    public static StrequentsFragment newInstance(UiCallManager callManager) {
-        StrequentsFragment fragment = new StrequentsFragment();
-        fragment.mUiCallManager = callManager;
-        return fragment;
+    public static StrequentsFragment newInstance() {
+        return new StrequentsFragment();
     }
 
     @Override
@@ -81,32 +80,33 @@
         }
 
         mContext = getContext();
+        mUiCallManager = UiCallManager.get();
 
         View view = inflater.inflate(R.layout.strequents_fragment, container, false);
-        mListView = (PagedListView) view.findViewById(R.id.list_view);
-        mListView.getLayoutManager().setOffsetRows(true);
+        mListView = view.findViewById(R.id.list_view);
+        int numOfColumn = getContext().getResources().getInteger(
+                R.integer.favorite_fragment_grid_column);
+        mListView.getRecyclerView().setLayoutManager(
+                new GridLayoutManager(getContext(), numOfColumn));
+        mListView.getRecyclerView().addItemDecoration(new ItemSpacingDecoration());
 
         mSpeedialCursorLoader = PhoneLoader.registerCallObserver(PhoneLoader.CALL_TYPE_SPEED_DIAL,
-            mContext, (loader, cursor) -> {
-                if (Log.isLoggable(TAG, Log.DEBUG)) {
-                    Log.d(TAG, "PhoneLoader: onLoadComplete (CALL_TYPE_SPEED_DIAL)");
-                }
+                mContext, (loader, cursor) -> {
+                    if (Log.isLoggable(TAG, Log.DEBUG)) {
+                        Log.d(TAG, "PhoneLoader: onLoadComplete (CALL_TYPE_SPEED_DIAL)");
+                    }
 
-                onLoadStrequentCursor(cursor);
-
-                if (mContext != null) {
-                    mListView.addItemDecoration(new Decoration(mContext));
-                }
-            });
+                    onLoadStrequentCursor(cursor);
+                });
 
         // Get the latest call log from the call logs history.
         mCallLogCursorLoader = PhoneLoader.registerCallObserver(PhoneLoader.CALL_TYPE_ALL, mContext,
-            (loader, cursor) -> {
-                if (Log.isLoggable(TAG, Log.DEBUG)) {
-                    Log.d(TAG, "PhoneLoader: onLoadComplete (CALL_TYPE_ALL)");
-                }
-                onLoadCallLogCursor(cursor);
-            });
+                (loader, cursor) -> {
+                    if (Log.isLoggable(TAG, Log.DEBUG)) {
+                        Log.d(TAG, "PhoneLoader: onLoadComplete (CALL_TYPE_ALL)");
+                    }
+                    onLoadCallLogCursor(cursor);
+                });
 
         ContentResolver contentResolver = mContext.getContentResolver();
         contentResolver.registerContentObserver(mSpeedialCursorLoader.getUri(),
@@ -126,7 +126,6 @@
             Log.v(TAG, "Max clicks: " + maxClicks + ", Max pages: " + maxPages);
         }
 
-        mListView.setLightMode();
         mAdapter = new StrequentsAdapter(mContext, mUiCallManager);
         mAdapter.setStrequentsListener(viewHolder -> {
             if (Log.isLoggable(TAG, Log.DEBUG)) {
@@ -142,7 +141,7 @@
             Log.d(TAG, "setItemAnimator");
         }
 
-        mListView.getRecyclerView().setItemAnimator(new StrequentsItemAnimator());
+        mListView.getRecyclerView().setItemAnimator(null);
         return view;
     }
 
@@ -255,64 +254,24 @@
         }
     }
 
-    /**
-     * Decoration for the speed dial cards. This ItemDecoration will not show a divider between
-     * the dialpad item and the first speed dial item and the divider is offset but a couple of
-     * pixels to offset the fact that the cards overlap.
-     */
-    private static class Decoration extends RecyclerView.ItemDecoration {
-        private final Paint mPaint;
-        private final int mPaintAlpha;
-        private final int mDividerHeight;
-
-        public Decoration(Context context) {
-            Resources res = context.getResources();
-            mPaint = new Paint();
-            mPaint.setColor(res.getColor(R.color.car_list_divider));
-            mDividerHeight = res.getDimensionPixelSize(R.dimen.car_divider_height);
-            mPaintAlpha = mPaint.getAlpha();
-        }
+    private class ItemSpacingDecoration extends RecyclerView.ItemDecoration {
 
         @Override
-        public void onDrawOver(Canvas c, RecyclerView parent, RecyclerView.State state) {
-            StrequentsAdapter adapter = (StrequentsAdapter) parent.getAdapter();
+        public void getItemOffsets(@NonNull Rect outRect, @NonNull View view,
+                @NonNull RecyclerView parent, @NonNull RecyclerView.State state) {
+            super.getItemOffsets(outRect, view, parent, state);
+            int carPadding1 = mContext.getResources().getDimensionPixelOffset(
+                    R.dimen.car_padding_1);
 
-            if (adapter.getItemCount() <= 0) {
-                return;
+            int leftPadding = 0;
+            int rightPadding = 0;
+            if (parent.getChildAdapterPosition(view) % 2 == 0) {
+                rightPadding = carPadding1;
+            } else {
+                leftPadding = carPadding1;
             }
 
-            final int childCount = parent.getChildCount();
-
-            // Don't draw decoration line on last item of the list.
-            for (int i = 0; i < childCount - 1; i++) {
-                final View child = parent.getChildAt(i);
-
-                // If the child is focused then the decoration will look bad with the focus
-                // highlight so don't draw it.
-                if (child.isFocused()) {
-                    continue;
-                }
-
-                // The left edge of the divider should align with the left edge of text_container.
-                LinearLayout container = child.findViewById(R.id.container);
-                View textContainer = child.findViewById(R.id.text_container);
-                View card = child.findViewById(R.id.call_log_card);
-
-                int left = textContainer.getLeft() + container.getLeft() + card.getLeft();
-                int right = left + textContainer.getWidth();
-
-                RecyclerView.LayoutParams lp = (RecyclerView.LayoutParams) child.getLayoutParams();
-                int bottom = child.getBottom() + lp.bottomMargin
-                        + Math.round(child.getTranslationY());
-                int top = bottom - mDividerHeight;
-
-                if (top >= c.getHeight() || top < 0) {
-                    break;
-                }
-
-                mPaint.setAlpha(Math.round(container.getAlpha() * mPaintAlpha));
-                c.drawRect(left, top, right, bottom, mPaint);
-            }
+            outRect.set(leftPadding, carPadding1, rightPadding, carPadding1);
         }
     }
 }
diff --git a/src/com/android/car/dialer/StrequentsItemAnimator.java b/src/com/android/car/dialer/StrequentsItemAnimator.java
deleted file mode 100644
index 23e8b1d..0000000
--- a/src/com/android/car/dialer/StrequentsItemAnimator.java
+++ /dev/null
@@ -1,637 +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.car.dialer;
-
-import android.support.v4.view.ViewCompat;
-import android.support.v4.view.ViewPropertyAnimatorCompat;
-import android.support.v4.view.ViewPropertyAnimatorListener;
-import android.support.v7.widget.RecyclerView.ViewHolder;
-import android.support.v7.widget.SimpleItemAnimator;
-import android.view.View;
-
-import java.util.ArrayList;
-import java.util.List;
-
-/**
- * Branch from {@link android.support.v7.widget.DefaultItemAnimator} with changes on
- * {@link #animateAddImpl}, {@link #animateAdd} and {@link #animateRemoveImpl}.
- */
-public class StrequentsItemAnimator extends SimpleItemAnimator {
-    private static final boolean DEBUG = false;
-
-    private ArrayList<ViewHolder> mPendingRemovals = new ArrayList<>();
-    private ArrayList<ViewHolder> mPendingAdditions = new ArrayList<>();
-    private ArrayList<MoveInfo> mPendingMoves = new ArrayList<>();
-    private ArrayList<ChangeInfo> mPendingChanges = new ArrayList<>();
-
-    private ArrayList<ArrayList<ViewHolder>> mAdditionsList = new ArrayList<>();
-    private ArrayList<ArrayList<MoveInfo>> mMovesList = new ArrayList<>();
-    private ArrayList<ArrayList<ChangeInfo>> mChangesList = new ArrayList<>();
-
-    private ArrayList<ViewHolder> mAddAnimations = new ArrayList<>();
-    private ArrayList<ViewHolder> mMoveAnimations = new ArrayList<>();
-    private ArrayList<ViewHolder> mRemoveAnimations = new ArrayList<>();
-    private ArrayList<ViewHolder> mChangeAnimations = new ArrayList<>();
-
-    private static class MoveInfo {
-        public ViewHolder holder;
-        public int fromX, fromY, toX, toY;
-
-        private MoveInfo(ViewHolder holder, int fromX, int fromY, int toX, int toY) {
-            this.holder = holder;
-            this.fromX = fromX;
-            this.fromY = fromY;
-            this.toX = toX;
-            this.toY = toY;
-        }
-    }
-
-    private static class ChangeInfo {
-        public ViewHolder oldHolder, newHolder;
-        public int fromX, fromY, toX, toY;
-        private ChangeInfo(ViewHolder oldHolder, ViewHolder newHolder) {
-            this.oldHolder = oldHolder;
-            this.newHolder = newHolder;
-        }
-
-        private ChangeInfo(ViewHolder oldHolder, ViewHolder newHolder,
-                int fromX, int fromY, int toX, int toY) {
-            this(oldHolder, newHolder);
-            this.fromX = fromX;
-            this.fromY = fromY;
-            this.toX = toX;
-            this.toY = toY;
-        }
-
-        @Override
-        public String toString() {
-            return "ChangeInfo{" +
-                    "oldHolder=" + oldHolder +
-                    ", newHolder=" + newHolder +
-                    ", fromX=" + fromX +
-                    ", fromY=" + fromY +
-                    ", toX=" + toX +
-                    ", toY=" + toY +
-                    '}';
-        }
-    }
-
-    @Override
-    public void runPendingAnimations() {
-        boolean removalsPending = !mPendingRemovals.isEmpty();
-        boolean movesPending = !mPendingMoves.isEmpty();
-        boolean changesPending = !mPendingChanges.isEmpty();
-        boolean additionsPending = !mPendingAdditions.isEmpty();
-        if (!removalsPending && !movesPending && !additionsPending && !changesPending) {
-            // nothing to animate
-            return;
-        }
-        // First, remove stuff
-        for (ViewHolder holder : mPendingRemovals) {
-            animateRemoveImpl(holder);
-        }
-        mPendingRemovals.clear();
-        // Next, move stuff
-        if (movesPending) {
-            final ArrayList<MoveInfo> moves = new ArrayList<MoveInfo>();
-            moves.addAll(mPendingMoves);
-            mMovesList.add(moves);
-            mPendingMoves.clear();
-            Runnable mover = new Runnable() {
-                @Override
-                public void run() {
-                    for (MoveInfo moveInfo : moves) {
-                        animateMoveImpl(moveInfo.holder, moveInfo.fromX, moveInfo.fromY,
-                                moveInfo.toX, moveInfo.toY);
-                    }
-                    moves.clear();
-                    mMovesList.remove(moves);
-                }
-            };
-            if (removalsPending) {
-                View view = moves.get(0).holder.itemView;
-                ViewCompat.postOnAnimationDelayed(view, mover, getRemoveDuration());
-            } else {
-                mover.run();
-            }
-        }
-        // Next, change stuff, to run in parallel with move animations
-        if (changesPending) {
-            final ArrayList<ChangeInfo> changes = new ArrayList<ChangeInfo>();
-            changes.addAll(mPendingChanges);
-            mChangesList.add(changes);
-            mPendingChanges.clear();
-            Runnable changer = new Runnable() {
-                @Override
-                public void run() {
-                    for (ChangeInfo change : changes) {
-                        animateChangeImpl(change);
-                    }
-                    changes.clear();
-                    mChangesList.remove(changes);
-                }
-            };
-            if (removalsPending) {
-                ViewHolder holder = changes.get(0).oldHolder;
-                ViewCompat.postOnAnimationDelayed(holder.itemView, changer, getRemoveDuration());
-            } else {
-                changer.run();
-            }
-        }
-        // Next, add stuff
-        if (additionsPending) {
-            final ArrayList<ViewHolder> additions = new ArrayList<ViewHolder>();
-            additions.addAll(mPendingAdditions);
-            mAdditionsList.add(additions);
-            mPendingAdditions.clear();
-            Runnable adder = new Runnable() {
-                public void run() {
-                    for (ViewHolder holder : additions) {
-                        animateAddImpl(holder);
-                    }
-                    additions.clear();
-                    mAdditionsList.remove(additions);
-                }
-            };
-            if (removalsPending || movesPending || changesPending) {
-                long removeDuration = removalsPending ? getRemoveDuration() : 0;
-                long moveDuration = movesPending ? getMoveDuration() : 0;
-                long changeDuration = changesPending ? getChangeDuration() : 0;
-                long totalDelay = removeDuration + Math.max(moveDuration, changeDuration);
-                View view = additions.get(0).itemView;
-                ViewCompat.postOnAnimationDelayed(view, adder, totalDelay);
-            } else {
-                adder.run();
-            }
-        }
-    }
-
-    @Override
-    public boolean animateRemove(final ViewHolder holder) {
-        endAnimation(holder);
-        mPendingRemovals.add(holder);
-        return true;
-    }
-
-    private void animateRemoveImpl(final ViewHolder holder) {
-        // Animate on the content if it's CallLogViewHolder.
-        final View view = holder instanceof CallLogViewHolder ?
-                ((CallLogViewHolder) holder).container : holder.itemView;
-        final ViewPropertyAnimatorCompat animation = ViewCompat.animate(view);
-        mRemoveAnimations.add(holder);
-        animation.setDuration(getRemoveDuration())
-                .alpha(0).setListener(new VpaListenerAdapter() {
-            @Override
-            public void onAnimationStart(View view) {
-                dispatchRemoveStarting(holder);
-            }
-
-            @Override
-            public void onAnimationEnd(View view) {
-                animation.setListener(null);
-                ViewCompat.setAlpha(view, 1);
-                dispatchRemoveFinished(holder);
-                mRemoveAnimations.remove(holder);
-                dispatchFinishedWhenDone();
-            }
-        }).start();
-    }
-
-    @Override
-    public boolean animateAdd(final ViewHolder holder) {
-        endAnimation(holder);
-        // for CallLogViewHolder, instead of fade out the whole card, fade out only the content.
-        if (holder instanceof CallLogViewHolder) {
-            ViewCompat.setAlpha(((CallLogViewHolder) holder).container, 0);
-        } else {
-            ViewCompat.setAlpha(holder.itemView, 0);
-        }
-        mPendingAdditions.add(holder);
-        return true;
-    }
-
-    private void animateAddImpl(final ViewHolder holder) {
-        // Animate on the content if it's CallLogViewHolder.
-        final View view = holder instanceof CallLogViewHolder ?
-                ((CallLogViewHolder) holder).container : holder.itemView;
-        final ViewPropertyAnimatorCompat animation = ViewCompat.animate(view);
-        mAddAnimations.add(holder);
-        animation.alpha(1).setDuration(getAddDuration()).
-                setListener(new VpaListenerAdapter() {
-                    @Override
-                    public void onAnimationStart(View view) {
-                        dispatchAddStarting(holder);
-                    }
-                    @Override
-                    public void onAnimationCancel(View view) {
-                        ViewCompat.setAlpha(view, 1);
-                    }
-
-                    @Override
-                    public void onAnimationEnd(View view) {
-                        animation.setListener(null);
-                        dispatchAddFinished(holder);
-                        mAddAnimations.remove(holder);
-                        dispatchFinishedWhenDone();
-                    }
-                }).start();
-    }
-
-    @Override
-    public boolean animateMove(final ViewHolder holder, int fromX, int fromY,
-            int toX, int toY) {
-        final View view = holder.itemView;
-        fromX += ViewCompat.getTranslationX(holder.itemView);
-        fromY += ViewCompat.getTranslationY(holder.itemView);
-        endAnimation(holder);
-        int deltaX = toX - fromX;
-        int deltaY = toY - fromY;
-        if (deltaX == 0 && deltaY == 0) {
-            dispatchMoveFinished(holder);
-            return false;
-        }
-        if (deltaX != 0) {
-            ViewCompat.setTranslationX(view, -deltaX);
-        }
-        if (deltaY != 0) {
-            ViewCompat.setTranslationY(view, -deltaY);
-        }
-        mPendingMoves.add(new MoveInfo(holder, fromX, fromY, toX, toY));
-        return true;
-    }
-
-    private void animateMoveImpl(final ViewHolder holder, int fromX, int fromY, int toX, int toY) {
-        final View view = holder.itemView;
-        final int deltaX = toX - fromX;
-        final int deltaY = toY - fromY;
-        if (deltaX != 0) {
-            ViewCompat.animate(view).translationX(0);
-        }
-        if (deltaY != 0) {
-            ViewCompat.animate(view).translationY(0);
-        }
-        // TODO: make EndActions end listeners instead, since end actions aren't called when
-        // vpas are canceled (and can't end them. why?)
-        // need listener functionality in VPACompat for this. Ick.
-        final ViewPropertyAnimatorCompat animation = ViewCompat.animate(view);
-        mMoveAnimations.add(holder);
-        animation.setDuration(getMoveDuration()).setListener(new VpaListenerAdapter() {
-            @Override
-            public void onAnimationStart(View view) {
-                dispatchMoveStarting(holder);
-            }
-            @Override
-            public void onAnimationCancel(View view) {
-                if (deltaX != 0) {
-                    ViewCompat.setTranslationX(view, 0);
-                }
-                if (deltaY != 0) {
-                    ViewCompat.setTranslationY(view, 0);
-                }
-            }
-            @Override
-            public void onAnimationEnd(View view) {
-                animation.setListener(null);
-                dispatchMoveFinished(holder);
-                mMoveAnimations.remove(holder);
-                dispatchFinishedWhenDone();
-            }
-        }).start();
-    }
-
-    @Override
-    public boolean animateChange(ViewHolder oldHolder, ViewHolder newHolder,
-            int fromX, int fromY, int toX, int toY) {
-        final float prevTranslationX = ViewCompat.getTranslationX(oldHolder.itemView);
-        final float prevTranslationY = ViewCompat.getTranslationY(oldHolder.itemView);
-        final float prevAlpha = ViewCompat.getAlpha(oldHolder.itemView);
-        endAnimation(oldHolder);
-        int deltaX = (int) (toX - fromX - prevTranslationX);
-        int deltaY = (int) (toY - fromY - prevTranslationY);
-        // recover prev translation state after ending animation
-        ViewCompat.setTranslationX(oldHolder.itemView, prevTranslationX);
-        ViewCompat.setTranslationY(oldHolder.itemView, prevTranslationY);
-        ViewCompat.setAlpha(oldHolder.itemView, prevAlpha);
-        if (newHolder != null && newHolder.itemView != null) {
-            // carry over translation values
-            endAnimation(newHolder);
-            ViewCompat.setTranslationX(newHolder.itemView, -deltaX);
-            ViewCompat.setTranslationY(newHolder.itemView, -deltaY);
-            ViewCompat.setAlpha(newHolder.itemView, 0);
-        }
-        mPendingChanges.add(new ChangeInfo(oldHolder, newHolder, fromX, fromY, toX, toY));
-        return true;
-    }
-
-    private void animateChangeImpl(final ChangeInfo changeInfo) {
-        final ViewHolder holder = changeInfo.oldHolder;
-        final View view = holder == null ? null : holder.itemView;
-        final ViewHolder newHolder = changeInfo.newHolder;
-        final View newView = newHolder != null ? newHolder.itemView : null;
-        if (view != null) {
-            final ViewPropertyAnimatorCompat oldViewAnim = ViewCompat.animate(view).setDuration(
-                    getChangeDuration());
-            mChangeAnimations.add(changeInfo.oldHolder);
-            oldViewAnim.translationX(changeInfo.toX - changeInfo.fromX);
-            oldViewAnim.translationY(changeInfo.toY - changeInfo.fromY);
-            oldViewAnim.alpha(0).setListener(new VpaListenerAdapter() {
-                @Override
-                public void onAnimationStart(View view) {
-                    dispatchChangeStarting(changeInfo.oldHolder, true);
-                }
-
-                @Override
-                public void onAnimationEnd(View view) {
-                    oldViewAnim.setListener(null);
-                    ViewCompat.setAlpha(view, 1);
-                    ViewCompat.setTranslationX(view, 0);
-                    ViewCompat.setTranslationY(view, 0);
-                    dispatchChangeFinished(changeInfo.oldHolder, true);
-                    mChangeAnimations.remove(changeInfo.oldHolder);
-                    dispatchFinishedWhenDone();
-                }
-            }).start();
-        }
-        if (newView != null) {
-            final ViewPropertyAnimatorCompat newViewAnimation = ViewCompat.animate(newView);
-            mChangeAnimations.add(changeInfo.newHolder);
-            newViewAnimation.translationX(0).translationY(0).setDuration(getChangeDuration()).
-                    alpha(1).setListener(new VpaListenerAdapter() {
-                @Override
-                public void onAnimationStart(View view) {
-                    dispatchChangeStarting(changeInfo.newHolder, false);
-                }
-                @Override
-                public void onAnimationEnd(View view) {
-                    newViewAnimation.setListener(null);
-                    ViewCompat.setAlpha(newView, 1);
-                    ViewCompat.setTranslationX(newView, 0);
-                    ViewCompat.setTranslationY(newView, 0);
-                    dispatchChangeFinished(changeInfo.newHolder, false);
-                    mChangeAnimations.remove(changeInfo.newHolder);
-                    dispatchFinishedWhenDone();
-                }
-            }).start();
-        }
-    }
-
-    private void endChangeAnimation(List<ChangeInfo> infoList, ViewHolder item) {
-        for (int i = infoList.size() - 1; i >= 0; i--) {
-            ChangeInfo changeInfo = infoList.get(i);
-            if (endChangeAnimationIfNecessary(changeInfo, item)) {
-                if (changeInfo.oldHolder == null && changeInfo.newHolder == null) {
-                    infoList.remove(changeInfo);
-                }
-            }
-        }
-    }
-
-    private void endChangeAnimationIfNecessary(ChangeInfo changeInfo) {
-        if (changeInfo.oldHolder != null) {
-            endChangeAnimationIfNecessary(changeInfo, changeInfo.oldHolder);
-        }
-        if (changeInfo.newHolder != null) {
-            endChangeAnimationIfNecessary(changeInfo, changeInfo.newHolder);
-        }
-    }
-    private boolean endChangeAnimationIfNecessary(ChangeInfo changeInfo, ViewHolder item) {
-        boolean oldItem = false;
-        if (changeInfo.newHolder == item) {
-            changeInfo.newHolder = null;
-        } else if (changeInfo.oldHolder == item) {
-            changeInfo.oldHolder = null;
-            oldItem = true;
-        } else {
-            return false;
-        }
-        ViewCompat.setAlpha(item.itemView, 1);
-        ViewCompat.setTranslationX(item.itemView, 0);
-        ViewCompat.setTranslationY(item.itemView, 0);
-        dispatchChangeFinished(item, oldItem);
-        return true;
-    }
-
-    @Override
-    public void endAnimation(ViewHolder item) {
-        final View view = item.itemView;
-        // this will trigger end callback which should set properties to their target values.
-        ViewCompat.animate(view).cancel();
-        // TODO if some other animations are chained to end, how do we cancel them as well?
-        for (int i = mPendingMoves.size() - 1; i >= 0; i--) {
-            MoveInfo moveInfo = mPendingMoves.get(i);
-            if (moveInfo.holder == item) {
-                ViewCompat.setTranslationY(view, 0);
-                ViewCompat.setTranslationX(view, 0);
-                dispatchMoveFinished(item);
-                mPendingMoves.remove(i);
-            }
-        }
-        endChangeAnimation(mPendingChanges, item);
-        if (mPendingRemovals.remove(item)) {
-            ViewCompat.setAlpha(view, 1);
-            dispatchRemoveFinished(item);
-        }
-        if (mPendingAdditions.remove(item)) {
-            ViewCompat.setAlpha(view, 1);
-            dispatchAddFinished(item);
-        }
-
-        for (int i = mChangesList.size() - 1; i >= 0; i--) {
-            ArrayList<ChangeInfo> changes = mChangesList.get(i);
-            endChangeAnimation(changes, item);
-            if (changes.isEmpty()) {
-                mChangesList.remove(i);
-            }
-        }
-        for (int i = mMovesList.size() - 1; i >= 0; i--) {
-            ArrayList<MoveInfo> moves = mMovesList.get(i);
-            for (int j = moves.size() - 1; j >= 0; j--) {
-                MoveInfo moveInfo = moves.get(j);
-                if (moveInfo.holder == item) {
-                    ViewCompat.setTranslationY(view, 0);
-                    ViewCompat.setTranslationX(view, 0);
-                    dispatchMoveFinished(item);
-                    moves.remove(j);
-                    if (moves.isEmpty()) {
-                        mMovesList.remove(i);
-                    }
-                    break;
-                }
-            }
-        }
-        for (int i = mAdditionsList.size() - 1; i >= 0; i--) {
-            ArrayList<ViewHolder> additions = mAdditionsList.get(i);
-            if (additions.remove(item)) {
-                ViewCompat.setAlpha(view, 1);
-                dispatchAddFinished(item);
-                if (additions.isEmpty()) {
-                    mAdditionsList.remove(i);
-                }
-            }
-        }
-
-        // animations should be ended by the cancel above.
-        if (mRemoveAnimations.remove(item) && DEBUG) {
-            throw new IllegalStateException("after animation is cancelled, item should not be in "
-                    + "mRemoveAnimations list");
-        }
-
-        if (mAddAnimations.remove(item) && DEBUG) {
-            throw new IllegalStateException("after animation is cancelled, item should not be in "
-                    + "mAddAnimations list");
-        }
-
-        if (mChangeAnimations.remove(item) && DEBUG) {
-            throw new IllegalStateException("after animation is cancelled, item should not be in "
-                    + "mChangeAnimations list");
-        }
-
-        if (mMoveAnimations.remove(item) && DEBUG) {
-            throw new IllegalStateException("after animation is cancelled, item should not be in "
-                    + "mMoveAnimations list");
-        }
-        dispatchFinishedWhenDone();
-    }
-
-    @Override
-    public boolean isRunning() {
-        return (!mPendingAdditions.isEmpty() ||
-                !mPendingChanges.isEmpty() ||
-                !mPendingMoves.isEmpty() ||
-                !mPendingRemovals.isEmpty() ||
-                !mMoveAnimations.isEmpty() ||
-                !mRemoveAnimations.isEmpty() ||
-                !mAddAnimations.isEmpty() ||
-                !mChangeAnimations.isEmpty() ||
-                !mMovesList.isEmpty() ||
-                !mAdditionsList.isEmpty() ||
-                !mChangesList.isEmpty());
-    }
-
-    /**
-     * Check the state of currently pending and running animations. If there are none
-     * pending/running, call {@link #dispatchAnimationsFinished()} to notify any
-     * listeners.
-     */
-    private void dispatchFinishedWhenDone() {
-        if (!isRunning()) {
-            dispatchAnimationsFinished();
-        }
-    }
-
-    @Override
-    public void endAnimations() {
-        int count = mPendingMoves.size();
-        for (int i = count - 1; i >= 0; i--) {
-            MoveInfo item = mPendingMoves.get(i);
-            View view = item.holder.itemView;
-            ViewCompat.setTranslationY(view, 0);
-            ViewCompat.setTranslationX(view, 0);
-            dispatchMoveFinished(item.holder);
-            mPendingMoves.remove(i);
-        }
-        count = mPendingRemovals.size();
-        for (int i = count - 1; i >= 0; i--) {
-            ViewHolder item = mPendingRemovals.get(i);
-            dispatchRemoveFinished(item);
-            mPendingRemovals.remove(i);
-        }
-        count = mPendingAdditions.size();
-        for (int i = count - 1; i >= 0; i--) {
-            ViewHolder item = mPendingAdditions.get(i);
-            View view = item.itemView;
-            ViewCompat.setAlpha(view, 1);
-            dispatchAddFinished(item);
-            mPendingAdditions.remove(i);
-        }
-        count = mPendingChanges.size();
-        for (int i = count - 1; i >= 0; i--) {
-            endChangeAnimationIfNecessary(mPendingChanges.get(i));
-        }
-        mPendingChanges.clear();
-        if (!isRunning()) {
-            return;
-        }
-
-        int listCount = mMovesList.size();
-        for (int i = listCount - 1; i >= 0; i--) {
-            ArrayList<MoveInfo> moves = mMovesList.get(i);
-            count = moves.size();
-            for (int j = count - 1; j >= 0; j--) {
-                MoveInfo moveInfo = moves.get(j);
-                ViewHolder item = moveInfo.holder;
-                View view = item.itemView;
-                ViewCompat.setTranslationY(view, 0);
-                ViewCompat.setTranslationX(view, 0);
-                dispatchMoveFinished(moveInfo.holder);
-                moves.remove(j);
-                if (moves.isEmpty()) {
-                    mMovesList.remove(moves);
-                }
-            }
-        }
-        listCount = mAdditionsList.size();
-        for (int i = listCount - 1; i >= 0; i--) {
-            ArrayList<ViewHolder> additions = mAdditionsList.get(i);
-            count = additions.size();
-            for (int j = count - 1; j >= 0; j--) {
-                ViewHolder item = additions.get(j);
-                View view = item.itemView;
-                ViewCompat.setAlpha(view, 1);
-                dispatchAddFinished(item);
-                additions.remove(j);
-                if (additions.isEmpty()) {
-                    mAdditionsList.remove(additions);
-                }
-            }
-        }
-        listCount = mChangesList.size();
-        for (int i = listCount - 1; i >= 0; i--) {
-            ArrayList<ChangeInfo> changes = mChangesList.get(i);
-            count = changes.size();
-            for (int j = count - 1; j >= 0; j--) {
-                endChangeAnimationIfNecessary(changes.get(j));
-                if (changes.isEmpty()) {
-                    mChangesList.remove(changes);
-                }
-            }
-        }
-
-        cancelAll(mRemoveAnimations);
-        cancelAll(mMoveAnimations);
-        cancelAll(mAddAnimations);
-        cancelAll(mChangeAnimations);
-
-        dispatchAnimationsFinished();
-    }
-
-    void cancelAll(List<ViewHolder> viewHolders) {
-        for (int i = viewHolders.size() - 1; i >= 0; i--) {
-            ViewCompat.animate(viewHolders.get(i).itemView).cancel();
-        }
-    }
-
-    private static class VpaListenerAdapter implements ViewPropertyAnimatorListener {
-        @Override
-        public void onAnimationStart(View view) {}
-
-        @Override
-        public void onAnimationEnd(View view) {}
-
-        @Override
-        public void onAnimationCancel(View view) {}
-    };
-}
diff --git a/src/com/android/car/dialer/TelecomActivity.java b/src/com/android/car/dialer/TelecomActivity.java
index 6738d04..5ec5493 100644
--- a/src/com/android/car/dialer/TelecomActivity.java
+++ b/src/com/android/car/dialer/TelecomActivity.java
@@ -15,8 +15,8 @@
  */
 package com.android.car.dialer;
 
-import android.animation.Animator;
-import android.animation.ObjectAnimator;
+import static com.android.car.dialer.ui.CallHistoryFragment.CALL_TYPE_KEY;
+
 import android.content.Intent;
 import android.graphics.PorterDuff;
 import android.graphics.drawable.Drawable;
@@ -24,21 +24,23 @@
 import android.support.annotation.Nullable;
 import android.support.annotation.StringRes;
 import android.support.v4.app.Fragment;
-import android.support.v4.view.animation.FastOutSlowInInterpolator;
 import android.telecom.Call;
 import android.telephony.PhoneNumberUtils;
 import android.util.Log;
-import android.view.View;
 
-import com.android.car.app.CarDrawerActivity;
-import com.android.car.app.CarDrawerAdapter;
-import com.android.car.app.DrawerItemViewHolder;
+import androidx.car.drawer.CarDrawerActivity;
+import androidx.car.drawer.CarDrawerAdapter;
+import androidx.car.drawer.DrawerItemViewHolder;
+
+import com.android.car.dialer.telecom.InMemoryPhoneBook;
 import com.android.car.dialer.telecom.PhoneLoader;
 import com.android.car.dialer.telecom.UiCall;
 import com.android.car.dialer.telecom.UiCallManager;
-import com.android.car.dialer.telecom.UiCallManager.CallListener;
+import com.android.car.dialer.ui.CallHistoryFragment;
+import com.android.car.dialer.ui.ContactListFragment;
+import com.android.car.dialer.ui.InCallFragment;
 
-import java.util.List;
+import java.util.stream.Stream;
 
 /**
  * Main activity for the Dialer app. Displays different fragments depending on call and
@@ -50,8 +52,7 @@
  * <li>StrequentFragment
  * </ul>
  */
-public class TelecomActivity extends CarDrawerActivity implements
-        DialerFragment.DialerBackButtonListener {
+public class TelecomActivity extends CarDrawerActivity implements CallListener {
     private static final String TAG = "TelecomActivity";
 
     private static final String ACTION_ANSWER_CALL = "com.android.car.dialer.ANSWER_CALL";
@@ -79,6 +80,7 @@
     @Override
     protected void onCreate(Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);
+        setToolbarElevation(0f);
 
         if (vdebug()) {
             Log.d(TAG, "onCreate");
@@ -86,13 +88,17 @@
 
         setMainContent(R.layout.telecom_activity);
         getWindow().getDecorView().setBackgroundColor(getColor(R.color.phone_theme));
-        setTitle(getString(R.string.phone_app_name));
+        updateTitle();
 
-        mUiCallManager = new UiCallManager(this);
+        mUiCallManager = UiCallManager.init(getApplicationContext());
         mUiBluetoothMonitor = new UiBluetoothMonitor(this);
 
+        InMemoryPhoneBook.init(getApplicationContext());
+
         findViewById(R.id.search).setOnClickListener(
                 v -> startActivity(new Intent(this, ContactSearchActivity.class)));
+
+        getDrawerController().setRootAdapter(new DialerRootAdapter());
     }
 
     @Override
@@ -102,6 +108,7 @@
             Log.d(TAG, "onDestroy");
         }
         mUiBluetoothMonitor.tearDown();
+        InMemoryPhoneBook.tearDown();
         mUiCallManager.tearDown();
         mUiCallManager = null;
     }
@@ -109,7 +116,7 @@
     @Override
     protected void onStop() {
         super.onStop();
-        mUiCallManager.removeListener(mCarCallListener);
+        mUiCallManager.removeListener(this);
         mUiBluetoothMonitor.removeListener(mBluetoothListener);
     }
 
@@ -143,7 +150,7 @@
         updateCurrentFragment();
         handleIntent();
 
-        mUiCallManager.addListener(mCarCallListener);
+        mUiCallManager.addListener(this);
         mUiBluetoothMonitor.addListener(mBluetoothListener);
     }
 
@@ -222,7 +229,7 @@
                         + getCurrentFragment());
             }
 
-            if (ongoingCall == null && getCurrentFragment() instanceof OngoingCallFragment) {
+            if (ongoingCall == null && getCurrentFragment() instanceof InCallFragment) {
                 showSpeedDialFragment();
             } else if (ongoingCall != null) {
                 showOngoingCallFragment();
@@ -245,29 +252,24 @@
             return;
         }
 
-        Fragment fragment = StrequentsFragment.newInstance(mUiCallManager);
-        if (getCurrentFragment() instanceof DialerFragment) {
-            setContentFragmentWithSlideAndDelayAnimation(fragment);
-        } else {
-            setContentFragmentWithFadeAnimation(fragment);
-        }
+        Fragment fragment = StrequentsFragment.newInstance();
+        setContentFragment(fragment);
     }
 
     private void showOngoingCallFragment() {
         if (vdebug()) {
             Log.d(TAG, "showOngoingCallFragment");
         }
-        if (!mAllowFragmentCommits || getCurrentFragment() instanceof OngoingCallFragment) {
+        if (!mAllowFragmentCommits || getCurrentFragment() instanceof InCallFragment) {
             // in case the dialer is still open, (e.g. when dialing the second phone during
             // a phone call), close it
             maybeHideDialer();
-            closeDrawer();
+            getDrawerController().closeDrawer();
             return;
         }
-
-        Fragment fragment = OngoingCallFragment.newInstance(mUiCallManager, mUiBluetoothMonitor);
+        Fragment fragment = InCallFragment.newInstance();
         setContentFragmentWithFadeAnimation(fragment);
-        closeDrawer();
+        getDrawerController().closeDrawer();
     }
 
     private void showDialer() {
@@ -291,24 +293,9 @@
             return;
         }
 
-        Fragment fragment =
-                DialerFragment.newInstance(mUiCallManager, this /* listener */, dialNumber);
-
-        if (Log.isLoggable(TAG, Log.VERBOSE)) {
-            Log.v(TAG, "adding dialer to fragment backstack");
-        }
-
+        Fragment fragment = DialerFragment.newInstance(dialNumber);
         // Add the dialer fragment to the backstack so that it can be popped off to dismiss it.
-        getSupportFragmentManager().beginTransaction()
-                .setCustomAnimations(R.anim.telecom_slide_in, R.anim.telecom_slide_out,
-                        R.anim.telecom_slide_in, R.anim.telecom_slide_out)
-                .add(R.id.content_fragment_container, fragment, DIALER_FRAGMENT_TAG)
-                .addToBackStack(DIALER_BACKSTACK)
-                .commit();
-
-        if (Log.isLoggable(TAG, Log.VERBOSE)) {
-            Log.v(TAG, "done adding fragment to backstack");
-        }
+        setContentFragment(fragment);
     }
 
     /**
@@ -322,11 +309,6 @@
         }
     }
 
-    @Override
-    public void onDialerBackClick() {
-        maybeHideDialer();
-    }
-
     private void showNoHfpFragment(@StringRes int stringResId) {
         if (!mAllowFragmentCommits) {
             return;
@@ -364,6 +346,7 @@
         }
 
         maybeHideDialer();
+
         getSupportFragmentManager().beginTransaction()
                 .setCustomAnimations(enter, exit)
                 .replace(R.id.content_fragment_container, fragment, CONTENT_FRAGMENT_TAG)
@@ -380,6 +363,7 @@
         getSupportFragmentManager().beginTransaction()
                 .replace(R.id.content_fragment_container, fragment, CONTENT_FRAGMENT_TAG)
                 .commitNow();
+        updateTitle();
     }
 
     /**
@@ -393,97 +377,85 @@
         return getSupportFragmentManager().findFragmentByTag(CONTENT_FRAGMENT_TAG);
     }
 
-    private final CallListener mCarCallListener = new UiCallManager.CallListener() {
-        @Override
-        public void onCallAdded(UiCall call) {
-            if (vdebug()) {
-                Log.d(TAG, "onCallAdded");
-            }
-            updateCurrentFragment();
-        }
-
-        @Override
-        public void onCallRemoved(UiCall call) {
-            if (vdebug()) {
-                Log.d(TAG, "onCallRemoved");
-            }
-            updateCurrentFragment();
-        }
-
-        @Override
-        public void onStateChanged(UiCall call, int state) {
-            if (vdebug()) {
-                Log.d(TAG, "onStateChanged");
-            }
-            updateCurrentFragment();
-        }
-
-        @Override
-        public void onCallUpdated(UiCall call) {
-            if (vdebug()) {
-                Log.d(TAG, "onCallUpdated");
-            }
-            updateCurrentFragment();
-        }
-    };
-
     private static boolean vdebug() {
         return Log.isLoggable(TAG, Log.DEBUG);
     }
 
     @Override
-    protected CarDrawerAdapter getRootAdapter() {
-        return new DialerRootAdapter();
+    public void onAudioStateChanged(boolean isMuted, int route, int supportedRouteMask) {
+        fragmentsToPropagateCallback().forEach(fragment -> ((CallListener) fragment)
+                .onAudioStateChanged(isMuted, route, supportedRouteMask));
     }
 
-    class CallLogAdapter extends CarDrawerAdapter {
-        private List<CallLogListingTask.CallLogItem> mItems;
-
-        public CallLogAdapter(int titleResId, List<CallLogListingTask.CallLogItem> items) {
-            super(TelecomActivity.this, true  /* showDisabledListOnEmpty */);
-            setTitle(getString(titleResId));
-            mItems = items;
+    @Override
+    public void onCallStateChanged(UiCall call, int state) {
+        if (vdebug()) {
+            Log.d(TAG, "onCallStateChanged");
         }
+        updateCurrentFragment();
 
-        @Override
-        protected boolean usesSmallLayout(int position) {
-            return false;
-        }
+        fragmentsToPropagateCallback().forEach(fragment -> ((CallListener) fragment)
+                .onCallStateChanged(call, state));
+    }
 
-        @Override
-        protected int getActualItemCount() {
-            return mItems.size();
+    @Override
+    public void onCallUpdated(UiCall call) {
+        if (vdebug()) {
+            Log.d(TAG, "onCallUpdated");
         }
+        updateCurrentFragment();
 
-        @Override
-        public void populateViewHolder(DrawerItemViewHolder holder, int position) {
-            CallLogListingTask.CallLogItem item = mItems.get(position);
-            holder.getTitle().setText(item.mTitle);
-            holder.getText().setText(item.mText);
-            holder.getIcon().setImageBitmap(item.mIcon);
-        }
+        fragmentsToPropagateCallback().forEach(fragment -> ((CallListener) fragment)
+                .onCallUpdated(call));
+    }
 
-        @Override
-        public void onItemClick(int position) {
-            closeDrawer();
-            mUiCallManager.safePlaceCall(mItems.get(position).mNumber, false);
+    @Override
+    public void onCallAdded(UiCall call) {
+        if (vdebug()) {
+            Log.d(TAG, "onCallAdded");
         }
+        updateCurrentFragment();
+
+        fragmentsToPropagateCallback().forEach(fragment -> ((CallListener) fragment)
+                .onCallAdded(call));
+    }
+
+    @Override
+    public void onCallRemoved(UiCall call) {
+        if (vdebug()) {
+            Log.d(TAG, "onCallRemoved");
+        }
+        updateCurrentFragment();
+
+        fragmentsToPropagateCallback().forEach(fragment -> ((CallListener) fragment)
+                .onCallRemoved(call));
+    }
+
+    private static boolean shouldPropagateCallback(Fragment fragment) {
+        return fragment instanceof CallListener && fragment.isAdded();
+    }
+
+    private Stream<Fragment> fragmentsToPropagateCallback() {
+        return getSupportFragmentManager().getFragments().stream()
+                .filter(fragment -> shouldPropagateCallback(fragment));
     }
 
     private class DialerRootAdapter extends CarDrawerAdapter {
-        private static final int ITEM_DIAL = 0;
+        private static final int ITEM_FAVORITES = 0;
         private static final int ITEM_CALLLOG_ALL = 1;
         private static final int ITEM_CALLLOG_MISSED = 2;
-        private static final int ITEM_MAX = 3;
+        private static final int ITEM_CONTACT = 3;
+        private static final int ITEM_DIAL = 4;
+
+        private static final int ITEM_COUNT = 5;
 
         DialerRootAdapter() {
             super(TelecomActivity.this, false /* showDisabledListOnEmpty */);
-            setTitle(getString(R.string.phone_app_name));
         }
 
         @Override
         protected int getActualItemCount() {
-            return ITEM_MAX;
+            return ITEM_COUNT;
         }
 
         @Override
@@ -501,7 +473,15 @@
                     break;
                 case ITEM_CALLLOG_MISSED:
                     textResId = R.string.calllog_missed;
-                    iconResId = R.drawable.ic_drawer_call_missed;
+                    iconResId = R.drawable.ic_call_missed;
+                    break;
+                case ITEM_FAVORITES:
+                    textResId = R.string.calllog_favorites;
+                    iconResId = R.drawable.ic_favorite;
+                    break;
+                case ITEM_CONTACT:
+                    textResId = R.string.contact_menu_label;
+                    iconResId = R.drawable.ic_contact;
                     break;
                 default:
                     Log.wtf(TAG, "Unexpected position: " + position);
@@ -511,48 +491,69 @@
             Drawable drawable = getDrawable(iconResId);
             drawable.setColorFilter(iconColor, PorterDuff.Mode.SRC_IN);
             holder.getIcon().setImageDrawable(drawable);
-            if (position > 0) {
-                drawable = getDrawable(R.drawable.ic_chevron_right);
-                drawable.setColorFilter(iconColor, PorterDuff.Mode.SRC_IN);
-                holder.getRightIcon().setImageDrawable(drawable);
-            }
         }
 
         @Override
         public void onItemClick(int position) {
+            getDrawerController().closeDrawer();
             switch (position) {
                 case ITEM_DIAL:
-                    closeDrawer();
                     showDialer();
                     break;
                 case ITEM_CALLLOG_ALL:
-                    loadCallHistoryAsync(PhoneLoader.CALL_TYPE_ALL, R.string.calllog_all);
+                    showCallHistory(PhoneLoader.CallType.CALL_TYPE_ALL);
                     break;
                 case ITEM_CALLLOG_MISSED:
-                    loadCallHistoryAsync(PhoneLoader.CALL_TYPE_MISSED, R.string.calllog_missed);
+                    showCallHistory(PhoneLoader.CallType.MISSED_TYPE);
+                    break;
+                case ITEM_FAVORITES:
+                    showSpeedDialFragment();
+                    break;
+                case ITEM_CONTACT:
+                    showContact();
                     break;
                 default:
                     Log.w(TAG, "Invalid position in ROOT menu! " + position);
             }
+            setTitle(getTitleString());
         }
     }
 
-    private void loadCallHistoryAsync(final int callType, final int titleResId) {
-        showLoadingProgressBar(true);
-        // Warning: much callbackiness!
-        // First load up the call log cursor using the PhoneLoader so that happens in a
-        // background thread. TODO: Why isn't PhoneLoader using a LoaderManager?
-        PhoneLoader.registerCallObserver(callType, this,
-            (loader, data) -> {
-                // This callback runs on the thread that created the loader which is
-                // the ui thread so spin off another async task because we still need
-                // to pull together all the data along with the contact photo.
-                CallLogListingTask task = new CallLogListingTask(TelecomActivity.this, data,
-                    (items) -> {
-                            showLoadingProgressBar(false);
-                            switchToAdapter(new CallLogAdapter(titleResId, items));
-                        });
-                task.execute();
-            });
+    private void showCallHistory(@PhoneLoader.CallType int callType) {
+        setContentFragment(CallHistoryFragment.newInstance(callType));
+    }
+
+    private void showContact() {
+        setContentFragment(ContactListFragment.newInstance());
+    }
+
+    private void updateTitle() {
+        setTitle(getTitleString());
+    }
+
+    private String getTitleString() {
+        Fragment currentFragment = getCurrentFragment();
+
+        int titleResId = R.string.phone_app_name;
+
+        if (currentFragment instanceof StrequentsFragment) {
+            titleResId = R.string.contacts_title;
+        } else if (currentFragment instanceof CallHistoryFragment) {
+            int callType = currentFragment.getArguments().getInt(CALL_TYPE_KEY);
+            if (callType == PhoneLoader.CallType.MISSED_TYPE) {
+                titleResId = R.string.missed_call_title;
+            } else {
+                titleResId = R.string.call_history_title;
+            }
+        } else if (currentFragment instanceof ContactListFragment) {
+            titleResId = R.string.contacts_title;
+        } else if (currentFragment instanceof DialerFragment) {
+            titleResId = R.string.dialpad_title;
+        } else if (currentFragment instanceof InCallFragment
+                || currentFragment instanceof OngoingCallFragment) {
+            titleResId = R.string.in_call_title;
+        }
+
+        return getString(titleResId);
     }
 }
diff --git a/src/com/android/car/dialer/livedata/CallHistoryLiveData.java b/src/com/android/car/dialer/livedata/CallHistoryLiveData.java
new file mode 100644
index 0000000..ea093fa
--- /dev/null
+++ b/src/com/android/car/dialer/livedata/CallHistoryLiveData.java
@@ -0,0 +1,90 @@
+/*
+ * 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.car.dialer.livedata;
+
+import android.arch.lifecycle.LiveData;
+import android.content.ContentResolver;
+import android.content.Context;
+import android.content.CursorLoader;
+import android.database.ContentObserver;
+import android.net.Uri;
+import android.os.Handler;
+
+import com.android.car.dialer.telecom.PhoneLoader;
+import com.android.car.dialer.ui.CallLogListingTask;
+
+import java.util.List;
+
+/**
+ * Live data which loads call history.
+ */
+public class CallHistoryLiveData extends LiveData<List<CallLogListingTask.CallLogItem>> {
+
+    private final Context mContext;
+    private final ContentResolver mContentResolver;
+    private CursorLoader mCursorLoader;
+    private CallLogContentObserver mCallLogContentObserver = new CallLogContentObserver(
+            new Handler());
+
+    public CallHistoryLiveData(Context context) {
+        this.mContext = context;
+        mContentResolver = context.getContentResolver();
+    }
+
+    @Override
+    protected void onActive() {
+        super.onActive();
+        mCursorLoader = PhoneLoader.registerCallObserver(getCallHistoryFilterType(),
+                mContext,
+                (loader, cursor) -> {
+                    CallLogListingTask task = new CallLogListingTask(mContext, cursor,
+                            this::setValue);
+                    task.execute();
+                });
+
+        mContentResolver.registerContentObserver(mCursorLoader.getUri(),
+                false, mCallLogContentObserver);
+    }
+
+    @Override
+    protected void onInactive() {
+        super.onInactive();
+        mContentResolver.unregisterContentObserver(mCallLogContentObserver);
+    }
+
+    protected int getCallHistoryFilterType() {
+        return PhoneLoader.CALL_TYPE_ALL;
+    }
+
+    /**
+     * A {@link ContentObserver} that is responsible for reloading the user's recent calls.
+     */
+    private class CallLogContentObserver extends ContentObserver {
+        public CallLogContentObserver(Handler handler) {
+            super(handler);
+        }
+
+        @Override
+        public void onChange(boolean selfChange) {
+            onChange(selfChange, null);
+        }
+
+        @Override
+        public void onChange(boolean selfChange, Uri uri) {
+            mCursorLoader.startLoading();
+        }
+    }
+}
diff --git a/src/com/android/car/dialer/livedata/MissedCallHistoryLiveData.java b/src/com/android/car/dialer/livedata/MissedCallHistoryLiveData.java
new file mode 100644
index 0000000..26a7f2e
--- /dev/null
+++ b/src/com/android/car/dialer/livedata/MissedCallHistoryLiveData.java
@@ -0,0 +1,35 @@
+/*
+ * 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.car.dialer.livedata;
+
+import android.content.Context;
+
+import com.android.car.dialer.telecom.PhoneLoader;
+
+/**
+ * Live data which loads missed call history.
+ */
+public class MissedCallHistoryLiveData extends CallHistoryLiveData {
+
+    public MissedCallHistoryLiveData(Context context) {
+        super(context);
+    }
+
+    @Override
+    protected int getCallHistoryFilterType() {
+        return PhoneLoader.MISSED_TYPE;
+    }
+}
diff --git a/src/com/android/car/dialer/log/L.java b/src/com/android/car/dialer/log/L.java
new file mode 100644
index 0000000..f85a51a
--- /dev/null
+++ b/src/com/android/car/dialer/log/L.java
@@ -0,0 +1,70 @@
+/*
+ * 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.car.dialer.log;
+
+import android.util.Log;
+
+/**
+ * Util class for logging.
+ */
+public class L {
+
+    private String mTag;
+
+    public L(String tag) {
+        mTag = tag;
+    }
+
+    public void v(String msg) {
+        if (Log.isLoggable(mTag, Log.VERBOSE)) {
+            Log.v(mTag, msg);
+        }
+    }
+
+    public void d(String msg) {
+        if (Log.isLoggable(mTag, Log.DEBUG)) {
+            Log.d(mTag, msg);
+        }
+    }
+
+    public void w(String msg) {
+        Log.w(mTag, msg);
+    }
+
+    public static L logger(String tag) {
+        return new L(tag);
+    }
+
+    public static void v(String tag, String msg) {
+        if (Log.isLoggable(tag, Log.VERBOSE)) {
+            Log.v(tag, msg);
+        }
+    }
+
+    public static void d(String tag, String msg) {
+        if (Log.isLoggable(tag, Log.DEBUG)) {
+            Log.d(tag, msg);
+        }
+    }
+
+    public static void w(String tag, String msg) {
+        Log.w(tag, msg);
+    }
+
+    public static void i(String tag, String msg) {
+        Log.i(tag, msg);
+    }
+}
diff --git a/src/com/android/car/dialer/telecom/InMemoryPhoneBook.java b/src/com/android/car/dialer/telecom/InMemoryPhoneBook.java
new file mode 100644
index 0000000..3aaa21f
--- /dev/null
+++ b/src/com/android/car/dialer/telecom/InMemoryPhoneBook.java
@@ -0,0 +1,121 @@
+package com.android.car.dialer.telecom;
+
+import android.content.Context;
+import android.database.Cursor;
+import android.provider.ContactsContract;
+import android.support.annotation.NonNull;
+import android.support.annotation.Nullable;
+import android.support.v4.content.CursorLoader;
+import android.support.v4.content.Loader;
+import android.telephony.PhoneNumberUtils;
+
+import com.android.car.dialer.ContactEntry;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * A singleton statically accessible helper class which pre-loads contacts list into memory so
+ * that they can be accessed more easily and quickly.
+ */
+public class InMemoryPhoneBook implements Loader.OnLoadCompleteListener<Cursor> {
+    private static InMemoryPhoneBook sInMemoryPhoneBook;
+
+    private final Context mContext;
+
+    private boolean mIsLoaded = false;
+    private List<ContactEntry> mContactEntries = new ArrayList<>();
+    Map<Integer, List<ContactEntry>> mIdToContactEntryMap;
+
+    private InMemoryPhoneBook(Context context) {
+        mContext = context;
+    }
+
+    public static InMemoryPhoneBook init(Context context) {
+        if (sInMemoryPhoneBook == null) {
+            sInMemoryPhoneBook = new InMemoryPhoneBook(context);
+            sInMemoryPhoneBook.onInit();
+        } else {
+            throw new IllegalStateException("Call teardown before reinitialized PhoneBook");
+        }
+        return get();
+    }
+
+    public static InMemoryPhoneBook get() {
+        if (sInMemoryPhoneBook != null) {
+            return sInMemoryPhoneBook;
+        } else {
+            throw new IllegalStateException("Call init before get InMemoryPhoneBook");
+        }
+    }
+
+    public static void tearDown() {
+        sInMemoryPhoneBook = null;
+    }
+
+    private void onInit() {
+        CursorLoader cursorLoader = createPhoneBookCursorLoader();
+        cursorLoader.registerListener(0, this);
+        cursorLoader.startLoading();
+    }
+
+    public boolean isLoaded() {
+        return mIsLoaded;
+    }
+
+    /**
+     * Returns a alphabetically sorted contact list.
+     */
+    public List<ContactEntry> getOrderedContactEntries() {
+        return mContactEntries;
+    }
+
+    @Nullable
+    public ContactEntry lookupContactEntry(String phoneNumber) {
+        for (ContactEntry contactEntry : mContactEntries) {
+            if (PhoneNumberUtils.compare(mContext, phoneNumber, contactEntry.getNumber())) {
+                return contactEntry;
+            }
+        }
+        return null;
+    }
+
+    public Map<Integer, List<ContactEntry>> getIdToContactEntryMap() {
+        if (mIdToContactEntryMap == null) {
+            mIdToContactEntryMap = new HashMap<>();
+            for (ContactEntry contactEntry : mContactEntries) {
+                List<ContactEntry> list;
+                if (mIdToContactEntryMap.containsKey(contactEntry.getId())) {
+                    list = mIdToContactEntryMap.get(contactEntry.getId());
+                } else {
+                    list = new ArrayList<>();
+                }
+                list.add(contactEntry);
+            }
+        }
+        return mIdToContactEntryMap;
+    }
+
+    @Override
+    public void onLoadComplete(@NonNull Loader<Cursor> loader, @Nullable Cursor cursor) {
+        if (cursor != null) {
+            while (cursor.moveToNext()) {
+                mContactEntries.add(ContactEntry.fromCursor(cursor, mContext));
+            }
+        }
+        mIsLoaded = true;
+    }
+
+    private CursorLoader createPhoneBookCursorLoader() {
+        return new CursorLoader(mContext,
+                ContactsContract.Data.CONTENT_URI,
+                null,
+                ContactsContract.Data.MIMETYPE + " = '"
+                        + ContactsContract.CommonDataKinds.Phone
+                        .CONTENT_ITEM_TYPE + "'",
+                null,
+                ContactsContract.Contacts.DISPLAY_NAME + " ASC ");
+    }
+}
diff --git a/src/com/android/car/dialer/telecom/PhoneLoader.java b/src/com/android/car/dialer/telecom/PhoneLoader.java
index 67fee4d..6ac5c6e 100644
--- a/src/com/android/car/dialer/telecom/PhoneLoader.java
+++ b/src/com/android/car/dialer/telecom/PhoneLoader.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2015 The Android Open Source Project
+ * 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.
@@ -24,6 +24,7 @@
 import android.provider.BaseColumns;
 import android.provider.CallLog;
 import android.provider.ContactsContract;
+import android.support.annotation.IntDef;
 import android.text.TextUtils;
 import android.util.Log;
 
@@ -32,11 +33,11 @@
 import java.util.List;
 
 /**
- * Manage loading different types of call logs.
+ * Manages loading different types of call logs.
  * Currently supports:
- *     All calls
- *     Missed calls
- *     speed dial calls
+ * All calls
+ * Missed calls
+ * speed dial calls
  */
 public class PhoneLoader {
     private static final String TAG = "Em.PhoneLoader";
@@ -47,6 +48,19 @@
     /** Starred and frequent **/
     public final static int CALL_TYPE_SPEED_DIAL = 2;
 
+    @IntDef({
+            CallType.CALL_TYPE_ALL,
+            CallType.INCOMING_TYPE,
+            CallType.OUTGOING_TYPE,
+            CallType.MISSED_TYPE,
+    })
+    public @interface CallType {
+        int CALL_TYPE_ALL = -1;
+        int INCOMING_TYPE = CallLog.Calls.INCOMING_TYPE;
+        int OUTGOING_TYPE = CallLog.Calls.OUTGOING_TYPE;
+        int MISSED_TYPE = CallLog.Calls.MISSED_TYPE;
+    }
+
     private static final int NUM_LOGS_TO_DISPLAY = 100;
     private static final String[] EMPTY_STRING_ARRAY = new String[0];
 
@@ -67,7 +81,7 @@
             Log.d(TAG, "registerCallObserver: type: " + type + ", listener: " + listener);
         }
 
-        switch(type) {
+        switch (type) {
             case CALL_TYPE_ALL:
             case CALL_TYPE_MISSED:
                 return fetchCallLog(type, context, listener);
@@ -129,8 +143,8 @@
 
     /**
      * @return The column index of the contact id. It should be {@link BaseColumns#_ID}. However,
-     *         if that fails use {@link android.provider.ContactsContract.RawContacts#CONTACT_ID}.
-     *         If that also fails, we use the first column in the table.
+     * if that fails use {@link android.provider.ContactsContract.RawContacts#CONTACT_ID}.
+     * If that also fails, we use the first column in the table.
      */
     public static int getIdColumnIndex(Cursor cursor) {
         int ret = cursor.getColumnIndex(BaseColumns._ID);
@@ -153,7 +167,7 @@
 
     /**
      * @return The column index of the number.
-     *         Will return a valid column for call log or contacts queries.
+     * Will return a valid column for call log or contacts queries.
      */
     public static int getNumberColumnIndex(Cursor cursor) {
         int numberColumn = cursor.getColumnIndex(CallLog.Calls.NUMBER);
@@ -166,7 +180,7 @@
 
     /**
      * @return The column index of the number type.
-     *         Will return a valid column for call log or contacts queries.
+     * Will return a valid column for call log or contacts queries.
      */
     public static int getTypeColumnIndex(Cursor cursor) {
         int typeColumn = cursor.getColumnIndex(CallLog.Calls.TYPE);
@@ -178,7 +192,7 @@
 
     /**
      * @return The column index of the name.
-     *         Will return a valid column for call log or contacts queries.
+     * Will return a valid column for call log or contacts queries.
      */
     public static int getNameColumnIndex(Cursor cursor) {
         int typeColumn = cursor.getColumnIndex(CallLog.Calls.CACHED_NAME);
@@ -190,10 +204,10 @@
 
     /**
      * @return The phone number for the contact. Most phones will simply get the value in the
-     *         column returned by {@link #getNumberColumnIndex(Cursor)}. However, some devices
-     *         such as the Galaxy S6 return null for those columns. In those cases, we use the
-     *         contact id (which we hopefully do have) to look up just the phone number for that
-     *         specific contact.
+     * column returned by {@link #getNumberColumnIndex(Cursor)}. However, some devices
+     * such as the Galaxy S6 return null for those columns. In those cases, we use the
+     * contact id (which we hopefully do have) to look up just the phone number for that
+     * specific contact.
      */
     public static String getPhoneNumber(Cursor cursor, ContentResolver cr) {
         int columnIndex = getNumberColumnIndex(cursor);
@@ -210,8 +224,9 @@
 
     /**
      * Return the phone number for the given contact id.
+     *
      * @param columnName On some phones, we have to use non-standard columns for the primary key.
-     * @param id The value in the columnName for the desired contact.
+     * @param id         The value in the columnName for the desired contact.
      * @return The phone number for the given contact or empty string if there was an error.
      */
     public static String getNumberFromContactId(ContentResolver cr, String columnName, String id) {
@@ -227,8 +242,8 @@
 
         Uri uri = ContactsContract.CommonDataKinds.Phone.CONTENT_URI;
         Cursor phoneNumberCursor = cr.query(uri,
-                new String[] {ContactsContract.CommonDataKinds.Phone.NUMBER},
-                columnName + " = ?" , new String[] {id}, null);
+                new String[]{ContactsContract.CommonDataKinds.Phone.NUMBER},
+                columnName + " = ?", new String[]{id}, null);
 
         if (!phoneNumberCursor.moveToFirst()) {
             Log.e(TAG, "Unable to move phone number cursor to the first item.");
diff --git a/src/com/android/car/dialer/telecom/TelecomUtils.java b/src/com/android/car/dialer/telecom/TelecomUtils.java
index ffae765..a0bd4d8 100644
--- a/src/com/android/car/dialer/telecom/TelecomUtils.java
+++ b/src/com/android/car/dialer/telecom/TelecomUtils.java
@@ -38,9 +38,10 @@
 import android.text.format.DateUtils;
 import android.util.Log;
 import android.widget.ImageView;
-import com.android.car.apps.common.CircleBitmapDrawable;
+
 import com.android.car.apps.common.LetterTileDrawable;
 import com.android.car.dialer.R;
+import com.android.car.dialer.ui.CircleBitmapDrawable;
 
 import java.io.InputStream;
 import java.util.Locale;
@@ -48,7 +49,7 @@
 public class TelecomUtils {
     private final static String TAG = "Em.TelecomUtils";
 
-    private static final String[] CONTACT_ID_PROJECTION = new String[] {
+    private static final String[] CONTACT_ID_PROJECTION = new String[]{
             ContactsContract.PhoneLookup.DISPLAY_NAME,
             ContactsContract.PhoneLookup.TYPE,
             ContactsContract.PhoneLookup.LABEL,
@@ -73,6 +74,7 @@
 
     /**
      * Return the contact id for the given contact id
+     *
      * @param id the contact id to get the photo for
      * @return the contact photo if it is found, null otherwise.
      */
@@ -97,6 +99,7 @@
 
     /**
      * Return the contact id for the given phone number.
+     *
      * @param number Caller phone number
      * @return the contact id if it is found, 0 otherwise.
      */
@@ -115,8 +118,7 @@
                 int id = cursor.getInt(cursor.getColumnIndex(ContactsContract.PhoneLookup._ID));
                 return id;
             }
-        }
-        finally {
+        } finally {
             if (cursor != null) {
                 cursor.close();
             }
@@ -126,6 +128,7 @@
 
     /**
      * Return the label for the given phone number.
+     *
      * @param number Caller phone number
      * @return the label if it is found, 0 otherwise.
      */
@@ -154,8 +157,7 @@
                         Phone.getTypeLabel(res, type, label);
                 return typeLabel;
             }
-        }
-        finally {
+        } finally {
             if (cursor != null) {
                 cursor.close();
             }
@@ -220,7 +222,8 @@
         return getDisplayName(context, number, null);
     }
 
-    private static String getDisplayName(Context context, String number, Uri gatewayOriginalAddress) {
+    private static String getDisplayName(Context context, String number,
+            Uri gatewayOriginalAddress) {
         if (Log.isLoggable(TAG, Log.DEBUG)) {
             Log.d(TAG, "getDisplayName: " + number
                     + ", gatewayOriginalAddress: " + gatewayOriginalAddress);
@@ -257,7 +260,7 @@
         String name = null;
         try {
             cursor = cr.query(uri,
-                    new String[] {ContactsContract.PhoneLookup.DISPLAY_NAME}, null, null, null);
+                    new String[]{ContactsContract.PhoneLookup.DISPLAY_NAME}, null, null, null);
             if (cursor != null && cursor.moveToFirst()) {
                 name = cursor.getString(0);
             }
@@ -306,7 +309,7 @@
      */
     public static String callStateToUiString(Context context, int state) {
         Resources res = context.getResources();
-        switch(state) {
+        switch (state) {
             case Call.STATE_ACTIVE:
                 return res.getString(R.string.call_state_call_active);
             case Call.STATE_HOLDING:
@@ -348,23 +351,21 @@
      * @param number A key to have a consisten color per phone number.
      * @return A worker task if a new one was needed to load the bitmap.
      */
-    @Nullable public static ContactBitmapWorker setContactBitmapAsync(Context context,
+    @Nullable
+    public static ContactBitmapWorker setContactBitmapAsync(Context context,
             final ImageView icon, final @Nullable String name, final String number) {
         return ContactBitmapWorker.loadBitmap(context.getContentResolver(), icon, number,
-                new ContactBitmapWorker.BitmapWorkerListener() {
-                    @Override
-                    public void onBitmapLoaded(@Nullable Bitmap bitmap) {
-                        Resources r = icon.getResources();
-                        if (bitmap != null) {
-                            icon.setScaleType(ImageView.ScaleType.CENTER_CROP);
-                            icon.setImageDrawable(new CircleBitmapDrawable(r, bitmap));
-                        } else {
-                            icon.setScaleType(ImageView.ScaleType.CENTER_INSIDE);
-                            LetterTileDrawable letterTileDrawable = new LetterTileDrawable(r);
-                            letterTileDrawable.setContactDetails(name, number);
-                            letterTileDrawable.setIsCircular(true);
-                            icon.setImageDrawable(letterTileDrawable);
-                        }
+                bitmap -> {
+                    Resources r = icon.getResources();
+                    if (bitmap != null) {
+                        icon.setScaleType(ImageView.ScaleType.CENTER_CROP);
+                        icon.setImageDrawable(new CircleBitmapDrawable(r, bitmap));
+                    } else {
+                        icon.setScaleType(ImageView.ScaleType.CENTER_INSIDE);
+                        LetterTileDrawable letterTileDrawable = new LetterTileDrawable(r);
+                        letterTileDrawable.setContactDetails(name, number);
+                        letterTileDrawable.setIsCircular(true);
+                        icon.setImageDrawable(letterTileDrawable);
                     }
                 });
     }
diff --git a/src/com/android/car/dialer/telecom/UiCallManager.java b/src/com/android/car/dialer/telecom/UiCallManager.java
index 95e5139..0e9c2a1 100644
--- a/src/com/android/car/dialer/telecom/UiCallManager.java
+++ b/src/com/android/car/dialer/telecom/UiCallManager.java
@@ -15,6 +15,11 @@
  */
 package com.android.car.dialer.telecom;
 
+import android.bluetooth.BluetoothAdapter;
+import android.bluetooth.BluetoothDevice;
+import android.bluetooth.BluetoothHeadsetClient;
+import android.bluetooth.BluetoothHeadsetClientCall;
+import android.bluetooth.BluetoothProfile;
 import android.content.ComponentName;
 import android.content.Context;
 import android.content.Intent;
@@ -25,15 +30,17 @@
 import android.provider.CallLog;
 import android.telecom.Call;
 import android.telecom.CallAudioState;
+import android.telecom.CallAudioState.CallAudioRoute;
 import android.telecom.DisconnectCause;
 import android.telecom.GatewayInfo;
 import android.telecom.InCallService;
+import android.telecom.PhoneAccountHandle;
 import android.telecom.TelecomManager;
 import android.telephony.TelephonyManager;
 import android.text.TextUtils;
 import android.util.Log;
-import android.view.KeyEvent;
 
+import com.android.car.dialer.CallListener;
 import com.android.car.dialer.R;
 
 import java.lang.ref.WeakReference;
@@ -52,9 +59,12 @@
 public class UiCallManager {
     private static String TAG = "Em.TelecomMgr";
 
+    private static final String HFP_CLIENT_CONNECTION_SERVICE_CLASS_NAME
+            = "com.android.bluetooth.hfpclient.connserv.HfpClientConnectionService";
     // Rate limit how often you can place outgoing calls.
     private static final long MIN_TIME_BETWEEN_CALLS_MS = 3000;
     private static final List<Integer> sCallStateRank = new ArrayList<>();
+    private static UiCallManager sUiCallManager;
 
     // Used to assign id's to UiCall objects as they're created.
     private static int nextCarPhoneCallId = 0;
@@ -78,10 +88,39 @@
 
     private TelecomManager mTelecomManager;
     private InCallServiceImpl mInCallService;
+    private BluetoothHeadsetClient mBluetoothHeadsetClient;
     private final Map<UiCall, Call> mCallMapping = new HashMap<>();
     private final List<CallListener> mCallListeners = new CopyOnWriteArrayList<>();
 
-    public UiCallManager(Context context) {
+    /**
+     * Initialized a globally accessible {@link UiCallManager} which can be retrieved by
+     * {@link #get}. If this function is called a second time before calling {@link #tearDown()},
+     * an exception will be thrown.
+     *
+     * @param applicationContext Application context.
+     */
+    public static UiCallManager init(Context applicationContext) {
+        if (sUiCallManager == null) {
+            sUiCallManager = new UiCallManager(applicationContext);
+        } else {
+            throw new IllegalStateException("UiCallManager has been initialized.");
+        }
+        return sUiCallManager;
+    }
+
+    /**
+     * Gets the global {@link UiCallManager} instance. Make sure
+     * {@link #init(Context)} is called before calling this method.
+     */
+    public static UiCallManager get() {
+        if (sUiCallManager == null) {
+            throw new IllegalStateException(
+                    "Call UiCallManager.init(Context) before calling this function");
+        }
+        return sUiCallManager;
+    }
+
+    private UiCallManager(Context context) {
         if (Log.isLoggable(TAG, Log.DEBUG)) {
             Log.d(TAG, "SetUp");
         }
@@ -93,6 +132,20 @@
         Intent intent = new Intent(context, InCallServiceImpl.class);
         intent.setAction(InCallServiceImpl.ACTION_LOCAL_BIND);
         context.bindService(intent, mInCallServiceConnection, Context.BIND_AUTO_CREATE);
+
+        BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
+        adapter.getProfileProxy(mContext, new BluetoothProfile.ServiceListener() {
+            @Override
+            public void onServiceConnected(int profile, BluetoothProfile proxy) {
+                if (profile == BluetoothProfile.HEADSET_CLIENT) {
+                    mBluetoothHeadsetClient = (BluetoothHeadsetClient) proxy;
+                }
+            }
+
+            @Override
+            public void onServiceDisconnected(int profile) {
+            }
+        }, BluetoothProfile.HEADSET_CLIENT);
     }
 
     private final ServiceConnection mInCallServiceConnection = new ServiceConnection() {
@@ -140,12 +193,20 @@
                 };
     };
 
+    /**
+     * Tears down the {@link UiCallManager}. Calling this function will null out the global
+     * accessible {@link UiCallManager} instance. Remember to re-initialize the
+     * {@link UiCallManager}.
+     */
     public void tearDown() {
         if (mInCallService != null) {
             mContext.unbindService(mInCallServiceConnection);
             mInCallService = null;
         }
         mCallMapping.clear();
+        // Clear out the mContext reference to avoid memory leak.
+        mContext = null;
+        sUiCallManager = null;
     }
 
     public void addListener(CallListener listener) {
@@ -239,6 +300,46 @@
         return audioState != null ? audioState.getSupportedRouteMask() : 0;
     }
 
+    public List<Integer> getSupportedAudioRoute() {
+        List<Integer> audioRouteList = new ArrayList<>();
+
+        boolean isBluetoothPhoneCall = isBluetoothCall();
+        if (isBluetoothPhoneCall) {
+            // if this is bluetooth phone call, we can only select audio route between vehicle
+            // and phone.
+            // Vehicle speaker route.
+            audioRouteList.add(CallAudioState.ROUTE_BLUETOOTH);
+            // Headset route.
+            audioRouteList.add(CallAudioState.ROUTE_EARPIECE);
+        } else {
+            // Most likely we are making phone call with on board SIM card.
+            int supportedAudioRouteMask = getSupportedAudioRouteMask();
+
+            if ((supportedAudioRouteMask & CallAudioState.ROUTE_EARPIECE) != 0) {
+                audioRouteList.add(CallAudioState.ROUTE_EARPIECE);
+            } else if ((supportedAudioRouteMask & CallAudioState.ROUTE_BLUETOOTH) != 0) {
+                audioRouteList.add(CallAudioState.ROUTE_BLUETOOTH);
+            } else if ((supportedAudioRouteMask & CallAudioState.ROUTE_WIRED_HEADSET) != 0) {
+                audioRouteList.add(CallAudioState.ROUTE_WIRED_HEADSET);
+            } else if ((supportedAudioRouteMask & CallAudioState.ROUTE_SPEAKER) != 0) {
+                audioRouteList.add(CallAudioState.ROUTE_SPEAKER);
+            }
+        }
+
+        return audioRouteList;
+    }
+
+    public boolean isBluetoothCall() {
+        PhoneAccountHandle phoneAccountHandle =
+                mTelecomManager.getUserSelectedOutgoingPhoneAccount();
+        if (phoneAccountHandle != null && phoneAccountHandle.getComponentName() != null) {
+            return HFP_CLIENT_CONNECTION_SERVICE_CLASS_NAME.equals(
+                    phoneAccountHandle.getComponentName().getClassName());
+        } else {
+            return false;
+        }
+    }
+
     public int getAudioRoute() {
         CallAudioState audioState = getCallAudioStateOrNull();
         int audioRoute = audioState != null ? audioState.getRoute() : 0;
@@ -248,10 +349,24 @@
         return audioRoute;
     }
 
-    public void setAudioRoute(int audioRoute) {
-        // In case of embedded where the CarKitt is always connected to one kind of speaker we
-        // should simply ignore any setAudioRoute requests.
-        Log.w(TAG, "setAudioRoute ignoring request " + audioRoute);
+    /**
+     * Re-route the audio out phone of the ongoing phone call.
+     */
+    public void setAudioRoute(@CallAudioRoute int audioRoute) {
+        if (mBluetoothHeadsetClient != null && isBluetoothCall()) {
+            for (BluetoothDevice device : mBluetoothHeadsetClient.getConnectedDevices()) {
+                List<BluetoothHeadsetClientCall> currentCalls =
+                        mBluetoothHeadsetClient.getCurrentCalls(device);
+                if (currentCalls != null && !currentCalls.isEmpty()) {
+                    if (audioRoute == CallAudioState.ROUTE_BLUETOOTH) {
+                        mBluetoothHeadsetClient.connectAudio(device);
+                    } else if ((audioRoute & CallAudioState.ROUTE_WIRED_OR_EARPIECE) != 0) {
+                        mBluetoothHeadsetClient.disconnectAudio(device);
+                    }
+                }
+            }
+        }
+        // TODO: Implement routing audio if current call is not a bluetooth call.
     }
 
     public void holdCall(UiCall uiCall) {
@@ -372,7 +487,7 @@
 
     private void onStateChanged(UiCall uiCall, int state) {
         for (CallListener listener : mCallListeners) {
-            listener.onStateChanged(uiCall, state);
+            listener.onCallStateChanged(uiCall, state);
         }
     }
 
@@ -432,21 +547,6 @@
         return mInCallService != null ? mInCallService.getCallAudioState() : null;
     }
 
-    public static class CallListener {
-        @SuppressWarnings("unused")
-        public void dispatchPhoneKeyEvent(KeyEvent event) {}
-        @SuppressWarnings("unused")
-        public void onAudioStateChanged(boolean isMuted, int route, int supportedRouteMask) {}
-        @SuppressWarnings("unused")
-        public void onCallAdded(UiCall call) {}
-        @SuppressWarnings("unused")
-        public void onStateChanged(UiCall call, int state) {}
-        @SuppressWarnings("unused")
-        public void onCallUpdated(UiCall call) {}
-        @SuppressWarnings("unused")
-        public void onCallRemoved(UiCall call) {}
-    }
-
     /** Returns a first call that matches at least one provided call state */
     public UiCall getCallWithState(int... callStates) {
         if (Log.isLoggable(TAG, Log.DEBUG)) {
diff --git a/src/com/android/car/dialer/ui/CallHistoryFragment.java b/src/com/android/car/dialer/ui/CallHistoryFragment.java
new file mode 100644
index 0000000..d5f8e5d
--- /dev/null
+++ b/src/com/android/car/dialer/ui/CallHistoryFragment.java
@@ -0,0 +1,81 @@
+/*
+ * 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.car.dialer.ui;
+
+import android.arch.lifecycle.LiveData;
+import android.arch.lifecycle.ViewModelProviders;
+import android.os.Bundle;
+import android.support.annotation.NonNull;
+import android.support.annotation.Nullable;
+import android.support.v4.app.Fragment;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+
+import androidx.car.widget.ListItemAdapter;
+import androidx.car.widget.PagedListView;
+
+import com.android.car.dialer.R;
+import com.android.car.dialer.telecom.PhoneLoader;
+import com.android.car.dialer.ui.viewmodel.CallHistoryViewModel;
+
+import java.util.List;
+
+public class CallHistoryFragment extends Fragment {
+    public static final String CALL_TYPE_KEY = "CALL_TYPE_KEY";
+
+    public static CallHistoryFragment newInstance(@PhoneLoader.CallType int callType) {
+        CallHistoryFragment fragment = new CallHistoryFragment();
+        Bundle arg = new Bundle();
+        arg.putInt(CALL_TYPE_KEY, callType);
+        fragment.setArguments(arg);
+        return fragment;
+    }
+
+    @Nullable
+    @Override
+    public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container,
+            @Nullable Bundle savedInstanceState) {
+        View fragmentView = inflater.inflate(R.layout.call_list_fragment, container, false);
+        PagedListView pagedListView = fragmentView.findViewById(R.id.list_view);
+        CallHistoryListItemProvider callHistoryListItemProvider = new CallHistoryListItemProvider();
+        ListItemAdapter adapter = new ListItemAdapter(getContext(), callHistoryListItemProvider);
+        pagedListView.setAdapter(adapter);
+
+        int callType = getArguments().getInt(CALL_TYPE_KEY);
+
+        CallHistoryViewModel viewModel = ViewModelProviders.of(this).get(
+                CallHistoryViewModel.class);
+
+        LiveData<List<CallLogListingTask.CallLogItem>> liveData = null;
+        if (callType == PhoneLoader.CallType.CALL_TYPE_ALL) {
+            liveData = viewModel.getCallHistory();
+        } else if (callType == PhoneLoader.CallType.MISSED_TYPE) {
+            liveData = viewModel.getMissedCallHistory();
+        }
+
+        if (liveData != null) {
+            liveData.observe(this,
+                    callHistoryItems -> {
+                        callHistoryListItemProvider.setCallHistoryListItems(getContext(),
+                                callHistoryItems);
+                        adapter.notifyDataSetChanged();
+                    });
+        }
+
+        return fragmentView;
+    }
+}
diff --git a/src/com/android/car/dialer/ui/CallHistoryListItemProvider.java b/src/com/android/car/dialer/ui/CallHistoryListItemProvider.java
new file mode 100644
index 0000000..2eaff9f
--- /dev/null
+++ b/src/com/android/car/dialer/ui/CallHistoryListItemProvider.java
@@ -0,0 +1,60 @@
+/*
+ * 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.car.dialer.ui;
+
+import android.content.Context;
+import android.graphics.drawable.BitmapDrawable;
+
+import androidx.car.widget.ListItem;
+import androidx.car.widget.ListItemProvider;
+import androidx.car.widget.TextListItem;
+
+import com.android.car.dialer.telecom.UiCallManager;
+import com.android.car.dialer.ui.listitem.CallLogListItem;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public class CallHistoryListItemProvider extends ListItemProvider {
+
+    private List<TextListItem> mItems = new ArrayList<>();
+
+    public void setCallHistoryListItems(Context context,
+            List<CallLogListingTask.CallLogItem> items) {
+        for (CallLogListingTask.CallLogItem callLogItem : items) {
+            TextListItem callLogListItem = new CallLogListItem(context, callLogItem);
+
+            callLogListItem.setPrimaryActionIcon(
+                    new BitmapDrawable(context.getResources(), callLogItem.mIcon), true);
+            callLogListItem.setTitle(callLogItem.mTitle);
+            callLogListItem.setBody(callLogItem.mText);
+            callLogListItem.setOnClickListener(
+                    (v) -> UiCallManager.get().safePlaceCall(callLogItem.mNumber, false));
+
+            mItems.add(callLogListItem);
+        }
+    }
+
+    @Override
+    public ListItem get(int position) {
+        return mItems.get(position);
+    }
+
+    @Override
+    public int size() {
+        return mItems.size();
+    }
+}
diff --git a/src/com/android/car/dialer/ui/CallLogListingTask.java b/src/com/android/car/dialer/ui/CallLogListingTask.java
new file mode 100644
index 0000000..5a73d1b
--- /dev/null
+++ b/src/com/android/car/dialer/ui/CallLogListingTask.java
@@ -0,0 +1,181 @@
+/*
+ * 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.car.dialer.ui;
+
+import static android.provider.ContactsContract.CommonDataKinds.Phone.getTypeLabel;
+
+import android.content.Context;
+import android.database.Cursor;
+import android.graphics.Bitmap;
+import android.os.AsyncTask;
+import android.provider.CallLog;
+import android.support.annotation.NonNull;
+import android.telephony.PhoneNumberUtils;
+import android.text.TextUtils;
+import android.text.format.DateUtils;
+
+import com.android.car.dialer.ContactEntry;
+import com.android.car.dialer.R;
+import com.android.car.dialer.telecom.InMemoryPhoneBook;
+import com.android.car.dialer.telecom.PhoneLoader;
+import com.android.car.dialer.telecom.TelecomUtils;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Async task which loads call history.
+ */
+public class CallLogListingTask extends AsyncTask<Void, Void, Void> {
+    public static class CallLogItem {
+        public final String mTitle;
+        public final String mText;
+        public final String mNumber;
+        public final Bitmap mIcon;
+
+        public CallLogItem(String title, String text, String number, Bitmap icon) {
+            mTitle = title;
+            mText = text;
+            mNumber = number;
+            mIcon = icon;
+        }
+    }
+
+    public interface LoadCompleteListener {
+        void onLoadComplete(List<CallLogItem> items);
+    }
+
+    private Context mContext;
+    private Cursor mCursor;
+    private List<CallLogItem> mItems;
+    private LoadCompleteListener mListener;
+
+    public CallLogListingTask(Context context, Cursor cursor,
+            @NonNull LoadCompleteListener listener) {
+        mContext = context;
+        mCursor = cursor;
+        mItems = new ArrayList<>(mCursor.getCount());
+        mListener = listener;
+    }
+
+    private String maybeAppendCount(StringBuilder sb, int count) {
+        if (count > 1) {
+            sb.append(" (").append(count).append(")");
+        }
+        return sb.toString();
+    }
+
+    private String getContactName(String cachedName, String number, int count,
+            boolean isVoicemail) {
+        StringBuilder sb = new StringBuilder();
+        if (isVoicemail) {
+            sb.append(mContext.getString(R.string.voicemail));
+        } else if (cachedName != null) {
+            sb.append(cachedName);
+        } else if (!TextUtils.isEmpty(number)) {
+            sb.append(TelecomUtils.getFormattedNumber(mContext, number));
+        } else {
+            sb.append(mContext.getString(R.string.unknown));
+        }
+        return maybeAppendCount(sb, count);
+    }
+
+    private static CharSequence getRelativeTime(long millis) {
+        boolean validTimestamp = millis > 0;
+
+        return validTimestamp ? DateUtils.getRelativeTimeSpanString(
+                millis, System.currentTimeMillis(), DateUtils.MINUTE_IN_MILLIS,
+                DateUtils.FORMAT_ABBREV_RELATIVE) : null;
+    }
+
+    @Override
+    protected Void doInBackground(Void... voids) {
+        if (mCursor != null) {
+            try {
+                int numberColumn = PhoneLoader.getNumberColumnIndex(mCursor);
+                int dateColumn = mCursor.getColumnIndex(CallLog.Calls.DATE);
+
+                while (mCursor.moveToNext()) {
+                    int count = 1;
+                    String number = mCursor.getString(numberColumn);
+                    // We want to group calls to the same number into one so seek
+                    // forward as many
+                    // entries as possible as long as the number is the same.
+                    int position = mCursor.getPosition();
+                    while (mCursor.moveToNext()) {
+                        String nextNumber = mCursor.getString(numberColumn);
+                        if (PhoneNumberUtils.compare(mContext, number, nextNumber)) {
+                            count++;
+                        } else {
+                            break;
+                        }
+                    }
+
+                    mCursor.moveToPosition(position);
+
+                    boolean isVoicemail = PhoneNumberUtils.isVoiceMailNumber(number);
+                    ContactEntry contactEntry = InMemoryPhoneBook.get().lookupContactEntry(number);
+                    String nameWithCount = getContactName(
+                            contactEntry != null ? contactEntry.getDisplayName() : null,
+                            number,
+                            count,
+                            isVoicemail);
+
+                    // Not sure why this is the only column checked here but I'm
+                    // assuming this was to work around some bug on some device.
+                    long millis = dateColumn == -1 ? 0 : mCursor.getLong(dateColumn);
+
+                    StringBuffer secondaryTextStringBuilder = new StringBuffer();
+                    CharSequence relativeDate = getRelativeTime(millis);
+
+                    // Append the type (work, mobile etc.) if it isn't voicemail.
+                    if (!isVoicemail) {
+                        CharSequence type = contactEntry != null
+                                ? getTypeLabel(mContext.getResources(), contactEntry.getType(),
+                                contactEntry.getLabel())
+                                : "";
+                        secondaryTextStringBuilder.append(type);
+                        if (!TextUtils.isEmpty(type) && !TextUtils.isEmpty(relativeDate)) {
+                            secondaryTextStringBuilder.append(", ");
+                        }
+                    }
+                    // Add in the timestamp.
+                    if (relativeDate != null) {
+                        secondaryTextStringBuilder.append(relativeDate);
+                    }
+
+                    CallLogItem item = new CallLogItem(nameWithCount,
+                            secondaryTextStringBuilder.toString(),
+                            number, null);
+                    mItems.add(item);
+                    // Since we deduplicated count rows, we can move all the way to that row so the
+                    // next iteration takes us to the row following the last duplicate row.
+                    if (count > 1) {
+                        mCursor.moveToPosition(position + count - 1);
+                    }
+                }
+            } finally {
+                mCursor.close();
+            }
+        }
+        return null;
+    }
+
+    @Override
+    protected void onPostExecute(Void aVoid) {
+        mListener.onLoadComplete(mItems);
+    }
+}
diff --git a/src/com/android/car/dialer/ui/CircleBitmapDrawable.java b/src/com/android/car/dialer/ui/CircleBitmapDrawable.java
new file mode 100644
index 0000000..1d35726
--- /dev/null
+++ b/src/com/android/car/dialer/ui/CircleBitmapDrawable.java
@@ -0,0 +1,115 @@
+/*
+ * 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.car.dialer.ui;
+
+import android.content.res.Resources;
+import android.graphics.Bitmap;
+import android.graphics.Canvas;
+import android.graphics.ColorFilter;
+import android.graphics.PixelFormat;
+import android.graphics.Rect;
+import android.graphics.drawable.Drawable;
+import android.support.annotation.NonNull;
+import android.support.v4.graphics.drawable.RoundedBitmapDrawable;
+import android.support.v4.graphics.drawable.RoundedBitmapDrawableFactory;
+
+
+/**
+ * A drawable for displaying a circular bitmap. This is a wrapper over {@link RoundedBitmapDrawable}
+ * since that implementation doesn't behave quite as desired.
+ *
+ * <p>Note that not all drawable functionality is passed to the RoundedBitmapDrawable at this
+ * time. Feel free to add more as necessary.
+ */
+public class CircleBitmapDrawable extends Drawable {
+    private final Resources mResources;
+
+    private Bitmap mBitmap;
+    private RoundedBitmapDrawable mDrawable;
+    private int mAlpha = -1;
+    private ColorFilter mCf = null;
+
+    public CircleBitmapDrawable(@NonNull Resources res, @NonNull Bitmap bitmap) {
+        mBitmap = bitmap;
+        mResources = res;
+    }
+
+    @Override
+    public void onBoundsChange(Rect bounds) {
+        super.onBoundsChange(bounds);
+        int width = bounds.right - bounds.left;
+        int height = bounds.bottom - bounds.top;
+
+        Bitmap processed = mBitmap;
+        mDrawable = RoundedBitmapDrawableFactory.create(mResources, processed);
+        mDrawable.setBounds(bounds);
+        mDrawable.setAntiAlias(true);
+        mDrawable.setCornerRadius(Math.min(width, height) / 2f);
+        if (mAlpha != -1) {
+            mDrawable.setAlpha(mAlpha);
+        }
+        if (mCf != null) {
+            mDrawable.setColorFilter(mCf);
+        }
+        invalidateSelf();
+    }
+
+    @Override
+    public void draw(Canvas canvas) {
+        if (mDrawable != null) {
+            mDrawable.draw(canvas);
+        }
+    }
+
+    @Override
+    public int getOpacity() {
+        return mDrawable != null ? mDrawable.getOpacity() : PixelFormat.TRANSLUCENT;
+    }
+
+    @Override
+    public void setAlpha(int alpha) {
+        mAlpha = alpha;
+        if (mDrawable != null) {
+            mDrawable.setAlpha(alpha);
+            invalidateSelf();
+        }
+    }
+
+    @Override
+    public void setColorFilter(ColorFilter cf) {
+        mCf = cf;
+        if (mDrawable != null) {
+            mDrawable.setColorFilter(cf);
+            invalidateSelf();
+        }
+    }
+
+    /**
+     * Convert the drawable to a bitmap.
+     * @param size The target size of the bitmap in pixels.
+     * @return A bitmap representation of the drawable.
+     */
+    public Bitmap toBitmap(int size) {
+        Bitmap largeIcon = Bitmap.createBitmap(size, size, Bitmap.Config.ARGB_8888);
+        Canvas canvas = new Canvas(largeIcon);
+        Rect bounds = getBounds();
+        setBounds(0, 0, canvas.getWidth(), canvas.getHeight());
+        draw(canvas);
+        setBounds(bounds);
+        return largeIcon;
+    }
+}
+
diff --git a/src/com/android/car/dialer/ui/ContactListFragment.java b/src/com/android/car/dialer/ui/ContactListFragment.java
new file mode 100644
index 0000000..21e2613
--- /dev/null
+++ b/src/com/android/car/dialer/ui/ContactListFragment.java
@@ -0,0 +1,211 @@
+/*
+ * 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.car.dialer.ui;
+
+import android.content.Context;
+import android.database.Cursor;
+import android.graphics.Bitmap;
+import android.net.Uri;
+import android.os.Bundle;
+import android.provider.ContactsContract;
+import android.support.annotation.NonNull;
+import android.support.annotation.Nullable;
+import android.support.v4.app.Fragment;
+import android.support.v4.app.LoaderManager;
+import android.support.v4.content.CursorLoader;
+import android.support.v4.content.Loader;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.TextView;
+
+import androidx.car.widget.AlphaJumpBucketer;
+import androidx.car.widget.IAlphaJumpAdapter;
+import androidx.car.widget.ListItemAdapter;
+import androidx.car.widget.PagedListView;
+
+import com.android.car.dialer.ContactDetailsFragment;
+import com.android.car.dialer.R;
+import com.android.car.dialer.telecom.PhoneLoader;
+import com.android.car.dialer.telecom.TelecomUtils;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+
+/**
+ * Contact Fragment.
+ */
+public class ContactListFragment extends Fragment implements LoaderManager.LoaderCallbacks<Cursor>,
+        ContactListItemProvider.OnShowContactDetailListener {
+    private static final int CONTACT_LOADER_ID = 1;
+
+    private PagedListView mPagedListView;
+
+    public static ContactListFragment newInstance() {
+        ContactListFragment fragment = new ContactListFragment();
+        return fragment;
+    }
+
+    @Override
+    public void onCreate(@Nullable Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        LoaderManager loaderManager = LoaderManager.getInstance(this);
+        loaderManager.initLoader(CONTACT_LOADER_ID, null, this);
+    }
+
+    @Override
+    public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container,
+            @Nullable Bundle savedInstanceState) {
+        View fragmentView = inflater.inflate(R.layout.contact_list_fragment, container, false);
+        mPagedListView = fragmentView.findViewById(R.id.list_view);
+        ((TextView) fragmentView.findViewById(R.id.title)).setText(
+                getContext().getString(R.string.contacts_title));
+        return fragmentView;
+    }
+
+    @Override
+    public Loader<Cursor> onCreateLoader(int i, @Nullable Bundle bundle) {
+        return new CursorLoader(
+                getContext(),
+                ContactsContract.Data.CONTENT_URI,
+                null,
+                ContactsContract.Data.MIMETYPE + " = '" + ContactsContract.CommonDataKinds.Phone
+                        .CONTENT_ITEM_TYPE + "'",
+                null,
+                ContactsContract.Contacts.DISPLAY_NAME + " ASC "
+        );
+    }
+
+    @Override
+    public void onLoadFinished(@NonNull Loader loader, Cursor cursor) {
+        List<ContactItem> contactItems = new ArrayList<>();
+        while (cursor.moveToNext()) {
+            String number = PhoneLoader.getPhoneNumber(cursor, getContext().getContentResolver());
+
+            int idColumnIndex = PhoneLoader.getIdColumnIndex(cursor);
+            int id = cursor.getInt(idColumnIndex);
+
+            int displayNameColumnIndex = cursor.getColumnIndex(
+                    ContactsContract.Contacts.DISPLAY_NAME);
+            String displayName = cursor.getString(displayNameColumnIndex);
+
+            int lookupKeyColumnIndex = cursor.getColumnIndex(
+                    ContactsContract.Contacts.LOOKUP_KEY);
+            String lookupKey = cursor.getString(lookupKeyColumnIndex);
+
+            contactItems.add(new ContactItem(number, id, displayName, null, lookupKey));
+        }
+
+        ListItemAdapter contactListAdapter = new ListItemAdapter(getContext(),
+                new ContactListItemProvider(getContext(), contactItems, ContactListFragment.this));
+        mPagedListView.setAdapter(contactListAdapter);
+        contactListAdapter.notifyDataSetChanged();
+    }
+
+    @Override
+    public void onLoaderReset(@NonNull Loader loader) {
+    }
+
+    @Override
+    public void onShowContactDetail(int contactId, String lookupKey) {
+        View contactDetailContainer =
+                getView().findViewById(R.id.contact_detail_container);
+        contactDetailContainer.setVisibility(View.VISIBLE);
+        setActivityActionBarVisibility(View.GONE);
+
+        final Uri uri = ContactsContract.Contacts.getLookupUri(contactId, lookupKey);
+        Fragment contactDetailFragment = ContactDetailsFragment.newInstance(uri, null);
+        getChildFragmentManager().beginTransaction().replace(R.id.contact_detail_fragment_container,
+                contactDetailFragment).commit();
+
+        getView().findViewById(R.id.back_button).setOnClickListener((v) -> {
+            getChildFragmentManager().beginTransaction().remove(contactDetailFragment).commit();
+            contactDetailContainer.setVisibility(View.GONE);
+            setActivityActionBarVisibility(View.VISIBLE);
+        });
+
+    }
+
+    private void setActivityActionBarVisibility(int visibility) {
+        View actionBar = getActivity().getWindow().getDecorView().findViewById(R.id.car_toolbar);
+        if (actionBar != null) {
+            actionBar.setVisibility(visibility);
+        }
+    }
+
+    /**
+     * Pojo which holds a contact entry information.
+     */
+    public static class ContactItem {
+        public final String mNumber;
+        public final int mId;
+        public final String mDisplayName;
+        public final Bitmap mIcon;
+        public final String mLookupKey;
+
+        private ContactItem(String number, int id, String displayName, Bitmap icon,
+                String lookupKey) {
+            mNumber = number;
+            mId = id;
+            mDisplayName = displayName;
+            mIcon = icon;
+            mLookupKey = lookupKey;
+        }
+    }
+
+    /**
+     * Use this Adapter to enabled AlphaJump.
+     */
+    private class ContactListAdapter extends ListItemAdapter implements IAlphaJumpAdapter {
+
+        List<ContactItem> mContactItems;
+
+        public ContactListAdapter(Context context,
+                List<ContactItem> contactItems) {
+            super(context,
+                    new ContactListItemProvider(context, contactItems, ContactListFragment.this));
+            mContactItems = contactItems;
+        }
+
+        public ContactListAdapter(Context context, List<ContactItem> contactItems,
+                int backgroundStyle) {
+            super(context,
+                    new ContactListItemProvider(context, contactItems, ContactListFragment.this),
+                    backgroundStyle);
+            mContactItems = contactItems;
+        }
+
+        @Override
+        public Collection<Bucket> getAlphaJumpBuckets() {
+            AlphaJumpBucketer alphaJumpBucketer = new AlphaJumpBucketer();
+            List<String> values = new ArrayList<>();
+            for (ContactItem contactItem : mContactItems) {
+                values.add(contactItem.mDisplayName);
+            }
+
+            return alphaJumpBucketer.createBuckets(values.toArray(new String[]{}));
+        }
+
+        @Override
+        public void onAlphaJumpEnter() {
+        }
+
+        @Override
+        public void onAlphaJumpLeave(Bucket bucket) {
+        }
+    }
+}
diff --git a/src/com/android/car/dialer/ui/ContactListItemProvider.java b/src/com/android/car/dialer/ui/ContactListItemProvider.java
new file mode 100644
index 0000000..7ad56c4
--- /dev/null
+++ b/src/com/android/car/dialer/ui/ContactListItemProvider.java
@@ -0,0 +1,77 @@
+/*
+ * 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.car.dialer.ui;
+
+import android.content.Context;
+import android.graphics.drawable.BitmapDrawable;
+import android.graphics.drawable.Drawable;
+
+import androidx.car.widget.ListItem;
+import androidx.car.widget.ListItemProvider;
+import androidx.car.widget.TextListItem;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import com.android.car.dialer.R;
+import com.android.car.dialer.telecom.UiCallManager;
+import com.android.car.dialer.ui.listitem.ContactListItem;
+
+/**
+ * Provides ListItem for contact list.
+ */
+public class ContactListItemProvider extends ListItemProvider {
+
+    private final List<TextListItem> mItems = new ArrayList<>();
+    private final OnShowContactDetailListener mOnShowContactDetailListener;
+
+    public interface OnShowContactDetailListener {
+        void onShowContactDetail(int contactId, String lookupKey);
+    }
+
+    public ContactListItemProvider(Context context, List<ContactListFragment.ContactItem> items,
+            OnShowContactDetailListener onShowContactDetailListener) {
+        mOnShowContactDetailListener = onShowContactDetailListener;
+        for (ContactListFragment.ContactItem contactItem : items) {
+            ContactListItem textListItem = new ContactListItem(context, contactItem);
+            textListItem.setPrimaryActionIcon(
+                    new BitmapDrawable(context.getResources(), contactItem.mIcon), true);
+            textListItem.setTitle(contactItem.mDisplayName);
+            textListItem.setOnClickListener(
+                    (v) -> UiCallManager.get().safePlaceCall(contactItem.mNumber, true));
+            Drawable supplementalIconDrawable = context.getDrawable(R.drawable.ic_contact);
+            supplementalIconDrawable.setTint(context.getColor(R.color.car_tint));
+            int iconSize = context.getResources().getDimensionPixelSize(
+                    R.dimen.car_primary_icon_size);
+            supplementalIconDrawable.setBounds(0, 0, iconSize, iconSize);
+            textListItem.setSupplementalIcon(supplementalIconDrawable, true, (v) -> {
+                mOnShowContactDetailListener.onShowContactDetail(contactItem.mId,
+                        contactItem.mLookupKey);
+            });
+            mItems.add(textListItem);
+        }
+    }
+
+    @Override
+    public ListItem get(int position) {
+        return mItems.get(position);
+    }
+
+    @Override
+    public int size() {
+        return mItems.size();
+    }
+}
diff --git a/src/com/android/car/dialer/ui/DialerInfoController.java b/src/com/android/car/dialer/ui/DialerInfoController.java
new file mode 100644
index 0000000..239c491
--- /dev/null
+++ b/src/com/android/car/dialer/ui/DialerInfoController.java
@@ -0,0 +1,173 @@
+/*
+ * 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.car.dialer.ui;
+
+import android.content.Context;
+import android.telecom.Call;
+import android.text.TextUtils;
+import android.view.View;
+import android.widget.ImageButton;
+import android.widget.ImageView;
+import android.widget.TextView;
+
+import com.android.car.apps.common.FabDrawable;
+import com.android.car.dialer.R;
+import com.android.car.dialer.telecom.TelecomUtils;
+import com.android.car.dialer.telecom.UiCall;
+import com.android.car.dialer.telecom.UiCallManager;
+
+/**
+ * Controls dialer information such as dialed number and shows proper action based on current call
+ * state.
+ */
+public class DialerInfoController {
+    private static final int MAX_DIAL_NUMBER = 20;
+
+    private TextView mTitleView;
+    private TextView mBodyView;
+
+    private ImageButton mCallButton;
+    private ImageButton mDeleteButton;
+
+    private ImageButton mEndCallButton;
+    private ImageButton mMuteButton;
+
+    private Context mContext;
+
+    private final StringBuffer mNumber = new StringBuffer(MAX_DIAL_NUMBER);
+
+    public DialerInfoController(Context context, View container) {
+        mContext = context;
+        init(container);
+    }
+
+    public View init(View container) {
+        mTitleView = container.findViewById(R.id.title);
+        mBodyView = container.findViewById(R.id.body);
+        mCallButton = container.findViewById(R.id.call_button);
+        mDeleteButton = container.findViewById(R.id.delete_button);
+        mEndCallButton = container.findViewById(R.id.end_call_button);
+        mMuteButton = container.findViewById(R.id.mute_button);
+
+        FabDrawable answerCallDrawable = new FabDrawable(mContext);
+        answerCallDrawable.setFabAndStrokeColor(mContext.getColor(R.color.phone_call));
+        mCallButton.setBackground(answerCallDrawable);
+        mCallButton.setOnClickListener((unusedView) -> {
+            if (!TextUtils.isEmpty(mNumber.toString())) {
+                UiCallManager.get().safePlaceCall(mNumber.toString(), false);
+            }
+        });
+        mDeleteButton.setOnClickListener(v -> {
+            removeLastDigit();
+        });
+        mDeleteButton.setOnLongClickListener(v -> {
+            // Clear all on long-press
+            clearDialedNumber();
+            return true;
+        });
+
+        updateView();
+
+        return container;
+    }
+
+    /**
+     * Append more number to the end of dialed number.
+     */
+    public void appendDialedNumber(String number) {
+        if (mNumber.length() < MAX_DIAL_NUMBER) {
+            mNumber.append(number);
+            mTitleView.setText(getFormattedNumber(mNumber.toString()));
+        }
+    }
+
+    /**
+     * Remove last digit of the dialed number. If there's no number left to delete, there's no
+     * operation to be take.
+     */
+    public void removeLastDigit() {
+        if (mNumber.length() != 0) {
+            mNumber.deleteCharAt(mNumber.length() - 1);
+            mTitleView.setText(getFormattedNumber(mNumber.toString()));
+        }
+        UiCall primaryCall = UiCallManager.get().getPrimaryCall();
+
+        if (mNumber.length() == 0 && primaryCall != null
+                && primaryCall.getState() != Call.STATE_ACTIVE) {
+            mTitleView.setText(R.string.dial_a_number);
+        }
+    }
+
+    private void updateView() {
+        UiCall onGoingCall = UiCallManager.get().getPrimaryCall();
+        if (onGoingCall == null) {
+            showPreDialUi();
+        } else if (onGoingCall.getState() == Call.STATE_CONNECTING) {
+            showDialingUi(onGoingCall);
+        } else if (onGoingCall.getState() == Call.STATE_ACTIVE) {
+            showInCallUi();
+        }
+    }
+
+    private void showPreDialUi() {
+        mCallButton.setVisibility(View.VISIBLE);
+        mDeleteButton.setVisibility(View.VISIBLE);
+
+        mEndCallButton.setVisibility(View.GONE);
+        mMuteButton.setVisibility(View.GONE);
+    }
+
+    private void showDialingUi(UiCall uiCall) {
+        if (mTitleView.getText().equals(mContext.getString(R.string.dial_a_number))) {
+            mTitleView.setText("");
+        }
+        FabDrawable endCallDrawable = new FabDrawable(mContext);
+        endCallDrawable.setFabAndStrokeColor(mContext.getColor(R.color.phone_end_call));
+        mEndCallButton.setBackground(endCallDrawable);
+        mEndCallButton.setVisibility(View.VISIBLE);
+        mMuteButton.setVisibility(View.VISIBLE);
+        mBodyView.setVisibility(View.VISIBLE);
+
+        mDeleteButton.setVisibility(View.GONE);
+        mCallButton.setVisibility(View.GONE);
+        bindUserProfileView(uiCall);
+    }
+
+    private void showInCallUi() {
+        if (mTitleView.getText().equals(mContext.getString(R.string.dial_a_number))) {
+            mTitleView.setText("");
+        }
+        mEndCallButton.setVisibility(View.GONE);
+        mDeleteButton.setVisibility(View.GONE);
+        mCallButton.setVisibility(View.GONE);
+    }
+
+    private String getFormattedNumber(String number) {
+        return TelecomUtils.getFormattedNumber(mContext, number);
+    }
+
+    private void clearDialedNumber() {
+        mNumber.setLength(0);
+        mTitleView.setText(getFormattedNumber(mNumber.toString()));
+    }
+
+    private void bindUserProfileView(UiCall primaryCall) {
+        if (primaryCall == null) {
+            return;
+        }
+        mTitleView.setText(TelecomUtils.getDisplayName(mContext, primaryCall));
+    }
+}
diff --git a/src/com/android/car/dialer/ui/DialpadFragment.java b/src/com/android/car/dialer/ui/DialpadFragment.java
new file mode 100644
index 0000000..863f740
--- /dev/null
+++ b/src/com/android/car/dialer/ui/DialpadFragment.java
@@ -0,0 +1,222 @@
+/*
+ * 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.car.dialer.ui;
+
+import android.media.AudioManager;
+import android.media.ToneGenerator;
+import android.os.Bundle;
+import android.support.annotation.NonNull;
+import android.support.annotation.Nullable;
+import android.support.v4.app.Fragment;
+import android.util.SparseArray;
+import android.util.SparseIntArray;
+import android.view.KeyEvent;
+import android.view.LayoutInflater;
+import android.view.MotionEvent;
+import android.view.View;
+import android.view.ViewGroup;
+
+import com.android.car.dialer.R;
+import com.android.car.dialer.telecom.UiCallManager;
+
+/**
+ * Dialpad Fragment which displays a dialpad.
+ */
+public class DialpadFragment extends Fragment {
+    private static final SparseIntArray sToneMap = new SparseIntArray();
+    private static final SparseArray<String> sDialValueMap = new SparseArray<>();
+    private static final SparseArray<Integer> sRIdMap = new SparseArray<>();
+
+    private static final int TONE_LENGTH_INFINITE = -1;
+    private static final int TONE_RELATIVE_VOLUME = 80;
+
+    static {
+        sToneMap.put(KeyEvent.KEYCODE_1, ToneGenerator.TONE_DTMF_1);
+        sToneMap.put(KeyEvent.KEYCODE_2, ToneGenerator.TONE_DTMF_2);
+        sToneMap.put(KeyEvent.KEYCODE_3, ToneGenerator.TONE_DTMF_3);
+        sToneMap.put(KeyEvent.KEYCODE_4, ToneGenerator.TONE_DTMF_4);
+        sToneMap.put(KeyEvent.KEYCODE_5, ToneGenerator.TONE_DTMF_5);
+        sToneMap.put(KeyEvent.KEYCODE_6, ToneGenerator.TONE_DTMF_6);
+        sToneMap.put(KeyEvent.KEYCODE_7, ToneGenerator.TONE_DTMF_7);
+        sToneMap.put(KeyEvent.KEYCODE_8, ToneGenerator.TONE_DTMF_8);
+        sToneMap.put(KeyEvent.KEYCODE_9, ToneGenerator.TONE_DTMF_9);
+        sToneMap.put(KeyEvent.KEYCODE_0, ToneGenerator.TONE_DTMF_0);
+        sToneMap.put(KeyEvent.KEYCODE_STAR, ToneGenerator.TONE_DTMF_S);
+        sToneMap.put(KeyEvent.KEYCODE_POUND, ToneGenerator.TONE_DTMF_P);
+
+        sDialValueMap.put(KeyEvent.KEYCODE_1, "1");
+        sDialValueMap.put(KeyEvent.KEYCODE_2, "2");
+        sDialValueMap.put(KeyEvent.KEYCODE_3, "3");
+        sDialValueMap.put(KeyEvent.KEYCODE_4, "4");
+        sDialValueMap.put(KeyEvent.KEYCODE_5, "5");
+        sDialValueMap.put(KeyEvent.KEYCODE_6, "6");
+        sDialValueMap.put(KeyEvent.KEYCODE_7, "7");
+        sDialValueMap.put(KeyEvent.KEYCODE_8, "8");
+        sDialValueMap.put(KeyEvent.KEYCODE_9, "9");
+        sDialValueMap.put(KeyEvent.KEYCODE_0, "0");
+        sDialValueMap.put(KeyEvent.KEYCODE_STAR, "*");
+        sDialValueMap.put(KeyEvent.KEYCODE_POUND, "#");
+
+        sRIdMap.put(KeyEvent.KEYCODE_1, R.id.one);
+        sRIdMap.put(KeyEvent.KEYCODE_2, R.id.two);
+        sRIdMap.put(KeyEvent.KEYCODE_3, R.id.three);
+        sRIdMap.put(KeyEvent.KEYCODE_4, R.id.four);
+        sRIdMap.put(KeyEvent.KEYCODE_5, R.id.five);
+        sRIdMap.put(KeyEvent.KEYCODE_6, R.id.six);
+        sRIdMap.put(KeyEvent.KEYCODE_7, R.id.seven);
+        sRIdMap.put(KeyEvent.KEYCODE_8, R.id.eight);
+        sRIdMap.put(KeyEvent.KEYCODE_9, R.id.nine);
+        sRIdMap.put(KeyEvent.KEYCODE_0, R.id.zero);
+        sRIdMap.put(KeyEvent.KEYCODE_STAR, R.id.star);
+        sRIdMap.put(KeyEvent.KEYCODE_POUND, R.id.pound);
+    }
+
+    public static DialpadFragment newInstance() {
+        return new DialpadFragment();
+    }
+
+    /**
+     * Callback for dialpad to interact with its host.
+     */
+    public interface DialpadCallback {
+        /**
+         * Called when voice mail should be dialed.
+         */
+        void onDialVoiceMail();
+
+        /**
+         * Called when a digit should be append.
+         */
+        void onAppendDigit(String digit);
+    }
+
+    private ToneGenerator mToneGenerator;
+    private DialpadCallback mDialpadCallback;
+
+    @Override
+    public void onCreate(@Nullable Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        mToneGenerator = new ToneGenerator(AudioManager.STREAM_MUSIC, TONE_RELATIVE_VOLUME);
+    }
+
+    @Override
+    public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container,
+            @Nullable Bundle savedInstanceState) {
+        if (getParentFragment() != null && getParentFragment() instanceof DialpadCallback) {
+            mDialpadCallback = (DialpadCallback) getParentFragment();
+        } else if (getHost() instanceof DialpadCallback) {
+            mDialpadCallback = (DialpadCallback) getHost();
+        }
+
+        View dialpadView = inflater.inflate(R.layout.dialpad, container, false);
+        setupKeypadClickListeners(dialpadView);
+        return dialpadView;
+    }
+
+    @Override
+    public void onPause() {
+        super.onPause();
+        stopTone();
+    }
+
+    /**
+     * The click listener for all dialpad buttons.  Reacts to touch-down and touch-up events, as
+     * well as long-press for certain keys.  Mimics the behavior of the phone dialer app.
+     */
+    private class DialpadClickListener implements View.OnTouchListener,
+            View.OnLongClickListener {
+        private final int mTone;
+        private final String mValue;
+
+        DialpadClickListener(int keyCode) {
+            mTone = sToneMap.get(keyCode);
+            mValue = sDialValueMap.get(keyCode);
+        }
+
+        @Override
+        public boolean onLongClick(View v) {
+            switch (mValue) {
+                case "0":
+                    if (mDialpadCallback != null) {
+                        mDialpadCallback.onAppendDigit("+");
+                    }
+                    stopTone();
+                    return true;
+                case "1":
+                    // TODO: this currently does not work (at least over bluetooth HFP), because
+                    // the framework is unable to get the voicemail number. Revisit later...
+                    if (mDialpadCallback != null) {
+                        mDialpadCallback.onDialVoiceMail();
+                    }
+                    return true;
+                default:
+                    return false;
+            }
+        }
+
+        @Override
+        public boolean onTouch(View v, MotionEvent event) {
+            UiCallManager uiCallmanager = UiCallManager.get();
+            boolean hasActiveCall = uiCallmanager.getPrimaryCall() != null;
+            if (event.getAction() == MotionEvent.ACTION_DOWN) {
+                if (mDialpadCallback != null) {
+                    mDialpadCallback.onAppendDigit(mValue);
+                }
+                if (hasActiveCall) {
+                    uiCallmanager.playDtmfTone(uiCallmanager.getPrimaryCall(), mValue.charAt(0));
+                } else {
+                    playTone(mTone);
+                }
+            } else if (event.getAction() == MotionEvent.ACTION_UP) {
+                if (hasActiveCall) {
+                    uiCallmanager.stopDtmfTone(uiCallmanager.getPrimaryCall());
+                } else {
+                    stopTone();
+                }
+            }
+
+            // Continue propagating the touch event
+            return false;
+        }
+    }
+
+    private void playTone(int tone) {
+        if (mToneGenerator == null) {
+            return;
+        }
+
+        // Start the new tone
+        mToneGenerator.startTone(tone, TONE_LENGTH_INFINITE);
+    }
+
+    private void stopTone() {
+        if (mToneGenerator == null) {
+            return;
+        }
+
+        mToneGenerator.stopTone();
+    }
+
+    private void setupKeypadClickListeners(View parent) {
+        for (int i = 0; i < sRIdMap.size(); i++) {
+            int key = sRIdMap.keyAt(i);
+            DialpadClickListener clickListener = new DialpadClickListener(key);
+            View v = parent.findViewById(sRIdMap.get(key));
+            v.setOnTouchListener(clickListener);
+            v.setOnLongClickListener(clickListener);
+        }
+    }
+}
diff --git a/src/com/android/car/dialer/ui/InCallFragment.java b/src/com/android/car/dialer/ui/InCallFragment.java
new file mode 100644
index 0000000..ff0e2ff
--- /dev/null
+++ b/src/com/android/car/dialer/ui/InCallFragment.java
@@ -0,0 +1,188 @@
+/*
+ * 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.car.dialer.ui;
+
+import static android.telecom.Call.STATE_RINGING;
+
+import android.os.Bundle;
+import android.os.Handler;
+import android.support.annotation.NonNull;
+import android.support.annotation.Nullable;
+import android.support.v4.app.Fragment;
+import android.telecom.Call;
+import android.text.TextUtils;
+import android.text.format.DateUtils;
+import android.util.Log;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.ImageView;
+import android.widget.TextView;
+
+import com.android.car.dialer.CallListener;
+import com.android.car.dialer.DialerFragment;
+import com.android.car.dialer.R;
+import com.android.car.dialer.telecom.TelecomUtils;
+import com.android.car.dialer.telecom.UiCall;
+import com.android.car.dialer.telecom.UiCallManager;
+
+/**
+ * A fragment that displays information about an on-going call with options to hang up.
+ */
+public class InCallFragment extends Fragment implements
+        OnGoingCallControllerBarFragment.OnGoingCallControllerBarCallback, CallListener {
+
+    private Fragment mDialerFragment;
+    private View mUserProfileContainerView;
+    private View mDialerFragmentContainer;
+    private TextView mUserProfileBodyText;
+
+    private Handler mHandler = new Handler();
+    private CharSequence mCallInfoLabel;
+
+    public static InCallFragment newInstance() {
+        return new InCallFragment();
+    }
+
+    @Override
+    public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container,
+            @Nullable Bundle savedInstanceState) {
+        View fragmentView = inflater.inflate(R.layout.in_call_fragment, container, false);
+        mUserProfileContainerView = fragmentView.findViewById(R.id.user_profile_container);
+        mDialerFragmentContainer = fragmentView.findViewById(R.id.dialer_container);
+        mUserProfileBodyText = mUserProfileContainerView.findViewById(R.id.body);
+        mDialerFragment = new DialerFragment();
+
+        updateControllerBarFragment(UiCallManager.get().getPrimaryCall().getState());
+        bindUserProfileView(fragmentView.findViewById(R.id.user_profile_container));
+        return fragmentView;
+    }
+
+    @Override
+    public void onPause() {
+        super.onPause();
+        mHandler.removeCallbacks(mUpdateDurationRunnable);
+    }
+
+    @Override
+    public void onOpenDialpad() {
+        mDialerFragment = new DialerFragment();
+        getChildFragmentManager().beginTransaction()
+                .replace(R.id.dialer_container, mDialerFragment)
+                .commit();
+        mDialerFragmentContainer.setVisibility(View.VISIBLE);
+        mUserProfileContainerView.setVisibility(View.GONE);
+    }
+
+    @Override
+    public void onCloseDialpad() {
+        getFragmentManager().beginTransaction()
+                .remove(mDialerFragment)
+                .commit();
+        mDialerFragmentContainer.setVisibility(View.GONE);
+        mUserProfileContainerView.setVisibility(View.VISIBLE);
+    }
+
+    private void bindUserProfileView(View container) {
+        UiCall primaryCall = UiCallManager.get().getPrimaryCall();
+        if (primaryCall == null) {
+            return;
+        }
+        String number = primaryCall.getNumber();
+        String displayName = TelecomUtils.getDisplayName(getContext(), primaryCall);
+
+        TextView nameView = container.findViewById(R.id.title);
+        nameView.setText(displayName);
+
+        ImageView avatar = container.findViewById(R.id.avatar);
+        TelecomUtils.setContactBitmapAsync(getContext(), avatar, displayName, number);
+
+        mCallInfoLabel = TelecomUtils.getTypeFromNumber(getContext(), primaryCall.getNumber());
+    }
+
+    private void updateControllerBarFragment(int callState) {
+        Fragment controllerBarFragment;
+        if (callState == Call.STATE_RINGING) {
+            controllerBarFragment = RingingCallControllerBarFragment.newInstance();
+        } else {
+            controllerBarFragment = OnGoingCallControllerBarFragment.newInstance();
+        }
+
+        getChildFragmentManager().beginTransaction()
+                .replace(R.id.controller_bar_container, controllerBarFragment)
+                .commit();
+    }
+
+    @Override
+    public void onAudioStateChanged(boolean isMuted, int route, int supportedRouteMask) {
+
+    }
+
+    @Override
+    public void onCallStateChanged(UiCall call, int state) {
+        int callState = call.getState();
+        switch (callState) {
+            case Call.STATE_NEW:
+            case Call.STATE_CONNECTING:
+            case Call.STATE_DIALING:
+            case Call.STATE_SELECT_PHONE_ACCOUNT:
+            case Call.STATE_HOLDING:
+            case Call.STATE_DISCONNECTED:
+                mHandler.removeCallbacks(mUpdateDurationRunnable);
+                updateBody(call);
+                break;
+            case Call.STATE_ACTIVE:
+                mHandler.post(mUpdateDurationRunnable);
+                updateControllerBarFragment(call.getState());
+                break;
+        }
+    }
+
+    @Override
+    public void onCallUpdated(UiCall call) {
+
+    }
+
+    @Override
+    public void onCallAdded(UiCall call) {
+
+    }
+
+    @Override
+    public void onCallRemoved(UiCall call) {
+
+    }
+
+    private final Runnable mUpdateDurationRunnable = new Runnable() {
+        @Override
+        public void run() {
+            UiCall primaryCall = UiCallManager.get().getPrimaryCall();
+            if (primaryCall.getState() != Call.STATE_ACTIVE) {
+                return;
+            }
+            updateBody(primaryCall);
+            mHandler.postDelayed(this /* runnable */, DateUtils.SECOND_IN_MILLIS);
+        }
+    };
+
+    private void updateBody(UiCall primaryCall) {
+        String callInfoText = TelecomUtils.getCallInfoText(getContext(),
+                primaryCall, mCallInfoLabel);
+        mUserProfileBodyText.setText(callInfoText);
+        mUserProfileBodyText.setVisibility(
+                TextUtils.isEmpty(callInfoText) ? View.GONE : View.VISIBLE);
+    }
+}
diff --git a/src/com/android/car/dialer/ui/OnGoingCallControllerBarFragment.java b/src/com/android/car/dialer/ui/OnGoingCallControllerBarFragment.java
new file mode 100644
index 0000000..7eeedae
--- /dev/null
+++ b/src/com/android/car/dialer/ui/OnGoingCallControllerBarFragment.java
@@ -0,0 +1,277 @@
+/*
+ * 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.car.dialer.ui;
+
+import android.app.AlertDialog;
+import android.content.Context;
+import android.os.Bundle;
+import android.support.annotation.NonNull;
+import android.support.annotation.Nullable;
+import android.support.v4.app.Fragment;
+import android.support.v7.widget.RecyclerView;
+import android.telecom.CallAudioState;
+import android.telecom.CallAudioState.CallAudioRoute;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.ImageView;
+import android.widget.TextView;
+
+import androidx.car.widget.PagedListView;
+
+import com.android.car.apps.common.FabDrawable;
+import com.android.car.dialer.R;
+import com.android.car.dialer.log.L;
+import com.android.car.dialer.telecom.UiCall;
+import com.android.car.dialer.telecom.UiCallManager;
+
+import java.util.List;
+
+/**
+ * A Fragment of the bar which controls on going call. Its host or parent Fragment is expected to
+ * implement {@link OnGoingCallControllerBarCallback}.
+ */
+public class OnGoingCallControllerBarFragment extends Fragment {
+    private static String TAG = "CDialer.OngoingCallCtlFrg";
+    private AlertDialog mAudioRouteSelectionDialog;
+    private ImageView mAudioRouteButton;
+
+    public static OnGoingCallControllerBarFragment newInstance() {
+        return new OnGoingCallControllerBarFragment();
+    }
+
+    /**
+     * Callback for control bar buttons.
+     */
+    public interface OnGoingCallControllerBarCallback {
+        void onOpenDialpad();
+
+        void onCloseDialpad();
+    }
+
+    private OnGoingCallControllerBarCallback mOnGoingCallControllerBarCallback;
+
+    @Override
+    public void onCreate(@Nullable Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        if (getParentFragment() != null
+                && getParentFragment() instanceof OnGoingCallControllerBarCallback) {
+            mOnGoingCallControllerBarCallback =
+                    (OnGoingCallControllerBarCallback) getParentFragment();
+        } else if (getHost() instanceof OnGoingCallControllerBarCallback) {
+            mOnGoingCallControllerBarCallback = (OnGoingCallControllerBarCallback) getHost();
+        }
+
+        View dialogView = LayoutInflater.from(getContext()).inflate(
+                R.layout.audio_route_switch_dialog, null, false);
+        PagedListView list = dialogView.findViewById(R.id.list);
+        List<Integer> availableRoutes = UiCallManager.get().getSupportedAudioRoute();
+        list.setDividerVisibilityManager(position -> position == (availableRoutes.size() - 1));
+
+        mAudioRouteSelectionDialog = new AlertDialog.Builder(getContext())
+                .setView(dialogView)
+                .create();
+        mAudioRouteSelectionDialog.getWindow().setBackgroundDrawableResource(
+                android.R.color.transpare‌​nt);
+        list.setAdapter(new AudioRouteListAdapter(getContext(), availableRoutes));
+    }
+
+    @Nullable
+    @Override
+    public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container,
+            @Nullable Bundle savedInstanceState) {
+        View fragmentView = inflater.inflate(R.layout.on_going_call_controller_bar_fragment,
+                container, false);
+        fragmentView.findViewById(R.id.mute_button).setOnClickListener((v) -> {
+            if (mOnGoingCallControllerBarCallback == null) {
+                return;
+            }
+            if (v.isActivated()) {
+                v.setActivated(false);
+                onMuteMic();
+            } else {
+                v.setActivated(true);
+                onUnmuteMic();
+            }
+        });
+
+        fragmentView.findViewById(R.id.toggle_dialpad_button).setOnClickListener((v) -> {
+            if (mOnGoingCallControllerBarCallback == null) {
+                return;
+            }
+            if (v.isActivated()) {
+                v.setActivated(false);
+                mOnGoingCallControllerBarCallback.onCloseDialpad();
+            } else {
+                v.setActivated(true);
+                mOnGoingCallControllerBarCallback.onOpenDialpad();
+            }
+        });
+
+        ImageView endCallButton = fragmentView.findViewById(R.id.end_call_button);
+        FabDrawable answerCallDrawable = new FabDrawable(getContext());
+        answerCallDrawable.setFabAndStrokeColor(getContext().getColor(R.color.phone_end_call));
+        endCallButton.setBackground(answerCallDrawable);
+        endCallButton.setOnClickListener((v) -> {
+            if (mOnGoingCallControllerBarCallback == null) {
+                return;
+            }
+            onEndCall();
+        });
+
+
+        List<Integer> audioRoutes = UiCallManager.get().getSupportedAudioRoute();
+        mAudioRouteButton = fragmentView.findViewById(R.id.voice_channel_button);
+        if (audioRoutes.size() > 1) {
+            fragmentView.findViewById(R.id.voice_channel_chevron).setVisibility(View.VISIBLE);
+            mAudioRouteButton.setOnClickListener(
+                    (v) -> mAudioRouteSelectionDialog.show());
+        } else {
+            fragmentView.findViewById(R.id.voice_channel_chevron).setVisibility(View.GONE);
+        }
+
+        fragmentView.findViewById(R.id.pause_button).setOnClickListener((v) -> {
+            if (mOnGoingCallControllerBarCallback == null) {
+                return;
+            }
+            if (v.isActivated()) {
+                v.setActivated(false);
+                onHoldCall();
+            } else {
+                v.setActivated(true);
+                onUnholdCall();
+            }
+        });
+        return fragmentView;
+    }
+
+    @Override
+    public void onPause() {
+        super.onPause();
+        if (mAudioRouteSelectionDialog.isShowing()) {
+            mAudioRouteSelectionDialog.dismiss();
+        }
+    }
+
+    private void onMuteMic() {
+        UiCallManager.get().setMuted(true);
+    }
+
+    private void onUnmuteMic() {
+        UiCallManager.get().setMuted(false);
+    }
+
+    private void onHoldCall() {
+        UiCallManager uiCallManager = UiCallManager.get();
+        UiCall primaryCall = UiCallManager.get().getPrimaryCall();
+        uiCallManager.holdCall(primaryCall);
+    }
+
+    private void onUnholdCall() {
+        UiCallManager uiCallManager = UiCallManager.get();
+        UiCall primaryCall = UiCallManager.get().getPrimaryCall();
+        uiCallManager.unholdCall(primaryCall);
+    }
+
+    private void onVoiceOutputChannelChanged(@CallAudioRoute int audioRoute) {
+        UiCallManager.get().setAudioRoute(audioRoute);
+        mAudioRouteSelectionDialog.dismiss();
+        mAudioRouteButton.setImageResource(getAudioRouteIconRes(audioRoute));
+    }
+
+    private void onEndCall() {
+        UiCallManager uiCallManager = UiCallManager.get();
+        UiCall primaryCall = UiCallManager.get().getPrimaryCall();
+        uiCallManager.disconnectCall(primaryCall);
+    }
+
+    private int getAudioRouteIconRes(@CallAudioRoute int audioRoute) {
+        switch (audioRoute) {
+            case CallAudioState.ROUTE_WIRED_HEADSET:
+            case CallAudioState.ROUTE_EARPIECE:
+                return R.drawable.ic_smartphone;
+            case CallAudioState.ROUTE_BLUETOOTH:
+                return R.drawable.ic_bluetooth;
+            case CallAudioState.ROUTE_SPEAKER:
+                return R.drawable.ic_speaker_phone;
+            default:
+                L.w(TAG, "Unknown audio route: " + audioRoute);
+                return -1;
+        }
+    }
+
+    private int getAudioRouteLabelRes(@CallAudioRoute int audioRoute) {
+        switch (audioRoute) {
+            case CallAudioState.ROUTE_WIRED_HEADSET:
+            case CallAudioState.ROUTE_EARPIECE:
+                return R.string.audio_route_handset;
+            case CallAudioState.ROUTE_BLUETOOTH:
+                return R.string.audio_route_vehicle;
+            case CallAudioState.ROUTE_SPEAKER:
+                return R.string.audio_route_phone_speaker;
+            default:
+                L.w(TAG, "Unknown audio route: " + audioRoute);
+                return -1;
+        }
+    }
+
+    private class AudioRouteListAdapter extends
+            RecyclerView.Adapter<AudioRouteItemViewHolder> {
+        private List<Integer> mSupportedRoutes;
+        private Context mContext;
+
+        public AudioRouteListAdapter(Context context, List<Integer> supportedRoutes) {
+            mSupportedRoutes = supportedRoutes;
+            mContext = context;
+            if (mSupportedRoutes.contains(CallAudioState.ROUTE_EARPIECE)
+                    && mSupportedRoutes.contains(CallAudioState.ROUTE_WIRED_HEADSET)) {
+                // Keep either ROUTE_EARPIECE or ROUTE_WIRED_HEADSET, but not both of them.
+                mSupportedRoutes.remove(CallAudioState.ROUTE_WIRED_HEADSET);
+            }
+        }
+
+        @Override
+        public AudioRouteItemViewHolder onCreateViewHolder(ViewGroup container, int position) {
+            View listItemView = LayoutInflater.from(mContext).inflate(
+                    R.layout.audio_route_list_item, container, false);
+            return new AudioRouteItemViewHolder(listItemView);
+        }
+
+        @Override
+        public void onBindViewHolder(AudioRouteItemViewHolder viewHolder, int position) {
+            int audioRoute = mSupportedRoutes.get(position);
+            viewHolder.mBody.setText(mContext.getString(getAudioRouteLabelRes(audioRoute)));
+            viewHolder.mIcon.setImageResource(getAudioRouteIconRes(audioRoute));
+            viewHolder.itemView.setOnClickListener((v) -> onVoiceOutputChannelChanged(audioRoute));
+        }
+
+        @Override
+        public int getItemCount() {
+            return mSupportedRoutes.size();
+        }
+    }
+
+    private static class AudioRouteItemViewHolder extends RecyclerView.ViewHolder {
+        public final ImageView mIcon;
+        public final TextView mBody;
+
+        public AudioRouteItemViewHolder(View itemView) {
+            super(itemView);
+            mIcon = itemView.findViewById(R.id.icon);
+            mBody = itemView.findViewById(R.id.body);
+        }
+    }
+}
\ No newline at end of file
diff --git a/src/com/android/car/dialer/ui/RingingCallControllerBarFragment.java b/src/com/android/car/dialer/ui/RingingCallControllerBarFragment.java
new file mode 100644
index 0000000..7b315b9
--- /dev/null
+++ b/src/com/android/car/dialer/ui/RingingCallControllerBarFragment.java
@@ -0,0 +1,49 @@
+package com.android.car.dialer.ui;
+
+import android.os.Bundle;
+import android.support.annotation.NonNull;
+import android.support.annotation.Nullable;
+import android.support.v4.app.Fragment;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.ImageView;
+
+import com.android.car.apps.common.FabDrawable;
+import com.android.car.dialer.R;
+import com.android.car.dialer.telecom.UiCall;
+import com.android.car.dialer.telecom.UiCallManager;
+
+public class RingingCallControllerBarFragment extends Fragment {
+
+    public static RingingCallControllerBarFragment newInstance() {
+        return new RingingCallControllerBarFragment();
+    }
+
+    @Nullable
+    @Override
+    public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container,
+            @Nullable Bundle savedInstanceState) {
+        View fragmentView = inflater.inflate(R.layout.ringing_call_controller_bar_fragment,
+                container, false);
+
+        fragmentView.findViewById(R.id.answer_call_button).setOnClickListener((v) -> answerCall());
+        fragmentView.findViewById(R.id.answer_call_text).setOnClickListener((v) -> answerCall());
+        fragmentView.findViewById(R.id.end_call_button).setOnClickListener((v) -> declineCall());
+        fragmentView.findViewById(R.id.end_call_text).setOnClickListener((v) -> declineCall());
+
+        return fragmentView;
+    }
+
+    private void answerCall() {
+        UiCallManager uiCallManager = UiCallManager.get();
+        UiCall primaryCall = uiCallManager.getPrimaryCall();
+        uiCallManager.answerCall(primaryCall);
+    }
+
+    private void declineCall() {
+        UiCallManager uiCallManager = UiCallManager.get();
+        UiCall primaryCall = uiCallManager.getPrimaryCall();
+        uiCallManager.rejectCall(primaryCall, false, null);
+    }
+}
diff --git a/src/com/android/car/dialer/ui/listitem/CallLogListItem.java b/src/com/android/car/dialer/ui/listitem/CallLogListItem.java
new file mode 100644
index 0000000..e48e92d
--- /dev/null
+++ b/src/com/android/car/dialer/ui/listitem/CallLogListItem.java
@@ -0,0 +1,89 @@
+/*
+ * 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.car.dialer.ui.listitem;
+
+import android.content.Context;
+import android.content.res.Resources;
+import android.graphics.Bitmap;
+import android.graphics.drawable.BitmapDrawable;
+import android.graphics.drawable.Drawable;
+import android.graphics.drawable.ScaleDrawable;
+import android.view.ViewGroup;
+import android.widget.ImageView;
+
+import androidx.car.widget.TextListItem;
+
+import com.android.car.apps.common.LetterTileDrawable;
+import com.android.car.dialer.telecom.ContactBitmapWorker;
+import com.android.car.dialer.ui.CallHistoryListItemProvider;
+import com.android.car.dialer.ui.CallLogListingTask;
+import com.android.car.dialer.ui.CircleBitmapDrawable;
+import com.android.car.dialer.R;
+
+/**
+ * List item which is created by {@link CallHistoryListItemProvider} binds a call list item to a
+ * list view item.
+ */
+public class CallLogListItem extends TextListItem {
+    private final CallLogListingTask.CallLogItem mCallLogItem;
+    private final Context mContext;
+
+    public CallLogListItem(Context context, CallLogListingTask.CallLogItem callLog) {
+        super(context);
+        mCallLogItem = callLog;
+        mContext = context;
+    }
+
+    @Override
+    public void onBind(ViewHolder viewHolder) {
+        super.onBind(viewHolder);
+        ContactBitmapWorker.loadBitmap(mContext.getContentResolver(), viewHolder.getPrimaryIcon(),
+                mCallLogItem.mNumber,
+                bitmap -> {
+                    Resources r = mContext.getResources();
+                    viewHolder.getPrimaryIcon().setScaleType(ImageView.ScaleType.CENTER);
+                    Drawable avatarDrawable;
+                    if (bitmap != null) {
+                        avatarDrawable = new CircleBitmapDrawable(r, bitmap);
+                        setPrimaryActionIcon(new CircleBitmapDrawable(r, bitmap), true);
+                    } else {
+                        LetterTileDrawable letterTileDrawable = new LetterTileDrawable(r);
+                        letterTileDrawable.setContactDetails(mCallLogItem.mTitle,
+                                mCallLogItem.mNumber);
+                        letterTileDrawable.setIsCircular(true);
+                        avatarDrawable = letterTileDrawable;
+                    }
+
+                    int iconSize = mContext.getResources().getDimensionPixelSize(
+                            R.dimen.avatar_icon_size);
+                    setPrimaryActionIcon(scaleDrawable(avatarDrawable, iconSize), true);
+                    super.onBind(viewHolder);
+                });
+
+        viewHolder.getContainerLayout().setBackgroundColor(
+                mContext.getColor(R.color.call_history_list_item_color));
+    }
+
+    private Drawable scaleDrawable(Drawable targetDrawable, int sizeInPixel) {
+        Bitmap bitmap = null;
+        if (targetDrawable instanceof CircleBitmapDrawable) {
+            bitmap = ((CircleBitmapDrawable) targetDrawable).toBitmap(sizeInPixel);
+        } else if (targetDrawable instanceof LetterTileDrawable){
+            bitmap = ((LetterTileDrawable) targetDrawable).toBitmap(sizeInPixel);
+        }
+        return new BitmapDrawable(mContext.getResources(), bitmap);
+    }
+}
diff --git a/src/com/android/car/dialer/ui/listitem/ContactListItem.java b/src/com/android/car/dialer/ui/listitem/ContactListItem.java
new file mode 100644
index 0000000..8a7b344
--- /dev/null
+++ b/src/com/android/car/dialer/ui/listitem/ContactListItem.java
@@ -0,0 +1,86 @@
+/*
+ * 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.car.dialer.ui.listitem;
+
+import android.content.Context;
+import android.content.res.Resources;
+import android.graphics.Bitmap;
+import android.graphics.drawable.BitmapDrawable;
+import android.graphics.drawable.Drawable;
+import android.widget.ImageView;
+
+import androidx.car.widget.TextListItem;
+
+import com.android.car.apps.common.LetterTileDrawable;
+import com.android.car.dialer.R;
+import com.android.car.dialer.telecom.ContactBitmapWorker;
+import com.android.car.dialer.ui.CircleBitmapDrawable;
+import com.android.car.dialer.ui.ContactListFragment;
+
+/**
+ * ListItem for contact.
+ */
+public class ContactListItem extends TextListItem {
+    private Context mContext;
+    private ContactListFragment.ContactItem mContactItem;
+
+    public ContactListItem(Context context, ContactListFragment.ContactItem contactItem) {
+        super(context);
+        mContext = context;
+        mContactItem = contactItem;
+    }
+
+    @Override
+    public void onBind(ViewHolder viewHolder) {
+        super.onBind(viewHolder);
+        ContactBitmapWorker.loadBitmap(mContext.getContentResolver(), viewHolder.getPrimaryIcon(),
+                mContactItem.mNumber,
+                bitmap -> {
+                    Resources r = mContext.getResources();
+                    viewHolder.getPrimaryIcon().setScaleType(ImageView.ScaleType.CENTER);
+                    Drawable avatarDrawable;
+                    if (bitmap != null) {
+                        avatarDrawable = new CircleBitmapDrawable(r, bitmap);
+                    } else {
+                        LetterTileDrawable letterTileDrawable = new LetterTileDrawable(r);
+                        letterTileDrawable.setContactDetails(mContactItem.mDisplayName,
+                                mContactItem.mNumber);
+                        letterTileDrawable.setIsCircular(true);
+                        avatarDrawable = letterTileDrawable;
+                    }
+
+                    int iconSize = mContext.getResources().getDimensionPixelSize(
+                            R.dimen.avatar_icon_size);
+                    setPrimaryActionIcon(scaleDrawable(avatarDrawable, iconSize), true);
+                    super.onBind(viewHolder);
+
+                    // force rebind the view.
+                    super.onBind(viewHolder);
+                });
+        viewHolder.getContainerLayout().setBackgroundColor(
+                mContext.getColor(R.color.contact_list_item_color));
+    }
+
+    private Drawable scaleDrawable(Drawable targetDrawable, int sizeInPixel) {
+        Bitmap bitmap = null;
+        if (targetDrawable instanceof CircleBitmapDrawable) {
+            bitmap = ((CircleBitmapDrawable) targetDrawable).toBitmap(sizeInPixel);
+        } else if (targetDrawable instanceof LetterTileDrawable){
+            bitmap = ((LetterTileDrawable) targetDrawable).toBitmap(sizeInPixel);
+        }
+        return new BitmapDrawable(mContext.getResources(), bitmap);
+    }
+}
diff --git a/src/com/android/car/dialer/ui/viewmodel/CallHistoryViewModel.java b/src/com/android/car/dialer/ui/viewmodel/CallHistoryViewModel.java
new file mode 100644
index 0000000..8afe0ef
--- /dev/null
+++ b/src/com/android/car/dialer/ui/viewmodel/CallHistoryViewModel.java
@@ -0,0 +1,58 @@
+package com.android.car.dialer.ui.viewmodel;
+/*
+ * 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.
+ */
+import android.app.Application;
+import android.arch.lifecycle.AndroidViewModel;
+import android.arch.lifecycle.LiveData;
+import android.content.Context;
+import android.support.annotation.NonNull;
+
+import com.android.car.dialer.livedata.CallHistoryLiveData;
+import com.android.car.dialer.livedata.MissedCallHistoryLiveData;
+import com.android.car.dialer.ui.CallLogListingTask;
+
+import java.util.List;
+
+/**
+ * View model for CallHistoryFragment which provides call history live data.
+ */
+public class CallHistoryViewModel extends AndroidViewModel {
+    private CallHistoryLiveData mCallHistoryLiveData;
+    private MissedCallHistoryLiveData mMissedCallHistoryLiveData;
+
+    private Context mContext;
+
+    public CallHistoryViewModel(
+            @NonNull Application application) {
+        super(application);
+        mContext = application;
+    }
+
+    public LiveData<List<CallLogListingTask.CallLogItem>> getCallHistory() {
+        if (mCallHistoryLiveData == null) {
+            mCallHistoryLiveData = new CallHistoryLiveData(mContext);
+        }
+        return mCallHistoryLiveData;
+    }
+
+    public LiveData<List<CallLogListingTask.CallLogItem>> getMissedCallHistory() {
+        if (mMissedCallHistoryLiveData == null) {
+            mMissedCallHistoryLiveData = new MissedCallHistoryLiveData(mContext);
+        }
+
+        return mMissedCallHistoryLiveData;
+    }
+}