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