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