Merge "HDR info listener" into sc-dev

This commit is contained in:
John Reck
2021-04-02 20:21:51 +00:00
committed by Android (Google) Code Review
5 changed files with 271 additions and 1 deletions

View File

@@ -0,0 +1,102 @@
/*
* Copyright 2021 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package android.view;
import android.annotation.RequiresPermission;
import android.os.IBinder;
import android.util.ArrayMap;
import libcore.util.NativeAllocationRegistry;
import java.util.Objects;
/**
* Allows for the monitoring of layers with HDR content
*
* @hide */
public abstract class SurfaceControlHdrLayerInfoListener {
private static final NativeAllocationRegistry sRegistry =
NativeAllocationRegistry.createMalloced(
SurfaceControlHdrLayerInfoListener.class.getClassLoader(), nGetDestructor());
/**
* Callback when the HDR information about the given display has changed
*
* @param displayToken The display this callback is about
* @param numberOfHdrLayers How many HDR layers are visible on the display
* @param maxW The width of the HDR layer with the largest area
* @param maxH The height of the HDR layer with the largest area
* @param flags Additional metadata flags, currently always 0
* TODO(b/182312559): Add some flags
*
* @hide */
public abstract void onHdrInfoChanged(IBinder displayToken, int numberOfHdrLayers,
int maxW, int maxH, int flags);
/**
* Registers this as an HDR info listener on the provided display
* @param displayToken
*/
@RequiresPermission(android.Manifest.permission.CONTROL_DISPLAY_BRIGHTNESS)
public void register(IBinder displayToken) {
Objects.requireNonNull(displayToken);
synchronized (this) {
if (mRegisteredListeners.containsKey(displayToken)) {
return;
}
long nativePtr = nRegister(displayToken);
Runnable destructor = sRegistry.registerNativeAllocation(this, nativePtr);
mRegisteredListeners.put(displayToken, destructor);
}
}
/**
* Unregisters this as an HDR info listener on the provided display
* @param displayToken
*/
@RequiresPermission(android.Manifest.permission.CONTROL_DISPLAY_BRIGHTNESS)
public void unregister(IBinder displayToken) {
Objects.requireNonNull(displayToken);
final Runnable destructor;
synchronized (this) {
destructor = mRegisteredListeners.remove(displayToken);
}
if (destructor != null) {
destructor.run();
}
}
/**
* Unregisters this on all previously registered displays
*/
@RequiresPermission(android.Manifest.permission.CONTROL_DISPLAY_BRIGHTNESS)
public void unregisterAll() {
final ArrayMap<IBinder, Runnable> toDestroy;
synchronized (this) {
toDestroy = mRegisteredListeners;
mRegisteredListeners = new ArrayMap<>();
}
for (Runnable destructor : toDestroy.values()) {
destructor.run();
}
}
private ArrayMap<IBinder, Runnable> mRegisteredListeners = new ArrayMap<>();
private static native long nGetDestructor();
private native long nRegister(IBinder displayToken);
}

View File

@@ -70,7 +70,10 @@ cc_library_shared {
"libz", "libz",
], ],
static_libs: ["libnativehelper_lazy", "libziparchive_for_incfs", ], static_libs: [
"libnativehelper_lazy",
"libziparchive_for_incfs",
],
export_include_dirs: [ export_include_dirs: [
".", ".",
@@ -121,6 +124,7 @@ cc_library_shared {
"android_view_Surface.cpp", "android_view_Surface.cpp",
"android_view_SurfaceControl.cpp", "android_view_SurfaceControl.cpp",
"android_view_SurfaceControlFpsListener.cpp", "android_view_SurfaceControlFpsListener.cpp",
"android_view_SurfaceControlHdrLayerInfoListener.cpp",
"android_graphics_BLASTBufferQueue.cpp", "android_graphics_BLASTBufferQueue.cpp",
"android_view_SurfaceSession.cpp", "android_view_SurfaceSession.cpp",
"android_view_TextureView.cpp", "android_view_TextureView.cpp",

View File

@@ -122,6 +122,7 @@ extern int register_android_view_InputWindowHandle(JNIEnv* env);
extern int register_android_view_Surface(JNIEnv* env); extern int register_android_view_Surface(JNIEnv* env);
extern int register_android_view_SurfaceControl(JNIEnv* env); extern int register_android_view_SurfaceControl(JNIEnv* env);
extern int register_android_view_SurfaceControlFpsListener(JNIEnv* env); extern int register_android_view_SurfaceControlFpsListener(JNIEnv* env);
extern int register_android_view_SurfaceControlHdrLayerInfoListener(JNIEnv* env);
extern int register_android_view_SurfaceSession(JNIEnv* env); extern int register_android_view_SurfaceSession(JNIEnv* env);
extern int register_android_view_CompositionSamplingListener(JNIEnv* env); extern int register_android_view_CompositionSamplingListener(JNIEnv* env);
extern int register_android_view_TextureView(JNIEnv* env); extern int register_android_view_TextureView(JNIEnv* env);
@@ -1515,6 +1516,7 @@ static const RegJNIRec gRegJNI[] = {
REG_JNI(register_android_view_Surface), REG_JNI(register_android_view_Surface),
REG_JNI(register_android_view_SurfaceControl), REG_JNI(register_android_view_SurfaceControl),
REG_JNI(register_android_view_SurfaceControlFpsListener), REG_JNI(register_android_view_SurfaceControlFpsListener),
REG_JNI(register_android_view_SurfaceControlHdrLayerInfoListener),
REG_JNI(register_android_view_SurfaceSession), REG_JNI(register_android_view_SurfaceSession),
REG_JNI(register_android_view_CompositionSamplingListener), REG_JNI(register_android_view_CompositionSamplingListener),
REG_JNI(register_android_view_TextureView), REG_JNI(register_android_view_TextureView),

View File

@@ -0,0 +1,136 @@
/*
* Copyright 2021 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#define LOG_TAG "SurfaceControlHdrLayerInfoListener"
#include <android/gui/BnHdrLayerInfoListener.h>
#include <android_runtime/Log.h>
#include <gui/ISurfaceComposer.h>
#include <gui/SurfaceComposerClient.h>
#include <log/log.h>
#include <nativehelper/JNIHelp.h>
#include <utils/RefBase.h>
#include "android_util_Binder.h"
#include "core_jni_helpers.h"
namespace android {
namespace {
struct {
jclass mClass;
jmethodID mOnHdrInfoChanged;
} gListenerClassInfo;
struct SurfaceControlHdrLayerInfoListener : public gui::BnHdrLayerInfoListener {
SurfaceControlHdrLayerInfoListener(JNIEnv* env, jobject listener, jobject displayToken)
: mListener(env->NewGlobalRef(listener)), mDisplayToken(env->NewGlobalRef(displayToken)) {
LOG_ALWAYS_FATAL_IF(env->GetJavaVM(&mVm) != JNI_OK, "Failed to GetJavaVm");
}
binder::Status onHdrLayerInfoChanged(int numberOfHdrLayers, int maxW, int maxH,
int flags) override {
JNIEnv* env = requireEnv();
env->CallVoidMethod(mListener, gListenerClassInfo.mOnHdrInfoChanged, mDisplayToken,
numberOfHdrLayers, maxW, maxH, flags);
if (env->ExceptionCheck()) {
ALOGE("SurfaceControlHdrLayerInfoListener.onHdrInfoChanged() failed.");
LOGE_EX(env);
env->ExceptionClear();
}
return binder::Status::ok();
}
status_t startListening() {
auto token = ibinderForJavaObject(requireEnv(), mDisplayToken);
return SurfaceComposerClient::addHdrLayerInfoListener(token, this);
}
status_t stopListening() {
auto token = ibinderForJavaObject(requireEnv(), mDisplayToken);
return SurfaceComposerClient::removeHdrLayerInfoListener(token, this);
}
protected:
virtual ~SurfaceControlHdrLayerInfoListener() {
JNIEnv* env = requireEnv();
env->DeleteGlobalRef(mListener);
env->DeleteGlobalRef(mDisplayToken);
}
JNIEnv* requireEnv() {
JNIEnv* env = nullptr;
if (mVm->GetEnv(reinterpret_cast<void**>(&env), JNI_VERSION_1_6) != JNI_OK) {
if (mVm->AttachCurrentThreadAsDaemon(&env, nullptr) != JNI_OK) {
LOG_ALWAYS_FATAL("Failed to AttachCurrentThread!");
}
}
return env;
}
private:
jobject mListener;
jobject mDisplayToken;
JavaVM* mVm;
};
jlong nRegister(JNIEnv* env, jobject jthis, jobject jbinderToken) {
auto callback = sp<SurfaceControlHdrLayerInfoListener>::make(env, jthis, jbinderToken);
status_t err = callback->startListening();
if (err != OK) {
auto errStr = statusToString(err);
jniThrowExceptionFmt(env, "java/lang/IllegalStateException",
"Failed to register HdrLayerInfoListener, err = %d (%s)", err,
errStr.c_str());
return 0;
}
SurfaceControlHdrLayerInfoListener* ret = callback.get();
ret->incStrong(0);
return static_cast<jlong>(reinterpret_cast<intptr_t>(ret));
}
static void destroy(SurfaceControlHdrLayerInfoListener* listener) {
listener->stopListening();
listener->decStrong(0);
}
static jlong nGetDestructor(JNIEnv* env, jobject clazz) {
return static_cast<jlong>(reinterpret_cast<intptr_t>(&destroy));
}
const JNINativeMethod gMethods[] = {
/* name, signature, funcPtr */
{"nGetDestructor", "()J", (void*)nGetDestructor},
{"nRegister", "(Landroid/os/IBinder;)J", (void*)nRegister}};
} // namespace
int register_android_view_SurfaceControlHdrLayerInfoListener(JNIEnv* env) {
int res = jniRegisterNativeMethods(env, "android/view/SurfaceControlHdrLayerInfoListener",
gMethods, NELEM(gMethods));
LOG_ALWAYS_FATAL_IF(res < 0, "Unable to register native methods.");
jclass clazz = env->FindClass("android/view/SurfaceControlHdrLayerInfoListener");
gListenerClassInfo.mClass = MakeGlobalRefOrDie(env, clazz);
gListenerClassInfo.mOnHdrInfoChanged =
env->GetMethodID(clazz, "onHdrInfoChanged", "(Landroid/os/IBinder;IIII)V");
return 0;
}
} // namespace android

View File

@@ -19,7 +19,11 @@ package com.android.test.silkfx.common
import android.content.Context import android.content.Context
import android.content.pm.ActivityInfo import android.content.pm.ActivityInfo
import android.hardware.display.DisplayManager import android.hardware.display.DisplayManager
import android.os.IBinder
import android.util.AttributeSet import android.util.AttributeSet
import android.util.Log
import android.view.SurfaceControl
import android.view.SurfaceControlHdrLayerInfoListener
import android.view.Window import android.view.Window
import android.widget.Button import android.widget.Button
import android.widget.LinearLayout import android.widget.LinearLayout
@@ -35,6 +39,7 @@ class ColorModeControls : LinearLayout, WindowObserver {
constructor(context: Context, attrs: AttributeSet?) : super(context, attrs) { constructor(context: Context, attrs: AttributeSet?) : super(context, attrs) {
displayManager = context.getSystemService(DisplayManager::class.java)!! displayManager = context.getSystemService(DisplayManager::class.java)!!
displayId = context.getDisplayId() displayId = context.getDisplayId()
displayToken = SurfaceControl.getInternalDisplayToken()
} }
private var window: Window? = null private var window: Window? = null
@@ -42,6 +47,7 @@ class ColorModeControls : LinearLayout, WindowObserver {
private val displayManager: DisplayManager private val displayManager: DisplayManager
private var targetSdrWhitePointIndex = 0 private var targetSdrWhitePointIndex = 0
private var displayId: Int private var displayId: Int
private var displayToken: IBinder
private val whitePoint get() = SDR_WHITE_POINTS[targetSdrWhitePointIndex] private val whitePoint get() = SDR_WHITE_POINTS[targetSdrWhitePointIndex]
@@ -109,6 +115,7 @@ class ColorModeControls : LinearLayout, WindowObserver {
// Imperfect, but close enough, synchronization by waiting for frame commit to set the value // Imperfect, but close enough, synchronization by waiting for frame commit to set the value
viewTreeObserver.registerFrameCommitCallback { viewTreeObserver.registerFrameCommitCallback {
try { try {
SurfaceControl.setDisplayBrightness(displayToken, level)
displayManager.setTemporaryBrightness(displayId, level) displayManager.setTemporaryBrightness(displayId, level)
} catch (ex: Exception) { } catch (ex: Exception) {
// Ignore a permission denied rejection - it doesn't meaningfully change much // Ignore a permission denied rejection - it doesn't meaningfully change much
@@ -116,9 +123,28 @@ class ColorModeControls : LinearLayout, WindowObserver {
} }
} }
private val listener = object : SurfaceControlHdrLayerInfoListener() {
override fun onHdrInfoChanged(
displayToken: IBinder?,
numberOfHdrLayers: Int,
maxW: Int,
maxH: Int,
flags: Int
) {
Log.d("HDRInfo", "onHdrInfoChanged: numLayer = $numberOfHdrLayers ($maxW x $maxH)" +
", flags = $flags")
}
}
override fun onAttachedToWindow() { override fun onAttachedToWindow() {
super.onAttachedToWindow() super.onAttachedToWindow()
threadedRenderer?.setColorMode(window!!.colorMode, whitePoint) threadedRenderer?.setColorMode(window!!.colorMode, whitePoint)
listener.register(displayToken)
}
override fun onDetachedFromWindow() {
super.onDetachedFromWindow()
listener.unregister(displayToken)
} }
} }