Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit d9915e4a authored by Aurélien Pomini's avatar Aurélien Pomini
Browse files

New methods setBitmap, setStream, getBitmapCrop, getWallpaperColors

See go/wallpaper-multi-crop

Flag: ACONFIG com.android.window.flags.multi_crop DEVELOPMENT
Bug: 270726737
Test: atest WallpaperManagerTest
Test: atest WallpaperControllerTests
Test: atest WallpaperBackupAgentTest
Test: quite a lot of manual testing

Change-Id: Ic0bb0bd450c02aad01ea59fbfdaab415fb9838f9
parent ae30e283
Loading
Loading
Loading
Loading
+37 −11
Original line number Original line Diff line number Diff line
@@ -16,6 +16,7 @@


package android.app;
package android.app;


import android.graphics.Point;
import android.graphics.Rect;
import android.graphics.Rect;
import android.graphics.RectF;
import android.graphics.RectF;
import android.os.Bundle;
import android.os.Bundle;
@@ -26,6 +27,8 @@ import android.app.WallpaperInfo;
import android.content.ComponentName;
import android.content.ComponentName;
import android.app.WallpaperColors;
import android.app.WallpaperColors;


import java.util.List;

/** @hide */
/** @hide */
interface IWallpaperManager {
interface IWallpaperManager {


@@ -39,15 +42,21 @@ interface IWallpaperManager {
     *   FLAG_SET_SYSTEM
     *   FLAG_SET_SYSTEM
     *   FLAG_SET_LOCK
     *   FLAG_SET_LOCK
     *
     *
     * A 'null' cropHint rectangle is explicitly permitted as a sentinel for "whatever
     * 'screenOrientations' and 'crops' define how the wallpaper will be positioned for
     * the source image's bounding rect is."
     * different screen orientations. If some screen orientations are missing, crops for these
     * orientations will be added by the system.
     *
     * If 'screenOrientations' is null, 'crops' can be null or a singleton list. The system will
     * fit the provided crop (or the whole image, if 'crops' is 'null') for the current device
     * orientation, and add crops for the missing orientations.
     *
     *
     * The completion callback's "onWallpaperChanged()" method is invoked when the
     * The completion callback's "onWallpaperChanged()" method is invoked when the
     * new wallpaper content is ready to display.
     * new wallpaper content is ready to display.
     */
     */
    @JavaPassthrough(annotation="@android.annotation.RequiresPermission(android.Manifest.permission.SET_WALLPAPER)")
    ParcelFileDescriptor setWallpaper(String name, in String callingPackage,
    ParcelFileDescriptor setWallpaper(String name, in String callingPackage,
            in Rect cropHint, boolean allowBackup, out Bundle extras, int which,
            in int[] screenOrientations, in List<Rect> crops, boolean allowBackup,
            IWallpaperManagerCallback completion, int userId);
            out Bundle extras, int which, IWallpaperManagerCallback completion, int userId);


    /**
    /**
     * Set the live wallpaper.
     * Set the live wallpaper.
@@ -77,6 +86,30 @@ interface IWallpaperManager {
            IWallpaperManagerCallback cb, int which, out Bundle outParams, int userId,
            IWallpaperManagerCallback cb, int which, out Bundle outParams, int userId,
            boolean getCropped);
            boolean getCropped);


    /**
     * For a given user and a list of display sizes, get a list of Rect representing the
     * area of the current wallpaper that is displayed for each display size.
     */
    @JavaPassthrough(annotation="@android.annotation.RequiresPermission(android.Manifest.permission.READ_WALLPAPER_INTERNAL)")
    @SuppressWarnings(value={"untyped-collection"})
    List getBitmapCrops(in List<Point> displaySizes, int which, boolean originalBitmap, int userId);

    /**
     * Return how a bitmap of a given size would be cropped for a given list of display sizes when
     * set with the given suggested crops.
     * @hide
     */
    @SuppressWarnings(value={"untyped-collection"})
    List getFutureBitmapCrops(in Point bitmapSize, in List<Point> displaySizes,
            in int[] screenOrientations, in List<Rect> crops);

    /**
     * Return how a bitmap of a given size would be cropped when set with the given suggested crops.
     * @hide
     */
    @SuppressWarnings(value={"untyped-collection"})
    Rect getBitmapCrop(in Point bitmapSize, in int[] screenOrientations, in List<Rect> crops);

    /**
    /**
     * Retrieve the given user's current wallpaper ID of the given kind.
     * Retrieve the given user's current wallpaper ID of the given kind.
     */
     */
@@ -245,11 +278,4 @@ interface IWallpaperManager {
     * @hide
     * @hide
     */
     */
    boolean isStaticWallpaper(int which);
    boolean isStaticWallpaper(int which);

    /**
     * Temporary method for project b/270726737.
     * Return true if the wallpaper supports different crops for different display dimensions.
     * @hide
     */
     boolean isMultiCropEnabled();
}
}
+319 −14
Original line number Original line Diff line number Diff line
@@ -18,11 +18,14 @@ package android.app;


import static android.Manifest.permission.MANAGE_EXTERNAL_STORAGE;
import static android.Manifest.permission.MANAGE_EXTERNAL_STORAGE;
import static android.Manifest.permission.READ_WALLPAPER_INTERNAL;
import static android.Manifest.permission.READ_WALLPAPER_INTERNAL;
import static android.Manifest.permission.SET_WALLPAPER_DIM_AMOUNT;
import static android.content.pm.PackageManager.PERMISSION_GRANTED;
import static android.content.pm.PackageManager.PERMISSION_GRANTED;
import static android.os.ParcelFileDescriptor.MODE_READ_ONLY;
import static android.os.ParcelFileDescriptor.MODE_READ_ONLY;


import static com.android.window.flags.Flags.FLAG_MULTI_CROP;
import static com.android.window.flags.Flags.multiCrop;
import static com.android.window.flags.Flags.multiCrop;


import android.annotation.FlaggedApi;
import android.annotation.FloatRange;
import android.annotation.FloatRange;
import android.annotation.IntDef;
import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.NonNull;
@@ -58,6 +61,7 @@ import android.graphics.ImageDecoder;
import android.graphics.Matrix;
import android.graphics.Matrix;
import android.graphics.Paint;
import android.graphics.Paint;
import android.graphics.PixelFormat;
import android.graphics.PixelFormat;
import android.graphics.Point;
import android.graphics.PorterDuff;
import android.graphics.PorterDuff;
import android.graphics.PorterDuffXfermode;
import android.graphics.PorterDuffXfermode;
import android.graphics.Rect;
import android.graphics.Rect;
@@ -84,6 +88,7 @@ import android.util.ArraySet;
import android.util.Log;
import android.util.Log;
import android.util.MathUtils;
import android.util.MathUtils;
import android.util.Pair;
import android.util.Pair;
import android.util.SparseArray;
import android.view.Display;
import android.view.Display;
import android.view.WindowManagerGlobal;
import android.view.WindowManagerGlobal;


@@ -104,6 +109,7 @@ import java.util.ArrayList;
import java.util.Arrays;
import java.util.Arrays;
import java.util.HashSet;
import java.util.HashSet;
import java.util.List;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.Set;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeUnit;
@@ -289,6 +295,79 @@ public class WallpaperManager {
    public static final String EXTRA_FROM_FOREGROUND_APP =
    public static final String EXTRA_FROM_FOREGROUND_APP =
            "android.service.wallpaper.extra.FROM_FOREGROUND_APP";
            "android.service.wallpaper.extra.FROM_FOREGROUND_APP";


    /**
     * The different screen orientations. {@link #getOrientation} provides their exact definition.
     * This is only used internally by the framework and the WallpaperBackupAgent.
     * @hide
     */
    @IntDef(value = {
            ORIENTATION_UNKNOWN,
            PORTRAIT,
            LANDSCAPE,
            SQUARE_PORTRAIT,
            SQUARE_LANDSCAPE,
    })
    @Retention(RetentionPolicy.SOURCE)
    public @interface ScreenOrientation {}

    /**
     * @hide
     */
    public static final int ORIENTATION_UNKNOWN = -1;

    /**
     * Portrait orientation of most screens
     * @hide
     */
    public static final int PORTRAIT = 0;

    /**
     * Landscape orientation of most screens
     * @hide
     */
    public static final int LANDSCAPE = 1;

    /**
     * Portrait orientation with similar width and height (e.g. the inner screen of a foldable)
     * @hide
     */
    public static final int SQUARE_PORTRAIT = 2;

    /**
     * Landscape orientation with similar width and height (e.g. the inner screen of a foldable)
     * @hide
     */
    public static final int SQUARE_LANDSCAPE = 3;

    /**
     * Converts a (width, height) screen size to a {@link ScreenOrientation}.
     * @param screenSize the dimensions of a screen
     * @return the corresponding {@link ScreenOrientation}.
     * @hide
     */
    public static @ScreenOrientation int getOrientation(Point screenSize) {
        float ratio = ((float) screenSize.x) / screenSize.y;
        // ratios between 3/4 and 4/3 are considered square
        return ratio >= 4 / 3f ? LANDSCAPE
                : ratio > 1f ? SQUARE_LANDSCAPE
                : ratio > 3 / 4f ? SQUARE_PORTRAIT
                : PORTRAIT;
    }

    /**
     * Get the 90° rotation of a given orientation
     * @hide
     */
    public static @ScreenOrientation int getRotatedOrientation(@ScreenOrientation int orientation) {
        switch (orientation) {
            case PORTRAIT: return LANDSCAPE;
            case LANDSCAPE: return PORTRAIT;
            case SQUARE_PORTRAIT: return SQUARE_LANDSCAPE;
            case SQUARE_LANDSCAPE: return SQUARE_PORTRAIT;
            default: return ORIENTATION_UNKNOWN;
        }
    }

    // flags for which kind of wallpaper to act on
    // flags for which kind of wallpaper to act on


    /** @hide */
    /** @hide */
@@ -867,15 +946,8 @@ public class WallpaperManager {
     * @hide
     * @hide
     */
     */
    public static boolean isMultiCropEnabled() {
    public static boolean isMultiCropEnabled() {
        if (sGlobals == null) {
            sIsMultiCropEnabled = multiCrop();
        }
        if (sIsMultiCropEnabled == null) {
        if (sIsMultiCropEnabled == null) {
            try {
            sIsMultiCropEnabled = multiCrop();
                sIsMultiCropEnabled = sGlobals.mService.isMultiCropEnabled();
            } catch (RemoteException e) {
                e.rethrowFromSystemServer();
            }
        }
        }
        return sIsMultiCropEnabled;
        return sIsMultiCropEnabled;
    }
    }
@@ -1501,6 +1573,99 @@ public class WallpaperManager {
                mContext.getUserId());
                mContext.getUserId());
    }
    }


    /**
     * For the current user, given a list of display sizes, return a list of rectangles representing
     * the area of the current wallpaper that would be shown for each of these sizes.
     *
     * @param displaySizes the display sizes.
     * @param which wallpaper type. Must be either {@link #FLAG_SYSTEM} or {@link #FLAG_LOCK}.
     * @param originalBitmap If true, return areas relative to the original bitmap.
     *                   If false, return areas relative to the cropped bitmap.
     * @return A List of Rect where the Rect is within the cropped/original bitmap, and corresponds
     *          to what is displayed. The Rect may have a larger width/height ratio than the screen
     *          due to parallax. Return {@code null} if the wallpaper is not an ImageWallpaper.
     *          Also return {@code null} when called with which={@link #FLAG_LOCK} if there is a
     *          shared home + lock wallpaper.
     * @hide
     */
    @FlaggedApi(FLAG_MULTI_CROP)
    @RequiresPermission(READ_WALLPAPER_INTERNAL)
    @Nullable
    public List<Rect> getBitmapCrops(@NonNull List<Point> displaySizes,
            @SetWallpaperFlags int which, boolean originalBitmap) {
        checkExactlyOneWallpaperFlagSet(which);
        try {
            return sGlobals.mService.getBitmapCrops(displaySizes, which, originalBitmap,
                    mContext.getUserId());
        } catch (RemoteException e) {
            throw e.rethrowFromSystemServer();
        }
    }

    /**
     * For preview purposes.
     * Return how a bitmap of a given size would be cropped for a given list of display sizes, if
     * it was set as wallpaper via {@link #setBitmapWithCrops(Bitmap, Map, boolean, int)} or
     * {@link #setStreamWithCrops(InputStream, Map, boolean, int)}.
     *
     * @return A List of Rect where the Rect is within the bitmap, and corresponds to what is
     *          displayed for each display size. The Rect may have a larger width/height ratio than
     *          the display due to parallax.
     * @hide
     */
    @FlaggedApi(FLAG_MULTI_CROP)
    @Nullable
    public List<Rect> getBitmapCrops(@NonNull Point bitmapSize, @NonNull List<Point> displaySizes,
            @Nullable Map<Point, Rect> cropHints) {
        try {
            if (cropHints == null) cropHints = Map.of();
            Set<Map.Entry<Point, Rect>> entries = cropHints.entrySet();
            int[] screenOrientations = entries.stream().mapToInt(entry ->
                    getOrientation(entry.getKey())).toArray();
            List<Rect> crops = entries.stream().map(Map.Entry::getValue).toList();
            return sGlobals.mService.getFutureBitmapCrops(bitmapSize, displaySizes,
                    screenOrientations, crops);
        } catch (RemoteException e) {
            throw e.rethrowFromSystemServer();
        }
    }

    /**
     * For preview purposes.
     * Compute the wallpaper colors of the given bitmap, if it was set as wallpaper via
     * {@link #setBitmapWithCrops(Bitmap, Map, boolean, int)} or
     * {@link #setStreamWithCrops(InputStream, Map, boolean, int)}.
     *  Return {@code null} if an error occurred and the colors could not be computed.
     *
     * @hide
     */
    @FlaggedApi(FLAG_MULTI_CROP)
    @RequiresPermission(SET_WALLPAPER_DIM_AMOUNT)
    @Nullable
    public WallpaperColors getWallpaperColors(@NonNull Bitmap bitmap,
            @Nullable Map<Point, Rect> cropHints) {
        if (sGlobals.mService == null) {
            Log.w(TAG, "WallpaperService not running");
            throw new RuntimeException(new DeadSystemException());
        }
        try {
            if (cropHints == null) cropHints = Map.of();
            Set<Map.Entry<Point, Rect>> entries = cropHints.entrySet();
            int[] screenOrientations = entries.stream().mapToInt(entry ->
                    getOrientation(entry.getKey())).toArray();
            List<Rect> crops = entries.stream().map(Map.Entry::getValue).toList();
            Point bitmapSize = new Point(bitmap.getWidth(), bitmap.getHeight());
            Rect crop = sGlobals.mService.getBitmapCrop(bitmapSize, screenOrientations, crops);
            float dimAmount = getWallpaperDimAmount();
            Bitmap croppedBitmap = Bitmap.createBitmap(
                    bitmap, crop.left, crop.top, crop.width(), crop.height());
            WallpaperColors result = WallpaperColors.fromBitmap(croppedBitmap, dimAmount);
            return result;
        } catch (RemoteException e) {
            throw e.rethrowFromSystemServer();
        }
    }

    /**
    /**
     * <strong> Important note: </strong>
     * <strong> Important note: </strong>
     * <ul>
     * <ul>
@@ -1971,7 +2136,7 @@ public class WallpaperManager {
            /* Set the wallpaper to the default values */
            /* Set the wallpaper to the default values */
            ParcelFileDescriptor fd = sGlobals.mService.setWallpaper(
            ParcelFileDescriptor fd = sGlobals.mService.setWallpaper(
                    "res:" + resources.getResourceName(resid),
                    "res:" + resources.getResourceName(resid),
                    mContext.getOpPackageName(), null, false, result, which, completion,
                    mContext.getOpPackageName(), null, null, false, result, which, completion,
                    mContext.getUserId());
                    mContext.getUserId());
            if (fd != null) {
            if (fd != null) {
                FileOutputStream fos = null;
                FileOutputStream fos = null;
@@ -2089,6 +2254,11 @@ public class WallpaperManager {
    public int setBitmap(Bitmap fullImage, Rect visibleCropHint,
    public int setBitmap(Bitmap fullImage, Rect visibleCropHint,
            boolean allowBackup, @SetWallpaperFlags int which, int userId)
            boolean allowBackup, @SetWallpaperFlags int which, int userId)
            throws IOException {
            throws IOException {
        if (multiCrop()) {
            SparseArray<Rect> cropMap = new SparseArray<>();
            if (visibleCropHint != null) cropMap.put(ORIENTATION_UNKNOWN, visibleCropHint);
            return setBitmapWithCrops(fullImage, cropMap, allowBackup, which, userId);
        }
        validateRect(visibleCropHint);
        validateRect(visibleCropHint);
        if (sGlobals.mService == null) {
        if (sGlobals.mService == null) {
            Log.w(TAG, "WallpaperService not running");
            Log.w(TAG, "WallpaperService not running");
@@ -2096,9 +2266,69 @@ public class WallpaperManager {
        }
        }
        final Bundle result = new Bundle();
        final Bundle result = new Bundle();
        final WallpaperSetCompletion completion = new WallpaperSetCompletion();
        final WallpaperSetCompletion completion = new WallpaperSetCompletion();
        final List<Rect> crops = visibleCropHint == null ? null : List.of(visibleCropHint);
        try {
            ParcelFileDescriptor fd = sGlobals.mService.setWallpaper(null,
                    mContext.getOpPackageName(), null, crops, allowBackup, result, which,
                    completion, userId);
            if (fd != null) {
                FileOutputStream fos = null;
                try {
                    fos = new ParcelFileDescriptor.AutoCloseOutputStream(fd);
                    fullImage.compress(Bitmap.CompressFormat.PNG, 90, fos);
                    fos.close();
                    completion.waitForCompletion();
                } finally {
                    IoUtils.closeQuietly(fos);
                }
            }
        } catch (RemoteException e) {
            throw e.rethrowFromSystemServer();
        }
        return result.getInt(EXTRA_NEW_WALLPAPER_ID, 0);
    }

    /**
     * Version of setBitmap that defines how the wallpaper will be positioned for different
     * display sizes.
     * Requires permission {@link android.Manifest.permission#SET_WALLPAPER}.
     * @param cropHints map from screen dimensions to a sub-region of the image to display for those
     *                  dimensions. The {@code Rect} sub-region may have a larger width/height ratio
     *                  than the screen dimensions to apply a horizontal parallax effect. If the
     *                  map is empty or some entries are missing, the system will apply a default
     *                  strategy to position the wallpaper for any unspecified screen dimensions.
     * @hide
     */
    @FlaggedApi(FLAG_MULTI_CROP)
    @RequiresPermission(android.Manifest.permission.SET_WALLPAPER)
    public int setBitmapWithCrops(@Nullable Bitmap fullImage, @NonNull Map<Point, Rect> cropHints,
            boolean allowBackup, @SetWallpaperFlags int which) throws IOException {
        SparseArray<Rect> crops = new SparseArray<>();
        cropHints.forEach((k, v) -> crops.put(getOrientation(k), v));
        return setBitmapWithCrops(fullImage, crops, allowBackup, which, mContext.getUserId());
    }

    @RequiresPermission(android.Manifest.permission.SET_WALLPAPER)
    private int setBitmapWithCrops(@Nullable Bitmap fullImage, @NonNull SparseArray<Rect> cropHints,
            boolean allowBackup, @SetWallpaperFlags int which, int userId) throws IOException {
        if (sGlobals.mService == null) {
            Log.w(TAG, "WallpaperService not running");
            throw new RuntimeException(new DeadSystemException());
        }
        int size = cropHints.size();
        int[] screenOrientations = new int[size];
        List<Rect> crops = new ArrayList<>(size);
        for (int i = 0; i < size; i++) {
            screenOrientations[i] = cropHints.keyAt(i);
            Rect cropHint = cropHints.valueAt(i);
            validateRect(cropHint);
            crops.add(cropHint);
        }
        final Bundle result = new Bundle();
        final WallpaperSetCompletion completion = new WallpaperSetCompletion();
        try {
        try {
            ParcelFileDescriptor fd = sGlobals.mService.setWallpaper(null,
            ParcelFileDescriptor fd = sGlobals.mService.setWallpaper(null,
                    mContext.getOpPackageName(), visibleCropHint, allowBackup,
                    mContext.getOpPackageName(), screenOrientations, crops, allowBackup,
                    result, which, completion, userId);
                    result, which, completion, userId);
            if (fd != null) {
            if (fd != null) {
                FileOutputStream fos = null;
                FileOutputStream fos = null;
@@ -2214,6 +2444,11 @@ public class WallpaperManager {
    public int setStream(InputStream bitmapData, Rect visibleCropHint,
    public int setStream(InputStream bitmapData, Rect visibleCropHint,
            boolean allowBackup, @SetWallpaperFlags int which)
            boolean allowBackup, @SetWallpaperFlags int which)
                    throws IOException {
                    throws IOException {
        if (multiCrop()) {
            SparseArray<Rect> cropMap = new SparseArray<>();
            if (visibleCropHint != null) cropMap.put(ORIENTATION_UNKNOWN, visibleCropHint);
            return setStreamWithCrops(bitmapData, cropMap, allowBackup, which);
        }
        validateRect(visibleCropHint);
        validateRect(visibleCropHint);
        if (sGlobals.mService == null) {
        if (sGlobals.mService == null) {
            Log.w(TAG, "WallpaperService not running");
            Log.w(TAG, "WallpaperService not running");
@@ -2221,10 +2456,11 @@ public class WallpaperManager {
        }
        }
        final Bundle result = new Bundle();
        final Bundle result = new Bundle();
        final WallpaperSetCompletion completion = new WallpaperSetCompletion();
        final WallpaperSetCompletion completion = new WallpaperSetCompletion();
        final List<Rect> crops = visibleCropHint == null ? null : List.of(visibleCropHint);
        try {
        try {
            ParcelFileDescriptor fd = sGlobals.mService.setWallpaper(null,
            ParcelFileDescriptor fd = sGlobals.mService.setWallpaper(null,
                    mContext.getOpPackageName(), visibleCropHint, allowBackup,
                    mContext.getOpPackageName(), null, crops, allowBackup, result, which,
                    result, which, completion, mContext.getUserId());
                    completion, mContext.getUserId());
            if (fd != null) {
            if (fd != null) {
                FileOutputStream fos = null;
                FileOutputStream fos = null;
                try {
                try {
@@ -2243,6 +2479,75 @@ public class WallpaperManager {
        return result.getInt(EXTRA_NEW_WALLPAPER_ID, 0);
        return result.getInt(EXTRA_NEW_WALLPAPER_ID, 0);
    }
    }


    /**
     * Version of setStream that defines how the wallpaper will be positioned for different
     * display sizes.
     * Requires permission {@link android.Manifest.permission#SET_WALLPAPER}.
     * @param cropHints map from screen dimensions to a sub-region of the image to display for those
     *                  dimensions. The {@code Rect} sub-region may have a larger width/height ratio
     *                  than the screen dimensions to apply a horizontal parallax effect. If the
     *                  map is empty or some entries are missing, the system will apply a default
     *                  strategy to position the wallpaper for any unspecified screen dimensions.
     * @hide
     */
    @FlaggedApi(FLAG_MULTI_CROP)
    @RequiresPermission(android.Manifest.permission.SET_WALLPAPER)
    public int setStreamWithCrops(InputStream bitmapData, @NonNull Map<Point, Rect> cropHints,
            boolean allowBackup, @SetWallpaperFlags int which) throws IOException {
        SparseArray<Rect> crops = new SparseArray<>();
        cropHints.forEach((k, v) -> crops.put(getOrientation(k), v));
        return setStreamWithCrops(bitmapData, crops, allowBackup, which);
    }

    /**
     * Similar to {@link #setStreamWithCrops(InputStream, Map, boolean, int)}, but using
     * {@link ScreenOrientation} as keys of the cropHints map. Used for backup & restore, since
     * WallpaperBackupAgent stores orientations rather than the exact display size.
     * Requires permission {@link android.Manifest.permission#SET_WALLPAPER}.
     * @param cropHints map from {@link ScreenOrientation} to a sub-region of the image to display
     *                  for that screen orientation.
     * @hide
     */
    @FlaggedApi(FLAG_MULTI_CROP)
    @RequiresPermission(android.Manifest.permission.SET_WALLPAPER)
    public int setStreamWithCrops(InputStream bitmapData, @NonNull SparseArray<Rect> cropHints,
            boolean allowBackup, @SetWallpaperFlags int which) throws IOException {
        if (sGlobals.mService == null) {
            Log.w(TAG, "WallpaperService not running");
            throw new RuntimeException(new DeadSystemException());
        }
        int size = cropHints.size();
        int[] screenOrientations = new int[size];
        List<Rect> crops = new ArrayList<>(size);
        for (int i = 0; i < size; i++) {
            screenOrientations[i] = cropHints.keyAt(i);
            Rect cropHint = cropHints.valueAt(i);
            validateRect(cropHint);
            crops.add(cropHint);
        }
        final Bundle result = new Bundle();
        final WallpaperSetCompletion completion = new WallpaperSetCompletion();
        try {
            ParcelFileDescriptor fd = sGlobals.mService.setWallpaper(null,
                    mContext.getOpPackageName(), screenOrientations, crops, allowBackup,
                    result, which, completion, mContext.getUserId());
            if (fd != null) {
                FileOutputStream fos = null;
                try {
                    fos = new ParcelFileDescriptor.AutoCloseOutputStream(fd);
                    copyStreamToWallpaperFile(bitmapData, fos);
                    fos.close();
                    completion.waitForCompletion();
                } finally {
                    IoUtils.closeQuietly(fos);
                }
            }
        } catch (RemoteException e) {
            throw e.rethrowFromSystemServer();
        }
        return result.getInt(EXTRA_NEW_WALLPAPER_ID, 0);
    }

    /**
    /**
     * Return whether any users are currently set to use the wallpaper
     * Return whether any users are currently set to use the wallpaper
     * with the given resource ID.  That is, their wallpaper has been
     * with the given resource ID.  That is, their wallpaper has been
@@ -2499,7 +2804,7 @@ public class WallpaperManager {
     * @hide
     * @hide
     */
     */
    @SystemApi
    @SystemApi
    @RequiresPermission(android.Manifest.permission.SET_WALLPAPER_DIM_AMOUNT)
    @RequiresPermission(SET_WALLPAPER_DIM_AMOUNT)
    public void setWallpaperDimAmount(@FloatRange (from = 0f, to = 1f) float dimAmount) {
    public void setWallpaperDimAmount(@FloatRange (from = 0f, to = 1f) float dimAmount) {
        if (sGlobals.mService == null) {
        if (sGlobals.mService == null) {
            Log.w(TAG, "WallpaperService not running");
            Log.w(TAG, "WallpaperService not running");
@@ -2519,7 +2824,7 @@ public class WallpaperManager {
     * @hide
     * @hide
     */
     */
    @SystemApi
    @SystemApi
    @RequiresPermission(android.Manifest.permission.SET_WALLPAPER_DIM_AMOUNT)
    @RequiresPermission(SET_WALLPAPER_DIM_AMOUNT)
    public @FloatRange (from = 0f, to = 1f) float getWallpaperDimAmount() {
    public @FloatRange (from = 0f, to = 1f) float getWallpaperDimAmount() {
        if (sGlobals.mService == null) {
        if (sGlobals.mService == null) {
            Log.w(TAG, "WallpaperService not running");
            Log.w(TAG, "WallpaperService not running");
+6 −0
Original line number Original line Diff line number Diff line
@@ -4333,6 +4333,12 @@
      "group": "WM_DEBUG_ANIM",
      "group": "WM_DEBUG_ANIM",
      "at": "com\/android\/server\/wm\/WindowStateAnimator.java"
      "at": "com\/android\/server\/wm\/WindowStateAnimator.java"
    },
    },
    "1810872941": {
      "message": "setWallpaperCropHints: non-existent wallpaper token: %s",
      "level": "WARN",
      "group": "WM_ERROR",
      "at": "com\/android\/server\/wm\/WindowManagerService.java"
    },
    "1820873642": {
    "1820873642": {
      "message": "SyncGroup %d:  Unfinished dependencies: %s",
      "message": "SyncGroup %d:  Unfinished dependencies: %s",
      "level": "VERBOSE",
      "level": "VERBOSE",
+67 −0

File changed.

Preview size limit exceeded, changes collapsed.

+9 −2
Original line number Original line Diff line number Diff line
@@ -31,6 +31,7 @@ import static com.android.wallpaperbackup.WallpaperEventLogger.WALLPAPER_IMG_LOC
import static com.android.wallpaperbackup.WallpaperEventLogger.WALLPAPER_IMG_SYSTEM;
import static com.android.wallpaperbackup.WallpaperEventLogger.WALLPAPER_IMG_SYSTEM;
import static com.android.wallpaperbackup.WallpaperEventLogger.WALLPAPER_LIVE_LOCK;
import static com.android.wallpaperbackup.WallpaperEventLogger.WALLPAPER_LIVE_LOCK;
import static com.android.wallpaperbackup.WallpaperEventLogger.WALLPAPER_LIVE_SYSTEM;
import static com.android.wallpaperbackup.WallpaperEventLogger.WALLPAPER_LIVE_SYSTEM;
import static com.android.window.flags.Flags.multiCrop;


import static com.google.common.truth.Truth.assertThat;
import static com.google.common.truth.Truth.assertThat;


@@ -60,6 +61,7 @@ import android.os.FileUtils;
import android.os.ParcelFileDescriptor;
import android.os.ParcelFileDescriptor;
import android.os.UserHandle;
import android.os.UserHandle;
import android.service.wallpaper.WallpaperService;
import android.service.wallpaper.WallpaperService;
import android.util.SparseArray;
import android.util.Xml;
import android.util.Xml;


import androidx.test.InstrumentationRegistry;
import androidx.test.InstrumentationRegistry;
@@ -711,8 +713,13 @@ public class WallpaperBackupAgentTest {


    @Test
    @Test
    public void testOnRestore_throwsException_logsErrors() throws Exception {
    public void testOnRestore_throwsException_logsErrors() throws Exception {
        when(mWallpaperManager.setStream(any(), any(), anyBoolean(), anyInt())).thenThrow(
        if (!multiCrop()) {
                new RuntimeException());
            when(mWallpaperManager.setStream(any(), any(), anyBoolean(), anyInt()))
                    .thenThrow(new RuntimeException());
        } else {
            when(mWallpaperManager.setStreamWithCrops(any(), any(SparseArray.class), anyBoolean(),
                    anyInt())).thenThrow(new RuntimeException());
        }
        mockStagedWallpaperFile(SYSTEM_WALLPAPER_STAGE);
        mockStagedWallpaperFile(SYSTEM_WALLPAPER_STAGE);
        mockStagedWallpaperFile(WALLPAPER_INFO_STAGE);
        mockStagedWallpaperFile(WALLPAPER_INFO_STAGE);
        mWallpaperBackupAgent.onCreate(USER_HANDLE, BackupAnnotations.BackupDestination.CLOUD,
        mWallpaperBackupAgent.onCreate(USER_HANDLE, BackupAnnotations.BackupDestination.CLOUD,
Loading