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.server.telecom.settings; 18 19 import android.annotation.Nullable; 20 import android.app.ActionBar; 21 import android.app.AlertDialog; 22 import android.app.Fragment; 23 import android.app.FragmentManager; 24 import android.app.FragmentTransaction; 25 import android.app.ListActivity; 26 import android.app.LoaderManager; 27 import android.content.BroadcastReceiver; 28 import android.content.Context; 29 import android.content.CursorLoader; 30 import android.content.DialogInterface; 31 import android.content.Intent; 32 import android.content.IntentFilter; 33 import android.content.Loader; 34 import android.database.Cursor; 35 import android.os.Bundle; 36 import android.provider.BlockedNumberContract; 37 import android.telephony.PhoneNumberFormattingTextWatcher; 38 import android.telephony.PhoneNumberUtils; 39 import android.telephony.TelephonyManager; 40 import android.text.Editable; 41 import android.text.TextUtils; 42 import android.text.TextWatcher; 43 import android.view.LayoutInflater; 44 import android.view.MenuItem; 45 import android.view.View; 46 import android.view.inputmethod.InputMethodManager; 47 import android.widget.Button; 48 import android.widget.EditText; 49 import android.widget.LinearLayout; 50 import android.widget.ListView; 51 import android.widget.ProgressBar; 52 import android.widget.RelativeLayout; 53 import android.widget.TextView; 54 import android.widget.Toast; 55 56 import com.android.server.telecom.R; 57 58 59 /** 60 * Activity to manage blocked numbers using {@link BlockedNumberContract}. 61 */ 62 public class BlockedNumbersActivity extends ListActivity 63 implements LoaderManager.LoaderCallbacks<Cursor>, View.OnClickListener, TextWatcher, 64 BlockNumberTaskFragment.Listener { 65 private static final String ACTION_MANAGE_BLOCKED_NUMBERS = 66 "android.telecom.action.MANAGE_BLOCKED_NUMBERS"; 67 private static final String TAG_BLOCK_NUMBER_TASK_FRAGMENT = "block_number_task_fragment"; 68 private static final String TELECOM_PACKAGE = "com.android.server.telecom"; 69 private static final String[] PROJECTION = new String[] { 70 BlockedNumberContract.BlockedNumbers.COLUMN_ID, 71 BlockedNumberContract.BlockedNumbers.COLUMN_ORIGINAL_NUMBER 72 }; 73 74 private static final String SELECTION = "((" + 75 BlockedNumberContract.BlockedNumbers.COLUMN_ORIGINAL_NUMBER + " NOTNULL) AND (" + 76 BlockedNumberContract.BlockedNumbers.COLUMN_ORIGINAL_NUMBER + " != '' ))"; 77 78 private BlockNumberTaskFragment mBlockNumberTaskFragment; 79 private BlockedNumbersAdapter mAdapter; 80 private TextView mAddButton; 81 private ProgressBar mProgressBar; 82 private RelativeLayout mButterBar; 83 @Nullable private Button mBlockButton; 84 @Nullable private Button mBlockButtonNegative; 85 private TextView mReEnableButton; 86 87 private BroadcastReceiver mBlockingStatusReceiver; 88 getIntentForStartingActivity()89 public static Intent getIntentForStartingActivity() { 90 Intent intent = new Intent(ACTION_MANAGE_BLOCKED_NUMBERS); 91 intent.setPackage(TELECOM_PACKAGE); 92 return intent; 93 } 94 95 @Override onCreate(Bundle savedInstanceState)96 public void onCreate(Bundle savedInstanceState) { 97 super.onCreate(savedInstanceState); 98 setContentView(R.xml.activity_blocked_numbers); 99 100 ActionBar actionBar = getActionBar(); 101 if (actionBar != null) { 102 actionBar.setDisplayHomeAsUpEnabled(true); 103 // set the talkback voice prompt to "Back" instead of "Navigate Up" 104 actionBar.setHomeActionContentDescription(R.string.back); 105 } 106 107 if (!BlockedNumberContract.canCurrentUserBlockNumbers(this)) { 108 TextView nonPrimaryUserText = (TextView) findViewById(R.id.non_primary_user); 109 nonPrimaryUserText.setVisibility(View.VISIBLE); 110 111 LinearLayout manageBlockedNumbersUi = 112 (LinearLayout) findViewById(R.id.manage_blocked_ui); 113 manageBlockedNumbersUi.setVisibility(View.GONE); 114 return; 115 } 116 117 FragmentManager fm = getFragmentManager(); 118 mBlockNumberTaskFragment = 119 (BlockNumberTaskFragment) fm.findFragmentByTag(TAG_BLOCK_NUMBER_TASK_FRAGMENT); 120 121 if (mBlockNumberTaskFragment == null) { 122 mBlockNumberTaskFragment = new BlockNumberTaskFragment(); 123 fm.beginTransaction() 124 .add(mBlockNumberTaskFragment, TAG_BLOCK_NUMBER_TASK_FRAGMENT).commit(); 125 } 126 127 mAddButton = (TextView) findViewById(R.id.add_blocked); 128 mAddButton.setOnClickListener(this); 129 mAddButton.setContentDescription(getText(R.string.block_number)); 130 131 mProgressBar = (ProgressBar) findViewById(R.id.progress_bar); 132 String[] fromColumns = {BlockedNumberContract.BlockedNumbers.COLUMN_ORIGINAL_NUMBER}; 133 int[] toViews = {R.id.blocked_number}; 134 mAdapter = new BlockedNumbersAdapter(this, R.xml.layout_blocked_number, null, fromColumns, 135 toViews, 0); 136 137 ListView listView = getListView(); 138 listView.setAdapter(mAdapter); 139 listView.setDivider(null); 140 listView.setDividerHeight(0); 141 142 mButterBar = (RelativeLayout) findViewById(R.id.butter_bar); 143 mReEnableButton = (TextView) mButterBar.findViewById(R.id.reenable_button); 144 mReEnableButton.setOnClickListener(this); 145 146 updateButterBar(); 147 148 updateEnhancedCallBlockingFragment( 149 BlockedNumbersUtil.isEnhancedCallBlockingEnabledByPlatform(this)); 150 151 mBlockingStatusReceiver = new BroadcastReceiver() { 152 @Override 153 public void onReceive(Context context, Intent intent) { 154 updateButterBar(); 155 } 156 }; 157 IntentFilter blockStatusIntentFilter = new IntentFilter( 158 BlockedNumberContract.SystemContract.ACTION_BLOCK_SUPPRESSION_STATE_CHANGED); 159 blockStatusIntentFilter.setPriority(IntentFilter.SYSTEM_HIGH_PRIORITY); 160 registerReceiver(mBlockingStatusReceiver, blockStatusIntentFilter, 161 Context.RECEIVER_EXPORTED); 162 163 getLoaderManager().initLoader(0, null, this); 164 } 165 166 @Override onDestroy()167 protected void onDestroy() { 168 if (mBlockingStatusReceiver != null) { 169 unregisterReceiver(mBlockingStatusReceiver); 170 } 171 super.onDestroy(); 172 } 173 174 @Override onOptionsItemSelected(MenuItem item)175 public boolean onOptionsItemSelected(MenuItem item) { 176 switch (item.getItemId()) { 177 case android.R.id.home: 178 this.finish(); 179 return true; 180 default: 181 return super.onOptionsItemSelected(item); 182 } 183 } 184 updateButterBar()185 private void updateButterBar() { 186 if (BlockedNumberContract.SystemContract.getBlockSuppressionStatus(this).isSuppressed) { 187 mButterBar.setVisibility(View.VISIBLE); 188 } else { 189 mButterBar.setVisibility(View.GONE); 190 } 191 } 192 193 /** 194 * Update the visibility of {@link EnhancedCallBlockingFragment}. 195 */ updateEnhancedCallBlockingFragment(boolean show)196 private void updateEnhancedCallBlockingFragment(boolean show) { 197 FragmentManager fragmentManager = getFragmentManager(); 198 Fragment fragment = fragmentManager.findFragmentById(R.id.enhanced_call_blocking_container); 199 if (!show && fragment == null) { 200 // Nothing to show, so bail early. 201 return; 202 } 203 final FragmentTransaction transaction = fragmentManager.beginTransaction(); 204 if (show) { 205 if (fragment == null) { 206 fragment = new EnhancedCallBlockingFragment(); 207 transaction.add(R.id.enhanced_call_blocking_container, fragment); 208 } else { 209 transaction.show(fragment); 210 } 211 } else { 212 transaction.hide(fragment); 213 } 214 transaction.commit(); 215 } 216 217 @Override onCreateLoader(int id, Bundle args)218 public Loader<Cursor> onCreateLoader(int id, Bundle args) { 219 return new CursorLoader(this, BlockedNumberContract.BlockedNumbers.CONTENT_URI, 220 PROJECTION, SELECTION, null, 221 BlockedNumberContract.BlockedNumbers.COLUMN_ORIGINAL_NUMBER + " ASC"); 222 } 223 224 @Override onLoadFinished(Loader<Cursor> loader, Cursor data)225 public void onLoadFinished(Loader<Cursor> loader, Cursor data) { 226 mAdapter.swapCursor(data); 227 mProgressBar.setVisibility(View.GONE); 228 } 229 230 @Override onLoaderReset(Loader<Cursor> loader)231 public void onLoaderReset(Loader<Cursor> loader) { 232 mAdapter.swapCursor(null); 233 mProgressBar.setVisibility(View.VISIBLE); 234 } 235 236 @Override onClick(View view)237 public void onClick(View view) { 238 if (view == mAddButton) { 239 showAddBlockedNumberDialog(); 240 } else if (view == mReEnableButton) { 241 BlockedNumberContract.SystemContract.endBlockSuppression(this); 242 mButterBar.setVisibility(View.GONE); 243 } 244 } 245 showAddBlockedNumberDialog()246 private void showAddBlockedNumberDialog() { 247 LayoutInflater inflater = this.getLayoutInflater(); 248 View dialogView = inflater.inflate(R.xml.add_blocked_number_dialog, null); 249 final EditText editText = (EditText) dialogView.findViewById(R.id.add_blocked_number); 250 editText.addTextChangedListener(new PhoneNumberFormattingTextWatcher()); 251 editText.addTextChangedListener(this); 252 AlertDialog dialog = new AlertDialog.Builder(this) 253 .setView(dialogView) 254 .setPositiveButton(R.string.block_button, new DialogInterface.OnClickListener() { 255 public void onClick(DialogInterface dialog, int id) { 256 addBlockedNumber(PhoneNumberUtils.stripSeparators( 257 editText.getText().toString())); 258 } 259 }) 260 .setNegativeButton(android.R.string.cancel, new DialogInterface.OnClickListener() { 261 public void onClick(DialogInterface dialog, int id) { 262 dialog.dismiss(); 263 } 264 }) 265 .create(); 266 dialog.setOnShowListener(new AlertDialog.OnShowListener() { 267 @Override 268 public void onShow(DialogInterface dialog) { 269 mBlockButton = ((AlertDialog) dialog) 270 .getButton(AlertDialog.BUTTON_POSITIVE); 271 mBlockButtonNegative = ((AlertDialog) dialog) 272 .getButton(AlertDialog.BUTTON_NEGATIVE); 273 mBlockButton.setAllCaps(false); 274 mBlockButtonNegative.setAllCaps(false); 275 mBlockButton.setEnabled(false); 276 // show keyboard 277 InputMethodManager inputMethodManager = 278 (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE); 279 inputMethodManager.showSoftInput(editText, 280 InputMethodManager.SHOW_IMPLICIT); 281 282 } 283 }); 284 dialog.show(); 285 } 286 287 /** 288 * Add blocked number if it does not exist. 289 */ addBlockedNumber(String number)290 private void addBlockedNumber(String number) { 291 if (isEmergencyNumber(this, number)) { 292 Toast.makeText( 293 this, 294 getString(R.string.blocked_numbers_block_emergency_number_message), 295 Toast.LENGTH_SHORT).show(); 296 } else { 297 // We disable the add button, to prevent the user from adding other numbers until the 298 // current number is added. 299 mAddButton.setEnabled(false); 300 mBlockNumberTaskFragment.blockIfNotAlreadyBlocked(number, this); 301 } 302 } 303 isEmergencyNumber(Context context, String number)304 private boolean isEmergencyNumber(Context context, String number) { 305 try { 306 TelephonyManager tm = (TelephonyManager) context.getSystemService( 307 Context.TELEPHONY_SERVICE); 308 return tm.isEmergencyNumber(number); 309 } catch (IllegalStateException ise) { 310 return false; 311 } 312 } 313 314 @Override beforeTextChanged(CharSequence s, int start, int count, int after)315 public void beforeTextChanged(CharSequence s, int start, int count, int after) { 316 // no-op 317 } 318 319 @Override onTextChanged(CharSequence text, int start, int before, int count)320 public void onTextChanged(CharSequence text, int start, int before, int count) { 321 if (mBlockButton != null) { 322 mBlockButton.setEnabled( 323 !TextUtils.isEmpty(PhoneNumberUtils.stripSeparators(text.toString()))); 324 } 325 } 326 327 @Override afterTextChanged(Editable s)328 public void afterTextChanged(Editable s) { 329 // no-op 330 } 331 332 @Override onBlocked(String number, boolean alreadyBlocked)333 public void onBlocked(String number, boolean alreadyBlocked) { 334 if (alreadyBlocked) { 335 BlockedNumbersUtil.showToastWithFormattedNumber(this, 336 R.string.blocked_numbers_number_already_blocked_message, number); 337 } else { 338 BlockedNumbersUtil.showToastWithFormattedNumber(this, 339 R.string.blocked_numbers_number_blocked_message, number); 340 } 341 mAddButton.setEnabled(true); 342 } 343 }