import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
import android.net.Uri;
+import android.os.Build;
import android.os.Bundle;
import android.os.DeadSystemException;
import android.os.Handler;
mCachedWallpaper = null;
mCachedWallpaperUserId = 0;
try {
- mCachedWallpaper = getCurrentWallpaperLocked(userId);
+ mCachedWallpaper = getCurrentWallpaperLocked(context, userId);
mCachedWallpaperUserId = userId;
} catch (OutOfMemoryError e) {
- Log.w(TAG, "No memory load current wallpaper", e);
+ Log.w(TAG, "Out of memory loading the current wallpaper: " + e);
+ } catch (SecurityException e) {
+ if (context.getApplicationInfo().targetSdkVersion <= Build.VERSION_CODES.O) {
+ Log.w(TAG, "No permission to access wallpaper, suppressing"
+ + " exception to avoid crashing legacy app.");
+ } else {
+ // Post-O apps really most sincerely need the permission.
+ throw e;
+ }
}
if (mCachedWallpaper != null) {
return mCachedWallpaper;
}
}
- private Bitmap getCurrentWallpaperLocked(int userId) {
+ private Bitmap getCurrentWallpaperLocked(Context context, int userId) {
if (mService == null) {
Log.w(TAG, "WallpaperService not running");
return null;
try {
Bundle params = new Bundle();
- ParcelFileDescriptor fd = mService.getWallpaper(this, FLAG_SYSTEM,
- params, userId);
+ ParcelFileDescriptor fd = mService.getWallpaper(context.getOpPackageName(),
+ this, FLAG_SYSTEM, params, userId);
if (fd != null) {
try {
BitmapFactory.Options options = new BitmapFactory.Options();
*
* @return Returns a Drawable object that will draw the wallpaper.
*/
+ @RequiresPermission(android.Manifest.permission.READ_EXTERNAL_STORAGE)
public Drawable getFastDrawable() {
Bitmap bm = sGlobals.peekWallpaperBitmap(mContext, true, FLAG_SYSTEM);
if (bm != null) {
* @return Returns an optimized Drawable object that will draw the
* wallpaper or a null pointer if these is none.
*/
+ @RequiresPermission(android.Manifest.permission.READ_EXTERNAL_STORAGE)
public Drawable peekFastDrawable() {
Bitmap bm = sGlobals.peekWallpaperBitmap(mContext, false, FLAG_SYSTEM);
if (bm != null) {
* @param which The wallpaper whose image file is to be retrieved. Must be a single
* defined kind of wallpaper, either {@link #FLAG_SYSTEM} or
* {@link #FLAG_LOCK}.
+ * @return An open, readable file desriptor to the requested wallpaper image file;
+ * or {@code null} if no such wallpaper is configured or if the calling app does
+ * not have permission to read the current wallpaper.
*
* @see #FLAG_LOCK
* @see #FLAG_SYSTEM
*/
+ @RequiresPermission(android.Manifest.permission.READ_EXTERNAL_STORAGE)
public ParcelFileDescriptor getWallpaperFile(@SetWallpaperFlags int which) {
return getWallpaperFile(which, mContext.getUserId());
}
} else {
try {
Bundle outParams = new Bundle();
- return sGlobals.mService.getWallpaper(null, which, outParams, userId);
+ return sGlobals.mService.getWallpaper(mContext.getOpPackageName(), null, which,
+ outParams, userId);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
+ } catch (SecurityException e) {
+ if (mContext.getApplicationInfo().targetSdkVersion <= Build.VERSION_CODES.O) {
+ Log.w(TAG, "No permission to access wallpaper, suppressing"
+ + " exception to avoid crashing legacy app.");
+ return null;
+ } else {
+ throw e;
+ }
}
}
}
* @throws IOException If an error occurs reverting to the built-in
* wallpaper.
*/
+ @RequiresPermission(android.Manifest.permission.SET_WALLPAPER)
public void setResource(@RawRes int resid) throws IOException {
setResource(resid, FLAG_SYSTEM | FLAG_LOCK);
}
*
* @throws IOException
*/
+ @RequiresPermission(android.Manifest.permission.SET_WALLPAPER)
public int setResource(@RawRes int resid, @SetWallpaperFlags int which)
throws IOException {
if (sGlobals.mService == null) {
* @throws IOException If an error occurs when attempting to set the wallpaper
* to the provided image.
*/
+ @RequiresPermission(android.Manifest.permission.SET_WALLPAPER)
public void setBitmap(Bitmap bitmap) throws IOException {
setBitmap(bitmap, null, true);
}
* @throws IllegalArgumentException If the {@code visibleCropHint} rectangle is
* empty or invalid.
*/
+ @RequiresPermission(android.Manifest.permission.SET_WALLPAPER)
public int setBitmap(Bitmap fullImage, Rect visibleCropHint, boolean allowBackup)
throws IOException {
return setBitmap(fullImage, visibleCropHint, allowBackup, FLAG_SYSTEM | FLAG_LOCK);
*
* @throws IOException
*/
+ @RequiresPermission(android.Manifest.permission.SET_WALLPAPER)
public int setBitmap(Bitmap fullImage, Rect visibleCropHint,
boolean allowBackup, @SetWallpaperFlags int which)
throws IOException {
* @throws IOException If an error occurs when attempting to set the wallpaper
* based on the provided image data.
*/
+ @RequiresPermission(android.Manifest.permission.SET_WALLPAPER)
public void setStream(InputStream bitmapData) throws IOException {
setStream(bitmapData, null, true);
}
* @throws IllegalArgumentException If the {@code visibleCropHint} rectangle is
* empty or invalid.
*/
+ @RequiresPermission(android.Manifest.permission.SET_WALLPAPER)
public int setStream(InputStream bitmapData, Rect visibleCropHint, boolean allowBackup)
throws IOException {
return setStream(bitmapData, visibleCropHint, allowBackup, FLAG_SYSTEM | FLAG_LOCK);
*
* @throws IOException
*/
+ @RequiresPermission(android.Manifest.permission.SET_WALLPAPER)
public int setStream(InputStream bitmapData, Rect visibleCropHint,
boolean allowBackup, @SetWallpaperFlags int which)
throws IOException {
*
* @hide
*/
+ @RequiresPermission(android.Manifest.permission.SET_WALLPAPER_COMPONENT)
public boolean setWallpaperComponent(ComponentName name, int userId) {
if (sGlobals.mService == null) {
Log.w(TAG, "WallpaperService not running");
* @throws IOException If an error occurs reverting to the built-in
* wallpaper.
*/
+ @RequiresPermission(android.Manifest.permission.SET_WALLPAPER)
public void clear() throws IOException {
setStream(openDefaultWallpaper(mContext, FLAG_SYSTEM), null, false);
}
* {@link #FLAG_LOCK}
* @throws IOException If an error occurs reverting to the built-in wallpaper.
*/
+ @RequiresPermission(android.Manifest.permission.SET_WALLPAPER)
public void clear(@SetWallpaperFlags int which) throws IOException {
if ((which & FLAG_SYSTEM) != 0) {
clear();
}
}
+ private void enforceCallingOrSelfPermissionAndAppOp(String permission, final String callingPkg,
+ final int callingUid, String message) {
+ mContext.enforceCallingOrSelfPermission(permission, message);
+
+ final String opName = AppOpsManager.permissionToOp(permission);
+ if (opName != null) {
+ final int appOpMode = mAppOpsManager.noteOp(opName, callingUid, callingPkg);
+ if (appOpMode != AppOpsManager.MODE_ALLOWED) {
+ throw new SecurityException(
+ message + ": " + callingPkg + " is not allowed to " + permission);
+ }
+ }
+ }
+
@Override
- public ParcelFileDescriptor getWallpaper(IWallpaperManagerCallback cb, final int which,
- Bundle outParams, int wallpaperUserId) {
+ public ParcelFileDescriptor getWallpaper(String callingPkg, IWallpaperManagerCallback cb,
+ final int which, Bundle outParams, int wallpaperUserId) {
+ enforceCallingOrSelfPermissionAndAppOp(android.Manifest.permission.READ_EXTERNAL_STORAGE,
+ callingPkg, Binder.getCallingUid(), "read wallpaper");
+
wallpaperUserId = ActivityManager.handleIncomingUser(Binder.getCallingPid(),
Binder.getCallingUid(), wallpaperUserId, false, true, "getWallpaper", null);