Merge "Let InCallActivity handle resize config change." into nyc-dev
diff --git a/Android.mk b/Android.mk
index 4c67293..eb6cbdc 100644
--- a/Android.mk
+++ b/Android.mk
@@ -64,9 +64,7 @@
 
 LOCAL_PROGUARD_FLAG_FILES := proguard.flags $(incallui_dir)/proguard.flags
 
-# Uncomment the following line to build against the current SDK
-# This is required for building an unbundled app.
-LOCAL_SDK_VERSION := system_current
+LOCAL_SDK_VERSION := current
 
 include $(BUILD_PACKAGE)
 
diff --git a/InCallUI/AndroidManifest.xml b/InCallUI/AndroidManifest.xml
new file mode 100644
index 0000000..5c758ed
--- /dev/null
+++ b/InCallUI/AndroidManifest.xml
@@ -0,0 +1,24 @@
+<?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
+  -->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+        package="com.android.incallui">
+    <uses-sdk
+        android:minSdkVersion="23"
+        android:targetSdkVersion="23" />
+</manifest>
+
diff --git a/InCallUI/build.gradle b/InCallUI/build.gradle
new file mode 100644
index 0000000..de47251
--- /dev/null
+++ b/InCallUI/build.gradle
@@ -0,0 +1,14 @@
+apply plugin: 'com.android.library'
+
+android {
+    sourceSets.main {
+        manifest.srcFile 'AndroidManifest.xml'
+        res.srcDirs = ['res']
+    }
+}
+
+dependencies {
+    compile 'com.android.support:support-v4:23.1.+'
+    compile project(':phonecommon')
+    compile project(':contactscommon')
+}
diff --git a/InCallUI/res/layout-h600dp/manage_conference_call_button.xml b/InCallUI/res/layout-h600dp/manage_conference_call_button.xml
new file mode 100644
index 0000000..9a83313
--- /dev/null
+++ b/InCallUI/res/layout-h600dp/manage_conference_call_button.xml
@@ -0,0 +1,61 @@
+<?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
+  -->
+
+<!-- This button is used only on GSM and IMS devices, during a conference call. -->
+<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:id="@+id/manage_conference_call_button"
+    android:layout_width="match_parent"
+    android:layout_height="wrap_content"
+    android:background="@color/incall_banner_secondary_background_color"
+    android:focusable="true"
+    android:contentDescription="@string/onscreenManageConferenceText">
+
+    <Space android:layout_width="match_parent"
+        android:layout_height="1dp"
+        android:background="@color/secondary_call_info_divider_highlight_color" />
+
+    <!-- This LinearLayout nested immediately in a FrameLayout is necessary to apply both a
+         background color and ripple to the button. -->
+    <LinearLayout
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:paddingStart="@dimen/secondary_call_info_horizontal_padding"
+        android:paddingEnd="@dimen/secondary_call_info_horizontal_padding"
+        android:paddingTop="@dimen/secondary_call_info_vertical_padding"
+        android:paddingBottom="@dimen/secondary_call_info_vertical_padding"
+        android:background="?android:attr/selectableItemBackground">
+
+        <ImageView android:id="@+id/manageConferenceButtonImage"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:src="@drawable/ic_group_white_24dp"
+            android:tint="@color/incall_banner_secondary_text_color"
+            android:paddingEnd="16dp"
+            android:importantForAccessibility="no" />
+
+        <TextView android:id="@+id/manageConferenceButtonLabel"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:gravity="center_vertical"
+            android:textColor="@color/incall_banner_secondary_text_color"
+            android:textSize="@dimen/secondary_call_info_text_size"
+            android:text="@string/onscreenManageConferenceText"
+            android:importantForAccessibility="no" />
+
+    </LinearLayout>
+
+</FrameLayout>
diff --git a/InCallUI/res/layout-w600dp-land/manage_conference_call_button.xml b/InCallUI/res/layout-w600dp-land/manage_conference_call_button.xml
new file mode 100644
index 0000000..9a83313
--- /dev/null
+++ b/InCallUI/res/layout-w600dp-land/manage_conference_call_button.xml
@@ -0,0 +1,61 @@
+<?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
+  -->
+
+<!-- This button is used only on GSM and IMS devices, during a conference call. -->
+<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:id="@+id/manage_conference_call_button"
+    android:layout_width="match_parent"
+    android:layout_height="wrap_content"
+    android:background="@color/incall_banner_secondary_background_color"
+    android:focusable="true"
+    android:contentDescription="@string/onscreenManageConferenceText">
+
+    <Space android:layout_width="match_parent"
+        android:layout_height="1dp"
+        android:background="@color/secondary_call_info_divider_highlight_color" />
+
+    <!-- This LinearLayout nested immediately in a FrameLayout is necessary to apply both a
+         background color and ripple to the button. -->
+    <LinearLayout
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:paddingStart="@dimen/secondary_call_info_horizontal_padding"
+        android:paddingEnd="@dimen/secondary_call_info_horizontal_padding"
+        android:paddingTop="@dimen/secondary_call_info_vertical_padding"
+        android:paddingBottom="@dimen/secondary_call_info_vertical_padding"
+        android:background="?android:attr/selectableItemBackground">
+
+        <ImageView android:id="@+id/manageConferenceButtonImage"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:src="@drawable/ic_group_white_24dp"
+            android:tint="@color/incall_banner_secondary_text_color"
+            android:paddingEnd="16dp"
+            android:importantForAccessibility="no" />
+
+        <TextView android:id="@+id/manageConferenceButtonLabel"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:gravity="center_vertical"
+            android:textColor="@color/incall_banner_secondary_text_color"
+            android:textSize="@dimen/secondary_call_info_text_size"
+            android:text="@string/onscreenManageConferenceText"
+            android:importantForAccessibility="no" />
+
+    </LinearLayout>
+
+</FrameLayout>
diff --git a/InCallUI/res/layout/call_card_fragment.xml b/InCallUI/res/layout/call_card_fragment.xml
index 03bbe87..fabde37 100644
--- a/InCallUI/res/layout/call_card_fragment.xml
+++ b/InCallUI/res/layout/call_card_fragment.xml
@@ -60,6 +60,12 @@
              android:elevation="4dp"
              android:layout_alignParentBottom="true" />
 
+    <include layout="@layout/manage_conference_call_button"
+             android:layout_width="match_parent"
+             android:layout_height="wrap_content"
+             android:elevation="5dp"
+             android:layout_alignParentBottom="true"/>
+
     <FrameLayout
         android:id="@+id/floating_end_call_action_button_container"
         android:layout_width="@dimen/end_call_floating_action_button_diameter"
@@ -147,12 +153,6 @@
                           android:dividerHeight="@dimen/contact_context_list_item_padding" />
             </LinearLayout>
         </FrameLayout>
-
-        <include layout="@layout/manage_conference_call_button"
-                 android:layout_width="match_parent"
-                 android:layout_height="wrap_content"
-                 android:layout_alignTop="@id/photoLarge" />
-
     </FrameLayout>
 
 </RelativeLayout>
diff --git a/InCallUI/res/layout/manage_conference_call_button.xml b/InCallUI/res/layout/manage_conference_call_button.xml
index 3b5ef99..01ca1bd 100644
--- a/InCallUI/res/layout/manage_conference_call_button.xml
+++ b/InCallUI/res/layout/manage_conference_call_button.xml
@@ -1,28 +1,27 @@
 <?xml version="1.0" encoding="utf-8"?>
-<!--
-  ~ Copyright (C) 2013 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
-  -->
+<!-- Copyright (C) 2013 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 button is used only on GSM and IMS devices, during a conference call. -->
 <FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
     android:id="@+id/manage_conference_call_button"
     android:layout_width="match_parent"
     android:layout_height="wrap_content"
+    android:layout_alignParentBottom="true"
     android:background="@color/incall_banner_secondary_background_color"
-    android:focusable="true"
-    android:contentDescription="@string/onscreenManageConferenceText">
+    android:visibility="gone">
 
     <Space android:layout_width="match_parent"
         android:layout_height="1dp"
@@ -32,30 +31,42 @@
          background color and ripple to the button. -->
     <LinearLayout
         android:layout_width="match_parent"
-        android:layout_height="wrap_content"
+        android:layout_height="match_parent"
+        android:orientation="horizontal"
         android:paddingStart="@dimen/secondary_call_info_horizontal_padding"
         android:paddingEnd="@dimen/secondary_call_info_horizontal_padding"
         android:paddingTop="@dimen/secondary_call_info_vertical_padding"
         android:paddingBottom="@dimen/secondary_call_info_vertical_padding"
         android:background="?android:attr/selectableItemBackground">
 
-        <ImageView android:id="@+id/manageConferenceButtonImage"
-            android:layout_width="wrap_content"
-            android:layout_height="wrap_content"
-            android:src="@drawable/ic_group_white_24dp"
-            android:tint="@color/incall_banner_secondary_text_color"
-            android:paddingEnd="16dp"
-            android:importantForAccessibility="no" />
+        <!-- Call status of the background call, usually the string "On hold". -->
+        <TextView android:id="@+id/conferenceLabel"
+                  android:layout_width="0dp"
+                  android:layout_height="wrap_content"
+                  android:layout_weight="1"
+                  android:layout_gravity="center_vertical"
+                  android:paddingEnd="18dp"
+                  android:text="@string/onscreenConferenceText"
+                  android:textColor="@color/incall_banner_secondary_text_color"
+                  android:textSize="@dimen/secondary_call_info_text_size"
+                  android:singleLine="true" />
 
-        <TextView android:id="@+id/manageConferenceButtonLabel"
-            android:layout_width="match_parent"
-            android:layout_height="wrap_content"
-            android:gravity="center_vertical"
-            android:textColor="@color/incall_banner_secondary_text_color"
-            android:textSize="@dimen/secondary_call_info_text_size"
-            android:text="@string/onscreenManageConferenceText"
-            android:importantForAccessibility="no" />
+        <ImageView android:id="@+id/manageConferenceImage"
+                   android:layout_width="wrap_content"
+                   android:layout_height="wrap_content"
+                   android:src="@drawable/ic_group_white_24dp"
+                   android:tint="@color/incall_banner_secondary_text_color"
+                   android:paddingEnd="16dp"/>
+
+        <TextView android:id="@+id/manageConferenceLabel"
+                  android:layout_width="wrap_content"
+                  android:layout_height="wrap_content"
+                  android:textColor="@color/incall_banner_secondary_text_color"
+                  android:textSize="@dimen/secondary_call_info_text_size"
+                  android:textAlignment="viewStart"
+                  android:text="@string/onscreenManageText"
+                  android:singleLine="true"/>
 
     </LinearLayout>
 
-</FrameLayout>
+</FrameLayout>
\ No newline at end of file
diff --git a/InCallUI/res/values/array.xml b/InCallUI/res/values/array.xml
index 8744d3e..7877ec8 100644
--- a/InCallUI/res/values/array.xml
+++ b/InCallUI/res/values/array.xml
@@ -76,10 +76,10 @@
         <item>@drawable/ic_lockscreen_answer_video</item>
     </array>
     <array name="incoming_call_widget_video_without_sms_target_descriptions">
-        <item>@string/description_target_answer_audio_call</item>
+        <item>@string/description_target_answer_video_call</item>
         <item>@null</item>
         <item>@string/description_target_decline</item>
-        <item>@string/description_target_answer_video_call</item>
+        <item>@string/description_target_answer_audio_call</item>
     </array>
     <array name="incoming_call_widget_video_without_sms_direction_descriptions">
         <item>@string/description_direction_right</item>
@@ -89,21 +89,21 @@
     </array>
 
     <!-- For video calls, if respond via SMS is enabled:
-         - Answer as audio call (drag right)
+         - Answer as video call (drag right)
          - Respond via SMS (drag up)
          - Decline (drag left)
-         - Answer as video call (drag down) -->
+         - Answer as audio call (drag down) -->
     <array name="incoming_call_widget_video_with_sms_targets">
-        <item>@drawable/ic_lockscreen_answer</item>
+        <item>@drawable/ic_lockscreen_answer_video</item>
         <item>@drawable/ic_lockscreen_text</item>
         <item>@drawable/ic_lockscreen_decline</item>
-        <item>@drawable/ic_lockscreen_answer_video</item>
+        <item>@drawable/ic_lockscreen_answer</item>
     </array>
     <array name="incoming_call_widget_video_with_sms_target_descriptions">
-        <item>@string/description_target_answer_audio_call</item>
+        <item>@string/description_target_answer_video_call</item>
         <item>@string/description_target_send_sms</item>
         <item>@string/description_target_decline</item>
-        <item>@string/description_target_answer_video_call</item>
+        <item>@string/description_target_answer_audio_call</item>
     </array>
     <array name="incoming_call_widget_video_with_sms_direction_descriptions">
         <item>@string/description_direction_right</item>
diff --git a/InCallUI/res/values/colors.xml b/InCallUI/res/values/colors.xml
index 60a017c..5e4eeee 100644
--- a/InCallUI/res/values/colors.xml
+++ b/InCallUI/res/values/colors.xml
@@ -119,4 +119,7 @@
     <color name="person_contact_context_message_background_color">@color/incall_call_banner_subtext_color</color>
     <color name="person_contact_context_detail_text_color">@color/incall_call_banner_subtext_color</color>
     <color name="business_contact_context_text_color">@color/incall_call_banner_subtext_color</color>
+
+    <!-- White background for dialer -->
+    <color name="background_dialer_white">#ffffff</color>
 </resources>
diff --git a/InCallUI/res/values/strings.xml b/InCallUI/res/values/strings.xml
index df588d5..2f3d16b 100644
--- a/InCallUI/res/values/strings.xml
+++ b/InCallUI/res/values/strings.xml
@@ -289,6 +289,10 @@
     <string name="onscreenManageCallsText">Manage calls</string>
     <!-- Text for the onscreen "Manage conference" button [CHAR LIMIT=30] -->
     <string name="onscreenManageConferenceText">Manage conference call</string>
+    <!-- Text for the first half of the onscreen "Manage conference" button [CHAR LIMIT=30] -->
+    <string name="onscreenConferenceText">Conference call</string>
+    <!-- Text for the second half of the onscreen "Manage conference" button [CHAR LIMIT=30] -->
+    <string name="onscreenManageText">Manage</string>
     <!-- Text for the onscreen "Audio" button that lets you switch
          between speaker / bluetooth / earpiece [CHAR LIMIT=10] -->
     <string name="onscreenAudioText">Audio</string>
diff --git a/InCallUI/src/com/android/incallui/AudioModeProvider.java b/InCallUI/src/com/android/incallui/AudioModeProvider.java
index 961fb11..ea56dd6 100644
--- a/InCallUI/src/com/android/incallui/AudioModeProvider.java
+++ b/InCallUI/src/com/android/incallui/AudioModeProvider.java
@@ -16,9 +16,9 @@
 
 package com.android.incallui;
 
-import com.google.common.collect.Lists;
+import android.telecom.CallAudioState;
 
-import com.android.dialer.compat.CallAudioStateCompat;
+import com.google.common.collect.Lists;
 
 import java.util.List;
 
@@ -30,11 +30,11 @@
     static final int AUDIO_MODE_INVALID = 0;
 
     private static AudioModeProvider sAudioModeProvider = new AudioModeProvider();
-    private int mAudioMode = CallAudioStateCompat.ROUTE_EARPIECE;
+    private int mAudioMode = CallAudioState.ROUTE_EARPIECE;
     private boolean mMuted = false;
-    private int mSupportedModes = CallAudioStateCompat.ROUTE_EARPIECE
-            | CallAudioStateCompat.ROUTE_BLUETOOTH | CallAudioStateCompat.ROUTE_WIRED_HEADSET
-            | CallAudioStateCompat.ROUTE_SPEAKER;
+    private int mSupportedModes = CallAudioState.ROUTE_EARPIECE
+            | CallAudioState.ROUTE_BLUETOOTH | CallAudioState.ROUTE_WIRED_HEADSET
+            | CallAudioState.ROUTE_SPEAKER;
     private final List<AudioModeListener> mListeners = Lists.newArrayList();
 
     public static AudioModeProvider getInstance() {
diff --git a/InCallUI/src/com/android/incallui/Call.java b/InCallUI/src/com/android/incallui/Call.java
index aec806f..54ec528 100644
--- a/InCallUI/src/com/android/incallui/Call.java
+++ b/InCallUI/src/com/android/incallui/Call.java
@@ -19,9 +19,9 @@
 import android.content.Context;
 import android.hardware.camera2.CameraCharacteristics;
 import android.net.Uri;
-import android.os.Build;
 import android.os.Bundle;
 import android.os.Trace;
+import android.telecom.Call.Details;
 import android.telecom.Connection;
 import android.telecom.DisconnectCause;
 import android.telecom.GatewayInfo;
@@ -37,8 +37,6 @@
 import com.android.contacts.common.compat.telecom.TelecomManagerCompat;
 import com.android.contacts.common.testing.NeededForTesting;
 import com.android.dialer.util.IntentUtil;
-import com.android.incallui.compat.telecom.DetailsCompat;
-import com.android.incallui.compat.telecom.VideoProfileCompat;
 import com.android.incallui.util.TelecomCallUtil;
 
 import java.util.ArrayList;
@@ -291,18 +289,8 @@
     private static final String ID_PREFIX = Call.class.getSimpleName() + "_";
     private static int sIdCounter = 0;
 
-    private Object mTelecomCallCallback = newTelecomCallCallback();
-
-    private Object newTelecomCallCallback() {
-        if (SdkVersionOverride.getSdkVersion(Build.VERSION_CODES.M) >= Build.VERSION_CODES.M) {
-            return newMarshmallowTelecomCallCallback();
-        }
-        return newLollipopTelecomCallCallback();
-    }
-
-    private Object newMarshmallowTelecomCallCallback() {
-        Log.i(this, "Using an android.telecom.Call$Callback");
-        return new android.telecom.Call.Callback() {
+    private final android.telecom.Call.Callback mTelecomCallCallback =
+        new android.telecom.Call.Callback() {
             @Override
             public void onStateChanged(android.telecom.Call call, int newState) {
                 Log.d(this, "TelecomCallCallback onStateChanged call=" + call + " newState="
@@ -367,81 +355,7 @@
                     List<android.telecom.Call> conferenceableCalls) {
                 update();
             }
-        };
-    }
-
-    private Object newLollipopTelecomCallCallback() {
-        // This code only runs for Google Experience phones on the pre-M sdk since only the system
-        // dialer can invoke the InCallUI code. This allows us to safely use the
-        // android.telecom.Call.Listener interface
-        Log.i(this, "Using an android.telecom.Call$Listener");
-        return new android.telecom.Call.Listener() {
-            @Override
-            public void onStateChanged(android.telecom.Call call, int newState) {
-                Log.d(this, "TelecomCallCallback onStateChanged call=" + call + " newState="
-                        + newState);
-                update();
-            }
-
-            @Override
-            public void onParentChanged(android.telecom.Call call,
-                    android.telecom.Call newParent) {
-                Log.d(this, "TelecomCallCallback onParentChanged call=" + call + " newParent="
-                        + newParent);
-                update();
-            }
-
-            @Override
-            public void onChildrenChanged(android.telecom.Call call,
-                    List<android.telecom.Call> children) {
-                update();
-            }
-
-            @Override
-            public void onDetailsChanged(android.telecom.Call call,
-                    android.telecom.Call.Details details) {
-                Log.d(this, "TelecomCallCallback onStateChanged call=" + call + " details="
-                        + details);
-                update();
-            }
-
-            @Override
-            public void onCannedTextResponsesLoaded(android.telecom.Call call,
-                    List<String> cannedTextResponses) {
-                Log.d(this, "TelecomCallCallback onStateChanged call=" + call
-                        + " cannedTextResponses=" + cannedTextResponses);
-                update();
-            }
-
-            @Override
-            public void onPostDialWait(android.telecom.Call call,
-                    String remainingPostDialSequence) {
-                Log.d(this, "TelecomCallCallback onStateChanged call=" + call
-                        + " remainingPostDialSequence=" + remainingPostDialSequence);
-                update();
-            }
-
-            @Override
-            public void onVideoCallChanged(android.telecom.Call call,
-                    VideoCall videoCall) {
-                Log.d(this, "TelecomCallCallback onStateChanged call=" + call + " videoCall="
-                        + videoCall);
-                update();
-            }
-
-            @Override
-            public void onCallDestroyed(android.telecom.Call call) {
-                Log.d(this, "TelecomCallCallback onStateChanged call=" + call);
-                call.removeListener(this);
-            }
-
-            @Override
-            public void onConferenceableCallsChanged(android.telecom.Call call,
-                    List<android.telecom.Call> conferenceableCalls) {
-                update();
-            }
-        };
-    }
+    };
 
     private android.telecom.Call mTelecomCall;
     private boolean mIsEmergencyCall;
@@ -491,11 +405,7 @@
 
         updateFromTelecomCall();
 
-        if (SdkVersionOverride.getSdkVersion(Build.VERSION_CODES.M) >= Build.VERSION_CODES.M) {
-            mTelecomCall.registerCallback((android.telecom.Call.Callback) mTelecomCallCallback);
-        } else {
-            mTelecomCall.addListener((android.telecom.Call.Listener) mTelecomCallCallback);
-        }
+        mTelecomCall.registerCallback(mTelecomCallCallback);
 
         mTimeAddedMs = System.currentTimeMillis();
     }
@@ -750,7 +660,7 @@
     }
 
     public Bundle getIntentExtras() {
-        return DetailsCompat.getIntentExtras(mTelecomCall.getDetails());
+        return mTelecomCall.getDetails().getIntentExtras();
     }
 
     public Bundle getExtras() {
@@ -824,7 +734,7 @@
     }
 
     public boolean hasProperty(int property) {
-        return DetailsCompat.hasProperty(mTelecomCall.getDetails(), property);
+        return mTelecomCall.getDetails().hasProperty(property);
     }
 
     /** Gets the time when the call first became active. */
@@ -989,11 +899,11 @@
                 "videoState:%s, mSessionModificationState:%d, VideoSettings:%s]",
                 mId,
                 State.toString(getState()),
-                DetailsCompat.capabilitiesToString(mTelecomCall.getDetails().getCallCapabilities()),
+                Details.capabilitiesToString(mTelecomCall.getDetails().getCallCapabilities()),
                 mChildCallIds,
                 getParentId(),
                 this.mTelecomCall.getConferenceableCalls(),
-                VideoProfileCompat.videoStateToString(mTelecomCall.getDetails().getVideoState()),
+                VideoProfile.videoStateToString(mTelecomCall.getDetails().getVideoState()),
                 mSessionModificationState,
                 getVideoSettings());
     }
diff --git a/InCallUI/src/com/android/incallui/CallButtonFragment.java b/InCallUI/src/com/android/incallui/CallButtonFragment.java
index 1904ab0..9859f4e 100644
--- a/InCallUI/src/com/android/incallui/CallButtonFragment.java
+++ b/InCallUI/src/com/android/incallui/CallButtonFragment.java
@@ -39,6 +39,7 @@
 import android.graphics.drawable.RippleDrawable;
 import android.graphics.drawable.StateListDrawable;
 import android.os.Bundle;
+import android.telecom.CallAudioState;
 import android.util.SparseIntArray;
 import android.view.ContextThemeWrapper;
 import android.view.HapticFeedbackConstants;
@@ -54,7 +55,7 @@
 import android.widget.PopupMenu.OnMenuItemClickListener;
 
 import com.android.contacts.common.util.MaterialColorMapUtils.MaterialPalette;
-import com.android.dialer.compat.CallAudioStateCompat;
+import com.android.dialer.R;
 
 /**
  * Fragment for call control buttons
@@ -199,56 +200,40 @@
         int id = view.getId();
         Log.d(this, "onClick(View " + view + ", id " + id + ")...");
 
-        switch (id) {
-            case R.id.audioButton:
-                onAudioButtonClicked();
-                break;
-            case R.id.addButton:
-                getPresenter().addCallClicked();
-                break;
-            case R.id.muteButton: {
-                getPresenter().muteClicked(!mMuteButton.isSelected());
-                break;
+        if (id == R.id.audioButton) {
+            onAudioButtonClicked();
+        } else if (id == R.id.addButton) {
+            getPresenter().addCallClicked();
+        } else if (id == R.id.muteButton) {
+            getPresenter().muteClicked(!mMuteButton.isSelected());
+        } else if (id == R.id.mergeButton) {
+            getPresenter().mergeClicked();
+            mMergeButton.setEnabled(false);
+        } else if (id == R.id.holdButton) {
+            getPresenter().holdClicked(!mHoldButton.isSelected());
+        } else if (id == R.id.swapButton) {
+            getPresenter().swapClicked();
+        } else if (id == R.id.dialpadButton) {
+            getPresenter().showDialpadClicked(!mShowDialpadButton.isSelected());
+        } else if (id == R.id.changeToVideoButton) {
+            getPresenter().changeToVideoClicked();
+        } else if (id == R.id.changeToVoiceButton) {
+            getPresenter().changeToVoiceClicked();
+        } else if (id == R.id.switchCameraButton) {
+            getPresenter().switchCameraClicked(
+                    mSwitchCameraButton.isSelected() /* useFrontFacingCamera */);
+        } else if (id == R.id.pauseVideoButton) {
+            getPresenter().pauseVideoClicked(
+                    !mPauseVideoButton.isSelected() /* pause */);
+        } else if (id == R.id.overflowButton) {
+            if (mOverflowPopup != null) {
+                mOverflowPopup.show();
             }
-            case R.id.mergeButton:
-                getPresenter().mergeClicked();
-                mMergeButton.setEnabled(false);
-                break;
-            case R.id.holdButton: {
-                getPresenter().holdClicked(!mHoldButton.isSelected());
-                break;
-            }
-            case R.id.swapButton:
-                getPresenter().swapClicked();
-                break;
-            case R.id.dialpadButton:
-                getPresenter().showDialpadClicked(!mShowDialpadButton.isSelected());
-                break;
-            case R.id.changeToVideoButton:
-                getPresenter().changeToVideoClicked();
-                break;
-            case R.id.changeToVoiceButton:
-                getPresenter().changeToVoiceClicked();
-                break;
-            case R.id.switchCameraButton:
-                getPresenter().switchCameraClicked(
-                        mSwitchCameraButton.isSelected() /* useFrontFacingCamera */);
-                break;
-            case R.id.pauseVideoButton:
-                getPresenter().pauseVideoClicked(
-                        !mPauseVideoButton.isSelected() /* pause */);
-                break;
-            case R.id.overflowButton:
-                if (mOverflowPopup != null) {
-                    mOverflowPopup.show();
-                }
-                break;
-            case R.id.manageVideoCallConferenceButton:
-                onManageVideoCallConferenceClicked();
-                break;
-            default:
-                Log.wtf(this, "onClick: unexpected");
-                return;
+        } else if (id == R.id.manageVideoCallConferenceButton) {
+            onManageVideoCallConferenceClicked();
+        } else {
+            Log.wtf(this, "onClick: unexpected");
+            return;
         }
 
         view.performHapticFeedback(
@@ -394,34 +379,33 @@
     }
 
     private View getButtonById(int id) {
-        switch (id) {
-            case BUTTON_AUDIO:
-                return mAudioButton;
-            case BUTTON_MUTE:
-                return mMuteButton;
-            case BUTTON_DIALPAD:
-                return mShowDialpadButton;
-            case BUTTON_HOLD:
-                return mHoldButton;
-            case BUTTON_SWAP:
-                return mSwapButton;
-            case BUTTON_UPGRADE_TO_VIDEO:
-                return mChangeToVideoButton;
-            case BUTTON_DOWNGRADE_TO_AUDIO:
-                return mChangeToVoiceButton;
-            case BUTTON_SWITCH_CAMERA:
-                return mSwitchCameraButton;
-            case BUTTON_ADD_CALL:
-                return mAddCallButton;
-            case BUTTON_MERGE:
-                return mMergeButton;
-            case BUTTON_PAUSE_VIDEO:
-                return mPauseVideoButton;
-            case BUTTON_MANAGE_VIDEO_CONFERENCE:
-                return mManageVideoCallConferenceButton;
-            default:
-                Log.w(this, "Invalid button id");
-                return null;
+        if (id == BUTTON_AUDIO) {
+            return mAudioButton;
+        } else if (id == BUTTON_MUTE) {
+            return mMuteButton;
+        } else if (id == BUTTON_DIALPAD) {
+            return mShowDialpadButton;
+        } else if (id == BUTTON_HOLD) {
+            return mHoldButton;
+        } else if (id == BUTTON_SWAP) {
+            return mSwapButton;
+        } else if (id == BUTTON_UPGRADE_TO_VIDEO) {
+            return mChangeToVideoButton;
+        } else if (id == BUTTON_DOWNGRADE_TO_AUDIO) {
+            return mChangeToVoiceButton;
+        } else if (id == BUTTON_SWITCH_CAMERA) {
+            return mSwitchCameraButton;
+        } else if (id == BUTTON_ADD_CALL) {
+            return mAddCallButton;
+        } else if (id == BUTTON_MERGE) {
+            return mMergeButton;
+        } else if (id == BUTTON_PAUSE_VIDEO) {
+            return mPauseVideoButton;
+        } else if (id == BUTTON_MANAGE_VIDEO_CONFERENCE) {
+            return mManageVideoCallConferenceButton;
+        } else {
+            Log.w(this, "Invalid button id");
+            return null;
         }
     }
 
@@ -539,25 +523,20 @@
         Log.d(this, "  id: " + item.getItemId());
         Log.d(this, "  title: '" + item.getTitle() + "'");
 
-        int mode = CallAudioStateCompat.ROUTE_WIRED_OR_EARPIECE;
+        int mode = CallAudioState.ROUTE_WIRED_OR_EARPIECE;
+        int resId = item.getItemId();
 
-        switch (item.getItemId()) {
-            case R.id.audio_mode_speaker:
-                mode = CallAudioStateCompat.ROUTE_SPEAKER;
-                break;
-            case R.id.audio_mode_earpiece:
-            case R.id.audio_mode_wired_headset:
-                // InCallCallAudioState.ROUTE_EARPIECE means either the handset earpiece,
-                // or the wired headset (if connected.)
-                mode = CallAudioStateCompat.ROUTE_WIRED_OR_EARPIECE;
-                break;
-            case R.id.audio_mode_bluetooth:
-                mode = CallAudioStateCompat.ROUTE_BLUETOOTH;
-                break;
-            default:
-                Log.e(this, "onMenuItemClick:  unexpected View ID " + item.getItemId()
-                        + " (MenuItem = '" + item + "')");
-                break;
+        if (resId == R.id.audio_mode_speaker) {
+            mode = CallAudioState.ROUTE_SPEAKER;
+        } else if (resId == R.id.audio_mode_earpiece || resId == R.id.audio_mode_wired_headset) {
+            // InCallCallAudioState.ROUTE_EARPIECE means either the handset earpiece,
+            // or the wired headset (if connected.)
+            mode = CallAudioState.ROUTE_WIRED_OR_EARPIECE;
+        } else if (resId == R.id.audio_mode_bluetooth) {
+            mode = CallAudioState.ROUTE_BLUETOOTH;
+        } else {
+            Log.e(this, "onMenuItemClick:  unexpected View ID " + item.getItemId()
+                    + " (MenuItem = '" + item + "')");
         }
 
         getPresenter().setAudioMode(mode);
@@ -582,9 +561,9 @@
      */
     private void onAudioButtonClicked() {
         Log.d(this, "onAudioButtonClicked: " +
-                CallAudioStateCompat.audioRouteToString(getPresenter().getSupportedAudio()));
+                CallAudioState.audioRouteToString(getPresenter().getSupportedAudio()));
 
-        if (isSupported(CallAudioStateCompat.ROUTE_BLUETOOTH)) {
+        if (isSupported(CallAudioState.ROUTE_BLUETOOTH)) {
             showAudioModePopup();
         } else {
             getPresenter().toggleSpeakerphone();
@@ -619,8 +598,8 @@
      * are visible based on the supported audio formats.
      */
     private void updateAudioButtons(int supportedModes) {
-        final boolean bluetoothSupported = isSupported(CallAudioStateCompat.ROUTE_BLUETOOTH);
-        final boolean speakerSupported = isSupported(CallAudioStateCompat.ROUTE_SPEAKER);
+        final boolean bluetoothSupported = isSupported(CallAudioState.ROUTE_BLUETOOTH);
+        final boolean speakerSupported = isSupported(CallAudioState.ROUTE_SPEAKER);
 
         boolean audioButtonEnabled = false;
         boolean audioButtonChecked = false;
@@ -640,9 +619,9 @@
             showMoreIndicator = true;
 
             // Update desired layers:
-            if (isAudio(CallAudioStateCompat.ROUTE_BLUETOOTH)) {
+            if (isAudio(CallAudioState.ROUTE_BLUETOOTH)) {
                 showBluetoothIcon = true;
-            } else if (isAudio(CallAudioStateCompat.ROUTE_SPEAKER)) {
+            } else if (isAudio(CallAudioState.ROUTE_SPEAKER)) {
                 showSpeakerphoneIcon = true;
             } else {
                 showHandsetIcon = true;
@@ -661,7 +640,7 @@
 
             // The audio button *is* a toggle in this state, and indicated the
             // current state of the speakerphone.
-            audioButtonChecked = isAudio(CallAudioStateCompat.ROUTE_SPEAKER);
+            audioButtonChecked = isAudio(CallAudioState.ROUTE_SPEAKER);
             mAudioButton.setSelected(audioButtonChecked);
 
             // update desired layers:
@@ -722,20 +701,20 @@
 
         // If bluetooth is not supported, the audio buttion will toggle, so use the label "speaker".
         // Otherwise, use the label of the currently selected audio mode.
-        if (!isSupported(CallAudioStateCompat.ROUTE_BLUETOOTH)) {
+        if (!isSupported(CallAudioState.ROUTE_BLUETOOTH)) {
             stringId = R.string.audio_mode_speaker;
         } else {
             switch (mode) {
-                case CallAudioStateCompat.ROUTE_EARPIECE:
+                case CallAudioState.ROUTE_EARPIECE:
                     stringId = R.string.audio_mode_earpiece;
                     break;
-                case CallAudioStateCompat.ROUTE_BLUETOOTH:
+                case CallAudioState.ROUTE_BLUETOOTH:
                     stringId = R.string.audio_mode_bluetooth;
                     break;
-                case CallAudioStateCompat.ROUTE_WIRED_HEADSET:
+                case CallAudioState.ROUTE_WIRED_HEADSET:
                     stringId = R.string.audio_mode_wired_headset;
                     break;
-                case CallAudioStateCompat.ROUTE_SPEAKER:
+                case CallAudioState.ROUTE_SPEAKER:
                     stringId = R.string.audio_mode_speaker;
                     break;
             }
@@ -765,7 +744,7 @@
         // See comments below for the exact logic.
 
         final MenuItem speakerItem = menu.findItem(R.id.audio_mode_speaker);
-        speakerItem.setEnabled(isSupported(CallAudioStateCompat.ROUTE_SPEAKER));
+        speakerItem.setEnabled(isSupported(CallAudioState.ROUTE_SPEAKER));
         // TODO: Show speakerItem as initially "selected" if
         // speaker is on.
 
@@ -774,7 +753,7 @@
         final MenuItem earpieceItem = menu.findItem(R.id.audio_mode_earpiece);
         final MenuItem wiredHeadsetItem = menu.findItem(R.id.audio_mode_wired_headset);
 
-        final boolean usingHeadset = isSupported(CallAudioStateCompat.ROUTE_WIRED_HEADSET);
+        final boolean usingHeadset = isSupported(CallAudioState.ROUTE_WIRED_HEADSET);
         earpieceItem.setVisible(!usingHeadset);
         earpieceItem.setEnabled(!usingHeadset);
         wiredHeadsetItem.setVisible(usingHeadset);
@@ -784,7 +763,7 @@
         // bluetoothIndicatorOn are both false.
 
         final MenuItem bluetoothItem = menu.findItem(R.id.audio_mode_bluetooth);
-        bluetoothItem.setEnabled(isSupported(CallAudioStateCompat.ROUTE_BLUETOOTH));
+        bluetoothItem.setEnabled(isSupported(CallAudioState.ROUTE_BLUETOOTH));
         // TODO: Show bluetoothItem as initially "selected" if
         // bluetoothIndicatorOn is true.
 
diff --git a/InCallUI/src/com/android/incallui/CallButtonPresenter.java b/InCallUI/src/com/android/incallui/CallButtonPresenter.java
index dde6295..e8c2d4b 100644
--- a/InCallUI/src/com/android/incallui/CallButtonPresenter.java
+++ b/InCallUI/src/com/android/incallui/CallButtonPresenter.java
@@ -31,12 +31,12 @@
 import android.content.Context;
 import android.os.Build;
 import android.os.Bundle;
+import android.telecom.CallAudioState;
 import android.telecom.InCallService.VideoCall;
 import android.telecom.VideoProfile;
 
 import com.android.contacts.common.compat.CallSdkCompat;
 import com.android.contacts.common.compat.SdkVersionOverride;
-import com.android.dialer.compat.CallAudioStateCompat;
 import com.android.dialer.compat.UserManagerCompat;
 import com.android.incallui.AudioModeProvider.AudioModeListener;
 import com.android.incallui.InCallCameraManager.Listener;
@@ -189,7 +189,7 @@
         // an update for onAudioMode().  This will make UI response immediate
         // if it turns out to be slow
 
-        Log.d(this, "Sending new Audio Mode: " + CallAudioStateCompat.audioRouteToString(mode));
+        Log.d(this, "Sending new Audio Mode: " + CallAudioState.audioRouteToString(mode));
         TelecomAdapter.getInstance().setAudioRoute(mode);
     }
 
@@ -198,7 +198,7 @@
      */
     public void toggleSpeakerphone() {
         // this function should not be called if bluetooth is available
-        if (0 != (CallAudioStateCompat.ROUTE_BLUETOOTH & getSupportedAudio())) {
+        if (0 != (CallAudioState.ROUTE_BLUETOOTH & getSupportedAudio())) {
 
             // It's clear the UI is wrong, so update the supported mode once again.
             Log.e(this, "toggling speakerphone not allowed when bluetooth supported.");
@@ -206,11 +206,11 @@
             return;
         }
 
-        int newMode = CallAudioStateCompat.ROUTE_SPEAKER;
+        int newMode = CallAudioState.ROUTE_SPEAKER;
 
         // if speakerphone is already on, change to wired/earpiece
-        if (getAudioMode() == CallAudioStateCompat.ROUTE_SPEAKER) {
-            newMode = CallAudioStateCompat.ROUTE_WIRED_OR_EARPIECE;
+        if (getAudioMode() == CallAudioState.ROUTE_SPEAKER) {
+            newMode = CallAudioState.ROUTE_WIRED_OR_EARPIECE;
         }
 
         setAudioMode(newMode);
@@ -380,7 +380,7 @@
                 && call.can(android.telecom.Call.Details.CAPABILITY_HOLD);
         final boolean isCallOnHold = call.getState() == Call.State.ONHOLD;
 
-        final boolean showAddCall = TelecomAdapter.getInstance().canAddCall(call)
+        final boolean showAddCall = TelecomAdapter.getInstance().canAddCall()
                 && UserManagerCompat.isUserUnlocked(ui.getContext());
         final boolean showMerge = call.can(
                 android.telecom.Call.Details.CAPABILITY_MERGE_CONFERENCE);
diff --git a/InCallUI/src/com/android/incallui/CallCardFragment.java b/InCallUI/src/com/android/incallui/CallCardFragment.java
index ad72690..84a732c 100644
--- a/InCallUI/src/com/android/incallui/CallCardFragment.java
+++ b/InCallUI/src/com/android/incallui/CallCardFragment.java
@@ -58,6 +58,7 @@
 import com.android.contacts.common.compat.PhoneNumberUtilsCompat;
 import com.android.contacts.common.util.MaterialColorMapUtils.MaterialPalette;
 import com.android.contacts.common.widget.FloatingActionButtonController;
+import com.android.dialer.R;
 import com.android.phone.common.animation.AnimUtils;
 
 import java.util.List;
diff --git a/InCallUI/src/com/android/incallui/CallCardPresenter.java b/InCallUI/src/com/android/incallui/CallCardPresenter.java
index 2acdc47..dd255e0 100644
--- a/InCallUI/src/com/android/incallui/CallCardPresenter.java
+++ b/InCallUI/src/com/android/incallui/CallCardPresenter.java
@@ -45,6 +45,7 @@
 import com.android.contacts.common.preference.ContactsPreferences;
 import com.android.contacts.common.testing.NeededForTesting;
 import com.android.contacts.common.util.ContactDisplayUtils;
+import com.android.dialer.R;
 import com.android.incallui.Call.State;
 import com.android.incallui.ContactInfoCache.ContactCacheEntry;
 import com.android.incallui.ContactInfoCache.ContactInfoCacheCallback;
@@ -53,7 +54,6 @@
 import com.android.incallui.InCallPresenter.InCallState;
 import com.android.incallui.InCallPresenter.InCallStateListener;
 import com.android.incallui.InCallPresenter.IncomingCallListener;
-import com.android.incallui.compat.telecom.DetailsCompat;
 import com.android.incalluibind.ObjectFactory;
 
 import java.lang.ref.WeakReference;
@@ -345,7 +345,7 @@
         updatePrimaryCallState();
 
         if (call.can(Details.CAPABILITY_MANAGE_CONFERENCE) !=
-                DetailsCompat.can(details, Details.CAPABILITY_MANAGE_CONFERENCE)) {
+                details.can(Details.CAPABILITY_MANAGE_CONFERENCE)) {
             maybeShowManageConferenceCallButton();
         }
     }
@@ -1112,8 +1112,8 @@
     }
 
     private static boolean hasCallSubject(Call call) {
-        return !TextUtils.isEmpty(DetailsCompat.getIntentExtras(
-                call.getTelecomCall().getDetails()).getString(TelecomManager.EXTRA_CALL_SUBJECT));
+        return !TextUtils.isEmpty(call.getTelecomCall().getDetails().getIntentExtras()
+                .getString(TelecomManager.EXTRA_CALL_SUBJECT));
     }
 
     public interface CallCardUi extends Ui {
diff --git a/InCallUI/src/com/android/incallui/CallerInfo.java b/InCallUI/src/com/android/incallui/CallerInfo.java
index 670c3fd..a638e11 100644
--- a/InCallUI/src/com/android/incallui/CallerInfo.java
+++ b/InCallUI/src/com/android/incallui/CallerInfo.java
@@ -16,6 +16,7 @@
 
 package com.android.incallui;
 
+import com.android.dialer.util.PhoneLookupUtil;
 import com.google.common.primitives.Longs;
 
 import android.content.Context;
@@ -32,10 +33,13 @@
 import android.telephony.PhoneNumberUtils;
 import android.text.TextUtils;
 
+import com.android.contacts.common.compat.CompatUtils;
+import com.android.contacts.common.compat.PhoneLookupSdkCompat;
 import com.android.contacts.common.ContactsUtils;
 import com.android.contacts.common.ContactsUtils.UserType;
 import com.android.contacts.common.util.PhoneNumberHelper;
 import com.android.contacts.common.util.TelephonyManagerUtils;
+import com.android.dialer.R;
 import com.android.dialer.calllog.ContactInfoHelper;
 
 /**
@@ -44,8 +48,9 @@
 public class CallerInfo {
     private static final String TAG = "CallerInfo";
 
-    public static final String[] DEFAULT_PHONELOOKUP_PROJECTION = new String[] {
-            PhoneLookup._ID,
+    // We should always use this projection starting from NYC onward.
+    private static final String[] DEFAULT_PHONELOOKUP_PROJECTION = new String[] {
+            PhoneLookupSdkCompat.CONTACT_ID,
             PhoneLookup.DISPLAY_NAME,
             PhoneLookup.LOOKUP_KEY,
             PhoneLookup.NUMBER,
@@ -57,6 +62,32 @@
             PhoneLookup.SEND_TO_VOICEMAIL
     };
 
+    // In pre-N, contact id is stored in {@link PhoneLookup._ID} in non-sip query.
+    private static final String[] BACKWARD_COMPATIBLE_NON_SIP_DEFAULT_PHONELOOKUP_PROJECTION =
+            new String[] {
+                    PhoneLookup._ID,
+                    PhoneLookup.DISPLAY_NAME,
+                    PhoneLookup.LOOKUP_KEY,
+                    PhoneLookup.NUMBER,
+                    PhoneLookup.NORMALIZED_NUMBER,
+                    PhoneLookup.LABEL,
+                    PhoneLookup.TYPE,
+                    PhoneLookup.PHOTO_URI,
+                    PhoneLookup.CUSTOM_RINGTONE,
+                    PhoneLookup.SEND_TO_VOICEMAIL
+    };
+
+    public static String[] getDefaultPhoneLookupProjection(Uri phoneLookupUri) {
+        if (CompatUtils.isNCompatible()) {
+            return DEFAULT_PHONELOOKUP_PROJECTION;
+        }
+        // Pre-N
+        boolean isSip = phoneLookupUri.getBooleanQueryParameter(
+                        ContactsContract.PhoneLookup.QUERY_PARAMETER_SIP_ADDRESS, false);
+        return (isSip) ? DEFAULT_PHONELOOKUP_PROJECTION
+                : BACKWARD_COMPATIBLE_NON_SIP_DEFAULT_PHONELOOKUP_PROJECTION;
+    }
+
     /**
      * Please note that, any one of these member variables can be null,
      * and any accesses to them should be prepared to handle such a case.
@@ -480,7 +511,7 @@
             // for phone numbers.
             // MIME type: PhoneLookup.CONTENT_TYPE (= "vnd.android.cursor.dir/phone_lookup")
             Log.v(TAG, "'phone_lookup' URI; using PhoneLookup._ID");
-            columnName = PhoneLookup._ID;
+            columnName = PhoneLookupUtil.getContactIdColumnNameForUri(contactRef);
         } else {
             Log.v(TAG, "Unexpected prefix for contactRef '" + url + "'");
         }
diff --git a/InCallUI/src/com/android/incallui/CallerInfoAsyncQuery.java b/InCallUI/src/com/android/incallui/CallerInfoAsyncQuery.java
index 590afaf..6dbbfc1 100644
--- a/InCallUI/src/com/android/incallui/CallerInfoAsyncQuery.java
+++ b/InCallUI/src/com/android/incallui/CallerInfoAsyncQuery.java
@@ -37,6 +37,7 @@
 import com.android.contacts.common.compat.DirectoryCompat;
 import com.android.contacts.common.util.PermissionsUtil;
 import com.android.contacts.common.util.TelephonyManagerUtils;
+import com.android.dialer.R;
 import com.android.dialer.calllog.ContactInfoHelper;
 import com.android.dialer.service.CachedNumberLookupService;
 import com.android.dialer.service.CachedNumberLookupService.CachedContactInfo;
@@ -407,13 +408,15 @@
             cw.event = EVENT_NEW_QUERY;
         }
 
+
+        String[] proejection = CallerInfo.getDefaultPhoneLookupProjection(contactRef);
         c.mHandler.startQuery(token,
-                              cw,  // cookie
-                              contactRef,  // uri
-                              CallerInfo.DEFAULT_PHONELOOKUP_PROJECTION,  // projection
-                              null,  // selection
-                              null,  // selectionArgs
-                              null);  // orderBy
+                cw,  // cookie
+                contactRef,  // uri
+                proejection, // projection
+                null,  // selection
+                null,  // selectionArgs
+                null);  // orderBy
         return c;
     }
 
diff --git a/InCallUI/src/com/android/incallui/CallerInfoUtils.java b/InCallUI/src/com/android/incallui/CallerInfoUtils.java
index ae59d7d..aff3956 100644
--- a/InCallUI/src/com/android/incallui/CallerInfoUtils.java
+++ b/InCallUI/src/com/android/incallui/CallerInfoUtils.java
@@ -12,6 +12,7 @@
 import com.android.contacts.common.compat.telecom.TelecomManagerCompat;
 import com.android.contacts.common.model.Contact;
 import com.android.contacts.common.model.ContactLoader;
+import com.android.dialer.R;
 import com.android.dialer.calllog.ContactInfo;
 import com.android.dialer.service.CachedNumberLookupService;
 import com.android.dialer.service.CachedNumberLookupService.CachedContactInfo;
diff --git a/InCallUI/src/com/android/incallui/CircularRevealFragment.java b/InCallUI/src/com/android/incallui/CircularRevealFragment.java
index f4a2e91..01bd253 100644
--- a/InCallUI/src/com/android/incallui/CircularRevealFragment.java
+++ b/InCallUI/src/com/android/incallui/CircularRevealFragment.java
@@ -34,6 +34,7 @@
 import android.view.ViewTreeObserver.OnPreDrawListener;
 
 import com.android.contacts.common.util.MaterialColorMapUtils.MaterialPalette;
+import com.android.dialer.R;
 
 public class CircularRevealFragment extends Fragment {
     static final String TAG = "CircularRevealFragment";
diff --git a/InCallUI/src/com/android/incallui/ConferenceManagerFragment.java b/InCallUI/src/com/android/incallui/ConferenceManagerFragment.java
index f5f52fc..fe941c8 100644
--- a/InCallUI/src/com/android/incallui/ConferenceManagerFragment.java
+++ b/InCallUI/src/com/android/incallui/ConferenceManagerFragment.java
@@ -25,6 +25,7 @@
 import android.widget.ListView;
 
 import com.android.contacts.common.ContactPhotoManager;
+import com.android.dialer.R;
 
 import java.util.List;
 
diff --git a/InCallUI/src/com/android/incallui/ConferenceParticipantListAdapter.java b/InCallUI/src/com/android/incallui/ConferenceParticipantListAdapter.java
index 86002b0..d68ae1f 100644
--- a/InCallUI/src/com/android/incallui/ConferenceParticipantListAdapter.java
+++ b/InCallUI/src/com/android/incallui/ConferenceParticipantListAdapter.java
@@ -37,8 +37,8 @@
 import com.android.contacts.common.compat.PhoneNumberUtilsCompat;
 import com.android.contacts.common.preference.ContactsPreferences;
 import com.android.contacts.common.util.ContactDisplayUtils;
+import com.android.dialer.R;
 import com.android.incallui.ContactInfoCache.ContactCacheEntry;
-import com.android.incallui.compat.telecom.DetailsCompat;
 
 import java.lang.ref.WeakReference;
 import java.util.ArrayList;
@@ -356,10 +356,9 @@
                     new ContactLookupCallback(this));
         }
 
-        boolean thisRowCanSeparate = mParentCanSeparate && DetailsCompat.can(
-                call.getTelecomCall().getDetails(),
+        boolean thisRowCanSeparate = mParentCanSeparate && call.getTelecomCall().getDetails().can(
                 android.telecom.Call.Details.CAPABILITY_SEPARATE_FROM_CONFERENCE);
-        boolean thisRowCanDisconnect = DetailsCompat.can(call.getTelecomCall().getDetails(),
+        boolean thisRowCanDisconnect = call.getTelecomCall().getDetails().can(
                 android.telecom.Call.Details.CAPABILITY_DISCONNECT_FROM_CONFERENCE);
 
         setCallerInfoForRow(result, contactCache.namePrimary,
diff --git a/InCallUI/src/com/android/incallui/ContactInfoCache.java b/InCallUI/src/com/android/incallui/ContactInfoCache.java
index ab4150b..9d6fc46 100644
--- a/InCallUI/src/com/android/incallui/ContactInfoCache.java
+++ b/InCallUI/src/com/android/incallui/ContactInfoCache.java
@@ -40,6 +40,7 @@
 
 import com.android.contacts.common.ContactsUtils;
 import com.android.contacts.common.util.PhoneNumberHelper;
+import com.android.dialer.R;
 import com.android.dialer.calllog.ContactInfo;
 import com.android.dialer.service.CachedNumberLookupService;
 import com.android.dialer.service.CachedNumberLookupService.CachedContactInfo;
diff --git a/InCallUI/src/com/android/incallui/ContactsAsyncHelper.java b/InCallUI/src/com/android/incallui/ContactsAsyncHelper.java
index 011eef2..d959fad 100644
--- a/InCallUI/src/com/android/incallui/ContactsAsyncHelper.java
+++ b/InCallUI/src/com/android/incallui/ContactsAsyncHelper.java
@@ -30,6 +30,8 @@
 import android.os.Message;
 import android.provider.ContactsContract.Contacts;
 
+import com.android.dialer.R;
+
 import java.io.IOException;
 import java.io.InputStream;
 
diff --git a/InCallUI/src/com/android/incallui/DialpadFragment.java b/InCallUI/src/com/android/incallui/DialpadFragment.java
index ab44cf2..ae66a49 100644
--- a/InCallUI/src/com/android/incallui/DialpadFragment.java
+++ b/InCallUI/src/com/android/incallui/DialpadFragment.java
@@ -34,6 +34,7 @@
 import android.widget.TextView;
 
 import com.android.contacts.common.compat.PhoneNumberUtilsCompat;
+import com.android.dialer.R;
 import com.android.phone.common.dialpad.DialpadKeyButton;
 import com.android.phone.common.dialpad.DialpadView;
 
diff --git a/InCallUI/src/com/android/incallui/GlowPadWrapper.java b/InCallUI/src/com/android/incallui/GlowPadWrapper.java
index 1bd6d39..342f6b4 100644
--- a/InCallUI/src/com/android/incallui/GlowPadWrapper.java
+++ b/InCallUI/src/com/android/incallui/GlowPadWrapper.java
@@ -23,6 +23,7 @@
 import android.util.AttributeSet;
 import android.view.View;
 
+import com.android.dialer.R;
 import com.android.incallui.widget.multiwaveview.GlowPadView;
 
 /**
@@ -111,31 +112,24 @@
     public void onTrigger(View v, int target) {
         Log.d(this, "onTrigger() view=" + v + " target=" + target);
         final int resId = getResourceIdForTarget(target);
-        switch (resId) {
-            case R.drawable.ic_lockscreen_answer:
-                mAnswerFragment.onAnswer(VideoProfile.STATE_AUDIO_ONLY, getContext());
-                mTargetTriggered = true;
-                break;
-            case R.drawable.ic_lockscreen_decline:
-                mAnswerFragment.onDecline(getContext());
-                mTargetTriggered = true;
-                break;
-            case R.drawable.ic_lockscreen_text:
-                mAnswerFragment.onText();
-                mTargetTriggered = true;
-                break;
-            case R.drawable.ic_videocam:
-            case R.drawable.ic_lockscreen_answer_video:
-                mAnswerFragment.onAnswer(mVideoState, getContext());
-                mTargetTriggered = true;
-                break;
-            case R.drawable.ic_lockscreen_decline_video:
-                mAnswerFragment.onDeclineUpgradeRequest(getContext());
-                mTargetTriggered = true;
-                break;
-            default:
-                // Code should never reach here.
-                Log.e(this, "Trigger detected on unhandled resource. Skipping.");
+        if (resId == R.drawable.ic_lockscreen_answer) {
+            mAnswerFragment.onAnswer(VideoProfile.STATE_AUDIO_ONLY, getContext());
+            mTargetTriggered = true;
+        } else if (resId == R.drawable.ic_lockscreen_decline) {
+            mAnswerFragment.onDecline(getContext());
+            mTargetTriggered = true;
+        } else if (resId == R.drawable.ic_lockscreen_text) {
+            mAnswerFragment.onText();
+            mTargetTriggered = true;
+        } else if (resId == R.drawable.ic_videocam || resId == R.drawable.ic_lockscreen_answer_video) {
+            mAnswerFragment.onAnswer(mVideoState, getContext());
+            mTargetTriggered = true;
+        } else if (resId == R.drawable.ic_lockscreen_decline_video) {
+            mAnswerFragment.onDeclineUpgradeRequest(getContext());
+            mTargetTriggered = true;
+        } else {
+            // Code should never reach here.
+            Log.e(this, "Trigger detected on unhandled resource. Skipping.");
         }
     }
 
diff --git a/InCallUI/src/com/android/incallui/InCallActivity.java b/InCallUI/src/com/android/incallui/InCallActivity.java
index 9e35c3d..eca79f8 100644
--- a/InCallUI/src/com/android/incallui/InCallActivity.java
+++ b/InCallUI/src/com/android/incallui/InCallActivity.java
@@ -55,10 +55,10 @@
 import com.android.contacts.common.interactions.TouchPointManager;
 import com.android.contacts.common.widget.SelectPhoneAccountDialogFragment;
 import com.android.contacts.common.widget.SelectPhoneAccountDialogFragment.SelectPhoneAccountListener;
+import com.android.dialer.R;
 import com.android.dialer.logging.Logger;
 import com.android.dialer.logging.ScreenEvent;
 import com.android.incallui.Call.State;
-import com.android.incallui.compat.telecom.DetailsCompat;
 import com.android.incallui.util.AccessibilityUtil;
 import com.android.phone.common.animation.AnimUtils;
 import com.android.phone.common.animation.AnimationListenerAdapter;
@@ -600,7 +600,7 @@
 
                 Bundle extras = null;
                 if (call != null) {
-                    extras = DetailsCompat.getIntentExtras(call.getTelecomCall().getDetails());
+                    extras = call.getTelecomCall().getDetails().getIntentExtras();
                 }
                 if (extras == null) {
                     // Initialize the extras bundle to avoid NPE
@@ -637,8 +637,8 @@
             Call pendingAccountSelectionCall = CallList.getInstance().getWaitingForAccountCall();
             if (pendingAccountSelectionCall != null) {
                 showCallCardFragment(false);
-                Bundle extras = DetailsCompat.getIntentExtras(pendingAccountSelectionCall
-                        .getTelecomCall().getDetails());
+                Bundle extras =
+                        pendingAccountSelectionCall.getTelecomCall().getDetails().getIntentExtras();
 
                 final List<PhoneAccountHandle> phoneAccountHandles;
                 if (extras != null) {
diff --git a/InCallUI/src/com/android/incallui/InCallContactInteractions.java b/InCallUI/src/com/android/incallui/InCallContactInteractions.java
index e627668..88070fe 100644
--- a/InCallUI/src/com/android/incallui/InCallContactInteractions.java
+++ b/InCallUI/src/com/android/incallui/InCallContactInteractions.java
@@ -33,6 +33,8 @@
 import android.widget.RelativeLayout.LayoutParams;
 import android.widget.TextView;
 
+import com.android.dialer.R;
+
 import java.text.ParseException;
 import java.text.SimpleDateFormat;
 import java.util.ArrayList;
@@ -394,4 +396,4 @@
             return listItem;
         }
     }
-}
\ No newline at end of file
+}
diff --git a/InCallUI/src/com/android/incallui/InCallDateUtils.java b/InCallUI/src/com/android/incallui/InCallDateUtils.java
index da3bb6b..e6089d5 100644
--- a/InCallUI/src/com/android/incallui/InCallDateUtils.java
+++ b/InCallUI/src/com/android/incallui/InCallDateUtils.java
@@ -3,6 +3,8 @@
 import android.content.Context;
 import android.content.res.Resources;
 
+import com.android.dialer.R;
+
 /**
  * Methods to parse time and date information in the InCallUi
  */
diff --git a/InCallUI/src/com/android/incallui/InCallPresenter.java b/InCallUI/src/com/android/incallui/InCallPresenter.java
index c51a561..5a27b4c 100644
--- a/InCallUI/src/com/android/incallui/InCallPresenter.java
+++ b/InCallUI/src/com/android/incallui/InCallPresenter.java
@@ -25,7 +25,6 @@
 import android.content.res.Resources;
 import android.database.ContentObserver;
 import android.graphics.Point;
-import android.os.Build;
 import android.os.Bundle;
 import android.os.Handler;
 import android.provider.CallLog;
@@ -48,6 +47,7 @@
 import com.android.contacts.common.interactions.TouchPointManager;
 import com.android.contacts.common.testing.NeededForTesting;
 import com.android.contacts.common.util.MaterialColorMapUtils.MaterialPalette;
+import com.android.dialer.R;
 import com.android.dialer.calllog.CallLogAsyncTaskUtil;
 import com.android.dialer.calllog.CallLogAsyncTaskUtil.OnCallLogQueryFinishedListener;
 import com.android.dialer.database.FilteredNumberAsyncQueryHandler;
@@ -56,7 +56,6 @@
 import com.android.dialer.logging.InteractionEvent;
 import com.android.dialer.logging.Logger;
 import com.android.dialer.util.TelecomUtil;
-import com.android.incallui.compat.telecom.DetailsCompat;
 import com.android.incallui.util.TelecomCallUtil;
 import com.android.incalluibind.ObjectFactory;
 
@@ -139,89 +138,38 @@
      */
     private boolean mIsFullScreen = false;
 
-    private final Object mCallCallback = newTelecomCallCallback();
-
-    private Object newTelecomCallCallback() {
-        if (SdkVersionOverride.getSdkVersion(Build.VERSION_CODES.M) >= Build.VERSION_CODES.M) {
-            return newMarshmallowTelecomCallCallback();
+    private final android.telecom.Call.Callback mCallCallback = new android.telecom.Call.Callback() {
+        @Override
+        public void onPostDialWait(android.telecom.Call telecomCall,
+                String remainingPostDialSequence) {
+            final Call call = mCallList.getCallByTelecomCall(telecomCall);
+            if (call == null) {
+                Log.w(this, "Call not found in call list: " + telecomCall);
+                return;
+            }
+            onPostDialCharWait(call.getId(), remainingPostDialSequence);
         }
-        return newLollipopTelecomCallCallback();
-    }
 
-    private Object newMarshmallowTelecomCallCallback() {
-        Log.i(this, "Using android.telecom.Call.Callback");
-        return new android.telecom.Call.Callback() {
-            @Override
-            public void onPostDialWait(android.telecom.Call telecomCall,
-                    String remainingPostDialSequence) {
-                final Call call = mCallList.getCallByTelecomCall(telecomCall);
-                if (call == null) {
-                    Log.w(this, "Call not found in call list: " + telecomCall);
-                    return;
-                }
-                onPostDialCharWait(call.getId(), remainingPostDialSequence);
+        @Override
+        public void onDetailsChanged(android.telecom.Call telecomCall,
+                android.telecom.Call.Details details) {
+            final Call call = mCallList.getCallByTelecomCall(telecomCall);
+            if (call == null) {
+                Log.w(this, "Call not found in call list: " + telecomCall);
+                return;
             }
+            for (InCallDetailsListener listener : mDetailsListeners) {
+                listener.onDetailsChanged(call, details);
+            }
+        }
 
-            @Override
-            public void onDetailsChanged(android.telecom.Call telecomCall,
-                    android.telecom.Call.Details details) {
-                final Call call = mCallList.getCallByTelecomCall(telecomCall);
-                if (call == null) {
-                    Log.w(this, "Call not found in call list: " + telecomCall);
-                    return;
-                }
-                for (InCallDetailsListener listener : mDetailsListeners) {
-                    listener.onDetailsChanged(call, details);
-                }
-            }
-
-            @Override
-            public void onConferenceableCallsChanged(android.telecom.Call telecomCall,
-                    List<android.telecom.Call> conferenceableCalls) {
-                Log.i(this, "onConferenceableCallsChanged: " + telecomCall);
-                onDetailsChanged(telecomCall, telecomCall.getDetails());
-            }
-        };
-    }
-
-    private Object newLollipopTelecomCallCallback() {
-        // This code only runs for Google Experience phones on the pre-M sdk since only the system
-        // dialer can invoke the InCallUI code. This allows us to safely use the
-        // android.telecom.Call.Listener interface
-        Log.i(this, "Using android.telecom.Call.Listener");
-        return new android.telecom.Call.Listener() {
-            @Override
-            public void onPostDialWait(android.telecom.Call telecomCall,
-                    String remainingPostDialSequence) {
-                final Call call = mCallList.getCallByTelecomCall(telecomCall);
-                if (call == null) {
-                    Log.w(this, "Call not found in call list: " + telecomCall);
-                    return;
-                }
-                onPostDialCharWait(call.getId(), remainingPostDialSequence);
-            }
-
-            @Override
-            public void onDetailsChanged(android.telecom.Call telecomCall,
-                    android.telecom.Call.Details details) {
-                final Call call = mCallList.getCallByTelecomCall(telecomCall);
-                if (call == null) {
-                    Log.w(this, "Call not found in call list: " + telecomCall);
-                    return;
-                }
-                for (InCallDetailsListener listener : mDetailsListeners) {
-                    listener.onDetailsChanged(call, details);
-                }
-            }
-
-            @Override
-            public void onConferenceableCallsChanged(android.telecom.Call telecomCall,
-                    List<android.telecom.Call> conferenceableCalls) {
-                Log.i(this, "onConferenceableCallsChanged: " + telecomCall);
-                onDetailsChanged(telecomCall, telecomCall.getDetails());
-            }
-        };
-    }
+        @Override
+        public void onConferenceableCallsChanged(android.telecom.Call telecomCall,
+                List<android.telecom.Call> conferenceableCalls) {
+            Log.i(this, "onConferenceableCallsChanged: " + telecomCall);
+            onDetailsChanged(telecomCall, telecomCall.getDetails());
+        }
+    };
 
     private PhoneStateListener mPhoneStateListener = new PhoneStateListener() {
         public void onCallStateChanged(int state, String incomingNumber) {
@@ -559,11 +507,7 @@
 
         // Since a call has been added we are no longer waiting for Telecom to send us a call.
         setBoundAndWaitingForOutgoingCall(false, null);
-        if (SdkVersionOverride.getSdkVersion(Build.VERSION_CODES.M) >= Build.VERSION_CODES.M) {
-            call.registerCallback((android.telecom.Call.Callback) mCallCallback);
-        } else {
-            call.addListener((android.telecom.Call.Listener) mCallCallback);
-        }
+        call.registerCallback(mCallCallback);
     }
 
     /**
@@ -632,11 +576,7 @@
 
     public void onCallRemoved(android.telecom.Call call) {
         mCallList.onCallRemoved(call);
-        if (SdkVersionOverride.getSdkVersion(Build.VERSION_CODES.M) >= Build.VERSION_CODES.M) {
-            call.unregisterCallback((android.telecom.Call.Callback) mCallCallback);
-        } else {
-            call.removeListener((android.telecom.Call.Listener) mCallCallback);
-        }
+        call.unregisterCallback(mCallCallback);
     }
 
     public void onCanAddCallChanged(boolean canAddCall) {
@@ -1470,7 +1410,7 @@
     private void setDisconnectCauseForMissingAccounts(Call call) {
         android.telecom.Call telecomCall = call.getTelecomCall();
 
-        Bundle extras = DetailsCompat.getIntentExtras(telecomCall.getDetails());
+        Bundle extras = telecomCall.getDetails().getIntentExtras();
         // Initialize the extras bundle to avoid NPE
         if (extras == null) {
             extras = new Bundle();
diff --git a/InCallUI/src/com/android/incallui/InCallServiceImpl.java b/InCallUI/src/com/android/incallui/InCallServiceImpl.java
index 31d6efb..8693697 100644
--- a/InCallUI/src/com/android/incallui/InCallServiceImpl.java
+++ b/InCallUI/src/com/android/incallui/InCallServiceImpl.java
@@ -18,15 +18,10 @@
 
 import android.content.Context;
 import android.content.Intent;
-import android.os.Build;
 import android.os.IBinder;
-import android.telecom.AudioState;
 import android.telecom.Call;
 import android.telecom.CallAudioState;
 import android.telecom.InCallService;
-import android.telecom.Phone;
-
-import com.android.contacts.common.compat.SdkVersionOverride;
 
 /**
  * Used to receive updates about calls from the Telecom component.  This service is bound to
@@ -100,85 +95,4 @@
         TelecomAdapter.getInstance().clearInCallService();
         InCallPresenter.getInstance().tearDown();
     }
-
-    /*
-     * Compatibility code for devices running the L sdk. In that version of the sdk, InCallService
-     * callbacks were registered via a android.telecom.Phone$Listener. These callbacks typically
-     * correspond 1:1 to callbacks now found in android.telecom.InCallService so the compatibility
-     * code forwards to those methods.
-     */
-    private Phone.Listener mPhoneListener = new Phone.Listener() {
-        @Override
-        public void onAudioStateChanged(Phone phone, AudioState audioState) {
-            /*
-             * Need to use reflection here; in M these are private fields retrieved through getters,
-             * but in L they are public fields without getters.
-             */
-            try {
-                boolean isMuted = AudioState.class.getField("isMuted").getBoolean(audioState);
-                int route = AudioState.class.getField("route").getInt(audioState);
-                int supportedRouteMask = AudioState.class.getField("supportedRouteMask")
-                        .getInt(audioState);
-                AudioModeProvider.getInstance()
-                        .onAudioStateChanged(isMuted, route, supportedRouteMask);
-            } catch (ReflectiveOperationException e) {
-                Log.e(this, "Unable to use reflection to retrieve AudioState fields", e);
-            }
-        }
-
-        @Override
-        public void onBringToForeground(Phone phone, boolean showDialpad) {
-            InCallServiceImpl.this.onBringToForeground(showDialpad);
-        }
-
-        @Override
-        public void onCallAdded(Phone phone, Call call) {
-            InCallServiceImpl.this.onCallAdded(call);
-        }
-
-        @Override
-        public void onCallRemoved(Phone phone, Call call) {
-            InCallServiceImpl.this.onCallRemoved(call);
-        }
-    };
-
-    private Phone mPhone;
-
-    @Override
-    public void onPhoneCreated(Phone phone) {
-        if (SdkVersionOverride.getSdkVersion(Build.VERSION_CODES.M) >= Build.VERSION_CODES.M) {
-            return;
-        }
-        mPhone = phone;
-        mPhone.addListener(mPhoneListener);
-    }
-
-    @Override
-    public void onPhoneDestroyed(Phone phone) {
-        if (SdkVersionOverride.getSdkVersion(Build.VERSION_CODES.M) >= Build.VERSION_CODES.M) {
-            return;
-        }
-        mPhone.removeListener(mPhoneListener);
-        mPhone = null;
-    }
-
-    /*
-     * setMuted and setAudioRoute are final in InCallService so compat methods are
-     * used to perform the needed branching logic based on sdk version
-     */
-    public void setMutedCompat(boolean state) {
-        if (SdkVersionOverride.getSdkVersion(Build.VERSION_CODES.M) >= Build.VERSION_CODES.M) {
-            super.setMuted(state);
-            return;
-        }
-        mPhone.setMuted(state);
-    }
-
-    public void setAudioRouteCompat(int route) {
-        if (SdkVersionOverride.getSdkVersion(Build.VERSION_CODES.M) >= Build.VERSION_CODES.M) {
-            super.setAudioRoute(route);
-            return;
-        }
-        mPhone.setAudioRoute(route);
-    }
 }
diff --git a/InCallUI/src/com/android/incallui/InCallUIMaterialColorMapUtils.java b/InCallUI/src/com/android/incallui/InCallUIMaterialColorMapUtils.java
index 44b035f..9c108b8 100644
--- a/InCallUI/src/com/android/incallui/InCallUIMaterialColorMapUtils.java
+++ b/InCallUI/src/com/android/incallui/InCallUIMaterialColorMapUtils.java
@@ -6,6 +6,7 @@
 
 import com.android.contacts.common.util.MaterialColorMapUtils;
 import com.android.contacts.common.util.MaterialColorMapUtils.MaterialPalette;
+import com.android.dialer.R;
 
 public class InCallUIMaterialColorMapUtils extends MaterialColorMapUtils {
     private final TypedArray sPrimaryColors;
@@ -14,10 +15,8 @@
 
     public InCallUIMaterialColorMapUtils(Resources resources) {
         super(resources);
-        sPrimaryColors = resources.obtainTypedArray(
-                com.android.incallui.R.array.background_colors);
-        sSecondaryColors = resources.obtainTypedArray(
-                com.android.incallui.R.array.background_colors_dark);
+        sPrimaryColors = resources.obtainTypedArray(R.array.background_colors);
+        sSecondaryColors = resources.obtainTypedArray(R.array.background_colors_dark);
         mResources = resources;
     }
 
@@ -53,4 +52,4 @@
         final int secondaryColor = resources.getColor(R.color.dialer_theme_color_dark);
         return new MaterialPalette(primaryColor, secondaryColor);
     }
-}
\ No newline at end of file
+}
diff --git a/InCallUI/src/com/android/incallui/PostCharDialogFragment.java b/InCallUI/src/com/android/incallui/PostCharDialogFragment.java
index 400e8d7..6f904ad 100644
--- a/InCallUI/src/com/android/incallui/PostCharDialogFragment.java
+++ b/InCallUI/src/com/android/incallui/PostCharDialogFragment.java
@@ -23,6 +23,8 @@
 import android.os.Bundle;
 import android.view.WindowManager;
 
+import com.android.dialer.R;
+
 /**
  * Pop up an alert dialog with OK and Cancel buttons to allow user to Accept or Reject the WAIT
  * inserted as part of the Dial string.
diff --git a/InCallUI/src/com/android/incallui/ProximitySensor.java b/InCallUI/src/com/android/incallui/ProximitySensor.java
index 733a67d..3c9fd93 100644
--- a/InCallUI/src/com/android/incallui/ProximitySensor.java
+++ b/InCallUI/src/com/android/incallui/ProximitySensor.java
@@ -23,9 +23,9 @@
 import android.hardware.display.DisplayManager;
 import android.hardware.display.DisplayManager.DisplayListener;
 import android.os.PowerManager;
+import android.telecom.CallAudioState;
 import android.view.Display;
 
-import com.android.dialer.compat.CallAudioStateCompat;
 import com.android.incallui.AudioModeProvider.AudioModeListener;
 import com.android.incallui.InCallPresenter.InCallState;
 import com.android.incallui.InCallPresenter.InCallStateListener;
@@ -228,9 +228,9 @@
         // turn proximity sensor off and turn screen on immediately if
         // we are using a headset, the keyboard is open, or the device
         // is being held in a horizontal position.
-            boolean screenOnImmediately = (CallAudioStateCompat.ROUTE_WIRED_HEADSET == audioMode
-                    || CallAudioStateCompat.ROUTE_SPEAKER == audioMode
-                    || CallAudioStateCompat.ROUTE_BLUETOOTH == audioMode
+            boolean screenOnImmediately = (CallAudioState.ROUTE_WIRED_HEADSET == audioMode
+                    || CallAudioState.ROUTE_SPEAKER == audioMode
+                    || CallAudioState.ROUTE_BLUETOOTH == audioMode
                     || mIsHardKeyboardOpen);
 
             // We do not keep the screen off when the user is outside in-call screen and we are
@@ -254,7 +254,7 @@
                     .add("offhook", mIsPhoneOffhook ? 1 : 0)
                     .add("hor", horizontal ? 1 : 0)
                     .add("ui", mUiShowing ? 1 : 0)
-                    .add("aud", CallAudioStateCompat.audioRouteToString(audioMode))
+                    .add("aud", CallAudioState.audioRouteToString(audioMode))
                     .toString());
 
             if (mIsPhoneOffhook && !screenOnImmediately) {
diff --git a/InCallUI/src/com/android/incallui/StatusBarNotifier.java b/InCallUI/src/com/android/incallui/StatusBarNotifier.java
index 6c00164..1a4ec09 100644
--- a/InCallUI/src/com/android/incallui/StatusBarNotifier.java
+++ b/InCallUI/src/com/android/incallui/StatusBarNotifier.java
@@ -50,6 +50,7 @@
 import com.android.contacts.common.testing.NeededForTesting;
 import com.android.contacts.common.util.BitmapUtil;
 import com.android.contacts.common.util.ContactDisplayUtils;
+import com.android.dialer.R;
 import com.android.incallui.Call.State;
 import com.android.incallui.ContactInfoCache.ContactCacheEntry;
 import com.android.incallui.ContactInfoCache.ContactInfoCacheCallback;
@@ -520,17 +521,16 @@
     }
 
     private static int getWorkStringFromPersonalString(int resId) {
-        switch(resId) {
-            case R.string.notification_ongoing_call:
-                return R.string.notification_ongoing_work_call;
-            case R.string.notification_ongoing_call_wifi:
-                return R.string.notification_ongoing_work_call_wifi;
-            case R.string.notification_incoming_call_wifi:
-                return R.string.notification_incoming_work_call_wifi;
-            case R.string.notification_incoming_call:
-                return R.string.notification_incoming_work_call;
-            default:
-                return resId;
+        if (resId == R.string.notification_ongoing_call) {
+            return R.string.notification_ongoing_work_call;
+        } else if (resId == R.string.notification_ongoing_call_wifi) {
+            return R.string.notification_ongoing_work_call_wifi;
+        } else if (resId == R.string.notification_incoming_call_wifi) {
+            return R.string.notification_incoming_work_call_wifi;
+        } else if (resId == R.string.notification_incoming_call) {
+            return R.string.notification_incoming_work_call;
+        } else {
+            return resId;
         }
     }
 
diff --git a/InCallUI/src/com/android/incallui/TelecomAdapter.java b/InCallUI/src/com/android/incallui/TelecomAdapter.java
index 0fc2e28..f172270 100644
--- a/InCallUI/src/com/android/incallui/TelecomAdapter.java
+++ b/InCallUI/src/com/android/incallui/TelecomAdapter.java
@@ -24,9 +24,6 @@
 import android.telecom.InCallService;
 import android.telecom.PhoneAccountHandle;
 
-import com.android.incallui.compat.telecom.DetailsCompat;
-import com.android.incallui.compat.telecom.InCallServiceCompat;
-
 import java.util.List;
 
 final class TelecomAdapter implements InCallServiceListener {
@@ -108,7 +105,7 @@
 
     void mute(boolean shouldMute) {
         if (mInCallService != null) {
-            InCallServiceCompat.setMuted(mInCallService, shouldMute);
+            mInCallService.setMuted(shouldMute);
         } else {
             Log.e(this, "error mute, mInCallService is null");
         }
@@ -116,7 +113,7 @@
 
     void setAudioRoute(int route) {
         if (mInCallService != null) {
-            InCallServiceCompat.setAudioRoute(mInCallService, route);
+            mInCallService.setAudioRoute(route);
         } else {
             Log.e(this, "error setAudioRoute, mInCallService is null");
         }
@@ -138,8 +135,7 @@
             if (!conferenceable.isEmpty()) {
                 call.conference(conferenceable.get(0));
             } else {
-                if (DetailsCompat.can(call.getDetails(),
-                        android.telecom.Call.Details.CAPABILITY_MERGE_CONFERENCE)) {
+                if (call.getDetails().can(android.telecom.Call.Details.CAPABILITY_MERGE_CONFERENCE)) {
                     call.mergeConference();
                 }
             }
@@ -151,8 +147,7 @@
     void swap(String callId) {
         android.telecom.Call call = getTelecomCallById(callId);
         if (call != null) {
-            if (DetailsCompat.can(call.getDetails(),
-                    android.telecom.Call.Details.CAPABILITY_SWAP_CONFERENCE)) {
+            if (call.getDetails().can(android.telecom.Call.Details.CAPABILITY_SWAP_CONFERENCE)) {
                 call.swapConference();
             }
         } else {
@@ -222,7 +217,10 @@
         }
     }
 
-    boolean canAddCall(Call call) {
-        return InCallServiceCompat.canAddCall(mInCallService, call);
+    boolean canAddCall() {
+        if (mInCallService != null) {
+            return mInCallService.canAddCall();
+        }
+        return false;
     }
 }
diff --git a/InCallUI/src/com/android/incallui/VideoCallFragment.java b/InCallUI/src/com/android/incallui/VideoCallFragment.java
index f80b04c..cb8c644 100644
--- a/InCallUI/src/com/android/incallui/VideoCallFragment.java
+++ b/InCallUI/src/com/android/incallui/VideoCallFragment.java
@@ -31,6 +31,7 @@
 import android.widget.FrameLayout;
 import android.widget.ImageView;
 
+import com.android.dialer.R;
 import com.android.phone.common.animation.AnimUtils;
 import com.google.common.base.Objects;
 
diff --git a/InCallUI/src/com/android/incallui/VideoCallPresenter.java b/InCallUI/src/com/android/incallui/VideoCallPresenter.java
index 2b6bc09..9a33d80 100644
--- a/InCallUI/src/com/android/incallui/VideoCallPresenter.java
+++ b/InCallUI/src/com/android/incallui/VideoCallPresenter.java
@@ -33,13 +33,13 @@
 
 import com.android.contacts.common.ContactPhotoManager;
 import com.android.contacts.common.compat.CompatUtils;
+import com.android.dialer.R;
 import com.android.incallui.InCallPresenter.InCallDetailsListener;
 import com.android.incallui.InCallPresenter.InCallOrientationListener;
 import com.android.incallui.InCallPresenter.InCallStateListener;
 import com.android.incallui.InCallPresenter.IncomingCallListener;
 import com.android.incallui.InCallVideoCallCallbackNotifier.SurfaceChangeListener;
 import com.android.incallui.InCallVideoCallCallbackNotifier.VideoEventListener;
-import com.android.incallui.compat.telecom.VideoProfileCompat;
 
 import java.util.Objects;
 
@@ -485,8 +485,8 @@
         Log.d(this, "checkForVideoStateChange: isVideoCall= " + isVideoCall
                 + " hasVideoStateChanged=" + hasVideoStateChanged + " isVideoMode="
                 + isVideoMode() + " previousVideoState: " +
-                VideoProfileCompat.videoStateToString(mCurrentVideoState) + " newVideoState: "
-                + VideoProfileCompat.videoStateToString(call.getVideoState()));
+                VideoProfile.videoStateToString(mCurrentVideoState) + " newVideoState: "
+                + VideoProfile.videoStateToString(call.getVideoState()));
 
         if (!hasVideoStateChanged) {
             return;
@@ -656,8 +656,8 @@
     }
 
     private static boolean isCameraRequired(int videoState) {
-        return VideoProfileCompat.isBidirectional(videoState) ||
-                VideoProfileCompat.isTransmissionEnabled(videoState);
+        return VideoProfile.isBidirectional(videoState) ||
+                VideoProfile.isTransmissionEnabled(videoState);
     }
 
     private boolean isCameraRequired() {
@@ -758,7 +758,7 @@
         if (showIncomingVideo || showOutgoingVideo) {
             ui.showVideoViews(showOutgoingVideo, showIncomingVideo);
 
-            if (VideoProfileCompat.isReceptionEnabled(videoState)) {
+            if (VideoProfile.isReceptionEnabled(videoState)) {
                 loadProfilePhotoAsync();
             }
         } else {
@@ -766,7 +766,7 @@
         }
 
         InCallPresenter.getInstance().enableScreenTimeout(
-                VideoProfileCompat.isAudioOnly(videoState));
+                VideoProfile.isAudioOnly(videoState));
     }
 
     /**
@@ -783,10 +783,10 @@
             return false;
         }
 
-        boolean isPaused = VideoProfileCompat.isPaused(videoState);
+        boolean isPaused = VideoProfile.isPaused(videoState);
         boolean isCallActive = callState == Call.State.ACTIVE;
 
-        return !isPaused && isCallActive && VideoProfileCompat.isReceptionEnabled(videoState);
+        return !isPaused && isCallActive && VideoProfile.isReceptionEnabled(videoState);
     }
 
     /**
@@ -802,7 +802,7 @@
             return false;
         }
 
-        return VideoProfileCompat.isTransmissionEnabled(videoState);
+        return VideoProfile.isTransmissionEnabled(videoState);
     }
 
     /**
@@ -1178,8 +1178,8 @@
     }
 
     private static int toCameraDirection(int videoState) {
-        return VideoProfileCompat.isTransmissionEnabled(videoState) &&
-                !VideoProfileCompat.isBidirectional(videoState)
+        return VideoProfile.isTransmissionEnabled(videoState) &&
+                !VideoProfile.isBidirectional(videoState)
                 ? Call.VideoSettings.CAMERA_DIRECTION_BACK_FACING
                 : Call.VideoSettings.CAMERA_DIRECTION_FRONT_FACING;
     }
diff --git a/InCallUI/src/com/android/incallui/VideoUtils.java b/InCallUI/src/com/android/incallui/VideoUtils.java
index 7e0926b..8641d60 100644
--- a/InCallUI/src/com/android/incallui/VideoUtils.java
+++ b/InCallUI/src/com/android/incallui/VideoUtils.java
@@ -19,7 +19,6 @@
 import android.telecom.VideoProfile;
 
 import com.android.contacts.common.compat.CompatUtils;
-import com.android.incallui.compat.telecom.VideoProfileCompat;
 
 import com.google.common.base.Preconditions;
 
@@ -34,8 +33,8 @@
             return false;
         }
 
-        return VideoProfileCompat.isTransmissionEnabled(videoState)
-                || VideoProfileCompat.isReceptionEnabled(videoState);
+        return VideoProfile.isTransmissionEnabled(videoState)
+                || VideoProfile.isReceptionEnabled(videoState);
     }
 
     public static boolean isBidirectionalVideoCall(Call call) {
@@ -43,7 +42,7 @@
             return false;
         }
 
-        return VideoProfileCompat.isBidirectional(call.getVideoState());
+        return VideoProfile.isBidirectional(call.getVideoState());
     }
 
     public static boolean isIncomingVideoCall(Call call) {
@@ -72,7 +71,7 @@
             return true;
         }
 
-        return call != null && VideoProfileCompat.isAudioOnly(call.getVideoState());
+        return call != null && VideoProfile.isAudioOnly(call.getVideoState());
     }
 
     // TODO (ims-vt) Check if special handling is needed for CONF calls.
@@ -82,7 +81,7 @@
 
     public static VideoProfile makeVideoPauseProfile(Call call) {
         Preconditions.checkNotNull(call);
-        Preconditions.checkState(!VideoProfileCompat.isAudioOnly(call.getVideoState()));
+        Preconditions.checkState(!VideoProfile.isAudioOnly(call.getVideoState()));
         return new VideoProfile(getPausedVideoState(call.getVideoState()));
     }
 
diff --git a/InCallUI/src/com/android/incallui/compat/telecom/DetailsCompat.java b/InCallUI/src/com/android/incallui/compat/telecom/DetailsCompat.java
deleted file mode 100644
index b9f82a9..0000000
--- a/InCallUI/src/com/android/incallui/compat/telecom/DetailsCompat.java
+++ /dev/null
@@ -1,108 +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.incallui.compat.telecom;
-
-import android.os.Build;
-import android.os.Bundle;
-import android.telecom.Call.Details;
-
-import com.android.contacts.common.compat.CompatUtils;
-import com.android.incallui.Log;
-
-/**
- * Compatibility class for {@link Details}
- */
-public class DetailsCompat {
-
-    /**
-     * Constant formerly in L as PhoneCapabilities#ADD_CALL. It was transferred to
-     * {@link Details#CAPABILITY_UNUSED_1} and hidden
-     */
-    public static final int CAPABILITY_UNUSED_1 = 0x00000010;
-
-    /**
-     * Returns the intent extras from the given {@link Details}
-     * For Sdk version L and earlier, this will return {@link Details#getExtras()}
-     *
-     * @param details The details whose intent extras should be returned
-     * @return The given details' intent extras
-     */
-    public static Bundle getIntentExtras(Details details) {
-        if (CompatUtils.isMarshmallowCompatible()) {
-            return details.getIntentExtras();
-        }
-        return details.getExtras();
-    }
-
-    /**
-     * Compatibility method to check whether the supplied properties includes the
-     * specified property.
-     *
-     * @param details The details whose properties should be checked.
-     * @param property The property to check properties for.
-     * @return Whether the specified property is supported.
-     */
-    public static boolean hasProperty(Details details, int property) {
-        if (CompatUtils.isMarshmallowCompatible()) {
-            return details.hasProperty(property);
-        }
-        return (details.getCallProperties() & property) != 0;
-    }
-
-    /**
-     * Compatibility method to check whether the capabilities of the given {@code Details}
-     * supports the specified capability.
-     *
-     * @param details The details whose capabilities should be checked.
-     * @param capability The capability to check capabilities for.
-     * @return Whether the specified capability is supported.
-     */
-    public static boolean can(Details details, int capability) {
-        if (CompatUtils.isLollipopMr1Compatible()) {
-            return details.can(capability);
-        }
-        return (details.getCallCapabilities() & capability) != 0;
-    }
-
-    /**
-     * Render a set of capability bits ({@code CAPABILITY_*}) as a human readable string.
-     *
-     * @param capabilities A capability bit field.
-     * @return A human readable string representation.
-     */
-    public static String capabilitiesToString(int capabilities) {
-        if (CompatUtils.isLollipopMr1Compatible()) {
-            return Details.capabilitiesToString(capabilities);
-        }
-        return capabilitiesToStringLollipop(capabilities);
-    }
-
-    /*
-     * Use reflection to call PhoneCapabilities.toString. InCallUI code is only run on Google
-     * Experience phones, so we will be the system Dialer and the method will exist
-     */
-    private static String capabilitiesToStringLollipop(int capabilities) {
-        try {
-            return (String) Class.forName("android.telecom.PhoneCapabilities")
-                    .getMethod("toString", Integer.TYPE)
-                    .invoke(null, capabilities);
-        } catch (ReflectiveOperationException e) {
-            Log.e(DetailsCompat.class, "Unable to use reflection to call "
-                    + "android.telecom.PhoneCapabilities.toString(int)", e);
-            return String.valueOf(capabilities);
-        }
-    }
-}
diff --git a/InCallUI/src/com/android/incallui/compat/telecom/InCallServiceCompat.java b/InCallUI/src/com/android/incallui/compat/telecom/InCallServiceCompat.java
deleted file mode 100644
index 0a3cb26..0000000
--- a/InCallUI/src/com/android/incallui/compat/telecom/InCallServiceCompat.java
+++ /dev/null
@@ -1,97 +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.incallui.compat.telecom;
-
-import android.support.annotation.Nullable;
-import android.telecom.InCallService;
-
-import com.android.contacts.common.compat.CompatUtils;
-import com.android.incallui.Call;
-import com.android.incallui.InCallServiceImpl;
-
-/**
- * Compatibility class for {@link android.telecom.InCallService}
- */
-public class InCallServiceCompat {
-
-    /**
-     * Sets the microphone mute state. When this request is honored, there
-     * will be a change to the {@link android.telecom.CallAudioState}.
-     *
-     * Note: Noop for Sdk versions less than M where inCallService is not of type
-     * {@link InCallServiceImpl}
-     *
-     * @param inCallService the {@link InCallService} to act on
-     * @param shouldMute {@code true} if the microphone should be muted; {@code false} otherwise.
-     */
-    public static void setMuted(@Nullable InCallService inCallService, boolean shouldMute) {
-        if (inCallService == null) {
-            return;
-        }
-        if (CompatUtils.isMarshmallowCompatible()) {
-            inCallService.setMuted(shouldMute);
-            return;
-        }
-
-        if (inCallService instanceof InCallServiceImpl) {
-            ((InCallServiceImpl) inCallService).setMutedCompat(shouldMute);
-        }
-    }
-
-    /**
-     * Sets the audio route (speaker, bluetooth, etc...).  When this request is honored, there will
-     * be change to the {@link android.telecom.CallAudioState}.
-     *
-     * Note: Noop for Sdk versions less than M where inCallService is not of type
-     * {@link InCallServiceImpl}
-     *
-     * @param inCallService the {@link InCallService} to act on
-     * @param route The audio route to use.
-     */
-    public static void setAudioRoute(@Nullable InCallService inCallService, int route) {
-        if (inCallService == null) {
-            return;
-        }
-        if (CompatUtils.isMarshmallowCompatible()) {
-            inCallService.setAudioRoute(route);
-            return;
-        }
-
-        if (inCallService instanceof InCallServiceImpl) {
-            ((InCallServiceImpl) inCallService).setAudioRouteCompat(route);
-        }
-    }
-
-    /**
-     * Returns if the device can support additional calls.
-     *
-     * @param inCallService the {@link InCallService} to act on
-     * @param call a {@link Call} to use if needed due to compatibility reasons
-     * @return Whether the phone supports adding more calls, defaulting to true if inCallService
-     *    is null
-     */
-    public static boolean canAddCall(@Nullable InCallService inCallService, Call call) {
-        if (inCallService == null) {
-            return true;
-        }
-
-        if (CompatUtils.isMarshmallowCompatible()) {
-            // Default to true if we are not connected to telecom.
-            return inCallService.canAddCall();
-        }
-        return call.can(DetailsCompat.CAPABILITY_UNUSED_1);
-    }
-}
diff --git a/InCallUI/src/com/android/incallui/compat/telecom/VideoProfileCompat.java b/InCallUI/src/com/android/incallui/compat/telecom/VideoProfileCompat.java
deleted file mode 100644
index 6e81bd7..0000000
--- a/InCallUI/src/com/android/incallui/compat/telecom/VideoProfileCompat.java
+++ /dev/null
@@ -1,140 +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.incallui.compat.telecom;
-
-import android.telecom.VideoProfile;
-
-import com.android.contacts.common.compat.CompatUtils;
-
-/**
- * Compatibility class for {@link android.telecom.VideoProfile}
- */
-public class VideoProfileCompat {
-
-    /**
-     * Generates a string representation of a video state.
-     *
-     * @param videoState The video state.
-     * @return String representation of the video state.
-     */
-    public static String videoStateToString(int videoState) {
-        if (CompatUtils.isMarshmallowCompatible()) {
-            return VideoProfile.videoStateToString(videoState);
-        }
-        return videoStateToStringLollipop(videoState);
-    }
-
-    /**
-     * Copied from {@link android.telecom.VideoProfile#videoStateToString}
-     */
-    private static String videoStateToStringLollipop(int videoState) {
-        StringBuilder sb = new StringBuilder();
-        sb.append("Audio");
-        if (isAudioOnly(videoState)) {
-            sb.append(" Only");
-        } else {
-            if (isTransmissionEnabled(videoState)) {
-                sb.append(" Tx");
-            }
-            if (isReceptionEnabled(videoState)) {
-                sb.append(" Rx");
-            }
-            if (isPaused(videoState)) {
-                sb.append(" Pause");
-            }
-        }
-        return sb.toString();
-    }
-
-    /**
-     * Indicates whether the video state is audio only.
-     *
-     * @param videoState The video state.
-     * @return {@code true} if the video state is audio only, {@code false} otherwise.
-     */
-    public static boolean isAudioOnly(int videoState) {
-        if (CompatUtils.isMarshmallowCompatible()) {
-            return VideoProfile.isAudioOnly(videoState);
-        }
-        return !hasState(videoState, VideoProfile.STATE_TX_ENABLED)
-                && !hasState(videoState, VideoProfile.STATE_RX_ENABLED);
-    }
-
-    /**
-     * Indicates whether the video state has video transmission enabled.
-     *
-     * @param videoState The video state.
-     * @return {@code true} if video transmission is enabled, {@code false} otherwise.
-     */
-    public static boolean isTransmissionEnabled(int videoState) {
-        if (CompatUtils.isMarshmallowCompatible()) {
-            return VideoProfile.isTransmissionEnabled(videoState);
-        }
-        return hasState(videoState, VideoProfile.STATE_TX_ENABLED);
-    }
-
-    /**
-     * Indicates whether the video state has video reception enabled.
-     *
-     * @param videoState The video state.
-     * @return {@code true} if video reception is enabled, {@code false} otherwise.
-     */
-    public static boolean isReceptionEnabled(int videoState) {
-        if (CompatUtils.isMarshmallowCompatible()) {
-            return VideoProfile.isReceptionEnabled(videoState);
-        }
-        return hasState(videoState, VideoProfile.STATE_RX_ENABLED);
-    }
-
-    /**
-     * Indicates whether the video state is paused.
-     *
-     * @param videoState The video state.
-     * @return {@code true} if the video is paused, {@code false} otherwise.
-     */
-    public static boolean isPaused(int videoState) {
-        if (CompatUtils.isMarshmallowCompatible()) {
-            return VideoProfile.isPaused(videoState);
-        }
-        return hasState(videoState, VideoProfile.STATE_PAUSED);
-    }
-
-    /**
-     * Copied from {@link android.telecom.VideoProfile}
-     *
-     * Determines if a specified state is set in a videoState bit-mask.
-     *
-     * @param videoState The video state bit-mask.
-     * @param state The state to check.
-     * @return {@code true} if the state is set.
-     */
-    private static boolean hasState(int videoState, int state) {
-        return (videoState & state) == state;
-    }
-
-    /**
-     * Indicates whether the video state is bi-directional.
-     *
-     * @param videoState The video state.
-     * @return {@code True} if the video is bi-directional, {@code false} otherwise.
-     */
-    public static boolean isBidirectional(int videoState) {
-        if (CompatUtils.isMarshmallowCompatible()) {
-            return VideoProfile.isBidirectional(videoState);
-        }
-        return hasState(videoState, VideoProfile.STATE_BIDIRECTIONAL);
-    }
-}
diff --git a/InCallUI/src/com/android/incallui/ringtone/InCallTonePlayer.java b/InCallUI/src/com/android/incallui/ringtone/InCallTonePlayer.java
index 6ef4e25..d930a92 100644
--- a/InCallUI/src/com/android/incallui/ringtone/InCallTonePlayer.java
+++ b/InCallUI/src/com/android/incallui/ringtone/InCallTonePlayer.java
@@ -23,9 +23,9 @@
 import android.media.ToneGenerator;
 import android.provider.MediaStore.Audio;
 import android.support.annotation.Nullable;
+import android.telecom.CallAudioState;
 
 import com.android.contacts.common.testing.NeededForTesting;
-import com.android.dialer.compat.CallAudioStateCompat;
 import com.android.incallui.AudioModeProvider;
 import com.android.incallui.Log;
 import com.android.incallui.async.PausableExecutor;
@@ -110,7 +110,7 @@
     }
 
     private int getPlaybackStream() {
-        if (mAudioModeProvider.getAudioMode() == CallAudioStateCompat.ROUTE_BLUETOOTH) {
+        if (mAudioModeProvider.getAudioMode() == CallAudioState.ROUTE_BLUETOOTH) {
             // TODO (maxwelb): b/26932998 play through bluetooth
             // return AudioManager.STREAM_BLUETOOTH_SCO;
         }
diff --git a/InCallUI/src/com/android/incallui/widget/multiwaveview/GlowPadView.java b/InCallUI/src/com/android/incallui/widget/multiwaveview/GlowPadView.java
index 2320027..efeb4b7 100644
--- a/InCallUI/src/com/android/incallui/widget/multiwaveview/GlowPadView.java
+++ b/InCallUI/src/com/android/incallui/widget/multiwaveview/GlowPadView.java
@@ -50,7 +50,7 @@
 import android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction;
 import android.view.accessibility.AccessibilityNodeProvider;
 
-import com.android.incallui.R;
+import com.android.dialer.R;
 
 import java.util.ArrayList;
 import java.util.List;
diff --git a/build-app.gradle b/build-app.gradle
new file mode 100644
index 0000000..9e24136
--- /dev/null
+++ b/build-app.gradle
@@ -0,0 +1,34 @@
+apply plugin: 'com.android.application'
+
+android {
+    defaultConfig {
+        minSdkVersion 23
+        targetSdkVersion 23
+        multiDexEnabled true
+    }
+
+    sourceSets.main {
+        java.srcDirs = ['src', 'src-pre-N', 'InCallUI/src']
+        manifest.srcFile 'AndroidManifest.xml'
+        res.srcDirs = ['res']
+    }
+}
+
+dependencies {
+    compile 'com.android.support:support-v4:23.1.+'
+    compile 'com.android.support:support-v13:23.1.+'
+    compile 'com.android.support:appcompat-v7:23.1.+'
+    compile 'com.android.support:cardview-v7:23.1.+'
+    compile 'com.android.support:design:23.1.+'
+    compile 'com.android.support:recyclerview-v7:23.1.+'
+
+    compile project(':android-common')
+    compile project(':guava')
+    compile project(':libphonenumber')
+    compile project(':jsr305')
+    compile project(':vcard')
+
+    compile project(':contactscommon')
+    compile project(':incallui')
+    compile project(':phonecommon')
+}
diff --git a/build-library.gradle b/build-library.gradle
new file mode 100644
index 0000000..d353016
--- /dev/null
+++ b/build-library.gradle
@@ -0,0 +1,34 @@
+apply plugin: 'com.android.library'
+
+android {
+    defaultConfig {
+        minSdkVersion 23
+        targetSdkVersion 23
+        multiDexEnabled true
+    }
+
+    sourceSets.main {
+        java.srcDirs = ['src', 'src-pre-N', 'InCallUI/src']
+        manifest.srcFile 'AndroidManifest.xml'
+        res.srcDirs = ['res']
+    }
+}
+
+dependencies {
+    compile 'com.android.support:support-v4:23.1.+'
+    compile 'com.android.support:support-v13:23.1.+'
+    compile 'com.android.support:appcompat-v7:23.1.+'
+    compile 'com.android.support:cardview-v7:23.1.+'
+    compile 'com.android.support:design:23.1.+'
+    compile 'com.android.support:recyclerview-v7:23.1.+'
+
+    compile project(':android-common')
+    compile project(':guava')
+    compile project(':libphonenumber')
+    compile project(':jsr305')
+    compile project(':vcard')
+
+    compile project(':contactscommon')
+    compile project(':incallui')
+    compile project(':phonecommon')
+}
diff --git a/res/layout-land/dialpad_fragment.xml b/res/layout-land/dialpad_fragment.xml
index 680c2d7..70a38ae 100644
--- a/res/layout-land/dialpad_fragment.xml
+++ b/res/layout-land/dialpad_fragment.xml
@@ -28,7 +28,7 @@
             android:id="@+id/spacer"
             android:layout_width="0dp"
             android:layout_height="match_parent"
-            android:layout_weight="1"
+            android:layout_weight="4"
             android:background="#00000000" />
 
         <!-- Dialpad shadow -->
@@ -40,7 +40,7 @@
         <RelativeLayout
             android:layout_height="match_parent"
             android:layout_width="0dp"
-            android:layout_weight="1">
+            android:layout_weight="6">
 
             <include layout="@layout/dialpad_view"
                  android:layout_height="match_parent"
@@ -60,7 +60,7 @@
             <!-- Margin bottom and alignParentBottom don't work well together, so use a Space instead. -->
             <Space android:id="@+id/dialpad_floating_action_button_margin_bottom"
                 android:layout_width="match_parent"
-                android:layout_height="8dp"
+                android:layout_height="@dimen/floating_action_button_margin_bottom"
                 android:layout_alignParentBottom="true" />
 
             <FrameLayout
diff --git a/src/com/android/dialer/CallDetailActivity.java b/src/com/android/dialer/CallDetailActivity.java
index 56e29a9..e6a29fb 100644
--- a/src/com/android/dialer/CallDetailActivity.java
+++ b/src/com/android/dialer/CallDetailActivity.java
@@ -349,51 +349,45 @@
 
     @Override
     public boolean onMenuItemClick(MenuItem item) {
-        switch (item.getItemId()) {
-            case R.id.call_detail_delete_menu_item:
-                if (hasVoicemail()) {
-                    CallLogAsyncTaskUtil.deleteVoicemail(
-                            this, mVoicemailUri, mCallLogAsyncTaskListener);
-                } else {
-                    final StringBuilder callIds = new StringBuilder();
-                    for (Uri callUri : getCallLogEntryUris()) {
-                        if (callIds.length() != 0) {
-                            callIds.append(",");
-                        }
-                        callIds.append(ContentUris.parseId(callUri));
+        if (item.getItemId() == R.id.call_detail_delete_menu_item) {
+            if (hasVoicemail()) {
+                CallLogAsyncTaskUtil.deleteVoicemail(
+                        this, mVoicemailUri, mCallLogAsyncTaskListener);
+            } else {
+                final StringBuilder callIds = new StringBuilder();
+                for (Uri callUri : getCallLogEntryUris()) {
+                    if (callIds.length() != 0) {
+                        callIds.append(",");
                     }
-                    CallLogAsyncTaskUtil.deleteCalls(
-                            this, callIds.toString(), mCallLogAsyncTaskListener);
+                    callIds.append(ContentUris.parseId(callUri));
                 }
-                break;
+                CallLogAsyncTaskUtil.deleteCalls(
+                        this, callIds.toString(), mCallLogAsyncTaskListener);
+            }
         }
         return true;
     }
 
     @Override
     public void onClick(View view) {
-        switch(view.getId()) {
-            case R.id.call_detail_action_block:
-                BlockNumberDialogFragment.show(
-                        mBlockedNumberId,
-                        mNumber,
-                        mDetails.countryIso,
-                        mDisplayNumber,
-                        R.id.call_detail,
-                        getFragmentManager(),
-                        this);
-                break;
-            case R.id.call_detail_action_copy:
-                ClipboardUtils.copyText(mContext, null, mNumber, true);
-                break;
-            case R.id.call_detail_action_edit_before_call:
-                Intent dialIntent = new Intent(Intent.ACTION_DIAL,
-                        CallUtil.getCallUri(getDialableNumber()));
-                DialerUtils.startActivityWithErrorToast(mContext, dialIntent);
-                break;
-            default:
-                Log.wtf(TAG, "Unexpected onClick event from " + view);
-                break;
+        int resId = view.getId();
+        if (resId == R.id.call_detail_action_block) {
+            BlockNumberDialogFragment.show(
+                    mBlockedNumberId,
+                    mNumber,
+                    mDetails.countryIso,
+                    mDisplayNumber,
+                    R.id.call_detail,
+                    getFragmentManager(),
+                    this);
+        } else if (resId == R.id.call_detail_action_copy) {
+            ClipboardUtils.copyText(mContext, null, mNumber, true);
+        } else if (resId == R.id.call_detail_action_edit_before_call) {
+            Intent dialIntent = new Intent(Intent.ACTION_DIAL,
+                    CallUtil.getCallUri(getDialableNumber()));
+            DialerUtils.startActivityWithErrorToast(mContext, dialIntent);
+        } else {
+            Log.wtf(TAG, "Unexpected onClick event from " + view);
         }
     }
 
diff --git a/src/com/android/dialer/DialtactsActivity.java b/src/com/android/dialer/DialtactsActivity.java
index 72753be..d507483 100644
--- a/src/com/android/dialer/DialtactsActivity.java
+++ b/src/com/android/dialer/DialtactsActivity.java
@@ -620,35 +620,30 @@
 
     @Override
     public void onClick(View view) {
-        switch (view.getId()) {
-            case R.id.floating_action_button:
-                if (mListsFragment.getCurrentTabIndex()
-                        == ListsFragment.TAB_INDEX_ALL_CONTACTS && !mInRegularSearch) {
-                    DialerUtils.startActivityWithErrorToast(
-                            this,
-                            IntentUtil.getNewContactIntent(),
-                            R.string.add_contact_not_available);
-                } else if (!mIsDialpadShown) {
-                    mInCallDialpadUp = false;
-                    showDialpadFragment(true);
-                }
-                break;
-            case R.id.voice_search_button:
-                try {
-                    startActivityForResult(new Intent(RecognizerIntent.ACTION_RECOGNIZE_SPEECH),
-                            ACTIVITY_REQUEST_CODE_VOICE_SEARCH);
-                } catch (ActivityNotFoundException e) {
-                    Toast.makeText(DialtactsActivity.this, R.string.voice_search_not_available,
-                            Toast.LENGTH_SHORT).show();
-                }
-                break;
-            case R.id.dialtacts_options_menu_button:
-                mOverflowMenu.show();
-                break;
-            default: {
-                Log.wtf(TAG, "Unexpected onClick event from " + view);
-                break;
+        int resId = view.getId();
+        if (resId == R.id.floating_action_button) {
+            if (mListsFragment.getCurrentTabIndex()
+                    == ListsFragment.TAB_INDEX_ALL_CONTACTS && !mInRegularSearch) {
+                DialerUtils.startActivityWithErrorToast(
+                        this,
+                        IntentUtil.getNewContactIntent(),
+                        R.string.add_contact_not_available);
+            } else if (!mIsDialpadShown) {
+                mInCallDialpadUp = false;
+                showDialpadFragment(true);
             }
+        } else if (resId == R.id.voice_search_button) {
+            try {
+                startActivityForResult(new Intent(RecognizerIntent.ACTION_RECOGNIZE_SPEECH),
+                        ACTIVITY_REQUEST_CODE_VOICE_SEARCH);
+            } catch (ActivityNotFoundException e) {
+                Toast.makeText(DialtactsActivity.this, R.string.voice_search_not_available,
+                        Toast.LENGTH_SHORT).show();
+            }
+        } else if (resId == R.id.dialtacts_options_menu_button) {
+            mOverflowMenu.show();
+        } else {
+            Log.wtf(TAG, "Unexpected onClick event from " + view);
         }
     }
 
@@ -658,41 +653,37 @@
             return true;
         }
 
-        switch (item.getItemId()) {
-            case R.id.menu_history:
-                // Use explicit CallLogActivity intent instead of ACTION_VIEW +
-                // CONTENT_TYPE, so that we always open our call log from our dialer
-                final Intent intent = new Intent(this, CallLogActivity.class);
-                startActivity(intent);
-                break;
-            case R.id.menu_add_contact:
-                DialerUtils.startActivityWithErrorToast(
-                        this,
-                        IntentUtil.getNewContactIntent(),
-                        R.string.add_contact_not_available);
-                break;
-            case R.id.menu_import_export:
-                // We hard-code the "contactsAreAvailable" argument because doing it properly would
-                // involve querying a {@link ProviderStatusLoader}, which we don't want to do right
-                // now in Dialtacts for (potential) performance reasons. Compare with how it is
-                // done in {@link PeopleActivity}.
-                if (mListsFragment.getCurrentTabIndex() == ListsFragment.TAB_INDEX_SPEED_DIAL) {
-                    ImportExportDialogFragment.show(getFragmentManager(), true,
-                            DialtactsActivity.class, ImportExportDialogFragment.EXPORT_MODE_FAVORITES);
-                } else {
-                    ImportExportDialogFragment.show(getFragmentManager(), true,
-                            DialtactsActivity.class, ImportExportDialogFragment.EXPORT_MODE_DEFAULT);
-                }
-                Logger.logScreenView(ScreenEvent.IMPORT_EXPORT_CONTACTS, this);
-                return true;
-            case R.id.menu_clear_frequents:
-                ClearFrequentsDialog.show(getFragmentManager());
-                Logger.logScreenView(ScreenEvent.CLEAR_FREQUENTS, this);
-                return true;
-            case R.id.menu_call_settings:
-                handleMenuSettings();
-                Logger.logScreenView(ScreenEvent.SETTINGS, this);
-                return true;
+        int resId = item.getItemId();
+        if (resId == R.id.menu_history) {// Use explicit CallLogActivity intent instead of ACTION_VIEW +
+            // CONTENT_TYPE, so that we always open our call log from our dialer
+            final Intent intent = new Intent(this, CallLogActivity.class);
+            startActivity(intent);
+        } else if (resId == R.id.menu_add_contact) {
+            DialerUtils.startActivityWithErrorToast(
+                    this,
+                    IntentUtil.getNewContactIntent(),
+                    R.string.add_contact_not_available);
+        } else if (resId == R.id.menu_import_export) {// We hard-code the "contactsAreAvailable" argument because doing it properly would
+            // involve querying a {@link ProviderStatusLoader}, which we don't want to do right
+            // now in Dialtacts for (potential) performance reasons. Compare with how it is
+            // done in {@link PeopleActivity}.
+            if (mListsFragment.getCurrentTabIndex() == ListsFragment.TAB_INDEX_SPEED_DIAL) {
+                ImportExportDialogFragment.show(getFragmentManager(), true,
+                        DialtactsActivity.class, ImportExportDialogFragment.EXPORT_MODE_FAVORITES);
+            } else {
+                ImportExportDialogFragment.show(getFragmentManager(), true,
+                        DialtactsActivity.class, ImportExportDialogFragment.EXPORT_MODE_DEFAULT);
+            }
+            Logger.logScreenView(ScreenEvent.IMPORT_EXPORT_CONTACTS, this);
+            return true;
+        } else if (resId == R.id.menu_clear_frequents) {
+            ClearFrequentsDialog.show(getFragmentManager());
+            Logger.logScreenView(ScreenEvent.CLEAR_FREQUENTS, this);
+            return true;
+        } else if (resId == R.id.menu_call_settings) {
+            handleMenuSettings();
+            Logger.logScreenView(ScreenEvent.SETTINGS, this);
+            return true;
         }
         return false;
     }
diff --git a/src/com/android/dialer/calllog/CallLogActivity.java b/src/com/android/dialer/calllog/CallLogActivity.java
index 243eda9..1823a5b 100644
--- a/src/com/android/dialer/calllog/CallLogActivity.java
+++ b/src/com/android/dialer/calllog/CallLogActivity.java
@@ -192,15 +192,14 @@
             return true;
         }
 
-        switch (item.getItemId()) {
-            case android.R.id.home:
-                final Intent intent = new Intent(this, DialtactsActivity.class);
-                intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
-                startActivity(intent);
-                return true;
-            case R.id.delete_all:
-                ClearCallLogDialog.show(getFragmentManager());
-                return true;
+        if (item.getItemId() == android.R.id.home) {
+            final Intent intent = new Intent(this, DialtactsActivity.class);
+            intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
+            startActivity(intent);
+            return true;
+        } else if (item.getItemId() == R.id.delete_all) {
+            ClearCallLogDialog.show(getFragmentManager());
+            return true;
         }
         return super.onOptionsItemSelected(item);
     }
diff --git a/src/com/android/dialer/calllog/CallLogListItemViewHolder.java b/src/com/android/dialer/calllog/CallLogListItemViewHolder.java
index cfc9375..1c27440 100644
--- a/src/com/android/dialer/calllog/CallLogListItemViewHolder.java
+++ b/src/com/android/dialer/calllog/CallLogListItemViewHolder.java
@@ -361,30 +361,30 @@
 
     @Override
     public boolean onMenuItemClick(MenuItem item) {
-        switch (item.getItemId()) {
-            case R.id.context_menu_block_number:
-                BlockNumberDialogFragment.show(
-                        blockId,
-                        number,
-                        countryIso,
-                        displayNumber,
-                        R.id.floating_action_button_container,
-                        ((Activity) mContext).getFragmentManager(),
-                        mFilteredNumberDialogCallback);
-                return true;
-            case R.id.context_menu_copy_to_clipboard:
-                ClipboardUtils.copyText(mContext, null, number, true);
-                return true;
-            case R.id.context_menu_copy_transcript_to_clipboard:
-                ClipboardUtils.copyText(mContext, null,
-                        phoneCallDetailsViews.voicemailTranscriptionView.getText(), true);
-                return true;
-            case R.id.context_menu_edit_before_call:
-                final Intent intent = new Intent(
-                        Intent.ACTION_DIAL, CallUtil.getCallUri(number));
-                intent.setClass(mContext, DialtactsActivity.class);
-                DialerUtils.startActivityWithErrorToast(mContext, intent);
-                return true;
+        int resId = item.getItemId();
+        if (resId == R.id.context_menu_block_number) {
+            BlockNumberDialogFragment.show(
+                    blockId,
+                    number,
+                    countryIso,
+                    displayNumber,
+                    R.id.floating_action_button_container,
+                    ((Activity) mContext).getFragmentManager(),
+                    mFilteredNumberDialogCallback);
+            return true;
+        } else if (resId == R.id.context_menu_copy_to_clipboard) {
+            ClipboardUtils.copyText(mContext, null, number, true);
+            return true;
+        } else if (resId == R.id.context_menu_copy_transcript_to_clipboard) {
+            ClipboardUtils.copyText(mContext, null,
+                    phoneCallDetailsViews.voicemailTranscriptionView.getText(), true);
+            return true;
+        } else if (resId == R.id.context_menu_edit_before_call) {
+            final Intent intent = new Intent(
+                    Intent.ACTION_DIAL, CallUtil.getCallUri(number));
+            intent.setClass(mContext, DialtactsActivity.class);
+            DialerUtils.startActivityWithErrorToast(mContext, intent);
+            return true;
         }
         return false;
     }
diff --git a/src/com/android/dialer/calllog/ContactInfoHelper.java b/src/com/android/dialer/calllog/ContactInfoHelper.java
index 75e7ab7..a9c7651 100644
--- a/src/com/android/dialer/calllog/ContactInfoHelper.java
+++ b/src/com/android/dialer/calllog/ContactInfoHelper.java
@@ -164,8 +164,7 @@
 
         Cursor phoneLookupCursor = null;
         try {
-            String[] projection = (isSip) ? PhoneQuery.SIP_PHONE_LOOKUP_PROJECTION
-                    : PhoneQuery.PHONE_LOOKUP_PROJECTION;
+            String[] projection = PhoneQuery.getPhoneLookupProjection(uri);
             phoneLookupCursor = mContext.getContentResolver().query(uri, projection, null, null,
                     null);
         } catch (NullPointerException e) {
diff --git a/src/com/android/dialer/calllog/PhoneQuery.java b/src/com/android/dialer/calllog/PhoneQuery.java
index 5261874..f1f14c6 100644
--- a/src/com/android/dialer/calllog/PhoneQuery.java
+++ b/src/com/android/dialer/calllog/PhoneQuery.java
@@ -16,10 +16,15 @@
 
 package com.android.dialer.calllog;
 
+import android.net.Uri;
+import android.provider.ContactsContract;
 import android.provider.ContactsContract.Contacts;
-import android.provider.ContactsContract.Data;
 import android.provider.ContactsContract.PhoneLookup;
 
+import com.android.contacts.common.compat.CompatUtils;
+import com.android.contacts.common.compat.PhoneLookupSdkCompat;
+import com.android.contacts.common.ContactsUtils;
+
 /**
  * The queries to look up the {@link ContactInfo} for a given number in the Call Log.
  */
@@ -27,10 +32,11 @@
 
     /**
      * Projection to look up the ContactInfo. Does not include DISPLAY_NAME_ALTERNATIVE as that
-     * column isn't available in ContactsCommon.PhoneLookup
+     * column isn't available in ContactsCommon.PhoneLookup.
+     * We should always use this projection starting from NYC onward.
      */
-    public static final String[] PHONE_LOOKUP_PROJECTION = new String[] {
-            PhoneLookup._ID,
+    private static final String[] PHONE_LOOKUP_PROJECTION = new String[] {
+            PhoneLookupSdkCompat.CONTACT_ID,
             PhoneLookup.DISPLAY_NAME,
             PhoneLookup.TYPE,
             PhoneLookup.LABEL,
@@ -42,21 +48,32 @@
     };
 
     /**
-     * Similar to {@link PHONE_LOOKUP_PROJECTION}. Due to a bug in framework, the column name of
-     * contact id in normal phonelookup query is _id, but that in sip phonelookup query is
-     * contact_id.
+     * Similar to {@link PHONE_LOOKUP_PROJECTION}. In pre-N, contact id is stored in
+     * {@link PhoneLookup#_ID} in non-sip query.
      */
-    public static final String[] SIP_PHONE_LOOKUP_PROJECTION = new String[] {
-            Data.CONTACT_ID,
-            PhoneLookup.DISPLAY_NAME,
-            PhoneLookup.TYPE,
-            PhoneLookup.LABEL,
-            PhoneLookup.NUMBER,
-            PhoneLookup.NORMALIZED_NUMBER,
-            PhoneLookup.PHOTO_ID,
-            PhoneLookup.LOOKUP_KEY,
-            PhoneLookup.PHOTO_URI
-    };
+    private static final String[] BACKWARD_COMPATIBLE_NON_SIP_PHONE_LOOKUP_PROJECTION =
+            new String[] {
+                    PhoneLookup._ID,
+                    PhoneLookup.DISPLAY_NAME,
+                    PhoneLookup.TYPE,
+                    PhoneLookup.LABEL,
+                    PhoneLookup.NUMBER,
+                    PhoneLookup.NORMALIZED_NUMBER,
+                    PhoneLookup.PHOTO_ID,
+                    PhoneLookup.LOOKUP_KEY,
+                    PhoneLookup.PHOTO_URI
+            };
+
+    public static String[] getPhoneLookupProjection(Uri phoneLookupUri) {
+        if (CompatUtils.isNCompatible()) {
+            return PHONE_LOOKUP_PROJECTION;
+        }
+        // Pre-N
+        boolean isSip = phoneLookupUri.getBooleanQueryParameter(
+                ContactsContract.PhoneLookup.QUERY_PARAMETER_SIP_ADDRESS, false);
+        return (isSip) ? PHONE_LOOKUP_PROJECTION
+                : BACKWARD_COMPATIBLE_NON_SIP_PHONE_LOOKUP_PROJECTION;
+    }
 
     public static final int PERSON_ID = 0;
     public static final int NAME = 1;
diff --git a/src/com/android/dialer/compat/CallAudioStateCompat.java b/src/com/android/dialer/compat/CallAudioStateCompat.java
deleted file mode 100644
index 51009d0..0000000
--- a/src/com/android/dialer/compat/CallAudioStateCompat.java
+++ /dev/null
@@ -1,331 +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.dialer.compat;
-
-import android.os.Build;
-import android.os.Parcel;
-import android.os.Parcelable;
-import android.telecom.CallAudioState;
-
-import com.android.contacts.common.compat.SdkVersionOverride;
-
-import java.util.Locale;
-
-/**
- * Compatibility class for {@link CallAudioState}
- */
-public class CallAudioStateCompat {
-
-    /**
-     * Direct the audio stream through the device's earpiece.
-     */
-    public static final int ROUTE_EARPIECE = CallAudioState.ROUTE_EARPIECE;
-
-    /**
-     * Direct the audio stream through Bluetooth.
-     */
-    public static final int ROUTE_BLUETOOTH = CallAudioState.ROUTE_BLUETOOTH;
-
-    /**
-     * Direct the audio stream through a wired headset.
-     */
-    public static final int ROUTE_WIRED_HEADSET = CallAudioState.ROUTE_WIRED_HEADSET;
-
-    /**
-     * Direct the audio stream through the device's speakerphone.
-     */
-    public static final int ROUTE_SPEAKER = CallAudioState.ROUTE_SPEAKER;
-
-    /**
-     * Direct the audio stream through the device's earpiece or wired headset if one is connected.
-     */
-    public static final int ROUTE_WIRED_OR_EARPIECE = CallAudioState.ROUTE_WIRED_OR_EARPIECE;
-
-    private final CallAudioStateImpl mCallAudioState;
-
-    /**
-     * Constructor for a {@link CallAudioStateCompat} object.
-     *
-     * @param muted {@code true} if the call is muted, {@code false} otherwise.
-     * @param route The current audio route being used. Allowed values: {@link #ROUTE_EARPIECE}
-     * {@link #ROUTE_BLUETOOTH} {@link #ROUTE_WIRED_HEADSET} {@link #ROUTE_SPEAKER}
-     * @param supportedRouteMask Bit mask of all routes supported by this call. This should be a
-     * bitwise combination of the following values: {@link #ROUTE_EARPIECE} {@link #ROUTE_BLUETOOTH}
-     * {@link #ROUTE_WIRED_HEADSET} {@link #ROUTE_SPEAKER}
-     */
-    public CallAudioStateCompat(boolean muted, int route, int supportedRouteMask) {
-        if (SdkVersionOverride.getSdkVersion(Build.VERSION_CODES.M)
-                < Build.VERSION_CODES.M) {
-            mCallAudioState = new CallAudioStateBase(muted, route, supportedRouteMask);
-        } else {
-            mCallAudioState = new CallAudioStateMarshmallow(muted, route, supportedRouteMask);
-        }
-    }
-
-    /**
-     * @return {@code true} if the call is muted, {@code false} otherwise.
-     */
-    public boolean isMuted() {
-        return mCallAudioState.isMuted();
-    }
-
-    /**
-     * @return The current audio route being used.
-     */
-    public int getRoute() {
-        return mCallAudioState.getRoute();
-    }
-
-    /**
-     * @return Bit mask of all routes supported by this call.
-     */
-    public int getSupportedRouteMask() {
-        return mCallAudioState.getSupportedRouteMask();
-    }
-
-    /**
-     * Converts the provided audio route into a human readable string representation.
-     *
-     * @param route to convert into a string.
-     * @return String representation of the provided audio route.
-     */
-    public static String audioRouteToString(int route) {
-        if (SdkVersionOverride.getSdkVersion(Build.VERSION_CODES.M)
-                < Build.VERSION_CODES.M) {
-            return CallAudioStateBase.audioRouteToString(route);
-        }
-        return CallAudioStateMarshmallow.audioRouteToString(route);
-    }
-
-
-    @Override
-    public boolean equals(Object o) {
-        if (this == o) {
-            return true;
-        }
-        if (o == null || getClass() != o.getClass()) {
-            return false;
-        }
-
-        CallAudioStateCompat that = (CallAudioStateCompat) o;
-
-        return mCallAudioState.equals(that.mCallAudioState);
-
-    }
-
-    @Override
-    public int hashCode() {
-        return mCallAudioState.hashCode();
-    }
-
-    @Override
-    public String toString() {
-        return mCallAudioState.toString();
-    }
-
-    private interface CallAudioStateImpl {
-        boolean isMuted();
-        int getRoute();
-        int getSupportedRouteMask();
-    }
-
-    /**
-     * CallAudioStateImpl to use if the Sdk version is lower than
-     * {@link android.os.Build.VERSION_CODES.M}
-     *
-     * Coped from {@link android.telecom.CallAudioState}
-     *
-     * Encapsulates the telecom audio state, including the current audio routing, supported audio
-     * routing and mute.
-     */
-    private static class CallAudioStateBase implements CallAudioStateImpl, Parcelable {
-
-        /**
-         * Bit mask of all possible audio routes.
-         */
-        private static final int ROUTE_ALL = ROUTE_EARPIECE | ROUTE_BLUETOOTH | ROUTE_WIRED_HEADSET
-                | ROUTE_SPEAKER;
-
-        private final boolean isMuted;
-        private final int route;
-        private final int supportedRouteMask;
-
-        /**
-         * Constructor for a {@link CallAudioStateBase} object.
-         *
-         * @param muted {@code true} if the call is muted, {@code false} otherwise.
-         * @param route The current audio route being used. Allowed values: {@link #ROUTE_EARPIECE}
-         *      {@link #ROUTE_BLUETOOTH}, {@link #ROUTE_WIRED_HEADSET}, {@link #ROUTE_SPEAKER}
-         * @param supportedRouteMask Bit mask of all routes supported by this call. This should be a
-         *      bitwise combination of the following values: {@link #ROUTE_EARPIECE},
-         *      {@link #ROUTE_BLUETOOTH}, {@link #ROUTE_WIRED_HEADSET}, {@link #ROUTE_SPEAKER}
-         */
-        public CallAudioStateBase(boolean muted, int route, int supportedRouteMask) {
-            this.isMuted = muted;
-            this.route = route;
-            this.supportedRouteMask = supportedRouteMask;
-        }
-
-        @Override
-        public boolean equals(Object obj) {
-            if (obj == null) {
-                return false;
-            }
-            if (!(obj instanceof CallAudioStateBase)) {
-                return false;
-            }
-            CallAudioStateBase state = (CallAudioStateBase) obj;
-            return isMuted() == state.isMuted() && getRoute() == state.getRoute() &&
-                    getSupportedRouteMask() == state.getSupportedRouteMask();
-        }
-
-        @Override
-        public String toString() {
-            return String.format(Locale.US,
-                    "[AudioState isMuted: %b, route: %s, supportedRouteMask: %s]",
-                    isMuted,
-                    audioRouteToString(route),
-                    audioRouteToString(supportedRouteMask));
-        }
-
-        /**
-         * @return {@code true} if the call is muted, {@code false} otherwise.
-         */
-        @Override
-        public boolean isMuted() {
-            return isMuted;
-        }
-
-        /**
-         * @return The current audio route being used.
-         */
-        public int getRoute() {
-            return route;
-        }
-
-        /**
-         * @return Bit mask of all routes supported by this call.
-         */
-        public int getSupportedRouteMask() {
-            return supportedRouteMask;
-        }
-
-        /**
-         * Converts the provided audio route into a human readable string representation.
-         *
-         * @param route to convert into a string.
-         * @return String representation of the provided audio route.
-         */
-        public static String audioRouteToString(int route) {
-            if (route == 0 || (route & ~ROUTE_ALL) != 0x0) {
-                return "UNKNOWN";
-            }
-
-            StringBuffer buffer = new StringBuffer();
-            if ((route & ROUTE_EARPIECE) == ROUTE_EARPIECE) {
-                listAppend(buffer, "EARPIECE");
-            }
-            if ((route & ROUTE_BLUETOOTH) == ROUTE_BLUETOOTH) {
-                listAppend(buffer, "BLUETOOTH");
-            }
-            if ((route & ROUTE_WIRED_HEADSET) == ROUTE_WIRED_HEADSET) {
-                listAppend(buffer, "WIRED_HEADSET");
-            }
-            if ((route & ROUTE_SPEAKER) == ROUTE_SPEAKER) {
-                listAppend(buffer, "SPEAKER");
-            }
-
-            return buffer.toString();
-        }
-
-        /**
-         * Responsible for creating AudioState objects for deserialized Parcels.
-         */
-        public static final Parcelable.Creator<CallAudioStateBase> CREATOR =
-                new Parcelable.Creator<CallAudioStateBase>() {
-
-                    @Override
-                    public CallAudioStateBase createFromParcel(Parcel source) {
-                        boolean isMuted = source.readByte() == 0 ? false : true;
-                        int route = source.readInt();
-                        int supportedRouteMask = source.readInt();
-                        return new CallAudioStateBase(isMuted, route, supportedRouteMask);
-                    }
-
-                    @Override
-                    public CallAudioStateBase[] newArray(int size) {
-                        return new CallAudioStateBase[size];
-                    }
-                };
-
-        /**
-         * {@inheritDoc}
-         */
-        @Override
-        public int describeContents() {
-            return 0;
-        }
-
-        /**
-         * Writes AudioState object into a serializeable Parcel.
-         */
-        @Override
-        public void writeToParcel(Parcel destination, int flags) {
-            destination.writeByte((byte) (isMuted ? 1 : 0));
-            destination.writeInt(route);
-            destination.writeInt(supportedRouteMask);
-        }
-
-        private static void listAppend(StringBuffer buffer, String str) {
-            if (buffer.length() > 0) {
-                buffer.append(", ");
-            }
-            buffer.append(str);
-        }
-    }
-
-    /**
-     * CallAudioStateImpl to use if the Sdk version is at least
-     * {@link android.os.Build.VERSION_CODES.M}
-     */
-    private static class CallAudioStateMarshmallow implements CallAudioStateImpl {
-
-        private final CallAudioState mCallAudioStateDelegate;
-
-        public CallAudioStateMarshmallow(boolean muted, int route, int supportedRouteMask) {
-            mCallAudioStateDelegate = new CallAudioState(muted, route, supportedRouteMask);
-        }
-
-        @Override
-        public boolean isMuted() {
-            return mCallAudioStateDelegate.isMuted();
-        }
-
-        @Override
-        public int getRoute() {
-            return mCallAudioStateDelegate.getRoute();
-        }
-
-        @Override
-        public int getSupportedRouteMask() {
-            return mCallAudioStateDelegate.getSupportedRouteMask();
-        }
-
-        public static String audioRouteToString(int route) {
-            return CallAudioState.audioRouteToString(route);
-        }
-    }
-}
diff --git a/src/com/android/dialer/dialpad/DialpadFragment.java b/src/com/android/dialer/dialpad/DialpadFragment.java
index 246b0d7..55d5346 100644
--- a/src/com/android/dialer/dialpad/DialpadFragment.java
+++ b/src/com/android/dialer/dialpad/DialpadFragment.java
@@ -822,13 +822,12 @@
 
     @Override
     public boolean onKey(View view, int keyCode, KeyEvent event) {
-        switch (view.getId()) {
-            case R.id.digits:
-                if (keyCode == KeyEvent.KEYCODE_ENTER) {
-                    handleDialButtonPressed();
-                    return true;
-                }
-                break;
+        if (view.getId() == R.id.digits) {
+            if (keyCode == KeyEvent.KEYCODE_ENTER) {
+                handleDialButtonPressed();
+                return true;
+            }
+
         }
         return false;
     }
@@ -843,59 +842,33 @@
     public void onPressed(View view, boolean pressed) {
         if (DEBUG) Log.d(TAG, "onPressed(). view: " + view + ", pressed: " + pressed);
         if (pressed) {
-            switch (view.getId()) {
-                case R.id.one: {
-                    keyPressed(KeyEvent.KEYCODE_1);
-                    break;
-                }
-                case R.id.two: {
-                    keyPressed(KeyEvent.KEYCODE_2);
-                    break;
-                }
-                case R.id.three: {
-                    keyPressed(KeyEvent.KEYCODE_3);
-                    break;
-                }
-                case R.id.four: {
-                    keyPressed(KeyEvent.KEYCODE_4);
-                    break;
-                }
-                case R.id.five: {
-                    keyPressed(KeyEvent.KEYCODE_5);
-                    break;
-                }
-                case R.id.six: {
-                    keyPressed(KeyEvent.KEYCODE_6);
-                    break;
-                }
-                case R.id.seven: {
-                    keyPressed(KeyEvent.KEYCODE_7);
-                    break;
-                }
-                case R.id.eight: {
-                    keyPressed(KeyEvent.KEYCODE_8);
-                    break;
-                }
-                case R.id.nine: {
-                    keyPressed(KeyEvent.KEYCODE_9);
-                    break;
-                }
-                case R.id.zero: {
-                    keyPressed(KeyEvent.KEYCODE_0);
-                    break;
-                }
-                case R.id.pound: {
-                    keyPressed(KeyEvent.KEYCODE_POUND);
-                    break;
-                }
-                case R.id.star: {
-                    keyPressed(KeyEvent.KEYCODE_STAR);
-                    break;
-                }
-                default: {
-                    Log.wtf(TAG, "Unexpected onTouch(ACTION_DOWN) event from: " + view);
-                    break;
-                }
+            int resId = view.getId();
+            if (resId == R.id.one) {
+                keyPressed(KeyEvent.KEYCODE_1);
+            } else if (resId == R.id.two) {
+                keyPressed(KeyEvent.KEYCODE_2);
+            } else if (resId == R.id.three) {
+                keyPressed(KeyEvent.KEYCODE_3);
+            } else if (resId == R.id.four) {
+                keyPressed(KeyEvent.KEYCODE_4);
+            } else if (resId == R.id.five) {
+                keyPressed(KeyEvent.KEYCODE_5);
+            } else if (resId == R.id.six) {
+                keyPressed(KeyEvent.KEYCODE_6);
+            } else if (resId == R.id.seven) {
+                keyPressed(KeyEvent.KEYCODE_7);
+            } else if (resId == R.id.eight) {
+                keyPressed(KeyEvent.KEYCODE_8);
+            } else if (resId == R.id.nine) {
+                keyPressed(KeyEvent.KEYCODE_9);
+            } else if (resId == R.id.zero) {
+                keyPressed(KeyEvent.KEYCODE_0);
+            } else if (resId == R.id.pound) {
+                keyPressed(KeyEvent.KEYCODE_POUND);
+            } else if (resId == R.id.star) {
+                keyPressed(KeyEvent.KEYCODE_STAR);
+            } else {
+                Log.wtf(TAG, "Unexpected onTouch(ACTION_DOWN) event from: " + view);
             }
             mPressedDialpadKeys.add(view);
         } else {
@@ -936,29 +909,21 @@
 
     @Override
     public void onClick(View view) {
-        switch (view.getId()) {
-            case R.id.dialpad_floating_action_button:
-                view.performHapticFeedback(HapticFeedbackConstants.VIRTUAL_KEY);
-                handleDialButtonPressed();
-                break;
-            case R.id.deleteButton: {
-                keyPressed(KeyEvent.KEYCODE_DEL);
-                break;
+        int resId = view.getId();
+        if (resId == R.id.dialpad_floating_action_button) {
+            view.performHapticFeedback(HapticFeedbackConstants.VIRTUAL_KEY);
+            handleDialButtonPressed();
+        } else if (resId == R.id.deleteButton) {
+            keyPressed(KeyEvent.KEYCODE_DEL);
+        } else if (resId == R.id.digits) {
+            if (!isDigitsEmpty()) {
+                mDigits.setCursorVisible(true);
             }
-            case R.id.digits: {
-                if (!isDigitsEmpty()) {
-                    mDigits.setCursorVisible(true);
-                }
-                break;
-            }
-            case R.id.dialpad_overflow: {
-                mOverflowPopupMenu.show();
-                break;
-            }
-            default: {
-                Log.wtf(TAG, "Unexpected onClick() event from: " + view);
-                return;
-            }
+        } else if (resId == R.id.dialpad_overflow) {
+            mOverflowPopupMenu.show();
+        } else {
+            Log.wtf(TAG, "Unexpected onClick() event from: " + view);
+            return;
         }
     }
 
@@ -966,75 +931,61 @@
     public boolean onLongClick(View view) {
         final Editable digits = mDigits.getText();
         final int id = view.getId();
-        switch (id) {
-            case R.id.deleteButton: {
-                digits.clear();
-                return true;
-            }
-            case R.id.one: {
-                // '1' may be already entered since we rely on onTouch() event for numeric buttons.
-                // Just for safety we also check if the digits field is empty or not.
-                if (isDigitsEmpty() || TextUtils.equals(mDigits.getText(), "1")) {
-                    // We'll try to initiate voicemail and thus we want to remove irrelevant string.
-                    removePreviousDigitIfPossible('1');
+        if (id == R.id.deleteButton) {
+            digits.clear();
+            return true;
+        } else if (id == R.id.one) {
+            if (isDigitsEmpty() || TextUtils.equals(mDigits.getText(), "1")) {
+                // We'll try to initiate voicemail and thus we want to remove irrelevant string.
+                removePreviousDigitIfPossible('1');
 
-                    List<PhoneAccountHandle> subscriptionAccountHandles =
-                            PhoneAccountUtils.getSubscriptionPhoneAccounts(getActivity());
-                    boolean hasUserSelectedDefault = subscriptionAccountHandles.contains(
-                            TelecomUtil.getDefaultOutgoingPhoneAccount(getActivity(),
-                                    PhoneAccount.SCHEME_VOICEMAIL));
-                    boolean needsAccountDisambiguation = subscriptionAccountHandles.size() > 1
-                            && !hasUserSelectedDefault;
+                List<PhoneAccountHandle> subscriptionAccountHandles =
+                        PhoneAccountUtils.getSubscriptionPhoneAccounts(getActivity());
+                boolean hasUserSelectedDefault = subscriptionAccountHandles.contains(
+                        TelecomUtil.getDefaultOutgoingPhoneAccount(getActivity(),
+                                PhoneAccount.SCHEME_VOICEMAIL));
+                boolean needsAccountDisambiguation = subscriptionAccountHandles.size() > 1
+                        && !hasUserSelectedDefault;
 
-                    if (needsAccountDisambiguation || isVoicemailAvailable()) {
-                        // On a multi-SIM phone, if the user has not selected a default
-                        // subscription, initiate a call to voicemail so they can select an account
-                        // from the "Call with" dialog.
-                        callVoicemail();
-                    } else if (getActivity() != null) {
-                        // Voicemail is unavailable maybe because Airplane mode is turned on.
-                        // Check the current status and show the most appropriate error message.
-                        final boolean isAirplaneModeOn =
-                                Settings.System.getInt(getActivity().getContentResolver(),
-                                Settings.System.AIRPLANE_MODE_ON, 0) != 0;
-                        if (isAirplaneModeOn) {
-                            DialogFragment dialogFragment = ErrorDialogFragment.newInstance(
-                                    R.string.dialog_voicemail_airplane_mode_message);
-                            dialogFragment.show(getFragmentManager(),
-                                    "voicemail_request_during_airplane_mode");
-                        } else {
-                            DialogFragment dialogFragment = ErrorDialogFragment.newInstance(
-                                    R.string.dialog_voicemail_not_ready_message);
-                            dialogFragment.show(getFragmentManager(), "voicemail_not_ready");
-                        }
+                if (needsAccountDisambiguation || isVoicemailAvailable()) {
+                    // On a multi-SIM phone, if the user has not selected a default
+                    // subscription, initiate a call to voicemail so they can select an account
+                    // from the "Call with" dialog.
+                    callVoicemail();
+                } else if (getActivity() != null) {
+                    // Voicemail is unavailable maybe because Airplane mode is turned on.
+                    // Check the current status and show the most appropriate error message.
+                    final boolean isAirplaneModeOn =
+                            Settings.System.getInt(getActivity().getContentResolver(),
+                                    Settings.System.AIRPLANE_MODE_ON, 0) != 0;
+                    if (isAirplaneModeOn) {
+                        DialogFragment dialogFragment = ErrorDialogFragment.newInstance(
+                                R.string.dialog_voicemail_airplane_mode_message);
+                        dialogFragment.show(getFragmentManager(),
+                                "voicemail_request_during_airplane_mode");
+                    } else {
+                        DialogFragment dialogFragment = ErrorDialogFragment.newInstance(
+                                R.string.dialog_voicemail_not_ready_message);
+                        dialogFragment.show(getFragmentManager(), "voicemail_not_ready");
                     }
-                    return true;
                 }
-                return false;
-            }
-            case R.id.zero: {
-                if (mPressedDialpadKeys.contains(view)) {
-                    // If the zero key is currently pressed, then the long press occurred by touch
-                    // (and not via other means like certain accessibility input methods).
-                    // Remove the '0' that was input when the key was first pressed.
-                    removePreviousDigitIfPossible('0');
-                }
-
-                keyPressed(KeyEvent.KEYCODE_PLUS);
-
-                // Stop tone immediately
-                stopTone();
-                mPressedDialpadKeys.remove(view);
-
                 return true;
             }
-            case R.id.digits: {
-                // Right now EditText does not show the "paste" option when cursor is not visible.
-                // To show that, make the cursor visible, and return false, letting the EditText
-                // show the option by itself.
-                mDigits.setCursorVisible(true);
-                return false;
+            return false;
+        } else if (id == R.id.zero) {
+            if (mPressedDialpadKeys.contains(view)) {
+                // If the zero key is currently pressed, then the long press occurred by touch
+                // (and not via other means like certain accessibility input methods).
+                // Remove the '0' that was input when the key was first pressed.
+                removePreviousDigitIfPossible('0');
             }
+            keyPressed(KeyEvent.KEYCODE_PLUS);
+            stopTone();
+            mPressedDialpadKeys.remove(view);
+            return true;
+        } else if (id == R.id.digits) {
+            mDigits.setCursorVisible(true);
+            return false;
         }
         return false;
     }
@@ -1438,31 +1389,20 @@
         DialpadChooserAdapter.ChoiceItem item =
                 (DialpadChooserAdapter.ChoiceItem) parent.getItemAtPosition(position);
         int itemId = item.id;
-        switch (itemId) {
-            case DialpadChooserAdapter.DIALPAD_CHOICE_USE_DTMF_DIALPAD:
-                // Log.i(TAG, "DIALPAD_CHOICE_USE_DTMF_DIALPAD");
-                // Fire off an intent to go back to the in-call UI
-                // with the dialpad visible.
-                returnToInCallScreen(true);
-                break;
-
-            case DialpadChooserAdapter.DIALPAD_CHOICE_RETURN_TO_CALL:
-                // Log.i(TAG, "DIALPAD_CHOICE_RETURN_TO_CALL");
-                // Fire off an intent to go back to the in-call UI
-                // (with the dialpad hidden).
-                returnToInCallScreen(false);
-                break;
-
-            case DialpadChooserAdapter.DIALPAD_CHOICE_ADD_NEW_CALL:
-                // Log.i(TAG, "DIALPAD_CHOICE_ADD_NEW_CALL");
-                // Ok, guess the user really did want to be here (in the
-                // regular Dialer) after all.  Bring back the normal Dialer UI.
-                showDialpadChooser(false);
-                break;
-
-            default:
-                Log.w(TAG, "onItemClick: unexpected itemId: " + itemId);
-                break;
+        if (itemId == DialpadChooserAdapter.DIALPAD_CHOICE_USE_DTMF_DIALPAD) {// Log.i(TAG, "DIALPAD_CHOICE_USE_DTMF_DIALPAD");
+            // Fire off an intent to go back to the in-call UI
+            // with the dialpad visible.
+            returnToInCallScreen(true);
+        } else if (itemId == DialpadChooserAdapter.DIALPAD_CHOICE_RETURN_TO_CALL) {// Log.i(TAG, "DIALPAD_CHOICE_RETURN_TO_CALL");
+            // Fire off an intent to go back to the in-call UI
+            // (with the dialpad hidden).
+            returnToInCallScreen(false);
+        } else if (itemId == DialpadChooserAdapter.DIALPAD_CHOICE_ADD_NEW_CALL) {// Log.i(TAG, "DIALPAD_CHOICE_ADD_NEW_CALL");
+            // Ok, guess the user really did want to be here (in the
+            // regular Dialer) after all.  Bring back the normal Dialer UI.
+            showDialpadChooser(false);
+        } else {
+            Log.w(TAG, "onItemClick: unexpected itemId: " + itemId);
         }
     }
 
@@ -1506,19 +1446,19 @@
 
     @Override
     public boolean onMenuItemClick(MenuItem item) {
-        switch (item.getItemId()) {
-            case R.id.menu_2s_pause:
-                updateDialString(PAUSE);
-                return true;
-            case R.id.menu_add_wait:
-                updateDialString(WAIT);
-                return true;
-            case R.id.menu_call_with_note:
-                CallSubjectDialog.start(getActivity(), mDigits.getText().toString());
-                hideAndClearDialpad(false);
-                return true;
-            default:
-                return false;
+        int resId = item.getItemId();
+        if (resId == R.id.menu_2s_pause) {
+            updateDialString(PAUSE);
+            return true;
+        } else if (resId == R.id.menu_add_wait) {
+            updateDialString(WAIT);
+            return true;
+        } else if (resId == R.id.menu_call_with_note) {
+            CallSubjectDialog.start(getActivity(), mDigits.getText().toString());
+            hideAndClearDialpad(false);
+            return true;
+        } else {
+            return false;
         }
     }
 
diff --git a/src/com/android/dialer/filterednumber/BlockedNumbersFragment.java b/src/com/android/dialer/filterednumber/BlockedNumbersFragment.java
index e231c6a..a878660 100644
--- a/src/com/android/dialer/filterednumber/BlockedNumbersFragment.java
+++ b/src/com/android/dialer/filterednumber/BlockedNumbersFragment.java
@@ -180,22 +180,19 @@
             return;
         }
 
-        switch (view.getId()) {
-            case R.id.add_number_linear_layout:
-                activity.showSearchUi();
-                break;
-            case R.id.view_numbers_button:
-                activity.showNumbersToImportPreviewUi();
-                break;
-            case R.id.import_button:
-                FilteredNumbersUtil.importSendToVoicemailContacts(activity,
-                        new ImportSendToVoicemailContactsListener() {
-                            @Override
-                            public void onImportComplete() {
-                                mImportSettings.setVisibility(View.GONE);
-                            }
-                        });
-                break;
+        int resId = view.getId();
+        if (resId == R.id.add_number_linear_layout) {
+            activity.showSearchUi();
+        } else if (resId == R.id.view_numbers_button) {
+            activity.showNumbersToImportPreviewUi();
+        } else if (resId == R.id.import_button) {
+            FilteredNumbersUtil.importSendToVoicemailContacts(activity,
+                    new ImportSendToVoicemailContactsListener() {
+                        @Override
+                        public void onImportComplete() {
+                            mImportSettings.setVisibility(View.GONE);
+                        }
+                    });
         }
     }
     @Override
diff --git a/src/com/android/dialer/filterednumber/ViewNumbersToImportFragment.java b/src/com/android/dialer/filterednumber/ViewNumbersToImportFragment.java
index 153d73c..8b24c06 100644
--- a/src/com/android/dialer/filterednumber/ViewNumbersToImportFragment.java
+++ b/src/com/android/dialer/filterednumber/ViewNumbersToImportFragment.java
@@ -116,21 +116,18 @@
 
     @Override
     public void onClick(final View view) {
-        switch (view.getId()) {
-            case R.id.import_button:
-                FilteredNumbersUtil.importSendToVoicemailContacts(getContext(),
-                        new ImportSendToVoicemailContactsListener() {
-                            @Override
-                            public void onImportComplete() {
-                                if (getActivity() != null) {
-                                    getActivity().onBackPressed();
-                                }
+        if (view.getId() == R.id.import_button) {
+            FilteredNumbersUtil.importSendToVoicemailContacts(getContext(),
+                    new ImportSendToVoicemailContactsListener() {
+                        @Override
+                        public void onImportComplete() {
+                            if (getActivity() != null) {
+                                getActivity().onBackPressed();
                             }
-                        });
-                break;
-            case R.id.cancel_button:
-                getActivity().onBackPressed();
-                break;
+                        }
+                    });
+        } else if (view.getId() == R.id.cancel_button) {
+            getActivity().onBackPressed();
         }
     }
 }
diff --git a/src/com/android/dialer/util/PhoneLookupUtil.java b/src/com/android/dialer/util/PhoneLookupUtil.java
new file mode 100644
index 0000000..1a72396
--- /dev/null
+++ b/src/com/android/dialer/util/PhoneLookupUtil.java
@@ -0,0 +1,40 @@
+/*
+ * 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.dialer.util;
+
+import android.net.Uri;
+import android.provider.ContactsContract;
+
+import com.android.contacts.common.compat.CompatUtils;
+import com.android.contacts.common.compat.PhoneLookupSdkCompat;
+
+public final class PhoneLookupUtil {
+    /**
+     * @return the column name that stores contact id for phone lookup query.
+     */
+    public static String getContactIdColumnNameForUri(Uri phoneLookupUri) {
+        if (CompatUtils.isNCompatible()) {
+            return PhoneLookupSdkCompat.CONTACT_ID;
+        }
+        // In pre-N, contact id is stored in {@link PhoneLookup#_ID} in non-sip query.
+        boolean isSip = phoneLookupUri.getBooleanQueryParameter(
+                ContactsContract.PhoneLookup.QUERY_PARAMETER_SIP_ADDRESS, false);
+        return (isSip) ? PhoneLookupSdkCompat.CONTACT_ID : ContactsContract.PhoneLookup._ID;
+    }
+
+    private PhoneLookupUtil() {}
+}
diff --git a/src/com/android/dialer/voicemail/VoicemailAudioManager.java b/src/com/android/dialer/voicemail/VoicemailAudioManager.java
index 712b20b..fe6cf5f 100644
--- a/src/com/android/dialer/voicemail/VoicemailAudioManager.java
+++ b/src/com/android/dialer/voicemail/VoicemailAudioManager.java
@@ -19,10 +19,9 @@
 import android.content.Context;
 import android.media.AudioManager;
 import android.media.AudioManager.OnAudioFocusChangeListener;
+import android.telecom.CallAudioState;
 import android.util.Log;
 
-import com.android.dialer.compat.CallAudioStateCompat;
-
 import java.util.concurrent.RejectedExecutionException;
 
 /**
@@ -38,7 +37,7 @@
     private VoicemailPlaybackPresenter mVoicemailPlaybackPresenter;
     private WiredHeadsetManager mWiredHeadsetManager;
     private boolean mWasSpeakerOn;
-    private CallAudioStateCompat mCallAudioState;
+    private CallAudioState mCallAudioState;
 
     public VoicemailAudioManager(Context context,
             VoicemailPlaybackPresenter voicemailPlaybackPresenter) {
@@ -82,26 +81,25 @@
 
         int newRoute = mCallAudioState.getRoute();  // start out with existing route
         if (newIsPluggedIn) {
-            newRoute = CallAudioStateCompat.ROUTE_WIRED_HEADSET;
+            newRoute = CallAudioState.ROUTE_WIRED_HEADSET;
         } else {
             if (mWasSpeakerOn) {
-                newRoute = CallAudioStateCompat.ROUTE_SPEAKER;
+                newRoute = CallAudioState.ROUTE_SPEAKER;
             } else {
-                newRoute = CallAudioStateCompat.ROUTE_EARPIECE;
+                newRoute = CallAudioState.ROUTE_EARPIECE;
             }
         }
 
-        mVoicemailPlaybackPresenter.setSpeakerphoneOn(newRoute == CallAudioStateCompat.ROUTE_SPEAKER);
+        mVoicemailPlaybackPresenter.setSpeakerphoneOn(newRoute == CallAudioState.ROUTE_SPEAKER);
 
         // We need to call this every time even if we do not change the route because the supported
         // routes changed either to include or not include WIRED_HEADSET.
         setSystemAudioState(
-                new CallAudioStateCompat(false /* muted */, newRoute, calculateSupportedRoutes()));
+                new CallAudioState(false /* muted */, newRoute, calculateSupportedRoutes()));
     }
 
     public void setSpeakerphoneOn(boolean on) {
-        setAudioRoute(on ? CallAudioStateCompat.ROUTE_SPEAKER
-                : CallAudioStateCompat.ROUTE_WIRED_OR_EARPIECE);
+        setAudioRoute(on ? CallAudioState.ROUTE_SPEAKER : CallAudioState.ROUTE_WIRED_OR_EARPIECE);
     }
 
     public boolean isWiredHeadsetPluggedIn() {
@@ -120,10 +118,10 @@
     /**
      * Change the audio route, for example from earpiece to speakerphone.
      *
-     * @param route The new audio route to use. See {@link CallAudioStateCompat}.
+     * @param route The new audio route to use. See {@link CallAudioState}.
      */
     void setAudioRoute(int route) {
-        Log.v(TAG, "setAudioRoute, route: " + CallAudioStateCompat.audioRouteToString(route));
+        Log.v(TAG, "setAudioRoute, route: " + CallAudioState.audioRouteToString(route));
 
         // Change ROUTE_WIRED_OR_EARPIECE to a single entry.
         int newRoute = selectWiredOrEarpiece(route, mCallAudioState.getSupportedRouteMask());
@@ -137,25 +135,25 @@
         if (mCallAudioState.getRoute() != newRoute) {
             // Remember the new speaker state so it can be restored when the user plugs and unplugs
             // a headset.
-            mWasSpeakerOn = newRoute == CallAudioStateCompat.ROUTE_SPEAKER;
-            setSystemAudioState(new CallAudioStateCompat(false /* muted */, newRoute,
+            mWasSpeakerOn = newRoute == CallAudioState.ROUTE_SPEAKER;
+            setSystemAudioState(new CallAudioState(false /* muted */, newRoute,
                     mCallAudioState.getSupportedRouteMask()));
         }
     }
 
-    private CallAudioStateCompat getInitialAudioState() {
+    private CallAudioState getInitialAudioState() {
         int supportedRouteMask = calculateSupportedRoutes();
-        int route = selectWiredOrEarpiece(CallAudioStateCompat.ROUTE_WIRED_OR_EARPIECE,
+        int route = selectWiredOrEarpiece(CallAudioState.ROUTE_WIRED_OR_EARPIECE,
                 supportedRouteMask);
-        return new CallAudioStateCompat(false /* muted */, route, supportedRouteMask);
+        return new CallAudioState(false /* muted */, route, supportedRouteMask);
     }
 
     private int calculateSupportedRoutes() {
-        int routeMask = CallAudioStateCompat.ROUTE_SPEAKER;
+        int routeMask = CallAudioState.ROUTE_SPEAKER;
         if (mWiredHeadsetManager.isPluggedIn()) {
-            routeMask |= CallAudioStateCompat.ROUTE_WIRED_HEADSET;
+            routeMask |= CallAudioState.ROUTE_WIRED_HEADSET;
         } else {
-            routeMask |= CallAudioStateCompat.ROUTE_EARPIECE;
+            routeMask |= CallAudioState.ROUTE_EARPIECE;
         }
         return routeMask;
     }
@@ -164,29 +162,29 @@
         // Since they are mutually exclusive and one is ALWAYS valid, we allow a special input of
         // ROUTE_WIRED_OR_EARPIECE so that callers don't have to make a call to check which is
         // supported before calling setAudioRoute.
-        if (route == CallAudioStateCompat.ROUTE_WIRED_OR_EARPIECE) {
-            route = CallAudioStateCompat.ROUTE_WIRED_OR_EARPIECE & supportedRouteMask;
+        if (route == CallAudioState.ROUTE_WIRED_OR_EARPIECE) {
+            route = CallAudioState.ROUTE_WIRED_OR_EARPIECE & supportedRouteMask;
             if (route == 0) {
                 Log.wtf(TAG, "One of wired headset or earpiece should always be valid.");
                 // assume earpiece in this case.
-                route = CallAudioStateCompat.ROUTE_EARPIECE;
+                route = CallAudioState.ROUTE_EARPIECE;
             }
         }
         return route;
     }
 
-    private void setSystemAudioState(CallAudioStateCompat callAudioState) {
-        CallAudioStateCompat oldAudioState = mCallAudioState;
+    private void setSystemAudioState(CallAudioState callAudioState) {
+        CallAudioState oldAudioState = mCallAudioState;
         mCallAudioState = callAudioState;
 
         Log.i(TAG, "setSystemAudioState: changing from " + oldAudioState + " to "
                 + mCallAudioState);
 
         // Audio route.
-        if (mCallAudioState.getRoute() == CallAudioStateCompat.ROUTE_SPEAKER) {
+        if (mCallAudioState.getRoute() == CallAudioState.ROUTE_SPEAKER) {
             turnOnSpeaker(true);
-        } else if (mCallAudioState.getRoute() == CallAudioStateCompat.ROUTE_EARPIECE ||
-                mCallAudioState.getRoute() == CallAudioStateCompat.ROUTE_WIRED_HEADSET) {
+        } else if (mCallAudioState.getRoute() == CallAudioState.ROUTE_EARPIECE ||
+                mCallAudioState.getRoute() == CallAudioState.ROUTE_WIRED_HEADSET) {
             // Just handle turning off the speaker, the system will handle switching between wired
             // headset and earpiece.
             turnOnSpeaker(false);
@@ -199,4 +197,4 @@
             mAudioManager.setSpeakerphoneOn(on);
         }
     }
-}
\ No newline at end of file
+}
diff --git a/tests/src/com/android/dialer/calllog/ContactInfoHelperTest.java b/tests/src/com/android/dialer/calllog/ContactInfoHelperTest.java
index 0e032c1..680afb1 100644
--- a/tests/src/com/android/dialer/calllog/ContactInfoHelperTest.java
+++ b/tests/src/com/android/dialer/calllog/ContactInfoHelperTest.java
@@ -63,7 +63,7 @@
 
     public void testLookupContactFromUri_NoResults() {
         setUpQueryExpectations(PhoneLookup.ENTERPRISE_CONTENT_FILTER_URI,
-                PhoneQuery.PHONE_LOOKUP_PROJECTION);
+                PhoneQuery.getPhoneLookupProjection(PhoneLookup.ENTERPRISE_CONTENT_FILTER_URI));
 
         Assert.assertEquals(ContactInfo.EMPTY, mContactInfoHelper.lookupContactFromUri(
                 PhoneLookup.ENTERPRISE_CONTENT_FILTER_URI, false));
@@ -72,7 +72,8 @@
 
     public void testLookupContactFromUri_NoDisplayNameAlternative() {
         setUpQueryExpectations(PhoneLookup.ENTERPRISE_CONTENT_FILTER_URI,
-                PhoneQuery.PHONE_LOOKUP_PROJECTION, TEST_LOOKUP_ROW);
+                PhoneQuery.getPhoneLookupProjection(PhoneLookup.ENTERPRISE_CONTENT_FILTER_URI),
+                TEST_LOOKUP_ROW);
         setUpQueryExpectations(displayNameAlternativeUri,
                 PhoneQuery.DISPLAY_NAME_ALTERNATIVE_PROJECTION);
 
@@ -85,7 +86,8 @@
 
     public void testLookupContactFromUri_HasDisplayNameAlternative() {
         setUpQueryExpectations(PhoneLookup.ENTERPRISE_CONTENT_FILTER_URI,
-                PhoneQuery.PHONE_LOOKUP_PROJECTION, TEST_LOOKUP_ROW);
+                PhoneQuery.getPhoneLookupProjection(PhoneLookup.ENTERPRISE_CONTENT_FILTER_URI),
+                TEST_LOOKUP_ROW);
         setUpQueryExpectations(displayNameAlternativeUri,
                 PhoneQuery.DISPLAY_NAME_ALTERNATIVE_PROJECTION, TEST_DISPLAY_NAME_ALTERNATIVE_ROW);
 
diff --git a/tools/gradle/android.properties b/tools/gradle/android.properties
new file mode 100644
index 0000000..fd1f721
--- /dev/null
+++ b/tools/gradle/android.properties
@@ -0,0 +1,2 @@
+compileSdkVersion 24
+buildToolsVersion = '24.0.0'
diff --git a/tools/gradle/gradlew b/tools/gradle/gradlew
new file mode 100755
index 0000000..7f33f9d
--- /dev/null
+++ b/tools/gradle/gradlew
@@ -0,0 +1,204 @@
+#!/usr/bin/env bash
+
+##############################################################################
+##
+##  Gradle start up script for UN*X
+##
+##############################################################################
+
+# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
+DEFAULT_JVM_OPTS=""
+
+APP_NAME="Gradle"
+APP_BASE_NAME=`basename "$0"`
+
+# Use the maximum available, or set MAX_FD != -1 to use that value.
+MAX_FD="maximum"
+
+warn ( ) {
+    echo "$*"
+}
+
+die ( ) {
+    echo
+    echo "$*"
+    echo
+    exit 1
+}
+
+# OS specific support (must be 'true' or 'false').
+cygwin=false
+msys=false
+darwin=false
+case "`uname`" in
+  CYGWIN* )
+    cygwin=true
+    ;;
+  Darwin* )
+    darwin=true
+    ;;
+  MINGW* )
+    msys=true
+    ;;
+esac
+
+# For Cygwin, ensure paths are in UNIX format before anything is touched.
+if $cygwin ; then
+    [ -n "$JAVA_HOME" ] && JAVA_HOME=`cygpath --unix "$JAVA_HOME"`
+fi
+
+# Attempt to set APP_HOME
+# Resolve links: $0 may be a link
+PRG="$0"
+# Need this for relative symlinks.
+# TODO(jpd): b/15773596 - This is broken because we symlinked
+# gradlew and the build server can't clean it up. Don't resolve
+# links.
+#while [ -h "$PRG" ] ; do
+#    ls=`ls -ld "$PRG"`
+#    link=`expr "$ls" : '.*-> \(.*\)$'`
+#    if expr "$link" : '/.*' > /dev/null; then
+#        PRG="$link"
+#    else
+#        PRG=`dirname "$PRG"`"/$link"
+#    fi
+#done
+SAVED="`pwd`"
+cd "`dirname \"$PRG\"`/" >&-
+APP_HOME="`pwd -P`"
+cd "$SAVED" >&-
+
+if [ $(basename `pwd`) == "gradle" ]; then
+    echo "This cannot be run here. It should be copied to the root of the platform."
+    exit
+else
+    CLASSPATH=./gradle/wrapper/gradle-wrapper.jar
+fi
+
+# Determine the Java command to use to start the JVM.
+if [ -n "$JAVA_HOME" ] ; then
+    if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
+        # IBM's JDK on AIX uses strange locations for the executables
+        JAVACMD="$JAVA_HOME/jre/sh/java"
+    else
+        JAVACMD="$JAVA_HOME/bin/java"
+    fi
+    if [ ! -x "$JAVACMD" ] ; then
+        die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
+
+Please set the JAVA_HOME variable in your environment to match the
+location of your Java installation."
+    fi
+else
+    JAVACMD="java"
+    which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
+
+Please set the JAVA_HOME variable in your environment to match the
+location of your Java installation."
+fi
+
+# Increase the maximum file descriptors if we can.
+if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then
+    MAX_FD_LIMIT=`ulimit -H -n`
+    if [ $? -eq 0 ] ; then
+        if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
+            MAX_FD="$MAX_FD_LIMIT"
+        fi
+        ulimit -n $MAX_FD
+        if [ $? -ne 0 ] ; then
+            warn "Could not set maximum file descriptor limit: $MAX_FD"
+        fi
+    else
+        warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
+    fi
+fi
+
+# For Darwin, add options to specify how the application appears in the dock
+if $darwin; then
+    GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
+fi
+
+# For Cygwin, switch paths to Windows format before running java
+if $cygwin ; then
+    APP_HOME=`cygpath --path --mixed "$APP_HOME"`
+    CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
+
+    # We build the pattern for arguments to be converted via cygpath
+    ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
+    SEP=""
+    for dir in $ROOTDIRSRAW ; do
+        ROOTDIRS="$ROOTDIRS$SEP$dir"
+        SEP="|"
+    done
+    OURCYGPATTERN="(^($ROOTDIRS))"
+    # Add a user-defined pattern to the cygpath arguments
+    if [ "$GRADLE_CYGPATTERN" != "" ] ; then
+        OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
+    fi
+    # Now convert the arguments - kludge to limit ourselves to /bin/sh
+    i=0
+    for arg in "$@" ; do
+        CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
+        CHECK2=`echo "$arg"|egrep -c "^-"`                                 ### Determine if an option
+
+        if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then                    ### Added a condition
+            eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
+        else
+            eval `echo args$i`="\"$arg\""
+        fi
+        i=$((i+1))
+    done
+    case $i in
+        (0) set -- ;;
+        (1) set -- "$args0" ;;
+        (2) set -- "$args0" "$args1" ;;
+        (3) set -- "$args0" "$args1" "$args2" ;;
+        (4) set -- "$args0" "$args1" "$args2" "$args3" ;;
+        (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
+        (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
+        (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
+        (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
+        (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
+    esac
+fi
+
+# Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules
+function splitJvmOpts() {
+    JVM_OPTS=("$@")
+}
+eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS
+JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME"
+
+# For reproducible builds, always use the SDKs stored in source control
+if $darwin; then
+    ANDROID_HOME="$APP_HOME/prebuilts/fullsdk/darwin"
+else
+    ANDROID_HOME="$APP_HOME/prebuilts/fullsdk/linux"
+fi
+export ANDROID_HOME
+
+# Change the project's .gradle to the android out dir.
+ANDROID_OUT_ROOT="$APP_HOME/out"
+if [[ -n "$OUT_DIR" ]]; then
+    ANDROID_OUT_ROOT="$OUT_DIR"
+fi
+
+ANDROID_CACHE_DIR="$ANDROID_OUT_ROOT/gradle/.gradle"
+
+# Prevent excess parallelization on the build servers, as it slows the
+# build to a crawl
+if [[ "$1" == --parallel-threads=* ]] && [[ "$2" == buildForBuildServer* ]]; then
+    set -- "--parallel-threads=4" "$2"
+fi
+
+# Change the local user directories to be under the android out dir
+export GRADLE_USER_HOME="$ANDROID_OUT_ROOT/gradle/.gradle"
+export M2_HOME="$ANDROID_OUT_ROOT/gradle/.m2"
+
+exec "$JAVACMD" "${JVM_OPTS[@]}" \
+    -classpath "$CLASSPATH" \
+    org.gradle.wrapper.GradleWrapperMain \
+    --project-cache-dir=$ANDROID_CACHE_DIR \
+    -Dorg.gradle.jvmargs="-Xmx4096m -XX:MaxPermSize=1024m" \
+    --configure-on-demand \
+    "$@"
diff --git a/tools/gradle/repositories.properties b/tools/gradle/repositories.properties
new file mode 100644
index 0000000..ffdd0d2
--- /dev/null
+++ b/tools/gradle/repositories.properties
@@ -0,0 +1 @@
+// Empty for now
diff --git a/tools/gradle/settings.gradle b/tools/gradle/settings.gradle
new file mode 100644
index 0000000..24d5e33
--- /dev/null
+++ b/tools/gradle/settings.gradle
@@ -0,0 +1,60 @@
+include 'android-common'
+project(':android-common').projectDir = new File(rootDir, 'frameworks/ex/common')
+
+include 'aplos'
+project(':aplos').projectDir = new File(rootDir, 'vendor/unbundled_google/libs/aplos')
+project(':aplos').buildFileName = 'build-split.gradle'
+
+include 'bind'
+project(':bind').projectDir = new File(rootDir, 'vendor/unbundled_google/libraries/bind')
+
+include 'gdata'
+project(':gdata').projectDir = new File(rootDir, 'vendor/unbundled_google/libraries/gdata')
+
+include 'golly'
+project(':golly').projectDir = new File(rootDir, 'vendor/unbundled_google/libraries/golly')
+
+include 'gsf-client'
+project(':gsf-client').projectDir = new File(rootDir, 'vendor/unbundled_google/libraries/gsfclient')
+
+include 'jsr305'
+project(':jsr305').projectDir = new File(rootDir, 'external/jsr305')
+
+include 'guava'
+project(':guava').projectDir = new File(rootDir, 'external/guava')
+
+include 'libphonenumber'
+project(':libphonenumber').projectDir = new File(rootDir, 'external/libphonenumber')
+project(':libphonenumber').buildFileName = 'build-full.gradle'
+
+include 'libprotobuf'
+project(':libprotobuf').projectDir = new File(rootDir, 'external/protobuf')
+
+include 'pseudonymous-http'
+project(':pseudonymous-http').projectDir = new File(rootDir, 'vendor/unbundled_google/libraries/pseudonymous_http')
+
+include 's2utils'
+project(':s2utils').projectDir = new File(rootDir, 'external/s2utils')
+
+include 'smslib_pduutils'
+project(':smslib_pduutils').projectDir = new File(rootDir, 'external/smslib_pduutils')
+
+include 'volley'
+project(':volley').projectDir = new File(rootDir, 'frameworks/volley')
+project(':volley').buildFileName = 'rules.gradle'
+
+include 'vcard'
+project(':vcard').projectDir = new File(rootDir, 'frameworks/opt/vcard')
+
+include 'phonecommon'
+project(':phonecommon').projectDir = new File(rootDir, 'packages/apps/PhoneCommon')
+
+include 'contactscommon'
+project(':contactscommon').projectDir = new File(rootDir, 'packages/apps/ContactsCommon')
+
+include 'incallui'
+project(':incallui').projectDir = new File(rootDir, 'packages/apps/Dialer/InCallUI')
+
+include 'dialer'
+project(':dialer').projectDir = new File(rootDir, 'packages/apps/Dialer')
+project(':dialer').buildFileName = 'build-app.gradle'