1 /* 2 * Copyright (C) 2018 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License 15 */ 16 17 package com.android.dialer.blockreportspam; 18 19 import android.content.BroadcastReceiver; 20 import android.content.Context; 21 import android.content.Intent; 22 import android.content.IntentFilter; 23 import android.support.v4.app.FragmentManager; 24 import android.widget.Toast; 25 import com.android.dialer.blocking.Blocking; 26 import com.android.dialer.blocking.Blocking.BlockingFailedException; 27 import com.android.dialer.blockreportspam.BlockReportSpamDialogs.DialogFragmentForBlockingNumber; 28 import com.android.dialer.blockreportspam.BlockReportSpamDialogs.DialogFragmentForBlockingNumberAndOptionallyReportingAsSpam; 29 import com.android.dialer.blockreportspam.BlockReportSpamDialogs.DialogFragmentForReportingNotSpam; 30 import com.android.dialer.blockreportspam.BlockReportSpamDialogs.DialogFragmentForUnblockingNumber; 31 import com.android.dialer.blockreportspam.BlockReportSpamDialogs.OnConfirmListener; 32 import com.android.dialer.blockreportspam.BlockReportSpamDialogs.OnSpamDialogClickListener; 33 import com.android.dialer.common.Assert; 34 import com.android.dialer.common.LogUtil; 35 import com.android.dialer.common.concurrent.DialerExecutorComponent; 36 import com.android.dialer.logging.DialerImpression; 37 import com.android.dialer.logging.DialerImpression.Type; 38 import com.android.dialer.logging.Logger; 39 import com.android.dialer.protos.ProtoParsers; 40 import com.android.dialer.spam.Spam; 41 import com.android.dialer.spam.SpamComponent; 42 import com.android.dialer.spam.SpamSettings; 43 import com.google.common.collect.ImmutableList; 44 import com.google.common.util.concurrent.FutureCallback; 45 import com.google.common.util.concurrent.Futures; 46 47 /** 48 * A {@link BroadcastReceiver} that shows an appropriate dialog upon receiving notifications from 49 * {@link ShowBlockReportSpamDialogNotifier}. 50 */ 51 public final class ShowBlockReportSpamDialogReceiver extends BroadcastReceiver { 52 53 static final String ACTION_SHOW_DIALOG_TO_BLOCK_NUMBER = "show_dialog_to_block_number"; 54 static final String ACTION_SHOW_DIALOG_TO_BLOCK_NUMBER_AND_OPTIONALLY_REPORT_SPAM = 55 "show_dialog_to_block_number_and_optionally_report_spam"; 56 static final String ACTION_SHOW_DIALOG_TO_REPORT_NOT_SPAM = "show_dialog_to_report_not_spam"; 57 static final String ACTION_SHOW_DIALOG_TO_UNBLOCK_NUMBER = "show_dialog_to_unblock_number"; 58 static final String EXTRA_DIALOG_INFO = "dialog_info"; 59 60 /** {@link FragmentManager} needed to show a {@link android.app.DialogFragment}. */ 61 private final FragmentManager fragmentManager; 62 63 /** Returns an {@link IntentFilter} containing all actions accepted by this broadcast receiver. */ getIntentFilter()64 public static IntentFilter getIntentFilter() { 65 IntentFilter intentFilter = new IntentFilter(); 66 intentFilter.addAction(ACTION_SHOW_DIALOG_TO_BLOCK_NUMBER_AND_OPTIONALLY_REPORT_SPAM); 67 intentFilter.addAction(ACTION_SHOW_DIALOG_TO_BLOCK_NUMBER); 68 intentFilter.addAction(ACTION_SHOW_DIALOG_TO_REPORT_NOT_SPAM); 69 intentFilter.addAction(ACTION_SHOW_DIALOG_TO_UNBLOCK_NUMBER); 70 return intentFilter; 71 } 72 ShowBlockReportSpamDialogReceiver(FragmentManager fragmentManager)73 public ShowBlockReportSpamDialogReceiver(FragmentManager fragmentManager) { 74 this.fragmentManager = fragmentManager; 75 } 76 77 @Override onReceive(Context context, Intent intent)78 public void onReceive(Context context, Intent intent) { 79 LogUtil.enterBlock("ShowBlockReportSpamDialogReceiver.onReceive"); 80 81 String action = intent.getAction(); 82 83 switch (Assert.isNotNull(action)) { 84 case ACTION_SHOW_DIALOG_TO_BLOCK_NUMBER: 85 showDialogToBlockNumber(context, intent); 86 break; 87 case ACTION_SHOW_DIALOG_TO_BLOCK_NUMBER_AND_OPTIONALLY_REPORT_SPAM: 88 showDialogToBlockNumberAndOptionallyReportSpam(context, intent); 89 break; 90 case ACTION_SHOW_DIALOG_TO_REPORT_NOT_SPAM: 91 showDialogToReportNotSpam(context, intent); 92 break; 93 case ACTION_SHOW_DIALOG_TO_UNBLOCK_NUMBER: 94 showDialogToUnblockNumber(context, intent); 95 break; 96 default: 97 throw new IllegalStateException("Unsupported action: " + action); 98 } 99 } 100 showDialogToBlockNumberAndOptionallyReportSpam(Context context, Intent intent)101 private void showDialogToBlockNumberAndOptionallyReportSpam(Context context, Intent intent) { 102 LogUtil.enterBlock( 103 "ShowBlockReportSpamDialogReceiver.showDialogToBlockNumberAndOptionallyReportSpam"); 104 105 Assert.checkArgument(intent.hasExtra(EXTRA_DIALOG_INFO)); 106 BlockReportSpamDialogInfo dialogInfo = 107 ProtoParsers.getTrusted( 108 intent, EXTRA_DIALOG_INFO, BlockReportSpamDialogInfo.getDefaultInstance()); 109 110 Spam spam = SpamComponent.get(context).spam(); 111 SpamSettings spamSettings = SpamComponent.get(context).spamSettings(); 112 113 // Set up the positive listener for the dialog. 114 OnSpamDialogClickListener onSpamDialogClickListener = 115 reportSpam -> { 116 LogUtil.i( 117 "ShowBlockReportSpamDialogReceiver.showDialogToBlockNumberAndOptionallyReportSpam", 118 "confirmed"); 119 120 if (reportSpam && spamSettings.isSpamEnabled()) { 121 LogUtil.i( 122 "ShowBlockReportSpamDialogReceiver.showDialogToBlockNumberAndOptionallyReportSpam", 123 "report spam"); 124 Logger.get(context) 125 .logImpression( 126 DialerImpression.Type 127 .REPORT_CALL_AS_SPAM_VIA_CALL_LOG_BLOCK_REPORT_SPAM_SENT_VIA_BLOCK_NUMBER_DIALOG); 128 spam.reportSpamFromCallHistory( 129 dialogInfo.getNormalizedNumber(), 130 dialogInfo.getCountryIso(), 131 dialogInfo.getCallType(), 132 dialogInfo.getReportingLocation(), 133 dialogInfo.getContactSource()); 134 } 135 136 blockNumber(context, dialogInfo); 137 }; 138 139 // Create and show the dialog. 140 DialogFragmentForBlockingNumberAndOptionallyReportingAsSpam.newInstance( 141 dialogInfo.getNormalizedNumber(), 142 spamSettings.isDialogReportSpamCheckedByDefault(), 143 onSpamDialogClickListener, 144 /* dismissListener = */ null) 145 .show(fragmentManager, BlockReportSpamDialogs.BLOCK_REPORT_SPAM_DIALOG_TAG); 146 } 147 showDialogToBlockNumber(Context context, Intent intent)148 private void showDialogToBlockNumber(Context context, Intent intent) { 149 LogUtil.enterBlock("ShowBlockReportSpamDialogReceiver.showDialogToBlockNumber"); 150 151 Assert.checkArgument(intent.hasExtra(EXTRA_DIALOG_INFO)); 152 BlockReportSpamDialogInfo dialogInfo = 153 ProtoParsers.getTrusted( 154 intent, EXTRA_DIALOG_INFO, BlockReportSpamDialogInfo.getDefaultInstance()); 155 156 // Set up the positive listener for the dialog. 157 OnConfirmListener onConfirmListener = 158 () -> { 159 LogUtil.i("ShowBlockReportSpamDialogReceiver.showDialogToBlockNumber", "block number"); 160 blockNumber(context, dialogInfo); 161 }; 162 163 // Create and show the dialog. 164 DialogFragmentForBlockingNumber.newInstance( 165 dialogInfo.getNormalizedNumber(), onConfirmListener, /* dismissListener = */ null) 166 .show(fragmentManager, BlockReportSpamDialogs.BLOCK_DIALOG_TAG); 167 } 168 showDialogToReportNotSpam(Context context, Intent intent)169 private void showDialogToReportNotSpam(Context context, Intent intent) { 170 LogUtil.enterBlock("ShowBlockReportSpamDialogReceiver.showDialogToReportNotSpam"); 171 172 Assert.checkArgument(intent.hasExtra(EXTRA_DIALOG_INFO)); 173 BlockReportSpamDialogInfo dialogInfo = 174 ProtoParsers.getTrusted( 175 intent, EXTRA_DIALOG_INFO, BlockReportSpamDialogInfo.getDefaultInstance()); 176 177 // Set up the positive listener for the dialog. 178 OnConfirmListener onConfirmListener = 179 () -> { 180 LogUtil.i("ShowBlockReportSpamDialogReceiver.showDialogToReportNotSpam", "confirmed"); 181 182 if (SpamComponent.get(context).spamSettings().isSpamEnabled()) { 183 Logger.get(context) 184 .logImpression(DialerImpression.Type.DIALOG_ACTION_CONFIRM_NUMBER_NOT_SPAM); 185 SpamComponent.get(context) 186 .spam() 187 .reportNotSpamFromCallHistory( 188 dialogInfo.getNormalizedNumber(), 189 dialogInfo.getCountryIso(), 190 dialogInfo.getCallType(), 191 dialogInfo.getReportingLocation(), 192 dialogInfo.getContactSource()); 193 } 194 }; 195 196 // Create & show the dialog. 197 DialogFragmentForReportingNotSpam.newInstance( 198 dialogInfo.getNormalizedNumber(), onConfirmListener, /* dismissListener = */ null) 199 .show(fragmentManager, BlockReportSpamDialogs.NOT_SPAM_DIALOG_TAG); 200 } 201 showDialogToUnblockNumber(Context context, Intent intent)202 private void showDialogToUnblockNumber(Context context, Intent intent) { 203 LogUtil.enterBlock("ShowBlockReportSpamDialogReceiver.showDialogToUnblockNumber"); 204 205 Assert.checkArgument(intent.hasExtra(EXTRA_DIALOG_INFO)); 206 BlockReportSpamDialogInfo dialogInfo = 207 ProtoParsers.getTrusted( 208 intent, EXTRA_DIALOG_INFO, BlockReportSpamDialogInfo.getDefaultInstance()); 209 210 // Set up the positive listener for the dialog. 211 OnConfirmListener onConfirmListener = 212 () -> { 213 LogUtil.i("ShowBlockReportSpamDialogReceiver.showDialogToUnblockNumber", "confirmed"); 214 215 unblockNumber(context, dialogInfo); 216 }; 217 218 // Create & show the dialog. 219 DialogFragmentForUnblockingNumber.newInstance( 220 dialogInfo.getNormalizedNumber(), onConfirmListener, /* dismissListener = */ null) 221 .show(fragmentManager, BlockReportSpamDialogs.UNBLOCK_DIALOG_TAG); 222 } 223 blockNumber(Context context, BlockReportSpamDialogInfo dialogInfo)224 private static void blockNumber(Context context, BlockReportSpamDialogInfo dialogInfo) { 225 Logger.get(context).logImpression(Type.USER_ACTION_BLOCKED_NUMBER); 226 Futures.addCallback( 227 Blocking.block( 228 context, 229 ImmutableList.of(dialogInfo.getNormalizedNumber()), 230 dialogInfo.getCountryIso()), 231 new FutureCallback<Void>() { 232 @Override 233 public void onSuccess(Void unused) { 234 // Do nothing 235 } 236 237 @Override 238 public void onFailure(Throwable throwable) { 239 if (throwable instanceof BlockingFailedException) { 240 Logger.get(context).logImpression(Type.USER_ACTION_BLOCK_NUMBER_FAILED); 241 Toast.makeText(context, R.string.block_number_failed_toast, Toast.LENGTH_LONG).show(); 242 } else { 243 throw new RuntimeException(throwable); 244 } 245 } 246 }, 247 DialerExecutorComponent.get(context).uiExecutor()); 248 } 249 unblockNumber(Context context, BlockReportSpamDialogInfo dialogInfo)250 private static void unblockNumber(Context context, BlockReportSpamDialogInfo dialogInfo) { 251 Logger.get(context).logImpression(Type.USER_ACTION_UNBLOCKED_NUMBER); 252 Futures.addCallback( 253 Blocking.unblock( 254 context, 255 ImmutableList.of(dialogInfo.getNormalizedNumber()), 256 dialogInfo.getCountryIso()), 257 new FutureCallback<Void>() { 258 @Override 259 public void onSuccess(Void unused) { 260 // Do nothing 261 } 262 263 @Override 264 public void onFailure(Throwable throwable) { 265 if (throwable instanceof BlockingFailedException) { 266 Logger.get(context).logImpression(Type.USER_ACTION_UNBLOCK_NUMBER_FAILED); 267 Toast.makeText(context, R.string.unblock_number_failed_toast, Toast.LENGTH_LONG) 268 .show(); 269 } else { 270 throw new RuntimeException(throwable); 271 } 272 } 273 }, 274 DialerExecutorComponent.get(context).uiExecutor()); 275 } 276 } 277