xref: /aosp_15_r20/frameworks/base/core/jni/android_hardware_input_InputWindowHandle.cpp (revision d57664e9bc4670b3ecf6748a746a57c557b6bc9e)
1 /*
2  * Copyright (C) 2011 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 "InputWindowHandle"
18 
19 #include "android_hardware_input_InputWindowHandle.h"
20 
21 #include <android/graphics/matrix.h>
22 #include <android/graphics/region.h>
23 #include <android_runtime/AndroidRuntime.h>
24 #include <android_runtime/Log.h>
25 #include <binder/IPCThreadState.h>
26 #include <ftl/flags.h>
27 #include <gui/SurfaceControl.h>
28 #include <gui/WindowInfo.h>
29 #include <nativehelper/JNIHelp.h>
30 #include <ui/Region.h>
31 #include <utils/threads.h>
32 
33 #include "SkRegion.h"
34 #include "android_hardware_input_InputApplicationHandle.h"
35 #include "android_util_Binder.h"
36 #include "core_jni_helpers.h"
37 #include "jni.h"
38 #include "jni_common.h"
39 
40 namespace android {
41 
42 using gui::TouchOcclusionMode;
43 using gui::WindowInfo;
44 
45 struct WeakRefHandleField {
46     jfieldID ctrl;
47     jmethodID get;
48     jfieldID mNativeObject;
49 };
50 
51 static struct {
52     jclass clazz;
53     jmethodID ctor;
54     jfieldID ptr;
55     jfieldID inputApplicationHandle;
56     jfieldID token;
57     jfieldID name;
58     jfieldID layoutParamsFlags;
59     jfieldID layoutParamsType;
60     jfieldID dispatchingTimeoutMillis;
61     jfieldID frame;
62     jfieldID contentSize;
63     jfieldID surfaceInset;
64     jfieldID scaleFactor;
65     jfieldID touchableRegion;
66     jfieldID touchOcclusionMode;
67     jfieldID ownerPid;
68     jfieldID ownerUid;
69     jfieldID packageName;
70     jfieldID inputConfig;
71     jfieldID displayId;
72     jfieldID replaceTouchableRegionWithCrop;
73     WeakRefHandleField touchableRegionSurfaceControl;
74     jfieldID transform;
75     jfieldID windowToken;
76     jfieldID focusTransferTarget;
77     jfieldID alpha;
78     jfieldID canOccludePresentation;
79 } gInputWindowHandleClassInfo;
80 
81 static struct {
82     jclass clazz;
83     jmethodID ctor;
84 } gRegionClassInfo;
85 
86 // --- Global functions ---
87 
android_view_InputWindowHandle_getHandle(JNIEnv * env,jobject obj)88 sp<gui::WindowInfoHandle> android_view_InputWindowHandle_getHandle(JNIEnv* env, jobject obj) {
89     sp<gui::WindowInfoHandle> handle = [&]() {
90         jlong cachedHandle = env->GetLongField(obj, gInputWindowHandleClassInfo.ptr);
91         if (cachedHandle) {
92             return sp<gui::WindowInfoHandle>::fromExisting(
93                     reinterpret_cast<gui::WindowInfoHandle*>(cachedHandle));
94         }
95 
96         auto newHandle = sp<gui::WindowInfoHandle>::make();
97         newHandle->incStrong((void*)android_view_InputWindowHandle_getHandle);
98         env->SetLongField(obj, gInputWindowHandleClassInfo.ptr,
99                           reinterpret_cast<jlong>(newHandle.get()));
100         return newHandle;
101     }();
102 
103     gui::WindowInfo* windowInfo = handle->editInfo();
104 
105     windowInfo->touchableRegion.clear();
106 
107     jobject tokenObj = env->GetObjectField(obj, gInputWindowHandleClassInfo.token);
108     if (tokenObj) {
109         windowInfo->token = ibinderForJavaObject(env, tokenObj);
110         env->DeleteLocalRef(tokenObj);
111     } else {
112         windowInfo->token.clear();
113     }
114 
115     windowInfo->name = getStringField(env, obj, gInputWindowHandleClassInfo.name, "<null>");
116 
117     windowInfo->dispatchingTimeout = std::chrono::milliseconds(
118             env->GetLongField(obj, gInputWindowHandleClassInfo.dispatchingTimeoutMillis));
119 
120     ScopedLocalRef<jobject> frameObj(env,
121                                      env->GetObjectField(obj, gInputWindowHandleClassInfo.frame));
122     windowInfo->frame = JNICommon::rectFromObj(env, frameObj.get());
123 
124     windowInfo->surfaceInset = env->GetIntField(obj, gInputWindowHandleClassInfo.surfaceInset);
125     windowInfo->globalScaleFactor =
126             env->GetFloatField(obj, gInputWindowHandleClassInfo.scaleFactor);
127 
128     jobject regionObj = env->GetObjectField(obj, gInputWindowHandleClassInfo.touchableRegion);
129     if (regionObj) {
130         for (graphics::RegionIterator it(env, regionObj); !it.isDone(); it.next()) {
131             ARect rect = it.getRect();
132             windowInfo->addTouchableRegion(Rect(rect.left, rect.top, rect.right, rect.bottom));
133         }
134         env->DeleteLocalRef(regionObj);
135     }
136 
137     const auto flags = ftl::Flags<WindowInfo::Flag>(
138             env->GetIntField(obj, gInputWindowHandleClassInfo.layoutParamsFlags));
139     const auto type = static_cast<WindowInfo::Type>(
140             env->GetIntField(obj, gInputWindowHandleClassInfo.layoutParamsType));
141     windowInfo->layoutParamsFlags = flags;
142     windowInfo->layoutParamsType = type;
143 
144     windowInfo->inputConfig = static_cast<gui::WindowInfo::InputConfig>(
145             env->GetIntField(obj, gInputWindowHandleClassInfo.inputConfig));
146 
147     windowInfo->touchOcclusionMode = static_cast<TouchOcclusionMode>(
148             env->GetIntField(obj, gInputWindowHandleClassInfo.touchOcclusionMode));
149     windowInfo->ownerPid = gui::Pid{env->GetIntField(obj, gInputWindowHandleClassInfo.ownerPid)};
150     windowInfo->ownerUid = gui::Uid{
151             static_cast<uid_t>(env->GetIntField(obj, gInputWindowHandleClassInfo.ownerUid))};
152     windowInfo->packageName =
153             getStringField(env, obj, gInputWindowHandleClassInfo.packageName, "<null>");
154     windowInfo->displayId =
155             ui::LogicalDisplayId{env->GetIntField(obj, gInputWindowHandleClassInfo.displayId)};
156 
157     jobject inputApplicationHandleObj =
158             env->GetObjectField(obj, gInputWindowHandleClassInfo.inputApplicationHandle);
159     if (inputApplicationHandleObj) {
160         std::shared_ptr<InputApplicationHandle> inputApplicationHandle =
161                 android_view_InputApplicationHandle_getHandle(env, inputApplicationHandleObj);
162         if (inputApplicationHandle != nullptr) {
163             inputApplicationHandle->updateInfo();
164             windowInfo->applicationInfo = *(inputApplicationHandle->getInfo());
165         }
166         env->DeleteLocalRef(inputApplicationHandleObj);
167     }
168 
169     windowInfo->replaceTouchableRegionWithCrop =
170             env->GetBooleanField(obj, gInputWindowHandleClassInfo.replaceTouchableRegionWithCrop);
171 
172     jobject weakSurfaceCtrl =
173             env->GetObjectField(obj,
174                                 gInputWindowHandleClassInfo.touchableRegionSurfaceControl.ctrl);
175     bool touchableRegionCropHandleSet = false;
176     if (weakSurfaceCtrl) {
177         // Promote java weak reference.
178         jobject strongSurfaceCtrl =
179                 env->CallObjectMethod(weakSurfaceCtrl,
180                                       gInputWindowHandleClassInfo.touchableRegionSurfaceControl
181                                               .get);
182         if (strongSurfaceCtrl) {
183             jlong mNativeObject =
184                     env->GetLongField(strongSurfaceCtrl,
185                                       gInputWindowHandleClassInfo.touchableRegionSurfaceControl
186                                               .mNativeObject);
187             if (mNativeObject) {
188                 auto ctrl = reinterpret_cast<SurfaceControl *>(mNativeObject);
189                 windowInfo->touchableRegionCropHandle = ctrl->getHandle();
190                 touchableRegionCropHandleSet = true;
191             }
192             env->DeleteLocalRef(strongSurfaceCtrl);
193         }
194         env->DeleteLocalRef(weakSurfaceCtrl);
195     }
196     if (!touchableRegionCropHandleSet) {
197         windowInfo->touchableRegionCropHandle.clear();
198     }
199 
200     jobject windowTokenObj = env->GetObjectField(obj, gInputWindowHandleClassInfo.windowToken);
201     if (windowTokenObj) {
202         windowInfo->windowToken = ibinderForJavaObject(env, windowTokenObj);
203         env->DeleteLocalRef(windowTokenObj);
204     } else {
205         windowInfo->windowToken.clear();
206     }
207 
208     ScopedLocalRef<jobject>
209             focusTransferTargetObj(env,
210                                    env->GetObjectField(obj,
211                                                        gInputWindowHandleClassInfo
212                                                                .focusTransferTarget));
213     if (focusTransferTargetObj.get()) {
214         windowInfo->focusTransferTarget = ibinderForJavaObject(env, focusTransferTargetObj.get());
215     } else {
216         windowInfo->focusTransferTarget.clear();
217     }
218 
219     return handle;
220 }
221 
android_view_InputWindowHandle_fromWindowInfo(JNIEnv * env,const gui::WindowInfo & windowInfo)222 jobject android_view_InputWindowHandle_fromWindowInfo(JNIEnv* env,
223                                                       const gui::WindowInfo& windowInfo) {
224     ScopedLocalRef<jobject>
225             applicationHandle(env,
226                               android_view_InputApplicationHandle_fromInputApplicationInfo(
227                                       env, windowInfo.applicationInfo));
228 
229     jobject inputWindowHandle =
230             env->NewObject(gInputWindowHandleClassInfo.clazz, gInputWindowHandleClassInfo.ctor,
231                            applicationHandle.get(), windowInfo.displayId);
232     if (env->ExceptionCheck()) {
233         LOGE_EX(env);
234         env->ExceptionClear();
235     }
236     LOG_ALWAYS_FATAL_IF(inputWindowHandle == nullptr,
237                         "Failed to create new InputWindowHandle object.");
238     env->SetObjectField(inputWindowHandle, gInputWindowHandleClassInfo.token,
239                         javaObjectForIBinder(env, windowInfo.token));
240     ScopedLocalRef<jstring> name(env, env->NewStringUTF(windowInfo.name.data()));
241     env->SetObjectField(inputWindowHandle, gInputWindowHandleClassInfo.name, name.get());
242     env->SetIntField(inputWindowHandle, gInputWindowHandleClassInfo.layoutParamsFlags,
243                      static_cast<uint32_t>(windowInfo.layoutParamsFlags.get()));
244     env->SetIntField(inputWindowHandle, gInputWindowHandleClassInfo.layoutParamsType,
245                      static_cast<int32_t>(windowInfo.layoutParamsType));
246     env->SetLongField(inputWindowHandle, gInputWindowHandleClassInfo.dispatchingTimeoutMillis,
247                       std::chrono::duration_cast<std::chrono::milliseconds>(
248                               windowInfo.dispatchingTimeout)
249                               .count());
250     ScopedLocalRef<jobject> rectObj(env, JNICommon::objFromRect(env, windowInfo.frame));
251     env->SetObjectField(inputWindowHandle, gInputWindowHandleClassInfo.frame, rectObj.get());
252 
253     ScopedLocalRef<jobject> sizeObj(env, JNICommon::objFromSize(env, windowInfo.contentSize));
254     env->SetObjectField(inputWindowHandle, gInputWindowHandleClassInfo.contentSize, sizeObj.get());
255 
256     env->SetIntField(inputWindowHandle, gInputWindowHandleClassInfo.surfaceInset,
257                      windowInfo.surfaceInset);
258     env->SetFloatField(inputWindowHandle, gInputWindowHandleClassInfo.scaleFactor,
259                        windowInfo.globalScaleFactor);
260 
261     SkRegion* region = new SkRegion();
262     for (const auto& r : windowInfo.touchableRegion) {
263         region->op({r.left, r.top, r.right, r.bottom}, SkRegion::kUnion_Op);
264     }
265     ScopedLocalRef<jobject> regionObj(env,
266                                       env->NewObject(gRegionClassInfo.clazz, gRegionClassInfo.ctor,
267                                                      reinterpret_cast<jlong>(region)));
268     env->SetObjectField(inputWindowHandle, gInputWindowHandleClassInfo.touchableRegion,
269                         regionObj.get());
270 
271     env->SetIntField(inputWindowHandle, gInputWindowHandleClassInfo.touchOcclusionMode,
272                      static_cast<int32_t>(windowInfo.touchOcclusionMode));
273     env->SetIntField(inputWindowHandle, gInputWindowHandleClassInfo.ownerPid,
274                      windowInfo.ownerPid.val());
275     env->SetIntField(inputWindowHandle, gInputWindowHandleClassInfo.ownerUid,
276                      windowInfo.ownerUid.val());
277     ScopedLocalRef<jstring> packageName(env, env->NewStringUTF(windowInfo.packageName.data()));
278     env->SetObjectField(inputWindowHandle, gInputWindowHandleClassInfo.packageName,
279                         packageName.get());
280 
281     const auto inputConfig = windowInfo.inputConfig.get();
282     static_assert(sizeof(inputConfig) == sizeof(int32_t));
283     env->SetIntField(inputWindowHandle, gInputWindowHandleClassInfo.inputConfig,
284                      static_cast<int32_t>(inputConfig));
285 
286     float transformVals[9];
287     for (int i = 0; i < 9; i++) {
288         transformVals[i] = windowInfo.transform[i % 3][i / 3];
289     }
290     ScopedLocalRef<jobject> matrixObj(env, AMatrix_newInstance(env, transformVals));
291     env->SetObjectField(inputWindowHandle, gInputWindowHandleClassInfo.transform, matrixObj.get());
292 
293     env->SetObjectField(inputWindowHandle, gInputWindowHandleClassInfo.windowToken,
294                         javaObjectForIBinder(env, windowInfo.windowToken));
295 
296     env->SetFloatField(inputWindowHandle, gInputWindowHandleClassInfo.alpha, windowInfo.alpha);
297     env->SetBooleanField(inputWindowHandle, gInputWindowHandleClassInfo.canOccludePresentation,
298                          windowInfo.canOccludePresentation);
299 
300     return inputWindowHandle;
301 }
302 
303 // --- JNI ---
304 
android_view_InputWindowHandle_nativeDispose(JNIEnv * env,jobject obj)305 static void android_view_InputWindowHandle_nativeDispose(JNIEnv* env, jobject obj) {
306     jlong ptr = env->GetLongField(obj, gInputWindowHandleClassInfo.ptr);
307     if (!ptr) {
308         return;
309     }
310     env->SetLongField(obj, gInputWindowHandleClassInfo.ptr, 0);
311     auto handle = reinterpret_cast<gui::WindowInfoHandle*>(ptr);
312     handle->decStrong((void*)android_view_InputWindowHandle_getHandle);
313 }
314 
315 static const JNINativeMethod gInputWindowHandleMethods[] = {
316     /* name, signature, funcPtr */
317     { "nativeDispose", "()V",
318             (void*) android_view_InputWindowHandle_nativeDispose },
319 };
320 
321 #define FIND_CLASS(var, className) \
322         var = env->FindClass(className); \
323         LOG_FATAL_IF(! (var), "Unable to find class " className);
324 
325 #define GET_FIELD_ID(var, clazz, fieldName, fieldDescriptor) \
326         var = env->GetFieldID(clazz, fieldName, fieldDescriptor); \
327         LOG_FATAL_IF(! (var), "Unable to find field " fieldName);
328 
329 #define GET_METHOD_ID(var, clazz, methodName, methodSignature) \
330         var = env->GetMethodID(clazz, methodName, methodSignature); \
331         LOG_FATAL_IF(! (var), "Unable to find method " methodName);
332 
register_android_view_InputWindowHandle(JNIEnv * env)333 int register_android_view_InputWindowHandle(JNIEnv* env) {
334     int res = jniRegisterNativeMethods(env, "android/view/InputWindowHandle",
335             gInputWindowHandleMethods, NELEM(gInputWindowHandleMethods));
336     (void) res;  // Faked use when LOG_NDEBUG.
337     LOG_FATAL_IF(res < 0, "Unable to register native methods.");
338 
339     jclass clazz;
340     FIND_CLASS(clazz, "android/view/InputWindowHandle");
341     gInputWindowHandleClassInfo.clazz = MakeGlobalRefOrDie(env, clazz);
342 
343     GET_METHOD_ID(gInputWindowHandleClassInfo.ctor, clazz, "<init>",
344                   "(Landroid/view/InputApplicationHandle;I)V");
345 
346     GET_FIELD_ID(gInputWindowHandleClassInfo.ptr, clazz,
347             "ptr", "J");
348 
349     GET_FIELD_ID(gInputWindowHandleClassInfo.inputApplicationHandle, clazz,
350             "inputApplicationHandle", "Landroid/view/InputApplicationHandle;");
351 
352     GET_FIELD_ID(gInputWindowHandleClassInfo.token, clazz,
353             "token", "Landroid/os/IBinder;");
354 
355     GET_FIELD_ID(gInputWindowHandleClassInfo.name, clazz,
356             "name", "Ljava/lang/String;");
357 
358     GET_FIELD_ID(gInputWindowHandleClassInfo.layoutParamsFlags, clazz,
359             "layoutParamsFlags", "I");
360 
361     GET_FIELD_ID(gInputWindowHandleClassInfo.layoutParamsType, clazz,
362             "layoutParamsType", "I");
363 
364     GET_FIELD_ID(gInputWindowHandleClassInfo.dispatchingTimeoutMillis, clazz,
365                  "dispatchingTimeoutMillis", "J");
366 
367     GET_FIELD_ID(gInputWindowHandleClassInfo.frame, clazz, "frame", "Landroid/graphics/Rect;");
368 
369     GET_FIELD_ID(gInputWindowHandleClassInfo.contentSize, clazz, "contentSize",
370                  "Landroid/util/Size;");
371 
372     GET_FIELD_ID(gInputWindowHandleClassInfo.surfaceInset, clazz,
373             "surfaceInset", "I");
374 
375     GET_FIELD_ID(gInputWindowHandleClassInfo.scaleFactor, clazz,
376             "scaleFactor", "F");
377 
378     GET_FIELD_ID(gInputWindowHandleClassInfo.touchableRegion, clazz,
379             "touchableRegion", "Landroid/graphics/Region;");
380 
381     GET_FIELD_ID(gInputWindowHandleClassInfo.touchOcclusionMode, clazz, "touchOcclusionMode", "I");
382 
383     GET_FIELD_ID(gInputWindowHandleClassInfo.ownerPid, clazz,
384             "ownerPid", "I");
385 
386     GET_FIELD_ID(gInputWindowHandleClassInfo.ownerUid, clazz,
387             "ownerUid", "I");
388 
389     GET_FIELD_ID(gInputWindowHandleClassInfo.packageName, clazz, "packageName",
390                  "Ljava/lang/String;");
391 
392     GET_FIELD_ID(gInputWindowHandleClassInfo.inputConfig, clazz, "inputConfig", "I");
393 
394     GET_FIELD_ID(gInputWindowHandleClassInfo.displayId, clazz,
395             "displayId", "I");
396 
397     GET_FIELD_ID(gInputWindowHandleClassInfo.replaceTouchableRegionWithCrop, clazz,
398             "replaceTouchableRegionWithCrop", "Z");
399 
400     GET_FIELD_ID(gInputWindowHandleClassInfo.transform, clazz, "transform",
401                  "Landroid/graphics/Matrix;");
402 
403     GET_FIELD_ID(gInputWindowHandleClassInfo.windowToken, clazz, "windowToken",
404                  "Landroid/os/IBinder;");
405 
406     GET_FIELD_ID(gInputWindowHandleClassInfo.focusTransferTarget, clazz, "focusTransferTarget",
407                  "Landroid/os/IBinder;");
408 
409     jclass weakRefClazz;
410     FIND_CLASS(weakRefClazz, "java/lang/ref/Reference");
411 
412     GET_METHOD_ID(gInputWindowHandleClassInfo.touchableRegionSurfaceControl.get, weakRefClazz,
413              "get", "()Ljava/lang/Object;")
414 
415     GET_FIELD_ID(gInputWindowHandleClassInfo.touchableRegionSurfaceControl.ctrl, clazz,
416             "touchableRegionSurfaceControl", "Ljava/lang/ref/WeakReference;");
417 
418     GET_FIELD_ID(gInputWindowHandleClassInfo.alpha, clazz, "alpha", "F");
419 
420     GET_FIELD_ID(gInputWindowHandleClassInfo.canOccludePresentation, clazz,
421                  "canOccludePresentation", "Z");
422 
423     jclass surfaceControlClazz;
424     FIND_CLASS(surfaceControlClazz, "android/view/SurfaceControl");
425     GET_FIELD_ID(gInputWindowHandleClassInfo.touchableRegionSurfaceControl.mNativeObject,
426         surfaceControlClazz, "mNativeObject", "J");
427 
428     jclass regionClazz;
429     FIND_CLASS(regionClazz, "android/graphics/Region");
430     gRegionClassInfo.clazz = MakeGlobalRefOrDie(env, regionClazz);
431     GET_METHOD_ID(gRegionClassInfo.ctor, gRegionClassInfo.clazz, "<init>", "(J)V");
432     return 0;
433 }
434 
435 } /* namespace android */
436