From af719e9e11aebf649d01651ed1960c6db9c1f2ef Mon Sep 17 00:00:00 2001 From: Zachary Heidepriem Date: Wed, 1 Nov 2017 12:24:16 -0700 Subject: Added CompositePhoneLookup and added and implemented "lookup" method. Fleshed out docs for PhoneLookup. Added dagger components and modules. Bug: 34672501 Test: unit PiperOrigin-RevId: 173977963 Change-Id: If07795d9d3d56a59afd27cdda3e98543bf30fdb8 --- .../android/dialer/phonelookup/PhoneLookup.java | 35 ++++++--- .../dialer/phonelookup/PhoneLookupComponent.java | 37 ++++++++++ .../dialer/phonelookup/PhoneLookupModule.java | 33 +++++++++ .../composite/CompositePhoneLookup.java | 84 ++++++++++++++++++++++ .../dialer/phonelookup/cp2/Cp2PhoneLookup.java | 24 +++++-- .../dialer/phonelookup/phone_lookup_info.proto | 10 ++- 6 files changed, 205 insertions(+), 18 deletions(-) create mode 100644 java/com/android/dialer/phonelookup/PhoneLookupComponent.java create mode 100644 java/com/android/dialer/phonelookup/PhoneLookupModule.java create mode 100644 java/com/android/dialer/phonelookup/composite/CompositePhoneLookup.java (limited to 'java/com/android/dialer/phonelookup') diff --git a/java/com/android/dialer/phonelookup/PhoneLookup.java b/java/com/android/dialer/phonelookup/PhoneLookup.java index 63b01c8e6..66f166d6d 100644 --- a/java/com/android/dialer/phonelookup/PhoneLookup.java +++ b/java/com/android/dialer/phonelookup/PhoneLookup.java @@ -16,30 +16,47 @@ package com.android.dialer.phonelookup; +import android.support.annotation.NonNull; +import android.telecom.Call; import com.android.dialer.DialerPhoneNumber; import com.google.common.collect.ImmutableMap; import com.google.common.collect.ImmutableSet; import com.google.common.util.concurrent.ListenableFuture; -/** TODO(zachh) update documentation. */ +/** + * Provides operations related to retrieving information about phone numbers. + * + *

Some operations defined by this interface are generally targeted towards specific use cases; + * for example {@link #isDirty(ImmutableSet, long)} and {@link #bulkUpdate(ImmutableMap, long)} are + * generally intended to be used by the call log. + */ public interface PhoneLookup { /** - * For Call Log "isDirty" operation. + * Returns a future containing a new {@link PhoneLookupInfo} for the provided call. * - * @param phoneNumbers - * @param lastModified - * @return TODO(zachh) + *

The returned message should contain populated data for the sub-message corresponding to this + * {@link PhoneLookup}. For example, the CP2 implementation returns a {@link PhoneLookupInfo} with + * the {@link PhoneLookupInfo.Cp2Info} sub-message populated. + */ + ListenableFuture lookup(@NonNull Call call); + + /** + * Returns a future which returns true if the information for any of the provided phone numbers + * has changed since {@code lastModified} according to this {@link PhoneLookup}. */ ListenableFuture isDirty( ImmutableSet phoneNumbers, long lastModified); /** - * For Call Log "fill" operation. + * Given a set of existing information and a timestamp, returns a set of information with any + * changes made since the timestamp according to this {@link PhoneLookup}. + * + *

If there are no changes required, it is valid for this method to simply return the provided + * {@code existingInfoMap}. * - * @param existingInfoMap - * @param lastModified - * @return TODO(zachh) + *

If there is no longer information associated with a number (for example, a local contact was + * deleted) the returned map should contain an empty {@link PhoneLookupInfo} for that number. */ ListenableFuture> bulkUpdate( ImmutableMap existingInfoMap, long lastModified); diff --git a/java/com/android/dialer/phonelookup/PhoneLookupComponent.java b/java/com/android/dialer/phonelookup/PhoneLookupComponent.java new file mode 100644 index 000000000..6d1f9a2fc --- /dev/null +++ b/java/com/android/dialer/phonelookup/PhoneLookupComponent.java @@ -0,0 +1,37 @@ +/* + * 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; + +import android.content.Context; +import com.android.dialer.inject.HasRootComponent; +import dagger.Subcomponent; + +/** Dagger component for the PhoneLookup package. */ +@Subcomponent +public abstract class PhoneLookupComponent { + + public abstract PhoneLookup phoneLookup(); + + public static PhoneLookupComponent get(Context context) { + return ((HasComponent) ((HasRootComponent) context.getApplicationContext()).component()) + .phoneLookupComponent(); + } + + /** Used to refer to the root application component. */ + public interface HasComponent { + PhoneLookupComponent phoneLookupComponent(); + } +} diff --git a/java/com/android/dialer/phonelookup/PhoneLookupModule.java b/java/com/android/dialer/phonelookup/PhoneLookupModule.java new file mode 100644 index 000000000..400caff3a --- /dev/null +++ b/java/com/android/dialer/phonelookup/PhoneLookupModule.java @@ -0,0 +1,33 @@ +/* + * 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; + +import com.android.dialer.phonelookup.composite.CompositePhoneLookup; +import com.android.dialer.phonelookup.cp2.Cp2PhoneLookup; +import com.google.common.collect.ImmutableList; +import dagger.Module; +import dagger.Provides; + +/** Dagger module which binds the PhoneLookup implementation. */ +@Module +public abstract class PhoneLookupModule { + + @Provides + static PhoneLookup providePhoneLookup(Cp2PhoneLookup cp2PhoneLookup) { + return new CompositePhoneLookup(ImmutableList.of(cp2PhoneLookup)); + } +} diff --git a/java/com/android/dialer/phonelookup/composite/CompositePhoneLookup.java b/java/com/android/dialer/phonelookup/composite/CompositePhoneLookup.java new file mode 100644 index 000000000..10b0e24d2 --- /dev/null +++ b/java/com/android/dialer/phonelookup/composite/CompositePhoneLookup.java @@ -0,0 +1,84 @@ +/* + * 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.composite; + +import android.support.annotation.NonNull; +import android.telecom.Call; +import com.android.dialer.DialerPhoneNumber; +import com.android.dialer.phonelookup.PhoneLookup; +import com.android.dialer.phonelookup.PhoneLookupInfo; +import com.google.common.base.Function; +import com.google.common.collect.ImmutableList; +import com.google.common.collect.ImmutableMap; +import com.google.common.collect.ImmutableSet; +import com.google.common.util.concurrent.Futures; +import com.google.common.util.concurrent.ListenableFuture; +import com.google.common.util.concurrent.MoreExecutors; +import java.util.ArrayList; +import java.util.List; + +/** + * {@link PhoneLookup} which delegates to a configured set of {@link PhoneLookup PhoneLookups}, + * iterating, prioritizing, and coalescing data as necessary. + */ +public final class CompositePhoneLookup implements PhoneLookup { + + private final ImmutableList phoneLookups; + + public CompositePhoneLookup(ImmutableList phoneLookups) { + this.phoneLookups = phoneLookups; + } + + /** + * Delegates to a set of dependent lookups to build a complete {@link PhoneLookupInfo}. + * + *

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 lookup(@NonNull Call call) { + List> futures = new ArrayList<>(); + for (PhoneLookup phoneLookup : phoneLookups) { + futures.add(phoneLookup.lookup(call)); + } + return Futures.transform( + Futures.allAsList(futures), + new Function, PhoneLookupInfo>() { + @Override + public PhoneLookupInfo apply(List infos) { + PhoneLookupInfo.Builder mergedInfo = PhoneLookupInfo.newBuilder(); + for (PhoneLookupInfo info : infos) { + mergedInfo.mergeFrom(info); + } + return mergedInfo.build(); + } + }, + MoreExecutors.directExecutor()); + } + + @Override + public ListenableFuture isDirty( + ImmutableSet phoneNumbers, long lastModified) { + return null; + } + + @Override + public ListenableFuture> bulkUpdate( + ImmutableMap existingInfoMap, long lastModified) { + return null; + } +} diff --git a/java/com/android/dialer/phonelookup/cp2/Cp2PhoneLookup.java b/java/com/android/dialer/phonelookup/cp2/Cp2PhoneLookup.java index a3d97c64e..f9fc1a6f4 100644 --- a/java/com/android/dialer/phonelookup/cp2/Cp2PhoneLookup.java +++ b/java/com/android/dialer/phonelookup/cp2/Cp2PhoneLookup.java @@ -21,9 +21,12 @@ import android.database.Cursor; import android.provider.ContactsContract.CommonDataKinds.Phone; import android.provider.ContactsContract.Contacts; import android.provider.ContactsContract.DeletedContacts; +import android.support.annotation.NonNull; import android.support.v4.util.ArraySet; +import android.telecom.Call; import com.android.dialer.DialerPhoneNumber; import com.android.dialer.common.concurrent.DialerExecutors; +import com.android.dialer.inject.ApplicationContext; import com.android.dialer.phonelookup.PhoneLookup; import com.android.dialer.phonelookup.PhoneLookupInfo; import com.google.common.collect.ImmutableMap; @@ -31,21 +34,28 @@ import com.google.common.collect.ImmutableSet; import com.google.common.util.concurrent.ListenableFuture; import com.google.common.util.concurrent.MoreExecutors; import java.util.Set; +import javax.inject.Inject; /** PhoneLookup implementation for local contacts. */ public final class Cp2PhoneLookup implements PhoneLookup { - private final Context context; + private final Context appContext; - Cp2PhoneLookup(Context context) { - this.context = context; + @Inject + Cp2PhoneLookup(@ApplicationContext Context appContext) { + this.appContext = appContext; + } + + @Override + public ListenableFuture lookup(@NonNull Call call) { + throw new UnsupportedOperationException(); } @Override public ListenableFuture isDirty( ImmutableSet phoneNumbers, long lastModified) { // TODO(calderwoodra): consider a different thread pool - return MoreExecutors.listeningDecorator(DialerExecutors.getLowPriorityThreadPool(context)) + return MoreExecutors.listeningDecorator(DialerExecutors.getLowPriorityThreadPool(appContext)) .submit(() -> isDirtyInternal(phoneNumbers, lastModified)); } @@ -58,7 +68,7 @@ public final class Cp2PhoneLookup implements PhoneLookup { private Set getContactIdsFromPhoneNumbers(ImmutableSet phoneNumbers) { Set contactIds = new ArraySet<>(); try (Cursor cursor = - context + appContext .getContentResolver() .query( Phone.CONTENT_URI, @@ -91,7 +101,7 @@ public final class Cp2PhoneLookup implements PhoneLookup { /** Returns true if any contacts were modified after {@code lastModified}. */ private boolean contactsUpdated(Set contactIds, long lastModified) { try (Cursor cursor = - context + appContext .getContentResolver() .query( Contacts.CONTENT_URI, @@ -126,7 +136,7 @@ public final class Cp2PhoneLookup implements PhoneLookup { /** Returns true if any contacts were deleted after {@code lastModified}. */ private boolean contactsDeleted(long lastModified) { try (Cursor cursor = - context + appContext .getContentResolver() .query( DeletedContacts.CONTENT_URI, diff --git a/java/com/android/dialer/phonelookup/phone_lookup_info.proto b/java/com/android/dialer/phonelookup/phone_lookup_info.proto index b959e78df..1027e5c22 100644 --- a/java/com/android/dialer/phonelookup/phone_lookup_info.proto +++ b/java/com/android/dialer/phonelookup/phone_lookup_info.proto @@ -7,9 +7,15 @@ option optimize_for = LITE_RUNTIME; package com.android.dialer.phonelookup; -// TODO(zachh) documentation +// Contains information about a phone number, possibly from many sources. +// +// This message is organized into sub-messages where each sub-message +// corresponds to an implementation of PhoneLookup. For example, the Cp2Info +// corresponds to Cp2PhoneLookup class, and the Cp2PhoneLookup class alone is +// responsible for populating its fields. message PhoneLookupInfo { - // TODO(calderwoodra): documentation + // Information about a PhoneNumber retrieved from CP2. Cp2PhoneLookup is + // responsible for populating the data in this message. message Cp2Info { optional string name = 1; optional string photo_uri = 2; -- cgit v1.2.3