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