From 6934a044b8ebf4dac28d1c1142b6eee4ecc64f66 Mon Sep 17 00:00:00 2001 From: Clara Bayarri Date: Wed, 14 Oct 2015 11:07:35 +0100 Subject: [PATCH] Work Profile Passphrase Setting Create a new section in Security Settings which includes all settings for the Work Challenge. Only some settings apply to the Work Challenge, so we reuse the security settings layouts for items and compare them against a whitelist to remove unwanted items. Additionally, remove all usages of ChooseLockGeneric.KEY_USER_ID in favor of Intent.EXTRA_USER_ID. Change-Id: I3d1ba953a2056f7c61a7b3feeb8b49f1a352dff6 --- res/values/strings.xml | 7 + res/xml/profile_challenge_settings.xml | 20 ++ res/xml/security_settings_profile.xml | 33 +++ .../android/settings/ChooseLockGeneric.java | 5 +- .../android/settings/ChooseLockPassword.java | 6 +- .../android/settings/ChooseLockPattern.java | 2 +- .../settings/ChooseLockSettingsHelper.java | 2 +- .../ProfileChallengePreferenceFragment.java | 193 ++++++++++++++++++ .../android/settings/SecuritySettings.java | 30 +++ .../android/settings/SettingsActivity.java | 13 ++ src/com/android/settings/Utils.java | 2 +- 11 files changed, 306 insertions(+), 7 deletions(-) create mode 100644 res/xml/profile_challenge_settings.xml create mode 100644 res/xml/security_settings_profile.xml create mode 100644 src/com/android/settings/ProfileChallengePreferenceFragment.java diff --git a/res/values/strings.xml b/res/values/strings.xml index fd359bcded5..bb6bbc0c506 100644 --- a/res/values/strings.xml +++ b/res/values/strings.xml @@ -3015,6 +3015,12 @@ Application is not installed on your phone. + + + Work profile + + Work profile security + Manage apps @@ -5562,6 +5568,7 @@ ignore optimizations, doze, app standby vibrant, RGB, sRGB, color, natural, standard slide to unlock, password, pattern, PIN + work challenge, work, profile diff --git a/res/xml/profile_challenge_settings.xml b/res/xml/profile_challenge_settings.xml new file mode 100644 index 00000000000..cd611191ebd --- /dev/null +++ b/res/xml/profile_challenge_settings.xml @@ -0,0 +1,20 @@ + + + + + + diff --git a/res/xml/security_settings_profile.xml b/res/xml/security_settings_profile.xml new file mode 100644 index 00000000000..1c10b794789 --- /dev/null +++ b/res/xml/security_settings_profile.xml @@ -0,0 +1,33 @@ + + + + + + + + + + + + diff --git a/src/com/android/settings/ChooseLockGeneric.java b/src/com/android/settings/ChooseLockGeneric.java index 73f8c46c482..2641ad2665e 100644 --- a/src/com/android/settings/ChooseLockGeneric.java +++ b/src/com/android/settings/ChooseLockGeneric.java @@ -48,7 +48,6 @@ import com.android.internal.widget.LockPatternUtils; public class ChooseLockGeneric extends SettingsActivity { public static final String CONFIRM_CREDENTIALS = "confirm_credentials"; - public static final String KEY_USER_ID = "user_id"; @Override public Intent getIntent() { @@ -369,6 +368,10 @@ public class ChooseLockGeneric extends SettingsActivity { visible = false; } } else if (KEY_UNLOCK_SET_NONE.equals(key)) { + if (mUserId != UserHandle.myUserId()) { + // Swipe doesn't make sense for profiles. + visible = false; + } enabled = quality <= DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED; } else if (KEY_UNLOCK_SET_PATTERN.equals(key)) { enabled = quality <= DevicePolicyManager.PASSWORD_QUALITY_SOMETHING; diff --git a/src/com/android/settings/ChooseLockPassword.java b/src/com/android/settings/ChooseLockPassword.java index cf330adbe56..eacf1ab0ebd 100644 --- a/src/com/android/settings/ChooseLockPassword.java +++ b/src/com/android/settings/ChooseLockPassword.java @@ -87,7 +87,7 @@ public class ChooseLockPassword extends SettingsActivity { boolean confirmCredentials, int userId) { Intent intent = createIntent(context, quality, minLength, maxLength, requirePasswordToDecrypt, confirmCredentials); - intent.putExtra(ChooseLockGeneric.KEY_USER_ID, userId); + intent.putExtra(Intent.EXTRA_USER_ID, userId); return intent; } @@ -103,7 +103,7 @@ public class ChooseLockPassword extends SettingsActivity { int maxLength, boolean requirePasswordToDecrypt, String password, int userId) { Intent intent = createIntent(context, quality, minLength, maxLength, requirePasswordToDecrypt, password); - intent.putExtra(ChooseLockGeneric.KEY_USER_ID, userId); + intent.putExtra(Intent.EXTRA_USER_ID, userId); return intent; } @@ -120,7 +120,7 @@ public class ChooseLockPassword extends SettingsActivity { int maxLength, boolean requirePasswordToDecrypt, long challenge, int userId) { Intent intent = createIntent(context, quality, minLength, maxLength, requirePasswordToDecrypt, challenge); - intent.putExtra(ChooseLockGeneric.KEY_USER_ID, userId); + intent.putExtra(Intent.EXTRA_USER_ID, userId); return intent; } diff --git a/src/com/android/settings/ChooseLockPattern.java b/src/com/android/settings/ChooseLockPattern.java index 4a6008c9053..e20db932889 100644 --- a/src/com/android/settings/ChooseLockPattern.java +++ b/src/com/android/settings/ChooseLockPattern.java @@ -78,7 +78,7 @@ public class ChooseLockPattern extends SettingsActivity { intent.putExtra("key_lock_method", "pattern"); intent.putExtra(ChooseLockGeneric.CONFIRM_CREDENTIALS, confirmCredentials); intent.putExtra(EncryptionInterstitial.EXTRA_REQUIRE_PASSWORD, requirePassword); - intent.putExtra(ChooseLockGeneric.KEY_USER_ID, userId); + intent.putExtra(Intent.EXTRA_USER_ID, userId); return intent; } diff --git a/src/com/android/settings/ChooseLockSettingsHelper.java b/src/com/android/settings/ChooseLockSettingsHelper.java index 53fbb7fb46d..b88dea2a9ce 100644 --- a/src/com/android/settings/ChooseLockSettingsHelper.java +++ b/src/com/android/settings/ChooseLockSettingsHelper.java @@ -192,7 +192,7 @@ public final class ChooseLockSettingsHelper { intent.putExtra(ConfirmDeviceCredentialBaseFragment.SHOW_WHEN_LOCKED, external); intent.putExtra(ChooseLockSettingsHelper.EXTRA_KEY_HAS_CHALLENGE, hasChallenge); intent.putExtra(ChooseLockSettingsHelper.EXTRA_KEY_CHALLENGE, challenge); - intent.putExtra(ChooseLockGeneric.KEY_USER_ID, userId); + intent.putExtra(Intent.EXTRA_USER_ID, userId); intent.setClassName(ConfirmDeviceCredentialBaseFragment.PACKAGE, activityClass.getName()); if (external) { intent.addFlags(Intent.FLAG_ACTIVITY_FORWARD_RESULT); diff --git a/src/com/android/settings/ProfileChallengePreferenceFragment.java b/src/com/android/settings/ProfileChallengePreferenceFragment.java new file mode 100644 index 00000000000..34c38f01b1a --- /dev/null +++ b/src/com/android/settings/ProfileChallengePreferenceFragment.java @@ -0,0 +1,193 @@ +/* + * 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.app.admin.DevicePolicyManager; +import android.content.Context; +import android.content.Intent; +import android.content.pm.UserInfo; +import android.os.Bundle; +import android.os.UserHandle; +import android.os.UserManager; +import android.provider.Settings; +import android.support.v14.preference.SwitchPreference; +import android.support.v7.preference.ListPreference; +import android.support.v7.preference.Preference; +import android.support.v7.preference.Preference.OnPreferenceChangeListener; +import android.support.v7.preference.Preference.OnPreferenceClickListener; +import android.support.v7.preference.PreferenceCategory; +import android.support.v7.preference.PreferenceGroup; +import android.support.v7.preference.PreferenceScreen; + +import com.android.internal.logging.MetricsLogger; +import com.android.internal.widget.LockPatternUtils; + +import java.util.Collections; +import java.util.HashSet; +import java.util.List; +import java.util.Set; + +/** + * Settings for the Profile Challenge. + */ +public class ProfileChallengePreferenceFragment extends SettingsPreferenceFragment + implements OnPreferenceChangeListener { + private static final String TAG = "WorkChallengePreferenceFragment"; + + private static final String KEY_UNLOCK_SET_OR_CHANGE = "unlock_set_or_change"; + private static final String KEY_VISIBLE_PATTERN = "visiblepattern"; + + private static final int SET_OR_CHANGE_LOCK_METHOD_REQUEST = 123; + + // Not all preferences make sense for the Work Challenge, this is a whitelist. + private static final Set ALLOWED_PREFERENCE_KEYS = new HashSet<>(); + { + ALLOWED_PREFERENCE_KEYS.add(KEY_UNLOCK_SET_OR_CHANGE); + ALLOWED_PREFERENCE_KEYS.add(KEY_VISIBLE_PATTERN); + } + // These switch preferences need special handling since they're not all stored in Settings. + private static final Set SWITCH_PREFERENCE_KEYS = new HashSet<>(); + { + SWITCH_PREFERENCE_KEYS.add(KEY_VISIBLE_PATTERN); + } + + private LockPatternUtils mLockPatternUtils; + private int mProfileUserId; + + private SwitchPreference mVisiblePattern; + + @Override + protected int getMetricsCategory() { + return MetricsLogger.PROFILE_CHALLENGE; + } + + @Override + public void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + + mLockPatternUtils = new LockPatternUtils(getActivity()); + + mProfileUserId = getArguments().getInt(Intent.EXTRA_USER_ID, -1); + if (mProfileUserId == -1) { + finish(); + } + } + + @Override + public boolean onPreferenceTreeClick(Preference preference) { + final String key = preference.getKey(); + if (KEY_UNLOCK_SET_OR_CHANGE.equals(key)) { + Bundle extras = new Bundle(); + extras.putInt(Intent.EXTRA_USER_ID, mProfileUserId); + startFragment(this, "com.android.settings.ChooseLockGeneric$ChooseLockGenericFragment", + R.string.lock_settings_picker_title, SET_OR_CHANGE_LOCK_METHOD_REQUEST, extras); + return true; + } + return super.onPreferenceTreeClick(preference); + } + + @Override + public boolean onPreferenceChange(Preference preference, Object value) { + final String key = preference.getKey(); + if (KEY_VISIBLE_PATTERN.equals(key)) { + mLockPatternUtils.setVisiblePatternEnabled((Boolean) value, mProfileUserId); + return true; + } + return false; + } + + @Override + public void onResume() { + super.onResume(); + + // Make sure we reload the preference hierarchy since some of these settings + // depend on others... + createPreferenceHierarchy(); + + if (mVisiblePattern != null) { + mVisiblePattern.setChecked(mLockPatternUtils.isVisiblePatternEnabled( + mProfileUserId)); + } + } + + private void createPreferenceHierarchy() { + PreferenceScreen root = getPreferenceScreen(); + if (root != null) { + root.removeAll(); + } + addPreferencesFromResource(R.xml.profile_challenge_settings); + root = getPreferenceScreen(); + + // Add options for lock/unlock screen + final int resid = getResIdForLockUnlockScreen(getActivity(), mLockPatternUtils); + addPreferencesFromResource(resid); + + mVisiblePattern = (SwitchPreference) root.findPreference(KEY_VISIBLE_PATTERN); + + removeNonWhitelistedItems(root); + } + + private void removeNonWhitelistedItems(PreferenceGroup prefScreen) { + int numPreferences = prefScreen.getPreferenceCount(); + int i = 0; + while (i < numPreferences) { + final Preference pref = prefScreen.getPreference(i); + // Recursively look into categories and remove them if they are empty. + if (pref instanceof PreferenceCategory) { + PreferenceCategory category = (PreferenceCategory) pref; + removeNonWhitelistedItems(category); + if (category.getPreferenceCount() == 0) { + prefScreen.removePreference(category); + --i; + --numPreferences; + } + } else if (ALLOWED_PREFERENCE_KEYS.contains(pref.getKey())) { + if (SWITCH_PREFERENCE_KEYS.contains(pref.getKey())) { + pref.setOnPreferenceChangeListener(this); + } + } else { + prefScreen.removePreference(pref); + --i; + --numPreferences; + } + ++i; + } + } + + private int getResIdForLockUnlockScreen(Context context, + LockPatternUtils lockPatternUtils) { + int resid = 0; + if (!lockPatternUtils.isSecure(mProfileUserId)) { + resid = R.xml.security_settings_lockscreen; + } else { + switch (lockPatternUtils.getKeyguardStoredPasswordQuality(mProfileUserId)) { + case DevicePolicyManager.PASSWORD_QUALITY_SOMETHING: + resid = R.xml.security_settings_pattern; + break; + case DevicePolicyManager.PASSWORD_QUALITY_NUMERIC: + case DevicePolicyManager.PASSWORD_QUALITY_NUMERIC_COMPLEX: + resid = R.xml.security_settings_pin; + break; + case DevicePolicyManager.PASSWORD_QUALITY_ALPHABETIC: + case DevicePolicyManager.PASSWORD_QUALITY_ALPHANUMERIC: + case DevicePolicyManager.PASSWORD_QUALITY_COMPLEX: + resid = R.xml.security_settings_password; + break; + } + } + return resid; + } +} diff --git a/src/com/android/settings/SecuritySettings.java b/src/com/android/settings/SecuritySettings.java index 4ce76ce4951..4e9447eecbc 100644 --- a/src/com/android/settings/SecuritySettings.java +++ b/src/com/android/settings/SecuritySettings.java @@ -26,6 +26,7 @@ import android.content.DialogInterface; import android.content.Intent; 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; @@ -79,6 +80,7 @@ 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"; @@ -138,6 +140,8 @@ public class SecuritySettings extends SettingsPreferenceFragment private Intent mTrustAgentClickIntent; private Preference mOwnerInfoPref; + private int mProfileChallengeUserId; + @Override protected int getMetricsCategory() { return MetricsLogger.SECURITY; @@ -209,6 +213,20 @@ public class SecuritySettings extends SettingsPreferenceFragment final int resid = getResIdForLockUnlockScreen(getActivity(), mLockPatternUtils); addPreferencesFromResource(resid); + List profiles = mUm.getProfiles(UserHandle.myUserId()); + int numProfiles = profiles.size(); + if (numProfiles > 1) { + for (int i = 0; i < numProfiles; ++i) { + UserInfo profile = profiles.get(i); + if (profile.id != UserHandle.myUserId()) { + mProfileChallengeUserId = profile.id; + } + } + if (LockPatternUtils.isSeparateWorkChallengeEnabled()) { + addPreferencesFromResource(R.xml.security_settings_profile); + } + } + // Add options for device encryption mIsAdmin = mUm.isAdminUser(); @@ -655,6 +673,11 @@ public class SecuritySettings extends SettingsPreferenceFragment if (KEY_UNLOCK_SET_OR_CHANGE.equals(key)) { startFragment(this, "com.android.settings.ChooseLockGeneric$ChooseLockGenericFragment", R.string.lock_settings_picker_title, SET_OR_CHANGE_LOCK_METHOD_REQUEST, null); + } else if (KEY_UNLOCK_SET_OR_CHANGE_PROFILE.equals(key)) { + Bundle extras = new Bundle(); + extras.putInt(Intent.EXTRA_USER_ID, mProfileChallengeUserId); + startFragment(this, "com.android.settings.ProfileChallengePreferenceFragment", + R.string.lock_settings_profile_label, SET_OR_CHANGE_LOCK_METHOD_REQUEST, extras); } else if (KEY_TRUST_AGENT.equals(key)) { ChooseLockSettingsHelper helper = new ChooseLockSettingsHelper(this.getActivity(), this); @@ -752,6 +775,13 @@ public class SecuritySettings extends SettingsPreferenceFragment result.add(sir); final UserManager um = UserManager.get(context); + boolean hasChildProfile = um.getProfiles(UserHandle.myUserId()).size() > 1; + if (hasChildProfile && LockPatternUtils.isSeparateWorkChallengeEnabled()) { + sir = new SearchIndexableResource(context); + sir.xmlResId = R.xml.security_settings_profile; + result.add(sir); + } + if (um.isAdminUser()) { DevicePolicyManager dpm = (DevicePolicyManager) context.getSystemService(Context.DEVICE_POLICY_SERVICE); diff --git a/src/com/android/settings/SettingsActivity.java b/src/com/android/settings/SettingsActivity.java index ba975a2c2e7..3014225c841 100644 --- a/src/com/android/settings/SettingsActivity.java +++ b/src/com/android/settings/SettingsActivity.java @@ -335,6 +335,17 @@ public class SettingsActivity extends SettingsDrawerActivity } }; + private final BroadcastReceiver mUserAddRemoveReceiver = new BroadcastReceiver() { + @Override + public void onReceive(Context context, Intent intent) { + String action = intent.getAction(); + if (action.equals(Intent.ACTION_USER_ADDED) + || action.equals(Intent.ACTION_USER_REMOVED)) { + Index.getInstance(getApplicationContext()).update(); + } + } + }; + private final DynamicIndexableContentMonitor mDynamicIndexableContentMonitor = new DynamicIndexableContentMonitor(); @@ -752,6 +763,8 @@ public class SettingsActivity extends SettingsDrawerActivity mDevelopmentPreferencesListener); registerReceiver(mBatteryInfoReceiver, new IntentFilter(Intent.ACTION_BATTERY_CHANGED)); + registerReceiver(mUserAddRemoveReceiver, new IntentFilter(Intent.ACTION_USER_ADDED)); + registerReceiver(mUserAddRemoveReceiver, new IntentFilter(Intent.ACTION_USER_REMOVED)); mDynamicIndexableContentMonitor.register(this); diff --git a/src/com/android/settings/Utils.java b/src/com/android/settings/Utils.java index ddea92b24be..9aa040388cf 100644 --- a/src/com/android/settings/Utils.java +++ b/src/com/android/settings/Utils.java @@ -1026,7 +1026,7 @@ public final class Utils { if (bundle == null) { return getEffectiveUserId(context); } - int userId = bundle.getInt(ChooseLockGeneric.KEY_USER_ID, UserHandle.myUserId()); + int userId = bundle.getInt(Intent.EXTRA_USER_ID, UserHandle.myUserId()); return getSameOwnerUserId(context, userId); }