1 /*
2  * Copyright 2021 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #define LOG_TAG "WindowInfosListener"
18 
19 #include <android_runtime/AndroidRuntime.h>
20 #include <android_runtime/Log.h>
21 #include <gui/SurfaceComposerClient.h>
22 #include <nativehelper/JNIHelp.h>
23 #include <utils/Log.h>
24 
25 #include "android_hardware_input_InputWindowHandle.h"
26 #include "core_jni_helpers.h"
27 
28 namespace android {
29 
30 using gui::WindowInfo;
31 
32 namespace {
33 
34 static struct {
35     jclass clazz;
36     jmethodID onWindowInfosChanged;
37 } gListenerClassInfo;
38 
39 static jclass gInputWindowHandleClass;
40 
41 struct WindowInfosListener : public gui::WindowInfosListener {
WindowInfosListenerandroid::__anon1be1e6920110::WindowInfosListener42     WindowInfosListener(JNIEnv* env, jobject listener)
43           : mListener(env->NewWeakGlobalRef(listener)) {}
44 
onWindowInfosChangedandroid::__anon1be1e6920110::WindowInfosListener45     void onWindowInfosChanged(const std::vector<WindowInfo>& windowInfos) override {
46         JNIEnv* env = AndroidRuntime::getJNIEnv();
47         LOG_ALWAYS_FATAL_IF(env == nullptr, "Unable to retrieve JNIEnv in onWindowInfoChanged.");
48 
49         jobject listener = env->NewGlobalRef(mListener);
50         if (listener == nullptr) {
51             // Weak reference went out of scope
52             return;
53         }
54 
55         jobjectArray jWindowHandlesArray =
56                 env->NewObjectArray(windowInfos.size(), gInputWindowHandleClass, nullptr);
57         for (int i = 0; i < windowInfos.size(); i++) {
58             ScopedLocalRef<jobject>
59                     jWindowHandle(env,
60                                   android_view_InputWindowHandle_fromWindowInfo(env,
61                                                                                 windowInfos[i]));
62             env->SetObjectArrayElement(jWindowHandlesArray, i, jWindowHandle.get());
63         }
64 
65         env->CallVoidMethod(listener, gListenerClassInfo.onWindowInfosChanged, jWindowHandlesArray);
66         env->DeleteGlobalRef(listener);
67 
68         if (env->ExceptionCheck()) {
69             ALOGE("WindowInfosListener.onWindowInfosChanged() failed.");
70             LOGE_EX(env);
71             env->ExceptionClear();
72         }
73     }
74 
~WindowInfosListenerandroid::__anon1be1e6920110::WindowInfosListener75     ~WindowInfosListener() override {
76         JNIEnv* env = AndroidRuntime::getJNIEnv();
77         env->DeleteWeakGlobalRef(mListener);
78     }
79 
80 private:
81     jweak mListener;
82 };
83 
nativeCreate(JNIEnv * env,jclass clazz,jobject obj)84 jlong nativeCreate(JNIEnv* env, jclass clazz, jobject obj) {
85     WindowInfosListener* listener = new WindowInfosListener(env, obj);
86     listener->incStrong((void*)nativeCreate);
87     return reinterpret_cast<jlong>(listener);
88 }
89 
destroyNativeService(void * ptr)90 void destroyNativeService(void* ptr) {
91     WindowInfosListener* listener = reinterpret_cast<WindowInfosListener*>(ptr);
92     listener->decStrong((void*)nativeCreate);
93 }
94 
nativeRegister(JNIEnv * env,jclass clazz,jlong ptr)95 void nativeRegister(JNIEnv* env, jclass clazz, jlong ptr) {
96     sp<WindowInfosListener> listener = reinterpret_cast<WindowInfosListener*>(ptr);
97     SurfaceComposerClient::getDefault()->addWindowInfosListener(listener);
98 }
99 
nativeUnregister(JNIEnv * env,jclass clazz,jlong ptr)100 void nativeUnregister(JNIEnv* env, jclass clazz, jlong ptr) {
101     sp<WindowInfosListener> listener = reinterpret_cast<WindowInfosListener*>(ptr);
102     SurfaceComposerClient::getDefault()->removeWindowInfosListener(listener);
103 }
104 
nativeGetFinalizer(JNIEnv *,jclass)105 static jlong nativeGetFinalizer(JNIEnv* /* env */, jclass /* clazz */) {
106     return static_cast<jlong>(reinterpret_cast<uintptr_t>(&destroyNativeService));
107 }
108 
109 const JNINativeMethod gMethods[] = {
110         /* name, signature, funcPtr */
111         {"nativeCreate", "(Landroid/window/WindowInfosListener;)J", (void*)nativeCreate},
112         {"nativeRegister", "(J)V", (void*)nativeRegister},
113         {"nativeUnregister", "(J)V", (void*)nativeUnregister},
114         {"nativeGetFinalizer", "()J", (void*)nativeGetFinalizer}};
115 
116 } // namespace
117 
register_android_window_WindowInfosListener(JNIEnv * env)118 int register_android_window_WindowInfosListener(JNIEnv* env) {
119     int res = jniRegisterNativeMethods(env, "android/window/WindowInfosListener", gMethods,
120                                        NELEM(gMethods));
121     LOG_ALWAYS_FATAL_IF(res < 0, "Unable to register native methods.");
122 
123     jclass clazz = env->FindClass("android/window/WindowInfosListener");
124     gListenerClassInfo.clazz = MakeGlobalRefOrDie(env, clazz);
125     gListenerClassInfo.onWindowInfosChanged =
126             env->GetMethodID(gListenerClassInfo.clazz, "onWindowInfosChanged",
127                              "([Landroid/view/InputWindowHandle;)V");
128 
129     clazz = env->FindClass("android/view/InputWindowHandle");
130     gInputWindowHandleClass = MakeGlobalRefOrDie(env, clazz);
131     return 0;
132 }
133 
134 } // namespace android
135