Loading core/java/android/view/SurfaceControlHdrLayerInfoListener.java 0 → 100644 +102 −0 Original line number Diff line number Diff line /* * 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); } core/jni/Android.bp +5 −1 Original line number Diff line number Diff line Loading @@ -70,7 +70,10 @@ cc_library_shared { "libz", ], static_libs: ["libnativehelper_lazy", "libziparchive_for_incfs", ], static_libs: [ "libnativehelper_lazy", "libziparchive_for_incfs", ], export_include_dirs: [ ".", Loading Loading @@ -121,6 +124,7 @@ cc_library_shared { "android_view_Surface.cpp", "android_view_SurfaceControl.cpp", "android_view_SurfaceControlFpsListener.cpp", "android_view_SurfaceControlHdrLayerInfoListener.cpp", "android_graphics_BLASTBufferQueue.cpp", "android_view_SurfaceSession.cpp", "android_view_TextureView.cpp", Loading core/jni/AndroidRuntime.cpp +2 −0 Original line number Diff line number Diff line Loading @@ -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_SurfaceControl(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_CompositionSamplingListener(JNIEnv* env); extern int register_android_view_TextureView(JNIEnv* env); Loading Loading @@ -1515,6 +1516,7 @@ static const RegJNIRec gRegJNI[] = { REG_JNI(register_android_view_Surface), REG_JNI(register_android_view_SurfaceControl), REG_JNI(register_android_view_SurfaceControlFpsListener), REG_JNI(register_android_view_SurfaceControlHdrLayerInfoListener), REG_JNI(register_android_view_SurfaceSession), REG_JNI(register_android_view_CompositionSamplingListener), REG_JNI(register_android_view_TextureView), Loading core/jni/android_view_SurfaceControlHdrLayerInfoListener.cpp 0 → 100644 +136 −0 Original line number Diff line number Diff line /* * 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 tests/SilkFX/src/com/android/test/silkfx/common/ColorModeControls.kt +26 −0 Original line number Diff line number Diff line Loading @@ -19,7 +19,11 @@ package com.android.test.silkfx.common import android.content.Context import android.content.pm.ActivityInfo import android.hardware.display.DisplayManager import android.os.IBinder import android.util.AttributeSet import android.util.Log import android.view.SurfaceControl import android.view.SurfaceControlHdrLayerInfoListener import android.view.Window import android.widget.Button import android.widget.LinearLayout Loading @@ -35,6 +39,7 @@ class ColorModeControls : LinearLayout, WindowObserver { constructor(context: Context, attrs: AttributeSet?) : super(context, attrs) { displayManager = context.getSystemService(DisplayManager::class.java)!! displayId = context.getDisplayId() displayToken = SurfaceControl.getInternalDisplayToken() } private var window: Window? = null Loading @@ -42,6 +47,7 @@ class ColorModeControls : LinearLayout, WindowObserver { private val displayManager: DisplayManager private var targetSdrWhitePointIndex = 0 private var displayId: Int private var displayToken: IBinder private val whitePoint get() = SDR_WHITE_POINTS[targetSdrWhitePointIndex] Loading Loading @@ -109,6 +115,7 @@ class ColorModeControls : LinearLayout, WindowObserver { // Imperfect, but close enough, synchronization by waiting for frame commit to set the value viewTreeObserver.registerFrameCommitCallback { try { SurfaceControl.setDisplayBrightness(displayToken, level) displayManager.setTemporaryBrightness(displayId, level) } catch (ex: Exception) { // Ignore a permission denied rejection - it doesn't meaningfully change much Loading @@ -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() { super.onAttachedToWindow() threadedRenderer?.setColorMode(window!!.colorMode, whitePoint) listener.register(displayToken) } override fun onDetachedFromWindow() { super.onDetachedFromWindow() listener.unregister(displayToken) } } No newline at end of file Loading
core/java/android/view/SurfaceControlHdrLayerInfoListener.java 0 → 100644 +102 −0 Original line number Diff line number Diff line /* * 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); }
core/jni/Android.bp +5 −1 Original line number Diff line number Diff line Loading @@ -70,7 +70,10 @@ cc_library_shared { "libz", ], static_libs: ["libnativehelper_lazy", "libziparchive_for_incfs", ], static_libs: [ "libnativehelper_lazy", "libziparchive_for_incfs", ], export_include_dirs: [ ".", Loading Loading @@ -121,6 +124,7 @@ cc_library_shared { "android_view_Surface.cpp", "android_view_SurfaceControl.cpp", "android_view_SurfaceControlFpsListener.cpp", "android_view_SurfaceControlHdrLayerInfoListener.cpp", "android_graphics_BLASTBufferQueue.cpp", "android_view_SurfaceSession.cpp", "android_view_TextureView.cpp", Loading
core/jni/AndroidRuntime.cpp +2 −0 Original line number Diff line number Diff line Loading @@ -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_SurfaceControl(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_CompositionSamplingListener(JNIEnv* env); extern int register_android_view_TextureView(JNIEnv* env); Loading Loading @@ -1515,6 +1516,7 @@ static const RegJNIRec gRegJNI[] = { REG_JNI(register_android_view_Surface), REG_JNI(register_android_view_SurfaceControl), REG_JNI(register_android_view_SurfaceControlFpsListener), REG_JNI(register_android_view_SurfaceControlHdrLayerInfoListener), REG_JNI(register_android_view_SurfaceSession), REG_JNI(register_android_view_CompositionSamplingListener), REG_JNI(register_android_view_TextureView), Loading
core/jni/android_view_SurfaceControlHdrLayerInfoListener.cpp 0 → 100644 +136 −0 Original line number Diff line number Diff line /* * 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
tests/SilkFX/src/com/android/test/silkfx/common/ColorModeControls.kt +26 −0 Original line number Diff line number Diff line Loading @@ -19,7 +19,11 @@ package com.android.test.silkfx.common import android.content.Context import android.content.pm.ActivityInfo import android.hardware.display.DisplayManager import android.os.IBinder import android.util.AttributeSet import android.util.Log import android.view.SurfaceControl import android.view.SurfaceControlHdrLayerInfoListener import android.view.Window import android.widget.Button import android.widget.LinearLayout Loading @@ -35,6 +39,7 @@ class ColorModeControls : LinearLayout, WindowObserver { constructor(context: Context, attrs: AttributeSet?) : super(context, attrs) { displayManager = context.getSystemService(DisplayManager::class.java)!! displayId = context.getDisplayId() displayToken = SurfaceControl.getInternalDisplayToken() } private var window: Window? = null Loading @@ -42,6 +47,7 @@ class ColorModeControls : LinearLayout, WindowObserver { private val displayManager: DisplayManager private var targetSdrWhitePointIndex = 0 private var displayId: Int private var displayToken: IBinder private val whitePoint get() = SDR_WHITE_POINTS[targetSdrWhitePointIndex] Loading Loading @@ -109,6 +115,7 @@ class ColorModeControls : LinearLayout, WindowObserver { // Imperfect, but close enough, synchronization by waiting for frame commit to set the value viewTreeObserver.registerFrameCommitCallback { try { SurfaceControl.setDisplayBrightness(displayToken, level) displayManager.setTemporaryBrightness(displayId, level) } catch (ex: Exception) { // Ignore a permission denied rejection - it doesn't meaningfully change much Loading @@ -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() { super.onAttachedToWindow() threadedRenderer?.setColorMode(window!!.colorMode, whitePoint) listener.register(displayToken) } override fun onDetachedFromWindow() { super.onDetachedFromWindow() listener.unregister(displayToken) } } No newline at end of file