Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit a2aa5f30 authored by Android Dialer's avatar Android Dialer Committed by Copybara-Service
Browse files

Internal change

Bug: 79169954
Test: added tests in BlockingTest.java
PiperOrigin-RevId: 198950042
Change-Id: I380bc93276223db74b87f94140bd6c5c29c3f3cb
parent 836b75d3
Loading
Loading
Loading
Loading
+127 −50
Original line number Diff line number Diff line
@@ -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<Void> block(
      Context context,
      ListeningExecutorService executorService,
      String number,
      @Nullable String countryIso) {
    return executorService.submit(
      Context context, ImmutableCollection<String> numbers, @Nullable String countryIso) {
    return DialerExecutorComponent.get(context)
        .backgroundExecutor()
        .submit(
            () -> {
              ArrayList<ContentProviderOperation> 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);
                }
          try {
            context.getContentResolver().insert(BlockedNumbers.CONTENT_URI, values);
          } catch (SecurityException e) {
            throw new BlockingFailedException(e);
                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,12 +100,13 @@ public final class Blocking {
   * @throws BlockingFailedException in the returned future if the operation failed.
   */
  public static ListenableFuture<Void> unblock(
      Context context,
      ListeningExecutorService executorService,
      String number,
      @Nullable String countryIso) {
    return executorService.submit(
      Context context, ImmutableCollection<String> numbers, @Nullable String countryIso) {
    return DialerExecutorComponent.get(context)
        .backgroundExecutor()
        .submit(
            () -> {
              ArrayList<ContentProviderOperation> operations = new ArrayList<>();
              for (String number : numbers) {
                Selection selection =
                    Selection.column(BlockedNumbers.COLUMN_ORIGINAL_NUMBER).is("=", number);
                String e164Number = PhoneNumberUtils.formatNumberToE164(number, countryIso);
@@ -98,20 +114,81 @@ public final class Blocking {
                  selection =
                      selection
                          .buildUpon()
                    .or(Selection.column(BlockedNumbers.COLUMN_E164_NUMBER).is("=", e164Number))
                          .or(
                              Selection.column(BlockedNumbers.COLUMN_E164_NUMBER)
                                  .is("=", e164Number))
                          .build();
                }
          try {
                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<ImmutableMap<String, Boolean>> isBlocked(
      Context context, ImmutableCollection<String> numbers, @Nullable String countryIso) {
    return DialerExecutorComponent.get(context)
        .backgroundExecutor()
        .submit(
            () -> {
              Map<String, Boolean> blockedStatus = new ArrayMap<>();
              List<String> 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()
                .delete(
                      .query(
                          BlockedNumbers.CONTENT_URI,
                          new String[] {BlockedNumbers.COLUMN_ORIGINAL_NUMBER},
                          selection.getSelection(),
                    selection.getSelectionArgs());
          } catch (SecurityException e) {
            throw new BlockingFailedException(e);
                          selection.getSelectionArgs(),
                          null)) {
                if (cursor == null) {
                  return ImmutableMap.copyOf(blockedStatus);
                }
          return null;
                while (cursor.moveToNext()) {
                  // Update blocked status
                  blockedStatus.put(cursor.getString(0), true);
                }
              }
              return ImmutableMap.copyOf(blockedStatus);
            });
  }

  private static ContentProviderResult[] applyBatchOps(
      ContentResolver resolver, ArrayList<ContentProviderOperation> ops)
      throws BlockingFailedException {
    try {
      return resolver.applyBatch(BlockedNumberContract.AUTHORITY, ops);
    } catch (RemoteException | OperationApplicationException | SecurityException e) {
      throw new BlockingFailedException(e);
    }
  }
}
+3 −4
Original line number Diff line number Diff line
@@ -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<Void>() {
          @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<Void>() {
          @Override
+3 −2
Original line number Diff line number Diff line
@@ -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());
    }
+1 −0
Original line number Diff line number Diff line
@@ -15,5 +15,6 @@ message ReportingLocation {
    CALL_LOG_HISTORY = 1;
    FEEDBACK_PROMPT = 2;
    VOICEMAIL_HISTORY = 3;
    CONTACT_DETAILS = 4;
  }
}