summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--core/java/com/android/internal/policy/TransitionAnimation.java92
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/transition/ScreenRotationAnimation.java96
-rw-r--r--services/core/java/com/android/server/wm/ScreenRotationAnimation.java7
-rw-r--r--services/core/java/com/android/server/wm/Transition.java4
-rw-r--r--services/core/java/com/android/server/wm/utils/RotationAnimationUtils.java96
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/utils/RotationAnimationUtilsTest.java15
6 files changed, 109 insertions, 201 deletions
diff --git a/core/java/com/android/internal/policy/TransitionAnimation.java b/core/java/com/android/internal/policy/TransitionAnimation.java
index 295dc545ef4b..25ac1bd678c6 100644
--- a/core/java/com/android/internal/policy/TransitionAnimation.java
+++ b/core/java/com/android/internal/policy/TransitionAnimation.java
@@ -41,12 +41,16 @@ import android.content.res.TypedArray;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Color;
+import android.graphics.ColorSpace;
import android.graphics.Picture;
import android.graphics.Rect;
import android.graphics.drawable.Drawable;
import android.hardware.HardwareBuffer;
+import android.media.Image;
+import android.media.ImageReader;
import android.os.SystemProperties;
import android.util.Slog;
+import android.view.SurfaceControl;
import android.view.WindowManager.LayoutParams;
import android.view.WindowManager.TransitionOldType;
import android.view.WindowManager.TransitionType;
@@ -59,9 +63,11 @@ import android.view.animation.Interpolator;
import android.view.animation.PathInterpolator;
import android.view.animation.ScaleAnimation;
import android.view.animation.TranslateAnimation;
+import android.window.ScreenCapture;
import com.android.internal.R;
+import java.nio.ByteBuffer;
import java.util.List;
/** @hide */
@@ -1262,4 +1268,90 @@ public class TransitionAnimation {
return set;
}
+
+ /** Returns whether the hardware buffer passed in is marked as protected. */
+ public static boolean hasProtectedContent(HardwareBuffer hardwareBuffer) {
+ return (hardwareBuffer.getUsage() & HardwareBuffer.USAGE_PROTECTED_CONTENT)
+ == HardwareBuffer.USAGE_PROTECTED_CONTENT;
+ }
+
+ /** Returns the luminance in 0~1. */
+ public static float getBorderLuma(SurfaceControl surfaceControl, int w, int h) {
+ final ScreenCapture.ScreenshotHardwareBuffer buffer =
+ ScreenCapture.captureLayers(surfaceControl, new Rect(0, 0, w, h), 1);
+ if (buffer != null) {
+ return getBorderLuma(buffer.getHardwareBuffer(), buffer.getColorSpace());
+ }
+ return 0;
+ }
+
+ /** Returns the luminance in 0~1. */
+ public static float getBorderLuma(HardwareBuffer hwBuffer, ColorSpace colorSpace) {
+ if (hwBuffer == null) {
+ return 0;
+ }
+ final int format = hwBuffer.getFormat();
+ // Only support RGB format in 4 bytes. And protected buffer is not readable.
+ if (format != HardwareBuffer.RGBA_8888 || hasProtectedContent(hwBuffer)) {
+ return 0;
+ }
+
+ final ImageReader ir = ImageReader.newInstance(hwBuffer.getWidth(), hwBuffer.getHeight(),
+ format, 1 /* maxImages */);
+ ir.getSurface().attachAndQueueBufferWithColorSpace(hwBuffer, colorSpace);
+ final Image image = ir.acquireLatestImage();
+ if (image == null || image.getPlaneCount() < 1) {
+ return 0;
+ }
+
+ final Image.Plane plane = image.getPlanes()[0];
+ final ByteBuffer buffer = plane.getBuffer();
+ final int width = image.getWidth();
+ final int height = image.getHeight();
+ final int pixelStride = plane.getPixelStride();
+ final int rowStride = plane.getRowStride();
+ final int sampling = 10;
+ final int[] borderLumas = new int[(width + height) * 2 / sampling];
+
+ // Grab the top and bottom borders.
+ int i = 0;
+ for (int x = 0, size = width - sampling; x < size; x += sampling) {
+ borderLumas[i++] = getPixelLuminance(buffer, x, 0, pixelStride, rowStride);
+ borderLumas[i++] = getPixelLuminance(buffer, x, height - 1, pixelStride, rowStride);
+ }
+
+ // Grab the left and right borders.
+ for (int y = 0, size = height - sampling; y < size; y += sampling) {
+ borderLumas[i++] = getPixelLuminance(buffer, 0, y, pixelStride, rowStride);
+ borderLumas[i++] = getPixelLuminance(buffer, width - 1, y, pixelStride, rowStride);
+ }
+
+ ir.close();
+
+ // Get "mode" by histogram.
+ final int[] histogram = new int[256];
+ int maxCount = 0;
+ int mostLuma = 0;
+ for (int luma : borderLumas) {
+ final int count = ++histogram[luma];
+ if (count > maxCount) {
+ maxCount = count;
+ mostLuma = luma;
+ }
+ }
+ return mostLuma / 255f;
+ }
+
+ /** Returns the luminance of the pixel in 0~255. */
+ private static int getPixelLuminance(ByteBuffer buffer, int x, int y, int pixelStride,
+ int rowStride) {
+ final int color = buffer.getInt(y * rowStride + x * pixelStride);
+ // The buffer from ImageReader is always in native order (little-endian), so extract the
+ // color components in reversed order.
+ final int r = color & 0xff;
+ final int g = (color >> 8) & 0xff;
+ final int b = (color >> 16) & 0xff;
+ // Approximation of WCAG 2.0 relative luminance.
+ return ((r * 8) + (g * 22) + (b * 2)) >> 5;
+ }
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/ScreenRotationAnimation.java b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/ScreenRotationAnimation.java
index 2b27baeb515a..66d0a2aa409b 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/ScreenRotationAnimation.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/ScreenRotationAnimation.java
@@ -16,8 +16,6 @@
package com.android.wm.shell.transition;
-import static android.hardware.HardwareBuffer.RGBA_8888;
-import static android.hardware.HardwareBuffer.USAGE_PROTECTED_CONTENT;
import static android.util.RotationUtils.deltaRotation;
import static android.view.WindowManager.LayoutParams.ROTATION_ANIMATION_CROSSFADE;
import static android.view.WindowManager.LayoutParams.ROTATION_ANIMATION_JUMPCUT;
@@ -37,8 +35,6 @@ import android.graphics.ColorSpace;
import android.graphics.Matrix;
import android.graphics.Rect;
import android.hardware.HardwareBuffer;
-import android.media.Image;
-import android.media.ImageReader;
import android.util.Slog;
import android.view.Surface;
import android.view.SurfaceControl;
@@ -50,12 +46,11 @@ import android.window.ScreenCapture;
import android.window.TransitionInfo;
import com.android.internal.R;
+import com.android.internal.policy.TransitionAnimation;
import com.android.wm.shell.common.ShellExecutor;
import com.android.wm.shell.common.TransactionPool;
-import java.nio.ByteBuffer;
import java.util.ArrayList;
-import java.util.Arrays;
/**
* This class handles the rotation animation when the device is rotated.
@@ -173,7 +168,7 @@ class ScreenRotationAnimation {
t.setBuffer(mScreenshotLayer, hardwareBuffer);
t.show(mScreenshotLayer);
if (!isCustomRotate()) {
- mStartLuma = getMedianBorderLuma(hardwareBuffer, colorSpace);
+ mStartLuma = TransitionAnimation.getBorderLuma(hardwareBuffer, colorSpace);
}
}
@@ -404,93 +399,6 @@ class ScreenRotationAnimation {
mTransactionPool.release(t);
}
- /**
- * Converts the provided {@link HardwareBuffer} and converts it to a bitmap to then sample the
- * luminance at the borders of the bitmap
- * @return the average luminance of all the pixels at the borders of the bitmap
- */
- private static float getMedianBorderLuma(HardwareBuffer hardwareBuffer, ColorSpace colorSpace) {
- // Cannot read content from buffer with protected usage.
- if (hardwareBuffer == null || hardwareBuffer.getFormat() != RGBA_8888
- || hasProtectedContent(hardwareBuffer)) {
- return 0;
- }
-
- ImageReader ir = ImageReader.newInstance(hardwareBuffer.getWidth(),
- hardwareBuffer.getHeight(), hardwareBuffer.getFormat(), 1);
- ir.getSurface().attachAndQueueBufferWithColorSpace(hardwareBuffer, colorSpace);
- Image image = ir.acquireLatestImage();
- if (image == null || image.getPlanes().length == 0) {
- return 0;
- }
-
- Image.Plane plane = image.getPlanes()[0];
- ByteBuffer buffer = plane.getBuffer();
- int width = image.getWidth();
- int height = image.getHeight();
- int pixelStride = plane.getPixelStride();
- int rowStride = plane.getRowStride();
- float[] borderLumas = new float[2 * width + 2 * height];
-
- // Grab the top and bottom borders
- int l = 0;
- for (int x = 0; x < width; x++) {
- borderLumas[l++] = getPixelLuminance(buffer, x, 0, pixelStride, rowStride);
- borderLumas[l++] = getPixelLuminance(buffer, x, height - 1, pixelStride, rowStride);
- }
-
- // Grab the left and right borders
- for (int y = 0; y < height; y++) {
- borderLumas[l++] = getPixelLuminance(buffer, 0, y, pixelStride, rowStride);
- borderLumas[l++] = getPixelLuminance(buffer, width - 1, y, pixelStride, rowStride);
- }
-
- // Cleanup
- ir.close();
-
- // Oh, is this too simple and inefficient for you?
- // How about implementing a O(n) solution? https://en.wikipedia.org/wiki/Median_of_medians
- Arrays.sort(borderLumas);
- return borderLumas[borderLumas.length / 2];
- }
-
- /**
- * @return whether the hardwareBuffer passed in is marked as protected.
- */
- private static boolean hasProtectedContent(HardwareBuffer hardwareBuffer) {
- return (hardwareBuffer.getUsage() & USAGE_PROTECTED_CONTENT) == USAGE_PROTECTED_CONTENT;
- }
-
- private static float getPixelLuminance(ByteBuffer buffer, int x, int y,
- int pixelStride, int rowStride) {
- int offset = y * rowStride + x * pixelStride;
- int pixel = 0;
- pixel |= (buffer.get(offset) & 0xff) << 16; // R
- pixel |= (buffer.get(offset + 1) & 0xff) << 8; // G
- pixel |= (buffer.get(offset + 2) & 0xff); // B
- pixel |= (buffer.get(offset + 3) & 0xff) << 24; // A
- return Color.valueOf(pixel).luminance();
- }
-
- /**
- * Gets the average border luma by taking a screenshot of the {@param surfaceControl}.
- * @see #getMedianBorderLuma(HardwareBuffer, ColorSpace)
- */
- private static float getLumaOfSurfaceControl(Rect bounds, SurfaceControl surfaceControl) {
- if (surfaceControl == null) {
- return 0;
- }
-
- Rect crop = new Rect(0, 0, bounds.width(), bounds.height());
- ScreenCapture.ScreenshotHardwareBuffer buffer =
- ScreenCapture.captureLayers(surfaceControl, crop, 1);
- if (buffer == null) {
- return 0;
- }
-
- return getMedianBorderLuma(buffer.getHardwareBuffer(), buffer.getColorSpace());
- }
-
private static void applyColor(int startColor, int endColor, float[] rgbFloat,
float fraction, SurfaceControl surface, SurfaceControl.Transaction t) {
final int color = (Integer) ArgbEvaluator.getInstance().evaluate(fraction, startColor,
diff --git a/services/core/java/com/android/server/wm/ScreenRotationAnimation.java b/services/core/java/com/android/server/wm/ScreenRotationAnimation.java
index 55055390b0ff..449e77fca399 100644
--- a/services/core/java/com/android/server/wm/ScreenRotationAnimation.java
+++ b/services/core/java/com/android/server/wm/ScreenRotationAnimation.java
@@ -55,6 +55,7 @@ import android.view.animation.Transformation;
import android.window.ScreenCapture;
import com.android.internal.R;
+import com.android.internal.policy.TransitionAnimation;
import com.android.internal.protolog.common.ProtoLog;
import com.android.server.display.DisplayControl;
import com.android.server.wm.SurfaceAnimator.AnimationType;
@@ -246,7 +247,7 @@ class ScreenRotationAnimation {
HardwareBuffer hardwareBuffer = screenshotBuffer.getHardwareBuffer();
Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER,
"ScreenRotationAnimation#getMedianBorderLuma");
- mStartLuma = RotationAnimationUtils.getMedianBorderLuma(hardwareBuffer,
+ mStartLuma = TransitionAnimation.getBorderLuma(hardwareBuffer,
screenshotBuffer.getColorSpace());
Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
@@ -489,8 +490,8 @@ class ScreenRotationAnimation {
return false;
}
if (!mStarted) {
- mEndLuma = RotationAnimationUtils.getLumaOfSurfaceControl(mDisplayContent.getDisplay(),
- mDisplayContent.getWindowingLayer());
+ mEndLuma = TransitionAnimation.getBorderLuma(mDisplayContent.getWindowingLayer(),
+ finalWidth, finalHeight);
startAnimation(t, maxAnimationDuration, animationScale, finalWidth, finalHeight,
exitAnim, enterAnim);
}
diff --git a/services/core/java/com/android/server/wm/Transition.java b/services/core/java/com/android/server/wm/Transition.java
index 4459d45f60a8..b2c8b7ab98d7 100644
--- a/services/core/java/com/android/server/wm/Transition.java
+++ b/services/core/java/com/android/server/wm/Transition.java
@@ -83,11 +83,11 @@ import android.window.TransitionInfo;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.graphics.ColorUtils;
+import com.android.internal.policy.TransitionAnimation;
import com.android.internal.protolog.ProtoLogGroup;
import com.android.internal.protolog.common.ProtoLog;
import com.android.internal.util.function.pooled.PooledLambda;
import com.android.server.inputmethod.InputMethodManagerInternal;
-import com.android.server.wm.utils.RotationAnimationUtils;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
@@ -2190,7 +2190,7 @@ class Transition extends Binder implements BLASTSyncEngine.TransactionReadyListe
changeInfo.mSnapshot = snapshotSurface;
if (isDisplayRotation) {
// This isn't cheap, so only do it for display rotations.
- changeInfo.mSnapshotLuma = RotationAnimationUtils.getMedianBorderLuma(
+ changeInfo.mSnapshotLuma = TransitionAnimation.getBorderLuma(
screenshotBuffer.getHardwareBuffer(), screenshotBuffer.getColorSpace());
}
SurfaceControl.Transaction t = wc.mWmService.mTransactionFactory.get();
diff --git a/services/core/java/com/android/server/wm/utils/RotationAnimationUtils.java b/services/core/java/com/android/server/wm/utils/RotationAnimationUtils.java
index b93b8d866a00..c11a6d02eb18 100644
--- a/services/core/java/com/android/server/wm/utils/RotationAnimationUtils.java
+++ b/services/core/java/com/android/server/wm/utils/RotationAnimationUtils.java
@@ -16,24 +16,11 @@
package com.android.server.wm.utils;
-import static android.hardware.HardwareBuffer.RGBA_8888;
import static android.hardware.HardwareBuffer.USAGE_PROTECTED_CONTENT;
-import android.graphics.Color;
-import android.graphics.ColorSpace;
import android.graphics.Matrix;
-import android.graphics.Point;
-import android.graphics.Rect;
import android.hardware.HardwareBuffer;
-import android.media.Image;
-import android.media.ImageReader;
-import android.view.Display;
import android.view.Surface;
-import android.view.SurfaceControl;
-import android.window.ScreenCapture;
-
-import java.nio.ByteBuffer;
-import java.util.Arrays;
/** Helper functions for the {@link com.android.server.wm.ScreenRotationAnimation} class*/
@@ -46,89 +33,6 @@ public class RotationAnimationUtils {
return (hardwareBuffer.getUsage() & USAGE_PROTECTED_CONTENT) == USAGE_PROTECTED_CONTENT;
}
- /**
- * Converts the provided {@link HardwareBuffer} and converts it to a bitmap to then sample the
- * luminance at the borders of the bitmap
- * @return the average luminance of all the pixels at the borders of the bitmap
- */
- public static float getMedianBorderLuma(HardwareBuffer hardwareBuffer, ColorSpace colorSpace) {
- // Cannot read content from buffer with protected usage.
- if (hardwareBuffer == null || hardwareBuffer.getFormat() != RGBA_8888
- || hasProtectedContent(hardwareBuffer)) {
- return 0;
- }
-
- ImageReader ir = ImageReader.newInstance(hardwareBuffer.getWidth(),
- hardwareBuffer.getHeight(), hardwareBuffer.getFormat(), 1);
- ir.getSurface().attachAndQueueBufferWithColorSpace(hardwareBuffer, colorSpace);
- Image image = ir.acquireLatestImage();
- if (image == null || image.getPlanes().length == 0) {
- return 0;
- }
-
- Image.Plane plane = image.getPlanes()[0];
- ByteBuffer buffer = plane.getBuffer();
- int width = image.getWidth();
- int height = image.getHeight();
- int pixelStride = plane.getPixelStride();
- int rowStride = plane.getRowStride();
- float[] borderLumas = new float[2 * width + 2 * height];
-
- // Grab the top and bottom borders
- int l = 0;
- for (int x = 0; x < width; x++) {
- borderLumas[l++] = getPixelLuminance(buffer, x, 0, pixelStride, rowStride);
- borderLumas[l++] = getPixelLuminance(buffer, x, height - 1, pixelStride, rowStride);
- }
-
- // Grab the left and right borders
- for (int y = 0; y < height; y++) {
- borderLumas[l++] = getPixelLuminance(buffer, 0, y, pixelStride, rowStride);
- borderLumas[l++] = getPixelLuminance(buffer, width - 1, y, pixelStride, rowStride);
- }
-
- // Cleanup
- ir.close();
-
- // Oh, is this too simple and inefficient for you?
- // How about implementing a O(n) solution? https://en.wikipedia.org/wiki/Median_of_medians
- Arrays.sort(borderLumas);
- return borderLumas[borderLumas.length / 2];
- }
-
- private static float getPixelLuminance(ByteBuffer buffer, int x, int y,
- int pixelStride, int rowStride) {
- int offset = y * rowStride + x * pixelStride;
- int pixel = 0;
- pixel |= (buffer.get(offset) & 0xff) << 16; // R
- pixel |= (buffer.get(offset + 1) & 0xff) << 8; // G
- pixel |= (buffer.get(offset + 2) & 0xff); // B
- pixel |= (buffer.get(offset + 3) & 0xff) << 24; // A
- return Color.valueOf(pixel).luminance();
- }
-
- /**
- * Gets the average border luma by taking a screenshot of the {@param surfaceControl}.
- * @see #getMedianBorderLuma(HardwareBuffer, ColorSpace)
- */
- public static float getLumaOfSurfaceControl(Display display, SurfaceControl surfaceControl) {
- if (surfaceControl == null) {
- return 0;
- }
-
- Point size = new Point();
- display.getSize(size);
- Rect crop = new Rect(0, 0, size.x, size.y);
- ScreenCapture.ScreenshotHardwareBuffer buffer =
- ScreenCapture.captureLayers(surfaceControl, crop, 1);
- if (buffer == null) {
- return 0;
- }
-
- return RotationAnimationUtils.getMedianBorderLuma(buffer.getHardwareBuffer(),
- buffer.getColorSpace());
- }
-
public static void createRotationMatrix(int rotation, int width, int height, Matrix outMatrix) {
switch (rotation) {
case Surface.ROTATION_0:
diff --git a/services/tests/wmtests/src/com/android/server/wm/utils/RotationAnimationUtilsTest.java b/services/tests/wmtests/src/com/android/server/wm/utils/RotationAnimationUtilsTest.java
index fc3962bd0b23..cd4d65d7dab1 100644
--- a/services/tests/wmtests/src/com/android/server/wm/utils/RotationAnimationUtilsTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/utils/RotationAnimationUtilsTest.java
@@ -26,8 +26,10 @@ import android.graphics.ColorSpace;
import android.graphics.Matrix;
import android.graphics.PointF;
import android.hardware.HardwareBuffer;
-import android.view.Surface;
import android.platform.test.annotations.Presubmit;
+import android.view.Surface;
+
+import com.android.internal.policy.TransitionAnimation;
import org.junit.Before;
import org.junit.Test;
@@ -52,7 +54,8 @@ public class RotationAnimationUtilsTest {
public void blackLuma() {
Bitmap swBitmap = createBitmap(0);
HardwareBuffer hb = swBitmapToHardwareBuffer(swBitmap);
- float borderLuma = RotationAnimationUtils.getMedianBorderLuma(hb, mColorSpace);
+ float borderLuma = TransitionAnimation.getBorderLuma(hb, mColorSpace);
+
assertEquals(0, borderLuma, 0);
}
@@ -60,7 +63,7 @@ public class RotationAnimationUtilsTest {
public void whiteLuma() {
Bitmap swBitmap = createBitmap(1);
HardwareBuffer hb = swBitmapToHardwareBuffer(swBitmap);
- float borderLuma = RotationAnimationUtils.getMedianBorderLuma(hb, mColorSpace);
+ float borderLuma = TransitionAnimation.getBorderLuma(hb, mColorSpace);
assertEquals(1, borderLuma, 0);
}
@@ -68,7 +71,7 @@ public class RotationAnimationUtilsTest {
public void unevenBitmapDimens() {
Bitmap swBitmap = createBitmap(1, BITMAP_WIDTH + 1, BITMAP_HEIGHT + 1);
HardwareBuffer hb = swBitmapToHardwareBuffer(swBitmap);
- float borderLuma = RotationAnimationUtils.getMedianBorderLuma(hb, mColorSpace);
+ float borderLuma = TransitionAnimation.getBorderLuma(hb, mColorSpace);
assertEquals(1, borderLuma, 0);
}
@@ -77,7 +80,7 @@ public class RotationAnimationUtilsTest {
Bitmap swBitmap = createBitmap(1);
setBorderLuma(swBitmap, 0);
HardwareBuffer hb = swBitmapToHardwareBuffer(swBitmap);
- float borderLuma = RotationAnimationUtils.getMedianBorderLuma(hb, mColorSpace);
+ float borderLuma = TransitionAnimation.getBorderLuma(hb, mColorSpace);
assertEquals(0, borderLuma, 0);
}
@@ -86,7 +89,7 @@ public class RotationAnimationUtilsTest {
Bitmap swBitmap = createBitmap(0);
setBorderLuma(swBitmap, 1);
HardwareBuffer hb = swBitmapToHardwareBuffer(swBitmap);
- float borderLuma = RotationAnimationUtils.getMedianBorderLuma(hb, mColorSpace);
+ float borderLuma = TransitionAnimation.getBorderLuma(hb, mColorSpace);
assertEquals(1, borderLuma, 0);
}