From a2aa5f3097fe3ca8e64a378095260448a29f5c5f Mon Sep 17 00:00:00 2001 From: Android Dialer Date: Fri, 1 Jun 2018 17:24:39 -0700 Subject: Internal change Bug: 79169954 Test: added tests in BlockingTest.java PiperOrigin-RevId: 198950042 Change-Id: I380bc93276223db74b87f94140bd6c5c29c3f3cb --- java/com/android/dialer/blocking/Blocking.java | 177 +++++++++++++++------ .../ShowBlockReportSpamDialogReceiver.java | 7 +- .../dialer/commandline/impl/BlockingCommand.java | 5 +- .../dialer/logging/reporting_location.proto | 1 + 4 files changed, 134 insertions(+), 56 deletions(-) (limited to 'java/com/android') diff --git a/java/com/android/dialer/blocking/Blocking.java b/java/com/android/dialer/blocking/Blocking.java index e86d0a6ac..a1d8b4fb3 100644 --- a/java/com/android/dialer/blocking/Blocking.java +++ b/java/com/android/dialer/blocking/Blocking.java @@ -16,14 +16,27 @@ package com.android.dialer.blocking; +import android.content.ContentProviderOperation; +import android.content.ContentProviderResult; +import android.content.ContentResolver; import android.content.ContentValues; import android.content.Context; +import android.content.OperationApplicationException; +import android.database.Cursor; +import android.os.RemoteException; +import android.provider.BlockedNumberContract; import android.provider.BlockedNumberContract.BlockedNumbers; import android.support.annotation.Nullable; import android.telephony.PhoneNumberUtils; +import android.util.ArrayMap; +import com.android.dialer.common.concurrent.DialerExecutorComponent; import com.android.dialer.common.database.Selection; +import com.google.common.collect.ImmutableCollection; +import com.google.common.collect.ImmutableMap; import com.google.common.util.concurrent.ListenableFuture; -import com.google.common.util.concurrent.ListeningExecutorService; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; /** Blocks and unblocks number. */ public final class Blocking { @@ -47,7 +60,7 @@ public final class Blocking { } /** - * Block a number. + * Block a list of numbers. * * @param countryIso the current location used to guess the country code of the number if not * available. If {@code null} and {@code number} does not have a country code, only the @@ -55,29 +68,31 @@ public final class Blocking { * @throws BlockingFailedException in the returned future if the operation failed. */ public static ListenableFuture block( - Context context, - ListeningExecutorService executorService, - String number, - @Nullable String countryIso) { - return executorService.submit( - () -> { - ContentValues values = new ContentValues(); - values.put(BlockedNumbers.COLUMN_ORIGINAL_NUMBER, number); - String e164Number = PhoneNumberUtils.formatNumberToE164(number, countryIso); - if (e164Number != null) { - values.put(BlockedNumbers.COLUMN_E164_NUMBER, e164Number); - } - try { - context.getContentResolver().insert(BlockedNumbers.CONTENT_URI, values); - } catch (SecurityException e) { - throw new BlockingFailedException(e); - } - return null; - }); + Context context, ImmutableCollection numbers, @Nullable String countryIso) { + return DialerExecutorComponent.get(context) + .backgroundExecutor() + .submit( + () -> { + ArrayList operations = new ArrayList<>(); + for (String number : numbers) { + ContentValues values = new ContentValues(); + values.put(BlockedNumbers.COLUMN_ORIGINAL_NUMBER, number); + String e164Number = PhoneNumberUtils.formatNumberToE164(number, countryIso); + if (e164Number != null) { + values.put(BlockedNumbers.COLUMN_E164_NUMBER, e164Number); + } + operations.add( + ContentProviderOperation.newInsert(BlockedNumbers.CONTENT_URI) + .withValues(values) + .build()); + } + applyBatchOps(context.getContentResolver(), operations); + return null; + }); } /** - * Unblock a number. + * Unblock a list of number. * * @param countryIso the current location used to guess the country code of the number if not * available. If {@code null} and {@code number} does not have a country code, only the @@ -85,33 +100,95 @@ public final class Blocking { * @throws BlockingFailedException in the returned future if the operation failed. */ public static ListenableFuture unblock( - Context context, - ListeningExecutorService executorService, - String number, - @Nullable String countryIso) { - return executorService.submit( - () -> { - Selection selection = - Selection.column(BlockedNumbers.COLUMN_ORIGINAL_NUMBER).is("=", number); - String e164Number = PhoneNumberUtils.formatNumberToE164(number, countryIso); - if (e164Number != null) { - selection = - selection - .buildUpon() - .or(Selection.column(BlockedNumbers.COLUMN_E164_NUMBER).is("=", e164Number)) - .build(); - } - try { - context - .getContentResolver() - .delete( - BlockedNumbers.CONTENT_URI, - selection.getSelection(), - selection.getSelectionArgs()); - } catch (SecurityException e) { - throw new BlockingFailedException(e); - } - return null; - }); + Context context, ImmutableCollection numbers, @Nullable String countryIso) { + return DialerExecutorComponent.get(context) + .backgroundExecutor() + .submit( + () -> { + ArrayList operations = new ArrayList<>(); + for (String number : numbers) { + Selection selection = + Selection.column(BlockedNumbers.COLUMN_ORIGINAL_NUMBER).is("=", number); + String e164Number = PhoneNumberUtils.formatNumberToE164(number, countryIso); + if (e164Number != null) { + selection = + selection + .buildUpon() + .or( + Selection.column(BlockedNumbers.COLUMN_E164_NUMBER) + .is("=", e164Number)) + .build(); + } + operations.add( + ContentProviderOperation.newDelete(BlockedNumbers.CONTENT_URI) + .withSelection(selection.getSelection(), selection.getSelectionArgs()) + .build()); + } + applyBatchOps(context.getContentResolver(), operations); + return null; + }); + } + + /** + * Get blocked numbers from a list of number. + * + * @param countryIso the current location used to guess the country code of the number if not + * available. If {@code null} and {@code number} does not have a country code, only the + * original number will be used to check blocked status. + * @throws BlockingFailedException in the returned future if the operation failed. + */ + public static ListenableFuture> isBlocked( + Context context, ImmutableCollection numbers, @Nullable String countryIso) { + return DialerExecutorComponent.get(context) + .backgroundExecutor() + .submit( + () -> { + Map blockedStatus = new ArrayMap<>(); + List e164Numbers = new ArrayList<>(); + + for (String number : numbers) { + // Initialize as unblocked + blockedStatus.put(number, false); + String e164Number = PhoneNumberUtils.formatNumberToE164(number, countryIso); + if (e164Number != null) { + e164Numbers.add(e164Number); + } + } + + Selection selection = + Selection.builder() + .or(Selection.column(BlockedNumbers.COLUMN_ORIGINAL_NUMBER).in(numbers)) + .or(Selection.column(BlockedNumbers.COLUMN_E164_NUMBER).in(e164Numbers)) + .build(); + + try (Cursor cursor = + context + .getContentResolver() + .query( + BlockedNumbers.CONTENT_URI, + new String[] {BlockedNumbers.COLUMN_ORIGINAL_NUMBER}, + selection.getSelection(), + selection.getSelectionArgs(), + null)) { + if (cursor == null) { + return ImmutableMap.copyOf(blockedStatus); + } + while (cursor.moveToNext()) { + // Update blocked status + blockedStatus.put(cursor.getString(0), true); + } + } + return ImmutableMap.copyOf(blockedStatus); + }); + } + + private static ContentProviderResult[] applyBatchOps( + ContentResolver resolver, ArrayList ops) + throws BlockingFailedException { + try { + return resolver.applyBatch(BlockedNumberContract.AUTHORITY, ops); + } catch (RemoteException | OperationApplicationException | SecurityException e) { + throw new BlockingFailedException(e); + } } } diff --git a/java/com/android/dialer/blockreportspam/ShowBlockReportSpamDialogReceiver.java b/java/com/android/dialer/blockreportspam/ShowBlockReportSpamDialogReceiver.java index fb0399d9a..28ac7bfcc 100644 --- a/java/com/android/dialer/blockreportspam/ShowBlockReportSpamDialogReceiver.java +++ b/java/com/android/dialer/blockreportspam/ShowBlockReportSpamDialogReceiver.java @@ -40,6 +40,7 @@ import com.android.dialer.protos.ProtoParsers; import com.android.dialer.spam.Spam; import com.android.dialer.spam.SpamComponent; import com.android.dialer.spam.SpamSettings; +import com.google.common.collect.ImmutableList; import com.google.common.util.concurrent.FutureCallback; import com.google.common.util.concurrent.Futures; @@ -225,8 +226,7 @@ public final class ShowBlockReportSpamDialogReceiver extends BroadcastReceiver { Futures.addCallback( Blocking.block( context, - DialerExecutorComponent.get(context).backgroundExecutor(), - dialogInfo.getNormalizedNumber(), + ImmutableList.of(dialogInfo.getNormalizedNumber()), dialogInfo.getCountryIso()), new FutureCallback() { @Override @@ -252,8 +252,7 @@ public final class ShowBlockReportSpamDialogReceiver extends BroadcastReceiver { Futures.addCallback( Blocking.unblock( context, - DialerExecutorComponent.get(context).backgroundExecutor(), - dialogInfo.getNormalizedNumber(), + ImmutableList.of(dialogInfo.getNormalizedNumber()), dialogInfo.getCountryIso()), new FutureCallback() { @Override diff --git a/java/com/android/dialer/commandline/impl/BlockingCommand.java b/java/com/android/dialer/commandline/impl/BlockingCommand.java index f06e240ae..d06450513 100644 --- a/java/com/android/dialer/commandline/impl/BlockingCommand.java +++ b/java/com/android/dialer/commandline/impl/BlockingCommand.java @@ -28,6 +28,7 @@ import com.android.dialer.phonelookup.PhoneLookupComponent; import com.android.dialer.phonelookup.PhoneLookupInfo; import com.android.dialer.phonelookup.consolidator.PhoneLookupInfoConsolidator; import com.android.dialer.phonenumberproto.DialerPhoneNumberUtil; +import com.google.common.collect.ImmutableList; import com.google.common.util.concurrent.Futures; import com.google.common.util.concurrent.ListenableFuture; import com.google.common.util.concurrent.ListeningExecutorService; @@ -71,7 +72,7 @@ public class BlockingCommand implements Command { if ("block".equals(command)) { String number = args.getPositionals().get(1); return Futures.transform( - Blocking.block(appContext, executorService, number, null), + Blocking.block(appContext, ImmutableList.of(number), null), (unused) -> "blocked " + number, MoreExecutors.directExecutor()); } @@ -79,7 +80,7 @@ public class BlockingCommand implements Command { if ("unblock".equals(command)) { String number = args.getPositionals().get(1); return Futures.transform( - Blocking.unblock(appContext, executorService, number, null), + Blocking.unblock(appContext, ImmutableList.of(number), null), (unused) -> "unblocked " + number, MoreExecutors.directExecutor()); } diff --git a/java/com/android/dialer/logging/reporting_location.proto b/java/com/android/dialer/logging/reporting_location.proto index b9912be75..1d6ba4752 100644 --- a/java/com/android/dialer/logging/reporting_location.proto +++ b/java/com/android/dialer/logging/reporting_location.proto @@ -15,5 +15,6 @@ message ReportingLocation { CALL_LOG_HISTORY = 1; FEEDBACK_PROMPT = 2; VOICEMAIL_HISTORY = 3; + CONTACT_DETAILS = 4; } } -- cgit v1.2.3