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/graphics/matrix.h>
20 #include <android_runtime/AndroidRuntime.h>
21 #include <android_runtime/Log.h>
22 #include <gui/DisplayInfo.h>
23 #include <gui/SurfaceComposerClient.h>
24 #include <gui/WindowInfosUpdate.h>
25 #include <nativehelper/JNIHelp.h>
26 #include <nativehelper/ScopedLocalFrame.h>
27 #include <utils/Log.h>
28
29 #include "android_hardware_input_InputWindowHandle.h"
30 #include "core_jni_helpers.h"
31
32 namespace android {
33
34 using gui::DisplayInfo;
35 using gui::WindowInfo;
36
37 namespace {
38
39 static struct {
40 jclass clazz;
41 jmethodID onWindowInfosChanged;
42 } gListenerClassInfo;
43
44 static struct {
45 jclass clazz;
46 jmethodID ctor;
47 } gDisplayInfoClassInfo;
48
49 static struct {
50 jclass clazz;
51 jmethodID ctor;
52 } gPairClassInfo;
53
54 static jclass gInputWindowHandleClass;
55
fromDisplayInfo(JNIEnv * env,gui::DisplayInfo displayInfo)56 jobject fromDisplayInfo(JNIEnv* env, gui::DisplayInfo displayInfo) {
57 float transformValues[9];
58 for (int i = 0; i < 9; i++) {
59 transformValues[i] = displayInfo.transform[i % 3][i / 3];
60 }
61 ScopedLocalRef<jobject> matrixObj(env, AMatrix_newInstance(env, transformValues));
62 return env->NewObject(gDisplayInfoClassInfo.clazz, gDisplayInfoClassInfo.ctor,
63 displayInfo.displayId, displayInfo.logicalWidth,
64 displayInfo.logicalHeight, matrixObj.get());
65 }
66
fromWindowInfos(JNIEnv * env,const std::vector<WindowInfo> & windowInfos)67 static jobjectArray fromWindowInfos(JNIEnv* env, const std::vector<WindowInfo>& windowInfos) {
68 jobjectArray jWindowHandlesArray =
69 env->NewObjectArray(windowInfos.size(), gInputWindowHandleClass, nullptr);
70 for (int i = 0; i < windowInfos.size(); i++) {
71 ScopedLocalRef<jobject>
72 jWindowHandle(env,
73 android_view_InputWindowHandle_fromWindowInfo(env, windowInfos[i]));
74 env->SetObjectArrayElement(jWindowHandlesArray, i, jWindowHandle.get());
75 }
76
77 return jWindowHandlesArray;
78 }
79
fromDisplayInfos(JNIEnv * env,const std::vector<DisplayInfo> & displayInfos)80 static jobjectArray fromDisplayInfos(JNIEnv* env, const std::vector<DisplayInfo>& displayInfos) {
81 jobjectArray jDisplayInfoArray =
82 env->NewObjectArray(displayInfos.size(), gDisplayInfoClassInfo.clazz, nullptr);
83 for (int i = 0; i < displayInfos.size(); i++) {
84 ScopedLocalRef<jobject> jDisplayInfo(env, fromDisplayInfo(env, displayInfos[i]));
85 env->SetObjectArrayElement(jDisplayInfoArray, i, jDisplayInfo.get());
86 }
87
88 return jDisplayInfoArray;
89 }
90
91 struct WindowInfosListener : public gui::WindowInfosListener {
WindowInfosListenerandroid::__anonfce0f6940110::WindowInfosListener92 WindowInfosListener(JNIEnv* env, jobject listener)
93 : mListener(env->NewWeakGlobalRef(listener)) {}
94
onWindowInfosChangedandroid::__anonfce0f6940110::WindowInfosListener95 void onWindowInfosChanged(const gui::WindowInfosUpdate& update) override {
96 JNIEnv* env = AndroidRuntime::getJNIEnv();
97 LOG_ALWAYS_FATAL_IF(env == nullptr, "Unable to retrieve JNIEnv in onWindowInfoChanged.");
98
99 ScopedLocalFrame localFrame(env);
100 jobject listener = env->NewGlobalRef(mListener);
101 if (listener == nullptr) {
102 // Weak reference went out of scope
103 return;
104 }
105
106 ScopedLocalRef<jobjectArray> jWindowHandlesArray(env,
107 fromWindowInfos(env, update.windowInfos));
108 ScopedLocalRef<jobjectArray> jDisplayInfoArray(env,
109 fromDisplayInfos(env, update.displayInfos));
110
111 env->CallVoidMethod(listener, gListenerClassInfo.onWindowInfosChanged,
112 jWindowHandlesArray.get(), jDisplayInfoArray.get());
113 env->DeleteGlobalRef(listener);
114
115 if (env->ExceptionCheck()) {
116 ALOGE("WindowInfosListener.onWindowInfosChanged() failed.");
117 LOGE_EX(env);
118 env->ExceptionClear();
119 }
120 }
121
~WindowInfosListenerandroid::__anonfce0f6940110::WindowInfosListener122 ~WindowInfosListener() override {
123 JNIEnv* env = AndroidRuntime::getJNIEnv();
124 env->DeleteWeakGlobalRef(mListener);
125 }
126
127 private:
128 jweak mListener;
129 };
130
nativeCreate(JNIEnv * env,jclass clazz,jobject obj)131 jlong nativeCreate(JNIEnv* env, jclass clazz, jobject obj) {
132 WindowInfosListener* listener = new WindowInfosListener(env, obj);
133 listener->incStrong((void*)nativeCreate);
134 return reinterpret_cast<jlong>(listener);
135 }
136
destroyNativeService(void * ptr)137 void destroyNativeService(void* ptr) {
138 WindowInfosListener* listener = reinterpret_cast<WindowInfosListener*>(ptr);
139 SurfaceComposerClient::getDefault()->removeWindowInfosListener(listener);
140 listener->decStrong((void*)nativeCreate);
141 }
142
nativeRegister(JNIEnv * env,jclass clazz,jlong ptr)143 jobject nativeRegister(JNIEnv* env, jclass clazz, jlong ptr) {
144 sp<WindowInfosListener> listener = reinterpret_cast<WindowInfosListener*>(ptr);
145 std::pair<std::vector<gui::WindowInfo>, std::vector<gui::DisplayInfo>> initialInfo;
146 SurfaceComposerClient::getDefault()->addWindowInfosListener(listener, &initialInfo);
147
148 ScopedLocalRef<jobjectArray> jWindowHandlesArray(env, fromWindowInfos(env, initialInfo.first));
149 ScopedLocalRef<jobjectArray> jDisplayInfoArray(env, fromDisplayInfos(env, initialInfo.second));
150
151 return env->NewObject(gPairClassInfo.clazz, gPairClassInfo.ctor, jWindowHandlesArray.get(),
152 jDisplayInfoArray.get());
153 }
154
nativeUnregister(JNIEnv * env,jclass clazz,jlong ptr)155 void nativeUnregister(JNIEnv* env, jclass clazz, jlong ptr) {
156 sp<WindowInfosListener> listener = reinterpret_cast<WindowInfosListener*>(ptr);
157 SurfaceComposerClient::getDefault()->removeWindowInfosListener(listener);
158 }
159
nativeGetFinalizer(JNIEnv *,jclass)160 static jlong nativeGetFinalizer(JNIEnv* /* env */, jclass /* clazz */) {
161 return static_cast<jlong>(reinterpret_cast<uintptr_t>(&destroyNativeService));
162 }
163
164 const JNINativeMethod gMethods[] = {
165 /* name, signature, funcPtr */
166 {"nativeCreate", "(Landroid/window/WindowInfosListener;)J", (void*)nativeCreate},
167 {"nativeRegister", "(J)Landroid/util/Pair;", (void*)nativeRegister},
168 {"nativeUnregister", "(J)V", (void*)nativeUnregister},
169 {"nativeGetFinalizer", "()J", (void*)nativeGetFinalizer}};
170
171 } // namespace
172
register_android_window_WindowInfosListener(JNIEnv * env)173 int register_android_window_WindowInfosListener(JNIEnv* env) {
174 int res = jniRegisterNativeMethods(env, "android/window/WindowInfosListener", gMethods,
175 NELEM(gMethods));
176 LOG_ALWAYS_FATAL_IF(res < 0, "Unable to register native methods.");
177
178 jclass clazz = env->FindClass("android/window/WindowInfosListener");
179 gListenerClassInfo.clazz = MakeGlobalRefOrDie(env, clazz);
180 gListenerClassInfo.onWindowInfosChanged =
181 env->GetMethodID(gListenerClassInfo.clazz, "onWindowInfosChanged",
182 "([Landroid/view/InputWindowHandle;[Landroid/window/"
183 "WindowInfosListener$DisplayInfo;)V");
184
185 clazz = env->FindClass("android/view/InputWindowHandle");
186 gInputWindowHandleClass = MakeGlobalRefOrDie(env, clazz);
187
188 clazz = env->FindClass("android/window/WindowInfosListener$DisplayInfo");
189 gDisplayInfoClassInfo.clazz = MakeGlobalRefOrDie(env, clazz);
190 gDisplayInfoClassInfo.ctor = env->GetMethodID(gDisplayInfoClassInfo.clazz, "<init>",
191 "(IIILandroid/graphics/Matrix;)V");
192
193 clazz = env->FindClass("android/util/Pair");
194 gPairClassInfo.clazz = MakeGlobalRefOrDie(env, clazz);
195 gPairClassInfo.ctor = env->GetMethodID(gPairClassInfo.clazz, "<init>",
196 "(Ljava/lang/Object;Ljava/lang/Object;)V");
197
198 return 0;
199 }
200
201 } // namespace android
202