diff options
| -rw-r--r-- | core/java/android/view/CompositionSamplingListener.java | 90 | ||||
| -rw-r--r-- | core/jni/Android.bp | 1 | ||||
| -rw-r--r-- | core/jni/AndroidRuntime.cpp | 2 | ||||
| -rw-r--r-- | core/jni/android_view_CompositionSamplingListener.cpp | 135 | ||||
| -rw-r--r-- | core/tests/coretests/src/android/view/CompositionSamplingListenerTest.java | 49 |
5 files changed, 277 insertions, 0 deletions
diff --git a/core/java/android/view/CompositionSamplingListener.java b/core/java/android/view/CompositionSamplingListener.java new file mode 100644 index 000000000000..e4309a6d9aa4 --- /dev/null +++ b/core/java/android/view/CompositionSamplingListener.java @@ -0,0 +1,90 @@ +/* + * 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); +} diff --git a/core/jni/Android.bp b/core/jni/Android.bp index 30e9937c7d7c..c309f276d3ed 100644 --- a/core/jni/Android.bp +++ b/core/jni/Android.bp @@ -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", diff --git a/core/jni/AndroidRuntime.cpp b/core/jni/AndroidRuntime.cpp index 019ade9a3914..0938e569ad7e 100644 --- a/core/jni/AndroidRuntime.cpp +++ b/core/jni/AndroidRuntime.cpp @@ -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), diff --git a/core/jni/android_view_CompositionSamplingListener.cpp b/core/jni/android_view_CompositionSamplingListener.cpp new file mode 100644 index 000000000000..283ba0d057c5 --- /dev/null +++ b/core/jni/android_view_CompositionSamplingListener.cpp @@ -0,0 +1,135 @@ +/* + * 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 diff --git a/core/tests/coretests/src/android/view/CompositionSamplingListenerTest.java b/core/tests/coretests/src/android/view/CompositionSamplingListenerTest.java new file mode 100644 index 000000000000..75a2e8a8241e --- /dev/null +++ b/core/tests/coretests/src/android/view/CompositionSamplingListenerTest.java @@ -0,0 +1,49 @@ +/* + * 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 + } + }; +} |