blob: ab3922f631acebfae0cb0fdf77defa0490f552d6 [file] [log] [blame]
Jeff Brown46b9ac0a2010-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
Jeff Brown9c3cda02010-06-15 01:31:58 -070019//#define LOG_NDEBUG 0
20
21// Log debug messages about InputReaderPolicy
22#define DEBUG_INPUT_READER_POLICY 1
23
24// Log debug messages about InputDispatcherPolicy
25#define DEBUG_INPUT_DISPATCHER_POLICY 1
26
27
Jeff Brown46b9ac0a2010-04-22 18:58:52 -070028#include "JNIHelp.h"
29#include "jni.h"
30#include <android_runtime/AndroidRuntime.h>
Jeff Brown9c3cda02010-06-15 01:31:58 -070031#include <ui/InputReader.h>
32#include <ui/InputDispatcher.h>
Jeff Brown46b9ac0a2010-04-22 18:58:52 -070033#include <ui/InputManager.h>
34#include <ui/InputTransport.h>
35#include <utils/Log.h>
36#include <utils/threads.h>
37#include "../../core/jni/android_view_KeyEvent.h"
38#include "../../core/jni/android_view_MotionEvent.h"
39#include "../../core/jni/android_view_InputChannel.h"
40#include "../../core/jni/android_view_InputTarget.h"
41
42namespace android {
43
Jeff Brown9c3cda02010-06-15 01:31:58 -070044// ----------------------------------------------------------------------------
Jeff Brown46b9ac0a2010-04-22 18:58:52 -070045
46static struct {
47 jclass clazz;
48
49 jmethodID isScreenOn;
50 jmethodID isScreenBright;
51 jmethodID notifyConfigurationChanged;
52 jmethodID notifyLidSwitchChanged;
53 jmethodID virtualKeyFeedback;
54 jmethodID hackInterceptKey;
55 jmethodID goToSleep;
56 jmethodID pokeUserActivityForKey;
57 jmethodID notifyAppSwitchComing;
58 jmethodID filterTouchEvents;
59 jmethodID filterJumpyTouchEvents;
60 jmethodID getVirtualKeyDefinitions;
61 jmethodID getExcludedDeviceNames;
62 jmethodID getKeyEventTargets;
63 jmethodID getMotionEventTargets;
64} gCallbacksClassInfo;
65
66static struct {
67 jclass clazz;
68
69 jfieldID scanCode;
70 jfieldID centerX;
71 jfieldID centerY;
72 jfieldID width;
73 jfieldID height;
74} gVirtualKeyDefinitionClassInfo;
75
Jeff Brown9c3cda02010-06-15 01:31:58 -070076// ----------------------------------------------------------------------------
77
78class NativeInputManager : public virtual RefBase,
79 public virtual InputReaderPolicyInterface,
80 public virtual InputDispatcherPolicyInterface {
81protected:
82 virtual ~NativeInputManager();
83
84public:
85 NativeInputManager(jobject callbacksObj);
86
87 inline sp<InputManager> getInputManager() const { return mInputManager; }
88
89 void setDisplaySize(int32_t displayId, int32_t width, int32_t height);
90 void setDisplayOrientation(int32_t displayId, int32_t orientation);
91
92 /* --- InputReaderPolicyInterface implementation --- */
93
94 virtual bool getDisplayInfo(int32_t displayId,
95 int32_t* width, int32_t* height, int32_t* orientation);
96 virtual void virtualKeyFeedback(nsecs_t when, int32_t deviceId,
97 int32_t action, int32_t flags, int32_t keyCode,
98 int32_t scanCode, int32_t metaState, nsecs_t downTime);
99 virtual int32_t interceptKey(nsecs_t when, int32_t deviceId,
100 bool down, int32_t keyCode, int32_t scanCode, uint32_t policyFlags);
101 virtual int32_t interceptTrackball(nsecs_t when, bool buttonChanged, bool buttonDown,
102 bool rolled);
103 virtual int32_t interceptTouch(nsecs_t when);
104 virtual int32_t interceptSwitch(nsecs_t when, int32_t switchCode, int32_t switchValue);
105 virtual bool filterTouchEvents();
106 virtual bool filterJumpyTouchEvents();
107 virtual void getVirtualKeyDefinitions(const String8& deviceName,
108 Vector<InputReaderPolicyInterface::VirtualKeyDefinition>& outVirtualKeyDefinitions);
109 virtual void getExcludedDeviceNames(Vector<String8>& outExcludedDeviceNames);
110
111 /* --- InputDispatcherPolicyInterface implementation --- */
112
113 virtual void notifyConfigurationChanged(nsecs_t when);
114 virtual void notifyInputChannelBroken(const sp<InputChannel>& inputChannel);
115 virtual void notifyInputChannelANR(const sp<InputChannel>& inputChannel);
116 virtual void notifyInputChannelRecoveredFromANR(const sp<InputChannel>& inputChannel);
117 virtual nsecs_t getKeyRepeatTimeout();
118 virtual void getKeyEventTargets(KeyEvent* keyEvent, uint32_t policyFlags,
119 Vector<InputTarget>& outTargets);
120 virtual void getMotionEventTargets(MotionEvent* motionEvent, uint32_t policyFlags,
121 Vector<InputTarget>& outTargets);
122
123private:
124 sp<InputManager> mInputManager;
125
126 jobject mCallbacksObj;
127
128 // Cached filtering policies.
129 int32_t mFilterTouchEvents;
130 int32_t mFilterJumpyTouchEvents;
131
132 // Cached display state. (lock mDisplayLock)
133 Mutex mDisplayLock;
134 int32_t mDisplayWidth, mDisplayHeight;
135 int32_t mDisplayOrientation;
136
137 // Callbacks.
138 bool isScreenOn();
139 bool isScreenBright();
140
141 static inline JNIEnv* jniEnv() {
142 return AndroidRuntime::getJNIEnv();
143 }
144
145 static bool isAppSwitchKey(int32_t keyCode);
146 static bool checkExceptionFromCallback(JNIEnv* env, const char* methodName);
147};
148
149// ----------------------------------------------------------------------------
150
151NativeInputManager::NativeInputManager(jobject callbacksObj) :
152 mFilterTouchEvents(-1), mFilterJumpyTouchEvents(-1),
153 mDisplayWidth(-1), mDisplayHeight(-1), mDisplayOrientation(-1) {
154 JNIEnv* env = jniEnv();
155
156 mCallbacksObj = env->NewGlobalRef(callbacksObj);
157
158 sp<EventHub> eventHub = new EventHub();
159 mInputManager = new InputManager(eventHub, this, this);
160}
161
162NativeInputManager::~NativeInputManager() {
163 JNIEnv* env = jniEnv();
164
165 env->DeleteGlobalRef(mCallbacksObj);
166}
167
168bool NativeInputManager::isAppSwitchKey(int32_t keyCode) {
169 return keyCode == KEYCODE_HOME || keyCode == KEYCODE_ENDCALL;
170}
171
172bool NativeInputManager::checkExceptionFromCallback(JNIEnv* env, const char* methodName) {
173 if (env->ExceptionCheck()) {
174 LOGE("An exception was thrown by callback '%s'.", methodName);
175 LOGE_EX(env);
176 env->ExceptionClear();
177 return true;
178 }
179 return false;
180}
181
182void NativeInputManager::setDisplaySize(int32_t displayId, int32_t width, int32_t height) {
183 if (displayId == 0) {
184 AutoMutex _l(mDisplayLock);
185
186 mDisplayWidth = width;
187 mDisplayHeight = height;
188 }
189}
190
191void NativeInputManager::setDisplayOrientation(int32_t displayId, int32_t orientation) {
192 if (displayId == 0) {
193 AutoMutex _l(mDisplayLock);
194
195 mDisplayOrientation = orientation;
196 }
197}
198
199bool NativeInputManager::getDisplayInfo(int32_t displayId,
200 int32_t* width, int32_t* height, int32_t* orientation) {
201 bool result = false;
202 if (displayId == 0) {
203 AutoMutex _l(mDisplayLock);
204
205 if (mDisplayWidth > 0) {
206 *width = mDisplayWidth;
207 *height = mDisplayHeight;
208 *orientation = mDisplayOrientation;
209 result = true;
210 }
211 }
212 return result;
213}
214
215bool NativeInputManager::isScreenOn() {
216 JNIEnv* env = jniEnv();
217
218 jboolean result = env->CallBooleanMethod(mCallbacksObj, gCallbacksClassInfo.isScreenOn);
219 if (checkExceptionFromCallback(env, "isScreenOn")) {
220 return true;
221 }
222 return result;
223}
224
225bool NativeInputManager::isScreenBright() {
226 JNIEnv* env = jniEnv();
227
228 jboolean result = env->CallBooleanMethod(mCallbacksObj, gCallbacksClassInfo.isScreenBright);
229 if (checkExceptionFromCallback(env, "isScreenBright")) {
230 return true;
231 }
232 return result;
233}
234
235void NativeInputManager::virtualKeyFeedback(nsecs_t when, int32_t deviceId,
236 int32_t action, int32_t flags, int32_t keyCode,
237 int32_t scanCode, int32_t metaState, nsecs_t downTime) {
238#if DEBUG_INPUT_READER_POLICY
239 LOGD("virtualKeyFeedback - when=%lld, deviceId=%d, action=%d, flags=%d, keyCode=%d, "
240 "scanCode=%d, metaState=%d, downTime=%lld",
241 when, deviceId, action, flags, keyCode, scanCode, metaState, downTime);
242#endif
243
244 JNIEnv* env = jniEnv();
245
246 env->CallVoidMethod(mCallbacksObj, gCallbacksClassInfo.virtualKeyFeedback,
247 when, deviceId, action, flags, keyCode, scanCode, metaState, downTime);
248 checkExceptionFromCallback(env, "virtualKeyFeedback");
249}
250
251int32_t NativeInputManager::interceptKey(nsecs_t when,
252 int32_t deviceId, bool down, int32_t keyCode, int32_t scanCode, uint32_t policyFlags) {
253#if DEBUG_INPUT_READER_POLICY
254 LOGD("interceptKey - when=%lld, deviceId=%d, down=%d, keyCode=%d, scanCode=%d, "
255 "policyFlags=%d",
256 when, deviceId, down, keyCode, scanCode, policyFlags);
257#endif
258
259 const int32_t WM_ACTION_PASS_TO_USER = 1;
260 const int32_t WM_ACTION_POKE_USER_ACTIVITY = 2;
261 const int32_t WM_ACTION_GO_TO_SLEEP = 4;
262
263 JNIEnv* env = jniEnv();
264
265 bool isScreenOn = this->isScreenOn();
266 bool isScreenBright = this->isScreenBright();
267
268 jint wmActions = env->CallIntMethod(mCallbacksObj, gCallbacksClassInfo.hackInterceptKey,
269 deviceId, EV_KEY, scanCode, keyCode, policyFlags, down ? 1 : 0, when, isScreenOn);
270 if (checkExceptionFromCallback(env, "hackInterceptKey")) {
271 wmActions = 0;
272 }
273
274 int32_t actions = InputReaderPolicyInterface::ACTION_NONE;
275 if (! isScreenOn) {
276 // Key presses and releases wake the device.
277 actions |= InputReaderPolicyInterface::ACTION_WOKE_HERE;
278 }
279
280 if (! isScreenBright) {
281 // Key presses and releases brighten the screen if dimmed.
282 actions |= InputReaderPolicyInterface::ACTION_BRIGHT_HERE;
283 }
284
285 if (wmActions & WM_ACTION_GO_TO_SLEEP) {
286 env->CallVoidMethod(mCallbacksObj, gCallbacksClassInfo.goToSleep, when);
287 checkExceptionFromCallback(env, "goToSleep");
288 }
289
290 if (wmActions & WM_ACTION_POKE_USER_ACTIVITY) {
291 env->CallVoidMethod(mCallbacksObj, gCallbacksClassInfo.pokeUserActivityForKey, when);
292 checkExceptionFromCallback(env, "pokeUserActivityForKey");
293 }
294
295 if (wmActions & WM_ACTION_PASS_TO_USER) {
296 actions |= InputReaderPolicyInterface::ACTION_DISPATCH;
Jeff Brown9c3cda02010-06-15 01:31:58 -0700297
Jeff Brown9c3cda02010-06-15 01:31:58 -0700298 if (down && isAppSwitchKey(keyCode)) {
299 env->CallVoidMethod(mCallbacksObj, gCallbacksClassInfo.notifyAppSwitchComing);
300 checkExceptionFromCallback(env, "notifyAppSwitchComing");
301
302 actions |= InputReaderPolicyInterface::ACTION_APP_SWITCH_COMING;
303 }
304 }
305 return actions;
306}
307
308int32_t NativeInputManager::interceptTouch(nsecs_t when) {
309#if DEBUG_INPUT_READER_POLICY
310 LOGD("interceptTouch - when=%lld", when);
311#endif
312
Jeff Brown5c225b12010-06-16 01:53:36 -0700313 int32_t actions = InputReaderPolicyInterface::ACTION_NONE;
314 if (isScreenOn()) {
315 // Only dispatch touch events when the device is awake.
316 actions |= InputReaderPolicyInterface::ACTION_DISPATCH;
Jeff Brown9c3cda02010-06-15 01:31:58 -0700317 }
318
Jeff Brown5c225b12010-06-16 01:53:36 -0700319 if (! isScreenBright()) {
320 // Brighten the screen if dimmed.
321 actions |= InputReaderPolicyInterface::ACTION_BRIGHT_HERE;
322 }
323
324 return actions;
Jeff Brown9c3cda02010-06-15 01:31:58 -0700325}
326
327int32_t NativeInputManager::interceptTrackball(nsecs_t when,
328 bool buttonChanged, bool buttonDown, bool rolled) {
329#if DEBUG_INPUT_READER_POLICY
330 LOGD("interceptTrackball - when=%lld, buttonChanged=%d, buttonDown=%d, rolled=%d",
331 when, buttonChanged, buttonDown, rolled);
332#endif
333
Jeff Brown5c225b12010-06-16 01:53:36 -0700334 int32_t actions = InputReaderPolicyInterface::ACTION_NONE;
335 if (isScreenOn()) {
336 // Only dispatch trackball events when the device is awake.
337 actions |= InputReaderPolicyInterface::ACTION_DISPATCH;
Jeff Brown9c3cda02010-06-15 01:31:58 -0700338 }
339
Jeff Brown5c225b12010-06-16 01:53:36 -0700340 if (! isScreenBright()) {
341 // Brighten the screen if dimmed.
342 actions |= InputReaderPolicyInterface::ACTION_BRIGHT_HERE;
343 }
344
345 return actions;
Jeff Brown9c3cda02010-06-15 01:31:58 -0700346}
347
348int32_t NativeInputManager::interceptSwitch(nsecs_t when, int32_t switchCode,
349 int32_t switchValue) {
350#if DEBUG_INPUT_READER_POLICY
351 LOGD("interceptSwitch - when=%lld, switchCode=%d, switchValue=%d",
352 when, switchCode, switchValue);
353#endif
354
355 JNIEnv* env = jniEnv();
356
357 switch (switchCode) {
358 case SW_LID:
359 env->CallVoidMethod(mCallbacksObj, gCallbacksClassInfo.notifyLidSwitchChanged,
360 when, switchValue == 0);
361 checkExceptionFromCallback(env, "notifyLidSwitchChanged");
362 break;
363 }
364
365 return InputReaderPolicyInterface::ACTION_NONE;
366}
367
368bool NativeInputManager::filterTouchEvents() {
369 if (mFilterTouchEvents < 0) {
370 JNIEnv* env = jniEnv();
371
372 jboolean result = env->CallBooleanMethod(mCallbacksObj,
373 gCallbacksClassInfo.filterTouchEvents);
374 if (checkExceptionFromCallback(env, "filterTouchEvents")) {
375 result = false;
376 }
377
378 mFilterTouchEvents = result ? 1 : 0;
379 }
380 return mFilterTouchEvents;
381}
382
383bool NativeInputManager::filterJumpyTouchEvents() {
384 if (mFilterJumpyTouchEvents < 0) {
385 JNIEnv* env = jniEnv();
386
387 jboolean result = env->CallBooleanMethod(mCallbacksObj,
388 gCallbacksClassInfo.filterJumpyTouchEvents);
389 if (checkExceptionFromCallback(env, "filterJumpyTouchEvents")) {
390 result = false;
391 }
392
393 mFilterJumpyTouchEvents = result ? 1 : 0;
394 }
395 return mFilterJumpyTouchEvents;
396}
397
398void NativeInputManager::getVirtualKeyDefinitions(const String8& deviceName,
399 Vector<InputReaderPolicyInterface::VirtualKeyDefinition>& outVirtualKeyDefinitions) {
400 JNIEnv* env = jniEnv();
401
402 jstring deviceNameStr = env->NewStringUTF(deviceName.string());
403 if (! checkExceptionFromCallback(env, "getVirtualKeyDefinitions")) {
404 jobjectArray result = jobjectArray(env->CallObjectMethod(mCallbacksObj,
405 gCallbacksClassInfo.getVirtualKeyDefinitions, deviceNameStr));
406 if (! checkExceptionFromCallback(env, "getVirtualKeyDefinitions") && result) {
407 jsize length = env->GetArrayLength(result);
408 for (jsize i = 0; i < length; i++) {
409 jobject item = env->GetObjectArrayElement(result, i);
410
411 outVirtualKeyDefinitions.add();
412 outVirtualKeyDefinitions.editTop().scanCode =
413 int32_t(env->GetIntField(item, gVirtualKeyDefinitionClassInfo.scanCode));
414 outVirtualKeyDefinitions.editTop().centerX =
415 int32_t(env->GetIntField(item, gVirtualKeyDefinitionClassInfo.centerX));
416 outVirtualKeyDefinitions.editTop().centerY =
417 int32_t(env->GetIntField(item, gVirtualKeyDefinitionClassInfo.centerY));
418 outVirtualKeyDefinitions.editTop().width =
419 int32_t(env->GetIntField(item, gVirtualKeyDefinitionClassInfo.width));
420 outVirtualKeyDefinitions.editTop().height =
421 int32_t(env->GetIntField(item, gVirtualKeyDefinitionClassInfo.height));
422
423 env->DeleteLocalRef(item);
424 }
425 env->DeleteLocalRef(result);
426 }
427 env->DeleteLocalRef(deviceNameStr);
428 }
429}
430
431void NativeInputManager::getExcludedDeviceNames(Vector<String8>& outExcludedDeviceNames) {
432 JNIEnv* env = jniEnv();
433
434 jobjectArray result = jobjectArray(env->CallObjectMethod(mCallbacksObj,
435 gCallbacksClassInfo.getExcludedDeviceNames));
436 if (! checkExceptionFromCallback(env, "getExcludedDeviceNames") && result) {
437 jsize length = env->GetArrayLength(result);
438 for (jsize i = 0; i < length; i++) {
439 jstring item = jstring(env->GetObjectArrayElement(result, i));
440
441 const char* deviceNameChars = env->GetStringUTFChars(item, NULL);
442 outExcludedDeviceNames.add(String8(deviceNameChars));
443 env->ReleaseStringUTFChars(item, deviceNameChars);
444
445 env->DeleteLocalRef(item);
446 }
447 env->DeleteLocalRef(result);
448 }
449}
450
451void NativeInputManager::notifyConfigurationChanged(nsecs_t when) {
452#if DEBUG_INPUT_DISPATCHER_POLICY
453 LOGD("notifyConfigurationChanged - when=%lld", when);
454#endif
455
456 JNIEnv* env = jniEnv();
457
458 InputConfiguration config;
459 mInputManager->getInputConfiguration(& config);
460
461 env->CallVoidMethod(mCallbacksObj, gCallbacksClassInfo.notifyConfigurationChanged,
462 when, config.touchScreen, config.keyboard, config.navigation);
463 checkExceptionFromCallback(env, "notifyConfigurationChanged");
464}
465
466void NativeInputManager::notifyInputChannelBroken(const sp<InputChannel>& inputChannel) {
467#if DEBUG_INPUT_DISPATCHER_POLICY
468 LOGD("notifyInputChannelBroken - inputChannel='%s'", inputChannel->getName().string());
469#endif
470
471 // TODO
472}
473
474void NativeInputManager::notifyInputChannelANR(const sp<InputChannel>& inputChannel) {
475#if DEBUG_INPUT_DISPATCHER_POLICY
476 LOGD("notifyInputChannelANR - inputChannel='%s'",
477 inputChannel->getName().string());
478#endif
479
480 // TODO
481}
482
483void NativeInputManager::notifyInputChannelRecoveredFromANR(const sp<InputChannel>& inputChannel) {
484#if DEBUG_INPUT_DISPATCHER_POLICY
485 LOGD("notifyInputChannelRecoveredFromANR - inputChannel='%s'",
486 inputChannel->getName().string());
487#endif
488
489 // TODO
490}
491
492nsecs_t NativeInputManager::getKeyRepeatTimeout() {
493 if (! isScreenOn()) {
494 // Disable key repeat when the screen is off.
495 return -1;
496 } else {
497 // TODO use ViewConfiguration.getLongPressTimeout()
498 return milliseconds_to_nanoseconds(500);
499 }
500}
501
502void NativeInputManager::getKeyEventTargets(KeyEvent* keyEvent, uint32_t policyFlags,
503 Vector<InputTarget>& outTargets) {
504#if DEBUG_INPUT_DISPATCHER_POLICY
505 LOGD("getKeyEventTargets - policyFlags=%d", policyFlags);
506#endif
507
508 JNIEnv* env = jniEnv();
509
510 jobject keyEventObj = android_view_KeyEvent_fromNative(env, keyEvent);
511 if (! keyEventObj) {
512 LOGE("Could not obtain DVM KeyEvent object to get key event targets.");
513 } else {
514 jobjectArray result = jobjectArray(env->CallObjectMethod(mCallbacksObj,
515 gCallbacksClassInfo.getKeyEventTargets,
516 keyEventObj, jint(keyEvent->getNature()), jint(policyFlags)));
517 if (! checkExceptionFromCallback(env, "getKeyEventTargets") && result) {
518 jsize length = env->GetArrayLength(result);
519 for (jsize i = 0; i < length; i++) {
520 jobject item = env->GetObjectArrayElement(result, i);
521 if (! item) {
522 break; // found null element indicating end of used portion of the array
523 }
524
525 outTargets.add();
526 android_view_InputTarget_toNative(env, item, & outTargets.editTop());
527
528 env->DeleteLocalRef(item);
529 }
530 env->DeleteLocalRef(result);
531 }
532 env->DeleteLocalRef(keyEventObj);
533 }
534}
535
536void NativeInputManager::getMotionEventTargets(MotionEvent* motionEvent, uint32_t policyFlags,
537 Vector<InputTarget>& outTargets) {
538#if DEBUG_INPUT_DISPATCHER_POLICY
539 LOGD("getMotionEventTargets - policyFlags=%d", policyFlags);
540#endif
541
542 JNIEnv* env = jniEnv();
543
544 jobject motionEventObj = android_view_MotionEvent_fromNative(env, motionEvent);
545 if (! motionEventObj) {
546 LOGE("Could not obtain DVM MotionEvent object to get key event targets.");
547 } else {
548 jobjectArray result = jobjectArray(env->CallObjectMethod(mCallbacksObj,
549 gCallbacksClassInfo.getMotionEventTargets,
550 motionEventObj, jint(motionEvent->getNature()), jint(policyFlags)));
551 if (! checkExceptionFromCallback(env, "getMotionEventTargets") && result) {
552 jsize length = env->GetArrayLength(result);
553 for (jsize i = 0; i < length; i++) {
554 jobject item = env->GetObjectArrayElement(result, i);
555 if (! item) {
556 break; // found null element indicating end of used portion of the array
557 }
558
559 outTargets.add();
560 android_view_InputTarget_toNative(env, item, & outTargets.editTop());
561
562 env->DeleteLocalRef(item);
563 }
564 env->DeleteLocalRef(result);
565 }
566 android_view_MotionEvent_recycle(env, motionEventObj);
567 env->DeleteLocalRef(motionEventObj);
568 }
569}
570
571
572// ----------------------------------------------------------------------------
573
574static sp<NativeInputManager> gNativeInputManager;
575
Jeff Brown46b9ac0a2010-04-22 18:58:52 -0700576static bool checkInputManagerUnitialized(JNIEnv* env) {
Jeff Brown9c3cda02010-06-15 01:31:58 -0700577 if (gNativeInputManager == NULL) {
Jeff Brown46b9ac0a2010-04-22 18:58:52 -0700578 LOGE("Input manager not initialized.");
579 jniThrowRuntimeException(env, "Input manager not initialized.");
580 return true;
581 }
582 return false;
583}
584
585static void android_server_InputManager_nativeInit(JNIEnv* env, jclass clazz,
586 jobject callbacks) {
Jeff Brown9c3cda02010-06-15 01:31:58 -0700587 if (gNativeInputManager == NULL) {
588 gNativeInputManager = new NativeInputManager(callbacks);
589 } else {
590 LOGE("Input manager already initialized.");
591 jniThrowRuntimeException(env, "Input manager already initialized.");
Jeff Brown46b9ac0a2010-04-22 18:58:52 -0700592 }
593}
594
595static void android_server_InputManager_nativeStart(JNIEnv* env, jclass clazz) {
596 if (checkInputManagerUnitialized(env)) {
597 return;
598 }
599
Jeff Brown9c3cda02010-06-15 01:31:58 -0700600 status_t result = gNativeInputManager->getInputManager()->start();
Jeff Brown46b9ac0a2010-04-22 18:58:52 -0700601 if (result) {
602 jniThrowRuntimeException(env, "Input manager could not be started.");
603 }
604}
605
606static void android_server_InputManager_nativeSetDisplaySize(JNIEnv* env, jclass clazz,
607 jint displayId, jint width, jint height) {
608 if (checkInputManagerUnitialized(env)) {
609 return;
610 }
611
612 // XXX we could get this from the SurfaceFlinger directly instead of requiring it
613 // to be passed in like this, not sure which is better but leaving it like this
614 // keeps the window manager in direct control of when display transitions propagate down
615 // to the input dispatcher
Jeff Brown9c3cda02010-06-15 01:31:58 -0700616 gNativeInputManager->setDisplaySize(displayId, width, height);
Jeff Brown46b9ac0a2010-04-22 18:58:52 -0700617}
618
619static void android_server_InputManager_nativeSetDisplayOrientation(JNIEnv* env, jclass clazz,
620 jint displayId, jint orientation) {
621 if (checkInputManagerUnitialized(env)) {
622 return;
623 }
624
Jeff Brown9c3cda02010-06-15 01:31:58 -0700625 gNativeInputManager->setDisplayOrientation(displayId, orientation);
Jeff Brown46b9ac0a2010-04-22 18:58:52 -0700626}
627
628static jint android_server_InputManager_nativeGetScanCodeState(JNIEnv* env, jclass clazz,
629 jint deviceId, jint deviceClasses, jint scanCode) {
630 if (checkInputManagerUnitialized(env)) {
631 return KEY_STATE_UNKNOWN;
632 }
633
Jeff Brown9c3cda02010-06-15 01:31:58 -0700634 return gNativeInputManager->getInputManager()->getScanCodeState(
635 deviceId, deviceClasses, scanCode);
Jeff Brown46b9ac0a2010-04-22 18:58:52 -0700636}
637
638static jint android_server_InputManager_nativeGetKeyCodeState(JNIEnv* env, jclass clazz,
639 jint deviceId, jint deviceClasses, jint keyCode) {
640 if (checkInputManagerUnitialized(env)) {
641 return KEY_STATE_UNKNOWN;
642 }
643
Jeff Brown9c3cda02010-06-15 01:31:58 -0700644 return gNativeInputManager->getInputManager()->getKeyCodeState(
645 deviceId, deviceClasses, keyCode);
Jeff Brown46b9ac0a2010-04-22 18:58:52 -0700646}
647
648static jint android_server_InputManager_nativeGetSwitchState(JNIEnv* env, jclass clazz,
649 jint deviceId, jint deviceClasses, jint sw) {
650 if (checkInputManagerUnitialized(env)) {
651 return KEY_STATE_UNKNOWN;
652 }
653
Jeff Brown9c3cda02010-06-15 01:31:58 -0700654 return gNativeInputManager->getInputManager()->getSwitchState(deviceId, deviceClasses, sw);
Jeff Brown46b9ac0a2010-04-22 18:58:52 -0700655}
656
657static jboolean android_server_InputManager_nativeHasKeys(JNIEnv* env, jclass clazz,
658 jintArray keyCodes, jbooleanArray outFlags) {
659 if (checkInputManagerUnitialized(env)) {
660 return JNI_FALSE;
661 }
662
663 int32_t* codes = env->GetIntArrayElements(keyCodes, NULL);
664 uint8_t* flags = env->GetBooleanArrayElements(outFlags, NULL);
665 jsize numCodes = env->GetArrayLength(keyCodes);
666 jboolean result;
667 if (numCodes == env->GetArrayLength(outFlags)) {
Jeff Brown9c3cda02010-06-15 01:31:58 -0700668 result = gNativeInputManager->getInputManager()->hasKeys(numCodes, codes, flags);
Jeff Brown46b9ac0a2010-04-22 18:58:52 -0700669 } else {
670 result = JNI_FALSE;
671 }
672
673 env->ReleaseBooleanArrayElements(outFlags, flags, 0);
674 env->ReleaseIntArrayElements(keyCodes, codes, 0);
675 return result;
676}
677
678static void throwInputChannelNotInitialized(JNIEnv* env) {
679 jniThrowException(env, "java/lang/IllegalStateException",
680 "inputChannel is not initialized");
681}
682
683static void android_server_InputManager_handleInputChannelDisposed(JNIEnv* env,
684 jobject inputChannelObj, const sp<InputChannel>& inputChannel, void* data) {
685 LOGW("Input channel object '%s' was disposed without first being unregistered with "
686 "the input manager!", inputChannel->getName().string());
687
Jeff Brown9c3cda02010-06-15 01:31:58 -0700688 if (gNativeInputManager != NULL) {
689 gNativeInputManager->getInputManager()->unregisterInputChannel(inputChannel);
690 }
Jeff Brown46b9ac0a2010-04-22 18:58:52 -0700691}
692
693static void android_server_InputManager_nativeRegisterInputChannel(JNIEnv* env, jclass clazz,
694 jobject inputChannelObj) {
695 if (checkInputManagerUnitialized(env)) {
696 return;
697 }
698
699 sp<InputChannel> inputChannel = android_view_InputChannel_getInputChannel(env,
700 inputChannelObj);
701 if (inputChannel == NULL) {
702 throwInputChannelNotInitialized(env);
703 return;
704 }
705
Jeff Brown9c3cda02010-06-15 01:31:58 -0700706 status_t status = gNativeInputManager->getInputManager()->registerInputChannel(inputChannel);
Jeff Brown46b9ac0a2010-04-22 18:58:52 -0700707 if (status) {
708 jniThrowRuntimeException(env, "Failed to register input channel. "
709 "Check logs for details.");
710 return;
711 }
712
713 android_view_InputChannel_setDisposeCallback(env, inputChannelObj,
714 android_server_InputManager_handleInputChannelDisposed, NULL);
715}
716
717static void android_server_InputManager_nativeUnregisterInputChannel(JNIEnv* env, jclass clazz,
718 jobject inputChannelObj) {
719 if (checkInputManagerUnitialized(env)) {
720 return;
721 }
722
723 sp<InputChannel> inputChannel = android_view_InputChannel_getInputChannel(env,
724 inputChannelObj);
725 if (inputChannel == NULL) {
726 throwInputChannelNotInitialized(env);
727 return;
728 }
729
730 android_view_InputChannel_setDisposeCallback(env, inputChannelObj, NULL, NULL);
731
Jeff Brown9c3cda02010-06-15 01:31:58 -0700732 status_t status = gNativeInputManager->getInputManager()->unregisterInputChannel(inputChannel);
Jeff Brown46b9ac0a2010-04-22 18:58:52 -0700733 if (status) {
734 jniThrowRuntimeException(env, "Failed to unregister input channel. "
735 "Check logs for details.");
736 }
737}
738
Jeff Brown9c3cda02010-06-15 01:31:58 -0700739// ----------------------------------------------------------------------------
740
Jeff Brown46b9ac0a2010-04-22 18:58:52 -0700741static JNINativeMethod gInputManagerMethods[] = {
742 /* name, signature, funcPtr */
743 { "nativeInit", "(Lcom/android/server/InputManager$Callbacks;)V",
744 (void*) android_server_InputManager_nativeInit },
745 { "nativeStart", "()V",
746 (void*) android_server_InputManager_nativeStart },
747 { "nativeSetDisplaySize", "(III)V",
748 (void*) android_server_InputManager_nativeSetDisplaySize },
749 { "nativeSetDisplayOrientation", "(II)V",
750 (void*) android_server_InputManager_nativeSetDisplayOrientation },
751 { "nativeGetScanCodeState", "(III)I",
752 (void*) android_server_InputManager_nativeGetScanCodeState },
753 { "nativeGetKeyCodeState", "(III)I",
754 (void*) android_server_InputManager_nativeGetKeyCodeState },
755 { "nativeGetSwitchState", "(III)I",
756 (void*) android_server_InputManager_nativeGetSwitchState },
757 { "nativeHasKeys", "([I[Z)Z",
758 (void*) android_server_InputManager_nativeHasKeys },
759 { "nativeRegisterInputChannel", "(Landroid/view/InputChannel;)V",
760 (void*) android_server_InputManager_nativeRegisterInputChannel },
761 { "nativeUnregisterInputChannel", "(Landroid/view/InputChannel;)V",
762 (void*) android_server_InputManager_nativeUnregisterInputChannel }
763};
764
765#define FIND_CLASS(var, className) \
766 var = env->FindClass(className); \
767 LOG_FATAL_IF(! var, "Unable to find class " className); \
768 var = jclass(env->NewGlobalRef(var));
769
770#define GET_METHOD_ID(var, clazz, methodName, methodDescriptor) \
771 var = env->GetMethodID(clazz, methodName, methodDescriptor); \
772 LOG_FATAL_IF(! var, "Unable to find method " methodName);
773
774#define GET_FIELD_ID(var, clazz, fieldName, fieldDescriptor) \
775 var = env->GetFieldID(clazz, fieldName, fieldDescriptor); \
776 LOG_FATAL_IF(! var, "Unable to find field " fieldName);
777
778int register_android_server_InputManager(JNIEnv* env) {
779 int res = jniRegisterNativeMethods(env, "com/android/server/InputManager",
780 gInputManagerMethods, NELEM(gInputManagerMethods));
781 LOG_FATAL_IF(res < 0, "Unable to register native methods.");
782
Jeff Brown9c3cda02010-06-15 01:31:58 -0700783 // Callbacks
Jeff Brown46b9ac0a2010-04-22 18:58:52 -0700784
785 FIND_CLASS(gCallbacksClassInfo.clazz, "com/android/server/InputManager$Callbacks");
786
787 GET_METHOD_ID(gCallbacksClassInfo.isScreenOn, gCallbacksClassInfo.clazz,
788 "isScreenOn", "()Z");
789
790 GET_METHOD_ID(gCallbacksClassInfo.isScreenBright, gCallbacksClassInfo.clazz,
791 "isScreenBright", "()Z");
792
793 GET_METHOD_ID(gCallbacksClassInfo.notifyConfigurationChanged, gCallbacksClassInfo.clazz,
794 "notifyConfigurationChanged", "(JIII)V");
795
796 GET_METHOD_ID(gCallbacksClassInfo.notifyLidSwitchChanged, gCallbacksClassInfo.clazz,
797 "notifyLidSwitchChanged", "(JZ)V");
798
799 GET_METHOD_ID(gCallbacksClassInfo.virtualKeyFeedback, gCallbacksClassInfo.clazz,
800 "virtualKeyFeedback", "(JIIIIIIJ)V");
801
802 GET_METHOD_ID(gCallbacksClassInfo.hackInterceptKey, gCallbacksClassInfo.clazz,
803 "hackInterceptKey", "(IIIIIIJZ)I");
804
805 GET_METHOD_ID(gCallbacksClassInfo.goToSleep, gCallbacksClassInfo.clazz,
806 "goToSleep", "(J)V");
807
808 GET_METHOD_ID(gCallbacksClassInfo.pokeUserActivityForKey, gCallbacksClassInfo.clazz,
809 "pokeUserActivityForKey", "(J)V");
810
811 GET_METHOD_ID(gCallbacksClassInfo.notifyAppSwitchComing, gCallbacksClassInfo.clazz,
812 "notifyAppSwitchComing", "()V");
813
814 GET_METHOD_ID(gCallbacksClassInfo.filterTouchEvents, gCallbacksClassInfo.clazz,
815 "filterTouchEvents", "()Z");
816
817 GET_METHOD_ID(gCallbacksClassInfo.filterJumpyTouchEvents, gCallbacksClassInfo.clazz,
818 "filterJumpyTouchEvents", "()Z");
819
820 GET_METHOD_ID(gCallbacksClassInfo.getVirtualKeyDefinitions, gCallbacksClassInfo.clazz,
821 "getVirtualKeyDefinitions",
822 "(Ljava/lang/String;)[Lcom/android/server/InputManager$VirtualKeyDefinition;");
823
824 GET_METHOD_ID(gCallbacksClassInfo.getExcludedDeviceNames, gCallbacksClassInfo.clazz,
825 "getExcludedDeviceNames", "()[Ljava/lang/String;");
826
827 GET_METHOD_ID(gCallbacksClassInfo.getKeyEventTargets, gCallbacksClassInfo.clazz,
828 "getKeyEventTargets", "(Landroid/view/KeyEvent;II)[Landroid/view/InputTarget;");
829
830 GET_METHOD_ID(gCallbacksClassInfo.getMotionEventTargets, gCallbacksClassInfo.clazz,
831 "getMotionEventTargets", "(Landroid/view/MotionEvent;II)[Landroid/view/InputTarget;");
832
833 // VirtualKeyDefinition
834
835 FIND_CLASS(gVirtualKeyDefinitionClassInfo.clazz,
836 "com/android/server/InputManager$VirtualKeyDefinition");
837
838 GET_FIELD_ID(gVirtualKeyDefinitionClassInfo.scanCode, gVirtualKeyDefinitionClassInfo.clazz,
839 "scanCode", "I");
840
841 GET_FIELD_ID(gVirtualKeyDefinitionClassInfo.centerX, gVirtualKeyDefinitionClassInfo.clazz,
842 "centerX", "I");
843
844 GET_FIELD_ID(gVirtualKeyDefinitionClassInfo.centerY, gVirtualKeyDefinitionClassInfo.clazz,
845 "centerY", "I");
846
847 GET_FIELD_ID(gVirtualKeyDefinitionClassInfo.width, gVirtualKeyDefinitionClassInfo.clazz,
848 "width", "I");
849
850 GET_FIELD_ID(gVirtualKeyDefinitionClassInfo.height, gVirtualKeyDefinitionClassInfo.clazz,
851 "height", "I");
852
853 return 0;
854}
855
Jeff Brown46b9ac0a2010-04-22 18:58:52 -0700856} /* namespace android */