1 /* 2 * Copyright (C) 2008 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.settings; 18 19 import android.app.settings.SettingsEnums; 20 import android.content.BroadcastReceiver; 21 import android.content.Context; 22 import android.content.Intent; 23 import android.content.IntentFilter; 24 import android.content.res.Configuration; 25 import android.content.res.Resources; 26 import android.graphics.PixelFormat; 27 import android.os.AsyncTask; 28 import android.os.Bundle; 29 import android.os.Handler; 30 import android.os.Message; 31 import android.os.PersistableBundle; 32 import android.telephony.CarrierConfigManager; 33 import android.telephony.SubscriptionInfo; 34 import android.telephony.SubscriptionManager; 35 import android.telephony.TelephonyManager; 36 import android.text.TextUtils; 37 import android.util.Log; 38 import android.view.Gravity; 39 import android.view.LayoutInflater; 40 import android.view.View; 41 import android.view.ViewGroup; 42 import android.view.WindowInsets.Type; 43 import android.view.WindowManager; 44 import android.widget.EditText; 45 import android.widget.ListView; 46 import android.widget.TabHost; 47 import android.widget.TabHost.OnTabChangeListener; 48 import android.widget.TabHost.TabContentFactory; 49 import android.widget.TabHost.TabSpec; 50 import android.widget.TabWidget; 51 import android.widget.TextView; 52 import android.widget.Toast; 53 54 import androidx.preference.Preference; 55 import androidx.preference.SwitchPreference; 56 57 import com.android.settings.network.ProxySubscriptionManager; 58 59 import java.util.ArrayList; 60 import java.util.List; 61 62 /** 63 * Implements the preference screen to enable/disable ICC lock and 64 * also the dialogs to change the ICC PIN. In the former case, enabling/disabling 65 * the ICC lock will prompt the user for the current PIN. 66 * In the Change PIN case, it prompts the user for old pin, new pin and new pin 67 * again before attempting to change it. Calls the SimCard interface to execute 68 * these operations. 69 * 70 */ 71 public class IccLockSettings extends SettingsPreferenceFragment 72 implements EditPinPreference.OnPinEnteredListener { 73 private static final String TAG = "IccLockSettings"; 74 private static final boolean DBG = false; 75 76 private static final int OFF_MODE = 0; 77 // State when enabling/disabling ICC lock 78 private static final int ICC_LOCK_MODE = 1; 79 // State when entering the old pin 80 private static final int ICC_OLD_MODE = 2; 81 // State when entering the new pin - first time 82 private static final int ICC_NEW_MODE = 3; 83 // State when entering the new pin - second time 84 private static final int ICC_REENTER_MODE = 4; 85 86 // Keys in xml file 87 private static final String PIN_DIALOG = "sim_pin"; 88 private static final String PIN_TOGGLE = "sim_toggle"; 89 // Keys in icicle 90 private static final String DIALOG_SUB_ID = "dialogSubId"; 91 private static final String DIALOG_STATE = "dialogState"; 92 private static final String DIALOG_PIN = "dialogPin"; 93 private static final String DIALOG_ERROR = "dialogError"; 94 private static final String ENABLE_TO_STATE = "enableState"; 95 private static final String CURRENT_TAB = "currentTab"; 96 97 // Save and restore inputted PIN code when configuration changed 98 // (ex. portrait<-->landscape) during change PIN code 99 private static final String OLD_PINCODE = "oldPinCode"; 100 private static final String NEW_PINCODE = "newPinCode"; 101 102 private static final int MIN_PIN_LENGTH = 4; 103 private static final int MAX_PIN_LENGTH = 8; 104 // Which dialog to show next when popped up 105 private int mDialogState = OFF_MODE; 106 107 private String mPin; 108 private String mOldPin; 109 private String mNewPin; 110 private String mError; 111 // Are we trying to enable or disable ICC lock? 112 private boolean mToState; 113 114 private TabHost mTabHost; 115 private TabWidget mTabWidget; 116 private ListView mListView; 117 118 private ProxySubscriptionManager mProxySubscriptionMgr; 119 120 private EditPinPreference mPinDialog; 121 private SwitchPreference mPinToggle; 122 123 private Resources mRes; 124 125 // For async handler to identify request type 126 private static final int MSG_SIM_STATE_CHANGED = 102; 127 128 // @see android.widget.Toast$TN 129 private static final long LONG_DURATION_TIMEOUT = 7000; 130 131 private int mSlotId = -1; 132 private int mSubId; 133 private TelephonyManager mTelephonyManager; 134 135 // For replies from IccCard interface 136 private Handler mHandler = new Handler() { 137 public void handleMessage(Message msg) { 138 switch (msg.what) { 139 case MSG_SIM_STATE_CHANGED: 140 updatePreferences(); 141 break; 142 } 143 144 return; 145 } 146 }; 147 148 private final BroadcastReceiver mSimStateReceiver = new BroadcastReceiver() { 149 public void onReceive(Context context, Intent intent) { 150 final String action = intent.getAction(); 151 if (Intent.ACTION_SIM_STATE_CHANGED.equals(action)) { 152 mHandler.sendMessage(mHandler.obtainMessage(MSG_SIM_STATE_CHANGED)); 153 } 154 } 155 }; 156 157 // For top-level settings screen to query isIccLockEnabled()158 private boolean isIccLockEnabled() { 159 mTelephonyManager = mTelephonyManager.createForSubscriptionId(mSubId); 160 return mTelephonyManager.isIccLockEnabled(); 161 } 162 getSummary(Context context)163 private String getSummary(Context context) { 164 final Resources res = context.getResources(); 165 final String summary = isIccLockEnabled() 166 ? res.getString(R.string.sim_lock_on) 167 : res.getString(R.string.sim_lock_off); 168 return summary; 169 } 170 171 @Override onCreate(Bundle savedInstanceState)172 public void onCreate(Bundle savedInstanceState) { 173 super.onCreate(savedInstanceState); 174 175 if (Utils.isMonkeyRunning()) { 176 finish(); 177 return; 178 } 179 180 // enable ProxySubscriptionMgr with Lifecycle support for all controllers 181 // live within this fragment 182 mProxySubscriptionMgr = ProxySubscriptionManager.getInstance(getContext()); 183 mProxySubscriptionMgr.setLifecycle(getLifecycle()); 184 185 mTelephonyManager = getContext().getSystemService(TelephonyManager.class); 186 187 addPreferencesFromResource(R.xml.sim_lock_settings); 188 189 mPinDialog = (EditPinPreference) findPreference(PIN_DIALOG); 190 mPinToggle = (SwitchPreference) findPreference(PIN_TOGGLE); 191 if (savedInstanceState != null) { 192 if (savedInstanceState.containsKey(DIALOG_STATE) 193 && restoreDialogStates(savedInstanceState)) { 194 Log.d(TAG, "onCreate: restore dialog for slotId=" + mSlotId + ", subId=" + mSubId); 195 } else if (savedInstanceState.containsKey(CURRENT_TAB) 196 && restoreTabFocus(savedInstanceState)) { 197 Log.d(TAG, "onCreate: restore focus on slotId=" + mSlotId + ", subId=" + mSubId); 198 } 199 } 200 201 mPinDialog.setOnPinEnteredListener(this); 202 203 // Don't need any changes to be remembered 204 getPreferenceScreen().setPersistent(false); 205 206 mRes = getResources(); 207 } 208 restoreDialogStates(Bundle savedInstanceState)209 private boolean restoreDialogStates(Bundle savedInstanceState) { 210 final SubscriptionInfo subInfo = mProxySubscriptionMgr 211 .getActiveSubscriptionInfo(savedInstanceState.getInt(DIALOG_SUB_ID)); 212 if (subInfo == null) { 213 return false; 214 } 215 216 final SubscriptionInfo visibleSubInfo = getVisibleSubscriptionInfoForSimSlotIndex( 217 subInfo.getSimSlotIndex()); 218 if (visibleSubInfo == null) { 219 return false; 220 } 221 if (visibleSubInfo.getSubscriptionId() != subInfo.getSubscriptionId()) { 222 return false; 223 } 224 225 mSlotId = subInfo.getSimSlotIndex(); 226 mSubId = subInfo.getSubscriptionId(); 227 mDialogState = savedInstanceState.getInt(DIALOG_STATE); 228 mPin = savedInstanceState.getString(DIALOG_PIN); 229 mError = savedInstanceState.getString(DIALOG_ERROR); 230 mToState = savedInstanceState.getBoolean(ENABLE_TO_STATE); 231 232 // Restore inputted PIN code 233 switch (mDialogState) { 234 case ICC_NEW_MODE: 235 mOldPin = savedInstanceState.getString(OLD_PINCODE); 236 break; 237 238 case ICC_REENTER_MODE: 239 mOldPin = savedInstanceState.getString(OLD_PINCODE); 240 mNewPin = savedInstanceState.getString(NEW_PINCODE); 241 break; 242 } 243 return true; 244 } 245 restoreTabFocus(Bundle savedInstanceState)246 private boolean restoreTabFocus(Bundle savedInstanceState) { 247 int slotId = 0; 248 try { 249 slotId = Integer.parseInt(savedInstanceState.getString(CURRENT_TAB)); 250 } catch (NumberFormatException exception) { 251 return false; 252 } 253 254 final SubscriptionInfo subInfo = getVisibleSubscriptionInfoForSimSlotIndex(slotId); 255 if (subInfo == null) { 256 return false; 257 } 258 259 mSlotId = subInfo.getSimSlotIndex(); 260 mSubId = subInfo.getSubscriptionId(); 261 if (mTabHost != null) { 262 mTabHost.setCurrentTabByTag(getTagForSlotId(mSlotId)); 263 } 264 return true; 265 } 266 267 @Override onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)268 public View onCreateView(LayoutInflater inflater, ViewGroup container, 269 Bundle savedInstanceState) { 270 271 final int numSims = mProxySubscriptionMgr.getActiveSubscriptionInfoCountMax(); 272 final List<SubscriptionInfo> componenterList = new ArrayList<>(); 273 274 for (int i = 0; i < numSims; ++i) { 275 final SubscriptionInfo subInfo = getVisibleSubscriptionInfoForSimSlotIndex(i); 276 if (subInfo != null) { 277 componenterList.add(subInfo); 278 } 279 } 280 281 if (componenterList.size() == 0) { 282 Log.e(TAG, "onCreateView: no sim info"); 283 return super.onCreateView(inflater, container, savedInstanceState); 284 } 285 286 if (mSlotId < 0) { 287 mSlotId = componenterList.get(0).getSimSlotIndex(); 288 mSubId = componenterList.get(0).getSubscriptionId(); 289 Log.d(TAG, "onCreateView: default slotId=" + mSlotId + ", subId=" + mSubId); 290 } 291 292 if (componenterList.size() > 1) { 293 final View view = inflater.inflate(R.layout.icc_lock_tabs, container, false); 294 final ViewGroup prefs_container = (ViewGroup) view.findViewById(R.id.prefs_container); 295 Utils.prepareCustomPreferencesList(container, view, prefs_container, false); 296 final View prefs = super.onCreateView(inflater, prefs_container, savedInstanceState); 297 prefs_container.addView(prefs); 298 299 mTabHost = (TabHost) view.findViewById(android.R.id.tabhost); 300 mTabWidget = (TabWidget) view.findViewById(android.R.id.tabs); 301 mListView = (ListView) view.findViewById(android.R.id.list); 302 303 mTabHost.setup(); 304 mTabHost.clearAllTabs(); 305 306 for (SubscriptionInfo subInfo : componenterList) { 307 final int slot = subInfo.getSimSlotIndex(); 308 final String tag = getTagForSlotId(slot); 309 mTabHost.addTab(buildTabSpec(tag, 310 String.valueOf(subInfo == null 311 ? getContext().getString(R.string.sim_editor_title, slot + 1) 312 : subInfo.getDisplayName()))); 313 } 314 315 mTabHost.setCurrentTabByTag(getTagForSlotId(mSlotId)); 316 mTabHost.setOnTabChangedListener(mTabListener); 317 return view; 318 } else { 319 return super.onCreateView(inflater, container, savedInstanceState); 320 } 321 } 322 323 @Override onViewCreated(View view, Bundle savedInstanceState)324 public void onViewCreated(View view, Bundle savedInstanceState) { 325 super.onViewCreated(view, savedInstanceState); 326 updatePreferences(); 327 } 328 updatePreferences()329 private void updatePreferences() { 330 331 final SubscriptionInfo sir = getVisibleSubscriptionInfoForSimSlotIndex(mSlotId); 332 final int subId = (sir != null) ? sir.getSubscriptionId() 333 : SubscriptionManager.INVALID_SUBSCRIPTION_ID; 334 335 if (mSubId != subId) { 336 mSubId = subId; 337 resetDialogState(); 338 if ((mPinDialog != null) && mPinDialog.isDialogOpen()) { 339 mPinDialog.getDialog().dismiss(); 340 } 341 } 342 343 if (mPinDialog != null) { 344 mPinDialog.setEnabled(sir != null); 345 } 346 if (mPinToggle != null) { 347 mPinToggle.setEnabled(sir != null); 348 349 if (sir != null) { 350 mPinToggle.setChecked(isIccLockEnabled()); 351 } 352 } 353 } 354 355 @Override getMetricsCategory()356 public int getMetricsCategory() { 357 return SettingsEnums.ICC_LOCK; 358 } 359 360 @Override onResume()361 public void onResume() { 362 super.onResume(); 363 364 // ACTION_SIM_STATE_CHANGED is sticky, so we'll receive current state after this call, 365 // which will call updatePreferences(). 366 final IntentFilter filter = new IntentFilter(Intent.ACTION_SIM_STATE_CHANGED); 367 getContext().registerReceiver(mSimStateReceiver, filter); 368 369 if (mDialogState != OFF_MODE) { 370 showPinDialog(); 371 } else { 372 // Prep for standard click on "Change PIN" 373 resetDialogState(); 374 } 375 } 376 377 @Override onPause()378 public void onPause() { 379 super.onPause(); 380 getContext().unregisterReceiver(mSimStateReceiver); 381 } 382 383 @Override getHelpResource()384 public int getHelpResource() { 385 return R.string.help_url_icc_lock; 386 } 387 388 @Override onSaveInstanceState(Bundle out)389 public void onSaveInstanceState(Bundle out) { 390 // Need to store this state for slider open/close 391 // There is one case where the dialog is popped up by the preference 392 // framework. In that case, let the preference framework store the 393 // dialog state. In other cases, where this activity manually launches 394 // the dialog, store the state of the dialog. 395 if (mPinDialog.isDialogOpen()) { 396 out.putInt(DIALOG_SUB_ID, mSubId); 397 out.putInt(DIALOG_STATE, mDialogState); 398 out.putString(DIALOG_PIN, mPinDialog.getEditText().getText().toString()); 399 out.putString(DIALOG_ERROR, mError); 400 out.putBoolean(ENABLE_TO_STATE, mToState); 401 402 // Save inputted PIN code 403 switch (mDialogState) { 404 case ICC_NEW_MODE: 405 out.putString(OLD_PINCODE, mOldPin); 406 break; 407 408 case ICC_REENTER_MODE: 409 out.putString(OLD_PINCODE, mOldPin); 410 out.putString(NEW_PINCODE, mNewPin); 411 break; 412 } 413 } else { 414 super.onSaveInstanceState(out); 415 } 416 417 if (mTabHost != null) { 418 out.putString(CURRENT_TAB, mTabHost.getCurrentTabTag()); 419 } 420 } 421 showPinDialog()422 private void showPinDialog() { 423 if (mDialogState == OFF_MODE) { 424 return; 425 } 426 setDialogValues(); 427 428 mPinDialog.showPinDialog(); 429 430 final EditText editText = mPinDialog.getEditText(); 431 if (!TextUtils.isEmpty(mPin) && editText != null) { 432 editText.setSelection(mPin.length()); 433 } 434 } 435 setDialogValues()436 private void setDialogValues() { 437 mPinDialog.setText(mPin); 438 String message = ""; 439 switch (mDialogState) { 440 case ICC_LOCK_MODE: 441 message = mRes.getString(R.string.sim_enter_pin); 442 mPinDialog.setDialogTitle(mToState 443 ? mRes.getString(R.string.sim_enable_sim_lock) 444 : mRes.getString(R.string.sim_disable_sim_lock)); 445 break; 446 case ICC_OLD_MODE: 447 message = mRes.getString(R.string.sim_enter_old); 448 mPinDialog.setDialogTitle(mRes.getString(R.string.sim_change_pin)); 449 break; 450 case ICC_NEW_MODE: 451 message = mRes.getString(R.string.sim_enter_new); 452 mPinDialog.setDialogTitle(mRes.getString(R.string.sim_change_pin)); 453 break; 454 case ICC_REENTER_MODE: 455 message = mRes.getString(R.string.sim_reenter_new); 456 mPinDialog.setDialogTitle(mRes.getString(R.string.sim_change_pin)); 457 break; 458 } 459 if (mError != null) { 460 message = mError + "\n" + message; 461 mError = null; 462 } 463 mPinDialog.setDialogMessage(message); 464 } 465 466 @Override onPinEntered(EditPinPreference preference, boolean positiveResult)467 public void onPinEntered(EditPinPreference preference, boolean positiveResult) { 468 if (!positiveResult) { 469 resetDialogState(); 470 return; 471 } 472 473 mPin = preference.getText(); 474 if (!reasonablePin(mPin)) { 475 // inject error message and display dialog again 476 mError = mRes.getString(R.string.sim_bad_pin); 477 showPinDialog(); 478 return; 479 } 480 switch (mDialogState) { 481 case ICC_LOCK_MODE: 482 tryChangeIccLockState(); 483 break; 484 case ICC_OLD_MODE: 485 mOldPin = mPin; 486 mDialogState = ICC_NEW_MODE; 487 mError = null; 488 mPin = null; 489 showPinDialog(); 490 break; 491 case ICC_NEW_MODE: 492 mNewPin = mPin; 493 mDialogState = ICC_REENTER_MODE; 494 mPin = null; 495 showPinDialog(); 496 break; 497 case ICC_REENTER_MODE: 498 if (!mPin.equals(mNewPin)) { 499 mError = mRes.getString(R.string.sim_pins_dont_match); 500 mDialogState = ICC_NEW_MODE; 501 mPin = null; 502 showPinDialog(); 503 } else { 504 mError = null; 505 tryChangePin(); 506 } 507 break; 508 } 509 } 510 511 @Override onPreferenceTreeClick(Preference preference)512 public boolean onPreferenceTreeClick(Preference preference) { 513 if (preference == mPinToggle) { 514 // Get the new, preferred state 515 mToState = mPinToggle.isChecked(); 516 // Flip it back and pop up pin dialog 517 mPinToggle.setChecked(!mToState); 518 mDialogState = ICC_LOCK_MODE; 519 showPinDialog(); 520 } else if (preference == mPinDialog) { 521 mDialogState = ICC_OLD_MODE; 522 return false; 523 } 524 return true; 525 } 526 tryChangeIccLockState()527 private void tryChangeIccLockState() { 528 // Try to change icc lock. If it succeeds, toggle the lock state and 529 // reset dialog state. Else inject error message and show dialog again. 530 new SetIccLockEnabled(mToState, mPin).execute(); 531 // Disable the setting till the response is received. 532 mPinToggle.setEnabled(false); 533 } 534 535 private class SetIccLockEnabled extends AsyncTask<Void, Void, Void> { 536 private final boolean mState; 537 private final String mPassword; 538 private int mAttemptsRemaining; 539 SetIccLockEnabled(boolean state, String pin)540 private SetIccLockEnabled(boolean state, String pin) { 541 mState = state; 542 mPassword = pin; 543 } 544 545 @Override doInBackground(Void... params)546 protected Void doInBackground(Void... params) { 547 mTelephonyManager = mTelephonyManager.createForSubscriptionId(mSubId); 548 mAttemptsRemaining = mTelephonyManager.setIccLockEnabled(mState, mPassword); 549 return null; 550 } 551 552 @Override onPostExecute(Void aVoid)553 protected void onPostExecute(Void aVoid) { 554 if (mAttemptsRemaining == TelephonyManager.CHANGE_ICC_LOCK_SUCCESS) { 555 iccLockChanged(true, mAttemptsRemaining); 556 } else { 557 iccLockChanged(false, mAttemptsRemaining); 558 } 559 } 560 } 561 iccLockChanged(boolean success, int attemptsRemaining)562 private void iccLockChanged(boolean success, int attemptsRemaining) { 563 Log.d(TAG, "iccLockChanged: success = " + success); 564 if (success) { 565 mPinToggle.setChecked(mToState); 566 } else { 567 if (attemptsRemaining >= 0) { 568 createCustomTextToast(getPinPasswordErrorMessage(attemptsRemaining)); 569 } else { 570 if (mToState) { 571 Toast.makeText(getContext(), mRes.getString( 572 R.string.sim_pin_enable_failed), Toast.LENGTH_LONG).show(); 573 } else { 574 Toast.makeText(getContext(), mRes.getString( 575 R.string.sim_pin_disable_failed), Toast.LENGTH_LONG).show(); 576 } 577 } 578 } 579 mPinToggle.setEnabled(true); 580 resetDialogState(); 581 } 582 createCustomTextToast(CharSequence errorMessage)583 private void createCustomTextToast(CharSequence errorMessage) { 584 // Cannot overlay Toast on PUK unlock screen. 585 // The window type of Toast is set by NotificationManagerService. 586 // It can't be overwritten by LayoutParams.type. 587 // Ovarlay a custom window with LayoutParams (TYPE_STATUS_BAR_PANEL) on PUK unlock screen. 588 final View v = ((LayoutInflater) getSystemService(Context.LAYOUT_INFLATER_SERVICE)) 589 .inflate(com.android.internal.R.layout.transient_notification, null); 590 final TextView tv = (TextView) v.findViewById(com.android.internal.R.id.message); 591 tv.setText(errorMessage); 592 593 final WindowManager.LayoutParams params = new WindowManager.LayoutParams(); 594 final Configuration config = v.getContext().getResources().getConfiguration(); 595 final int gravity = Gravity.getAbsoluteGravity( 596 getContext().getResources().getInteger( 597 com.android.internal.R.integer.config_toastDefaultGravity), 598 config.getLayoutDirection()); 599 params.gravity = gravity; 600 if ((gravity & Gravity.HORIZONTAL_GRAVITY_MASK) == Gravity.FILL_HORIZONTAL) { 601 params.horizontalWeight = 1.0f; 602 } 603 if ((gravity & Gravity.VERTICAL_GRAVITY_MASK) == Gravity.FILL_VERTICAL) { 604 params.verticalWeight = 1.0f; 605 } 606 params.y = getContext().getResources().getDimensionPixelSize( 607 com.android.internal.R.dimen.toast_y_offset); 608 609 params.height = WindowManager.LayoutParams.WRAP_CONTENT; 610 params.width = WindowManager.LayoutParams.WRAP_CONTENT; 611 params.format = PixelFormat.TRANSLUCENT; 612 params.windowAnimations = com.android.internal.R.style.Animation_Toast; 613 params.type = WindowManager.LayoutParams.TYPE_STATUS_BAR_SUB_PANEL; 614 params.setFitInsetsTypes(params.getFitInsetsTypes() & ~Type.statusBars()); 615 params.setTitle(errorMessage); 616 params.flags = WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON 617 | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE 618 | WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE; 619 620 final WindowManager wm = (WindowManager) getSystemService(Context.WINDOW_SERVICE); 621 wm.addView(v, params); 622 623 mHandler.postDelayed(new Runnable() { 624 @Override 625 public void run() { 626 wm.removeViewImmediate(v); 627 } 628 }, LONG_DURATION_TIMEOUT); 629 } 630 iccPinChanged(boolean success, int attemptsRemaining)631 private void iccPinChanged(boolean success, int attemptsRemaining) { 632 Log.d(TAG, "iccPinChanged: success = " + success); 633 if (!success) { 634 createCustomTextToast(getPinPasswordErrorMessage(attemptsRemaining)); 635 } else { 636 Toast.makeText(getContext(), mRes.getString(R.string.sim_change_succeeded), 637 Toast.LENGTH_SHORT) 638 .show(); 639 } 640 resetDialogState(); 641 } 642 tryChangePin()643 private void tryChangePin() { 644 new ChangeIccLockPassword(mOldPin, mNewPin).execute(); 645 } 646 647 private class ChangeIccLockPassword extends AsyncTask<Void, Void, Void> { 648 private final String mOldPwd; 649 private final String mNewPwd; 650 private int mAttemptsRemaining; 651 ChangeIccLockPassword(String oldPin, String newPin)652 private ChangeIccLockPassword(String oldPin, String newPin) { 653 mOldPwd = oldPin; 654 mNewPwd = newPin; 655 } 656 657 @Override doInBackground(Void... params)658 protected Void doInBackground(Void... params) { 659 mTelephonyManager = mTelephonyManager.createForSubscriptionId(mSubId); 660 mAttemptsRemaining = mTelephonyManager.changeIccLockPassword(mOldPwd, mNewPwd); 661 return null; 662 } 663 664 @Override onPostExecute(Void aVoid)665 protected void onPostExecute(Void aVoid) { 666 if (mAttemptsRemaining == TelephonyManager.CHANGE_ICC_LOCK_SUCCESS) { 667 iccPinChanged(true, mAttemptsRemaining); 668 } else { 669 iccPinChanged(false, mAttemptsRemaining); 670 } 671 } 672 } 673 getPinPasswordErrorMessage(int attemptsRemaining)674 private String getPinPasswordErrorMessage(int attemptsRemaining) { 675 String displayMessage; 676 677 if (attemptsRemaining == 0) { 678 displayMessage = mRes.getString(R.string.wrong_pin_code_pukked); 679 } else if (attemptsRemaining == 1) { 680 displayMessage = mRes.getString(R.string.wrong_pin_code_one, attemptsRemaining); 681 } else if (attemptsRemaining > 1) { 682 displayMessage = mRes 683 .getQuantityString(R.plurals.wrong_pin_code, attemptsRemaining, 684 attemptsRemaining); 685 } else { 686 displayMessage = mRes.getString(R.string.pin_failed); 687 } 688 if (DBG) Log.d(TAG, "getPinPasswordErrorMessage:" 689 + " attemptsRemaining=" + attemptsRemaining + " displayMessage=" + displayMessage); 690 return displayMessage; 691 } 692 reasonablePin(String pin)693 private boolean reasonablePin(String pin) { 694 if (pin == null || pin.length() < MIN_PIN_LENGTH || pin.length() > MAX_PIN_LENGTH) { 695 return false; 696 } else { 697 return true; 698 } 699 } 700 resetDialogState()701 private void resetDialogState() { 702 mError = null; 703 mDialogState = ICC_OLD_MODE; // Default for when Change PIN is clicked 704 mPin = ""; 705 setDialogValues(); 706 mDialogState = OFF_MODE; 707 } 708 getTagForSlotId(int slotId)709 private String getTagForSlotId(int slotId) { 710 return String.valueOf(slotId); 711 } 712 getSlotIndexFromTag(String tag)713 private int getSlotIndexFromTag(String tag) { 714 int slotId = -1; 715 try { 716 slotId = Integer.parseInt(tag); 717 } catch (NumberFormatException exception) { 718 } 719 return slotId; 720 } 721 getVisibleSubscriptionInfoForSimSlotIndex(int slotId)722 private SubscriptionInfo getVisibleSubscriptionInfoForSimSlotIndex(int slotId) { 723 final List<SubscriptionInfo> subInfoList = 724 mProxySubscriptionMgr.getActiveSubscriptionsInfo(); 725 if (subInfoList == null) { 726 return null; 727 } 728 final CarrierConfigManager carrierConfigManager = getContext().getSystemService( 729 CarrierConfigManager.class); 730 for (SubscriptionInfo subInfo : subInfoList) { 731 if ((isSubscriptionVisible(carrierConfigManager, subInfo) 732 && (subInfo.getSimSlotIndex() == slotId))) { 733 return subInfo; 734 } 735 } 736 return null; 737 } 738 isSubscriptionVisible(CarrierConfigManager carrierConfigManager, SubscriptionInfo subInfo)739 private boolean isSubscriptionVisible(CarrierConfigManager carrierConfigManager, 740 SubscriptionInfo subInfo) { 741 final PersistableBundle bundle = carrierConfigManager 742 .getConfigForSubId(subInfo.getSubscriptionId()); 743 if (bundle == null) { 744 return false; 745 } 746 return !bundle.getBoolean(CarrierConfigManager.KEY_HIDE_SIM_LOCK_SETTINGS_BOOL); 747 } 748 749 private OnTabChangeListener mTabListener = new OnTabChangeListener() { 750 @Override 751 public void onTabChanged(String tabId) { 752 mSlotId = getSlotIndexFromTag(tabId); 753 754 // The User has changed tab; update the body. 755 updatePreferences(); 756 } 757 }; 758 759 private TabContentFactory mEmptyTabContent = new TabContentFactory() { 760 @Override 761 public View createTabContent(String tag) { 762 return new View(mTabHost.getContext()); 763 } 764 }; 765 buildTabSpec(String tag, String title)766 private TabSpec buildTabSpec(String tag, String title) { 767 return mTabHost.newTabSpec(tag).setIndicator(title).setContent( 768 mEmptyTabContent); 769 } 770 } 771