Loading core/java/android/view/CompositionSamplingListener.java 0 → 100644 +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); } core/jni/Android.bp +1 −0 Original line number Diff line number Diff line Loading @@ -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", Loading core/jni/AndroidRuntime.cpp +2 −0 Original line number Diff line number Diff line Loading @@ -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); Loading Loading @@ -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), Loading core/jni/android_view_CompositionSamplingListener.cpp 0 → 100644 +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 core/tests/coretests/src/android/view/CompositionSamplingListenerTest.java 0 → 100644 +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 } }; } Loading
core/java/android/view/CompositionSamplingListener.java 0 → 100644 +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); }
core/jni/Android.bp +1 −0 Original line number Diff line number Diff line Loading @@ -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", Loading
core/jni/AndroidRuntime.cpp +2 −0 Original line number Diff line number Diff line Loading @@ -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); Loading Loading @@ -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), Loading
core/jni/android_view_CompositionSamplingListener.cpp 0 → 100644 +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
core/tests/coretests/src/android/view/CompositionSamplingListenerTest.java 0 → 100644 +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 } }; }