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