Implemented CompositePhoneLookup#bulkUpdate.

Bug: 34672501
Test: unit
PiperOrigin-RevId: 174532642
Change-Id: I0115fb26f99fe764bc90625e3ed51f3c4c99439d
diff --git a/java/com/android/dialer/phonelookup/composite/CompositePhoneLookup.java b/java/com/android/dialer/phonelookup/composite/CompositePhoneLookup.java
index ba08fe9..f85b357 100644
--- a/java/com/android/dialer/phonelookup/composite/CompositePhoneLookup.java
+++ b/java/com/android/dialer/phonelookup/composite/CompositePhoneLookup.java
@@ -19,6 +19,7 @@
 import android.support.annotation.NonNull;
 import android.telecom.Call;
 import com.android.dialer.DialerPhoneNumber;
+import com.android.dialer.common.LogUtil;
 import com.android.dialer.common.concurrent.DialerFutures;
 import com.android.dialer.phonelookup.PhoneLookup;
 import com.android.dialer.phonelookup.PhoneLookupInfo;
@@ -85,9 +86,47 @@
         futures, Preconditions::checkNotNull, false /* defaultValue */);
   }
 
+  /**
+   * Delegates to a set of dependent lookups and combines results.
+   *
+   * <p>Note: If any of the dependent lookups fails, the returned future will also fail. If any of
+   * the dependent lookups does not complete, the returned future will also not complete.
+   */
   @Override
   public ListenableFuture<ImmutableMap<DialerPhoneNumber, PhoneLookupInfo>> bulkUpdate(
       ImmutableMap<DialerPhoneNumber, PhoneLookupInfo> existingInfoMap, long lastModified) {
-    return null;
+    List<ListenableFuture<ImmutableMap<DialerPhoneNumber, PhoneLookupInfo>>> futures =
+        new ArrayList<>();
+    for (PhoneLookup phoneLookup : phoneLookups) {
+      futures.add(phoneLookup.bulkUpdate(existingInfoMap, lastModified));
+    }
+    return Futures.transform(
+        Futures.allAsList(futures),
+        new Function<
+            List<ImmutableMap<DialerPhoneNumber, PhoneLookupInfo>>,
+            ImmutableMap<DialerPhoneNumber, PhoneLookupInfo>>() {
+          @Override
+          public ImmutableMap<DialerPhoneNumber, PhoneLookupInfo> apply(
+              List<ImmutableMap<DialerPhoneNumber, PhoneLookupInfo>> allMaps) {
+            ImmutableMap.Builder<DialerPhoneNumber, PhoneLookupInfo> combinedMap =
+                ImmutableMap.builder();
+            for (DialerPhoneNumber dialerPhoneNumber : existingInfoMap.keySet()) {
+              PhoneLookupInfo.Builder combinedInfo = PhoneLookupInfo.newBuilder();
+              for (ImmutableMap<DialerPhoneNumber, PhoneLookupInfo> map : allMaps) {
+                PhoneLookupInfo subInfo = map.get(dialerPhoneNumber);
+                if (subInfo == null) {
+                  throw new IllegalStateException(
+                      "A sublookup didn't return an info for number: "
+                          + LogUtil.sanitizePhoneNumber(
+                              dialerPhoneNumber.getRawInput().getNumber()));
+                }
+                combinedInfo.mergeFrom(subInfo);
+              }
+              combinedMap.put(dialerPhoneNumber, combinedInfo.build());
+            }
+            return combinedMap.build();
+          }
+        },
+        MoreExecutors.directExecutor());
   }
 }