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