Loading core/java/android/view/TunnelModeEnabledListener.java 0 → 100644 +98 −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 com.android.internal.annotations.VisibleForTesting; import java.util.concurrent.Executor; /** * Listens for tunnel mode enabled/disabled events from SurfaceFlinger. * {@hide} */ public abstract class TunnelModeEnabledListener { private long mNativeListener; private final Executor mExecutor; public TunnelModeEnabledListener(Executor executor) { mExecutor = executor; mNativeListener = nativeCreate(this); } /** * Destroys the listener. */ public void destroy() { if (mNativeListener == 0) { return; } unregister(this); nativeDestroy(mNativeListener); mNativeListener = 0; } @Override protected void finalize() throws Throwable { try { destroy(); } finally { super.finalize(); } } /** * Reports when tunnel mode has been enabled/disabled. */ public abstract void onTunnelModeEnabledChanged(boolean tunnelModeEnabled); /** * Registers a listener. */ public static void register(TunnelModeEnabledListener listener) { if (listener.mNativeListener == 0) { return; } nativeRegister(listener.mNativeListener); } /** * Unregisters a listener. */ public static void unregister(TunnelModeEnabledListener listener) { if (listener.mNativeListener == 0) { return; } nativeUnregister(listener.mNativeListener); } /** * Dispatch tunnel mode enabled. * * Called from native code on a binder thread. */ @VisibleForTesting public static void dispatchOnTunnelModeEnabledChanged(TunnelModeEnabledListener listener, boolean tunnelModeEnabled) { listener.mExecutor.execute(() -> listener.onTunnelModeEnabledChanged(tunnelModeEnabled)); } private static native long nativeCreate(TunnelModeEnabledListener thiz); private static native void nativeDestroy(long ptr); private static native void nativeRegister(long ptr); private static native void nativeUnregister(long ptr); } core/jni/Android.bp +1 −0 Original line number Diff line number Diff line Loading @@ -128,6 +128,7 @@ cc_library_shared { "android_graphics_BLASTBufferQueue.cpp", "android_view_SurfaceSession.cpp", "android_view_TextureView.cpp", "android_view_TunnelModeEnabledListener.cpp", "android_view_VelocityTracker.cpp", "android_view_VerifiedKeyEvent.cpp", "android_view_VerifiedMotionEvent.cpp", Loading core/jni/AndroidRuntime.cpp +2 −0 Original line number Diff line number Diff line Loading @@ -127,6 +127,7 @@ 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); extern int register_android_view_TunnelModeEnabledListener(JNIEnv* env); extern int register_android_database_CursorWindow(JNIEnv* env); extern int register_android_database_SQLiteConnection(JNIEnv* env); extern int register_android_database_SQLiteGlobal(JNIEnv* env); Loading Loading @@ -1521,6 +1522,7 @@ static const RegJNIRec gRegJNI[] = { REG_JNI(register_android_view_SurfaceSession), REG_JNI(register_android_view_CompositionSamplingListener), REG_JNI(register_android_view_TextureView), REG_JNI(register_android_view_TunnelModeEnabledListener), REG_JNI(register_com_google_android_gles_jni_EGLImpl), REG_JNI(register_com_google_android_gles_jni_GLImpl), REG_JNI(register_android_opengl_jni_EGL14), Loading core/jni/android_view_TunnelModeEnabledListener.cpp 0 → 100644 +130 −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 "TunnelModeEnabledListener" #include "android_util_Binder.h" #include "core_jni_helpers.h" #include <nativehelper/JNIHelp.h> #include <android/gui/BnTunnelModeEnabledListener.h> #include <android_runtime/AndroidRuntime.h> #include <android_runtime/Log.h> #include <utils/Log.h> #include <gui/SurfaceComposerClient.h> #include <ui/Rect.h> namespace android { namespace { struct { jclass mClass; jmethodID mDispatchOnTunnelModeEnabledChanged; } gListenerClassInfo; struct TunnelModeEnabledListener : public gui::BnTunnelModeEnabledListener { TunnelModeEnabledListener(JNIEnv* env, jobject listener) : mListener(env->NewWeakGlobalRef(listener)) {} binder::Status onTunnelModeEnabledChanged(bool tunnelModeEnabled) override { JNIEnv* env = AndroidRuntime::getJNIEnv(); LOG_ALWAYS_FATAL_IF(env == nullptr, "Unable to retrieve JNIEnv in onTunnelModeEnabledChanged."); jobject listener = env->NewGlobalRef(mListener); if (listener == NULL) { // Weak reference went out of scope return binder::Status::ok(); } env->CallStaticVoidMethod(gListenerClassInfo.mClass, gListenerClassInfo.mDispatchOnTunnelModeEnabledChanged, listener, static_cast<jboolean>(tunnelModeEnabled)); env->DeleteGlobalRef(listener); if (env->ExceptionCheck()) { ALOGE("TunnelModeEnabledListener.onTunnelModeEnabledChanged() failed."); LOGE_EX(env); env->ExceptionClear(); } return binder::Status::ok(); } protected: virtual ~TunnelModeEnabledListener() { JNIEnv* env = AndroidRuntime::getJNIEnv(); env->DeleteWeakGlobalRef(mListener); } private: jweak mListener; }; jlong nativeCreate(JNIEnv* env, jclass clazz, jobject obj) { TunnelModeEnabledListener* listener = new TunnelModeEnabledListener(env, obj); listener->incStrong((void*)nativeCreate); return reinterpret_cast<jlong>(listener); } void nativeDestroy(JNIEnv* env, jclass clazz, jlong ptr) { TunnelModeEnabledListener* listener = reinterpret_cast<TunnelModeEnabledListener*>(ptr); listener->decStrong((void*)nativeCreate); } void nativeRegister(JNIEnv* env, jclass clazz, jlong ptr) { sp<TunnelModeEnabledListener> listener = reinterpret_cast<TunnelModeEnabledListener*>(ptr); if (SurfaceComposerClient::addTunnelModeEnabledListener(listener) != OK) { constexpr auto error_msg = "Couldn't addTunnelModeEnabledListener"; ALOGE(error_msg); jniThrowRuntimeException(env, error_msg); } } void nativeUnregister(JNIEnv* env, jclass clazz, jlong ptr) { sp<TunnelModeEnabledListener> listener = reinterpret_cast<TunnelModeEnabledListener*>(ptr); if (SurfaceComposerClient::removeTunnelModeEnabledListener(listener) != OK) { constexpr auto error_msg = "Couldn't removeTunnelModeEnabledListener"; ALOGE(error_msg); jniThrowRuntimeException(env, error_msg); } } const JNINativeMethod gMethods[] = { /* name, signature, funcPtr */ {"nativeCreate", "(Landroid/view/TunnelModeEnabledListener;)J", (void*)nativeCreate}, {"nativeDestroy", "(J)V", (void*)nativeDestroy}, {"nativeRegister", "(J)V", (void*)nativeRegister}, {"nativeUnregister", "(J)V", (void*)nativeUnregister}}; } // namespace int register_android_view_TunnelModeEnabledListener(JNIEnv* env) { int res = jniRegisterNativeMethods(env, "android/view/TunnelModeEnabledListener", gMethods, NELEM(gMethods)); LOG_ALWAYS_FATAL_IF(res < 0, "Unable to register native methods."); jclass clazz = env->FindClass("android/view/TunnelModeEnabledListener"); gListenerClassInfo.mClass = MakeGlobalRefOrDie(env, clazz); gListenerClassInfo.mDispatchOnTunnelModeEnabledChanged = env->GetStaticMethodID(clazz, "dispatchOnTunnelModeEnabledChanged", "(Landroid/view/TunnelModeEnabledListener;Z)V"); return 0; } } // namespace android core/tests/coretests/src/android/view/TunnelModeEnabledListenerTest.java 0 → 100644 +84 −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 static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; import android.platform.test.annotations.Presubmit; import androidx.test.filters.MediumTest; import androidx.test.runner.AndroidJUnit4; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicBoolean; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; @RunWith(AndroidJUnit4.class) @MediumTest @Presubmit public class TunnelModeEnabledListenerTest { private TestableTunnelModeEnabledListener mListener; @Before public void init() { mListener = new TestableTunnelModeEnabledListener(); } @Test public void testRegisterUnregister() { TunnelModeEnabledListener.register(mListener); TunnelModeEnabledListener.unregister(mListener); } @Test public void testDispatchUpdatesListener() { TunnelModeEnabledListener.dispatchOnTunnelModeEnabledChanged(mListener, true); assertEquals(true, mListener.mTunnelModeEnabled.get()); TunnelModeEnabledListener.dispatchOnTunnelModeEnabledChanged(mListener, false); assertEquals(false, mListener.mTunnelModeEnabled.get()); } @Test public void testRegisterUpdatesListener() throws Exception { TunnelModeEnabledListener.register(mListener); TimeUnit.SECONDS.sleep(1); assertTrue(mListener.mTunnelModeEnabledUpdated.get()); TunnelModeEnabledListener.unregister(mListener); } private static class TestableTunnelModeEnabledListener extends TunnelModeEnabledListener { AtomicBoolean mTunnelModeEnabled; AtomicBoolean mTunnelModeEnabledUpdated; TestableTunnelModeEnabledListener() { super(Runnable::run); mTunnelModeEnabled = new AtomicBoolean(false); mTunnelModeEnabledUpdated = new AtomicBoolean(); } @Override public void onTunnelModeEnabledChanged(boolean tunnelModeEnabled) { mTunnelModeEnabled.set(tunnelModeEnabled); mTunnelModeEnabledUpdated.set(true); } } } Loading
core/java/android/view/TunnelModeEnabledListener.java 0 → 100644 +98 −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 com.android.internal.annotations.VisibleForTesting; import java.util.concurrent.Executor; /** * Listens for tunnel mode enabled/disabled events from SurfaceFlinger. * {@hide} */ public abstract class TunnelModeEnabledListener { private long mNativeListener; private final Executor mExecutor; public TunnelModeEnabledListener(Executor executor) { mExecutor = executor; mNativeListener = nativeCreate(this); } /** * Destroys the listener. */ public void destroy() { if (mNativeListener == 0) { return; } unregister(this); nativeDestroy(mNativeListener); mNativeListener = 0; } @Override protected void finalize() throws Throwable { try { destroy(); } finally { super.finalize(); } } /** * Reports when tunnel mode has been enabled/disabled. */ public abstract void onTunnelModeEnabledChanged(boolean tunnelModeEnabled); /** * Registers a listener. */ public static void register(TunnelModeEnabledListener listener) { if (listener.mNativeListener == 0) { return; } nativeRegister(listener.mNativeListener); } /** * Unregisters a listener. */ public static void unregister(TunnelModeEnabledListener listener) { if (listener.mNativeListener == 0) { return; } nativeUnregister(listener.mNativeListener); } /** * Dispatch tunnel mode enabled. * * Called from native code on a binder thread. */ @VisibleForTesting public static void dispatchOnTunnelModeEnabledChanged(TunnelModeEnabledListener listener, boolean tunnelModeEnabled) { listener.mExecutor.execute(() -> listener.onTunnelModeEnabledChanged(tunnelModeEnabled)); } private static native long nativeCreate(TunnelModeEnabledListener thiz); private static native void nativeDestroy(long ptr); private static native void nativeRegister(long ptr); private static native void nativeUnregister(long ptr); }
core/jni/Android.bp +1 −0 Original line number Diff line number Diff line Loading @@ -128,6 +128,7 @@ cc_library_shared { "android_graphics_BLASTBufferQueue.cpp", "android_view_SurfaceSession.cpp", "android_view_TextureView.cpp", "android_view_TunnelModeEnabledListener.cpp", "android_view_VelocityTracker.cpp", "android_view_VerifiedKeyEvent.cpp", "android_view_VerifiedMotionEvent.cpp", Loading
core/jni/AndroidRuntime.cpp +2 −0 Original line number Diff line number Diff line Loading @@ -127,6 +127,7 @@ 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); extern int register_android_view_TunnelModeEnabledListener(JNIEnv* env); extern int register_android_database_CursorWindow(JNIEnv* env); extern int register_android_database_SQLiteConnection(JNIEnv* env); extern int register_android_database_SQLiteGlobal(JNIEnv* env); Loading Loading @@ -1521,6 +1522,7 @@ static const RegJNIRec gRegJNI[] = { REG_JNI(register_android_view_SurfaceSession), REG_JNI(register_android_view_CompositionSamplingListener), REG_JNI(register_android_view_TextureView), REG_JNI(register_android_view_TunnelModeEnabledListener), REG_JNI(register_com_google_android_gles_jni_EGLImpl), REG_JNI(register_com_google_android_gles_jni_GLImpl), REG_JNI(register_android_opengl_jni_EGL14), Loading
core/jni/android_view_TunnelModeEnabledListener.cpp 0 → 100644 +130 −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 "TunnelModeEnabledListener" #include "android_util_Binder.h" #include "core_jni_helpers.h" #include <nativehelper/JNIHelp.h> #include <android/gui/BnTunnelModeEnabledListener.h> #include <android_runtime/AndroidRuntime.h> #include <android_runtime/Log.h> #include <utils/Log.h> #include <gui/SurfaceComposerClient.h> #include <ui/Rect.h> namespace android { namespace { struct { jclass mClass; jmethodID mDispatchOnTunnelModeEnabledChanged; } gListenerClassInfo; struct TunnelModeEnabledListener : public gui::BnTunnelModeEnabledListener { TunnelModeEnabledListener(JNIEnv* env, jobject listener) : mListener(env->NewWeakGlobalRef(listener)) {} binder::Status onTunnelModeEnabledChanged(bool tunnelModeEnabled) override { JNIEnv* env = AndroidRuntime::getJNIEnv(); LOG_ALWAYS_FATAL_IF(env == nullptr, "Unable to retrieve JNIEnv in onTunnelModeEnabledChanged."); jobject listener = env->NewGlobalRef(mListener); if (listener == NULL) { // Weak reference went out of scope return binder::Status::ok(); } env->CallStaticVoidMethod(gListenerClassInfo.mClass, gListenerClassInfo.mDispatchOnTunnelModeEnabledChanged, listener, static_cast<jboolean>(tunnelModeEnabled)); env->DeleteGlobalRef(listener); if (env->ExceptionCheck()) { ALOGE("TunnelModeEnabledListener.onTunnelModeEnabledChanged() failed."); LOGE_EX(env); env->ExceptionClear(); } return binder::Status::ok(); } protected: virtual ~TunnelModeEnabledListener() { JNIEnv* env = AndroidRuntime::getJNIEnv(); env->DeleteWeakGlobalRef(mListener); } private: jweak mListener; }; jlong nativeCreate(JNIEnv* env, jclass clazz, jobject obj) { TunnelModeEnabledListener* listener = new TunnelModeEnabledListener(env, obj); listener->incStrong((void*)nativeCreate); return reinterpret_cast<jlong>(listener); } void nativeDestroy(JNIEnv* env, jclass clazz, jlong ptr) { TunnelModeEnabledListener* listener = reinterpret_cast<TunnelModeEnabledListener*>(ptr); listener->decStrong((void*)nativeCreate); } void nativeRegister(JNIEnv* env, jclass clazz, jlong ptr) { sp<TunnelModeEnabledListener> listener = reinterpret_cast<TunnelModeEnabledListener*>(ptr); if (SurfaceComposerClient::addTunnelModeEnabledListener(listener) != OK) { constexpr auto error_msg = "Couldn't addTunnelModeEnabledListener"; ALOGE(error_msg); jniThrowRuntimeException(env, error_msg); } } void nativeUnregister(JNIEnv* env, jclass clazz, jlong ptr) { sp<TunnelModeEnabledListener> listener = reinterpret_cast<TunnelModeEnabledListener*>(ptr); if (SurfaceComposerClient::removeTunnelModeEnabledListener(listener) != OK) { constexpr auto error_msg = "Couldn't removeTunnelModeEnabledListener"; ALOGE(error_msg); jniThrowRuntimeException(env, error_msg); } } const JNINativeMethod gMethods[] = { /* name, signature, funcPtr */ {"nativeCreate", "(Landroid/view/TunnelModeEnabledListener;)J", (void*)nativeCreate}, {"nativeDestroy", "(J)V", (void*)nativeDestroy}, {"nativeRegister", "(J)V", (void*)nativeRegister}, {"nativeUnregister", "(J)V", (void*)nativeUnregister}}; } // namespace int register_android_view_TunnelModeEnabledListener(JNIEnv* env) { int res = jniRegisterNativeMethods(env, "android/view/TunnelModeEnabledListener", gMethods, NELEM(gMethods)); LOG_ALWAYS_FATAL_IF(res < 0, "Unable to register native methods."); jclass clazz = env->FindClass("android/view/TunnelModeEnabledListener"); gListenerClassInfo.mClass = MakeGlobalRefOrDie(env, clazz); gListenerClassInfo.mDispatchOnTunnelModeEnabledChanged = env->GetStaticMethodID(clazz, "dispatchOnTunnelModeEnabledChanged", "(Landroid/view/TunnelModeEnabledListener;Z)V"); return 0; } } // namespace android
core/tests/coretests/src/android/view/TunnelModeEnabledListenerTest.java 0 → 100644 +84 −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 static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; import android.platform.test.annotations.Presubmit; import androidx.test.filters.MediumTest; import androidx.test.runner.AndroidJUnit4; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicBoolean; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; @RunWith(AndroidJUnit4.class) @MediumTest @Presubmit public class TunnelModeEnabledListenerTest { private TestableTunnelModeEnabledListener mListener; @Before public void init() { mListener = new TestableTunnelModeEnabledListener(); } @Test public void testRegisterUnregister() { TunnelModeEnabledListener.register(mListener); TunnelModeEnabledListener.unregister(mListener); } @Test public void testDispatchUpdatesListener() { TunnelModeEnabledListener.dispatchOnTunnelModeEnabledChanged(mListener, true); assertEquals(true, mListener.mTunnelModeEnabled.get()); TunnelModeEnabledListener.dispatchOnTunnelModeEnabledChanged(mListener, false); assertEquals(false, mListener.mTunnelModeEnabled.get()); } @Test public void testRegisterUpdatesListener() throws Exception { TunnelModeEnabledListener.register(mListener); TimeUnit.SECONDS.sleep(1); assertTrue(mListener.mTunnelModeEnabledUpdated.get()); TunnelModeEnabledListener.unregister(mListener); } private static class TestableTunnelModeEnabledListener extends TunnelModeEnabledListener { AtomicBoolean mTunnelModeEnabled; AtomicBoolean mTunnelModeEnabledUpdated; TestableTunnelModeEnabledListener() { super(Runnable::run); mTunnelModeEnabled = new AtomicBoolean(false); mTunnelModeEnabledUpdated = new AtomicBoolean(); } @Override public void onTunnelModeEnabledChanged(boolean tunnelModeEnabled) { mTunnelModeEnabled.set(tunnelModeEnabled); mTunnelModeEnabledUpdated.set(true); } } }