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