Merge changes Ia937f030,Ia5f33e45,I1d73a90b,I90fe2d24,I030acbd7, ...

* changes:
  Add Motorola hidden menu to all Sprint MCCMNCs
  Remove obsolete version checks and compat utilities after min SDK was bumped up to N.
  Bump version codes and name to v20
  Catch BadParcelableException
  Move spam setting related methods out of spam interface into a separate spam setting interface.
  Add logging support for auto blocked spam calls.
diff --git a/AndroidManifest.xml b/AndroidManifest.xml
index 26fed40..f5cbd02 100644
--- a/AndroidManifest.xml
+++ b/AndroidManifest.xml
@@ -16,8 +16,8 @@
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
   coreApp="true"
   package="com.android.dialer"
-  android:versionCode="250000"
-  android:versionName="19.0">
+  android:versionCode="260000"
+  android:versionName="20.0">
 
   <uses-sdk
     android:minSdkVersion="24"
diff --git a/java/com/android/contacts/common/ContactsUtils.java b/java/com/android/contacts/common/ContactsUtils.java
index bca8b62..7e44a26 100644
--- a/java/com/android/contacts/common/ContactsUtils.java
+++ b/java/com/android/contacts/common/ContactsUtils.java
@@ -17,8 +17,8 @@
 package com.android.contacts.common;
 
 import android.provider.ContactsContract.Contacts;
+import android.provider.ContactsContract.Directory;
 import android.support.annotation.IntDef;
-import com.android.dialer.common.cp2.DirectoryCompat;
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
 
@@ -60,9 +60,7 @@
   public static @UserType long determineUserType(Long directoryId, Long contactId) {
     // First check directory id
     if (directoryId != null) {
-      return DirectoryCompat.isEnterpriseDirectoryId(directoryId)
-          ? USER_TYPE_WORK
-          : USER_TYPE_CURRENT;
+      return Directory.isEnterpriseDirectoryId(directoryId) ? USER_TYPE_WORK : USER_TYPE_CURRENT;
     }
     // Only check contact id if directory id is null
     if (contactId != null && contactId != 0L && Contacts.isEnterpriseContactId(contactId)) {
diff --git a/java/com/android/contacts/common/compat/CallableCompat.java b/java/com/android/contacts/common/compat/CallableCompat.java
deleted file mode 100644
index 5e86f51..0000000
--- a/java/com/android/contacts/common/compat/CallableCompat.java
+++ /dev/null
@@ -1,36 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.contacts.common.compat;
-
-import android.net.Uri;
-import android.os.Build.VERSION;
-import android.os.Build.VERSION_CODES;
-import android.provider.ContactsContract.CommonDataKinds.Callable;
-
-public class CallableCompat {
-
-  // TODO: Use N APIs
-  private static final Uri ENTERPRISE_CONTENT_FILTER_URI =
-      Uri.withAppendedPath(Callable.CONTENT_URI, "filter_enterprise");
-
-  public static Uri getContentFilterUri() {
-    if (VERSION.SDK_INT >= VERSION_CODES.N) {
-      return ENTERPRISE_CONTENT_FILTER_URI;
-    }
-    return Callable.CONTENT_FILTER_URI;
-  }
-}
diff --git a/java/com/android/contacts/common/compat/ContactsCompat.java b/java/com/android/contacts/common/compat/ContactsCompat.java
deleted file mode 100644
index e0c9b7e..0000000
--- a/java/com/android/contacts/common/compat/ContactsCompat.java
+++ /dev/null
@@ -1,41 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.contacts.common.compat;
-
-import android.net.Uri;
-import android.os.Build.VERSION;
-import android.os.Build.VERSION_CODES;
-import android.provider.ContactsContract;
-import android.provider.ContactsContract.Contacts;
-
-/** Compatibility class for {@link ContactsContract.Contacts} */
-public class ContactsCompat {
-
-  // TODO: Use N APIs
-  private static final Uri ENTERPRISE_CONTENT_FILTER_URI =
-      Uri.withAppendedPath(Contacts.CONTENT_URI, "filter_enterprise");
-
-  /** Not instantiable. */
-  private ContactsCompat() {}
-
-  public static Uri getContentUri() {
-    if (VERSION.SDK_INT >= VERSION_CODES.N) {
-      return ENTERPRISE_CONTENT_FILTER_URI;
-    }
-    return Contacts.CONTENT_FILTER_URI;
-  }
-}
diff --git a/java/com/android/contacts/common/compat/PhoneCompat.java b/java/com/android/contacts/common/compat/PhoneCompat.java
deleted file mode 100644
index 31db7b5..0000000
--- a/java/com/android/contacts/common/compat/PhoneCompat.java
+++ /dev/null
@@ -1,36 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.contacts.common.compat;
-
-import android.net.Uri;
-import android.os.Build.VERSION;
-import android.os.Build.VERSION_CODES;
-import android.provider.ContactsContract.CommonDataKinds.Phone;
-
-public class PhoneCompat {
-
-  // TODO: Use N APIs
-  private static final Uri ENTERPRISE_CONTENT_FILTER_URI =
-      Uri.withAppendedPath(Phone.CONTENT_URI, "filter_enterprise");
-
-  public static Uri getContentFilterUri() {
-    if (VERSION.SDK_INT >= VERSION_CODES.N) {
-      return ENTERPRISE_CONTENT_FILTER_URI;
-    }
-    return Phone.CONTENT_FILTER_URI;
-  }
-}
diff --git a/java/com/android/dialer/animation/AnimUtils.java b/java/com/android/dialer/animation/AnimUtils.java
index 9c9396e..9160cf5 100644
--- a/java/com/android/dialer/animation/AnimUtils.java
+++ b/java/com/android/dialer/animation/AnimUtils.java
@@ -22,17 +22,16 @@
 import android.view.View;
 import android.view.ViewPropertyAnimator;
 import android.view.animation.Interpolator;
-import com.android.dialer.compat.PathInterpolatorCompat;
+import android.view.animation.PathInterpolator;
 
 public class AnimUtils {
 
   public static final int DEFAULT_DURATION = -1;
   public static final int NO_DELAY = 0;
 
-  public static final Interpolator EASE_IN = PathInterpolatorCompat.create(0.0f, 0.0f, 0.2f, 1.0f);
-  public static final Interpolator EASE_OUT = PathInterpolatorCompat.create(0.4f, 0.0f, 1.0f, 1.0f);
-  public static final Interpolator EASE_OUT_EASE_IN =
-      PathInterpolatorCompat.create(0.4f, 0, 0.2f, 1);
+  public static final Interpolator EASE_IN = new PathInterpolator(0.0f, 0.0f, 0.2f, 1.0f);
+  public static final Interpolator EASE_OUT = new PathInterpolator(0.4f, 0.0f, 1.0f, 1.0f);
+  public static final Interpolator EASE_OUT_EASE_IN = new PathInterpolator(0.4f, 0, 0.2f, 1);
 
   public static void crossFadeViews(View fadeIn, View fadeOut, int duration) {
     fadeIn(fadeIn, duration);
diff --git a/java/com/android/dialer/app/calllog/BlockReportSpamListener.java b/java/com/android/dialer/app/calllog/BlockReportSpamListener.java
index 5c7641c..d52ac32 100644
--- a/java/com/android/dialer/app/calllog/BlockReportSpamListener.java
+++ b/java/com/android/dialer/app/calllog/BlockReportSpamListener.java
@@ -32,6 +32,7 @@
 import com.android.dialer.logging.ReportingLocation;
 import com.android.dialer.spam.Spam;
 import com.android.dialer.spam.SpamComponent;
+import com.android.dialer.spam.SpamSettings;
 import com.android.dialer.spam.promo.SpamBlockingPromoHelper;
 
 /** Listener to show dialogs for block and report spam actions. */
@@ -43,6 +44,7 @@
   private final RecyclerView.Adapter adapter;
   private final FilteredNumberAsyncQueryHandler filteredNumberAsyncQueryHandler;
   private final Spam spam;
+  private final SpamSettings spamSettings;
   private final SpamBlockingPromoHelper spamBlockingPromoHelper;
 
   public BlockReportSpamListener(
@@ -57,7 +59,8 @@
     this.adapter = adapter;
     this.filteredNumberAsyncQueryHandler = filteredNumberAsyncQueryHandler;
     spam = SpamComponent.get(context).spam();
-    spamBlockingPromoHelper = new SpamBlockingPromoHelper(context, spam);
+    spamSettings = SpamComponent.get(context).spamSettings();
+    spamBlockingPromoHelper = new SpamBlockingPromoHelper(context, spamSettings);
   }
 
   @Override
@@ -69,10 +72,10 @@
       @NonNull final ContactSource.Type contactSourceType) {
     BlockReportSpamDialogs.DialogFragmentForBlockingNumberAndOptionallyReportingAsSpam.newInstance(
             displayNumber,
-            spam.isDialogReportSpamCheckedByDefault(),
+            spamSettings.isDialogReportSpamCheckedByDefault(),
             isSpamChecked -> {
               LogUtil.i("BlockReportSpamListener.onBlockReportSpam", "onClick");
-              if (isSpamChecked && spam.isSpamEnabled()) {
+              if (isSpamChecked && spamSettings.isSpamEnabled()) {
                 Logger.get(context)
                     .logImpression(
                         DialerImpression.Type
@@ -110,10 +113,10 @@
       @NonNull final ContactSource.Type contactSourceType) {
     BlockReportSpamDialogs.DialogFragmentForBlockingNumberAndReportingAsSpam.newInstance(
             displayNumber,
-            spam.isSpamEnabled(),
+            spamSettings.isSpamEnabled(),
             () -> {
               LogUtil.i("BlockReportSpamListener.onBlock", "onClick");
-              if (spam.isSpamEnabled()) {
+              if (spamSettings.isSpamEnabled()) {
                 Logger.get(context)
                     .logImpression(
                         DialerImpression.Type
@@ -154,7 +157,7 @@
             isSpam,
             () -> {
               LogUtil.i("BlockReportSpamListener.onUnblock", "onClick");
-              if (isSpam && spam.isSpamEnabled()) {
+              if (isSpam && spamSettings.isSpamEnabled()) {
                 Logger.get(context)
                     .logImpression(DialerImpression.Type.REPORT_AS_NOT_SPAM_VIA_UNBLOCK_NUMBER);
                 spam.reportNotSpamFromCallHistory(
@@ -187,7 +190,7 @@
             displayNumber,
             () -> {
               LogUtil.i("BlockReportSpamListener.onReportNotSpam", "onClick");
-              if (spam.isSpamEnabled()) {
+              if (spamSettings.isSpamEnabled()) {
                 Logger.get(context)
                     .logImpression(DialerImpression.Type.DIALOG_ACTION_CONFIRM_NUMBER_NOT_SPAM);
                 spam.reportNotSpamFromCallHistory(
diff --git a/java/com/android/dialer/app/calllog/CallLogAdapter.java b/java/com/android/dialer/app/calllog/CallLogAdapter.java
index 376057f..d25a2f3 100644
--- a/java/com/android/dialer/app/calllog/CallLogAdapter.java
+++ b/java/com/android/dialer/app/calllog/CallLogAdapter.java
@@ -682,7 +682,7 @@
       contactInfoCache.start();
     }
     contactsPreferences.refreshValue(ContactsPreferences.DISPLAY_ORDER_KEY);
-    isSpamEnabled = SpamComponent.get(activity).spam().isSpamEnabled();
+    isSpamEnabled = SpamComponent.get(activity).spamSettings().isSpamEnabled();
     getDuo().registerListener(this);
     notifyDataSetChanged();
   }
@@ -945,10 +945,8 @@
       Cursor cursor, int count, final CallLogListItemViewHolder views) {
     Assert.isMainThread();
     final String number = cursor.getString(CallLogQuery.NUMBER);
-    final String postDialDigits =
-        (VERSION.SDK_INT >= VERSION_CODES.N) ? cursor.getString(CallLogQuery.POST_DIAL_DIGITS) : "";
-    final String viaNumber =
-        (VERSION.SDK_INT >= VERSION_CODES.N) ? cursor.getString(CallLogQuery.VIA_NUMBER) : "";
+    final String postDialDigits = cursor.getString(CallLogQuery.POST_DIAL_DIGITS);
+    final String viaNumber = cursor.getString(CallLogQuery.VIA_NUMBER);
     final int numberPresentation = cursor.getInt(CallLogQuery.NUMBER_PRESENTATION);
     final ContactInfo cachedContactInfo = ContactInfoHelper.getContactInfo(cursor);
     final int transcriptionState =
diff --git a/java/com/android/dialer/app/calllog/VisualVoicemailUpdateTask.java b/java/com/android/dialer/app/calllog/VisualVoicemailUpdateTask.java
index 6d2581f..4516382 100644
--- a/java/com/android/dialer/app/calllog/VisualVoicemailUpdateTask.java
+++ b/java/com/android/dialer/app/calllog/VisualVoicemailUpdateTask.java
@@ -36,7 +36,6 @@
 import com.android.dialer.logging.Logger;
 import com.android.dialer.notification.DialerNotificationManager;
 import com.android.dialer.phonenumbercache.ContactInfo;
-import com.android.dialer.spam.Spam;
 import com.android.dialer.spam.SpamComponent;
 import com.android.dialer.telecom.TelecomUtil;
 import java.util.ArrayList;
@@ -48,7 +47,7 @@
   @Nullable
   @Override
   public Void doInBackground(@NonNull Input input) throws Throwable {
-    updateNotification(input.context, input.queryHelper, input.queryHandler, input.spam);
+    updateNotification(input.context, input.queryHelper, input.queryHandler);
     return null;
   }
 
@@ -62,8 +61,7 @@
   private static void updateNotification(
       Context context,
       CallLogNotificationsQueryHelper queryHelper,
-      FilteredNumberAsyncQueryHandler queryHandler,
-      Spam spam) {
+      FilteredNumberAsyncQueryHandler queryHandler) {
     Assert.isWorkerThread();
     LogUtil.enterBlock("VisualVoicemailUpdateTask.updateNotification");
 
@@ -79,7 +77,7 @@
           "not filtering due to recent emergency call");
     } else {
       voicemailsToNotify = filterBlockedNumbers(context, queryHandler, voicemailsToNotify);
-      voicemailsToNotify = filterSpamNumbers(context, spam, voicemailsToNotify);
+      voicemailsToNotify = filterSpamNumbers(context, voicemailsToNotify);
     }
     boolean shouldAlert =
         !voicemailsToNotify.isEmpty()
@@ -197,23 +195,26 @@
   }
 
   @WorkerThread
-  private static List<NewCall> filterSpamNumbers(
-      Context context, Spam spam, List<NewCall> newCalls) {
+  private static List<NewCall> filterSpamNumbers(Context context, List<NewCall> newCalls) {
     Assert.isWorkerThread();
-    if (!spam.isSpamBlockingEnabled()) {
+    if (!SpamComponent.get(context).spamSettings().isSpamBlockingEnabled()) {
+      LogUtil.w("VisualVoicemailUpdateTask.wwwwwwwwwwwww", "NOT ENABLED");
       return newCalls;
     }
 
     List<NewCall> result = new ArrayList<>();
     for (NewCall newCall : newCalls) {
       Logger.get(context).logImpression(DialerImpression.Type.INCOMING_VOICEMAIL_SCREENED);
-      if (spam.checkSpamStatusSynchronous(newCall.number, newCall.countryIso)) {
+      if (SpamComponent.get(context)
+          .spam()
+          .checkSpamStatusSynchronous(newCall.number, newCall.countryIso)) {
         LogUtil.i(
             "VisualVoicemailUpdateTask.filterSpamNumbers",
             "found voicemail from spam number, suppressing notification");
         Logger.get(context)
             .logImpression(DialerImpression.Type.INCOMING_VOICEMAIL_AUTO_BLOCKED_AS_SPAM);
       } else {
+        LogUtil.w("VisualVoicemailUpdateTask.wwwwwwwwwwwww", "NOT SPAM NUMBER");
         result.add(newCall);
       }
     }
@@ -234,8 +235,7 @@
         new Input(
             context,
             CallLogNotificationsQueryHelper.getInstance(context),
-            new FilteredNumberAsyncQueryHandler(context),
-            SpamComponent.get(context).spam());
+            new FilteredNumberAsyncQueryHandler(context));
     DialerExecutorComponent.get(context)
         .dialerExecutorFactory()
         .createNonUiTaskBuilder(new VisualVoicemailUpdateTask())
@@ -257,17 +257,14 @@
     @NonNull final Context context;
     @NonNull final CallLogNotificationsQueryHelper queryHelper;
     @NonNull final FilteredNumberAsyncQueryHandler queryHandler;
-    @NonNull final Spam spam;
 
     Input(
         Context context,
         CallLogNotificationsQueryHelper queryHelper,
-        FilteredNumberAsyncQueryHandler queryHandler,
-        Spam spam) {
+        FilteredNumberAsyncQueryHandler queryHandler) {
       this.context = context;
       this.queryHelper = queryHelper;
       this.queryHandler = queryHandler;
-      this.spam = spam;
     }
   }
 }
diff --git a/java/com/android/dialer/app/list/DragDropController.java b/java/com/android/dialer/app/list/DragDropController.java
index 458e31e..1c33a8a 100644
--- a/java/com/android/dialer/app/list/DragDropController.java
+++ b/java/com/android/dialer/app/list/DragDropController.java
@@ -16,8 +16,6 @@
 
 package com.android.dialer.app.list;
 
-import android.os.Build.VERSION;
-import android.os.Build.VERSION_CODES;
 import android.view.View;
 import java.util.ArrayList;
 import java.util.List;
@@ -38,22 +36,15 @@
 
   /** @return True if the drag is started, false if the drag is cancelled for some reason. */
   boolean handleDragStarted(View v, int x, int y) {
-    int screenX = x;
-    int screenY = y;
-    // The coordinates in dragEvent of DragEvent.ACTION_DRAG_STARTED before NYC is window-related.
-    // This is fixed in NYC.
-    if (VERSION.SDK_INT >= VERSION_CODES.N) {
-      v.getLocationOnScreen(locationOnScreen);
-      screenX = x + locationOnScreen[0];
-      screenY = y + locationOnScreen[1];
-    }
-    final PhoneFavoriteSquareTileView tileView =
-        dragItemContainer.getViewForLocation(screenX, screenY);
+    v.getLocationOnScreen(locationOnScreen);
+    x = x + locationOnScreen[0];
+    y = y + locationOnScreen[1];
+    final PhoneFavoriteSquareTileView tileView = dragItemContainer.getViewForLocation(x, y);
     if (tileView == null) {
       return false;
     }
     for (int i = 0; i < onDragDropListeners.size(); i++) {
-      onDragDropListeners.get(i).onDragStarted(screenX, screenY, tileView);
+      onDragDropListeners.get(i).onDragStarted(x, y, tileView);
     }
 
     return true;
diff --git a/java/com/android/dialer/app/settings/DialerSettingsActivity.java b/java/com/android/dialer/app/settings/DialerSettingsActivity.java
index 09fe03e..6b763ae 100644
--- a/java/com/android/dialer/app/settings/DialerSettingsActivity.java
+++ b/java/com/android/dialer/app/settings/DialerSettingsActivity.java
@@ -128,7 +128,7 @@
       callSettingsHeader.titleRes = R.string.call_settings_label;
       callSettingsHeader.intent = callSettingsIntent;
       target.add(callSettingsHeader);
-    } else if ((VERSION.SDK_INT >= VERSION_CODES.N) || isPrimaryUser) {
+    } else if (isPrimaryUser) {
       Header phoneAccountSettingsHeader = new Header();
       Intent phoneAccountSettingsIntent = new Intent(TelecomManager.ACTION_CHANGE_PHONE_ACCOUNTS);
       phoneAccountSettingsIntent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
diff --git a/java/com/android/dialer/binary/google/AndroidManifest.xml b/java/com/android/dialer/binary/google/AndroidManifest.xml
index f6ac430..acab0a8 100644
--- a/java/com/android/dialer/binary/google/AndroidManifest.xml
+++ b/java/com/android/dialer/binary/google/AndroidManifest.xml
@@ -16,8 +16,8 @@
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
   coreApp="true"
   package="com.google.android.google_stub_dialer"
-  android:versionCode="250000"
-  android:versionName="19.0">
+  android:versionCode="260000"
+  android:versionName="20.0">
 
   <uses-sdk
     android:minSdkVersion="24"
diff --git a/java/com/android/dialer/blockreportspam/ShowBlockReportSpamDialogReceiver.java b/java/com/android/dialer/blockreportspam/ShowBlockReportSpamDialogReceiver.java
index 02aa994..cc307b6 100644
--- a/java/com/android/dialer/blockreportspam/ShowBlockReportSpamDialogReceiver.java
+++ b/java/com/android/dialer/blockreportspam/ShowBlockReportSpamDialogReceiver.java
@@ -38,6 +38,7 @@
 import com.android.dialer.protos.ProtoParsers;
 import com.android.dialer.spam.Spam;
 import com.android.dialer.spam.SpamComponent;
+import com.android.dialer.spam.SpamSettings;
 import com.google.auto.value.AutoValue;
 
 /**
@@ -104,6 +105,7 @@
             intent, EXTRA_DIALOG_INFO, BlockReportSpamDialogInfo.getDefaultInstance());
 
     Spam spam = SpamComponent.get(context).spam();
+    SpamSettings spamSettings = SpamComponent.get(context).spamSettings();
     FilteredNumberAsyncQueryHandler filteredNumberAsyncQueryHandler =
         new FilteredNumberAsyncQueryHandler(context);
 
@@ -114,7 +116,7 @@
               "ShowBlockReportSpamDialogReceiver.showDialogToBlockNumberAndOptionallyReportSpam",
               "confirmed");
 
-          if (reportSpam && spam.isSpamEnabled()) {
+          if (reportSpam && spamSettings.isSpamEnabled()) {
             LogUtil.i(
                 "ShowBlockReportSpamDialogReceiver.showDialogToBlockNumberAndOptionallyReportSpam",
                 "report spam");
@@ -141,7 +143,7 @@
     // Create and show the dialog.
     DialogFragmentForBlockingNumberAndOptionallyReportingAsSpam.newInstance(
             dialogInfo.getNormalizedNumber(),
-            spam.isDialogReportSpamCheckedByDefault(),
+            spamSettings.isDialogReportSpamCheckedByDefault(),
             onSpamDialogClickListener,
             /* dismissListener = */ null)
         .show(fragmentManager, BlockReportSpamDialogs.BLOCK_REPORT_SPAM_DIALOG_TAG);
@@ -189,16 +191,17 @@
         () -> {
           LogUtil.i("ShowBlockReportSpamDialogReceiver.showDialogToReportNotSpam", "confirmed");
 
-          Spam spam = SpamComponent.get(context).spam();
-          if (spam.isSpamEnabled()) {
+          if (SpamComponent.get(context).spamSettings().isSpamEnabled()) {
             Logger.get(context)
                 .logImpression(DialerImpression.Type.DIALOG_ACTION_CONFIRM_NUMBER_NOT_SPAM);
-            spam.reportNotSpamFromCallHistory(
-                dialogInfo.getNormalizedNumber(),
-                dialogInfo.getCountryIso(),
-                dialogInfo.getCallType(),
-                dialogInfo.getReportingLocation(),
-                dialogInfo.getContactSource());
+            SpamComponent.get(context)
+                .spam()
+                .reportNotSpamFromCallHistory(
+                    dialogInfo.getNormalizedNumber(),
+                    dialogInfo.getCountryIso(),
+                    dialogInfo.getCallType(),
+                    dialogInfo.getReportingLocation(),
+                    dialogInfo.getContactSource());
           }
         };
 
diff --git a/java/com/android/dialer/common/cp2/DirectoryCompat.java b/java/com/android/dialer/common/cp2/DirectoryCompat.java
deleted file mode 100644
index 3e33394..0000000
--- a/java/com/android/dialer/common/cp2/DirectoryCompat.java
+++ /dev/null
@@ -1,56 +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.common.cp2;
-
-import android.net.Uri;
-import android.os.Build.VERSION;
-import android.os.Build.VERSION_CODES;
-import android.provider.ContactsContract.Directory;
-
-/** Compatibility utility for {@link Directory}. */
-public class DirectoryCompat {
-
-  public static Uri getContentUri() {
-    if (VERSION.SDK_INT >= VERSION_CODES.N) {
-      return Directory.ENTERPRISE_CONTENT_URI;
-    }
-    return Directory.CONTENT_URI;
-  }
-
-  public static boolean isInvisibleDirectory(long directoryId) {
-    if (VERSION.SDK_INT >= VERSION_CODES.N) {
-      return (directoryId == Directory.LOCAL_INVISIBLE
-          || directoryId == Directory.ENTERPRISE_LOCAL_INVISIBLE);
-    }
-    return directoryId == Directory.LOCAL_INVISIBLE;
-  }
-
-  public static boolean isRemoteDirectoryId(long directoryId) {
-    if (VERSION.SDK_INT >= VERSION_CODES.N) {
-      return Directory.isRemoteDirectoryId(directoryId);
-    }
-    return directoryId != Directory.DEFAULT && directoryId != Directory.LOCAL_INVISIBLE;
-  }
-
-  public static boolean isEnterpriseDirectoryId(long directoryId) {
-    return VERSION.SDK_INT >= VERSION_CODES.N && Directory.isEnterpriseDirectoryId(directoryId);
-  }
-
-  public static boolean isOnlyEnterpriseDirectoryId(long directoryId) {
-    return isEnterpriseDirectoryId(directoryId) && !isRemoteDirectoryId(directoryId);
-  }
-}
diff --git a/java/com/android/dialer/common/cp2/DirectoryUtils.java b/java/com/android/dialer/common/cp2/DirectoryUtils.java
new file mode 100644
index 0000000..fa5a226
--- /dev/null
+++ b/java/com/android/dialer/common/cp2/DirectoryUtils.java
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.dialer.common.cp2;
+
+import android.provider.ContactsContract.Directory;
+
+/** Utilities for {@link Directory}. */
+public class DirectoryUtils {
+
+  /** Returns true if the given ID belongs to an invisible directory. */
+  public static boolean isInvisibleDirectoryId(long directoryId) {
+    return directoryId == Directory.LOCAL_INVISIBLE
+        || directoryId == Directory.ENTERPRISE_LOCAL_INVISIBLE;
+  }
+
+  /** Returns true if the given ID belongs to a local enterprise directory. */
+  public static boolean isLocalEnterpriseDirectoryId(long directoryId) {
+    return Directory.isEnterpriseDirectoryId(directoryId)
+        && !Directory.isRemoteDirectoryId(directoryId);
+  }
+}
diff --git a/java/com/android/dialer/compat/ActivityCompat.java b/java/com/android/dialer/compat/ActivityCompat.java
deleted file mode 100644
index e59b115..0000000
--- a/java/com/android/dialer/compat/ActivityCompat.java
+++ /dev/null
@@ -1,29 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.dialer.compat;
-
-import android.app.Activity;
-import android.os.Build.VERSION;
-import android.os.Build.VERSION_CODES;
-
-/** Utility for calling methods introduced after Marshmallow for Activities. */
-public class ActivityCompat {
-
-  public static boolean isInMultiWindowMode(Activity activity) {
-    return VERSION.SDK_INT >= VERSION_CODES.N && activity.isInMultiWindowMode();
-  }
-}
diff --git a/java/com/android/dialer/compat/CompatUtils.java b/java/com/android/dialer/compat/CompatUtils.java
index d09f8b0..f0039e9 100644
--- a/java/com/android/dialer/compat/CompatUtils.java
+++ b/java/com/android/dialer/compat/CompatUtils.java
@@ -16,15 +16,14 @@
 package com.android.dialer.compat;
 
 import android.content.Context;
-import android.os.Build.VERSION;
-import android.os.Build.VERSION_CODES;
 import android.os.LocaleList;
 import java.util.Locale;
 
-/** TODO(calderwoodra): documentation */
+/** TODO(linyuh): Remove deprecated methods and rename this class. */
 public final class CompatUtils {
 
   /** PrioritizedMimeType is added in API level 23. */
+  @Deprecated
   public static boolean hasPrioritizedMimeType() {
     return true;
   }
@@ -35,6 +34,7 @@
    *
    * @return {@code true} if multi-SIM capability is available, {@code false} otherwise.
    */
+  @Deprecated
   public static boolean isMSIMCompatible() {
     return true;
   }
@@ -45,6 +45,7 @@
    *
    * @return {@code true} if video calling is allowed, {@code false} otherwise.
    */
+  @Deprecated
   public static boolean isVideoCompatible() {
     return true;
   }
@@ -55,6 +56,7 @@
    *
    * @return {@code true} if video presence checking is allowed, {@code false} otherwise.
    */
+  @Deprecated
   public static boolean isVideoPresenceCompatible() {
     return true;
   }
@@ -65,20 +67,17 @@
    *
    * @return {@code true} if call subject is a feature on this device, {@code false} otherwise.
    */
+  @Deprecated
   public static boolean isCallSubjectCompatible() {
     return true;
   }
 
   /** Returns locale of the device. */
   public static Locale getLocale(Context context) {
-    if (VERSION.SDK_INT >= VERSION_CODES.N) {
-      LocaleList localList = context.getResources().getConfiguration().getLocales();
-      if (!localList.isEmpty()) {
-        return localList.get(0);
-      }
-      return Locale.getDefault();
-    } else {
-      return context.getResources().getConfiguration().locale;
+    LocaleList localList = context.getResources().getConfiguration().getLocales();
+    if (!localList.isEmpty()) {
+      return localList.get(0);
     }
+    return Locale.getDefault();
   }
 }
diff --git a/java/com/android/dialer/compat/PathInterpolatorCompat.java b/java/com/android/dialer/compat/PathInterpolatorCompat.java
deleted file mode 100644
index d0d410d..0000000
--- a/java/com/android/dialer/compat/PathInterpolatorCompat.java
+++ /dev/null
@@ -1,120 +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.graphics.Path;
-import android.graphics.PathMeasure;
-import android.os.Build;
-import android.view.animation.Interpolator;
-import android.view.animation.PathInterpolator;
-
-public class PathInterpolatorCompat {
-
-  public static Interpolator create(
-      float controlX1, float controlY1, float controlX2, float controlY2) {
-    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
-      return new PathInterpolator(controlX1, controlY1, controlX2, controlY2);
-    }
-    return new PathInterpolatorBase(controlX1, controlY1, controlX2, controlY2);
-  }
-
-  private static class PathInterpolatorBase implements Interpolator {
-
-    /** Governs the accuracy of the approximation of the {@link Path}. */
-    private static final float PRECISION = 0.002f;
-
-    private final float[] x;
-    private final float[] y;
-
-    public PathInterpolatorBase(Path path) {
-      final PathMeasure pathMeasure = new PathMeasure(path, false /* forceClosed */);
-
-      final float pathLength = pathMeasure.getLength();
-      final int numPoints = (int) (pathLength / PRECISION) + 1;
-
-      x = new float[numPoints];
-      y = new float[numPoints];
-
-      final float[] position = new float[2];
-      for (int i = 0; i < numPoints; ++i) {
-        final float distance = (i * pathLength) / (numPoints - 1);
-        pathMeasure.getPosTan(distance, position, null /* tangent */);
-
-        x[i] = position[0];
-        y[i] = position[1];
-      }
-    }
-
-    public PathInterpolatorBase(float controlX, float controlY) {
-      this(createQuad(controlX, controlY));
-    }
-
-    public PathInterpolatorBase(
-        float controlX1, float controlY1, float controlX2, float controlY2) {
-      this(createCubic(controlX1, controlY1, controlX2, controlY2));
-    }
-
-    private static Path createQuad(float controlX, float controlY) {
-      final Path path = new Path();
-      path.moveTo(0.0f, 0.0f);
-      path.quadTo(controlX, controlY, 1.0f, 1.0f);
-      return path;
-    }
-
-    private static Path createCubic(
-        float controlX1, float controlY1, float controlX2, float controlY2) {
-      final Path path = new Path();
-      path.moveTo(0.0f, 0.0f);
-      path.cubicTo(controlX1, controlY1, controlX2, controlY2, 1.0f, 1.0f);
-      return path;
-    }
-
-    @Override
-    public float getInterpolation(float t) {
-      if (t <= 0.0f) {
-        return 0.0f;
-      } else if (t >= 1.0f) {
-        return 1.0f;
-      }
-
-      // Do a binary search for the correct x to interpolate between.
-      int startIndex = 0;
-      int endIndex = x.length - 1;
-      while (endIndex - startIndex > 1) {
-        int midIndex = (startIndex + endIndex) / 2;
-        if (t < x[midIndex]) {
-          endIndex = midIndex;
-        } else {
-          startIndex = midIndex;
-        }
-      }
-
-      final float xRange = x[endIndex] - x[startIndex];
-      if (xRange == 0) {
-        return y[startIndex];
-      }
-
-      final float tInRange = t - x[startIndex];
-      final float fraction = tInRange / xRange;
-
-      final float startY = y[startIndex];
-      final float endY = y[endIndex];
-
-      return startY + (fraction * (endY - startY));
-    }
-  }
-}
diff --git a/java/com/android/dialer/logging/LoggingBindings.java b/java/com/android/dialer/logging/LoggingBindings.java
index ca9a053..a6795ed 100644
--- a/java/com/android/dialer/logging/LoggingBindings.java
+++ b/java/com/android/dialer/logging/LoggingBindings.java
@@ -87,4 +87,7 @@
 
   /** Logs successful People Api lookup result */
   void logSuccessfulPeopleApiLookupReport(long latency, int httpResponseCode);
+
+  /** Logs a call auto-blocked in call screening. */
+  void logAutoBlockedCall(String phoneNumber);
 }
diff --git a/java/com/android/dialer/logging/LoggingBindingsStub.java b/java/com/android/dialer/logging/LoggingBindingsStub.java
index 2dbcc3f..de08f44 100644
--- a/java/com/android/dialer/logging/LoggingBindingsStub.java
+++ b/java/com/android/dialer/logging/LoggingBindingsStub.java
@@ -61,4 +61,7 @@
 
   @Override
   public void logSuccessfulPeopleApiLookupReport(long latency, int httpResponseCode) {}
+
+  @Override
+  public void logAutoBlockedCall(String phoneNumber) {}
 }
diff --git a/java/com/android/dialer/oem/MotorolaHiddenMenuKeySequence.java b/java/com/android/dialer/oem/MotorolaHiddenMenuKeySequence.java
index 079624b..74ad1b8 100644
--- a/java/com/android/dialer/oem/MotorolaHiddenMenuKeySequence.java
+++ b/java/com/android/dialer/oem/MotorolaHiddenMenuKeySequence.java
@@ -71,6 +71,11 @@
   }
 
   @VisibleForTesting
+  static void setInstanceForTest(MotorolaHiddenMenuKeySequence instance) {
+    MotorolaHiddenMenuKeySequence.instance = instance;
+  }
+
+  @VisibleForTesting
   MotorolaHiddenMenuKeySequence(
       Context context, SystemPropertiesAccessor systemPropertiesAccessor) {
     if (MotorolaUtils.isSupportingHiddenMenu(context)) {
diff --git a/java/com/android/dialer/oem/MotorolaUtils.java b/java/com/android/dialer/oem/MotorolaUtils.java
index 993078d..3879f91 100644
--- a/java/com/android/dialer/oem/MotorolaUtils.java
+++ b/java/com/android/dialer/oem/MotorolaUtils.java
@@ -59,9 +59,14 @@
    */
   private static boolean isSpnMatched(Context context) {
     try {
-      String spnResource = context.getResources().getString(R.string.motorola_enabled_spn);
-      return spnResource.equalsIgnoreCase(
-          context.getSystemService(TelephonyManager.class).getSimOperatorName());
+      for (String spnResource :
+          context.getResources().getStringArray(R.array.motorola_enabled_spn)) {
+        if (spnResource.equalsIgnoreCase(
+            context.getSystemService(TelephonyManager.class).getSimOperatorName())) {
+          return true;
+        }
+      }
+      return false;
     } catch (Resources.NotFoundException exception) {
       // If SPN is not specified we consider as not necessary to enable/disable the feature.
       return true;
@@ -69,7 +74,8 @@
   }
 
   static boolean isSupportingHiddenMenu(Context context) {
-    return context.getPackageManager().hasSystemFeature(HIDDEN_MENU_FEATURE);
+    return context.getPackageManager().hasSystemFeature(HIDDEN_MENU_FEATURE)
+        && context.getResources().getBoolean(R.bool.motorola_hidden_menu_enabled);
   }
 
   public static boolean shouldBlinkHdIconWhenConnectingCall(Context context) {
diff --git a/java/com/android/dialer/oem/res/values-mcc310-mnc000/motorola_config.xml b/java/com/android/dialer/oem/res/values-mcc310-mnc000/motorola_config.xml
index ac33975..3b4d547 100644
--- a/java/com/android/dialer/oem/res/values-mcc310-mnc000/motorola_config.xml
+++ b/java/com/android/dialer/oem/res/values-mcc310-mnc000/motorola_config.xml
@@ -17,5 +17,9 @@
 
 <resources>
   <bool name="motorola_sprint_hd_codec">true</bool>
-  <string name="motorola_enabled_spn">Sprint</string>
+  <bool name="motorola_hidden_menu_enabled">true</bool>
+  <string-array name="motorola_enabled_spn">
+    <item>Sprint</item>
+    <item>moto</item>
+  </string-array>
 </resources>
\ No newline at end of file
diff --git a/java/com/android/dialer/oem/res/values-mcc310-mnc120/motorola_config.xml b/java/com/android/dialer/oem/res/values-mcc310-mnc120/motorola_config.xml
index 417a4b8..18c4c3f 100644
--- a/java/com/android/dialer/oem/res/values-mcc310-mnc120/motorola_config.xml
+++ b/java/com/android/dialer/oem/res/values-mcc310-mnc120/motorola_config.xml
@@ -17,60 +17,5 @@
 
 <resources>
   <bool name="motorola_sprint_hd_codec">true</bool>
-
-  <!-- Hidden menu configuration for Motorola. -->
-  <!-- This defines the specific key sequence that will be caught in the SpecialCharSequenceMgr
-       such as, ##OMADM# -->
-  <string-array name="motorola_hidden_menu_key_sequence">
-    <item>##66236#</item>   <!--##OMADM#-->
-    <item>##2539#</item>    <!--##AKEY#-->
-    <item>##786#</item>     <!--##RTN#-->
-    <item>##72786#</item>   <!--##SCRTN#-->
-    <item>##3282#</item>    <!--##DATA#-->
-    <item>##33284#</item>   <!--##DEBUG#-->
-    <item>##3424#</item>    <!--##DIAG#-->
-    <item>##564#</item>     <!--##LOG#-->
-    <item>##4567257#</item> <!--##GLMSCLR#-->
-    <item>##873283#</item>  <!--##UPDATE#-->
-    <item>##6343#</item>    <!--##MEID#-->
-    <item>##27263#</item>   <!--##BRAND#-->
-    <item>##258#</item>     <!--##BLV#-->
-    <item>##8422#</item>    <!--##UICC#-->
-    <item>##4382#</item>    <!--CMAS/WEA-->
-  </string-array>
-
-  <string name="motorola_hidden_menu_intent">com.motorola.intent.action.LAUNCH_HIDDEN_MENU</string>
-
-  <!-- This defines the intents that will be send out when the key sequence is matched, this must be
-       in the same order with he KeySequence array. -->
-  <string-array name="motorola_hidden_menu_key_sequence_intents">
-    <item>@string/motorola_hidden_menu_intent</item>
-    <item>@string/motorola_hidden_menu_intent</item>
-    <item>@string/motorola_hidden_menu_intent</item>
-    <item>@string/motorola_hidden_menu_intent</item>
-    <item>@string/motorola_hidden_menu_intent</item>
-    <item>@string/motorola_hidden_menu_intent</item>
-    <item>@string/motorola_hidden_menu_intent</item>
-    <item>@string/motorola_hidden_menu_intent</item>
-    <item>@string/motorola_hidden_menu_intent</item>
-    <item>com.motorola.android.intent.action.omadm.sprint.hfa</item>
-    <item>@string/motorola_hidden_menu_intent</item>
-    <item>@string/motorola_hidden_menu_intent</item>
-    <item>@string/motorola_hidden_menu_intent</item>
-    <item>@string/motorola_hidden_menu_intent</item>
-    <item>@string/motorola_hidden_menu_intent</item>
-  </string-array>
-
-  <!-- This defines the specific key patterns that will be caught in the SpecialCharSequenceMgr
-       such as, ##[0-9]{3,7}# -->
-  <string-array name="motorola_hidden_menu_key_pattern">
-    <!--##MSL#, here MSL is 6 digits SPC code, ##OTKSL#, OTKSL is also digits code -->
-    <item>##[0-9]{6}#</item>
-  </string-array>
-
-  <!-- This defines the intents that will be send out when the key sequence is matched, this must be
-     in the same order with he KeyPattern array. -->
-  <string-array name="motorola_hidden_menu_key_pattern_intents">
-    <item>@string/motorola_hidden_menu_intent</item>
-  </string-array>
+  <bool name="motorola_hidden_menu_enabled">true</bool>
 </resources>
\ No newline at end of file
diff --git a/java/com/android/dialer/oem/res/values-mcc310-mnc130/motorola_config.xml b/java/com/android/dialer/oem/res/values-mcc310-mnc130/motorola_config.xml
new file mode 100644
index 0000000..935627b
--- /dev/null
+++ b/java/com/android/dialer/oem/res/values-mcc310-mnc130/motorola_config.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 2018 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License
+  -->
+
+<resources>
+  <bool name="motorola_sprint_hd_codec">true</bool>
+  <bool name="motorola_hidden_menu_enabled">true</bool>
+</resources>
\ No newline at end of file
diff --git a/java/com/android/dialer/oem/res/values-mcc310-mnc470/motorola_config.xml b/java/com/android/dialer/oem/res/values-mcc310-mnc470/motorola_config.xml
new file mode 100644
index 0000000..935627b
--- /dev/null
+++ b/java/com/android/dialer/oem/res/values-mcc310-mnc470/motorola_config.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 2018 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License
+  -->
+
+<resources>
+  <bool name="motorola_sprint_hd_codec">true</bool>
+  <bool name="motorola_hidden_menu_enabled">true</bool>
+</resources>
\ No newline at end of file
diff --git a/java/com/android/dialer/oem/res/values-mcc310-mnc580/motorola_config.xml b/java/com/android/dialer/oem/res/values-mcc310-mnc580/motorola_config.xml
new file mode 100644
index 0000000..935627b
--- /dev/null
+++ b/java/com/android/dialer/oem/res/values-mcc310-mnc580/motorola_config.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 2018 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License
+  -->
+
+<resources>
+  <bool name="motorola_sprint_hd_codec">true</bool>
+  <bool name="motorola_hidden_menu_enabled">true</bool>
+</resources>
\ No newline at end of file
diff --git a/java/com/android/dialer/oem/res/values-mcc311-mnc230/motorola_config.xml b/java/com/android/dialer/oem/res/values-mcc311-mnc230/motorola_config.xml
new file mode 100644
index 0000000..935627b
--- /dev/null
+++ b/java/com/android/dialer/oem/res/values-mcc311-mnc230/motorola_config.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 2018 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License
+  -->
+
+<resources>
+  <bool name="motorola_sprint_hd_codec">true</bool>
+  <bool name="motorola_hidden_menu_enabled">true</bool>
+</resources>
\ No newline at end of file
diff --git a/java/com/android/dialer/oem/res/values-mcc311-mnc450/motorola_config.xml b/java/com/android/dialer/oem/res/values-mcc311-mnc450/motorola_config.xml
new file mode 100644
index 0000000..935627b
--- /dev/null
+++ b/java/com/android/dialer/oem/res/values-mcc311-mnc450/motorola_config.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 2018 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License
+  -->
+
+<resources>
+  <bool name="motorola_sprint_hd_codec">true</bool>
+  <bool name="motorola_hidden_menu_enabled">true</bool>
+</resources>
\ No newline at end of file
diff --git a/java/com/android/dialer/oem/res/values-mcc311-mnc490/motorola_config.xml b/java/com/android/dialer/oem/res/values-mcc311-mnc490/motorola_config.xml
index c5cb0d1..18c4c3f 100644
--- a/java/com/android/dialer/oem/res/values-mcc311-mnc490/motorola_config.xml
+++ b/java/com/android/dialer/oem/res/values-mcc311-mnc490/motorola_config.xml
@@ -17,4 +17,5 @@
 
 <resources>
   <bool name="motorola_sprint_hd_codec">true</bool>
+  <bool name="motorola_hidden_menu_enabled">true</bool>
 </resources>
\ No newline at end of file
diff --git a/java/com/android/dialer/oem/res/values-mcc311-mnc670/motorola_config.xml b/java/com/android/dialer/oem/res/values-mcc311-mnc670/motorola_config.xml
new file mode 100644
index 0000000..935627b
--- /dev/null
+++ b/java/com/android/dialer/oem/res/values-mcc311-mnc670/motorola_config.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 2018 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License
+  -->
+
+<resources>
+  <bool name="motorola_sprint_hd_codec">true</bool>
+  <bool name="motorola_hidden_menu_enabled">true</bool>
+</resources>
\ No newline at end of file
diff --git a/java/com/android/dialer/oem/res/values-mcc311-mnc870/motorola_config.xml b/java/com/android/dialer/oem/res/values-mcc311-mnc870/motorola_config.xml
index c5cb0d1..18c4c3f 100644
--- a/java/com/android/dialer/oem/res/values-mcc311-mnc870/motorola_config.xml
+++ b/java/com/android/dialer/oem/res/values-mcc311-mnc870/motorola_config.xml
@@ -17,4 +17,5 @@
 
 <resources>
   <bool name="motorola_sprint_hd_codec">true</bool>
+  <bool name="motorola_hidden_menu_enabled">true</bool>
 </resources>
\ No newline at end of file
diff --git a/java/com/android/dialer/oem/res/values-mcc312-mnc420/motorola_config.xml b/java/com/android/dialer/oem/res/values-mcc312-mnc420/motorola_config.xml
new file mode 100644
index 0000000..935627b
--- /dev/null
+++ b/java/com/android/dialer/oem/res/values-mcc312-mnc420/motorola_config.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 2018 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License
+  -->
+
+<resources>
+  <bool name="motorola_sprint_hd_codec">true</bool>
+  <bool name="motorola_hidden_menu_enabled">true</bool>
+</resources>
\ No newline at end of file
diff --git a/java/com/android/dialer/oem/res/values-mcc312-mnc530/motorola_config.xml b/java/com/android/dialer/oem/res/values-mcc312-mnc530/motorola_config.xml
index c5cb0d1..18c4c3f 100644
--- a/java/com/android/dialer/oem/res/values-mcc312-mnc530/motorola_config.xml
+++ b/java/com/android/dialer/oem/res/values-mcc312-mnc530/motorola_config.xml
@@ -17,4 +17,5 @@
 
 <resources>
   <bool name="motorola_sprint_hd_codec">true</bool>
+  <bool name="motorola_hidden_menu_enabled">true</bool>
 </resources>
\ No newline at end of file
diff --git a/java/com/android/dialer/oem/res/values-mcc312-mnc570/motorola_config.xml b/java/com/android/dialer/oem/res/values-mcc312-mnc570/motorola_config.xml
new file mode 100644
index 0000000..935627b
--- /dev/null
+++ b/java/com/android/dialer/oem/res/values-mcc312-mnc570/motorola_config.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 2018 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License
+  -->
+
+<resources>
+  <bool name="motorola_sprint_hd_codec">true</bool>
+  <bool name="motorola_hidden_menu_enabled">true</bool>
+</resources>
\ No newline at end of file
diff --git a/java/com/android/dialer/oem/res/values-mcc312-mnc720/motorola_config.xml b/java/com/android/dialer/oem/res/values-mcc312-mnc720/motorola_config.xml
new file mode 100644
index 0000000..935627b
--- /dev/null
+++ b/java/com/android/dialer/oem/res/values-mcc312-mnc720/motorola_config.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 2018 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License
+  -->
+
+<resources>
+  <bool name="motorola_sprint_hd_codec">true</bool>
+  <bool name="motorola_hidden_menu_enabled">true</bool>
+</resources>
\ No newline at end of file
diff --git a/java/com/android/dialer/oem/res/values-mcc316-mnc010/motorola_config.xml b/java/com/android/dialer/oem/res/values-mcc316-mnc010/motorola_config.xml
index c5cb0d1..18c4c3f 100644
--- a/java/com/android/dialer/oem/res/values-mcc316-mnc010/motorola_config.xml
+++ b/java/com/android/dialer/oem/res/values-mcc316-mnc010/motorola_config.xml
@@ -17,4 +17,5 @@
 
 <resources>
   <bool name="motorola_sprint_hd_codec">true</bool>
+  <bool name="motorola_hidden_menu_enabled">true</bool>
 </resources>
\ No newline at end of file
diff --git a/java/com/android/dialer/oem/res/values/motorola_config.xml b/java/com/android/dialer/oem/res/values/motorola_config.xml
index 614514e..47f9287 100644
--- a/java/com/android/dialer/oem/res/values/motorola_config.xml
+++ b/java/com/android/dialer/oem/res/values/motorola_config.xml
@@ -20,26 +20,61 @@
   <bool name="motorola_sprint_hd_codec">false</bool>
 
   <!-- Hidden menu configuration for Motorola. -->
+  <!-- Hidden menu is only enabled for sprint-->
+  <bool name="motorola_hidden_menu_enabled">false</bool>
   <!-- This defines the specific key sequence that will be caught in the SpecialCharSequenceMgr
        such as, ##OMADM# -->
   <string-array name="motorola_hidden_menu_key_sequence">
+    <item>##66236#</item>   <!--##OMADM#-->
+    <item>##2539#</item>    <!--##AKEY#-->
+    <item>##786#</item>     <!--##RTN#-->
+    <item>##72786#</item>   <!--##SCRTN#-->
+    <item>##3282#</item>    <!--##DATA#-->
+    <item>##33284#</item>   <!--##DEBUG#-->
+    <item>##3424#</item>    <!--##DIAG#-->
+    <item>##564#</item>     <!--##LOG#-->
+    <item>##4567257#</item> <!--##GLMSCLR#-->
+    <item>##873283#</item>  <!--##UPDATE#-->
+    <item>##6343#</item>    <!--##MEID#-->
+    <item>##27263#</item>   <!--##BRAND#-->
+    <item>##258#</item>     <!--##BLV#-->
+    <item>##8422#</item>    <!--##UICC#-->
+    <item>##4382#</item>    <!--CMAS/WEA-->
   </string-array>
 
-  <string name="motorola_hidden_menu_intent"></string>
+  <string name="motorola_hidden_menu_intent">com.motorola.intent.action.LAUNCH_HIDDEN_MENU</string>
 
   <!-- This defines the intents that will be send out when the key sequence is matched, this must be
        in the same order with he KeySequence array. -->
   <string-array name="motorola_hidden_menu_key_sequence_intents">
+    <item>@string/motorola_hidden_menu_intent</item>
+    <item>@string/motorola_hidden_menu_intent</item>
+    <item>@string/motorola_hidden_menu_intent</item>
+    <item>@string/motorola_hidden_menu_intent</item>
+    <item>@string/motorola_hidden_menu_intent</item>
+    <item>@string/motorola_hidden_menu_intent</item>
+    <item>@string/motorola_hidden_menu_intent</item>
+    <item>@string/motorola_hidden_menu_intent</item>
+    <item>@string/motorola_hidden_menu_intent</item>
+    <item>com.motorola.android.intent.action.omadm.sprint.hfa</item>
+    <item>@string/motorola_hidden_menu_intent</item>
+    <item>@string/motorola_hidden_menu_intent</item>
+    <item>@string/motorola_hidden_menu_intent</item>
+    <item>@string/motorola_hidden_menu_intent</item>
+    <item>@string/motorola_hidden_menu_intent</item>
   </string-array>
 
   <!-- This defines the specific key patterns that will be caught in the SpecialCharSequenceMgr
        such as, ##[0-9]{3,7}# -->
   <string-array name="motorola_hidden_menu_key_pattern">
+    <!--##MSL#, here MSL is 6 digits SPC code, ##OTKSL#, OTKSL is also digits code -->
+    <item>##[0-9]{6}#</item>
   </string-array>
 
   <!-- This defines the intents that will be send out when the key sequence is matched, this must be
-       in the same order with he KeyPattern array. -->
+     in the same order with he KeyPattern array. -->
   <string-array name="motorola_hidden_menu_key_pattern_intents">
+    <item>@string/motorola_hidden_menu_intent</item>
   </string-array>
 
   <!-- This defines the provider names for cequint callerid applications
diff --git a/java/com/android/dialer/phonelookup/cp2/Cp2ExtendedDirectoryPhoneLookup.java b/java/com/android/dialer/phonelookup/cp2/Cp2ExtendedDirectoryPhoneLookup.java
index e497989..2b98f26 100644
--- a/java/com/android/dialer/phonelookup/cp2/Cp2ExtendedDirectoryPhoneLookup.java
+++ b/java/com/android/dialer/phonelookup/cp2/Cp2ExtendedDirectoryPhoneLookup.java
@@ -19,15 +19,13 @@
 import android.content.Context;
 import android.database.Cursor;
 import android.net.Uri;
-import android.os.Build.VERSION;
-import android.os.Build.VERSION_CODES;
 import android.provider.ContactsContract;
+import android.provider.ContactsContract.Directory;
 import android.support.annotation.VisibleForTesting;
 import com.android.dialer.DialerPhoneNumber;
 import com.android.dialer.common.LogUtil;
 import com.android.dialer.common.concurrent.Annotations.BackgroundExecutor;
 import com.android.dialer.common.concurrent.Annotations.LightweightExecutor;
-import com.android.dialer.common.cp2.DirectoryCompat;
 import com.android.dialer.inject.ApplicationContext;
 import com.android.dialer.phonelookup.PhoneLookup;
 import com.android.dialer.phonelookup.PhoneLookupInfo;
@@ -80,7 +78,7 @@
               appContext
                   .getContentResolver()
                   .query(
-                      DirectoryCompat.getContentUri(),
+                      Directory.ENTERPRISE_CONTENT_URI,
                       /* projection = */ new String[] {ContactsContract.Directory._ID},
                       /* selection = */ null,
                       /* selectionArgs = */ null,
@@ -178,13 +176,8 @@
 
   @VisibleForTesting
   static Uri getContentUriForContacts(String number, long directoryId) {
-    Uri baseUri =
-        VERSION.SDK_INT >= VERSION_CODES.N
-            ? ContactsContract.PhoneLookup.ENTERPRISE_CONTENT_FILTER_URI
-            : ContactsContract.PhoneLookup.CONTENT_FILTER_URI;
-
     Uri.Builder builder =
-        baseUri
+        ContactsContract.PhoneLookup.ENTERPRISE_CONTENT_FILTER_URI
             .buildUpon()
             .appendPath(number)
             .appendQueryParameter(
@@ -197,8 +190,8 @@
   }
 
   private static boolean isExtendedDirectory(long directoryId) {
-    return DirectoryCompat.isRemoteDirectoryId(directoryId)
-        || DirectoryCompat.isEnterpriseDirectoryId(directoryId);
+    return Directory.isRemoteDirectoryId(directoryId)
+        || Directory.isEnterpriseDirectoryId(directoryId);
   }
 
   @Override
diff --git a/java/com/android/dialer/phonenumbercache/CallLogQuery.java b/java/com/android/dialer/phonenumbercache/CallLogQuery.java
index 2ebc302..488aa26 100644
--- a/java/com/android/dialer/phonenumbercache/CallLogQuery.java
+++ b/java/com/android/dialer/phonenumbercache/CallLogQuery.java
@@ -63,7 +63,7 @@
   @RequiresApi(VERSION_CODES.O)
   public static final int TRANSCRIPTION_STATE = 26;
 
-  private static final String[] PROJECTION_M =
+  private static final String[] PROJECTION_N =
       new String[] {
         Calls._ID, // 0
         Calls.NUMBER, // 1
@@ -89,17 +89,10 @@
         Calls.DATA_USAGE, // 21
         Calls.TRANSCRIPTION, // 22
         Calls.CACHED_PHOTO_URI, // 23
+        CallLog.Calls.POST_DIAL_DIGITS, // 24
+        CallLog.Calls.VIA_NUMBER // 25
       };
 
-  private static final String[] PROJECTION_N;
-
-  static {
-    List<String> projectionList = new ArrayList<>(Arrays.asList(PROJECTION_M));
-    projectionList.add(CallLog.Calls.POST_DIAL_DIGITS);
-    projectionList.add(CallLog.Calls.VIA_NUMBER);
-    PROJECTION_N = projectionList.toArray(new String[projectionList.size()]);
-  }
-
   private static final String[] PROJECTION_O;
 
   // TODO(mdooley): remove when this becomes a public api
@@ -114,12 +107,6 @@
 
   @NonNull
   public static String[] getProjection() {
-    if (VERSION.SDK_INT >= VERSION_CODES.O) {
-      return PROJECTION_O;
-    }
-    if (VERSION.SDK_INT >= VERSION_CODES.N) {
-      return PROJECTION_N;
-    }
-    return PROJECTION_M;
+    return VERSION.SDK_INT >= VERSION_CODES.O ? PROJECTION_O : PROJECTION_N;
   }
 }
diff --git a/java/com/android/dialer/phonenumbercache/ContactInfoHelper.java b/java/com/android/dialer/phonenumbercache/ContactInfoHelper.java
index d6e378c..777175e 100644
--- a/java/com/android/dialer/phonenumbercache/ContactInfoHelper.java
+++ b/java/com/android/dialer/phonenumbercache/ContactInfoHelper.java
@@ -35,7 +35,6 @@
 import com.android.contacts.common.util.Constants;
 import com.android.dialer.common.Assert;
 import com.android.dialer.common.LogUtil;
-import com.android.dialer.common.cp2.DirectoryCompat;
 import com.android.dialer.logging.ContactSource;
 import com.android.dialer.oem.CequintCallerIdManager;
 import com.android.dialer.oem.CequintCallerIdManager.CequintCallerIdContact;
@@ -107,12 +106,12 @@
 
     if (directoryId != null) {
       // Query {@link Contacts#CONTENT_LOOKUP_URI} with work lookup key is not allowed.
-      if (DirectoryCompat.isEnterpriseDirectoryId(directoryId)) {
+      if (Directory.isEnterpriseDirectoryId(directoryId)) {
         return null;
       }
 
       // Skip this to avoid an extra remote network call for alternative name
-      if (DirectoryCompat.isRemoteDirectoryId(directoryId)) {
+      if (Directory.isRemoteDirectoryId(directoryId)) {
         return null;
       }
     }
@@ -289,7 +288,7 @@
     try {
       while (cursor.moveToNext()) {
         long directoryId = cursor.getLong(idIndex);
-        if (DirectoryCompat.isRemoteDirectoryId(directoryId)) {
+        if (Directory.isRemoteDirectoryId(directoryId)) {
           remoteDirectories.add(directoryId);
         }
       }
@@ -323,7 +322,7 @@
             .getContentResolver()
             .query(
                 uri,
-                PhoneQuery.getPhoneLookupProjection(uri),
+                PhoneQuery.getPhoneLookupProjection(),
                 null /* selection */,
                 null /* selectionArgs */,
                 null /* sortOrder */)) {
diff --git a/java/com/android/dialer/phonenumbercache/PhoneLookupUtil.java b/java/com/android/dialer/phonenumbercache/PhoneLookupUtil.java
deleted file mode 100644
index 74175e8..0000000
--- a/java/com/android/dialer/phonenumbercache/PhoneLookupUtil.java
+++ /dev/null
@@ -1,40 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License
- */
-
-package com.android.dialer.phonenumbercache;
-
-import android.net.Uri;
-import android.os.Build.VERSION;
-import android.os.Build.VERSION_CODES;
-import android.provider.ContactsContract;
-import android.provider.ContactsContract.PhoneLookup;
-
-public final class PhoneLookupUtil {
-
-  private PhoneLookupUtil() {}
-
-  /** @return the column name that stores contact id for phone lookup query. */
-  public static String getContactIdColumnNameForUri(Uri phoneLookupUri) {
-    if (VERSION.SDK_INT >= VERSION_CODES.N) {
-      return PhoneLookup.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) ? PhoneLookup.CONTACT_ID : ContactsContract.PhoneLookup._ID;
-  }
-}
diff --git a/java/com/android/dialer/phonenumbercache/PhoneQuery.java b/java/com/android/dialer/phonenumbercache/PhoneQuery.java
index 5ddd5f8..a43e489 100644
--- a/java/com/android/dialer/phonenumbercache/PhoneQuery.java
+++ b/java/com/android/dialer/phonenumbercache/PhoneQuery.java
@@ -16,10 +16,6 @@
 
 package com.android.dialer.phonenumbercache;
 
-import android.net.Uri;
-import android.os.Build.VERSION;
-import android.os.Build.VERSION_CODES;
-import android.provider.ContactsContract;
 import android.provider.ContactsContract.CommonDataKinds.Phone;
 import android.provider.ContactsContract.Contacts;
 import android.provider.ContactsContract.PhoneLookup;
@@ -27,27 +23,27 @@
 /** The queries to look up the {@link ContactInfo} for a given number in the Call Log. */
 final class PhoneQuery {
 
-  public static final int PERSON_ID = 0;
-  public static final int NAME = 1;
-  public static final int PHONE_TYPE = 2;
-  public static final int LABEL = 3;
-  public static final int MATCHED_NUMBER = 4;
-  public static final int NORMALIZED_NUMBER = 5;
-  public static final int PHOTO_ID = 6;
-  public static final int LOOKUP_KEY = 7;
-  public static final int PHOTO_URI = 8;
+  static final int PERSON_ID = 0;
+  static final int NAME = 1;
+  static final int PHONE_TYPE = 2;
+  static final int LABEL = 3;
+  static final int MATCHED_NUMBER = 4;
+  static final int NORMALIZED_NUMBER = 5;
+  static final int PHOTO_ID = 6;
+  static final int LOOKUP_KEY = 7;
+  static final int PHOTO_URI = 8;
   /** Projection to look up a contact's DISPLAY_NAME_ALTERNATIVE */
-  public static final String[] DISPLAY_NAME_ALTERNATIVE_PROJECTION =
+  static final String[] DISPLAY_NAME_ALTERNATIVE_PROJECTION =
       new String[] {
         Contacts.DISPLAY_NAME_ALTERNATIVE,
       };
 
-  public static final int NAME_ALTERNATIVE = 0;
+  static final int NAME_ALTERNATIVE = 0;
 
-  public static final String[] ADDITIONAL_CONTACT_INFO_PROJECTION =
+  static final String[] ADDITIONAL_CONTACT_INFO_PROJECTION =
       new String[] {Phone.DISPLAY_NAME_ALTERNATIVE, Phone.CARRIER_PRESENCE};
-  public static final int ADDITIONAL_CONTACT_INFO_DISPLAY_NAME_ALTERNATIVE = 0;
-  public static final int ADDITIONAL_CONTACT_INFO_CARRIER_PRESENCE = 1;
+  static final int ADDITIONAL_CONTACT_INFO_DISPLAY_NAME_ALTERNATIVE = 0;
+  static final int ADDITIONAL_CONTACT_INFO_CARRIER_PRESENCE = 1;
 
   /**
    * Projection to look up the ContactInfo. Does not include DISPLAY_NAME_ALTERNATIVE as that column
@@ -66,31 +62,8 @@
         PhoneLookup.LOOKUP_KEY,
         PhoneLookup.PHOTO_URI
       };
-  /**
-   * Similar to {@link PHONE_LOOKUP_PROJECTION}. In pre-N, contact id is stored in {@link
-   * PhoneLookup#_ID} in non-sip query.
-   */
-  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 (VERSION.SDK_INT >= VERSION_CODES.N) {
+  static String[] getPhoneLookupProjection() {
       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;
   }
 }
diff --git a/java/com/android/dialer/searchfragment/directories/DirectoriesCursorLoader.java b/java/com/android/dialer/searchfragment/directories/DirectoriesCursorLoader.java
index 4d7ea3f..754e055 100644
--- a/java/com/android/dialer/searchfragment/directories/DirectoriesCursorLoader.java
+++ b/java/com/android/dialer/searchfragment/directories/DirectoriesCursorLoader.java
@@ -20,9 +20,6 @@
 import android.content.Context;
 import android.content.CursorLoader;
 import android.database.Cursor;
-import android.net.Uri;
-import android.os.Build.VERSION;
-import android.os.Build.VERSION_CODES;
 import android.provider.ContactsContract;
 import android.support.annotation.Nullable;
 import com.android.dialer.common.LogUtil;
@@ -51,7 +48,13 @@
   private static final int PHOTO_SUPPORT = 2;
 
   public DirectoriesCursorLoader(Context context) {
-    super(context, getContentUri(), PROJECTION, null, null, ContactsContract.Directory._ID);
+    super(
+        context,
+        ContactsContract.Directory.ENTERPRISE_CONTENT_URI,
+        PROJECTION,
+        null,
+        null,
+        ContactsContract.Directory._ID);
   }
 
   @Override
@@ -88,12 +91,6 @@
     return directories;
   }
 
-  private static Uri getContentUri() {
-    return VERSION.SDK_INT >= VERSION_CODES.N
-        ? ContactsContract.Directory.ENTERPRISE_CONTENT_URI
-        : ContactsContract.Directory.CONTENT_URI;
-  }
-
   /** POJO representing the results returned from {@link DirectoriesCursorLoader}. */
   @AutoValue
   public abstract static class Directory {
diff --git a/java/com/android/dialer/searchfragment/directories/DirectoryContactViewHolder.java b/java/com/android/dialer/searchfragment/directories/DirectoryContactViewHolder.java
index fbb662c..29127ff 100644
--- a/java/com/android/dialer/searchfragment/directories/DirectoryContactViewHolder.java
+++ b/java/com/android/dialer/searchfragment/directories/DirectoryContactViewHolder.java
@@ -29,7 +29,7 @@
 import android.widget.ImageView;
 import android.widget.QuickContactBadge;
 import android.widget.TextView;
-import com.android.dialer.common.cp2.DirectoryCompat;
+import com.android.dialer.common.cp2.DirectoryUtils;
 import com.android.dialer.contactphoto.ContactPhotoManager;
 import com.android.dialer.lettertile.LetterTileDrawable;
 import com.android.dialer.searchfragment.common.Projections;
@@ -80,7 +80,7 @@
     nameView.setText(QueryBoldingUtil.getNameWithQueryBolded(query, name, context));
     numberView.setText(QueryBoldingUtil.getNameWithQueryBolded(query, secondaryInfo, context));
     workBadge.setVisibility(
-        DirectoryCompat.isOnlyEnterpriseDirectoryId(cursor.getDirectoryId())
+        DirectoryUtils.isLocalEnterpriseDirectoryId(cursor.getDirectoryId())
             ? View.VISIBLE
             : View.GONE);
 
diff --git a/java/com/android/dialer/searchfragment/directories/DirectoryContactsCursor.java b/java/com/android/dialer/searchfragment/directories/DirectoryContactsCursor.java
index 0c1ad83..b081de0 100644
--- a/java/com/android/dialer/searchfragment/directories/DirectoryContactsCursor.java
+++ b/java/com/android/dialer/searchfragment/directories/DirectoryContactsCursor.java
@@ -23,7 +23,7 @@
 import android.support.annotation.Nullable;
 import android.support.annotation.VisibleForTesting;
 import com.android.dialer.common.Assert;
-import com.android.dialer.common.cp2.DirectoryCompat;
+import com.android.dialer.common.cp2.DirectoryUtils;
 import com.android.dialer.searchfragment.common.SearchCursor;
 import com.android.dialer.searchfragment.directories.DirectoriesCursorLoader.Directory;
 import java.util.ArrayList;
@@ -101,7 +101,7 @@
 
   private static MatrixCursor createHeaderCursor(Context context, String name, long id) {
     MatrixCursor headerCursor = new MatrixCursor(PROJECTION, 1);
-    if (DirectoryCompat.isOnlyEnterpriseDirectoryId(id)) {
+    if (DirectoryUtils.isLocalEnterpriseDirectoryId(id)) {
       headerCursor.addRow(
           new Object[] {context.getString(R.string.directory_search_label_work), id});
     } else {
diff --git a/java/com/android/dialer/searchfragment/directories/DirectoryContactsCursorLoader.java b/java/com/android/dialer/searchfragment/directories/DirectoryContactsCursorLoader.java
index d719cb9..bf56a1c 100644
--- a/java/com/android/dialer/searchfragment/directories/DirectoryContactsCursorLoader.java
+++ b/java/com/android/dialer/searchfragment/directories/DirectoryContactsCursorLoader.java
@@ -21,13 +21,11 @@
 import android.database.Cursor;
 import android.database.MatrixCursor;
 import android.net.Uri;
-import android.os.Build.VERSION;
-import android.os.Build.VERSION_CODES;
 import android.provider.ContactsContract;
 import android.provider.ContactsContract.CommonDataKinds.Phone;
 import android.support.annotation.NonNull;
 import android.support.annotation.VisibleForTesting;
-import com.android.dialer.common.cp2.DirectoryCompat;
+import com.android.dialer.common.cp2.DirectoryUtils;
 import com.android.dialer.searchfragment.common.Projections;
 import com.android.dialer.searchfragment.directories.DirectoriesCursorLoader.Directory;
 import java.util.ArrayList;
@@ -71,14 +69,14 @@
     for (int i = 0; i < directories.size(); i++) {
       Directory directory = directories.get(i);
 
-      if (!DirectoryCompat.isRemoteDirectoryId(directory.getId())
-          && !DirectoryCompat.isEnterpriseDirectoryId(directory.getId())) {
+      if (!ContactsContract.Directory.isRemoteDirectoryId(directory.getId())
+          && !ContactsContract.Directory.isEnterpriseDirectoryId(directory.getId())) {
         cursors[i] = null;
         continue;
       }
 
       // Filter out invisible directories.
-      if (DirectoryCompat.isInvisibleDirectory(directory.getId())) {
+      if (DirectoryUtils.isInvisibleDirectoryId(directory.getId())) {
         cursors[i] = null;
         continue;
       }
@@ -145,12 +143,7 @@
 
   @VisibleForTesting
   static Uri getContentFilterUri(String query, long directoryId) {
-    Uri baseUri =
-        VERSION.SDK_INT >= VERSION_CODES.N
-            ? ENTERPRISE_CONTENT_FILTER_URI
-            : Phone.CONTENT_FILTER_URI;
-
-    return baseUri
+    return ENTERPRISE_CONTENT_FILTER_URI
         .buildUpon()
         .appendPath(query)
         .appendQueryParameter(ContactsContract.DIRECTORY_PARAM_KEY, String.valueOf(directoryId))
diff --git a/java/com/android/dialer/spam/Spam.java b/java/com/android/dialer/spam/Spam.java
index 09b7ce9..c22f541 100644
--- a/java/com/android/dialer/spam/Spam.java
+++ b/java/com/android/dialer/spam/Spam.java
@@ -16,8 +16,6 @@
 
 package com.android.dialer.spam;
 
-import android.content.Context;
-import android.content.Intent;
 import android.support.annotation.NonNull;
 import android.support.annotation.Nullable;
 import com.android.dialer.DialerPhoneNumber;
@@ -31,23 +29,6 @@
 /** Allows the container application to mark calls as spam. */
 public interface Spam {
 
-  boolean isSpamEnabled();
-
-  boolean isSpamNotificationEnabled();
-
-  boolean isSpamBlockingAvailable();
-
-  boolean isSpamBlockingEnabled();
-
-  boolean isDialogEnabledForSpamNotification();
-
-  boolean isDialogReportSpamCheckedByDefault();
-
-  /** @return what percentage of aftercall notifications to show to the user */
-  int percentOfSpamNotificationsToShow();
-
-  int percentOfNonSpamNotificationsToShow();
-
   /**
    * Checks if each of numbers in the given list is suspected of being a spam.
    *
@@ -184,28 +165,10 @@
       ReportingLocation.Type from,
       ContactSource.Type contactSourceType);
 
-  /**
-   * Modifies spam blocking setting.
-   *
-   * @param enabled Whether to enable or disable the setting.
-   * @param listener The callback to be invoked after setting change is done.
-   */
-  void modifySpamBlockingSetting(boolean enabled, ModifySettingListener listener);
-
-  /** Returns an intent to start spam blocking setting */
-  Intent getSpamBlockingSettingIntent(Context context);
-
   /** Callback to be invoked when data is fetched. */
   interface Listener {
 
     /** Called when data is fetched. */
     void onComplete(boolean isSpam);
   }
-
-  /** Callback to be invoked when setting change completes. */
-  interface ModifySettingListener {
-
-    /** Called when setting change completes. */
-    void onComplete(boolean success);
-  }
 }
diff --git a/java/com/android/dialer/spam/SpamComponent.java b/java/com/android/dialer/spam/SpamComponent.java
index 0bcdafa..2b70b6f 100644
--- a/java/com/android/dialer/spam/SpamComponent.java
+++ b/java/com/android/dialer/spam/SpamComponent.java
@@ -26,6 +26,8 @@
 
   public abstract Spam spam();
 
+  public abstract SpamSettings spamSettings();
+
   public static SpamComponent get(Context context) {
     return ((SpamComponent.HasComponent)
             ((HasRootComponent) context.getApplicationContext()).component())
diff --git a/java/com/android/dialer/spam/SpamSettings.java b/java/com/android/dialer/spam/SpamSettings.java
new file mode 100644
index 0000000..e0c0682
--- /dev/null
+++ b/java/com/android/dialer/spam/SpamSettings.java
@@ -0,0 +1,72 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dialer.spam;
+
+import android.content.Context;
+import android.content.Intent;
+
+/** Allows the container application to interact with spam settings. */
+public interface SpamSettings {
+
+  /** @return if spam module is enabled */
+  boolean isSpamEnabled();
+
+  /** @return if spam after call notification is enabled */
+  boolean isSpamNotificationEnabled();
+
+  /** @return if spam blocking is enabled */
+  boolean isSpamBlockingEnabled();
+
+  /** @return if spam blocking user setting is controlled by carrier */
+  boolean isSpamBlockingControlledByCarrier();
+
+  /** @return if spam blocking module is enabled by flag */
+  boolean isSpamBlockingEnabledByFlag();
+
+  /** @return if spam blocking setting is enabled by user */
+  boolean isSpamBlockingEnabledByUser();
+
+  /** @return if dialog is used by default for spam after call notification */
+  boolean isDialogEnabledForSpamNotification();
+
+  /** @return if report spam is checked by default in block/report dialog */
+  boolean isDialogReportSpamCheckedByDefault();
+
+  /** @return percentage of after call notifications for spam numbers to show to the user */
+  int percentOfSpamNotificationsToShow();
+
+  /** @return percentage of after call notifications for nonspam numbers to show to the user */
+  int percentOfNonSpamNotificationsToShow();
+
+  /**
+   * Modifies spam blocking setting.
+   *
+   * @param enabled Whether to enable or disable the setting.
+   * @param listener The callback to be invoked after setting change is done.
+   */
+  void modifySpamBlockingSetting(boolean enabled, ModifySettingListener listener);
+
+  /** @return an intent to start spam blocking setting */
+  Intent getSpamBlockingSettingIntent(Context context);
+
+  /** Callback to be invoked when setting change completes. */
+  interface ModifySettingListener {
+
+    /** Called when setting change completes. */
+    void onComplete(boolean success);
+  }
+}
diff --git a/java/com/android/dialer/spam/SpamSettingsStub.java b/java/com/android/dialer/spam/SpamSettingsStub.java
new file mode 100644
index 0000000..905daa4
--- /dev/null
+++ b/java/com/android/dialer/spam/SpamSettingsStub.java
@@ -0,0 +1,88 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dialer.spam;
+
+import android.content.Context;
+import android.content.Intent;
+import javax.inject.Inject;
+
+/** Default implementation of SpamSettings. */
+public class SpamSettingsStub implements SpamSettings {
+
+  @Inject
+  public SpamSettingsStub() {}
+
+  @Override
+  public boolean isSpamEnabled() {
+    return false;
+  }
+
+  @Override
+  public boolean isSpamNotificationEnabled() {
+    return false;
+  }
+
+  @Override
+  public boolean isSpamBlockingEnabledByFlag() {
+    return false;
+  }
+
+  @Override
+  public boolean isSpamBlockingControlledByCarrier() {
+    return false;
+  }
+
+  @Override
+  public boolean isSpamBlockingEnabled() {
+    return false;
+  }
+
+  @Override
+  public boolean isSpamBlockingEnabledByUser() {
+    return false;
+  }
+
+  @Override
+  public boolean isDialogEnabledForSpamNotification() {
+    return false;
+  }
+
+  @Override
+  public boolean isDialogReportSpamCheckedByDefault() {
+    return false;
+  }
+
+  @Override
+  public int percentOfSpamNotificationsToShow() {
+    return 0;
+  }
+
+  @Override
+  public int percentOfNonSpamNotificationsToShow() {
+    return 0;
+  }
+
+  @Override
+  public void modifySpamBlockingSetting(boolean enabled, ModifySettingListener listener) {
+    listener.onComplete(false);
+  }
+
+  @Override
+  public Intent getSpamBlockingSettingIntent(Context context) {
+    return new Intent();
+  }
+}
diff --git a/java/com/android/dialer/spam/SpamStub.java b/java/com/android/dialer/spam/SpamStub.java
index 39b05fc..28f26d1 100644
--- a/java/com/android/dialer/spam/SpamStub.java
+++ b/java/com/android/dialer/spam/SpamStub.java
@@ -16,8 +16,6 @@
 
 package com.android.dialer.spam;
 
-import android.content.Context;
-import android.content.Intent;
 import com.android.dialer.DialerPhoneNumber;
 import com.android.dialer.common.concurrent.Annotations.BackgroundExecutor;
 import com.android.dialer.logging.ContactLookupResult;
@@ -42,46 +40,6 @@
   }
 
   @Override
-  public boolean isSpamEnabled() {
-    return false;
-  }
-
-  @Override
-  public boolean isSpamNotificationEnabled() {
-    return false;
-  }
-
-  @Override
-  public boolean isSpamBlockingAvailable() {
-    return false;
-  }
-
-  @Override
-  public boolean isSpamBlockingEnabled() {
-    return false;
-  }
-
-  @Override
-  public boolean isDialogEnabledForSpamNotification() {
-    return false;
-  }
-
-  @Override
-  public boolean isDialogReportSpamCheckedByDefault() {
-    return false;
-  }
-
-  @Override
-  public int percentOfSpamNotificationsToShow() {
-    return 0;
-  }
-
-  @Override
-  public int percentOfNonSpamNotificationsToShow() {
-    return 0;
-  }
-
-  @Override
   public ListenableFuture<ImmutableMap<DialerPhoneNumber, SpamStatus>> batchCheckSpamStatus(
       ImmutableSet<DialerPhoneNumber> dialerPhoneNumbers) {
     return backgroundExecutorService.submit(
@@ -168,14 +126,4 @@
       int callType,
       ReportingLocation.Type from,
       ContactSource.Type contactSourceType) {}
-
-  @Override
-  public void modifySpamBlockingSetting(boolean enabled, ModifySettingListener listener) {
-    listener.onComplete(false);
-  }
-
-  @Override
-  public Intent getSpamBlockingSettingIntent(Context context) {
-    return new Intent();
-  }
 }
diff --git a/java/com/android/dialer/spam/StubSpamModule.java b/java/com/android/dialer/spam/StubSpamModule.java
index 0d3b917..5540408 100644
--- a/java/com/android/dialer/spam/StubSpamModule.java
+++ b/java/com/android/dialer/spam/StubSpamModule.java
@@ -25,4 +25,7 @@
 
   @Binds
   public abstract Spam bindSpam(SpamStub stub);
+
+  @Binds
+  public abstract SpamSettings bindSpamSettings(SpamSettingsStub stub);
 }
diff --git a/java/com/android/dialer/spam/promo/SpamBlockingPromoHelper.java b/java/com/android/dialer/spam/promo/SpamBlockingPromoHelper.java
index 9349577..cba94e0 100644
--- a/java/com/android/dialer/spam/promo/SpamBlockingPromoHelper.java
+++ b/java/com/android/dialer/spam/promo/SpamBlockingPromoHelper.java
@@ -25,7 +25,7 @@
 import com.android.dialer.configprovider.ConfigProviderBindings;
 import com.android.dialer.logging.DialerImpression;
 import com.android.dialer.logging.Logger;
-import com.android.dialer.spam.Spam;
+import com.android.dialer.spam.SpamSettings;
 
 /** Helper class for showing spam blocking on-boarding promotions. */
 public class SpamBlockingPromoHelper {
@@ -34,11 +34,11 @@
   static final String SPAM_BLOCKING_PROMO_LAST_SHOW_MILLIS = "spam_blocking_promo_last_show_millis";
 
   private final Context context;
-  private final Spam spam;
+  private final SpamSettings spamSettings;
 
-  public SpamBlockingPromoHelper(Context context, Spam spam) {
+  public SpamBlockingPromoHelper(Context context, SpamSettings spamSettings) {
     this.context = context;
-    this.spam = spam;
+    this.spamSettings = spamSettings;
   }
 
   /** Shows a spam blocking promo dialog with on complete snackbar if all the prerequisites meet. */
@@ -54,7 +54,7 @@
               Logger.get(context)
                   .logImpression(
                       DialerImpression.Type.SPAM_BLOCKING_ENABLED_THROUGH_CALL_LOG_PROMO);
-              spam.modifySpamBlockingSetting(
+              spamSettings.modifySpamBlockingSetting(
                   true, success -> showModifySettingOnCompleteSnackbar(view, success));
             })
         .show(fragmentManager, SpamBlockingPromoDialogFragment.SPAM_BLOCKING_PROMO_DIALOG_TAG);
@@ -71,7 +71,9 @@
    */
   @VisibleForTesting
   boolean shouldShowSpamBlockingPromo() {
-    if (!spam.isSpamEnabled() || !spam.isSpamBlockingAvailable() || spam.isSpamBlockingEnabled()) {
+    if (!spamSettings.isSpamEnabled()
+        || !spamSettings.isSpamBlockingEnabledByFlag()
+        || spamSettings.isSpamBlockingEnabledByUser()) {
       return false;
     }
 
@@ -109,7 +111,7 @@
     Snackbar.make(view, snackBarText, Snackbar.LENGTH_LONG)
         .setAction(
             R.string.spam_blocking_setting_prompt,
-            v -> context.startActivity(spam.getSpamBlockingSettingIntent(context)))
+            v -> context.startActivity(spamSettings.getSpamBlockingSettingIntent(context)))
         .setActionTextColor(
             context.getResources().getColor(R.color.dialer_snackbar_action_text_color))
         .show();
diff --git a/java/com/android/dialer/strictmode/impl/SystemDialerStrictMode.java b/java/com/android/dialer/strictmode/impl/SystemDialerStrictMode.java
index 09fdf5c..f3ce70c 100644
--- a/java/com/android/dialer/strictmode/impl/SystemDialerStrictMode.java
+++ b/java/com/android/dialer/strictmode/impl/SystemDialerStrictMode.java
@@ -18,6 +18,7 @@
 
 import android.app.Application;
 import android.os.Build;
+import android.os.Build.VERSION_CODES;
 import android.os.Handler;
 import android.os.Looper;
 import android.os.StrictMode;
@@ -91,7 +92,7 @@
         new StrictMode.VmPolicy.Builder(vmPenalties)
             .detectLeakedClosableObjects()
             .detectLeakedSqlLiteObjects();
-    if (Build.VERSION.SDK_INT >= 26) {
+    if (Build.VERSION.SDK_INT >= VERSION_CODES.O) {
       vmPolicyBuilder.detectContentUriWithoutPermission();
       // TODO(azlatin): Enable detecting untagged sockets once: a bug is fixed.
       // vmPolicyBuilder.detectUntaggedSockets();
diff --git a/java/com/android/dialer/util/DialerUtils.java b/java/com/android/dialer/util/DialerUtils.java
index 7f7b9da..49a0733 100644
--- a/java/com/android/dialer/util/DialerUtils.java
+++ b/java/com/android/dialer/util/DialerUtils.java
@@ -15,6 +15,7 @@
  */
 package com.android.dialer.util;
 
+import android.annotation.SuppressLint;
 import android.app.AlertDialog;
 import android.content.ActivityNotFoundException;
 import android.content.Context;
@@ -22,8 +23,6 @@
 import android.content.DialogInterface.OnClickListener;
 import android.content.Intent;
 import android.graphics.Point;
-import android.os.Build.VERSION;
-import android.os.Build.VERSION_CODES;
 import android.os.Bundle;
 import android.telecom.TelecomManager;
 import android.telephony.TelephonyManager;
@@ -131,12 +130,12 @@
    * currently active call over LTE. Regardless of the country or carrier, the radio will drop an
    * active LTE call if a WPS number is dialed, so this warning is necessary.
    */
+  @SuppressLint("MissingPermission")
   private static boolean shouldWarnForOutgoingWps(Context context, String number) {
     if (number != null && number.startsWith(WPS_PREFIX)) {
       TelephonyManager telephonyManager = context.getSystemService(TelephonyManager.class);
       boolean isOnVolte =
-          VERSION.SDK_INT >= VERSION_CODES.N
-              && telephonyManager.getVoiceNetworkType() == TelephonyManager.NETWORK_TYPE_LTE;
+          telephonyManager.getVoiceNetworkType() == TelephonyManager.NETWORK_TYPE_LTE;
       boolean hasCurrentActiveCall =
           telephonyManager.getCallState() == TelephonyManager.CALL_STATE_OFFHOOK;
       return isOnVolte && hasCurrentActiveCall;
diff --git a/java/com/android/dialer/voicemail/listui/error/VoicemailStatus.java b/java/com/android/dialer/voicemail/listui/error/VoicemailStatus.java
index 9b7b7fd..4f4dbbb 100644
--- a/java/com/android/dialer/voicemail/listui/error/VoicemailStatus.java
+++ b/java/com/android/dialer/voicemail/listui/error/VoicemailStatus.java
@@ -107,16 +107,10 @@
     }
     isAirplaneMode =
         Settings.System.getInt(context.getContentResolver(), Global.AIRPLANE_MODE_ON, 0) != 0;
-
-    if (VERSION.SDK_INT >= VERSION_CODES.N) {
-      quotaOccupied =
-          getInt(statusCursor, VoicemailStatusQuery.QUOTA_OCCUPIED_INDEX, Status.QUOTA_UNAVAILABLE);
-      quotaTotal =
-          getInt(statusCursor, VoicemailStatusQuery.QUOTA_TOTAL_INDEX, Status.QUOTA_UNAVAILABLE);
-    } else {
-      quotaOccupied = Status.QUOTA_UNAVAILABLE;
-      quotaTotal = Status.QUOTA_UNAVAILABLE;
-    }
+    quotaOccupied =
+        getInt(statusCursor, VoicemailStatusQuery.QUOTA_OCCUPIED_INDEX, Status.QUOTA_UNAVAILABLE);
+    quotaTotal =
+        getInt(statusCursor, VoicemailStatusQuery.QUOTA_TOTAL_INDEX, Status.QUOTA_UNAVAILABLE);
   }
 
   private VoicemailStatus(Builder builder) {
diff --git a/java/com/android/dialer/voicemailstatus/VoicemailStatusQuery.java b/java/com/android/dialer/voicemailstatus/VoicemailStatusQuery.java
index 4a6e9f7..8923f74 100644
--- a/java/com/android/dialer/voicemailstatus/VoicemailStatusQuery.java
+++ b/java/com/android/dialer/voicemailstatus/VoicemailStatusQuery.java
@@ -51,28 +51,24 @@
   @RequiresApi(VERSION_CODES.N_MR1)
   public static final int SOURCE_TYPE_INDEX = 10;
 
-  private static final String[] PROJECTION_M =
+  @RequiresApi(VERSION_CODES.N)
+  private static final String[] PROJECTION_N =
       new String[] {
         Status.SOURCE_PACKAGE, // 0
         Status.SETTINGS_URI, // 1
         Status.VOICEMAIL_ACCESS_URI, // 2
         Status.CONFIGURATION_STATE, // 3
         Status.DATA_CHANNEL_STATE, // 4
-        Status.NOTIFICATION_CHANNEL_STATE // 5
+        Status.NOTIFICATION_CHANNEL_STATE, // 5
+        Status.QUOTA_OCCUPIED, // 6
+        Status.QUOTA_TOTAL // 7
       };
 
-  @RequiresApi(VERSION_CODES.N)
-  private static final String[] PROJECTION_N;
-
   @RequiresApi(VERSION_CODES.N_MR1)
   private static final String[] PROJECTION_NMR1;
 
   static {
-    List<String> projectionList = new ArrayList<>(Arrays.asList(PROJECTION_M));
-    projectionList.add(Status.QUOTA_OCCUPIED); // 6
-    projectionList.add(Status.QUOTA_TOTAL); // 7
-    PROJECTION_N = projectionList.toArray(new String[projectionList.size()]);
-
+    List<String> projectionList = new ArrayList<>(Arrays.asList(PROJECTION_N));
     projectionList.add(Status.PHONE_ACCOUNT_COMPONENT_NAME); // 8
     projectionList.add(Status.PHONE_ACCOUNT_ID); // 9
     projectionList.add(Status.SOURCE_TYPE); // 10
@@ -80,12 +76,6 @@
   }
 
   public static String[] getProjection() {
-    if (VERSION.SDK_INT >= VERSION_CODES.N_MR1) {
-      return PROJECTION_NMR1;
-    }
-    if (VERSION.SDK_INT >= VERSION_CODES.N) {
-      return PROJECTION_N;
-    }
-    return PROJECTION_M;
+    return VERSION.SDK_INT >= VERSION_CODES.N_MR1 ? PROJECTION_NMR1 : PROJECTION_N;
   }
 }
diff --git a/java/com/android/incallui/CallCardPresenter.java b/java/com/android/incallui/CallCardPresenter.java
index 316b6cc..9c5e062 100644
--- a/java/com/android/incallui/CallCardPresenter.java
+++ b/java/com/android/incallui/CallCardPresenter.java
@@ -46,7 +46,6 @@
 import com.android.contacts.common.util.ContactDisplayUtils;
 import com.android.dialer.common.Assert;
 import com.android.dialer.common.LogUtil;
-import com.android.dialer.compat.ActivityCompat;
 import com.android.dialer.configprovider.ConfigProviderBindings;
 import com.android.dialer.logging.DialerImpression;
 import com.android.dialer.logging.Logger;
@@ -836,7 +835,7 @@
       LogUtil.i("CallCardPresenter.getLocationFragment", "low battery.");
       return false;
     }
-    if (ActivityCompat.isInMultiWindowMode(inCallScreen.getInCallScreenFragment().getActivity())) {
+    if (inCallScreen.getInCallScreenFragment().getActivity().isInMultiWindowMode()) {
       LogUtil.i("CallCardPresenter.getLocationFragment", "in multi-window mode");
       return false;
     }
diff --git a/java/com/android/incallui/CallerInfo.java b/java/com/android/incallui/CallerInfo.java
index 0aedea5..817535f 100644
--- a/java/com/android/incallui/CallerInfo.java
+++ b/java/com/android/incallui/CallerInfo.java
@@ -21,7 +21,6 @@
 import android.graphics.Bitmap;
 import android.graphics.drawable.Drawable;
 import android.net.Uri;
-import android.os.Build.VERSION;
 import android.os.Build.VERSION_CODES;
 import android.provider.ContactsContract;
 import android.provider.ContactsContract.CommonDataKinds.Phone;
@@ -37,7 +36,6 @@
 import com.android.contacts.common.util.TelephonyManagerUtils;
 import com.android.dialer.logging.ContactLookupResult;
 import com.android.dialer.phonenumbercache.ContactInfoHelper;
-import com.android.dialer.phonenumbercache.PhoneLookupUtil;
 import com.android.dialer.phonenumberutil.PhoneNumberHelper;
 
 /**
@@ -48,7 +46,6 @@
 
   private static final String TAG = "CallerInfo";
 
-  // We should always use this projection starting from N onward.
   @RequiresApi(VERSION_CODES.N)
   private static final String[] DEFAULT_PHONELOOKUP_PROJECTION =
       new String[] {
@@ -64,20 +61,6 @@
         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
-      };
   /**
    * 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.
@@ -176,17 +159,8 @@
     userType = ContactsUtils.USER_TYPE_CURRENT;
   }
 
-  public static String[] getDefaultPhoneLookupProjection(Uri phoneLookupUri) {
-    if (VERSION.SDK_INT >= VERSION_CODES.N) {
-      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;
+  static String[] getDefaultPhoneLookupProjection() {
+    return DEFAULT_PHONELOOKUP_PROJECTION;
   }
 
   /**
@@ -276,9 +250,7 @@
     columnIndex = getColumnIndexForPersonId(contactRef, cursor);
     if (columnIndex != -1) {
       contactId = cursor.getLong(columnIndex);
-      // QuickContacts in M doesn't support enterprise contact id
-      if (contactId != 0
-          && (VERSION.SDK_INT >= VERSION_CODES.N || !Contacts.isEnterpriseContactId(contactId))) {
+      if (contactId != 0 && !Contacts.isEnterpriseContactId(contactId)) {
         info.contactIdOrZero = contactId;
         Log.v(TAG, "==> got info.contactIdOrZero: " + info.contactIdOrZero);
       }
@@ -453,7 +425,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 = PhoneLookupUtil.getContactIdColumnNameForUri(contactRef);
+      columnName = PhoneLookup.CONTACT_ID;
     } else {
       Log.v(TAG, "Unexpected prefix for contactRef '" + url + "'");
     }
diff --git a/java/com/android/incallui/CallerInfoAsyncQuery.java b/java/com/android/incallui/CallerInfoAsyncQuery.java
index 4170cc3..0ac252a 100644
--- a/java/com/android/incallui/CallerInfoAsyncQuery.java
+++ b/java/com/android/incallui/CallerInfoAsyncQuery.java
@@ -24,7 +24,6 @@
 import android.database.Cursor;
 import android.database.SQLException;
 import android.net.Uri;
-import android.os.Build.VERSION;
 import android.os.Build.VERSION_CODES;
 import android.os.Handler;
 import android.os.Looper;
@@ -36,7 +35,6 @@
 import android.support.annotation.RequiresPermission;
 import android.support.annotation.WorkerThread;
 import android.text.TextUtils;
-import com.android.dialer.common.cp2.DirectoryCompat;
 import com.android.dialer.phonenumbercache.CachedNumberLookupService;
 import com.android.dialer.phonenumbercache.CachedNumberLookupService.CachedContactInfo;
 import com.android.dialer.phonenumbercache.ContactInfoHelper;
@@ -174,7 +172,7 @@
       cw.event = EVENT_NEW_QUERY;
     }
 
-    String[] proejection = CallerInfo.getDefaultPhoneLookupProjection(contactRef);
+    String[] proejection = CallerInfo.getDefaultPhoneLookupProjection();
     handler.startQuery(
         token,
         cw, // cookie
@@ -223,10 +221,7 @@
   private static long[] getDirectoryIds(Context context) {
     ArrayList<Long> results = new ArrayList<>();
 
-    Uri uri = Directory.CONTENT_URI;
-    if (VERSION.SDK_INT >= VERSION_CODES.N) {
-      uri = Uri.withAppendedPath(ContactsContract.AUTHORITY_URI, "directories_enterprise");
-    }
+    Uri uri = Uri.withAppendedPath(ContactsContract.AUTHORITY_URI, "directories_enterprise");
 
     ContentResolver cr = context.getContentResolver();
     Cursor cursor = cr.query(uri, DIRECTORY_PROJECTION, null, null, null);
@@ -244,7 +239,7 @@
       int idIndex = cursor.getColumnIndex(Directory._ID);
       while (cursor.moveToNext()) {
         long id = cursor.getLong(idIndex);
-        if (DirectoryCompat.isRemoteDirectoryId(id)) {
+        if (Directory.isRemoteDirectoryId(id)) {
           results.add(id);
         }
       }
diff --git a/java/com/android/incallui/ContactInfoCache.java b/java/com/android/incallui/ContactInfoCache.java
index b79fd64..165ec13 100644
--- a/java/com/android/incallui/ContactInfoCache.java
+++ b/java/com/android/incallui/ContactInfoCache.java
@@ -22,8 +22,6 @@
 import android.graphics.drawable.Drawable;
 import android.media.RingtoneManager;
 import android.net.Uri;
-import android.os.Build.VERSION;
-import android.os.Build.VERSION_CODES;
 import android.os.SystemClock;
 import android.os.Trace;
 import android.provider.ContactsContract.CommonDataKinds.Phone;
@@ -641,10 +639,7 @@
       cce.photo = null;
     }
 
-    // Support any contact id in N because QuickContacts in N starts supporting enterprise
-    // contact id
-    if (info.lookupKeyOrNull != null
-        && (VERSION.SDK_INT >= VERSION_CODES.N || info.contactIdOrZero != 0)) {
+    if (info.lookupKeyOrNull != null && info.contactIdOrZero != 0) {
       cce.lookupUri = Contacts.getLookupUri(info.contactIdOrZero, info.lookupKeyOrNull);
     } else {
       Log.v(TAG, "lookup key is null or contact ID is 0 on M. Don't create a lookup uri.");
diff --git a/java/com/android/incallui/InCallActivity.java b/java/com/android/incallui/InCallActivity.java
index be36509..3236e16 100644
--- a/java/com/android/incallui/InCallActivity.java
+++ b/java/com/android/incallui/InCallActivity.java
@@ -60,7 +60,6 @@
 import com.android.dialer.common.LogUtil;
 import com.android.dialer.common.concurrent.DialerExecutorComponent;
 import com.android.dialer.common.concurrent.ThreadUtil;
-import com.android.dialer.compat.ActivityCompat;
 import com.android.dialer.compat.CompatUtils;
 import com.android.dialer.configprovider.ConfigProviderBindings;
 import com.android.dialer.logging.DialerImpression.Type;
@@ -465,8 +464,7 @@
       InCallPresenter.getInstance().onUiShowing(true);
     }
 
-    if (ActivityCompat.isInMultiWindowMode(this)
-        && !getResources().getBoolean(R.bool.incall_dialpad_allowed)) {
+    if (isInMultiWindowMode() && !getResources().getBoolean(R.bool.incall_dialpad_allowed)) {
       // Hide the dialpad because there may not be enough room
       showDialpadFragment(false, false);
     }
@@ -926,7 +924,7 @@
     @ColorInt int bottom;
     @ColorInt int gray = 0x66000000;
 
-    if (ActivityCompat.isInMultiWindowMode(this)) {
+    if (isInMultiWindowMode()) {
       top = themeColorManager.getBackgroundColorSolid();
       middle = themeColorManager.getBackgroundColorSolid();
       bottom = themeColorManager.getBackgroundColorSolid();
@@ -1236,7 +1234,7 @@
   }
 
   private void updateNavigationBar(boolean isDialpadVisible) {
-    if (ActivityCompat.isInMultiWindowMode(this)) {
+    if (isInMultiWindowMode()) {
       return;
     }
 
diff --git a/java/com/android/incallui/answer/impl/AnswerFragment.java b/java/com/android/incallui/answer/impl/AnswerFragment.java
index 05fd4f6..e5271f5 100644
--- a/java/com/android/incallui/answer/impl/AnswerFragment.java
+++ b/java/com/android/incallui/answer/impl/AnswerFragment.java
@@ -53,7 +53,6 @@
 import com.android.dialer.common.FragmentUtils;
 import com.android.dialer.common.LogUtil;
 import com.android.dialer.common.MathUtil;
-import com.android.dialer.compat.ActivityCompat;
 import com.android.dialer.logging.DialerImpression;
 import com.android.dialer.logging.Logger;
 import com.android.dialer.multimedia.MultimediaData;
@@ -411,7 +410,7 @@
       LogUtil.i("AnswerFragment.setTextResponses", "no text responses, hiding secondary button");
       this.textResponses = null;
       secondaryButton.setVisibility(View.INVISIBLE);
-    } else if (ActivityCompat.isInMultiWindowMode(getActivity())) {
+    } else if (getActivity().isInMultiWindowMode()) {
       LogUtil.i("AnswerFragment.setTextResponses", "in multiwindow, hiding secondary button");
       this.textResponses = null;
       secondaryButton.setVisibility(View.INVISIBLE);
@@ -731,7 +730,7 @@
     updateImportanceBadgeVisibility();
 
     contactGridManager = new ContactGridManager(view, null, 0, false /* showAnonymousAvatar */);
-    boolean isInMultiWindowMode = ActivityCompat.isInMultiWindowMode(getActivity());
+    boolean isInMultiWindowMode = getActivity().isInMultiWindowMode();
     contactGridManager.onMultiWindowModeChanged(isInMultiWindowMode);
 
     Fragment answerMethod =
diff --git a/java/com/android/incallui/answer/impl/answermethod/AnswerMethodFactory.java b/java/com/android/incallui/answer/impl/answermethod/AnswerMethodFactory.java
index ccb132b..f318f08 100644
--- a/java/com/android/incallui/answer/impl/answermethod/AnswerMethodFactory.java
+++ b/java/com/android/incallui/answer/impl/answermethod/AnswerMethodFactory.java
@@ -22,7 +22,6 @@
 import android.support.annotation.VisibleForTesting;
 import android.support.v4.app.Fragment;
 import com.android.dialer.common.LogUtil;
-import com.android.dialer.compat.ActivityCompat;
 import com.android.incallui.util.AccessibilityUtil;
 
 /** Creates the appropriate {@link AnswerMethod} for the circumstances. */
@@ -59,7 +58,6 @@
       return true;
     }
 
-    return AccessibilityUtil.isTouchExplorationEnabled(activity)
-        || ActivityCompat.isInMultiWindowMode(activity);
+    return AccessibilityUtil.isTouchExplorationEnabled(activity) || activity.isInMultiWindowMode();
   }
 }
diff --git a/java/com/android/incallui/answer/impl/answermethod/TwoButtonMethod.java b/java/com/android/incallui/answer/impl/answermethod/TwoButtonMethod.java
index 67b1b96..1086449 100644
--- a/java/com/android/incallui/answer/impl/answermethod/TwoButtonMethod.java
+++ b/java/com/android/incallui/answer/impl/answermethod/TwoButtonMethod.java
@@ -36,7 +36,6 @@
 import android.widget.TextView;
 import com.android.dialer.common.Assert;
 import com.android.dialer.common.LogUtil;
-import com.android.dialer.compat.ActivityCompat;
 import com.android.incallui.answer.impl.answermethod.FlingUpDownTouchHandler.OnProgressChangedListener;
 import com.android.incallui.util.AccessibilityUtil;
 
@@ -157,8 +156,7 @@
     if (hintTextView == null) {
       return;
     }
-    hintTextView.setVisibility(
-        ActivityCompat.isInMultiWindowMode(getActivity()) ? View.GONE : View.VISIBLE);
+    hintTextView.setVisibility(getActivity().isInMultiWindowMode() ? View.GONE : View.VISIBLE);
     if (!TextUtils.isEmpty(hintText) && !buttonClicked) {
       hintTextView.setText(hintText);
       hintTextView.animate().alpha(1f).start();
diff --git a/java/com/android/incallui/autoresizetext/AutoResizeTextView.java b/java/com/android/incallui/autoresizetext/AutoResizeTextView.java
index 487283a..c8647fc 100644
--- a/java/com/android/incallui/autoresizetext/AutoResizeTextView.java
+++ b/java/com/android/incallui/autoresizetext/AutoResizeTextView.java
@@ -19,8 +19,6 @@
 import android.content.Context;
 import android.content.res.TypedArray;
 import android.graphics.RectF;
-import android.os.Build.VERSION;
-import android.os.Build.VERSION_CODES;
 import android.support.annotation.Nullable;
 import android.text.Layout.Alignment;
 import android.text.StaticLayout;
@@ -52,9 +50,6 @@
   private float minTextSize = DEFAULT_MIN_TEXT_SIZE;
   private float maxTextSize;
   private int maxWidth;
-  private int maxLines;
-  private float lineSpacingMultiplier = 1.0f;
-  private float lineSpacingExtra = 0.0f;
 
   public AutoResizeTextView(Context context) {
     super(context, null, 0);
@@ -86,53 +81,6 @@
     textPaint.set(getPaint());
   }
 
-  /** Overridden because getMaxLines is only defined in JB+. */
-  @Override
-  public final int getMaxLines() {
-    if (VERSION.SDK_INT >= VERSION_CODES.JELLY_BEAN) {
-      return super.getMaxLines();
-    } else {
-      return maxLines;
-    }
-  }
-
-  /** Overridden because getMaxLines is only defined in JB+. */
-  @Override
-  public final void setMaxLines(int maxLines) {
-    super.setMaxLines(maxLines);
-    this.maxLines = maxLines;
-  }
-
-  /** Overridden because getLineSpacingMultiplier is only defined in JB+. */
-  @Override
-  public final float getLineSpacingMultiplier() {
-    if (VERSION.SDK_INT >= VERSION_CODES.JELLY_BEAN) {
-      return super.getLineSpacingMultiplier();
-    } else {
-      return lineSpacingMultiplier;
-    }
-  }
-
-  /** Overridden because getLineSpacingExtra is only defined in JB+. */
-  @Override
-  public final float getLineSpacingExtra() {
-    if (VERSION.SDK_INT >= VERSION_CODES.JELLY_BEAN) {
-      return super.getLineSpacingExtra();
-    } else {
-      return lineSpacingExtra;
-    }
-  }
-
-  /**
-   * Overridden because getLineSpacingMultiplier and getLineSpacingExtra are only defined in JB+.
-   */
-  @Override
-  public final void setLineSpacing(float add, float mult) {
-    super.setLineSpacing(add, mult);
-    lineSpacingMultiplier = mult;
-    lineSpacingExtra = add;
-  }
-
   /**
    * Although this overrides the setTextSize method from the TextView base class, it changes the
    * semantics a bit: Calling setTextSize now specifies the maximum text size to be used by this
diff --git a/java/com/android/incallui/call/CallList.java b/java/com/android/incallui/call/CallList.java
index 9a09026..f639e5b 100644
--- a/java/com/android/incallui/call/CallList.java
+++ b/java/com/android/incallui/call/CallList.java
@@ -144,7 +144,7 @@
     Trace.beginSection("checkSpam");
     call.addListener(new DialerCallListenerImpl(call));
     LogUtil.d("CallList.onCallAdded", "callState=" + call.getState());
-    if (SpamComponent.get(context).spam().isSpamEnabled()) {
+    if (SpamComponent.get(context).spamSettings().isSpamEnabled()) {
       String number = TelecomCallUtil.getNumber(telecomCall);
       SpamComponent.get(context)
           .spam()
diff --git a/java/com/android/incallui/call/DialerCall.java b/java/com/android/incallui/call/DialerCall.java
index 2ce4550..9a7c653 100644
--- a/java/com/android/incallui/call/DialerCall.java
+++ b/java/com/android/incallui/call/DialerCall.java
@@ -1018,13 +1018,10 @@
    * <p>An external call is one which does not exist locally for the {@link
    * android.telecom.ConnectionService} it is associated with.
    *
-   * <p>External calls are only supported in N and higher.
-   *
    * @return {@code true} if the call is an external call, {@code false} otherwise.
    */
-  public boolean isExternalCall() {
-    return VERSION.SDK_INT >= VERSION_CODES.N
-        && hasProperty(CallCompat.Details.PROPERTY_IS_EXTERNAL_CALL);
+  boolean isExternalCall() {
+    return hasProperty(CallCompat.Details.PROPERTY_IS_EXTERNAL_CALL);
   }
 
   /**
diff --git a/java/com/android/incallui/incall/impl/InCallFragment.java b/java/com/android/incallui/incall/impl/InCallFragment.java
index 1cada32..fb8c2c4 100644
--- a/java/com/android/incallui/incall/impl/InCallFragment.java
+++ b/java/com/android/incallui/incall/impl/InCallFragment.java
@@ -17,10 +17,9 @@
 package com.android.incallui.incall.impl;
 
 import android.Manifest.permission;
+import android.annotation.SuppressLint;
 import android.content.Context;
 import android.content.pm.PackageManager;
-import android.os.Build.VERSION;
-import android.os.Build.VERSION_CODES;
 import android.os.Bundle;
 import android.os.Handler;
 import android.support.annotation.ColorInt;
@@ -44,7 +43,6 @@
 import com.android.dialer.common.Assert;
 import com.android.dialer.common.FragmentUtils;
 import com.android.dialer.common.LogUtil;
-import com.android.dialer.compat.ActivityCompat;
 import com.android.dialer.logging.DialerImpression;
 import com.android.dialer.logging.Logger;
 import com.android.dialer.multimedia.MultimediaData;
@@ -141,6 +139,7 @@
 
   @Nullable
   @Override
+  @SuppressLint("MissingPermission")
   public View onCreateView(
       @NonNull LayoutInflater layoutInflater,
       @Nullable ViewGroup viewGroup,
@@ -156,7 +155,7 @@
             (ImageView) view.findViewById(R.id.contactgrid_avatar),
             getResources().getDimensionPixelSize(R.dimen.incall_avatar_size),
             true /* showAnonymousAvatar */);
-    contactGridManager.onMultiWindowModeChanged(ActivityCompat.isInMultiWindowMode(getActivity()));
+    contactGridManager.onMultiWindowModeChanged(getActivity().isInMultiWindowMode());
 
     paginator = (InCallPaginator) view.findViewById(R.id.incall_paginator);
     pager = (LockableViewPager) view.findViewById(R.id.incall_pager);
@@ -173,11 +172,8 @@
         != PackageManager.PERMISSION_GRANTED) {
       voiceNetworkType = TelephonyManager.NETWORK_TYPE_UNKNOWN;
     } else {
-
       voiceNetworkType =
-          VERSION.SDK_INT >= VERSION_CODES.N
-              ? getContext().getSystemService(TelephonyManager.class).getVoiceNetworkType()
-              : TelephonyManager.NETWORK_TYPE_UNKNOWN;
+          getContext().getSystemService(TelephonyManager.class).getVoiceNetworkType();
     }
     // TODO(a bug): Change to use corresponding phone type used for current call.
     phoneType = getContext().getSystemService(TelephonyManager.class).getPhoneType();
diff --git a/java/com/android/incallui/ringtone/DialerRingtoneManager.java b/java/com/android/incallui/ringtone/DialerRingtoneManager.java
index 49badf5..b8a3071 100644
--- a/java/com/android/incallui/ringtone/DialerRingtoneManager.java
+++ b/java/com/android/incallui/ringtone/DialerRingtoneManager.java
@@ -18,8 +18,6 @@
 
 import android.content.ContentResolver;
 import android.net.Uri;
-import android.os.Build.VERSION;
-import android.os.Build.VERSION_CODES;
 import android.provider.Settings;
 import android.support.annotation.NonNull;
 import android.support.annotation.Nullable;
@@ -92,11 +90,9 @@
   }
 
   private boolean isDialerRingingEnabled() {
-    boolean enabledFlag =
-        isDialerRingingEnabledForTesting != null
-            ? isDialerRingingEnabledForTesting
-            : IS_DIALER_RINGING_ENABLED;
-    return VERSION.SDK_INT >= VERSION_CODES.N && enabledFlag;
+    return isDialerRingingEnabledForTesting != null
+        ? isDialerRingingEnabledForTesting
+        : IS_DIALER_RINGING_ENABLED;
   }
 
   /**
diff --git a/java/com/android/incallui/spam/SpamCallListListener.java b/java/com/android/incallui/spam/SpamCallListListener.java
index 9ef65d8..e852f3d 100644
--- a/java/com/android/incallui/spam/SpamCallListListener.java
+++ b/java/com/android/incallui/spam/SpamCallListListener.java
@@ -205,7 +205,7 @@
 
   /** Determines if the after call notification should be shown for the specified call. */
   private boolean shouldShowAfterCallNotification(DialerCall call) {
-    if (!SpamComponent.get(context).spam().isSpamNotificationEnabled()) {
+    if (!SpamComponent.get(context).spamSettings().isSpamNotificationEnabled()) {
       return false;
     }
 
@@ -305,7 +305,8 @@
 
   private boolean shouldThrottleSpamNotification() {
     int randomNumber = random.nextInt(100);
-    int thresholdForShowing = SpamComponent.get(context).spam().percentOfSpamNotificationsToShow();
+    int thresholdForShowing =
+        SpamComponent.get(context).spamSettings().percentOfSpamNotificationsToShow();
     if (thresholdForShowing == 0) {
       LogUtil.d(
           "SpamCallListListener.shouldThrottleSpamNotification",
@@ -329,7 +330,7 @@
   private boolean shouldThrottleNonSpamNotification() {
     int randomNumber = random.nextInt(100);
     int thresholdForShowing =
-        SpamComponent.get(context).spam().percentOfNonSpamNotificationsToShow();
+        SpamComponent.get(context).spamSettings().percentOfNonSpamNotificationsToShow();
     if (thresholdForShowing == 0) {
       LogUtil.d(
           "SpamCallListListener.shouldThrottleNonSpamNotification",
@@ -418,7 +419,7 @@
    */
   private PendingIntent createBlockReportSpamPendingIntent(DialerCall call) {
     String action = SpamNotificationActivity.ACTION_MARK_NUMBER_AS_SPAM;
-    return SpamComponent.get(context).spam().isDialogEnabledForSpamNotification()
+    return SpamComponent.get(context).spamSettings().isDialogEnabledForSpamNotification()
         ? createActivityPendingIntent(call, action)
         : createServicePendingIntent(call, action);
   }
@@ -429,7 +430,7 @@
    */
   private PendingIntent createNotSpamPendingIntent(DialerCall call) {
     String action = SpamNotificationActivity.ACTION_MARK_NUMBER_AS_NOT_SPAM;
-    return SpamComponent.get(context).spam().isDialogEnabledForSpamNotification()
+    return SpamComponent.get(context).spamSettings().isDialogEnabledForSpamNotification()
         ? createActivityPendingIntent(call, action)
         : createServicePendingIntent(call, action);
   }
diff --git a/java/com/android/incallui/spam/SpamNotificationActivity.java b/java/com/android/incallui/spam/SpamNotificationActivity.java
index 61d04a0..cb5f8e5 100644
--- a/java/com/android/incallui/spam/SpamNotificationActivity.java
+++ b/java/com/android/incallui/spam/SpamNotificationActivity.java
@@ -197,7 +197,7 @@
   /** Creates and displays the dialog for whitelisting a number. */
   private void maybeShowNotSpamDialog(
       final String number, final ContactLookupResult.Type contactLookupResultType) {
-    if (SpamComponent.get(this).spam().isDialogEnabledForSpamNotification()) {
+    if (SpamComponent.get(this).spamSettings().isDialogEnabledForSpamNotification()) {
       DialogFragmentForReportingNotSpam.newInstance(
               getFormattedNumber(number, this),
               new BlockReportSpamDialogs.OnConfirmListener() {
@@ -216,7 +216,7 @@
   /** Creates and displays the dialog for blocking/reporting a number as spam. */
   private void maybeShowBlockReportSpamDialog(
       final String number, final ContactLookupResult.Type contactLookupResultType) {
-    if (SpamComponent.get(this).spam().isDialogEnabledForSpamNotification()) {
+    if (SpamComponent.get(this).spamSettings().isDialogEnabledForSpamNotification()) {
       String displayNumber = getFormattedNumber(number, this);
       maybeShowBlockNumberMigrationDialog(
           new BlockedNumbersMigrator.Listener() {
@@ -225,7 +225,7 @@
               DialogFragmentForBlockingNumberAndOptionallyReportingAsSpam.newInstance(
                       displayNumber,
                       SpamComponent.get(SpamNotificationActivity.this)
-                          .spam()
+                          .spamSettings()
                           .isDialogReportSpamCheckedByDefault(),
                       new BlockReportSpamDialogs.OnSpamDialogClickListener() {
                         @Override
@@ -319,7 +319,7 @@
   }
 
   private void assertDialogsEnabled() {
-    if (!SpamComponent.get(this).spam().isDialogEnabledForSpamNotification()) {
+    if (!SpamComponent.get(this).spamSettings().isDialogEnabledForSpamNotification()) {
       throw new IllegalStateException(
           "Cannot start this activity with given action because dialogs are not enabled.");
     }
diff --git a/java/com/android/incallui/video/impl/SurfaceViewVideoCallFragment.java b/java/com/android/incallui/video/impl/SurfaceViewVideoCallFragment.java
index b97d2eb..f270eda 100644
--- a/java/com/android/incallui/video/impl/SurfaceViewVideoCallFragment.java
+++ b/java/com/android/incallui/video/impl/SurfaceViewVideoCallFragment.java
@@ -50,7 +50,6 @@
 import com.android.dialer.common.Assert;
 import com.android.dialer.common.FragmentUtils;
 import com.android.dialer.common.LogUtil;
-import com.android.dialer.compat.ActivityCompat;
 import com.android.dialer.util.PermissionsUtil;
 import com.android.incallui.audioroute.AudioRouteSelectorDialogFragment;
 import com.android.incallui.audioroute.AudioRouteSelectorDialogFragment.AudioRouteSelectorPresenter;
@@ -187,8 +186,7 @@
         new ContactGridManager(view, null /* no avatar */, 0, false /* showAnonymousAvatar */);
 
     controls = view.findViewById(R.id.videocall_video_controls);
-    controls.setVisibility(
-        ActivityCompat.isInMultiWindowMode(getActivity()) ? View.GONE : View.VISIBLE);
+    controls.setVisibility(getActivity().isInMultiWindowMode() ? View.GONE : View.VISIBLE);
     controlsContainer = view.findViewById(R.id.videocall_video_controls_container);
     speakerButton = (CheckableImageButton) view.findViewById(R.id.videocall_speaker_button);
     muteButton = (CheckableImageButton) view.findViewById(R.id.videocall_mute_button);
@@ -200,8 +198,7 @@
     swapCameraButton = (ImageButton) view.findViewById(R.id.videocall_switch_video);
     swapCameraButton.setOnClickListener(this);
     view.findViewById(R.id.videocall_switch_controls)
-        .setVisibility(
-            ActivityCompat.isInMultiWindowMode(getActivity()) ? View.GONE : View.VISIBLE);
+        .setVisibility(getActivity().isInMultiWindowMode() ? View.GONE : View.VISIBLE);
     switchOnHoldButton = view.findViewById(R.id.videocall_switch_on_hold);
     onHoldContainer = view.findViewById(R.id.videocall_on_hold_banner);
     remoteVideoOff = (TextView) view.findViewById(R.id.videocall_remote_video_off);
@@ -478,7 +475,7 @@
 
   private Point getPreviewOffsetStartShown() {
     // No insets in multiwindow mode, and rootWindowInsets will get the display's insets.
-    if (ActivityCompat.isInMultiWindowMode(getActivity())) {
+    if (getActivity().isInMultiWindowMode()) {
       return new Point();
     }
     if (isLandscape()) {
@@ -690,7 +687,7 @@
     isInGreenScreenMode = shouldShowGreenScreen;
     isInFullscreenMode = shouldShowFullscreen;
 
-    if (getView().isAttachedToWindow() && !ActivityCompat.isInMultiWindowMode(getActivity())) {
+    if (getView().isAttachedToWindow() && !getActivity().isInMultiWindowMode()) {
       controlsContainer.onApplyWindowInsets(getView().getRootWindowInsets());
     }
     if (shouldShowGreenScreen) {
diff --git a/java/com/android/incallui/video/impl/VideoCallFragment.java b/java/com/android/incallui/video/impl/VideoCallFragment.java
index 2a810cf..11b80ce 100644
--- a/java/com/android/incallui/video/impl/VideoCallFragment.java
+++ b/java/com/android/incallui/video/impl/VideoCallFragment.java
@@ -60,7 +60,6 @@
 import com.android.dialer.common.Assert;
 import com.android.dialer.common.FragmentUtils;
 import com.android.dialer.common.LogUtil;
-import com.android.dialer.compat.ActivityCompat;
 import com.android.dialer.util.PermissionsUtil;
 import com.android.incallui.audioroute.AudioRouteSelectorDialogFragment;
 import com.android.incallui.audioroute.AudioRouteSelectorDialogFragment.AudioRouteSelectorPresenter;
@@ -234,8 +233,7 @@
         new ContactGridManager(view, null /* no avatar */, 0, false /* showAnonymousAvatar */);
 
     controls = view.findViewById(R.id.videocall_video_controls);
-    controls.setVisibility(
-        ActivityCompat.isInMultiWindowMode(getActivity()) ? View.GONE : View.VISIBLE);
+    controls.setVisibility(getActivity().isInMultiWindowMode() ? View.GONE : View.VISIBLE);
     controlsContainer = view.findViewById(R.id.videocall_video_controls_container);
     speakerButton = (CheckableImageButton) view.findViewById(R.id.videocall_speaker_button);
     muteButton = (CheckableImageButton) view.findViewById(R.id.videocall_mute_button);
@@ -249,8 +247,7 @@
     swapCameraButton = (ImageButton) view.findViewById(R.id.videocall_switch_video);
     swapCameraButton.setOnClickListener(this);
     view.findViewById(R.id.videocall_switch_controls)
-        .setVisibility(
-            ActivityCompat.isInMultiWindowMode(getActivity()) ? View.GONE : View.VISIBLE);
+        .setVisibility(getActivity().isInMultiWindowMode() ? View.GONE : View.VISIBLE);
     switchOnHoldButton = view.findViewById(R.id.videocall_switch_on_hold);
     onHoldContainer = view.findViewById(R.id.videocall_on_hold_banner);
     remoteVideoOff = (TextView) view.findViewById(R.id.videocall_remote_video_off);
@@ -540,7 +537,7 @@
 
   private Point getPreviewOffsetStartShown() {
     // No insets in multiwindow mode, and rootWindowInsets will get the display's insets.
-    if (ActivityCompat.isInMultiWindowMode(getActivity())) {
+    if (getActivity().isInMultiWindowMode()) {
       return new Point();
     }
     if (isLandscape()) {
@@ -758,7 +755,7 @@
     isInGreenScreenMode = shouldShowGreenScreen;
     isInFullscreenMode = shouldShowFullscreen;
 
-    if (getView().isAttachedToWindow() && !ActivityCompat.isInMultiWindowMode(getActivity())) {
+    if (getView().isAttachedToWindow() && !getActivity().isInMultiWindowMode()) {
       controlsContainer.onApplyWindowInsets(getView().getRootWindowInsets());
     }
     if (shouldShowGreenScreen) {
diff --git a/java/com/android/voicemail/impl/scheduling/TaskQueue.java b/java/com/android/voicemail/impl/scheduling/TaskQueue.java
index fc5aa94..6afcf00 100644
--- a/java/com/android/voicemail/impl/scheduling/TaskQueue.java
+++ b/java/com/android/voicemail/impl/scheduling/TaskQueue.java
@@ -23,6 +23,7 @@
 import com.android.voicemail.impl.Assert;
 import com.android.voicemail.impl.VvmLog;
 import com.android.voicemail.impl.scheduling.Task.TaskId;
+import com.android.voicemail.impl.scheduling.Tasks.TaskCreationException;
 import java.util.ArrayDeque;
 import java.util.ArrayList;
 import java.util.Iterator;
@@ -49,9 +50,13 @@
   public void fromBundles(Context context, List<Bundle> pendingTasks) {
     Assert.isTrue(queue.isEmpty());
     for (Bundle pendingTask : pendingTasks) {
-      Task task = Tasks.createTask(context, pendingTask);
-      task.onRestore(pendingTask);
-      add(task);
+      try {
+        Task task = Tasks.createTask(context, pendingTask);
+        task.onRestore(pendingTask);
+        add(task);
+      } catch (TaskCreationException e) {
+        VvmLog.e("TaskQueue.fromBundles", "cannot create task", e);
+      }
     }
   }
 
diff --git a/java/com/android/voicemail/impl/scheduling/TaskReceiver.java b/java/com/android/voicemail/impl/scheduling/TaskReceiver.java
index e78dcf7..b9fd272 100644
--- a/java/com/android/voicemail/impl/scheduling/TaskReceiver.java
+++ b/java/com/android/voicemail/impl/scheduling/TaskReceiver.java
@@ -23,6 +23,7 @@
 import android.os.Build.VERSION_CODES;
 import android.os.Bundle;
 import com.android.voicemail.impl.VvmLog;
+import com.android.voicemail.impl.scheduling.Tasks.TaskCreationException;
 import java.util.ArrayList;
 import java.util.List;
 
@@ -69,8 +70,12 @@
         deferredBroadcasts.add(intent);
         return;
       }
-      Task task = Tasks.createTask(context.getApplicationContext(), intent.getExtras());
-      taskExecutor.addTask(task);
+      try {
+        Task task = Tasks.createTask(context.getApplicationContext(), intent.getExtras());
+        taskExecutor.addTask(task);
+      } catch (TaskCreationException e) {
+        VvmLog.e(TAG, "cannot create task", e);
+      }
     } else {
       VvmLog.i(TAG, "scheduling new job");
       List<Bundle> taskList = new ArrayList<>();
diff --git a/java/com/android/voicemail/impl/scheduling/TaskSchedulerJobService.java b/java/com/android/voicemail/impl/scheduling/TaskSchedulerJobService.java
index 0e3f27c..77a0d25 100644
--- a/java/com/android/voicemail/impl/scheduling/TaskSchedulerJobService.java
+++ b/java/com/android/voicemail/impl/scheduling/TaskSchedulerJobService.java
@@ -33,6 +33,7 @@
 import com.android.dialer.strictmode.StrictModeUtils;
 import com.android.voicemail.impl.Assert;
 import com.android.voicemail.impl.VvmLog;
+import com.android.voicemail.impl.scheduling.Tasks.TaskCreationException;
 import java.util.ArrayList;
 import java.util.List;
 
@@ -110,7 +111,11 @@
         TaskQueue queue = new TaskQueue();
         queue.fromBundles(context, existingTasks);
         for (Bundle pendingTask : pendingTasks) {
-          queue.add(Tasks.createTask(context, pendingTask));
+          try {
+            queue.add(Tasks.createTask(context, pendingTask));
+          } catch (TaskCreationException e) {
+            VvmLog.e(TAG, "cannot create task", e);
+          }
         }
         pendingTasks = queue.toBundles();
       }
diff --git a/java/com/android/voicemail/impl/scheduling/Tasks.java b/java/com/android/voicemail/impl/scheduling/Tasks.java
index 76da3d7..0333e16 100644
--- a/java/com/android/voicemail/impl/scheduling/Tasks.java
+++ b/java/com/android/voicemail/impl/scheduling/Tasks.java
@@ -18,6 +18,7 @@
 
 import android.content.Context;
 import android.content.Intent;
+import android.os.BadParcelableException;
 import android.os.Bundle;
 import android.support.annotation.NonNull;
 import com.android.voicemail.impl.VvmLog;
@@ -29,16 +30,30 @@
 
   static final String EXTRA_CLASS_NAME = "extra_class_name";
 
+  /** The task cannot be created. */
+  static final class TaskCreationException extends Exception {
+    TaskCreationException(Throwable throwable) {
+      super(throwable);
+    }
+  }
+
   /**
    * Create a task from a bundle. The bundle is created either with {@link #toBundle(Task)} or
    * {@link #createIntent(Context, Class)} from the target {@link Task}
    */
   @NonNull
-  public static Task createTask(Context context, Bundle extras) {
+  public static Task createTask(Context context, Bundle extras) throws TaskCreationException {
     // The extra contains custom parcelables which cannot be unmarshalled by the framework class
     // loader.
     extras.setClassLoader(context.getClassLoader());
-    String className = extras.getString(EXTRA_CLASS_NAME);
+    String className;
+    try {
+      className = extras.getString(EXTRA_CLASS_NAME);
+    } catch (BadParcelableException e) {
+      // BadParcelableException:Parcelable protocol requires that the class implements Parcelable
+      // This happens when the task is submitted before an update, and can no longer be unparceled.
+      throw new TaskCreationException(e);
+    }
     VvmLog.i("Task.createTask", "create task:" + className);
     if (className == null) {
       throw new IllegalArgumentException("EXTRA_CLASS_NAME expected");