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

Commit ee1219ac authored by Galia Peycheva's avatar Galia Peycheva Committed by Android (Google) Code Review
Browse files

Merge "Add TunnelModeStateListener in java+jni" into sc-dev

parents 94c64def fde81bf2
Loading
Loading
Loading
Loading
+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);
}
+1 −0
Original line number Diff line number Diff line
@@ -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",
+2 −0
Original line number Diff line number Diff line
@@ -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);
@@ -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),
+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
+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