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

Commit 69449100 authored by TreeHugger Robot's avatar TreeHugger Robot Committed by Android (Google) Code Review
Browse files

Merge "Add CompositionSamplingListener"

parents d5d7dbaa 9b963d3c
Loading
Loading
Loading
Loading
+90 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2019 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.graphics.Rect;
import android.os.IBinder;

import com.android.internal.util.Preconditions;

import java.util.concurrent.Executor;

/**
 * Listener for sampling the result of the screen composition.
 * {@hide}
 */
public abstract class CompositionSamplingListener {

    private final long mNativeListener;
    private final Executor mExecutor;

    public CompositionSamplingListener(Executor executor) {
        mExecutor = executor;
        mNativeListener = nativeCreate(this);
    }

    @Override
    protected void finalize() throws Throwable {
        try {
            if (mNativeListener != 0) {
                unregister(this);
                nativeDestroy(mNativeListener);
            }
        } finally {
            super.finalize();
        }
    }

    /**
     * Reports a luma sample from the registered region.
     */
    public abstract void onSampleCollected(float medianLuma);

    /**
     * Registers a sampling listener.
     */
    public static void register(CompositionSamplingListener listener,
            int displayId, IBinder stopLayer, Rect samplingArea) {
        Preconditions.checkArgument(displayId == Display.DEFAULT_DISPLAY,
                "default display only for now");
        nativeRegister(listener.mNativeListener, stopLayer, samplingArea.left, samplingArea.top,
                samplingArea.right, samplingArea.bottom);
    }

    /**
     * Unregisters a sampling listener.
     */
    public static void unregister(CompositionSamplingListener listener) {
        nativeUnregister(listener.mNativeListener);
    }

    /**
     * Dispatch the collected sample.
     *
     * Called from native code on a binder thread.
     */
    private static void dispatchOnSampleCollected(CompositionSamplingListener listener,
            float medianLuma) {
        listener.mExecutor.execute(() -> listener.onSampleCollected(medianLuma));
    }

    private static native long nativeCreate(CompositionSamplingListener thiz);
    private static native void nativeDestroy(long ptr);
    private static native void nativeRegister(long ptr, IBinder stopLayer,
            int samplingAreaLeft, int top, int right, int bottom);
    private static native void nativeUnregister(long ptr);
}
+1 −0
Original line number Diff line number Diff line
@@ -62,6 +62,7 @@ cc_library_shared {
        "android_graphics_drawable_AnimatedVectorDrawable.cpp",
        "android_graphics_drawable_VectorDrawable.cpp",
        "android_graphics_Picture.cpp",
        "android_view_CompositionSamplingListener.cpp",
        "android_view_DisplayEventReceiver.cpp",
        "android_view_DisplayListCanvas.cpp",
        "android_view_TextureLayer.cpp",
+2 −0
Original line number Diff line number Diff line
@@ -163,6 +163,7 @@ extern int register_android_view_RenderNodeAnimator(JNIEnv* env);
extern int register_android_view_Surface(JNIEnv* env);
extern int register_android_view_SurfaceControl(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);
extern int register_android_view_ThreadedRenderer(JNIEnv* env);
extern int register_com_android_internal_view_animation_NativeInterpolatorFactoryHelper(JNIEnv *env);
@@ -1415,6 +1416,7 @@ static const RegJNIRec gRegJNI[] = {
    REG_JNI(register_android_view_Surface),
    REG_JNI(register_android_view_SurfaceControl),
    REG_JNI(register_android_view_SurfaceSession),
    REG_JNI(register_android_view_CompositionSamplingListener),
    REG_JNI(register_android_view_TextureView),
    REG_JNI(register_com_android_internal_view_animation_NativeInterpolatorFactoryHelper),
    REG_JNI(register_com_google_android_gles_jni_EGLImpl),
+135 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2012 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 "CompositionSamplingListener"

#include "android_util_Binder.h"

#include <nativehelper/JNIHelp.h>

#include <android_runtime/AndroidRuntime.h>
#include <android_runtime/Log.h>
#include <utils/Log.h>
#include <utils/RefBase.h>
#include <binder/IServiceManager.h>

#include <gui/IRegionSamplingListener.h>
#include <gui/ISurfaceComposer.h>
#include <ui/Rect.h>

namespace android {

namespace {

struct {
    jclass mClass;
    jmethodID mDispatchOnSampleCollected;
} gListenerClassInfo;

struct CompositionSamplingListener : public BnRegionSamplingListener {
    CompositionSamplingListener(JNIEnv* env, jobject listener)
            : mListener(env->NewGlobalRef(listener)) {}

    void onSampleCollected(float medianLuma) override {
        JNIEnv* env = AndroidRuntime::getJNIEnv();
        LOG_ALWAYS_FATAL_IF(env == nullptr, "Unable to retrieve JNIEnv in onSampleCollected.");

        env->CallStaticVoidMethod(gListenerClassInfo.mClass,
                gListenerClassInfo.mDispatchOnSampleCollected, mListener,
                static_cast<jfloat>(medianLuma));
        if (env->ExceptionCheck()) {
            ALOGE("CompositionSamplingListener.onSampleCollected() failed.");
            LOGE_EX(env);
            env->ExceptionClear();
        }
    }

protected:
    virtual ~CompositionSamplingListener() {
        JNIEnv* env = AndroidRuntime::getJNIEnv();
        env->DeleteGlobalRef(mListener);
    }

private:
    jobject mListener;
};

jlong nativeCreate(JNIEnv* env, jclass clazz, jobject obj) {
    CompositionSamplingListener* listener = new CompositionSamplingListener(env, obj);
    listener->incStrong((void*)nativeCreate);
    return reinterpret_cast<jlong>(listener);
}

void nativeDestroy(JNIEnv* env, jclass clazz, jlong ptr) {
    CompositionSamplingListener* listener = reinterpret_cast<CompositionSamplingListener*>(ptr);
    listener->decStrong((void*)nativeCreate);
}

void nativeRegister(JNIEnv* env, jclass clazz, jlong ptr, jobject stopLayerTokenObj,
        jint left, jint top, jint right, jint bottom) {
    sp<CompositionSamplingListener> listener = reinterpret_cast<CompositionSamplingListener*>(ptr);
    sp<IBinder> stopLayerHandle = ibinderForJavaObject(env, stopLayerTokenObj);

    // TODO: Use SurfaceComposerClient once it has addRegionSamplingListener.
    sp<ISurfaceComposer> composer;
    if (getService(String16("SurfaceFlinger"), &composer) != NO_ERROR) {
        jniThrowRuntimeException(env, "Couldn't retrieve SurfaceFlinger");
        return;
    }

    composer->addRegionSamplingListener(
            Rect(left, top, right, bottom), stopLayerHandle, listener);
}

void nativeUnregister(JNIEnv* env, jclass clazz, jlong ptr) {
    sp<CompositionSamplingListener> listener = reinterpret_cast<CompositionSamplingListener*>(ptr);

    // TODO: Use SurfaceComposerClient once it has addRegionSamplingListener.
    sp<ISurfaceComposer> composer;
    if (getService(String16("SurfaceFlinger"), &composer) != NO_ERROR) {
        jniThrowRuntimeException(env, "Couldn't retrieve SurfaceFlinger");
        return;
    }

    composer->removeRegionSamplingListener(listener);
}

const JNINativeMethod gMethods[] = {
    /* name, signature, funcPtr */
    { "nativeCreate", "(Landroid/view/CompositionSamplingListener;)J",
            (void*)nativeCreate },
    { "nativeDestroy", "(J)V",
            (void*)nativeDestroy },
    { "nativeRegister", "(JLandroid/os/IBinder;IIII)V",
            (void*)nativeRegister },
    { "nativeUnregister", "(J)V",
            (void*)nativeUnregister }
};

} // namespace

int register_android_view_CompositionSamplingListener(JNIEnv* env) {
    int res = jniRegisterNativeMethods(env, "android/view/CompositionSamplingListener",
            gMethods, NELEM(gMethods));
    LOG_ALWAYS_FATAL_IF(res < 0, "Unable to register native methods.");

    jclass clazz = env->FindClass("android/view/CompositionSamplingListener");
    gListenerClassInfo.mDispatchOnSampleCollected = env->GetStaticMethodID(
            clazz, "dispatchOnSampleCollected", "(Landroid/view/CompositionSamplingListener;F)V");
    return 0;
}

} // namespace android
+49 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2019 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 static android.view.Display.DEFAULT_DISPLAY;

import android.graphics.Rect;
import android.os.Binder;
import android.platform.test.annotations.Presubmit;

import androidx.test.filters.SmallTest;
import androidx.test.runner.AndroidJUnit4;

import org.junit.Test;
import org.junit.runner.RunWith;

@RunWith(AndroidJUnit4.class)
@SmallTest
@Presubmit
public class CompositionSamplingListenerTest {

    @Test
    public void testRegisterUnregister() {
        CompositionSamplingListener.register(mListener, DEFAULT_DISPLAY, new Binder(),
                new Rect(1, 1, 10, 10));
        CompositionSamplingListener.unregister(mListener);
    }

    private CompositionSamplingListener mListener = new CompositionSamplingListener(Runnable::run) {
        @Override
        public void onSampleCollected(float medianLuma) {
            // Ignore
        }
    };
}