1 /*
2 * Copyright (C) 2012 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 #include "android_view_InputDevice.h"
18
19 #include <android_runtime/AndroidRuntime.h>
20 #include <com_android_input_flags.h>
21 #include <input/Input.h>
22 #include <jni.h>
23 #include <nativehelper/JNIHelp.h>
24 #include <nativehelper/ScopedLocalRef.h>
25
26 #include "android_view_KeyCharacterMap.h"
27 #include "core_jni_helpers.h"
28
29 namespace android {
30
31 static struct {
32 jclass clazz;
33
34 jmethodID ctor;
35 jmethodID addMotionRange;
36 jmethodID setShouldSmoothScroll;
37 } gInputDeviceClassInfo;
38
android_view_InputDevice_create(JNIEnv * env,const InputDeviceInfo & deviceInfo)39 jobject android_view_InputDevice_create(JNIEnv* env, const InputDeviceInfo& deviceInfo) {
40 ScopedLocalRef<jstring> nameObj(env, env->NewStringUTF(deviceInfo.getDisplayName().c_str()));
41 if (!nameObj.get()) {
42 return NULL;
43 }
44
45 ScopedLocalRef<jstring> descriptorObj(env,
46 env->NewStringUTF(deviceInfo.getIdentifier().descriptor.c_str()));
47 if (!descriptorObj.get()) {
48 return NULL;
49 }
50
51 std::optional<KeyboardLayoutInfo> layoutInfo = deviceInfo.getKeyboardLayoutInfo();
52 ScopedLocalRef<jstring> keyboardLanguageTagObj(env,
53 env->NewStringUTF(
54 layoutInfo
55 ? layoutInfo->languageTag.c_str()
56 : NULL));
57 ScopedLocalRef<jstring> keyboardLayoutTypeObj(env,
58 env->NewStringUTF(
59 layoutInfo
60 ? layoutInfo->layoutType.c_str()
61 : NULL));
62
63 std::shared_ptr<KeyCharacterMap> map = deviceInfo.getKeyCharacterMap();
64 std::unique_ptr<KeyCharacterMap> mapCopy;
65 if (map != nullptr) {
66 mapCopy = std::make_unique<KeyCharacterMap>(*map);
67 }
68 ScopedLocalRef<jobject> kcmObj(env,
69 android_view_KeyCharacterMap_create(env, deviceInfo.getId(),
70 std::move(mapCopy)));
71 if (!kcmObj.get()) {
72 return NULL;
73 }
74
75 const InputDeviceIdentifier& ident = deviceInfo.getIdentifier();
76 const auto usiVersion = deviceInfo.getUsiVersion().value_or(InputDeviceUsiVersion{-1, -1});
77
78 ScopedLocalRef<jobject>
79 inputDeviceObj(env,
80 env->NewObject(gInputDeviceClassInfo.clazz, gInputDeviceClassInfo.ctor,
81 deviceInfo.getId(), deviceInfo.getGeneration(),
82 deviceInfo.getControllerNumber(), nameObj.get(),
83 static_cast<int32_t>(ident.vendor),
84 static_cast<int32_t>(ident.product),
85 static_cast<int32_t>(ident.bus), descriptorObj.get(),
86 deviceInfo.isExternal(), deviceInfo.getSources(),
87 deviceInfo.getKeyboardType(), kcmObj.get(),
88 keyboardLanguageTagObj.get(), keyboardLayoutTypeObj.get(),
89 deviceInfo.hasVibrator(), deviceInfo.hasMic(),
90 deviceInfo.hasButtonUnderPad(), deviceInfo.hasSensor(),
91 deviceInfo.hasBattery(), usiVersion.majorVersion,
92 usiVersion.minorVersion,
93 deviceInfo.getAssociatedDisplayId(),
94 deviceInfo.isEnabled()));
95 // Note: We do not populate the Bluetooth address into the InputDevice object to avoid leaking
96 // it to apps that do not have the Bluetooth permission.
97
98 const std::vector<InputDeviceInfo::MotionRange>& ranges = deviceInfo.getMotionRanges();
99 for (const InputDeviceInfo::MotionRange& range: ranges) {
100 env->CallVoidMethod(inputDeviceObj.get(), gInputDeviceClassInfo.addMotionRange, range.axis,
101 range.source, range.min, range.max, range.flat, range.fuzz, range.resolution);
102 if (env->ExceptionCheck()) {
103 return NULL;
104 }
105 }
106
107 if (com::android::input::flags::input_device_view_behavior_api()) {
108 const InputDeviceViewBehavior& viewBehavior = deviceInfo.getViewBehavior();
109 std::optional<bool> defaultSmoothScroll = viewBehavior.shouldSmoothScroll;
110 if (defaultSmoothScroll.has_value()) {
111 env->CallVoidMethod(inputDeviceObj.get(), gInputDeviceClassInfo.setShouldSmoothScroll,
112 *defaultSmoothScroll);
113 if (env->ExceptionCheck()) {
114 return NULL;
115 }
116 }
117 }
118
119 return env->NewLocalRef(inputDeviceObj.get());
120 }
121
register_android_view_InputDevice(JNIEnv * env)122 int register_android_view_InputDevice(JNIEnv* env)
123 {
124 gInputDeviceClassInfo.clazz = FindClassOrDie(env, "android/view/InputDevice");
125 gInputDeviceClassInfo.clazz = MakeGlobalRefOrDie(env, gInputDeviceClassInfo.clazz);
126
127 gInputDeviceClassInfo.ctor = GetMethodIDOrDie(env, gInputDeviceClassInfo.clazz, "<init>",
128 "(IIILjava/lang/String;IIILjava/lang/"
129 "String;ZIILandroid/view/KeyCharacterMap;Ljava/"
130 "lang/String;Ljava/lang/String;ZZZZZIIIZ)V");
131
132 gInputDeviceClassInfo.addMotionRange =
133 GetMethodIDOrDie(env, gInputDeviceClassInfo.clazz, "addMotionRange", "(IIFFFFF)V");
134 gInputDeviceClassInfo.setShouldSmoothScroll =
135 GetMethodIDOrDie(env, gInputDeviceClassInfo.clazz, "setShouldSmoothScroll", "(Z)V");
136 return 0;
137 }
138
139 }; // namespace android
140