diff options
author | twyen <twyen@google.com> | 2018-01-22 16:08:08 -0800 |
---|---|---|
committer | Copybara-Service <copybara-piper@google.com> | 2018-01-22 16:12:39 -0800 |
commit | 0e00f578d641440c5ddc4da48ab86eabbc21d403 (patch) | |
tree | 9ae99486deaf71b55a3f2a635ff95581d703c90b | |
parent | a2c2d5c65ec2aad3ba198ab645e01f51331c8e83 (diff) |
Implement System blocked number
This CL implements looking up blocked number in the Android system blocked number provider, which is available after N. Dialer and system blocked number will return empty if requirements are not made (N+ and migration completed is needed for system, otherwise dialer should not be used).
Bug: 70989543
Test: Unit tests
PiperOrigin-RevId: 182852672
Change-Id: I1360b7eed7c18f459292d769529ffcfceb61a7ed
5 files changed, 260 insertions, 37 deletions
diff --git a/java/com/android/dialer/phonelookup/PhoneLookupModule.java b/java/com/android/dialer/phonelookup/PhoneLookupModule.java index e93ca0f77..8a78ba038 100644 --- a/java/com/android/dialer/phonelookup/PhoneLookupModule.java +++ b/java/com/android/dialer/phonelookup/PhoneLookupModule.java @@ -17,6 +17,7 @@ package com.android.dialer.phonelookup; import com.android.dialer.phonelookup.blockednumber.DialerBlockedNumberPhoneLookup; +import com.android.dialer.phonelookup.blockednumber.SystemBlockedNumberPhoneLookup; import com.android.dialer.phonelookup.composite.CompositePhoneLookup; import com.android.dialer.phonelookup.cp2.Cp2LocalPhoneLookup; import com.android.dialer.phonelookup.cp2.Cp2RemotePhoneLookup; @@ -33,9 +34,13 @@ public abstract class PhoneLookupModule { static ImmutableList<PhoneLookup> providePhoneLookupList( Cp2LocalPhoneLookup cp2LocalPhoneLookup, Cp2RemotePhoneLookup cp2RemotePhoneLookup, - DialerBlockedNumberPhoneLookup dialerBlockedNumberPhoneLookup) { + DialerBlockedNumberPhoneLookup dialerBlockedNumberPhoneLookup, + SystemBlockedNumberPhoneLookup systemBlockedNumberPhoneLookup) { return ImmutableList.of( - cp2LocalPhoneLookup, cp2RemotePhoneLookup, dialerBlockedNumberPhoneLookup); + cp2LocalPhoneLookup, + cp2RemotePhoneLookup, + dialerBlockedNumberPhoneLookup, + systemBlockedNumberPhoneLookup); } @Provides diff --git a/java/com/android/dialer/phonelookup/blockednumber/DialerBlockedNumberPhoneLookup.java b/java/com/android/dialer/phonelookup/blockednumber/DialerBlockedNumberPhoneLookup.java index ce1217751..2271c7580 100644 --- a/java/com/android/dialer/phonelookup/blockednumber/DialerBlockedNumberPhoneLookup.java +++ b/java/com/android/dialer/phonelookup/blockednumber/DialerBlockedNumberPhoneLookup.java @@ -17,17 +17,14 @@ 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.WorkerThread; import android.util.ArraySet; import com.android.dialer.DialerPhoneNumber; +import com.android.dialer.blocking.FilteredNumberCompat; 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.concurrent.ThreadUtil; import com.android.dialer.common.database.Selection; import com.android.dialer.database.FilteredNumberContract.FilteredNumber; import com.android.dialer.database.FilteredNumberContract.FilteredNumberColumns; @@ -65,6 +62,9 @@ public final class DialerBlockedNumberPhoneLookup implements PhoneLookup<DialerB @Override public ListenableFuture<DialerBlockedNumberInfo> lookup(DialerPhoneNumber dialerPhoneNumber) { + if (FilteredNumberCompat.useNewFiltering(appContext)) { + return Futures.immediateFuture(DialerBlockedNumberInfo.getDefaultInstance()); + } return executorService.submit( () -> queryNumbers(ImmutableSet.of(dialerPhoneNumber)).get(dialerPhoneNumber)); } @@ -79,6 +79,9 @@ public final class DialerBlockedNumberPhoneLookup implements PhoneLookup<DialerB @Override public ListenableFuture<ImmutableMap<DialerPhoneNumber, DialerBlockedNumberInfo>> getMostRecentInfo(ImmutableMap<DialerPhoneNumber, DialerBlockedNumberInfo> existingInfoMap) { + if (FilteredNumberCompat.useNewFiltering(appContext)) { + return Futures.immediateFuture(existingInfoMap); + } LogUtil.enterBlock("DialerBlockedNumberPhoneLookup.getMostRecentPhoneLookupInfo"); return executorService.submit(() -> queryNumbers(existingInfoMap.keySet())); } @@ -128,11 +131,7 @@ public final class DialerBlockedNumberPhoneLookup implements PhoneLookup<DialerB } Selection rawSelection = - Selection.column(FilteredNumberColumns.NUMBER) - .in( - partitionedNumbers - .invalidNumbers() - .toArray(new String[partitionedNumbers.invalidNumbers().size()])); + Selection.column(FilteredNumberColumns.NUMBER).in(partitionedNumbers.invalidNumbers()); try (Cursor cursor = appContext .getContentResolver() @@ -173,26 +172,6 @@ public final class DialerBlockedNumberPhoneLookup implements PhoneLookup<DialerB .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(ThreadUtil.getUiThreadHandler()); - 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); - } + new MarkDirtyObserver(appContext, contentObserverCallbacks)); } } diff --git a/java/com/android/dialer/phonelookup/blockednumber/MarkDirtyObserver.java b/java/com/android/dialer/phonelookup/blockednumber/MarkDirtyObserver.java new file mode 100644 index 000000000..1c41d8f7f --- /dev/null +++ b/java/com/android/dialer/phonelookup/blockednumber/MarkDirtyObserver.java @@ -0,0 +1,47 @@ +/* + * 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.net.Uri; +import android.support.annotation.MainThread; +import com.android.dialer.common.Assert; +import com.android.dialer.common.LogUtil; +import com.android.dialer.common.concurrent.ThreadUtil; +import com.android.dialer.phonelookup.PhoneLookup.ContentObserverCallbacks; + +/** Calls {@link ContentObserverCallbacks#markDirtyAndNotify(Context)} when the content changed */ +class MarkDirtyObserver extends ContentObserver { + + private final Context appContext; + private final ContentObserverCallbacks contentObserverCallbacks; + + MarkDirtyObserver(Context appContext, ContentObserverCallbacks contentObserverCallbacks) { + super(ThreadUtil.getUiThreadHandler()); + this.appContext = appContext; + this.contentObserverCallbacks = contentObserverCallbacks; + } + + @MainThread + @Override + public void onChange(boolean selfChange, Uri uri) { + Assert.isMainThread(); + LogUtil.enterBlock("SystemBlockedNumberPhoneLookup.FilteredNumberObserver.onChange"); + contentObserverCallbacks.markDirtyAndNotify(appContext); + } +} diff --git a/java/com/android/dialer/phonelookup/blockednumber/SystemBlockedNumberPhoneLookup.java b/java/com/android/dialer/phonelookup/blockednumber/SystemBlockedNumberPhoneLookup.java new file mode 100644 index 000000000..e0ff995e7 --- /dev/null +++ b/java/com/android/dialer/phonelookup/blockednumber/SystemBlockedNumberPhoneLookup.java @@ -0,0 +1,181 @@ +/* + * 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.annotation.TargetApi; +import android.content.Context; +import android.database.Cursor; +import android.os.Build.VERSION; +import android.os.Build.VERSION_CODES; +import android.provider.BlockedNumberContract.BlockedNumbers; +import android.support.annotation.NonNull; +import android.support.annotation.WorkerThread; +import android.util.ArraySet; +import com.android.dialer.DialerPhoneNumber; +import com.android.dialer.blocking.FilteredNumberCompat; +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.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.Builder; +import com.android.dialer.phonelookup.PhoneLookupInfo.SystemBlockedNumberInfo; +import com.android.dialer.phonenumberproto.PartitionedNumbers; +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 java.util.Set; +import javax.inject.Inject; + +/** + * Lookup blocked numbers in the system database. Requires N+ and migration from dialer database + * completed (need user consent to move data into system). + */ +public class SystemBlockedNumberPhoneLookup implements PhoneLookup<SystemBlockedNumberInfo> { + + private final Context appContext; + private final ListeningExecutorService executorService; + + @Inject + SystemBlockedNumberPhoneLookup( + @ApplicationContext Context appContext, + @BackgroundExecutor ListeningExecutorService executorService) { + this.appContext = appContext; + this.executorService = executorService; + } + + @Override + public ListenableFuture<SystemBlockedNumberInfo> lookup(@NonNull DialerPhoneNumber number) { + if (!FilteredNumberCompat.useNewFiltering(appContext)) { + return Futures.immediateFuture(SystemBlockedNumberInfo.getDefaultInstance()); + } + return executorService.submit( + () -> { + 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, SystemBlockedNumberInfo>> + getMostRecentInfo(ImmutableMap<DialerPhoneNumber, SystemBlockedNumberInfo> existingInfoMap) { + LogUtil.enterBlock("SystemBlockedNumberPhoneLookup.getMostRecentPhoneLookupInfo"); + if (!FilteredNumberCompat.useNewFiltering(appContext)) { + return Futures.immediateFuture(existingInfoMap); + } + return executorService.submit(() -> queryNumbers(existingInfoMap.keySet())); + } + + @WorkerThread + @TargetApi(VERSION_CODES.N) + private ImmutableMap<DialerPhoneNumber, SystemBlockedNumberInfo> queryNumbers( + ImmutableSet<DialerPhoneNumber> numbers) { + Assert.isWorkerThread(); + PartitionedNumbers partitionedNumbers = new PartitionedNumbers(numbers); + + Set<DialerPhoneNumber> blockedNumbers = new ArraySet<>(); + + Selection normalizedSelection = + Selection.column(BlockedNumbers.COLUMN_E164_NUMBER) + .in(partitionedNumbers.validE164Numbers()); + try (Cursor cursor = + appContext + .getContentResolver() + .query( + BlockedNumbers.CONTENT_URI, + new String[] {BlockedNumbers.COLUMN_E164_NUMBER}, + normalizedSelection.getSelection(), + normalizedSelection.getSelectionArgs(), + null)) { + while (cursor != null && cursor.moveToNext()) { + blockedNumbers.addAll( + partitionedNumbers.dialerPhoneNumbersForValidE164(cursor.getString(0))); + } + } + + Selection rawSelection = + Selection.column(BlockedNumbers.COLUMN_ORIGINAL_NUMBER) + .in(partitionedNumbers.invalidNumbers()); + try (Cursor cursor = + appContext + .getContentResolver() + .query( + BlockedNumbers.CONTENT_URI, + new String[] {BlockedNumbers.COLUMN_ORIGINAL_NUMBER}, + rawSelection.getSelection(), + rawSelection.getSelectionArgs(), + null)) { + while (cursor != null && cursor.moveToNext()) { + blockedNumbers.addAll(partitionedNumbers.dialerPhoneNumbersForInvalid(cursor.getString(0))); + } + } + + ImmutableMap.Builder<DialerPhoneNumber, SystemBlockedNumberInfo> result = + ImmutableMap.builder(); + + for (DialerPhoneNumber number : numbers) { + result.put( + number, + SystemBlockedNumberInfo.newBuilder() + .setBlockedState( + blockedNumbers.contains(number) ? BlockedState.BLOCKED : BlockedState.NOT_BLOCKED) + .build()); + } + + return result.build(); + } + + @Override + public void setSubMessage(Builder phoneLookupInfo, SystemBlockedNumberInfo subMessage) { + phoneLookupInfo.setSystemBlockedNumberInfo(subMessage); + } + + @Override + public SystemBlockedNumberInfo getSubMessage(PhoneLookupInfo phoneLookupInfo) { + return phoneLookupInfo.getSystemBlockedNumberInfo(); + } + + @Override + public ListenableFuture<Void> onSuccessfulBulkUpdate() { + return Futures.immediateFuture(null); + } + + @Override + public void registerContentObservers( + Context appContext, ContentObserverCallbacks contentObserverCallbacks) { + if (VERSION.SDK_INT < VERSION_CODES.N) { + return; + } + appContext + .getContentResolver() + .registerContentObserver( + BlockedNumbers.CONTENT_URI, + true, // BlockedNumbers notifies on the item + new MarkDirtyObserver(appContext, contentObserverCallbacks)); + } +} diff --git a/java/com/android/dialer/phonelookup/consolidator/PhoneLookupInfoConsolidator.java b/java/com/android/dialer/phonelookup/consolidator/PhoneLookupInfoConsolidator.java index ccad3e7bc..27f0d21ae 100644 --- a/java/com/android/dialer/phonelookup/consolidator/PhoneLookupInfoConsolidator.java +++ b/java/com/android/dialer/phonelookup/consolidator/PhoneLookupInfoConsolidator.java @@ -179,11 +179,7 @@ public final class PhoneLookupInfoConsolidator { * returned. */ public String getNumberLabel() { - if (phoneLookupInfo.hasDialerBlockedNumberInfo() - && phoneLookupInfo - .getDialerBlockedNumberInfo() - .getBlockedState() - .equals(BlockedState.BLOCKED)) { + if (isBlocked()) { return appContext.getString(R.string.blocked_number_new_call_log_label); } @@ -219,6 +215,21 @@ public final class PhoneLookupInfoConsolidator { return false; } + public boolean isBlocked() { + // If system blocking reported blocked state it always takes priority over the dialer blocking. + // It will be absent if dialer blocking should be used. + if (phoneLookupInfo.getSystemBlockedNumberInfo().hasBlockedState()) { + return phoneLookupInfo + .getSystemBlockedNumberInfo() + .getBlockedState() + .equals(BlockedState.BLOCKED); + } + return phoneLookupInfo + .getDialerBlockedNumberInfo() + .getBlockedState() + .equals(BlockedState.BLOCKED); + } + /** * Returns true if the {@link PhoneLookupInfo} passed to the constructor has incomplete CP2 local * info. |