1 /* 2 * Copyright (C) 2015 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.blocking; 18 19 import android.app.AlertDialog; 20 import android.app.Dialog; 21 import android.app.DialogFragment; 22 import android.app.FragmentManager; 23 import android.content.ContentValues; 24 import android.content.Context; 25 import android.content.DialogInterface; 26 import android.net.Uri; 27 import android.os.Bundle; 28 import android.support.design.widget.Snackbar; 29 import android.telephony.PhoneNumberUtils; 30 import android.text.TextUtils; 31 import android.view.View; 32 import android.widget.Toast; 33 import com.android.contacts.common.util.ContactDisplayUtils; 34 import com.android.dialer.blocking.FilteredNumberAsyncQueryHandler.OnBlockNumberListener; 35 import com.android.dialer.blocking.FilteredNumberAsyncQueryHandler.OnUnblockNumberListener; 36 import com.android.dialer.logging.InteractionEvent; 37 import com.android.dialer.logging.Logger; 38 import com.android.dialer.voicemailstatus.VisualVoicemailEnabledChecker; 39 40 /** 41 * Fragment for confirming and enacting blocking/unblocking a number. Also invokes snackbar 42 * providing undo functionality. 43 */ 44 @Deprecated 45 public class BlockNumberDialogFragment extends DialogFragment { 46 47 private static final String BLOCK_DIALOG_FRAGMENT = "BlockNumberDialog"; 48 private static final String ARG_BLOCK_ID = "argBlockId"; 49 private static final String ARG_NUMBER = "argNumber"; 50 private static final String ARG_COUNTRY_ISO = "argCountryIso"; 51 private static final String ARG_DISPLAY_NUMBER = "argDisplayNumber"; 52 private static final String ARG_PARENT_VIEW_ID = "parentViewId"; 53 private String number; 54 private String displayNumber; 55 private String countryIso; 56 private FilteredNumberAsyncQueryHandler handler; 57 private View parentView; 58 private VisualVoicemailEnabledChecker voicemailEnabledChecker; 59 private Callback callback; 60 show( Integer blockId, String number, String countryIso, String displayNumber, Integer parentViewId, FragmentManager fragmentManager, Callback callback)61 public static BlockNumberDialogFragment show( 62 Integer blockId, 63 String number, 64 String countryIso, 65 String displayNumber, 66 Integer parentViewId, 67 FragmentManager fragmentManager, 68 Callback callback) { 69 final BlockNumberDialogFragment newFragment = 70 BlockNumberDialogFragment.newInstance( 71 blockId, number, countryIso, displayNumber, parentViewId); 72 73 newFragment.setCallback(callback); 74 newFragment.show(fragmentManager, BlockNumberDialogFragment.BLOCK_DIALOG_FRAGMENT); 75 return newFragment; 76 } 77 newInstance( Integer blockId, String number, String countryIso, String displayNumber, Integer parentViewId)78 private static BlockNumberDialogFragment newInstance( 79 Integer blockId, 80 String number, 81 String countryIso, 82 String displayNumber, 83 Integer parentViewId) { 84 final BlockNumberDialogFragment fragment = new BlockNumberDialogFragment(); 85 final Bundle args = new Bundle(); 86 if (blockId != null) { 87 args.putInt(ARG_BLOCK_ID, blockId.intValue()); 88 } 89 if (parentViewId != null) { 90 args.putInt(ARG_PARENT_VIEW_ID, parentViewId.intValue()); 91 } 92 args.putString(ARG_NUMBER, number); 93 args.putString(ARG_COUNTRY_ISO, countryIso); 94 args.putString(ARG_DISPLAY_NUMBER, displayNumber); 95 fragment.setArguments(args); 96 return fragment; 97 } 98 setFilteredNumberAsyncQueryHandlerForTesting( FilteredNumberAsyncQueryHandler handler)99 public void setFilteredNumberAsyncQueryHandlerForTesting( 100 FilteredNumberAsyncQueryHandler handler) { 101 this.handler = handler; 102 } 103 104 @Override getContext()105 public Context getContext() { 106 return getActivity(); 107 } 108 109 @Override onCreateDialog(Bundle savedInstanceState)110 public Dialog onCreateDialog(Bundle savedInstanceState) { 111 super.onCreateDialog(savedInstanceState); 112 final boolean isBlocked = getArguments().containsKey(ARG_BLOCK_ID); 113 114 number = getArguments().getString(ARG_NUMBER); 115 displayNumber = getArguments().getString(ARG_DISPLAY_NUMBER); 116 countryIso = getArguments().getString(ARG_COUNTRY_ISO); 117 118 if (TextUtils.isEmpty(displayNumber)) { 119 displayNumber = number; 120 } 121 122 handler = new FilteredNumberAsyncQueryHandler(getContext()); 123 voicemailEnabledChecker = new VisualVoicemailEnabledChecker(getActivity(), null); 124 // Choose not to update VoicemailEnabledChecker, as checks should already been done in 125 // all current use cases. 126 parentView = getActivity().findViewById(getArguments().getInt(ARG_PARENT_VIEW_ID)); 127 128 CharSequence title; 129 String okText; 130 String message; 131 if (isBlocked) { 132 title = null; 133 okText = getString(R.string.unblock_number_ok); 134 message = 135 ContactDisplayUtils.getTtsSpannedPhoneNumber( 136 getResources(), R.string.unblock_number_confirmation_title, displayNumber) 137 .toString(); 138 } else { 139 title = 140 ContactDisplayUtils.getTtsSpannedPhoneNumber( 141 getResources(), R.string.old_block_number_confirmation_title, displayNumber); 142 okText = getString(R.string.block_number_ok); 143 if (FilteredNumberCompat.useNewFiltering(getContext())) { 144 message = getString(R.string.block_number_confirmation_message_new_filtering); 145 } else if (voicemailEnabledChecker.isVisualVoicemailEnabled()) { 146 message = getString(R.string.block_number_confirmation_message_vvm); 147 } else { 148 message = getString(R.string.block_number_confirmation_message_no_vvm); 149 } 150 } 151 152 AlertDialog.Builder builder = 153 new AlertDialog.Builder(getActivity()) 154 .setTitle(title) 155 .setMessage(message) 156 .setPositiveButton( 157 okText, 158 new DialogInterface.OnClickListener() { 159 @Override 160 public void onClick(DialogInterface dialog, int id) { 161 if (isBlocked) { 162 unblockNumber(); 163 } else { 164 blockNumber(); 165 } 166 } 167 }) 168 .setNegativeButton(android.R.string.cancel, null); 169 return builder.create(); 170 } 171 172 @Override onActivityCreated(Bundle savedInstanceState)173 public void onActivityCreated(Bundle savedInstanceState) { 174 super.onActivityCreated(savedInstanceState); 175 String e164Number = PhoneNumberUtils.formatNumberToE164(number, countryIso); 176 if (!FilteredNumbersUtil.canBlockNumber(getContext(), e164Number, number)) { 177 dismiss(); 178 Toast.makeText( 179 getContext(), 180 ContactDisplayUtils.getTtsSpannedPhoneNumber( 181 getResources(), R.string.invalidNumber, displayNumber), 182 Toast.LENGTH_SHORT) 183 .show(); 184 } 185 } 186 187 @Override onPause()188 public void onPause() { 189 // Dismiss on rotation. 190 dismiss(); 191 callback = null; 192 193 super.onPause(); 194 } 195 setCallback(Callback callback)196 public void setCallback(Callback callback) { 197 this.callback = callback; 198 } 199 getBlockedMessage()200 private CharSequence getBlockedMessage() { 201 return ContactDisplayUtils.getTtsSpannedPhoneNumber( 202 getResources(), R.string.snackbar_number_blocked, displayNumber); 203 } 204 getUnblockedMessage()205 private CharSequence getUnblockedMessage() { 206 return ContactDisplayUtils.getTtsSpannedPhoneNumber( 207 getResources(), R.string.snackbar_number_unblocked, displayNumber); 208 } 209 getActionTextColor()210 private int getActionTextColor() { 211 return getContext().getResources().getColor(R.color.dialer_snackbar_action_text_color); 212 } 213 blockNumber()214 private void blockNumber() { 215 final CharSequence message = getBlockedMessage(); 216 final CharSequence undoMessage = getUnblockedMessage(); 217 final Callback callback = this.callback; 218 final int actionTextColor = getActionTextColor(); 219 final Context applicationContext = getContext().getApplicationContext(); 220 221 final OnUnblockNumberListener onUndoListener = 222 new OnUnblockNumberListener() { 223 @Override 224 public void onUnblockComplete(int rows, ContentValues values) { 225 Snackbar.make(parentView, undoMessage, Snackbar.LENGTH_LONG).show(); 226 if (callback != null) { 227 callback.onChangeFilteredNumberUndo(); 228 } 229 } 230 }; 231 232 final OnBlockNumberListener onBlockNumberListener = 233 new OnBlockNumberListener() { 234 @Override 235 public void onBlockComplete(final Uri uri) { 236 final View.OnClickListener undoListener = 237 new View.OnClickListener() { 238 @Override 239 public void onClick(View view) { 240 // Delete the newly created row on 'undo'. 241 Logger.get(applicationContext) 242 .logInteraction(InteractionEvent.Type.UNDO_BLOCK_NUMBER); 243 handler.unblock(onUndoListener, uri); 244 } 245 }; 246 247 Snackbar.make(parentView, message, Snackbar.LENGTH_LONG) 248 .setAction(R.string.snackbar_undo, undoListener) 249 .setActionTextColor(actionTextColor) 250 .show(); 251 252 if (callback != null) { 253 callback.onFilterNumberSuccess(); 254 } 255 256 if (FilteredNumbersUtil.hasRecentEmergencyCall(applicationContext)) { 257 FilteredNumbersUtil.maybeNotifyCallBlockingDisabled(applicationContext); 258 } 259 } 260 }; 261 262 handler.blockNumber(onBlockNumberListener, number, countryIso); 263 } 264 unblockNumber()265 private void unblockNumber() { 266 final CharSequence message = getUnblockedMessage(); 267 final CharSequence undoMessage = getBlockedMessage(); 268 final Callback callback = this.callback; 269 final int actionTextColor = getActionTextColor(); 270 final Context applicationContext = getContext().getApplicationContext(); 271 272 final OnBlockNumberListener onUndoListener = 273 new OnBlockNumberListener() { 274 @Override 275 public void onBlockComplete(final Uri uri) { 276 Snackbar.make(parentView, undoMessage, Snackbar.LENGTH_LONG).show(); 277 if (callback != null) { 278 callback.onChangeFilteredNumberUndo(); 279 } 280 } 281 }; 282 283 handler.unblock( 284 new OnUnblockNumberListener() { 285 @Override 286 public void onUnblockComplete(int rows, final ContentValues values) { 287 final View.OnClickListener undoListener = 288 new View.OnClickListener() { 289 @Override 290 public void onClick(View view) { 291 // Re-insert the row on 'undo', with a new ID. 292 Logger.get(applicationContext) 293 .logInteraction(InteractionEvent.Type.UNDO_UNBLOCK_NUMBER); 294 handler.blockNumber(onUndoListener, values); 295 } 296 }; 297 298 Snackbar.make(parentView, message, Snackbar.LENGTH_LONG) 299 .setAction(R.string.snackbar_undo, undoListener) 300 .setActionTextColor(actionTextColor) 301 .show(); 302 303 if (callback != null) { 304 callback.onUnfilterNumberSuccess(); 305 } 306 } 307 }, 308 getArguments().getInt(ARG_BLOCK_ID)); 309 } 310 311 /** 312 * Use a callback interface to update UI after success/undo. Favor this approach over other more 313 * standard paradigms because of the variety of scenarios in which the DialogFragment can be 314 * invoked (by an Activity, by a fragment, by an adapter, by an adapter list item). Because of 315 * this, we do NOT support retaining state on rotation, and will dismiss the dialog upon rotation 316 * instead. 317 */ 318 public interface Callback { 319 320 /** Called when a number is successfully added to the set of filtered numbers */ onFilterNumberSuccess()321 void onFilterNumberSuccess(); 322 323 /** Called when a number is successfully removed from the set of filtered numbers */ onUnfilterNumberSuccess()324 void onUnfilterNumberSuccess(); 325 326 /** Called when the action of filtering or unfiltering a number is undone */ onChangeFilteredNumberUndo()327 void onChangeFilteredNumberUndo(); 328 } 329 } 330