Search in sources :

Example 6 with PhoneLookupInfo

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

the class CompositePhoneLookup method getMostRecentInfo.

/**
 * 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.
 */
@SuppressWarnings("unchecked")
public ListenableFuture<ImmutableMap<DialerPhoneNumber, PhoneLookupInfo>> getMostRecentInfo(ImmutableMap<DialerPhoneNumber, PhoneLookupInfo> existingInfoMap) {
    return Futures.transformAsync(callLogState.isBuilt(), isBuilt -> {
        Preconditions.checkNotNull(isBuilt);
        List<ListenableFuture<ImmutableMap<DialerPhoneNumber, ?>>> futures = new ArrayList<>();
        for (PhoneLookup phoneLookup : phoneLookups) {
            futures.add(buildSubmapAndGetMostRecentInfo(existingInfoMap, phoneLookup, isBuilt));
        }
        ListenableFuture<ImmutableMap<DialerPhoneNumber, PhoneLookupInfo>> combinedFuture = Futures.transform(Futures.allAsList(futures), (allMaps) -> {
            Preconditions.checkNotNull(allMaps);
            ImmutableMap.Builder<DialerPhoneNumber, PhoneLookupInfo> combinedMap = ImmutableMap.builder();
            for (DialerPhoneNumber dialerPhoneNumber : existingInfoMap.keySet()) {
                PhoneLookupInfo.Builder combinedInfo = PhoneLookupInfo.newBuilder();
                for (int i = 0; i < allMaps.size(); i++) {
                    ImmutableMap<DialerPhoneNumber, ?> map = allMaps.get(i);
                    Object subInfo = map.get(dialerPhoneNumber);
                    if (subInfo == null) {
                        throw new IllegalStateException("A sublookup didn't return an info for number: " + LogUtil.sanitizePhoneNumber(dialerPhoneNumber.getNormalizedNumber()));
                    }
                    phoneLookups.get(i).setSubMessage(combinedInfo, subInfo);
                }
                combinedMap.put(dialerPhoneNumber, combinedInfo.build());
            }
            return combinedMap.build();
        }, lightweightExecutorService);
        String eventName = getMostRecentInfoEventName(getLoggingName(), isBuilt);
        futureTimer.applyTiming(combinedFuture, eventName);
        return combinedFuture;
    }, MoreExecutors.directExecutor());
}
Also used : PhoneLookupInfo(com.android.dialer.phonelookup.PhoneLookupInfo) ArrayList(java.util.ArrayList) ImmutableMap(com.google.common.collect.ImmutableMap) Builder(com.android.dialer.phonelookup.PhoneLookupInfo.Builder) DialerPhoneNumber(com.android.dialer.DialerPhoneNumber) ListenableFuture(com.google.common.util.concurrent.ListenableFuture) PhoneLookup(com.android.dialer.phonelookup.PhoneLookup)

Example 7 with PhoneLookupInfo

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

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

the class MissingPermissionsOperations method isDirtyForMissingPermissions.

/**
 * Returns true if there is any CP2 data for the specified numbers in PhoneLookupHistory, because
 * that data needs to be cleared.
 *
 * <p>Note: This might be a little slow for users without contacts permissions, but we don't
 * expect this to often be the case. If necessary, a shared pref could be used to track the
 * permission state as an optimization.
 */
ListenableFuture<Boolean> isDirtyForMissingPermissions(ImmutableSet<DialerPhoneNumber> phoneNumbers, Predicate<PhoneLookupInfo> phoneLookupInfoIsDirtyFn) {
    return backgroundExecutor.submit(() -> {
        // Note: This loses country info when number is not valid.
        String[] normalizedNumbers = phoneNumbers.stream().map(DialerPhoneNumber::getNormalizedNumber).toArray(String[]::new);
        Selection selection = Selection.builder().and(Selection.column(PhoneLookupHistory.NORMALIZED_NUMBER).in(normalizedNumbers)).build();
        try (Cursor cursor = appContext.getContentResolver().query(PhoneLookupHistory.CONTENT_URI, new String[] { PhoneLookupHistory.PHONE_LOOKUP_INFO }, selection.getSelection(), selection.getSelectionArgs(), null)) {
            if (cursor == null) {
                LogUtil.w("MissingPermissionsOperations.isDirtyForMissingPermissions", "null cursor");
                return false;
            }
            if (cursor.moveToFirst()) {
                int phoneLookupInfoColumn = cursor.getColumnIndexOrThrow(PhoneLookupHistory.PHONE_LOOKUP_INFO);
                do {
                    PhoneLookupInfo phoneLookupInfo;
                    try {
                        phoneLookupInfo = PhoneLookupInfo.parseFrom(cursor.getBlob(phoneLookupInfoColumn));
                    } catch (InvalidProtocolBufferException e) {
                        throw new IllegalStateException(e);
                    }
                    if (phoneLookupInfoIsDirtyFn.test(phoneLookupInfo)) {
                        return true;
                    }
                } while (cursor.moveToNext());
            }
        }
        return false;
    });
}
Also used : PhoneLookupInfo(com.android.dialer.phonelookup.PhoneLookupInfo) Selection(com.android.dialer.common.database.Selection) InvalidProtocolBufferException(com.google.protobuf.InvalidProtocolBufferException) Cursor(android.database.Cursor)

Example 9 with PhoneLookupInfo

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

the class BlockingCommand method run.

@Override
public ListenableFuture<String> run(Arguments args) throws IllegalCommandLineArgumentException {
    if (args.getPositionals().isEmpty()) {
        return Futures.immediateFuture(getUsage());
    }
    String command = args.getPositionals().get(0);
    if ("block".equals(command)) {
        String number = args.getPositionals().get(1);
        return Futures.transform(Blocking.block(appContext, ImmutableList.of(number), null), (unused) -> "blocked " + number, MoreExecutors.directExecutor());
    }
    if ("unblock".equals(command)) {
        String number = args.getPositionals().get(1);
        return Futures.transform(Blocking.unblock(appContext, ImmutableList.of(number), null), (unused) -> "unblocked " + number, MoreExecutors.directExecutor());
    }
    if ("isblocked".equals(command)) {
        String number = args.getPositionals().get(1);
        ListenableFuture<DialerPhoneNumber> dialerPhoneNumberFuture = executorService.submit(() -> new DialerPhoneNumberUtil().parse(number, null));
        ListenableFuture<PhoneLookupInfo> lookupFuture = Futures.transformAsync(dialerPhoneNumberFuture, (dialerPhoneNumber) -> PhoneLookupComponent.get(appContext).compositePhoneLookup().lookup(dialerPhoneNumber), executorService);
        return Futures.transform(lookupFuture, (info) -> new PhoneLookupInfoConsolidator(info).isBlocked() ? "true" : "false", MoreExecutors.directExecutor());
    }
    return Futures.immediateFuture(getUsage());
}
Also used : PhoneLookupInfoConsolidator(com.android.dialer.phonelookup.consolidator.PhoneLookupInfoConsolidator) PhoneLookupInfo(com.android.dialer.phonelookup.PhoneLookupInfo) DialerPhoneNumber(com.android.dialer.DialerPhoneNumber) DialerPhoneNumberUtil(com.android.dialer.phonenumberproto.DialerPhoneNumberUtil)

Example 10 with PhoneLookupInfo

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

the class RealtimeRowProcessor method applyRealtimeProcessing.

/**
 * Converts a {@link CoalescedRow} to a future which is the result of performing additional work
 * on the row. May simply return the original row if no modifications were necessary.
 */
@MainThread
ListenableFuture<CoalescedRow> applyRealtimeProcessing(final CoalescedRow row) {
    // Cp2DefaultDirectoryPhoneLookup can not always efficiently process all rows.
    if (!row.getNumberAttributes().getIsCp2InfoIncomplete()) {
        return Futures.immediateFuture(row);
    }
    PhoneLookupInfo cachedPhoneLookupInfo = cache.get(row.getNumber());
    if (cachedPhoneLookupInfo != null) {
        return Futures.immediateFuture(applyPhoneLookupInfoToRow(cachedPhoneLookupInfo, row));
    }
    ListenableFuture<PhoneLookupInfo> phoneLookupInfoFuture = compositePhoneLookup.lookup(row.getNumber());
    return Futures.transform(phoneLookupInfoFuture, phoneLookupInfo -> {
        queuePhoneLookupHistoryWrite(row.getNumber(), phoneLookupInfo);
        cache.put(row.getNumber(), phoneLookupInfo);
        return applyPhoneLookupInfoToRow(phoneLookupInfo, row);
    }, uiExecutor);
}
Also used : PhoneLookupInfo(com.android.dialer.phonelookup.PhoneLookupInfo) MainThread(android.support.annotation.MainThread)

Aggregations

PhoneLookupInfo (com.android.dialer.phonelookup.PhoneLookupInfo)12 ContentValues (android.content.ContentValues)6 DialerPhoneNumber (com.android.dialer.DialerPhoneNumber)5 ArrayList (java.util.ArrayList)5 Cursor (android.database.Cursor)4 InvalidProtocolBufferException (com.google.protobuf.InvalidProtocolBufferException)4 ContentProviderOperation (android.content.ContentProviderOperation)3 MainThread (android.support.annotation.MainThread)3 PhoneLookup (com.android.dialer.phonelookup.PhoneLookup)3 ImmutableMap (com.google.common.collect.ImmutableMap)3 ListenableFuture (com.google.common.util.concurrent.ListenableFuture)3 Context (android.content.Context)2 WorkerThread (android.support.annotation.WorkerThread)2 TextUtils (android.text.TextUtils)2 Assert (com.android.dialer.common.Assert)2 LogUtil (com.android.dialer.common.LogUtil)2 BackgroundExecutor (com.android.dialer.common.concurrent.Annotations.BackgroundExecutor)2 LightweightExecutor (com.android.dialer.common.concurrent.Annotations.LightweightExecutor)2 ApplicationContext (com.android.dialer.inject.ApplicationContext)2 PhoneLookupHistory (com.android.dialer.phonelookup.database.contract.PhoneLookupHistoryContract.PhoneLookupHistory)2