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