In security setting, if user change orientation during entering pin code, the change will not apply successfully, it is because the entered pin codes has not been saved and restored when application was re-create after changed orientation. So we save entered pin codes and restore them in onCreate when application is re-created. Change-Id: Ia8a3fb3ee75185ce028104487377e47f272905ce
369 lines
13 KiB
Java
369 lines
13 KiB
Java
/*
|
|
* Copyright (C) 2008 The Android Open Source Project
|
|
*
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
* you may not use this file except in compliance with the License.
|
|
* You may obtain a copy of the License at
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
* See the License for the specific language governing permissions and
|
|
* limitations under the License.
|
|
*/
|
|
|
|
package com.android.settings;
|
|
|
|
import android.content.Context;
|
|
import android.content.res.Resources;
|
|
import android.os.AsyncResult;
|
|
import android.os.Bundle;
|
|
import android.os.Handler;
|
|
import android.os.Message;
|
|
import android.preference.CheckBoxPreference;
|
|
import android.preference.Preference;
|
|
import android.preference.PreferenceActivity;
|
|
import android.preference.PreferenceScreen;
|
|
import android.widget.Toast;
|
|
|
|
import com.android.internal.telephony.Phone;
|
|
import com.android.internal.telephony.PhoneFactory;
|
|
|
|
/**
|
|
* Implements the preference screen to enable/disable ICC lock and
|
|
* also the dialogs to change the ICC PIN. In the former case, enabling/disabling
|
|
* the ICC lock will prompt the user for the current PIN.
|
|
* In the Change PIN case, it prompts the user for old pin, new pin and new pin
|
|
* again before attempting to change it. Calls the SimCard interface to execute
|
|
* these operations.
|
|
*
|
|
*/
|
|
public class IccLockSettings extends PreferenceActivity
|
|
implements EditPinPreference.OnPinEnteredListener {
|
|
|
|
private static final int OFF_MODE = 0;
|
|
// State when enabling/disabling ICC lock
|
|
private static final int ICC_LOCK_MODE = 1;
|
|
// State when entering the old pin
|
|
private static final int ICC_OLD_MODE = 2;
|
|
// State when entering the new pin - first time
|
|
private static final int ICC_NEW_MODE = 3;
|
|
// State when entering the new pin - second time
|
|
private static final int ICC_REENTER_MODE = 4;
|
|
|
|
// Keys in xml file
|
|
private static final String PIN_DIALOG = "sim_pin";
|
|
private static final String PIN_TOGGLE = "sim_toggle";
|
|
// Keys in icicle
|
|
private static final String DIALOG_STATE = "dialogState";
|
|
private static final String DIALOG_PIN = "dialogPin";
|
|
private static final String DIALOG_ERROR = "dialogError";
|
|
private static final String ENABLE_TO_STATE = "enableState";
|
|
|
|
// Save and restore inputted PIN code when configuration changed
|
|
// (ex. portrait<-->landscape) during change PIN code
|
|
private static final String OLD_PINCODE = "oldPinCode";
|
|
private static final String NEW_PINCODE = "newPinCode";
|
|
|
|
private static final int MIN_PIN_LENGTH = 4;
|
|
private static final int MAX_PIN_LENGTH = 8;
|
|
// Which dialog to show next when popped up
|
|
private int mDialogState = OFF_MODE;
|
|
|
|
private String mPin;
|
|
private String mOldPin;
|
|
private String mNewPin;
|
|
private String mError;
|
|
// Are we trying to enable or disable ICC lock?
|
|
private boolean mToState;
|
|
|
|
private Phone mPhone;
|
|
|
|
private EditPinPreference mPinDialog;
|
|
private CheckBoxPreference mPinToggle;
|
|
|
|
private Resources mRes;
|
|
|
|
// For async handler to identify request type
|
|
private static final int ENABLE_ICC_PIN_COMPLETE = 100;
|
|
private static final int CHANGE_ICC_PIN_COMPLETE = 101;
|
|
|
|
// For replies from IccCard interface
|
|
private Handler mHandler = new Handler() {
|
|
public void handleMessage(Message msg) {
|
|
AsyncResult ar = (AsyncResult) msg.obj;
|
|
switch (msg.what) {
|
|
case ENABLE_ICC_PIN_COMPLETE:
|
|
iccLockChanged(ar.exception == null);
|
|
break;
|
|
case CHANGE_ICC_PIN_COMPLETE:
|
|
iccPinChanged(ar.exception == null);
|
|
break;
|
|
}
|
|
|
|
return;
|
|
}
|
|
};
|
|
|
|
// For top-level settings screen to query
|
|
static boolean isIccLockEnabled() {
|
|
return PhoneFactory.getDefaultPhone().getIccCard().getIccLockEnabled();
|
|
}
|
|
|
|
static String getSummary(Context context) {
|
|
Resources res = context.getResources();
|
|
String summary = isIccLockEnabled()
|
|
? res.getString(R.string.sim_lock_on)
|
|
: res.getString(R.string.sim_lock_off);
|
|
return summary;
|
|
}
|
|
|
|
@Override
|
|
protected void onCreate(Bundle savedInstanceState) {
|
|
super.onCreate(savedInstanceState);
|
|
|
|
if (Utils.isMonkeyRunning()) {
|
|
finish();
|
|
return;
|
|
}
|
|
|
|
addPreferencesFromResource(R.xml.sim_lock_settings);
|
|
|
|
mPinDialog = (EditPinPreference) findPreference(PIN_DIALOG);
|
|
mPinToggle = (CheckBoxPreference) findPreference(PIN_TOGGLE);
|
|
if (savedInstanceState != null && savedInstanceState.containsKey(DIALOG_STATE)) {
|
|
mDialogState = savedInstanceState.getInt(DIALOG_STATE);
|
|
mPin = savedInstanceState.getString(DIALOG_PIN);
|
|
mError = savedInstanceState.getString(DIALOG_ERROR);
|
|
mToState = savedInstanceState.getBoolean(ENABLE_TO_STATE);
|
|
|
|
// Restore inputted PIN code
|
|
switch (mDialogState) {
|
|
case ICC_NEW_MODE:
|
|
mOldPin = savedInstanceState.getString(OLD_PINCODE);
|
|
break;
|
|
|
|
case ICC_REENTER_MODE:
|
|
mOldPin = savedInstanceState.getString(OLD_PINCODE);
|
|
mNewPin = savedInstanceState.getString(NEW_PINCODE);
|
|
break;
|
|
|
|
case ICC_LOCK_MODE:
|
|
case ICC_OLD_MODE:
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
mPinDialog.setOnPinEnteredListener(this);
|
|
|
|
// Don't need any changes to be remembered
|
|
getPreferenceScreen().setPersistent(false);
|
|
|
|
mPhone = PhoneFactory.getDefaultPhone();
|
|
mRes = getResources();
|
|
}
|
|
|
|
@Override
|
|
protected void onResume() {
|
|
super.onResume();
|
|
|
|
mPinToggle.setChecked(mPhone.getIccCard().getIccLockEnabled());
|
|
|
|
if (mDialogState != OFF_MODE) {
|
|
showPinDialog();
|
|
} else {
|
|
// Prep for standard click on "Change PIN"
|
|
resetDialogState();
|
|
}
|
|
}
|
|
|
|
@Override
|
|
protected void onSaveInstanceState(Bundle out) {
|
|
// Need to store this state for slider open/close
|
|
// There is one case where the dialog is popped up by the preference
|
|
// framework. In that case, let the preference framework store the
|
|
// dialog state. In other cases, where this activity manually launches
|
|
// the dialog, store the state of the dialog.
|
|
if (mPinDialog.isDialogOpen()) {
|
|
out.putInt(DIALOG_STATE, mDialogState);
|
|
out.putString(DIALOG_PIN, mPinDialog.getEditText().getText().toString());
|
|
out.putString(DIALOG_ERROR, mError);
|
|
out.putBoolean(ENABLE_TO_STATE, mToState);
|
|
|
|
// Save inputted PIN code
|
|
switch (mDialogState) {
|
|
case ICC_NEW_MODE:
|
|
out.putString(OLD_PINCODE, mOldPin);
|
|
break;
|
|
|
|
case ICC_REENTER_MODE:
|
|
out.putString(OLD_PINCODE, mOldPin);
|
|
out.putString(NEW_PINCODE, mNewPin);
|
|
break;
|
|
|
|
case ICC_LOCK_MODE:
|
|
case ICC_OLD_MODE:
|
|
default:
|
|
break;
|
|
}
|
|
} else {
|
|
super.onSaveInstanceState(out);
|
|
}
|
|
}
|
|
|
|
private void showPinDialog() {
|
|
if (mDialogState == OFF_MODE) {
|
|
return;
|
|
}
|
|
setDialogValues();
|
|
|
|
mPinDialog.showPinDialog();
|
|
}
|
|
|
|
private void setDialogValues() {
|
|
mPinDialog.setText(mPin);
|
|
String message = "";
|
|
switch (mDialogState) {
|
|
case ICC_LOCK_MODE:
|
|
message = mRes.getString(R.string.sim_enter_pin);
|
|
mPinDialog.setDialogTitle(mToState
|
|
? mRes.getString(R.string.sim_enable_sim_lock)
|
|
: mRes.getString(R.string.sim_disable_sim_lock));
|
|
break;
|
|
case ICC_OLD_MODE:
|
|
message = mRes.getString(R.string.sim_enter_old);
|
|
mPinDialog.setDialogTitle(mRes.getString(R.string.sim_change_pin));
|
|
break;
|
|
case ICC_NEW_MODE:
|
|
message = mRes.getString(R.string.sim_enter_new);
|
|
mPinDialog.setDialogTitle(mRes.getString(R.string.sim_change_pin));
|
|
break;
|
|
case ICC_REENTER_MODE:
|
|
message = mRes.getString(R.string.sim_reenter_new);
|
|
mPinDialog.setDialogTitle(mRes.getString(R.string.sim_change_pin));
|
|
break;
|
|
}
|
|
if (mError != null) {
|
|
message = mError + "\n" + message;
|
|
mError = null;
|
|
}
|
|
mPinDialog.setDialogMessage(message);
|
|
}
|
|
|
|
public void onPinEntered(EditPinPreference preference, boolean positiveResult) {
|
|
if (!positiveResult) {
|
|
resetDialogState();
|
|
return;
|
|
}
|
|
|
|
mPin = preference.getText();
|
|
if (!reasonablePin(mPin)) {
|
|
// inject error message and display dialog again
|
|
mError = mRes.getString(R.string.sim_bad_pin);
|
|
showPinDialog();
|
|
return;
|
|
}
|
|
switch (mDialogState) {
|
|
case ICC_LOCK_MODE:
|
|
tryChangeIccLockState();
|
|
break;
|
|
case ICC_OLD_MODE:
|
|
mOldPin = mPin;
|
|
mDialogState = ICC_NEW_MODE;
|
|
mError = null;
|
|
mPin = null;
|
|
showPinDialog();
|
|
break;
|
|
case ICC_NEW_MODE:
|
|
mNewPin = mPin;
|
|
mDialogState = ICC_REENTER_MODE;
|
|
mPin = null;
|
|
showPinDialog();
|
|
break;
|
|
case ICC_REENTER_MODE:
|
|
if (!mPin.equals(mNewPin)) {
|
|
mError = mRes.getString(R.string.sim_pins_dont_match);
|
|
mDialogState = ICC_NEW_MODE;
|
|
mPin = null;
|
|
showPinDialog();
|
|
} else {
|
|
mError = null;
|
|
tryChangePin();
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
|
|
public boolean onPreferenceTreeClick(PreferenceScreen preferenceScreen, Preference preference) {
|
|
if (preference == mPinToggle) {
|
|
// Get the new, preferred state
|
|
mToState = mPinToggle.isChecked();
|
|
// Flip it back and pop up pin dialog
|
|
mPinToggle.setChecked(!mToState);
|
|
mDialogState = ICC_LOCK_MODE;
|
|
showPinDialog();
|
|
} else if (preference == mPinDialog) {
|
|
mDialogState = ICC_OLD_MODE;
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
private void tryChangeIccLockState() {
|
|
// Try to change icc lock. If it succeeds, toggle the lock state and
|
|
// reset dialog state. Else inject error message and show dialog again.
|
|
Message callback = Message.obtain(mHandler, ENABLE_ICC_PIN_COMPLETE);
|
|
mPhone.getIccCard().setIccLockEnabled(mToState, mPin, callback);
|
|
|
|
}
|
|
|
|
private void iccLockChanged(boolean success) {
|
|
if (success) {
|
|
mPinToggle.setChecked(mToState);
|
|
} else {
|
|
Toast.makeText(this, mRes.getString(R.string.sim_lock_failed), Toast.LENGTH_SHORT)
|
|
.show();
|
|
}
|
|
resetDialogState();
|
|
}
|
|
|
|
private void iccPinChanged(boolean success) {
|
|
if (!success) {
|
|
Toast.makeText(this, mRes.getString(R.string.sim_change_failed),
|
|
Toast.LENGTH_SHORT)
|
|
.show();
|
|
} else {
|
|
Toast.makeText(this, mRes.getString(R.string.sim_change_succeeded),
|
|
Toast.LENGTH_SHORT)
|
|
.show();
|
|
|
|
}
|
|
resetDialogState();
|
|
}
|
|
|
|
private void tryChangePin() {
|
|
Message callback = Message.obtain(mHandler, CHANGE_ICC_PIN_COMPLETE);
|
|
mPhone.getIccCard().changeIccLockPassword(mOldPin,
|
|
mNewPin, callback);
|
|
}
|
|
|
|
private boolean reasonablePin(String pin) {
|
|
if (pin == null || pin.length() < MIN_PIN_LENGTH || pin.length() > MAX_PIN_LENGTH) {
|
|
return false;
|
|
} else {
|
|
return true;
|
|
}
|
|
}
|
|
|
|
private void resetDialogState() {
|
|
mError = null;
|
|
mDialogState = ICC_OLD_MODE; // Default for when Change PIN is clicked
|
|
mPin = "";
|
|
setDialogValues();
|
|
mDialogState = OFF_MODE;
|
|
}
|
|
}
|