Add policy to set the organization name
We allow the profile owner of a managed profile to set the name of the
managed organization.
This name is used as the default header message shown in the confirm
credentials screen a.k.a. work challenge.
Bug: 26638631
Change-Id: I03c5acc9fffe06cdb9d0d60dd1580b20e21783b1
diff --git a/api/current.txt b/api/current.txt
index aa503af1..327ab21 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -5821,6 +5821,7 @@
method public int getMaximumFailedPasswordsForWipe(android.content.ComponentName);
method public long getMaximumTimeToLock(android.content.ComponentName);
method public int getOrganizationColor(android.content.ComponentName);
+ method public java.lang.String getOrganizationName(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);
@@ -5890,6 +5891,7 @@
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 void setOrganizationName(android.content.ComponentName, java.lang.String);
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 95c19d7..3869a59 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -5961,6 +5961,7 @@
method public int getMaximumFailedPasswordsForWipe(android.content.ComponentName);
method public long getMaximumTimeToLock(android.content.ComponentName);
method public int getOrganizationColor(android.content.ComponentName);
+ method public java.lang.String getOrganizationName(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);
@@ -6036,6 +6037,7 @@
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 void setOrganizationName(android.content.ComponentName, java.lang.String);
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 081c471..45b0ea8 100644
--- a/api/test-current.txt
+++ b/api/test-current.txt
@@ -5823,6 +5823,7 @@
method public int getMaximumFailedPasswordsForWipe(android.content.ComponentName);
method public long getMaximumTimeToLock(android.content.ComponentName);
method public int getOrganizationColor(android.content.ComponentName);
+ method public java.lang.String getOrganizationName(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);
@@ -5892,6 +5893,7 @@
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 void setOrganizationName(android.content.ComponentName, java.lang.String);
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 e4e97a1..c79c407 100644
--- a/core/java/android/app/admin/DevicePolicyManager.java
+++ b/core/java/android/app/admin/DevicePolicyManager.java
@@ -3346,6 +3346,10 @@
* <p>If the device owner information contains only whitespaces then the message on the lock
* screen will be blank and the user will not be allowed to change it.
*
+ * <p>If the device owner information needs to be localized, it is the responsibility of the
+ * {@link DeviceAdminReceiver} to listen to the {@link Intent#ACTION_LOCALE_CHANGED} broadcast
+ * and set a new version of this string accordingly.
+ *
* @param admin The name of the admin component to check.
* @param info Device owner information which will be displayed instead of the user
* owner info.
@@ -5211,6 +5215,10 @@
* for support."
* If the message is longer than 200 characters it may be truncated.
*
+ * <p>If the short support message needs to be localized, it is the responsibility of the
+ * {@link DeviceAdminReceiver} to listen to the {@link Intent#ACTION_LOCALE_CHANGED} broadcast
+ * and set a new version of this string accordingly.
+ *
* @see #setLongSupportMessage
*
* @param admin Which {@link DeviceAdminReceiver} this request is associated with.
@@ -5250,6 +5258,10 @@
* Called by a device admin to set the long support message. This will
* be displayed to the user in the device administators settings screen.
*
+ * <p>If the long support message needs to be localized, it is the responsibility of the
+ * {@link DeviceAdminReceiver} to listen to the {@link Intent#ACTION_LOCALE_CHANGED} broadcast
+ * and set a new version of this string accordingly.
+ *
* @see #setShortSupportMessage
*
* @param admin Which {@link DeviceAdminReceiver} this request is associated with.
@@ -5414,6 +5426,58 @@
}
/**
+ * Called by a profile owner of a managed profile to set the name of the organization under
+ * management.
+ *
+ * <p>If the organization name needs to be localized, it is the responsibility of the
+ * {@link DeviceAdminReceiver} to listen to the {@link Intent#ACTION_LOCALE_CHANGED} broadcast
+ * and set a new version of this string accordingly.
+ *
+ * @param admin Which {@link DeviceAdminReceiver} this request is associated with.
+ * @param title The organization name or {@code null} to clear a previously set name.
+ */
+ public void setOrganizationName(@NonNull ComponentName admin, @Nullable String title) {
+ try {
+ mService.setOrganizationName(admin, title);
+ } catch (RemoteException re) {
+ Log.w(TAG, REMOTE_EXCEPTION_MESSAGE);
+ }
+ }
+
+ /**
+ * Called by a profile owner of a managed profile to retrieve the name of the organization
+ * under management.
+ *
+ * @param admin Which {@link DeviceAdminReceiver} this request is associated with.
+ * @return The organization name or {@code null} if none is set.
+ */
+ public String getOrganizationName(@NonNull ComponentName admin) {
+ try {
+ return mService.getOrganizationName(admin);
+ } catch (RemoteException re) {
+ Log.w(TAG, REMOTE_EXCEPTION_MESSAGE);
+ return null;
+ }
+ }
+
+ /**
+ * Retrieve the default title message used in the confirm credentials screen for a given user.
+ *
+ * @param userHandle The user id of the user we're interested in.
+ * @return The organization name or {@code null} if none is set.
+ *
+ * @hide
+ */
+ public String getOrganizationNameForUser(int userHandle) {
+ try {
+ return mService.getOrganizationNameForUser(userHandle);
+ } catch (RemoteException re) {
+ Log.w(TAG, REMOTE_EXCEPTION_MESSAGE);
+ return null;
+ }
+ }
+
+ /**
* @return the {@link UserProvisioningState} for the current user - for unmanaged users will
* return {@link #STATE_USER_UNMANAGED}
* @hide
diff --git a/core/java/android/app/admin/IDevicePolicyManager.aidl b/core/java/android/app/admin/IDevicePolicyManager.aidl
index 6333013..37d13e5 100644
--- a/core/java/android/app/admin/IDevicePolicyManager.aidl
+++ b/core/java/android/app/admin/IDevicePolicyManager.aidl
@@ -276,6 +276,10 @@
int getOrganizationColor(in ComponentName admin);
int getOrganizationColorForUser(int userHandle);
+ void setOrganizationName(in ComponentName admin, in String title);
+ String getOrganizationName(in ComponentName admin);
+ String getOrganizationNameForUser(int userHandle);
+
int getUserProvisioningState();
void setUserProvisioningState(int state, 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 236ae68e..dd786b2 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
@@ -509,6 +509,7 @@
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";
+ private static final String TAG_ORGANIZATION_NAME = "organization-name";
final DeviceAdminInfo info;
@@ -607,6 +608,9 @@
static final int DEF_ORGANIZATION_COLOR = Color.GRAY;
int organizationColor = DEF_ORGANIZATION_COLOR;
+ // Default title of confirm credentials screen
+ String organizationName = null;
+
ActiveAdmin(DeviceAdminInfo _info, boolean parent) {
info = _info;
isParent = parent;
@@ -830,6 +834,11 @@
out.attribute(null, ATTR_VALUE, Integer.toString(organizationColor));
out.endTag(null, TAG_ORGANIZATION_COLOR);
}
+ if (organizationName != null) {
+ out.startTag(null, TAG_ORGANIZATION_NAME);
+ out.text(organizationName);
+ out.endTag(null, TAG_ORGANIZATION_NAME);
+ }
}
void writePackageListToXml(XmlSerializer out, String outerTag,
@@ -971,6 +980,13 @@
} else if (TAG_ORGANIZATION_COLOR.equals(tag)) {
organizationColor = Integer.parseInt(
parser.getAttributeValue(null, ATTR_VALUE));
+ } else if (TAG_ORGANIZATION_NAME.equals(tag)) {
+ type = parser.next();
+ if (type == XmlPullParser.TEXT) {
+ organizationName = parser.getText();
+ } else {
+ Log.w(LOG_TAG, "Missing text when loading organization name");
+ }
} else {
Slog.w(LOG_TAG, "Unknown admin tag: " + tag);
XmlUtils.skipCurrentTag(parser);
@@ -1179,6 +1195,12 @@
pw.print(prefix); pw.print("keepUninstalledPackages=");
pw.println(keepUninstalledPackages);
}
+ pw.print(prefix); pw.print("organizationColor=");
+ pw.println(organizationColor);
+ if (organizationName != null) {
+ pw.print(prefix); pw.print("organizationName=");
+ pw.println(organizationName);
+ }
pw.print(prefix); pw.println("userRestrictions:");
UserRestrictionsUtils.dumpRestrictions(pw, prefix + " ", userRestrictions);
pw.print(prefix); pw.print("isParent=");
@@ -8097,11 +8119,12 @@
@Override
public void setOrganizationColor(@NonNull ComponentName who, int color) {
- final int userHandle = mInjector.userHandleGetCallingUserId();
- if (!mHasFeature || !isManagedProfile(userHandle)) {
+ if (!mHasFeature) {
return;
}
Preconditions.checkNotNull(who, "ComponentName is null");
+ final int userHandle = mInjector.userHandleGetCallingUserId();
+ enforceManagedProfile(userHandle, "set organization color");
synchronized (this) {
ActiveAdmin admin = getActiveAdminForCallerLocked(who,
DeviceAdminInfo.USES_POLICY_PROFILE_OWNER);
@@ -8112,11 +8135,11 @@
@Override
public int getOrganizationColor(@NonNull ComponentName who) {
- final int userHandle = mInjector.userHandleGetCallingUserId();
- if (!mHasFeature || !isManagedProfile(userHandle)) {
+ if (!mHasFeature) {
return ActiveAdmin.DEF_ORGANIZATION_COLOR;
}
Preconditions.checkNotNull(who, "ComponentName is null");
+ enforceManagedProfile(mInjector.userHandleGetCallingUserId(), "get organization color");
synchronized (this) {
ActiveAdmin admin = getActiveAdminForCallerLocked(who,
DeviceAdminInfo.USES_POLICY_PROFILE_OWNER);
@@ -8126,10 +8149,11 @@
@Override
public int getOrganizationColorForUser(int userHandle) {
- if (!mHasFeature || !isManagedProfile(userHandle)) {
+ if (!mHasFeature) {
return ActiveAdmin.DEF_ORGANIZATION_COLOR;
}
- enforceCrossUsersPermission(userHandle);
+ enforceFullCrossUsersPermission(userHandle);
+ enforceManagedProfile(userHandle, "get organization color");
synchronized (this) {
ActiveAdmin profileOwner = getProfileOwnerAdminLocked(userHandle);
return (profileOwner != null)
@@ -8139,6 +8163,53 @@
}
@Override
+ public void setOrganizationName(@NonNull ComponentName who, String text) {
+ if (!mHasFeature) {
+ return;
+ }
+ Preconditions.checkNotNull(who, "ComponentName is null");
+ final int userHandle = mInjector.userHandleGetCallingUserId();
+ enforceManagedProfile(userHandle, "set organization name");
+ synchronized (this) {
+ ActiveAdmin admin = getActiveAdminForCallerLocked(who,
+ DeviceAdminInfo.USES_POLICY_PROFILE_OWNER);
+ if (!TextUtils.equals(admin.organizationName, text)) {
+ admin.organizationName = TextUtils.nullIfEmpty(text);
+ saveSettingsLocked(userHandle);
+ }
+ }
+ }
+
+ @Override
+ public String getOrganizationName(@NonNull ComponentName who) {
+ if (!mHasFeature) {
+ return null;
+ }
+ Preconditions.checkNotNull(who, "ComponentName is null");
+ enforceManagedProfile(mInjector.userHandleGetCallingUserId(), "get organization name");
+ synchronized(this) {
+ ActiveAdmin admin = getActiveAdminForCallerLocked(who,
+ DeviceAdminInfo.USES_POLICY_PROFILE_OWNER);
+ return admin.organizationName;
+ }
+ }
+
+ @Override
+ public String getOrganizationNameForUser(int userHandle) {
+ if (!mHasFeature) {
+ return null;
+ }
+ enforceFullCrossUsersPermission(userHandle);
+ enforceManagedProfile(userHandle, "get organization name");
+ synchronized (this) {
+ ActiveAdmin profileOwner = getProfileOwnerAdminLocked(userHandle);
+ return (profileOwner != null)
+ ? profileOwner.organizationName
+ : null;
+ }
+ }
+
+ @Override
public void setAffiliationIds(ComponentName admin, List<String> ids) {
final Set<String> affiliationIds = new ArraySet<String>(ids);
final int callingUserId = mInjector.userHandleGetCallingUserId();