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 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 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 125 mProgressBar = (ProgressBar) findViewById(R.id.progress_bar); 126 String[] fromColumns = {BlockedNumberContract.BlockedNumbers.COLUMN_ORIGINAL_NUMBER}; 127 int[] toViews = {R.id.blocked_number}; 128 mAdapter = new BlockedNumbersAdapter(this, R.xml.layout_blocked_number, null, fromColumns, 129 toViews, 0); 130 131 ListView listView = getListView(); 132 listView.setAdapter(mAdapter); 133 listView.setDivider(null); 134 listView.setDividerHeight(0); 135 136 mButterBar = (RelativeLayout) findViewById(R.id.butter_bar); 137 mReEnableButton = (TextView) mButterBar.findViewById(R.id.reenable_button); 138 mReEnableButton.setOnClickListener(this); 139 140 updateButterBar(); 141 142 updateEnhancedCallBlockingFragment( 143 BlockedNumbersUtil.isEnhancedCallBlockingEnabledByPlatform(this)); 144 145 mBlockingStatusReceiver = new BroadcastReceiver() { 146 @Override 147 public void onReceive(Context context, Intent intent) { 148 updateButterBar(); 149 } 150 }; 151 registerReceiver(mBlockingStatusReceiver, new IntentFilter( 152 BlockedNumberContract.SystemContract.ACTION_BLOCK_SUPPRESSION_STATE_CHANGED)); 153 154 getLoaderManager().initLoader(0, null, this); 155 } 156 157 @Override 158 protected void onDestroy() { 159 if (mBlockingStatusReceiver != null) { 160 unregisterReceiver(mBlockingStatusReceiver); 161 } 162 super.onDestroy(); 163 } 164 165 @Override 166 public boolean onOptionsItemSelected(MenuItem item) { 167 switch (item.getItemId()) { 168 case android.R.id.home: 169 this.finish(); 170 return true; 171 default: 172 return super.onOptionsItemSelected(item); 173 } 174 } 175 176 private void updateButterBar() { 177 if (BlockedNumberContract.SystemContract.getBlockSuppressionStatus(this).isSuppressed) { 178 mButterBar.setVisibility(View.VISIBLE); 179 } else { 180 mButterBar.setVisibility(View.GONE); 181 } 182 } 183 184 /** 185 * Update the visibility of {@link EnhancedCallBlockingFragment}. 186 */ 187 private void updateEnhancedCallBlockingFragment(boolean show) { 188 FragmentManager fragmentManager = getFragmentManager(); 189 Fragment fragment = fragmentManager.findFragmentById(R.id.enhanced_call_blocking_container); 190 if (!show && fragment == null) { 191 // Nothing to show, so bail early. 192 return; 193 } 194 final FragmentTransaction transaction = fragmentManager.beginTransaction(); 195 if (show) { 196 if (fragment == null) { 197 fragment = new EnhancedCallBlockingFragment(); 198 transaction.add(R.id.enhanced_call_blocking_container, fragment); 199 } else { 200 transaction.show(fragment); 201 } 202 } else { 203 transaction.hide(fragment); 204 } 205 transaction.commit(); 206 } 207 208 @Override 209 public Loader<Cursor> onCreateLoader(int id, Bundle args) { 210 return new CursorLoader(this, BlockedNumberContract.BlockedNumbers.CONTENT_URI, 211 PROJECTION, SELECTION, null, 212 BlockedNumberContract.BlockedNumbers.COLUMN_ID + " DESC"); 213 } 214 215 @Override 216 public void onLoadFinished(Loader<Cursor> loader, Cursor data) { 217 mAdapter.swapCursor(data); 218 mProgressBar.setVisibility(View.GONE); 219 } 220 221 @Override 222 public void onLoaderReset(Loader<Cursor> loader) { 223 mAdapter.swapCursor(null); 224 mProgressBar.setVisibility(View.VISIBLE); 225 } 226 227 @Override 228 public void onClick(View view) { 229 if (view == mAddButton) { 230 showAddBlockedNumberDialog(); 231 } else if (view == mReEnableButton) { 232 BlockedNumberContract.SystemContract.endBlockSuppression(this); 233 mButterBar.setVisibility(View.GONE); 234 } 235 } 236 237 private void showAddBlockedNumberDialog() { 238 LayoutInflater inflater = this.getLayoutInflater(); 239 View dialogView = inflater.inflate(R.xml.add_blocked_number_dialog, null); 240 final EditText editText = (EditText) dialogView.findViewById(R.id.add_blocked_number); 241 editText.addTextChangedListener(new PhoneNumberFormattingTextWatcher()); 242 editText.addTextChangedListener(this); 243 AlertDialog dialog = new AlertDialog.Builder(this) 244 .setView(dialogView) 245 .setPositiveButton(R.string.block_button, new DialogInterface.OnClickListener() { 246 public void onClick(DialogInterface dialog, int id) { 247 addBlockedNumber(PhoneNumberUtils.stripSeparators( 248 editText.getText().toString())); 249 } 250 }) 251 .setNegativeButton(android.R.string.cancel, new DialogInterface.OnClickListener() { 252 public void onClick(DialogInterface dialog, int id) { 253 dialog.dismiss(); 254 } 255 }) 256 .create(); 257 dialog.setOnShowListener(new AlertDialog.OnShowListener() { 258 @Override 259 public void onShow(DialogInterface dialog) { 260 mBlockButton = ((AlertDialog) dialog) 261 .getButton(AlertDialog.BUTTON_POSITIVE); 262 mBlockButton.setEnabled(false); 263 // show keyboard 264 InputMethodManager inputMethodManager = 265 (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE); 266 inputMethodManager.showSoftInput(editText, 267 InputMethodManager.SHOW_IMPLICIT); 268 269 } 270 }); 271 dialog.show(); 272 } 273 274 /** 275 * Add blocked number if it does not exist. 276 */ 277 private void addBlockedNumber(String number) { 278 if (PhoneNumberUtils.isEmergencyNumber(number)) { 279 Toast.makeText( 280 this, 281 getString(R.string.blocked_numbers_block_emergency_number_message), 282 Toast.LENGTH_SHORT).show(); 283 } else { 284 // We disable the add button, to prevent the user from adding other numbers until the 285 // current number is added. 286 mAddButton.setEnabled(false); 287 mBlockNumberTaskFragment.blockIfNotAlreadyBlocked(number, this); 288 } 289 } 290 291 @Override 292 public void beforeTextChanged(CharSequence s, int start, int count, int after) { 293 // no-op 294 } 295 296 @Override 297 public void onTextChanged(CharSequence text, int start, int before, int count) { 298 if (mBlockButton != null) { 299 mBlockButton.setEnabled( 300 !TextUtils.isEmpty(PhoneNumberUtils.stripSeparators(text.toString()))); 301 } 302 } 303 304 @Override 305 public void afterTextChanged(Editable s) { 306 // no-op 307 } 308 309 @Override 310 public void onBlocked(String number, boolean alreadyBlocked) { 311 if (alreadyBlocked) { 312 BlockedNumbersUtil.showToastWithFormattedNumber(this, 313 R.string.blocked_numbers_number_already_blocked_message, number); 314 } else { 315 BlockedNumbersUtil.showToastWithFormattedNumber(this, 316 R.string.blocked_numbers_number_blocked_message, number); 317 } 318 mAddButton.setEnabled(true); 319 } 320 } 321