From 62775bf756a8eca9423bb4fab3fc7b71ab22d1a7 Mon Sep 17 00:00:00 2001 From: Adrian Roos Date: Thu, 28 Jan 2016 13:23:53 -0800 Subject: [PATCH] Move lock screen setting behind gear Bug: 19003093 Change-Id: I15baa5b1d19324521070d641ae6a227d782a4e9e --- res/values/strings.xml | 12 + res/xml/security_settings_chooser.xml | 9 +- res/xml/security_settings_lockscreen.xml | 6 - res/xml/security_settings_password.xml | 19 +- res/xml/security_settings_password_sub.xml | 45 ++ res/xml/security_settings_pattern.xml | 23 +- res/xml/security_settings_pattern_sub.xml | 49 ++ res/xml/security_settings_pin.xml | 19 +- res/xml/security_settings_pin_sub.xml | 45 ++ res/xml/security_settings_slide_sub.xml | 27 + .../android/settings/ChooseLockGeneric.java | 27 + .../android/settings/ChooseLockPassword.java | 13 + .../android/settings/ChooseLockPattern.java | 13 + .../settings/ChooseLockSettingsHelper.java | 1 + src/com/android/settings/GearPreference.java | 59 ++ .../android/settings/OwnerInfoSettings.java | 4 +- .../settings/SaveChosenLockWorkerBase.java | 12 +- .../android/settings/SecuritySettings.java | 508 +++++++++++------- 18 files changed, 629 insertions(+), 262 deletions(-) create mode 100644 res/xml/security_settings_password_sub.xml create mode 100644 res/xml/security_settings_pattern_sub.xml create mode 100644 res/xml/security_settings_pin_sub.xml create mode 100644 res/xml/security_settings_slide_sub.xml create mode 100644 src/com/android/settings/GearPreference.java diff --git a/res/values/strings.xml b/res/values/strings.xml index f86ba755da1..bc2076a1d69 100644 --- a/res/values/strings.xml +++ b/res/values/strings.xml @@ -7024,6 +7024,18 @@ No default Home + + Secure start-up + + + Require pattern to start up your device. While off, this device can\'t receive calls, messages, notifications, or alarms. + + + Require PIN to start up your device. While off, this device can\'t receive calls, messages, notifications, or alarms. + + + Require password to start up your device. While off, this device can\'t receive calls, messages, notifications, or alarms. + Additional Fingerprints diff --git a/res/xml/security_settings_chooser.xml b/res/xml/security_settings_chooser.xml index af7bfebc04c..dd8ae555716 100644 --- a/res/xml/security_settings_chooser.xml +++ b/res/xml/security_settings_chooser.xml @@ -15,23 +15,20 @@ --> - - - diff --git a/res/xml/security_settings_lockscreen.xml b/res/xml/security_settings_lockscreen.xml index fde0446ee02..a5aa7673fe7 100644 --- a/res/xml/security_settings_lockscreen.xml +++ b/res/xml/security_settings_lockscreen.xml @@ -29,12 +29,6 @@ settings:keywords="@string/keywords_lockscreen" android:persistent="false"/> - - diff --git a/res/xml/security_settings_password.xml b/res/xml/security_settings_password.xml index a6fe1a4e4f0..d96ca4b1080 100644 --- a/res/xml/security_settings_password.xml +++ b/res/xml/security_settings_password.xml @@ -22,30 +22,13 @@ android:key="security_category" android:title="@string/lock_settings_title"> - - - - - - - diff --git a/res/xml/security_settings_password_sub.xml b/res/xml/security_settings_password_sub.xml new file mode 100644 index 00000000000..0fa3731e78e --- /dev/null +++ b/res/xml/security_settings_password_sub.xml @@ -0,0 +1,45 @@ + + + + + + + + + + + + + + + diff --git a/res/xml/security_settings_pattern.xml b/res/xml/security_settings_pattern.xml index f8c4bd9a0f9..d3fd97d2e31 100644 --- a/res/xml/security_settings_pattern.xml +++ b/res/xml/security_settings_pattern.xml @@ -22,34 +22,13 @@ android:key="security_category" android:title="@string/lock_settings_title"> - - - - - - - - - diff --git a/res/xml/security_settings_pattern_sub.xml b/res/xml/security_settings_pattern_sub.xml new file mode 100644 index 00000000000..adaaca64a05 --- /dev/null +++ b/res/xml/security_settings_pattern_sub.xml @@ -0,0 +1,49 @@ + + + + + + + + + + + + + + + + + diff --git a/res/xml/security_settings_pin.xml b/res/xml/security_settings_pin.xml index abab140e5d0..ba19c43ac3c 100644 --- a/res/xml/security_settings_pin.xml +++ b/res/xml/security_settings_pin.xml @@ -22,30 +22,13 @@ android:key="security_category" android:title="@string/lock_settings_title"> - - - - - - - diff --git a/res/xml/security_settings_pin_sub.xml b/res/xml/security_settings_pin_sub.xml new file mode 100644 index 00000000000..6dff551bdc8 --- /dev/null +++ b/res/xml/security_settings_pin_sub.xml @@ -0,0 +1,45 @@ + + + + + + + + + + + + + + + diff --git a/res/xml/security_settings_slide_sub.xml b/res/xml/security_settings_slide_sub.xml new file mode 100644 index 00000000000..1efb370a1f9 --- /dev/null +++ b/res/xml/security_settings_slide_sub.xml @@ -0,0 +1,27 @@ + + + + + + + + diff --git a/src/com/android/settings/ChooseLockGeneric.java b/src/com/android/settings/ChooseLockGeneric.java index b44ee48f0ea..03a3fef3f25 100644 --- a/src/com/android/settings/ChooseLockGeneric.java +++ b/src/com/android/settings/ChooseLockGeneric.java @@ -37,6 +37,7 @@ import android.os.UserManager; import android.security.KeyStore; import android.support.v7.preference.Preference; import android.support.v7.preference.PreferenceScreen; +import android.text.TextUtils; import android.util.EventLog; import android.util.Log; import android.view.View; @@ -104,6 +105,7 @@ public class ChooseLockGeneric extends SettingsActivity { private boolean mEncryptionRequestDisabled; private boolean mRequirePassword; private boolean mForFingerprint = false; + private boolean mForChangeCredRequiredForBoot = false; private String mUserPassword; private LockPatternUtils mLockPatternUtils; private FingerprintManager mFingerprintManager; @@ -157,6 +159,8 @@ public class ChooseLockGeneric extends SettingsActivity { ChooseLockSettingsHelper.EXTRA_KEY_CHALLENGE, 0); mForFingerprint = getActivity().getIntent().getBooleanExtra( ChooseLockSettingsHelper.EXTRA_KEY_FOR_FINGERPRINT, false); + mForChangeCredRequiredForBoot = getArguments() != null && getArguments().getBoolean( + ChooseLockSettingsHelper.EXTRA_KEY_FOR_CHANGE_CRED_REQUIRED_FOR_BOOT); if (savedInstanceState != null) { mPasswordConfirmed = savedInstanceState.getBoolean(PASSWORD_CONFIRMED); @@ -183,6 +187,10 @@ public class ChooseLockGeneric extends SettingsActivity { if (mPasswordConfirmed) { updatePreferencesOrFinish(); + if (mForChangeCredRequiredForBoot) { + maybeEnableEncryption(mLockPatternUtils.getKeyguardStoredPasswordQuality( + mUserId), false); + } } else if (!mWaitingForConfirmation) { ChooseLockSettingsHelper helper = new ChooseLockSettingsHelper(this.getActivity(), this); @@ -238,6 +246,9 @@ public class ChooseLockGeneric extends SettingsActivity { // Get the intent that the encryption interstitial should start for creating // the new unlock method. Intent unlockMethodIntent = getIntentForUnlockMethod(quality, disabled); + unlockMethodIntent.putExtra( + ChooseLockSettingsHelper.EXTRA_KEY_FOR_CHANGE_CRED_REQUIRED_FOR_BOOT, + mForChangeCredRequiredForBoot); final Context context = getActivity(); // If accessibility is enabled and the user hasn't seen this dialog before, set the // default state to agree with that which is compatible with accessibility @@ -250,6 +261,11 @@ public class ChooseLockGeneric extends SettingsActivity { mForFingerprint); startActivityForResult(intent, ENABLE_ENCRYPTION_REQUEST); } else { + if (mForChangeCredRequiredForBoot) { + // Welp, couldn't change it. Oh well. + finish(); + return; + } mRequirePassword = false; // device encryption not enabled or not device owner. updateUnlockMethodAndFinish(quality, disabled); } @@ -263,6 +279,14 @@ public class ChooseLockGeneric extends SettingsActivity { mPasswordConfirmed = true; mUserPassword = data.getStringExtra(ChooseLockSettingsHelper.EXTRA_KEY_PASSWORD); updatePreferencesOrFinish(); + if (mForChangeCredRequiredForBoot) { + if (!TextUtils.isEmpty(mUserPassword)) { + maybeEnableEncryption( + mLockPatternUtils.getKeyguardStoredPasswordQuality(mUserId), false); + } else { + finish(); + } + } } else if (requestCode == CHOOSE_LOCK_REQUEST || requestCode == ENABLE_ENCRYPTION_REQUEST) { if (resultCode != RESULT_CANCELED) { @@ -273,6 +297,9 @@ public class ChooseLockGeneric extends SettingsActivity { getActivity().setResult(Activity.RESULT_CANCELED); finish(); } + if (requestCode == Activity.RESULT_CANCELED && mForChangeCredRequiredForBoot) { + finish(); + } } @Override diff --git a/src/com/android/settings/ChooseLockPassword.java b/src/com/android/settings/ChooseLockPassword.java index 2fd012e311a..fcedea3bbb5 100644 --- a/src/com/android/settings/ChooseLockPassword.java +++ b/src/com/android/settings/ChooseLockPassword.java @@ -267,6 +267,19 @@ public class ChooseLockPassword extends SettingsActivity { mUserId)); mChooseLockSettingsHelper = new ChooseLockSettingsHelper(getActivity()); + + if (intent.getBooleanExtra( + ChooseLockSettingsHelper.EXTRA_KEY_FOR_CHANGE_CRED_REQUIRED_FOR_BOOT, false)) { + SaveAndFinishWorker w = new SaveAndFinishWorker(); + final boolean required = getActivity().getIntent().getBooleanExtra( + EncryptionInterstitial.EXTRA_REQUIRE_PASSWORD, true); + String current = intent.getStringExtra( + ChooseLockSettingsHelper.EXTRA_KEY_PASSWORD); + w.setBlocking(true); + w.setListener(this); + w.start(mChooseLockSettingsHelper.utils(), required, + false, 0, current, current, mRequestedQuality, mUserId); + } } @Override diff --git a/src/com/android/settings/ChooseLockPattern.java b/src/com/android/settings/ChooseLockPattern.java index 960ec1a0c85..4a9295180ba 100644 --- a/src/com/android/settings/ChooseLockPattern.java +++ b/src/com/android/settings/ChooseLockPattern.java @@ -371,6 +371,19 @@ public class ChooseLockPattern extends SettingsActivity { Intent intent = getActivity().getIntent(); // Only take this argument into account if it belongs to the current profile. mUserId = Utils.getUserIdFromBundle(getActivity(), intent.getExtras()); + + if (intent.getBooleanExtra( + ChooseLockSettingsHelper.EXTRA_KEY_FOR_CHANGE_CRED_REQUIRED_FOR_BOOT, false)) { + SaveAndFinishWorker w = new SaveAndFinishWorker(); + final boolean required = getActivity().getIntent().getBooleanExtra( + EncryptionInterstitial.EXTRA_REQUIRE_PASSWORD, true); + String current = intent.getStringExtra( + ChooseLockSettingsHelper.EXTRA_KEY_PASSWORD); + w.setBlocking(true); + w.setListener(this); + w.start(mChooseLockSettingsHelper.utils(), required, + false, 0, LockPatternUtils.stringToPattern(current), current, mUserId); + } } @Override diff --git a/src/com/android/settings/ChooseLockSettingsHelper.java b/src/com/android/settings/ChooseLockSettingsHelper.java index 1035ef11935..dda8da280c6 100644 --- a/src/com/android/settings/ChooseLockSettingsHelper.java +++ b/src/com/android/settings/ChooseLockSettingsHelper.java @@ -33,6 +33,7 @@ public final class ChooseLockSettingsHelper { public static final String EXTRA_KEY_CHALLENGE = "challenge"; public static final String EXTRA_KEY_CHALLENGE_TOKEN = "hw_auth_token"; public static final String EXTRA_KEY_FOR_FINGERPRINT = "for_fingerprint"; + public static final String EXTRA_KEY_FOR_CHANGE_CRED_REQUIRED_FOR_BOOT = "for_cred_req_boot"; private LockPatternUtils mLockPatternUtils; diff --git a/src/com/android/settings/GearPreference.java b/src/com/android/settings/GearPreference.java new file mode 100644 index 00000000000..a8c1e9d6693 --- /dev/null +++ b/src/com/android/settings/GearPreference.java @@ -0,0 +1,59 @@ +/* + * Copyright (C) 2016 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License + */ + +package com.android.settings; + +import android.content.Context; +import android.support.v7.preference.Preference; +import android.support.v7.preference.PreferenceViewHolder; +import android.util.AttributeSet; +import android.view.View; + +/** + * A preference with a Gear on the side + */ +public class GearPreference extends Preference implements View.OnClickListener { + + private OnGearClickListener mOnGearClickListener; + + public GearPreference(Context context, AttributeSet attrs) { + super(context, attrs); + setWidgetLayoutResource(R.layout.preference_widget_settings); + } + + public void setOnGearClickListener(OnGearClickListener l) { + mOnGearClickListener = l; + } + + @Override + public void onBindViewHolder(PreferenceViewHolder holder) { + super.onBindViewHolder(holder); + holder.findViewById(R.id.settings_button).setOnClickListener(this); + } + + @Override + public void onClick(View v) { + if (v.getId() == R.id.settings_button) { + if (mOnGearClickListener != null) { + mOnGearClickListener.onGearClick(this); + } + } + } + + public interface OnGearClickListener { + void onGearClick(GearPreference p); + } +} diff --git a/src/com/android/settings/OwnerInfoSettings.java b/src/com/android/settings/OwnerInfoSettings.java index 7fffb11b695..cad06931659 100644 --- a/src/com/android/settings/OwnerInfoSettings.java +++ b/src/com/android/settings/OwnerInfoSettings.java @@ -75,8 +75,8 @@ public class OwnerInfoSettings extends DialogFragment implements OnClickListener mLockPatternUtils.setOwnerInfoEnabled(!TextUtils.isEmpty(info), mUserId); mLockPatternUtils.setOwnerInfo(info, mUserId); - if (getTargetFragment() instanceof SecuritySettings) { - ((SecuritySettings) getTargetFragment()).updateOwnerInfo(); + if (getTargetFragment() instanceof SecuritySettings.SecuritySubSettings) { + ((SecuritySettings.SecuritySubSettings) getTargetFragment()).updateOwnerInfo(); } } } diff --git a/src/com/android/settings/SaveChosenLockWorkerBase.java b/src/com/android/settings/SaveChosenLockWorkerBase.java index 4d8964a5e54..155dcb8ee72 100644 --- a/src/com/android/settings/SaveChosenLockWorkerBase.java +++ b/src/com/android/settings/SaveChosenLockWorkerBase.java @@ -39,6 +39,8 @@ abstract class SaveChosenLockWorkerBase extends Fragment { protected boolean mWasSecureBefore; protected int mUserId; + private boolean mBlocking; + @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); @@ -74,7 +76,11 @@ abstract class SaveChosenLockWorkerBase extends Fragment { } protected void start() { - new Task().execute(); + if (mBlocking) { + finish(saveAndVerifyInBackground()); + } else { + new Task().execute(); + } } /** @@ -91,6 +97,10 @@ abstract class SaveChosenLockWorkerBase extends Fragment { } } + public void setBlocking(boolean blocking) { + mBlocking = blocking; + } + private class Task extends AsyncTask { @Override protected Intent doInBackground(Void... params){ diff --git a/src/com/android/settings/SecuritySettings.java b/src/com/android/settings/SecuritySettings.java index 415f4d37c76..3e873d463c7 100644 --- a/src/com/android/settings/SecuritySettings.java +++ b/src/com/android/settings/SecuritySettings.java @@ -28,7 +28,6 @@ import android.content.pm.PackageManager; import android.content.pm.ResolveInfo; import android.content.pm.UserInfo; import android.content.res.Resources; -import android.hardware.fingerprint.Fingerprint; import android.hardware.fingerprint.FingerprintManager; import android.os.Bundle; import android.os.PersistableBundle; @@ -55,7 +54,6 @@ import com.android.internal.logging.MetricsProto.MetricsEvent; import com.android.internal.widget.LockPatternUtils; import com.android.settings.RestrictedListPreference; import com.android.settings.TrustAgentUtils.TrustAgentComponentInfo; -import com.android.settings.fingerprint.FingerprintEnrollIntroduction; import com.android.settings.fingerprint.FingerprintSettings; import com.android.settings.search.BaseSearchIndexProvider; import com.android.settings.search.Index; @@ -77,7 +75,8 @@ import static com.android.settingslib.RestrictedLockUtils.EnforcedAdmin; * Gesture lock pattern settings. */ public class SecuritySettings extends SettingsPreferenceFragment - implements OnPreferenceChangeListener, DialogInterface.OnClickListener, Indexable { + implements OnPreferenceChangeListener, DialogInterface.OnClickListener, Indexable, + GearPreference.OnGearClickListener { private static final String TAG = "SecuritySettings"; private static final String TRUST_AGENT_CLICK_INTENT = "trust_agent_click_intent"; @@ -87,11 +86,8 @@ public class SecuritySettings extends SettingsPreferenceFragment // Lock Settings private static final String KEY_UNLOCK_SET_OR_CHANGE = "unlock_set_or_change"; private static final String KEY_UNLOCK_SET_OR_CHANGE_PROFILE = "profile_challenge"; - private static final String KEY_VISIBLE_PATTERN = "visiblepattern"; private static final String KEY_SECURITY_CATEGORY = "security_category"; private static final String KEY_DEVICE_ADMIN_CATEGORY = "device_admin_category"; - private static final String KEY_LOCK_AFTER_TIMEOUT = "lock_after_timeout"; - private static final String KEY_OWNER_INFO_SETTINGS = "owner_info_settings"; private static final String KEY_ADVANCED_SECURITY = "advanced_security"; private static final String KEY_MANAGE_TRUST_AGENTS = "manage_trust_agents"; @@ -105,16 +101,14 @@ public class SecuritySettings extends SettingsPreferenceFragment private static final String KEY_RESET_CREDENTIALS = "credentials_reset"; private static final String KEY_CREDENTIALS_INSTALL = "credentials_install"; private static final String KEY_TOGGLE_INSTALL_APPLICATIONS = "toggle_install_applications"; - private static final String KEY_POWER_INSTANTLY_LOCKS = "power_button_instantly_locks"; private static final String KEY_CREDENTIALS_MANAGER = "credentials_management"; private static final String PACKAGE_MIME_TYPE = "application/vnd.android.package-archive"; private static final String KEY_TRUST_AGENT = "trust_agent"; private static final String KEY_SCREEN_PINNING = "screen_pinning_settings"; // These switch preferences need special handling since they're not all stored in Settings. - private static final String SWITCH_PREFERENCE_KEYS[] = { KEY_LOCK_AFTER_TIMEOUT, - KEY_VISIBLE_PATTERN, KEY_POWER_INSTANTLY_LOCKS, KEY_SHOW_PASSWORD, - KEY_TOGGLE_INSTALL_APPLICATIONS }; + private static final String SWITCH_PREFERENCE_KEYS[] = { + KEY_SHOW_PASSWORD, KEY_TOGGLE_INSTALL_APPLICATIONS }; // Only allow one trust agent on the platform. private static final boolean ONLY_ONE_TRUST_AGENT = true; @@ -127,9 +121,6 @@ public class SecuritySettings extends SettingsPreferenceFragment private ChooseLockSettingsHelper mChooseLockSettingsHelper; private LockPatternUtils mLockPatternUtils; - private RestrictedListPreference mLockAfter; - - private SwitchPreference mVisiblePattern; private SwitchPreference mShowPassword; @@ -138,12 +129,10 @@ public class SecuritySettings extends SettingsPreferenceFragment private RestrictedSwitchPreference mToggleAppInstallation; private DialogInterface mWarnInstallApps; - private SwitchPreference mPowerButtonInstantlyLocks; private boolean mIsAdmin; private Intent mTrustAgentClickIntent; - private Preference mOwnerInfoPref; private int mProfileChallengeUserId; @@ -232,25 +221,14 @@ public class SecuritySettings extends SettingsPreferenceFragment } } + Preference unlockSetOrChange = findPreference(KEY_UNLOCK_SET_OR_CHANGE); + if (unlockSetOrChange instanceof GearPreference) { + ((GearPreference) unlockSetOrChange).setOnGearClickListener(this); + } + // Add options for device encryption mIsAdmin = mUm.isAdminUser(); - mOwnerInfoPref = findPreference(KEY_OWNER_INFO_SETTINGS); - if (mOwnerInfoPref != null) { - mOwnerInfoPref.setEnabled(!mLockPatternUtils.isLockScreenDisabled(MY_USER_ID) - && !mLockPatternUtils.isDeviceOwnerInfoEnabled()); - - if (mOwnerInfoPref.isEnabled()) { - mOwnerInfoPref.setOnPreferenceClickListener(new OnPreferenceClickListener() { - @Override - public boolean onPreferenceClick(Preference preference) { - OwnerInfoSettings.show(SecuritySettings.this); - return true; - } - }); - } - } - if (mIsAdmin) { if (LockPatternUtils.isDeviceEncryptionEnabled()) { // The device is currently encrypted. @@ -269,28 +247,6 @@ public class SecuritySettings extends SettingsPreferenceFragment addTrustAgentSettings(securityCategory); } - // lock after preference - mLockAfter = (RestrictedListPreference) root.findPreference(KEY_LOCK_AFTER_TIMEOUT); - if (mLockAfter != null) { - setupLockAfterPreference(); - updateLockAfterPreferenceSummary(); - } - - // visible pattern - mVisiblePattern = (SwitchPreference) root.findPreference(KEY_VISIBLE_PATTERN); - - // lock instantly on power key press - mPowerButtonInstantlyLocks = (SwitchPreference) root.findPreference( - KEY_POWER_INSTANTLY_LOCKS); - Preference trustAgentPreference = root.findPreference(KEY_TRUST_AGENT); - if (mPowerButtonInstantlyLocks != null && - trustAgentPreference != null && - trustAgentPreference.getTitle().length() > 0) { - mPowerButtonInstantlyLocks.setSummary(getString( - R.string.lockpattern_settings_power_button_instantly_locks_summary, - trustAgentPreference.getTitle())); - } - // Append the rest of the settings addPreferencesFromResource(R.xml.security_settings_misc); @@ -521,6 +477,13 @@ public class SecuritySettings extends SettingsPreferenceFragment } } + @Override + public void onGearClick(GearPreference p) { + if (KEY_UNLOCK_SET_OR_CHANGE.equals(p.getKey())) { + startFragment(this, SecuritySubSettings.class.getName(), 0, 0, null); + } + } + @Override public void onDestroy() { super.onDestroy(); @@ -529,105 +492,6 @@ public class SecuritySettings extends SettingsPreferenceFragment } } - private void setupLockAfterPreference() { - // Compatible with pre-Froyo - long currentTimeout = Settings.Secure.getLong(getContentResolver(), - Settings.Secure.LOCK_SCREEN_LOCK_AFTER_TIMEOUT, 5000); - mLockAfter.setValue(String.valueOf(currentTimeout)); - mLockAfter.setOnPreferenceChangeListener(this); - final EnforcedAdmin admin = RestrictedLockUtils.checkIfMaximumTimeToLockIsSet( - getActivity()); - if (admin != null) { - final long adminTimeout = (mDPM != null ? mDPM.getMaximumTimeToLock(null) : 0); - final long displayTimeout = Math.max(0, - Settings.System.getInt(getContentResolver(), 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(Math.max(0, adminTimeout - displayTimeout), admin); - } - } - } - - private void updateLockAfterPreferenceSummary() { - final String summary; - if (mLockAfter.isDisabledByAdmin()) { - summary = getString(R.string.disabled_by_policy_title); - } else { - // Update summary message with current value - long currentTimeout = Settings.Secure.getLong(getContentResolver(), - Settings.Secure.LOCK_SCREEN_LOCK_AFTER_TIMEOUT, 5000); - final CharSequence[] entries = mLockAfter.getEntries(); - final CharSequence[] values = mLockAfter.getEntryValues(); - int best = 0; - for (int i = 0; i < values.length; i++) { - if (mLockAfter.isRestrictedForEntry(entries[i])) { - break; - } - long timeout = Long.valueOf(values[i].toString()); - if (currentTimeout >= timeout) { - best = i; - } - } - - Preference preference = getPreferenceScreen().findPreference(KEY_TRUST_AGENT); - if (preference != null && preference.getTitle().length() > 0) { - if (Long.valueOf(values[best].toString()) == 0) { - summary = getString(R.string.lock_immediately_summary_with_exception, - preference.getTitle()); - } else { - summary = getString(R.string.lock_after_timeout_summary_with_exception, - entries[best], preference.getTitle()); - } - } else { - summary = getString(R.string.lock_after_timeout_summary, entries[best]); - } - } - mLockAfter.setSummary(summary); - } - - private void disableUnusableTimeouts(long maxTimeout, EnforcedAdmin admin) { - final CharSequence[] entries = mLockAfter.getEntries(); - final CharSequence[] values = mLockAfter.getEntryValues(); - long maxTimeoutSelectable = 0; - int maxTimeoutEntryIndex = -1; - for (int i = 0; i < values.length; i++) { - long timeout = Long.parseLong(values[i].toString()); - if (timeout > maxTimeout) { - break; - } - maxTimeoutSelectable = timeout; - maxTimeoutEntryIndex = i; - } - // If there are no possible options for the user, then set this preference as - // disabled by admin, otherwise remove the padlock in case it was set earlier. - if (maxTimeoutSelectable == 0) { - mLockAfter.setDisabledByAdmin(admin); - return; - } else { - mLockAfter.setDisabledByAdmin(null); - } - - mLockAfter.clearRestrictedItems(); - // Set all the entries after the maximum selectable timeout as disabled by admin. - for (int i = maxTimeoutEntryIndex + 1; i < values.length; i++) { - mLockAfter.addRestrictedItem( - new RestrictedItem(entries[i], values[i], admin)); - } - - final int userPreference = Integer.valueOf(mLockAfter.getValue()); - if (userPreference <= maxTimeout) { - mLockAfter.setValue(String.valueOf(userPreference)); - } else if (maxTimeoutSelectable == maxTimeout) { - mLockAfter.setValue(String.valueOf(maxTimeout)); - } 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. - } - } - @Override public void onSaveInstanceState(Bundle outState) { super.onSaveInstanceState(outState); @@ -645,15 +509,6 @@ public class SecuritySettings extends SettingsPreferenceFragment createPreferenceHierarchy(); final LockPatternUtils lockPatternUtils = mChooseLockSettingsHelper.utils(); - if (mVisiblePattern != null) { - mVisiblePattern.setChecked(lockPatternUtils.isVisiblePatternEnabled( - MY_USER_ID)); - } - if (mPowerButtonInstantlyLocks != null) { - mPowerButtonInstantlyLocks.setChecked(lockPatternUtils.getPowerButtonInstantlyLocks( - MY_USER_ID)); - } - if (mShowPassword != null) { mShowPassword.setChecked(Settings.System.getInt(getContentResolver(), Settings.System.TEXT_SHOW_PASSWORD, 1) != 0); @@ -662,20 +517,6 @@ public class SecuritySettings extends SettingsPreferenceFragment if (mResetCredentials != null) { mResetCredentials.setEnabled(!mKeyStore.isEmpty()); } - - updateOwnerInfo(); - } - - public void updateOwnerInfo() { - if (mOwnerInfoPref != null) { - if (mLockPatternUtils.isDeviceOwnerInfoEnabled()) { - mOwnerInfoPref.setSummary(R.string.disabled_by_administrator_summary); - } else { - mOwnerInfoPref.setSummary(mLockPatternUtils.isOwnerInfoEnabled(MY_USER_ID) - ? mLockPatternUtils.getOwnerInfo(MY_USER_ID) - : getString(R.string.owner_info_settings_summary)); - } - } } @Override @@ -728,20 +569,7 @@ public class SecuritySettings extends SettingsPreferenceFragment boolean result = true; final String key = preference.getKey(); final LockPatternUtils lockPatternUtils = mChooseLockSettingsHelper.utils(); - if (KEY_LOCK_AFTER_TIMEOUT.equals(key)) { - int timeout = Integer.parseInt((String) value); - try { - Settings.Secure.putInt(getContentResolver(), - Settings.Secure.LOCK_SCREEN_LOCK_AFTER_TIMEOUT, timeout); - } catch (NumberFormatException e) { - Log.e("SecuritySettings", "could not persist lockAfter timeout setting", e); - } - updateLockAfterPreferenceSummary(); - } else if (KEY_VISIBLE_PATTERN.equals(key)) { - lockPatternUtils.setVisiblePatternEnabled((Boolean) value, MY_USER_ID); - } else if (KEY_POWER_INSTANTLY_LOCKS.equals(key)) { - mLockPatternUtils.setPowerButtonInstantlyLocks((Boolean) value, MY_USER_ID); - } else if (KEY_SHOW_PASSWORD.equals(key)) { + if (KEY_SHOW_PASSWORD.equals(key)) { Settings.System.putInt(getContentResolver(), Settings.System.TEXT_SHOW_PASSWORD, ((Boolean) value) ? 1 : 0); lockPatternUtils.setVisiblePasswordEnabled((Boolean) value, MY_USER_ID); @@ -823,6 +651,12 @@ public class SecuritySettings extends SettingsPreferenceFragment result.add(sir); } + sir = new SearchIndexableResource(context); + sir.xmlResId = SecuritySubSettings.getResIdForLockUnlockSubScreen(context, + lockPatternUtils); + sir.className = SecuritySubSettings.class.getName(); + result.add(sir); + // Append the rest of the settings sir = new SearchIndexableResource(context); sir.xmlResId = R.xml.security_settings_misc; @@ -924,8 +758,304 @@ public class SecuritySettings extends SettingsPreferenceFragment keys.add(KEY_MANAGE_TRUST_AGENTS); } + if (!SecuritySubSettings.canChangeRequireCredentialBeforeStartup(context)) { + keys.add(SecuritySubSettings.KEY_REQUIRE_CRED_BEFORE_STARTUP); + } + return keys; } } + public static class SecuritySubSettings extends SettingsPreferenceFragment + implements OnPreferenceChangeListener { + + private static final String KEY_VISIBLE_PATTERN = "visiblepattern"; + private static final String KEY_LOCK_AFTER_TIMEOUT = "lock_after_timeout"; + private static final String KEY_OWNER_INFO_SETTINGS = "owner_info_settings"; + private static final String KEY_POWER_INSTANTLY_LOCKS = "power_button_instantly_locks"; + private static final String KEY_REQUIRE_CRED_BEFORE_STARTUP = "require_cred_before_startup"; + + public static final int REQUEST_CHANGE_REQUIRE_CRED_FOR_START = 2; + + // These switch preferences need special handling since they're not all stored in Settings. + private static final String SWITCH_PREFERENCE_KEYS[] = { KEY_LOCK_AFTER_TIMEOUT, + KEY_VISIBLE_PATTERN, KEY_POWER_INSTANTLY_LOCKS, KEY_REQUIRE_CRED_BEFORE_STARTUP }; + + private RestrictedListPreference mLockAfter; + private SwitchPreference mVisiblePattern; + private SwitchPreference mPowerButtonInstantlyLocks; + private Preference mOwnerInfoPref; + + private LockPatternUtils mLockPatternUtils; + private DevicePolicyManager mDPM; + + @Override + protected int getMetricsCategory() { + return MetricsEvent.SECURITY; + } + + @Override + public void onCreate(Bundle icicle) { + super.onCreate(icicle); + mLockPatternUtils = new LockPatternUtils(getContext()); + mDPM = getContext().getSystemService(DevicePolicyManager.class); + } + + @Override + public void onResume() { + super.onResume(); + + createPreferenceHierarchy(); + + final LockPatternUtils lockPatternUtils = mLockPatternUtils; + if (mVisiblePattern != null) { + mVisiblePattern.setChecked(lockPatternUtils.isVisiblePatternEnabled( + MY_USER_ID)); + } + if (mPowerButtonInstantlyLocks != null) { + mPowerButtonInstantlyLocks.setChecked(lockPatternUtils.getPowerButtonInstantlyLocks( + MY_USER_ID)); + } + + updateOwnerInfo(); + } + + @Override + public void onActivityResult(int requestCode, int resultCode, Intent data) { + super.onActivityResult(requestCode, resultCode, data); + + createPreferenceHierarchy(); + } + + private void createPreferenceHierarchy() { + PreferenceScreen root = getPreferenceScreen(); + if (root != null) { + root.removeAll(); + } + root = null; + + final int resid = getResIdForLockUnlockSubScreen(getActivity(), + new LockPatternUtils(getContext())); + addPreferencesFromResource(resid); + + // lock after preference + mLockAfter = (RestrictedListPreference) findPreference(KEY_LOCK_AFTER_TIMEOUT); + if (mLockAfter != null) { + setupLockAfterPreference(); + updateLockAfterPreferenceSummary(); + } + + // visible pattern + mVisiblePattern = (SwitchPreference) findPreference(KEY_VISIBLE_PATTERN); + + // lock instantly on power key press + mPowerButtonInstantlyLocks = (SwitchPreference) findPreference( + KEY_POWER_INSTANTLY_LOCKS); + Preference trustAgentPreference = findPreference(KEY_TRUST_AGENT); + if (mPowerButtonInstantlyLocks != null && + trustAgentPreference != null && + trustAgentPreference.getTitle().length() > 0) { + mPowerButtonInstantlyLocks.setSummary(getString( + R.string.lockpattern_settings_power_button_instantly_locks_summary, + trustAgentPreference.getTitle())); + } + + mOwnerInfoPref = findPreference(KEY_OWNER_INFO_SETTINGS); + if (mOwnerInfoPref != null) { + mOwnerInfoPref.setEnabled(!mLockPatternUtils.isLockScreenDisabled(MY_USER_ID) + && !mLockPatternUtils.isDeviceOwnerInfoEnabled()); + + if (mOwnerInfoPref.isEnabled()) { + mOwnerInfoPref.setOnPreferenceClickListener(new OnPreferenceClickListener() { + @Override + public boolean onPreferenceClick(Preference preference) { + OwnerInfoSettings.show(SecuritySubSettings.this); + return true; + } + }); + } + } + + Preference requireCredForStartup = findPreference(KEY_REQUIRE_CRED_BEFORE_STARTUP); + if (requireCredForStartup instanceof SwitchPreference) { + ((SwitchPreference) requireCredForStartup).setChecked( + mLockPatternUtils.isCredentialRequiredToDecrypt(false)); + if (!canChangeRequireCredentialBeforeStartup(getContext())) { + removePreference(KEY_REQUIRE_CRED_BEFORE_STARTUP); + } + } + + for (int i = 0; i < SWITCH_PREFERENCE_KEYS.length; i++) { + final Preference pref = findPreference(SWITCH_PREFERENCE_KEYS[i]); + if (pref != null) pref.setOnPreferenceChangeListener(this); + } + } + + static boolean canChangeRequireCredentialBeforeStartup(Context context) { + DevicePolicyManager dpm = context.getSystemService(DevicePolicyManager.class); + return UserManager.get(context).isAdminUser() + && LockPatternUtils.isDeviceEncryptionEnabled() + && !dpm.getDoNotAskCredentialsOnBoot(); + } + + private void setupLockAfterPreference() { + // Compatible with pre-Froyo + long currentTimeout = Settings.Secure.getLong(getContentResolver(), + Settings.Secure.LOCK_SCREEN_LOCK_AFTER_TIMEOUT, 5000); + mLockAfter.setValue(String.valueOf(currentTimeout)); + mLockAfter.setOnPreferenceChangeListener(this); + final EnforcedAdmin admin = RestrictedLockUtils.checkIfMaximumTimeToLockIsSet( + getActivity()); + if (admin != null) { + final long adminTimeout = (mDPM != null ? mDPM.getMaximumTimeToLock(null) : 0); + final long displayTimeout = Math.max(0, + Settings.System.getInt(getContentResolver(), 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(Math.max(0, adminTimeout - displayTimeout), admin); + } + } + } + + private void updateLockAfterPreferenceSummary() { + final String summary; + if (mLockAfter.isDisabledByAdmin()) { + summary = getString(R.string.disabled_by_policy_title); + } else { + // Update summary message with current value + long currentTimeout = Settings.Secure.getLong(getContentResolver(), + Settings.Secure.LOCK_SCREEN_LOCK_AFTER_TIMEOUT, 5000); + final CharSequence[] entries = mLockAfter.getEntries(); + final CharSequence[] values = mLockAfter.getEntryValues(); + int best = 0; + for (int i = 0; i < values.length; i++) { + if (mLockAfter.isRestrictedForEntry(entries[i])) { + break; + } + long timeout = Long.valueOf(values[i].toString()); + if (currentTimeout >= timeout) { + best = i; + } + } + + Preference preference = findPreference(KEY_TRUST_AGENT); + if (preference != null && preference.getTitle().length() > 0) { + if (Long.valueOf(values[best].toString()) == 0) { + summary = getString(R.string.lock_immediately_summary_with_exception, + preference.getTitle()); + } else { + summary = getString(R.string.lock_after_timeout_summary_with_exception, + entries[best], preference.getTitle()); + } + } else { + summary = getString(R.string.lock_after_timeout_summary, entries[best]); + } + } + mLockAfter.setSummary(summary); + } + + private void disableUnusableTimeouts(long maxTimeout, EnforcedAdmin admin) { + final CharSequence[] entries = mLockAfter.getEntries(); + final CharSequence[] values = mLockAfter.getEntryValues(); + long maxTimeoutSelectable = 0; + int maxTimeoutEntryIndex = -1; + for (int i = 0; i < values.length; i++) { + long timeout = Long.parseLong(values[i].toString()); + if (timeout > maxTimeout) { + break; + } + maxTimeoutSelectable = timeout; + maxTimeoutEntryIndex = i; + } + // If there are no possible options for the user, then set this preference as + // disabled by admin, otherwise remove the padlock in case it was set earlier. + if (maxTimeoutSelectable == 0) { + mLockAfter.setDisabledByAdmin(admin); + return; + } else { + mLockAfter.setDisabledByAdmin(null); + } + + mLockAfter.clearRestrictedItems(); + // Set all the entries after the maximum selectable timeout as disabled by admin. + for (int i = maxTimeoutEntryIndex + 1; i < values.length; i++) { + mLockAfter.addRestrictedItem( + new RestrictedItem(entries[i], values[i], admin)); + } + + final int userPreference = Integer.valueOf(mLockAfter.getValue()); + if (userPreference <= maxTimeout) { + mLockAfter.setValue(String.valueOf(userPreference)); + } else if (maxTimeoutSelectable == maxTimeout) { + mLockAfter.setValue(String.valueOf(maxTimeout)); + } 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. + } + } + + public void updateOwnerInfo() { + if (mOwnerInfoPref != null) { + if (mLockPatternUtils.isDeviceOwnerInfoEnabled()) { + mOwnerInfoPref.setSummary(R.string.disabled_by_administrator_summary); + } else { + mOwnerInfoPref.setSummary(mLockPatternUtils.isOwnerInfoEnabled(MY_USER_ID) + ? mLockPatternUtils.getOwnerInfo(MY_USER_ID) + : getString(R.string.owner_info_settings_summary)); + } + } + } + + private static int getResIdForLockUnlockSubScreen(Context context, + LockPatternUtils lockPatternUtils) { + if (lockPatternUtils.isSecure(MY_USER_ID)) { + switch (lockPatternUtils.getKeyguardStoredPasswordQuality(MY_USER_ID)) { + case DevicePolicyManager.PASSWORD_QUALITY_SOMETHING: + return R.xml.security_settings_pattern_sub; + case DevicePolicyManager.PASSWORD_QUALITY_NUMERIC: + case DevicePolicyManager.PASSWORD_QUALITY_NUMERIC_COMPLEX: + return R.xml.security_settings_pin_sub; + case DevicePolicyManager.PASSWORD_QUALITY_ALPHABETIC: + case DevicePolicyManager.PASSWORD_QUALITY_ALPHANUMERIC: + case DevicePolicyManager.PASSWORD_QUALITY_COMPLEX: + return R.xml.security_settings_password_sub; + } + } else if (!lockPatternUtils.isLockScreenDisabled(MY_USER_ID)) { + return R.xml.security_settings_slide_sub; + } + return 0; + } + + @Override + public boolean onPreferenceChange(Preference preference, Object value) { + String key = preference.getKey(); + if (KEY_POWER_INSTANTLY_LOCKS.equals(key)) { + mLockPatternUtils.setPowerButtonInstantlyLocks((Boolean) value, MY_USER_ID); + } else if (KEY_LOCK_AFTER_TIMEOUT.equals(key)) { + int timeout = Integer.parseInt((String) value); + try { + Settings.Secure.putInt(getContentResolver(), + Settings.Secure.LOCK_SCREEN_LOCK_AFTER_TIMEOUT, timeout); + } catch (NumberFormatException e) { + Log.e("SecuritySettings", "could not persist lockAfter timeout setting", e); + } + updateLockAfterPreferenceSummary(); + } else if (KEY_VISIBLE_PATTERN.equals(key)) { + mLockPatternUtils.setVisiblePatternEnabled((Boolean) value, MY_USER_ID); + } else if (KEY_REQUIRE_CRED_BEFORE_STARTUP.equals(key)) { + Bundle extras = new Bundle(); + extras.putBoolean( + ChooseLockSettingsHelper.EXTRA_KEY_FOR_CHANGE_CRED_REQUIRED_FOR_BOOT, true); + startFragment(this, + "com.android.settings.ChooseLockGeneric$ChooseLockGenericFragment", + R.string.lock_settings_picker_title, REQUEST_CHANGE_REQUIRE_CRED_FOR_START, + extras); + return false; + } + return true; + } + } }