Merge "Add profile policy to set work challenge background color"
diff --git a/api/current.txt b/api/current.txt
index 9de0af6..e50eba1 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -5807,6 +5807,7 @@
     method public java.lang.String getLongSupportMessage(android.content.ComponentName);
     method public int getMaximumFailedPasswordsForWipe(android.content.ComponentName);
     method public long getMaximumTimeToLock(android.content.ComponentName);
+    method public int getOrganizationColor(android.content.ComponentName);
     method public boolean getPackageSuspended(android.content.ComponentName, java.lang.String);
     method public android.app.admin.DevicePolicyManager getParentProfileInstance(android.content.ComponentName);
     method public long getPasswordExpiration(android.content.ComponentName);
@@ -5875,6 +5876,7 @@
     method public void setMasterVolumeMuted(android.content.ComponentName, boolean);
     method public void setMaximumFailedPasswordsForWipe(android.content.ComponentName, int);
     method public void setMaximumTimeToLock(android.content.ComponentName, long);
+    method public void setOrganizationColor(android.content.ComponentName, int);
     method public boolean setPackageSuspended(android.content.ComponentName, java.lang.String, boolean);
     method public void setPasswordExpirationTimeout(android.content.ComponentName, long);
     method public void setPasswordHistoryLength(android.content.ComponentName, int);
diff --git a/api/system-current.txt b/api/system-current.txt
index e723d099..2d358bf 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -5947,6 +5947,7 @@
     method public java.lang.String getLongSupportMessage(android.content.ComponentName);
     method public int getMaximumFailedPasswordsForWipe(android.content.ComponentName);
     method public long getMaximumTimeToLock(android.content.ComponentName);
+    method public int getOrganizationColor(android.content.ComponentName);
     method public boolean getPackageSuspended(android.content.ComponentName, java.lang.String);
     method public android.app.admin.DevicePolicyManager getParentProfileInstance(android.content.ComponentName);
     method public long getPasswordExpiration(android.content.ComponentName);
@@ -6021,6 +6022,7 @@
     method public void setMasterVolumeMuted(android.content.ComponentName, boolean);
     method public void setMaximumFailedPasswordsForWipe(android.content.ComponentName, int);
     method public void setMaximumTimeToLock(android.content.ComponentName, long);
+    method public void setOrganizationColor(android.content.ComponentName, int);
     method public boolean setPackageSuspended(android.content.ComponentName, java.lang.String, boolean);
     method public void setPasswordExpirationTimeout(android.content.ComponentName, long);
     method public void setPasswordHistoryLength(android.content.ComponentName, int);
diff --git a/api/test-current.txt b/api/test-current.txt
index e39efca..bcdf5c1 100644
--- a/api/test-current.txt
+++ b/api/test-current.txt
@@ -5809,6 +5809,7 @@
     method public java.lang.String getLongSupportMessage(android.content.ComponentName);
     method public int getMaximumFailedPasswordsForWipe(android.content.ComponentName);
     method public long getMaximumTimeToLock(android.content.ComponentName);
+    method public int getOrganizationColor(android.content.ComponentName);
     method public boolean getPackageSuspended(android.content.ComponentName, java.lang.String);
     method public android.app.admin.DevicePolicyManager getParentProfileInstance(android.content.ComponentName);
     method public long getPasswordExpiration(android.content.ComponentName);
@@ -5877,6 +5878,7 @@
     method public void setMasterVolumeMuted(android.content.ComponentName, boolean);
     method public void setMaximumFailedPasswordsForWipe(android.content.ComponentName, int);
     method public void setMaximumTimeToLock(android.content.ComponentName, long);
+    method public void setOrganizationColor(android.content.ComponentName, int);
     method public boolean setPackageSuspended(android.content.ComponentName, java.lang.String, boolean);
     method public void setPasswordExpirationTimeout(android.content.ComponentName, long);
     method public void setPasswordHistoryLength(android.content.ComponentName, int);
diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java
index 20cacff..a655bfd 100644
--- a/core/java/android/app/admin/DevicePolicyManager.java
+++ b/core/java/android/app/admin/DevicePolicyManager.java
@@ -5142,4 +5142,55 @@
             return null;
         }
     }
+
+    /**
+     * Called by a profile owner of a managed profile to set the color used for customization.
+     * This color is used as background color of the confirm credentials screen for that user.
+     * The default color is {@link android.graphics.Color#GRAY}.
+     *
+     * <p>The confirm credentials screen can be created using
+     * {@link android.app.KeyguardManager#createConfirmDeviceCredentialIntent}.
+     *
+     * @param admin Which {@link DeviceAdminReceiver} this request is associated with.
+     * @param color The 32bit representation of the color to be used.
+     */
+    public void setOrganizationColor(@NonNull ComponentName admin, int color) {
+        try {
+            mService.setOrganizationColor(admin, color);
+        } catch (RemoteException re) {
+            Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, re);
+        }
+    }
+
+    /**
+     * Called by a profile owner of a managed profile to retrieve the color used for customization.
+     * This color is used as background color of the confirm credentials screen for that user.
+     *
+     * @param admin Which {@link DeviceAdminReceiver} this request is associated with.
+     * @return The 32bit representation of the color to be used.
+     */
+    public int getOrganizationColor(@NonNull ComponentName admin) {
+        try {
+            return mService.getOrganizationColor(admin);
+        } catch (RemoteException re) {
+            Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, re);
+            return 0;
+        }
+    }
+
+    /**
+     * @hide
+     * Retrieve the customization color for a given user.
+     *
+     * @param userHandle The user id of the user we're interested in.
+     * @return The 32bit representation of the color to be used.
+     */
+    public int getOrganizationColorForUser(int userHandle) {
+        try {
+            return mService.getOrganizationColorForUser(userHandle);
+        } catch (RemoteException re) {
+            Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, re);
+            return 0;
+        }
+    }
 }
diff --git a/core/java/android/app/admin/IDevicePolicyManager.aidl b/core/java/android/app/admin/IDevicePolicyManager.aidl
index 08cab88..82115a2 100644
--- a/core/java/android/app/admin/IDevicePolicyManager.aidl
+++ b/core/java/android/app/admin/IDevicePolicyManager.aidl
@@ -263,4 +263,8 @@
     String getLongSupportMessageForUser(in ComponentName admin, int userHandle);
 
     boolean isSeparateProfileChallengeAllowed(int userHandle);
+
+    void setOrganizationColor(in ComponentName admin, in int color);
+    int getOrganizationColor(in ComponentName admin);
+    int getOrganizationColorForUser(int userHandle);
 }
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
index eb75914..f68a299 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
@@ -67,6 +67,7 @@
 import android.content.pm.UserInfo;
 import android.database.ContentObserver;
 import android.graphics.Bitmap;
+import android.graphics.Color;
 import android.media.AudioManager;
 import android.media.IAudioService;
 import android.net.ConnectivityManager;
@@ -487,6 +488,7 @@
         private static final String TAG_SHORT_SUPPORT_MESSAGE = "short-support-message";
         private static final String TAG_LONG_SUPPORT_MESSAGE = "long-support-message";
         private static final String TAG_PARENT_ADMIN = "parent-admin";
+        private static final String TAG_ORGANIZATION_COLOR = "organization-color";
 
         final DeviceAdminInfo info;
 
@@ -580,6 +582,10 @@
         String shortSupportMessage = null;
         String longSupportMessage = null;
 
+        // Background color of confirm credentials screen. Default: gray.
+        static final int DEF_ORGANIZATION_COLOR = Color.GRAY;
+        int organizationColor = DEF_ORGANIZATION_COLOR;
+
         ActiveAdmin(DeviceAdminInfo _info, boolean parent) {
             info = _info;
             isParent = parent;
@@ -787,6 +793,11 @@
                 parentAdmin.writeToXml(out);
                 out.endTag(null, TAG_PARENT_ADMIN);
             }
+            if (organizationColor != DEF_ORGANIZATION_COLOR) {
+                out.startTag(null, TAG_ORGANIZATION_COLOR);
+                out.attribute(null, ATTR_VALUE, Integer.toString(organizationColor));
+                out.endTag(null, TAG_ORGANIZATION_COLOR);
+            }
         }
 
         void writePackageListToXml(XmlSerializer out, String outerTag,
@@ -920,6 +931,9 @@
                 } else if (TAG_PARENT_ADMIN.equals(tag)) {
                     parentAdmin = new ActiveAdmin(info, /* parent */ true);
                     parentAdmin.readFromXml(parser);
+                } else if (TAG_ORGANIZATION_COLOR.equals(tag)) {
+                    organizationColor = Integer.parseInt(
+                            parser.getAttributeValue(null, ATTR_VALUE));
                 } else {
                     Slog.w(LOG_TAG, "Unknown admin tag: " + tag);
                     XmlUtils.skipCurrentTag(parser);
@@ -7685,4 +7699,46 @@
         }
         return null;
     }
+
+    @Override
+    public void setOrganizationColor(@NonNull ComponentName who, int color) {
+        final int userHandle = mInjector.userHandleGetCallingUserId();
+        if (!mHasFeature || !isManagedProfile(userHandle)) {
+            return;
+        }
+        Preconditions.checkNotNull(who, "ComponentName is null");
+        synchronized (this) {
+            ActiveAdmin admin = getActiveAdminForCallerLocked(who,
+                    DeviceAdminInfo.USES_POLICY_PROFILE_OWNER);
+            admin.organizationColor = color;
+            saveSettingsLocked(userHandle);
+        }
+    }
+
+    @Override
+    public int getOrganizationColor(@NonNull ComponentName who) {
+        final int userHandle = mInjector.userHandleGetCallingUserId();
+        if (!mHasFeature || !isManagedProfile(userHandle)) {
+            return ActiveAdmin.DEF_ORGANIZATION_COLOR;
+        }
+        synchronized (this) {
+            ActiveAdmin admin = getActiveAdminForCallerLocked(who,
+                    DeviceAdminInfo.USES_POLICY_PROFILE_OWNER);
+            return admin.organizationColor;
+        }
+    }
+
+    @Override
+    public int getOrganizationColorForUser(int userHandle) {
+        if (!mHasFeature || !isManagedProfile(userHandle)) {
+            return ActiveAdmin.DEF_ORGANIZATION_COLOR;
+        }
+        enforceCrossUsersPermission(userHandle);
+        synchronized (this) {
+            ActiveAdmin profileOwner = getProfileOwnerAdminLocked(userHandle);
+            return (profileOwner != null)
+                    ? profileOwner.organizationColor
+                    : ActiveAdmin.DEF_ORGANIZATION_COLOR;
+        }
+    }
 }