Replace PhoneLookupSelector with PhoneLookupInfoConsolidator.

PhoneLookupInfoConsolidator is designed for the following two purposes.

(1) Different sub-messages in a PhoneLookupInfo proto can contain information for the same purpose. For example, all of cp2_local_info, cp2_remote_info, and people_api_info have the information for a contact's name. PhoneLookupInfoConsolidator defines the rules that determine which sub-message should be used to display the name in the UI. This is the same as PhoneLookupSelector.

(2) Avoid mixing info from different sub-messages when we are supposed to stick with only one sub-message. For example, if a PhoneLookupInfo proto has both cp2_local_info and cp2_remote_info but only cp2_remote_info has a photo URI, PhoneLookupInfoConsolidator should return an *empty* photo URI as cp2_local_info has higher priority and we should not use cp2_remote_info's photo URI to display the contact's photo. This is what PhoneLookupSelector is unable to do.

Bug: 71763594
Test: PhoneLookupInfoConsolidatorTest
PiperOrigin-RevId: 182236013
Change-Id: If19cdc1a9e076f3ebc8f9e2901f050b519e273f2
diff --git a/java/com/android/dialer/calllog/datasources/phonelookup/PhoneLookupDataSource.java b/java/com/android/dialer/calllog/datasources/phonelookup/PhoneLookupDataSource.java
index b73c169..1d4a35a 100644
--- a/java/com/android/dialer/calllog/datasources/phonelookup/PhoneLookupDataSource.java
+++ b/java/com/android/dialer/calllog/datasources/phonelookup/PhoneLookupDataSource.java
@@ -37,11 +37,12 @@
 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.inject.ApplicationContext;
 import com.android.dialer.phonelookup.PhoneLookup;
 import com.android.dialer.phonelookup.PhoneLookupInfo;
+import com.android.dialer.phonelookup.consolidator.PhoneLookupInfoConsolidator;
 import com.android.dialer.phonelookup.database.contract.PhoneLookupHistoryContract;
 import com.android.dialer.phonelookup.database.contract.PhoneLookupHistoryContract.PhoneLookupHistory;
-import com.android.dialer.phonelookup.selector.PhoneLookupSelector;
 import com.android.dialer.phonenumberproto.DialerPhoneNumberUtil;
 import com.google.common.collect.ImmutableMap;
 import com.google.common.collect.ImmutableSet;
@@ -67,8 +68,8 @@
 public final class PhoneLookupDataSource
     implements CallLogDataSource, PhoneLookup.ContentObserverCallbacks {
 
+  private final Context appContext;
   private final PhoneLookup<PhoneLookupInfo> phoneLookup;
-  private final PhoneLookupSelector phoneLookupSelector;
   private final ListeningExecutorService backgroundExecutorService;
   private final ListeningExecutorService lightweightExecutorService;
 
@@ -94,11 +95,11 @@
   @Inject
   PhoneLookupDataSource(
       PhoneLookup<PhoneLookupInfo> phoneLookup,
-      PhoneLookupSelector phoneLookupSelector,
+      @ApplicationContext Context appContext,
       @BackgroundExecutor ListeningExecutorService backgroundExecutorService,
       @LightweightExecutor ListeningExecutorService lightweightExecutorService) {
     this.phoneLookup = phoneLookup;
-    this.phoneLookupSelector = phoneLookupSelector;
+    this.appContext = appContext;
     this.backgroundExecutorService = backgroundExecutorService;
     this.lightweightExecutorService = lightweightExecutorService;
   }
@@ -579,19 +580,20 @@
   }
 
   private void updateContentValues(ContentValues contentValues, PhoneLookupInfo phoneLookupInfo) {
+    PhoneLookupInfoConsolidator phoneLookupInfoConsolidator =
+        new PhoneLookupInfoConsolidator(appContext, phoneLookupInfo);
     contentValues.put(
         AnnotatedCallLog.NUMBER_ATTRIBUTES,
         NumberAttributes.newBuilder()
-            .setName(phoneLookupSelector.selectName(phoneLookupInfo))
-            .setPhotoUri(phoneLookupSelector.selectPhotoUri(phoneLookupInfo))
-            .setPhotoId(phoneLookupSelector.selectPhotoId(phoneLookupInfo))
-            .setLookupUri(phoneLookupSelector.selectLookupUri(phoneLookupInfo))
-            .setNumberTypeLabel(phoneLookupSelector.selectNumberLabel(phoneLookupInfo))
-            .setIsBusiness(phoneLookupSelector.selectIsBusiness(phoneLookupInfo))
-            .setIsVoicemail(phoneLookupSelector.selectIsVoicemail(phoneLookupInfo))
-            .setCanReportAsInvalidNumber(
-                phoneLookupSelector.canReportAsInvalidNumber(phoneLookupInfo))
-            .setIsCp2InfoIncomplete(phoneLookupSelector.selectIsCp2InfoIncomplete(phoneLookupInfo))
+            .setName(phoneLookupInfoConsolidator.getName())
+            .setPhotoUri(phoneLookupInfoConsolidator.getPhotoUri())
+            .setPhotoId(phoneLookupInfoConsolidator.getPhotoId())
+            .setLookupUri(phoneLookupInfoConsolidator.getLookupUri())
+            .setNumberTypeLabel(phoneLookupInfoConsolidator.getNumberLabel())
+            .setIsBusiness(phoneLookupInfoConsolidator.isBusiness())
+            .setIsVoicemail(phoneLookupInfoConsolidator.isVoicemail())
+            .setCanReportAsInvalidNumber(phoneLookupInfoConsolidator.canReportAsInvalidNumber())
+            .setIsCp2InfoIncomplete(phoneLookupInfoConsolidator.isCp2LocalInfoIncomplete())
             .build()
             .toByteArray());
   }
diff --git a/java/com/android/dialer/calllog/ui/RealtimeRowProcessor.java b/java/com/android/dialer/calllog/ui/RealtimeRowProcessor.java
index 393482a..6e214ed 100644
--- a/java/com/android/dialer/calllog/ui/RealtimeRowProcessor.java
+++ b/java/com/android/dialer/calllog/ui/RealtimeRowProcessor.java
@@ -16,6 +16,7 @@
 
 package com.android.dialer.calllog.ui;
 
+import android.content.Context;
 import android.support.annotation.MainThread;
 import android.util.ArrayMap;
 import com.android.dialer.DialerPhoneNumber;
@@ -23,10 +24,11 @@
 import com.android.dialer.calllog.model.CoalescedRow;
 import com.android.dialer.common.Assert;
 import com.android.dialer.common.concurrent.Annotations.Ui;
+import com.android.dialer.inject.ApplicationContext;
 import com.android.dialer.phonelookup.PhoneLookupInfo;
 import com.android.dialer.phonelookup.PhoneLookupInfo.Cp2Info;
+import com.android.dialer.phonelookup.consolidator.PhoneLookupInfoConsolidator;
 import com.android.dialer.phonelookup.cp2.Cp2LocalPhoneLookup;
-import com.android.dialer.phonelookup.selector.PhoneLookupSelector;
 import com.google.common.base.Optional;
 import com.google.common.util.concurrent.Futures;
 import com.google.common.util.concurrent.ListenableFuture;
@@ -47,20 +49,20 @@
  */
 public final class RealtimeRowProcessor {
 
-  private final ListeningExecutorService uiExecutor;
+  private final Context appContext;
   private final Cp2LocalPhoneLookup cp2LocalPhoneLookup;
-  private final PhoneLookupSelector phoneLookupSelector;
+  private final ListeningExecutorService uiExecutor;
 
   private final Map<DialerPhoneNumber, Cp2Info> cache = new ArrayMap<>();
 
   @Inject
   RealtimeRowProcessor(
+      @ApplicationContext Context appContext,
       @Ui ListeningExecutorService uiExecutor,
-      Cp2LocalPhoneLookup cp2LocalPhoneLookup,
-      PhoneLookupSelector phoneLookupSelector) {
+      Cp2LocalPhoneLookup cp2LocalPhoneLookup) {
+    this.appContext = appContext;
     this.uiExecutor = uiExecutor;
     this.cp2LocalPhoneLookup = cp2LocalPhoneLookup;
-    this.phoneLookupSelector = phoneLookupSelector;
   }
 
   /**
@@ -104,19 +106,20 @@
 
   private CoalescedRow applyCp2LocalInfoToRow(Cp2Info cp2Info, CoalescedRow row) {
     PhoneLookupInfo phoneLookupInfo = PhoneLookupInfo.newBuilder().setCp2LocalInfo(cp2Info).build();
+    PhoneLookupInfoConsolidator phoneLookupInfoConsolidator =
+        new PhoneLookupInfoConsolidator(appContext, phoneLookupInfo);
     // It is safe to overwrite any existing data because CP2 always has highest priority.
     return row.toBuilder()
         .setNumberAttributes(
             NumberAttributes.newBuilder()
-                .setName(phoneLookupSelector.selectName(phoneLookupInfo))
-                .setPhotoUri(phoneLookupSelector.selectPhotoUri(phoneLookupInfo))
-                .setPhotoId(phoneLookupSelector.selectPhotoId(phoneLookupInfo))
-                .setLookupUri(phoneLookupSelector.selectLookupUri(phoneLookupInfo))
-                .setNumberTypeLabel(phoneLookupSelector.selectNumberLabel(phoneLookupInfo))
-                .setIsBusiness(phoneLookupSelector.selectIsBusiness(phoneLookupInfo))
-                .setIsVoicemail(phoneLookupSelector.selectIsVoicemail(phoneLookupInfo))
-                .setCanReportAsInvalidNumber(
-                    phoneLookupSelector.canReportAsInvalidNumber(phoneLookupInfo))
+                .setName(phoneLookupInfoConsolidator.getName())
+                .setPhotoUri(phoneLookupInfoConsolidator.getPhotoUri())
+                .setPhotoId(phoneLookupInfoConsolidator.getPhotoId())
+                .setLookupUri(phoneLookupInfoConsolidator.getLookupUri())
+                .setNumberTypeLabel(phoneLookupInfoConsolidator.getNumberLabel())
+                .setIsBusiness(phoneLookupInfoConsolidator.isBusiness())
+                .setIsVoicemail(phoneLookupInfoConsolidator.isVoicemail())
+                .setCanReportAsInvalidNumber(phoneLookupInfoConsolidator.canReportAsInvalidNumber())
                 .build())
         .build();
   }
diff --git a/java/com/android/dialer/phonelookup/selector/AndroidManifest.xml b/java/com/android/dialer/phonelookup/consolidator/AndroidManifest.xml
similarity index 91%
rename from java/com/android/dialer/phonelookup/selector/AndroidManifest.xml
rename to java/com/android/dialer/phonelookup/consolidator/AndroidManifest.xml
index 5d836c7..98e07e5 100644
--- a/java/com/android/dialer/phonelookup/selector/AndroidManifest.xml
+++ b/java/com/android/dialer/phonelookup/consolidator/AndroidManifest.xml
@@ -14,5 +14,5 @@
  ~ limitations under the License
  -->
 <manifest
-    package="com.android.dialer.phonelookup.selector">
+    package="com.android.dialer.phonelookup.consolidator">
 </manifest>
diff --git a/java/com/android/dialer/phonelookup/consolidator/PhoneLookupInfoConsolidator.java b/java/com/android/dialer/phonelookup/consolidator/PhoneLookupInfoConsolidator.java
new file mode 100644
index 0000000..ccad3e7
--- /dev/null
+++ b/java/com/android/dialer/phonelookup/consolidator/PhoneLookupInfoConsolidator.java
@@ -0,0 +1,306 @@
+/*
+ * 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.phonelookup.consolidator;
+
+import android.content.Context;
+import android.support.annotation.IntDef;
+import android.support.annotation.Nullable;
+import com.android.dialer.common.Assert;
+import com.android.dialer.phonelookup.PhoneLookup;
+import com.android.dialer.phonelookup.PhoneLookupInfo;
+import com.android.dialer.phonelookup.PhoneLookupInfo.BlockedState;
+import com.android.dialer.phonelookup.PhoneLookupInfo.Cp2Info.Cp2ContactInfo;
+import com.android.dialer.phonelookup.PhoneLookupInfo.PeopleApiInfo;
+import com.android.dialer.phonelookup.PhoneLookupInfo.PeopleApiInfo.InfoType;
+import com.google.common.collect.ImmutableList;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
+/**
+ * Consolidates information from a {@link PhoneLookupInfo}.
+ *
+ * <p>For example, a single {@link PhoneLookupInfo} may contain different name information from many
+ * different {@link PhoneLookup} implementations. This class defines the rules for deciding which
+ * name should be selected for display to the user, by prioritizing the data from some {@link
+ * PhoneLookup PhoneLookups} over others.
+ */
+public final class PhoneLookupInfoConsolidator {
+
+  /** Integers representing {@link PhoneLookup} implementations that can provide a contact's name */
+  @Retention(RetentionPolicy.SOURCE)
+  @IntDef({NameSource.NONE, NameSource.CP2_LOCAL, NameSource.CP2_REMOTE, NameSource.PEOPLE_API})
+  @interface NameSource {
+    int NONE = 0; // used when none of the other sources can provide the name
+    int CP2_LOCAL = 1;
+    int CP2_REMOTE = 2;
+    int PEOPLE_API = 3;
+  }
+
+  /**
+   * Sources that can provide information about a contact's name.
+   *
+   * <p>Each source is one of the values in NameSource, as defined above.
+   *
+   * <p>Sources are sorted in the order of priority. For example, if source CP2_LOCAL can provide
+   * the name, we will use that name in the UI and ignore all the other sources. If source CP2_LOCAL
+   * can't provide the name, source CP2_REMOTE will be consulted.
+   *
+   * <p>The reason for defining a name source is to avoid mixing info from different sub-messages in
+   * PhoneLookupInfo proto when we are supposed to stick with only one sub-message. For example, if
+   * a PhoneLookupInfo proto has both cp2_local_info and cp2_remote_info but only cp2_remote_info
+   * has a photo URI, PhoneLookupInfoConsolidator should provide an empty photo URI as CP2_LOCAL has
+   * higher priority and we should not use cp2_remote_info's photo URI to display the contact's
+   * photo.
+   */
+  private static final ImmutableList<Integer> NAME_SOURCES_IN_PRIORITY_ORDER =
+      ImmutableList.of(NameSource.CP2_LOCAL, NameSource.CP2_REMOTE, NameSource.PEOPLE_API);
+
+  private final Context appContext;
+  private final @NameSource int nameSource;
+  private final PhoneLookupInfo phoneLookupInfo;
+
+  @Nullable private final Cp2ContactInfo firstCp2LocalContact;
+  @Nullable private final Cp2ContactInfo firstCp2RemoteContact;
+
+  public PhoneLookupInfoConsolidator(Context appContext, PhoneLookupInfo phoneLookupInfo) {
+    this.appContext = appContext;
+    this.phoneLookupInfo = phoneLookupInfo;
+
+    this.firstCp2LocalContact = getFirstLocalContact();
+    this.firstCp2RemoteContact = getFirstRemoteContact();
+    this.nameSource = selectNameSource();
+  }
+
+  /**
+   * The {@link PhoneLookupInfo} passed to the constructor is associated with a number. This method
+   * returns the name associated with that number.
+   *
+   * <p>Examples of this are a local contact's name or a business name received from caller ID.
+   *
+   * <p>If no name can be obtained from the {@link PhoneLookupInfo}, an empty string will be
+   * returned.
+   */
+  public String getName() {
+    switch (nameSource) {
+      case NameSource.CP2_LOCAL:
+        return Assert.isNotNull(firstCp2LocalContact).getName();
+      case NameSource.CP2_REMOTE:
+        return Assert.isNotNull(firstCp2RemoteContact).getName();
+      case NameSource.PEOPLE_API:
+        return phoneLookupInfo.getPeopleApiInfo().getDisplayName();
+      case NameSource.NONE:
+        return "";
+      default:
+        throw Assert.createUnsupportedOperationFailException(
+            String.format("Unsupported name source: %s", nameSource));
+    }
+  }
+
+  /**
+   * The {@link PhoneLookupInfo} passed to the constructor is associated with a number. This method
+   * returns the photo URI associated with that number.
+   *
+   * <p>If no photo URI can be obtained from the {@link PhoneLookupInfo}, an empty string will be
+   * returned.
+   */
+  public String getPhotoUri() {
+    switch (nameSource) {
+      case NameSource.CP2_LOCAL:
+        return Assert.isNotNull(firstCp2LocalContact).getPhotoUri();
+      case NameSource.CP2_REMOTE:
+        return Assert.isNotNull(firstCp2RemoteContact).getPhotoUri();
+      case NameSource.PEOPLE_API:
+      case NameSource.NONE:
+        return "";
+      default:
+        throw Assert.createUnsupportedOperationFailException(
+            String.format("Unsupported name source: %s", nameSource));
+    }
+  }
+
+  /**
+   * The {@link PhoneLookupInfo} passed to the constructor is associated with a number. This method
+   * returns the photo ID associated with that number, or 0 if there is none.
+   */
+  public long getPhotoId() {
+    switch (nameSource) {
+      case NameSource.CP2_LOCAL:
+        return Math.max(Assert.isNotNull(firstCp2LocalContact).getPhotoId(), 0);
+      case NameSource.CP2_REMOTE:
+        return Math.max(Assert.isNotNull(firstCp2RemoteContact).getPhotoId(), 0);
+      case NameSource.PEOPLE_API:
+      case NameSource.NONE:
+        return 0;
+      default:
+        throw Assert.createUnsupportedOperationFailException(
+            String.format("Unsupported name source: %s", nameSource));
+    }
+  }
+
+  /**
+   * The {@link PhoneLookupInfo} passed to the constructor is associated with a number. This method
+   * returns the lookup URI associated with that number, or an empty string if no lookup URI can be
+   * obtained.
+   */
+  public String getLookupUri() {
+    switch (nameSource) {
+      case NameSource.CP2_LOCAL:
+        return Assert.isNotNull(firstCp2LocalContact).getLookupUri();
+      case NameSource.CP2_REMOTE:
+        return Assert.isNotNull(firstCp2RemoteContact).getLookupUri();
+      case NameSource.PEOPLE_API:
+      case NameSource.NONE:
+        return "";
+      default:
+        throw Assert.createUnsupportedOperationFailException(
+            String.format("Unsupported name source: %s", nameSource));
+    }
+  }
+
+  /**
+   * The {@link PhoneLookupInfo} passed to the constructor is associated with a number. This method
+   * returns a localized string representing the number type such as "Home" or "Mobile", or a custom
+   * value set by the user.
+   *
+   * <p>If no label can be obtained from the {@link PhoneLookupInfo}, an empty string will be
+   * returned.
+   */
+  public String getNumberLabel() {
+    if (phoneLookupInfo.hasDialerBlockedNumberInfo()
+        && phoneLookupInfo
+            .getDialerBlockedNumberInfo()
+            .getBlockedState()
+            .equals(BlockedState.BLOCKED)) {
+      return appContext.getString(R.string.blocked_number_new_call_log_label);
+    }
+
+    switch (nameSource) {
+      case NameSource.CP2_LOCAL:
+        return Assert.isNotNull(firstCp2LocalContact).getLabel();
+      case NameSource.CP2_REMOTE:
+        return Assert.isNotNull(firstCp2RemoteContact).getLabel();
+      case NameSource.PEOPLE_API:
+      case NameSource.NONE:
+        return "";
+      default:
+        throw Assert.createUnsupportedOperationFailException(
+            String.format("Unsupported name source: %s", nameSource));
+    }
+  }
+
+  /**
+   * The {@link PhoneLookupInfo} passed to the constructor is associated with a number. This method
+   * returns whether the number belongs to a business place.
+   */
+  public boolean isBusiness() {
+    return phoneLookupInfo.hasPeopleApiInfo()
+        && phoneLookupInfo.getPeopleApiInfo().getInfoType() == InfoType.NEARBY_BUSINESS;
+  }
+
+  /**
+   * The {@link PhoneLookupInfo} passed to the constructor is associated with a number. This method
+   * returns whether the number is a voicemail number.
+   */
+  public boolean isVoicemail() {
+    // TODO(twyen): implement
+    return false;
+  }
+
+  /**
+   * Returns true if the {@link PhoneLookupInfo} passed to the constructor has incomplete CP2 local
+   * info.
+   */
+  public boolean isCp2LocalInfoIncomplete() {
+    return phoneLookupInfo.getCp2LocalInfo().getIsIncomplete();
+  }
+
+  /**
+   * The {@link PhoneLookupInfo} passed to the constructor is associated with a number. This method
+   * returns whether the number can be reported as invalid.
+   *
+   * <p>As we currently report invalid numbers via the People API, only numbers from the People API
+   * can be reported as invalid.
+   */
+  public boolean canReportAsInvalidNumber() {
+    switch (nameSource) {
+      case NameSource.CP2_LOCAL:
+      case NameSource.CP2_REMOTE:
+        return false;
+      case NameSource.PEOPLE_API:
+        PeopleApiInfo peopleApiInfo = phoneLookupInfo.getPeopleApiInfo();
+        return peopleApiInfo.getInfoType() != InfoType.UNKNOWN
+            && !peopleApiInfo.getPersonId().isEmpty();
+      case NameSource.NONE:
+        return false;
+      default:
+        throw Assert.createUnsupportedOperationFailException(
+            String.format("Unsupported name source: %s", nameSource));
+    }
+  }
+
+  /**
+   * Arbitrarily select the first local CP2 contact. In the future, it may make sense to display
+   * contact information from all contacts with the same number (for example show the name as "Mom,
+   * Dad" or show a synthesized photo containing photos of both "Mom" and "Dad").
+   */
+  @Nullable
+  private Cp2ContactInfo getFirstLocalContact() {
+    return phoneLookupInfo.getCp2LocalInfo().getCp2ContactInfoCount() > 0
+        ? phoneLookupInfo.getCp2LocalInfo().getCp2ContactInfo(0)
+        : null;
+  }
+
+  /**
+   * Arbitrarily select the first remote CP2 contact. In the future, it may make sense to display
+   * contact information from all contacts with the same number (for example show the name as "Mom,
+   * Dad" or show a synthesized photo containing photos of both "Mom" and "Dad").
+   */
+  @Nullable
+  private Cp2ContactInfo getFirstRemoteContact() {
+    return phoneLookupInfo.getCp2RemoteInfo().getCp2ContactInfoCount() > 0
+        ? phoneLookupInfo.getCp2RemoteInfo().getCp2ContactInfo(0)
+        : null;
+  }
+
+  /** Select the {@link PhoneLookup} source providing a contact's name. */
+  private @NameSource int selectNameSource() {
+    for (int nameSource : NAME_SOURCES_IN_PRIORITY_ORDER) {
+      switch (nameSource) {
+        case NameSource.CP2_LOCAL:
+          if (firstCp2LocalContact != null && !firstCp2LocalContact.getName().isEmpty()) {
+            return NameSource.CP2_LOCAL;
+          }
+          break;
+        case NameSource.CP2_REMOTE:
+          if (firstCp2RemoteContact != null && !firstCp2RemoteContact.getName().isEmpty()) {
+            return NameSource.CP2_REMOTE;
+          }
+          break;
+        case NameSource.PEOPLE_API:
+          if (phoneLookupInfo.hasPeopleApiInfo()
+              && !phoneLookupInfo.getPeopleApiInfo().getDisplayName().isEmpty()) {
+            return NameSource.PEOPLE_API;
+          }
+          break;
+        default:
+          throw Assert.createUnsupportedOperationFailException(
+              String.format("Unsupported name source: %s", nameSource));
+      }
+    }
+
+    return NameSource.NONE;
+  }
+}
diff --git a/java/com/android/dialer/phonelookup/selector/res/values/strings.xml b/java/com/android/dialer/phonelookup/consolidator/res/values/strings.xml
similarity index 100%
rename from java/com/android/dialer/phonelookup/selector/res/values/strings.xml
rename to java/com/android/dialer/phonelookup/consolidator/res/values/strings.xml
diff --git a/java/com/android/dialer/phonelookup/selector/PhoneLookupSelector.java b/java/com/android/dialer/phonelookup/selector/PhoneLookupSelector.java
deleted file mode 100644
index 8d08291..0000000
--- a/java/com/android/dialer/phonelookup/selector/PhoneLookupSelector.java
+++ /dev/null
@@ -1,182 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License
- */
-package com.android.dialer.phonelookup.selector;
-
-import android.content.Context;
-import android.support.annotation.NonNull;
-import android.support.annotation.Nullable;
-import android.support.annotation.VisibleForTesting;
-import com.android.dialer.inject.ApplicationContext;
-import com.android.dialer.phonelookup.PhoneLookup;
-import com.android.dialer.phonelookup.PhoneLookupInfo;
-import com.android.dialer.phonelookup.PhoneLookupInfo.BlockedState;
-import com.android.dialer.phonelookup.PhoneLookupInfo.Cp2Info.Cp2ContactInfo;
-import com.android.dialer.phonelookup.PhoneLookupInfo.PeopleApiInfo;
-import com.android.dialer.phonelookup.PhoneLookupInfo.PeopleApiInfo.InfoType;
-import javax.inject.Inject;
-
-/**
- * Prioritizes information from a {@link PhoneLookupInfo}.
- *
- * <p>For example, a single {@link PhoneLookupInfo} may contain different name information from many
- * different {@link PhoneLookup} sources. This class defines the rules for deciding which name
- * should be selected for display to the user, by prioritizing the data from some {@link PhoneLookup
- * PhoneLookups} over others.
- *
- * <p>Note that the logic in this class may be highly coupled with the logic in {@code
- * CompositePhoneLookup}, because {@code CompositePhoneLookup} may also include prioritization logic
- * for short-circuiting low-priority {@link PhoneLookup PhoneLookups}.
- */
-public final class PhoneLookupSelector {
-
-  private final Context appContext;
-
-  @Inject
-  @VisibleForTesting(otherwise = VisibleForTesting.PACKAGE_PRIVATE)
-  public PhoneLookupSelector(@ApplicationContext Context appContext) {
-    this.appContext = appContext;
-  }
-
-  /**
-   * Select the name associated with this number. Examples of this are a local contact's name or a
-   * business name received from caller ID.
-   */
-  @NonNull
-  public String selectName(PhoneLookupInfo phoneLookupInfo) {
-    Cp2ContactInfo firstLocalContact = firstLocalContact(phoneLookupInfo);
-    if (firstLocalContact != null) {
-      String name = firstLocalContact.getName();
-      if (!name.isEmpty()) {
-        return firstLocalContact.getName();
-      }
-    }
-    if (phoneLookupInfo.hasPeopleApiInfo()) {
-      return phoneLookupInfo.getPeopleApiInfo().getDisplayName();
-    }
-    return "";
-  }
-
-  /** Select the photo URI associated with this number. */
-  @NonNull
-  public String selectPhotoUri(PhoneLookupInfo phoneLookupInfo) {
-    Cp2ContactInfo firstLocalContact = firstLocalContact(phoneLookupInfo);
-    if (firstLocalContact != null) {
-      String photoUri = firstLocalContact.getPhotoUri();
-      if (!photoUri.isEmpty()) {
-        return photoUri;
-      }
-    }
-    return "";
-  }
-
-  /** Select the photo ID associated with this number, or 0 if there is none. */
-  public long selectPhotoId(PhoneLookupInfo phoneLookupInfo) {
-    Cp2ContactInfo firstLocalContact = firstLocalContact(phoneLookupInfo);
-    if (firstLocalContact != null) {
-      long photoId = firstLocalContact.getPhotoId();
-      if (photoId > 0) {
-        return photoId;
-      }
-    }
-    return 0;
-  }
-
-  /** Select the lookup URI associated with this number. */
-  @NonNull
-  public String selectLookupUri(PhoneLookupInfo phoneLookupInfo) {
-    Cp2ContactInfo firstLocalContact = firstLocalContact(phoneLookupInfo);
-    if (firstLocalContact != null) {
-      String lookupUri = firstLocalContact.getLookupUri();
-      if (!lookupUri.isEmpty()) {
-        return lookupUri;
-      }
-    }
-    return "";
-  }
-
-  /**
-   * A localized string representing the number type such as "Home" or "Mobile", or a custom value
-   * set by the user.
-   */
-  @NonNull
-  public String selectNumberLabel(PhoneLookupInfo phoneLookupInfo) {
-    if (isBlocked(phoneLookupInfo)) {
-      return appContext.getString(R.string.blocked_number_new_call_log_label);
-    }
-
-    Cp2ContactInfo firstLocalContact = firstLocalContact(phoneLookupInfo);
-    if (firstLocalContact != null) {
-      String label = firstLocalContact.getLabel();
-      if (!label.isEmpty()) {
-        return label;
-      }
-    }
-    return "";
-  }
-
-  public boolean selectIsBusiness(PhoneLookupInfo phoneLookupInfo) {
-    return phoneLookupInfo.hasPeopleApiInfo()
-        && phoneLookupInfo.getPeopleApiInfo().getInfoType() == InfoType.NEARBY_BUSINESS;
-  }
-
-  public boolean selectIsVoicemail(PhoneLookupInfo unused) {
-    // TODO(twyen): implement
-    return false;
-  }
-
-  public boolean selectIsCp2InfoIncomplete(PhoneLookupInfo phoneLookupInfo) {
-    return phoneLookupInfo.getCp2LocalInfo().getIsIncomplete();
-  }
-
-  /**
-   * Returns true if the number associated with the given {@link PhoneLookupInfo} can be reported as
-   * invalid.
-   *
-   * <p>As we currently report invalid numbers via the People API, only numbers from the People API
-   * can be reported as invalid.
-   */
-  public boolean canReportAsInvalidNumber(PhoneLookupInfo phoneLookupInfo) {
-    // The presence of Cp2ContactInfo means the number associated with the given PhoneLookupInfo
-    // matches that of a Cp2 (local) contact, and PeopleApiInfo will not be used to display
-    // information like name, photo, etc. We should not allow the user to report the number in this
-    // case as the info displayed is not from the People API.
-    if (phoneLookupInfo.getCp2LocalInfo().getCp2ContactInfoCount() > 0) {
-      return false;
-    }
-
-    PeopleApiInfo peopleApiInfo = phoneLookupInfo.getPeopleApiInfo();
-    return peopleApiInfo.getInfoType() != InfoType.UNKNOWN
-        && !peopleApiInfo.getPersonId().isEmpty();
-  }
-
-  /**
-   * Arbitrarily select the first contact. In the future, it may make sense to display contact
-   * information from all contacts with the same number (for example show the name as "Mom, Dad" or
-   * show a synthesized photo containing photos of both "Mom" and "Dad").
-   */
-  @Nullable
-  private Cp2ContactInfo firstLocalContact(PhoneLookupInfo phoneLookupInfo) {
-    if (phoneLookupInfo.getCp2LocalInfo().getCp2ContactInfoCount() > 0) {
-      return phoneLookupInfo.getCp2LocalInfo().getCp2ContactInfo(0);
-    }
-    return null;
-  }
-
-  private static boolean isBlocked(PhoneLookupInfo info) {
-    return info.hasDialerBlockedNumberInfo()
-        && info.getDialerBlockedNumberInfo().getBlockedState().equals(BlockedState.BLOCKED);
-  }
-}
diff --git a/packages.mk b/packages.mk
index 2a445a3..d4b225a 100644
--- a/packages.mk
+++ b/packages.mk
@@ -41,7 +41,7 @@
 	com.android.dialer.notification \
 	com.android.dialer.oem \
 	com.android.dialer.phonelookup.database \
-	com.android.dialer.phonelookup.selector \
+	com.android.dialer.phonelookup.consolidator \
 	com.android.dialer.phonenumberutil \
 	com.android.dialer.postcall \
 	com.android.dialer.precall.impl \