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.telephony.ServiceState; 30 import android.text.method.DigitsKeyListener; 31 import android.text.method.PasswordTransformationMethod; 32 import android.util.AttributeSet; 33 import android.util.Log; 34 import android.view.View; 35 import android.widget.EditText; 36 import android.widget.TextView; 37 import android.widget.Toast; 38 39 import com.android.internal.telephony.CommandException; 40 import com.android.internal.telephony.Phone; 41 import com.android.internal.telephony.PhoneFactory; 42 import com.android.internal.telephony.imsphone.ImsPhone; 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 CharSequence mDialogMessageEnabled; 62 private CharSequence mDialogMessageDisabled; 63 private int mButtonClicked; 64 private boolean mShowPassword; 65 private final MyHandler mHandler = new MyHandler(this); 66 private Phone mPhone; 67 private TimeConsumingPreferenceListener mTcpListener; 68 69 private static final int PW_LENGTH = 4; 70 71 /** 72 * CallBarringEditPreference constructor. 73 * 74 * @param context The context of view. 75 * @param attrs The attributes of the XML tag that is inflating EditTextPreference. 76 */ 77 public CallBarringEditPreference(Context context, AttributeSet attrs) { 78 super(context, attrs); 79 // Get the summary settings, use CheckBoxPreference as the standard. 80 TypedArray typedArray = context.obtainStyledAttributes(attrs, 81 android.R.styleable.CheckBoxPreference, 0, 0); 82 mSummaryOn = typedArray.getString(android.R.styleable.CheckBoxPreference_summaryOn); 83 mSummaryOff = typedArray.getString(android.R.styleable.CheckBoxPreference_summaryOff); 84 mDisableText = context.getText(R.string.disable); 85 mEnableText = context.getText(R.string.enable); 86 typedArray.recycle(); 87 88 // Get default phone 89 mPhone = PhoneFactory.getDefaultPhone(); 90 91 typedArray = context.obtainStyledAttributes(attrs, 92 R.styleable.CallBarringEditPreference, 0, R.style.EditPhoneNumberPreference); 93 mFacility = typedArray.getString(R.styleable.CallBarringEditPreference_facility); 94 mDialogMessageEnabled = typedArray.getString( 95 R.styleable.CallBarringEditPreference_dialogMessageEnabledNoPwd); 96 mDialogMessageDisabled = typedArray.getString( 97 R.styleable.CallBarringEditPreference_dialogMessageDisabledNoPwd); 98 typedArray.recycle(); 99 } 100 101 /** 102 * CallBarringEditPreference constructor. 103 * 104 * @param context The context of view. 105 */ 106 public CallBarringEditPreference(Context context) { 107 this(context, null); 108 } 109 110 void init(TimeConsumingPreferenceListener listener, boolean skipReading, Phone phone) { 111 if (DBG) { 112 Log.d(LOG_TAG, "init: phone id = " + phone.getPhoneId()); 113 } 114 mPhone = phone; 115 116 mTcpListener = listener; 117 if (!skipReading) { 118 // Query call barring status 119 mPhone.getCallBarring(mFacility, "", mHandler.obtainMessage( 120 MyHandler.MESSAGE_GET_CALL_BARRING), 0); 121 if (mTcpListener != null) { 122 mTcpListener.onStarted(this, true); 123 } 124 } 125 } 126 127 @Override 128 public void onClick(DialogInterface dialog, int which) { 129 super.onClick(dialog, which); 130 mButtonClicked = which; 131 } 132 133 @Override 134 protected boolean needInputMethod() { 135 // Input method should only be displayed if the password-field is shown. 136 return mShowPassword; 137 } 138 139 void setInputMethodNeeded(boolean needed) { 140 mShowPassword = needed; 141 } 142 143 @Override 144 protected void showDialog(Bundle state) { 145 setShowPassword(); 146 if (mShowPassword) { 147 setDialogMessage(getContext().getString(R.string.messageCallBarring)); 148 } else { 149 setDialogMessage(mIsActivated ? mDialogMessageEnabled : mDialogMessageDisabled); 150 } 151 152 if (DBG) { 153 Log.d(LOG_TAG, "showDialog: mShowPassword: " + mShowPassword 154 + ", mIsActivated: " + mIsActivated); 155 } 156 157 super.showDialog(state); 158 } 159 160 @Override 161 protected void onBindView(View view) { 162 super.onBindView(view); 163 164 // Sync the summary view 165 TextView summaryView = (TextView) view.findViewById(android.R.id.summary); 166 if (summaryView != null) { 167 CharSequence sum; 168 int vis; 169 170 // Set summary depending upon mode 171 if (mIsActivated) { 172 sum = (mSummaryOn == null) ? getSummary() : mSummaryOn; 173 } else { 174 sum = (mSummaryOff == null) ? getSummary() : mSummaryOff; 175 } 176 177 if (sum != null) { 178 summaryView.setText(sum); 179 vis = View.VISIBLE; 180 } else { 181 vis = View.GONE; 182 } 183 184 if (vis != summaryView.getVisibility()) { 185 summaryView.setVisibility(vis); 186 } 187 } 188 } 189 190 @Override 191 protected void onPrepareDialogBuilder(AlertDialog.Builder builder) { 192 builder.setPositiveButton(null, null); 193 builder.setNeutralButton(mIsActivated ? mDisableText : mEnableText, this); 194 } 195 196 @Override 197 protected void onBindDialogView(View view) { 198 super.onBindDialogView(view); 199 // Default the button clicked to be the cancel button. 200 mButtonClicked = DialogInterface.BUTTON_NEGATIVE; 201 202 final EditText editText = (EditText) view.findViewById(android.R.id.edit); 203 if (editText != null) { 204 editText.setSingleLine(true); 205 editText.setTransformationMethod(PasswordTransformationMethod.getInstance()); 206 editText.setKeyListener(DigitsKeyListener.getInstance()); 207 208 // Hide the input-text-line if the password is not shown. 209 editText.setVisibility(mShowPassword ? View.VISIBLE : View.GONE); 210 } 211 } 212 213 @Override 214 protected void onDialogClosed(boolean positiveResult) { 215 super.onDialogClosed(positiveResult); 216 if (DBG) { 217 Log.d(LOG_TAG, "onDialogClosed: mButtonClicked=" + mButtonClicked + ", positiveResult=" 218 + positiveResult); 219 } 220 if (mButtonClicked != DialogInterface.BUTTON_NEGATIVE) { 221 String password = null; 222 if (mShowPassword) { 223 password = getEditText().getText().toString(); 224 225 // Check if the password is valid. 226 if (password == null || password.length() != PW_LENGTH) { 227 Toast.makeText(getContext(), 228 getContext().getString(R.string.call_barring_right_pwd_number), 229 Toast.LENGTH_SHORT).show(); 230 return; 231 } 232 } 233 234 if (DBG) { 235 Log.d(LOG_TAG, "onDialogClosed: password=" + password); 236 } 237 // Send set call barring message to RIL layer. 238 mPhone.setCallBarring(mFacility, !mIsActivated, password, 239 mHandler.obtainMessage(MyHandler.MESSAGE_SET_CALL_BARRING), 0); 240 if (mTcpListener != null) { 241 mTcpListener.onStarted(this, false); 242 } 243 } 244 } 245 246 void handleCallBarringResult(boolean status) { 247 mIsActivated = status; 248 if (DBG) { 249 Log.d(LOG_TAG, "handleCallBarringResult: mIsActivated=" + mIsActivated); 250 } 251 } 252 253 void updateSummaryText() { 254 notifyChanged(); 255 notifyDependencyChange(shouldDisableDependents()); 256 } 257 258 private void setShowPassword() { 259 ImsPhone imsPhone = mPhone != null ? (ImsPhone) mPhone.getImsPhone() : null; 260 mShowPassword = !(imsPhone != null 261 && ((imsPhone.getServiceState().getState() == ServiceState.STATE_IN_SERVICE) 262 || imsPhone.isUtEnabled())); 263 } 264 265 @Override 266 public boolean shouldDisableDependents() { 267 return mIsActivated; 268 } 269 270 // Message protocol: 271 // what: get vs. set 272 // arg1: action -- register vs. disable 273 // arg2: get vs. set for the preceding request 274 private static class MyHandler extends Handler { 275 private static final int MESSAGE_GET_CALL_BARRING = 0; 276 private static final int MESSAGE_SET_CALL_BARRING = 1; 277 278 private final WeakReference<CallBarringEditPreference> mCallBarringEditPreference; 279 280 private MyHandler(CallBarringEditPreference callBarringEditPreference) { 281 mCallBarringEditPreference = 282 new WeakReference<CallBarringEditPreference>(callBarringEditPreference); 283 } 284 285 @Override 286 public void handleMessage(Message msg) { 287 switch (msg.what) { 288 case MESSAGE_GET_CALL_BARRING: 289 handleGetCallBarringResponse(msg); 290 break; 291 case MESSAGE_SET_CALL_BARRING: 292 handleSetCallBarringResponse(msg); 293 break; 294 default: 295 break; 296 } 297 } 298 299 // Handle the response message for query CB status. 300 private void handleGetCallBarringResponse(Message msg) { 301 final CallBarringEditPreference pref = mCallBarringEditPreference.get(); 302 if (pref == null) { 303 return; 304 } 305 306 if (DBG) { 307 Log.d(LOG_TAG, "handleGetCallBarringResponse: done"); 308 } 309 310 AsyncResult ar = (AsyncResult) msg.obj; 311 312 if (msg.arg2 == MESSAGE_SET_CALL_BARRING) { 313 pref.mTcpListener.onFinished(pref, false); 314 } else { 315 pref.mTcpListener.onFinished(pref, true); 316 ImsPhone imsPhone = pref.mPhone != null 317 ? (ImsPhone) pref.mPhone.getImsPhone() : null; 318 if (!pref.mShowPassword && (imsPhone == null || !imsPhone.isUtEnabled())) { 319 // Re-enable password when rejected from NW and modem would perform CSFB 320 pref.mShowPassword = true; 321 if (DBG) { 322 Log.d(LOG_TAG, 323 "handleGetCallBarringResponse: mShowPassword changed for CSFB"); 324 } 325 } 326 } 327 328 // Unsuccessful query for call barring. 329 if (ar.exception != null) { 330 if (DBG) { 331 Log.d(LOG_TAG, "handleGetCallBarringResponse: ar.exception=" + ar.exception); 332 } 333 pref.mTcpListener.onException(pref, (CommandException) ar.exception); 334 } else { 335 if (ar.userObj instanceof Throwable) { 336 pref.mTcpListener.onError(pref, RESPONSE_ERROR); 337 } 338 int[] ints = (int[]) ar.result; 339 if (ints.length == 0) { 340 if (DBG) { 341 Log.d(LOG_TAG, "handleGetCallBarringResponse: ar.result.length==0"); 342 } 343 pref.setEnabled(false); 344 pref.mTcpListener.onError(pref, RESPONSE_ERROR); 345 } else { 346 pref.handleCallBarringResult(ints[0] != 0); 347 if (DBG) { 348 Log.d(LOG_TAG, 349 "handleGetCallBarringResponse: CB state successfully queried: " 350 + ints[0]); 351 } 352 } 353 } 354 // Update call barring status. 355 pref.updateSummaryText(); 356 } 357 358 // Handle the response message for CB settings. 359 private void handleSetCallBarringResponse(Message msg) { 360 final CallBarringEditPreference pref = mCallBarringEditPreference.get(); 361 if (pref == null) { 362 return; 363 } 364 365 AsyncResult ar = (AsyncResult) msg.obj; 366 367 if (ar.exception != null || ar.userObj instanceof Throwable) { 368 if (DBG) { 369 Log.d(LOG_TAG, "handleSetCallBarringResponse: ar.exception=" + ar.exception); 370 } 371 } 372 if (DBG) { 373 Log.d(LOG_TAG, "handleSetCallBarringResponse: re-get call barring option"); 374 } 375 pref.mPhone.getCallBarring( 376 pref.mFacility, 377 "", 378 obtainMessage(MESSAGE_GET_CALL_BARRING, 0, MESSAGE_SET_CALL_BARRING, 379 ar.exception), 380 0); 381 } 382 } 383 } 384