diff options
Diffstat (limited to 'services/jni')
-rw-r--r-- | services/jni/Android.mk | 2 | ||||
-rw-r--r-- | services/jni/com_android_server_InputManager.cpp | 746 | ||||
-rw-r--r-- | services/jni/com_android_server_KeyInputQueue.cpp | 14 | ||||
-rw-r--r-- | services/jni/onload.cpp | 2 |
4 files changed, 757 insertions, 7 deletions
diff --git a/services/jni/Android.mk b/services/jni/Android.mk index b90e327..499ca86 100644 --- a/services/jni/Android.mk +++ b/services/jni/Android.mk @@ -5,6 +5,7 @@ LOCAL_SRC_FILES:= \ com_android_server_AlarmManagerService.cpp \ com_android_server_BatteryService.cpp \ com_android_server_KeyInputQueue.cpp \ + com_android_server_InputManager.cpp \ com_android_server_LightsService.cpp \ com_android_server_SensorService.cpp \ com_android_server_SystemServer.cpp \ @@ -16,6 +17,7 @@ LOCAL_C_INCLUDES += \ $(JNI_H_INCLUDE) LOCAL_SHARED_LIBRARIES := \ + libandroid_runtime \ libcutils \ libhardware \ libhardware_legacy \ diff --git a/services/jni/com_android_server_InputManager.cpp b/services/jni/com_android_server_InputManager.cpp new file mode 100644 index 0000000..53262ae --- /dev/null +++ b/services/jni/com_android_server_InputManager.cpp @@ -0,0 +1,746 @@ +/* + * Copyright (C) 2010 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#define LOG_TAG "InputManager-JNI" + +#include "JNIHelp.h" +#include "jni.h" +#include <android_runtime/AndroidRuntime.h> +#include <ui/InputManager.h> +#include <ui/InputTransport.h> +#include <utils/Log.h> +#include <utils/threads.h> +#include "../../core/jni/android_view_KeyEvent.h" +#include "../../core/jni/android_view_MotionEvent.h" +#include "../../core/jni/android_view_InputChannel.h" +#include "../../core/jni/android_view_InputTarget.h" + +namespace android { + +class InputDispatchPolicy : public InputDispatchPolicyInterface { +public: + InputDispatchPolicy(JNIEnv* env, jobject callbacks); + virtual ~InputDispatchPolicy(); + + void setDisplaySize(int32_t displayId, int32_t width, int32_t height); + void setDisplayOrientation(int32_t displayId, int32_t orientation); + + virtual bool getDisplayInfo(int32_t displayId, + int32_t* width, int32_t* height, int32_t* orientation); + + virtual void notifyConfigurationChanged(nsecs_t when, + int32_t touchScreenConfig, int32_t keyboardConfig, int32_t navigationConfig); + + virtual void notifyLidSwitchChanged(nsecs_t when, bool lidOpen); + + virtual void virtualKeyFeedback(nsecs_t when, int32_t deviceId, + int32_t action, int32_t flags, int32_t keyCode, + int32_t scanCode, int32_t metaState, nsecs_t downTime); + + virtual int32_t interceptKey(nsecs_t when, int32_t deviceId, + bool down, int32_t keyCode, int32_t scanCode, uint32_t policyFlags); + virtual int32_t interceptTrackball(nsecs_t when, bool buttonChanged, bool buttonDown, + bool rolled); + virtual int32_t interceptTouch(nsecs_t when); + + virtual bool filterTouchEvents(); + virtual bool filterJumpyTouchEvents(); + virtual void getVirtualKeyDefinitions(const String8& deviceName, + Vector<VirtualKeyDefinition>& outVirtualKeyDefinitions); + virtual void getExcludedDeviceNames(Vector<String8>& outExcludedDeviceNames); + + virtual bool allowKeyRepeat(); + virtual nsecs_t getKeyRepeatTimeout(); + + virtual void getKeyEventTargets(KeyEvent* keyEvent, uint32_t policyFlags, + Vector<InputTarget>& outTargets); + virtual void getMotionEventTargets(MotionEvent* motionEvent, uint32_t policyFlags, + Vector<InputTarget>& outTargets); + +private: + bool isScreenOn(); + bool isScreenBright(); + +private: + jobject mCallbacks; + + int32_t mFilterTouchEvents; + int32_t mFilterJumpyTouchEvents; + + Mutex mDisplayLock; + int32_t mDisplayWidth, mDisplayHeight; + int32_t mDisplayOrientation; + + inline JNIEnv* threadEnv() const { + return AndroidRuntime::getJNIEnv(); + } +}; + + +// globals + +static sp<EventHub> gEventHub; +static sp<InputDispatchPolicy> gInputDispatchPolicy; +static sp<InputManager> gInputManager; + +// JNI + +static struct { + jclass clazz; + + jmethodID isScreenOn; + jmethodID isScreenBright; + jmethodID notifyConfigurationChanged; + jmethodID notifyLidSwitchChanged; + jmethodID virtualKeyFeedback; + jmethodID hackInterceptKey; + jmethodID goToSleep; + jmethodID pokeUserActivityForKey; + jmethodID notifyAppSwitchComing; + jmethodID filterTouchEvents; + jmethodID filterJumpyTouchEvents; + jmethodID getVirtualKeyDefinitions; + jmethodID getExcludedDeviceNames; + jmethodID getKeyEventTargets; + jmethodID getMotionEventTargets; +} gCallbacksClassInfo; + +static struct { + jclass clazz; + + jfieldID scanCode; + jfieldID centerX; + jfieldID centerY; + jfieldID width; + jfieldID height; +} gVirtualKeyDefinitionClassInfo; + +static bool checkInputManagerUnitialized(JNIEnv* env) { + if (gInputManager == NULL) { + LOGE("Input manager not initialized."); + jniThrowRuntimeException(env, "Input manager not initialized."); + return true; + } + return false; +} + +static void android_server_InputManager_nativeInit(JNIEnv* env, jclass clazz, + jobject callbacks) { + if (gEventHub == NULL) { + gEventHub = new EventHub(); + } + + if (gInputDispatchPolicy == NULL) { + gInputDispatchPolicy = new InputDispatchPolicy(env, callbacks); + } + + if (gInputManager == NULL) { + gInputManager = new InputManager(gEventHub, gInputDispatchPolicy); + } +} + +static void android_server_InputManager_nativeStart(JNIEnv* env, jclass clazz) { + if (checkInputManagerUnitialized(env)) { + return; + } + + status_t result = gInputManager->start(); + if (result) { + jniThrowRuntimeException(env, "Input manager could not be started."); + } +} + +static void android_server_InputManager_nativeSetDisplaySize(JNIEnv* env, jclass clazz, + jint displayId, jint width, jint height) { + if (checkInputManagerUnitialized(env)) { + return; + } + + // XXX we could get this from the SurfaceFlinger directly instead of requiring it + // to be passed in like this, not sure which is better but leaving it like this + // keeps the window manager in direct control of when display transitions propagate down + // to the input dispatcher + gInputDispatchPolicy->setDisplaySize(displayId, width, height); +} + +static void android_server_InputManager_nativeSetDisplayOrientation(JNIEnv* env, jclass clazz, + jint displayId, jint orientation) { + if (checkInputManagerUnitialized(env)) { + return; + } + + gInputDispatchPolicy->setDisplayOrientation(displayId, orientation); +} + +static jint android_server_InputManager_nativeGetScanCodeState(JNIEnv* env, jclass clazz, + jint deviceId, jint deviceClasses, jint scanCode) { + if (checkInputManagerUnitialized(env)) { + return KEY_STATE_UNKNOWN; + } + + return gInputManager->getScanCodeState(deviceId, deviceClasses, scanCode); +} + +static jint android_server_InputManager_nativeGetKeyCodeState(JNIEnv* env, jclass clazz, + jint deviceId, jint deviceClasses, jint keyCode) { + if (checkInputManagerUnitialized(env)) { + return KEY_STATE_UNKNOWN; + } + + return gInputManager->getKeyCodeState(deviceId, deviceClasses, keyCode); +} + +static jint android_server_InputManager_nativeGetSwitchState(JNIEnv* env, jclass clazz, + jint deviceId, jint deviceClasses, jint sw) { + if (checkInputManagerUnitialized(env)) { + return KEY_STATE_UNKNOWN; + } + + return gInputManager->getSwitchState(deviceId, deviceClasses, sw); +} + +static jboolean android_server_InputManager_nativeHasKeys(JNIEnv* env, jclass clazz, + jintArray keyCodes, jbooleanArray outFlags) { + if (checkInputManagerUnitialized(env)) { + return JNI_FALSE; + } + + int32_t* codes = env->GetIntArrayElements(keyCodes, NULL); + uint8_t* flags = env->GetBooleanArrayElements(outFlags, NULL); + jsize numCodes = env->GetArrayLength(keyCodes); + jboolean result; + if (numCodes == env->GetArrayLength(outFlags)) { + result = gInputManager->hasKeys(numCodes, codes, flags); + } else { + result = JNI_FALSE; + } + + env->ReleaseBooleanArrayElements(outFlags, flags, 0); + env->ReleaseIntArrayElements(keyCodes, codes, 0); + return result; +} + +static void throwInputChannelNotInitialized(JNIEnv* env) { + jniThrowException(env, "java/lang/IllegalStateException", + "inputChannel is not initialized"); +} + +static void android_server_InputManager_handleInputChannelDisposed(JNIEnv* env, + jobject inputChannelObj, const sp<InputChannel>& inputChannel, void* data) { + LOGW("Input channel object '%s' was disposed without first being unregistered with " + "the input manager!", inputChannel->getName().string()); + + gInputManager->unregisterInputChannel(inputChannel); +} + +static void android_server_InputManager_nativeRegisterInputChannel(JNIEnv* env, jclass clazz, + jobject inputChannelObj) { + if (checkInputManagerUnitialized(env)) { + return; + } + + sp<InputChannel> inputChannel = android_view_InputChannel_getInputChannel(env, + inputChannelObj); + if (inputChannel == NULL) { + throwInputChannelNotInitialized(env); + return; + } + + status_t status = gInputManager->registerInputChannel(inputChannel); + if (status) { + jniThrowRuntimeException(env, "Failed to register input channel. " + "Check logs for details."); + return; + } + + android_view_InputChannel_setDisposeCallback(env, inputChannelObj, + android_server_InputManager_handleInputChannelDisposed, NULL); +} + +static void android_server_InputManager_nativeUnregisterInputChannel(JNIEnv* env, jclass clazz, + jobject inputChannelObj) { + if (checkInputManagerUnitialized(env)) { + return; + } + + sp<InputChannel> inputChannel = android_view_InputChannel_getInputChannel(env, + inputChannelObj); + if (inputChannel == NULL) { + throwInputChannelNotInitialized(env); + return; + } + + android_view_InputChannel_setDisposeCallback(env, inputChannelObj, NULL, NULL); + + status_t status = gInputManager->unregisterInputChannel(inputChannel); + if (status) { + jniThrowRuntimeException(env, "Failed to unregister input channel. " + "Check logs for details."); + } +} + +static JNINativeMethod gInputManagerMethods[] = { + /* name, signature, funcPtr */ + { "nativeInit", "(Lcom/android/server/InputManager$Callbacks;)V", + (void*) android_server_InputManager_nativeInit }, + { "nativeStart", "()V", + (void*) android_server_InputManager_nativeStart }, + { "nativeSetDisplaySize", "(III)V", + (void*) android_server_InputManager_nativeSetDisplaySize }, + { "nativeSetDisplayOrientation", "(II)V", + (void*) android_server_InputManager_nativeSetDisplayOrientation }, + { "nativeGetScanCodeState", "(III)I", + (void*) android_server_InputManager_nativeGetScanCodeState }, + { "nativeGetKeyCodeState", "(III)I", + (void*) android_server_InputManager_nativeGetKeyCodeState }, + { "nativeGetSwitchState", "(III)I", + (void*) android_server_InputManager_nativeGetSwitchState }, + { "nativeHasKeys", "([I[Z)Z", + (void*) android_server_InputManager_nativeHasKeys }, + { "nativeRegisterInputChannel", "(Landroid/view/InputChannel;)V", + (void*) android_server_InputManager_nativeRegisterInputChannel }, + { "nativeUnregisterInputChannel", "(Landroid/view/InputChannel;)V", + (void*) android_server_InputManager_nativeUnregisterInputChannel } +}; + +#define FIND_CLASS(var, className) \ + var = env->FindClass(className); \ + LOG_FATAL_IF(! var, "Unable to find class " className); \ + var = jclass(env->NewGlobalRef(var)); + +#define GET_METHOD_ID(var, clazz, methodName, methodDescriptor) \ + var = env->GetMethodID(clazz, methodName, methodDescriptor); \ + LOG_FATAL_IF(! var, "Unable to find method " methodName); + +#define GET_FIELD_ID(var, clazz, fieldName, fieldDescriptor) \ + var = env->GetFieldID(clazz, fieldName, fieldDescriptor); \ + LOG_FATAL_IF(! var, "Unable to find field " fieldName); + +int register_android_server_InputManager(JNIEnv* env) { + int res = jniRegisterNativeMethods(env, "com/android/server/InputManager", + gInputManagerMethods, NELEM(gInputManagerMethods)); + LOG_FATAL_IF(res < 0, "Unable to register native methods."); + + // Policy + + FIND_CLASS(gCallbacksClassInfo.clazz, "com/android/server/InputManager$Callbacks"); + + GET_METHOD_ID(gCallbacksClassInfo.isScreenOn, gCallbacksClassInfo.clazz, + "isScreenOn", "()Z"); + + GET_METHOD_ID(gCallbacksClassInfo.isScreenBright, gCallbacksClassInfo.clazz, + "isScreenBright", "()Z"); + + GET_METHOD_ID(gCallbacksClassInfo.notifyConfigurationChanged, gCallbacksClassInfo.clazz, + "notifyConfigurationChanged", "(JIII)V"); + + GET_METHOD_ID(gCallbacksClassInfo.notifyLidSwitchChanged, gCallbacksClassInfo.clazz, + "notifyLidSwitchChanged", "(JZ)V"); + + GET_METHOD_ID(gCallbacksClassInfo.virtualKeyFeedback, gCallbacksClassInfo.clazz, + "virtualKeyFeedback", "(JIIIIIIJ)V"); + + GET_METHOD_ID(gCallbacksClassInfo.hackInterceptKey, gCallbacksClassInfo.clazz, + "hackInterceptKey", "(IIIIIIJZ)I"); + + GET_METHOD_ID(gCallbacksClassInfo.goToSleep, gCallbacksClassInfo.clazz, + "goToSleep", "(J)V"); + + GET_METHOD_ID(gCallbacksClassInfo.pokeUserActivityForKey, gCallbacksClassInfo.clazz, + "pokeUserActivityForKey", "(J)V"); + + GET_METHOD_ID(gCallbacksClassInfo.notifyAppSwitchComing, gCallbacksClassInfo.clazz, + "notifyAppSwitchComing", "()V"); + + GET_METHOD_ID(gCallbacksClassInfo.filterTouchEvents, gCallbacksClassInfo.clazz, + "filterTouchEvents", "()Z"); + + GET_METHOD_ID(gCallbacksClassInfo.filterJumpyTouchEvents, gCallbacksClassInfo.clazz, + "filterJumpyTouchEvents", "()Z"); + + GET_METHOD_ID(gCallbacksClassInfo.getVirtualKeyDefinitions, gCallbacksClassInfo.clazz, + "getVirtualKeyDefinitions", + "(Ljava/lang/String;)[Lcom/android/server/InputManager$VirtualKeyDefinition;"); + + GET_METHOD_ID(gCallbacksClassInfo.getExcludedDeviceNames, gCallbacksClassInfo.clazz, + "getExcludedDeviceNames", "()[Ljava/lang/String;"); + + GET_METHOD_ID(gCallbacksClassInfo.getKeyEventTargets, gCallbacksClassInfo.clazz, + "getKeyEventTargets", "(Landroid/view/KeyEvent;II)[Landroid/view/InputTarget;"); + + GET_METHOD_ID(gCallbacksClassInfo.getMotionEventTargets, gCallbacksClassInfo.clazz, + "getMotionEventTargets", "(Landroid/view/MotionEvent;II)[Landroid/view/InputTarget;"); + + // VirtualKeyDefinition + + FIND_CLASS(gVirtualKeyDefinitionClassInfo.clazz, + "com/android/server/InputManager$VirtualKeyDefinition"); + + GET_FIELD_ID(gVirtualKeyDefinitionClassInfo.scanCode, gVirtualKeyDefinitionClassInfo.clazz, + "scanCode", "I"); + + GET_FIELD_ID(gVirtualKeyDefinitionClassInfo.centerX, gVirtualKeyDefinitionClassInfo.clazz, + "centerX", "I"); + + GET_FIELD_ID(gVirtualKeyDefinitionClassInfo.centerY, gVirtualKeyDefinitionClassInfo.clazz, + "centerY", "I"); + + GET_FIELD_ID(gVirtualKeyDefinitionClassInfo.width, gVirtualKeyDefinitionClassInfo.clazz, + "width", "I"); + + GET_FIELD_ID(gVirtualKeyDefinitionClassInfo.height, gVirtualKeyDefinitionClassInfo.clazz, + "height", "I"); + + return 0; +} + +// static functions + +static bool isAppSwitchKey(int32_t keyCode) { + return keyCode == KEYCODE_HOME || keyCode == KEYCODE_ENDCALL; +} + +static bool checkException(JNIEnv* env, const char* methodName) { + if (env->ExceptionCheck()) { + LOGE("An exception was thrown by an InputDispatchPolicy callback '%s'.", methodName); + LOGE_EX(env); + env->ExceptionClear(); + return true; + } + return false; +} + + +// InputDispatchPolicy implementation + +InputDispatchPolicy::InputDispatchPolicy(JNIEnv* env, jobject callbacks) : + mFilterTouchEvents(-1), mFilterJumpyTouchEvents(-1), + mDisplayWidth(-1), mDisplayHeight(-1), mDisplayOrientation(-1) { + mCallbacks = env->NewGlobalRef(callbacks); +} + +InputDispatchPolicy::~InputDispatchPolicy() { + JNIEnv* env = threadEnv(); + + env->DeleteGlobalRef(mCallbacks); +} + +void InputDispatchPolicy::setDisplaySize(int32_t displayId, int32_t width, int32_t height) { + if (displayId == 0) { + AutoMutex _l(mDisplayLock); + + mDisplayWidth = width; + mDisplayHeight = height; + } +} + +void InputDispatchPolicy::setDisplayOrientation(int32_t displayId, int32_t orientation) { + if (displayId == 0) { + AutoMutex _l(mDisplayLock); + + mDisplayOrientation = orientation; + } +} + +bool InputDispatchPolicy::getDisplayInfo(int32_t displayId, + int32_t* width, int32_t* height, int32_t* orientation) { + bool result = false; + if (displayId == 0) { + AutoMutex _l(mDisplayLock); + + if (mDisplayWidth > 0) { + *width = mDisplayWidth; + *height = mDisplayHeight; + *orientation = mDisplayOrientation; + result = true; + } + } + return result; +} + +bool InputDispatchPolicy::isScreenOn() { + JNIEnv* env = threadEnv(); + + jboolean result = env->CallBooleanMethod(mCallbacks, gCallbacksClassInfo.isScreenOn); + if (checkException(env, "isScreenOn")) { + return true; + } + return result; +} + +bool InputDispatchPolicy::isScreenBright() { + JNIEnv* env = threadEnv(); + + jboolean result = env->CallBooleanMethod(mCallbacks, gCallbacksClassInfo.isScreenBright); + if (checkException(env, "isScreenBright")) { + return true; + } + return result; +} + +void InputDispatchPolicy::notifyConfigurationChanged(nsecs_t when, + int32_t touchScreenConfig, int32_t keyboardConfig, int32_t navigationConfig) { + JNIEnv* env = threadEnv(); + + env->CallVoidMethod(mCallbacks, gCallbacksClassInfo.notifyConfigurationChanged, + when, touchScreenConfig, keyboardConfig, navigationConfig); + checkException(env, "notifyConfigurationChanged"); +} + +void InputDispatchPolicy::notifyLidSwitchChanged(nsecs_t when, bool lidOpen) { + JNIEnv* env = threadEnv(); + env->CallVoidMethod(mCallbacks, gCallbacksClassInfo.notifyLidSwitchChanged, + when, lidOpen); + checkException(env, "notifyLidSwitchChanged"); +} + +void InputDispatchPolicy::virtualKeyFeedback(nsecs_t when, int32_t deviceId, + int32_t action, int32_t flags, int32_t keyCode, + int32_t scanCode, int32_t metaState, nsecs_t downTime) { + JNIEnv* env = threadEnv(); + + env->CallVoidMethod(mCallbacks, gCallbacksClassInfo.virtualKeyFeedback, + when, deviceId, action, flags, keyCode, scanCode, metaState, downTime); + checkException(env, "virtualKeyFeedback"); +} + +int32_t InputDispatchPolicy::interceptKey(nsecs_t when, + int32_t deviceId, bool down, int32_t keyCode, int32_t scanCode, uint32_t policyFlags) { + const int32_t WM_ACTION_PASS_TO_USER = 1; + const int32_t WM_ACTION_POKE_USER_ACTIVITY = 2; + const int32_t WM_ACTION_GO_TO_SLEEP = 4; + + JNIEnv* env = threadEnv(); + + bool isScreenOn = this->isScreenOn(); + bool isScreenBright = this->isScreenBright(); + + jint wmActions = env->CallIntMethod(mCallbacks, gCallbacksClassInfo.hackInterceptKey, + deviceId, EV_KEY, scanCode, keyCode, policyFlags, down ? 1 : 0, when, isScreenOn); + if (checkException(env, "hackInterceptKey")) { + wmActions = 0; + } + + int32_t actions = ACTION_NONE; + if (! isScreenOn) { + // Key presses and releases wake the device. + actions |= ACTION_WOKE_HERE; + } + + if (! isScreenBright) { + // Key presses and releases brighten the screen if dimmed. + actions |= ACTION_BRIGHT_HERE; + } + + if (wmActions & WM_ACTION_GO_TO_SLEEP) { + env->CallVoidMethod(mCallbacks, gCallbacksClassInfo.goToSleep, when); + checkException(env, "goToSleep"); + } + + if (wmActions & WM_ACTION_POKE_USER_ACTIVITY) { + env->CallVoidMethod(mCallbacks, gCallbacksClassInfo.pokeUserActivityForKey, when); + checkException(env, "pokeUserActivityForKey"); + } + + if (wmActions & WM_ACTION_PASS_TO_USER) { + actions |= ACTION_DISPATCH; + } + + if (! (wmActions & WM_ACTION_PASS_TO_USER)) { + if (down && isAppSwitchKey(keyCode)) { + env->CallVoidMethod(mCallbacks, gCallbacksClassInfo.notifyAppSwitchComing); + checkException(env, "notifyAppSwitchComing"); + + actions |= ACTION_APP_SWITCH_COMING; + } + } + return actions; +} + +int32_t InputDispatchPolicy::interceptTouch(nsecs_t when) { + if (! isScreenOn()) { + // Touch events do not wake the device. + return ACTION_NONE; + } + + return ACTION_DISPATCH; +} + +int32_t InputDispatchPolicy::interceptTrackball(nsecs_t when, + bool buttonChanged, bool buttonDown, bool rolled) { + if (! isScreenOn()) { + // Trackball motions and button presses do not wake the device. + return ACTION_NONE; + } + + return ACTION_DISPATCH; +} + +bool InputDispatchPolicy::filterTouchEvents() { + if (mFilterTouchEvents < 0) { + JNIEnv* env = threadEnv(); + + jboolean result = env->CallBooleanMethod(mCallbacks, + gCallbacksClassInfo.filterTouchEvents); + if (checkException(env, "filterTouchEvents")) { + result = false; + } + + mFilterTouchEvents = result ? 1 : 0; + } + return mFilterTouchEvents; +} + +bool InputDispatchPolicy::filterJumpyTouchEvents() { + if (mFilterJumpyTouchEvents < 0) { + JNIEnv* env = threadEnv(); + + jboolean result = env->CallBooleanMethod(mCallbacks, + gCallbacksClassInfo.filterJumpyTouchEvents); + if (checkException(env, "filterJumpyTouchEvents")) { + result = false; + } + + mFilterJumpyTouchEvents = result ? 1 : 0; + } + return mFilterJumpyTouchEvents; +} + +void InputDispatchPolicy::getVirtualKeyDefinitions(const String8& deviceName, + Vector<VirtualKeyDefinition>& outVirtualKeyDefinitions) { + JNIEnv* env = threadEnv(); + + jstring deviceNameStr = env->NewStringUTF(deviceName.string()); + if (! checkException(env, "getVirtualKeyDefinitions")) { + jobjectArray result = jobjectArray(env->CallObjectMethod(mCallbacks, + gCallbacksClassInfo.getVirtualKeyDefinitions, deviceNameStr)); + if (! checkException(env, "getVirtualKeyDefinitions") && result) { + jsize length = env->GetArrayLength(result); + for (jsize i = 0; i < length; i++) { + jobject item = env->GetObjectArrayElement(result, i); + + outVirtualKeyDefinitions.add(); + outVirtualKeyDefinitions.editTop().scanCode = + int32_t(env->GetIntField(item, gVirtualKeyDefinitionClassInfo.scanCode)); + outVirtualKeyDefinitions.editTop().centerX = + int32_t(env->GetIntField(item, gVirtualKeyDefinitionClassInfo.centerX)); + outVirtualKeyDefinitions.editTop().centerY = + int32_t(env->GetIntField(item, gVirtualKeyDefinitionClassInfo.centerY)); + outVirtualKeyDefinitions.editTop().width = + int32_t(env->GetIntField(item, gVirtualKeyDefinitionClassInfo.width)); + outVirtualKeyDefinitions.editTop().height = + int32_t(env->GetIntField(item, gVirtualKeyDefinitionClassInfo.height)); + + env->DeleteLocalRef(item); + } + env->DeleteLocalRef(result); + } + env->DeleteLocalRef(deviceNameStr); + } +} + +void InputDispatchPolicy::getExcludedDeviceNames(Vector<String8>& outExcludedDeviceNames) { + JNIEnv* env = threadEnv(); + + jobjectArray result = jobjectArray(env->CallObjectMethod(mCallbacks, + gCallbacksClassInfo.getExcludedDeviceNames)); + if (! checkException(env, "getExcludedDeviceNames") && result) { + jsize length = env->GetArrayLength(result); + for (jsize i = 0; i < length; i++) { + jstring item = jstring(env->GetObjectArrayElement(result, i)); + + const char* deviceNameChars = env->GetStringUTFChars(item, NULL); + outExcludedDeviceNames.add(String8(deviceNameChars)); + env->ReleaseStringUTFChars(item, deviceNameChars); + + env->DeleteLocalRef(item); + } + env->DeleteLocalRef(result); + } +} + +bool InputDispatchPolicy::allowKeyRepeat() { + // Disable key repeat when the screen is off. + return isScreenOn(); +} + +nsecs_t InputDispatchPolicy::getKeyRepeatTimeout() { + // TODO use ViewConfiguration.getLongPressTimeout() + return milliseconds_to_nanoseconds(500); +} + +void InputDispatchPolicy::getKeyEventTargets(KeyEvent* keyEvent, uint32_t policyFlags, + Vector<InputTarget>& outTargets) { + JNIEnv* env = threadEnv(); + + jobject keyEventObj = android_view_KeyEvent_fromNative(env, keyEvent); + if (! keyEventObj) { + LOGE("Could not obtain DVM KeyEvent object to get key event targets."); + } else { + jobjectArray result = jobjectArray(env->CallObjectMethod(mCallbacks, + gCallbacksClassInfo.getKeyEventTargets, + keyEventObj, jint(keyEvent->getNature()), jint(policyFlags))); + if (! checkException(env, "getKeyEventTargets") && result) { + jsize length = env->GetArrayLength(result); + for (jsize i = 0; i < length; i++) { + jobject item = env->GetObjectArrayElement(result, i); + if (! item) { + break; // found null element indicating end of used portion of the array + } + + outTargets.add(); + android_view_InputTarget_toNative(env, item, & outTargets.editTop()); + + env->DeleteLocalRef(item); + } + env->DeleteLocalRef(result); + } + env->DeleteLocalRef(keyEventObj); + } +} + +void InputDispatchPolicy::getMotionEventTargets(MotionEvent* motionEvent, uint32_t policyFlags, + Vector<InputTarget>& outTargets) { + JNIEnv* env = threadEnv(); + + jobject motionEventObj = android_view_MotionEvent_fromNative(env, motionEvent); + if (! motionEventObj) { + LOGE("Could not obtain DVM MotionEvent object to get key event targets."); + } else { + jobjectArray result = jobjectArray(env->CallObjectMethod(mCallbacks, + gCallbacksClassInfo.getMotionEventTargets, + motionEventObj, jint(motionEvent->getNature()), jint(policyFlags))); + if (! checkException(env, "getMotionEventTargets") && result) { + jsize length = env->GetArrayLength(result); + for (jsize i = 0; i < length; i++) { + jobject item = env->GetObjectArrayElement(result, i); + if (! item) { + break; // found null element indicating end of used portion of the array + } + + outTargets.add(); + android_view_InputTarget_toNative(env, item, & outTargets.editTop()); + + env->DeleteLocalRef(item); + } + env->DeleteLocalRef(result); + } + android_view_MotionEvent_recycle(env, motionEventObj); + env->DeleteLocalRef(motionEventObj); + } +} + +} /* namespace android */ diff --git a/services/jni/com_android_server_KeyInputQueue.cpp b/services/jni/com_android_server_KeyInputQueue.cpp index c92f8df..f9e3585 100644 --- a/services/jni/com_android_server_KeyInputQueue.cpp +++ b/services/jni/com_android_server_KeyInputQueue.cpp @@ -156,7 +156,7 @@ android_server_KeyInputQueue_getSwitchState(JNIEnv* env, jobject clazz, { jint st = -1; gLock.lock(); - if (gHub != NULL) st = gHub->getSwitchState(sw); + if (gHub != NULL) st = gHub->getSwitchState(-1, -1, sw); gLock.unlock(); return st; @@ -168,7 +168,7 @@ android_server_KeyInputQueue_getSwitchStateDevice(JNIEnv* env, jobject clazz, { jint st = -1; gLock.lock(); - if (gHub != NULL) st = gHub->getSwitchState(deviceId, sw); + if (gHub != NULL) st = gHub->getSwitchState(deviceId, -1, sw); gLock.unlock(); return st; @@ -180,7 +180,7 @@ android_server_KeyInputQueue_getScancodeState(JNIEnv* env, jobject clazz, { jint st = -1; gLock.lock(); - if (gHub != NULL) st = gHub->getScancodeState(sw); + if (gHub != NULL) st = gHub->getScanCodeState(0, -1, sw); gLock.unlock(); return st; @@ -192,7 +192,7 @@ android_server_KeyInputQueue_getScancodeStateDevice(JNIEnv* env, jobject clazz, { jint st = -1; gLock.lock(); - if (gHub != NULL) st = gHub->getScancodeState(deviceId, sw); + if (gHub != NULL) st = gHub->getScanCodeState(deviceId, -1, sw); gLock.unlock(); return st; @@ -204,7 +204,7 @@ android_server_KeyInputQueue_getKeycodeState(JNIEnv* env, jobject clazz, { jint st = -1; gLock.lock(); - if (gHub != NULL) st = gHub->getKeycodeState(sw); + if (gHub != NULL) st = gHub->getKeyCodeState(0, -1, sw); gLock.unlock(); return st; @@ -216,7 +216,7 @@ android_server_KeyInputQueue_getKeycodeStateDevice(JNIEnv* env, jobject clazz, { jint st = -1; gLock.lock(); - if (gHub != NULL) st = gHub->getKeycodeState(deviceId, sw); + if (gHub != NULL) st = gHub->getKeyCodeState(deviceId,-1, sw); gLock.unlock(); return st; @@ -247,7 +247,7 @@ android_server_KeyInputQueue_hasKeys(JNIEnv* env, jobject clazz, int32_t* codes = env->GetIntArrayElements(keyCodes, NULL); uint8_t* flags = env->GetBooleanArrayElements(outFlags, NULL); - size_t numCodes = env->GetArrayLength(keyCodes); + jsize numCodes = env->GetArrayLength(keyCodes); if (numCodes == env->GetArrayLength(outFlags)) { gLock.lock(); if (gHub != NULL) ret = gHub->hasKeys(numCodes, codes, flags); diff --git a/services/jni/onload.cpp b/services/jni/onload.cpp index d11e7e1..a1a6838 100644 --- a/services/jni/onload.cpp +++ b/services/jni/onload.cpp @@ -7,6 +7,7 @@ namespace android { int register_android_server_AlarmManagerService(JNIEnv* env); int register_android_server_BatteryService(JNIEnv* env); int register_android_server_KeyInputQueue(JNIEnv* env); +int register_android_server_InputManager(JNIEnv* env); int register_android_server_LightsService(JNIEnv* env); int register_android_server_SensorService(JNIEnv* env); int register_android_server_VibratorService(JNIEnv* env); @@ -28,6 +29,7 @@ extern "C" jint JNI_OnLoad(JavaVM* vm, void* reserved) LOG_ASSERT(env, "Could not retrieve the env!"); register_android_server_KeyInputQueue(env); + register_android_server_InputManager(env); register_android_server_LightsService(env); register_android_server_AlarmManagerService(env); register_android_server_BatteryService(env); |