Merge changes from topic "overrideDrawables"
* changes: Send broadcast when a device policy resource is updated Add APIs to allow updating enterprise related drawables
This commit is contained in:
committed by
Android (Google) Code Review
commit
3c71e8fea8
@@ -7286,6 +7286,10 @@ package android.app.admin {
|
||||
method @Nullable public java.util.List<java.lang.String> getDelegatePackages(@NonNull android.content.ComponentName, @NonNull String);
|
||||
method @NonNull public java.util.List<java.lang.String> getDelegatedScopes(@Nullable android.content.ComponentName, @NonNull String);
|
||||
method public CharSequence getDeviceOwnerLockScreenInfo();
|
||||
method @Nullable public android.graphics.drawable.Drawable getDrawable(int, int, @NonNull java.util.concurrent.Callable<android.graphics.drawable.Drawable>);
|
||||
method @Nullable public android.graphics.drawable.Drawable getDrawable(int, int, int, @NonNull java.util.concurrent.Callable<android.graphics.drawable.Drawable>);
|
||||
method @Nullable public android.graphics.drawable.Drawable getDrawableForDensity(int, int, int, @NonNull java.util.concurrent.Callable<android.graphics.drawable.Drawable>);
|
||||
method @Nullable public android.graphics.drawable.Drawable getDrawableForDensity(int, int, int, int, @NonNull java.util.concurrent.Callable<android.graphics.drawable.Drawable>);
|
||||
method public CharSequence getEndUserSessionMessage(@NonNull android.content.ComponentName);
|
||||
method @NonNull public String getEnrollmentSpecificId();
|
||||
method @Nullable public android.app.admin.FactoryResetProtectionPolicy getFactoryResetProtectionPolicy(@Nullable android.content.ComponentName);
|
||||
@@ -7509,6 +7513,7 @@ package android.app.admin {
|
||||
field public static final String ACTION_CHECK_POLICY_COMPLIANCE = "android.app.action.CHECK_POLICY_COMPLIANCE";
|
||||
field public static final String ACTION_DEVICE_ADMIN_SERVICE = "android.app.action.DEVICE_ADMIN_SERVICE";
|
||||
field public static final String ACTION_DEVICE_OWNER_CHANGED = "android.app.action.DEVICE_OWNER_CHANGED";
|
||||
field public static final String ACTION_DEVICE_POLICY_RESOURCE_UPDATED = "android.app.action.DEVICE_POLICY_RESOURCE_UPDATED";
|
||||
field public static final String ACTION_GET_PROVISIONING_MODE = "android.app.action.GET_PROVISIONING_MODE";
|
||||
field public static final String ACTION_MANAGED_PROFILE_PROVISIONED = "android.app.action.MANAGED_PROFILE_PROVISIONED";
|
||||
field public static final String ACTION_PROFILE_OWNER_CHANGED = "android.app.action.PROFILE_OWNER_CHANGED";
|
||||
@@ -7584,6 +7589,8 @@ package android.app.admin {
|
||||
field public static final String EXTRA_PROVISIONING_WIFI_SECURITY_TYPE = "android.app.extra.PROVISIONING_WIFI_SECURITY_TYPE";
|
||||
field public static final String EXTRA_PROVISIONING_WIFI_SSID = "android.app.extra.PROVISIONING_WIFI_SSID";
|
||||
field public static final String EXTRA_PROVISIONING_WIFI_USER_CERTIFICATE = "android.app.extra.PROVISIONING_WIFI_USER_CERTIFICATE";
|
||||
field public static final String EXTRA_RESOURCE_ID = "android.app.extra.RESOURCE_ID";
|
||||
field public static final String EXTRA_RESOURCE_TYPE_DRAWABLE = "android.app.extra.RESOURCE_TYPE_DRAWABLE";
|
||||
field public static final int FLAG_EVICT_CREDENTIAL_ENCRYPTION_KEY = 1; // 0x1
|
||||
field public static final int FLAG_MANAGED_CAN_ACCESS_PARENT = 2; // 0x2
|
||||
field public static final int FLAG_PARENT_CAN_ACCESS_MANAGED = 1; // 0x1
|
||||
@@ -7678,6 +7685,35 @@ package android.app.admin {
|
||||
method public void onApplicationUserDataCleared(String, boolean);
|
||||
}
|
||||
|
||||
public final class DevicePolicyResources {
|
||||
ctor public DevicePolicyResources();
|
||||
}
|
||||
|
||||
public static final class DevicePolicyResources.Drawable {
|
||||
field public static final int INVALID_ID = -1; // 0xffffffff
|
||||
field public static final int WORK_PROFILE_ICON = 1; // 0x1
|
||||
field public static final int WORK_PROFILE_ICON_BADGE = 0; // 0x0
|
||||
field public static final int WORK_PROFILE_OFF_ICON = 2; // 0x2
|
||||
field public static final int WORK_PROFILE_USER_ICON = 3; // 0x3
|
||||
}
|
||||
|
||||
public static final class DevicePolicyResources.Drawable.Source {
|
||||
field public static final int HOME_WIDGET = 2; // 0x2
|
||||
field public static final int LAUNCHER_OFF_BUTTON = 3; // 0x3
|
||||
field public static final int NOTIFICATION = 0; // 0x0
|
||||
field public static final int PROFILE_SWITCH_ANIMATION = 1; // 0x1
|
||||
field public static final int QUICK_SETTINGS = 4; // 0x4
|
||||
field public static final int STATUS_BAR = 5; // 0x5
|
||||
field public static final int UNDEFINED = -1; // 0xffffffff
|
||||
}
|
||||
|
||||
public static final class DevicePolicyResources.Drawable.Style {
|
||||
field public static final int DEFAULT = -1; // 0xffffffff
|
||||
field public static final int OUTLINE = 2; // 0x2
|
||||
field public static final int SOLID_COLORED = 0; // 0x0
|
||||
field public static final int SOLID_NOT_COLORED = 1; // 0x1
|
||||
}
|
||||
|
||||
public final class DnsEvent extends android.app.admin.NetworkEvent implements android.os.Parcelable {
|
||||
method public String getHostname();
|
||||
method public java.util.List<java.net.InetAddress> getInetAddresses();
|
||||
|
||||
@@ -993,6 +993,18 @@ package android.app {
|
||||
|
||||
package android.app.admin {
|
||||
|
||||
public final class DevicePolicyDrawableResource implements android.os.Parcelable {
|
||||
ctor public DevicePolicyDrawableResource(@NonNull android.content.Context, int, int, int, @DrawableRes int);
|
||||
ctor public DevicePolicyDrawableResource(@NonNull android.content.Context, int, int, @DrawableRes int);
|
||||
method public int describeContents();
|
||||
method @DrawableRes public int getCallingPackageResourceId();
|
||||
method public int getDrawableId();
|
||||
method public int getDrawableSource();
|
||||
method public int getDrawableStyle();
|
||||
method public void writeToParcel(@NonNull android.os.Parcel, int);
|
||||
field @NonNull public static final android.os.Parcelable.Creator<android.app.admin.DevicePolicyDrawableResource> CREATOR;
|
||||
}
|
||||
|
||||
public class DevicePolicyKeyguardService extends android.app.Service {
|
||||
ctor public DevicePolicyKeyguardService();
|
||||
method @Nullable public void dismiss();
|
||||
@@ -1025,8 +1037,10 @@ package android.app.admin {
|
||||
method @RequiresPermission("android.permission.NOTIFY_PENDING_SYSTEM_UPDATE") public void notifyPendingSystemUpdate(long, boolean);
|
||||
method @RequiresPermission(android.Manifest.permission.INTERACT_ACROSS_USERS_FULL) public boolean packageHasActiveAdmins(String);
|
||||
method @RequiresPermission(android.Manifest.permission.MANAGE_PROFILE_AND_DEVICE_OWNERS) public void provisionFullyManagedDevice(@NonNull android.app.admin.FullyManagedDeviceProvisioningParams) throws android.app.admin.ProvisioningException;
|
||||
method @RequiresPermission(android.Manifest.permission.UPDATE_DEVICE_MANAGEMENT_RESOURCES) public void resetDrawables(@NonNull int[]);
|
||||
method @Deprecated @RequiresPermission(android.Manifest.permission.MANAGE_DEVICE_ADMINS) public boolean setActiveProfileOwner(@NonNull android.content.ComponentName, String) throws java.lang.IllegalArgumentException;
|
||||
method @RequiresPermission(android.Manifest.permission.MANAGE_USERS) public void setDeviceProvisioningConfigApplied();
|
||||
method @RequiresPermission(android.Manifest.permission.UPDATE_DEVICE_MANAGEMENT_RESOURCES) public void setDrawables(@NonNull java.util.Set<android.app.admin.DevicePolicyDrawableResource>);
|
||||
method @Deprecated @RequiresPermission(value=android.Manifest.permission.GRANT_PROFILE_OWNER_DEVICE_IDS_ACCESS, conditional=true) public void setProfileOwnerCanAccessDeviceIds(@NonNull android.content.ComponentName);
|
||||
method public void setSecondaryLockscreenEnabled(@NonNull android.content.ComponentName, boolean);
|
||||
method @RequiresPermission(android.Manifest.permission.MANAGE_PROFILE_AND_DEVICE_OWNERS) public void setUserProvisioningState(int, @NonNull android.os.UserHandle);
|
||||
|
||||
@@ -0,0 +1,19 @@
|
||||
/*
|
||||
* Copyright (C) 2022 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 android.app.admin;
|
||||
|
||||
parcelable DevicePolicyDrawableResource;
|
||||
203
core/java/android/app/admin/DevicePolicyDrawableResource.java
Normal file
203
core/java/android/app/admin/DevicePolicyDrawableResource.java
Normal file
@@ -0,0 +1,203 @@
|
||||
/*
|
||||
* Copyright (C) 2022 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 android.app.admin;
|
||||
|
||||
import android.annotation.DrawableRes;
|
||||
import android.annotation.NonNull;
|
||||
import android.annotation.Nullable;
|
||||
import android.annotation.SystemApi;
|
||||
import android.content.Context;
|
||||
import android.os.Parcel;
|
||||
import android.os.Parcelable;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* Used to pass in the required information for updating an enterprise drawable resource using
|
||||
* {@link DevicePolicyManager#setDrawables}.
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
@SystemApi
|
||||
public final class DevicePolicyDrawableResource implements Parcelable {
|
||||
private final @DevicePolicyResources.UpdatableDrawableId int mDrawableId;
|
||||
private final @DevicePolicyResources.UpdatableDrawableStyle int mDrawableStyle;
|
||||
private final @DevicePolicyResources.UpdatableDrawableSource int mDrawableSource;
|
||||
private final @DrawableRes int mCallingPackageResourceId;
|
||||
@NonNull private ParcelableResource mResource;
|
||||
|
||||
/**
|
||||
* Creates an object containing the required information for updating an enterprise drawable
|
||||
* resource using {@link DevicePolicyManager#setDrawables}.
|
||||
*
|
||||
* <p>It will be used to update the drawable defined by {@code drawableId} with style
|
||||
* {@code drawableStyle} located in source {@code drawableSource} to the drawable with ID
|
||||
* {@code callingPackageResourceId} in the calling package</p>
|
||||
*
|
||||
* @param drawableId The ID of the drawable to update.
|
||||
* @param drawableStyle The style of the drawable to update.
|
||||
* @param drawableSource The source of the drawable to update.
|
||||
* @param callingPackageResourceId The ID of the drawable resource in the calling package to
|
||||
* use as an updated resource.
|
||||
*
|
||||
* @throws IllegalStateException if the resource with ID
|
||||
* {@code callingPackageResourceId} doesn't exist in the {@code context} package.
|
||||
*/
|
||||
public DevicePolicyDrawableResource(
|
||||
@NonNull Context context,
|
||||
@DevicePolicyResources.UpdatableDrawableId int drawableId,
|
||||
@DevicePolicyResources.UpdatableDrawableStyle int drawableStyle,
|
||||
@DevicePolicyResources.UpdatableDrawableSource int drawableSource,
|
||||
@DrawableRes int callingPackageResourceId) {
|
||||
this(drawableId, drawableStyle, drawableSource, callingPackageResourceId,
|
||||
new ParcelableResource(context, callingPackageResourceId,
|
||||
ParcelableResource.RESOURCE_TYPE_DRAWABLE));
|
||||
}
|
||||
|
||||
private DevicePolicyDrawableResource(
|
||||
@DevicePolicyResources.UpdatableDrawableId int drawableId,
|
||||
@DevicePolicyResources.UpdatableDrawableStyle int drawableStyle,
|
||||
@DevicePolicyResources.UpdatableDrawableSource int drawableSource,
|
||||
@DrawableRes int callingPackageResourceId,
|
||||
@NonNull ParcelableResource resource) {
|
||||
this.mDrawableId = drawableId;
|
||||
this.mDrawableStyle = drawableStyle;
|
||||
this.mDrawableSource = drawableSource;
|
||||
this.mCallingPackageResourceId = callingPackageResourceId;
|
||||
this.mResource = resource;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an object containing the required information for updating an enterprise drawable
|
||||
* resource using {@link DevicePolicyManager#setDrawables}.
|
||||
* <p>It will be used to update the drawable defined by {@code drawableId} with style
|
||||
* {@code drawableStyle} to the drawable with ID {@code callingPackageResourceId} in the
|
||||
* calling package</p>
|
||||
*
|
||||
* @param drawableId The ID of the drawable to update.
|
||||
* @param drawableStyle The style of the drawable to update.
|
||||
* @param callingPackageResourceId The ID of the drawable resource in the calling package to
|
||||
* use as an updated resource.
|
||||
*
|
||||
* @throws IllegalStateException if the resource with ID
|
||||
* {@code callingPackageResourceId} doesn't exist in the calling package.
|
||||
*/
|
||||
public DevicePolicyDrawableResource(
|
||||
@NonNull Context context,
|
||||
@DevicePolicyResources.UpdatableDrawableId int drawableId,
|
||||
@DevicePolicyResources.UpdatableDrawableStyle int drawableStyle,
|
||||
@DrawableRes int callingPackageResourceId) {
|
||||
this(context, drawableId, drawableStyle, DevicePolicyResources.Drawable.Source.UNDEFINED,
|
||||
callingPackageResourceId);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the ID of the drawable to update.
|
||||
*/
|
||||
@DevicePolicyResources.UpdatableDrawableId
|
||||
public int getDrawableId() {
|
||||
return mDrawableId;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the style of the drawable to update
|
||||
*/
|
||||
@DevicePolicyResources.UpdatableDrawableStyle
|
||||
public int getDrawableStyle() {
|
||||
return mDrawableStyle;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the source of the drawable to update.
|
||||
*/
|
||||
@DevicePolicyResources.UpdatableDrawableSource
|
||||
public int getDrawableSource() {
|
||||
return mDrawableSource;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the ID of the drawable resource in the calling package to use as an updated
|
||||
* resource.
|
||||
*/
|
||||
@DrawableRes
|
||||
public int getCallingPackageResourceId() {
|
||||
return mCallingPackageResourceId;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the {@link ParcelableResource} of the drawable.
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
@NonNull
|
||||
public ParcelableResource getResource() {
|
||||
return mResource;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(@Nullable Object o) {
|
||||
if (this == o) return true;
|
||||
if (o == null || getClass() != o.getClass()) return false;
|
||||
DevicePolicyDrawableResource other = (DevicePolicyDrawableResource) o;
|
||||
return mDrawableId == other.mDrawableId
|
||||
&& mDrawableStyle == other.mDrawableStyle
|
||||
&& mDrawableSource == other.mDrawableSource
|
||||
&& mCallingPackageResourceId == other.mCallingPackageResourceId
|
||||
&& mResource.equals(other.mResource);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(
|
||||
mDrawableId, mDrawableStyle, mDrawableSource, mCallingPackageResourceId, mResource);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int describeContents() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeToParcel(@NonNull Parcel dest, int flags) {
|
||||
dest.writeInt(mDrawableId);
|
||||
dest.writeInt(mDrawableStyle);
|
||||
dest.writeInt(mDrawableSource);
|
||||
dest.writeInt(mCallingPackageResourceId);
|
||||
dest.writeTypedObject(mResource, flags);
|
||||
}
|
||||
|
||||
public static final @NonNull Creator<DevicePolicyDrawableResource> CREATOR =
|
||||
new Creator<DevicePolicyDrawableResource>() {
|
||||
@Override
|
||||
public DevicePolicyDrawableResource createFromParcel(Parcel in) {
|
||||
int drawableId = in.readInt();
|
||||
int drawableStyle = in.readInt();
|
||||
int drawableSource = in.readInt();
|
||||
int callingPackageResourceId = in.readInt();
|
||||
ParcelableResource resource = in.readTypedObject(ParcelableResource.CREATOR);
|
||||
|
||||
return new DevicePolicyDrawableResource(
|
||||
drawableId, drawableStyle, drawableSource, callingPackageResourceId,
|
||||
resource);
|
||||
}
|
||||
|
||||
@Override
|
||||
public DevicePolicyDrawableResource[] newArray(int size) {
|
||||
return new DevicePolicyDrawableResource[size];
|
||||
}
|
||||
};
|
||||
}
|
||||
@@ -16,6 +16,9 @@
|
||||
|
||||
package android.app.admin;
|
||||
|
||||
import static android.app.admin.DevicePolicyResources.Drawable.INVALID_ID;
|
||||
import static android.app.admin.DevicePolicyResources.Drawable.Source.UNDEFINED;
|
||||
|
||||
import static com.android.internal.util.function.pooled.PooledLambda.obtainMessage;
|
||||
|
||||
import android.Manifest.permission;
|
||||
@@ -52,7 +55,9 @@ import android.content.pm.PackageManager;
|
||||
import android.content.pm.PackageManager.NameNotFoundException;
|
||||
import android.content.pm.ParceledListSlice;
|
||||
import android.content.pm.UserInfo;
|
||||
import android.content.res.Resources;
|
||||
import android.graphics.Bitmap;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.net.PrivateDnsConnectivityChecker;
|
||||
import android.net.ProxyInfo;
|
||||
import android.net.Uri;
|
||||
@@ -89,6 +94,7 @@ import android.telephony.data.ApnSetting;
|
||||
import android.text.TextUtils;
|
||||
import android.util.ArraySet;
|
||||
import android.util.DebugUtils;
|
||||
import android.util.DisplayMetrics;
|
||||
import android.util.Log;
|
||||
import android.util.Pair;
|
||||
|
||||
@@ -123,6 +129,7 @@ import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.Callable;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import java.util.concurrent.Executor;
|
||||
@@ -3233,6 +3240,36 @@ public class DevicePolicyManager {
|
||||
*/
|
||||
public static final int OPERATION_SAFETY_REASON_DRIVING_DISTRACTION = 1;
|
||||
|
||||
/**
|
||||
* Broadcast action: notify system apps (e.g. settings, SysUI, etc) that the device management
|
||||
* resources with IDs {@link #EXTRA_RESOURCE_ID} has been updated using, the updated resources
|
||||
* can be retrieved using {@link #getDrawable}.
|
||||
*
|
||||
* <p>This broadcast is sent to registered receivers only.
|
||||
*
|
||||
* <p> The following extras will be included to identify the type of resource being updated:
|
||||
* <ul>
|
||||
* <li>{@link #EXTRA_RESOURCE_TYPE_DRAWABLE} for drawable resources</li>
|
||||
* </ul>
|
||||
*/
|
||||
@SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
|
||||
public static final String ACTION_DEVICE_POLICY_RESOURCE_UPDATED =
|
||||
"android.app.action.DEVICE_POLICY_RESOURCE_UPDATED";
|
||||
|
||||
/**
|
||||
* A boolean extra for {@link #ACTION_DEVICE_POLICY_RESOURCE_UPDATED} to indicate that a
|
||||
* resource of type {@link Drawable} is being updated.
|
||||
*/
|
||||
public static final String EXTRA_RESOURCE_TYPE_DRAWABLE =
|
||||
"android.app.extra.RESOURCE_TYPE_DRAWABLE";
|
||||
|
||||
/**
|
||||
* An integer array extra for {@link #ACTION_DEVICE_POLICY_RESOURCE_UPDATED} to indicate which
|
||||
* drawable IDs (see {@link DevicePolicyResources.UpdatableDrawableId}) have been updated.
|
||||
*/
|
||||
public static final String EXTRA_RESOURCE_ID =
|
||||
"android.app.extra.RESOURCE_ID";
|
||||
|
||||
/** @hide */
|
||||
@NonNull
|
||||
@TestApi
|
||||
@@ -14424,4 +14461,243 @@ public class DevicePolicyManager {
|
||||
public Intent createProvisioningIntentFromNfcIntent(@NonNull Intent nfcIntent) {
|
||||
return ProvisioningIntentHelper.createProvisioningIntentFromNfcIntent(nfcIntent);
|
||||
}
|
||||
|
||||
/**
|
||||
* For each {@link DevicePolicyDrawableResource} item in {@code drawables}, if
|
||||
* {@link DevicePolicyDrawableResource#getDrawableSource()} is not set or is set to
|
||||
* {@link DevicePolicyResources.Drawable.Source#UNDEFINED}, it updates the drawable resource for
|
||||
* the combination of {@link DevicePolicyDrawableResource#getDrawableId()} and
|
||||
* {@link DevicePolicyDrawableResource#getDrawableStyle()}, (see
|
||||
* {@link DevicePolicyResources.Drawable} and {@link DevicePolicyResources.Drawable.Style}) to
|
||||
* the drawable with ID {@link DevicePolicyDrawableResource#getCallingPackageResourceId()},
|
||||
* meaning any system UI surface calling {@link #getDrawable}
|
||||
* with {@code drawableId} and {@code drawableStyle} will get the new resource after this API
|
||||
* is called.
|
||||
*
|
||||
* <p>Otherwise, if {@link DevicePolicyDrawableResource#getDrawableSource()} is set (see
|
||||
* {@link DevicePolicyResources.Drawable.Source}, it overrides any drawables that was set for
|
||||
* the same {@code drawableId} and {@code drawableStyle} for the provided source.
|
||||
*
|
||||
* <p>Sends a broadcast with action {@link #ACTION_DEVICE_POLICY_RESOURCE_UPDATED} to
|
||||
* registered receivers when a resource has been updated successfully.
|
||||
*
|
||||
* <p>Important notes to consider when using this API:
|
||||
* <ul>
|
||||
* <li>{@link #getDrawable} references the resource
|
||||
* {@link DevicePolicyDrawableResource#getCallingPackageResourceId()} in the
|
||||
* calling package each time it gets called. You have to ensure that the resource is always
|
||||
* available in the calling package as long as it is used as an updated resource.
|
||||
* <li>You still have to re-call {@code setDrawables} even if you only make changes to the
|
||||
* content of the resource with ID
|
||||
* {@link DevicePolicyDrawableResource#getCallingPackageResourceId()} as the content might be
|
||||
* cached and would need updating.
|
||||
* </ul>
|
||||
*
|
||||
* @param drawables The list of {@link DevicePolicyDrawableResource} to update.
|
||||
*
|
||||
* @throws IllegalArgumentException if {@link DevicePolicyDrawableResource#getDrawableId()},
|
||||
* {@link DevicePolicyDrawableResource#getDrawableStyle()}, or
|
||||
* {@link DevicePolicyDrawableResource#getDrawableSource()} aren't defined in
|
||||
* {@link DevicePolicyResources.Drawable}.
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
@SystemApi
|
||||
@RequiresPermission(android.Manifest.permission.UPDATE_DEVICE_MANAGEMENT_RESOURCES)
|
||||
public void setDrawables(@NonNull Set<DevicePolicyDrawableResource> drawables) {
|
||||
if (mService != null) {
|
||||
try {
|
||||
mService.setDrawables(new ArrayList<>(drawables));
|
||||
} catch (RemoteException e) {
|
||||
throw e.rethrowFromSystemServer();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes all updated drawables for the list of {@code drawableIds} (see
|
||||
* {@link DevicePolicyResources.Drawable} that was previously set by calling
|
||||
* {@link #setDrawables}, meaning any subsequent calls to {@link #getDrawable} for the provided
|
||||
* IDs with any {@link DevicePolicyResources.Drawable.Style} and any
|
||||
* {@link DevicePolicyResources.Drawable.Source} will return the default drawable from
|
||||
* {@code defaultDrawableLoader}.
|
||||
*
|
||||
* <p>Sends a broadcast with action {@link #ACTION_DEVICE_POLICY_RESOURCE_UPDATED} to
|
||||
* registered receivers when a resource has been reset successfully.
|
||||
*
|
||||
* @param drawableIds The list of IDs to remove.
|
||||
*
|
||||
* @throws IllegalArgumentException if IDs are not defined in
|
||||
* {@link DevicePolicyResources.Drawable}
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
@SystemApi
|
||||
@RequiresPermission(android.Manifest.permission.UPDATE_DEVICE_MANAGEMENT_RESOURCES)
|
||||
public void resetDrawables(@NonNull int[] drawableIds) {
|
||||
if (mService != null) {
|
||||
try {
|
||||
mService.resetDrawables(drawableIds);
|
||||
} catch (RemoteException e) {
|
||||
throw e.rethrowFromSystemServer();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the appropriate updated drawable for the {@code drawableId}
|
||||
* (see {@link DevicePolicyResources.Drawable}), with style {@code drawableStyle}
|
||||
* (see {@link DevicePolicyResources.Drawable.Style}) if one was set using
|
||||
* {@code setDrawables}, otherwise returns the drawable from {@code defaultDrawableLoader}.
|
||||
*
|
||||
* <p>Also returns the drawable from {@code defaultDrawableLoader} if
|
||||
* {@link DevicePolicyResources.Drawable#INVALID_ID} was passed.
|
||||
*
|
||||
* <p>This API uses the screen density returned from {@link Resources#getConfiguration()}, to
|
||||
* set a different value use
|
||||
* {@link #getDrawableForDensity(int, int, int, Callable)}.
|
||||
*
|
||||
* <p>Callers should register for {@link #ACTION_DEVICE_POLICY_RESOURCE_UPDATED} to get
|
||||
* notified when a resource has been updated.
|
||||
*
|
||||
* <p>Note that each call to this API loads the resource from the package that called
|
||||
* {@code setDrawables} to set the updated resource.
|
||||
*
|
||||
* @param drawableId The drawable ID to get the updated resource for.
|
||||
* @param drawableStyle The drawable style to use.
|
||||
* @param defaultDrawableLoader To get the default drawable if no updated drawable was set for
|
||||
* the provided params.
|
||||
*/
|
||||
@Nullable
|
||||
public Drawable getDrawable(
|
||||
@DevicePolicyResources.UpdatableDrawableId int drawableId,
|
||||
@DevicePolicyResources.UpdatableDrawableStyle int drawableStyle,
|
||||
@NonNull Callable<Drawable> defaultDrawableLoader) {
|
||||
return getDrawable(drawableId, drawableStyle, UNDEFINED, defaultDrawableLoader);
|
||||
}
|
||||
|
||||
/**
|
||||
* Similar to {@link #getDrawable(int, int, Callable)}, but also accepts
|
||||
* a {@code drawableSource} (see {@link DevicePolicyResources.Drawable.Source}) which
|
||||
* could result in returning a different drawable than {@link #getDrawable(int, int, Callable)}
|
||||
* if an override was set for that specific source.
|
||||
*
|
||||
* <p>Callers should register for {@link #ACTION_DEVICE_POLICY_RESOURCE_UPDATED} to get
|
||||
* notified when a resource has been updated.
|
||||
*
|
||||
* @param drawableId The drawable ID to get the updated resource for.
|
||||
* @param drawableStyle The drawable style to use.
|
||||
* @param drawableSource The source for the caller.
|
||||
* @param defaultDrawableLoader To get the default drawable if no updated drawable was set for
|
||||
* the provided params.
|
||||
*/
|
||||
@Nullable
|
||||
public Drawable getDrawable(
|
||||
@DevicePolicyResources.UpdatableDrawableId int drawableId,
|
||||
@DevicePolicyResources.UpdatableDrawableStyle int drawableStyle,
|
||||
@DevicePolicyResources.UpdatableDrawableSource int drawableSource,
|
||||
@NonNull Callable<Drawable> defaultDrawableLoader) {
|
||||
Objects.requireNonNull(defaultDrawableLoader, "defaultDrawableLoader can't be null");
|
||||
if (drawableId == INVALID_ID) {
|
||||
return ParcelableResource.loadDefaultDrawable(defaultDrawableLoader);
|
||||
}
|
||||
if (mService != null) {
|
||||
try {
|
||||
ParcelableResource resource = mService.getDrawable(
|
||||
drawableId, drawableStyle, drawableSource);
|
||||
if (resource == null) {
|
||||
return ParcelableResource.loadDefaultDrawable(
|
||||
defaultDrawableLoader);
|
||||
}
|
||||
return resource.getDrawable(
|
||||
mContext,
|
||||
/* density= */ 0,
|
||||
defaultDrawableLoader);
|
||||
|
||||
} catch (RemoteException e) {
|
||||
Log.e(
|
||||
TAG,
|
||||
"Error getting the updated drawable from DevicePolicyManagerService.",
|
||||
e);
|
||||
return ParcelableResource.loadDefaultDrawable(defaultDrawableLoader);
|
||||
}
|
||||
}
|
||||
return ParcelableResource.loadDefaultDrawable(defaultDrawableLoader);
|
||||
}
|
||||
|
||||
/**
|
||||
* Similar to {@link #getDrawable(int, int, Callable)}, but also accepts
|
||||
* {@code density}. See {@link Resources#getDrawableForDensity(int, int, Resources.Theme)}.
|
||||
*
|
||||
* <p>Callers should register for {@link #ACTION_DEVICE_POLICY_RESOURCE_UPDATED} to get
|
||||
* notified when a resource has been updated.
|
||||
*
|
||||
* @param drawableId The drawable ID to get the updated resource for.
|
||||
* @param drawableStyle The drawable style to use.
|
||||
* @param density The desired screen density indicated by the resource as
|
||||
* found in {@link DisplayMetrics}. A value of 0 means to use the
|
||||
* density returned from {@link Resources#getConfiguration()}.
|
||||
* @param defaultDrawableLoader To get the default drawable if no updated drawable was set for
|
||||
* the provided params.
|
||||
*/
|
||||
@Nullable
|
||||
public Drawable getDrawableForDensity(
|
||||
@DevicePolicyResources.UpdatableDrawableId int drawableId,
|
||||
@DevicePolicyResources.UpdatableDrawableStyle int drawableStyle,
|
||||
int density,
|
||||
@NonNull Callable<Drawable> defaultDrawableLoader) {
|
||||
return getDrawableForDensity(
|
||||
drawableId,
|
||||
drawableStyle,
|
||||
UNDEFINED,
|
||||
density,
|
||||
defaultDrawableLoader);
|
||||
}
|
||||
|
||||
/**
|
||||
* Similar to {@link #getDrawable(int, int, int, Callable)}, but also accepts
|
||||
* {@code density}. See {@link Resources#getDrawableForDensity(int, int, Resources.Theme)}.
|
||||
*
|
||||
* <p>Callers should register for {@link #ACTION_DEVICE_POLICY_RESOURCE_UPDATED} to get
|
||||
* notified when a resource has been updated.
|
||||
*
|
||||
* @param drawableId The drawable ID to get the updated resource for.
|
||||
* @param drawableStyle The drawable style to use.
|
||||
* @param drawableSource The source for the caller.
|
||||
* @param density The desired screen density indicated by the resource as
|
||||
* found in {@link DisplayMetrics}. A value of 0 means to use the
|
||||
* density returned from {@link Resources#getConfiguration()}.
|
||||
* @param defaultDrawableLoader To get the default drawable if no updated drawable was set for
|
||||
* the provided params.
|
||||
*/
|
||||
@Nullable
|
||||
public Drawable getDrawableForDensity(
|
||||
@DevicePolicyResources.UpdatableDrawableId int drawableId,
|
||||
@DevicePolicyResources.UpdatableDrawableStyle int drawableStyle,
|
||||
@DevicePolicyResources.UpdatableDrawableSource int drawableSource,
|
||||
int density,
|
||||
@NonNull Callable<Drawable> defaultDrawableLoader) {
|
||||
Objects.requireNonNull(defaultDrawableLoader, "defaultDrawableLoader can't be null");
|
||||
if (drawableId == INVALID_ID) {
|
||||
return ParcelableResource.loadDefaultDrawable(defaultDrawableLoader);
|
||||
}
|
||||
if (mService != null) {
|
||||
try {
|
||||
ParcelableResource resource = mService.getDrawable(
|
||||
drawableId, drawableStyle, drawableSource);
|
||||
if (resource == null) {
|
||||
return ParcelableResource.loadDefaultDrawable(
|
||||
defaultDrawableLoader);
|
||||
}
|
||||
return resource.getDrawable(mContext, density, defaultDrawableLoader);
|
||||
} catch (RemoteException e) {
|
||||
Log.e(
|
||||
TAG,
|
||||
"Error getting the updated drawable from DevicePolicyManagerService.",
|
||||
e);
|
||||
return ParcelableResource.loadDefaultDrawable(defaultDrawableLoader);
|
||||
}
|
||||
}
|
||||
return ParcelableResource.loadDefaultDrawable(defaultDrawableLoader);
|
||||
}
|
||||
}
|
||||
|
||||
243
core/java/android/app/admin/DevicePolicyResources.java
Normal file
243
core/java/android/app/admin/DevicePolicyResources.java
Normal file
@@ -0,0 +1,243 @@
|
||||
/*
|
||||
* Copyright (C) 2022 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 android.app.admin;
|
||||
|
||||
import android.annotation.IntDef;
|
||||
import android.annotation.SuppressLint;
|
||||
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* Class containing the required identifiers to update device management resources.
|
||||
*
|
||||
* <p>See {@link DevicePolicyManager#getDrawable}.
|
||||
*
|
||||
*/
|
||||
public final class DevicePolicyResources {
|
||||
|
||||
/**
|
||||
* Resource identifiers used to update device management-related system drawable resources.
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
@Retention(RetentionPolicy.SOURCE)
|
||||
@IntDef(value = {
|
||||
Drawable.INVALID_ID,
|
||||
Drawable.WORK_PROFILE_ICON_BADGE,
|
||||
Drawable.WORK_PROFILE_ICON,
|
||||
Drawable.WORK_PROFILE_OFF_ICON,
|
||||
Drawable.WORK_PROFILE_USER_ICON
|
||||
})
|
||||
public @interface UpdatableDrawableId {}
|
||||
|
||||
/**
|
||||
* Identifiers to specify the desired style for the updatable device management system
|
||||
* resource.
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
@Retention(RetentionPolicy.SOURCE)
|
||||
@IntDef(value = {
|
||||
Drawable.Style.SOLID_COLORED,
|
||||
Drawable.Style.SOLID_NOT_COLORED,
|
||||
Drawable.Style.OUTLINE,
|
||||
})
|
||||
public @interface UpdatableDrawableStyle {}
|
||||
|
||||
/**
|
||||
* Identifiers to specify the location if the updatable device management system resource.
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
@Retention(RetentionPolicy.SOURCE)
|
||||
@IntDef(value = {
|
||||
Drawable.Source.UNDEFINED,
|
||||
Drawable.Source.NOTIFICATION,
|
||||
Drawable.Source.PROFILE_SWITCH_ANIMATION,
|
||||
Drawable.Source.HOME_WIDGET,
|
||||
Drawable.Source.LAUNCHER_OFF_BUTTON,
|
||||
Drawable.Source.QUICK_SETTINGS,
|
||||
Drawable.Source.STATUS_BAR
|
||||
})
|
||||
public @interface UpdatableDrawableSource {}
|
||||
|
||||
|
||||
/**
|
||||
* Class containing the identifiers used to update device management-related system drawable.
|
||||
*/
|
||||
public static final class Drawable {
|
||||
|
||||
private Drawable() {
|
||||
}
|
||||
|
||||
/**
|
||||
* An ID for any drawable that can't be updated.
|
||||
*/
|
||||
public static final int INVALID_ID = -1;
|
||||
|
||||
/**
|
||||
* Specifically used to badge work profile app icons.
|
||||
*/
|
||||
public static final int WORK_PROFILE_ICON_BADGE = 0;
|
||||
|
||||
/**
|
||||
* General purpose work profile icon (i.e. generic icon badging). For badging app icons
|
||||
* specifically, see {@link #WORK_PROFILE_ICON_BADGE}.
|
||||
*/
|
||||
public static final int WORK_PROFILE_ICON = 1;
|
||||
|
||||
/**
|
||||
* General purpose icon representing the work profile off state.
|
||||
*/
|
||||
public static final int WORK_PROFILE_OFF_ICON = 2;
|
||||
|
||||
/**
|
||||
* General purpose icon for the work profile user avatar.
|
||||
*/
|
||||
public static final int WORK_PROFILE_USER_ICON = 3;
|
||||
|
||||
/**
|
||||
* @hide
|
||||
*/
|
||||
public static final Set<Integer> UPDATABLE_DRAWABLE_IDS = buildDrawablesSet();
|
||||
|
||||
private static Set<Integer> buildDrawablesSet() {
|
||||
Set<Integer> drawables = new HashSet<>();
|
||||
drawables.add(WORK_PROFILE_ICON_BADGE);
|
||||
drawables.add(WORK_PROFILE_ICON);
|
||||
drawables.add(WORK_PROFILE_OFF_ICON);
|
||||
drawables.add(WORK_PROFILE_USER_ICON);
|
||||
return drawables;
|
||||
}
|
||||
|
||||
/**
|
||||
* Class containing the source identifiers used to update device management-related system
|
||||
* drawable.
|
||||
*/
|
||||
public static final class Source {
|
||||
|
||||
private Source() {
|
||||
}
|
||||
|
||||
/**
|
||||
* A source identifier indicating that the updatable resource is used in a generic
|
||||
* undefined location.
|
||||
*/
|
||||
public static final int UNDEFINED = -1;
|
||||
|
||||
/**
|
||||
* A source identifier indicating that the updatable drawable is used in notifications.
|
||||
*/
|
||||
public static final int NOTIFICATION = 0;
|
||||
|
||||
/**
|
||||
* A source identifier indicating that the updatable drawable is used in a cross
|
||||
* profile switching animation.
|
||||
*/
|
||||
public static final int PROFILE_SWITCH_ANIMATION = 1;
|
||||
|
||||
/**
|
||||
* A source identifier indicating that the updatable drawable is used in a work
|
||||
* profile home screen widget.
|
||||
*/
|
||||
public static final int HOME_WIDGET = 2;
|
||||
|
||||
/**
|
||||
* A source identifier indicating that the updatable drawable is used in the launcher
|
||||
* turn off work button.
|
||||
*/
|
||||
public static final int LAUNCHER_OFF_BUTTON = 3;
|
||||
|
||||
/**
|
||||
* A source identifier indicating that the updatable drawable is used in quick settings.
|
||||
*/
|
||||
public static final int QUICK_SETTINGS = 4;
|
||||
|
||||
/**
|
||||
* A source identifier indicating that the updatable drawable is used in the status bar.
|
||||
*/
|
||||
public static final int STATUS_BAR = 5;
|
||||
|
||||
/**
|
||||
* @hide
|
||||
*/
|
||||
public static final Set<Integer> UPDATABLE_DRAWABLE_SOURCES = buildSourcesSet();
|
||||
|
||||
private static Set<Integer> buildSourcesSet() {
|
||||
Set<Integer> sources = new HashSet<>();
|
||||
sources.add(UNDEFINED);
|
||||
sources.add(NOTIFICATION);
|
||||
sources.add(PROFILE_SWITCH_ANIMATION);
|
||||
sources.add(HOME_WIDGET);
|
||||
sources.add(LAUNCHER_OFF_BUTTON);
|
||||
sources.add(QUICK_SETTINGS);
|
||||
sources.add(STATUS_BAR);
|
||||
return sources;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Class containing the style identifiers used to update device management-related system
|
||||
* drawable.
|
||||
*/
|
||||
@SuppressLint("StaticUtils")
|
||||
public static final class Style {
|
||||
|
||||
private Style() {
|
||||
}
|
||||
|
||||
/**
|
||||
* A style identifier indicating that the updatable drawable should use the default
|
||||
* style.
|
||||
*/
|
||||
public static final int DEFAULT = -1;
|
||||
|
||||
/**
|
||||
* A style identifier indicating that the updatable drawable has a solid color fill.
|
||||
*/
|
||||
public static final int SOLID_COLORED = 0;
|
||||
|
||||
/**
|
||||
* A style identifier indicating that the updatable drawable has a solid non-colored
|
||||
* fill.
|
||||
*/
|
||||
public static final int SOLID_NOT_COLORED = 1;
|
||||
|
||||
/**
|
||||
* A style identifier indicating that the updatable drawable is an outline.
|
||||
*/
|
||||
public static final int OUTLINE = 2;
|
||||
|
||||
/**
|
||||
* @hide
|
||||
*/
|
||||
public static final Set<Integer> UPDATABLE_DRAWABLE_STYLES = buildStylesSet();
|
||||
|
||||
private static Set<Integer> buildStylesSet() {
|
||||
Set<Integer> styles = new HashSet<>();
|
||||
styles.add(DEFAULT);
|
||||
styles.add(SOLID_COLORED);
|
||||
styles.add(SOLID_NOT_COLORED);
|
||||
styles.add(OUTLINE);
|
||||
return styles;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -17,6 +17,8 @@
|
||||
|
||||
package android.app.admin;
|
||||
|
||||
import android.app.admin.DevicePolicyDrawableResource;
|
||||
import android.app.admin.ParcelableResource;
|
||||
import android.app.admin.NetworkEvent;
|
||||
import android.app.IApplicationThread;
|
||||
import android.app.IServiceConnection;
|
||||
@@ -531,4 +533,7 @@ interface IDevicePolicyManager {
|
||||
boolean canUsbDataSignalingBeDisabled();
|
||||
|
||||
List<UserHandle> listForegroundAffiliatedUsers();
|
||||
void setDrawables(in List<DevicePolicyDrawableResource> resource);
|
||||
void resetDrawables(in int[] drawableIds);
|
||||
ParcelableResource getDrawable(int drawableId, int drawableStyle, int drawableSource);
|
||||
}
|
||||
|
||||
20
core/java/android/app/admin/ParcelableResource.aidl
Normal file
20
core/java/android/app/admin/ParcelableResource.aidl
Normal file
@@ -0,0 +1,20 @@
|
||||
/*
|
||||
* Copyright (C) 2022 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 android.app.admin;
|
||||
|
||||
parcelable ParcelableResource;
|
||||
286
core/java/android/app/admin/ParcelableResource.java
Normal file
286
core/java/android/app/admin/ParcelableResource.java
Normal file
@@ -0,0 +1,286 @@
|
||||
/*
|
||||
* Copyright (C) 2022 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 android.app.admin;
|
||||
|
||||
import static java.util.Objects.requireNonNull;
|
||||
|
||||
import android.annotation.AnyRes;
|
||||
import android.annotation.IntDef;
|
||||
import android.annotation.NonNull;
|
||||
import android.annotation.Nullable;
|
||||
import android.content.Context;
|
||||
import android.content.pm.ApplicationInfo;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.content.res.Resources;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.os.Parcel;
|
||||
import android.os.Parcelable;
|
||||
import android.util.Slog;
|
||||
import android.util.TypedXmlPullParser;
|
||||
import android.util.TypedXmlSerializer;
|
||||
|
||||
import org.xmlpull.v1.XmlPullParserException;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.util.Objects;
|
||||
import java.util.concurrent.Callable;
|
||||
|
||||
/**
|
||||
* Used to store the required information to load a resource that was updated using
|
||||
* {@link DevicePolicyManager#setDrawables}.
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
public final class ParcelableResource implements Parcelable {
|
||||
|
||||
private static String TAG = "DevicePolicyManager";
|
||||
|
||||
private static final String ATTR_RESOURCE_ID = "resource-id";
|
||||
private static final String ATTR_PACKAGE_NAME = "package-name";
|
||||
private static final String ATTR_RESOURCE_NAME = "resource-name";
|
||||
private static final String ATTR_RESOURCE_TYPE = "resource-type";
|
||||
|
||||
public static final int RESOURCE_TYPE_DRAWABLE = 1;
|
||||
|
||||
@Retention(RetentionPolicy.SOURCE)
|
||||
@IntDef(prefix = { "RESOURCE_TYPE_" }, value = {
|
||||
RESOURCE_TYPE_DRAWABLE
|
||||
})
|
||||
public @interface ResourceType {}
|
||||
|
||||
private final int mResourceId;
|
||||
@NonNull private final String mPackageName;
|
||||
@NonNull private final String mResourceName;
|
||||
private final int mResourceType;
|
||||
|
||||
/**
|
||||
*
|
||||
* Creates a {@code ParcelableDevicePolicyResource} for the given {@code resourceId} and
|
||||
* verifies that it exists in the package of the given {@code context}.
|
||||
*
|
||||
* @param context for the package containing the {@code resourceId} to use as the updated
|
||||
* resource
|
||||
* @param resourceId of the resource to use as an updated resource
|
||||
* @param resourceType see {@link ResourceType}
|
||||
* @throws IllegalArgumentException if the given {@code resourceId} doesn't exist in the
|
||||
* {@link Context#getResources()} of the given {@code context}
|
||||
*/
|
||||
public ParcelableResource(@NonNull Context context, @AnyRes int resourceId,
|
||||
@ResourceType int resourceType) throws IllegalArgumentException {
|
||||
Objects.requireNonNull(context, "context must be provided");
|
||||
|
||||
verifyResourceExistsInCallingPackage(context, resourceId, resourceType);
|
||||
|
||||
this.mResourceId = resourceId;
|
||||
this.mPackageName = context.getResources().getResourcePackageName(resourceId);
|
||||
this.mResourceName = context.getResources().getResourceName(resourceId);
|
||||
this.mResourceType = resourceType;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a {@code ParcelableDevicePolicyResource} with the given params, this DOES NOT make
|
||||
* any verifications on whether the given {@code resourceId} actually exists.
|
||||
*/
|
||||
private ParcelableResource(
|
||||
@AnyRes int resourceId, @NonNull String packageName, @NonNull String resourceName,
|
||||
@ResourceType int resourceType) {
|
||||
this.mResourceId = resourceId;
|
||||
this.mPackageName = requireNonNull(packageName);
|
||||
this.mResourceName = requireNonNull(resourceName);
|
||||
this.mResourceType = resourceType;
|
||||
}
|
||||
|
||||
private static void verifyResourceExistsInCallingPackage(
|
||||
Context context, @AnyRes int resourceId, @ResourceType int resourceType)
|
||||
throws IllegalArgumentException {
|
||||
switch (resourceType) {
|
||||
case RESOURCE_TYPE_DRAWABLE:
|
||||
if (!hasDrawableInCallingPackage(context, resourceId)) {
|
||||
throw new IllegalArgumentException(String.format(
|
||||
"Drawable with id %d doesn't exist in the calling package %s",
|
||||
resourceId,
|
||||
context.getPackageName()));
|
||||
}
|
||||
break;
|
||||
default:
|
||||
throw new IllegalArgumentException(
|
||||
"Unknown ParcelableDevicePolicyResourceType: " + resourceType);
|
||||
}
|
||||
}
|
||||
|
||||
private static boolean hasDrawableInCallingPackage(Context context, @AnyRes int resourceId) {
|
||||
try {
|
||||
return context.getDrawable(resourceId) != null;
|
||||
} catch (Resources.NotFoundException e) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public @AnyRes int getResourceId() {
|
||||
return mResourceId;
|
||||
}
|
||||
|
||||
@NonNull
|
||||
public String getPackageName() {
|
||||
return mPackageName;
|
||||
}
|
||||
|
||||
@NonNull
|
||||
public String getResourceName() {
|
||||
return mResourceName;
|
||||
}
|
||||
|
||||
public int getResourceType() {
|
||||
return mResourceType;
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads the drawable with id {@code mResourceId} from {@code mPackageName} using the provided
|
||||
* {@code density} and {@link Resources.Theme} and {@link Resources#getConfiguration} of the
|
||||
* provided {@code context}.
|
||||
*
|
||||
* <p>Returns the default drawable by calling the {@code defaultDrawableLoader} if the updated
|
||||
* drawable was not found or could not be loaded.</p>
|
||||
*/
|
||||
@Nullable
|
||||
public Drawable getDrawable(
|
||||
Context context,
|
||||
int density,
|
||||
@NonNull Callable<Drawable> defaultDrawableLoader) {
|
||||
// TODO(b/203548565): properly handle edge case when the device manager role holder is
|
||||
// unavailable because it's being updated.
|
||||
try {
|
||||
Resources resources = getAppResourcesWithCallersConfiguration(context);
|
||||
verifyResourceName(resources);
|
||||
return resources.getDrawableForDensity(mResourceId, density, context.getTheme());
|
||||
} catch (PackageManager.NameNotFoundException | RuntimeException e) {
|
||||
Slog.e(TAG, "Unable to load drawable resource " + mResourceName, e);
|
||||
return loadDefaultDrawable(defaultDrawableLoader);
|
||||
}
|
||||
}
|
||||
|
||||
private Resources getAppResourcesWithCallersConfiguration(Context context)
|
||||
throws PackageManager.NameNotFoundException {
|
||||
PackageManager pm = context.getPackageManager();
|
||||
ApplicationInfo ai = pm.getApplicationInfo(
|
||||
mPackageName,
|
||||
PackageManager.MATCH_UNINSTALLED_PACKAGES
|
||||
| PackageManager.GET_SHARED_LIBRARY_FILES);
|
||||
return pm.getResourcesForApplication(ai, context.getResources().getConfiguration());
|
||||
}
|
||||
|
||||
private void verifyResourceName(Resources resources) throws IllegalStateException {
|
||||
String name = resources.getResourceName(mResourceId);
|
||||
if (!mResourceName.equals(name)) {
|
||||
throw new IllegalStateException(String.format("Current resource name %s for resource id"
|
||||
+ " %d has changed from the previously stored resource name %s.",
|
||||
name, mResourceId, mResourceName));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* returns the {@link Drawable} loaded from calling
|
||||
* {@code defaultDrawableLoader}.
|
||||
*/
|
||||
public static Drawable loadDefaultDrawable(
|
||||
@NonNull Callable<Drawable> defaultDrawableLoader) {
|
||||
try {
|
||||
return defaultDrawableLoader.call();
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException("Couldn't load default drawable", e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes the content of the current {@code ParcelableDevicePolicyResource} to the xml file
|
||||
* specified by {@code xmlSerializer}.
|
||||
*/
|
||||
public void writeToXmlFile(TypedXmlSerializer xmlSerializer) throws IOException {
|
||||
xmlSerializer.attributeInt(/* namespace= */ null, ATTR_RESOURCE_ID, mResourceId);
|
||||
xmlSerializer.attribute(/* namespace= */ null, ATTR_PACKAGE_NAME, mPackageName);
|
||||
xmlSerializer.attribute(/* namespace= */ null, ATTR_RESOURCE_NAME, mResourceName);
|
||||
xmlSerializer.attributeInt(/* namespace= */ null, ATTR_RESOURCE_TYPE, mResourceType);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new {@code ParcelableDevicePolicyResource} using the content of
|
||||
* {@code xmlPullParser}.
|
||||
*/
|
||||
public static ParcelableResource createFromXml(TypedXmlPullParser xmlPullParser)
|
||||
throws XmlPullParserException, IOException {
|
||||
int resourceId = xmlPullParser.getAttributeInt(/* namespace= */ null, ATTR_RESOURCE_ID);
|
||||
String packageName = xmlPullParser.getAttributeValue(
|
||||
/* namespace= */ null, ATTR_PACKAGE_NAME);
|
||||
String resourceName = xmlPullParser.getAttributeValue(
|
||||
/* namespace= */ null, ATTR_RESOURCE_NAME);
|
||||
int resourceType = xmlPullParser.getAttributeInt(
|
||||
/* namespace= */ null, ATTR_RESOURCE_TYPE);
|
||||
|
||||
return new ParcelableResource(
|
||||
resourceId, packageName, resourceName, resourceType);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(@Nullable Object o) {
|
||||
if (this == o) return true;
|
||||
if (o == null || getClass() != o.getClass()) return false;
|
||||
ParcelableResource other = (ParcelableResource) o;
|
||||
return mResourceId == other.mResourceId
|
||||
&& mPackageName.equals(other.mPackageName)
|
||||
&& mResourceName.equals(other.mResourceName)
|
||||
&& mResourceType == other.mResourceType;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(mResourceId, mPackageName, mResourceName, mResourceType);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int describeContents() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeToParcel(Parcel dest, int flags) {
|
||||
dest.writeInt(mResourceId);
|
||||
dest.writeString(mPackageName);
|
||||
dest.writeString(mResourceName);
|
||||
dest.writeInt(mResourceType);
|
||||
}
|
||||
|
||||
public static final @NonNull Creator<ParcelableResource> CREATOR =
|
||||
new Creator<ParcelableResource>() {
|
||||
@Override
|
||||
public ParcelableResource createFromParcel(Parcel in) {
|
||||
int resourceId = in.readInt();
|
||||
String packageName = in.readString();
|
||||
String resourceName = in.readString();
|
||||
int resourceType = in.readInt();
|
||||
|
||||
return new ParcelableResource(
|
||||
resourceId, packageName, resourceName, resourceType);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ParcelableResource[] newArray(int size) {
|
||||
return new ParcelableResource[size];
|
||||
}
|
||||
};
|
||||
}
|
||||
@@ -716,6 +716,7 @@
|
||||
|
||||
<!-- Added in T -->
|
||||
<protected-broadcast android:name="android.intent.action.REFRESH_SAFETY_SOURCES" />
|
||||
<protected-broadcast android:name="android.app.action.DEVICE_POLICY_RESOURCE_UPDATED" />
|
||||
|
||||
<!-- ====================================================================== -->
|
||||
<!-- RUNTIME PERMISSIONS -->
|
||||
|
||||
@@ -17,16 +17,20 @@ package com.android.server.devicepolicy;
|
||||
|
||||
import android.annotation.NonNull;
|
||||
import android.annotation.UserIdInt;
|
||||
import android.app.admin.DevicePolicyDrawableResource;
|
||||
import android.app.admin.DevicePolicySafetyChecker;
|
||||
import android.app.admin.FullyManagedDeviceProvisioningParams;
|
||||
import android.app.admin.IDevicePolicyManager;
|
||||
import android.app.admin.ManagedProfileProvisioningParams;
|
||||
import android.app.admin.ParcelableResource;
|
||||
import android.content.ComponentName;
|
||||
import android.os.UserHandle;
|
||||
import android.util.Slog;
|
||||
|
||||
import com.android.server.SystemService;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Defines the required interface for IDevicePolicyManager implemenation.
|
||||
*
|
||||
@@ -161,4 +165,16 @@ abstract class BaseIDevicePolicyManager extends IDevicePolicyManager.Stub {
|
||||
public boolean isKeyPairGrantedToWifiAuth(String callerPackage, String alias) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setDrawables(@NonNull List<DevicePolicyDrawableResource> drawables){}
|
||||
|
||||
@Override
|
||||
public void resetDrawables(@NonNull int[] drawableIds){}
|
||||
|
||||
@Override
|
||||
public ParcelableResource getDrawable(
|
||||
int drawableId, int drawableStyle, int drawableSource) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,417 @@
|
||||
/*
|
||||
* Copyright (C) 2022 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.server.devicepolicy;
|
||||
|
||||
import static android.app.admin.DevicePolicyResources.Drawable.Source.UPDATABLE_DRAWABLE_SOURCES;
|
||||
import static android.app.admin.DevicePolicyResources.Drawable.Style;
|
||||
import static android.app.admin.DevicePolicyResources.Drawable.Style.UPDATABLE_DRAWABLE_STYLES;
|
||||
import static android.app.admin.DevicePolicyResources.Drawable.UPDATABLE_DRAWABLE_IDS;
|
||||
|
||||
import static java.util.Objects.requireNonNull;
|
||||
|
||||
import android.annotation.NonNull;
|
||||
import android.annotation.Nullable;
|
||||
import android.app.admin.DevicePolicyDrawableResource;
|
||||
import android.app.admin.DevicePolicyResources;
|
||||
import android.app.admin.ParcelableResource;
|
||||
import android.os.Environment;
|
||||
import android.util.AtomicFile;
|
||||
import android.util.Log;
|
||||
import android.util.TypedXmlPullParser;
|
||||
import android.util.TypedXmlSerializer;
|
||||
import android.util.Xml;
|
||||
|
||||
import libcore.io.IoUtils;
|
||||
|
||||
import org.xmlpull.v1.XmlPullParserException;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* A helper class for {@link DevicePolicyManagerService} to store/retrieve updated device
|
||||
* management resources.
|
||||
*/
|
||||
class DeviceManagementResourcesProvider {
|
||||
private static final String TAG = "DevicePolicyManagerService";
|
||||
|
||||
private static final String UPDATED_RESOURCES_XML = "updated_resources.xml";
|
||||
private static final String TAG_ROOT = "root";
|
||||
private static final String TAG_DRAWABLE_STYLE_ENTRY = "drawable-style-entry";
|
||||
private static final String TAG_DRAWABLE_SOURCE_ENTRY = "drawable-source-entry";
|
||||
private static final String ATTR_DRAWABLE_STYLE_SIZE = "drawable-style-size";
|
||||
private static final String ATTR_DRAWABLE_SOURCE_SIZE = "drawable-source-size";
|
||||
private static final String ATTR_DRAWABLE_STYLE = "drawable-style";
|
||||
private static final String ATTR_DRAWABLE_SOURCE = "drawable-source";
|
||||
private static final String ATTR_DRAWABLE_ID = "drawable-id";
|
||||
|
||||
|
||||
private final Map<Integer, Map<Integer, ParcelableResource>>
|
||||
mUpdatedDrawablesForStyle = new HashMap<>();
|
||||
|
||||
private final Map<Integer, Map<Integer, ParcelableResource>>
|
||||
mUpdatedDrawablesForSource = new HashMap<>();
|
||||
|
||||
private final Object mLock = new Object();
|
||||
private final Injector mInjector;
|
||||
|
||||
DeviceManagementResourcesProvider() {
|
||||
this(new Injector());
|
||||
}
|
||||
|
||||
DeviceManagementResourcesProvider(Injector injector) {
|
||||
mInjector = requireNonNull(injector);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns {@code false} if no resources were updated.
|
||||
*/
|
||||
boolean updateDrawables(@NonNull List<DevicePolicyDrawableResource> drawables) {
|
||||
boolean updated = false;
|
||||
for (int i = 0; i < drawables.size(); i++) {
|
||||
int drawableId = drawables.get(i).getDrawableId();
|
||||
int drawableStyle = drawables.get(i).getDrawableStyle();
|
||||
int drawableSource = drawables.get(i).getDrawableSource();
|
||||
ParcelableResource resource = drawables.get(i).getResource();
|
||||
|
||||
Objects.requireNonNull(resource, "ParcelableResource must be provided.");
|
||||
|
||||
if (drawableSource == DevicePolicyResources.Drawable.Source.UNDEFINED) {
|
||||
updated |= updateDrawable(drawableId, drawableStyle, resource);
|
||||
} else {
|
||||
updated |= updateDrawableForSource(drawableId, drawableSource, resource);
|
||||
}
|
||||
}
|
||||
if (!updated) {
|
||||
return false;
|
||||
}
|
||||
synchronized (mLock) {
|
||||
write();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
private boolean updateDrawable(
|
||||
int drawableId, int drawableStyle, ParcelableResource updatableResource) {
|
||||
if (!UPDATABLE_DRAWABLE_IDS.contains(drawableId)) {
|
||||
throw new IllegalArgumentException(
|
||||
"Can't update drawable resource, invalid drawable " + "id " + drawableId);
|
||||
}
|
||||
if (!UPDATABLE_DRAWABLE_STYLES.contains(drawableStyle)) {
|
||||
throw new IllegalArgumentException(
|
||||
"Can't update drawable resource, invalid style id " + drawableStyle);
|
||||
}
|
||||
synchronized (mLock) {
|
||||
if (!mUpdatedDrawablesForStyle.containsKey(drawableId)) {
|
||||
mUpdatedDrawablesForStyle.put(drawableId, new HashMap<>());
|
||||
}
|
||||
ParcelableResource current = mUpdatedDrawablesForStyle.get(drawableId).get(
|
||||
drawableStyle);
|
||||
if (updatableResource.equals(current)) {
|
||||
return false;
|
||||
}
|
||||
mUpdatedDrawablesForStyle.get(drawableId).put(drawableStyle, updatableResource);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
// TODO(b/214576716): change this to respect style
|
||||
private boolean updateDrawableForSource(
|
||||
int drawableId, int drawableSource, ParcelableResource updatableResource) {
|
||||
if (!UPDATABLE_DRAWABLE_IDS.contains(drawableId)) {
|
||||
throw new IllegalArgumentException("Can't update drawable resource, invalid drawable "
|
||||
+ "id " + drawableId);
|
||||
}
|
||||
if (!UPDATABLE_DRAWABLE_SOURCES.contains(drawableSource)) {
|
||||
throw new IllegalArgumentException("Can't update drawable resource, invalid source id "
|
||||
+ drawableSource);
|
||||
}
|
||||
synchronized (mLock) {
|
||||
if (!mUpdatedDrawablesForSource.containsKey(drawableId)) {
|
||||
mUpdatedDrawablesForSource.put(drawableId, new HashMap<>());
|
||||
}
|
||||
ParcelableResource current = mUpdatedDrawablesForSource.get(drawableId).get(
|
||||
drawableSource);
|
||||
if (updatableResource.equals(current)) {
|
||||
return false;
|
||||
}
|
||||
mUpdatedDrawablesForSource.get(drawableId).put(drawableSource, updatableResource);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns {@code false} if no resources were removed.
|
||||
*/
|
||||
boolean removeDrawables(@NonNull int[] drawableIds) {
|
||||
synchronized (mLock) {
|
||||
boolean removed = false;
|
||||
for (int i = 0; i < drawableIds.length; i++) {
|
||||
int drawableId = drawableIds[i];
|
||||
removed |= mUpdatedDrawablesForStyle.remove(drawableId) != null
|
||||
|| mUpdatedDrawablesForSource.remove(drawableId) != null;
|
||||
}
|
||||
if (!removed) {
|
||||
return false;
|
||||
}
|
||||
write();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
@Nullable
|
||||
ParcelableResource getDrawable(
|
||||
int drawableId, int drawableStyle, int drawableSource) {
|
||||
if (!UPDATABLE_DRAWABLE_IDS.contains(drawableId)) {
|
||||
Log.e(TAG, "Can't get updated drawable resource, invalid drawable id "
|
||||
+ drawableId);
|
||||
return null;
|
||||
}
|
||||
if (!UPDATABLE_DRAWABLE_STYLES.contains(drawableStyle)) {
|
||||
Log.e(TAG, "Can't get updated drawable resource, invalid style id "
|
||||
+ drawableStyle);
|
||||
return null;
|
||||
}
|
||||
if (!UPDATABLE_DRAWABLE_SOURCES.contains(drawableSource)) {
|
||||
Log.e(TAG, "Can't get updated drawable resource, invalid source id "
|
||||
+ drawableSource);
|
||||
return null;
|
||||
}
|
||||
if (mUpdatedDrawablesForSource.containsKey(drawableId)
|
||||
&& mUpdatedDrawablesForSource.get(drawableId).containsKey(drawableSource)) {
|
||||
return mUpdatedDrawablesForSource.get(drawableId).get(drawableSource);
|
||||
}
|
||||
if (!mUpdatedDrawablesForStyle.containsKey(drawableId)) {
|
||||
Log.d(TAG, "No updated drawable found for drawable id " + drawableId);
|
||||
return null;
|
||||
}
|
||||
if (mUpdatedDrawablesForStyle.get(drawableId).containsKey(drawableStyle)) {
|
||||
return mUpdatedDrawablesForStyle.get(drawableId).get(drawableStyle);
|
||||
}
|
||||
|
||||
if (mUpdatedDrawablesForStyle.get(drawableId).containsKey(Style.DEFAULT)) {
|
||||
return mUpdatedDrawablesForStyle.get(drawableId).get(Style.DEFAULT);
|
||||
}
|
||||
Log.d(TAG, "No updated drawable found for drawable id " + drawableId);
|
||||
return null;
|
||||
}
|
||||
|
||||
private void write() {
|
||||
Log.d(TAG, "Writing updated resources to file.");
|
||||
new ResourcesReaderWriter().writeToFileLocked();
|
||||
}
|
||||
|
||||
void load() {
|
||||
synchronized (mLock) {
|
||||
new ResourcesReaderWriter().readFromFileLocked();
|
||||
}
|
||||
}
|
||||
|
||||
private File getResourcesFile() {
|
||||
return new File(mInjector.environmentGetDataSystemDirectory(), UPDATED_RESOURCES_XML);
|
||||
}
|
||||
|
||||
private class ResourcesReaderWriter {
|
||||
private final File mFile;
|
||||
private ResourcesReaderWriter() {
|
||||
mFile = getResourcesFile();
|
||||
}
|
||||
|
||||
void writeToFileLocked() {
|
||||
Log.d(TAG, "Writing to " + mFile);
|
||||
|
||||
AtomicFile f = new AtomicFile(mFile);
|
||||
FileOutputStream outputStream = null;
|
||||
try {
|
||||
outputStream = f.startWrite();
|
||||
TypedXmlSerializer out = Xml.resolveSerializer(outputStream);
|
||||
|
||||
// Root tag
|
||||
out.startDocument(null, true);
|
||||
out.startTag(null, TAG_ROOT);
|
||||
|
||||
// Actual content
|
||||
writeInner(out);
|
||||
|
||||
// Close root
|
||||
out.endTag(null, TAG_ROOT);
|
||||
out.endDocument();
|
||||
out.flush();
|
||||
|
||||
// Commit the content.
|
||||
f.finishWrite(outputStream);
|
||||
outputStream = null;
|
||||
|
||||
} catch (IOException e) {
|
||||
Log.e(TAG, "Exception when writing", e);
|
||||
if (outputStream != null) {
|
||||
f.failWrite(outputStream);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void readFromFileLocked() {
|
||||
if (!mFile.exists()) {
|
||||
Log.d(TAG, "" + mFile + " doesn't exist");
|
||||
return;
|
||||
}
|
||||
|
||||
Log.d(TAG, "Reading from " + mFile);
|
||||
AtomicFile f = new AtomicFile(mFile);
|
||||
InputStream input = null;
|
||||
try {
|
||||
input = f.openRead();
|
||||
TypedXmlPullParser parser = Xml.resolvePullParser(input);
|
||||
|
||||
int type;
|
||||
int depth = 0;
|
||||
while ((type = parser.next()) != TypedXmlPullParser.END_DOCUMENT) {
|
||||
switch (type) {
|
||||
case TypedXmlPullParser.START_TAG:
|
||||
depth++;
|
||||
break;
|
||||
case TypedXmlPullParser.END_TAG:
|
||||
depth--;
|
||||
// fallthrough
|
||||
default:
|
||||
continue;
|
||||
}
|
||||
// Check the root tag
|
||||
String tag = parser.getName();
|
||||
if (depth == 1) {
|
||||
if (!TAG_ROOT.equals(tag)) {
|
||||
Log.e(TAG, "Invalid root tag: " + tag);
|
||||
return;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
// readInner() will only see START_TAG at depth >= 2.
|
||||
if (!readInner(parser, depth, tag)) {
|
||||
return; // Error
|
||||
}
|
||||
}
|
||||
} catch (XmlPullParserException | IOException e) {
|
||||
Log.e(TAG, "Error parsing resources file", e);
|
||||
} finally {
|
||||
IoUtils.closeQuietly(input);
|
||||
}
|
||||
}
|
||||
|
||||
void writeInner(TypedXmlSerializer out) throws IOException {
|
||||
if (mUpdatedDrawablesForStyle != null && !mUpdatedDrawablesForStyle.isEmpty()) {
|
||||
for (Map.Entry<Integer, Map<Integer, ParcelableResource>> drawableEntry
|
||||
: mUpdatedDrawablesForStyle.entrySet()) {
|
||||
out.startTag(/* namespace= */ null, TAG_DRAWABLE_STYLE_ENTRY);
|
||||
out.attributeInt(
|
||||
/* namespace= */ null, ATTR_DRAWABLE_ID, drawableEntry.getKey());
|
||||
out.attributeInt(
|
||||
/* namespace= */ null,
|
||||
ATTR_DRAWABLE_STYLE_SIZE,
|
||||
drawableEntry.getValue().size());
|
||||
int counter = 0;
|
||||
for (Map.Entry<Integer, ParcelableResource> styleEntry
|
||||
: drawableEntry.getValue().entrySet()) {
|
||||
out.attributeInt(
|
||||
/* namespace= */ null,
|
||||
ATTR_DRAWABLE_STYLE + (counter++),
|
||||
styleEntry.getKey());
|
||||
styleEntry.getValue().writeToXmlFile(out);
|
||||
}
|
||||
out.endTag(/* namespace= */ null, TAG_DRAWABLE_STYLE_ENTRY);
|
||||
}
|
||||
}
|
||||
if (mUpdatedDrawablesForSource != null && !mUpdatedDrawablesForSource.isEmpty()) {
|
||||
for (Map.Entry<Integer, Map<Integer, ParcelableResource>> drawableEntry
|
||||
: mUpdatedDrawablesForSource.entrySet()) {
|
||||
out.startTag(/* namespace= */ null, TAG_DRAWABLE_SOURCE_ENTRY);
|
||||
out.attributeInt(
|
||||
/* namespace= */ null, ATTR_DRAWABLE_ID, drawableEntry.getKey());
|
||||
out.attributeInt(
|
||||
/* namespace= */ null,
|
||||
ATTR_DRAWABLE_SOURCE_SIZE,
|
||||
drawableEntry.getValue().size());
|
||||
int counter = 0;
|
||||
for (Map.Entry<Integer, ParcelableResource> sourceEntry
|
||||
: drawableEntry.getValue().entrySet()) {
|
||||
out.attributeInt(
|
||||
/* namespace= */ null,
|
||||
ATTR_DRAWABLE_SOURCE + (counter++),
|
||||
sourceEntry.getKey());
|
||||
sourceEntry.getValue().writeToXmlFile(out);
|
||||
}
|
||||
out.endTag(/* namespace= */ null, TAG_DRAWABLE_SOURCE_ENTRY);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private boolean readInner(
|
||||
TypedXmlPullParser parser, int depth, String tag)
|
||||
throws XmlPullParserException, IOException {
|
||||
if (depth > 2) {
|
||||
return true; // Ignore
|
||||
}
|
||||
switch (tag) {
|
||||
case TAG_DRAWABLE_STYLE_ENTRY:
|
||||
int drawableId = parser.getAttributeInt(
|
||||
/* namespace= */ null, ATTR_DRAWABLE_ID);
|
||||
mUpdatedDrawablesForStyle.put(
|
||||
drawableId,
|
||||
new HashMap<>());
|
||||
int size = parser.getAttributeInt(
|
||||
/* namespace= */ null, ATTR_DRAWABLE_STYLE_SIZE);
|
||||
for (int i = 0; i < size; i++) {
|
||||
int style = parser.getAttributeInt(
|
||||
/* namespace= */ null, ATTR_DRAWABLE_STYLE + i);
|
||||
mUpdatedDrawablesForStyle.get(drawableId).put(
|
||||
style,
|
||||
ParcelableResource.createFromXml(parser));
|
||||
}
|
||||
break;
|
||||
case TAG_DRAWABLE_SOURCE_ENTRY:
|
||||
drawableId = parser.getAttributeInt(
|
||||
/* namespace= */ null, ATTR_DRAWABLE_ID);
|
||||
mUpdatedDrawablesForSource.put(drawableId, new HashMap<>());
|
||||
size = parser.getAttributeInt(
|
||||
/* namespace= */ null, ATTR_DRAWABLE_SOURCE_SIZE);
|
||||
for (int i = 0; i < size; i++) {
|
||||
int source = parser.getAttributeInt(
|
||||
/* namespace= */ null, ATTR_DRAWABLE_SOURCE + i);
|
||||
mUpdatedDrawablesForSource.get(drawableId).put(
|
||||
source,
|
||||
ParcelableResource.createFromXml(parser));
|
||||
}
|
||||
break;
|
||||
default:
|
||||
Log.e(TAG, "Unexpected tag: " + tag);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
public static class Injector {
|
||||
File environmentGetDataSystemDirectory() {
|
||||
return Environment.getDataSystemDirectory();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -26,6 +26,7 @@ import static android.app.AppOpsManager.MODE_DEFAULT;
|
||||
import static android.app.admin.DeviceAdminReceiver.ACTION_COMPLIANCE_ACKNOWLEDGEMENT_REQUIRED;
|
||||
import static android.app.admin.DeviceAdminReceiver.EXTRA_TRANSFER_OWNERSHIP_ADMIN_EXTRAS_BUNDLE;
|
||||
import static android.app.admin.DevicePolicyManager.ACTION_CHECK_POLICY_COMPLIANCE;
|
||||
import static android.app.admin.DevicePolicyManager.ACTION_DEVICE_POLICY_RESOURCE_UPDATED;
|
||||
import static android.app.admin.DevicePolicyManager.ACTION_PROVISION_MANAGED_DEVICE;
|
||||
import static android.app.admin.DevicePolicyManager.ACTION_PROVISION_MANAGED_PROFILE;
|
||||
import static android.app.admin.DevicePolicyManager.ACTION_PROVISION_MANAGED_USER;
|
||||
@@ -56,6 +57,8 @@ import static android.app.admin.DevicePolicyManager.DELEGATION_PACKAGE_ACCESS;
|
||||
import static android.app.admin.DevicePolicyManager.DELEGATION_PERMISSION_GRANT;
|
||||
import static android.app.admin.DevicePolicyManager.DELEGATION_SECURITY_LOGGING;
|
||||
import static android.app.admin.DevicePolicyManager.ENCRYPTION_STATUS_ACTIVE_PER_USER;
|
||||
import static android.app.admin.DevicePolicyManager.EXTRA_RESOURCE_ID;
|
||||
import static android.app.admin.DevicePolicyManager.EXTRA_RESOURCE_TYPE_DRAWABLE;
|
||||
import static android.app.admin.DevicePolicyManager.ID_TYPE_BASE_INFO;
|
||||
import static android.app.admin.DevicePolicyManager.ID_TYPE_IMEI;
|
||||
import static android.app.admin.DevicePolicyManager.ID_TYPE_INDIVIDUAL_ATTESTATION;
|
||||
@@ -161,6 +164,7 @@ import android.app.StatusBarManager;
|
||||
import android.app.admin.DeviceAdminInfo;
|
||||
import android.app.admin.DeviceAdminReceiver;
|
||||
import android.app.admin.DevicePolicyCache;
|
||||
import android.app.admin.DevicePolicyDrawableResource;
|
||||
import android.app.admin.DevicePolicyEventLogger;
|
||||
import android.app.admin.DevicePolicyManager;
|
||||
import android.app.admin.DevicePolicyManager.DeviceOwnerType;
|
||||
@@ -177,6 +181,7 @@ import android.app.admin.FullyManagedDeviceProvisioningParams;
|
||||
import android.app.admin.ManagedProfileProvisioningParams;
|
||||
import android.app.admin.NetworkEvent;
|
||||
import android.app.admin.ParcelableGranteeMap;
|
||||
import android.app.admin.ParcelableResource;
|
||||
import android.app.admin.PasswordMetrics;
|
||||
import android.app.admin.PasswordPolicy;
|
||||
import android.app.admin.SecurityLog;
|
||||
@@ -716,6 +721,8 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
|
||||
// Guarded by mHandler
|
||||
private @UserIdInt int mNetworkLoggingNotificationUserId = UserHandle.USER_NULL;
|
||||
|
||||
private final DeviceManagementResourcesProvider mDeviceManagementResourcesProvider;
|
||||
|
||||
private static final boolean ENABLE_LOCK_GUARD = true;
|
||||
|
||||
/**
|
||||
@@ -1740,6 +1747,10 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
|
||||
void setDevicePolicySafetyChecker(DevicePolicySafetyChecker safetyChecker) {
|
||||
mSafetyChecker = safetyChecker;
|
||||
}
|
||||
|
||||
DeviceManagementResourcesProvider getDeviceManagementResourcesProvider() {
|
||||
return new DeviceManagementResourcesProvider();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1792,6 +1803,8 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
|
||||
mTransferOwnershipMetadataManager = mInjector.newTransferOwnershipMetadataManager();
|
||||
mBugreportCollectionManager = new RemoteBugreportManager(this, mInjector);
|
||||
|
||||
mDeviceManagementResourcesProvider = mInjector.getDeviceManagementResourcesProvider();
|
||||
|
||||
// "Lite" interface is available even when the device doesn't have the feature
|
||||
LocalServices.addService(DevicePolicyManagerLiteInternal.class, mLocalService);
|
||||
if (!mHasFeature) {
|
||||
@@ -1838,6 +1851,8 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
|
||||
loadOwners();
|
||||
|
||||
performPolicyVersionUpgrade();
|
||||
|
||||
mDeviceManagementResourcesProvider.load();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -17956,4 +17971,54 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
|
||||
&& mInjector.getUsbManager().getUsbHalVersion() >= UsbManager.USB_HAL_V1_3
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setDrawables(@NonNull List<DevicePolicyDrawableResource> drawables) {
|
||||
Preconditions.checkCallAuthorization(hasCallingOrSelfPermission(
|
||||
android.Manifest.permission.UPDATE_DEVICE_MANAGEMENT_RESOURCES));
|
||||
|
||||
Objects.requireNonNull(drawables, "drawables must be provided.");
|
||||
|
||||
mInjector.binderWithCleanCallingIdentity(() -> {
|
||||
if (mDeviceManagementResourcesProvider.updateDrawables(drawables)) {
|
||||
sendDrawableUpdatedBroadcast(
|
||||
drawables.stream().mapToInt(d -> d.getDrawableId()).toArray());
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void resetDrawables(@NonNull int[] drawableIds) {
|
||||
Preconditions.checkCallAuthorization(hasCallingOrSelfPermission(
|
||||
android.Manifest.permission.UPDATE_DEVICE_MANAGEMENT_RESOURCES));
|
||||
|
||||
Objects.requireNonNull(drawableIds, "drawableIds must be provided.");
|
||||
|
||||
mInjector.binderWithCleanCallingIdentity(() -> {
|
||||
if (mDeviceManagementResourcesProvider.removeDrawables(drawableIds)) {
|
||||
sendDrawableUpdatedBroadcast(drawableIds);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public ParcelableResource getDrawable(int drawableId, int drawableStyle, int drawableSource) {
|
||||
return mInjector.binderWithCleanCallingIdentity(() ->
|
||||
mDeviceManagementResourcesProvider.getDrawable(
|
||||
drawableId, drawableStyle, drawableSource));
|
||||
}
|
||||
|
||||
private void sendDrawableUpdatedBroadcast(int[] drawableIds) {
|
||||
final Intent intent = new Intent(ACTION_DEVICE_POLICY_RESOURCE_UPDATED);
|
||||
intent.putExtra(EXTRA_RESOURCE_ID, drawableIds);
|
||||
intent.putExtra(EXTRA_RESOURCE_TYPE_DRAWABLE, /* value= */ true);
|
||||
intent.setFlags(Intent.FLAG_RECEIVER_FOREGROUND);
|
||||
intent.setFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
|
||||
|
||||
List<UserInfo> users = mUserManager.getAliveUsers();
|
||||
for (int i = 0; i < users.size(); i++) {
|
||||
UserHandle user = users.get(i).getUserHandle();
|
||||
mContext.sendBroadcastAsUser(intent, user);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user