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