blob: 53262ae9525d288681d5d1c0761f68b3b785ac75 [file] [log] [blame]
Jeff Brown46b9ac02010-04-22 18:58:52 -07001/*
2 * Copyright (C) 2010 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 "InputManager-JNI"
18
19#include "JNIHelp.h"
20#include "jni.h"
21#include <android_runtime/AndroidRuntime.h>
22#include <ui/InputManager.h>
23#include <ui/InputTransport.h>
24#include <utils/Log.h>
25#include <utils/threads.h>
26#include "../../core/jni/android_view_KeyEvent.h"
27#include "../../core/jni/android_view_MotionEvent.h"
28#include "../../core/jni/android_view_InputChannel.h"
29#include "../../core/jni/android_view_InputTarget.h"
30
31namespace android {
32
33class InputDispatchPolicy : public InputDispatchPolicyInterface {
34public:
35 InputDispatchPolicy(JNIEnv* env, jobject callbacks);
36 virtual ~InputDispatchPolicy();
37
38 void setDisplaySize(int32_t displayId, int32_t width, int32_t height);
39 void setDisplayOrientation(int32_t displayId, int32_t orientation);
40
41 virtual bool getDisplayInfo(int32_t displayId,
42 int32_t* width, int32_t* height, int32_t* orientation);
43
44 virtual void notifyConfigurationChanged(nsecs_t when,
45 int32_t touchScreenConfig, int32_t keyboardConfig, int32_t navigationConfig);
46
47 virtual void notifyLidSwitchChanged(nsecs_t when, bool lidOpen);
48
49 virtual void virtualKeyFeedback(nsecs_t when, int32_t deviceId,
50 int32_t action, int32_t flags, int32_t keyCode,
51 int32_t scanCode, int32_t metaState, nsecs_t downTime);
52
53 virtual int32_t interceptKey(nsecs_t when, int32_t deviceId,
54 bool down, int32_t keyCode, int32_t scanCode, uint32_t policyFlags);
55 virtual int32_t interceptTrackball(nsecs_t when, bool buttonChanged, bool buttonDown,
56 bool rolled);
57 virtual int32_t interceptTouch(nsecs_t when);
58
59 virtual bool filterTouchEvents();
60 virtual bool filterJumpyTouchEvents();
61 virtual void getVirtualKeyDefinitions(const String8& deviceName,
62 Vector<VirtualKeyDefinition>& outVirtualKeyDefinitions);
63 virtual void getExcludedDeviceNames(Vector<String8>& outExcludedDeviceNames);
64
65 virtual bool allowKeyRepeat();
66 virtual nsecs_t getKeyRepeatTimeout();
67
68 virtual void getKeyEventTargets(KeyEvent* keyEvent, uint32_t policyFlags,
69 Vector<InputTarget>& outTargets);
70 virtual void getMotionEventTargets(MotionEvent* motionEvent, uint32_t policyFlags,
71 Vector<InputTarget>& outTargets);
72
73private:
74 bool isScreenOn();
75 bool isScreenBright();
76
77private:
78 jobject mCallbacks;
79
80 int32_t mFilterTouchEvents;
81 int32_t mFilterJumpyTouchEvents;
82
83 Mutex mDisplayLock;
84 int32_t mDisplayWidth, mDisplayHeight;
85 int32_t mDisplayOrientation;
86
87 inline JNIEnv* threadEnv() const {
88 return AndroidRuntime::getJNIEnv();
89 }
90};
91
92
93// globals
94
95static sp<EventHub> gEventHub;
96static sp<InputDispatchPolicy> gInputDispatchPolicy;
97static sp<InputManager> gInputManager;
98
99// JNI
100
101static struct {
102 jclass clazz;
103
104 jmethodID isScreenOn;
105 jmethodID isScreenBright;
106 jmethodID notifyConfigurationChanged;
107 jmethodID notifyLidSwitchChanged;
108 jmethodID virtualKeyFeedback;
109 jmethodID hackInterceptKey;
110 jmethodID goToSleep;
111 jmethodID pokeUserActivityForKey;
112 jmethodID notifyAppSwitchComing;
113 jmethodID filterTouchEvents;
114 jmethodID filterJumpyTouchEvents;
115 jmethodID getVirtualKeyDefinitions;
116 jmethodID getExcludedDeviceNames;
117 jmethodID getKeyEventTargets;
118 jmethodID getMotionEventTargets;
119} gCallbacksClassInfo;
120
121static struct {
122 jclass clazz;
123
124 jfieldID scanCode;
125 jfieldID centerX;
126 jfieldID centerY;
127 jfieldID width;
128 jfieldID height;
129} gVirtualKeyDefinitionClassInfo;
130
131static bool checkInputManagerUnitialized(JNIEnv* env) {
132 if (gInputManager == NULL) {
133 LOGE("Input manager not initialized.");
134 jniThrowRuntimeException(env, "Input manager not initialized.");
135 return true;
136 }
137 return false;
138}
139
140static void android_server_InputManager_nativeInit(JNIEnv* env, jclass clazz,
141 jobject callbacks) {
142 if (gEventHub == NULL) {
143 gEventHub = new EventHub();
144 }
145
146 if (gInputDispatchPolicy == NULL) {
147 gInputDispatchPolicy = new InputDispatchPolicy(env, callbacks);
148 }
149
150 if (gInputManager == NULL) {
151 gInputManager = new InputManager(gEventHub, gInputDispatchPolicy);
152 }
153}
154
155static void android_server_InputManager_nativeStart(JNIEnv* env, jclass clazz) {
156 if (checkInputManagerUnitialized(env)) {
157 return;
158 }
159
160 status_t result = gInputManager->start();
161 if (result) {
162 jniThrowRuntimeException(env, "Input manager could not be started.");
163 }
164}
165
166static void android_server_InputManager_nativeSetDisplaySize(JNIEnv* env, jclass clazz,
167 jint displayId, jint width, jint height) {
168 if (checkInputManagerUnitialized(env)) {
169 return;
170 }
171
172 // XXX we could get this from the SurfaceFlinger directly instead of requiring it
173 // to be passed in like this, not sure which is better but leaving it like this
174 // keeps the window manager in direct control of when display transitions propagate down
175 // to the input dispatcher
176 gInputDispatchPolicy->setDisplaySize(displayId, width, height);
177}
178
179static void android_server_InputManager_nativeSetDisplayOrientation(JNIEnv* env, jclass clazz,
180 jint displayId, jint orientation) {
181 if (checkInputManagerUnitialized(env)) {
182 return;
183 }
184
185 gInputDispatchPolicy->setDisplayOrientation(displayId, orientation);
186}
187
188static jint android_server_InputManager_nativeGetScanCodeState(JNIEnv* env, jclass clazz,
189 jint deviceId, jint deviceClasses, jint scanCode) {
190 if (checkInputManagerUnitialized(env)) {
191 return KEY_STATE_UNKNOWN;
192 }
193
194 return gInputManager->getScanCodeState(deviceId, deviceClasses, scanCode);
195}
196
197static jint android_server_InputManager_nativeGetKeyCodeState(JNIEnv* env, jclass clazz,
198 jint deviceId, jint deviceClasses, jint keyCode) {
199 if (checkInputManagerUnitialized(env)) {
200 return KEY_STATE_UNKNOWN;
201 }
202
203 return gInputManager->getKeyCodeState(deviceId, deviceClasses, keyCode);
204}
205
206static jint android_server_InputManager_nativeGetSwitchState(JNIEnv* env, jclass clazz,
207 jint deviceId, jint deviceClasses, jint sw) {
208 if (checkInputManagerUnitialized(env)) {
209 return KEY_STATE_UNKNOWN;
210 }
211
212 return gInputManager->getSwitchState(deviceId, deviceClasses, sw);
213}
214
215static jboolean android_server_InputManager_nativeHasKeys(JNIEnv* env, jclass clazz,
216 jintArray keyCodes, jbooleanArray outFlags) {
217 if (checkInputManagerUnitialized(env)) {
218 return JNI_FALSE;
219 }
220
221 int32_t* codes = env->GetIntArrayElements(keyCodes, NULL);
222 uint8_t* flags = env->GetBooleanArrayElements(outFlags, NULL);
223 jsize numCodes = env->GetArrayLength(keyCodes);
224 jboolean result;
225 if (numCodes == env->GetArrayLength(outFlags)) {
226 result = gInputManager->hasKeys(numCodes, codes, flags);
227 } else {
228 result = JNI_FALSE;
229 }
230
231 env->ReleaseBooleanArrayElements(outFlags, flags, 0);
232 env->ReleaseIntArrayElements(keyCodes, codes, 0);
233 return result;
234}
235
236static void throwInputChannelNotInitialized(JNIEnv* env) {
237 jniThrowException(env, "java/lang/IllegalStateException",
238 "inputChannel is not initialized");
239}
240
241static void android_server_InputManager_handleInputChannelDisposed(JNIEnv* env,
242 jobject inputChannelObj, const sp<InputChannel>& inputChannel, void* data) {
243 LOGW("Input channel object '%s' was disposed without first being unregistered with "
244 "the input manager!", inputChannel->getName().string());
245
246 gInputManager->unregisterInputChannel(inputChannel);
247}
248
249static void android_server_InputManager_nativeRegisterInputChannel(JNIEnv* env, jclass clazz,
250 jobject inputChannelObj) {
251 if (checkInputManagerUnitialized(env)) {
252 return;
253 }
254
255 sp<InputChannel> inputChannel = android_view_InputChannel_getInputChannel(env,
256 inputChannelObj);
257 if (inputChannel == NULL) {
258 throwInputChannelNotInitialized(env);
259 return;
260 }
261
262 status_t status = gInputManager->registerInputChannel(inputChannel);
263 if (status) {
264 jniThrowRuntimeException(env, "Failed to register input channel. "
265 "Check logs for details.");
266 return;
267 }
268
269 android_view_InputChannel_setDisposeCallback(env, inputChannelObj,
270 android_server_InputManager_handleInputChannelDisposed, NULL);
271}
272
273static void android_server_InputManager_nativeUnregisterInputChannel(JNIEnv* env, jclass clazz,
274 jobject inputChannelObj) {
275 if (checkInputManagerUnitialized(env)) {
276 return;
277 }
278
279 sp<InputChannel> inputChannel = android_view_InputChannel_getInputChannel(env,
280 inputChannelObj);
281 if (inputChannel == NULL) {
282 throwInputChannelNotInitialized(env);
283 return;
284 }
285
286 android_view_InputChannel_setDisposeCallback(env, inputChannelObj, NULL, NULL);
287
288 status_t status = gInputManager->unregisterInputChannel(inputChannel);
289 if (status) {
290 jniThrowRuntimeException(env, "Failed to unregister input channel. "
291 "Check logs for details.");
292 }
293}
294
295static JNINativeMethod gInputManagerMethods[] = {
296 /* name, signature, funcPtr */
297 { "nativeInit", "(Lcom/android/server/InputManager$Callbacks;)V",
298 (void*) android_server_InputManager_nativeInit },
299 { "nativeStart", "()V",
300 (void*) android_server_InputManager_nativeStart },
301 { "nativeSetDisplaySize", "(III)V",
302 (void*) android_server_InputManager_nativeSetDisplaySize },
303 { "nativeSetDisplayOrientation", "(II)V",
304 (void*) android_server_InputManager_nativeSetDisplayOrientation },
305 { "nativeGetScanCodeState", "(III)I",
306 (void*) android_server_InputManager_nativeGetScanCodeState },
307 { "nativeGetKeyCodeState", "(III)I",
308 (void*) android_server_InputManager_nativeGetKeyCodeState },
309 { "nativeGetSwitchState", "(III)I",
310 (void*) android_server_InputManager_nativeGetSwitchState },
311 { "nativeHasKeys", "([I[Z)Z",
312 (void*) android_server_InputManager_nativeHasKeys },
313 { "nativeRegisterInputChannel", "(Landroid/view/InputChannel;)V",
314 (void*) android_server_InputManager_nativeRegisterInputChannel },
315 { "nativeUnregisterInputChannel", "(Landroid/view/InputChannel;)V",
316 (void*) android_server_InputManager_nativeUnregisterInputChannel }
317};
318
319#define FIND_CLASS(var, className) \
320 var = env->FindClass(className); \
321 LOG_FATAL_IF(! var, "Unable to find class " className); \
322 var = jclass(env->NewGlobalRef(var));
323
324#define GET_METHOD_ID(var, clazz, methodName, methodDescriptor) \
325 var = env->GetMethodID(clazz, methodName, methodDescriptor); \
326 LOG_FATAL_IF(! var, "Unable to find method " methodName);
327
328#define GET_FIELD_ID(var, clazz, fieldName, fieldDescriptor) \
329 var = env->GetFieldID(clazz, fieldName, fieldDescriptor); \
330 LOG_FATAL_IF(! var, "Unable to find field " fieldName);
331
332int register_android_server_InputManager(JNIEnv* env) {
333 int res = jniRegisterNativeMethods(env, "com/android/server/InputManager",
334 gInputManagerMethods, NELEM(gInputManagerMethods));
335 LOG_FATAL_IF(res < 0, "Unable to register native methods.");
336
337 // Policy
338
339 FIND_CLASS(gCallbacksClassInfo.clazz, "com/android/server/InputManager$Callbacks");
340
341 GET_METHOD_ID(gCallbacksClassInfo.isScreenOn, gCallbacksClassInfo.clazz,
342 "isScreenOn", "()Z");
343
344 GET_METHOD_ID(gCallbacksClassInfo.isScreenBright, gCallbacksClassInfo.clazz,
345 "isScreenBright", "()Z");
346
347 GET_METHOD_ID(gCallbacksClassInfo.notifyConfigurationChanged, gCallbacksClassInfo.clazz,
348 "notifyConfigurationChanged", "(JIII)V");
349
350 GET_METHOD_ID(gCallbacksClassInfo.notifyLidSwitchChanged, gCallbacksClassInfo.clazz,
351 "notifyLidSwitchChanged", "(JZ)V");
352
353 GET_METHOD_ID(gCallbacksClassInfo.virtualKeyFeedback, gCallbacksClassInfo.clazz,
354 "virtualKeyFeedback", "(JIIIIIIJ)V");
355
356 GET_METHOD_ID(gCallbacksClassInfo.hackInterceptKey, gCallbacksClassInfo.clazz,
357 "hackInterceptKey", "(IIIIIIJZ)I");
358
359 GET_METHOD_ID(gCallbacksClassInfo.goToSleep, gCallbacksClassInfo.clazz,
360 "goToSleep", "(J)V");
361
362 GET_METHOD_ID(gCallbacksClassInfo.pokeUserActivityForKey, gCallbacksClassInfo.clazz,
363 "pokeUserActivityForKey", "(J)V");
364
365 GET_METHOD_ID(gCallbacksClassInfo.notifyAppSwitchComing, gCallbacksClassInfo.clazz,
366 "notifyAppSwitchComing", "()V");
367
368 GET_METHOD_ID(gCallbacksClassInfo.filterTouchEvents, gCallbacksClassInfo.clazz,
369 "filterTouchEvents", "()Z");
370
371 GET_METHOD_ID(gCallbacksClassInfo.filterJumpyTouchEvents, gCallbacksClassInfo.clazz,
372 "filterJumpyTouchEvents", "()Z");
373
374 GET_METHOD_ID(gCallbacksClassInfo.getVirtualKeyDefinitions, gCallbacksClassInfo.clazz,
375 "getVirtualKeyDefinitions",
376 "(Ljava/lang/String;)[Lcom/android/server/InputManager$VirtualKeyDefinition;");
377
378 GET_METHOD_ID(gCallbacksClassInfo.getExcludedDeviceNames, gCallbacksClassInfo.clazz,
379 "getExcludedDeviceNames", "()[Ljava/lang/String;");
380
381 GET_METHOD_ID(gCallbacksClassInfo.getKeyEventTargets, gCallbacksClassInfo.clazz,
382 "getKeyEventTargets", "(Landroid/view/KeyEvent;II)[Landroid/view/InputTarget;");
383
384 GET_METHOD_ID(gCallbacksClassInfo.getMotionEventTargets, gCallbacksClassInfo.clazz,
385 "getMotionEventTargets", "(Landroid/view/MotionEvent;II)[Landroid/view/InputTarget;");
386
387 // VirtualKeyDefinition
388
389 FIND_CLASS(gVirtualKeyDefinitionClassInfo.clazz,
390 "com/android/server/InputManager$VirtualKeyDefinition");
391
392 GET_FIELD_ID(gVirtualKeyDefinitionClassInfo.scanCode, gVirtualKeyDefinitionClassInfo.clazz,
393 "scanCode", "I");
394
395 GET_FIELD_ID(gVirtualKeyDefinitionClassInfo.centerX, gVirtualKeyDefinitionClassInfo.clazz,
396 "centerX", "I");
397
398 GET_FIELD_ID(gVirtualKeyDefinitionClassInfo.centerY, gVirtualKeyDefinitionClassInfo.clazz,
399 "centerY", "I");
400
401 GET_FIELD_ID(gVirtualKeyDefinitionClassInfo.width, gVirtualKeyDefinitionClassInfo.clazz,
402 "width", "I");
403
404 GET_FIELD_ID(gVirtualKeyDefinitionClassInfo.height, gVirtualKeyDefinitionClassInfo.clazz,
405 "height", "I");
406
407 return 0;
408}
409
410// static functions
411
412static bool isAppSwitchKey(int32_t keyCode) {
413 return keyCode == KEYCODE_HOME || keyCode == KEYCODE_ENDCALL;
414}
415
416static bool checkException(JNIEnv* env, const char* methodName) {
417 if (env->ExceptionCheck()) {
418 LOGE("An exception was thrown by an InputDispatchPolicy callback '%s'.", methodName);
419 LOGE_EX(env);
420 env->ExceptionClear();
421 return true;
422 }
423 return false;
424}
425
426
427// InputDispatchPolicy implementation
428
429InputDispatchPolicy::InputDispatchPolicy(JNIEnv* env, jobject callbacks) :
430 mFilterTouchEvents(-1), mFilterJumpyTouchEvents(-1),
431 mDisplayWidth(-1), mDisplayHeight(-1), mDisplayOrientation(-1) {
432 mCallbacks = env->NewGlobalRef(callbacks);
433}
434
435InputDispatchPolicy::~InputDispatchPolicy() {
436 JNIEnv* env = threadEnv();
437
438 env->DeleteGlobalRef(mCallbacks);
439}
440
441void InputDispatchPolicy::setDisplaySize(int32_t displayId, int32_t width, int32_t height) {
442 if (displayId == 0) {
443 AutoMutex _l(mDisplayLock);
444
445 mDisplayWidth = width;
446 mDisplayHeight = height;
447 }
448}
449
450void InputDispatchPolicy::setDisplayOrientation(int32_t displayId, int32_t orientation) {
451 if (displayId == 0) {
452 AutoMutex _l(mDisplayLock);
453
454 mDisplayOrientation = orientation;
455 }
456}
457
458bool InputDispatchPolicy::getDisplayInfo(int32_t displayId,
459 int32_t* width, int32_t* height, int32_t* orientation) {
460 bool result = false;
461 if (displayId == 0) {
462 AutoMutex _l(mDisplayLock);
463
464 if (mDisplayWidth > 0) {
465 *width = mDisplayWidth;
466 *height = mDisplayHeight;
467 *orientation = mDisplayOrientation;
468 result = true;
469 }
470 }
471 return result;
472}
473
474bool InputDispatchPolicy::isScreenOn() {
475 JNIEnv* env = threadEnv();
476
477 jboolean result = env->CallBooleanMethod(mCallbacks, gCallbacksClassInfo.isScreenOn);
478 if (checkException(env, "isScreenOn")) {
479 return true;
480 }
481 return result;
482}
483
484bool InputDispatchPolicy::isScreenBright() {
485 JNIEnv* env = threadEnv();
486
487 jboolean result = env->CallBooleanMethod(mCallbacks, gCallbacksClassInfo.isScreenBright);
488 if (checkException(env, "isScreenBright")) {
489 return true;
490 }
491 return result;
492}
493
494void InputDispatchPolicy::notifyConfigurationChanged(nsecs_t when,
495 int32_t touchScreenConfig, int32_t keyboardConfig, int32_t navigationConfig) {
496 JNIEnv* env = threadEnv();
497
498 env->CallVoidMethod(mCallbacks, gCallbacksClassInfo.notifyConfigurationChanged,
499 when, touchScreenConfig, keyboardConfig, navigationConfig);
500 checkException(env, "notifyConfigurationChanged");
501}
502
503void InputDispatchPolicy::notifyLidSwitchChanged(nsecs_t when, bool lidOpen) {
504 JNIEnv* env = threadEnv();
505 env->CallVoidMethod(mCallbacks, gCallbacksClassInfo.notifyLidSwitchChanged,
506 when, lidOpen);
507 checkException(env, "notifyLidSwitchChanged");
508}
509
510void InputDispatchPolicy::virtualKeyFeedback(nsecs_t when, int32_t deviceId,
511 int32_t action, int32_t flags, int32_t keyCode,
512 int32_t scanCode, int32_t metaState, nsecs_t downTime) {
513 JNIEnv* env = threadEnv();
514
515 env->CallVoidMethod(mCallbacks, gCallbacksClassInfo.virtualKeyFeedback,
516 when, deviceId, action, flags, keyCode, scanCode, metaState, downTime);
517 checkException(env, "virtualKeyFeedback");
518}
519
520int32_t InputDispatchPolicy::interceptKey(nsecs_t when,
521 int32_t deviceId, bool down, int32_t keyCode, int32_t scanCode, uint32_t policyFlags) {
522 const int32_t WM_ACTION_PASS_TO_USER = 1;
523 const int32_t WM_ACTION_POKE_USER_ACTIVITY = 2;
524 const int32_t WM_ACTION_GO_TO_SLEEP = 4;
525
526 JNIEnv* env = threadEnv();
527
528 bool isScreenOn = this->isScreenOn();
529 bool isScreenBright = this->isScreenBright();
530
531 jint wmActions = env->CallIntMethod(mCallbacks, gCallbacksClassInfo.hackInterceptKey,
532 deviceId, EV_KEY, scanCode, keyCode, policyFlags, down ? 1 : 0, when, isScreenOn);
533 if (checkException(env, "hackInterceptKey")) {
534 wmActions = 0;
535 }
536
537 int32_t actions = ACTION_NONE;
538 if (! isScreenOn) {
539 // Key presses and releases wake the device.
540 actions |= ACTION_WOKE_HERE;
541 }
542
543 if (! isScreenBright) {
544 // Key presses and releases brighten the screen if dimmed.
545 actions |= ACTION_BRIGHT_HERE;
546 }
547
548 if (wmActions & WM_ACTION_GO_TO_SLEEP) {
549 env->CallVoidMethod(mCallbacks, gCallbacksClassInfo.goToSleep, when);
550 checkException(env, "goToSleep");
551 }
552
553 if (wmActions & WM_ACTION_POKE_USER_ACTIVITY) {
554 env->CallVoidMethod(mCallbacks, gCallbacksClassInfo.pokeUserActivityForKey, when);
555 checkException(env, "pokeUserActivityForKey");
556 }
557
558 if (wmActions & WM_ACTION_PASS_TO_USER) {
559 actions |= ACTION_DISPATCH;
560 }
561
562 if (! (wmActions & WM_ACTION_PASS_TO_USER)) {
563 if (down && isAppSwitchKey(keyCode)) {
564 env->CallVoidMethod(mCallbacks, gCallbacksClassInfo.notifyAppSwitchComing);
565 checkException(env, "notifyAppSwitchComing");
566
567 actions |= ACTION_APP_SWITCH_COMING;
568 }
569 }
570 return actions;
571}
572
573int32_t InputDispatchPolicy::interceptTouch(nsecs_t when) {
574 if (! isScreenOn()) {
575 // Touch events do not wake the device.
576 return ACTION_NONE;
577 }
578
579 return ACTION_DISPATCH;
580}
581
582int32_t InputDispatchPolicy::interceptTrackball(nsecs_t when,
583 bool buttonChanged, bool buttonDown, bool rolled) {
584 if (! isScreenOn()) {
585 // Trackball motions and button presses do not wake the device.
586 return ACTION_NONE;
587 }
588
589 return ACTION_DISPATCH;
590}
591
592bool InputDispatchPolicy::filterTouchEvents() {
593 if (mFilterTouchEvents < 0) {
594 JNIEnv* env = threadEnv();
595
596 jboolean result = env->CallBooleanMethod(mCallbacks,
597 gCallbacksClassInfo.filterTouchEvents);
598 if (checkException(env, "filterTouchEvents")) {
599 result = false;
600 }
601
602 mFilterTouchEvents = result ? 1 : 0;
603 }
604 return mFilterTouchEvents;
605}
606
607bool InputDispatchPolicy::filterJumpyTouchEvents() {
608 if (mFilterJumpyTouchEvents < 0) {
609 JNIEnv* env = threadEnv();
610
611 jboolean result = env->CallBooleanMethod(mCallbacks,
612 gCallbacksClassInfo.filterJumpyTouchEvents);
613 if (checkException(env, "filterJumpyTouchEvents")) {
614 result = false;
615 }
616
617 mFilterJumpyTouchEvents = result ? 1 : 0;
618 }
619 return mFilterJumpyTouchEvents;
620}
621
622void InputDispatchPolicy::getVirtualKeyDefinitions(const String8& deviceName,
623 Vector<VirtualKeyDefinition>& outVirtualKeyDefinitions) {
624 JNIEnv* env = threadEnv();
625
626 jstring deviceNameStr = env->NewStringUTF(deviceName.string());
627 if (! checkException(env, "getVirtualKeyDefinitions")) {
628 jobjectArray result = jobjectArray(env->CallObjectMethod(mCallbacks,
629 gCallbacksClassInfo.getVirtualKeyDefinitions, deviceNameStr));
630 if (! checkException(env, "getVirtualKeyDefinitions") && result) {
631 jsize length = env->GetArrayLength(result);
632 for (jsize i = 0; i < length; i++) {
633 jobject item = env->GetObjectArrayElement(result, i);
634
635 outVirtualKeyDefinitions.add();
636 outVirtualKeyDefinitions.editTop().scanCode =
637 int32_t(env->GetIntField(item, gVirtualKeyDefinitionClassInfo.scanCode));
638 outVirtualKeyDefinitions.editTop().centerX =
639 int32_t(env->GetIntField(item, gVirtualKeyDefinitionClassInfo.centerX));
640 outVirtualKeyDefinitions.editTop().centerY =
641 int32_t(env->GetIntField(item, gVirtualKeyDefinitionClassInfo.centerY));
642 outVirtualKeyDefinitions.editTop().width =
643 int32_t(env->GetIntField(item, gVirtualKeyDefinitionClassInfo.width));
644 outVirtualKeyDefinitions.editTop().height =
645 int32_t(env->GetIntField(item, gVirtualKeyDefinitionClassInfo.height));
646
647 env->DeleteLocalRef(item);
648 }
649 env->DeleteLocalRef(result);
650 }
651 env->DeleteLocalRef(deviceNameStr);
652 }
653}
654
655void InputDispatchPolicy::getExcludedDeviceNames(Vector<String8>& outExcludedDeviceNames) {
656 JNIEnv* env = threadEnv();
657
658 jobjectArray result = jobjectArray(env->CallObjectMethod(mCallbacks,
659 gCallbacksClassInfo.getExcludedDeviceNames));
660 if (! checkException(env, "getExcludedDeviceNames") && result) {
661 jsize length = env->GetArrayLength(result);
662 for (jsize i = 0; i < length; i++) {
663 jstring item = jstring(env->GetObjectArrayElement(result, i));
664
665 const char* deviceNameChars = env->GetStringUTFChars(item, NULL);
666 outExcludedDeviceNames.add(String8(deviceNameChars));
667 env->ReleaseStringUTFChars(item, deviceNameChars);
668
669 env->DeleteLocalRef(item);
670 }
671 env->DeleteLocalRef(result);
672 }
673}
674
675bool InputDispatchPolicy::allowKeyRepeat() {
676 // Disable key repeat when the screen is off.
677 return isScreenOn();
678}
679
680nsecs_t InputDispatchPolicy::getKeyRepeatTimeout() {
681 // TODO use ViewConfiguration.getLongPressTimeout()
682 return milliseconds_to_nanoseconds(500);
683}
684
685void InputDispatchPolicy::getKeyEventTargets(KeyEvent* keyEvent, uint32_t policyFlags,
686 Vector<InputTarget>& outTargets) {
687 JNIEnv* env = threadEnv();
688
689 jobject keyEventObj = android_view_KeyEvent_fromNative(env, keyEvent);
690 if (! keyEventObj) {
691 LOGE("Could not obtain DVM KeyEvent object to get key event targets.");
692 } else {
693 jobjectArray result = jobjectArray(env->CallObjectMethod(mCallbacks,
694 gCallbacksClassInfo.getKeyEventTargets,
695 keyEventObj, jint(keyEvent->getNature()), jint(policyFlags)));
696 if (! checkException(env, "getKeyEventTargets") && result) {
697 jsize length = env->GetArrayLength(result);
698 for (jsize i = 0; i < length; i++) {
699 jobject item = env->GetObjectArrayElement(result, i);
700 if (! item) {
701 break; // found null element indicating end of used portion of the array
702 }
703
704 outTargets.add();
705 android_view_InputTarget_toNative(env, item, & outTargets.editTop());
706
707 env->DeleteLocalRef(item);
708 }
709 env->DeleteLocalRef(result);
710 }
711 env->DeleteLocalRef(keyEventObj);
712 }
713}
714
715void InputDispatchPolicy::getMotionEventTargets(MotionEvent* motionEvent, uint32_t policyFlags,
716 Vector<InputTarget>& outTargets) {
717 JNIEnv* env = threadEnv();
718
719 jobject motionEventObj = android_view_MotionEvent_fromNative(env, motionEvent);
720 if (! motionEventObj) {
721 LOGE("Could not obtain DVM MotionEvent object to get key event targets.");
722 } else {
723 jobjectArray result = jobjectArray(env->CallObjectMethod(mCallbacks,
724 gCallbacksClassInfo.getMotionEventTargets,
725 motionEventObj, jint(motionEvent->getNature()), jint(policyFlags)));
726 if (! checkException(env, "getMotionEventTargets") && result) {
727 jsize length = env->GetArrayLength(result);
728 for (jsize i = 0; i < length; i++) {
729 jobject item = env->GetObjectArrayElement(result, i);
730 if (! item) {
731 break; // found null element indicating end of used portion of the array
732 }
733
734 outTargets.add();
735 android_view_InputTarget_toNative(env, item, & outTargets.editTop());
736
737 env->DeleteLocalRef(item);
738 }
739 env->DeleteLocalRef(result);
740 }
741 android_view_MotionEvent_recycle(env, motionEventObj);
742 env->DeleteLocalRef(motionEventObj);
743 }
744}
745
746} /* namespace android */