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);
     }