diff options
-rw-r--r-- | api/current.txt | 1 | ||||
-rw-r--r-- | api/system-current.txt | 1 | ||||
-rw-r--r-- | core/java/android/app/AppOpsManager.java | 12 | ||||
-rw-r--r-- | core/java/android/app/IWallpaperManager.aidl | 20 | ||||
-rw-r--r-- | core/java/android/app/WallpaperManager.java | 54 | ||||
-rw-r--r-- | core/java/android/os/UserManager.java | 9 | ||||
-rw-r--r-- | services/core/java/com/android/server/pm/UserManagerService.java | 2 | ||||
-rw-r--r-- | services/core/java/com/android/server/wallpaper/WallpaperManagerService.java | 67 | ||||
-rw-r--r-- | services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java | 11 |
9 files changed, 153 insertions, 24 deletions
diff --git a/api/current.txt b/api/current.txt index e6d8546..99d8fd4 100644 --- a/api/current.txt +++ b/api/current.txt @@ -5369,6 +5369,7 @@ package android.app { method public static android.app.WallpaperManager getInstance(android.content.Context); method public android.app.WallpaperInfo getWallpaperInfo(); method public boolean hasResourceWallpaper(int); + method public boolean isWallpaperSupported(); method public android.graphics.drawable.Drawable peekDrawable(); method public android.graphics.drawable.Drawable peekFastDrawable(); method public void sendWallpaperCommand(android.os.IBinder, java.lang.String, int, int, int, android.os.Bundle); diff --git a/api/system-current.txt b/api/system-current.txt index ca84133..21aee04 100644 --- a/api/system-current.txt +++ b/api/system-current.txt @@ -5460,6 +5460,7 @@ package android.app { method public static android.app.WallpaperManager getInstance(android.content.Context); method public android.app.WallpaperInfo getWallpaperInfo(); method public boolean hasResourceWallpaper(int); + method public boolean isWallpaperSupported(); method public android.graphics.drawable.Drawable peekDrawable(); method public android.graphics.drawable.Drawable peekFastDrawable(); method public void sendWallpaperCommand(android.os.IBinder, java.lang.String, int, int, int, android.os.Bundle); diff --git a/core/java/android/app/AppOpsManager.java b/core/java/android/app/AppOpsManager.java index 95870cf..4bd2332 100644 --- a/core/java/android/app/AppOpsManager.java +++ b/core/java/android/app/AppOpsManager.java @@ -206,8 +206,10 @@ public class AppOpsManager { public static final int OP_PROJECT_MEDIA = 46; /** @hide Activate a VPN connection without user intervention. */ public static final int OP_ACTIVATE_VPN = 47; + /** @hide Access the WallpaperManagerAPI to write wallpapers. */ + public static final int OP_WRITE_WALLPAPER = 48; /** @hide */ - public static final int _NUM_OP = 48; + public static final int _NUM_OP = 49; /** Access to coarse location information. */ public static final String OPSTR_COARSE_LOCATION = @@ -285,6 +287,7 @@ public class AppOpsManager { OP_TOAST_WINDOW, OP_PROJECT_MEDIA, OP_ACTIVATE_VPN, + OP_WRITE_WALLPAPER, }; /** @@ -340,6 +343,7 @@ public class AppOpsManager { null, null, OPSTR_ACTIVATE_VPN, + null, }; /** @@ -395,6 +399,7 @@ public class AppOpsManager { "TOAST_WINDOW", "PROJECT_MEDIA", "ACTIVATE_VPN", + "WRITE_WALLPAPER", }; /** @@ -450,6 +455,7 @@ public class AppOpsManager { null, // no permission for displaying toasts null, // no permission for projecting media null, // no permission for activating vpn + null, // no permission for supporting wallpaper }; /** @@ -506,6 +512,7 @@ public class AppOpsManager { UserManager.DISALLOW_CREATE_WINDOWS, // TOAST_WINDOW null, //PROJECT_MEDIA UserManager.DISALLOW_CONFIG_VPN, // ACTIVATE_VPN + UserManager.DISALLOW_WALLPAPER, // WRITE_WALLPAPER }; /** @@ -561,6 +568,7 @@ public class AppOpsManager { true, //TOAST_WINDOW false, //PROJECT_MEDIA false, //ACTIVATE_VPN + false, //WALLPAPER }; /** @@ -615,6 +623,7 @@ public class AppOpsManager { AppOpsManager.MODE_ALLOWED, AppOpsManager.MODE_IGNORED, // OP_PROJECT_MEDIA AppOpsManager.MODE_IGNORED, // OP_ACTIVATE_VPN + AppOpsManager.MODE_ALLOWED, }; /** @@ -673,6 +682,7 @@ public class AppOpsManager { false, false, false, + false, }; private static HashMap<String, Integer> sOpStrToOp = new HashMap<String, Integer>(); diff --git a/core/java/android/app/IWallpaperManager.aidl b/core/java/android/app/IWallpaperManager.aidl index 3b5900b..ccba250 100644 --- a/core/java/android/app/IWallpaperManager.aidl +++ b/core/java/android/app/IWallpaperManager.aidl @@ -29,13 +29,18 @@ interface IWallpaperManager { /** * Set the wallpaper. */ - ParcelFileDescriptor setWallpaper(String name); + ParcelFileDescriptor setWallpaper(String name, in String callingPackage); /** * Set the live wallpaper. */ + void setWallpaperComponentChecked(in ComponentName name, in String callingPackage); + + /** + * Set the live wallpaper. + */ void setWallpaperComponent(in ComponentName name); - + /** * Get the wallpaper. */ @@ -50,7 +55,7 @@ interface IWallpaperManager { /** * Clear the wallpaper. */ - void clearWallpaper(); + void clearWallpaper(in String callingPackage); /** * Return whether there is a wallpaper set with the given name. @@ -61,7 +66,7 @@ interface IWallpaperManager { * Sets the dimension hint for the wallpaper. These hints indicate the desired * minimum width and height for the wallpaper. */ - void setDimensionHints(in int width, in int height); + void setDimensionHints(in int width, in int height, in String callingPackage); /** * Returns the desired minimum width for the wallpaper. @@ -76,7 +81,7 @@ interface IWallpaperManager { /** * Sets extra padding that we would like the wallpaper to have outside of the display. */ - void setDisplayPadding(in Rect padding); + void setDisplayPadding(in Rect padding, in String callingPackage); /** * Returns the name of the wallpaper. Private API. @@ -87,4 +92,9 @@ interface IWallpaperManager { * Informs the service that wallpaper settings have been restored. Private API. */ void settingsRestored(); + + /** + * Check whether wallpapers are supported for the calling user. + */ + boolean isWallpaperSupported(in String callingPackage); } diff --git a/core/java/android/app/WallpaperManager.java b/core/java/android/app/WallpaperManager.java index badb606..22e79b6 100644 --- a/core/java/android/app/WallpaperManager.java +++ b/core/java/android/app/WallpaperManager.java @@ -64,7 +64,10 @@ import java.util.List; * Provides access to the system wallpaper. With WallpaperManager, you can * get the current wallpaper, get the desired dimensions for the wallpaper, set * the wallpaper, and more. Get an instance of WallpaperManager with - * {@link #getInstance(android.content.Context) getInstance()}. + * {@link #getInstance(android.content.Context) getInstance()}. + * + * <p> An app can check whether wallpapers are supported for the current user, by calling + * {@link #isWallpaperSupported()}. */ public class WallpaperManager { private static String TAG = "WallpaperManager"; @@ -249,6 +252,15 @@ public class WallpaperManager { public Bitmap peekWallpaperBitmap(Context context, boolean returnDefault) { synchronized (this) { + if (mService != null) { + try { + if (!mService.isWallpaperSupported(context.getOpPackageName())) { + return null; + } + } catch (RemoteException e) { + // Ignore + } + } if (mWallpaper != null) { return mWallpaper; } @@ -618,7 +630,9 @@ public class WallpaperManager { * wallpaper will require reloading it again from disk. */ public void forgetLoadedWallpaper() { - sGlobals.forgetLoadedWallpaper(); + if (isWallpaperSupported()) { + sGlobals.forgetLoadedWallpaper(); + } } /** @@ -717,7 +731,7 @@ public class WallpaperManager { Resources resources = mContext.getResources(); /* Set the wallpaper to the default values */ ParcelFileDescriptor fd = sGlobals.mService.setWallpaper( - "res:" + resources.getResourceName(resid)); + "res:" + resources.getResourceName(resid), mContext.getOpPackageName()); if (fd != null) { FileOutputStream fos = null; try { @@ -753,7 +767,8 @@ public class WallpaperManager { return; } try { - ParcelFileDescriptor fd = sGlobals.mService.setWallpaper(null); + ParcelFileDescriptor fd = sGlobals.mService.setWallpaper(null, + mContext.getOpPackageName()); if (fd == null) { return; } @@ -792,7 +807,8 @@ public class WallpaperManager { return; } try { - ParcelFileDescriptor fd = sGlobals.mService.setWallpaper(null); + ParcelFileDescriptor fd = sGlobals.mService.setWallpaper(null, + mContext.getOpPackageName()); if (fd == null) { return; } @@ -945,7 +961,8 @@ public class WallpaperManager { if (sGlobals.mService == null) { Log.w(TAG, "WallpaperService not running"); } else { - sGlobals.mService.setDimensionHints(minimumWidth, minimumHeight); + sGlobals.mService.setDimensionHints(minimumWidth, minimumHeight, + mContext.getOpPackageName()); } } catch (RemoteException e) { // Ignore @@ -966,7 +983,7 @@ public class WallpaperManager { if (sGlobals.mService == null) { Log.w(TAG, "WallpaperService not running"); } else { - sGlobals.mService.setDisplayPadding(padding); + sGlobals.mService.setDisplayPadding(padding, mContext.getOpPackageName()); } } catch (RemoteException e) { // Ignore @@ -1006,7 +1023,7 @@ public class WallpaperManager { return; } try { - sGlobals.mService.clearWallpaper(); + sGlobals.mService.clearWallpaper(mContext.getOpPackageName()); } catch (RemoteException e) { // Ignore } @@ -1027,7 +1044,7 @@ public class WallpaperManager { return false; } try { - sGlobals.mService.setWallpaperComponent(name); + sGlobals.mService.setWallpaperComponentChecked(name, mContext.getOpPackageName()); return true; } catch (RemoteException e) { // Ignore @@ -1096,7 +1113,24 @@ public class WallpaperManager { // Ignore. } } - + + /** + * Returns whether wallpapers are supported for the calling user. If this function returns + * false, any attempts to changing the wallpaper will have no effect. + */ + public boolean isWallpaperSupported() { + if (sGlobals.mService == null) { + Log.w(TAG, "WallpaperService not running"); + } else { + try { + return sGlobals.mService.isWallpaperSupported(mContext.getOpPackageName()); + } catch (RemoteException e) { + // Ignore + } + } + return false; + } + /** * Clear the offsets previously associated with this window through * {@link #setWallpaperOffsets(IBinder, float, float)}. This reverts diff --git a/core/java/android/os/UserManager.java b/core/java/android/os/UserManager.java index 650f3b3..706e0d0 100644 --- a/core/java/android/os/UserManager.java +++ b/core/java/android/os/UserManager.java @@ -391,6 +391,15 @@ public class UserManager { 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. + * @hide + * @see #setUserRestrictions(Bundle) + * @see #getUserRestrictions() + */ + public static final String DISALLOW_WALLPAPER = "no_wallpaper"; + + /** * Application restriction key that is used to indicate the pending arrival * of real restrictions for the app. * diff --git a/services/core/java/com/android/server/pm/UserManagerService.java b/services/core/java/com/android/server/pm/UserManagerService.java index 2729392..e4f5e7d 100644 --- a/services/core/java/com/android/server/pm/UserManagerService.java +++ b/services/core/java/com/android/server/pm/UserManagerService.java @@ -917,6 +917,7 @@ public class UserManagerService extends IUserManager.Stub { writeBoolean(serializer, restrictions, UserManager.DISALLOW_CREATE_WINDOWS); writeBoolean(serializer, restrictions, UserManager.DISALLOW_CROSS_PROFILE_COPY_PASTE); writeBoolean(serializer, restrictions, UserManager.DISALLOW_OUTGOING_BEAM); + writeBoolean(serializer, restrictions, UserManager.DISALLOW_WALLPAPER); serializer.endTag(null, TAG_RESTRICTIONS); } @@ -1063,6 +1064,7 @@ public class UserManagerService extends IUserManager.Stub { readBoolean(parser, restrictions, UserManager.DISALLOW_CREATE_WINDOWS); readBoolean(parser, restrictions, UserManager.DISALLOW_CROSS_PROFILE_COPY_PASTE); readBoolean(parser, restrictions, UserManager.DISALLOW_OUTGOING_BEAM); + readBoolean(parser, restrictions, UserManager.DISALLOW_WALLPAPER); } private void readBoolean(XmlPullParser parser, Bundle restrictions, diff --git a/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java b/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java index b48fadb..99cf8df 100644 --- a/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java +++ b/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java @@ -20,6 +20,7 @@ import static android.os.ParcelFileDescriptor.*; import android.app.ActivityManagerNative; import android.app.AppGlobals; +import android.app.AppOpsManager; import android.app.IUserSwitchObserver; import android.app.IWallpaperManager; import android.app.IWallpaperManagerCallback; @@ -164,6 +165,7 @@ public class WallpaperManagerService extends IWallpaperManager.Stub { final IWindowManager mIWindowManager; final IPackageManager mIPackageManager; final MyPackageMonitor mMonitor; + final AppOpsManager mAppOpsManager; WallpaperData mLastWallpaper; /** @@ -478,6 +480,7 @@ public class WallpaperManagerService extends IWallpaperManager.Stub { mIWindowManager = IWindowManager.Stub.asInterface( ServiceManager.getService(Context.WINDOW_SERVICE)); mIPackageManager = AppGlobals.getPackageManager(); + mAppOpsManager = (AppOpsManager) mContext.getSystemService(Context.APP_OPS_SERVICE); mMonitor = new MyPackageMonitor(); mMonitor.register(context, null, UserHandle.ALL, true); getWallpaperDir(UserHandle.USER_OWNER).mkdirs(); @@ -613,8 +616,12 @@ public class WallpaperManagerService extends IWallpaperManager.Stub { } } - public void clearWallpaper() { + public void clearWallpaper(String callingPackage) { if (DEBUG) Slog.v(TAG, "clearWallpaper"); + checkPermission(android.Manifest.permission.SET_WALLPAPER); + if (!isWallpaperSupported(callingPackage)) { + return; + } synchronized (mLock) { clearWallpaperLocked(false, UserHandle.getCallingUserId(), null); } @@ -622,6 +629,9 @@ public class WallpaperManagerService extends IWallpaperManager.Stub { void clearWallpaperLocked(boolean defaultFailed, int userId, IRemoteCallback reply) { WallpaperData wallpaper = mWallpaperMap.get(userId); + if (wallpaper == null) { + return; + } File f = new File(getWallpaperDir(userId), WALLPAPER); if (f.exists()) { f.delete(); @@ -668,6 +678,10 @@ public class WallpaperManagerService extends IWallpaperManager.Stub { Binder.restoreCallingIdentity(ident); } for (UserInfo user: users) { + // ignore managed profiles + if (user.isManagedProfile()) { + continue; + } WallpaperData wd = mWallpaperMap.get(user.id); if (wd == null) { // User hasn't started yet, so load her settings to peek at the wallpaper @@ -690,8 +704,12 @@ public class WallpaperManagerService extends IWallpaperManager.Stub { return p; } - public void setDimensionHints(int width, int height) throws RemoteException { + public void setDimensionHints(int width, int height, String callingPackage) + throws RemoteException { checkPermission(android.Manifest.permission.SET_WALLPAPER_HINTS); + if (!isWallpaperSupported(callingPackage)) { + return; + } synchronized (mLock) { int userId = UserHandle.getCallingUserId(); WallpaperData wallpaper = mWallpaperMap.get(userId); @@ -733,19 +751,30 @@ public class WallpaperManagerService extends IWallpaperManager.Stub { public int getWidthHint() throws RemoteException { synchronized (mLock) { WallpaperData wallpaper = mWallpaperMap.get(UserHandle.getCallingUserId()); - return wallpaper.width; + if (wallpaper != null) { + return wallpaper.width; + } else { + return 0; + } } } public int getHeightHint() throws RemoteException { synchronized (mLock) { WallpaperData wallpaper = mWallpaperMap.get(UserHandle.getCallingUserId()); - return wallpaper.height; + if (wallpaper != null) { + return wallpaper.height; + } else { + return 0; + } } } - public void setDisplayPadding(Rect padding) { + public void setDisplayPadding(Rect padding, String callingPackage) { checkPermission(android.Manifest.permission.SET_WALLPAPER_HINTS); + if (!isWallpaperSupported(callingPackage)) { + return; + } synchronized (mLock) { int userId = UserHandle.getCallingUserId(); WallpaperData wallpaper = mWallpaperMap.get(userId); @@ -791,6 +820,9 @@ public class WallpaperManagerService extends IWallpaperManager.Stub { wallpaperUserId = UserHandle.getUserId(callingUid); } WallpaperData wallpaper = mWallpaperMap.get(wallpaperUserId); + if (wallpaper == null) { + return null; + } try { if (outParams != null) { outParams.putInt("width", wallpaper.width); @@ -814,15 +846,18 @@ public class WallpaperManagerService extends IWallpaperManager.Stub { int userId = UserHandle.getCallingUserId(); synchronized (mLock) { WallpaperData wallpaper = mWallpaperMap.get(userId); - if (wallpaper.connection != null) { + if (wallpaper != null && wallpaper.connection != null) { return wallpaper.connection.mInfo; } return null; } } - public ParcelFileDescriptor setWallpaper(String name) { + public ParcelFileDescriptor setWallpaper(String name, String callingPackage) { checkPermission(android.Manifest.permission.SET_WALLPAPER); + if (!isWallpaperSupported(callingPackage)) { + return null; + } synchronized (mLock) { if (DEBUG) Slog.v(TAG, "setWallpaper"); int userId = UserHandle.getCallingUserId(); @@ -868,6 +903,13 @@ public class WallpaperManagerService extends IWallpaperManager.Stub { return null; } + public void setWallpaperComponentChecked(ComponentName name, String callingPackage) { + if (isWallpaperSupported(callingPackage)) { + setWallpaperComponent(name); + } + } + + // ToDo: Remove this version of the function public void setWallpaperComponent(ComponentName name) { checkPermission(android.Manifest.permission.SET_WALLPAPER_COMPONENT); synchronized (mLock) { @@ -1097,6 +1139,15 @@ public class WallpaperManagerService extends IWallpaperManager.Stub { } } + /** + * Certain user types do not support wallpapers (e.g. managed profiles). The check is + * implemented through through the OP_WRITE_WALLPAPER AppOp. + */ + public boolean isWallpaperSupported(String callingPackage) { + return mAppOpsManager.checkOpNoThrow(AppOpsManager.OP_WRITE_WALLPAPER, Binder.getCallingUid(), + callingPackage) == AppOpsManager.MODE_ALLOWED; + } + 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")); @@ -1174,7 +1225,7 @@ public class WallpaperManagerService extends IWallpaperManager.Stub { private void loadSettingsLocked(int userId) { if (DEBUG) Slog.v(TAG, "loadSettingsLocked"); - + JournaledFile journal = makeJournaledFile(userId); FileInputStream stream = null; File file = journal.chooseForRead(); diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java index b90666f..00d7971 100644 --- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java +++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java @@ -180,6 +180,14 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { DEVICE_OWNER_USER_RESTRICTIONS.add(UserManager.DISALLOW_SMS); } + // The following user restrictions cannot be changed by any active admin, including device + // owner and profile owner. + private static final Set<String> IMMUTABLE_USER_RESTRICTIONS; + static { + IMMUTABLE_USER_RESTRICTIONS = new HashSet(); + IMMUTABLE_USER_RESTRICTIONS.add(UserManager.DISALLOW_WALLPAPER); + } + private static final Set<String> SECURE_SETTINGS_WHITELIST; private static final Set<String> SECURE_SETTINGS_DEVICEOWNER_WHITELIST; private static final Set<String> GLOBAL_SETTINGS_WHITELIST; @@ -4953,6 +4961,9 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { && DEVICE_OWNER_USER_RESTRICTIONS.contains(key)) { throw new SecurityException("Profile owners cannot set user restriction " + key); } + if (IMMUTABLE_USER_RESTRICTIONS.contains(key)) { + throw new SecurityException("User restriction " + key + " cannot be changed"); + } boolean alreadyRestricted = mUserManager.hasUserRestriction(key, user); IAudioService iAudioService = null; |