Search in sources :

Example 11 with DialerPhoneNumber

use of com.android.dialer.DialerPhoneNumber in project android_packages_apps_Dialer by LineageOS.

the class Cp2DefaultDirectoryPhoneLookup method buildMapForUpdatedOrAddedContacts.

/**
 * 1. get all contact ids. if the id is unset, add the number to the list of contacts to look up.
 * 2. reduce our list of contact ids to those that were updated after lastModified. 3. Now we have
 * the smallest set of dialer phone numbers to query cp2 against. 4. build and return the map of
 * dialerphonenumbers to their new Cp2ContactInfo
 *
 * @return Map of {@link DialerPhoneNumber} to {@link Cp2Info} with updated {@link
 *     Cp2ContactInfo}.
 */
private ListenableFuture<Map<DialerPhoneNumber, Set<Cp2ContactInfo>>> buildMapForUpdatedOrAddedContacts(Map<DialerPhoneNumber, Cp2Info> existingInfoMap, long lastModified, Set<DialerPhoneNumber> deletedPhoneNumbers) {
    // Start by building a set of DialerPhoneNumbers that we want to update.
    ListenableFuture<Set<DialerPhoneNumber>> updatedNumbersFuture = findNumbersToUpdate(existingInfoMap, lastModified, deletedPhoneNumbers);
    return Futures.transformAsync(updatedNumbersFuture, updatedNumbers -> {
        if (updatedNumbers.isEmpty()) {
            return Futures.immediateFuture(new ArrayMap<>());
        }
        // Divide the numbers into those that are valid and those that are not. Issue a single
        // batch query for the valid numbers against the PHONE table, and in parallel issue
        // individual queries against PHONE_LOOKUP for each invalid number.
        // TODO(zachh): These queries are inefficient without a lastModified column to filter on.
        PartitionedNumbers partitionedNumbers = new PartitionedNumbers(ImmutableSet.copyOf(updatedNumbers));
        ListenableFuture<Map<String, Set<Cp2ContactInfo>>> validNumbersFuture = batchQueryForValidNumbers(partitionedNumbers.validE164Numbers());
        List<ListenableFuture<Set<Cp2ContactInfo>>> invalidNumbersFuturesList = new ArrayList<>();
        for (String invalidNumber : partitionedNumbers.invalidNumbers()) {
            invalidNumbersFuturesList.add(individualQueryForInvalidNumber(invalidNumber));
        }
        ListenableFuture<List<Set<Cp2ContactInfo>>> invalidNumbersFuture = Futures.allAsList(invalidNumbersFuturesList);
        Callable<Map<DialerPhoneNumber, Set<Cp2ContactInfo>>> computeMap = () -> {
            // These get() calls are safe because we are using whenAllSucceed below.
            Map<String, Set<Cp2ContactInfo>> validNumbersResult = validNumbersFuture.get();
            List<Set<Cp2ContactInfo>> invalidNumbersResult = invalidNumbersFuture.get();
            Map<DialerPhoneNumber, Set<Cp2ContactInfo>> map = new ArrayMap<>();
            // First update the map with the valid number results.
            for (Entry<String, Set<Cp2ContactInfo>> entry : validNumbersResult.entrySet()) {
                String validNumber = entry.getKey();
                Set<Cp2ContactInfo> cp2ContactInfos = entry.getValue();
                Set<DialerPhoneNumber> dialerPhoneNumbers = partitionedNumbers.dialerPhoneNumbersForValidE164(validNumber);
                addInfo(map, dialerPhoneNumbers, cp2ContactInfos);
                // We are going to remove the numbers that we've handled so that we later can
                // detect numbers that weren't handled and therefore need to have their contact
                // information removed.
                updatedNumbers.removeAll(dialerPhoneNumbers);
            }
            // Next update the map with the invalid results.
            int i = 0;
            for (String invalidNumber : partitionedNumbers.invalidNumbers()) {
                Set<Cp2ContactInfo> cp2Infos = invalidNumbersResult.get(i++);
                Set<DialerPhoneNumber> dialerPhoneNumbers = partitionedNumbers.dialerPhoneNumbersForInvalid(invalidNumber);
                addInfo(map, dialerPhoneNumbers, cp2Infos);
                // We are going to remove the numbers that we've handled so that we later can
                // detect numbers that weren't handled and therefore need to have their contact
                // information removed.
                updatedNumbers.removeAll(dialerPhoneNumbers);
            }
            // information for them.
            for (DialerPhoneNumber dialerPhoneNumber : updatedNumbers) {
                map.put(dialerPhoneNumber, ImmutableSet.of());
            }
            LogUtil.v("Cp2DefaultDirectoryPhoneLookup.buildMapForUpdatedOrAddedContacts", "found %d numbers that may need updating", updatedNumbers.size());
            return map;
        };
        return Futures.whenAllSucceed(validNumbersFuture, invalidNumbersFuture).call(computeMap, lightweightExecutorService);
    }, lightweightExecutorService);
}
Also used : ImmutableSet(com.google.common.collect.ImmutableSet) Set(java.util.Set) ArraySet(android.support.v4.util.ArraySet) ArrayList(java.util.ArrayList) Cp2ContactInfo(com.android.dialer.phonelookup.PhoneLookupInfo.Cp2Info.Cp2ContactInfo) PartitionedNumbers(com.android.dialer.phonenumberproto.PartitionedNumbers) Entry(java.util.Map.Entry) DialerPhoneNumber(com.android.dialer.DialerPhoneNumber) ListenableFuture(com.google.common.util.concurrent.ListenableFuture) ArrayList(java.util.ArrayList) List(java.util.List) ArrayMap(android.support.v4.util.ArrayMap) Map(java.util.Map) ImmutableMap(com.google.common.collect.ImmutableMap)

Example 12 with DialerPhoneNumber

use of com.android.dialer.DialerPhoneNumber in project android_packages_apps_Dialer by LineageOS.

the class Cp2DefaultDirectoryPhoneLookup method isDirty.

@Override
public ListenableFuture<Boolean> isDirty(ImmutableSet<DialerPhoneNumber> phoneNumbers) {
    if (!PermissionsUtil.hasContactsReadPermissions(appContext)) {
        LogUtil.w("Cp2DefaultDirectoryPhoneLookup.isDirty", "missing permissions");
        Predicate<PhoneLookupInfo> phoneLookupInfoIsDirtyFn = phoneLookupInfo -> !phoneLookupInfo.getDefaultCp2Info().equals(Cp2Info.getDefaultInstance());
        return missingPermissionsOperations.isDirtyForMissingPermissions(phoneNumbers, phoneLookupInfoIsDirtyFn);
    }
    PartitionedNumbers partitionedNumbers = new PartitionedNumbers(phoneNumbers);
    if (partitionedNumbers.invalidNumbers().size() > getMaxSupportedInvalidNumbers()) {
        // If there are N invalid numbers, we can't determine determine dirtiness without running N
        // queries; since running this many queries is not feasible for the (lightweight) isDirty
        // check, simply return true. The expectation is that this should rarely be the case as the
        // vast majority of numbers in call logs should be valid.
        LogUtil.v("Cp2DefaultDirectoryPhoneLookup.isDirty", "returning true because too many invalid numbers (%d)", partitionedNumbers.invalidNumbers().size());
        return Futures.immediateFuture(true);
    }
    ListenableFuture<Long> lastModifiedFuture = backgroundExecutorService.submit(() -> sharedPreferences.getLong(PREF_LAST_TIMESTAMP_PROCESSED, 0L));
    return Futures.transformAsync(lastModifiedFuture, lastModified -> {
        // We are always going to need to do this check and it is pretty cheap so do it first.
        ListenableFuture<Boolean> anyContactsDeletedFuture = anyContactsDeletedSince(lastModified);
        return Futures.transformAsync(anyContactsDeletedFuture, anyContactsDeleted -> {
            if (anyContactsDeleted) {
                LogUtil.v("Cp2DefaultDirectoryPhoneLookup.isDirty", "returning true because contacts deleted");
                return Futures.immediateFuture(true);
            }
            // Hopefully the most common case is there are no contacts updated; we can detect
            // this cheaply.
            ListenableFuture<Boolean> noContactsModifiedSinceFuture = noContactsModifiedSince(lastModified);
            return Futures.transformAsync(noContactsModifiedSinceFuture, noContactsModifiedSince -> {
                if (noContactsModifiedSince) {
                    LogUtil.v("Cp2DefaultDirectoryPhoneLookup.isDirty", "returning false because no contacts modified since last run");
                    return Futures.immediateFuture(false);
                }
                // This method is more expensive but is probably the most likely scenario; we
                // are looking for changes to contacts which have been called.
                ListenableFuture<Set<Long>> contactIdsFuture = queryPhoneTableForContactIds(phoneNumbers);
                ListenableFuture<Boolean> contactsUpdatedFuture = Futures.transformAsync(contactIdsFuture, contactIds -> contactsUpdated(contactIds, lastModified), MoreExecutors.directExecutor());
                return Futures.transformAsync(contactsUpdatedFuture, contactsUpdated -> {
                    if (contactsUpdated) {
                        LogUtil.v("Cp2DefaultDirectoryPhoneLookup.isDirty", "returning true because a previously called contact was updated");
                        return Futures.immediateFuture(true);
                    }
                    // This is the most expensive method so do it last; the scenario is that
                    // a contact which has been called got disassociated with a number and
                    // we need to clear their information.
                    ListenableFuture<Set<Long>> phoneLookupContactIdsFuture = queryPhoneLookupHistoryForContactIds();
                    return Futures.transformAsync(phoneLookupContactIdsFuture, phoneLookupContactIds -> contactsUpdated(phoneLookupContactIds, lastModified), MoreExecutors.directExecutor());
                }, MoreExecutors.directExecutor());
            }, MoreExecutors.directExecutor());
        }, MoreExecutors.directExecutor());
    }, MoreExecutors.directExecutor());
}
Also used : Assert(com.android.dialer.common.Assert) Context(android.content.Context) LogUtil(com.android.dialer.common.LogUtil) Iterables(com.google.common.collect.Iterables) MoreExecutors(com.google.common.util.concurrent.MoreExecutors) ListenableFuture(com.google.common.util.concurrent.ListenableFuture) Uri(android.net.Uri) DeletedContacts(android.provider.ContactsContract.DeletedContacts) Callable(java.util.concurrent.Callable) ConfigProvider(com.android.dialer.configprovider.ConfigProvider) Cp2Info(com.android.dialer.phonelookup.PhoneLookupInfo.Cp2Info) ArrayList(java.util.ArrayList) Inject(javax.inject.Inject) BackgroundExecutor(com.android.dialer.common.concurrent.Annotations.BackgroundExecutor) ContactsContract(android.provider.ContactsContract) PhoneLookup(com.android.dialer.phonelookup.PhoneLookup) ArrayMap(android.support.v4.util.ArrayMap) PartitionedNumbers(com.android.dialer.phonenumberproto.PartitionedNumbers) Unencrypted(com.android.dialer.storage.Unencrypted) Map(java.util.Map) PermissionsUtil(com.android.dialer.util.PermissionsUtil) Logger(com.android.dialer.logging.Logger) PhoneLookupHistory(com.android.dialer.phonelookup.database.contract.PhoneLookupHistoryContract.PhoneLookupHistory) ApplicationContext(com.android.dialer.inject.ApplicationContext) Cursor(android.database.Cursor) Contacts(android.provider.ContactsContract.Contacts) InvalidProtocolBufferException(com.google.protobuf.InvalidProtocolBufferException) LightweightExecutor(com.android.dialer.common.concurrent.Annotations.LightweightExecutor) ImmutableSet(com.google.common.collect.ImmutableSet) PhoneLookupInfo(com.android.dialer.phonelookup.PhoneLookupInfo) ImmutableMap(com.google.common.collect.ImmutableMap) Predicate(java.util.function.Predicate) Set(java.util.Set) TextUtils(android.text.TextUtils) ArraySet(android.support.v4.util.ArraySet) Cp2ContactInfo(com.android.dialer.phonelookup.PhoneLookupInfo.Cp2Info.Cp2ContactInfo) Phone(android.provider.ContactsContract.CommonDataKinds.Phone) Maps(com.google.common.collect.Maps) DialerPhoneNumber(com.android.dialer.DialerPhoneNumber) Futures(com.google.common.util.concurrent.Futures) List(java.util.List) SharedPreferences(android.content.SharedPreferences) Entry(java.util.Map.Entry) Directory(android.provider.ContactsContract.Directory) Nullable(android.support.annotation.Nullable) ListeningExecutorService(com.google.common.util.concurrent.ListeningExecutorService) PartitionedNumbers(com.android.dialer.phonenumberproto.PartitionedNumbers) PhoneLookupInfo(com.android.dialer.phonelookup.PhoneLookupInfo) ImmutableSet(com.google.common.collect.ImmutableSet) Set(java.util.Set) ArraySet(android.support.v4.util.ArraySet)

Example 13 with DialerPhoneNumber

use of com.android.dialer.DialerPhoneNumber in project android_packages_apps_Dialer by LineageOS.

the class Cp2DefaultDirectoryPhoneLookup method findDialerPhoneNumbersContainingContactId.

private static Set<DialerPhoneNumber> findDialerPhoneNumbersContainingContactId(Map<DialerPhoneNumber, Cp2Info> existingInfoMap, long contactId) {
    Set<DialerPhoneNumber> matches = new ArraySet<>();
    for (Entry<DialerPhoneNumber, Cp2Info> entry : existingInfoMap.entrySet()) {
        for (Cp2ContactInfo cp2ContactInfo : entry.getValue().getCp2ContactInfoList()) {
            if (cp2ContactInfo.getContactId() == contactId) {
                matches.add(entry.getKey());
            }
        }
    }
    Assert.checkArgument(matches.size() > 0, "Couldn't find DialerPhoneNumber for contact ID: " + contactId);
    return matches;
}
Also used : Cp2Info(com.android.dialer.phonelookup.PhoneLookupInfo.Cp2Info) ArraySet(android.support.v4.util.ArraySet) DialerPhoneNumber(com.android.dialer.DialerPhoneNumber) Cp2ContactInfo(com.android.dialer.phonelookup.PhoneLookupInfo.Cp2Info.Cp2ContactInfo)

Example 14 with DialerPhoneNumber

use of com.android.dialer.DialerPhoneNumber in project android_packages_apps_Dialer by LineageOS.

the class Cp2DefaultDirectoryPhoneLookup method getMostRecentInfo.

@Override
public ListenableFuture<ImmutableMap<DialerPhoneNumber, Cp2Info>> getMostRecentInfo(ImmutableMap<DialerPhoneNumber, Cp2Info> existingInfoMap) {
    currentLastTimestampProcessed = null;
    if (!PermissionsUtil.hasContactsReadPermissions(appContext)) {
        LogUtil.w("Cp2DefaultDirectoryPhoneLookup.getMostRecentInfo", "missing permissions");
        return missingPermissionsOperations.getMostRecentInfoForMissingPermissions(existingInfoMap);
    }
    ListenableFuture<Long> lastModifiedFuture = backgroundExecutorService.submit(() -> sharedPreferences.getLong(PREF_LAST_TIMESTAMP_PROCESSED, 0L));
    return Futures.transformAsync(lastModifiedFuture, lastModified -> {
        // Build a set of each DialerPhoneNumber that was associated with a contact, and is no
        // longer associated with that same contact.
        ListenableFuture<Set<DialerPhoneNumber>> deletedPhoneNumbersFuture = getDeletedPhoneNumbers(existingInfoMap, lastModified);
        return Futures.transformAsync(deletedPhoneNumbersFuture, deletedPhoneNumbers -> {
            // If there are too many invalid numbers, just defer the work to render time.
            ArraySet<DialerPhoneNumber> unprocessableNumbers = findUnprocessableNumbers(existingInfoMap);
            Map<DialerPhoneNumber, Cp2Info> existingInfoMapToProcess = existingInfoMap;
            if (!unprocessableNumbers.isEmpty()) {
                existingInfoMapToProcess = Maps.filterKeys(existingInfoMap, number -> !unprocessableNumbers.contains(number));
            }
            // For each DialerPhoneNumber that was associated with a contact or added to a
            // contact, build a map of those DialerPhoneNumbers to a set Cp2ContactInfos, where
            // each Cp2ContactInfo represents a contact.
            ListenableFuture<Map<DialerPhoneNumber, Set<Cp2ContactInfo>>> updatedContactsFuture = buildMapForUpdatedOrAddedContacts(existingInfoMapToProcess, lastModified, deletedPhoneNumbers);
            return Futures.transform(updatedContactsFuture, updatedContacts -> {
                // Start build a new map of updated info. This will replace existing info.
                ImmutableMap.Builder<DialerPhoneNumber, Cp2Info> newInfoMapBuilder = ImmutableMap.builder();
                // For each DialerPhoneNumber in existing info...
                for (Entry<DialerPhoneNumber, Cp2Info> entry : existingInfoMap.entrySet()) {
                    DialerPhoneNumber dialerPhoneNumber = entry.getKey();
                    Cp2Info existingInfo = entry.getValue();
                    // Build off the existing info
                    Cp2Info.Builder infoBuilder = Cp2Info.newBuilder(existingInfo);
                    // If the contact was updated, replace the Cp2ContactInfo list
                    if (updatedContacts.containsKey(dialerPhoneNumber)) {
                        infoBuilder.clear().addAllCp2ContactInfo(updatedContacts.get(dialerPhoneNumber));
                    // If it was deleted and not added to a new contact, clear all the CP2
                    // information.
                    } else if (deletedPhoneNumbers.contains(dialerPhoneNumber)) {
                        infoBuilder.clear();
                    } else if (unprocessableNumbers.contains(dialerPhoneNumber)) {
                        // does not have the ability to fetch information at render time).
                        if (!dialerPhoneNumber.getNormalizedNumber().isEmpty()) {
                            // Don't clear the existing info when the number is unprocessable. It's
                            // likely that the existing info is up-to-date so keep it in place so
                            // that the UI doesn't pop when the query is completed at display time.
                            infoBuilder.setIsIncomplete(true);
                        }
                    }
                    // If the DialerPhoneNumber didn't change, add the unchanged existing info.
                    newInfoMapBuilder.put(dialerPhoneNumber, infoBuilder.build());
                }
                return newInfoMapBuilder.build();
            }, lightweightExecutorService);
        }, lightweightExecutorService);
    }, lightweightExecutorService);
}
Also used : Assert(com.android.dialer.common.Assert) Context(android.content.Context) LogUtil(com.android.dialer.common.LogUtil) Iterables(com.google.common.collect.Iterables) MoreExecutors(com.google.common.util.concurrent.MoreExecutors) ListenableFuture(com.google.common.util.concurrent.ListenableFuture) Uri(android.net.Uri) DeletedContacts(android.provider.ContactsContract.DeletedContacts) Callable(java.util.concurrent.Callable) ConfigProvider(com.android.dialer.configprovider.ConfigProvider) Cp2Info(com.android.dialer.phonelookup.PhoneLookupInfo.Cp2Info) ArrayList(java.util.ArrayList) Inject(javax.inject.Inject) BackgroundExecutor(com.android.dialer.common.concurrent.Annotations.BackgroundExecutor) ContactsContract(android.provider.ContactsContract) PhoneLookup(com.android.dialer.phonelookup.PhoneLookup) ArrayMap(android.support.v4.util.ArrayMap) PartitionedNumbers(com.android.dialer.phonenumberproto.PartitionedNumbers) Unencrypted(com.android.dialer.storage.Unencrypted) Map(java.util.Map) PermissionsUtil(com.android.dialer.util.PermissionsUtil) Logger(com.android.dialer.logging.Logger) PhoneLookupHistory(com.android.dialer.phonelookup.database.contract.PhoneLookupHistoryContract.PhoneLookupHistory) ApplicationContext(com.android.dialer.inject.ApplicationContext) Cursor(android.database.Cursor) Contacts(android.provider.ContactsContract.Contacts) InvalidProtocolBufferException(com.google.protobuf.InvalidProtocolBufferException) LightweightExecutor(com.android.dialer.common.concurrent.Annotations.LightweightExecutor) ImmutableSet(com.google.common.collect.ImmutableSet) PhoneLookupInfo(com.android.dialer.phonelookup.PhoneLookupInfo) ImmutableMap(com.google.common.collect.ImmutableMap) Predicate(java.util.function.Predicate) Set(java.util.Set) TextUtils(android.text.TextUtils) ArraySet(android.support.v4.util.ArraySet) Cp2ContactInfo(com.android.dialer.phonelookup.PhoneLookupInfo.Cp2Info.Cp2ContactInfo) Phone(android.provider.ContactsContract.CommonDataKinds.Phone) Maps(com.google.common.collect.Maps) DialerPhoneNumber(com.android.dialer.DialerPhoneNumber) Futures(com.google.common.util.concurrent.Futures) List(java.util.List) SharedPreferences(android.content.SharedPreferences) Entry(java.util.Map.Entry) Directory(android.provider.ContactsContract.Directory) Nullable(android.support.annotation.Nullable) ListeningExecutorService(com.google.common.util.concurrent.ListeningExecutorService) ImmutableSet(com.google.common.collect.ImmutableSet) Set(java.util.Set) ArraySet(android.support.v4.util.ArraySet) Cp2ContactInfo(com.android.dialer.phonelookup.PhoneLookupInfo.Cp2Info.Cp2ContactInfo) ImmutableMap(com.google.common.collect.ImmutableMap) Cp2Info(com.android.dialer.phonelookup.PhoneLookupInfo.Cp2Info) DialerPhoneNumber(com.android.dialer.DialerPhoneNumber) ArrayMap(android.support.v4.util.ArrayMap) Map(java.util.Map) ImmutableMap(com.google.common.collect.ImmutableMap)

Example 15 with DialerPhoneNumber

use of com.android.dialer.DialerPhoneNumber in project android_packages_apps_Dialer by LineageOS.

the class SpamPhoneLookup method getMostRecentInfo.

@Override
public ListenableFuture<ImmutableMap<DialerPhoneNumber, SpamInfo>> getMostRecentInfo(ImmutableMap<DialerPhoneNumber, SpamInfo> existingInfoMap) {
    currentLastTimestampProcessed = null;
    ListenableFuture<ImmutableMap<DialerPhoneNumber, SpamStatus>> spamStatusMapFuture = spam.batchCheckSpamStatus(existingInfoMap.keySet());
    return Futures.transform(spamStatusMapFuture, spamStatusMap -> {
        ImmutableMap.Builder<DialerPhoneNumber, SpamInfo> mostRecentSpamInfo = new ImmutableMap.Builder<>();
        for (Entry<DialerPhoneNumber, SpamStatus> dialerPhoneNumberAndSpamStatus : spamStatusMap.entrySet()) {
            DialerPhoneNumber dialerPhoneNumber = dialerPhoneNumberAndSpamStatus.getKey();
            SpamStatus spamStatus = dialerPhoneNumberAndSpamStatus.getValue();
            mostRecentSpamInfo.put(dialerPhoneNumber, SpamInfo.newBuilder().setIsSpam(spamStatus.isSpam()).build());
            Optional<Long> timestampMillis = spamStatus.getTimestampMillis();
            if (timestampMillis.isPresent()) {
                currentLastTimestampProcessed = currentLastTimestampProcessed == null ? timestampMillis.get() : Math.max(timestampMillis.get(), currentLastTimestampProcessed);
            }
        }
        // triggering the bulk update flow repeatedly.
        if (currentLastTimestampProcessed == null) {
            currentLastTimestampProcessed = System.currentTimeMillis();
        }
        return mostRecentSpamInfo.build();
    }, lightweightExecutorService);
}
Also used : SpamInfo(com.android.dialer.phonelookup.PhoneLookupInfo.SpamInfo) SpamStatus(com.android.dialer.spam.status.SpamStatus) DialerPhoneNumber(com.android.dialer.DialerPhoneNumber) ImmutableMap(com.google.common.collect.ImmutableMap)

Aggregations

DialerPhoneNumber (com.android.dialer.DialerPhoneNumber)26 InvalidProtocolBufferException (com.google.protobuf.InvalidProtocolBufferException)8 ContentValues (android.content.ContentValues)7 Cursor (android.database.Cursor)7 ImmutableMap (com.google.common.collect.ImmutableMap)7 ArrayList (java.util.ArrayList)7 ArraySet (android.support.v4.util.ArraySet)6 PhoneLookupInfo (com.android.dialer.phonelookup.PhoneLookupInfo)6 Cp2ContactInfo (com.android.dialer.phonelookup.PhoneLookupInfo.Cp2Info.Cp2ContactInfo)6 ImmutableSet (com.google.common.collect.ImmutableSet)6 ListenableFuture (com.google.common.util.concurrent.ListenableFuture)6 Set (java.util.Set)6 PartitionedNumbers (com.android.dialer.phonenumberproto.PartitionedNumbers)5 ListeningExecutorService (com.google.common.util.concurrent.ListeningExecutorService)5 Context (android.content.Context)4 ArraySet (android.util.ArraySet)4 LogUtil (com.android.dialer.common.LogUtil)4 BackgroundExecutor (com.android.dialer.common.concurrent.Annotations.BackgroundExecutor)4 ApplicationContext (com.android.dialer.inject.ApplicationContext)4 PhoneLookup (com.android.dialer.phonelookup.PhoneLookup)4