Merge "Power widget visual updates"
diff --git a/res/layout/app_percentage_item.xml b/res/layout/app_percentage_item.xml
index c134949..0c9f742 100644
--- a/res/layout/app_percentage_item.xml
+++ b/res/layout/app_percentage_item.xml
@@ -58,7 +58,6 @@
     <TextView
         android:id="@android:id/summary"
         android:layout_columnSpan="2"
-        android:layout_gravity="fill_horizontal"
         android:layout_marginTop="4dip"
         android:visibility="gone"
         android:textAppearance="?android:attr/textAppearanceSmall" />
diff --git a/res/layout/data_usage_chart.xml b/res/layout/data_usage_chart.xml
index 2e0cbdd..a1a7ec4 100644
--- a/res/layout/data_usage_chart.xml
+++ b/res/layout/data_usage_chart.xml
@@ -20,10 +20,13 @@
     android:id="@+id/chart"
     android:layout_width="match_parent"
     android:layout_height="@dimen/data_usage_chart_height"
-    android:paddingLeft="16dip"
-    android:paddingRight="16dip"
+    android:layout_marginLeft="-16dip"
+    android:layout_marginRight="-16dip"
+    android:layout_marginBottom="-32dip"
+    android:paddingLeft="24dip"
+    android:paddingRight="24dip"
     android:paddingTop="16dip"
-    android:paddingBottom="16dip"
+    android:paddingBottom="48dip"
     settings:optimalWidth="@dimen/data_usage_chart_optimalWidth"
     settings:optimalWidthWeight="0.4">
 
diff --git a/res/layout/data_usage_header.xml b/res/layout/data_usage_header.xml
index b27d88f..9dcb456 100644
--- a/res/layout/data_usage_header.xml
+++ b/res/layout/data_usage_header.xml
@@ -17,6 +17,8 @@
 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
     android:layout_width="match_parent"
     android:layout_height="wrap_content"
+    android:paddingLeft="@*android:dimen/preference_fragment_padding_side"
+    android:paddingRight="@*android:dimen/preference_fragment_padding_side"
     android:orientation="vertical"
     android:clipChildren="false"
     android:clipToPadding="false">
diff --git a/res/layout/data_usage_item.xml b/res/layout/data_usage_item.xml
new file mode 100644
index 0000000..7808173
--- /dev/null
+++ b/res/layout/data_usage_item.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2011 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.
+-->
+
+<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="match_parent"
+    android:layout_height="wrap_content"
+    android:paddingLeft="@*android:dimen/preference_fragment_padding_side"
+    android:paddingRight="@*android:dimen/preference_fragment_padding_side">
+
+    <include layout="@layout/app_percentage_item" />
+
+</FrameLayout>
diff --git a/res/values/arrays.xml b/res/values/arrays.xml
index 3cd367f..1c6bc24 100644
--- a/res/values/arrays.xml
+++ b/res/values/arrays.xml
@@ -358,34 +358,34 @@
 
     <!-- Wi-Fi settings. Presented as a list dialog to the user to choose the Wi-Fi sleep policy. -->
     <string-array name="wifi_sleep_policy_entries">
-        <!-- Wi-Fi should go to sleep when the screen turns off. -->
-        <item>When screen turns off (uses more mobile data)</item>
-        <!-- When plugged in, never go to sleep.  When on battery, go to sleep when screen turns off. -->
-        <item>Never when plugged in</item>
-        <!-- Never go to sleep. -->
-        <item>Never (uses more battery power)</item>
+        <!-- Always keep Wi-Fi on when screen turns off. -->
+        <item>Always</item>
+        <!-- Keep Wi-Fi on when screen turns off and plugged in.  When on battery, go to sleep when screen turns off. -->
+        <item>Only when plugged in</item>
+        <!-- Do not keep Wi-Fi on when screen turns off. -->
+        <item>Never (increases data usage)</item>
     </string-array>
 
     <!-- Wi-Fi settings. Presented as a list dialog to the user to choose the Wi-Fi sleep policy. Used when
          the device is Wi-Fi-only. [CHAR LIMIT=30] -->
     <string-array name="wifi_sleep_policy_entries_wifi_only">
-        <!-- Wi-Fi should go to sleep when the screen turns off, for Wi-Fi-only devices. -->
-        <item>When screen turns off</item>
-        <!-- When plugged in, never go to sleep.  When on battery, go to sleep when screen turns off. -->
-        <item>Never when plugged in</item>
-        <!-- Never go to sleep. -->
-        <item>Never (uses more battery power)</item>
+        <!-- Always keep Wi-Fi on when screen turns off. -->
+        <item>Always</item>
+        <!-- Keep Wi-Fi on when screen turns off and plugged in.  When on battery, go to sleep when screen turns off. -->
+        <item>Only when plugged in</item>
+        <!-- Do not keep Wi-Fi on when screen turns off, for Wi-Fi-only devices, no other data connection -->
+        <item>Never</item>
     </string-array>
 
     <!-- Match with wifi_sleep_policy_entries and the values of the settings in Settings class. --> <skip />
     <!-- Do not translate. -->
     <string-array name="wifi_sleep_policy_values">
         <!-- Do not translate. -->
-        <item>0</item>
+        <item>2</item>
         <!-- Do not translate. -->
         <item>1</item>
         <!-- Do not translate. -->
-        <item>2</item>
+        <item>0</item>
     </string-array>
 
     <!-- Wi-Fi settings. Presented as a list dialog to the user to choose the Wi-Fi frequency band. -->
diff --git a/res/values/dimens.xml b/res/values/dimens.xml
index ffdec52..9649ed3 100755
--- a/res/values/dimens.xml
+++ b/res/values/dimens.xml
@@ -28,7 +28,7 @@
     <dimen name="description_margin_top">26dip</dimen>
     <dimen name="description_margin_sides">40dip</dimen>
 
-    <dimen name="data_usage_chart_height">220dip</dimen>
+    <dimen name="data_usage_chart_height">252dip</dimen>
     <dimen name="data_usage_chart_optimalWidth">440dip</dimen>
 
     <dimen name="volume_seekbar_side_margin">8dip</dimen>
diff --git a/res/values/strings.xml b/res/values/strings.xml
index 3b70830..1874107 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -777,22 +777,27 @@
     <!-- Title for preference that disables unlock security [CHAR LIMIT=22] -->
     <string name="unlock_set_unlock_none_title">Slide</string>
     <!-- Summary for preference that disables unlock security [CHAR LIMIT=45]-->
-    <string name="unlock_set_unlock_none_summary"></string>
+    <string name="unlock_set_unlock_none_summary">No security</string>
+
+    <!-- Title for preference that guides the user through a weak biometric lock [CHAR LIMIT=22] -->
+    <string name="unlock_set_unlock_biometric_weak_title">FacePass</string>
+    <!-- Summary for preference that disables unlock security [CHAR LIMIT=45]-->
+    <string name="unlock_set_unlock_biometric_weak_summary">Low security, experimental</string>
 
     <!-- Title for preference that guides the user through creating an unlock pattern [CHAR LIMIT=22]-->
     <string name="unlock_set_unlock_pattern_title">Pattern</string>
     <!-- Summary for preference that guides the user through creating an unlock pattern [CHAR LIMIT=45] -->
-    <string name="unlock_set_unlock_pattern_summary"></string>
+    <string name="unlock_set_unlock_pattern_summary">Medium security</string>
 
     <!-- Title for preference that guides the user through creating an unlock PIN (Personal Identification Number) [CHAR LIMIT=22] -->
     <string name="unlock_set_unlock_pin_title">PIN</string>
     <!-- Summary for preference that guides the user through creating an unlock PIN (Personal Identification Number) [CHAR LIMIT=45] -->
-    <string name="unlock_set_unlock_pin_summary"></string>
+    <string name="unlock_set_unlock_pin_summary">Medium to high security</string>
 
     <!-- Title for preference that guides the user through creating an unlock password [CHAR LIMIT=22] -->
     <string name="unlock_set_unlock_password_title">Password</string>
     <!-- Title for preference that guides the user through creating an unlock password [CHAR LIMIT=45] -->
-    <string name="unlock_set_unlock_password_summary"></string>
+    <string name="unlock_set_unlock_password_summary">High security</string>
 
     <!-- Summary for preference that has been disabled by because of the DevicePolicyAdmin, or because device encryption is enabled, or because there are credentials in the credential storage [CHAR LIMIT=50] -->
     <string name="unlock_set_unlock_disabled_summary">Disabled by administrator, encryption policy, or credential storage</string>
@@ -801,6 +806,8 @@
     <string name="unlock_set_unlock_mode_off">None</string>
     <!-- Summary for "Configure lockscreen" when security is disabled [CHAR LIMIT=45] -->
     <string name="unlock_set_unlock_mode_none">Slide</string>
+    <!-- Summary for "Configure lockscreen" when security biometric weak is enabled [CHAR LIMIT=45] -->
+    <string name="unlock_set_unlock_mode_biometric_weak">FacePass</string>
     <!-- Summary for "Configure lockscreen" when security pattern is enabled [CHAR LIMIT=45] -->
     <string name="unlock_set_unlock_mode_pattern">Secured with pattern</string>
     <!-- Summary for "Configure lockscreen" when security PIN is enabled [CHAR LIMIT=45] -->
@@ -1143,12 +1150,8 @@
     <string name="wifi_enable_watchdog_service">Avoid poor connections</string>
     <!-- Checkbox summary for option to toggle wifi watchdog service -->
     <string name="wifi_enable_watchdog_service_summary">Don\'t use a Wi-Fi network unless it has a decent internet connection</string>
-    <!-- Setting title for setting the wifi sleep policy -->
-    <string name="wifi_setting_sleep_policy_title">Wi-Fi disconnect policy</string>
-    <!-- Setting summary for setting the wifi sleep policy -->
-    <string name="wifi_setting_sleep_policy_summary">Specify when to switch from Wi-Fi to mobile data</string>
-    <!-- Setting summary for setting the wifi sleep policy for wifi-only devices [CHAR LIMIT=100] -->
-    <string name="wifi_setting_sleep_policy_summary_wifi_only">Specify when to disconnect from Wi-Fi</string>
+    <!-- Setting title for setting the wifi sleep policy. Do we keep Wi-Fi active when the screen turns off? -->
+    <string name="wifi_setting_sleep_policy_title">Keep Wi-Fi during sleep</string>
     <!-- Generic error message when the sleep policy could not be set. -->
     <string name="wifi_setting_sleep_policy_error">There was a problem changing the setting</string>
     <!-- Action bar text message to manually add a wifi network [CHAR LIMIT=20]-->
diff --git a/res/xml/appwidget_info.xml b/res/xml/appwidget_info.xml
index 7a89cec..dc90d4e 100644
--- a/res/xml/appwidget_info.xml
+++ b/res/xml/appwidget_info.xml
@@ -15,8 +15,8 @@
 -->
 
 <appwidget-provider xmlns:android="http://schemas.android.com/apk/res/android"
-    android:minWidth="288dip"
-    android:minHeight="48dip"
+    android:minWidth="260dip"
+    android:minHeight="40dip"
     android:previewImage="@drawable/preview"
     android:initialLayout="@layout/widget"
     >
diff --git a/res/xml/security_settings_biometric_weak.xml b/res/xml/security_settings_biometric_weak.xml
new file mode 100644
index 0000000..42af769
--- /dev/null
+++ b/res/xml/security_settings_biometric_weak.xml
@@ -0,0 +1,45 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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.
+-->
+
+<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android">
+
+    <PreferenceCategory
+        android:key="security_category"
+        android:title="@string/lock_settings_title">
+
+        <PreferenceScreen
+            android:key="unlock_set_or_change"
+            android:title="@string/unlock_set_unlock_launch_picker_title"
+            android:summary="@string/unlock_set_unlock_mode_biometric_weak"
+            android:persistent="false"/>
+
+        <ListPreference
+            android:key="lock_after_timeout"
+            android:title="@string/lock_after_timeout"
+            android:summary="@string/lock_after_timeout_summary"
+            android:entries="@array/lock_after_timeout_entries"
+            android:entryValues="@array/lock_after_timeout_values"
+            android:persistent="false"/>
+
+        <PreferenceScreen
+            android:fragment="com.android.settings.OwnerInfoSettings"
+            android:key="owner_info_settings"
+            android:title="@string/owner_info_settings_title"
+            android:summary="@string/owner_info_settings_summary"/>
+
+    </PreferenceCategory>
+
+</PreferenceScreen>
diff --git a/res/xml/security_settings_picker.xml b/res/xml/security_settings_picker.xml
index 04258df..c220214 100644
--- a/res/xml/security_settings_picker.xml
+++ b/res/xml/security_settings_picker.xml
@@ -33,6 +33,12 @@
             android:persistent="false"/>
 
         <PreferenceScreen
+            android:key="unlock_set_biometric_weak"
+            android:title="@string/unlock_set_unlock_biometric_weak_title"
+            android:summary="@string/unlock_set_unlock_biometric_weak_summary"
+            android:persistent="false"/>
+
+        <PreferenceScreen
             android:key="unlock_set_pattern"
             android:title="@string/unlock_set_unlock_pattern_title"
             android:summary="@string/unlock_set_unlock_pattern_summary"
diff --git a/res/xml/sound_settings.xml b/res/xml/sound_settings.xml
index a13d6fc..da33d6a 100644
--- a/res/xml/sound_settings.xml
+++ b/res/xml/sound_settings.xml
@@ -64,11 +64,6 @@
             android:persistent="false"
             android:ringtoneType="notification" />
 
-    <CheckBoxPreference
-            android:key="notification_pulse"
-            android:title="@string/notification_pulse_title"
-            android:persistent="false" />
-
     <PreferenceCategory
             android:title="@string/sound_category_feedback_title"/>
 
@@ -94,6 +89,11 @@
             android:title="@string/haptic_feedback_enable_title"
             android:defaultValue="true" />
 
+    <CheckBoxPreference
+            android:key="notification_pulse"
+            android:title="@string/notification_pulse_title"
+            android:persistent="false" />
+
     <ListPreference
             android:key="emergency_tone"
             android:title="@string/emergency_tone_title"
diff --git a/res/xml/wifi_advanced_settings.xml b/res/xml/wifi_advanced_settings.xml
index c9cc884..d500ff2 100644
--- a/res/xml/wifi_advanced_settings.xml
+++ b/res/xml/wifi_advanced_settings.xml
@@ -27,7 +27,6 @@
     <ListPreference
             android:key="sleep_policy"
             android:title="@string/wifi_setting_sleep_policy_title"
-            android:summary="@string/wifi_setting_sleep_policy_summary"
             android:persistent="false"
             android:entries="@array/wifi_sleep_policy_entries"
             android:entryValues="@array/wifi_sleep_policy_values"
diff --git a/src/com/android/settings/ChooseLockGeneric.java b/src/com/android/settings/ChooseLockGeneric.java
index b1bc856..5e44df3 100644
--- a/src/com/android/settings/ChooseLockGeneric.java
+++ b/src/com/android/settings/ChooseLockGeneric.java
@@ -17,10 +17,12 @@
 package com.android.settings;
 
 import android.app.Activity;
+import android.app.PendingIntent;
 import android.app.admin.DevicePolicyManager;
 import android.content.Context;
 import android.content.Intent;
 import android.os.Bundle;
+import android.os.SystemProperties;
 import android.preference.Preference;
 import android.preference.PreferenceActivity;
 import android.preference.PreferenceCategory;
@@ -43,6 +45,7 @@
         private static final int MIN_PASSWORD_LENGTH = 4;
         private static final String KEY_UNLOCK_SET_OFF = "unlock_set_off";
         private static final String KEY_UNLOCK_SET_NONE = "unlock_set_none";
+        private static final String KEY_UNLOCK_SET_BIOMETRIC_WEAK = "unlock_set_biometric_weak";
         private static final String KEY_UNLOCK_SET_PIN = "unlock_set_pin";
         private static final String KEY_UNLOCK_SET_PASSWORD = "unlock_set_password";
         private static final String KEY_UNLOCK_SET_PATTERN = "unlock_set_pattern";
@@ -91,7 +94,10 @@
             } else if (KEY_UNLOCK_SET_NONE.equals(key)) {
                 updateUnlockMethodAndFinish(
                         DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED, false);
-            } else if (KEY_UNLOCK_SET_PATTERN.equals(key)) {
+            } else if (KEY_UNLOCK_SET_BIOMETRIC_WEAK.equals(key)) {
+                updateUnlockMethodAndFinish(
+                        DevicePolicyManager.PASSWORD_QUALITY_BIOMETRIC_WEAK, false);
+            }else if (KEY_UNLOCK_SET_PATTERN.equals(key)) {
                 updateUnlockMethodAndFinish(
                         DevicePolicyManager.PASSWORD_QUALITY_SOMETHING, false);
             } else if (KEY_UNLOCK_SET_PIN.equals(key)) {
@@ -126,11 +132,11 @@
         }
 
         private void updatePreferencesOrFinish() {
-            int quality = getActivity().getIntent()
-                    .getIntExtra(LockPatternUtils.PASSWORD_TYPE_KEY, -1);
+            Intent intent = getActivity().getIntent();
+            int quality = intent.getIntExtra(LockPatternUtils.PASSWORD_TYPE_KEY, -1);
             if (quality == -1) {
                 // If caller didn't specify password quality, show UI and allow the user to choose.
-                quality = getActivity().getIntent().getIntExtra(MINIMUM_QUALITY_KEY, -1);
+                quality = intent.getIntExtra(MINIMUM_QUALITY_KEY, -1);
                 quality = upgradeQuality(quality);
                 final PreferenceScreen prefScreen = getPreferenceScreen();
                 if (prefScreen != null) {
@@ -197,15 +203,23 @@
                     getPreferenceScreen().findPreference("security_picker_category");
             final PreferenceCategory cat = (PreferenceCategory) picker;
             final int preferenceCount = cat.getPreferenceCount();
-            for (int i = 0; i < preferenceCount; i++) {
+            final boolean onlyShowFallback = getActivity().getIntent()
+                    .getBooleanExtra(LockPatternUtils.LOCKSCREEN_BIOMETRIC_WEAK_FALLBACK, false);
+            final boolean weakBiometricAvailable = isBiometricSensorAvailable(
+                    DevicePolicyManager.PASSWORD_QUALITY_BIOMETRIC_WEAK);
+            for (int i = preferenceCount-1; i >= 0; --i) {
                 Preference pref = cat.getPreference(i);
                 if (pref instanceof PreferenceScreen) {
                     final String key = ((PreferenceScreen) pref).getKey();
                     boolean enabled = true;
+                    boolean visible = true;
                     if (KEY_UNLOCK_SET_OFF.equals(key)) {
                         enabled = quality <= DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED;
                     } else if (KEY_UNLOCK_SET_NONE.equals(key)) {
                         enabled = quality <= DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED;
+                    } else if (KEY_UNLOCK_SET_BIOMETRIC_WEAK.equals(key)) {
+                        enabled = quality <= DevicePolicyManager.PASSWORD_QUALITY_BIOMETRIC_WEAK;
+                        visible = weakBiometricAvailable; // If not available, then don't show it.
                     } else if (KEY_UNLOCK_SET_PATTERN.equals(key)) {
                         enabled = quality <= DevicePolicyManager.PASSWORD_QUALITY_SOMETHING;
                     } else if (KEY_UNLOCK_SET_PIN.equals(key)) {
@@ -213,7 +227,9 @@
                     } else if (KEY_UNLOCK_SET_PASSWORD.equals(key)) {
                         enabled = quality <= DevicePolicyManager.PASSWORD_QUALITY_COMPLEX;
                     }
-                    if (!enabled) {
+                    if (!visible || (onlyShowFallback && !allowedForFallback(key))) {
+                        cat.removePreference(pref);
+                    } else if (!enabled) {
                         pref.setSummary(R.string.unlock_set_unlock_disabled_summary);
                         pref.setEnabled(false);
                     }
@@ -222,6 +238,34 @@
         }
 
         /**
+         * Check whether the key is allowed for fallback (e.g. bio sensor). Returns true if it's
+         * supported as a backup.
+         *
+         * @param key
+         * @return true if allowed
+         */
+        private boolean allowedForFallback(String key) {
+            return KEY_UNLOCK_SET_PATTERN.equals(key) || KEY_UNLOCK_SET_PIN.equals(key);
+        }
+
+        private boolean isBiometricSensorAvailable(int quality) {
+            return SystemProperties.getBoolean("ro.lockscreen.facelock_enabled", false);
+        }
+
+        private Intent getBiometricSensorIntent(int quality) {
+            Intent fallBackIntent = new Intent().setClass(getActivity(), ChooseLockGeneric.class);
+            fallBackIntent.putExtra(LockPatternUtils.LOCKSCREEN_BIOMETRIC_WEAK_FALLBACK, true);
+            fallBackIntent.putExtra(CONFIRM_CREDENTIALS, false);
+            fallBackIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+
+            Intent intent = new Intent().setClassName("com.android.facelock",
+                    "com.android.facelock.SetupFaceLock");
+            PendingIntent pending = PendingIntent.getActivity(getActivity(), 0, fallBackIntent, 0);
+            intent.putExtra("PendingIntent", pending);
+            return intent;
+        }
+
+        /**
          * Invokes an activity to change the user's pattern, password or PIN based on given quality
          * and minimum quality specified by DevicePolicyManager. If quality is
          * {@link DevicePolicyManager#PASSWORD_QUALITY_UNSPECIFIED}, password is cleared.
@@ -236,6 +280,9 @@
                 throw new IllegalStateException("Tried to update password without confirming it");
             }
 
+            final boolean isFallback = getActivity().getIntent()
+                .getBooleanExtra(LockPatternUtils.LOCKSCREEN_BIOMETRIC_WEAK_FALLBACK, false);
+
             quality = upgradeQuality(quality);
             if (quality >= DevicePolicyManager.PASSWORD_QUALITY_NUMERIC) {
                 int minLength = mDPM.getPasswordMinimumLength(null);
@@ -249,6 +296,8 @@
                 intent.putExtra(ChooseLockPassword.PASSWORD_MAX_KEY, maxLength);
                 intent.putExtra(CONFIRM_CREDENTIALS, false);
                 intent.addFlags(Intent.FLAG_ACTIVITY_FORWARD_RESULT);
+                intent.putExtra(LockPatternUtils.LOCKSCREEN_BIOMETRIC_WEAK_FALLBACK,
+                        isFallback);
                 startActivity(intent);
             } else if (quality == DevicePolicyManager.PASSWORD_QUALITY_SOMETHING) {
                 boolean showTutorial = !mChooseLockSettingsHelper.utils().isPatternEverChosen();
@@ -259,6 +308,11 @@
                 intent.addFlags(Intent.FLAG_ACTIVITY_FORWARD_RESULT);
                 intent.putExtra("key_lock_method", "pattern");
                 intent.putExtra(CONFIRM_CREDENTIALS, false);
+                intent.putExtra(LockPatternUtils.LOCKSCREEN_BIOMETRIC_WEAK_FALLBACK,
+                        isFallback);
+                startActivity(intent);
+            } else if (quality == DevicePolicyManager.PASSWORD_QUALITY_BIOMETRIC_WEAK) {
+                Intent intent = getBiometricSensorIntent(quality);
                 startActivity(intent);
             } else if (quality == DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED) {
                 mChooseLockSettingsHelper.utils().clearLock();
diff --git a/src/com/android/settings/ChooseLockPassword.java b/src/com/android/settings/ChooseLockPassword.java
index 96255eb..c201d15 100644
--- a/src/com/android/settings/ChooseLockPassword.java
+++ b/src/com/android/settings/ChooseLockPassword.java
@@ -368,7 +368,9 @@
             } else if (mUiStage == Stage.NeedToConfirm) {
                 if (mFirstPin.equals(pin)) {
                     mLockPatternUtils.clearLock();
-                    mLockPatternUtils.saveLockPassword(pin, mRequestedQuality);
+                    final boolean isFallback = getActivity().getIntent().getBooleanExtra(
+                            LockPatternUtils.LOCKSCREEN_BIOMETRIC_WEAK_FALLBACK, false);
+                    mLockPatternUtils.saveLockPassword(pin, mRequestedQuality, isFallback);
                     getActivity().finish();
                 } else {
                     updateStage(Stage.ConfirmWrong);
diff --git a/src/com/android/settings/ChooseLockPattern.java b/src/com/android/settings/ChooseLockPattern.java
index 9a34f2f..180eee1 100644
--- a/src/com/android/settings/ChooseLockPattern.java
+++ b/src/com/android/settings/ChooseLockPattern.java
@@ -507,7 +507,9 @@
             LockPatternUtils utils = mChooseLockSettingsHelper.utils();
             final boolean lockVirgin = !utils.isPatternEverChosen();
 
-            utils.saveLockPattern(mChosenPattern);
+            final boolean isFallback = getActivity().getIntent()
+                .getBooleanExtra(LockPatternUtils.LOCKSCREEN_BIOMETRIC_WEAK_FALLBACK, false);
+            utils.saveLockPattern(mChosenPattern, isFallback);
             utils.setLockPatternEnabled(true);
 
             if (lockVirgin) {
diff --git a/src/com/android/settings/DataUsageSummary.java b/src/com/android/settings/DataUsageSummary.java
index 87ce772..417c525 100644
--- a/src/com/android/settings/DataUsageSummary.java
+++ b/src/com/android/settings/DataUsageSummary.java
@@ -64,7 +64,9 @@
 import android.content.pm.PackageManager.NameNotFoundException;
 import android.content.res.Resources;
 import android.graphics.Color;
+import android.graphics.drawable.ColorDrawable;
 import android.graphics.drawable.Drawable;
+import android.graphics.drawable.InsetDrawable;
 import android.net.ConnectivityManager;
 import android.net.INetworkPolicyManager;
 import android.net.INetworkStatsService;
@@ -120,6 +122,8 @@
 import android.widget.TextView;
 
 import com.android.internal.telephony.Phone;
+import com.android.settings.drawable.InsetBoundsDrawable;
+import com.android.settings.drawable.DrawableWrapper;
 import com.android.settings.net.NetworkPolicyEditor;
 import com.android.settings.net.SummaryForAllUidLoader;
 import com.android.settings.widget.ChartDataUsageView;
@@ -275,7 +279,12 @@
         mListView = (ListView) view.findViewById(android.R.id.list);
 
         // adjust padding around tabwidget as needed
-        prepareCustomPreferencesList(container, view, mListView);
+        prepareCustomPreferencesList(container, view, mListView, true);
+
+        // inset selector and divider drawables
+        final int insetSide = view.getResources().getDimensionPixelOffset(
+                com.android.internal.R.dimen.preference_fragment_padding_side);
+        insetListViewDrawables(mListView, insetSide);
 
         mTabHost.setup();
         mTabHost.setOnTabChangedListener(mTabListener);
@@ -1391,7 +1400,7 @@
         public View getView(int position, View convertView, ViewGroup parent) {
             if (convertView == null) {
                 convertView = LayoutInflater.from(parent.getContext()).inflate(
-                        R.layout.app_percentage_item, parent, false);
+                        R.layout.data_usage_item, parent, false);
             }
 
             final Context context = parent.getContext();
@@ -1913,6 +1922,24 @@
     }
 
     /**
+     * Inset both selector and divider {@link Drawable} on the given
+     * {@link ListView} by the requested dimensions.
+     */
+    private static void insetListViewDrawables(ListView view, int insetSide) {
+        final Drawable selector = view.getSelector();
+        final Drawable divider = view.getDivider();
+
+        // fully unregister these drawables so callbacks can be maintained after
+        // wrapping below.
+        final Drawable stub = new ColorDrawable(Color.TRANSPARENT);
+        view.setSelector(stub);
+        view.setDivider(stub);
+
+        view.setSelector(new InsetBoundsDrawable(selector, insetSide));
+        view.setDivider(new InsetBoundsDrawable(divider, insetSide));
+    }
+
+    /**
      * Set {@link android.R.id#title} for a preference view inflated with
      * {@link #inflatePreference(LayoutInflater, ViewGroup, View)}.
      */
diff --git a/src/com/android/settings/SecuritySettings.java b/src/com/android/settings/SecuritySettings.java
index 3813ecd..5b8035d 100644
--- a/src/com/android/settings/SecuritySettings.java
+++ b/src/com/android/settings/SecuritySettings.java
@@ -106,6 +106,8 @@
             } else {
                 resid = R.xml.security_settings_chooser;
             }
+        } else if (mLockPatternUtils.usingBiometricWeak()) {
+            resid = R.xml.security_settings_biometric_weak;
         } else {
             switch (mLockPatternUtils.getKeyguardStoredPasswordQuality()) {
                 case DevicePolicyManager.PASSWORD_QUALITY_SOMETHING:
@@ -120,6 +122,7 @@
                     resid = R.xml.security_settings_password;
                     break;
             }
+            // TODO: enable facepass options
         }
         addPreferencesFromResource(resid);
 
diff --git a/src/com/android/settings/Utils.java b/src/com/android/settings/Utils.java
index 2d2b654..20a34a3 100644
--- a/src/com/android/settings/Utils.java
+++ b/src/com/android/settings/Utils.java
@@ -377,7 +377,8 @@
      * when outside scrollbars are requested. Usually used to display
      * {@link ListView} and {@link TabWidget} with correct padding.
      */
-    public static void prepareCustomPreferencesList(ViewGroup parent, View child, ListView list) {
+    public static void prepareCustomPreferencesList(
+            ViewGroup parent, View child, ListView list, boolean ignoreSidePadding) {
         final boolean movePadding = list.getScrollBarStyle() == View.SCROLLBARS_OUTSIDE_OVERLAY;
         if (movePadding && parent instanceof PreferenceFrameLayout) {
             ((PreferenceFrameLayout.LayoutParams) child.getLayoutParams()).removeBorders = true;
@@ -387,7 +388,9 @@
                     com.android.internal.R.dimen.preference_fragment_padding_side);
             final int paddingBottom = res.getDimensionPixelSize(
                     com.android.internal.R.dimen.preference_fragment_padding_bottom);
-            list.setPadding(paddingSide, 0, paddingSide, paddingBottom);
+
+            final int effectivePaddingSide = ignoreSidePadding ? 0 : paddingBottom;
+            list.setPadding(effectivePaddingSide, 0, effectivePaddingSide, paddingBottom);
         }
     }
 }
diff --git a/src/com/android/settings/applications/ManageApplications.java b/src/com/android/settings/applications/ManageApplications.java
index d4abfa8..4157e8a 100644
--- a/src/com/android/settings/applications/ManageApplications.java
+++ b/src/com/android/settings/applications/ManageApplications.java
@@ -646,7 +646,7 @@
         tabHost.setOnTabChangedListener(this);
 
         // adjust padding around tabwidget as needed
-        prepareCustomPreferencesList(container, mTabHost, mListView);
+        prepareCustomPreferencesList(container, mTabHost, mListView, false);
 
         return mTabHost;
     }
diff --git a/src/com/android/settings/drawable/DrawableWrapper.java b/src/com/android/settings/drawable/DrawableWrapper.java
new file mode 100644
index 0000000..0ac4f7c
--- /dev/null
+++ b/src/com/android/settings/drawable/DrawableWrapper.java
@@ -0,0 +1,162 @@
+/*
+ * Copyright (C) 2011 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.drawable;
+
+import android.graphics.Canvas;
+import android.graphics.ColorFilter;
+import android.graphics.Rect;
+import android.graphics.Region;
+import android.graphics.drawable.Drawable;
+import android.view.View;
+
+import com.android.internal.util.Preconditions;
+
+/**
+ * Base wrapper that delegates all calls to another {@link Drawable}. The
+ * wrapped {@link Drawable} <em>must</em> be fully released from any
+ * {@link View} before wrapping, otherwise internal {@link Drawable.Callback}
+ * may be dropped.
+ */
+public class DrawableWrapper extends Drawable implements Drawable.Callback {
+    private final Drawable mDrawable;
+
+    public DrawableWrapper(Drawable drawable) {
+        mDrawable = Preconditions.checkNotNull(drawable);
+        mDrawable.setCallback(this);
+    }
+
+    @Override
+    public void draw(Canvas canvas) {
+        mDrawable.draw(canvas);
+    }
+
+    @Override
+    public void setBounds(int left, int top, int right, int bottom) {
+        super.setBounds(left, top, right, bottom);
+        mDrawable.setBounds(left, top, right, bottom);
+    }
+
+    @Override
+    public void setChangingConfigurations(int configs) {
+        mDrawable.setChangingConfigurations(configs);
+    }
+
+    @Override
+    public int getChangingConfigurations() {
+        return mDrawable.getChangingConfigurations();
+    }
+
+    @Override
+    public void setDither(boolean dither) {
+        mDrawable.setDither(dither);
+    }
+
+    @Override
+    public void setFilterBitmap(boolean filter) {
+        mDrawable.setFilterBitmap(filter);
+    }
+
+    @Override
+    public void setAlpha(int alpha) {
+        mDrawable.setAlpha(alpha);
+    }
+
+    @Override
+    public void setColorFilter(ColorFilter cf) {
+        mDrawable.setColorFilter(cf);
+    }
+
+    @Override
+    public boolean isStateful() {
+        return mDrawable.isStateful();
+    }
+
+    @Override
+    public boolean setState(final int[] stateSet) {
+        return mDrawable.setState(stateSet);
+    }
+
+    @Override
+    public int[] getState() {
+        return mDrawable.getState();
+    }
+
+    @Override
+    public void jumpToCurrentState() {
+        mDrawable.jumpToCurrentState();
+    }
+
+    @Override
+    public Drawable getCurrent() {
+        return mDrawable.getCurrent();
+    }
+
+    @Override
+    public boolean setVisible(boolean visible, boolean restart) {
+        return super.setVisible(visible, restart) || mDrawable.setVisible(visible, restart);
+    }
+
+    @Override
+    public int getOpacity() {
+        return mDrawable.getOpacity();
+    }
+
+    @Override
+    public Region getTransparentRegion() {
+        return mDrawable.getTransparentRegion();
+    }
+
+    @Override
+    public int getIntrinsicWidth() {
+        return mDrawable.getIntrinsicWidth();
+    }
+
+    @Override
+    public int getIntrinsicHeight() {
+        return mDrawable.getIntrinsicHeight();
+    }
+
+    @Override
+    public int getMinimumWidth() {
+        return mDrawable.getMinimumWidth();
+    }
+
+    @Override
+    public int getMinimumHeight() {
+        return mDrawable.getMinimumHeight();
+    }
+
+    @Override
+    public boolean getPadding(Rect padding) {
+        return mDrawable.getPadding(padding);
+    }
+
+    /** {@inheritDoc} */
+    public void invalidateDrawable(Drawable who) {
+        invalidateSelf();
+    }
+
+    /** {@inheritDoc} */
+    public void scheduleDrawable(Drawable who, Runnable what, long when) {
+        scheduleSelf(what, when);
+    }
+
+    /** {@inheritDoc} */
+    public void unscheduleDrawable(Drawable who, Runnable what) {
+        unscheduleSelf(what);
+    }
+}
diff --git a/src/com/android/settings/drawable/InsetBoundsDrawable.java b/src/com/android/settings/drawable/InsetBoundsDrawable.java
new file mode 100644
index 0000000..50ef9f3
--- /dev/null
+++ b/src/com/android/settings/drawable/InsetBoundsDrawable.java
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2011 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.drawable;
+
+import android.graphics.drawable.Drawable;
+
+/**
+ * Wrapper around another {@link Drawable} that insets requested bounds by a
+ * specific amount.
+ */
+public class InsetBoundsDrawable extends DrawableWrapper {
+    private final int mInsetBoundsSides;
+
+    public InsetBoundsDrawable(Drawable drawable, int insetBoundsSides) {
+        super(drawable);
+        mInsetBoundsSides = insetBoundsSides;
+    }
+
+    @Override
+    public void setBounds(int left, int top, int right, int bottom) {
+        super.setBounds(left + mInsetBoundsSides, top, right - mInsetBoundsSides, bottom);
+    }
+}
diff --git a/src/com/android/settings/widget/ChartDataUsageView.java b/src/com/android/settings/widget/ChartDataUsageView.java
index cad2ed8..cb9c8d7 100644
--- a/src/com/android/settings/widget/ChartDataUsageView.java
+++ b/src/com/android/settings/widget/ChartDataUsageView.java
@@ -496,32 +496,32 @@
         public long buildLabel(Resources res, SpannableStringBuilder builder, long value) {
 
             final CharSequence unit;
-            float result = value;
-            long labelValue = 1;
-            if (result <= 100 * MB_IN_BYTES) {
+            final long unitFactor;
+            if (value <= 100 * MB_IN_BYTES) {
                 unit = res.getText(com.android.internal.R.string.megabyteShort);
-                result /= MB_IN_BYTES;
-                labelValue = MB_IN_BYTES;
+                unitFactor = MB_IN_BYTES;
             } else {
                 unit = res.getText(com.android.internal.R.string.gigabyteShort);
-                result /= GB_IN_BYTES;
-                labelValue = GB_IN_BYTES;
+                unitFactor = GB_IN_BYTES;
             }
 
+            final double result = (double) value / unitFactor;
+            final double resultRounded;
             final CharSequence size;
             if (result < 10) {
                 size = String.format("%.1f", result);
+                resultRounded = (unitFactor * Math.round(result * 10)) / 10;
             } else {
                 size = String.format("%.0f", result);
+                resultRounded = unitFactor * Math.round(result);
             }
-            labelValue *= Float.parseFloat(size.toString());
 
             final int[] sizeBounds = findOrCreateSpan(builder, sSpanSize, "^1");
             builder.replace(sizeBounds[0], sizeBounds[1], size);
             final int[] unitBounds = findOrCreateSpan(builder, sSpanUnit, "^2");
             builder.replace(unitBounds[0], unitBounds[1], unit);
 
-            return labelValue;
+            return (long) resultRounded;
         }
 
         /** {@inheritDoc} */
diff --git a/src/com/android/settings/widget/ChartSweepView.java b/src/com/android/settings/widget/ChartSweepView.java
index 33e90c8..7b6d887 100644
--- a/src/com/android/settings/widget/ChartSweepView.java
+++ b/src/com/android/settings/widget/ChartSweepView.java
@@ -45,11 +45,13 @@
 
     private static final boolean DRAW_OUTLINE = false;
 
+    // TODO: clean up all the various padding/offset/margins
+
     private Drawable mSweep;
     private Rect mSweepPadding = new Rect();
 
     /** Offset of content inside this view. */
-    private Point mContentOffset = new Point();
+    private Rect mContentOffset = new Rect();
     /** Offset of {@link #mSweep} inside this view. */
     private Point mSweepOffset = new Point();
 
@@ -229,6 +231,8 @@
         if (mLabelTemplate != null && mAxis != null) {
             mLabelValue = mAxis.buildLabel(getResources(), mLabelTemplate, mValue);
             invalidate();
+        } else {
+            mLabelValue = mValue;
         }
     }
 
@@ -333,9 +337,9 @@
                 // only start tracking when in sweet spot
                 final boolean accept;
                 if (mFollowAxis == VERTICAL) {
-                    accept = event.getX() > getWidth() - (mSweepPadding.right * 3);
+                    accept = event.getX() > getWidth() - (mSweepPadding.right * 8);
                 } else {
-                    accept = event.getY() > getHeight() - (mSweepPadding.bottom * 3);
+                    accept = event.getY() > getHeight() - (mSweepPadding.bottom * 8);
                 }
 
                 final MotionEvent eventInParent = event.copy();
@@ -392,6 +396,7 @@
             }
             case MotionEvent.ACTION_UP: {
                 mTracking = null;
+                mValue = mLabelValue;
                 dispatchOnSweep(true);
                 setTranslationX(0);
                 setTranslationY(0);
@@ -534,23 +539,30 @@
             mMargins.bottom = mSweepPadding.bottom;
         }
 
-        mContentOffset.x = 0;
-        mContentOffset.y = 0;
+        mContentOffset.set(0, 0, 0, 0);
 
         // make touch target area larger
+        final int widthBefore = getMeasuredWidth();
+        final int heightBefore = getMeasuredHeight();
         if (mFollowAxis == HORIZONTAL) {
-            final int widthBefore = getMeasuredWidth();
             final int widthAfter = widthBefore * 3;
-            setMeasuredDimension(widthAfter, getMeasuredHeight());
-            mContentOffset.offset((widthAfter - widthBefore) / 2, 0);
+            setMeasuredDimension(widthAfter, heightBefore);
+            mContentOffset.left = (widthAfter - widthBefore) / 2;
+
+            final int offset = mSweepPadding.bottom * 2;
+            mContentOffset.bottom -= offset;
+            mMargins.bottom += offset;
         } else {
-            final int heightBefore = getMeasuredHeight();
             final int heightAfter = heightBefore * 3;
-            setMeasuredDimension(getMeasuredWidth(), heightAfter);
+            setMeasuredDimension(widthBefore, heightAfter);
             mContentOffset.offset(0, (heightAfter - heightBefore) / 2);
+
+            final int offset = mSweepPadding.right * 2;
+            mContentOffset.right -= offset;
+            mMargins.right += offset;
         }
 
-        mSweepOffset.offset(mContentOffset.x, mContentOffset.y);
+        mSweepOffset.offset(mContentOffset.left, mContentOffset.top);
         mMargins.offset(-mSweepOffset.x, -mSweepOffset.y);
     }
 
@@ -592,7 +604,7 @@
         if (isEnabled() && mLabelLayout != null) {
             final int count = canvas.save();
             {
-                canvas.translate(mContentOffset.x, mContentOffset.y + labelOffset);
+                canvas.translate(mContentOffset.left, mContentOffset.top + labelOffset);
                 mLabelLayout.draw(canvas);
             }
             canvas.restoreToCount(count);
@@ -602,18 +614,18 @@
         }
 
         if (mFollowAxis == VERTICAL) {
-            mSweep.setBounds(labelSize, mSweepOffset.y, width,
+            mSweep.setBounds(labelSize, mSweepOffset.y, width + mContentOffset.right,
                     mSweepOffset.y + mSweep.getIntrinsicHeight());
         } else {
-            mSweep.setBounds(mSweepOffset.x, labelSize,
-                    mSweepOffset.x + mSweep.getIntrinsicWidth(), height);
+            mSweep.setBounds(mSweepOffset.x, labelSize, mSweepOffset.x + mSweep.getIntrinsicWidth(),
+                    height + mContentOffset.bottom);
         }
 
         mSweep.draw(canvas);
     }
 
     public static float getLabelTop(ChartSweepView view) {
-        return view.getY() + view.mContentOffset.y;
+        return view.getY() + view.mContentOffset.top;
     }
 
     public static float getLabelBottom(ChartSweepView view) {
diff --git a/src/com/android/settings/wifi/AdvancedWifiSettings.java b/src/com/android/settings/wifi/AdvancedWifiSettings.java
index 7fb9871..19d05c1 100644
--- a/src/com/android/settings/wifi/AdvancedWifiSettings.java
+++ b/src/com/android/settings/wifi/AdvancedWifiSettings.java
@@ -99,16 +99,37 @@
         if (sleepPolicyPref != null) {
             if (Utils.isWifiOnly(getActivity())) {
                 sleepPolicyPref.setEntries(R.array.wifi_sleep_policy_entries_wifi_only);
-                sleepPolicyPref.setSummary(R.string.wifi_setting_sleep_policy_summary_wifi_only);
             }
             sleepPolicyPref.setOnPreferenceChangeListener(this);
             int value = Settings.System.getInt(getContentResolver(),
                     Settings.System.WIFI_SLEEP_POLICY,
                     Settings.System.WIFI_SLEEP_POLICY_NEVER);
-            sleepPolicyPref.setValue(String.valueOf(value));
+            String stringValue = String.valueOf(value);
+            sleepPolicyPref.setValue(stringValue);
+            updateSleepPolicySummary(sleepPolicyPref, stringValue);
         }
     }
 
+    private void updateSleepPolicySummary(Preference sleepPolicyPref, String value) {
+        if (value != null) {
+            String[] values = getResources().getStringArray(R.array.wifi_sleep_policy_values);
+            final int summaryArrayResId = Utils.isWifiOnly(getActivity()) ?
+                    R.array.wifi_sleep_policy_entries_wifi_only : R.array.wifi_sleep_policy_entries;
+            String[] summaries = getResources().getStringArray(summaryArrayResId);
+            for (int i = 0; i < values.length; i++) {
+                if (value.equals(values[i])) {
+                    if (i < summaries.length) {
+                        sleepPolicyPref.setSummary(summaries[i]);
+                        return;
+                    }
+                }
+            }
+        }
+
+        sleepPolicyPref.setSummary("");
+        Log.e(TAG, "Invalid sleep policy value: " + value);
+    }
+
     @Override
     public boolean onPreferenceTreeClick(PreferenceScreen screen, Preference preference) {
         String key = preference.getKey();
@@ -133,7 +154,7 @@
 
         if (KEY_FREQUENCY_BAND.equals(key)) {
             try {
-                mWifiManager.setFrequencyBand(Integer.parseInt(((String) newValue)), true);
+                mWifiManager.setFrequencyBand(Integer.parseInt((String) newValue), true);
             } catch (NumberFormatException e) {
                 Toast.makeText(getActivity(), R.string.wifi_setting_frequency_band_error,
                         Toast.LENGTH_SHORT).show();
@@ -143,8 +164,10 @@
 
         if (KEY_SLEEP_POLICY.equals(key)) {
             try {
-                Settings.System.putInt(getContentResolver(),
-                        Settings.System.WIFI_SLEEP_POLICY, Integer.parseInt(((String) newValue)));
+                String stringValue = (String) newValue;
+                Settings.System.putInt(getContentResolver(), Settings.System.WIFI_SLEEP_POLICY,
+                        Integer.parseInt(stringValue));
+                updateSleepPolicySummary(preference, stringValue);
             } catch (NumberFormatException e) {
                 Toast.makeText(getActivity(), R.string.wifi_setting_sleep_policy_error,
                         Toast.LENGTH_SHORT).show();