Search in sources :

Example 1 with Cp2ContactInfo

use of com.android.dialer.phonelookup.PhoneLookupInfo.Cp2Info.Cp2ContactInfo in project android_packages_apps_Dialer by LineageOS.

the class Cp2DefaultDirectoryPhoneLookup method batchQueryForValidNumbers.

private ListenableFuture<Map<String, Set<Cp2ContactInfo>>> batchQueryForValidNumbers(Set<String> validE164Numbers) {
    return backgroundExecutorService.submit(() -> {
        Map<String, Set<Cp2ContactInfo>> cp2ContactInfosByNumber = new ArrayMap<>();
        if (validE164Numbers.isEmpty()) {
            return cp2ContactInfosByNumber;
        }
        try (Cursor cursor = queryPhoneTableBasedOnE164(Cp2Projections.getProjectionForPhoneTable(), validE164Numbers)) {
            if (cursor == null) {
                LogUtil.w("Cp2DefaultDirectoryPhoneLookup.batchQueryForValidNumbers", "null cursor");
            } else {
                while (cursor.moveToNext()) {
                    String validE164Number = Cp2Projections.getNormalizedNumberFromCursor(cursor);
                    Set<Cp2ContactInfo> cp2ContactInfos = cp2ContactInfosByNumber.get(validE164Number);
                    if (cp2ContactInfos == null) {
                        cp2ContactInfos = new ArraySet<>();
                        cp2ContactInfosByNumber.put(validE164Number, cp2ContactInfos);
                    }
                    cp2ContactInfos.add(Cp2Projections.buildCp2ContactInfoFromCursor(appContext, cursor, Directory.DEFAULT));
                }
            }
        }
        return cp2ContactInfosByNumber;
    });
}
Also used : ImmutableSet(com.google.common.collect.ImmutableSet) Set(java.util.Set) ArraySet(android.support.v4.util.ArraySet) ArrayMap(android.support.v4.util.ArrayMap) Cursor(android.database.Cursor) Cp2ContactInfo(com.android.dialer.phonelookup.PhoneLookupInfo.Cp2Info.Cp2ContactInfo)

Example 2 with Cp2ContactInfo

use of com.android.dialer.phonelookup.PhoneLookupInfo.Cp2Info.Cp2ContactInfo in project android_packages_apps_Dialer by LineageOS.

the class Cp2DefaultDirectoryPhoneLookup method lookupInternal.

private Cp2Info lookupInternal(DialerPhoneNumber dialerPhoneNumber) {
    String number = dialerPhoneNumber.getNormalizedNumber();
    if (TextUtils.isEmpty(number)) {
        return Cp2Info.getDefaultInstance();
    }
    Set<Cp2ContactInfo> cp2ContactInfos = new ArraySet<>();
    // Even though this is only a single number, use PartitionedNumbers to mimic the logic used
    // during getMostRecentInfo.
    PartitionedNumbers partitionedNumbers = new PartitionedNumbers(ImmutableSet.of(dialerPhoneNumber));
    Cursor cursor = null;
    try {
        // to ensure consistency when the batch methods are used to update data.
        if (!partitionedNumbers.validE164Numbers().isEmpty()) {
            cursor = queryPhoneTableBasedOnE164(Cp2Projections.getProjectionForPhoneTable(), partitionedNumbers.validE164Numbers());
        } else {
            cursor = queryPhoneLookup(Cp2Projections.getProjectionForPhoneLookupTable(), Iterables.getOnlyElement(partitionedNumbers.invalidNumbers()));
        }
        if (cursor == null) {
            LogUtil.w("Cp2DefaultDirectoryPhoneLookup.lookupInternal", "null cursor");
            return Cp2Info.getDefaultInstance();
        }
        while (cursor.moveToNext()) {
            cp2ContactInfos.add(Cp2Projections.buildCp2ContactInfoFromCursor(appContext, cursor, Directory.DEFAULT));
        }
    } finally {
        if (cursor != null) {
            cursor.close();
        }
    }
    return Cp2Info.newBuilder().addAllCp2ContactInfo(cp2ContactInfos).build();
}
Also used : PartitionedNumbers(com.android.dialer.phonenumberproto.PartitionedNumbers) ArraySet(android.support.v4.util.ArraySet) Cp2ContactInfo(com.android.dialer.phonelookup.PhoneLookupInfo.Cp2Info.Cp2ContactInfo) Cursor(android.database.Cursor)

Example 3 with Cp2ContactInfo

use of com.android.dialer.phonelookup.PhoneLookupInfo.Cp2Info.Cp2ContactInfo 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 4 with Cp2ContactInfo

use of com.android.dialer.phonelookup.PhoneLookupInfo.Cp2Info.Cp2ContactInfo 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 5 with Cp2ContactInfo

use of com.android.dialer.phonelookup.PhoneLookupInfo.Cp2Info.Cp2ContactInfo 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)

Aggregations

Cp2ContactInfo (com.android.dialer.phonelookup.PhoneLookupInfo.Cp2Info.Cp2ContactInfo)7 ArraySet (android.support.v4.util.ArraySet)6 DialerPhoneNumber (com.android.dialer.DialerPhoneNumber)5 Cursor (android.database.Cursor)4 ArrayMap (android.support.v4.util.ArrayMap)3 Cp2Info (com.android.dialer.phonelookup.PhoneLookupInfo.Cp2Info)3 PartitionedNumbers (com.android.dialer.phonenumberproto.PartitionedNumbers)3 ImmutableSet (com.google.common.collect.ImmutableSet)3 Set (java.util.Set)3 ImmutableMap (com.google.common.collect.ImmutableMap)2 ListenableFuture (com.google.common.util.concurrent.ListenableFuture)2 ArrayList (java.util.ArrayList)2 List (java.util.List)2 Map (java.util.Map)2 Entry (java.util.Map.Entry)2 Context (android.content.Context)1 SharedPreferences (android.content.SharedPreferences)1 Uri (android.net.Uri)1 ContactsContract (android.provider.ContactsContract)1 Phone (android.provider.ContactsContract.CommonDataKinds.Phone)1