[DO NOT MERGE] Unify the cropping mechanism in Preview and in Rotation

Move most of the scaling and cropping logic from ImagePreviewFragment
into WallpaperCropUtils and reuse it in DefaultWallpaperPersister when
setting a wallpaper in rotation.

Fixes: 155943055
Change-Id: Id010ee18da7ee055a3595fdeff7122f7ef0d7630
diff --git a/src/com/android/wallpaper/module/DefaultWallpaperPersister.java b/src/com/android/wallpaper/module/DefaultWallpaperPersister.java
index 27e4491..f19e116 100755
--- a/src/com/android/wallpaper/module/DefaultWallpaperPersister.java
+++ b/src/com/android/wallpaper/module/DefaultWallpaperPersister.java
@@ -19,16 +19,19 @@
 import android.app.Activity;
 import android.app.WallpaperManager;
 import android.content.Context;
+import android.content.res.Resources;
 import android.graphics.Bitmap;
 import android.graphics.Bitmap.CompressFormat;
 import android.graphics.BitmapFactory;
 import android.graphics.Point;
+import android.graphics.PointF;
 import android.graphics.Rect;
 import android.graphics.drawable.BitmapDrawable;
 import android.os.AsyncTask;
 import android.os.ParcelFileDescriptor;
 import android.util.Log;
 import android.view.Display;
+import android.view.View;
 import android.view.WindowManager;
 
 import androidx.annotation.Nullable;
@@ -45,6 +48,7 @@
 import com.android.wallpaper.module.BitmapCropper.Callback;
 import com.android.wallpaper.util.BitmapTransformer;
 import com.android.wallpaper.util.ScreenSizeCalculator;
+import com.android.wallpaper.util.WallpaperCropUtils;
 
 import java.io.ByteArrayInputStream;
 import java.io.ByteArrayOutputStream;
@@ -342,7 +346,7 @@
 
     @Override
     public int setWallpaperBitmapInNextRotation(Bitmap wallpaperBitmap) {
-        return setWallpaperBitmapInRotationStatic(wallpaperBitmap);
+        return cropAndSetWallpaperBitmapInRotationStatic(wallpaperBitmap);
     }
 
     @Override
@@ -359,7 +363,7 @@
      */
     private boolean setWallpaperInRotationStatic(Bitmap wallpaperBitmap, List<String> attributions,
             String actionUrl, int actionLabelRes, int actionIconRes, String collectionId) {
-        final int wallpaperId = setWallpaperBitmapInRotationStatic(wallpaperBitmap);
+        final int wallpaperId = cropAndSetWallpaperBitmapInRotationStatic(wallpaperBitmap);
 
         if (wallpaperId == 0) {
             return false;
@@ -423,7 +427,50 @@
      *
      * @return wallpaper ID for the wallpaper bitmap.
      */
-    private int setWallpaperBitmapInRotationStatic(Bitmap wallpaperBitmap) {
+    private int cropAndSetWallpaperBitmapInRotationStatic(Bitmap wallpaperBitmap) {
+        // Calculate crop and scale of the wallpaper to match the default one used in preview
+        Point wallpaperSize = new Point(wallpaperBitmap.getWidth(), wallpaperBitmap.getHeight());
+        WindowManager windowManager =
+                (WindowManager) mAppContext.getSystemService(Context.WINDOW_SERVICE);
+        Resources resources = mAppContext.getResources();
+        Point defaultCropSurfaceSize = WallpaperCropUtils.getDefaultCropSurfaceSize(
+                resources, windowManager.getDefaultDisplay());
+        Point screenSize = ScreenSizeCalculator.getInstance().getScreenSize(
+                windowManager.getDefaultDisplay());
+
+        boolean isRtl = resources.getConfiguration().getLayoutDirection()
+                == View.LAYOUT_DIRECTION_RTL;
+        // Determine minimum zoom to fit maximum visible area of wallpaper on crop surface.
+        float defaultWallpaperZoom =
+                WallpaperCropUtils.calculateMinZoom(wallpaperSize, defaultCropSurfaceSize);
+        float minWallpaperZoom =
+                WallpaperCropUtils.calculateMinZoom(wallpaperSize, screenSize);
+
+        PointF centerPosition = WallpaperCropUtils.calculateDefaultCenter(wallpaperSize,
+                defaultCropSurfaceSize, screenSize, defaultWallpaperZoom, isRtl);
+
+        Point scaledCenter = new Point((int) (minWallpaperZoom * centerPosition.x),
+                (int) (minWallpaperZoom * centerPosition.y));
+
+        int offsetX = Math.max(0, -(screenSize.x / 2 - scaledCenter.x));
+        int offsetY = Math.max(0, -(screenSize.y / 2 - scaledCenter.y));
+
+        Rect cropRect = WallpaperCropUtils.calculateCropRect(minWallpaperZoom, wallpaperSize,
+                defaultCropSurfaceSize, screenSize, offsetX, offsetY, isRtl);
+
+        Rect scaledCropRect = new Rect(
+                Math.round((float) cropRect.left / minWallpaperZoom),
+                Math.round((float) cropRect.top / minWallpaperZoom),
+                Math.round((float) cropRect.right / minWallpaperZoom),
+                Math.round((float) cropRect.bottom / minWallpaperZoom));
+
+        // Scale and crop the bitmap
+        wallpaperBitmap = Bitmap.createBitmap(wallpaperBitmap,
+                scaledCropRect.left,
+                scaledCropRect.top,
+                scaledCropRect.width(),
+                scaledCropRect.height());
+
         // Set wallpaper to home-only instead of both home and lock if there's a distinct lock-only
         // static wallpaper set so we don't override the lock wallpaper.
         boolean isLockWallpaperSet = isSeparateLockScreenWallpaperSet();
diff --git a/src/com/android/wallpaper/picker/ImagePreviewFragment.java b/src/com/android/wallpaper/picker/ImagePreviewFragment.java
index a6babe3..30a95ab 100755
--- a/src/com/android/wallpaper/picker/ImagePreviewFragment.java
+++ b/src/com/android/wallpaper/picker/ImagePreviewFragment.java
@@ -26,7 +26,6 @@
 import android.graphics.PointF;
 import android.graphics.Rect;
 import android.os.Bundle;
-import android.view.Display;
 import android.view.LayoutInflater;
 import android.view.View;
 import android.view.ViewGroup;
@@ -282,73 +281,23 @@
         float minWallpaperZoom =
                 WallpaperCropUtils.calculateMinZoom(mRawWallpaperSize, mScreenSize);
 
-        Point screenToCropSurfacePosition = WallpaperCropUtils.calculateCenterPosition(
-                mDefaultCropSurfaceSize, mScreenSize, true /* alignStart */, isRtl());
-        Point zoomedWallpaperSize = new Point(
-                Math.round(mRawWallpaperSize.x * defaultWallpaperZoom),
-                Math.round(mRawWallpaperSize.y * defaultWallpaperZoom));
-        Point cropSurfaceToWallpaperPosition = WallpaperCropUtils.calculateCenterPosition(
-                zoomedWallpaperSize, mDefaultCropSurfaceSize, false /* alignStart */, isRtl());
-
+        PointF centerPosition = WallpaperCropUtils.calculateDefaultCenter(mRawWallpaperSize,
+                mDefaultCropSurfaceSize, mScreenSize, defaultWallpaperZoom, isRtl());
         // Set min wallpaper zoom and max zoom on MosaicView widget.
         mFullResImageView.setMaxScale(Math.max(DEFAULT_WALLPAPER_MAX_ZOOM, defaultWallpaperZoom));
         mFullResImageView.setMinScale(minWallpaperZoom);
 
-        // Set center to composite positioning between scaled wallpaper and screen.
-        PointF centerPosition = new PointF(
-                mRawWallpaperSize.x / 2f,
-                mRawWallpaperSize.y / 2f);
-        centerPosition.offset(-(screenToCropSurfacePosition.x + cropSurfaceToWallpaperPosition.x),
-                -(screenToCropSurfacePosition.y + cropSurfaceToWallpaperPosition.y));
-
         mFullResImageView.setScaleAndCenter(minWallpaperZoom, centerPosition);
     }
 
     private Rect calculateCropRect() {
-        // Calculate Rect of wallpaper in physical pixel terms (i.e., scaled to current zoom).
         float wallpaperZoom = mFullResImageView.getScale();
-        int scaledWallpaperWidth = (int) (mRawWallpaperSize.x * wallpaperZoom);
-        int scaledWallpaperHeight = (int) (mRawWallpaperSize.y * wallpaperZoom);
         Rect rect = new Rect();
         mFullResImageView.visibleFileRect(rect);
         int scrollX = (int) (rect.left * wallpaperZoom);
         int scrollY = (int) (rect.top * wallpaperZoom);
-
-        rect.set(0, 0, scaledWallpaperWidth, scaledWallpaperHeight);
-
-        Display defaultDisplay =  requireActivity().getWindowManager().getDefaultDisplay();
-        Point screenSize = ScreenSizeCalculator.getInstance().getScreenSize(defaultDisplay);
-        // Crop rect should start off as the visible screen and then include extra width and height
-        // if available within wallpaper at the current zoom.
-        Rect cropRect = new Rect(scrollX, scrollY, scrollX + screenSize.x, scrollY + screenSize.y);
-
-        Point defaultCropSurfaceSize = WallpaperCropUtils.getDefaultCropSurfaceSize(
-                getResources(), defaultDisplay);
-        int extraWidth = defaultCropSurfaceSize.x - screenSize.x;
-        int extraHeightTopAndBottom = (int) ((defaultCropSurfaceSize.y - screenSize.y) / 2f);
-
-        // Try to increase size of screenRect to include extra width depending on the layout
-        // direction.
-        if (isRtl()) {
-            cropRect.left = Math.max(cropRect.left - extraWidth, rect.left);
-        } else {
-            cropRect.right = Math.min(cropRect.right + extraWidth, rect.right);
-        }
-
-        // Try to increase the size of the cropRect to to include extra height.
-        int availableExtraHeightTop = cropRect.top - Math.max(
-                rect.top,
-                cropRect.top - extraHeightTopAndBottom);
-        int availableExtraHeightBottom = Math.min(
-                rect.bottom,
-                cropRect.bottom + extraHeightTopAndBottom) - cropRect.bottom;
-
-        int availableExtraHeightTopAndBottom =
-                Math.min(availableExtraHeightTop, availableExtraHeightBottom);
-        cropRect.top -= availableExtraHeightTopAndBottom;
-        cropRect.bottom += availableExtraHeightTopAndBottom;
-
-        return cropRect;
+        return WallpaperCropUtils.calculateCropRect(wallpaperZoom, mRawWallpaperSize,
+                mDefaultCropSurfaceSize, mScreenSize, scrollX, scrollY, isRtl());
     }
 
     @Override
diff --git a/src/com/android/wallpaper/util/WallpaperCropUtils.java b/src/com/android/wallpaper/util/WallpaperCropUtils.java
index 4940eb1..67bd00b 100755
--- a/src/com/android/wallpaper/util/WallpaperCropUtils.java
+++ b/src/com/android/wallpaper/util/WallpaperCropUtils.java
@@ -17,6 +17,8 @@
 
 import android.content.res.Resources;
 import android.graphics.Point;
+import android.graphics.PointF;
+import android.graphics.Rect;
 import android.os.Build.VERSION;
 import android.os.Build.VERSION_CODES;
 import android.view.Display;
@@ -138,4 +140,91 @@
         }
         return minZoom;
     }
+
+    /**
+     * Calculates the center position of a wallpaper of the given size, based on a "crop surface"
+     * (with extra width to account for parallax) superimposed on the screen. Trying to show as
+     * much of the wallpaper as possible on the crop surface and align screen to crop surface such
+     * that the centered wallpaper matches what would be seen by the user in the left-most home
+     * screen.
+     *
+     * @param wallpaperSize full size of the wallpaper
+     * @param cropSurfaceSize ideal crop size
+     *          @see #getDefaultCropSurfaceSize(Resources, Display)
+     * @param screenSize size of the display
+     * @param defaultWallpaperScale default scale the wallpaper is set to
+     * @param isRtl whether we're in RTL mode
+     * @return a point corresponding to the position of wallpaper that should be in the center
+     *      of the screen.
+     */
+    public static PointF calculateDefaultCenter(Point wallpaperSize, Point cropSurfaceSize,
+            Point screenSize, float defaultWallpaperScale, boolean isRtl) {
+        Point screenToCropSurfacePosition = calculateCenterPosition(
+                cropSurfaceSize, screenSize, true /* alignStart */, isRtl);
+        Point zoomedWallpaperSize = new Point(
+                Math.round(wallpaperSize.x * defaultWallpaperScale),
+                Math.round(wallpaperSize.y * defaultWallpaperScale));
+        Point cropSurfaceToWallpaperPosition = calculateCenterPosition(
+                zoomedWallpaperSize, cropSurfaceSize, false /* alignStart */, isRtl);
+
+        // Set center to composite positioning between scaled wallpaper and screen.
+        PointF centerPosition = new PointF(
+                wallpaperSize.x / 2f,
+                wallpaperSize.y / 2f);
+        centerPosition.offset(-(screenToCropSurfacePosition.x + cropSurfaceToWallpaperPosition.x),
+                -(screenToCropSurfacePosition.y + cropSurfaceToWallpaperPosition.y));
+        return centerPosition;
+    }
+
+    /**
+     * Calculates the rectangle to crop a wallpaper of the given size, and considering the given
+     * scrollX and scrollY offsets
+     * @param wallpaperZoom zoom applied to the raw wallpaper image
+     * @param wallpaperSize full ("raw") wallpaper size
+     * @param defaultCropSurfaceSize @see #getDefaultCropSurfaceSize(Resources, Display)
+     * @param screenSize size of the display
+     * @param scrollX x-axis offset the cropping area from the wallpaper's 0,0 position
+     * @param scrollY y-axis offset the cropping area from the wallpaper's 0,0 position
+     * @param isRtl whether we're in RTL mode
+     * @return a Rect representing the area of the wallpaper to crop.
+     */
+    public static Rect calculateCropRect(float wallpaperZoom, Point wallpaperSize,
+            Point defaultCropSurfaceSize, Point screenSize, int scrollX, int scrollY,
+            boolean isRtl) {
+        // Calculate Rect of wallpaper in physical pixel terms (i.e., scaled to current zoom).
+        int scaledWallpaperWidth = (int) (wallpaperSize.x * wallpaperZoom);
+        int scaledWallpaperHeight = (int) (wallpaperSize.y * wallpaperZoom);
+        Rect rect = new Rect();
+        rect.set(0, 0, scaledWallpaperWidth, scaledWallpaperHeight);
+
+        // Crop rect should start off as the visible screen and then include extra width and height
+        // if available within wallpaper at the current zoom.
+        Rect cropRect = new Rect(scrollX, scrollY, scrollX + screenSize.x, scrollY + screenSize.y);
+
+        int extraWidth = defaultCropSurfaceSize.x - screenSize.x;
+        int extraHeightTopAndBottom = (int) ((defaultCropSurfaceSize.y - screenSize.y) / 2f);
+
+        // Try to increase size of screenRect to include extra width depending on the layout
+        // direction.
+        if (isRtl) {
+            cropRect.left = Math.max(cropRect.left - extraWidth, rect.left);
+        } else {
+            cropRect.right = Math.min(cropRect.right + extraWidth, rect.right);
+        }
+
+        // Try to increase the size of the cropRect to to include extra height.
+        int availableExtraHeightTop = cropRect.top - Math.max(
+                rect.top,
+                cropRect.top - extraHeightTopAndBottom);
+        int availableExtraHeightBottom = Math.min(
+                rect.bottom,
+                cropRect.bottom + extraHeightTopAndBottom) - cropRect.bottom;
+
+        int availableExtraHeightTopAndBottom =
+                Math.min(availableExtraHeightTop, availableExtraHeightBottom);
+        cropRect.top -= availableExtraHeightTopAndBottom;
+        cropRect.bottom += availableExtraHeightTopAndBottom;
+
+        return cropRect;
+    }
 }