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