Merge "Allowing profile to set a subset of keyguard restrictions." into mnc-dev
diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java
index 1bbbb8e..55ff85a 100644
--- a/core/java/android/app/admin/DevicePolicyManager.java
+++ b/core/java/android/app/admin/DevicePolicyManager.java
@@ -2523,13 +2523,26 @@
      * {@link DeviceAdminInfo#USES_POLICY_DISABLE_KEYGUARD_FEATURES} to be able to call
      * this method; if it has not, a security exception will be thrown.
      *
-     * <p>Calling this from a managed profile will throw a security exception.
+     * <p>Calling this from a managed profile before version
+     * {@link android.os.Build.VERSION_CODES#MNC} will throw a security exception.
+     *
+     * <p>From version {@link android.os.Build.VERSION_CODES#MNC} a profile owner can set:
+     * <ul>
+     * <li>{@link #KEYGUARD_DISABLE_TRUST_AGENTS}, {@link #KEYGUARD_DISABLE_FINGERPRINT}
+     *      these will affect the profile's parent user.
+     * <li>{@link #KEYGUARD_DISABLE_UNREDACTED_NOTIFICATIONS} this will affect notifications
+     * generated by applications in the managed profile.
+     * </ul>
+     * <p>Requests to disable other features on a managed profile will be ignored. The admin
+     * can check which features have been disabled by calling
+     * {@link #getKeyguardDisabledFeatures(ComponentName)}
      *
      * @param admin Which {@link DeviceAdminReceiver} this request is associated with.
      * @param which {@link #KEYGUARD_DISABLE_FEATURES_NONE} (default),
      * {@link #KEYGUARD_DISABLE_WIDGETS_ALL}, {@link #KEYGUARD_DISABLE_SECURE_CAMERA},
      * {@link #KEYGUARD_DISABLE_SECURE_NOTIFICATIONS}, {@link #KEYGUARD_DISABLE_TRUST_AGENTS},
-     * {@link #KEYGUARD_DISABLE_UNREDACTED_NOTIFICATIONS}, {@link #KEYGUARD_DISABLE_FEATURES_ALL}
+     * {@link #KEYGUARD_DISABLE_UNREDACTED_NOTIFICATIONS}, {@link #KEYGUARD_DISABLE_FINGERPRINT},
+     * {@link #KEYGUARD_DISABLE_FEATURES_ALL}
      */
     public void setKeyguardDisabledFeatures(ComponentName admin, int which) {
         if (mService != null) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
index 588ec26..2913c7d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
@@ -395,11 +395,6 @@
                                 Toast.LENGTH_SHORT).show();
                     }
                 }
-            } else if (DevicePolicyManager.ACTION_DEVICE_POLICY_MANAGER_STATE_CHANGED.equals(
-                    action)) {
-                mUsersAllowingPrivateNotifications.clear();
-                updateLockscreenNotificationSetting();
-                updateNotifications();
             } else if (BANNER_ACTION_CANCEL.equals(action) || BANNER_ACTION_SETUP.equals(action)) {
                 NotificationManager noMan = (NotificationManager)
                         mContext.getSystemService(Context.NOTIFICATION_SERVICE);
@@ -419,6 +414,19 @@
         }
     };
 
+    private final BroadcastReceiver mAllUsersReceiver = new BroadcastReceiver() {
+        @Override
+        public void onReceive(Context context, Intent intent) {
+            String action = intent.getAction();
+            if (DevicePolicyManager.ACTION_DEVICE_POLICY_MANAGER_STATE_CHANGED.equals(action) &&
+                    isCurrentProfile(getSendingUserId())) {
+                mUsersAllowingPrivateNotifications.clear();
+                updateLockscreenNotificationSetting();
+                updateNotifications();
+            }
+        }
+    };
+
     private final NotificationListenerService mNotificationListener =
             new NotificationListenerService() {
         @Override
@@ -631,9 +639,13 @@
         filter.addAction(Intent.ACTION_USER_PRESENT);
         filter.addAction(BANNER_ACTION_CANCEL);
         filter.addAction(BANNER_ACTION_SETUP);
-        filter.addAction(DevicePolicyManager.ACTION_DEVICE_POLICY_MANAGER_STATE_CHANGED);
         mContext.registerReceiver(mBroadcastReceiver, filter);
 
+        IntentFilter allUsersFilter = new IntentFilter();
+        allUsersFilter.addAction(
+                DevicePolicyManager.ACTION_DEVICE_POLICY_MANAGER_STATE_CHANGED);
+        mContext.registerReceiverAsUser(mAllUsersReceiver, UserHandle.ALL, allUsersFilter,
+                null, null);
         updateCurrentProfilesCache();
     }
 
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
index 675be0e..822ffd3 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
@@ -246,6 +246,17 @@
         GLOBAL_SETTINGS_WHITELIST.add(Settings.Global.STAY_ON_WHILE_PLUGGED_IN);
     }
 
+    // Keyguard features that when set of a profile will affect the profiles
+    // parent user.
+    private static final int PROFILE_KEYGUARD_FEATURES_AFFECT_OWNER =
+            DevicePolicyManager.KEYGUARD_DISABLE_TRUST_AGENTS
+            | DevicePolicyManager.KEYGUARD_DISABLE_FINGERPRINT;
+
+    // Keyguard features that are allowed to be set on a managed profile
+    private static final int PROFILE_KEYGUARD_FEATURES =
+            PROFILE_KEYGUARD_FEATURES_AFFECT_OWNER
+            | DevicePolicyManager.KEYGUARD_DISABLE_UNREDACTED_NOTIFICATIONS;
+
     final Context mContext;
     final UserManager mUserManager;
     final PowerManager.WakeLock mWakeLock;
@@ -3957,7 +3968,9 @@
         }
         Preconditions.checkNotNull(who, "ComponentName is null");
         final int userHandle = UserHandle.getCallingUserId();
-        enforceNotManagedProfile(userHandle, "disable keyguard features");
+        if (isManagedProfile(userHandle)) {
+            which = which & PROFILE_KEYGUARD_FEATURES;
+        }
         synchronized (this) {
             ActiveAdmin ap = getActiveAdminForCallerLocked(who,
                     DeviceAdminInfo.USES_POLICY_DISABLE_KEYGUARD_FEATURES);
@@ -3978,21 +3991,50 @@
             return 0;
         }
         enforceCrossUserPermission(userHandle);
-        synchronized (this) {
-            if (who != null) {
-                ActiveAdmin admin = getActiveAdminUncheckedLocked(who, userHandle);
-                return (admin != null) ? admin.disabledKeyguardFeatures : 0;
-            }
+        long ident = Binder.clearCallingIdentity();
+        try {
+            synchronized (this) {
+                if (who != null) {
+                    ActiveAdmin admin = getActiveAdminUncheckedLocked(who, userHandle);
+                    return (admin != null) ? admin.disabledKeyguardFeatures : 0;
+                }
 
-            // Determine which keyguard features are disabled for any active admins.
-            DevicePolicyData policy = getUserData(userHandle);
-            final int N = policy.mAdminList.size();
-            int which = 0;
-            for (int i = 0; i < N; i++) {
-                ActiveAdmin admin = policy.mAdminList.get(i);
-                which |= admin.disabledKeyguardFeatures;
+                UserInfo user = mUserManager.getUserInfo(userHandle);
+                final List<UserInfo> profiles;
+                if (user.isManagedProfile()) {
+                    // If we are being asked about a managed profile just return
+                    // keyguard features disabled by admins in the profile.
+                    profiles = new ArrayList<UserInfo>(1);
+                    profiles.add(user);
+                } else {
+                    // Otherwise return those set by admins in the user
+                    // and its profiles.
+                    profiles = mUserManager.getProfiles(userHandle);
+                }
+
+                // Determine which keyguard features are disabled by any active admin.
+                int which = 0;
+                for (UserInfo userInfo : profiles) {
+                    DevicePolicyData policy = getUserData(userInfo.id);
+                    final int N = policy.mAdminList.size();
+                    for (int i = 0; i < N; i++) {
+                        ActiveAdmin admin = policy.mAdminList.get(i);
+                        if (userInfo.id == userHandle || !userInfo.isManagedProfile()) {
+                            // If we are being asked explictly about this user
+                            // return all disabled features even if its a managed profile.
+                            which |= admin.disabledKeyguardFeatures;
+                        } else {
+                            // Otherwise a managed profile is only allowed to disable
+                            // some features on the parent user.
+                            which |= (admin.disabledKeyguardFeatures
+                                    & PROFILE_KEYGUARD_FEATURES_AFFECT_OWNER);
+                        }
+                    }
+                }
+                return which;
             }
-            return which;
+        } finally {
+            Binder.restoreCallingIdentity(ident);
         }
     }