Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 35aa049b authored by John Reck's avatar John Reck
Browse files

HDR info listener

Bug: 182312559
Test: SilkFX listener is called

Change-Id: I2c93f6ab51263a905c17a7afabb845317d33419d
parent 0f979050
Loading
Loading
Loading
Loading
+102 −0
Original line number Original line 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);
}
+5 −1
Original line number Original line Diff line number Diff line
@@ -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",
+2 −0
Original line number Original line Diff line number Diff line
@@ -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);
@@ -1514,6 +1515,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),
+136 −0
Original line number Original line 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
+26 −0
Original line number Original line Diff line number Diff line
@@ -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)
    }
    }
}
}
 No newline at end of file