com_android_server_input_InputManagerService.cpp revision 603b44589682db3ff33ade172facb0c5e309f1be
1/*
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//#define LOG_NDEBUG 0
20
21// Log debug messages about InputReaderPolicy
22#define DEBUG_INPUT_READER_POLICY 0
23
24// Log debug messages about InputDispatcherPolicy
25#define DEBUG_INPUT_DISPATCHER_POLICY 0
26
27
28#include "JNIHelp.h"
29#include "jni.h"
30#include <limits.h>
31#include <android_runtime/AndroidRuntime.h>
32
33#include <utils/Log.h>
34#include <utils/Looper.h>
35#include <utils/threads.h>
36
37#include <input/InputManager.h>
38#include <input/PointerController.h>
39#include <input/SpriteController.h>
40
41#include <android_os_MessageQueue.h>
42#include <android_view_KeyEvent.h>
43#include <android_view_MotionEvent.h>
44#include <android_view_InputChannel.h>
45#include <android_view_PointerIcon.h>
46#include <android/graphics/GraphicsJNI.h>
47
48#include "com_android_server_PowerManagerService.h"
49#include "com_android_server_input_InputApplicationHandle.h"
50#include "com_android_server_input_InputWindowHandle.h"
51
52namespace android {
53
54// The exponent used to calculate the pointer speed scaling factor.
55// The scaling factor is calculated as 2 ^ (speed * exponent),
56// where the speed ranges from -7 to + 7 and is supplied by the user.
57static const float POINTER_SPEED_EXPONENT = 1.0f / 4;
58
59static struct {
60    jmethodID notifyConfigurationChanged;
61    jmethodID notifyLidSwitchChanged;
62    jmethodID notifyInputChannelBroken;
63    jmethodID notifyANR;
64    jmethodID filterInputEvent;
65    jmethodID interceptKeyBeforeQueueing;
66    jmethodID interceptMotionBeforeQueueingWhenScreenOff;
67    jmethodID interceptKeyBeforeDispatching;
68    jmethodID dispatchUnhandledKey;
69    jmethodID checkInjectEventsPermission;
70    jmethodID getVirtualKeyQuietTimeMillis;
71    jmethodID getExcludedDeviceNames;
72    jmethodID getKeyRepeatTimeout;
73    jmethodID getKeyRepeatDelay;
74    jmethodID getHoverTapTimeout;
75    jmethodID getHoverTapSlop;
76    jmethodID getDoubleTapTimeout;
77    jmethodID getLongPressTimeout;
78    jmethodID getPointerLayer;
79    jmethodID getPointerIcon;
80} gServiceClassInfo;
81
82static struct {
83    jclass clazz;
84} gKeyEventClassInfo;
85
86static struct {
87    jclass clazz;
88} gMotionEventClassInfo;
89
90static struct {
91    jclass clazz;
92
93    jmethodID ctor;
94    jmethodID addMotionRange;
95
96    jfieldID mId;
97    jfieldID mName;
98    jfieldID mDescriptor;
99    jfieldID mSources;
100    jfieldID mKeyboardType;
101    jfieldID mKeyCharacterMapFile;
102} gInputDeviceClassInfo;
103
104static struct {
105    jfieldID touchscreen;
106    jfieldID keyboard;
107    jfieldID navigation;
108} gConfigurationClassInfo;
109
110
111// --- Global functions ---
112
113template<typename T>
114inline static T min(const T& a, const T& b) {
115    return a < b ? a : b;
116}
117
118template<typename T>
119inline static T max(const T& a, const T& b) {
120    return a > b ? a : b;
121}
122
123static jobject getInputApplicationHandleObjLocalRef(JNIEnv* env,
124        const sp<InputApplicationHandle>& inputApplicationHandle) {
125    if (inputApplicationHandle == NULL) {
126        return NULL;
127    }
128    return static_cast<NativeInputApplicationHandle*>(inputApplicationHandle.get())->
129            getInputApplicationHandleObjLocalRef(env);
130}
131
132static jobject getInputWindowHandleObjLocalRef(JNIEnv* env,
133        const sp<InputWindowHandle>& inputWindowHandle) {
134    if (inputWindowHandle == NULL) {
135        return NULL;
136    }
137    return static_cast<NativeInputWindowHandle*>(inputWindowHandle.get())->
138            getInputWindowHandleObjLocalRef(env);
139}
140
141static void loadSystemIconAsSprite(JNIEnv* env, jobject contextObj, int32_t style,
142        SpriteIcon* outSpriteIcon) {
143    PointerIcon pointerIcon;
144    status_t status = android_view_PointerIcon_loadSystemIcon(env,
145            contextObj, style, &pointerIcon);
146    if (!status) {
147        pointerIcon.bitmap.copyTo(&outSpriteIcon->bitmap, SkBitmap::kARGB_8888_Config);
148        outSpriteIcon->hotSpotX = pointerIcon.hotSpotX;
149        outSpriteIcon->hotSpotY = pointerIcon.hotSpotY;
150    }
151}
152
153enum {
154    WM_ACTION_PASS_TO_USER = 1,
155    WM_ACTION_POKE_USER_ACTIVITY = 2,
156    WM_ACTION_GO_TO_SLEEP = 4,
157};
158
159
160// --- NativeInputManager ---
161
162class NativeInputManager : public virtual RefBase,
163    public virtual InputReaderPolicyInterface,
164    public virtual InputDispatcherPolicyInterface,
165    public virtual PointerControllerPolicyInterface {
166protected:
167    virtual ~NativeInputManager();
168
169public:
170    NativeInputManager(jobject contextObj, jobject serviceObj, const sp<Looper>& looper);
171
172    inline sp<InputManager> getInputManager() const { return mInputManager; }
173
174    void dump(String8& dump);
175
176    void setDisplaySize(int32_t displayId, int32_t width, int32_t height,
177            int32_t externalWidth, int32_t externalHeight);
178    void setDisplayOrientation(int32_t displayId, int32_t orientation);
179
180    status_t registerInputChannel(JNIEnv* env, const sp<InputChannel>& inputChannel,
181            const sp<InputWindowHandle>& inputWindowHandle, bool monitor);
182    status_t unregisterInputChannel(JNIEnv* env, const sp<InputChannel>& inputChannel);
183
184    void setInputWindows(JNIEnv* env, jobjectArray windowHandleObjArray);
185    void setFocusedApplication(JNIEnv* env, jobject applicationHandleObj);
186    void setInputDispatchMode(bool enabled, bool frozen);
187    void setSystemUiVisibility(int32_t visibility);
188    void setPointerSpeed(int32_t speed);
189    void setShowTouches(bool enabled);
190
191    /* --- InputReaderPolicyInterface implementation --- */
192
193    virtual void getReaderConfiguration(InputReaderConfiguration* outConfig);
194    virtual sp<PointerControllerInterface> obtainPointerController(int32_t deviceId);
195
196    /* --- InputDispatcherPolicyInterface implementation --- */
197
198    virtual void notifySwitch(nsecs_t when, int32_t switchCode, int32_t switchValue,
199            uint32_t policyFlags);
200    virtual void notifyConfigurationChanged(nsecs_t when);
201    virtual nsecs_t notifyANR(const sp<InputApplicationHandle>& inputApplicationHandle,
202            const sp<InputWindowHandle>& inputWindowHandle);
203    virtual void notifyInputChannelBroken(const sp<InputWindowHandle>& inputWindowHandle);
204    virtual bool filterInputEvent(const InputEvent* inputEvent, uint32_t policyFlags);
205    virtual void getDispatcherConfiguration(InputDispatcherConfiguration* outConfig);
206    virtual bool isKeyRepeatEnabled();
207    virtual void interceptKeyBeforeQueueing(const KeyEvent* keyEvent, uint32_t& policyFlags);
208    virtual void interceptMotionBeforeQueueing(nsecs_t when, uint32_t& policyFlags);
209    virtual nsecs_t interceptKeyBeforeDispatching(
210            const sp<InputWindowHandle>& inputWindowHandle,
211            const KeyEvent* keyEvent, uint32_t policyFlags);
212    virtual bool dispatchUnhandledKey(const sp<InputWindowHandle>& inputWindowHandle,
213            const KeyEvent* keyEvent, uint32_t policyFlags, KeyEvent* outFallbackKeyEvent);
214    virtual void pokeUserActivity(nsecs_t eventTime, int32_t eventType);
215    virtual bool checkInjectEventsPermissionNonReentrant(
216            int32_t injectorPid, int32_t injectorUid);
217
218    /* --- PointerControllerPolicyInterface implementation --- */
219
220    virtual void loadPointerResources(PointerResources* outResources);
221
222private:
223    sp<InputManager> mInputManager;
224
225    jobject mContextObj;
226    jobject mServiceObj;
227    sp<Looper> mLooper;
228
229    Mutex mLock;
230    struct Locked {
231        // Display size information.
232        int32_t displayWidth, displayHeight; // -1 when not initialized
233        int32_t displayExternalWidth, displayExternalHeight; // -1 when not initialized
234        int32_t displayOrientation;
235
236        // System UI visibility.
237        int32_t systemUiVisibility;
238
239        // Pointer speed.
240        int32_t pointerSpeed;
241
242        // True if pointer gestures are enabled.
243        bool pointerGesturesEnabled;
244
245        // Show touches feature enable/disable.
246        bool showTouches;
247
248        // Sprite controller singleton, created on first use.
249        sp<SpriteController> spriteController;
250
251        // Pointer controller singleton, created and destroyed as needed.
252        wp<PointerController> pointerController;
253    } mLocked;
254
255    void updateInactivityTimeoutLocked(const sp<PointerController>& controller);
256    void handleInterceptActions(jint wmActions, nsecs_t when, uint32_t& policyFlags);
257    void ensureSpriteControllerLocked();
258
259    // Power manager interactions.
260    bool isScreenOn();
261    bool isScreenBright();
262
263    static bool checkAndClearExceptionFromCallback(JNIEnv* env, const char* methodName);
264
265    static inline JNIEnv* jniEnv() {
266        return AndroidRuntime::getJNIEnv();
267    }
268};
269
270
271
272NativeInputManager::NativeInputManager(jobject contextObj,
273        jobject serviceObj, const sp<Looper>& looper) :
274        mLooper(looper) {
275    JNIEnv* env = jniEnv();
276
277    mContextObj = env->NewGlobalRef(contextObj);
278    mServiceObj = env->NewGlobalRef(serviceObj);
279
280    {
281        AutoMutex _l(mLock);
282        mLocked.displayWidth = -1;
283        mLocked.displayHeight = -1;
284        mLocked.displayExternalWidth = -1;
285        mLocked.displayExternalHeight = -1;
286        mLocked.displayOrientation = DISPLAY_ORIENTATION_0;
287
288        mLocked.systemUiVisibility = ASYSTEM_UI_VISIBILITY_STATUS_BAR_VISIBLE;
289        mLocked.pointerSpeed = 0;
290        mLocked.pointerGesturesEnabled = true;
291        mLocked.showTouches = false;
292    }
293
294    sp<EventHub> eventHub = new EventHub();
295    mInputManager = new InputManager(eventHub, this, this);
296}
297
298NativeInputManager::~NativeInputManager() {
299    JNIEnv* env = jniEnv();
300
301    env->DeleteGlobalRef(mContextObj);
302    env->DeleteGlobalRef(mServiceObj);
303}
304
305void NativeInputManager::dump(String8& dump) {
306    mInputManager->getReader()->dump(dump);
307    dump.append("\n");
308
309    mInputManager->getDispatcher()->dump(dump);
310    dump.append("\n");
311}
312
313bool NativeInputManager::checkAndClearExceptionFromCallback(JNIEnv* env, const char* methodName) {
314    if (env->ExceptionCheck()) {
315        ALOGE("An exception was thrown by callback '%s'.", methodName);
316        LOGE_EX(env);
317        env->ExceptionClear();
318        return true;
319    }
320    return false;
321}
322
323void NativeInputManager::setDisplaySize(int32_t displayId, int32_t width, int32_t height,
324        int32_t externalWidth, int32_t externalHeight) {
325    bool changed = false;
326    if (displayId == 0) {
327        AutoMutex _l(mLock);
328
329        if (mLocked.displayWidth != width || mLocked.displayHeight != height) {
330            changed = true;
331            mLocked.displayWidth = width;
332            mLocked.displayHeight = height;
333
334            sp<PointerController> controller = mLocked.pointerController.promote();
335            if (controller != NULL) {
336                controller->setDisplaySize(width, height);
337            }
338        }
339
340        if (mLocked.displayExternalWidth != externalWidth
341                || mLocked.displayExternalHeight != externalHeight) {
342            changed = true;
343            mLocked.displayExternalWidth = externalWidth;
344            mLocked.displayExternalHeight = externalHeight;
345        }
346    }
347
348    if (changed) {
349        mInputManager->getReader()->requestRefreshConfiguration(
350                InputReaderConfiguration::CHANGE_DISPLAY_INFO);
351    }
352}
353
354void NativeInputManager::setDisplayOrientation(int32_t displayId, int32_t orientation) {
355    bool changed = false;
356    if (displayId == 0) {
357        AutoMutex _l(mLock);
358
359        if (mLocked.displayOrientation != orientation) {
360            changed = true;
361            mLocked.displayOrientation = orientation;
362
363            sp<PointerController> controller = mLocked.pointerController.promote();
364            if (controller != NULL) {
365                controller->setDisplayOrientation(orientation);
366            }
367        }
368    }
369
370    if (changed) {
371        mInputManager->getReader()->requestRefreshConfiguration(
372                InputReaderConfiguration::CHANGE_DISPLAY_INFO);
373    }
374}
375
376status_t NativeInputManager::registerInputChannel(JNIEnv* env,
377        const sp<InputChannel>& inputChannel,
378        const sp<InputWindowHandle>& inputWindowHandle, bool monitor) {
379    return mInputManager->getDispatcher()->registerInputChannel(
380            inputChannel, inputWindowHandle, monitor);
381}
382
383status_t NativeInputManager::unregisterInputChannel(JNIEnv* env,
384        const sp<InputChannel>& inputChannel) {
385    return mInputManager->getDispatcher()->unregisterInputChannel(inputChannel);
386}
387
388void NativeInputManager::getReaderConfiguration(InputReaderConfiguration* outConfig) {
389    JNIEnv* env = jniEnv();
390
391    jint virtualKeyQuietTime = env->CallIntMethod(mServiceObj,
392            gServiceClassInfo.getVirtualKeyQuietTimeMillis);
393    if (!checkAndClearExceptionFromCallback(env, "getVirtualKeyQuietTimeMillis")) {
394        outConfig->virtualKeyQuietTime = milliseconds_to_nanoseconds(virtualKeyQuietTime);
395    }
396
397    outConfig->excludedDeviceNames.clear();
398    jobjectArray excludedDeviceNames = jobjectArray(env->CallObjectMethod(mServiceObj,
399            gServiceClassInfo.getExcludedDeviceNames));
400    if (!checkAndClearExceptionFromCallback(env, "getExcludedDeviceNames") && excludedDeviceNames) {
401        jsize length = env->GetArrayLength(excludedDeviceNames);
402        for (jsize i = 0; i < length; i++) {
403            jstring item = jstring(env->GetObjectArrayElement(excludedDeviceNames, i));
404            const char* deviceNameChars = env->GetStringUTFChars(item, NULL);
405            outConfig->excludedDeviceNames.add(String8(deviceNameChars));
406            env->ReleaseStringUTFChars(item, deviceNameChars);
407            env->DeleteLocalRef(item);
408        }
409        env->DeleteLocalRef(excludedDeviceNames);
410    }
411
412    jint hoverTapTimeout = env->CallIntMethod(mServiceObj,
413            gServiceClassInfo.getHoverTapTimeout);
414    if (!checkAndClearExceptionFromCallback(env, "getHoverTapTimeout")) {
415        jint doubleTapTimeout = env->CallIntMethod(mServiceObj,
416                gServiceClassInfo.getDoubleTapTimeout);
417        if (!checkAndClearExceptionFromCallback(env, "getDoubleTapTimeout")) {
418            jint longPressTimeout = env->CallIntMethod(mServiceObj,
419                    gServiceClassInfo.getLongPressTimeout);
420            if (!checkAndClearExceptionFromCallback(env, "getLongPressTimeout")) {
421                outConfig->pointerGestureTapInterval = milliseconds_to_nanoseconds(hoverTapTimeout);
422
423                // We must ensure that the tap-drag interval is significantly shorter than
424                // the long-press timeout because the tap is held down for the entire duration
425                // of the double-tap timeout.
426                jint tapDragInterval = max(min(longPressTimeout - 100,
427                        doubleTapTimeout), hoverTapTimeout);
428                outConfig->pointerGestureTapDragInterval =
429                        milliseconds_to_nanoseconds(tapDragInterval);
430            }
431        }
432    }
433
434    jint hoverTapSlop = env->CallIntMethod(mServiceObj,
435            gServiceClassInfo.getHoverTapSlop);
436    if (!checkAndClearExceptionFromCallback(env, "getHoverTapSlop")) {
437        outConfig->pointerGestureTapSlop = hoverTapSlop;
438    }
439
440    { // acquire lock
441        AutoMutex _l(mLock);
442
443        outConfig->pointerVelocityControlParameters.scale = exp2f(mLocked.pointerSpeed
444                * POINTER_SPEED_EXPONENT);
445        outConfig->pointerGesturesEnabled = mLocked.pointerGesturesEnabled;
446
447        outConfig->showTouches = mLocked.showTouches;
448
449        outConfig->setDisplayInfo(0, false /*external*/,
450                mLocked.displayWidth, mLocked.displayHeight, mLocked.displayOrientation);
451        outConfig->setDisplayInfo(0, true /*external*/,
452                mLocked.displayExternalWidth, mLocked.displayExternalHeight,
453                mLocked.displayOrientation);
454    } // release lock
455}
456
457sp<PointerControllerInterface> NativeInputManager::obtainPointerController(int32_t deviceId) {
458    AutoMutex _l(mLock);
459
460    sp<PointerController> controller = mLocked.pointerController.promote();
461    if (controller == NULL) {
462        ensureSpriteControllerLocked();
463
464        controller = new PointerController(this, mLooper, mLocked.spriteController);
465        mLocked.pointerController = controller;
466
467        controller->setDisplaySize(mLocked.displayWidth, mLocked.displayHeight);
468        controller->setDisplayOrientation(mLocked.displayOrientation);
469
470        JNIEnv* env = jniEnv();
471        jobject pointerIconObj = env->CallObjectMethod(mServiceObj,
472                gServiceClassInfo.getPointerIcon);
473        if (!checkAndClearExceptionFromCallback(env, "getPointerIcon")) {
474            PointerIcon pointerIcon;
475            status_t status = android_view_PointerIcon_load(env, pointerIconObj,
476                    mContextObj, &pointerIcon);
477            if (!status && !pointerIcon.isNullIcon()) {
478                controller->setPointerIcon(SpriteIcon(pointerIcon.bitmap,
479                        pointerIcon.hotSpotX, pointerIcon.hotSpotY));
480            } else {
481                controller->setPointerIcon(SpriteIcon());
482            }
483            env->DeleteLocalRef(pointerIconObj);
484        }
485
486        updateInactivityTimeoutLocked(controller);
487    }
488    return controller;
489}
490
491void NativeInputManager::ensureSpriteControllerLocked() {
492    if (mLocked.spriteController == NULL) {
493        JNIEnv* env = jniEnv();
494        jint layer = env->CallIntMethod(mServiceObj, gServiceClassInfo.getPointerLayer);
495        if (checkAndClearExceptionFromCallback(env, "getPointerLayer")) {
496            layer = -1;
497        }
498        mLocked.spriteController = new SpriteController(mLooper, layer);
499    }
500}
501
502void NativeInputManager::notifySwitch(nsecs_t when, int32_t switchCode,
503        int32_t switchValue, uint32_t policyFlags) {
504#if DEBUG_INPUT_DISPATCHER_POLICY
505    ALOGD("notifySwitch - when=%lld, switchCode=%d, switchValue=%d, policyFlags=0x%x",
506            when, switchCode, switchValue, policyFlags);
507#endif
508
509    JNIEnv* env = jniEnv();
510
511    switch (switchCode) {
512    case SW_LID:
513        env->CallVoidMethod(mServiceObj, gServiceClassInfo.notifyLidSwitchChanged,
514                when, switchValue == 0);
515        checkAndClearExceptionFromCallback(env, "notifyLidSwitchChanged");
516        break;
517    }
518}
519
520void NativeInputManager::notifyConfigurationChanged(nsecs_t when) {
521#if DEBUG_INPUT_DISPATCHER_POLICY
522    ALOGD("notifyConfigurationChanged - when=%lld", when);
523#endif
524
525    JNIEnv* env = jniEnv();
526
527    env->CallVoidMethod(mServiceObj, gServiceClassInfo.notifyConfigurationChanged, when);
528    checkAndClearExceptionFromCallback(env, "notifyConfigurationChanged");
529}
530
531nsecs_t NativeInputManager::notifyANR(const sp<InputApplicationHandle>& inputApplicationHandle,
532        const sp<InputWindowHandle>& inputWindowHandle) {
533#if DEBUG_INPUT_DISPATCHER_POLICY
534    ALOGD("notifyANR");
535#endif
536
537    JNIEnv* env = jniEnv();
538
539    jobject inputApplicationHandleObj =
540            getInputApplicationHandleObjLocalRef(env, inputApplicationHandle);
541    jobject inputWindowHandleObj =
542            getInputWindowHandleObjLocalRef(env, inputWindowHandle);
543
544    jlong newTimeout = env->CallLongMethod(mServiceObj,
545                gServiceClassInfo.notifyANR, inputApplicationHandleObj, inputWindowHandleObj);
546    if (checkAndClearExceptionFromCallback(env, "notifyANR")) {
547        newTimeout = 0; // abort dispatch
548    } else {
549        assert(newTimeout >= 0);
550    }
551
552    env->DeleteLocalRef(inputWindowHandleObj);
553    env->DeleteLocalRef(inputApplicationHandleObj);
554    return newTimeout;
555}
556
557void NativeInputManager::notifyInputChannelBroken(const sp<InputWindowHandle>& inputWindowHandle) {
558#if DEBUG_INPUT_DISPATCHER_POLICY
559    ALOGD("notifyInputChannelBroken");
560#endif
561
562    JNIEnv* env = jniEnv();
563
564    jobject inputWindowHandleObj =
565            getInputWindowHandleObjLocalRef(env, inputWindowHandle);
566    if (inputWindowHandleObj) {
567        env->CallVoidMethod(mServiceObj, gServiceClassInfo.notifyInputChannelBroken,
568                inputWindowHandleObj);
569        checkAndClearExceptionFromCallback(env, "notifyInputChannelBroken");
570
571        env->DeleteLocalRef(inputWindowHandleObj);
572    }
573}
574
575void NativeInputManager::getDispatcherConfiguration(InputDispatcherConfiguration* outConfig) {
576    JNIEnv* env = jniEnv();
577
578    jint keyRepeatTimeout = env->CallIntMethod(mServiceObj,
579            gServiceClassInfo.getKeyRepeatTimeout);
580    if (!checkAndClearExceptionFromCallback(env, "getKeyRepeatTimeout")) {
581        outConfig->keyRepeatTimeout = milliseconds_to_nanoseconds(keyRepeatTimeout);
582    }
583
584    jint keyRepeatDelay = env->CallIntMethod(mServiceObj,
585            gServiceClassInfo.getKeyRepeatDelay);
586    if (!checkAndClearExceptionFromCallback(env, "getKeyRepeatDelay")) {
587        outConfig->keyRepeatDelay = milliseconds_to_nanoseconds(keyRepeatDelay);
588    }
589}
590
591bool NativeInputManager::isKeyRepeatEnabled() {
592    // Only enable automatic key repeating when the screen is on.
593    return isScreenOn();
594}
595
596void NativeInputManager::setInputWindows(JNIEnv* env, jobjectArray windowHandleObjArray) {
597    Vector<sp<InputWindowHandle> > windowHandles;
598
599    if (windowHandleObjArray) {
600        jsize length = env->GetArrayLength(windowHandleObjArray);
601        for (jsize i = 0; i < length; i++) {
602            jobject windowHandleObj = env->GetObjectArrayElement(windowHandleObjArray, i);
603            if (! windowHandleObj) {
604                break; // found null element indicating end of used portion of the array
605            }
606
607            sp<InputWindowHandle> windowHandle =
608                    android_server_InputWindowHandle_getHandle(env, windowHandleObj);
609            if (windowHandle != NULL) {
610                windowHandles.push(windowHandle);
611            }
612            env->DeleteLocalRef(windowHandleObj);
613        }
614    }
615
616    mInputManager->getDispatcher()->setInputWindows(windowHandles);
617
618    // Do this after the dispatcher has updated the window handle state.
619    bool newPointerGesturesEnabled = true;
620    size_t numWindows = windowHandles.size();
621    for (size_t i = 0; i < numWindows; i++) {
622        const sp<InputWindowHandle>& windowHandle = windowHandles.itemAt(i);
623        const InputWindowInfo* windowInfo = windowHandle->getInfo();
624        if (windowInfo && windowInfo->hasFocus && (windowInfo->inputFeatures
625                & InputWindowInfo::INPUT_FEATURE_DISABLE_TOUCH_PAD_GESTURES)) {
626            newPointerGesturesEnabled = false;
627        }
628    }
629
630    uint32_t changes = 0;
631    { // acquire lock
632        AutoMutex _l(mLock);
633
634        if (mLocked.pointerGesturesEnabled != newPointerGesturesEnabled) {
635            mLocked.pointerGesturesEnabled = newPointerGesturesEnabled;
636            changes |= InputReaderConfiguration::CHANGE_POINTER_GESTURE_ENABLEMENT;
637        }
638    } // release lock
639
640    if (changes) {
641        mInputManager->getReader()->requestRefreshConfiguration(changes);
642    }
643}
644
645void NativeInputManager::setFocusedApplication(JNIEnv* env, jobject applicationHandleObj) {
646    sp<InputApplicationHandle> applicationHandle =
647            android_server_InputApplicationHandle_getHandle(env, applicationHandleObj);
648    mInputManager->getDispatcher()->setFocusedApplication(applicationHandle);
649}
650
651void NativeInputManager::setInputDispatchMode(bool enabled, bool frozen) {
652    mInputManager->getDispatcher()->setInputDispatchMode(enabled, frozen);
653}
654
655void NativeInputManager::setSystemUiVisibility(int32_t visibility) {
656    AutoMutex _l(mLock);
657
658    if (mLocked.systemUiVisibility != visibility) {
659        mLocked.systemUiVisibility = visibility;
660
661        sp<PointerController> controller = mLocked.pointerController.promote();
662        if (controller != NULL) {
663            updateInactivityTimeoutLocked(controller);
664        }
665    }
666}
667
668void NativeInputManager::updateInactivityTimeoutLocked(const sp<PointerController>& controller) {
669    bool lightsOut = mLocked.systemUiVisibility & ASYSTEM_UI_VISIBILITY_STATUS_BAR_HIDDEN;
670    controller->setInactivityTimeout(lightsOut
671            ? PointerController::INACTIVITY_TIMEOUT_SHORT
672            : PointerController::INACTIVITY_TIMEOUT_NORMAL);
673}
674
675void NativeInputManager::setPointerSpeed(int32_t speed) {
676    { // acquire lock
677        AutoMutex _l(mLock);
678
679        if (mLocked.pointerSpeed == speed) {
680            return;
681        }
682
683        ALOGI("Setting pointer speed to %d.", speed);
684        mLocked.pointerSpeed = speed;
685    } // release lock
686
687    mInputManager->getReader()->requestRefreshConfiguration(
688            InputReaderConfiguration::CHANGE_POINTER_SPEED);
689}
690
691void NativeInputManager::setShowTouches(bool enabled) {
692    { // acquire lock
693        AutoMutex _l(mLock);
694
695        if (mLocked.showTouches == enabled) {
696            return;
697        }
698
699        ALOGI("Setting show touches feature to %s.", enabled ? "enabled" : "disabled");
700        mLocked.showTouches = enabled;
701    } // release lock
702
703    mInputManager->getReader()->requestRefreshConfiguration(
704            InputReaderConfiguration::CHANGE_SHOW_TOUCHES);
705}
706
707bool NativeInputManager::isScreenOn() {
708    return android_server_PowerManagerService_isScreenOn();
709}
710
711bool NativeInputManager::isScreenBright() {
712    return android_server_PowerManagerService_isScreenBright();
713}
714
715bool NativeInputManager::filterInputEvent(const InputEvent* inputEvent, uint32_t policyFlags) {
716    jobject inputEventObj;
717
718    JNIEnv* env = jniEnv();
719    switch (inputEvent->getType()) {
720    case AINPUT_EVENT_TYPE_KEY:
721        inputEventObj = android_view_KeyEvent_fromNative(env,
722                static_cast<const KeyEvent*>(inputEvent));
723        break;
724    case AINPUT_EVENT_TYPE_MOTION:
725        inputEventObj = android_view_MotionEvent_obtainAsCopy(env,
726                static_cast<const MotionEvent*>(inputEvent));
727        break;
728    default:
729        return true; // dispatch the event normally
730    }
731
732    if (!inputEventObj) {
733        ALOGE("Failed to obtain input event object for filterInputEvent.");
734        return true; // dispatch the event normally
735    }
736
737    // The callee is responsible for recycling the event.
738    jboolean pass = env->CallBooleanMethod(mServiceObj, gServiceClassInfo.filterInputEvent,
739            inputEventObj, policyFlags);
740    if (checkAndClearExceptionFromCallback(env, "filterInputEvent")) {
741        pass = true;
742    }
743    env->DeleteLocalRef(inputEventObj);
744    return pass;
745}
746
747void NativeInputManager::interceptKeyBeforeQueueing(const KeyEvent* keyEvent,
748        uint32_t& policyFlags) {
749    // Policy:
750    // - Ignore untrusted events and pass them along.
751    // - Ask the window manager what to do with normal events and trusted injected events.
752    // - For normal events wake and brighten the screen if currently off or dim.
753    if ((policyFlags & POLICY_FLAG_TRUSTED)) {
754        nsecs_t when = keyEvent->getEventTime();
755        bool isScreenOn = this->isScreenOn();
756        bool isScreenBright = this->isScreenBright();
757
758        JNIEnv* env = jniEnv();
759        jobject keyEventObj = android_view_KeyEvent_fromNative(env, keyEvent);
760        jint wmActions;
761        if (keyEventObj) {
762            wmActions = env->CallIntMethod(mServiceObj,
763                    gServiceClassInfo.interceptKeyBeforeQueueing,
764                    keyEventObj, policyFlags, isScreenOn);
765            if (checkAndClearExceptionFromCallback(env, "interceptKeyBeforeQueueing")) {
766                wmActions = 0;
767            }
768            android_view_KeyEvent_recycle(env, keyEventObj);
769            env->DeleteLocalRef(keyEventObj);
770        } else {
771            ALOGE("Failed to obtain key event object for interceptKeyBeforeQueueing.");
772            wmActions = 0;
773        }
774
775        if (!(policyFlags & POLICY_FLAG_INJECTED)) {
776            if (!isScreenOn) {
777                policyFlags |= POLICY_FLAG_WOKE_HERE;
778            }
779
780            if (!isScreenBright) {
781                policyFlags |= POLICY_FLAG_BRIGHT_HERE;
782            }
783        }
784
785        handleInterceptActions(wmActions, when, /*byref*/ policyFlags);
786    } else {
787        policyFlags |= POLICY_FLAG_PASS_TO_USER;
788    }
789}
790
791void NativeInputManager::interceptMotionBeforeQueueing(nsecs_t when, uint32_t& policyFlags) {
792    // Policy:
793    // - Ignore untrusted events and pass them along.
794    // - No special filtering for injected events required at this time.
795    // - Filter normal events based on screen state.
796    // - For normal events brighten (but do not wake) the screen if currently dim.
797    if ((policyFlags & POLICY_FLAG_TRUSTED) && !(policyFlags & POLICY_FLAG_INJECTED)) {
798        if (isScreenOn()) {
799            policyFlags |= POLICY_FLAG_PASS_TO_USER;
800
801            if (!isScreenBright()) {
802                policyFlags |= POLICY_FLAG_BRIGHT_HERE;
803            }
804        } else {
805            JNIEnv* env = jniEnv();
806            jint wmActions = env->CallIntMethod(mServiceObj,
807                        gServiceClassInfo.interceptMotionBeforeQueueingWhenScreenOff,
808                        policyFlags);
809            if (checkAndClearExceptionFromCallback(env,
810                    "interceptMotionBeforeQueueingWhenScreenOff")) {
811                wmActions = 0;
812            }
813
814            policyFlags |= POLICY_FLAG_WOKE_HERE | POLICY_FLAG_BRIGHT_HERE;
815            handleInterceptActions(wmActions, when, /*byref*/ policyFlags);
816        }
817    } else {
818        policyFlags |= POLICY_FLAG_PASS_TO_USER;
819    }
820}
821
822void NativeInputManager::handleInterceptActions(jint wmActions, nsecs_t when,
823        uint32_t& policyFlags) {
824    if (wmActions & WM_ACTION_GO_TO_SLEEP) {
825#if DEBUG_INPUT_DISPATCHER_POLICY
826        ALOGD("handleInterceptActions: Going to sleep.");
827#endif
828        android_server_PowerManagerService_goToSleep(when);
829    }
830
831    if (wmActions & WM_ACTION_POKE_USER_ACTIVITY) {
832#if DEBUG_INPUT_DISPATCHER_POLICY
833        ALOGD("handleInterceptActions: Poking user activity.");
834#endif
835        android_server_PowerManagerService_userActivity(when, POWER_MANAGER_BUTTON_EVENT);
836    }
837
838    if (wmActions & WM_ACTION_PASS_TO_USER) {
839        policyFlags |= POLICY_FLAG_PASS_TO_USER;
840    } else {
841#if DEBUG_INPUT_DISPATCHER_POLICY
842        ALOGD("handleInterceptActions: Not passing key to user.");
843#endif
844    }
845}
846
847nsecs_t NativeInputManager::interceptKeyBeforeDispatching(
848        const sp<InputWindowHandle>& inputWindowHandle,
849        const KeyEvent* keyEvent, uint32_t policyFlags) {
850    // Policy:
851    // - Ignore untrusted events and pass them along.
852    // - Filter normal events and trusted injected events through the window manager policy to
853    //   handle the HOME key and the like.
854    nsecs_t result = 0;
855    if (policyFlags & POLICY_FLAG_TRUSTED) {
856        JNIEnv* env = jniEnv();
857
858        // Note: inputWindowHandle may be null.
859        jobject inputWindowHandleObj = getInputWindowHandleObjLocalRef(env, inputWindowHandle);
860        jobject keyEventObj = android_view_KeyEvent_fromNative(env, keyEvent);
861        if (keyEventObj) {
862            jlong delayMillis = env->CallLongMethod(mServiceObj,
863                    gServiceClassInfo.interceptKeyBeforeDispatching,
864                    inputWindowHandleObj, keyEventObj, policyFlags);
865            bool error = checkAndClearExceptionFromCallback(env, "interceptKeyBeforeDispatching");
866            android_view_KeyEvent_recycle(env, keyEventObj);
867            env->DeleteLocalRef(keyEventObj);
868            if (!error) {
869                if (delayMillis < 0) {
870                    result = -1;
871                } else if (delayMillis > 0) {
872                    result = milliseconds_to_nanoseconds(delayMillis);
873                }
874            }
875        } else {
876            ALOGE("Failed to obtain key event object for interceptKeyBeforeDispatching.");
877        }
878        env->DeleteLocalRef(inputWindowHandleObj);
879    }
880    return result;
881}
882
883bool NativeInputManager::dispatchUnhandledKey(const sp<InputWindowHandle>& inputWindowHandle,
884        const KeyEvent* keyEvent, uint32_t policyFlags, KeyEvent* outFallbackKeyEvent) {
885    // Policy:
886    // - Ignore untrusted events and do not perform default handling.
887    bool result = false;
888    if (policyFlags & POLICY_FLAG_TRUSTED) {
889        JNIEnv* env = jniEnv();
890
891        // Note: inputWindowHandle may be null.
892        jobject inputWindowHandleObj = getInputWindowHandleObjLocalRef(env, inputWindowHandle);
893        jobject keyEventObj = android_view_KeyEvent_fromNative(env, keyEvent);
894        if (keyEventObj) {
895            jobject fallbackKeyEventObj = env->CallObjectMethod(mServiceObj,
896                    gServiceClassInfo.dispatchUnhandledKey,
897                    inputWindowHandleObj, keyEventObj, policyFlags);
898            if (checkAndClearExceptionFromCallback(env, "dispatchUnhandledKey")) {
899                fallbackKeyEventObj = NULL;
900            }
901            android_view_KeyEvent_recycle(env, keyEventObj);
902            env->DeleteLocalRef(keyEventObj);
903
904            if (fallbackKeyEventObj) {
905                // Note: outFallbackKeyEvent may be the same object as keyEvent.
906                if (!android_view_KeyEvent_toNative(env, fallbackKeyEventObj,
907                        outFallbackKeyEvent)) {
908                    result = true;
909                }
910                android_view_KeyEvent_recycle(env, fallbackKeyEventObj);
911                env->DeleteLocalRef(fallbackKeyEventObj);
912            }
913        } else {
914            ALOGE("Failed to obtain key event object for dispatchUnhandledKey.");
915        }
916        env->DeleteLocalRef(inputWindowHandleObj);
917    }
918    return result;
919}
920
921void NativeInputManager::pokeUserActivity(nsecs_t eventTime, int32_t eventType) {
922    android_server_PowerManagerService_userActivity(eventTime, eventType);
923}
924
925
926bool NativeInputManager::checkInjectEventsPermissionNonReentrant(
927        int32_t injectorPid, int32_t injectorUid) {
928    JNIEnv* env = jniEnv();
929    jboolean result = env->CallBooleanMethod(mServiceObj,
930            gServiceClassInfo.checkInjectEventsPermission, injectorPid, injectorUid);
931    if (checkAndClearExceptionFromCallback(env, "checkInjectEventsPermission")) {
932        result = false;
933    }
934    return result;
935}
936
937void NativeInputManager::loadPointerResources(PointerResources* outResources) {
938    JNIEnv* env = jniEnv();
939
940    loadSystemIconAsSprite(env, mContextObj, POINTER_ICON_STYLE_SPOT_HOVER,
941            &outResources->spotHover);
942    loadSystemIconAsSprite(env, mContextObj, POINTER_ICON_STYLE_SPOT_TOUCH,
943            &outResources->spotTouch);
944    loadSystemIconAsSprite(env, mContextObj, POINTER_ICON_STYLE_SPOT_ANCHOR,
945            &outResources->spotAnchor);
946}
947
948
949// ----------------------------------------------------------------------------
950
951static jint nativeInit(JNIEnv* env, jclass clazz,
952        jobject serviceObj, jobject contextObj, jobject messageQueueObj) {
953    sp<MessageQueue> messageQueue = android_os_MessageQueue_getMessageQueue(env, messageQueueObj);
954    NativeInputManager* im = new NativeInputManager(contextObj, serviceObj,
955            messageQueue->getLooper());
956    im->incStrong(serviceObj);
957    return reinterpret_cast<jint>(im);
958}
959
960static void nativeStart(JNIEnv* env, jclass clazz, jint ptr) {
961    NativeInputManager* im = reinterpret_cast<NativeInputManager*>(ptr);
962
963    status_t result = im->getInputManager()->start();
964    if (result) {
965        jniThrowRuntimeException(env, "Input manager could not be started.");
966    }
967}
968
969static void nativeSetDisplaySize(JNIEnv* env, jclass clazz, jint ptr,
970        jint displayId, jint width, jint height, jint externalWidth, jint externalHeight) {
971    NativeInputManager* im = reinterpret_cast<NativeInputManager*>(ptr);
972
973    // XXX we could get this from the SurfaceFlinger directly instead of requiring it
974    // to be passed in like this, not sure which is better but leaving it like this
975    // keeps the window manager in direct control of when display transitions propagate down
976    // to the input dispatcher
977    im->setDisplaySize(displayId, width, height, externalWidth, externalHeight);
978}
979
980static void nativeSetDisplayOrientation(JNIEnv* env, jclass clazz,
981        jint ptr, jint displayId, jint orientation) {
982    NativeInputManager* im = reinterpret_cast<NativeInputManager*>(ptr);
983
984    im->setDisplayOrientation(displayId, orientation);
985}
986
987static jint nativeGetScanCodeState(JNIEnv* env, jclass clazz,
988        jint ptr, jint deviceId, jint sourceMask, jint scanCode) {
989    NativeInputManager* im = reinterpret_cast<NativeInputManager*>(ptr);
990
991    return im->getInputManager()->getReader()->getScanCodeState(
992            deviceId, uint32_t(sourceMask), scanCode);
993}
994
995static jint nativeGetKeyCodeState(JNIEnv* env, jclass clazz,
996        jint ptr, jint deviceId, jint sourceMask, jint keyCode) {
997    NativeInputManager* im = reinterpret_cast<NativeInputManager*>(ptr);
998
999    return im->getInputManager()->getReader()->getKeyCodeState(
1000            deviceId, uint32_t(sourceMask), keyCode);
1001}
1002
1003static jint nativeGetSwitchState(JNIEnv* env, jclass clazz,
1004        jint ptr, jint deviceId, jint sourceMask, jint sw) {
1005    NativeInputManager* im = reinterpret_cast<NativeInputManager*>(ptr);
1006
1007    return im->getInputManager()->getReader()->getSwitchState(
1008            deviceId, uint32_t(sourceMask), sw);
1009}
1010
1011static jboolean nativeHasKeys(JNIEnv* env, jclass clazz,
1012        jint ptr, jint deviceId, jint sourceMask, jintArray keyCodes, jbooleanArray outFlags) {
1013    NativeInputManager* im = reinterpret_cast<NativeInputManager*>(ptr);
1014
1015    int32_t* codes = env->GetIntArrayElements(keyCodes, NULL);
1016    uint8_t* flags = env->GetBooleanArrayElements(outFlags, NULL);
1017    jsize numCodes = env->GetArrayLength(keyCodes);
1018    jboolean result;
1019    if (numCodes == env->GetArrayLength(keyCodes)) {
1020        result = im->getInputManager()->getReader()->hasKeys(
1021                deviceId, uint32_t(sourceMask), numCodes, codes, flags);
1022    } else {
1023        result = JNI_FALSE;
1024    }
1025
1026    env->ReleaseBooleanArrayElements(outFlags, flags, 0);
1027    env->ReleaseIntArrayElements(keyCodes, codes, 0);
1028    return result;
1029}
1030
1031static void throwInputChannelNotInitialized(JNIEnv* env) {
1032    jniThrowException(env, "java/lang/IllegalStateException",
1033             "inputChannel is not initialized");
1034}
1035
1036static void handleInputChannelDisposed(JNIEnv* env,
1037        jobject inputChannelObj, const sp<InputChannel>& inputChannel, void* data) {
1038    NativeInputManager* im = static_cast<NativeInputManager*>(data);
1039
1040    ALOGW("Input channel object '%s' was disposed without first being unregistered with "
1041            "the input manager!", inputChannel->getName().string());
1042    im->unregisterInputChannel(env, inputChannel);
1043}
1044
1045static void nativeRegisterInputChannel(JNIEnv* env, jclass clazz,
1046        jint ptr, jobject inputChannelObj, jobject inputWindowHandleObj, jboolean monitor) {
1047    NativeInputManager* im = reinterpret_cast<NativeInputManager*>(ptr);
1048
1049    sp<InputChannel> inputChannel = android_view_InputChannel_getInputChannel(env,
1050            inputChannelObj);
1051    if (inputChannel == NULL) {
1052        throwInputChannelNotInitialized(env);
1053        return;
1054    }
1055
1056    sp<InputWindowHandle> inputWindowHandle =
1057            android_server_InputWindowHandle_getHandle(env, inputWindowHandleObj);
1058
1059    status_t status = im->registerInputChannel(
1060            env, inputChannel, inputWindowHandle, monitor);
1061    if (status) {
1062        String8 message;
1063        message.appendFormat("Failed to register input channel.  status=%d", status);
1064        jniThrowRuntimeException(env, message.string());
1065        return;
1066    }
1067
1068    if (! monitor) {
1069        android_view_InputChannel_setDisposeCallback(env, inputChannelObj,
1070                handleInputChannelDisposed, im);
1071    }
1072}
1073
1074static void nativeUnregisterInputChannel(JNIEnv* env, jclass clazz,
1075        jint ptr, jobject inputChannelObj) {
1076    NativeInputManager* im = reinterpret_cast<NativeInputManager*>(ptr);
1077
1078    sp<InputChannel> inputChannel = android_view_InputChannel_getInputChannel(env,
1079            inputChannelObj);
1080    if (inputChannel == NULL) {
1081        throwInputChannelNotInitialized(env);
1082        return;
1083    }
1084
1085    android_view_InputChannel_setDisposeCallback(env, inputChannelObj, NULL, NULL);
1086
1087    status_t status = im->unregisterInputChannel(env, inputChannel);
1088    if (status && status != BAD_VALUE) { // ignore already unregistered channel
1089        String8 message;
1090        message.appendFormat("Failed to unregister input channel.  status=%d", status);
1091        jniThrowRuntimeException(env, message.string());
1092    }
1093}
1094
1095static void nativeSetInputFilterEnabled(JNIEnv* env, jclass clazz,
1096        jint ptr, jboolean enabled) {
1097    NativeInputManager* im = reinterpret_cast<NativeInputManager*>(ptr);
1098
1099    im->getInputManager()->getDispatcher()->setInputFilterEnabled(enabled);
1100}
1101
1102static jint nativeInjectInputEvent(JNIEnv* env, jclass clazz,
1103        jint ptr, jobject inputEventObj, jint injectorPid, jint injectorUid,
1104        jint syncMode, jint timeoutMillis, jint policyFlags) {
1105    NativeInputManager* im = reinterpret_cast<NativeInputManager*>(ptr);
1106
1107    if (env->IsInstanceOf(inputEventObj, gKeyEventClassInfo.clazz)) {
1108        KeyEvent keyEvent;
1109        status_t status = android_view_KeyEvent_toNative(env, inputEventObj, & keyEvent);
1110        if (status) {
1111            jniThrowRuntimeException(env, "Could not read contents of KeyEvent object.");
1112            return INPUT_EVENT_INJECTION_FAILED;
1113        }
1114
1115        return im->getInputManager()->getDispatcher()->injectInputEvent(
1116                & keyEvent, injectorPid, injectorUid, syncMode, timeoutMillis,
1117                uint32_t(policyFlags));
1118    } else if (env->IsInstanceOf(inputEventObj, gMotionEventClassInfo.clazz)) {
1119        const MotionEvent* motionEvent = android_view_MotionEvent_getNativePtr(env, inputEventObj);
1120        if (!motionEvent) {
1121            jniThrowRuntimeException(env, "Could not read contents of MotionEvent object.");
1122            return INPUT_EVENT_INJECTION_FAILED;
1123        }
1124
1125        return im->getInputManager()->getDispatcher()->injectInputEvent(
1126                motionEvent, injectorPid, injectorUid, syncMode, timeoutMillis,
1127                uint32_t(policyFlags));
1128    } else {
1129        jniThrowRuntimeException(env, "Invalid input event type.");
1130        return INPUT_EVENT_INJECTION_FAILED;
1131    }
1132}
1133
1134static void nativeSetInputWindows(JNIEnv* env, jclass clazz,
1135        jint ptr, jobjectArray windowHandleObjArray) {
1136    NativeInputManager* im = reinterpret_cast<NativeInputManager*>(ptr);
1137
1138    im->setInputWindows(env, windowHandleObjArray);
1139}
1140
1141static void nativeSetFocusedApplication(JNIEnv* env, jclass clazz,
1142        jint ptr, jobject applicationHandleObj) {
1143    NativeInputManager* im = reinterpret_cast<NativeInputManager*>(ptr);
1144
1145    im->setFocusedApplication(env, applicationHandleObj);
1146}
1147
1148static void nativeSetInputDispatchMode(JNIEnv* env,
1149        jclass clazz, jint ptr, jboolean enabled, jboolean frozen) {
1150    NativeInputManager* im = reinterpret_cast<NativeInputManager*>(ptr);
1151
1152    im->setInputDispatchMode(enabled, frozen);
1153}
1154
1155static void nativeSetSystemUiVisibility(JNIEnv* env,
1156        jclass clazz, jint ptr, jint visibility) {
1157    NativeInputManager* im = reinterpret_cast<NativeInputManager*>(ptr);
1158
1159    im->setSystemUiVisibility(visibility);
1160}
1161
1162static jobject nativeGetInputDevice(JNIEnv* env,
1163        jclass clazz, jint ptr, jint deviceId) {
1164    NativeInputManager* im = reinterpret_cast<NativeInputManager*>(ptr);
1165
1166    InputDeviceInfo deviceInfo;
1167    status_t status = im->getInputManager()->getReader()->getInputDeviceInfo(
1168            deviceId, & deviceInfo);
1169    if (status) {
1170        return NULL;
1171    }
1172
1173    jobject deviceObj = env->NewObject(gInputDeviceClassInfo.clazz, gInputDeviceClassInfo.ctor);
1174    if (!deviceObj) {
1175        return NULL;
1176    }
1177
1178    jstring deviceNameObj = env->NewStringUTF(deviceInfo.getName().string());
1179    if (!deviceNameObj) {
1180        return NULL;
1181    }
1182
1183    jstring deviceDescriptorObj = env->NewStringUTF(deviceInfo.getDescriptor().string());
1184    if (!deviceDescriptorObj) {
1185        return NULL;
1186    }
1187
1188    jstring fileStr = env->NewStringUTF(deviceInfo.getKeyCharacterMapFile());
1189    if (!fileStr) {
1190        return NULL;
1191    }
1192
1193    env->SetIntField(deviceObj, gInputDeviceClassInfo.mId, deviceInfo.getId());
1194    env->SetObjectField(deviceObj, gInputDeviceClassInfo.mName, deviceNameObj);
1195    env->SetObjectField(deviceObj, gInputDeviceClassInfo.mDescriptor, deviceDescriptorObj);
1196    env->SetIntField(deviceObj, gInputDeviceClassInfo.mSources, deviceInfo.getSources());
1197    env->SetIntField(deviceObj, gInputDeviceClassInfo.mKeyboardType, deviceInfo.getKeyboardType());
1198    env->SetObjectField(deviceObj, gInputDeviceClassInfo.mKeyCharacterMapFile, fileStr);
1199
1200    const Vector<InputDeviceInfo::MotionRange>& ranges = deviceInfo.getMotionRanges();
1201    for (size_t i = 0; i < ranges.size(); i++) {
1202        const InputDeviceInfo::MotionRange& range = ranges.itemAt(i);
1203        env->CallVoidMethod(deviceObj, gInputDeviceClassInfo.addMotionRange,
1204                range.axis, range.source, range.min, range.max, range.flat, range.fuzz);
1205        if (env->ExceptionCheck()) {
1206            return NULL;
1207        }
1208    }
1209
1210    return deviceObj;
1211}
1212
1213static jintArray nativeGetInputDeviceIds(JNIEnv* env,
1214        jclass clazz, jint ptr) {
1215    NativeInputManager* im = reinterpret_cast<NativeInputManager*>(ptr);
1216
1217    Vector<int> deviceIds;
1218    im->getInputManager()->getReader()->getInputDeviceIds(deviceIds);
1219
1220    jintArray deviceIdsObj = env->NewIntArray(deviceIds.size());
1221    if (! deviceIdsObj) {
1222        return NULL;
1223    }
1224
1225    env->SetIntArrayRegion(deviceIdsObj, 0, deviceIds.size(), deviceIds.array());
1226    return deviceIdsObj;
1227}
1228
1229static void nativeGetInputConfiguration(JNIEnv* env,
1230        jclass clazz, jint ptr, jobject configObj) {
1231    NativeInputManager* im = reinterpret_cast<NativeInputManager*>(ptr);
1232
1233    InputConfiguration config;
1234    im->getInputManager()->getReader()->getInputConfiguration(& config);
1235
1236    env->SetIntField(configObj, gConfigurationClassInfo.touchscreen, config.touchScreen);
1237    env->SetIntField(configObj, gConfigurationClassInfo.keyboard, config.keyboard);
1238    env->SetIntField(configObj, gConfigurationClassInfo.navigation, config.navigation);
1239}
1240
1241static jboolean nativeTransferTouchFocus(JNIEnv* env,
1242        jclass clazz, jint ptr, jobject fromChannelObj, jobject toChannelObj) {
1243    NativeInputManager* im = reinterpret_cast<NativeInputManager*>(ptr);
1244
1245    sp<InputChannel> fromChannel =
1246            android_view_InputChannel_getInputChannel(env, fromChannelObj);
1247    sp<InputChannel> toChannel =
1248            android_view_InputChannel_getInputChannel(env, toChannelObj);
1249
1250    if (fromChannel == NULL || toChannel == NULL) {
1251        return false;
1252    }
1253
1254    return im->getInputManager()->getDispatcher()->
1255            transferTouchFocus(fromChannel, toChannel);
1256}
1257
1258static void nativeSetPointerSpeed(JNIEnv* env,
1259        jclass clazz, jint ptr, jint speed) {
1260    NativeInputManager* im = reinterpret_cast<NativeInputManager*>(ptr);
1261
1262    im->setPointerSpeed(speed);
1263}
1264
1265static void nativeSetShowTouches(JNIEnv* env,
1266        jclass clazz, jint ptr, jboolean enabled) {
1267    NativeInputManager* im = reinterpret_cast<NativeInputManager*>(ptr);
1268
1269    im->setShowTouches(enabled);
1270}
1271
1272static jstring nativeDump(JNIEnv* env, jclass clazz, jint ptr) {
1273    NativeInputManager* im = reinterpret_cast<NativeInputManager*>(ptr);
1274
1275    String8 dump;
1276    im->dump(dump);
1277    return env->NewStringUTF(dump.string());
1278}
1279
1280static void nativeMonitor(JNIEnv* env, jclass clazz, jint ptr) {
1281    NativeInputManager* im = reinterpret_cast<NativeInputManager*>(ptr);
1282
1283    im->getInputManager()->getReader()->monitor();
1284    im->getInputManager()->getDispatcher()->monitor();
1285}
1286
1287// ----------------------------------------------------------------------------
1288
1289static JNINativeMethod gInputManagerMethods[] = {
1290    /* name, signature, funcPtr */
1291    { "nativeInit",
1292            "(Lcom/android/server/input/InputManagerService;Landroid/content/Context;Landroid/os/MessageQueue;)I",
1293            (void*) nativeInit },
1294    { "nativeStart", "(I)V",
1295            (void*) nativeStart },
1296    { "nativeSetDisplaySize", "(IIIIII)V",
1297            (void*) nativeSetDisplaySize },
1298    { "nativeSetDisplayOrientation", "(III)V",
1299            (void*) nativeSetDisplayOrientation },
1300    { "nativeGetScanCodeState", "(IIII)I",
1301            (void*) nativeGetScanCodeState },
1302    { "nativeGetKeyCodeState", "(IIII)I",
1303            (void*) nativeGetKeyCodeState },
1304    { "nativeGetSwitchState", "(IIII)I",
1305            (void*) nativeGetSwitchState },
1306    { "nativeHasKeys", "(III[I[Z)Z",
1307            (void*) nativeHasKeys },
1308    { "nativeRegisterInputChannel",
1309            "(ILandroid/view/InputChannel;Lcom/android/server/input/InputWindowHandle;Z)V",
1310            (void*) nativeRegisterInputChannel },
1311    { "nativeUnregisterInputChannel", "(ILandroid/view/InputChannel;)V",
1312            (void*) nativeUnregisterInputChannel },
1313    { "nativeSetInputFilterEnabled", "(IZ)V",
1314            (void*) nativeSetInputFilterEnabled },
1315    { "nativeInjectInputEvent", "(ILandroid/view/InputEvent;IIIII)I",
1316            (void*) nativeInjectInputEvent },
1317    { "nativeSetInputWindows", "(I[Lcom/android/server/input/InputWindowHandle;)V",
1318            (void*) nativeSetInputWindows },
1319    { "nativeSetFocusedApplication", "(ILcom/android/server/input/InputApplicationHandle;)V",
1320            (void*) nativeSetFocusedApplication },
1321    { "nativeSetInputDispatchMode", "(IZZ)V",
1322            (void*) nativeSetInputDispatchMode },
1323    { "nativeSetSystemUiVisibility", "(II)V",
1324            (void*) nativeSetSystemUiVisibility },
1325    { "nativeGetInputDevice", "(II)Landroid/view/InputDevice;",
1326            (void*) nativeGetInputDevice },
1327    { "nativeGetInputDeviceIds", "(I)[I",
1328            (void*) nativeGetInputDeviceIds },
1329    { "nativeGetInputConfiguration", "(ILandroid/content/res/Configuration;)V",
1330            (void*) nativeGetInputConfiguration },
1331    { "nativeTransferTouchFocus", "(ILandroid/view/InputChannel;Landroid/view/InputChannel;)Z",
1332            (void*) nativeTransferTouchFocus },
1333    { "nativeSetPointerSpeed", "(II)V",
1334            (void*) nativeSetPointerSpeed },
1335    { "nativeSetShowTouches", "(IZ)V",
1336            (void*) nativeSetShowTouches },
1337    { "nativeDump", "(I)Ljava/lang/String;",
1338            (void*) nativeDump },
1339    { "nativeMonitor", "(I)V",
1340            (void*) nativeMonitor },
1341};
1342
1343#define FIND_CLASS(var, className) \
1344        var = env->FindClass(className); \
1345        LOG_FATAL_IF(! var, "Unable to find class " className);
1346
1347#define GET_METHOD_ID(var, clazz, methodName, methodDescriptor) \
1348        var = env->GetMethodID(clazz, methodName, methodDescriptor); \
1349        LOG_FATAL_IF(! var, "Unable to find method " methodName);
1350
1351#define GET_FIELD_ID(var, clazz, fieldName, fieldDescriptor) \
1352        var = env->GetFieldID(clazz, fieldName, fieldDescriptor); \
1353        LOG_FATAL_IF(! var, "Unable to find field " fieldName);
1354
1355int register_android_server_InputManager(JNIEnv* env) {
1356    int res = jniRegisterNativeMethods(env, "com/android/server/input/InputManagerService",
1357            gInputManagerMethods, NELEM(gInputManagerMethods));
1358    LOG_FATAL_IF(res < 0, "Unable to register native methods.");
1359
1360    // Callbacks
1361
1362    jclass clazz;
1363    FIND_CLASS(clazz, "com/android/server/input/InputManagerService");
1364
1365    GET_METHOD_ID(gServiceClassInfo.notifyConfigurationChanged, clazz,
1366            "notifyConfigurationChanged", "(J)V");
1367
1368    GET_METHOD_ID(gServiceClassInfo.notifyLidSwitchChanged, clazz,
1369            "notifyLidSwitchChanged", "(JZ)V");
1370
1371    GET_METHOD_ID(gServiceClassInfo.notifyInputChannelBroken, clazz,
1372            "notifyInputChannelBroken", "(Lcom/android/server/input/InputWindowHandle;)V");
1373
1374    GET_METHOD_ID(gServiceClassInfo.notifyANR, clazz,
1375            "notifyANR",
1376            "(Lcom/android/server/input/InputApplicationHandle;Lcom/android/server/input/InputWindowHandle;)J");
1377
1378    GET_METHOD_ID(gServiceClassInfo.filterInputEvent, clazz,
1379            "filterInputEvent", "(Landroid/view/InputEvent;I)Z");
1380
1381    GET_METHOD_ID(gServiceClassInfo.interceptKeyBeforeQueueing, clazz,
1382            "interceptKeyBeforeQueueing", "(Landroid/view/KeyEvent;IZ)I");
1383
1384    GET_METHOD_ID(gServiceClassInfo.interceptMotionBeforeQueueingWhenScreenOff,
1385            clazz,
1386            "interceptMotionBeforeQueueingWhenScreenOff", "(I)I");
1387
1388    GET_METHOD_ID(gServiceClassInfo.interceptKeyBeforeDispatching, clazz,
1389            "interceptKeyBeforeDispatching",
1390            "(Lcom/android/server/input/InputWindowHandle;Landroid/view/KeyEvent;I)J");
1391
1392    GET_METHOD_ID(gServiceClassInfo.dispatchUnhandledKey, clazz,
1393            "dispatchUnhandledKey",
1394            "(Lcom/android/server/input/InputWindowHandle;Landroid/view/KeyEvent;I)Landroid/view/KeyEvent;");
1395
1396    GET_METHOD_ID(gServiceClassInfo.checkInjectEventsPermission, clazz,
1397            "checkInjectEventsPermission", "(II)Z");
1398
1399    GET_METHOD_ID(gServiceClassInfo.getVirtualKeyQuietTimeMillis, clazz,
1400            "getVirtualKeyQuietTimeMillis", "()I");
1401
1402    GET_METHOD_ID(gServiceClassInfo.getExcludedDeviceNames, clazz,
1403            "getExcludedDeviceNames", "()[Ljava/lang/String;");
1404
1405    GET_METHOD_ID(gServiceClassInfo.getKeyRepeatTimeout, clazz,
1406            "getKeyRepeatTimeout", "()I");
1407
1408    GET_METHOD_ID(gServiceClassInfo.getKeyRepeatDelay, clazz,
1409            "getKeyRepeatDelay", "()I");
1410
1411    GET_METHOD_ID(gServiceClassInfo.getHoverTapTimeout, clazz,
1412            "getHoverTapTimeout", "()I");
1413
1414    GET_METHOD_ID(gServiceClassInfo.getHoverTapSlop, clazz,
1415            "getHoverTapSlop", "()I");
1416
1417    GET_METHOD_ID(gServiceClassInfo.getDoubleTapTimeout, clazz,
1418            "getDoubleTapTimeout", "()I");
1419
1420    GET_METHOD_ID(gServiceClassInfo.getLongPressTimeout, clazz,
1421            "getLongPressTimeout", "()I");
1422
1423    GET_METHOD_ID(gServiceClassInfo.getPointerLayer, clazz,
1424            "getPointerLayer", "()I");
1425
1426    GET_METHOD_ID(gServiceClassInfo.getPointerIcon, clazz,
1427            "getPointerIcon", "()Landroid/view/PointerIcon;");
1428
1429    // KeyEvent
1430
1431    FIND_CLASS(gKeyEventClassInfo.clazz, "android/view/KeyEvent");
1432    gKeyEventClassInfo.clazz = jclass(env->NewGlobalRef(gKeyEventClassInfo.clazz));
1433
1434    // MotionEvent
1435
1436    FIND_CLASS(gMotionEventClassInfo.clazz, "android/view/MotionEvent");
1437    gMotionEventClassInfo.clazz = jclass(env->NewGlobalRef(gMotionEventClassInfo.clazz));
1438
1439    // InputDevice
1440
1441    FIND_CLASS(gInputDeviceClassInfo.clazz, "android/view/InputDevice");
1442    gInputDeviceClassInfo.clazz = jclass(env->NewGlobalRef(gInputDeviceClassInfo.clazz));
1443
1444    GET_METHOD_ID(gInputDeviceClassInfo.ctor, gInputDeviceClassInfo.clazz,
1445            "<init>", "()V");
1446
1447    GET_METHOD_ID(gInputDeviceClassInfo.addMotionRange, gInputDeviceClassInfo.clazz,
1448            "addMotionRange", "(IIFFFF)V");
1449
1450    GET_FIELD_ID(gInputDeviceClassInfo.mId, gInputDeviceClassInfo.clazz,
1451            "mId", "I");
1452
1453    GET_FIELD_ID(gInputDeviceClassInfo.mName, gInputDeviceClassInfo.clazz,
1454            "mName", "Ljava/lang/String;");
1455
1456    GET_FIELD_ID(gInputDeviceClassInfo.mDescriptor, gInputDeviceClassInfo.clazz,
1457            "mDescriptor", "Ljava/lang/String;");
1458
1459    GET_FIELD_ID(gInputDeviceClassInfo.mSources, gInputDeviceClassInfo.clazz,
1460            "mSources", "I");
1461
1462    GET_FIELD_ID(gInputDeviceClassInfo.mKeyboardType, gInputDeviceClassInfo.clazz,
1463            "mKeyboardType", "I");
1464
1465    GET_FIELD_ID(gInputDeviceClassInfo.mKeyCharacterMapFile, gInputDeviceClassInfo.clazz,
1466            "mKeyCharacterMapFile", "Ljava/lang/String;");
1467
1468    // Configuration
1469
1470    FIND_CLASS(clazz, "android/content/res/Configuration");
1471
1472    GET_FIELD_ID(gConfigurationClassInfo.touchscreen, clazz,
1473            "touchscreen", "I");
1474
1475    GET_FIELD_ID(gConfigurationClassInfo.keyboard, clazz,
1476            "keyboard", "I");
1477
1478    GET_FIELD_ID(gConfigurationClassInfo.navigation, clazz,
1479            "navigation", "I");
1480
1481    return 0;
1482}
1483
1484} /* namespace android */
1485