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