Merge "Support both HDR and display-native screenshots." into udc-dev
This commit is contained in:
@@ -198,17 +198,21 @@ public class ScreenCapture {
|
||||
* Create ScreenshotHardwareBuffer from an existing HardwareBuffer object.
|
||||
*
|
||||
* @param hardwareBuffer The existing HardwareBuffer object
|
||||
* @param namedColorSpace Integer value of a named color space {@link ColorSpace.Named}
|
||||
* @param dataspace Dataspace describing the content.
|
||||
* {@see android.hardware.DataSpace}
|
||||
* @param containsSecureLayers Indicates whether this graphic buffer contains captured
|
||||
* contents of secure layers, in which case the screenshot
|
||||
* should not be persisted.
|
||||
* @param containsHdrLayers Indicates whether this graphic buffer contains HDR content.
|
||||
*/
|
||||
private static ScreenshotHardwareBuffer createFromNative(HardwareBuffer hardwareBuffer,
|
||||
int namedColorSpace, boolean containsSecureLayers, boolean containsHdrLayers) {
|
||||
ColorSpace colorSpace = ColorSpace.get(ColorSpace.Named.values()[namedColorSpace]);
|
||||
int dataspace, boolean containsSecureLayers, boolean containsHdrLayers) {
|
||||
ColorSpace colorSpace = ColorSpace.getFromDataSpace(dataspace);
|
||||
return new ScreenshotHardwareBuffer(
|
||||
hardwareBuffer, colorSpace, containsSecureLayers, containsHdrLayers);
|
||||
hardwareBuffer,
|
||||
colorSpace != null ? colorSpace : ColorSpace.get(ColorSpace.Named.SRGB),
|
||||
containsSecureLayers,
|
||||
containsHdrLayers);
|
||||
}
|
||||
|
||||
public ColorSpace getColorSpace() {
|
||||
@@ -271,8 +275,8 @@ public class ScreenCapture {
|
||||
public final boolean mAllowProtected;
|
||||
public final long mUid;
|
||||
public final boolean mGrayscale;
|
||||
|
||||
final SurfaceControl[] mExcludeLayers;
|
||||
public final boolean mHintForSeamlessTransition;
|
||||
|
||||
private CaptureArgs(CaptureArgs.Builder<? extends CaptureArgs.Builder<?>> builder) {
|
||||
mPixelFormat = builder.mPixelFormat;
|
||||
@@ -284,6 +288,7 @@ public class ScreenCapture {
|
||||
mUid = builder.mUid;
|
||||
mGrayscale = builder.mGrayscale;
|
||||
mExcludeLayers = builder.mExcludeLayers;
|
||||
mHintForSeamlessTransition = builder.mHintForSeamlessTransition;
|
||||
}
|
||||
|
||||
private CaptureArgs(Parcel in) {
|
||||
@@ -305,6 +310,7 @@ public class ScreenCapture {
|
||||
} else {
|
||||
mExcludeLayers = null;
|
||||
}
|
||||
mHintForSeamlessTransition = in.readBoolean();
|
||||
}
|
||||
|
||||
/** Release any layers if set using {@link Builder#setExcludeLayers(SurfaceControl[])}. */
|
||||
@@ -352,6 +358,7 @@ public class ScreenCapture {
|
||||
private long mUid = -1;
|
||||
private boolean mGrayscale;
|
||||
private SurfaceControl[] mExcludeLayers;
|
||||
private boolean mHintForSeamlessTransition;
|
||||
|
||||
/**
|
||||
* Construct a new {@link CaptureArgs} with the set parameters. The builder remains
|
||||
@@ -448,6 +455,21 @@ public class ScreenCapture {
|
||||
return getThis();
|
||||
}
|
||||
|
||||
/**
|
||||
* Set whether the screenshot will be used in a system animation.
|
||||
* This hint is used for picking the "best" colorspace for the screenshot, in particular
|
||||
* for mixing HDR and SDR content.
|
||||
* E.g., hintForSeamlessTransition is false, then a colorspace suitable for file
|
||||
* encoding, such as BT2100, may be chosen. Otherwise, then the display's color space
|
||||
* would be chosen, with the possibility of having an extended brightness range. This
|
||||
* is important for screenshots that are directly re-routed to a SurfaceControl in
|
||||
* order to preserve accurate colors.
|
||||
*/
|
||||
public T setHintForSeamlessTransition(boolean hintForSeamlessTransition) {
|
||||
mHintForSeamlessTransition = hintForSeamlessTransition;
|
||||
return getThis();
|
||||
}
|
||||
|
||||
/**
|
||||
* Each sub class should return itself to allow the builder to chain properly
|
||||
*/
|
||||
@@ -471,7 +493,6 @@ public class ScreenCapture {
|
||||
dest.writeBoolean(mAllowProtected);
|
||||
dest.writeLong(mUid);
|
||||
dest.writeBoolean(mGrayscale);
|
||||
|
||||
if (mExcludeLayers != null) {
|
||||
dest.writeInt(mExcludeLayers.length);
|
||||
for (SurfaceControl excludeLayer : mExcludeLayers) {
|
||||
@@ -480,6 +501,7 @@ public class ScreenCapture {
|
||||
} else {
|
||||
dest.writeInt(0);
|
||||
}
|
||||
dest.writeBoolean(mHintForSeamlessTransition);
|
||||
}
|
||||
|
||||
public static final Parcelable.Creator<CaptureArgs> CREATOR =
|
||||
@@ -627,6 +649,7 @@ public class ScreenCapture {
|
||||
setUid(args.mUid);
|
||||
setGrayscale(args.mGrayscale);
|
||||
setExcludeLayers(args.mExcludeLayers);
|
||||
setHintForSeamlessTransition(args.mHintForSeamlessTransition);
|
||||
}
|
||||
|
||||
public Builder(SurfaceControl layer) {
|
||||
|
||||
@@ -46,6 +46,7 @@ static struct {
|
||||
jfieldID uid;
|
||||
jfieldID grayscale;
|
||||
jmethodID getNativeExcludeLayers;
|
||||
jfieldID hintForSeamlessTransition;
|
||||
} gCaptureArgsClassInfo;
|
||||
|
||||
static struct {
|
||||
@@ -69,23 +70,6 @@ static struct {
|
||||
jmethodID builder;
|
||||
} gScreenshotHardwareBufferClassInfo;
|
||||
|
||||
enum JNamedColorSpace : jint {
|
||||
// ColorSpace.Named.SRGB.ordinal() = 0;
|
||||
SRGB = 0,
|
||||
|
||||
// ColorSpace.Named.DISPLAY_P3.ordinal() = 7;
|
||||
DISPLAY_P3 = 7,
|
||||
};
|
||||
|
||||
constexpr jint fromDataspaceToNamedColorSpaceValue(const ui::Dataspace dataspace) {
|
||||
switch (dataspace) {
|
||||
case ui::Dataspace::DISPLAY_P3:
|
||||
return JNamedColorSpace::DISPLAY_P3;
|
||||
default:
|
||||
return JNamedColorSpace::SRGB;
|
||||
}
|
||||
}
|
||||
|
||||
static void checkAndClearException(JNIEnv* env, const char* methodName) {
|
||||
if (env->ExceptionCheck()) {
|
||||
ALOGE("An exception was thrown by callback '%s'.", methodName);
|
||||
@@ -119,12 +103,11 @@ public:
|
||||
captureResults.fenceResult.value()->waitForever(LOG_TAG);
|
||||
jobject jhardwareBuffer = android_hardware_HardwareBuffer_createFromAHardwareBuffer(
|
||||
env, captureResults.buffer->toAHardwareBuffer());
|
||||
const jint namedColorSpace =
|
||||
fromDataspaceToNamedColorSpaceValue(captureResults.capturedDataspace);
|
||||
jobject screenshotHardwareBuffer =
|
||||
env->CallStaticObjectMethod(gScreenshotHardwareBufferClassInfo.clazz,
|
||||
gScreenshotHardwareBufferClassInfo.builder,
|
||||
jhardwareBuffer, namedColorSpace,
|
||||
jhardwareBuffer,
|
||||
static_cast<jint>(captureResults.capturedDataspace),
|
||||
captureResults.capturedSecureLayers,
|
||||
captureResults.capturedHdrLayers);
|
||||
checkAndClearException(env, "builder");
|
||||
@@ -185,6 +168,9 @@ static void getCaptureArgs(JNIEnv* env, jobject captureArgsObject, CaptureArgs&
|
||||
captureArgs.excludeHandles.emplace(excludeObject->getHandle());
|
||||
}
|
||||
}
|
||||
captureArgs.hintForSeamlessTransition =
|
||||
env->GetBooleanField(captureArgsObject,
|
||||
gCaptureArgsClassInfo.hintForSeamlessTransition);
|
||||
}
|
||||
|
||||
static DisplayCaptureArgs displayCaptureArgsFromObject(JNIEnv* env,
|
||||
@@ -318,9 +304,10 @@ int register_android_window_ScreenCapture(JNIEnv* env) {
|
||||
GetFieldIDOrDie(env, captureArgsClazz, "mAllowProtected", "Z");
|
||||
gCaptureArgsClassInfo.uid = GetFieldIDOrDie(env, captureArgsClazz, "mUid", "J");
|
||||
gCaptureArgsClassInfo.grayscale = GetFieldIDOrDie(env, captureArgsClazz, "mGrayscale", "Z");
|
||||
|
||||
gCaptureArgsClassInfo.getNativeExcludeLayers =
|
||||
GetMethodIDOrDie(env, captureArgsClazz, "getNativeExcludeLayers", "()[J");
|
||||
gCaptureArgsClassInfo.hintForSeamlessTransition =
|
||||
GetFieldIDOrDie(env, captureArgsClazz, "mHintForSeamlessTransition", "Z");
|
||||
|
||||
jclass displayCaptureArgsClazz =
|
||||
FindClassOrDie(env, "android/window/ScreenCapture$DisplayCaptureArgs");
|
||||
|
||||
@@ -144,6 +144,7 @@ class ScreenRotationAnimation {
|
||||
.setCaptureSecureLayers(true)
|
||||
.setAllowProtected(true)
|
||||
.setSourceCrop(new Rect(0, 0, mStartWidth, mStartHeight))
|
||||
.setHintForSeamlessTransition(true)
|
||||
.build();
|
||||
ScreenCapture.ScreenshotHardwareBuffer screenshotBuffer =
|
||||
ScreenCapture.captureLayers(args);
|
||||
|
||||
@@ -193,6 +193,7 @@ class ScreenRotationAnimation {
|
||||
.setSourceCrop(new Rect(0, 0, width, height))
|
||||
.setAllowProtected(true)
|
||||
.setCaptureSecureLayers(true)
|
||||
.setHintForSeamlessTransition(true)
|
||||
.build();
|
||||
screenshotBuffer = ScreenCapture.captureDisplay(captureArgs);
|
||||
} else {
|
||||
@@ -202,6 +203,7 @@ class ScreenRotationAnimation {
|
||||
.setCaptureSecureLayers(true)
|
||||
.setAllowProtected(true)
|
||||
.setSourceCrop(new Rect(0, 0, width, height))
|
||||
.setHintForSeamlessTransition(true)
|
||||
.build();
|
||||
screenshotBuffer = ScreenCapture.captureLayers(captureArgs);
|
||||
}
|
||||
|
||||
@@ -2999,11 +2999,14 @@ class Transition implements BLASTSyncEngine.TransactionReadyListener {
|
||||
|
||||
Rect cropBounds = new Rect(bounds);
|
||||
cropBounds.offsetTo(0, 0);
|
||||
final boolean isDisplayRotation = wc.asDisplayContent() != null
|
||||
&& wc.asDisplayContent().isRotationChanging();
|
||||
ScreenCapture.LayerCaptureArgs captureArgs =
|
||||
new ScreenCapture.LayerCaptureArgs.Builder(wc.getSurfaceControl())
|
||||
.setSourceCrop(cropBounds)
|
||||
.setCaptureSecureLayers(true)
|
||||
.setAllowProtected(true)
|
||||
.setHintForSeamlessTransition(isDisplayRotation)
|
||||
.build();
|
||||
ScreenCapture.ScreenshotHardwareBuffer screenshotBuffer =
|
||||
ScreenCapture.captureLayers(captureArgs);
|
||||
@@ -3014,8 +3017,6 @@ class Transition implements BLASTSyncEngine.TransactionReadyListener {
|
||||
Slog.w(TAG, "Failed to capture screenshot for " + wc);
|
||||
return false;
|
||||
}
|
||||
final boolean isDisplayRotation = wc.asDisplayContent() != null
|
||||
&& wc.asDisplayContent().isRotationChanging();
|
||||
// Some tests may check the name "RotationLayer" to detect display rotation.
|
||||
final String name = isDisplayRotation ? "RotationLayer" : "transition snapshot: " + wc;
|
||||
SurfaceControl snapshotSurface = wc.makeAnimationLeash()
|
||||
|
||||
Reference in New Issue
Block a user