Add crop hint and backup-eligible info to wallpaper API
The OS will not distinguish between the physical underlying wallpaper
image and the target displayable subrect of that image. This will enable
more pleasing conveyance of backed-up wallpaper imagery between dissimilar
devices. The allow-backup hint is a way for wallpaper sources to ensure
that the OS doesn't back up imagery that should not be propagated across
devices.
(NB: the backing implementation isn't in place yet; this is just to
permit forward-looking work on client apps in the interim.)
Bug 25454501
Bug 25453848
Change-Id: Id014d552ae509f659992d57b915ef95c5d4b8d1a
diff --git a/api/current.txt b/api/current.txt
index d03cf15..39a3b1e 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -5658,8 +5658,10 @@
method public android.graphics.drawable.Drawable peekFastDrawable();
method public void sendWallpaperCommand(android.os.IBinder, java.lang.String, int, int, int, android.os.Bundle);
method public void setBitmap(android.graphics.Bitmap) throws java.io.IOException;
+ method public void setBitmap(android.graphics.Bitmap, android.graphics.Rect, boolean) throws java.io.IOException;
method public void setResource(int) throws java.io.IOException;
method public void setStream(java.io.InputStream) throws java.io.IOException;
+ method public void setStream(java.io.InputStream, android.graphics.Rect, boolean) throws java.io.IOException;
method public void setWallpaperOffsetSteps(float, float);
method public void setWallpaperOffsets(android.os.IBinder, float, float);
method public void suggestDesiredDimensions(int, int);
diff --git a/api/system-current.txt b/api/system-current.txt
index 780a6774..9240d4f 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -5779,10 +5779,12 @@
method public android.graphics.drawable.Drawable peekFastDrawable();
method public void sendWallpaperCommand(android.os.IBinder, java.lang.String, int, int, int, android.os.Bundle);
method public void setBitmap(android.graphics.Bitmap) throws java.io.IOException;
+ method public void setBitmap(android.graphics.Bitmap, android.graphics.Rect, boolean) throws java.io.IOException;
method public void setDisplayOffset(android.os.IBinder, int, int);
method public void setDisplayPadding(android.graphics.Rect);
method public void setResource(int) throws java.io.IOException;
method public void setStream(java.io.InputStream) throws java.io.IOException;
+ method public void setStream(java.io.InputStream, android.graphics.Rect, boolean) throws java.io.IOException;
method public boolean setWallpaperComponent(android.content.ComponentName);
method public void setWallpaperOffsetSteps(float, float);
method public void setWallpaperOffsets(android.os.IBinder, float, float);
diff --git a/api/test-current.txt b/api/test-current.txt
index 00abd31..e8d8748 100644
--- a/api/test-current.txt
+++ b/api/test-current.txt
@@ -5658,8 +5658,10 @@
method public android.graphics.drawable.Drawable peekFastDrawable();
method public void sendWallpaperCommand(android.os.IBinder, java.lang.String, int, int, int, android.os.Bundle);
method public void setBitmap(android.graphics.Bitmap) throws java.io.IOException;
+ method public void setBitmap(android.graphics.Bitmap, android.graphics.Rect, boolean) throws java.io.IOException;
method public void setResource(int) throws java.io.IOException;
method public void setStream(java.io.InputStream) throws java.io.IOException;
+ method public void setStream(java.io.InputStream, android.graphics.Rect, boolean) throws java.io.IOException;
method public void setWallpaperOffsetSteps(float, float);
method public void setWallpaperOffsets(android.os.IBinder, float, float);
method public void suggestDesiredDimensions(int, int);
diff --git a/core/java/android/app/WallpaperManager.java b/core/java/android/app/WallpaperManager.java
index 22e79b6..5b5bba4 100644
--- a/core/java/android/app/WallpaperManager.java
+++ b/core/java/android/app/WallpaperManager.java
@@ -52,6 +52,8 @@
import android.util.Log;
import android.view.WindowManagerGlobal;
+import libcore.io.IoUtils;
+
import java.io.BufferedInputStream;
import java.io.File;
import java.io.FileInputStream;
@@ -309,11 +311,7 @@
} catch (OutOfMemoryError e) {
Log.w(TAG, "Can't decode file", e);
} finally {
- try {
- fd.close();
- } catch (IOException e) {
- // Ignore
- }
+ IoUtils.closeQuietly(fd);
}
}
} catch (RemoteException e) {
@@ -321,7 +319,7 @@
}
return null;
}
-
+
private Bitmap getDefaultWallpaperLocked(Context context) {
InputStream is = openDefaultWallpaper(context);
if (is != null) {
@@ -331,11 +329,7 @@
} catch (OutOfMemoryError e) {
Log.w(TAG, "Can't decode stream", e);
} finally {
- try {
- is.close();
- } catch (IOException e) {
- // Ignore
- }
+ IoUtils.closeQuietly(is);
}
}
return null;
@@ -738,30 +732,65 @@
fos = new ParcelFileDescriptor.AutoCloseOutputStream(fd);
setWallpaper(resources.openRawResource(resid), fos);
} finally {
- if (fos != null) {
- fos.close();
- }
+ IoUtils.closeQuietly(fos);
}
}
} catch (RemoteException e) {
// Ignore
}
}
-
+
/**
* Change the current system wallpaper to a bitmap. The given bitmap is
* converted to a PNG and stored as the wallpaper. On success, the intent
* {@link Intent#ACTION_WALLPAPER_CHANGED} is broadcast.
*
+ * <p>This method is equivalent to calling
+ * {@link #setBitmap(Bitmap, Rect, boolean)} and passing {@code null} for the
+ * {@code visibleCrop} rectangle and {@code true} for the {@code allowBackup}
+ * parameter.
+ *
* <p>This method requires the caller to hold the permission
* {@link android.Manifest.permission#SET_WALLPAPER}.
*
* @param bitmap The bitmap to save.
*
- * @throws IOException If an error occurs reverting to the built-in
- * wallpaper.
+ * @throws IOException If an error occurs when attempting to set the wallpaper
+ * to the provided image.
*/
public void setBitmap(Bitmap bitmap) throws IOException {
+ setBitmap(bitmap, null, true);
+ }
+
+ /**
+ * Change the current system wallpaper to a bitmap, specifying a hint about
+ * which subrectangle of the full image is to be visible. The OS will then
+ * try to best present the given portion of the full image as the static system
+ * wallpaper image. On success, the intent
+ * {@link Intent#ACTION_WALLPAPER_CHANGED} is broadcast.
+ *
+ * <p>Passing {@code null} as the {@code visibleHint} parameter is equivalent to
+ * passing (0, 0, {@code fullImage.getWidth()}, {@code fullImage.getHeight()}).
+ *
+ * <p>This method requires the caller to hold the permission
+ * {@link android.Manifest.permission#SET_WALLPAPER}.
+ *
+ * @param fullImage A bitmap that will supply the wallpaper imagery.
+ * @param visibleCropHint The rectangular subregion of {@code fullImage} that should be
+ * displayed as wallpaper. Passing {@code null} for this parameter means that
+ * the full image should be displayed if possible given the image's and device's
+ * aspect ratios, etc.
+ * @param allowBackup {@code true} if the OS is permitted to back up this wallpaper
+ * image for restore to a future device; {@code false} otherwise.
+ *
+ * @throws IOException If an error occurs when attempting to set the wallpaper
+ * to the provided image.
+ * @throws IllegalArgumentException If the {@code visibleCropHint} rectangle is
+ * empty or invalid.
+ */
+ public void setBitmap(Bitmap fullImage, Rect visibleCropHint, boolean allowBackup)
+ throws IOException {
+ validateRect(visibleCropHint);
if (sGlobals.mService == null) {
Log.w(TAG, "WallpaperService not running");
return;
@@ -775,17 +804,21 @@
FileOutputStream fos = null;
try {
fos = new ParcelFileDescriptor.AutoCloseOutputStream(fd);
- bitmap.compress(Bitmap.CompressFormat.PNG, 90, fos);
+ fullImage.compress(Bitmap.CompressFormat.PNG, 90, fos);
} finally {
- if (fos != null) {
- fos.close();
- }
+ IoUtils.closeQuietly(fos);
}
} catch (RemoteException e) {
// Ignore
}
}
+ private final void validateRect(Rect rect) {
+ if (rect != null && rect.isEmpty()) {
+ throw new IllegalArgumentException("visibleCrop rectangle must be valid and non-empty");
+ }
+ }
+
/**
* Change the current system wallpaper to a specific byte stream. The
* give InputStream is copied into persistent storage and will now be
@@ -793,15 +826,60 @@
* image. On success, the intent {@link Intent#ACTION_WALLPAPER_CHANGED}
* is broadcast.
*
+ * <p>This method is equivalent to calling
+ * {@link #setStream(InputStream, Rect, boolean)} and passing {@code null} for the
+ * {@code visibleCrop} rectangle and {@code true} for the {@code allowBackup}
+ * parameter.
+ *
* <p>This method requires the caller to hold the permission
* {@link android.Manifest.permission#SET_WALLPAPER}.
*
- * @param data A stream containing the raw data to install as a wallpaper.
+ * @param bitmapData A stream containing the raw data to install as a wallpaper.
*
- * @throws IOException If an error occurs reverting to the built-in
- * wallpaper.
+ * @throws IOException If an error occurs when attempting to set the wallpaper
+ * based on the provided image data.
*/
- public void setStream(InputStream data) throws IOException {
+ public void setStream(InputStream bitmapData) throws IOException {
+ setStream(bitmapData, null, true);
+ }
+
+ private void setWallpaper(InputStream data, FileOutputStream fos)
+ throws IOException {
+ byte[] buffer = new byte[32768];
+ int amt;
+ while ((amt=data.read(buffer)) > 0) {
+ fos.write(buffer, 0, amt);
+ }
+ }
+
+ /**
+ * Change the current system wallpaper to a specific byte stream, specifying a
+ * hint about which subrectangle of the full image is to be visible. The OS will
+ * then try to best present the given portion of the full image as the static system
+ * wallpaper image. The data from the given InputStream is copied into persistent
+ * storage and will then be used as the system wallpaper. Currently the data must
+ * be either a JPEG or PNG image. On success, the intent
+ * {@link Intent#ACTION_WALLPAPER_CHANGED} is broadcast.
+ *
+ * <p>This method requires the caller to hold the permission
+ * {@link android.Manifest.permission#SET_WALLPAPER}.
+ *
+ * @param bitmapData A stream containing the raw data to install as a wallpaper.
+ * @param visibleCropHint The rectangular subregion of the streamed image that should be
+ * displayed as wallpaper. Passing {@code null} for this parameter means that
+ * the full image should be displayed if possible given the image's and device's
+ * aspect ratios, etc.
+ * @param allowBackup {@code true} if the OS is permitted to back up this wallpaper
+ * image for restore to a future device; {@code false} otherwise.
+ *
+ * @throws IOException If an error occurs when attempting to set the wallpaper
+ * based on the provided image data.
+ * @throws IllegalArgumentException If the {@code visibleCropHint} rectangle is
+ * empty or invalid.
+ */
+ public void setStream(InputStream bitmapData, Rect visibleCropHint, boolean allowBackup)
+ throws IOException {
+ validateRect(visibleCropHint);
if (sGlobals.mService == null) {
Log.w(TAG, "WallpaperService not running");
return;
@@ -815,26 +893,15 @@
FileOutputStream fos = null;
try {
fos = new ParcelFileDescriptor.AutoCloseOutputStream(fd);
- setWallpaper(data, fos);
+ setWallpaper(bitmapData, fos);
} finally {
- if (fos != null) {
- fos.close();
- }
+ IoUtils.closeQuietly(fos);
}
} catch (RemoteException e) {
// Ignore
}
}
- private void setWallpaper(InputStream data, FileOutputStream fos)
- throws IOException {
- byte[] buffer = new byte[32768];
- int amt;
- while ((amt=data.read(buffer)) > 0) {
- fos.write(buffer, 0, amt);
- }
- }
-
/**
* Return whether any users are currently set to use the wallpaper
* with the given resource ID. That is, their wallpaper has been
@@ -915,8 +982,8 @@
* the size of their workspace.
*
* <p>Note developers, who don't seem to be reading this. This is
- * for <em>home screens</em> to tell what size wallpaper they would like.
- * Nobody else should be calling this! Certainly not other non-home-screen
+ * for <em>home apps</em> to tell what size wallpaper they would like.
+ * Nobody else should be calling this! Certainly not other non-home
* apps that change the wallpaper. Those apps are supposed to
* <b>retrieve</b> the suggested size so they can construct a wallpaper
* that matches it.
@@ -1053,11 +1120,11 @@
}
/**
- * Set the position of the current wallpaper within any larger space, when
+ * Set the display position of the current wallpaper within any larger space, when
* that wallpaper is visible behind the given window. The X and Y offsets
* 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 screen.
+ * 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()