Fix 2579224: Add a separate timeout for lockscreen vs display

This change adds a second timeout to the SecuritySettings page
separate from the standard display timeout.

Change-Id: I033a3578d876148bd723dee5d1a2531be5d6b51d
diff --git a/res/values/arrays.xml b/res/values/arrays.xml
index 1a8e17b..0b44edd 100644
--- a/res/values/arrays.xml
+++ b/res/values/arrays.xml
@@ -72,7 +72,7 @@
         <item>11</item>
     </string-array>
 
-    <!-- Display settings.  The delay in inactivity before the screen is turned off. These are shown ain a list dialog. -->
+    <!-- Display settings.  The delay in inactivity before the screen is turned off. These are shown in a list dialog. -->
     <string-array name="screen_timeout_entries">
         <item>15 seconds</item>
         <item>30 seconds</item>
@@ -97,7 +97,40 @@
         <!-- Do not translate. -->
         <item>1800000</item>
     </string-array>
+    
+    <!-- Security settings.  The delay after screen is turned off until device locks. 
+         These are shown in a list dialog. -->
+    <string-array name="lock_after_timeout_entries">
+        <item>immediately</item>
+        <item>5 seconds</item>
+        <item>15 seconds</item>
+        <item>30 seconds</item>
+        <item>1 minute</item>
+        <item>2 minutes</item>
+        <item>10 minutes</item>
+        <item>30 minutes</item>
+    </string-array>
 
+    <!-- Do not translate. -->
+    <string-array name="lock_after_timeout_values" translatable="false">
+        <!-- Do not translate. -->
+        <item>0</item>
+        <!-- Do not translate. -->
+        <item>5000</item>
+        <!-- Do not translate. -->
+        <item>15000</item>
+        <!-- Do not translate. -->
+        <item>30000</item>
+        <!-- Do not translate. -->
+        <item>60000</item>
+        <!-- Do not translate. -->
+        <item>120000</item>
+        <!-- Do not translate. -->
+        <item>600000</item>
+        <!-- Do not translate. -->
+        <item>1800000</item>
+    </string-array>
+    
     <!-- TTS settings -->
 
     <!-- Default speech rate choices -->
diff --git a/res/values/strings.xml b/res/values/strings.xml
index 6e8082d..495608e 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -520,6 +520,11 @@
 
     <!-- Security Settings --><skip />
 
+    <!-- Security settings screen, setting option name to change screen timeout -->
+    <string name="lock_after_timeout">Lock device after timeout</string>
+    <!-- Security settings screen, setting option summary to change screen timeout -->
+    <string name="lock_after_timeout_summary">Adjust the delay before the device automatically locks</string>
+    
     <!-- Main Settings screen setting option title for the item to take you the security and location screen -->
     <string name="security_settings_title">Location &amp; security</string>
     <!-- Location & security settings screen title -->
diff --git a/res/xml/security_settings_password.xml b/res/xml/security_settings_password.xml
index ac06711..6411091 100644
--- a/res/xml/security_settings_password.xml
+++ b/res/xml/security_settings_password.xml
@@ -20,6 +20,14 @@
         android:key="security_category"
         android:title="@string/lock_settings_title">
 
+        <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:key="unlock_set_or_change"
             android:title="@string/unlock_set_unlock_launch_picker_change_title"
diff --git a/res/xml/security_settings_pattern.xml b/res/xml/security_settings_pattern.xml
index 095828a..200c260 100644
--- a/res/xml/security_settings_pattern.xml
+++ b/res/xml/security_settings_pattern.xml
@@ -20,6 +20,14 @@
         android:key="security_category"
         android:title="@string/lock_settings_title">
 
+        <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:key="unlock_set_or_change"
             android:title="@string/unlock_set_unlock_launch_picker_change_title"
diff --git a/res/xml/security_settings_pin.xml b/res/xml/security_settings_pin.xml
index ac06711..31fa110 100644
--- a/res/xml/security_settings_pin.xml
+++ b/res/xml/security_settings_pin.xml
@@ -20,6 +20,14 @@
         android:key="security_category"
         android:title="@string/lock_settings_title">
 
+        <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:key="unlock_set_or_change"
             android:title="@string/unlock_set_unlock_launch_picker_change_title"
diff --git a/src/com/android/settings/SecuritySettings.java b/src/com/android/settings/SecuritySettings.java
index e618448..287e312 100644
--- a/src/com/android/settings/SecuritySettings.java
+++ b/src/com/android/settings/SecuritySettings.java
@@ -17,6 +17,8 @@
 package com.android.settings;
 
 
+import static android.provider.Settings.System.SCREEN_OFF_TIMEOUT;
+
 import com.android.internal.widget.LockPatternUtils;
 
 import android.app.AlertDialog;
@@ -32,25 +34,30 @@
 import android.os.Bundle;
 import android.os.SystemProperties;
 import android.preference.CheckBoxPreference;
+import android.preference.ListPreference;
 import android.preference.Preference;
 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;
 import android.telephony.TelephonyManager;
+import android.util.Log;
 import android.view.View;
 import android.widget.TextView;
 import android.widget.Toast;
 
+import java.util.ArrayList;
 import java.util.Observable;
 import java.util.Observer;
 
 /**
  * Gesture lock pattern settings.
  */
-public class SecuritySettings extends SettingsPreferenceFragment {
+public class SecuritySettings extends SettingsPreferenceFragment 
+        implements OnPreferenceChangeListener {
     private static final String KEY_UNLOCK_SET_OR_CHANGE = "unlock_set_or_change";
 
     // Lock Settings
@@ -74,7 +81,9 @@
     private static final String LOCATION_NETWORK = "location_network";
     private static final String LOCATION_GPS = "location_gps";
     private static final String ASSISTED_GPS = "assisted_gps";
+    private static final String LOCK_AFTER_TIMEOUT_KEY = "lock_after_timeout";
     private static final int SET_OR_CHANGE_LOCK_METHOD_REQUEST = 123;
+    private static final int FALLBACK_LOCK_AFTER_TIMEOUT_VALUE = 5000; // compatible with pre-Froyo
 
     // Credential storage
     private CredentialStorage mCredentialStorage = new CredentialStorage();
@@ -92,8 +101,11 @@
     // This is necessary because the Network Location Provider can change settings
     // if the user does not confirm enabling the provider.
     private ContentQueryMap mContentQueryMap;
+    
     private ChooseLockSettingsHelper mChooseLockSettingsHelper;
     private LockPatternUtils mLockPatternUtils;
+    private ListPreference mLockAfter;
+    
     private final class SettingsObserver implements Observer {
         public void update(Observable o, Object arg) {
             updateToggles();
@@ -156,8 +168,8 @@
             }
         }
 
-        // set or change current. Should be common to all unlock preference screens
-        // mSetOrChange = (PreferenceScreen) pm.findPreference(KEY_UNLOCK_SET_OR_CHANGE);
+        // lock after preference
+        mLockAfter = setupLockAfterPreference(pm);
 
         // visible pattern
         mVisiblePattern = (CheckBoxPreference) pm.findPreference(KEY_VISIBLE_PATTERN);
@@ -220,10 +232,65 @@
         return root;
     }
 
+    private ListPreference setupLockAfterPreference(PreferenceManager pm) {
+        ListPreference result = (ListPreference) pm.findPreference(LOCK_AFTER_TIMEOUT_KEY);
+        if (result != null) {
+            int lockAfterValue = Settings.Secure.getInt(getContentResolver(), 
+                    Settings.Secure.LOCK_SCREEN_LOCK_AFTER_TIMEOUT, 
+                    FALLBACK_LOCK_AFTER_TIMEOUT_VALUE);
+            result.setValue(String.valueOf(lockAfterValue));
+            result.setOnPreferenceChangeListener(this);
+            final long adminTimeout = mDPM != null ? mDPM.getMaximumTimeToLock(null) : 0;
+            final ContentResolver cr = getContentResolver();
+            final long displayTimeout = Math.max(0, 
+                    Settings.System.getInt(cr, SCREEN_OFF_TIMEOUT, 0));
+            if (adminTimeout > 0) {
+                // This setting is a slave to display timeout when a device policy is enforced.
+                // As such, maxLockTimeout = adminTimeout - displayTimeout.
+                // If there isn't enough time, shows "immediately" setting.
+                disableUnusableTimeouts(result, Math.max(0, adminTimeout - displayTimeout));
+            }
+        }
+        return result;
+    }
+
+    private static void disableUnusableTimeouts(ListPreference pref, long maxTimeout) {
+        final CharSequence[] entries = pref.getEntries();
+        final CharSequence[] values = pref.getEntryValues();
+        ArrayList<CharSequence> revisedEntries = new ArrayList<CharSequence>();
+        ArrayList<CharSequence> revisedValues = new ArrayList<CharSequence>();
+        for (int i = 0; i < values.length; i++) {
+            long timeout = Long.valueOf(values[i].toString());
+            if (timeout <= maxTimeout) {
+                revisedEntries.add(entries[i]);
+                revisedValues.add(values[i]);
+            }
+        }
+        if (revisedEntries.size() != entries.length || revisedValues.size() != values.length) {
+            pref.setEntries(
+                    revisedEntries.toArray(new CharSequence[revisedEntries.size()]));
+            pref.setEntryValues(
+                    revisedValues.toArray(new CharSequence[revisedValues.size()]));
+            final int userPreference = Integer.valueOf(pref.getValue());
+            if (userPreference <= maxTimeout) {
+                pref.setValue(String.valueOf(userPreference));
+            } else {
+                // There will be no highlighted selection since nothing in the list matches
+                // maxTimeout. The user can still select anything less than maxTimeout.
+                // TODO: maybe append maxTimeout to the list and mark selected.
+            }
+        }
+        pref.setEnabled(revisedEntries.size() > 0);
+    }
+
     @Override
     public void onResume() {
         super.onResume();
 
+        // Make sure we reload the preference hierarchy since some of these settings
+        // depend on others...
+        createPreferenceHierarchy();
+
         final LockPatternUtils lockPatternUtils = mChooseLockSettingsHelper.utils();
         if (mVisiblePattern != null) {
             mVisiblePattern.setChecked(lockPatternUtils.isVisiblePatternEnabled());
@@ -393,7 +460,7 @@
                 Boolean bval = (Boolean)value;
                 mWillEnableEncryptedFS = bval.booleanValue();
                 showSwitchEncryptedFSDialog();
-            }
+            } 
             return true;
         }
 
@@ -659,4 +726,17 @@
             }
         }
     }
+
+    public boolean onPreferenceChange(Preference preference, Object value) {
+        if (preference == mLockAfter) {
+            int lockAfter = Integer.parseInt((String) value);
+            try {
+                Settings.Secure.putInt(getContentResolver(),
+                        Settings.Secure.LOCK_SCREEN_LOCK_AFTER_TIMEOUT, lockAfter);
+            } catch (NumberFormatException e) {
+                Log.e("SecuritySettings", "could not persist lockAfter timeout setting", e);
+            }
+        }
+        return true;
+    }
 }