blob: 986771dad802d151483901ed2dafaa93fc0b3998 [file] [log] [blame]
/*
* Copyright (C) 2013 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.
*/
#define LOG_TAG "SurfaceControl"
#define LOG_NDEBUG 0
#include "android_os_Parcel.h"
#include "android_util_Binder.h"
#include "android_hardware_input_InputWindowHandle.h"
#include "android/graphics/Bitmap.h"
#include "android/graphics/GraphicsJNI.h"
#include "android/graphics/Region.h"
#include "core_jni_helpers.h"
#include <android-base/chrono_utils.h>
#include <nativehelper/JNIHelp.h>
#include <nativehelper/ScopedUtfChars.h>
#include <android_runtime/android_view_Surface.h>
#include <android_runtime/android_view_SurfaceSession.h>
#include <gui/Surface.h>
#include <gui/SurfaceComposerClient.h>
#include <jni.h>
#include <memory>
#include <stdio.h>
#include <system/graphics.h>
#include <ui/ConfigStoreTypes.h>
#include <ui/DisplayInfo.h>
#include <ui/DisplayedFrameStats.h>
#include <ui/FrameStats.h>
#include <ui/GraphicTypes.h>
#include <ui/HdrCapabilities.h>
#include <ui/Rect.h>
#include <ui/Region.h>
#include <utils/Log.h>
// ----------------------------------------------------------------------------
namespace android {
static const char* const OutOfResourcesException =
"android/view/Surface$OutOfResourcesException";
static struct {
jclass clazz;
jmethodID ctor;
jfieldID width;
jfieldID height;
jfieldID refreshRate;
jfieldID density;
jfieldID xDpi;
jfieldID yDpi;
jfieldID secure;
jfieldID appVsyncOffsetNanos;
jfieldID presentationDeadlineNanos;
} gPhysicalDisplayInfoClassInfo;
static struct {
jfieldID bottom;
jfieldID left;
jfieldID right;
jfieldID top;
} gRectClassInfo;
// Implements SkMallocPixelRef::ReleaseProc, to delete the screenshot on unref.
void DeleteScreenshot(void* addr, void* context) {
delete ((ScreenshotClient*) context);
}
static struct {
nsecs_t UNDEFINED_TIME_NANO;
jmethodID init;
} gWindowContentFrameStatsClassInfo;
static struct {
nsecs_t UNDEFINED_TIME_NANO;
jmethodID init;
} gWindowAnimationFrameStatsClassInfo;
static struct {
jclass clazz;
jmethodID ctor;
} gHdrCapabilitiesClassInfo;
static struct {
jclass clazz;
jmethodID builder;
} gGraphicBufferClassInfo;
static struct {
jclass clazz;
jmethodID ctor;
} gDisplayedContentSampleClassInfo;
static struct {
jclass clazz;
jmethodID ctor;
} gDisplayedContentSamplingAttributesClassInfo;
static struct {
jclass clazz;
jmethodID ctor;
jfieldID X;
jfieldID Y;
jfieldID Z;
} gCieXyzClassInfo;
static struct {
jclass clazz;
jmethodID ctor;
jfieldID red;
jfieldID green;
jfieldID blue;
jfieldID white;
} gDisplayPrimariesClassInfo;
static struct {
jclass clazz;
jmethodID builder;
} gScreenshotGraphicBufferClassInfo;
class JNamedColorSpace {
public:
// ColorSpace.Named.SRGB.ordinal() = 0;
static constexpr jint SRGB = 0;
// ColorSpace.Named.DISPLAY_P3.ordinal() = 7;
static constexpr jint 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;
}
}
constexpr ui::Dataspace pickDataspaceFromColorMode(const ui::ColorMode colorMode) {
switch (colorMode) {
case ui::ColorMode::DISPLAY_P3:
case ui::ColorMode::BT2100_PQ:
case ui::ColorMode::BT2100_HLG:
case ui::ColorMode::DISPLAY_BT2020:
return ui::Dataspace::DISPLAY_P3;
default:
return ui::Dataspace::V0_SRGB;
}
}
// ----------------------------------------------------------------------------
static jlong nativeCreateTransaction(JNIEnv* env, jclass clazz) {
return reinterpret_cast<jlong>(new SurfaceComposerClient::Transaction);
}
static void releaseTransaction(SurfaceComposerClient::Transaction* t) {
delete t;
}
static jlong nativeGetNativeTransactionFinalizer(JNIEnv* env, jclass clazz) {
return static_cast<jlong>(reinterpret_cast<uintptr_t>(&releaseTransaction));
}
static jlong nativeCreate(JNIEnv* env, jclass clazz, jobject sessionObj,
jstring nameStr, jint w, jint h, jint format, jint flags, jlong parentObject,
jobject metadataParcel) {
ScopedUtfChars name(env, nameStr);
sp<SurfaceComposerClient> client;
if (sessionObj != NULL) {
client = android_view_SurfaceSession_getClient(env, sessionObj);
} else {
client = SurfaceComposerClient::getDefault();
}
SurfaceControl *parent = reinterpret_cast<SurfaceControl*>(parentObject);
sp<SurfaceControl> surface;
LayerMetadata metadata;
Parcel* parcel = parcelForJavaObject(env, metadataParcel);
if (parcel && !parcel->objectsCount()) {
status_t err = metadata.readFromParcel(parcel);
if (err != NO_ERROR) {
jniThrowException(env, "java/lang/IllegalArgumentException",
"Metadata parcel has wrong format");
}
}
status_t err = client->createSurfaceChecked(
String8(name.c_str()), w, h, format, &surface, flags, parent, std::move(metadata));
if (err == NAME_NOT_FOUND) {
jniThrowException(env, "java/lang/IllegalArgumentException", NULL);
return 0;
} else if (err != NO_ERROR) {
jniThrowException(env, OutOfResourcesException, NULL);
return 0;
}
surface->incStrong((void *)nativeCreate);
return reinterpret_cast<jlong>(surface.get());
}
static void nativeRelease(JNIEnv* env, jclass clazz, jlong nativeObject) {
sp<SurfaceControl> ctrl(reinterpret_cast<SurfaceControl *>(nativeObject));
ctrl->release();
ctrl->decStrong((void *)nativeCreate);
}
static void nativeDestroy(JNIEnv* env, jclass clazz, jlong nativeObject) {
sp<SurfaceControl> ctrl(reinterpret_cast<SurfaceControl *>(nativeObject));
ctrl->destroy();
ctrl->decStrong((void *)nativeCreate);
}
static void nativeDisconnect(JNIEnv* env, jclass clazz, jlong nativeObject) {
SurfaceControl* const ctrl = reinterpret_cast<SurfaceControl *>(nativeObject);
if (ctrl != NULL) {
ctrl->disconnect();
}
}
static Rect rectFromObj(JNIEnv* env, jobject rectObj) {
int left = env->GetIntField(rectObj, gRectClassInfo.left);
int top = env->GetIntField(rectObj, gRectClassInfo.top);
int right = env->GetIntField(rectObj, gRectClassInfo.right);
int bottom = env->GetIntField(rectObj, gRectClassInfo.bottom);
return Rect(left, top, right, bottom);
}
static jobject nativeScreenshot(JNIEnv* env, jclass clazz,
jobject displayTokenObj, jobject sourceCropObj, jint width, jint height,
bool useIdentityTransform, int rotation, bool captureSecureLayers) {
sp<IBinder> displayToken = ibinderForJavaObject(env, displayTokenObj);
if (displayToken == NULL) {
return NULL;
}
const ui::ColorMode colorMode = SurfaceComposerClient::getActiveColorMode(displayToken);
const ui::Dataspace dataspace = pickDataspaceFromColorMode(colorMode);
Rect sourceCrop = rectFromObj(env, sourceCropObj);
sp<GraphicBuffer> buffer;
bool capturedSecureLayers = false;
status_t res = ScreenshotClient::capture(displayToken, dataspace,
ui::PixelFormat::RGBA_8888,
sourceCrop, width, height,
useIdentityTransform, rotation, captureSecureLayers, &buffer, capturedSecureLayers);
if (res != NO_ERROR) {
return NULL;
}
const jint namedColorSpace = fromDataspaceToNamedColorSpaceValue(dataspace);
return env->CallStaticObjectMethod(gScreenshotGraphicBufferClassInfo.clazz,
gScreenshotGraphicBufferClassInfo.builder,
buffer->getWidth(),
buffer->getHeight(),
buffer->getPixelFormat(),
(jint)buffer->getUsage(),
(jlong)buffer.get(),
namedColorSpace,
capturedSecureLayers);
}
static jobject nativeCaptureLayers(JNIEnv* env, jclass clazz, jobject displayTokenObj,
jobject layerHandleToken, jobject sourceCropObj, jfloat frameScale,
jobjectArray excludeArray) {
sp<IBinder> layerHandle = ibinderForJavaObject(env, layerHandleToken);
if (layerHandle == NULL) {
return NULL;
}
Rect sourceCrop;
if (sourceCropObj != NULL) {
sourceCrop = rectFromObj(env, sourceCropObj);
}
std::unordered_set<sp<IBinder>,ISurfaceComposer::SpHash<IBinder>> excludeHandles;
if (excludeArray != NULL) {
const jsize len = env->GetArrayLength(excludeArray);
excludeHandles.reserve(len);
for (jsize i = 0; i < len; i++) {
jobject obj = env->GetObjectArrayElement(excludeArray, i);
if (obj == nullptr) {
jniThrowNullPointerException(env, "Exclude layer is null");
return NULL;
}
sp<IBinder> excludeHandle = ibinderForJavaObject(env, obj);
excludeHandles.emplace(excludeHandle);
}
}
sp<GraphicBuffer> buffer;
ui::Dataspace dataspace = ui::Dataspace::V0_SRGB;
sp<IBinder> displayToken = ibinderForJavaObject(env, displayTokenObj);
if (displayToken != nullptr) {
const ui::ColorMode colorMode = SurfaceComposerClient::getActiveColorMode(displayToken);
dataspace = pickDataspaceFromColorMode(colorMode);
}
status_t res = ScreenshotClient::captureChildLayers(layerHandle, dataspace,
ui::PixelFormat::RGBA_8888, sourceCrop,
excludeHandles, frameScale, &buffer);
if (res != NO_ERROR) {
return NULL;
}
const jint namedColorSpace = fromDataspaceToNamedColorSpaceValue(dataspace);
return env->CallStaticObjectMethod(gScreenshotGraphicBufferClassInfo.clazz,
gScreenshotGraphicBufferClassInfo.builder,
buffer->getWidth(),
buffer->getHeight(),
buffer->getPixelFormat(),
(jint)buffer->getUsage(),
(jlong)buffer.get(),
namedColorSpace,
false /* capturedSecureLayers */);
}
static void nativeApplyTransaction(JNIEnv* env, jclass clazz, jlong transactionObj, jboolean sync) {
auto transaction = reinterpret_cast<SurfaceComposerClient::Transaction*>(transactionObj);
transaction->apply(sync);
}
static void nativeMergeTransaction(JNIEnv* env, jclass clazz,
jlong transactionObj, jlong otherTransactionObj) {
auto transaction = reinterpret_cast<SurfaceComposerClient::Transaction*>(transactionObj);
auto otherTransaction = reinterpret_cast<SurfaceComposerClient::Transaction*>(
otherTransactionObj);
transaction->merge(std::move(*otherTransaction));
}
static void nativeSetAnimationTransaction(JNIEnv* env, jclass clazz, jlong transactionObj) {
auto transaction = reinterpret_cast<SurfaceComposerClient::Transaction*>(transactionObj);
transaction->setAnimationTransaction();
}
static void nativeSetEarlyWakeup(JNIEnv* env, jclass clazz, jlong transactionObj) {
auto transaction = reinterpret_cast<SurfaceComposerClient::Transaction*>(transactionObj);
transaction->setEarlyWakeup();
}
static void nativeSetLayer(JNIEnv* env, jclass clazz, jlong transactionObj,
jlong nativeObject, jint zorder) {
auto transaction = reinterpret_cast<SurfaceComposerClient::Transaction*>(transactionObj);
SurfaceControl* const ctrl = reinterpret_cast<SurfaceControl *>(nativeObject);
transaction->setLayer(ctrl, zorder);
}
static void nativeSetRelativeLayer(JNIEnv* env, jclass clazz, jlong transactionObj,
jlong nativeObject,
jobject relativeTo, jint zorder) {
auto ctrl = reinterpret_cast<SurfaceControl *>(nativeObject);
sp<IBinder> handle = ibinderForJavaObject(env, relativeTo);
{
auto transaction = reinterpret_cast<SurfaceComposerClient::Transaction*>(transactionObj);
transaction->setRelativeLayer(ctrl, handle, zorder);
}
}
static void nativeSetPosition(JNIEnv* env, jclass clazz, jlong transactionObj,
jlong nativeObject, jfloat x, jfloat y) {
auto transaction = reinterpret_cast<SurfaceComposerClient::Transaction*>(transactionObj);
SurfaceControl* const ctrl = reinterpret_cast<SurfaceControl *>(nativeObject);
transaction->setPosition(ctrl, x, y);
}
static void nativeSetGeometry(JNIEnv* env, jclass clazz, jlong transactionObj, jlong nativeObject,
jobject sourceObj, jobject dstObj, jlong orientation) {
auto transaction = reinterpret_cast<SurfaceComposerClient::Transaction*>(transactionObj);
SurfaceControl* const ctrl = reinterpret_cast<SurfaceControl *>(nativeObject);
Rect source, dst;
if (sourceObj != NULL) {
source = rectFromObj(env, sourceObj);
} else {
source.makeInvalid();
}
if (dstObj != NULL) {
dst = rectFromObj(env, dstObj);
} else {
dst.makeInvalid();
}
transaction->setGeometry(ctrl, source, dst, orientation);
}
static void nativeSetGeometryAppliesWithResize(JNIEnv* env, jclass clazz,
jlong transactionObj,
jlong nativeObject) {
auto transaction = reinterpret_cast<SurfaceComposerClient::Transaction*>(transactionObj);
SurfaceControl* const ctrl = reinterpret_cast<SurfaceControl *>(nativeObject);
transaction->setGeometryAppliesWithResize(ctrl);
}
static void nativeSetSize(JNIEnv* env, jclass clazz, jlong transactionObj,
jlong nativeObject, jint w, jint h) {
auto transaction = reinterpret_cast<SurfaceComposerClient::Transaction*>(transactionObj);
SurfaceControl* const ctrl = reinterpret_cast<SurfaceControl *>(nativeObject);
transaction->setSize(ctrl, w, h);
}
static void nativeSetFlags(JNIEnv* env, jclass clazz, jlong transactionObj,
jlong nativeObject, jint flags, jint mask) {
auto transaction = reinterpret_cast<SurfaceComposerClient::Transaction*>(transactionObj);
SurfaceControl* const ctrl = reinterpret_cast<SurfaceControl *>(nativeObject);
transaction->setFlags(ctrl, flags, mask);
}
static void nativeSetTransparentRegionHint(JNIEnv* env, jclass clazz, jlong transactionObj,
jlong nativeObject, jobject regionObj) {
SurfaceControl* const ctrl = reinterpret_cast<SurfaceControl *>(nativeObject);
SkRegion* region = android_graphics_Region_getSkRegion(env, regionObj);
if (!region) {
doThrowIAE(env);
return;
}
const SkIRect& b(region->getBounds());
Region reg(Rect(b.fLeft, b.fTop, b.fRight, b.fBottom));
if (region->isComplex()) {
SkRegion::Iterator it(*region);
while (!it.done()) {
const SkIRect& r(it.rect());
reg.addRectUnchecked(r.fLeft, r.fTop, r.fRight, r.fBottom);
it.next();
}
}
{
auto transaction = reinterpret_cast<SurfaceComposerClient::Transaction*>(transactionObj);
transaction->setTransparentRegionHint(ctrl, reg);
}
}
static void nativeSetAlpha(JNIEnv* env, jclass clazz, jlong transactionObj,
jlong nativeObject, jfloat alpha) {
auto transaction = reinterpret_cast<SurfaceComposerClient::Transaction*>(transactionObj);
SurfaceControl* const ctrl = reinterpret_cast<SurfaceControl *>(nativeObject);
transaction->setAlpha(ctrl, alpha);
}
static void nativeSetInputWindowInfo(JNIEnv* env, jclass clazz, jlong transactionObj,
jlong nativeObject, jobject inputWindow) {
auto transaction = reinterpret_cast<SurfaceComposerClient::Transaction*>(transactionObj);
sp<NativeInputWindowHandle> handle = android_view_InputWindowHandle_getHandle(
env, inputWindow);
handle->updateInfo();
SurfaceControl* const ctrl = reinterpret_cast<SurfaceControl *>(nativeObject);
transaction->setInputWindowInfo(ctrl, *handle->getInfo());
}
static void nativeTransferTouchFocus(JNIEnv* env, jclass clazz, jlong transactionObj,
jobject fromTokenObj, jobject toTokenObj) {
auto transaction = reinterpret_cast<SurfaceComposerClient::Transaction*>(transactionObj);
sp<IBinder> fromToken(ibinderForJavaObject(env, fromTokenObj));
sp<IBinder> toToken(ibinderForJavaObject(env, toTokenObj));
transaction->transferTouchFocus(fromToken, toToken);
}
static void nativeSyncInputWindows(JNIEnv* env, jclass clazz, jlong transactionObj) {
auto transaction = reinterpret_cast<SurfaceComposerClient::Transaction*>(transactionObj);
transaction->syncInputWindows();
}
static void nativeSetMetadata(JNIEnv* env, jclass clazz, jlong transactionObj,
jlong nativeObject, jint id, jobject parcelObj) {
Parcel* parcel = parcelForJavaObject(env, parcelObj);
if (!parcel) {
jniThrowNullPointerException(env, "attribute data");
return;
}
if (parcel->objectsCount()) {
jniThrowException(env, "java/lang/RuntimeException",
"Tried to marshall a Parcel that contained Binder objects.");
return;
}
auto transaction = reinterpret_cast<SurfaceComposerClient::Transaction*>(transactionObj);
std::vector<uint8_t> byteData(parcel->dataSize());
memcpy(byteData.data(), parcel->data(), parcel->dataSize());
SurfaceControl* const ctrl = reinterpret_cast<SurfaceControl*>(nativeObject);
transaction->setMetadata(ctrl, id, std::move(byteData));
}
static void nativeSetColor(JNIEnv* env, jclass clazz, jlong transactionObj,
jlong nativeObject, jfloatArray fColor) {
auto transaction = reinterpret_cast<SurfaceComposerClient::Transaction*>(transactionObj);
SurfaceControl* const ctrl = reinterpret_cast<SurfaceControl *>(nativeObject);
float* floatColors = env->GetFloatArrayElements(fColor, 0);
half3 color(floatColors[0], floatColors[1], floatColors[2]);
transaction->setColor(ctrl, color);
}
static void nativeSetMatrix(JNIEnv* env, jclass clazz, jlong transactionObj,
jlong nativeObject,
jfloat dsdx, jfloat dtdx, jfloat dtdy, jfloat dsdy) {
auto transaction = reinterpret_cast<SurfaceComposerClient::Transaction*>(transactionObj);
SurfaceControl* const ctrl = reinterpret_cast<SurfaceControl *>(nativeObject);
transaction->setMatrix(ctrl, dsdx, dtdx, dtdy, dsdy);
}
static void nativeSetColorTransform(JNIEnv* env, jclass clazz, jlong transactionObj,
jlong nativeObject, jfloatArray fMatrix, jfloatArray fTranslation) {
auto transaction = reinterpret_cast<SurfaceComposerClient::Transaction*>(transactionObj);
SurfaceControl* const surfaceControl = reinterpret_cast<SurfaceControl*>(nativeObject);
float* floatMatrix = env->GetFloatArrayElements(fMatrix, 0);
mat3 matrix(static_cast<float const*>(floatMatrix));
float* floatTranslation = env->GetFloatArrayElements(fTranslation, 0);
vec3 translation(floatTranslation[0], floatTranslation[1], floatTranslation[2]);
transaction->setColorTransform(surfaceControl, matrix, translation);
}
static void nativeSetColorSpaceAgnostic(JNIEnv* env, jclass clazz, jlong transactionObj,
jlong nativeObject, jboolean agnostic) {
auto transaction = reinterpret_cast<SurfaceComposerClient::Transaction*>(transactionObj);
SurfaceControl* const surfaceControl = reinterpret_cast<SurfaceControl*>(nativeObject);
transaction->setColorSpaceAgnostic(surfaceControl, agnostic);
}
static void nativeSetWindowCrop(JNIEnv* env, jclass clazz, jlong transactionObj,
jlong nativeObject,
jint l, jint t, jint r, jint b) {
auto transaction = reinterpret_cast<SurfaceComposerClient::Transaction*>(transactionObj);
SurfaceControl* const ctrl = reinterpret_cast<SurfaceControl *>(nativeObject);
Rect crop(l, t, r, b);
transaction->setCrop_legacy(ctrl, crop);
}
static void nativeSetCornerRadius(JNIEnv* env, jclass clazz, jlong transactionObj,
jlong nativeObject, jfloat cornerRadius) {
auto transaction = reinterpret_cast<SurfaceComposerClient::Transaction*>(transactionObj);
SurfaceControl* const ctrl = reinterpret_cast<SurfaceControl *>(nativeObject);
transaction->setCornerRadius(ctrl, cornerRadius);
}
static void nativeSetLayerStack(JNIEnv* env, jclass clazz, jlong transactionObj,
jlong nativeObject, jint layerStack) {
auto transaction = reinterpret_cast<SurfaceComposerClient::Transaction*>(transactionObj);
SurfaceControl* const ctrl = reinterpret_cast<SurfaceControl *>(nativeObject);
transaction->setLayerStack(ctrl, layerStack);
}
static jlongArray nativeGetPhysicalDisplayIds(JNIEnv* env, jclass clazz) {
const auto displayIds = SurfaceComposerClient::getPhysicalDisplayIds();
jlongArray array = env->NewLongArray(displayIds.size());
if (array == nullptr) {
jniThrowException(env, "java/lang/OutOfMemoryError", nullptr);
return nullptr;
}
if (displayIds.empty()) {
return array;
}
jlong* values = env->GetLongArrayElements(array, 0);
for (size_t i = 0; i < displayIds.size(); ++i) {
values[i] = static_cast<jlong>(displayIds[i]);
}
env->ReleaseLongArrayElements(array, values, 0);
return array;
}
static jobject nativeGetPhysicalDisplayToken(JNIEnv* env, jclass clazz, jlong physicalDisplayId) {
sp<IBinder> token = SurfaceComposerClient::getPhysicalDisplayToken(physicalDisplayId);
return javaObjectForIBinder(env, token);
}
static jobject nativeGetDisplayedContentSamplingAttributes(JNIEnv* env, jclass clazz,
jobject tokenObj) {
sp<IBinder> token(ibinderForJavaObject(env, tokenObj));
ui::PixelFormat format;
ui::Dataspace dataspace;
uint8_t componentMask;
status_t err = SurfaceComposerClient::getDisplayedContentSamplingAttributes(
token, &format, &dataspace, &componentMask);
if (err != OK) {
return nullptr;
}
return env->NewObject(gDisplayedContentSamplingAttributesClassInfo.clazz,
gDisplayedContentSamplingAttributesClassInfo.ctor,
format, dataspace, componentMask);
}
static jboolean nativeSetDisplayedContentSamplingEnabled(JNIEnv* env, jclass clazz,
jobject tokenObj, jboolean enable, jint componentMask, jint maxFrames) {
sp<IBinder> token(ibinderForJavaObject(env, tokenObj));
status_t rc = SurfaceComposerClient::setDisplayContentSamplingEnabled(
token, enable, componentMask, maxFrames);
return rc == OK;
}
static jobject nativeGetDisplayedContentSample(JNIEnv* env, jclass clazz, jobject tokenObj,
jlong maxFrames, jlong timestamp) {
sp<IBinder> token(ibinderForJavaObject(env, tokenObj));
DisplayedFrameStats stats;
status_t err = SurfaceComposerClient::getDisplayedContentSample(
token, maxFrames, timestamp, &stats);
if (err != OK) {
return nullptr;
}
jlongArray histogramComponent0 = env->NewLongArray(stats.component_0_sample.size());
jlongArray histogramComponent1 = env->NewLongArray(stats.component_1_sample.size());
jlongArray histogramComponent2 = env->NewLongArray(stats.component_2_sample.size());
jlongArray histogramComponent3 = env->NewLongArray(stats.component_3_sample.size());
if ((histogramComponent0 == nullptr) ||
(histogramComponent1 == nullptr) ||
(histogramComponent2 == nullptr) ||
(histogramComponent3 == nullptr)) {
return JNI_FALSE;
}
env->SetLongArrayRegion(histogramComponent0, 0,
stats.component_0_sample.size(),
reinterpret_cast<jlong*>(stats.component_0_sample.data()));
env->SetLongArrayRegion(histogramComponent1, 0,
stats.component_1_sample.size(),
reinterpret_cast<jlong*>(stats.component_1_sample.data()));
env->SetLongArrayRegion(histogramComponent2, 0,
stats.component_2_sample.size(),
reinterpret_cast<jlong*>(stats.component_2_sample.data()));
env->SetLongArrayRegion(histogramComponent3, 0,
stats.component_3_sample.size(),
reinterpret_cast<jlong*>(stats.component_3_sample.data()));
return env->NewObject(gDisplayedContentSampleClassInfo.clazz,
gDisplayedContentSampleClassInfo.ctor,
stats.numFrames,
histogramComponent0,
histogramComponent1,
histogramComponent2,
histogramComponent3);
}
static jobject nativeCreateDisplay(JNIEnv* env, jclass clazz, jstring nameObj,
jboolean secure) {
ScopedUtfChars name(env, nameObj);
sp<IBinder> token(SurfaceComposerClient::createDisplay(
String8(name.c_str()), bool(secure)));
return javaObjectForIBinder(env, token);
}
static void nativeDestroyDisplay(JNIEnv* env, jclass clazz, jobject tokenObj) {
sp<IBinder> token(ibinderForJavaObject(env, tokenObj));
if (token == NULL) return;
SurfaceComposerClient::destroyDisplay(token);
}
static void nativeSetDisplaySurface(JNIEnv* env, jclass clazz,
jlong transactionObj,
jobject tokenObj, jlong nativeSurfaceObject) {
sp<IBinder> token(ibinderForJavaObject(env, tokenObj));
if (token == NULL) return;
sp<IGraphicBufferProducer> bufferProducer;
sp<Surface> sur(reinterpret_cast<Surface *>(nativeSurfaceObject));
if (sur != NULL) {
bufferProducer = sur->getIGraphicBufferProducer();
}
status_t err = NO_ERROR;
{
auto transaction = reinterpret_cast<SurfaceComposerClient::Transaction*>(transactionObj);
err = transaction->setDisplaySurface(token,
bufferProducer);
}
if (err != NO_ERROR) {
doThrowIAE(env, "Illegal Surface, could not enable async mode. Was this"
" Surface created with singleBufferMode?");
}
}
static void nativeSetDisplayLayerStack(JNIEnv* env, jclass clazz,
jlong transactionObj,
jobject tokenObj, jint layerStack) {
sp<IBinder> token(ibinderForJavaObject(env, tokenObj));
if (token == NULL) return;
{
auto transaction = reinterpret_cast<SurfaceComposerClient::Transaction*>(transactionObj);
transaction->setDisplayLayerStack(token, layerStack);
}
}
static void nativeSetDisplayProjection(JNIEnv* env, jclass clazz,
jlong transactionObj,
jobject tokenObj, jint orientation,
jint layerStackRect_left, jint layerStackRect_top, jint layerStackRect_right, jint layerStackRect_bottom,
jint displayRect_left, jint displayRect_top, jint displayRect_right, jint displayRect_bottom) {
sp<IBinder> token(ibinderForJavaObject(env, tokenObj));
if (token == NULL) return;
Rect layerStackRect(layerStackRect_left, layerStackRect_top, layerStackRect_right, layerStackRect_bottom);
Rect displayRect(displayRect_left, displayRect_top, displayRect_right, displayRect_bottom);
{
auto transaction = reinterpret_cast<SurfaceComposerClient::Transaction*>(transactionObj);
transaction->setDisplayProjection(token, orientation, layerStackRect, displayRect);
}
}
static void nativeSetDisplaySize(JNIEnv* env, jclass clazz,
jlong transactionObj,
jobject tokenObj, jint width, jint height) {
sp<IBinder> token(ibinderForJavaObject(env, tokenObj));
if (token == NULL) return;
{
auto transaction = reinterpret_cast<SurfaceComposerClient::Transaction*>(transactionObj);
transaction->setDisplaySize(token, width, height);
}
}
static jobjectArray nativeGetDisplayConfigs(JNIEnv* env, jclass clazz,
jobject tokenObj) {
sp<IBinder> token(ibinderForJavaObject(env, tokenObj));
if (token == NULL) return NULL;
Vector<DisplayInfo> configs;
if (SurfaceComposerClient::getDisplayConfigs(token, &configs) != NO_ERROR ||
configs.size() == 0) {
return NULL;
}
jobjectArray configArray = env->NewObjectArray(configs.size(),
gPhysicalDisplayInfoClassInfo.clazz, NULL);
for (size_t c = 0; c < configs.size(); ++c) {
const DisplayInfo& info = configs[c];
jobject infoObj = env->NewObject(gPhysicalDisplayInfoClassInfo.clazz,
gPhysicalDisplayInfoClassInfo.ctor);
env->SetIntField(infoObj, gPhysicalDisplayInfoClassInfo.width, info.w);
env->SetIntField(infoObj, gPhysicalDisplayInfoClassInfo.height, info.h);
env->SetFloatField(infoObj, gPhysicalDisplayInfoClassInfo.refreshRate, info.fps);
env->SetFloatField(infoObj, gPhysicalDisplayInfoClassInfo.density, info.density);
env->SetFloatField(infoObj, gPhysicalDisplayInfoClassInfo.xDpi, info.xdpi);
env->SetFloatField(infoObj, gPhysicalDisplayInfoClassInfo.yDpi, info.ydpi);
env->SetBooleanField(infoObj, gPhysicalDisplayInfoClassInfo.secure, info.secure);
env->SetLongField(infoObj, gPhysicalDisplayInfoClassInfo.appVsyncOffsetNanos,
info.appVsyncOffset);
env->SetLongField(infoObj, gPhysicalDisplayInfoClassInfo.presentationDeadlineNanos,
info.presentationDeadline);
env->SetObjectArrayElement(configArray, static_cast<jsize>(c), infoObj);
env->DeleteLocalRef(infoObj);
}
return configArray;
}
static jboolean nativeSetAllowedDisplayConfigs(JNIEnv* env, jclass clazz,
jobject tokenObj, jintArray configArray) {
sp<IBinder> token(ibinderForJavaObject(env, tokenObj));
if (token == nullptr) return JNI_FALSE;
std::vector<int32_t> allowedConfigs;
jsize configArraySize = env->GetArrayLength(configArray);
allowedConfigs.reserve(configArraySize);
jint* configArrayElements = env->GetIntArrayElements(configArray, 0);
for (int i = 0; i < configArraySize; i++) {
allowedConfigs.push_back(configArrayElements[i]);
}
env->ReleaseIntArrayElements(configArray, configArrayElements, 0);
size_t result = SurfaceComposerClient::setAllowedDisplayConfigs(token, allowedConfigs);
return result == NO_ERROR ? JNI_TRUE : JNI_FALSE;
}
static jintArray nativeGetAllowedDisplayConfigs(JNIEnv* env, jclass clazz, jobject tokenObj) {
sp<IBinder> token(ibinderForJavaObject(env, tokenObj));
if (token == nullptr) return JNI_FALSE;
std::vector<int32_t> allowedConfigs;
size_t result = SurfaceComposerClient::getAllowedDisplayConfigs(token, &allowedConfigs);
if (result != NO_ERROR) {
return nullptr;
}
jintArray allowedConfigsArray = env->NewIntArray(allowedConfigs.size());
if (allowedConfigsArray == nullptr) {
jniThrowException(env, "java/lang/OutOfMemoryError", NULL);
return nullptr;
}
jint* allowedConfigsArrayValues = env->GetIntArrayElements(allowedConfigsArray, 0);
for (size_t i = 0; i < allowedConfigs.size(); i++) {
allowedConfigsArrayValues[i] = static_cast<jint>(allowedConfigs[i]);
}
env->ReleaseIntArrayElements(allowedConfigsArray, allowedConfigsArrayValues, 0);
return allowedConfigsArray;
}
static jint nativeGetActiveConfig(JNIEnv* env, jclass clazz, jobject tokenObj) {
sp<IBinder> token(ibinderForJavaObject(env, tokenObj));
if (token == NULL) return -1;
return static_cast<jint>(SurfaceComposerClient::getActiveConfig(token));
}
static jboolean nativeSetActiveConfig(JNIEnv* env, jclass clazz, jobject tokenObj, jint id) {
sp<IBinder> token(ibinderForJavaObject(env, tokenObj));
if (token == NULL) return JNI_FALSE;
status_t err = SurfaceComposerClient::setActiveConfig(token, static_cast<int>(id));
return err == NO_ERROR ? JNI_TRUE : JNI_FALSE;
}
static jintArray nativeGetDisplayColorModes(JNIEnv* env, jclass, jobject tokenObj) {
sp<IBinder> token(ibinderForJavaObject(env, tokenObj));
if (token == NULL) return NULL;
Vector<ui::ColorMode> colorModes;
if (SurfaceComposerClient::getDisplayColorModes(token, &colorModes) != NO_ERROR ||
colorModes.isEmpty()) {
return NULL;
}
jintArray colorModesArray = env->NewIntArray(colorModes.size());
if (colorModesArray == NULL) {
jniThrowException(env, "java/lang/OutOfMemoryError", NULL);
return NULL;
}
jint* colorModesArrayValues = env->GetIntArrayElements(colorModesArray, 0);
for (size_t i = 0; i < colorModes.size(); i++) {
colorModesArrayValues[i] = static_cast<jint>(colorModes[i]);
}
env->ReleaseIntArrayElements(colorModesArray, colorModesArrayValues, 0);
return colorModesArray;
}
static jobject nativeGetDisplayNativePrimaries(JNIEnv* env, jclass, jobject tokenObj) {
sp<IBinder> token(ibinderForJavaObject(env, tokenObj));
if (token == NULL) return NULL;
ui::DisplayPrimaries primaries;
if (SurfaceComposerClient::getDisplayNativePrimaries(token, primaries) != NO_ERROR) {
return NULL;
}
jobject jred = env->NewObject(gCieXyzClassInfo.clazz, gCieXyzClassInfo.ctor);
if (jred == NULL) {
jniThrowException(env, "java/lang/OutOfMemoryError", NULL);
return NULL;
}
jobject jgreen = env->NewObject(gCieXyzClassInfo.clazz, gCieXyzClassInfo.ctor);
if (jgreen == NULL) {
jniThrowException(env, "java/lang/OutOfMemoryError", NULL);
return NULL;
}
jobject jblue = env->NewObject(gCieXyzClassInfo.clazz, gCieXyzClassInfo.ctor);
if (jblue == NULL) {
jniThrowException(env, "java/lang/OutOfMemoryError", NULL);
return NULL;
}
jobject jwhite = env->NewObject(gCieXyzClassInfo.clazz, gCieXyzClassInfo.ctor);
if (jwhite == NULL) {
jniThrowException(env, "java/lang/OutOfMemoryError", NULL);
return NULL;
}
jobject jprimaries = env->NewObject(gDisplayPrimariesClassInfo.clazz,
gDisplayPrimariesClassInfo.ctor);
if (jprimaries == NULL) {
jniThrowException(env, "java/lang/OutOfMemoryError", NULL);
return NULL;
}
env->SetFloatField(jred, gCieXyzClassInfo.X, primaries.red.X);
env->SetFloatField(jred, gCieXyzClassInfo.Y, primaries.red.Y);
env->SetFloatField(jred, gCieXyzClassInfo.Z, primaries.red.Z);
env->SetFloatField(jgreen, gCieXyzClassInfo.X, primaries.green.X);
env->SetFloatField(jgreen, gCieXyzClassInfo.Y, primaries.green.Y);
env->SetFloatField(jgreen, gCieXyzClassInfo.Z, primaries.green.Z);
env->SetFloatField(jblue, gCieXyzClassInfo.X, primaries.blue.X);
env->SetFloatField(jblue, gCieXyzClassInfo.Y, primaries.blue.Y);
env->SetFloatField(jblue, gCieXyzClassInfo.Z, primaries.blue.Z);
env->SetFloatField(jwhite, gCieXyzClassInfo.X, primaries.white.X);
env->SetFloatField(jwhite, gCieXyzClassInfo.Y, primaries.white.Y);
env->SetFloatField(jwhite, gCieXyzClassInfo.Z, primaries.white.Z);
env->SetObjectField(jprimaries, gDisplayPrimariesClassInfo.red, jred);
env->SetObjectField(jprimaries, gDisplayPrimariesClassInfo.green, jgreen);
env->SetObjectField(jprimaries, gDisplayPrimariesClassInfo.blue, jblue);
env->SetObjectField(jprimaries, gDisplayPrimariesClassInfo.white, jwhite);
return jprimaries;
}
static jint nativeGetActiveColorMode(JNIEnv* env, jclass, jobject tokenObj) {
sp<IBinder> token(ibinderForJavaObject(env, tokenObj));
if (token == NULL) return -1;
return static_cast<jint>(SurfaceComposerClient::getActiveColorMode(token));
}
static jintArray nativeGetCompositionDataspaces(JNIEnv* env, jclass) {
ui::Dataspace defaultDataspace, wcgDataspace;
ui::PixelFormat defaultPixelFormat, wcgPixelFormat;
if (SurfaceComposerClient::getCompositionPreference(&defaultDataspace,
&defaultPixelFormat,
&wcgDataspace,
&wcgPixelFormat) != NO_ERROR) {
return nullptr;
}
jintArray array = env->NewIntArray(2);
if (array == nullptr) {
jniThrowException(env, "java/lang/OutOfMemoryError", nullptr);
return nullptr;
}
jint* arrayValues = env->GetIntArrayElements(array, 0);
arrayValues[0] = static_cast<jint>(defaultDataspace);
arrayValues[1] = static_cast<jint>(wcgDataspace);
env->ReleaseIntArrayElements(array, arrayValues, 0);
return array;
}
static jboolean nativeSetActiveColorMode(JNIEnv* env, jclass,
jobject tokenObj, jint colorMode) {
sp<IBinder> token(ibinderForJavaObject(env, tokenObj));
if (token == NULL) return JNI_FALSE;
status_t err = SurfaceComposerClient::setActiveColorMode(token,
static_cast<ui::ColorMode>(colorMode));
return err == NO_ERROR ? JNI_TRUE : JNI_FALSE;
}
static void nativeSetDisplayPowerMode(JNIEnv* env, jclass clazz, jobject tokenObj, jint mode) {
sp<IBinder> token(ibinderForJavaObject(env, tokenObj));
if (token == NULL) return;
android::base::Timer t;
SurfaceComposerClient::setDisplayPowerMode(token, mode);
if (t.duration() > 100ms) ALOGD("Excessive delay in setPowerMode()");
}
static jboolean nativeGetProtectedContentSupport(JNIEnv* env, jclass) {
return static_cast<jboolean>(SurfaceComposerClient::getProtectedContentSupport());
}
static jboolean nativeClearContentFrameStats(JNIEnv* env, jclass clazz, jlong nativeObject) {
SurfaceControl* const ctrl = reinterpret_cast<SurfaceControl *>(nativeObject);
status_t err = ctrl->clearLayerFrameStats();
if (err < 0 && err != NO_INIT) {
doThrowIAE(env);
}
// The other end is not ready, just report we failed.
if (err == NO_INIT) {
return JNI_FALSE;
}
return JNI_TRUE;
}
static jboolean nativeGetContentFrameStats(JNIEnv* env, jclass clazz, jlong nativeObject,
jobject outStats) {
FrameStats stats;
SurfaceControl* const ctrl = reinterpret_cast<SurfaceControl *>(nativeObject);
status_t err = ctrl->getLayerFrameStats(&stats);
if (err < 0 && err != NO_INIT) {
doThrowIAE(env);
}
// The other end is not ready, fine just return empty stats.
if (err == NO_INIT) {
return JNI_FALSE;
}
jlong refreshPeriodNano = static_cast<jlong>(stats.refreshPeriodNano);
size_t frameCount = stats.desiredPresentTimesNano.size();
jlongArray postedTimesNanoDst = env->NewLongArray(frameCount);
if (postedTimesNanoDst == NULL) {
return JNI_FALSE;
}
jlongArray presentedTimesNanoDst = env->NewLongArray(frameCount);
if (presentedTimesNanoDst == NULL) {
return JNI_FALSE;
}
jlongArray readyTimesNanoDst = env->NewLongArray(frameCount);
if (readyTimesNanoDst == NULL) {
return JNI_FALSE;
}
nsecs_t postedTimesNanoSrc[frameCount];
nsecs_t presentedTimesNanoSrc[frameCount];
nsecs_t readyTimesNanoSrc[frameCount];
for (size_t i = 0; i < frameCount; i++) {
nsecs_t postedTimeNano = stats.desiredPresentTimesNano[i];
if (postedTimeNano == INT64_MAX) {
postedTimeNano = gWindowContentFrameStatsClassInfo.UNDEFINED_TIME_NANO;
}
postedTimesNanoSrc[i] = postedTimeNano;
nsecs_t presentedTimeNano = stats.actualPresentTimesNano[i];
if (presentedTimeNano == INT64_MAX) {
presentedTimeNano = gWindowContentFrameStatsClassInfo.UNDEFINED_TIME_NANO;
}
presentedTimesNanoSrc[i] = presentedTimeNano;
nsecs_t readyTimeNano = stats.frameReadyTimesNano[i];
if (readyTimeNano == INT64_MAX) {
readyTimeNano = gWindowContentFrameStatsClassInfo.UNDEFINED_TIME_NANO;
}
readyTimesNanoSrc[i] = readyTimeNano;
}
env->SetLongArrayRegion(postedTimesNanoDst, 0, frameCount, postedTimesNanoSrc);
env->SetLongArrayRegion(presentedTimesNanoDst, 0, frameCount, presentedTimesNanoSrc);
env->SetLongArrayRegion(readyTimesNanoDst, 0, frameCount, readyTimesNanoSrc);
env->CallVoidMethod(outStats, gWindowContentFrameStatsClassInfo.init, refreshPeriodNano,
postedTimesNanoDst, presentedTimesNanoDst, readyTimesNanoDst);
if (env->ExceptionCheck()) {
return JNI_FALSE;
}
return JNI_TRUE;
}
static jboolean nativeClearAnimationFrameStats(JNIEnv* env, jclass clazz) {
status_t err = SurfaceComposerClient::clearAnimationFrameStats();
if (err < 0 && err != NO_INIT) {
doThrowIAE(env);
}
// The other end is not ready, just report we failed.
if (err == NO_INIT) {
return JNI_FALSE;
}
return JNI_TRUE;
}
static jboolean nativeGetAnimationFrameStats(JNIEnv* env, jclass clazz, jobject outStats) {
FrameStats stats;
status_t err = SurfaceComposerClient::getAnimationFrameStats(&stats);
if (err < 0 && err != NO_INIT) {
doThrowIAE(env);
}
// The other end is not ready, fine just return empty stats.
if (err == NO_INIT) {
return JNI_FALSE;
}
jlong refreshPeriodNano = static_cast<jlong>(stats.refreshPeriodNano);
size_t frameCount = stats.desiredPresentTimesNano.size();
jlongArray presentedTimesNanoDst = env->NewLongArray(frameCount);
if (presentedTimesNanoDst == NULL) {
return JNI_FALSE;
}
nsecs_t presentedTimesNanoSrc[frameCount];
for (size_t i = 0; i < frameCount; i++) {
nsecs_t presentedTimeNano = stats.actualPresentTimesNano[i];
if (presentedTimeNano == INT64_MAX) {
presentedTimeNano = gWindowContentFrameStatsClassInfo.UNDEFINED_TIME_NANO;
}
presentedTimesNanoSrc[i] = presentedTimeNano;
}
env->SetLongArrayRegion(presentedTimesNanoDst, 0, frameCount, presentedTimesNanoSrc);
env->CallVoidMethod(outStats, gWindowAnimationFrameStatsClassInfo.init, refreshPeriodNano,
presentedTimesNanoDst);
if (env->ExceptionCheck()) {
return JNI_FALSE;
}
return JNI_TRUE;
}
static void nativeDeferTransactionUntil(JNIEnv* env, jclass clazz, jlong transactionObj,
jlong nativeObject,
jobject handleObject, jlong frameNumber) {
auto ctrl = reinterpret_cast<SurfaceControl *>(nativeObject);
sp<IBinder> handle = ibinderForJavaObject(env, handleObject);
{
auto transaction = reinterpret_cast<SurfaceComposerClient::Transaction*>(transactionObj);
transaction->deferTransactionUntil_legacy(ctrl, handle, frameNumber);
}
}
static void nativeDeferTransactionUntilSurface(JNIEnv* env, jclass clazz, jlong transactionObj,
jlong nativeObject,
jlong surfaceObject, jlong frameNumber) {
auto transaction = reinterpret_cast<SurfaceComposerClient::Transaction*>(transactionObj);
auto ctrl = reinterpret_cast<SurfaceControl *>(nativeObject);
sp<Surface> barrier = reinterpret_cast<Surface *>(surfaceObject);
transaction->deferTransactionUntil_legacy(ctrl, barrier, frameNumber);
}
static void nativeReparentChildren(JNIEnv* env, jclass clazz, jlong transactionObj,
jlong nativeObject,
jobject newParentObject) {
auto ctrl = reinterpret_cast<SurfaceControl *>(nativeObject);
sp<IBinder> handle = ibinderForJavaObject(env, newParentObject);
{
auto transaction = reinterpret_cast<SurfaceComposerClient::Transaction*>(transactionObj);
transaction->reparentChildren(ctrl, handle);
}
}
static void nativeReparent(JNIEnv* env, jclass clazz, jlong transactionObj,
jlong nativeObject,
jlong newParentObject) {
auto ctrl = reinterpret_cast<SurfaceControl *>(nativeObject);
auto newParent = reinterpret_cast<SurfaceControl *>(newParentObject);
{
auto transaction = reinterpret_cast<SurfaceComposerClient::Transaction*>(transactionObj);
transaction->reparent(ctrl, newParent != NULL ? newParent->getHandle() : NULL);
}
}
static void nativeSeverChildren(JNIEnv* env, jclass clazz, jlong transactionObj,
jlong nativeObject) {
auto transaction = reinterpret_cast<SurfaceComposerClient::Transaction*>(transactionObj);
auto ctrl = reinterpret_cast<SurfaceControl *>(nativeObject);
transaction->detachChildren(ctrl);
}
static void nativeSetOverrideScalingMode(JNIEnv* env, jclass clazz, jlong transactionObj,
jlong nativeObject,
jint scalingMode) {
auto transaction = reinterpret_cast<SurfaceComposerClient::Transaction*>(transactionObj);
auto ctrl = reinterpret_cast<SurfaceControl *>(nativeObject);
transaction->setOverrideScalingMode(ctrl, scalingMode);
}
static jobject nativeGetHandle(JNIEnv* env, jclass clazz, jlong nativeObject) {
auto ctrl = reinterpret_cast<SurfaceControl *>(nativeObject);
return javaObjectForIBinder(env, ctrl->getHandle());
}
static jobject nativeGetHdrCapabilities(JNIEnv* env, jclass clazz, jobject tokenObject) {
sp<IBinder> token(ibinderForJavaObject(env, tokenObject));
if (token == NULL) return NULL;
HdrCapabilities capabilities;
SurfaceComposerClient::getHdrCapabilities(token, &capabilities);
const auto& types = capabilities.getSupportedHdrTypes();
std::vector<int32_t> intTypes;
for (auto type : types) {
intTypes.push_back(static_cast<int32_t>(type));
}
auto typesArray = env->NewIntArray(types.size());
env->SetIntArrayRegion(typesArray, 0, intTypes.size(), intTypes.data());
return env->NewObject(gHdrCapabilitiesClassInfo.clazz, gHdrCapabilitiesClassInfo.ctor,
typesArray, capabilities.getDesiredMaxLuminance(),
capabilities.getDesiredMaxAverageLuminance(), capabilities.getDesiredMinLuminance());
}
static jlong nativeReadFromParcel(JNIEnv* env, jclass clazz, jobject parcelObj) {
Parcel* parcel = parcelForJavaObject(env, parcelObj);
if (parcel == NULL) {
doThrowNPE(env);
return 0;
}
sp<SurfaceControl> surface = SurfaceControl::readFromParcel(parcel);
if (surface == nullptr) {
return 0;
}
surface->incStrong((void *)nativeCreate);
return reinterpret_cast<jlong>(surface.get());
}
static jlong nativeCopyFromSurfaceControl(JNIEnv* env, jclass clazz, jlong surfaceControlNativeObj) {
sp<SurfaceControl> surface(reinterpret_cast<SurfaceControl *>(surfaceControlNativeObj));
if (surface == nullptr) {
return 0;
}
sp<SurfaceControl> newSurface = new SurfaceControl(surface);
newSurface->incStrong((void *)nativeCreate);
return reinterpret_cast<jlong>(newSurface.get());
}
static void nativeWriteToParcel(JNIEnv* env, jclass clazz,
jlong nativeObject, jobject parcelObj) {
Parcel* parcel = parcelForJavaObject(env, parcelObj);
if (parcel == NULL) {
doThrowNPE(env);
return;
}
SurfaceControl* const self = reinterpret_cast<SurfaceControl *>(nativeObject);
if (self != nullptr) {
self->writeToParcel(parcel);
}
}
static jboolean nativeGetDisplayBrightnessSupport(JNIEnv* env, jclass clazz,
jobject displayTokenObject) {
sp<IBinder> displayToken(ibinderForJavaObject(env, displayTokenObject));
if (displayToken == nullptr) {
return JNI_FALSE;
}
return static_cast<jboolean>(SurfaceComposerClient::getDisplayBrightnessSupport(displayToken));
}
static jboolean nativeSetDisplayBrightness(JNIEnv* env, jclass clazz, jobject displayTokenObject,
jfloat brightness) {
sp<IBinder> displayToken(ibinderForJavaObject(env, displayTokenObject));
if (displayToken == nullptr) {
return JNI_FALSE;
}
status_t error = SurfaceComposerClient::setDisplayBrightness(displayToken, brightness);
return error == OK ? JNI_TRUE : JNI_FALSE;
}
// ----------------------------------------------------------------------------
static const JNINativeMethod sSurfaceControlMethods[] = {
{"nativeCreate", "(Landroid/view/SurfaceSession;Ljava/lang/String;IIIIJLandroid/os/Parcel;)J",
(void*)nativeCreate },
{"nativeReadFromParcel", "(Landroid/os/Parcel;)J",
(void*)nativeReadFromParcel },
{"nativeCopyFromSurfaceControl", "(J)J" ,
(void*)nativeCopyFromSurfaceControl },
{"nativeWriteToParcel", "(JLandroid/os/Parcel;)V",
(void*)nativeWriteToParcel },
{"nativeRelease", "(J)V",
(void*)nativeRelease },
{"nativeDestroy", "(J)V",
(void*)nativeDestroy },
{"nativeDisconnect", "(J)V",
(void*)nativeDisconnect },
{"nativeCreateTransaction", "()J",
(void*)nativeCreateTransaction },
{"nativeApplyTransaction", "(JZ)V",
(void*)nativeApplyTransaction },
{"nativeGetNativeTransactionFinalizer", "()J",
(void*)nativeGetNativeTransactionFinalizer },
{"nativeMergeTransaction", "(JJ)V",
(void*)nativeMergeTransaction },
{"nativeSetAnimationTransaction", "(J)V",
(void*)nativeSetAnimationTransaction },
{"nativeSetEarlyWakeup", "(J)V",
(void*)nativeSetEarlyWakeup },
{"nativeSetLayer", "(JJI)V",
(void*)nativeSetLayer },
{"nativeSetRelativeLayer", "(JJLandroid/os/IBinder;I)V",
(void*)nativeSetRelativeLayer },
{"nativeSetPosition", "(JJFF)V",
(void*)nativeSetPosition },
{"nativeSetGeometryAppliesWithResize", "(JJ)V",
(void*)nativeSetGeometryAppliesWithResize },
{"nativeSetSize", "(JJII)V",
(void*)nativeSetSize },
{"nativeSetTransparentRegionHint", "(JJLandroid/graphics/Region;)V",
(void*)nativeSetTransparentRegionHint },
{"nativeSetAlpha", "(JJF)V",
(void*)nativeSetAlpha },
{"nativeSetColor", "(JJ[F)V",
(void*)nativeSetColor },
{"nativeSetMatrix", "(JJFFFF)V",
(void*)nativeSetMatrix },
{"nativeSetColorTransform", "(JJ[F[F)V",
(void*)nativeSetColorTransform },
{"nativeSetColorSpaceAgnostic", "(JJZ)V",
(void*)nativeSetColorSpaceAgnostic },
{"nativeSetFlags", "(JJII)V",
(void*)nativeSetFlags },
{"nativeSetWindowCrop", "(JJIIII)V",
(void*)nativeSetWindowCrop },
{"nativeSetCornerRadius", "(JJF)V",
(void*)nativeSetCornerRadius },
{"nativeSetLayerStack", "(JJI)V",
(void*)nativeSetLayerStack },
{"nativeGetPhysicalDisplayIds", "()[J",
(void*)nativeGetPhysicalDisplayIds },
{"nativeGetPhysicalDisplayToken", "(J)Landroid/os/IBinder;",
(void*)nativeGetPhysicalDisplayToken },
{"nativeCreateDisplay", "(Ljava/lang/String;Z)Landroid/os/IBinder;",
(void*)nativeCreateDisplay },
{"nativeDestroyDisplay", "(Landroid/os/IBinder;)V",
(void*)nativeDestroyDisplay },
{"nativeSetDisplaySurface", "(JLandroid/os/IBinder;J)V",
(void*)nativeSetDisplaySurface },
{"nativeSetDisplayLayerStack", "(JLandroid/os/IBinder;I)V",
(void*)nativeSetDisplayLayerStack },
{"nativeSetDisplayProjection", "(JLandroid/os/IBinder;IIIIIIIII)V",
(void*)nativeSetDisplayProjection },
{"nativeSetDisplaySize", "(JLandroid/os/IBinder;II)V",
(void*)nativeSetDisplaySize },
{"nativeGetDisplayConfigs", "(Landroid/os/IBinder;)[Landroid/view/SurfaceControl$PhysicalDisplayInfo;",
(void*)nativeGetDisplayConfigs },
{"nativeGetActiveConfig", "(Landroid/os/IBinder;)I",
(void*)nativeGetActiveConfig },
{"nativeSetActiveConfig", "(Landroid/os/IBinder;I)Z",
(void*)nativeSetActiveConfig },
{"nativeSetAllowedDisplayConfigs", "(Landroid/os/IBinder;[I)Z",
(void*)nativeSetAllowedDisplayConfigs },
{"nativeGetAllowedDisplayConfigs", "(Landroid/os/IBinder;)[I",
(void*)nativeGetAllowedDisplayConfigs },
{"nativeGetDisplayColorModes", "(Landroid/os/IBinder;)[I",
(void*)nativeGetDisplayColorModes},
{"nativeGetDisplayNativePrimaries", "(Landroid/os/IBinder;)Landroid/view/SurfaceControl$DisplayPrimaries;",
(void*)nativeGetDisplayNativePrimaries },
{"nativeGetActiveColorMode", "(Landroid/os/IBinder;)I",
(void*)nativeGetActiveColorMode},
{"nativeSetActiveColorMode", "(Landroid/os/IBinder;I)Z",
(void*)nativeSetActiveColorMode},
{"nativeGetCompositionDataspaces", "()[I",
(void*)nativeGetCompositionDataspaces},
{"nativeGetHdrCapabilities", "(Landroid/os/IBinder;)Landroid/view/Display$HdrCapabilities;",
(void*)nativeGetHdrCapabilities },
{"nativeClearContentFrameStats", "(J)Z",
(void*)nativeClearContentFrameStats },
{"nativeGetContentFrameStats", "(JLandroid/view/WindowContentFrameStats;)Z",
(void*)nativeGetContentFrameStats },
{"nativeClearAnimationFrameStats", "()Z",
(void*)nativeClearAnimationFrameStats },
{"nativeGetAnimationFrameStats", "(Landroid/view/WindowAnimationFrameStats;)Z",
(void*)nativeGetAnimationFrameStats },
{"nativeSetDisplayPowerMode", "(Landroid/os/IBinder;I)V",
(void*)nativeSetDisplayPowerMode },
{"nativeGetProtectedContentSupport", "()Z",
(void*)nativeGetProtectedContentSupport },
{"nativeDeferTransactionUntil", "(JJLandroid/os/IBinder;J)V",
(void*)nativeDeferTransactionUntil },
{"nativeDeferTransactionUntilSurface", "(JJJJ)V",
(void*)nativeDeferTransactionUntilSurface },
{"nativeReparentChildren", "(JJLandroid/os/IBinder;)V",
(void*)nativeReparentChildren } ,
{"nativeReparent", "(JJJ)V",
(void*)nativeReparent },
{"nativeSeverChildren", "(JJ)V",
(void*)nativeSeverChildren } ,
{"nativeSetOverrideScalingMode", "(JJI)V",
(void*)nativeSetOverrideScalingMode },
{"nativeGetHandle", "(J)Landroid/os/IBinder;",
(void*)nativeGetHandle },
{"nativeScreenshot",
"(Landroid/os/IBinder;Landroid/graphics/Rect;IIZIZ)"
"Landroid/view/SurfaceControl$ScreenshotGraphicBuffer;",
(void*)nativeScreenshot },
{"nativeCaptureLayers",
"(Landroid/os/IBinder;Landroid/os/IBinder;Landroid/graphics/Rect;"
"F[Landroid/os/IBinder;)"
"Landroid/view/SurfaceControl$ScreenshotGraphicBuffer;",
(void*)nativeCaptureLayers },
{"nativeSetInputWindowInfo", "(JJLandroid/view/InputWindowHandle;)V",
(void*)nativeSetInputWindowInfo },
{"nativeTransferTouchFocus", "(JLandroid/os/IBinder;Landroid/os/IBinder;)V",
(void*)nativeTransferTouchFocus },
{"nativeSetMetadata", "(JJILandroid/os/Parcel;)V",
(void*)nativeSetMetadata },
{"nativeGetDisplayedContentSamplingAttributes",
"(Landroid/os/IBinder;)Landroid/hardware/display/DisplayedContentSamplingAttributes;",
(void*)nativeGetDisplayedContentSamplingAttributes },
{"nativeSetDisplayedContentSamplingEnabled", "(Landroid/os/IBinder;ZII)Z",
(void*)nativeSetDisplayedContentSamplingEnabled },
{"nativeGetDisplayedContentSample",
"(Landroid/os/IBinder;JJ)Landroid/hardware/display/DisplayedContentSample;",
(void*)nativeGetDisplayedContentSample },
{"nativeSetGeometry", "(JJLandroid/graphics/Rect;Landroid/graphics/Rect;J)V",
(void*)nativeSetGeometry },
{"nativeSyncInputWindows", "(J)V",
(void*)nativeSyncInputWindows },
{"nativeGetDisplayBrightnessSupport", "(Landroid/os/IBinder;)Z",
(void*)nativeGetDisplayBrightnessSupport },
{"nativeSetDisplayBrightness", "(Landroid/os/IBinder;F)Z",
(void*)nativeSetDisplayBrightness },
};
int register_android_view_SurfaceControl(JNIEnv* env)
{
int err = RegisterMethodsOrDie(env, "android/view/SurfaceControl",
sSurfaceControlMethods, NELEM(sSurfaceControlMethods));
jclass clazz = FindClassOrDie(env, "android/view/SurfaceControl$PhysicalDisplayInfo");
gPhysicalDisplayInfoClassInfo.clazz = MakeGlobalRefOrDie(env, clazz);
gPhysicalDisplayInfoClassInfo.ctor = GetMethodIDOrDie(env,
gPhysicalDisplayInfoClassInfo.clazz, "<init>", "()V");
gPhysicalDisplayInfoClassInfo.width = GetFieldIDOrDie(env, clazz, "width", "I");
gPhysicalDisplayInfoClassInfo.height = GetFieldIDOrDie(env, clazz, "height", "I");
gPhysicalDisplayInfoClassInfo.refreshRate = GetFieldIDOrDie(env, clazz, "refreshRate", "F");
gPhysicalDisplayInfoClassInfo.density = GetFieldIDOrDie(env, clazz, "density", "F");
gPhysicalDisplayInfoClassInfo.xDpi = GetFieldIDOrDie(env, clazz, "xDpi", "F");
gPhysicalDisplayInfoClassInfo.yDpi = GetFieldIDOrDie(env, clazz, "yDpi", "F");
gPhysicalDisplayInfoClassInfo.secure = GetFieldIDOrDie(env, clazz, "secure", "Z");
gPhysicalDisplayInfoClassInfo.appVsyncOffsetNanos = GetFieldIDOrDie(env,
clazz, "appVsyncOffsetNanos", "J");
gPhysicalDisplayInfoClassInfo.presentationDeadlineNanos = GetFieldIDOrDie(env,
clazz, "presentationDeadlineNanos", "J");
jclass rectClazz = FindClassOrDie(env, "android/graphics/Rect");
gRectClassInfo.bottom = GetFieldIDOrDie(env, rectClazz, "bottom", "I");
gRectClassInfo.left = GetFieldIDOrDie(env, rectClazz, "left", "I");
gRectClassInfo.right = GetFieldIDOrDie(env, rectClazz, "right", "I");
gRectClassInfo.top = GetFieldIDOrDie(env, rectClazz, "top", "I");
jclass frameStatsClazz = FindClassOrDie(env, "android/view/FrameStats");
jfieldID undefined_time_nano_field = GetStaticFieldIDOrDie(env,
frameStatsClazz, "UNDEFINED_TIME_NANO", "J");
nsecs_t undefined_time_nano = env->GetStaticLongField(frameStatsClazz, undefined_time_nano_field);
jclass contFrameStatsClazz = FindClassOrDie(env, "android/view/WindowContentFrameStats");
gWindowContentFrameStatsClassInfo.init = GetMethodIDOrDie(env,
contFrameStatsClazz, "init", "(J[J[J[J)V");
gWindowContentFrameStatsClassInfo.UNDEFINED_TIME_NANO = undefined_time_nano;
jclass animFrameStatsClazz = FindClassOrDie(env, "android/view/WindowAnimationFrameStats");
gWindowAnimationFrameStatsClassInfo.init = GetMethodIDOrDie(env,
animFrameStatsClazz, "init", "(J[J)V");
gWindowAnimationFrameStatsClassInfo.UNDEFINED_TIME_NANO = undefined_time_nano;
jclass hdrCapabilitiesClazz = FindClassOrDie(env, "android/view/Display$HdrCapabilities");
gHdrCapabilitiesClassInfo.clazz = MakeGlobalRefOrDie(env, hdrCapabilitiesClazz);
gHdrCapabilitiesClassInfo.ctor = GetMethodIDOrDie(env, hdrCapabilitiesClazz, "<init>",
"([IFFF)V");
jclass graphicsBufferClazz = FindClassOrDie(env, "android/graphics/GraphicBuffer");
gGraphicBufferClassInfo.clazz = MakeGlobalRefOrDie(env, graphicsBufferClazz);
gGraphicBufferClassInfo.builder = GetStaticMethodIDOrDie(env, graphicsBufferClazz,
"createFromExisting", "(IIIIJ)Landroid/graphics/GraphicBuffer;");
jclass screenshotGraphicsBufferClazz = FindClassOrDie(env,
"android/view/SurfaceControl$ScreenshotGraphicBuffer");
gScreenshotGraphicBufferClassInfo.clazz =
MakeGlobalRefOrDie(env, screenshotGraphicsBufferClazz);
gScreenshotGraphicBufferClassInfo.builder = GetStaticMethodIDOrDie(env,
screenshotGraphicsBufferClazz,
"createFromNative", "(IIIIJIZ)Landroid/view/SurfaceControl$ScreenshotGraphicBuffer;");
jclass displayedContentSampleClazz = FindClassOrDie(env,
"android/hardware/display/DisplayedContentSample");
gDisplayedContentSampleClassInfo.clazz = MakeGlobalRefOrDie(env, displayedContentSampleClazz);
gDisplayedContentSampleClassInfo.ctor = GetMethodIDOrDie(env,
displayedContentSampleClazz, "<init>", "(J[J[J[J[J)V");
jclass displayedContentSamplingAttributesClazz = FindClassOrDie(env,
"android/hardware/display/DisplayedContentSamplingAttributes");
gDisplayedContentSamplingAttributesClassInfo.clazz = MakeGlobalRefOrDie(env,
displayedContentSamplingAttributesClazz);
gDisplayedContentSamplingAttributesClassInfo.ctor = GetMethodIDOrDie(env,
displayedContentSamplingAttributesClazz, "<init>", "(III)V");
jclass cieXyzClazz = FindClassOrDie(env, "android/view/SurfaceControl$CieXyz");
gCieXyzClassInfo.clazz = MakeGlobalRefOrDie(env, cieXyzClazz);
gCieXyzClassInfo.ctor = GetMethodIDOrDie(env, gCieXyzClassInfo.clazz, "<init>", "()V");
gCieXyzClassInfo.X = GetFieldIDOrDie(env, cieXyzClazz, "X", "F");
gCieXyzClassInfo.Y = GetFieldIDOrDie(env, cieXyzClazz, "Y", "F");
gCieXyzClassInfo.Z = GetFieldIDOrDie(env, cieXyzClazz, "Z", "F");
jclass displayPrimariesClazz = FindClassOrDie(env,
"android/view/SurfaceControl$DisplayPrimaries");
gDisplayPrimariesClassInfo.clazz = MakeGlobalRefOrDie(env, displayPrimariesClazz);
gDisplayPrimariesClassInfo.ctor = GetMethodIDOrDie(env, gDisplayPrimariesClassInfo.clazz,
"<init>", "()V");
gDisplayPrimariesClassInfo.red = GetFieldIDOrDie(env, displayPrimariesClazz, "red",
"Landroid/view/SurfaceControl$CieXyz;");
gDisplayPrimariesClassInfo.green = GetFieldIDOrDie(env, displayPrimariesClazz, "green",
"Landroid/view/SurfaceControl$CieXyz;");
gDisplayPrimariesClassInfo.blue = GetFieldIDOrDie(env, displayPrimariesClazz, "blue",
"Landroid/view/SurfaceControl$CieXyz;");
gDisplayPrimariesClassInfo.white = GetFieldIDOrDie(env, displayPrimariesClazz, "white",
"Landroid/view/SurfaceControl$CieXyz;");
return err;
}
} // namespace android