1 /* 2 * Copyright (C) 2016 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.incallui.spam; 18 19 import android.app.Dialog; 20 import android.app.DialogFragment; 21 import android.content.Context; 22 import android.content.DialogInterface; 23 import android.content.Intent; 24 import android.os.Bundle; 25 import android.provider.CallLog; 26 import android.provider.ContactsContract; 27 import android.support.annotation.Nullable; 28 import android.support.v4.app.FragmentActivity; 29 import android.support.v7.app.AlertDialog; 30 import android.telephony.PhoneNumberUtils; 31 import com.android.dialer.blocking.BlockedNumbersMigrator; 32 import com.android.dialer.blocking.FilteredNumberAsyncQueryHandler; 33 import com.android.dialer.blocking.FilteredNumberCompat; 34 import com.android.dialer.blockreportspam.BlockReportSpamDialogs; 35 import com.android.dialer.blockreportspam.BlockReportSpamDialogs.DialogFragmentForBlockingNumberAndOptionallyReportingAsSpam; 36 import com.android.dialer.blockreportspam.BlockReportSpamDialogs.DialogFragmentForReportingNotSpam; 37 import com.android.dialer.common.LogUtil; 38 import com.android.dialer.location.GeoUtil; 39 import com.android.dialer.logging.ContactLookupResult; 40 import com.android.dialer.logging.DialerImpression; 41 import com.android.dialer.logging.Logger; 42 import com.android.dialer.logging.ReportingLocation; 43 import com.android.dialer.notification.DialerNotificationManager; 44 import com.android.dialer.phonenumberutil.PhoneNumberHelper; 45 import com.android.dialer.spam.SpamComponent; 46 import com.android.dialer.spam.SpamSettings; 47 import com.android.dialer.spam.promo.SpamBlockingPromoHelper; 48 import com.android.incallui.call.DialerCall; 49 50 /** Creates the after call notification dialogs. */ 51 public class SpamNotificationActivity extends FragmentActivity { 52 53 /** Action to add number to contacts. */ 54 static final String ACTION_ADD_TO_CONTACTS = "com.android.incallui.spam.ACTION_ADD_TO_CONTACTS"; 55 /** Action to show dialog. */ 56 static final String ACTION_SHOW_DIALOG = "com.android.incallui.spam.ACTION_SHOW_DIALOG"; 57 /** Action to mark a number as spam. */ 58 static final String ACTION_MARK_NUMBER_AS_SPAM = 59 "com.android.incallui.spam.ACTION_MARK_NUMBER_AS_SPAM"; 60 /** Action to mark a number as not spam. */ 61 static final String ACTION_MARK_NUMBER_AS_NOT_SPAM = 62 "com.android.incallui.spam.ACTION_MARK_NUMBER_AS_NOT_SPAM"; 63 64 static final String ACTION_ENABLE_SPAM_BLOCKING = 65 "com.android.incallui.spam.ACTION_ENABLE_SPAM_BLOCKING"; 66 67 static final String ACTION_SHOW_SPAM_BLOCKING_PROMO_DIALOG = 68 "com.android.incallui.spam.ACTION_SHOW_SPAM_BLOCKING_PROMO_DIALOG"; 69 70 private static final String TAG = "SpamNotifications"; 71 private static final String EXTRA_NOTIFICATION_TAG = "notification_tag"; 72 private static final String EXTRA_NOTIFICATION_ID = "notification_id"; 73 private static final String EXTRA_CALL_INFO = "call_info"; 74 75 private static final String CALL_INFO_KEY_PHONE_NUMBER = "phone_number"; 76 private static final String CALL_INFO_KEY_IS_SPAM = "is_spam"; 77 private static final String CALL_INFO_KEY_CALL_ID = "call_id"; 78 private static final String CALL_INFO_KEY_START_TIME_MILLIS = "call_start_time_millis"; 79 private static final String CALL_INFO_CONTACT_LOOKUP_RESULT_TYPE = "contact_lookup_result_type"; 80 private final DialogInterface.OnDismissListener dismissListener = 81 new DialogInterface.OnDismissListener() { 82 @Override 83 public void onDismiss(DialogInterface dialog) { 84 if (!isFinishing()) { 85 finish(); 86 } 87 } 88 }; 89 private FilteredNumberAsyncQueryHandler filteredNumberAsyncQueryHandler; 90 private SpamSettings spamSettings; 91 private SpamBlockingPromoHelper spamBlockingPromoHelper; 92 93 /** 94 * Creates an intent to start this activity. 95 * 96 * @return Intent intent that starts this activity. 97 */ createActivityIntent( Context context, @Nullable DialerCall call, String action, String notificationTag, int notificationId)98 public static Intent createActivityIntent( 99 Context context, 100 @Nullable DialerCall call, 101 String action, 102 String notificationTag, 103 int notificationId) { 104 Intent intent = new Intent(context, SpamNotificationActivity.class); 105 intent.setAction(action); 106 // This ensures only one activity of this kind exists at a time. 107 intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK); 108 intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); 109 intent.putExtra(EXTRA_NOTIFICATION_TAG, notificationTag); 110 intent.putExtra(EXTRA_NOTIFICATION_ID, notificationId); 111 112 if (call != null) { 113 intent.putExtra(EXTRA_CALL_INFO, newCallInfoBundle(call)); 114 } 115 return intent; 116 } 117 118 /** Creates the intent to insert a contact. */ createInsertContactsIntent(String number)119 private static Intent createInsertContactsIntent(String number) { 120 Intent intent = new Intent(ContactsContract.Intents.Insert.ACTION); 121 // This ensures that the edit contact number field gets updated if called more than once. 122 intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); 123 intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP); 124 intent.setType(ContactsContract.RawContacts.CONTENT_TYPE); 125 intent.putExtra(ContactsContract.Intents.Insert.PHONE, number); 126 return intent; 127 } 128 129 /** Returns the formatted version of the given number. */ getFormattedNumber(String number, Context context)130 private static String getFormattedNumber(String number, Context context) { 131 String formattedNumber = 132 PhoneNumberHelper.formatNumber(context, number, GeoUtil.getCurrentCountryIso(context)); 133 return PhoneNumberUtils.createTtsSpannable(formattedNumber).toString(); 134 } 135 logCallImpression(DialerImpression.Type impression)136 private void logCallImpression(DialerImpression.Type impression) { 137 logCallImpression(this, getCallInfo(), impression); 138 } 139 logCallImpression( Context context, Bundle bundle, DialerImpression.Type impression)140 private static void logCallImpression( 141 Context context, Bundle bundle, DialerImpression.Type impression) { 142 Logger.get(context) 143 .logCallImpression( 144 impression, 145 bundle.getString(CALL_INFO_KEY_CALL_ID), 146 bundle.getLong(CALL_INFO_KEY_START_TIME_MILLIS, 0)); 147 } 148 newCallInfoBundle(DialerCall call)149 private static Bundle newCallInfoBundle(DialerCall call) { 150 Bundle bundle = new Bundle(); 151 bundle.putString(CALL_INFO_KEY_PHONE_NUMBER, call.getNumber()); 152 bundle.putBoolean(CALL_INFO_KEY_IS_SPAM, call.isSpam()); 153 bundle.putString(CALL_INFO_KEY_CALL_ID, call.getUniqueCallId()); 154 bundle.putLong(CALL_INFO_KEY_START_TIME_MILLIS, call.getTimeAddedMs()); 155 bundle.putInt( 156 CALL_INFO_CONTACT_LOOKUP_RESULT_TYPE, call.getLogState().contactLookupResult.getNumber()); 157 return bundle; 158 } 159 160 @Override onCreate(Bundle savedInstanceState)161 protected void onCreate(Bundle savedInstanceState) { 162 LogUtil.i(TAG, "onCreate"); 163 super.onCreate(savedInstanceState); 164 setFinishOnTouchOutside(true); 165 filteredNumberAsyncQueryHandler = new FilteredNumberAsyncQueryHandler(this); 166 spamSettings = SpamComponent.get(this).spamSettings(); 167 spamBlockingPromoHelper = new SpamBlockingPromoHelper(getApplicationContext(), spamSettings); 168 cancelNotification(); 169 } 170 171 @Override onResume()172 protected void onResume() { 173 LogUtil.i(TAG, "onResume"); 174 super.onResume(); 175 Intent intent = getIntent(); 176 String number = getCallInfo().getString(CALL_INFO_KEY_PHONE_NUMBER); 177 boolean isSpam = getCallInfo().getBoolean(CALL_INFO_KEY_IS_SPAM); 178 ContactLookupResult.Type contactLookupResultType = 179 ContactLookupResult.Type.forNumber( 180 getCallInfo().getInt(CALL_INFO_CONTACT_LOOKUP_RESULT_TYPE, 0)); 181 switch (intent.getAction()) { 182 case ACTION_ADD_TO_CONTACTS: 183 logCallImpression(DialerImpression.Type.SPAM_AFTER_CALL_NOTIFICATION_ADD_TO_CONTACTS); 184 startActivity(createInsertContactsIntent(number)); 185 finish(); 186 break; 187 case ACTION_MARK_NUMBER_AS_SPAM: 188 assertDialogsEnabled(); 189 maybeShowBlockReportSpamDialog(number, contactLookupResultType); 190 break; 191 case ACTION_MARK_NUMBER_AS_NOT_SPAM: 192 assertDialogsEnabled(); 193 maybeShowNotSpamDialog(number, contactLookupResultType); 194 break; 195 case ACTION_SHOW_DIALOG: 196 if (isSpam) { 197 showSpamFullDialog(); 198 } else { 199 showNonSpamDialog(); 200 } 201 break; 202 case ACTION_SHOW_SPAM_BLOCKING_PROMO_DIALOG: 203 showSpamBlockingPromoDialog(); 204 break; 205 default: // fall out 206 } 207 } 208 209 @Override onPause()210 protected void onPause() { 211 LogUtil.d(TAG, "onPause"); 212 // Finish activity on pause (e.g: orientation change or back button pressed) 213 filteredNumberAsyncQueryHandler = null; 214 if (!isFinishing()) { 215 finish(); 216 } 217 super.onPause(); 218 } 219 220 /** Creates and displays the dialog for whitelisting a number. */ maybeShowNotSpamDialog( final String number, final ContactLookupResult.Type contactLookupResultType)221 private void maybeShowNotSpamDialog( 222 final String number, final ContactLookupResult.Type contactLookupResultType) { 223 if (SpamComponent.get(this).spamSettings().isDialogEnabledForSpamNotification()) { 224 DialogFragmentForReportingNotSpam.newInstance( 225 getFormattedNumber(number, this), 226 new BlockReportSpamDialogs.OnConfirmListener() { 227 @Override 228 public void onClick() { 229 reportNotSpamAndFinish(number, contactLookupResultType); 230 } 231 }, 232 dismissListener) 233 .show(getSupportFragmentManager(), BlockReportSpamDialogs.NOT_SPAM_DIALOG_TAG); 234 } else { 235 reportNotSpamAndFinish(number, contactLookupResultType); 236 } 237 } 238 239 /** Creates and displays the dialog for blocking/reporting a number as spam. */ maybeShowBlockReportSpamDialog( final String number, final ContactLookupResult.Type contactLookupResultType)240 private void maybeShowBlockReportSpamDialog( 241 final String number, final ContactLookupResult.Type contactLookupResultType) { 242 if (SpamComponent.get(this).spamSettings().isDialogEnabledForSpamNotification()) { 243 String displayNumber = getFormattedNumber(number, this); 244 maybeShowBlockNumberMigrationDialog( 245 new BlockedNumbersMigrator.Listener() { 246 @Override 247 public void onComplete() { 248 DialogFragmentForBlockingNumberAndOptionallyReportingAsSpam.newInstance( 249 displayNumber, 250 SpamComponent.get(SpamNotificationActivity.this) 251 .spamSettings() 252 .isDialogReportSpamCheckedByDefault(), 253 new BlockReportSpamDialogs.OnSpamDialogClickListener() { 254 @Override 255 public void onClick(boolean isSpamChecked) { 256 blockReportNumber(number, isSpamChecked, contactLookupResultType); 257 } 258 }, 259 dismissListener) 260 .show( 261 getSupportFragmentManager(), 262 BlockReportSpamDialogs.BLOCK_REPORT_SPAM_DIALOG_TAG); 263 } 264 }); 265 } else { 266 blockReportNumber(number, true, contactLookupResultType); 267 } 268 } 269 270 /** 271 * Displays the dialog for the first time unknown calls with actions "Add contact", "Block/report 272 * spam", and "Dismiss". 273 */ showNonSpamDialog()274 private void showNonSpamDialog() { 275 logCallImpression(DialerImpression.Type.SPAM_AFTER_CALL_NOTIFICATION_SHOW_NON_SPAM_DIALOG); 276 FirstTimeNonSpamCallDialogFragment.newInstance(getCallInfo()) 277 .show(getFragmentManager(), FirstTimeNonSpamCallDialogFragment.TAG); 278 } 279 280 /** 281 * Displays the dialog for first time spam calls with actions "Not spam", "Block", and "Dismiss". 282 */ showSpamFullDialog()283 private void showSpamFullDialog() { 284 logCallImpression(DialerImpression.Type.SPAM_AFTER_CALL_NOTIFICATION_SHOW_SPAM_DIALOG); 285 FirstTimeSpamCallDialogFragment.newInstance(getCallInfo()) 286 .show(getFragmentManager(), FirstTimeSpamCallDialogFragment.TAG); 287 } 288 289 /** Checks if the user has migrated to the new blocking and display a dialog if necessary. */ maybeShowBlockNumberMigrationDialog(BlockedNumbersMigrator.Listener listener)290 private void maybeShowBlockNumberMigrationDialog(BlockedNumbersMigrator.Listener listener) { 291 if (!FilteredNumberCompat.maybeShowBlockNumberMigrationDialog( 292 this, getFragmentManager(), listener)) { 293 listener.onComplete(); 294 } 295 } 296 297 /** Block and report the number as spam. */ blockReportNumber( String number, boolean reportAsSpam, ContactLookupResult.Type contactLookupResultType)298 private void blockReportNumber( 299 String number, boolean reportAsSpam, ContactLookupResult.Type contactLookupResultType) { 300 if (reportAsSpam) { 301 logCallImpression(DialerImpression.Type.SPAM_AFTER_CALL_NOTIFICATION_MARKED_NUMBER_AS_SPAM); 302 SpamComponent.get(this) 303 .spam() 304 .reportSpamFromAfterCallNotification( 305 number, 306 getCountryIso(), 307 CallLog.Calls.INCOMING_TYPE, 308 ReportingLocation.Type.FEEDBACK_PROMPT, 309 contactLookupResultType); 310 } 311 312 logCallImpression(DialerImpression.Type.SPAM_AFTER_CALL_NOTIFICATION_BLOCK_NUMBER); 313 filteredNumberAsyncQueryHandler.blockNumber(null, number, getCountryIso()); 314 } 315 316 /** Report the number as not spam. */ reportNotSpamAndFinish( String number, ContactLookupResult.Type contactLookupResultType)317 private void reportNotSpamAndFinish( 318 String number, ContactLookupResult.Type contactLookupResultType) { 319 logCallImpression(DialerImpression.Type.SPAM_AFTER_CALL_NOTIFICATION_REPORT_NUMBER_AS_NOT_SPAM); 320 SpamComponent.get(this) 321 .spam() 322 .reportNotSpamFromAfterCallNotification( 323 number, 324 getCountryIso(), 325 CallLog.Calls.INCOMING_TYPE, 326 ReportingLocation.Type.FEEDBACK_PROMPT, 327 contactLookupResultType); 328 // TODO: DialerCall finish() after async task completes (a bug) 329 finish(); 330 } 331 332 /** Cancels the notification associated with the number. */ cancelNotification()333 private void cancelNotification() { 334 String notificationTag = getIntent().getStringExtra(EXTRA_NOTIFICATION_TAG); 335 int notificationId = getIntent().getIntExtra(EXTRA_NOTIFICATION_ID, 1); 336 DialerNotificationManager.cancel(this, notificationTag, notificationId); 337 } 338 getCountryIso()339 private String getCountryIso() { 340 return GeoUtil.getCurrentCountryIso(this); 341 } 342 assertDialogsEnabled()343 private void assertDialogsEnabled() { 344 if (!SpamComponent.get(this).spamSettings().isDialogEnabledForSpamNotification()) { 345 throw new IllegalStateException( 346 "Cannot start this activity with given action because dialogs are not enabled."); 347 } 348 } 349 getCallInfo()350 private Bundle getCallInfo() { 351 return getIntent().hasExtra(EXTRA_CALL_INFO) 352 ? getIntent().getBundleExtra(EXTRA_CALL_INFO) 353 : new Bundle(); 354 } 355 356 /** Dialog that displays "Not spam", "Block/report spam" and "Dismiss". */ 357 public static class FirstTimeSpamCallDialogFragment extends DialogFragment { 358 359 public static final String TAG = "FirstTimeSpamDialog"; 360 361 private boolean dismissed; 362 private Context applicationContext; 363 newInstance(Bundle bundle)364 private static DialogFragment newInstance(Bundle bundle) { 365 FirstTimeSpamCallDialogFragment fragment = new FirstTimeSpamCallDialogFragment(); 366 fragment.setArguments(bundle); 367 return fragment; 368 } 369 370 @Override onPause()371 public void onPause() { 372 dismiss(); 373 super.onPause(); 374 } 375 376 @Override onDismiss(DialogInterface dialog)377 public void onDismiss(DialogInterface dialog) { 378 logCallImpression( 379 applicationContext, 380 getArguments(), 381 DialerImpression.Type.SPAM_AFTER_CALL_NOTIFICATION_ON_DISMISS_SPAM_DIALOG); 382 super.onDismiss(dialog); 383 // If dialog was not dismissed by user pressing one of the buttons, finish activity 384 if (!dismissed && getActivity() != null && !getActivity().isFinishing()) { 385 getActivity().finish(); 386 } 387 } 388 389 @Override onAttach(Context context)390 public void onAttach(Context context) { 391 super.onAttach(context); 392 applicationContext = context.getApplicationContext(); 393 } 394 395 @Override onCreateDialog(Bundle savedInstanceState)396 public Dialog onCreateDialog(Bundle savedInstanceState) { 397 super.onCreateDialog(savedInstanceState); 398 final SpamNotificationActivity spamNotificationActivity = 399 (SpamNotificationActivity) getActivity(); 400 final String number = getArguments().getString(CALL_INFO_KEY_PHONE_NUMBER); 401 final ContactLookupResult.Type contactLookupResultType = 402 ContactLookupResult.Type.forNumber( 403 getArguments().getInt(CALL_INFO_CONTACT_LOOKUP_RESULT_TYPE, 0)); 404 405 return new AlertDialog.Builder(getActivity()) 406 .setCancelable(false) 407 .setTitle( 408 getString( 409 SpamAlternativeExperimentUtil.getResourceIdByName( 410 "spam_notification_title", applicationContext), 411 getFormattedNumber(number, applicationContext))) 412 .setNeutralButton( 413 getString(R.string.spam_notification_action_dismiss), 414 new DialogInterface.OnClickListener() { 415 @Override 416 public void onClick(DialogInterface dialog, int which) { 417 dismiss(); 418 } 419 }) 420 .setPositiveButton( 421 getString(R.string.spam_notification_block_spam_action_text), 422 new DialogInterface.OnClickListener() { 423 @Override 424 public void onClick(DialogInterface dialog, int which) { 425 dismissed = true; 426 dismiss(); 427 spamNotificationActivity.maybeShowBlockReportSpamDialog( 428 number, contactLookupResultType); 429 spamNotificationActivity.maybeShowSpamBlockingPromoAndFinish(); 430 } 431 }) 432 .setNegativeButton( 433 getString( 434 SpamAlternativeExperimentUtil.getResourceIdByName( 435 "spam_notification_was_not_spam_action_text", applicationContext)), 436 new DialogInterface.OnClickListener() { 437 @Override 438 public void onClick(DialogInterface dialog, int which) { 439 dismissed = true; 440 dismiss(); 441 spamNotificationActivity.maybeShowNotSpamDialog(number, contactLookupResultType); 442 } 443 }) 444 .create(); 445 } 446 } 447 448 /** Dialog that displays "Add contact", "Block/report spam" and "Dismiss". */ 449 public static class FirstTimeNonSpamCallDialogFragment extends DialogFragment { 450 451 public static final String TAG = "FirstTimeNonSpamDialog"; 452 453 private boolean dismissed; 454 private Context context; 455 456 private static DialogFragment newInstance(Bundle bundle) { 457 FirstTimeNonSpamCallDialogFragment fragment = new FirstTimeNonSpamCallDialogFragment(); 458 fragment.setArguments(bundle); 459 return fragment; 460 } 461 462 @Override 463 public void onPause() { 464 // Dismiss on pause e.g: orientation change 465 dismiss(); 466 super.onPause(); 467 } 468 469 @Override 470 public void onDismiss(DialogInterface dialog) { 471 super.onDismiss(dialog); 472 logCallImpression( 473 context, 474 getArguments(), 475 DialerImpression.Type.SPAM_AFTER_CALL_NOTIFICATION_ON_DISMISS_NON_SPAM_DIALOG); 476 // If dialog was not dismissed by user pressing one of the buttons, finish activity 477 if (!dismissed && getActivity() != null && !getActivity().isFinishing()) { 478 getActivity().finish(); 479 } 480 } 481 482 @Override 483 public void onAttach(Context context) { 484 super.onAttach(context); 485 this.context = context.getApplicationContext(); 486 } 487 488 @Override 489 public Dialog onCreateDialog(Bundle savedInstanceState) { 490 super.onCreateDialog(savedInstanceState); 491 final SpamNotificationActivity spamNotificationActivity = 492 (SpamNotificationActivity) getActivity(); 493 final String number = getArguments().getString(CALL_INFO_KEY_PHONE_NUMBER); 494 final ContactLookupResult.Type contactLookupResultType = 495 ContactLookupResult.Type.forNumber( 496 getArguments().getInt(CALL_INFO_CONTACT_LOOKUP_RESULT_TYPE, 0)); 497 return new AlertDialog.Builder(getActivity()) 498 .setTitle( 499 getString(R.string.non_spam_notification_title, getFormattedNumber(number, context))) 500 .setCancelable(false) 501 .setMessage( 502 getString( 503 SpamAlternativeExperimentUtil.getResourceIdByName( 504 "spam_notification_non_spam_call_expanded_text", context))) 505 .setNeutralButton( 506 getString(R.string.spam_notification_action_dismiss), 507 new DialogInterface.OnClickListener() { 508 @Override 509 public void onClick(DialogInterface dialog, int which) { 510 dismiss(); 511 } 512 }) 513 .setPositiveButton( 514 getString(R.string.spam_notification_dialog_add_contact_action_text), 515 new DialogInterface.OnClickListener() { 516 @Override 517 public void onClick(DialogInterface dialog, int which) { 518 dismissed = true; 519 dismiss(); 520 startActivity(createInsertContactsIntent(number)); 521 } 522 }) 523 .setNegativeButton( 524 getString( 525 SpamAlternativeExperimentUtil.getResourceIdByName( 526 "spam_notification_dialog_block_report_spam_action_text", context)), 527 new DialogInterface.OnClickListener() { 528 @Override 529 public void onClick(DialogInterface dialog, int which) { 530 dismissed = true; 531 dismiss(); 532 spamNotificationActivity.maybeShowBlockReportSpamDialog( 533 number, contactLookupResultType); 534 spamNotificationActivity.maybeShowSpamBlockingPromoAndFinish(); 535 } 536 }) 537 .create(); 538 } 539 } 540 541 private void maybeShowSpamBlockingPromoAndFinish() { 542 if (!spamBlockingPromoHelper.shouldShowAfterCallSpamBlockingPromo()) { 543 finish(); 544 return; 545 } 546 Logger.get(this) 547 .logImpression(DialerImpression.Type.SPAM_BLOCKING_AFTER_CALL_NOTIFICATION_PROMO_SHOWN); 548 showSpamBlockingPromoDialog(); 549 } 550 551 private void showSpamBlockingPromoDialog() { 552 spamBlockingPromoHelper.showSpamBlockingPromoDialog( 553 getSupportFragmentManager(), 554 () -> { 555 Logger.get(this) 556 .logImpression( 557 DialerImpression.Type 558 .SPAM_BLOCKING_ENABLED_THROUGH_AFTER_CALL_NOTIFICATION_PROMO); 559 spamSettings.modifySpamBlockingSetting( 560 true, 561 success -> { 562 if (!success) { 563 Logger.get(this) 564 .logImpression( 565 DialerImpression.Type 566 .SPAM_BLOCKING_MODIFY_FAILURE_THROUGH_AFTER_CALL_NOTIFICATION_PROMO); 567 } 568 spamBlockingPromoHelper.showModifySettingOnCompleteToast(success); 569 }); 570 }, 571 dialog -> finish()); 572 } 573 } 574