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