diff --git a/AndroidManifest.xml b/AndroidManifest.xml
index f4b1181f88b..2cb7772331a 100644
--- a/AndroidManifest.xml
+++ b/AndroidManifest.xml
@@ -406,6 +406,9 @@
+
+
@@ -413,9 +416,15 @@
+
+
+
+
+
+
+ android:label="@string/lockpattern_change_lock_pattern_label">
diff --git a/res/layout-land/choose_lock_pin.xml b/res/layout-land/choose_lock_pin.xml
new file mode 100644
index 00000000000..cdc75d3be37
--- /dev/null
+++ b/res/layout-land/choose_lock_pin.xml
@@ -0,0 +1,84 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/res/layout-land/confirm_lock_pin.xml b/res/layout-land/confirm_lock_pin.xml
new file mode 100644
index 00000000000..beff4a13a21
--- /dev/null
+++ b/res/layout-land/confirm_lock_pin.xml
@@ -0,0 +1,83 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/res/layout/choose_lock_password.xml b/res/layout/choose_lock_password.xml
new file mode 100644
index 00000000000..213f9a4b117
--- /dev/null
+++ b/res/layout/choose_lock_password.xml
@@ -0,0 +1,80 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/res/layout/choose_lock_pin.xml b/res/layout/choose_lock_pin.xml
new file mode 100644
index 00000000000..beff4a13a21
--- /dev/null
+++ b/res/layout/choose_lock_pin.xml
@@ -0,0 +1,83 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/res/layout/confirm_lock_pin.xml b/res/layout/confirm_lock_pin.xml
new file mode 100644
index 00000000000..beff4a13a21
--- /dev/null
+++ b/res/layout/confirm_lock_pin.xml
@@ -0,0 +1,83 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/res/layout/twelve_key_entry.xml b/res/layout/twelve_key_entry.xml
new file mode 100644
index 00000000000..81ead98f90d
--- /dev/null
+++ b/res/layout/twelve_key_entry.xml
@@ -0,0 +1,181 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/res/values/arrays.xml b/res/values/arrays.xml
index 2981b1245e4..eec1ffc4aed 100644
--- a/res/values/arrays.xml
+++ b/res/values/arrays.xml
@@ -23,19 +23,19 @@
strings. -->
-
+
- America
-
+
- Europe
-
+
- Africa
-
+
- Asia
-
+
- Australia
-
+
- Pacific
-
+
- All
@@ -98,6 +98,22 @@
- 1800000
+
+
+ - Password
+ - PIN
+ - Pattern
+ - None
+
+
+
+
+ - password
+ - pin
+ - pattern
+ - none
+
+
@@ -133,7 +149,7 @@
- 120
- 150
-
+
- American English
@@ -202,7 +218,7 @@
- WEP hexadecimal
-
+
diff --git a/res/values/strings.xml b/res/values/strings.xml
index 6152ecc459f..83fda4d39c4 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -4,9 +4,9 @@
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.
@@ -135,7 +135,7 @@
Awake time when charging:
Screen ON time:
-
+
Unknown
@@ -158,7 +158,7 @@
USB
AC+USB
Unknown
-
+
Unknown
@@ -516,6 +516,18 @@
Set My Location, screen unlock, credential storage lock
Passwords
+
+ Unlock Method
+
+ Change the method used to unlock your phone
+
+ Password must be at least %d digits
+
+ Password can be no longer than %d digits
+
+ PIN must contain only digits 0-9
+
+ Password contains an illegal character
@@ -553,7 +565,7 @@
Attention
- There was a problem pairing with %1$s.
+ There was a problem pairing with %1$s.
There was a problem pairing with %1$s because the PIN or Passkey is incorrect.
@@ -563,7 +575,7 @@
Pairing rejected by %1$s.
- There was a problem connecting to %1$s.
+ There was a problem connecting to %1$s.
Device alias
@@ -576,7 +588,7 @@
Scan for devices
-
+
Connect
@@ -588,8 +600,8 @@
Disconnect & unpair
- Options\u2026
-
+ Options\u2026
+
Connect to\u2026
@@ -807,7 +819,7 @@
Specify when to switch from Wi-Fi to mobile data
There was a problem setting the sleep policy.
-
+
MAC address
@@ -1253,10 +1265,10 @@
MNC field must be 2 or 3 digits.
Restoring default APN settings
-
- Reset to default
-
- Reset default APN settings completed
+
+ Reset to default
+
+ Reset default APN settings completed
@@ -1378,12 +1390,24 @@
Loading\u2026
+
+
+ Choose your password
+
+ Confirm password
+
+ Passwords don\'t match
+
+ Password confirmed
+
Screen unlock pattern
Change unlock pattern
+ Change unlock PIN
+
Confirm saved pattern
@@ -1447,8 +1471,8 @@
\n\n3\u00A0 Redraw your pattern to confirm.
\n\nReady to start? Touch \u201CNext\u201D.
\n\nTo leave your phone unprotected, touch \u201CCancel\u201D.
-
-
+
+
Example pattern
@@ -1528,7 +1552,7 @@
All
-
Downloaded
Process: %1$s
-
+
Language & keyboard
@@ -1639,7 +1663,7 @@ found in the list of installed applications.
card numbers. It comes from the application
%1$s.
Use this input method?
-
+
User dictionary
@@ -1731,7 +1755,7 @@ found in the list of installed applications.
(or other screens that can host gadgets). Note to translators: we're still determining
the final name for Gadgets/Widgets, so please translate both for now. -->
Choose gadget
-
+
@@ -1784,52 +1808,52 @@ found in the list of installed applications.
Packages sharing this UID:
-
+
No battery usage data available
-
+
Sensor:
-
+
Partial Wakelock:
-
+
Sensor used by packages:
-
+
Used %1$d times by %2$s
-
+
Used %1$d times by one of:
-
+
Running
-
+
Screen on
-
+
Phone on
-
+
Time spent without sleeping:
-
+
Time spent with screen on:
-
+
Time spent with phone on:
-
+
On battery:
-
+
Plugged in:
Usage statistics
-
+
Usage statistics
@@ -2263,7 +2287,7 @@ found in the list of installed applications.
Emergency tone
Set behavior when an emergency call is placed
-
+
Privacy
diff --git a/res/xml/security_settings.xml b/res/xml/security_settings.xml
index 1b735848b9c..d1f896afa4f 100644
--- a/res/xml/security_settings.xml
+++ b/res/xml/security_settings.xml
@@ -4,9 +4,9 @@
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.
@@ -19,15 +19,15 @@
-
-
-
-
@@ -42,5 +42,27 @@
-->
-
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/com/android/settings/ChooseLockPassword.java b/src/com/android/settings/ChooseLockPassword.java
new file mode 100644
index 00000000000..4a8b543a720
--- /dev/null
+++ b/src/com/android/settings/ChooseLockPassword.java
@@ -0,0 +1,232 @@
+/*
+ * Copyright (C) 2010 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 java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+import com.android.internal.widget.LockPatternUtils;
+import com.android.settings.ChooseLockPattern.LeftButtonMode;
+import com.android.settings.ChooseLockPattern.RightButtonMode;
+import com.android.settings.ChooseLockPattern.Stage;
+
+import android.app.Activity;
+import android.content.Intent;
+import android.os.Bundle;
+import android.os.Handler;
+import android.text.Editable;
+import android.text.TextUtils;
+import android.view.View;
+import android.view.View.OnClickListener;
+import android.widget.Button;
+import android.widget.TextView;
+
+
+public class ChooseLockPassword extends Activity implements OnClickListener {
+ private final int digitIds[] = new int[] { R.id.zero, R.id.one, R.id.two, R.id.three,
+ R.id.four, R.id.five, R.id.six, R.id.seven, R.id.eight, R.id.nine };
+ private TextView mPasswordTextView;
+ private int mPasswordMinLength = 4;
+ private int mPasswordMaxLength = 8;
+ private LockPatternUtils mLockPatternUtils;
+ private int mRequestedMode = LockPatternUtils.MODE_PIN;
+ private ChooseLockSettingsHelper mChooseLockSettingsHelper;
+ private com.android.settings.ChooseLockPassword.Stage mUiStage = Stage.Introduction;
+ private TextView mHeaderText;
+ private String mFirstPin;
+ public static final String PASSWORD_MIN_KEY = "lockscreen.password_min";
+ public static final String PASSWORD_MAX_KEY = "lockscreen.password_max";
+ private static Handler mHandler = new Handler();
+ private static final int CONFIRM_EXISTING_REQUEST = 58;
+ static final int RESULT_FINISHED = RESULT_FIRST_USER;
+ private static final long ERROR_MESSAGE_TIMEOUT = 3000;
+
+ /**
+ * Keep track internally of where the user is in choosing a pattern.
+ */
+ protected enum Stage {
+
+ Introduction(R.string.lockpassword_choose_your_password_header),
+ NeedToConfirm(R.string.lockpassword_confirm_your_password_header),
+ ConfirmWrong(R.string.lockpassword_confirm_passwords_dont_match),
+ ChoiceConfirmed(R.string.lockpassword_password_confirmed_header);
+
+ /**
+ * @param headerMessage The message displayed at the top.
+ */
+ Stage(int headerMessage) {
+ this.headerMessage = headerMessage;
+ }
+
+ final int headerMessage;
+ }
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ mLockPatternUtils = new LockPatternUtils(getContentResolver());
+ mRequestedMode = getIntent().getIntExtra("password_mode", mRequestedMode);
+ mPasswordMinLength = getIntent().getIntExtra("password_min_length", mPasswordMinLength);
+ mPasswordMaxLength = getIntent().getIntExtra("password_max_length", mPasswordMaxLength);
+ initViews();
+ mChooseLockSettingsHelper = new ChooseLockSettingsHelper(this);
+ if (savedInstanceState == null) {
+ updateStage(Stage.Introduction);
+ mChooseLockSettingsHelper.launchConfirmationActivity(CONFIRM_EXISTING_REQUEST);
+ }
+ }
+
+ private void initViews() {
+ if (LockPatternUtils.MODE_PIN == mRequestedMode
+ || LockPatternUtils.MODE_PASSWORD == mRequestedMode) {
+ setContentView(R.layout.choose_lock_pin);
+ // TODO: alphanumeric layout
+ // setContentView(R.layout.choose_lock_password);
+ for (int i = 0; i < digitIds.length; i++) {
+ Button button = (Button) findViewById(digitIds[i]);
+ button.setOnClickListener(this);
+ button.setText(Integer.toString(i));
+ }
+ findViewById(R.id.ok).setOnClickListener(this);
+ findViewById(R.id.cancel).setOnClickListener(this);
+ }
+ findViewById(R.id.backspace).setOnClickListener(this);
+ mPasswordTextView = (TextView) findViewById(R.id.pinDisplay);
+ mHeaderText = (TextView) findViewById(R.id.headerText);
+ }
+
+ @Override
+ protected void onActivityResult(int requestCode, int resultCode,
+ Intent data) {
+ super.onActivityResult(requestCode, resultCode, data);
+ switch (requestCode) {
+ case CONFIRM_EXISTING_REQUEST:
+ if (resultCode != Activity.RESULT_OK) {
+ setResult(RESULT_FINISHED);
+ finish();
+ }
+ break;
+ }
+ }
+
+ protected void updateStage(Stage stage) {
+ mHeaderText.setText(stage.headerMessage);
+ mPasswordTextView.setText("");
+ mUiStage = stage;
+ }
+
+ /**
+ * Validates PIN and returns a message to display if PIN fails test.
+ * @param pin
+ * @return message id to display to user
+ */
+ private String validatePassword(String pin) {
+ if (pin.length() < mPasswordMinLength) {
+ return getString(R.string.pin_password_too_short, mPasswordMinLength);
+ }
+ if (pin.length() > mPasswordMaxLength) {
+ return getString(R.string.pin_password_too_long, mPasswordMaxLength);
+ }
+ if (LockPatternUtils.MODE_PIN == mRequestedMode) {
+ Pattern p = Pattern.compile("[0-9]+");
+ Matcher m = p.matcher(pin);
+ if (!m.find()) {
+ return getString(R.string.pin_password_contains_non_digits);
+ }
+ } else if (LockPatternUtils.MODE_PASSWORD == mRequestedMode) {
+ // allow Latin-1 characters only
+ for (int i = 0; i < pin.length(); i++) {
+ char c = pin.charAt(i);
+ if (c <= 32 || c > 127) {
+ return getString(R.string.pin_password_illegal_character);
+ }
+ }
+ }
+ return null;
+ }
+
+ public void onClick(View v) {
+ switch (v.getId()) {
+ case R.id.ok:
+ {
+ final String pin = mPasswordTextView.getText().toString();
+ if (TextUtils.isEmpty(pin)) {
+ break;
+ }
+ String errorMsg = null;
+ if (mUiStage == Stage.Introduction) {
+ errorMsg = validatePassword(pin);
+ if (errorMsg == null) {
+ mFirstPin = pin;
+ updateStage(Stage.NeedToConfirm);
+ }
+ } else if (mUiStage == Stage.NeedToConfirm) {
+ if (mFirstPin.equals(pin)) {
+ // TODO: move these to LockPatternUtils
+ mLockPatternUtils.setLockPatternEnabled(false);
+ mLockPatternUtils.saveLockPattern(null);
+
+
+ mLockPatternUtils.saveLockPassword(pin);
+ finish();
+ } else {
+ int msg = R.string.lockpassword_confirm_passwords_dont_match;
+ errorMsg = getString(msg);
+ }
+ }
+ if (errorMsg != null) {
+ showError(errorMsg, Stage.Introduction);
+ }
+ }
+ break;
+
+ case R.id.backspace:
+ {
+ final Editable digits = mPasswordTextView.getEditableText();
+ final int len = digits.length();
+ if (len > 0) {
+ digits.delete(len-1, len);
+ }
+ }
+ break;
+
+ case R.id.cancel:
+ finish();
+ break;
+
+ default:
+ // Digits
+ for (int i = 0; i < digitIds.length; i++) {
+ if (v.getId() == digitIds[i]) {
+ mPasswordTextView.append(Integer.toString(i));
+ return;
+ }
+ }
+ break;
+ }
+ }
+
+ private void showError(String msg, final Stage next) {
+ mHeaderText.setText(msg);
+ mPasswordTextView.setText("");
+ mHandler.postDelayed(new Runnable() {
+ public void run() {
+ updateStage(next);
+ }
+ }, ERROR_MESSAGE_TIMEOUT);
+ }
+}
diff --git a/src/com/android/settings/ChooseLockPattern.java b/src/com/android/settings/ChooseLockPattern.java
index f103c6b5927..859d96b2a52 100644
--- a/src/com/android/settings/ChooseLockPattern.java
+++ b/src/com/android/settings/ChooseLockPattern.java
@@ -45,7 +45,6 @@ import java.util.List;
* - saves chosen password when confirmed
*/
public class ChooseLockPattern extends Activity implements View.OnClickListener{
-
/**
* Used by the choose lock pattern wizard to indicate the wizard is
* finished, and each activity in the wizard should finish.
@@ -56,7 +55,9 @@ public class ChooseLockPattern extends Activity implements View.OnClickListener{
* result.
*/
static final int RESULT_FINISHED = RESULT_FIRST_USER;
-
+
+ public static final int CONFIRM_EXISTING_REQUEST = 55;
+
// how long after a confirmation message is shown before moving on
static final int INFORMATION_MSG_TIMEOUT_MS = 3000;
@@ -65,29 +66,38 @@ public class ChooseLockPattern extends Activity implements View.OnClickListener{
private static final int ID_EMPTY_MESSAGE = -1;
-
protected TextView mHeaderText;
protected LockPatternView mLockPatternView;
protected TextView mFooterText;
private TextView mFooterLeftButton;
private TextView mFooterRightButton;
-
protected List mChosenPattern = null;
- protected LockPatternUtils mLockPatternUtils;
-
/**
* The patten used during the help screen to show how to draw a pattern.
*/
private final List mAnimatePattern =
- Collections.unmodifiableList(
- Lists.newArrayList(
- LockPatternView.Cell.of(0, 0),
- LockPatternView.Cell.of(0, 1),
- LockPatternView.Cell.of(1, 1),
- LockPatternView.Cell.of(2, 1)
- ));
+ Collections.unmodifiableList(Lists.newArrayList(
+ LockPatternView.Cell.of(0, 0),
+ LockPatternView.Cell.of(0, 1),
+ LockPatternView.Cell.of(1, 1),
+ LockPatternView.Cell.of(2, 1)
+ ));
+ @Override
+ protected void onActivityResult(int requestCode, int resultCode,
+ Intent data) {
+ super.onActivityResult(requestCode, resultCode, data);
+ switch (requestCode) {
+ case CONFIRM_EXISTING_REQUEST:
+ if (resultCode != Activity.RESULT_OK) {
+ setResult(RESULT_FINISHED);
+ finish();
+ }
+ updateStage(Stage.Introduction);
+ break;
+ }
+ }
/**
* The pattern listener that responds according to a user choosing a new
@@ -125,7 +135,7 @@ public class ChooseLockPattern extends Activity implements View.OnClickListener{
}
}
- public void onPatternCellAdded(List pattern) {
+ public void onPatternCellAdded(List pattern) {
}
@@ -250,19 +260,19 @@ public class ChooseLockPattern extends Activity implements View.OnClickListener{
}
};
+ private ChooseLockSettingsHelper mChooseLockSettingsHelper;
+
private static final String KEY_UI_STAGE = "uiStage";
private static final String KEY_PATTERN_CHOICE = "chosenPattern";
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
-
- mLockPatternUtils = new LockPatternUtils(getContentResolver());
-
+ mChooseLockSettingsHelper = new ChooseLockSettingsHelper(this);
requestWindowFeature(Window.FEATURE_NO_TITLE);
setupViews();
-
+
// make it so unhandled touch events within the unlock screen go to the
// lock pattern view.
final LinearLayoutWithDefaultTouchRecepient topLayout
@@ -271,11 +281,12 @@ public class ChooseLockPattern extends Activity implements View.OnClickListener{
topLayout.setDefaultTouchRecepient(mLockPatternView);
if (savedInstanceState == null) {
- // first launch
- updateStage(Stage.Introduction);
- if (mLockPatternUtils.savedPatternExists()) {
- confirmPattern();
- }
+ // first launch. As a security measure, we're in NeedToConfirm mode until we know
+ // there isn't an existing password or the user confirms their password.
+ updateStage(Stage.NeedToConfirm);
+ if (!mChooseLockSettingsHelper.launchConfirmationActivity(CONFIRM_EXISTING_REQUEST)) {
+ updateStage(Stage.Introduction);
+ }
} else {
// restore from previous state
final String patternString = savedInstanceState.getString(KEY_PATTERN_CHOICE);
@@ -285,19 +296,20 @@ public class ChooseLockPattern extends Activity implements View.OnClickListener{
updateStage(Stage.values()[savedInstanceState.getInt(KEY_UI_STAGE)]);
}
}
-
+
/**
* Keep all "find view" related stuff confined to this function since in
* case someone needs to subclass and customize.
*/
protected void setupViews() {
setContentView(R.layout.choose_lock_pattern);
-
+
mHeaderText = (TextView) findViewById(R.id.headerText);
mLockPatternView = (LockPatternView) findViewById(R.id.lockPattern);
mLockPatternView.setOnPatternListener(mChooseNewLockPatternListener);
- mLockPatternView.setTactileFeedbackEnabled(mLockPatternUtils.isTactileFeedbackEnabled());
+ mLockPatternView.setTactileFeedbackEnabled(
+ mChooseLockSettingsHelper.utils().isTactileFeedbackEnabled());
mFooterText = (TextView) findViewById(R.id.footerText);
@@ -364,35 +376,6 @@ public class ChooseLockPattern extends Activity implements View.OnClickListener{
return super.onKeyDown(keyCode, event);
}
- /**
- * Launch screen to confirm the existing lock pattern.
- * @see #onActivityResult(int, int, android.content.Intent)
- */
- protected void confirmPattern() {
- final Intent intent = new Intent();
- intent.setClassName("com.android.settings", "com.android.settings.ConfirmLockPattern");
- startActivityForResult(intent, 55);
- }
-
- /**
- * @see #confirmPattern
- */
- @Override
- protected void onActivityResult(int requestCode, int resultCode,
- Intent data) {
- super.onActivityResult(requestCode, resultCode, data);
-
- if (requestCode != 55) {
- return;
- }
-
- if (resultCode != Activity.RESULT_OK) {
- setResult(RESULT_FINISHED);
- finish();
- }
- updateStage(Stage.Introduction);
- }
-
@Override
protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
@@ -414,7 +397,7 @@ public class ChooseLockPattern extends Activity implements View.OnClickListener{
mUiStage = stage;
- // header text, footer text, visibility and
+ // header text, footer text, visibility and
// enabled state all known from the stage
if (stage == Stage.ChoiceTooShort) {
mHeaderText.setText(
@@ -486,16 +469,17 @@ public class ChooseLockPattern extends Activity implements View.OnClickListener{
}
private void saveChosenPatternAndFinish() {
- final boolean lockVirgin = !mLockPatternUtils.isPatternEverChosen();
+ LockPatternUtils utils = mChooseLockSettingsHelper.utils();
+ final boolean lockVirgin = !utils.isPatternEverChosen();
- mLockPatternUtils.saveLockPattern(mChosenPattern);
- mLockPatternUtils.setLockPatternEnabled(true);
+ utils.saveLockPattern(mChosenPattern);
+ utils.setLockPatternEnabled(true);
if (lockVirgin) {
- mLockPatternUtils.setVisiblePatternEnabled(true);
- mLockPatternUtils.setTactileFeedbackEnabled(false);
+ utils.setVisiblePatternEnabled(true);
+ utils.setTactileFeedbackEnabled(false);
}
-
+
setResult(RESULT_FINISHED);
finish();
}
diff --git a/src/com/android/settings/ChooseLockSettingsHelper.java b/src/com/android/settings/ChooseLockSettingsHelper.java
new file mode 100644
index 00000000000..ab2f8c0ed11
--- /dev/null
+++ b/src/com/android/settings/ChooseLockSettingsHelper.java
@@ -0,0 +1,85 @@
+/*
+ * Copyright (C) 2010 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.app.Activity;
+import android.content.Intent;
+
+import com.android.internal.widget.LockPatternUtils;
+
+public class ChooseLockSettingsHelper {
+ private LockPatternUtils mLockPatternUtils;
+ private Activity mActivity;
+
+ public ChooseLockSettingsHelper(Activity activity) {
+ mActivity = activity;
+ mLockPatternUtils = new LockPatternUtils(activity.getContentResolver());
+ }
+
+ public LockPatternUtils utils() {
+ return mLockPatternUtils;
+ }
+
+ /**
+ * If a pattern, password or PIN exists, prompt the user before allowing them to change it.
+ * @return true if one exists and we launched an activity to confirm it
+ * @see #onActivityResult(int, int, android.content.Intent)
+ */
+ protected boolean launchConfirmationActivity(int request) {
+ boolean launched = false;
+ switch (mLockPatternUtils.getPasswordMode()) {
+ case LockPatternUtils.MODE_PATTERN:
+ launched = confirmPattern(request);
+ break;
+ case LockPatternUtils.MODE_PIN:
+ case LockPatternUtils.MODE_PASSWORD:
+ launched = confirmPassword(request);
+ break;
+ }
+ return launched;
+ }
+
+ /**
+ * Launch screen to confirm the existing lock pattern.
+ * @see #onActivityResult(int, int, android.content.Intent)
+ * @return true if we launched an activity to confirm pattern
+ */
+ private boolean confirmPattern(int request) {
+ if (!mLockPatternUtils.isLockPatternEnabled() || !mLockPatternUtils.savedPatternExists()) {
+ return false;
+ }
+ final Intent intent = new Intent();
+ intent.setClassName("com.android.settings", "com.android.settings.ConfirmLockPattern");
+ mActivity.startActivityForResult(intent, request);
+ return true;
+ }
+
+ /**
+ * Launch screen to confirm the existing lock password.
+ * @see #onActivityResult(int, int, android.content.Intent)
+ * @return true if we launched an activity to confirm password
+ */
+ private boolean confirmPassword(int request) {
+ if (!mLockPatternUtils.isLockPasswordEnabled()) return false;
+ final Intent intent = new Intent();
+ intent.setClassName("com.android.settings", "com.android.settings.ConfirmLockPassword");
+ mActivity.startActivityForResult(intent, request);
+ return true;
+ }
+
+
+}
diff --git a/src/com/android/settings/ConfirmLockPassword.java b/src/com/android/settings/ConfirmLockPassword.java
new file mode 100644
index 00000000000..0cbc158830f
--- /dev/null
+++ b/src/com/android/settings/ConfirmLockPassword.java
@@ -0,0 +1,114 @@
+/*
+ * Copyright (C) 2010 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 com.android.internal.widget.LockPatternUtils;
+
+import android.app.Activity;
+import android.os.Bundle;
+import android.os.Handler;
+import android.text.Editable;
+import android.view.View;
+import android.view.View.OnClickListener;
+import android.widget.Button;
+import android.widget.TextView;
+
+public class ConfirmLockPassword extends Activity implements OnClickListener {
+ private static final long ERROR_MESSAGE_TIMEOUT = 3000;
+ private final int digitIds[] = new int[] { R.id.zero, R.id.one, R.id.two, R.id.three,
+ R.id.four, R.id.five, R.id.six, R.id.seven, R.id.eight, R.id.nine };
+ private TextView mPasswordTextView;
+ private LockPatternUtils mLockPatternUtils;
+ private TextView mHeaderText;
+ private Handler mHandler = new Handler();
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ mLockPatternUtils = new LockPatternUtils(getContentResolver());
+ initViews();
+ }
+
+ private void initViews() {
+ int mode = mLockPatternUtils.getPasswordMode();
+ if (LockPatternUtils.MODE_PIN == mode || LockPatternUtils.MODE_PASSWORD == mode) {
+ setContentView(R.layout.confirm_lock_pin);
+ for (int i = 0; i < digitIds.length; i++) {
+ Button button = (Button) findViewById(digitIds[i]);
+ button.setOnClickListener(this);
+ button.setText(Integer.toString(i));
+ }
+ findViewById(R.id.ok).setOnClickListener(this);
+ findViewById(R.id.cancel).setOnClickListener(this);
+ }
+ findViewById(R.id.backspace).setOnClickListener(this);
+ mPasswordTextView = (TextView) findViewById(R.id.pinDisplay);
+ mHeaderText = (TextView) findViewById(R.id.headerText);
+ mHeaderText.setText(R.string.lockpassword_confirm_your_password_header);
+ }
+
+ public void onClick(View v) {
+ switch (v.getId()) {
+ case R.id.ok:
+ {
+ final String pin = mPasswordTextView.getText().toString();
+ if (mLockPatternUtils.checkPassword(pin)) {
+ setResult(RESULT_OK);
+ finish();
+ } else {
+ showError(R.string.lockpattern_need_to_unlock_wrong);
+ }
+ }
+ break;
+
+ case R.id.backspace:
+ {
+ final Editable digits = mPasswordTextView.getEditableText();
+ final int len = digits.length();
+ if (len > 0) {
+ digits.delete(len-1, len);
+ }
+ }
+ break;
+
+ case R.id.cancel:
+ setResult(RESULT_CANCELED);
+ finish();
+ break;
+
+ default:
+ // Digits
+ for (int i = 0; i < digitIds.length; i++) {
+ if (v.getId() == digitIds[i]) {
+ mPasswordTextView.append(Integer.toString(i));
+ return;
+ }
+ }
+ break;
+ }
+ }
+
+ private void showError(int msg) {
+ mHeaderText.setText(msg);
+ mPasswordTextView.setText(null);
+ mHandler.postDelayed(new Runnable() {
+ public void run() {
+ mHeaderText.setText(R.string.lockpassword_confirm_your_password_header);
+ }
+ }, ERROR_MESSAGE_TIMEOUT);
+ }
+}
diff --git a/src/com/android/settings/SecuritySettings.java b/src/com/android/settings/SecuritySettings.java
index 0202f4cd073..fb284fd6f7b 100644
--- a/src/com/android/settings/SecuritySettings.java
+++ b/src/com/android/settings/SecuritySettings.java
@@ -25,7 +25,6 @@ import android.app.AlertDialog;
import android.app.Dialog;
import android.content.ContentQueryMap;
import android.content.ContentResolver;
-import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.database.Cursor;
@@ -35,10 +34,13 @@ import android.os.ICheckinService;
import android.os.ServiceManager;
import android.os.SystemProperties;
import android.preference.CheckBoxPreference;
+import android.preference.ListPreference;
import android.preference.Preference;
import android.preference.PreferenceActivity;
import android.preference.PreferenceCategory;
+import android.preference.PreferenceManager;
import android.preference.PreferenceScreen;
+import android.preference.Preference.OnPreferenceChangeListener;
import android.provider.Settings;
import android.security.Credentials;
import android.security.KeyStore;
@@ -56,11 +58,18 @@ import com.android.internal.widget.LockPatternUtils;
public class SecuritySettings extends PreferenceActivity {
// Lock Settings
+ private static final String PACKAGE = "com.android.settings";
+ private static final String LOCK_PATTERN_TUTORIAL = PACKAGE + ".ChooseLockPatternTutorial";
+ private static final String ICC_LOCK_SETTINGS = PACKAGE + ".IccLockSettings";
+ private static final String CHOOSE_LOCK_PATTERN = PACKAGE + ".ChooseLockPattern";
+ private static final String CHOOSE_LOCK_PIN = PACKAGE + ".ChooseLockPassword";
private static final String KEY_LOCK_ENABLED = "lockenabled";
private static final String KEY_VISIBLE_PATTERN = "visiblepattern";
private static final String KEY_TACTILE_FEEDBACK_ENABLED = "tactilefeedback";
- private static final int CONFIRM_PATTERN_THEN_DISABLE_AND_CLEAR_REQUEST_CODE = 55;
+ private static final String KEY_UNLOCK_METHOD = "unlock_method";
+ private static final int UPDATE_PASSWORD_REQUEST = 56;
+ private static final int CONFIRM_EXISTING_REQUEST = 57;
// Encrypted File Systems constants
private static final String PROPERTY_EFS_ENABLED = "persist.security.efs.enabled";
@@ -69,11 +78,8 @@ public class SecuritySettings extends PreferenceActivity {
private static final String PREFS_NAME = "location_prefs";
private static final String PREFS_USE_LOCATION = "use_location";
- private LockPatternUtils mLockPatternUtils;
- private CheckBoxPreference mLockEnabled;
private CheckBoxPreference mVisiblePattern;
private CheckBoxPreference mTactileFeedback;
- private Preference mChoosePattern;
private CheckBoxPreference mShowPassword;
@@ -97,6 +103,8 @@ public class SecuritySettings extends PreferenceActivity {
// This is necessary because the Network Location Provider can change settings
// if the user does not confirm enabling the provider.
private ContentQueryMap mContentQueryMap;
+ private ListPreference mUnlockMethod;
+ private ChooseLockSettingsHelper mChooseLockSettingsHelper;
private final class SettingsObserver implements Observer {
public void update(Observable o, Object arg) {
updateToggles();
@@ -108,7 +116,7 @@ public class SecuritySettings extends PreferenceActivity {
super.onCreate(savedInstanceState);
addPreferencesFromResource(R.xml.security_settings);
- mLockPatternUtils = new LockPatternUtils(getContentResolver());
+ mChooseLockSettingsHelper = new ChooseLockSettingsHelper(this);
createPreferenceHierarchy();
@@ -131,37 +139,22 @@ public class SecuritySettings extends PreferenceActivity {
// Root
PreferenceScreen root = this.getPreferenceScreen();
- // Inline preferences
- PreferenceCategory inlinePrefCat = new PreferenceCategory(this);
- inlinePrefCat.setTitle(R.string.lock_settings_title);
- root.addPreference(inlinePrefCat);
+ PreferenceManager pm = getPreferenceManager();
- // change pattern lock
- Intent intent = new Intent();
- intent.setClassName("com.android.settings",
- "com.android.settings.ChooseLockPatternTutorial");
- mChoosePattern = getPreferenceManager().createPreferenceScreen(this);
- mChoosePattern.setIntent(intent);
- inlinePrefCat.addPreference(mChoosePattern);
-
- // autolock toggle
- mLockEnabled = new LockEnabledPref(this);
- mLockEnabled.setTitle(R.string.lockpattern_settings_enable_title);
- mLockEnabled.setSummary(R.string.lockpattern_settings_enable_summary);
- mLockEnabled.setKey(KEY_LOCK_ENABLED);
- inlinePrefCat.addPreference(mLockEnabled);
+ mUnlockMethod = (ListPreference) pm.findPreference(KEY_UNLOCK_METHOD);
+ mUnlockMethod.setOnPreferenceChangeListener(new OnPreferenceChangeListener() {
+ public boolean onPreferenceChange(Preference preference, Object newValue) {
+ String value = (String) newValue;
+ handleUpdateUnlockMethod(value);
+ return false;
+ }
+ });
// visible pattern
- mVisiblePattern = new CheckBoxPreference(this);
- mVisiblePattern.setKey(KEY_VISIBLE_PATTERN);
- mVisiblePattern.setTitle(R.string.lockpattern_settings_enable_visible_pattern_title);
- inlinePrefCat.addPreference(mVisiblePattern);
+ mVisiblePattern = (CheckBoxPreference) pm.findPreference(KEY_VISIBLE_PATTERN);
// tactile feedback
- mTactileFeedback = new CheckBoxPreference(this);
- mTactileFeedback.setKey(KEY_TACTILE_FEEDBACK_ENABLED);
- mTactileFeedback.setTitle(R.string.lockpattern_settings_enable_tactile_feedback_title);
- inlinePrefCat.addPreference(mTactileFeedback);
+ mTactileFeedback = (CheckBoxPreference) pm.findPreference(KEY_TACTILE_FEEDBACK_ENABLED);
int activePhoneType = TelephonyManager.getDefault().getPhoneType();
@@ -172,10 +165,7 @@ public class SecuritySettings extends PreferenceActivity {
.createPreferenceScreen(this);
simLockPreferences.setTitle(R.string.sim_lock_settings_category);
// Intent to launch SIM lock settings
- intent = new Intent();
- intent.setClassName("com.android.settings", "com.android.settings.IccLockSettings");
- simLockPreferences.setIntent(intent);
-
+ simLockPreferences.setIntent(new Intent().setClassName(PACKAGE, ICC_LOCK_SETTINGS));
PreferenceCategory simLockCat = new PreferenceCategory(this);
simLockCat.setTitle(R.string.sim_lock_settings_title);
root.addPreference(simLockCat);
@@ -209,23 +199,41 @@ public class SecuritySettings extends PreferenceActivity {
return root;
}
+ protected void handleUpdateUnlockMethod(final String value) {
+ final LockPatternUtils lockPatternUtils = mChooseLockSettingsHelper.utils();
+ if ("none".equals(value)) {
+ mChooseLockSettingsHelper.launchConfirmationActivity(CONFIRM_EXISTING_REQUEST);
+ } else if ("password".equals(value) || "pin".equals(value)) {
+ final int minLength = 4; // TODO: get from policy store.
+ final int maxLength = 16;
+ final int mode = "password".equals(value)
+ ? LockPatternUtils.MODE_PASSWORD : LockPatternUtils.MODE_PIN;
+ Intent intent = new Intent().setClassName(PACKAGE, CHOOSE_LOCK_PIN);
+ intent.putExtra(LockPatternUtils.PASSWORD_TYPE_KEY, mode);
+ intent.putExtra(ChooseLockPassword.PASSWORD_MIN_KEY, minLength);
+ intent.putExtra(ChooseLockPassword.PASSWORD_MAX_KEY, maxLength);
+ startActivityForResult(intent, UPDATE_PASSWORD_REQUEST);
+ } else if ("pattern".equals(value)) {
+ boolean showTutorial = !lockPatternUtils.isPatternEverChosen();
+ Intent intent = new Intent();
+ intent.setClassName(PACKAGE, showTutorial ?
+ LOCK_PATTERN_TUTORIAL : CHOOSE_LOCK_PATTERN);
+ intent.putExtra("key_lock_method", value);
+ startActivityForResult(intent, UPDATE_PASSWORD_REQUEST);
+ }
+ }
+
@Override
protected void onResume() {
super.onResume();
- boolean patternExists = mLockPatternUtils.savedPatternExists();
- mLockEnabled.setEnabled(patternExists);
+ final LockPatternUtils lockPatternUtils = mChooseLockSettingsHelper.utils();
+ boolean patternExists = lockPatternUtils.savedPatternExists();
mVisiblePattern.setEnabled(patternExists);
mTactileFeedback.setEnabled(patternExists);
- mLockEnabled.setChecked(mLockPatternUtils.isLockPatternEnabled());
- mVisiblePattern.setChecked(mLockPatternUtils.isVisiblePatternEnabled());
- mTactileFeedback.setChecked(mLockPatternUtils.isTactileFeedbackEnabled());
-
- int chooseStringRes = mLockPatternUtils.savedPatternExists() ?
- R.string.lockpattern_settings_change_lock_pattern :
- R.string.lockpattern_settings_choose_lock_pattern;
- mChoosePattern.setTitle(chooseStringRes);
+ mVisiblePattern.setChecked(lockPatternUtils.isVisiblePatternEnabled());
+ mTactileFeedback.setChecked(lockPatternUtils.isTactileFeedbackEnabled());
mShowPassword.setChecked(Settings.System.getInt(getContentResolver(),
Settings.System.TEXT_SHOW_PASSWORD, 1) != 0);
@@ -238,12 +246,13 @@ public class SecuritySettings extends PreferenceActivity {
Preference preference) {
final String key = preference.getKey();
+ final LockPatternUtils lockPatternUtils = mChooseLockSettingsHelper.utils();
if (KEY_LOCK_ENABLED.equals(key)) {
- mLockPatternUtils.setLockPatternEnabled(isToggled(preference));
+ lockPatternUtils.setLockPatternEnabled(isToggled(preference));
} else if (KEY_VISIBLE_PATTERN.equals(key)) {
- mLockPatternUtils.setVisiblePatternEnabled(isToggled(preference));
+ lockPatternUtils.setVisiblePatternEnabled(isToggled(preference));
} else if (KEY_TACTILE_FEEDBACK_ENABLED.equals(key)) {
- mLockPatternUtils.setTactileFeedbackEnabled(isToggled(preference));
+ lockPatternUtils.setTactileFeedbackEnabled(isToggled(preference));
} else if (preference == mShowPassword) {
Settings.System.putInt(getContentResolver(), Settings.System.TEXT_SHOW_PASSWORD,
mShowPassword.isChecked() ? 1 : 0);
@@ -265,11 +274,6 @@ public class SecuritySettings extends PreferenceActivity {
return false;
}
- private void showPrivacyPolicy() {
- Intent intent = new Intent("android.settings.TERMS");
- startActivity(intent);
- }
-
/*
* Creates toggles for each available location provider
*/
@@ -291,36 +295,6 @@ public class SecuritySettings extends PreferenceActivity {
return ((CheckBoxPreference) pref).isChecked();
}
- /**
- * For the user to disable keyguard, we first make them verify their
- * existing pattern.
- */
- private class LockEnabledPref extends CheckBoxPreference {
-
- public LockEnabledPref(Context context) {
- super(context);
- }
-
- @Override
- protected void onClick() {
- if (mLockPatternUtils.savedPatternExists() && isChecked()) {
- confirmPatternThenDisableAndClear();
- } else {
- super.onClick();
- }
- }
- }
-
- /**
- * Launch screen to confirm the existing lock pattern.
- * @see #onActivityResult(int, int, android.content.Intent)
- */
- private void confirmPatternThenDisableAndClear() {
- final Intent intent = new Intent();
- intent.setClassName("com.android.settings", "com.android.settings.ConfirmLockPattern");
- startActivityForResult(intent, CONFIRM_PATTERN_THEN_DISABLE_AND_CLEAR_REQUEST_CODE);
- }
-
/**
* @see #confirmPatternThenDisableAndClear
*/
@@ -330,10 +304,11 @@ public class SecuritySettings extends PreferenceActivity {
final boolean resultOk = resultCode == Activity.RESULT_OK;
- if ((requestCode == CONFIRM_PATTERN_THEN_DISABLE_AND_CLEAR_REQUEST_CODE)
- && resultOk) {
- mLockPatternUtils.setLockPatternEnabled(false);
- mLockPatternUtils.saveLockPattern(null);
+ LockPatternUtils lockPatternUtils = mChooseLockSettingsHelper.utils();
+ if ((requestCode == CONFIRM_EXISTING_REQUEST) && resultOk) {
+ lockPatternUtils.saveLockPassword(null);
+ lockPatternUtils.setLockPatternEnabled(false);
+ lockPatternUtils.saveLockPattern(null);
}
}
| |