Merge "Use the largest display size when calculating wallpaper crop size" into sc-v2-dev
diff --git a/src/com/android/wallpaper/module/BaseWallpaperInjector.java b/src/com/android/wallpaper/module/BaseWallpaperInjector.java
index ea429a6..75b59fe 100755
--- a/src/com/android/wallpaper/module/BaseWallpaperInjector.java
+++ b/src/com/android/wallpaper/module/BaseWallpaperInjector.java
@@ -21,6 +21,7 @@
 import com.android.wallpaper.network.Requester;
 import com.android.wallpaper.network.WallpaperRequester;
 import com.android.wallpaper.picker.individual.IndividualPickerFragment;
+import com.android.wallpaper.util.DisplayUtils;
 
 /**
  * Base implementation of Injector.
@@ -44,6 +45,7 @@
     private LiveWallpaperInfoFactory mLiveWallpaperInfoFactory;
     private DrawableLayerResolver mDrawableLayerResolver;
     private CustomizationSections mCustomizationSections;
+    private DisplayUtils mDisplayUtils;
 
     @Override
     public synchronized BitmapCropper getBitmapCropper() {
@@ -195,4 +197,12 @@
         }
         return mCustomizationSections;
     }
+
+    @Override
+    public DisplayUtils getDisplayUtils(Context context) {
+        if (mDisplayUtils == null) {
+            mDisplayUtils = new DisplayUtils(context.getApplicationContext());
+        }
+        return mDisplayUtils;
+    }
 }
diff --git a/src/com/android/wallpaper/module/DefaultWallpaperPersister.java b/src/com/android/wallpaper/module/DefaultWallpaperPersister.java
index 9148b9f..dc87467 100755
--- a/src/com/android/wallpaper/module/DefaultWallpaperPersister.java
+++ b/src/com/android/wallpaper/module/DefaultWallpaperPersister.java
@@ -48,6 +48,7 @@
 import com.android.wallpaper.model.WallpaperInfo;
 import com.android.wallpaper.module.BitmapCropper.Callback;
 import com.android.wallpaper.util.BitmapTransformer;
+import com.android.wallpaper.util.DisplayUtils;
 import com.android.wallpaper.util.ScreenSizeCalculator;
 import com.android.wallpaper.util.WallpaperCropUtils;
 
@@ -73,6 +74,7 @@
     private final WallpaperManagerCompat mWallpaperManagerCompat;
     private final WallpaperPreferences mWallpaperPreferences;
     private final WallpaperChangedNotifier mWallpaperChangedNotifier;
+    private final DisplayUtils mDisplayUtils;
 
     private WallpaperInfo mWallpaperInfoInPreview;
 
@@ -86,6 +88,7 @@
         mWallpaperManagerCompat = injector.getWallpaperManagerCompat(context);
         mWallpaperPreferences = injector.getPreferences(context);
         mWallpaperChangedNotifier = WallpaperChangedNotifier.getInstance();
+        mDisplayUtils = injector.getDisplayUtils(context);
     }
 
     @Override
@@ -421,13 +424,11 @@
     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();
+        Display croppingDisplay = mDisplayUtils.getWallpaperDisplay();
         Point defaultCropSurfaceSize = WallpaperCropUtils.getDefaultCropSurfaceSize(
-                resources, windowManager.getDefaultDisplay());
-        Point screenSize = ScreenSizeCalculator.getInstance().getScreenSize(
-                windowManager.getDefaultDisplay());
+                resources, croppingDisplay);
+        Point screenSize = ScreenSizeCalculator.getInstance().getScreenSize(croppingDisplay);
 
         // Determine minimum zoom to fit maximum visible area of wallpaper on crop surface.
         float minWallpaperZoom =
diff --git a/src/com/android/wallpaper/module/Injector.java b/src/com/android/wallpaper/module/Injector.java
index 919d1ba..2ec21fd 100755
--- a/src/com/android/wallpaper/module/Injector.java
+++ b/src/com/android/wallpaper/module/Injector.java
@@ -28,6 +28,7 @@
 import com.android.wallpaper.network.Requester;
 import com.android.wallpaper.picker.PreviewFragment.PreviewMode;
 import com.android.wallpaper.picker.individual.IndividualPickerFragment;
+import com.android.wallpaper.util.DisplayUtils;
 
 /**
  * Interface for a provider of "injected dependencies." (NOTE: The term "injector" is somewhat of a
@@ -92,4 +93,9 @@
     String getDownloadableIntentAction();
 
     CustomizationSections getCustomizationSections();
+
+    /**
+     * @return the singleton instance of {@link DisplayUtils}
+     */
+    DisplayUtils getDisplayUtils(Context context);
 }
diff --git a/src/com/android/wallpaper/picker/ImagePreviewFragment.java b/src/com/android/wallpaper/picker/ImagePreviewFragment.java
index cc3b047..2a70325 100755
--- a/src/com/android/wallpaper/picker/ImagePreviewFragment.java
+++ b/src/com/android/wallpaper/picker/ImagePreviewFragment.java
@@ -62,6 +62,7 @@
 import com.android.wallpaper.asset.CurrentWallpaperAssetVN;
 import com.android.wallpaper.model.SetWallpaperViewModel;
 import com.android.wallpaper.module.BitmapCropper;
+import com.android.wallpaper.module.Injector;
 import com.android.wallpaper.module.InjectorProvider;
 import com.android.wallpaper.module.WallpaperPersister.Destination;
 import com.android.wallpaper.util.FullScreenAnimation;
@@ -101,9 +102,18 @@
 
     private final AtomicInteger mImageScaleChangeCounter = new AtomicInteger(0);
     private final AtomicInteger mRecalculateColorCounter = new AtomicInteger(0);
+    private final Injector mInjector = InjectorProvider.getInjector();
 
     private SubsamplingScaleImageView mFullResImageView;
     private Asset mWallpaperAsset;
+    /**
+     * Size of the screen considered for cropping the wallpaper (typically the same as
+     * {@link #mScreenSize} but it could be different on multi-display)
+     */
+    private Point mWallpaperScreenSize;
+    /**
+     * The size of the current screen
+     */
     private Point mScreenSize;
     private Point mRawWallpaperSize; // Native size of wallpaper image.
     private ImageView mLowResImageView;
@@ -137,8 +147,12 @@
         View view = super.onCreateView(inflater, container, savedInstanceState);
 
         Activity activity = requireActivity();
-        mScreenSize = ScreenSizeCalculator.getInstance().getScreenSize(
+        ScreenSizeCalculator screenSizeCalculator = ScreenSizeCalculator.getInstance();
+        mScreenSize = screenSizeCalculator.getScreenSize(
                 activity.getWindowManager().getDefaultDisplay());
+        // "Wallpaper screen" size will be the size of the largest screen available
+        mWallpaperScreenSize = screenSizeCalculator.getScreenSize(
+                mInjector.getDisplayUtils(activity).getWallpaperDisplay());
 
         mContainer = view.findViewById(R.id.container);
         mTouchForwardingLayout = mContainer.findViewById(R.id.touch_forwarding_layout);
@@ -351,7 +365,7 @@
             return;
         }
 
-        BitmapCropper bitmapCropper = InjectorProvider.getInjector().getBitmapCropper();
+        BitmapCropper bitmapCropper = mInjector.getBitmapCropper();
         bitmapCropper.cropAndScaleBitmap(mWallpaperAsset, mFullResImageView.getScale(),
                 calculateCropRect(context), /* adjustForRtl= */ false,
                 new BitmapCropper.Callback() {
@@ -537,13 +551,21 @@
                     mRawWallpaperSize = dimensions;
                     initFullResView();
                 });
-                // Scale the mWallpaperSurface based on system zoom's scale so that the wallpaper is
+
+                // Calculate the size of mWallpaperSurface based on system zoom's scale and
+                // on the larger screen size (if more than one) so that the wallpaper is
                 // rendered in a larger surface than what preview shows, simulating the behavior of
-                // the actual wallpaper surface.
+                // the actual wallpaper surface and so we can crop it to a size that fits in all
+                // screens.
                 float scale = WallpaperCropUtils.getSystemWallpaperMaximumScale(context);
                 int origWidth = mWallpaperSurface.getWidth();
-                int width = (int) (origWidth * scale);
                 int origHeight = mWallpaperSurface.getHeight();
+
+                if (!mScreenSize.equals(mWallpaperScreenSize)) {
+                    float previewToScreenScale = (float) origWidth / mScreenSize.x;
+                    origWidth = (int) (mWallpaperScreenSize.x * previewToScreenScale);
+                }
+                int width = (int) (origWidth * scale);
                 int height = (int) (origHeight * scale);
                 int left = (origWidth - width) / 2;
                 int top = (origHeight - height) / 2;
diff --git a/src/com/android/wallpaper/util/DisplayUtils.kt b/src/com/android/wallpaper/util/DisplayUtils.kt
new file mode 100644
index 0000000..9f7c644
--- /dev/null
+++ b/src/com/android/wallpaper/util/DisplayUtils.kt
@@ -0,0 +1,59 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.wallpaper.util
+
+import android.content.Context
+import android.graphics.Point
+import android.hardware.display.DisplayManager
+import android.util.Log
+import android.view.Display
+
+/**
+ * Utility class to provide methods to find and obtain information about displays via
+ * {@link DisplayManager}
+ */
+class DisplayUtils(context: Context) {
+    companion object {
+        private const val TAG = "DisplayUtils"
+    }
+
+    private val internalDisplays: List<Display>
+
+    init {
+        val appContext = context.applicationContext
+        val dm = appContext.getSystemService(Context.DISPLAY_SERVICE) as DisplayManager
+        val allDisplays: Array<out Display> = dm.displays
+        if (allDisplays.isEmpty()) {
+            Log.e(TAG, "No displays found on context $appContext")
+            throw RuntimeException("No displays found!")
+        }
+        internalDisplays = allDisplays.filter { it.type == Display.TYPE_INTERNAL }
+    }
+
+    /**
+     * Returns the {@link Display} to be used to calculate wallpaper size and cropping.
+     */
+    fun getWallpaperDisplay(): Display {
+        return internalDisplays.maxWithOrNull { a, b -> getRealSize(a) - getRealSize(b) }
+                ?: internalDisplays[0]
+    }
+
+    private fun getRealSize(display: Display): Int {
+        val p = Point()
+        display.getRealSize(p)
+        return p.x * p.y
+    }
+}
diff --git a/src/com/android/wallpaper/util/ScreenSizeCalculator.java b/src/com/android/wallpaper/util/ScreenSizeCalculator.java
index d206e55..64ca88d 100755
--- a/src/com/android/wallpaper/util/ScreenSizeCalculator.java
+++ b/src/com/android/wallpaper/util/ScreenSizeCalculator.java
@@ -88,7 +88,7 @@
             mPortraitScreenSize = new Point();
         }
         writeDisplaySizeToPoint(display, mPortraitScreenSize);
-        return mPortraitScreenSize;
+        return new Point(mPortraitScreenSize);
     }
 
     private Point getLandscapeScreenSize(Display display) {
@@ -96,7 +96,7 @@
             mLandscapeScreenSize = new Point();
         }
         writeDisplaySizeToPoint(display, mLandscapeScreenSize);
-        return mLandscapeScreenSize;
+        return new Point(mLandscapeScreenSize);
     }
 
     /**
diff --git a/tests/src/com/android/wallpaper/testing/TestInjector.java b/tests/src/com/android/wallpaper/testing/TestInjector.java
index 42cb7f5..61d6d36 100644
--- a/tests/src/com/android/wallpaper/testing/TestInjector.java
+++ b/tests/src/com/android/wallpaper/testing/TestInjector.java
@@ -49,6 +49,7 @@
 import com.android.wallpaper.network.Requester;
 import com.android.wallpaper.picker.ImagePreviewFragment;
 import com.android.wallpaper.picker.individual.IndividualPickerFragment;
+import com.android.wallpaper.util.DisplayUtils;
 
 /**
  * Test implementation of the dependency injector.
@@ -266,4 +267,9 @@
     public CustomizationSections getCustomizationSections() {
         return null;
     }
+
+    @Override
+    public DisplayUtils getDisplayUtils(Context context) {
+        return null;
+    }
 }