1 /* 2 * Copyright (C) 2018 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.phone; 18 19 import static com.android.phone.TimeConsumingPreferenceActivity.RESPONSE_ERROR; 20 21 import android.app.AlertDialog; 22 import android.content.Context; 23 import android.content.DialogInterface; 24 import android.content.res.TypedArray; 25 import android.os.AsyncResult; 26 import android.os.Bundle; 27 import android.os.Handler; 28 import android.os.Message; 29 import android.os.PersistableBundle; 30 import android.telephony.CarrierConfigManager; 31 import android.text.method.DigitsKeyListener; 32 import android.text.method.PasswordTransformationMethod; 33 import android.util.AttributeSet; 34 import android.util.Log; 35 import android.view.View; 36 import android.widget.EditText; 37 import android.widget.TextView; 38 import android.widget.Toast; 39 40 import com.android.internal.telephony.CommandException; 41 import com.android.internal.telephony.Phone; 42 import com.android.internal.telephony.PhoneFactory; 43 import com.android.phone.settings.fdn.EditPinPreference; 44 45 import java.lang.ref.WeakReference; 46 47 /** 48 * This preference represents the status of call barring options, enabling/disabling 49 * the call barring option will prompt the user for the current password. 50 */ 51 public class CallBarringEditPreference extends EditPinPreference { 52 private static final String LOG_TAG = "CallBarringEditPreference"; 53 private static final boolean DBG = (PhoneGlobals.DBG_LEVEL >= 2); 54 55 private String mFacility; 56 boolean mIsActivated = false; 57 private CharSequence mEnableText; 58 private CharSequence mDisableText; 59 private CharSequence mSummaryOn; 60 private CharSequence mSummaryOff; 61 private int mButtonClicked; 62 private final MyHandler mHandler = new MyHandler(this); 63 private Phone mPhone; 64 private TimeConsumingPreferenceListener mTcpListener; 65 66 private static final int PW_LENGTH = 4; 67 68 /** 69 * CallBarringEditPreference constructor. 70 * 71 * @param context The context of view. 72 * @param attrs The attributes of the XML tag that is inflating EditTextPreference. 73 */ CallBarringEditPreference(Context context, AttributeSet attrs)74 public CallBarringEditPreference(Context context, AttributeSet attrs) { 75 super(context, attrs); 76 // Get the summary settings, use CheckBoxPreference as the standard. 77 TypedArray typedArray = context.obtainStyledAttributes(attrs, 78 android.R.styleable.CheckBoxPreference, 0, 0); 79 mSummaryOn = typedArray.getString(android.R.styleable.CheckBoxPreference_summaryOn); 80 mSummaryOff = typedArray.getString(android.R.styleable.CheckBoxPreference_summaryOff); 81 mDisableText = context.getText(R.string.disable); 82 mEnableText = context.getText(R.string.enable); 83 typedArray.recycle(); 84 85 // Get default phone 86 mPhone = PhoneFactory.getDefaultPhone(); 87 88 typedArray = context.obtainStyledAttributes(attrs, 89 R.styleable.CallBarringEditPreference, 0, R.style.EditPhoneNumberPreference); 90 mFacility = typedArray.getString(R.styleable.CallBarringEditPreference_facility); 91 typedArray.recycle(); 92 } 93 94 /** 95 * CallBarringEditPreference constructor. 96 * 97 * @param context The context of view. 98 */ CallBarringEditPreference(Context context)99 public CallBarringEditPreference(Context context) { 100 this(context, null); 101 } 102 init(TimeConsumingPreferenceListener listener, boolean skipReading, Phone phone)103 void init(TimeConsumingPreferenceListener listener, boolean skipReading, Phone phone) { 104 if (DBG) { 105 Log.d(LOG_TAG, "init: phone id = " + phone.getPhoneId()); 106 } 107 mPhone = phone; 108 109 mTcpListener = listener; 110 if (!skipReading) { 111 // Query call barring status 112 mPhone.getCallBarring(mFacility, "", mHandler.obtainMessage( 113 MyHandler.MESSAGE_GET_CALL_BARRING), getServiceClassForCallBarring(mPhone)); 114 if (mTcpListener != null) { 115 mTcpListener.onStarted(this, true); 116 } 117 } 118 } 119 120 @Override onClick(DialogInterface dialog, int which)121 public void onClick(DialogInterface dialog, int which) { 122 super.onClick(dialog, which); 123 mButtonClicked = which; 124 } 125 126 @Override showDialog(Bundle state)127 protected void showDialog(Bundle state) { 128 setDialogMessage(getContext().getString(R.string.messageCallBarring)); 129 super.showDialog(state); 130 } 131 132 @Override onBindView(View view)133 protected void onBindView(View view) { 134 super.onBindView(view); 135 136 // Sync the summary view 137 TextView summaryView = (TextView) view.findViewById(android.R.id.summary); 138 if (summaryView != null) { 139 CharSequence sum; 140 int vis; 141 142 // Set summary depending upon mode 143 if (mIsActivated) { 144 sum = (mSummaryOn == null) ? getSummary() : mSummaryOn; 145 } else { 146 sum = (mSummaryOff == null) ? getSummary() : mSummaryOff; 147 } 148 149 if (sum != null) { 150 summaryView.setText(sum); 151 vis = View.VISIBLE; 152 } else { 153 vis = View.GONE; 154 } 155 156 if (vis != summaryView.getVisibility()) { 157 summaryView.setVisibility(vis); 158 } 159 } 160 } 161 162 @Override onPrepareDialogBuilder(AlertDialog.Builder builder)163 protected void onPrepareDialogBuilder(AlertDialog.Builder builder) { 164 builder.setPositiveButton(null, null); 165 builder.setNeutralButton(mIsActivated ? mDisableText : mEnableText, this); 166 } 167 168 @Override onBindDialogView(View view)169 protected void onBindDialogView(View view) { 170 super.onBindDialogView(view); 171 // Default the button clicked to be the cancel button. 172 mButtonClicked = DialogInterface.BUTTON_NEGATIVE; 173 174 final EditText editText = (EditText) view.findViewById(android.R.id.edit); 175 if (editText != null) { 176 editText.setSingleLine(true); 177 editText.setTransformationMethod(PasswordTransformationMethod.getInstance()); 178 editText.setKeyListener(DigitsKeyListener.getInstance()); 179 180 editText.setVisibility(View.VISIBLE); 181 } 182 } 183 184 @Override onDialogClosed(boolean positiveResult)185 protected void onDialogClosed(boolean positiveResult) { 186 super.onDialogClosed(positiveResult); 187 if (DBG) { 188 Log.d(LOG_TAG, "onDialogClosed: mButtonClicked=" + mButtonClicked + ", positiveResult=" 189 + positiveResult); 190 } 191 if (mButtonClicked != DialogInterface.BUTTON_NEGATIVE) { 192 String password = getEditText().getText().toString(); 193 194 // Check if the password is valid. 195 if (password == null || password.length() != PW_LENGTH) { 196 Toast.makeText(getContext(), 197 getContext().getString(R.string.call_barring_right_pwd_number), 198 Toast.LENGTH_SHORT).show(); 199 return; 200 } 201 202 if (DBG) { 203 Log.d(LOG_TAG, "onDialogClosed: password=" + password); 204 } 205 // Send set call barring message to RIL layer. 206 mPhone.setCallBarring(mFacility, !mIsActivated, password, 207 mHandler.obtainMessage(MyHandler.MESSAGE_SET_CALL_BARRING), 208 getServiceClassForCallBarring(mPhone)); 209 if (mTcpListener != null) { 210 mTcpListener.onStarted(this, false); 211 } 212 } 213 } 214 handleCallBarringResult(boolean status)215 void handleCallBarringResult(boolean status) { 216 mIsActivated = status; 217 if (DBG) { 218 Log.d(LOG_TAG, "handleCallBarringResult: mIsActivated=" + mIsActivated); 219 } 220 } 221 getServiceClassForCallBarring(Phone phone)222 private static int getServiceClassForCallBarring(Phone phone) { 223 int serviceClass = CarrierConfigManager.SERVICE_CLASS_VOICE; 224 PersistableBundle carrierConfig = PhoneGlobals.getInstance() 225 .getCarrierConfigForSubId(phone.getSubId()); 226 if (carrierConfig != null) { 227 serviceClass = carrierConfig.getInt( 228 CarrierConfigManager.KEY_CALL_BARRING_DEFAULT_SERVICE_CLASS_INT, 229 CarrierConfigManager.SERVICE_CLASS_VOICE); 230 } 231 return serviceClass; 232 } 233 updateSummaryText()234 void updateSummaryText() { 235 notifyChanged(); 236 notifyDependencyChange(shouldDisableDependents()); 237 } 238 239 @Override shouldDisableDependents()240 public boolean shouldDisableDependents() { 241 return mIsActivated; 242 } 243 244 // Message protocol: 245 // what: get vs. set 246 // arg1: action -- register vs. disable 247 // arg2: get vs. set for the preceding request 248 private static class MyHandler extends Handler { 249 private static final int MESSAGE_GET_CALL_BARRING = 0; 250 private static final int MESSAGE_SET_CALL_BARRING = 1; 251 252 private final WeakReference<CallBarringEditPreference> mCallBarringEditPreference; 253 MyHandler(CallBarringEditPreference callBarringEditPreference)254 private MyHandler(CallBarringEditPreference callBarringEditPreference) { 255 mCallBarringEditPreference = 256 new WeakReference<CallBarringEditPreference>(callBarringEditPreference); 257 } 258 259 @Override handleMessage(Message msg)260 public void handleMessage(Message msg) { 261 switch (msg.what) { 262 case MESSAGE_GET_CALL_BARRING: 263 handleGetCallBarringResponse(msg); 264 break; 265 case MESSAGE_SET_CALL_BARRING: 266 handleSetCallBarringResponse(msg); 267 break; 268 default: 269 break; 270 } 271 } 272 273 // Handle the response message for query CB status. handleGetCallBarringResponse(Message msg)274 private void handleGetCallBarringResponse(Message msg) { 275 final CallBarringEditPreference pref = mCallBarringEditPreference.get(); 276 if (pref == null) { 277 return; 278 } 279 280 if (DBG) { 281 Log.d(LOG_TAG, "handleGetCallBarringResponse: done"); 282 } 283 284 AsyncResult ar = (AsyncResult) msg.obj; 285 286 if (msg.arg2 == MESSAGE_SET_CALL_BARRING) { 287 pref.mTcpListener.onFinished(pref, false); 288 } else { 289 pref.mTcpListener.onFinished(pref, true); 290 } 291 292 // Unsuccessful query for call barring. 293 if (ar.exception != null) { 294 if (DBG) { 295 Log.d(LOG_TAG, "handleGetCallBarringResponse: ar.exception=" + ar.exception); 296 } 297 pref.mTcpListener.onException(pref, (CommandException) ar.exception); 298 } else { 299 if (ar.userObj instanceof Throwable) { 300 pref.mTcpListener.onError(pref, RESPONSE_ERROR); 301 } 302 int[] ints = (int[]) ar.result; 303 if (ints.length == 0) { 304 if (DBG) { 305 Log.d(LOG_TAG, "handleGetCallBarringResponse: ar.result.length==0"); 306 } 307 pref.setEnabled(false); 308 pref.mTcpListener.onError(pref, RESPONSE_ERROR); 309 } else { 310 pref.handleCallBarringResult(ints[0] != 0); 311 if (DBG) { 312 Log.d(LOG_TAG, 313 "handleGetCallBarringResponse: CB state successfully queried: " 314 + ints[0]); 315 } 316 } 317 } 318 // Update call barring status. 319 pref.updateSummaryText(); 320 } 321 322 // Handle the response message for CB settings. handleSetCallBarringResponse(Message msg)323 private void handleSetCallBarringResponse(Message msg) { 324 final CallBarringEditPreference pref = mCallBarringEditPreference.get(); 325 if (pref == null) { 326 return; 327 } 328 329 AsyncResult ar = (AsyncResult) msg.obj; 330 331 if (ar.exception != null || ar.userObj instanceof Throwable) { 332 if (DBG) { 333 Log.d(LOG_TAG, "handleSetCallBarringResponse: ar.exception=" + ar.exception); 334 } 335 } 336 if (DBG) { 337 Log.d(LOG_TAG, "handleSetCallBarringResponse: re-get call barring option"); 338 } 339 pref.mPhone.getCallBarring( 340 pref.mFacility, 341 "", 342 obtainMessage(MESSAGE_GET_CALL_BARRING, 0, MESSAGE_SET_CALL_BARRING, 343 ar.exception), getServiceClassForCallBarring(pref.mPhone)); 344 } 345 } 346 } 347