Fix 2332563: Add password-lock support to lockscreen

This commit is contained in:
Jim Miller
2009-12-22 19:03:28 -08:00
parent 6d40ee33f5
commit 69aa4a953f
8 changed files with 627 additions and 462 deletions

View File

@@ -38,8 +38,9 @@ import java.util.List;
public class LockPatternUtils {
private static final String TAG = "LockPatternUtils";
private static final String LOCK_PATTERN_FILE = "/system/gesture.key";
private static final String LOCK_PASSWORD_FILE = "/system/password.key";
/**
* The maximum number of incorrect attempts before the user is prevented
@@ -69,21 +70,33 @@ public class LockPatternUtils {
*/
public static final int MIN_LOCK_PATTERN_SIZE = 4;
/**
* Type of password being stored.
* pattern = pattern screen
* pin = digit-only password
* password = alphanumeric password
*/
public static final int MODE_PATTERN = 0;
public static final int MODE_PIN = 1;
public static final int MODE_PASSWORD = 2;
/**
* The minimum number of dots the user must include in a wrong pattern
* attempt for it to be counted against the counts that affect
* {@link #FAILED_ATTEMPTS_BEFORE_TIMEOUT} and {@link #FAILED_ATTEMPTS_BEFORE_RESET}
*/
public static final int MIN_PATTERN_REGISTER_FAIL = 3;
public static final int MIN_PATTERN_REGISTER_FAIL = 3;
private final static String LOCKOUT_PERMANENT_KEY = "lockscreen.lockedoutpermanently";
private final static String LOCKOUT_ATTEMPT_DEADLINE = "lockscreen.lockoutattemptdeadline";
private final static String PATTERN_EVER_CHOSEN = "lockscreen.patterneverchosen";
private final static String PATTERN_EVER_CHOSEN_KEY = "lockscreen.patterneverchosen";
public final static String PASSWORD_TYPE_KEY = "lockscreen.password_type";
private final ContentResolver mContentResolver;
private static String sLockPatternFilename;
private static String sLockPasswordFilename;
/**
* @param contentResolver Used to look up and save settings.
*/
@@ -91,16 +104,19 @@ public class LockPatternUtils {
mContentResolver = contentResolver;
// Initialize the location of gesture lock file
if (sLockPatternFilename == null) {
sLockPatternFilename = android.os.Environment.getDataDirectory()
sLockPatternFilename = android.os.Environment.getDataDirectory()
.getAbsolutePath() + LOCK_PATTERN_FILE;
sLockPasswordFilename = android.os.Environment.getDataDirectory()
.getAbsolutePath() + LOCK_PASSWORD_FILE;
}
}
/**
* Check to see if a pattern matches the saved pattern. If no pattern exists,
* always returns true.
* @param pattern The pattern to check.
* @return Whether the pattern matchees the stored one.
* @return Whether the pattern matches the stored one.
*/
public boolean checkPattern(List<LockPatternView.Cell> pattern) {
try {
@@ -122,13 +138,40 @@ public class LockPatternUtils {
}
/**
* Check to see if the user has stored a lock pattern.
* @return Whether a saved pattern exists.
* Check to see if a password matches the saved password. If no password exists,
* always returns true.
* @param password The password to check.
* @return Whether the password matches the stored one.
*/
public boolean savedPatternExists() {
public boolean checkPassword(String password) {
try {
// Read all the bytes from the file
RandomAccessFile raf = new RandomAccessFile(sLockPasswordFilename, "r");
final byte[] stored = new byte[(int) raf.length()];
int got = raf.read(stored, 0, stored.length);
raf.close();
if (got <= 0) {
return true;
}
// Compare the hash from the file with the entered password's hash
return Arrays.equals(stored, LockPatternUtils.passwordToHash(password));
} catch (FileNotFoundException fnfe) {
return true;
} catch (IOException ioe) {
return true;
}
}
/**
* Checks to see if the given file exists and contains any data. Returns true if it does,
* false otherwise.
* @param filename
* @return true if file exists and is non-empty.
*/
private boolean nonEmptyFileExists(String filename) {
try {
// Check if we can read a byte from the file
RandomAccessFile raf = new RandomAccessFile(sLockPatternFilename, "r");
RandomAccessFile raf = new RandomAccessFile(filename, "r");
byte first = raf.readByte();
raf.close();
return true;
@@ -139,6 +182,22 @@ public class LockPatternUtils {
}
}
/**
* Check to see if the user has stored a lock pattern.
* @return Whether a saved pattern exists.
*/
public boolean savedPatternExists() {
return nonEmptyFileExists(sLockPatternFilename);
}
/**
* Check to see if the user has stored a lock pattern.
* @return Whether a saved pattern exists.
*/
public boolean savedPasswordExists() {
return nonEmptyFileExists(sLockPasswordFilename);
}
/**
* Return true if the user has ever chosen a pattern. This is true even if the pattern is
* currently cleared.
@@ -146,7 +205,7 @@ public class LockPatternUtils {
* @return True if the user has ever chosen a pattern.
*/
public boolean isPatternEverChosen() {
return getBoolean(PATTERN_EVER_CHOSEN);
return getBoolean(PATTERN_EVER_CHOSEN_KEY);
}
/**
@@ -166,7 +225,8 @@ public class LockPatternUtils {
raf.write(hash, 0, hash.length);
}
raf.close();
setBoolean(PATTERN_EVER_CHOSEN, true);
setBoolean(PATTERN_EVER_CHOSEN_KEY, true);
setLong(PASSWORD_TYPE_KEY, MODE_PATTERN);
} catch (FileNotFoundException fnfe) {
// Cant do much, unless we want to fail over to using the settings provider
Log.e(TAG, "Unable to save lock pattern to " + sLockPatternFilename);
@@ -176,6 +236,38 @@ public class LockPatternUtils {
}
}
/**
* Save a lock password.
* @param password The password to save
*/
public void saveLockPassword(String password) {
// Compute the hash
boolean numericHint = password != null ? TextUtils.isDigitsOnly(password) : false;
final byte[] hash = LockPatternUtils.passwordToHash(password);
try {
// Write the hash to file
RandomAccessFile raf = new RandomAccessFile(sLockPasswordFilename, "rw");
// Truncate the file if pattern is null, to clear the lock
if (password == null) {
raf.setLength(0);
} else {
raf.write(hash, 0, hash.length);
}
raf.close();
setLong(PASSWORD_TYPE_KEY, numericHint ? MODE_PIN : MODE_PASSWORD);
} catch (FileNotFoundException fnfe) {
// Cant do much, unless we want to fail over to using the settings provider
Log.e(TAG, "Unable to save lock pattern to " + sLockPasswordFilename);
} catch (IOException ioe) {
// Cant do much
Log.e(TAG, "Unable to save lock pattern to " + sLockPasswordFilename);
}
}
public int getPasswordMode() {
return (int) getLong(PASSWORD_TYPE_KEY, MODE_PATTERN);
}
/**
* Deserialize a pattern.
* @param string The pattern serialized with {@link #patternToString}
@@ -210,7 +302,7 @@ public class LockPatternUtils {
}
return new String(res);
}
/*
* Generate an SHA-1 hash for the pattern. Not the most secure, but it is
* at least a second level of protection. First level is that the file
@@ -218,11 +310,11 @@ public class LockPatternUtils {
* @param pattern the gesture pattern.
* @return the hash of the pattern in a byte array.
*/
static byte[] patternToHash(List<LockPatternView.Cell> pattern) {
private static byte[] patternToHash(List<LockPatternView.Cell> pattern) {
if (pattern == null) {
return null;
}
final int patternSize = pattern.size();
byte[] res = new byte[patternSize];
for (int i = 0; i < patternSize; i++) {
@@ -238,11 +330,55 @@ public class LockPatternUtils {
}
}
/*
* Generate a hash for the given password. To avoid brute force attacks, we use a salted hash.
* Not the most secure, but it is at least a second level of protection. First level is that
* the file is in a location only readable by the system process.
* @param password the gesture pattern.
* @return the hash of the pattern in a byte array.
*/
public static byte[] passwordToHash(String password) {
if (password == null) {
return null;
}
String algo = null;
byte[] hashed = null;
try {
long salt = 0x2374868151054924L; // TODO: make this unique to device
byte[] saltedPassword = (password + Long.toString(salt)).getBytes();
byte[] sha1 = MessageDigest.getInstance(algo = "SHA-1").digest(saltedPassword);
byte[] md5 = MessageDigest.getInstance(algo = "MD5").digest(saltedPassword);
hashed = (toHex(sha1) + toHex(md5)).getBytes();
} catch (NoSuchAlgorithmException e) {
Log.w(TAG, "Failed to encode string because of missing algorithm: " + algo);
}
return hashed;
}
private static String toHex(byte[] ary) {
final String hex = "0123456789ABCDEF";
String ret = "";
for (int i = 0; i < ary.length; i++) {
ret += hex.charAt((ary[i] >> 4) & 0xf);
ret += hex.charAt(ary[i] & 0xf);
}
return ret;
}
/**
* @return Whether the lock password is enabled.
*/
public boolean isLockPasswordEnabled() {
long mode = getLong(PASSWORD_TYPE_KEY, 0);
return savedPasswordExists() && (mode == MODE_PASSWORD || mode == MODE_PIN);
}
/**
* @return Whether the lock pattern is enabled.
*/
public boolean isLockPatternEnabled() {
return getBoolean(Settings.System.LOCK_PATTERN_ENABLED);
return getBoolean(Settings.System.LOCK_PATTERN_ENABLED)
&& getLong(PASSWORD_TYPE_KEY, MODE_PATTERN) == MODE_PATTERN;
}
/**
@@ -361,5 +497,10 @@ public class LockPatternUtils {
android.provider.Settings.System.putLong(mContentResolver, systemSettingKey, value);
}
public boolean isSecure() {
long mode = getPasswordMode();
boolean secure = mode == MODE_PATTERN && isLockPatternEnabled() && savedPatternExists()
|| (mode == MODE_PIN || mode == MODE_PASSWORD) && savedPasswordExists();
return secure;
}
}

View File

@@ -0,0 +1,120 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
**
** Copyright 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.
*/
-->
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:background="@android:color/background_dark">
<!-- displays dots as user enters pin -->
<LinearLayout android:id="@+id/pinDisplayGroup"
android:orientation="horizontal"
android:layout_centerInParent="true"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:addStatesFromChildren="true"
android:gravity="center_vertical"
android:baselineAligned="false"
android:paddingRight="0dip"
android:layout_marginRight="30dip"
android:layout_marginLeft="30dip"
android:layout_marginTop="6dip"
android:background="@android:drawable/edit_text">
<EditText android:id="@+id/pinDisplay"
android:layout_width="0dip"
android:layout_weight="1"
android:layout_height="fill_parent"
android:maxLines="1"
android:background="@null"
android:textSize="32sp"
android:inputType="textPassword"
/>
<ImageButton android:id="@+id/backspace"
android:src="@android:drawable/ic_input_delete"
android:layout_width="wrap_content"
android:layout_height="fill_parent"
android:layout_marginTop="2dip"
android:layout_marginRight="2dip"
android:layout_marginBottom="2dip"
android:gravity="center"
/>
</LinearLayout>
<!-- header text ('Enter Pin Code') -->
<TextView android:id="@+id/headerText"
android:layout_above="@id/pinDisplayGroup"
android:layout_centerHorizontal="true"
android:layout_marginBottom="30dip"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textSize="24sp"
/>
<LinearLayout
android:orientation="horizontal"
android:layout_alignParentBottom="true"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="8dip"
android:layout_marginLeft="8dip"
android:layout_marginRight="8dip">
<Button android:id="@+id/ok"
android:text="@android:string/ok"
android:layout_alignParentBottom="true"
android:layout_width="0dip"
android:layout_height="wrap_content"
android:layout_weight="1.0"
android:layout_marginBottom="8dip"
android:layout_marginRight="8dip"
android:textSize="18sp"
/>
<Button android:id="@+id/emergencyCall"
android:text="@android:string/lockscreen_emergency_call"
android:layout_alignParentBottom="true"
android:layout_centerHorizontal="true"
android:layout_width="0dip"
android:layout_height="wrap_content"
android:layout_weight="1.0"
android:layout_marginBottom="8dip"
android:layout_marginLeft="8dip"
android:textSize="18sp"
android:drawableLeft="@drawable/ic_emergency"
android:drawablePadding="8dip"
/>
</LinearLayout>
<!-- Not currently visible on this screen -->
<TextView
android:id="@+id/carrier"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentTop="true"
android:layout_marginTop="6dip"
android:layout_alignParentRight="true"
android:layout_marginRight="8dip"
android:textAppearance="?android:attr/textAppearanceMedium"
android:visibility="gone"
/>
</RelativeLayout>

View File

@@ -0,0 +1,158 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
**
** Copyright 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.
*/
-->
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical"
android:background="#70000000"
android:gravity="center_horizontal">
<LinearLayout android:id="@+id/topDisplayGroup"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<RelativeLayout
android:layout_width="fill_parent"
android:layout_height="wrap_content">
<com.android.internal.widget.DigitalClock android:id="@+id/time"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="6dip"
android:layout_marginLeft="6dip"
android:layout_alignParentTop="true"
android:layout_alignParentLeft="true">
<TextView android:id="@+id/timeDisplay"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:gravity="bottom"
android:singleLine="true"
android:ellipsize="none"
android:textSize="56sp"
android:textAppearance="?android:attr/textAppearanceMedium"
android:shadowColor="#C0000000"
android:shadowDx="0"
android:shadowDy="0"
android:shadowRadius="3.0"
android:layout_marginBottom="6dip"
/>
<TextView android:id="@+id/am_pm"
android:layout_width="wrap_content"
android:layout_height="fill_parent"
android:gravity="bottom"
android:singleLine="true"
android:ellipsize="none"
android:textSize="18sp"
android:layout_marginLeft="4dip"
android:textAppearance="?android:attr/textAppearanceMedium"
android:shadowColor="#C0000000"
android:shadowDx="0"
android:shadowDy="0"
android:shadowRadius="3.0"
/>
</com.android.internal.widget.DigitalClock>
<TextView android:id="@+id/carrier"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentTop="true"
android:layout_marginTop="6dip"
android:layout_alignParentRight="true"
android:layout_marginRight="8dip"
android:textAppearance="?android:attr/textAppearanceMedium"
/>
</RelativeLayout>
<!-- password entry -->
<LinearLayout
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:layout_marginRight="6dip"
android:layout_marginLeft="6dip"
android:gravity="center_vertical"
android:hint="@android:string/keyguard_password_enter_password_code"
android:background="@android:drawable/edit_text">
<!-- displays dots as user enters pin -->
<TextView android:id="@+id/pinDisplay"
android:layout_width="0dip"
android:layout_height="wrap_content"
android:layout_weight="1"
android:maxLines="1"
android:textAppearance="?android:attr/textAppearanceLargeInverse"
android:textStyle="bold"
android:inputType="textPassword"
/>
<ImageButton android:id="@+id/backspace"
android:src="@android:drawable/ic_input_delete"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginRight="-3dip"
android:layout_marginBottom="-3dip"
/>
</LinearLayout>
</LinearLayout>
<include
android:id="@+id/keyPad"
layout="@android:layout/twelve_key_entry"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_below="@id/topDisplayGroup"
android:layout_marginTop="10dip"
/>
<!-- spacer below keypad -->
<View
android:id="@+id/spacerBottom"
android:layout_width="fill_parent"
android:layout_height="1dip"
android:layout_marginTop="6dip"
android:layout_above="@id/emergencyCall"
android:background="@android:drawable/divider_horizontal_dark"
/>
<!-- The emergency button should take the rest of the space and be centered vertically -->
<LinearLayout
android:layout_width="fill_parent"
android:layout_height="0dip"
android:layout_weight="1"
android:gravity="center"
android:orientation="vertical">
<!-- emergency call button -->
<Button
android:id="@+id/emergencyCall"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:drawableLeft="@android:drawable/ic_emergency"
android:drawablePadding="8dip"
android:text="@android:string/lockscreen_emergency_call"
/>
</LinearLayout>
</LinearLayout>

View File

@@ -1,138 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
**
** Copyright 2009, 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.
*/
-->
<!-- This is the general lock screen which shows information about the
state of the device, as well as instructions on how to get past it
depending on the state of the device. It is the same for landscape
and portrait.-->
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="@+id/root"
>
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#70000000"
>
<TextView
android:id="@+id/carrier"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentTop="true"
android:layout_centerHorizontal="true"
android:layout_marginTop="20dip"
android:textAppearance="?android:attr/textAppearanceMedium"
android:textColor="?android:attr/textColorSecondary"
/>
<TextView
android:id="@+id/time"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="@id/carrier"
android:layout_centerHorizontal="true"
android:layout_marginTop="25dip"
android:textAppearance="?android:attr/textAppearanceLarge"
android:textSize="55sp"
/>
<TextView
android:id="@+id/date"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="@id/time"
android:layout_centerHorizontal="true"
android:layout_marginTop="-12dip"
android:textAppearance="?android:attr/textAppearanceMedium"
/>
<View
android:id="@+id/divider"
android:layout_width="match_parent"
android:layout_height="1dip"
android:layout_marginTop="10dip"
android:layout_below="@id/date"
android:background="@android:drawable/divider_horizontal_dark"
/>
<TextView
android:id="@+id/status1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="@id/divider"
android:layout_centerHorizontal="true"
android:layout_marginTop="6dip"
android:textAppearance="?android:attr/textAppearanceMedium"
android:textColor="?android:attr/textColorSecondary"
android:drawablePadding="4dip"
/>
<TextView
android:id="@+id/status2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="@id/status1"
android:layout_centerHorizontal="true"
android:layout_marginTop="6dip"
android:textAppearance="?android:attr/textAppearanceMedium"
android:textColor="?android:attr/textColorSecondary"
android:drawablePadding="4dip"
/>
<TextView
android:id="@+id/screenLocked"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="@id/status2"
android:layout_centerHorizontal="true"
android:textAppearance="?android:attr/textAppearanceMedium"
android:textColor="?android:attr/textColorSecondary"
android:gravity="center"
android:layout_marginTop="12dip"
/>
<!-- By having the rotary selector hang from the top, we get a layout more
robust for different screen sizes. On hvga, the widget should be flush with the bottom.-->
<com.android.internal.widget.RotarySelector
android:id="@+id/rotary"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_centerHorizontal="true"
android:layout_alignParentTop="true"
android:layout_marginTop="286dip"
/>
<!-- emergency call button shown when sim is missing or PUKd -->
<Button
android:id="@+id/emergencyCallButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="@id/screenLocked"
android:layout_centerHorizontal="true"
android:layout_marginTop="24dip"
android:drawableLeft="@drawable/ic_emergency"
android:drawablePadding="8dip"
/>
</RelativeLayout>
</FrameLayout>

View File

@@ -1,145 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
**
** Copyright 2009, 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.
*/
-->
<!-- This is the general lock screen which shows information about the
state of the device, as well as instructions on how to get past it
depending on the state of the device.-->
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:rotaryunlock="http://schemas.android.com/apk/res/com.android.rotaryunlock"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="@+id/root"
>
<LinearLayout
android:orientation="horizontal"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#70000000"
>
<!-- left side -->
<RelativeLayout
android:orientation="vertical"
android:layout_width="0dip"
android:layout_height="match_parent"
android:layout_weight="1.0"
android:gravity="center_horizontal"
>
<TextView
android:id="@+id/carrier"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentTop="true"
android:layout_centerHorizontal="true"
android:layout_marginTop="20dip"
android:textAppearance="?android:attr/textAppearanceMedium"
android:textColor="?android:attr/textColorSecondary"
/>
<TextView
android:id="@+id/time"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="@id/carrier"
android:layout_centerHorizontal="true"
android:layout_marginTop="25dip"
android:textAppearance="?android:attr/textAppearanceLarge"
android:textSize="55sp"
/>
<TextView
android:id="@+id/date"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="@id/time"
android:layout_centerHorizontal="true"
android:layout_marginTop="-12dip"
android:textAppearance="?android:attr/textAppearanceMedium"
/>
<View
android:id="@+id/divider"
android:layout_width="match_parent"
android:layout_height="1dip"
android:layout_marginTop="10dip"
android:layout_below="@id/date"
android:background="@android:drawable/divider_horizontal_dark"
/>
<TextView
android:id="@+id/status1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="@id/divider"
android:layout_centerHorizontal="true"
android:layout_marginTop="6dip"
android:textAppearance="?android:attr/textAppearanceMedium"
android:textColor="?android:attr/textColorSecondary"
android:drawablePadding="4dip"
/>
<TextView
android:id="@+id/status2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="@id/status1"
android:layout_centerHorizontal="true"
android:layout_marginTop="6dip"
android:textAppearance="?android:attr/textAppearanceMedium"
android:textColor="?android:attr/textColorSecondary"
android:drawablePadding="4dip"
/>
<TextView
android:id="@+id/screenLocked"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="@id/status2"
android:layout_centerHorizontal="true"
android:textAppearance="?android:attr/textAppearanceMedium"
android:textColor="?android:attr/textColorSecondary"
android:gravity="center"
android:layout_marginTop="12dip"
/>
<!-- emergency call button shown when sim is missing or PUKd -->
<Button
android:id="@+id/emergencyCallButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="@id/screenLocked"
android:layout_centerHorizontal="true"
android:layout_marginTop="24dip"
android:drawableLeft="@drawable/ic_emergency"
android:drawablePadding="8dip"
/>
</RelativeLayout>
<!-- right side -->
<com.android.internal.widget.RotarySelector
android:id="@+id/rotary"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:orientation="vertical"
/>
</LinearLayout>
</FrameLayout>

View File

@@ -68,170 +68,14 @@
</LinearLayout>
<!-- Keypad section -->
<LinearLayout android:id="@+id/keyPad"
android:layout_width="match_parent"
<include
android:id="@+id/keyPad"
layout="@android:layout/twelve_key_entry"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_below="@id/topDisplayGroup"
android:layout_marginTop="10dip"
android:orientation="vertical">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="64dip"
android:layout_marginLeft="2dip"
android:layout_marginRight="2dip"
android:orientation="horizontal">
<Button android:id="@+id/one"
android:layout_width="0sp"
android:layout_height="match_parent"
android:layout_weight="1"
android:layout_marginLeft="2dip"
android:layout_marginRight="2dip"
android:textAppearance="?android:attr/textAppearanceLarge"
android:textStyle="bold"
/>
<Button android:id="@+id/two"
android:layout_width="0sp"
android:layout_height="match_parent"
android:layout_weight="1"
android:layout_marginLeft="2dip"
android:layout_marginRight="2dip"
android:textAppearance="?android:attr/textAppearanceLarge"
android:textStyle="bold"
/>
<Button android:id="@+id/three"
android:layout_width="0sp"
android:layout_height="match_parent"
android:layout_weight="1"
android:layout_marginLeft="2dip"
android:layout_marginRight="2dip"
android:textAppearance="?android:attr/textAppearanceLarge"
android:textStyle="bold"
/>
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="64dip"
android:layout_marginLeft="2dip"
android:layout_marginRight="2dip"
android:orientation="horizontal">
<Button android:id="@+id/four"
android:layout_width="0sp"
android:layout_height="match_parent"
android:layout_weight="1"
android:layout_marginLeft="2dip"
android:layout_marginRight="2dip"
android:textAppearance="?android:attr/textAppearanceLarge"
android:textStyle="bold"
/>
<Button android:id="@+id/five"
android:layout_width="0sp"
android:layout_height="match_parent"
android:layout_weight="1"
android:layout_marginLeft="2dip"
android:layout_marginRight="2dip"
android:textAppearance="?android:attr/textAppearanceLarge"
android:textStyle="bold"
/>
<Button android:id="@+id/six"
android:layout_width="0sp"
android:layout_height="match_parent"
android:layout_weight="1"
android:layout_marginLeft="2dip"
android:layout_marginRight="2dip"
android:textAppearance="?android:attr/textAppearanceLarge"
android:textStyle="bold"
/>
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="64dip"
android:layout_marginLeft="2dip"
android:layout_marginRight="2dip"
android:orientation="horizontal">
<Button android:id="@+id/seven"
android:layout_width="0sp"
android:layout_height="match_parent"
android:layout_weight="1"
android:layout_marginLeft="2dip"
android:layout_marginRight="2dip"
android:textAppearance="?android:attr/textAppearanceLarge"
android:textStyle="bold"
/>
<Button android:id="@+id/eight"
android:layout_width="0sp"
android:layout_height="match_parent"
android:layout_weight="1"
android:layout_marginLeft="2dip"
android:layout_marginRight="2dip"
android:textAppearance="?android:attr/textAppearanceLarge"
android:textStyle="bold"
/>
<Button android:id="@+id/nine"
android:layout_width="0sp"
android:layout_height="match_parent"
android:layout_weight="1"
android:layout_marginLeft="2dip"
android:layout_marginRight="2dip"
android:textAppearance="?android:attr/textAppearanceLarge"
android:textStyle="bold"
/>
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="64dip"
android:layout_marginLeft="2dip"
android:layout_marginRight="2dip"
android:orientation="horizontal">
<Button android:id="@+id/ok"
android:layout_width="0sp"
android:layout_height="match_parent"
android:layout_weight="1"
android:layout_marginLeft="2dip"
android:layout_marginRight="2dip"
android:textAppearance="?android:attr/textAppearanceMedium"
android:textStyle="bold"
android:text="@android:string/ok"
/>
<Button android:id="@+id/zero"
android:layout_width="0sp"
android:layout_height="match_parent"
android:layout_weight="1"
android:layout_marginLeft="2dip"
android:layout_marginRight="2dip"
android:textAppearance="?android:attr/textAppearanceLarge"
android:textStyle="bold"
/>
<Button android:id="@+id/cancel"
android:layout_width="0sp"
android:layout_height="match_parent"
android:layout_weight="1"
android:layout_marginLeft="2dip"
android:layout_marginRight="2dip"
android:textAppearance="?android:attr/textAppearanceMedium"
android:textStyle="bold"
android:text="@android:string/cancel"
/>
</LinearLayout>
<!-- end keypad -->
</LinearLayout>
/>
<!-- spacer below keypad -->
<View

View File

@@ -0,0 +1,181 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
/*
** Copyright 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.
*/
-->
<!-- This is not a standalone element it can be included into apps that need 12-key input -->
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical">
<LinearLayout
android:layout_width="fill_parent"
android:layout_height="64dip"
android:layout_marginLeft="2dip"
android:layout_marginRight="2dip"
android:orientation="horizontal">
<Button android:id="@+id/one"
android:layout_width="0sp"
android:layout_height="fill_parent"
android:layout_weight="1"
android:layout_marginLeft="2dip"
android:layout_marginRight="2dip"
android:textAppearance="?android:attr/textAppearanceLarge"
android:textStyle="bold"
/>
<Button android:id="@+id/two"
android:layout_width="0sp"
android:layout_height="fill_parent"
android:layout_weight="1"
android:layout_marginLeft="2dip"
android:layout_marginRight="2dip"
android:textAppearance="?android:attr/textAppearanceLarge"
android:textStyle="bold"
/>
<Button android:id="@+id/three"
android:layout_width="0sp"
android:layout_height="fill_parent"
android:layout_weight="1"
android:layout_marginLeft="2dip"
android:layout_marginRight="2dip"
android:textAppearance="?android:attr/textAppearanceLarge"
android:textStyle="bold"
/>
</LinearLayout>
<LinearLayout
android:layout_width="fill_parent"
android:layout_height="64dip"
android:layout_marginLeft="2dip"
android:layout_marginRight="2dip"
android:orientation="horizontal">
<Button android:id="@+id/four"
android:layout_width="0sp"
android:layout_height="fill_parent"
android:layout_weight="1"
android:layout_marginLeft="2dip"
android:layout_marginRight="2dip"
android:textAppearance="?android:attr/textAppearanceLarge"
android:textStyle="bold"
/>
<Button android:id="@+id/five"
android:layout_width="0sp"
android:layout_height="fill_parent"
android:layout_weight="1"
android:layout_marginLeft="2dip"
android:layout_marginRight="2dip"
android:textAppearance="?android:attr/textAppearanceLarge"
android:textStyle="bold"
/>
<Button android:id="@+id/six"
android:layout_width="0sp"
android:layout_height="fill_parent"
android:layout_weight="1"
android:layout_marginLeft="2dip"
android:layout_marginRight="2dip"
android:textAppearance="?android:attr/textAppearanceLarge"
android:textStyle="bold"
/>
</LinearLayout>
<LinearLayout
android:layout_width="fill_parent"
android:layout_height="64dip"
android:layout_marginLeft="2dip"
android:layout_marginRight="2dip"
android:orientation="horizontal">
<Button android:id="@+id/seven"
android:layout_width="0sp"
android:layout_height="fill_parent"
android:layout_weight="1"
android:layout_marginLeft="2dip"
android:layout_marginRight="2dip"
android:textAppearance="?android:attr/textAppearanceLarge"
android:textStyle="bold"
/>
<Button android:id="@+id/eight"
android:layout_width="0sp"
android:layout_height="fill_parent"
android:layout_weight="1"
android:layout_marginLeft="2dip"
android:layout_marginRight="2dip"
android:textAppearance="?android:attr/textAppearanceLarge"
android:textStyle="bold"
/>
<Button android:id="@+id/nine"
android:layout_width="0sp"
android:layout_height="fill_parent"
android:layout_weight="1"
android:layout_marginLeft="2dip"
android:layout_marginRight="2dip"
android:textAppearance="?android:attr/textAppearanceLarge"
android:textStyle="bold"
/>
</LinearLayout>
<LinearLayout
android:layout_width="fill_parent"
android:layout_height="64dip"
android:layout_marginLeft="2dip"
android:layout_marginRight="2dip"
android:orientation="horizontal">
<Button android:id="@+id/ok"
android:layout_width="0sp"
android:layout_height="fill_parent"
android:layout_weight="1"
android:layout_marginLeft="2dip"
android:layout_marginRight="2dip"
android:textAppearance="?android:attr/textAppearanceMedium"
android:textStyle="bold"
android:text="@android:string/ok"
/>
<Button android:id="@+id/zero"
android:layout_width="0sp"
android:layout_height="fill_parent"
android:layout_weight="1"
android:layout_marginLeft="2dip"
android:layout_marginRight="2dip"
android:textAppearance="?android:attr/textAppearanceLarge"
android:textStyle="bold"
/>
<Button android:id="@+id/cancel"
android:layout_width="0sp"
android:layout_height="fill_parent"
android:layout_weight="1"
android:layout_marginLeft="2dip"
android:layout_marginRight="2dip"
android:textAppearance="?android:attr/textAppearanceMedium"
android:textStyle="bold"
android:text="@android:string/cancel"
/>
</LinearLayout>
</LinearLayout>

View File

@@ -1325,10 +1325,14 @@
<!-- Attbution of a contact status update, when the time of update is known -->
<string name="contact_status_update_attribution_with_date"><xliff:g id="date" example="3 hours ago">%1$s</xliff:g> via <xliff:g id="source" example="Google Talk">%2$s</xliff:g></string>
<!-- Instructions telling the user to enter their pin to unlock the keyguard.
<!-- Instructions telling the user to enter their SIM PIN to unlock the keyguard.
Displayed in one line in a large font. -->
<string name="keyguard_password_enter_pin_code">Enter PIN code</string>
<!-- Instructions telling the user to enter their PIN password to unlock the keyguard.
Displayed in one line in a large font. -->
<string name="keyguard_password_enter_password_code">Enter password to unlock</string>
<!-- Instructions telling the user that they entered the wrong pin while trying
to unlock the keyguard. Displayed in one line in a large font. -->
<string name="keyguard_password_wrong_pin_code">Incorrect PIN code!</string>