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