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