Added restriction that disallows ability to set wallpaper.
BUG: 24890474
Change-Id: I424aa80d914e3b6f3f9eba8ccb4802bad6f54907
diff --git a/api/current.txt b/api/current.txt
index 2fd32c5..53bbd40 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -5705,6 +5705,7 @@
method public static android.app.WallpaperManager getInstance(android.content.Context);
method public android.app.WallpaperInfo getWallpaperInfo();
method public boolean hasResourceWallpaper(int);
+ method public boolean isWallpaperSettingAllowed();
method public boolean isWallpaperSupported();
method public android.graphics.drawable.Drawable peekDrawable();
method public android.graphics.drawable.Drawable peekFastDrawable();
@@ -29264,6 +29265,7 @@
field public static final java.lang.String DISALLOW_REMOVE_USER = "no_remove_user";
field public static final java.lang.String DISALLOW_SAFE_BOOT = "no_safe_boot";
field public static final java.lang.String DISALLOW_SET_USER_ICON = "no_set_user_icon";
+ field public static final java.lang.String DISALLOW_SET_WALLPAPER = "no_set_wallpaper";
field public static final java.lang.String DISALLOW_SHARE_LOCATION = "no_share_location";
field public static final java.lang.String DISALLOW_SMS = "no_sms";
field public static final java.lang.String DISALLOW_UNINSTALL_APPS = "no_uninstall_apps";
diff --git a/api/system-current.txt b/api/system-current.txt
index 5b640cd..87bf496 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -5838,6 +5838,7 @@
method public static android.app.WallpaperManager getInstance(android.content.Context);
method public android.app.WallpaperInfo getWallpaperInfo();
method public boolean hasResourceWallpaper(int);
+ method public boolean isWallpaperSettingAllowed();
method public boolean isWallpaperSupported();
method public android.graphics.drawable.Drawable peekDrawable();
method public android.graphics.drawable.Drawable peekFastDrawable();
@@ -31310,6 +31311,7 @@
field public static final java.lang.String DISALLOW_REMOVE_USER = "no_remove_user";
field public static final java.lang.String DISALLOW_SAFE_BOOT = "no_safe_boot";
field public static final java.lang.String DISALLOW_SET_USER_ICON = "no_set_user_icon";
+ field public static final java.lang.String DISALLOW_SET_WALLPAPER = "no_set_wallpaper";
field public static final java.lang.String DISALLOW_SHARE_LOCATION = "no_share_location";
field public static final java.lang.String DISALLOW_SMS = "no_sms";
field public static final java.lang.String DISALLOW_UNINSTALL_APPS = "no_uninstall_apps";
diff --git a/api/test-current.txt b/api/test-current.txt
index 47eec48..bc3b47c 100644
--- a/api/test-current.txt
+++ b/api/test-current.txt
@@ -5707,6 +5707,7 @@
method public static android.app.WallpaperManager getInstance(android.content.Context);
method public android.app.WallpaperInfo getWallpaperInfo();
method public boolean hasResourceWallpaper(int);
+ method public boolean isWallpaperSettingAllowed();
method public boolean isWallpaperSupported();
method public android.graphics.drawable.Drawable peekDrawable();
method public android.graphics.drawable.Drawable peekFastDrawable();
@@ -29274,6 +29275,7 @@
field public static final java.lang.String DISALLOW_REMOVE_USER = "no_remove_user";
field public static final java.lang.String DISALLOW_SAFE_BOOT = "no_safe_boot";
field public static final java.lang.String DISALLOW_SET_USER_ICON = "no_set_user_icon";
+ field public static final java.lang.String DISALLOW_SET_WALLPAPER = "no_set_wallpaper";
field public static final java.lang.String DISALLOW_SHARE_LOCATION = "no_share_location";
field public static final java.lang.String DISALLOW_SMS = "no_sms";
field public static final java.lang.String DISALLOW_UNINSTALL_APPS = "no_uninstall_apps";
diff --git a/core/java/android/app/IWallpaperManager.aidl b/core/java/android/app/IWallpaperManager.aidl
index fa0fbd1..04493cb 100644
--- a/core/java/android/app/IWallpaperManager.aidl
+++ b/core/java/android/app/IWallpaperManager.aidl
@@ -113,4 +113,9 @@
* Check whether wallpapers are supported for the calling user.
*/
boolean isWallpaperSupported(in String callingPackage);
+
+ /**
+ * Check whether setting of wallpapers are allowed for the calling user.
+ */
+ boolean isWallpaperSettingAllowed(in String callingPackage);
}
diff --git a/core/java/android/app/WallpaperManager.java b/core/java/android/app/WallpaperManager.java
index b0ffd21..eda82c0 100644
--- a/core/java/android/app/WallpaperManager.java
+++ b/core/java/android/app/WallpaperManager.java
@@ -74,7 +74,8 @@
* {@link #getInstance(android.content.Context) getInstance()}.
*
* <p> An app can check whether wallpapers are supported for the current user, by calling
- * {@link #isWallpaperSupported()}.
+ * {@link #isWallpaperSupported()}, and whether setting of wallpapers is allowed, by calling
+ * {@link #isWallpaperSettingAllowed()}.
*/
public class WallpaperManager {
private static String TAG = "WallpaperManager";
@@ -134,7 +135,7 @@
* screen coordinates.
*/
public static final String COMMAND_TAP = "android.wallpaper.tap";
-
+
/**
* Command for {@link #sendWallpaperCommand}: reported by the wallpaper
* host when the user releases a secondary pointer on an empty area
@@ -177,7 +178,7 @@
public static final int FLAG_SET_LOCK = 1 << 1;
private final Context mContext;
-
+
/**
* Special drawable that draws a wallpaper as fast as possible. Assumes
* no scaling or placement off (0,0) of the wallpaper (this should be done
@@ -258,19 +259,19 @@
return mHeight;
}
}
-
+
static class Globals extends IWallpaperManagerCallback.Stub {
private IWallpaperManager mService;
private Bitmap mWallpaper;
private Bitmap mDefaultWallpaper;
-
+
private static final int MSG_CLEAR_WALLPAPER = 1;
-
+
Globals(Looper looper) {
IBinder b = ServiceManager.getService(Context.WALLPAPER_SERVICE);
mService = IWallpaperManager.Stub.asInterface(b);
}
-
+
public void onWallpaperChanged() {
/* The wallpaper has changed but we shouldn't eagerly load the
* wallpaper as that would be inefficient. Reset the cached wallpaper
@@ -366,7 +367,7 @@
return null;
}
}
-
+
private static final Object sSync = new Object[0];
private static Globals sGlobals;
@@ -377,7 +378,7 @@
}
}
}
-
+
/*package*/ WallpaperManager(Context context, Handler handler) {
mContext = context;
initGlobals(context.getMainLooper());
@@ -390,18 +391,18 @@
return (WallpaperManager)context.getSystemService(
Context.WALLPAPER_SERVICE);
}
-
+
/** @hide */
public IWallpaperManager getIWallpaperManager() {
return sGlobals.mService;
}
-
+
/**
* Retrieve the current system wallpaper; if
* no wallpaper is set, the system built-in static wallpaper is returned.
* This is returned as an
* abstract Drawable that you can install in a View to display whatever
- * wallpaper the user has currently set.
+ * wallpaper the user has currently set.
*
* @return Returns a Drawable object that will draw the wallpaper.
*/
@@ -588,7 +589,7 @@
* Retrieve the current system wallpaper; if there is no wallpaper set,
* a null pointer is returned. This is returned as an
* abstract Drawable that you can install in a View to display whatever
- * wallpaper the user has currently set.
+ * wallpaper the user has currently set.
*
* @return Returns a Drawable object that will draw the wallpaper or a
* null pointer if these is none.
@@ -641,7 +642,7 @@
/**
* Like {@link #getDrawable()} but returns a Bitmap.
- *
+ *
* @hide
*/
public Bitmap getBitmap() {
@@ -1248,7 +1249,7 @@
* are floating point numbers ranging from 0 to 1, representing where the
* wallpaper should be positioned within the screen space. These only
* make sense when the wallpaper is larger than the display.
- *
+ *
* @param windowToken The window who these offsets should be associated
* with, as returned by {@link android.view.View#getWindowToken()
* View.getWindowToken()}.
@@ -1271,17 +1272,17 @@
* specify the step size between virtual screens. For example, if the
* launcher has 3 virtual screens, it would specify an xStep of 0.5,
* since the X offset for those screens are 0.0, 0.5 and 1.0
- * @param xStep The X offset delta from one screen to the next one
+ * @param xStep The X offset delta from one screen to the next one
* @param yStep The Y offset delta from one screen to the next one
*/
public void setWallpaperOffsetSteps(float xStep, float yStep) {
mWallpaperXStep = xStep;
mWallpaperYStep = yStep;
}
-
+
/**
* Send an arbitrary command to the current active wallpaper.
- *
+ *
* @param windowToken The window who these offsets should be associated
* with, as returned by {@link android.view.View#getWindowToken()
* View.getWindowToken()}.
@@ -1306,7 +1307,8 @@
/**
* Returns whether wallpapers are supported for the calling user. If this function returns
- * false, any attempts to changing the wallpaper will have no effect.
+ * {@code false}, any attempts to changing the wallpaper will have no effect,
+ * and any attempt to obtain of the wallpaper will return {@code null}.
*/
public boolean isWallpaperSupported() {
if (sGlobals.mService == null) {
@@ -1322,11 +1324,31 @@
}
/**
+ * Returns whether the calling package is allowed to set the wallpaper for the calling user.
+ * If this function returns {@code false}, any attempts to change the wallpaper will have
+ * no effect. Always returns {@code true} for device owner and profile owner.
+ *
+ * @see android.os.UserManager#DISALLOW_SET_WALLPAPER
+ */
+ public boolean isWallpaperSettingAllowed() {
+ if (sGlobals.mService == null) {
+ Log.w(TAG, "WallpaperService not running");
+ } else {
+ try {
+ return sGlobals.mService.isWallpaperSettingAllowed(mContext.getOpPackageName());
+ } catch (RemoteException e) {
+ // Ignore
+ }
+ }
+ return false;
+ }
+
+ /**
* Clear the offsets previously associated with this window through
* {@link #setWallpaperOffsets(IBinder, float, float)}. This reverts
* the window to its default state, where it does not cause the wallpaper
* to scroll from whatever its last offsets were.
- *
+ *
* @param windowToken The window who these offsets should be associated
* with, as returned by {@link android.view.View#getWindowToken()
* View.getWindowToken()}.
@@ -1339,7 +1361,7 @@
// Ignore.
}
}
-
+
/**
* Remove any currently set wallpaper, reverting to the system's built-in
* wallpaper. On success, the intent {@link Intent#ACTION_WALLPAPER_CHANGED}
diff --git a/core/java/android/os/UserManager.java b/core/java/android/os/UserManager.java
index 1ac798b..ad7b4e2 100644
--- a/core/java/android/os/UserManager.java
+++ b/core/java/android/os/UserManager.java
@@ -463,9 +463,11 @@
public static final String DISALLOW_OUTGOING_BEAM = "no_outgoing_beam";
/**
- * Hidden user restriction to disallow access to wallpaper manager APIs. This user restriction
- * is always set for managed profiles.
+ * Hidden user restriction to disallow access to wallpaper manager APIs. This restriction
+ * generally means that wallpapers are not supported for the particular user. This user
+ * restriction is always set for managed profiles, because such profiles don't have wallpapers.
* @hide
+ * @see #DISALLOW_SET_WALLPAPER
* @see DevicePolicyManager#addUserRestriction(ComponentName, String)
* @see DevicePolicyManager#clearUserRestriction(ComponentName, String)
* @see #getUserRestrictions()
@@ -473,6 +475,19 @@
public static final String DISALLOW_WALLPAPER = "no_wallpaper";
/**
+ * User restriction to disallow setting a wallpaper. Profile owner and device owner
+ * are able to set wallpaper regardless of this restriction.
+ * The default value is <code>false</code>.
+ *
+ * <p>Key for user restrictions.
+ * <p>Type: Boolean
+ * @see DevicePolicyManager#addUserRestriction(ComponentName, String)
+ * @see DevicePolicyManager#clearUserRestriction(ComponentName, String)
+ * @see #getUserRestrictions()
+ */
+ public static final String DISALLOW_SET_WALLPAPER = "no_set_wallpaper";
+
+ /**
* Specifies if the user is not allowed to reboot the device into safe boot mode.
* This can only be set by device owners and profile owners on the primary user.
* The default value is <code>false</code>.
@@ -535,9 +550,7 @@
* affected. The default value is <code>false</code>.
*
* <p>Key for user restrictions.
- *
* <p>Type: Boolean
- *
* @see DevicePolicyManager#addUserRestriction(ComponentName, String)
* @see DevicePolicyManager#clearUserRestriction(ComponentName, String)
* @see #getUserRestrictions()
diff --git a/services/core/java/com/android/server/pm/UserRestrictionsUtils.java b/services/core/java/com/android/server/pm/UserRestrictionsUtils.java
index 87f505d..f11872e 100644
--- a/services/core/java/com/android/server/pm/UserRestrictionsUtils.java
+++ b/services/core/java/com/android/server/pm/UserRestrictionsUtils.java
@@ -93,7 +93,8 @@
UserManager.DISALLOW_CAMERA,
UserManager.DISALLOW_RUN_IN_BACKGROUND,
UserManager.DISALLOW_DATA_ROAMING,
- UserManager.DISALLOW_SET_USER_ICON
+ UserManager.DISALLOW_SET_USER_ICON,
+ UserManager.DISALLOW_SET_WALLPAPER
);
/**
diff --git a/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java b/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java
index c7d7096..09c53ae 100644
--- a/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java
+++ b/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java
@@ -27,6 +27,7 @@
import android.app.PendingIntent;
import android.app.WallpaperInfo;
import android.app.WallpaperManager;
+import android.app.admin.DevicePolicyManager;
import android.app.backup.BackupManager;
import android.app.backup.WallpaperBackupHelper;
import android.content.BroadcastReceiver;
@@ -84,6 +85,7 @@
import java.io.FileOutputStream;
import java.io.PrintWriter;
import java.nio.charset.StandardCharsets;
+import java.util.Arrays;
import java.util.List;
import org.xmlpull.v1.XmlPullParser;
@@ -611,7 +613,7 @@
return changed;
}
}
-
+
public WallpaperManagerService(Context context) {
if (DEBUG) Slog.v(TAG, "WallpaperService startup");
mContext = context;
@@ -626,7 +628,7 @@
getWallpaperDir(UserHandle.USER_SYSTEM).mkdirs();
loadSettingsLocked(UserHandle.USER_SYSTEM);
}
-
+
private static File getWallpaperDir(int userId) {
return Environment.getUserSystemDirectory(userId);
}
@@ -764,7 +766,7 @@
public void clearWallpaper(String callingPackage) {
if (DEBUG) Slog.v(TAG, "clearWallpaper");
checkPermission(android.Manifest.permission.SET_WALLPAPER);
- if (!isWallpaperSupported(callingPackage)) {
+ if (!isWallpaperSupported(callingPackage) || !isWallpaperSettingAllowed(callingPackage)) {
return;
}
synchronized (mLock) {
@@ -1000,7 +1002,7 @@
return null;
}
- if (!isWallpaperSupported(callingPackage)) {
+ if (!isWallpaperSupported(callingPackage) || !isWallpaperSettingAllowed(callingPackage)) {
return null;
}
@@ -1069,7 +1071,7 @@
}
public void setWallpaperComponentChecked(ComponentName name, String callingPackage) {
- if (isWallpaperSupported(callingPackage)) {
+ if (isWallpaperSupported(callingPackage) && isWallpaperSettingAllowed(callingPackage)) {
setWallpaperComponent(name);
}
}
@@ -1093,7 +1095,7 @@
}
}
}
-
+
boolean bindWallpaperComponentLocked(ComponentName componentName, boolean force,
boolean fromUser, WallpaperData wallpaper, IRemoteCallback reply) {
if (DEBUG) Slog.v(TAG, "bindWallpaperComponentLocked: componentName=" + componentName);
@@ -1113,7 +1115,7 @@
}
}
}
-
+
try {
if (componentName == null) {
componentName = WallpaperManager.getDefaultWallpaperComponent(mContext);
@@ -1143,9 +1145,9 @@
Slog.w(TAG, msg);
return false;
}
-
+
WallpaperInfo wi = null;
-
+
Intent intent = new Intent(WallpaperService.SERVICE_INTERFACE);
if (componentName != null && !componentName.equals(mImageWallpaper)) {
// Make sure the selected service is actually a wallpaper service.
@@ -1185,7 +1187,7 @@
return false;
}
}
-
+
// Bind the service!
if (DEBUG) Slog.v(TAG, "Binding to:" + componentName);
WallpaperConnection newConn = new WallpaperConnection(wi, wallpaper);
@@ -1314,6 +1316,23 @@
callingPackage) == AppOpsManager.MODE_ALLOWED;
}
+ @Override
+ public boolean isWallpaperSettingAllowed(String callingPackage) {
+ final PackageManager pm = mContext.getPackageManager();
+ String[] uidPackages = pm.getPackagesForUid(Binder.getCallingUid());
+ boolean uidMatchPackage = Arrays.asList(uidPackages).contains(callingPackage);
+ if (!uidMatchPackage) {
+ return false; // callingPackage was faked.
+ }
+
+ final DevicePolicyManager dpm = mContext.getSystemService(DevicePolicyManager.class);
+ if (dpm.isDeviceOwnerApp(callingPackage) || dpm.isProfileOwnerApp(callingPackage)) {
+ return true;
+ }
+ final UserManager um = (UserManager) mContext.getSystemService(Context.USER_SERVICE);
+ return !um.hasUserRestriction(UserManager.DISALLOW_SET_WALLPAPER);
+ }
+
private static JournaledFile makeJournaledFile(int userId) {
final String base = new File(getWallpaperDir(userId), WALLPAPER_INFO).getAbsolutePath();
return new JournaledFile(new File(base), new File(base + ".tmp"));
@@ -1465,7 +1484,7 @@
.getPackageName())) {
wallpaper.nextWallpaperComponent = mImageWallpaper;
}
-
+
if (DEBUG) {
Slog.v(TAG, "mWidth:" + wallpaper.width);
Slog.v(TAG, "mHeight:" + wallpaper.height);
@@ -1666,7 +1685,7 @@
protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DUMP)
!= PackageManager.PERMISSION_GRANTED) {
-
+
pw.println("Permission Denial: can't dump wallpaper service from from pid="
+ Binder.getCallingPid()
+ ", uid=" + Binder.getCallingUid());