summaryrefslogtreecommitdiff
path: root/java/com/android/dialer/phonelookup/blockednumber/DialerBlockedNumberPhoneLookup.java
diff options
context:
space:
mode:
authortwyen <twyen@google.com>2018-01-05 11:52:45 -0800
committerEric Erfanian <erfanian@google.com>2018-01-05 11:57:00 -0800
commitfb112d870c3a564d2dcb0e72dcdcabb6e0375520 (patch)
treedbda20e83cb3458fefec613b56d4b9d0a4814e66 /java/com/android/dialer/phonelookup/blockednumber/DialerBlockedNumberPhoneLookup.java
parent417be6a9e3482472cce238e0a51b6367b86aba1f (diff)
Implement dialer blocked number phone lookup
This CL implements looking up the dialer internal database for blocked numbers when the system database is not available yet. Data is only invalidated when dialer is alive since that is the only time blocked numbers can be set and removed. Bug: 70989538,70989547 Test: DialerBlockedNumberPhoneLookupTest PiperOrigin-RevId: 180956355 Change-Id: Ie7acf091bf58a074d0a1ee39613fad035d2e6e60
Diffstat (limited to 'java/com/android/dialer/phonelookup/blockednumber/DialerBlockedNumberPhoneLookup.java')
-rw-r--r--java/com/android/dialer/phonelookup/blockednumber/DialerBlockedNumberPhoneLookup.java210
1 files changed, 210 insertions, 0 deletions
diff --git a/java/com/android/dialer/phonelookup/blockednumber/DialerBlockedNumberPhoneLookup.java b/java/com/android/dialer/phonelookup/blockednumber/DialerBlockedNumberPhoneLookup.java
new file mode 100644
index 000000000..54df3995c
--- /dev/null
+++ b/java/com/android/dialer/phonelookup/blockednumber/DialerBlockedNumberPhoneLookup.java
@@ -0,0 +1,210 @@
+/*
+ * Copyright (C) 2018 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.blockednumber;
+
+import android.content.Context;
+import android.database.ContentObserver;
+import android.database.Cursor;
+import android.net.Uri;
+import android.support.annotation.MainThread;
+import android.support.annotation.NonNull;
+import android.support.annotation.WorkerThread;
+import android.telecom.Call;
+import android.util.ArraySet;
+import com.android.dialer.DialerPhoneNumber;
+import com.android.dialer.common.Assert;
+import com.android.dialer.common.LogUtil;
+import com.android.dialer.common.concurrent.Annotations.BackgroundExecutor;
+import com.android.dialer.common.database.Selection;
+import com.android.dialer.database.FilteredNumberContract.FilteredNumber;
+import com.android.dialer.database.FilteredNumberContract.FilteredNumberColumns;
+import com.android.dialer.database.FilteredNumberContract.FilteredNumberTypes;
+import com.android.dialer.inject.ApplicationContext;
+import com.android.dialer.phonelookup.PhoneLookup;
+import com.android.dialer.phonelookup.PhoneLookupInfo;
+import com.android.dialer.phonelookup.PhoneLookupInfo.BlockedState;
+import com.android.dialer.phonelookup.PhoneLookupInfo.DialerBlockedNumberInfo;
+import com.android.dialer.phonenumberproto.DialerPhoneNumberUtil;
+import com.android.dialer.phonenumberproto.PartitionedNumbers;
+import com.android.dialer.telecom.TelecomCallUtil;
+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.ListeningExecutorService;
+import com.google.i18n.phonenumbers.PhoneNumberUtil;
+import java.util.Set;
+import javax.inject.Inject;
+
+/**
+ * Lookup blocked numbers in the dialer internal database. This is used when the system database is
+ * not yet available.
+ */
+public final class DialerBlockedNumberPhoneLookup implements PhoneLookup<DialerBlockedNumberInfo> {
+
+ private final Context appContext;
+ private final ListeningExecutorService executorService;
+
+ @Inject
+ DialerBlockedNumberPhoneLookup(
+ @ApplicationContext Context appContext,
+ @BackgroundExecutor ListeningExecutorService executorService) {
+ this.appContext = appContext;
+ this.executorService = executorService;
+ }
+
+ @Override
+ public ListenableFuture<DialerBlockedNumberInfo> lookup(@NonNull Call call) {
+ return executorService.submit(
+ () -> {
+ DialerPhoneNumberUtil dialerPhoneNumberUtil =
+ new DialerPhoneNumberUtil(PhoneNumberUtil.getInstance());
+
+ DialerPhoneNumber number =
+ dialerPhoneNumberUtil.parse(
+ TelecomCallUtil.getNumber(call),
+ TelecomCallUtil.getCountryCode(appContext, call).orNull());
+ return queryNumbers(ImmutableSet.of(number)).get(number);
+ });
+ }
+
+ @Override
+ public ListenableFuture<Boolean> isDirty(ImmutableSet<DialerPhoneNumber> phoneNumbers) {
+ // Dirty state is recorded with PhoneLookupDataSource.markDirtyAndNotify(), which will force
+ // rebuild with the CallLogFramework
+ return Futures.immediateFuture(false);
+ }
+
+ @Override
+ public ListenableFuture<ImmutableMap<DialerPhoneNumber, DialerBlockedNumberInfo>>
+ getMostRecentInfo(ImmutableMap<DialerPhoneNumber, DialerBlockedNumberInfo> existingInfoMap) {
+ LogUtil.enterBlock("DialerBlockedNumberPhoneLookup.getMostRecentPhoneLookupInfo");
+ return executorService.submit(() -> queryNumbers(existingInfoMap.keySet()));
+ }
+
+ @Override
+ public void setSubMessage(
+ PhoneLookupInfo.Builder phoneLookupInfo, DialerBlockedNumberInfo subMessage) {
+ phoneLookupInfo.setDialerBlockedNumberInfo(subMessage);
+ }
+
+ @Override
+ public DialerBlockedNumberInfo getSubMessage(PhoneLookupInfo phoneLookupInfo) {
+ return phoneLookupInfo.getDialerBlockedNumberInfo();
+ }
+
+ @Override
+ public ListenableFuture<Void> onSuccessfulBulkUpdate() {
+ return Futures.immediateFuture(null);
+ }
+
+ @WorkerThread
+ private ImmutableMap<DialerPhoneNumber, DialerBlockedNumberInfo> queryNumbers(
+ ImmutableSet<DialerPhoneNumber> numbers) {
+ Assert.isWorkerThread();
+ PartitionedNumbers partitionedNumbers = new PartitionedNumbers(numbers);
+
+ Set<DialerPhoneNumber> blockedNumbers = new ArraySet<>();
+
+ Selection normalizedSelection =
+ Selection.column(FilteredNumberColumns.NORMALIZED_NUMBER)
+ .in(partitionedNumbers.validE164Numbers());
+ try (Cursor cursor =
+ appContext
+ .getContentResolver()
+ .query(
+ FilteredNumber.CONTENT_URI,
+ new String[] {FilteredNumberColumns.NORMALIZED_NUMBER, FilteredNumberColumns.TYPE},
+ normalizedSelection.getSelection(),
+ normalizedSelection.getSelectionArgs(),
+ null)) {
+ while (cursor != null && cursor.moveToNext()) {
+ if (cursor.getInt(1) == FilteredNumberTypes.BLOCKED_NUMBER) {
+ blockedNumbers.addAll(partitionedNumbers.dialerPhoneNumbersForE164(cursor.getString(0)));
+ }
+ }
+ }
+
+ Selection rawSelection =
+ Selection.column(FilteredNumberColumns.NUMBER)
+ .in(
+ partitionedNumbers
+ .unformattableNumbers()
+ .toArray(new String[partitionedNumbers.unformattableNumbers().size()]));
+ try (Cursor cursor =
+ appContext
+ .getContentResolver()
+ .query(
+ FilteredNumber.CONTENT_URI,
+ new String[] {FilteredNumberColumns.NUMBER, FilteredNumberColumns.TYPE},
+ rawSelection.getSelection(),
+ rawSelection.getSelectionArgs(),
+ null)) {
+ while (cursor != null && cursor.moveToNext()) {
+ if (cursor.getInt(1) == FilteredNumberTypes.BLOCKED_NUMBER) {
+ blockedNumbers.addAll(
+ partitionedNumbers.dialerPhoneNumbersForUnformattable(cursor.getString(0)));
+ }
+ }
+ }
+
+ ImmutableMap.Builder<DialerPhoneNumber, DialerBlockedNumberInfo> result =
+ ImmutableMap.builder();
+
+ for (DialerPhoneNumber number : numbers) {
+ result.put(
+ number,
+ DialerBlockedNumberInfo.newBuilder()
+ .setBlockedState(
+ blockedNumbers.contains(number) ? BlockedState.BLOCKED : BlockedState.NOT_BLOCKED)
+ .build());
+ }
+
+ return result.build();
+ }
+
+ @Override
+ public void registerContentObservers(
+ Context appContext, ContentObserverCallbacks contentObserverCallbacks) {
+ appContext
+ .getContentResolver()
+ .registerContentObserver(
+ FilteredNumber.CONTENT_URI,
+ true, // FilteredNumberProvider notifies on the item
+ new FilteredNumberObserver(appContext, contentObserverCallbacks));
+ }
+
+ private static class FilteredNumberObserver extends ContentObserver {
+ private final Context appContext;
+ private final ContentObserverCallbacks contentObserverCallbacks;
+
+ FilteredNumberObserver(Context appContext, ContentObserverCallbacks contentObserverCallbacks) {
+ super(null);
+ this.appContext = appContext;
+ this.contentObserverCallbacks = contentObserverCallbacks;
+ }
+
+ @MainThread
+ @Override
+ @SuppressWarnings("FutureReturnValueIgnored") // never throws.
+ public void onChange(boolean selfChange, Uri uri) {
+ Assert.isMainThread();
+ LogUtil.enterBlock("DialerBlockedNumberPhoneLookup.FilteredNumberObserver.onChange");
+ contentObserverCallbacks.markDirtyAndNotify(appContext);
+ }
+ }
+}