Allow disabling layer rotation during screenshots

Add the ability to ignore layers' transformation matrices during
screenshot capture, which will allow the window manager to capture
unrotated images for recents during the device rotation animation.

Bug: 11805195
Change-Id: I96e65506b198d34724eb3aa84815aae6f6de4935
diff --git a/cmds/screencap/screencap.cpp b/cmds/screencap/screencap.cpp
index a57de01..2efe4d3 100644
--- a/cmds/screencap/screencap.cpp
+++ b/cmds/screencap/screencap.cpp
@@ -141,7 +141,7 @@
 
     ScreenshotClient screenshot;
     sp<IBinder> display = SurfaceComposerClient::getBuiltInDisplay(displayId);
-    if (display != NULL && screenshot.update(display) == NO_ERROR) {
+    if (display != NULL && screenshot.update(display, false) == NO_ERROR) {
         base = screenshot.getPixels();
         w = screenshot.getWidth();
         h = screenshot.getHeight();
diff --git a/core/java/android/view/SurfaceControl.java b/core/java/android/view/SurfaceControl.java
index 97a1f21..5a8d2c8 100644
--- a/core/java/android/view/SurfaceControl.java
+++ b/core/java/android/view/SurfaceControl.java
@@ -39,9 +39,11 @@
     private static native void nativeDestroy(long nativeObject);
 
     private static native Bitmap nativeScreenshot(IBinder displayToken,
-            int width, int height, int minLayer, int maxLayer, boolean allLayers);
+            int width, int height, int minLayer, int maxLayer, boolean allLayers,
+            boolean useIdentityTransform);
     private static native void nativeScreenshot(IBinder displayToken, Surface consumer,
-            int width, int height, int minLayer, int maxLayer, boolean allLayers);
+            int width, int height, int minLayer, int maxLayer, boolean allLayers,
+            boolean useIdentityTransform);
 
     private static native void nativeOpenTransaction();
     private static native void nativeCloseTransaction();
@@ -554,10 +556,15 @@
      * include in the screenshot.
      * @param maxLayer The highest (top-most Z order) surface layer to
      * include in the screenshot.
+     * @param useIdentityTransform Replace whatever transformation (rotation,
+     * scaling, translation) the surface layers are currently using with the
+     * identity transformation while taking the screenshot.
      */
     public static void screenshot(IBinder display, Surface consumer,
-            int width, int height, int minLayer, int maxLayer) {
-        screenshot(display, consumer, width, height, minLayer, maxLayer, false);
+            int width, int height, int minLayer, int maxLayer,
+            boolean useIdentityTransform) {
+        screenshot(display, consumer, width, height, minLayer, maxLayer, false,
+                useIdentityTransform);
     }
 
     /**
@@ -572,7 +579,7 @@
      */
     public static void screenshot(IBinder display, Surface consumer,
             int width, int height) {
-        screenshot(display, consumer, width, height, 0, 0, true);
+        screenshot(display, consumer, width, height, 0, 0, true, false);
     }
 
     /**
@@ -582,7 +589,7 @@
      * @param consumer The {@link Surface} to take the screenshot into.
      */
     public static void screenshot(IBinder display, Surface consumer) {
-        screenshot(display, consumer, 0, 0, 0, 0, true);
+        screenshot(display, consumer, 0, 0, 0, 0, true, false);
     }
 
 
@@ -602,15 +609,20 @@
      * include in the screenshot.
      * @param maxLayer The highest (top-most Z order) surface layer to
      * include in the screenshot.
+     * @param useIdentityTransform Replace whatever transformation (rotation,
+     * scaling, translation) the surface layers are currently using with the
+     * identity transformation while taking the screenshot.
      * @return Returns a Bitmap containing the screen contents, or null
      * if an error occurs. Make sure to call Bitmap.recycle() as soon as
      * possible, once its content is not needed anymore.
      */
-    public static Bitmap screenshot(int width, int height, int minLayer, int maxLayer) {
+    public static Bitmap screenshot(int width, int height, int minLayer, int maxLayer,
+            boolean useIdentityTransform) {
         // TODO: should take the display as a parameter
         IBinder displayToken = SurfaceControl.getBuiltInDisplay(
                 SurfaceControl.BUILT_IN_DISPLAY_ID_MAIN);
-        return nativeScreenshot(displayToken, width, height, minLayer, maxLayer, false);
+        return nativeScreenshot(displayToken, width, height, minLayer, maxLayer, false,
+                useIdentityTransform);
     }
 
     /**
@@ -629,17 +641,19 @@
         // TODO: should take the display as a parameter
         IBinder displayToken = SurfaceControl.getBuiltInDisplay(
                 SurfaceControl.BUILT_IN_DISPLAY_ID_MAIN);
-        return nativeScreenshot(displayToken, width, height, 0, 0, true);
+        return nativeScreenshot(displayToken, width, height, 0, 0, true, false);
     }
 
     private static void screenshot(IBinder display, Surface consumer,
-            int width, int height, int minLayer, int maxLayer, boolean allLayers) {
+            int width, int height, int minLayer, int maxLayer, boolean allLayers,
+            boolean useIdentityTransform) {
         if (display == null) {
             throw new IllegalArgumentException("displayToken must not be null");
         }
         if (consumer == null) {
             throw new IllegalArgumentException("consumer must not be null");
         }
-        nativeScreenshot(display, consumer, width, height, minLayer, maxLayer, allLayers);
+        nativeScreenshot(display, consumer, width, height, minLayer, maxLayer, allLayers,
+                useIdentityTransform);
     }
 }
diff --git a/core/jni/android_view_SurfaceControl.cpp b/core/jni/android_view_SurfaceControl.cpp
index 88ec0d7..480d0ac 100644
--- a/core/jni/android_view_SurfaceControl.cpp
+++ b/core/jni/android_view_SurfaceControl.cpp
@@ -72,12 +72,15 @@
     }
 
     status_t update(const sp<IBinder>& display, int width, int height,
-            int minLayer, int maxLayer, bool allLayers) {
+            int minLayer, int maxLayer, bool allLayers,
+            bool useIdentityTransform) {
         status_t res = (width > 0 && height > 0)
                 ? (allLayers
-                        ? mScreenshot.update(display, width, height)
-                        : mScreenshot.update(display, width, height, minLayer, maxLayer))
-                : mScreenshot.update(display);
+                        ? mScreenshot.update(display, width, height,
+                                useIdentityTransform)
+                        : mScreenshot.update(display, width, height,
+                                minLayer, maxLayer, useIdentityTransform))
+                : mScreenshot.update(display, useIdentityTransform);
         if (res != NO_ERROR) {
             return res;
         }
@@ -162,7 +165,8 @@
 }
 
 static jobject nativeScreenshotBitmap(JNIEnv* env, jclass clazz, jobject displayTokenObj,
-        jint width, jint height, jint minLayer, jint maxLayer, bool allLayers) {
+        jint width, jint height, jint minLayer, jint maxLayer, bool allLayers,
+        bool useIdentityTransform) {
     sp<IBinder> displayToken = ibinderForJavaObject(env, displayTokenObj);
     if (displayToken == NULL) {
         return NULL;
@@ -170,7 +174,7 @@
 
     ScreenshotPixelRef* pixels = new ScreenshotPixelRef(NULL);
     if (pixels->update(displayToken, width, height,
-            minLayer, maxLayer, allLayers) != NO_ERROR) {
+            minLayer, maxLayer, allLayers, useIdentityTransform) != NO_ERROR) {
         delete pixels;
         return NULL;
     }
@@ -202,7 +206,8 @@
 
 static void nativeScreenshot(JNIEnv* env, jclass clazz,
         jobject displayTokenObj, jobject surfaceObj,
-        jint width, jint height, jint minLayer, jint maxLayer, bool allLayers) {
+        jint width, jint height, jint minLayer, jint maxLayer, bool allLayers,
+        bool useIdentityTransform) {
     sp<IBinder> displayToken = ibinderForJavaObject(env, displayTokenObj);
     if (displayToken != NULL) {
         sp<Surface> consumer = android_view_Surface_getSurface(env, surfaceObj);
@@ -213,7 +218,8 @@
             }
             ScreenshotClient::capture(
                     displayToken, consumer->getIGraphicBufferProducer(),
-                    width, height, uint32_t(minLayer), uint32_t(maxLayer));
+                    width, height, uint32_t(minLayer), uint32_t(maxLayer),
+                    useIdentityTransform);
         }
     }
 }
@@ -417,9 +423,9 @@
             (void*)nativeRelease },
     {"nativeDestroy", "(J)V",
             (void*)nativeDestroy },
-    {"nativeScreenshot", "(Landroid/os/IBinder;IIIIZ)Landroid/graphics/Bitmap;",
+    {"nativeScreenshot", "(Landroid/os/IBinder;IIIIZZ)Landroid/graphics/Bitmap;",
             (void*)nativeScreenshotBitmap },
-    {"nativeScreenshot", "(Landroid/os/IBinder;Landroid/view/Surface;IIIIZ)V",
+    {"nativeScreenshot", "(Landroid/os/IBinder;Landroid/view/Surface;IIIIZZ)V",
             (void*)nativeScreenshot },
     {"nativeOpenTransaction", "()V",
             (void*)nativeOpenTransaction },
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index 8f07e27..e664050 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -5757,7 +5757,11 @@
                                 + " surfaceLayer=" + win.mWinAnimator.mSurfaceLayer);
                     }
                 }
-                rawss = SurfaceControl.screenshot(dw, dh, minLayer, maxLayer);
+                // TODO: Replace 'false' in the following line with a variable that indicates
+                // whether the screenshot should use the identity transformation matrix
+                // (e.g., enable it when taking a screenshot for recents, since we might be in
+                // the middle of the rotation animation, but don't want a rotated recent image).
+                rawss = SurfaceControl.screenshot(dw, dh, minLayer, maxLayer, false);
             }
         } while (!screenshotReady && retryCount <= MAX_SCREENSHOT_RETRIES);
         if (retryCount > MAX_SCREENSHOT_RETRIES)  Slog.i(TAG, "Screenshot max retries " +