Merge "Work Profile Passphrase Setting"
diff --git a/res/values/strings.xml b/res/values/strings.xml
index fd359bc..bb6bbc0 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -3015,6 +3015,12 @@
<!-- Displayed when user launches a widget configuration activity that was uninstalled -->
<string name="activity_not_found">Application is not installed on your phone.</string>
+ <!-- Profile Lock settings -->
+ <!-- Security & location settings screen, header for profile specific section -->
+ <string name="lock_settings_profile_title">Work profile</string>
+ <!-- Security & location settings screen, setting option name -->
+ <string name="lock_settings_profile_label">Work profile security</string>
+
<!-- Applications Settings --> <skip />
<!-- Applications settings screen, setting option name for the user to go to the screen to manage installed applications -->
<string name="manageapplications_settings_title">Manage apps</string>
@@ -5562,6 +5568,7 @@
<string name="keywords_ignore_optimizations">ignore optimizations, doze, app standby</string>
<string name="keywords_color_mode">vibrant, RGB, sRGB, color, natural, standard</string>
<string name="keywords_lockscreen">slide to unlock, password, pattern, PIN</string>
+ <string name="keywords_profile_challenge">work challenge, work, profile</string>
<!-- NFC Wi-Fi pairing/setup strings-->
diff --git a/res/xml/profile_challenge_settings.xml b/res/xml/profile_challenge_settings.xml
new file mode 100644
index 0000000..cd61119
--- /dev/null
+++ b/res/xml/profile_challenge_settings.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2008 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android"
+ android:title="@string/lock_settings_profile_label">
+
+</PreferenceScreen>
diff --git a/res/xml/security_settings_profile.xml b/res/xml/security_settings_profile.xml
new file mode 100644
index 0000000..1c10b79
--- /dev/null
+++ b/res/xml/security_settings_profile.xml
@@ -0,0 +1,33 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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.
+-->
+
+<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:settings="http://schemas.android.com/apk/res/com.android.settings"
+ android:title="@string/lock_settings_picker_title">
+
+ <PreferenceCategory
+ android:key="security_category_profile"
+ android:title="@string/lock_settings_profile_title">
+
+ <PreferenceScreen
+ android:key="profile_challenge"
+ android:title="@string/lock_settings_profile_label"
+ settings:keywords="@string/keywords_profile_challenge"
+ android:persistent="false"/>
+
+ </PreferenceCategory>
+
+</PreferenceScreen>
diff --git a/src/com/android/settings/ChooseLockGeneric.java b/src/com/android/settings/ChooseLockGeneric.java
index 73f8c46..2641ad2 100644
--- a/src/com/android/settings/ChooseLockGeneric.java
+++ b/src/com/android/settings/ChooseLockGeneric.java
@@ -48,7 +48,6 @@
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 @@
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 cf330ad..eacf1ab 100644
--- a/src/com/android/settings/ChooseLockPassword.java
+++ b/src/com/android/settings/ChooseLockPassword.java
@@ -87,7 +87,7 @@
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 @@
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 @@
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 4a6008c..e20db93 100644
--- a/src/com/android/settings/ChooseLockPattern.java
+++ b/src/com/android/settings/ChooseLockPattern.java
@@ -78,7 +78,7 @@
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 53fbb7f..b88dea2 100644
--- a/src/com/android/settings/ChooseLockSettingsHelper.java
+++ b/src/com/android/settings/ChooseLockSettingsHelper.java
@@ -192,7 +192,7 @@
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 0000000..34c38f0
--- /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<String> 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<String> 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 4ce76ce..4e9447e 100644
--- a/src/com/android/settings/SecuritySettings.java
+++ b/src/com/android/settings/SecuritySettings.java
@@ -26,6 +26,7 @@
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 @@
// 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 @@
private Intent mTrustAgentClickIntent;
private Preference mOwnerInfoPref;
+ private int mProfileChallengeUserId;
+
@Override
protected int getMetricsCategory() {
return MetricsLogger.SECURITY;
@@ -209,6 +213,20 @@
final int resid = getResIdForLockUnlockScreen(getActivity(), mLockPatternUtils);
addPreferencesFromResource(resid);
+ List<UserInfo> 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 @@
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 @@
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 ba975a2..3014225 100644
--- a/src/com/android/settings/SettingsActivity.java
+++ b/src/com/android/settings/SettingsActivity.java
@@ -335,6 +335,17 @@
}
};
+ 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 @@
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 ddea92b..9aa0403 100644
--- a/src/com/android/settings/Utils.java
+++ b/src/com/android/settings/Utils.java
@@ -1026,7 +1026,7 @@
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);
}