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