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 Log.d(LOG_TAG, "init: phone id = " + phone.getPhoneId()); 105 106 mPhone = phone; 107 108 mTcpListener = listener; 109 if (!skipReading) { 110 // Query call barring status 111 mPhone.getCallBarring(mFacility, "", mHandler.obtainMessage( 112 MyHandler.MESSAGE_GET_CALL_BARRING), getServiceClassForCallBarring(mPhone)); 113 if (mTcpListener != null) { 114 mTcpListener.onStarted(this, true); 115 } 116 } 117 } 118 119 @Override onClick(DialogInterface dialog, int which)120 public void onClick(DialogInterface dialog, int which) { 121 super.onClick(dialog, which); 122 mButtonClicked = which; 123 } 124 125 @Override showDialog(Bundle state)126 protected void showDialog(Bundle state) { 127 setDialogMessage(getContext().getString(R.string.messageCallBarring)); 128 super.showDialog(state); 129 } 130 131 @Override onBindView(View view)132 protected void onBindView(View view) { 133 super.onBindView(view); 134 135 // Sync the summary view 136 TextView summaryView = (TextView) view.findViewById(android.R.id.summary); 137 if (summaryView != null) { 138 CharSequence sum; 139 int vis; 140 141 // Set summary depending upon mode 142 if (mIsActivated) { 143 sum = (mSummaryOn == null) ? getSummary() : mSummaryOn; 144 } else { 145 sum = (mSummaryOff == null) ? getSummary() : mSummaryOff; 146 } 147 148 if (sum != null) { 149 summaryView.setText(sum); 150 vis = View.VISIBLE; 151 } else { 152 vis = View.GONE; 153 } 154 155 if (vis != summaryView.getVisibility()) { 156 summaryView.setVisibility(vis); 157 } 158 } 159 } 160 161 @Override onPrepareDialogBuilder(AlertDialog.Builder builder)162 protected void onPrepareDialogBuilder(AlertDialog.Builder builder) { 163 builder.setPositiveButton(null, null); 164 builder.setNeutralButton(mIsActivated ? mDisableText : mEnableText, this); 165 } 166 167 @Override onBindDialogView(View view)168 protected void onBindDialogView(View view) { 169 super.onBindDialogView(view); 170 // Default the button clicked to be the cancel button. 171 mButtonClicked = DialogInterface.BUTTON_NEGATIVE; 172 173 final EditText editText = (EditText) view.findViewById(android.R.id.edit); 174 if (editText != null) { 175 editText.setSingleLine(true); 176 editText.setTransformationMethod(PasswordTransformationMethod.getInstance()); 177 editText.setKeyListener(DigitsKeyListener.getInstance()); 178 179 editText.setVisibility(View.VISIBLE); 180 } 181 } 182 183 @Override onDialogClosed(boolean positiveResult)184 protected void onDialogClosed(boolean positiveResult) { 185 super.onDialogClosed(positiveResult); 186 Log.d(LOG_TAG, "onDialogClosed: mButtonClicked=" + mButtonClicked + ", positiveResult=" 187 + positiveResult); 188 189 if (mButtonClicked != DialogInterface.BUTTON_NEGATIVE) { 190 String password = getEditText().getText().toString(); 191 192 // Check if the password is valid. 193 if (password == null || password.length() != PW_LENGTH) { 194 Toast.makeText(getContext(), 195 getContext().getString(R.string.call_barring_right_pwd_number), 196 Toast.LENGTH_SHORT).show(); 197 return; 198 } 199 200 Log.d(LOG_TAG, "onDialogClosed"); 201 202 // Send set call barring message to RIL layer. 203 mPhone.setCallBarring(mFacility, !mIsActivated, password, 204 mHandler.obtainMessage(MyHandler.MESSAGE_SET_CALL_BARRING), 205 getServiceClassForCallBarring(mPhone)); 206 if (mTcpListener != null) { 207 mTcpListener.onStarted(this, false); 208 } 209 } 210 } 211 handleCallBarringResult(boolean status)212 void handleCallBarringResult(boolean status) { 213 mIsActivated = status; 214 Log.i(LOG_TAG, "handleCallBarringResult: mIsActivated=" + mIsActivated); 215 } 216 getServiceClassForCallBarring(Phone phone)217 private static int getServiceClassForCallBarring(Phone phone) { 218 int serviceClass = CarrierConfigManager.SERVICE_CLASS_VOICE; 219 PersistableBundle carrierConfig = PhoneGlobals.getInstance() 220 .getCarrierConfigForSubId(phone.getSubId()); 221 if (carrierConfig != null) { 222 serviceClass = carrierConfig.getInt( 223 CarrierConfigManager.KEY_CALL_BARRING_DEFAULT_SERVICE_CLASS_INT, 224 CarrierConfigManager.SERVICE_CLASS_VOICE); 225 } 226 return serviceClass; 227 } 228 updateSummaryText()229 void updateSummaryText() { 230 notifyChanged(); 231 notifyDependencyChange(shouldDisableDependents()); 232 } 233 234 @Override shouldDisableDependents()235 public boolean shouldDisableDependents() { 236 return mIsActivated; 237 } 238 239 // Message protocol: 240 // what: get vs. set 241 // arg1: action -- register vs. disable 242 // arg2: get vs. set for the preceding request 243 private static class MyHandler extends Handler { 244 private static final int MESSAGE_GET_CALL_BARRING = 0; 245 private static final int MESSAGE_SET_CALL_BARRING = 1; 246 247 private final WeakReference<CallBarringEditPreference> mCallBarringEditPreference; 248 MyHandler(CallBarringEditPreference callBarringEditPreference)249 private MyHandler(CallBarringEditPreference callBarringEditPreference) { 250 mCallBarringEditPreference = 251 new WeakReference<CallBarringEditPreference>(callBarringEditPreference); 252 } 253 254 @Override handleMessage(Message msg)255 public void handleMessage(Message msg) { 256 switch (msg.what) { 257 case MESSAGE_GET_CALL_BARRING: 258 handleGetCallBarringResponse(msg); 259 break; 260 case MESSAGE_SET_CALL_BARRING: 261 handleSetCallBarringResponse(msg); 262 break; 263 default: 264 break; 265 } 266 } 267 268 // Handle the response message for query CB status. handleGetCallBarringResponse(Message msg)269 private void handleGetCallBarringResponse(Message msg) { 270 final CallBarringEditPreference pref = mCallBarringEditPreference.get(); 271 if (pref == null) { 272 return; 273 } 274 275 Log.i(LOG_TAG, "handleGetCallBarringResponse: done"); 276 277 AsyncResult ar = (AsyncResult) msg.obj; 278 279 if (msg.arg2 == MESSAGE_SET_CALL_BARRING) { 280 pref.mTcpListener.onFinished(pref, false); 281 } else { 282 pref.mTcpListener.onFinished(pref, true); 283 } 284 285 // Unsuccessful query for call barring. 286 if (ar.exception != null) { 287 Log.i(LOG_TAG, "handleGetCallBarringResponse: ar.exception=" + ar.exception); 288 pref.mTcpListener.onException(pref, (CommandException) ar.exception); 289 } else { 290 if (ar.userObj instanceof Throwable) { 291 pref.mTcpListener.onError(pref, RESPONSE_ERROR); 292 } 293 int[] ints = (int[]) ar.result; 294 if (ints.length == 0) { 295 Log.i(LOG_TAG, "handleGetCallBarringResponse: ar.result.length==0"); 296 pref.setEnabled(false); 297 pref.mTcpListener.onError(pref, RESPONSE_ERROR); 298 } else { 299 pref.handleCallBarringResult(ints[0] != 0); 300 Log.i(LOG_TAG, 301 "handleGetCallBarringResponse: CB state successfully queried: " 302 + ints[0]); 303 } 304 } 305 // Update call barring status. 306 pref.updateSummaryText(); 307 } 308 309 // Handle the response message for CB settings. handleSetCallBarringResponse(Message msg)310 private void handleSetCallBarringResponse(Message msg) { 311 final CallBarringEditPreference pref = mCallBarringEditPreference.get(); 312 if (pref == null) { 313 return; 314 } 315 316 AsyncResult ar = (AsyncResult) msg.obj; 317 318 if (ar.exception != null || ar.userObj instanceof Throwable) { 319 Log.i(LOG_TAG, "handleSetCallBarringResponse: ar.exception=" + ar.exception); 320 } 321 Log.i(LOG_TAG, "handleSetCallBarringResponse: re-get call barring option"); 322 pref.mPhone.getCallBarring( 323 pref.mFacility, 324 "", 325 obtainMessage(MESSAGE_GET_CALL_BARRING, 0, MESSAGE_SET_CALL_BARRING, 326 ar.exception), getServiceClassForCallBarring(pref.mPhone)); 327 } 328 } 329 } 330