diff options
Diffstat (limited to 'services/jni')
-rw-r--r-- | services/jni/Android.mk | 9 | ||||
-rw-r--r-- | services/jni/com_android_server_InputManager.cpp | 1541 | ||||
-rw-r--r-- | services/jni/com_android_server_KeyInputQueue.cpp | 358 | ||||
-rw-r--r-- | services/jni/com_android_server_PowerManagerService.cpp | 182 | ||||
-rw-r--r-- | services/jni/com_android_server_PowerManagerService.h | 34 | ||||
-rw-r--r-- | services/jni/com_android_server_SensorService.cpp | 177 | ||||
-rwxr-xr-x | services/jni/com_android_server_location_GpsLocationProvider.cpp | 638 | ||||
-rw-r--r-- | services/jni/onload.cpp | 10 |
8 files changed, 2407 insertions, 542 deletions
diff --git a/services/jni/Android.mk b/services/jni/Android.mk index 9d2760e..c90879d 100644 --- a/services/jni/Android.mk +++ b/services/jni/Android.mk @@ -4,24 +4,27 @@ include $(CLEAR_VARS) 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_PowerManagerService.cpp \ com_android_server_SystemServer.cpp \ com_android_server_VibratorService.cpp \ + com_android_server_location_GpsLocationProvider.cpp \ onload.cpp LOCAL_C_INCLUDES += \ $(JNI_H_INCLUDE) LOCAL_SHARED_LIBRARIES := \ + libandroid_runtime \ libcutils \ libhardware \ libhardware_legacy \ libnativehelper \ libsystem_server \ libutils \ - libui + libui \ + libsurfaceflinger_client ifeq ($(TARGET_SIMULATOR),true) ifeq ($(TARGET_OS),linux) diff --git a/services/jni/com_android_server_InputManager.cpp b/services/jni/com_android_server_InputManager.cpp new file mode 100644 index 0000000..1bd1874 --- /dev/null +++ b/services/jni/com_android_server_InputManager.cpp @@ -0,0 +1,1541 @@ +/* + * 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" + +//#define LOG_NDEBUG 0 + +// Log debug messages about InputReaderPolicy +#define DEBUG_INPUT_READER_POLICY 0 + +// Log debug messages about InputDispatcherPolicy +#define DEBUG_INPUT_DISPATCHER_POLICY 0 + +#include "JNIHelp.h" +#include "jni.h" +#include <limits.h> +#include <android_runtime/AndroidRuntime.h> +#include <ui/InputReader.h> +#include <ui/InputDispatcher.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 "com_android_server_PowerManagerService.h" + +namespace android { + +// ---------------------------------------------------------------------------- + +static struct { + jclass clazz; + + jmethodID notifyConfigurationChanged; + jmethodID notifyLidSwitchChanged; + jmethodID notifyInputChannelBroken; + jmethodID notifyANR; + jmethodID interceptKeyBeforeQueueing; + jmethodID interceptKeyBeforeDispatching; + jmethodID checkInjectEventsPermission; + jmethodID filterTouchEvents; + jmethodID filterJumpyTouchEvents; + jmethodID getVirtualKeyDefinitions; + jmethodID getInputDeviceCalibration; + jmethodID getExcludedDeviceNames; + jmethodID getMaxEventsPerSecond; +} gCallbacksClassInfo; + +static struct { + jclass clazz; + + jfieldID scanCode; + jfieldID centerX; + jfieldID centerY; + jfieldID width; + jfieldID height; +} gVirtualKeyDefinitionClassInfo; + +static struct { + jclass clazz; + + jfieldID keys; + jfieldID values; +} gInputDeviceCalibrationClassInfo; + +static struct { + jclass clazz; + + jfieldID inputChannel; + jfieldID name; + jfieldID layoutParamsFlags; + jfieldID layoutParamsType; + jfieldID dispatchingTimeoutNanos; + jfieldID frameLeft; + jfieldID frameTop; + jfieldID frameRight; + jfieldID frameBottom; + jfieldID visibleFrameLeft; + jfieldID visibleFrameTop; + jfieldID visibleFrameRight; + jfieldID visibleFrameBottom; + jfieldID touchableAreaLeft; + jfieldID touchableAreaTop; + jfieldID touchableAreaRight; + jfieldID touchableAreaBottom; + jfieldID visible; + jfieldID canReceiveKeys; + jfieldID hasFocus; + jfieldID hasWallpaper; + jfieldID paused; + jfieldID layer; + jfieldID ownerPid; + jfieldID ownerUid; +} gInputWindowClassInfo; + +static struct { + jclass clazz; + + jfieldID name; + jfieldID dispatchingTimeoutNanos; + jfieldID token; +} gInputApplicationClassInfo; + +static struct { + jclass clazz; +} gKeyEventClassInfo; + +static struct { + jclass clazz; +} gMotionEventClassInfo; + +static struct { + jclass clazz; + + jmethodID ctor; + jmethodID addMotionRange; + + jfieldID mId; + jfieldID mName; + jfieldID mSources; + jfieldID mKeyboardType; + jfieldID mMotionRanges; +} gInputDeviceClassInfo; + +static struct { + jclass clazz; + + jfieldID touchscreen; + jfieldID keyboard; + jfieldID navigation; +} gConfigurationClassInfo; + +// ---------------------------------------------------------------------------- + +static inline nsecs_t now() { + return systemTime(SYSTEM_TIME_MONOTONIC); +} + +// ---------------------------------------------------------------------------- + +class NativeInputManager : public virtual RefBase, + public virtual InputReaderPolicyInterface, + public virtual InputDispatcherPolicyInterface { +protected: + virtual ~NativeInputManager(); + +public: + NativeInputManager(jobject callbacksObj); + + inline sp<InputManager> getInputManager() const { return mInputManager; } + + void dump(String8& dump); + + void setDisplaySize(int32_t displayId, int32_t width, int32_t height); + void setDisplayOrientation(int32_t displayId, int32_t orientation); + + status_t registerInputChannel(JNIEnv* env, const sp<InputChannel>& inputChannel, + jweak inputChannelObjWeak, bool monitor); + status_t unregisterInputChannel(JNIEnv* env, const sp<InputChannel>& inputChannel); + + void setInputWindows(JNIEnv* env, jobjectArray windowObjArray); + void setFocusedApplication(JNIEnv* env, jobject applicationObj); + void setInputDispatchMode(bool enabled, bool frozen); + + /* --- InputReaderPolicyInterface implementation --- */ + + virtual bool getDisplayInfo(int32_t displayId, + int32_t* width, int32_t* height, int32_t* orientation); + virtual bool filterTouchEvents(); + virtual bool filterJumpyTouchEvents(); + virtual void getVirtualKeyDefinitions(const String8& deviceName, + Vector<VirtualKeyDefinition>& outVirtualKeyDefinitions); + virtual void getInputDeviceCalibration(const String8& deviceName, + InputDeviceCalibration& outCalibration); + virtual void getExcludedDeviceNames(Vector<String8>& outExcludedDeviceNames); + + /* --- InputDispatcherPolicyInterface implementation --- */ + + virtual void notifySwitch(nsecs_t when, int32_t switchCode, int32_t switchValue, + uint32_t policyFlags); + virtual void notifyConfigurationChanged(nsecs_t when); + virtual nsecs_t notifyANR(const sp<InputApplicationHandle>& inputApplicationHandle, + const sp<InputChannel>& inputChannel); + virtual void notifyInputChannelBroken(const sp<InputChannel>& inputChannel); + virtual nsecs_t getKeyRepeatTimeout(); + virtual nsecs_t getKeyRepeatDelay(); + virtual int32_t getMaxEventsPerSecond(); + virtual void interceptKeyBeforeQueueing(nsecs_t when, int32_t deviceId, + int32_t action, int32_t& flags, int32_t keyCode, int32_t scanCode, + uint32_t& policyFlags); + virtual void interceptGenericBeforeQueueing(nsecs_t when, uint32_t& policyFlags); + virtual bool interceptKeyBeforeDispatching(const sp<InputChannel>& inputChannel, + const KeyEvent* keyEvent, uint32_t policyFlags); + virtual void pokeUserActivity(nsecs_t eventTime, int32_t eventType); + virtual bool checkInjectEventsPermissionNonReentrant( + int32_t injectorPid, int32_t injectorUid); + +private: + class ApplicationToken : public InputApplicationHandle { + jweak mTokenObjWeak; + + public: + ApplicationToken(jweak tokenObjWeak) : + mTokenObjWeak(tokenObjWeak) { } + + virtual ~ApplicationToken() { + JNIEnv* env = NativeInputManager::jniEnv(); + env->DeleteWeakGlobalRef(mTokenObjWeak); + } + + inline jweak getTokenObj() { return mTokenObjWeak; } + }; + + sp<InputManager> mInputManager; + + jobject mCallbacksObj; + + // Cached filtering policies. + int32_t mFilterTouchEvents; + int32_t mFilterJumpyTouchEvents; + + // Cached throttling policy. + int32_t mMaxEventsPerSecond; + + // Cached display state. (lock mDisplayLock) + Mutex mDisplayLock; + int32_t mDisplayWidth, mDisplayHeight; + int32_t mDisplayOrientation; + + // Power manager interactions. + bool isScreenOn(); + bool isScreenBright(); + + // Weak references to all currently registered input channels by connection pointer. + Mutex mInputChannelRegistryLock; + KeyedVector<InputChannel*, jweak> mInputChannelObjWeakTable; + + jobject getInputChannelObjLocal(JNIEnv* env, const sp<InputChannel>& inputChannel); + + static bool populateWindow(JNIEnv* env, jobject windowObj, InputWindow& outWindow); + + static bool checkAndClearExceptionFromCallback(JNIEnv* env, const char* methodName); + + static inline JNIEnv* jniEnv() { + return AndroidRuntime::getJNIEnv(); + } +}; + +// ---------------------------------------------------------------------------- + +NativeInputManager::NativeInputManager(jobject callbacksObj) : + mFilterTouchEvents(-1), mFilterJumpyTouchEvents(-1), + mMaxEventsPerSecond(-1), + mDisplayWidth(-1), mDisplayHeight(-1), mDisplayOrientation(ROTATION_0) { + JNIEnv* env = jniEnv(); + + mCallbacksObj = env->NewGlobalRef(callbacksObj); + + sp<EventHub> eventHub = new EventHub(); + mInputManager = new InputManager(eventHub, this, this); +} + +NativeInputManager::~NativeInputManager() { + JNIEnv* env = jniEnv(); + + env->DeleteGlobalRef(mCallbacksObj); +} + +void NativeInputManager::dump(String8& dump) { + mInputManager->getReader()->dump(dump); + dump.append("\n"); + + mInputManager->getDispatcher()->dump(dump); + dump.append("\n"); +} + +bool NativeInputManager::checkAndClearExceptionFromCallback(JNIEnv* env, const char* methodName) { + if (env->ExceptionCheck()) { + LOGE("An exception was thrown by callback '%s'.", methodName); + LOGE_EX(env); + env->ExceptionClear(); + return true; + } + return false; +} + +void NativeInputManager::setDisplaySize(int32_t displayId, int32_t width, int32_t height) { + if (displayId == 0) { + AutoMutex _l(mDisplayLock); + + mDisplayWidth = width; + mDisplayHeight = height; + } +} + +void NativeInputManager::setDisplayOrientation(int32_t displayId, int32_t orientation) { + if (displayId == 0) { + AutoMutex _l(mDisplayLock); + + mDisplayOrientation = orientation; + } +} + +status_t NativeInputManager::registerInputChannel(JNIEnv* env, + const sp<InputChannel>& inputChannel, jobject inputChannelObj, bool monitor) { + jweak inputChannelObjWeak = env->NewWeakGlobalRef(inputChannelObj); + if (! inputChannelObjWeak) { + LOGE("Could not create weak reference for input channel."); + LOGE_EX(env); + return NO_MEMORY; + } + + status_t status; + { + AutoMutex _l(mInputChannelRegistryLock); + + ssize_t index = mInputChannelObjWeakTable.indexOfKey(inputChannel.get()); + if (index >= 0) { + LOGE("Input channel object '%s' has already been registered", + inputChannel->getName().string()); + status = INVALID_OPERATION; + goto DeleteWeakRef; + } + + mInputChannelObjWeakTable.add(inputChannel.get(), inputChannelObjWeak); + } + + status = mInputManager->getDispatcher()->registerInputChannel(inputChannel, monitor); + if (! status) { + // Success. + return OK; + } + + // Failed! + { + AutoMutex _l(mInputChannelRegistryLock); + mInputChannelObjWeakTable.removeItem(inputChannel.get()); + } + +DeleteWeakRef: + env->DeleteWeakGlobalRef(inputChannelObjWeak); + return status; +} + +status_t NativeInputManager::unregisterInputChannel(JNIEnv* env, + const sp<InputChannel>& inputChannel) { + jweak inputChannelObjWeak; + { + AutoMutex _l(mInputChannelRegistryLock); + + ssize_t index = mInputChannelObjWeakTable.indexOfKey(inputChannel.get()); + if (index < 0) { + LOGE("Input channel object '%s' is not currently registered", + inputChannel->getName().string()); + return INVALID_OPERATION; + } + + inputChannelObjWeak = mInputChannelObjWeakTable.valueAt(index); + mInputChannelObjWeakTable.removeItemsAt(index); + } + + env->DeleteWeakGlobalRef(inputChannelObjWeak); + + return mInputManager->getDispatcher()->unregisterInputChannel(inputChannel); +} + +jobject NativeInputManager::getInputChannelObjLocal(JNIEnv* env, + const sp<InputChannel>& inputChannel) { + InputChannel* inputChannelPtr = inputChannel.get(); + if (! inputChannelPtr) { + return NULL; + } + + { + AutoMutex _l(mInputChannelRegistryLock); + + ssize_t index = mInputChannelObjWeakTable.indexOfKey(inputChannelPtr); + if (index < 0) { + return NULL; + } + + jweak inputChannelObjWeak = mInputChannelObjWeakTable.valueAt(index); + return env->NewLocalRef(inputChannelObjWeak); + } +} + +bool NativeInputManager::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) { + if (width) { + *width = mDisplayWidth; + } + if (height) { + *height = mDisplayHeight; + } + if (orientation) { + *orientation = mDisplayOrientation; + } + result = true; + } + } + return result; +} + +bool NativeInputManager::filterTouchEvents() { + if (mFilterTouchEvents < 0) { + JNIEnv* env = jniEnv(); + + jboolean result = env->CallBooleanMethod(mCallbacksObj, + gCallbacksClassInfo.filterTouchEvents); + if (checkAndClearExceptionFromCallback(env, "filterTouchEvents")) { + result = false; + } + + mFilterTouchEvents = result ? 1 : 0; + } + return mFilterTouchEvents; +} + +bool NativeInputManager::filterJumpyTouchEvents() { + if (mFilterJumpyTouchEvents < 0) { + JNIEnv* env = jniEnv(); + + jboolean result = env->CallBooleanMethod(mCallbacksObj, + gCallbacksClassInfo.filterJumpyTouchEvents); + if (checkAndClearExceptionFromCallback(env, "filterJumpyTouchEvents")) { + result = false; + } + + mFilterJumpyTouchEvents = result ? 1 : 0; + } + return mFilterJumpyTouchEvents; +} + +void NativeInputManager::getVirtualKeyDefinitions(const String8& deviceName, + Vector<VirtualKeyDefinition>& outVirtualKeyDefinitions) { + outVirtualKeyDefinitions.clear(); + + JNIEnv* env = jniEnv(); + + jstring deviceNameStr = env->NewStringUTF(deviceName.string()); + if (! checkAndClearExceptionFromCallback(env, "getVirtualKeyDefinitions")) { + jobjectArray result = jobjectArray(env->CallObjectMethod(mCallbacksObj, + gCallbacksClassInfo.getVirtualKeyDefinitions, deviceNameStr)); + if (! checkAndClearExceptionFromCallback(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 NativeInputManager::getInputDeviceCalibration(const String8& deviceName, + InputDeviceCalibration& outCalibration) { + outCalibration.clear(); + + JNIEnv* env = jniEnv(); + + jstring deviceNameStr = env->NewStringUTF(deviceName.string()); + if (! checkAndClearExceptionFromCallback(env, "getInputDeviceCalibration")) { + jobject result = env->CallObjectMethod(mCallbacksObj, + gCallbacksClassInfo.getInputDeviceCalibration, deviceNameStr); + if (! checkAndClearExceptionFromCallback(env, "getInputDeviceCalibration") && result) { + jobjectArray keys = jobjectArray(env->GetObjectField(result, + gInputDeviceCalibrationClassInfo.keys)); + jobjectArray values = jobjectArray(env->GetObjectField(result, + gInputDeviceCalibrationClassInfo.values)); + + jsize length = env->GetArrayLength(keys); + for (jsize i = 0; i < length; i++) { + jstring keyStr = jstring(env->GetObjectArrayElement(keys, i)); + jstring valueStr = jstring(env->GetObjectArrayElement(values, i)); + + const char* keyChars = env->GetStringUTFChars(keyStr, NULL); + String8 key(keyChars); + env->ReleaseStringUTFChars(keyStr, keyChars); + + const char* valueChars = env->GetStringUTFChars(valueStr, NULL); + String8 value(valueChars); + env->ReleaseStringUTFChars(valueStr, valueChars); + + outCalibration.addProperty(key, value); + + env->DeleteLocalRef(keyStr); + env->DeleteLocalRef(valueStr); + } + env->DeleteLocalRef(keys); + env->DeleteLocalRef(values); + env->DeleteLocalRef(result); + } + env->DeleteLocalRef(deviceNameStr); + } +} + +void NativeInputManager::getExcludedDeviceNames(Vector<String8>& outExcludedDeviceNames) { + outExcludedDeviceNames.clear(); + + JNIEnv* env = jniEnv(); + + jobjectArray result = jobjectArray(env->CallObjectMethod(mCallbacksObj, + gCallbacksClassInfo.getExcludedDeviceNames)); + if (! checkAndClearExceptionFromCallback(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); + } +} + +void NativeInputManager::notifySwitch(nsecs_t when, int32_t switchCode, + int32_t switchValue, uint32_t policyFlags) { +#if DEBUG_INPUT_DISPATCHER_POLICY + LOGD("notifySwitch - when=%lld, switchCode=%d, switchValue=%d, policyFlags=0x%x", + when, switchCode, switchValue, policyFlags); +#endif + + JNIEnv* env = jniEnv(); + + switch (switchCode) { + case SW_LID: + env->CallVoidMethod(mCallbacksObj, gCallbacksClassInfo.notifyLidSwitchChanged, + when, switchValue == 0); + checkAndClearExceptionFromCallback(env, "notifyLidSwitchChanged"); + break; + } +} + +void NativeInputManager::notifyConfigurationChanged(nsecs_t when) { +#if DEBUG_INPUT_DISPATCHER_POLICY + LOGD("notifyConfigurationChanged - when=%lld", when); +#endif + + JNIEnv* env = jniEnv(); + + env->CallVoidMethod(mCallbacksObj, gCallbacksClassInfo.notifyConfigurationChanged, when); + checkAndClearExceptionFromCallback(env, "notifyConfigurationChanged"); +} + +nsecs_t NativeInputManager::notifyANR(const sp<InputApplicationHandle>& inputApplicationHandle, + const sp<InputChannel>& inputChannel) { +#if DEBUG_INPUT_DISPATCHER_POLICY + LOGD("notifyANR"); +#endif + + JNIEnv* env = jniEnv(); + + jobject tokenObjLocal; + if (inputApplicationHandle.get()) { + ApplicationToken* token = static_cast<ApplicationToken*>(inputApplicationHandle.get()); + jweak tokenObjWeak = token->getTokenObj(); + tokenObjLocal = env->NewLocalRef(tokenObjWeak); + } else { + tokenObjLocal = NULL; + } + + jobject inputChannelObjLocal = getInputChannelObjLocal(env, inputChannel); + jlong newTimeout = env->CallLongMethod(mCallbacksObj, + gCallbacksClassInfo.notifyANR, tokenObjLocal, inputChannelObjLocal); + if (checkAndClearExceptionFromCallback(env, "notifyANR")) { + newTimeout = 0; // abort dispatch + } else { + assert(newTimeout >= 0); + } + + env->DeleteLocalRef(tokenObjLocal); + env->DeleteLocalRef(inputChannelObjLocal); + return newTimeout; +} + +void NativeInputManager::notifyInputChannelBroken(const sp<InputChannel>& inputChannel) { +#if DEBUG_INPUT_DISPATCHER_POLICY + LOGD("notifyInputChannelBroken - inputChannel='%s'", inputChannel->getName().string()); +#endif + + JNIEnv* env = jniEnv(); + + jobject inputChannelObjLocal = getInputChannelObjLocal(env, inputChannel); + if (inputChannelObjLocal) { + env->CallVoidMethod(mCallbacksObj, gCallbacksClassInfo.notifyInputChannelBroken, + inputChannelObjLocal); + checkAndClearExceptionFromCallback(env, "notifyInputChannelBroken"); + + env->DeleteLocalRef(inputChannelObjLocal); + } +} + +nsecs_t NativeInputManager::getKeyRepeatTimeout() { + if (! isScreenOn()) { + // Disable key repeat when the screen is off. + return -1; + } else { + // TODO use ViewConfiguration.getLongPressTimeout() + return milliseconds_to_nanoseconds(500); + } +} + +nsecs_t NativeInputManager::getKeyRepeatDelay() { + return milliseconds_to_nanoseconds(50); +} + +int32_t NativeInputManager::getMaxEventsPerSecond() { + if (mMaxEventsPerSecond < 0) { + JNIEnv* env = jniEnv(); + + jint result = env->CallIntMethod(mCallbacksObj, + gCallbacksClassInfo.getMaxEventsPerSecond); + if (checkAndClearExceptionFromCallback(env, "getMaxEventsPerSecond")) { + result = 60; + } + + mMaxEventsPerSecond = result; + } + return mMaxEventsPerSecond; +} + +void NativeInputManager::setInputWindows(JNIEnv* env, jobjectArray windowObjArray) { + Vector<InputWindow> windows; + + jsize length = env->GetArrayLength(windowObjArray); + for (jsize i = 0; i < length; i++) { + jobject inputTargetObj = env->GetObjectArrayElement(windowObjArray, i); + if (! inputTargetObj) { + break; // found null element indicating end of used portion of the array + } + + windows.push(); + InputWindow& window = windows.editTop(); + bool valid = populateWindow(env, inputTargetObj, window); + if (! valid) { + windows.pop(); + } + + env->DeleteLocalRef(inputTargetObj); + } + + mInputManager->getDispatcher()->setInputWindows(windows); +} + +bool NativeInputManager::populateWindow(JNIEnv* env, jobject windowObj, + InputWindow& outWindow) { + bool valid = false; + + jobject inputChannelObj = env->GetObjectField(windowObj, + gInputWindowClassInfo.inputChannel); + if (inputChannelObj) { + sp<InputChannel> inputChannel = + android_view_InputChannel_getInputChannel(env, inputChannelObj); + if (inputChannel != NULL) { + jstring name = jstring(env->GetObjectField(windowObj, + gInputWindowClassInfo.name)); + jint layoutParamsFlags = env->GetIntField(windowObj, + gInputWindowClassInfo.layoutParamsFlags); + jint layoutParamsType = env->GetIntField(windowObj, + gInputWindowClassInfo.layoutParamsType); + jlong dispatchingTimeoutNanos = env->GetLongField(windowObj, + gInputWindowClassInfo.dispatchingTimeoutNanos); + jint frameLeft = env->GetIntField(windowObj, + gInputWindowClassInfo.frameLeft); + jint frameTop = env->GetIntField(windowObj, + gInputWindowClassInfo.frameTop); + jint frameRight = env->GetIntField(windowObj, + gInputWindowClassInfo.frameRight); + jint frameBottom = env->GetIntField(windowObj, + gInputWindowClassInfo.frameBottom); + jint visibleFrameLeft = env->GetIntField(windowObj, + gInputWindowClassInfo.visibleFrameLeft); + jint visibleFrameTop = env->GetIntField(windowObj, + gInputWindowClassInfo.visibleFrameTop); + jint visibleFrameRight = env->GetIntField(windowObj, + gInputWindowClassInfo.visibleFrameRight); + jint visibleFrameBottom = env->GetIntField(windowObj, + gInputWindowClassInfo.visibleFrameBottom); + jint touchableAreaLeft = env->GetIntField(windowObj, + gInputWindowClassInfo.touchableAreaLeft); + jint touchableAreaTop = env->GetIntField(windowObj, + gInputWindowClassInfo.touchableAreaTop); + jint touchableAreaRight = env->GetIntField(windowObj, + gInputWindowClassInfo.touchableAreaRight); + jint touchableAreaBottom = env->GetIntField(windowObj, + gInputWindowClassInfo.touchableAreaBottom); + jboolean visible = env->GetBooleanField(windowObj, + gInputWindowClassInfo.visible); + jboolean canReceiveKeys = env->GetBooleanField(windowObj, + gInputWindowClassInfo.canReceiveKeys); + jboolean hasFocus = env->GetBooleanField(windowObj, + gInputWindowClassInfo.hasFocus); + jboolean hasWallpaper = env->GetBooleanField(windowObj, + gInputWindowClassInfo.hasWallpaper); + jboolean paused = env->GetBooleanField(windowObj, + gInputWindowClassInfo.paused); + jint layer = env->GetIntField(windowObj, + gInputWindowClassInfo.layer); + jint ownerPid = env->GetIntField(windowObj, + gInputWindowClassInfo.ownerPid); + jint ownerUid = env->GetIntField(windowObj, + gInputWindowClassInfo.ownerUid); + + const char* nameStr = env->GetStringUTFChars(name, NULL); + + outWindow.inputChannel = inputChannel; + outWindow.name.setTo(nameStr); + outWindow.layoutParamsFlags = layoutParamsFlags; + outWindow.layoutParamsType = layoutParamsType; + outWindow.dispatchingTimeout = dispatchingTimeoutNanos; + outWindow.frameLeft = frameLeft; + outWindow.frameTop = frameTop; + outWindow.frameRight = frameRight; + outWindow.frameBottom = frameBottom; + outWindow.visibleFrameLeft = visibleFrameLeft; + outWindow.visibleFrameTop = visibleFrameTop; + outWindow.visibleFrameRight = visibleFrameRight; + outWindow.visibleFrameBottom = visibleFrameBottom; + outWindow.touchableAreaLeft = touchableAreaLeft; + outWindow.touchableAreaTop = touchableAreaTop; + outWindow.touchableAreaRight = touchableAreaRight; + outWindow.touchableAreaBottom = touchableAreaBottom; + outWindow.visible = visible; + outWindow.canReceiveKeys = canReceiveKeys; + outWindow.hasFocus = hasFocus; + outWindow.hasWallpaper = hasWallpaper; + outWindow.paused = paused; + outWindow.layer = layer; + outWindow.ownerPid = ownerPid; + outWindow.ownerUid = ownerUid; + + env->ReleaseStringUTFChars(name, nameStr); + valid = true; + } else { + LOGW("Dropping input target because its input channel is not initialized."); + } + + env->DeleteLocalRef(inputChannelObj); + } else { + LOGW("Dropping input target because the input channel object was null."); + } + return valid; +} + +void NativeInputManager::setFocusedApplication(JNIEnv* env, jobject applicationObj) { + if (applicationObj) { + jstring nameObj = jstring(env->GetObjectField(applicationObj, + gInputApplicationClassInfo.name)); + jlong dispatchingTimeoutNanos = env->GetLongField(applicationObj, + gInputApplicationClassInfo.dispatchingTimeoutNanos); + jobject tokenObj = env->GetObjectField(applicationObj, + gInputApplicationClassInfo.token); + jweak tokenObjWeak = env->NewWeakGlobalRef(tokenObj); + if (! tokenObjWeak) { + LOGE("Could not create weak reference for application token."); + LOGE_EX(env); + env->ExceptionClear(); + } + env->DeleteLocalRef(tokenObj); + + String8 name; + if (nameObj) { + const char* nameStr = env->GetStringUTFChars(nameObj, NULL); + name.setTo(nameStr); + env->ReleaseStringUTFChars(nameObj, nameStr); + env->DeleteLocalRef(nameObj); + } else { + LOGE("InputApplication.name should not be null."); + name.setTo("unknown"); + } + + InputApplication application; + application.name = name; + application.dispatchingTimeout = dispatchingTimeoutNanos; + application.handle = new ApplicationToken(tokenObjWeak); + mInputManager->getDispatcher()->setFocusedApplication(& application); + } else { + mInputManager->getDispatcher()->setFocusedApplication(NULL); + } +} + +void NativeInputManager::setInputDispatchMode(bool enabled, bool frozen) { + mInputManager->getDispatcher()->setInputDispatchMode(enabled, frozen); +} + +bool NativeInputManager::isScreenOn() { + return android_server_PowerManagerService_isScreenOn(); +} + +bool NativeInputManager::isScreenBright() { + return android_server_PowerManagerService_isScreenBright(); +} + +void NativeInputManager::interceptKeyBeforeQueueing(nsecs_t when, + int32_t deviceId, int32_t action, int32_t &flags, + int32_t keyCode, int32_t scanCode, uint32_t& policyFlags) { +#if DEBUG_INPUT_DISPATCHER_POLICY + LOGD("interceptKeyBeforeQueueing - when=%lld, deviceId=%d, action=%d, flags=%d, " + "keyCode=%d, scanCode=%d, policyFlags=0x%x", + when, deviceId, action, flags, keyCode, scanCode, policyFlags); +#endif + + if ((policyFlags & POLICY_FLAG_VIRTUAL) || (flags & AKEY_EVENT_FLAG_VIRTUAL_HARD_KEY)) { + policyFlags |= POLICY_FLAG_VIRTUAL; + flags |= AKEY_EVENT_FLAG_VIRTUAL_HARD_KEY; + } + + // Policy: + // - Ignore untrusted events and pass them along. + // - Ask the window manager what to do with normal events and trusted injected events. + // - For normal events wake and brighten the screen if currently off or dim. + if ((policyFlags & POLICY_FLAG_TRUSTED)) { + 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; + + bool isScreenOn = this->isScreenOn(); + bool isScreenBright = this->isScreenBright(); + + JNIEnv* env = jniEnv(); + jint wmActions = env->CallIntMethod(mCallbacksObj, + gCallbacksClassInfo.interceptKeyBeforeQueueing, + when, keyCode, action == AKEY_EVENT_ACTION_DOWN, policyFlags, isScreenOn); + if (checkAndClearExceptionFromCallback(env, "interceptKeyBeforeQueueing")) { + wmActions = 0; + } + + if (!(flags & POLICY_FLAG_INJECTED)) { + if (!isScreenOn) { + policyFlags |= POLICY_FLAG_WOKE_HERE; + flags |= AKEY_EVENT_FLAG_WOKE_HERE; + } + + if (!isScreenBright) { + policyFlags |= POLICY_FLAG_BRIGHT_HERE; + } + } + + if (wmActions & WM_ACTION_GO_TO_SLEEP) { + android_server_PowerManagerService_goToSleep(when); + } + + if (wmActions & WM_ACTION_POKE_USER_ACTIVITY) { + android_server_PowerManagerService_userActivity(when, POWER_MANAGER_BUTTON_EVENT); + } + + if (wmActions & WM_ACTION_PASS_TO_USER) { + policyFlags |= POLICY_FLAG_PASS_TO_USER; + } + } else { + policyFlags |= POLICY_FLAG_PASS_TO_USER; + } +} + +void NativeInputManager::interceptGenericBeforeQueueing(nsecs_t when, uint32_t& policyFlags) { +#if DEBUG_INPUT_DISPATCHER_POLICY + LOGD("interceptGenericBeforeQueueing - when=%lld, policyFlags=0x%x", when, policyFlags); +#endif + + // Policy: + // - Ignore untrusted events and pass them along. + // - No special filtering for injected events required at this time. + // - Filter normal events based on screen state. + // - For normal events brighten (but do not wake) the screen if currently dim. + if ((policyFlags & POLICY_FLAG_TRUSTED) && !(policyFlags & POLICY_FLAG_INJECTED)) { + if (isScreenOn()) { + policyFlags |= POLICY_FLAG_PASS_TO_USER; + + if (!isScreenBright()) { + policyFlags |= POLICY_FLAG_BRIGHT_HERE; + } + } + } else { + policyFlags |= POLICY_FLAG_PASS_TO_USER; + } +} + +bool NativeInputManager::interceptKeyBeforeDispatching(const sp<InputChannel>& inputChannel, + const KeyEvent* keyEvent, uint32_t policyFlags) { + // Policy: + // - Ignore untrusted events and pass them along. + // - Filter normal events and trusted injected events through the window manager policy to + // handle the HOME key and the like. + if (policyFlags & POLICY_FLAG_TRUSTED) { + JNIEnv* env = jniEnv(); + + // Note: inputChannel may be null. + jobject inputChannelObj = getInputChannelObjLocal(env, inputChannel); + jboolean consumed = env->CallBooleanMethod(mCallbacksObj, + gCallbacksClassInfo.interceptKeyBeforeDispatching, + inputChannelObj, keyEvent->getAction(), keyEvent->getFlags(), + keyEvent->getKeyCode(), keyEvent->getMetaState(), + keyEvent->getRepeatCount(), policyFlags); + bool error = checkAndClearExceptionFromCallback(env, "interceptKeyBeforeDispatching"); + + env->DeleteLocalRef(inputChannelObj); + return consumed && ! error; + } else { + return false; + } +} + +void NativeInputManager::pokeUserActivity(nsecs_t eventTime, int32_t eventType) { + android_server_PowerManagerService_userActivity(eventTime, eventType); +} + + +bool NativeInputManager::checkInjectEventsPermissionNonReentrant( + int32_t injectorPid, int32_t injectorUid) { + JNIEnv* env = jniEnv(); + jboolean result = env->CallBooleanMethod(mCallbacksObj, + gCallbacksClassInfo.checkInjectEventsPermission, injectorPid, injectorUid); + checkAndClearExceptionFromCallback(env, "checkInjectEventsPermission"); + return result; +} + +// ---------------------------------------------------------------------------- + +static sp<NativeInputManager> gNativeInputManager; + +static bool checkInputManagerUnitialized(JNIEnv* env) { + if (gNativeInputManager == 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 (gNativeInputManager == NULL) { + gNativeInputManager = new NativeInputManager(callbacks); + } else { + LOGE("Input manager already initialized."); + jniThrowRuntimeException(env, "Input manager already initialized."); + } +} + +static void android_server_InputManager_nativeStart(JNIEnv* env, jclass clazz) { + if (checkInputManagerUnitialized(env)) { + return; + } + + status_t result = gNativeInputManager->getInputManager()->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 + gNativeInputManager->setDisplaySize(displayId, width, height); +} + +static void android_server_InputManager_nativeSetDisplayOrientation(JNIEnv* env, jclass clazz, + jint displayId, jint orientation) { + if (checkInputManagerUnitialized(env)) { + return; + } + + gNativeInputManager->setDisplayOrientation(displayId, orientation); +} + +static jint android_server_InputManager_nativeGetScanCodeState(JNIEnv* env, jclass clazz, + jint deviceId, jint sourceMask, jint scanCode) { + if (checkInputManagerUnitialized(env)) { + return AKEY_STATE_UNKNOWN; + } + + return gNativeInputManager->getInputManager()->getReader()->getScanCodeState( + deviceId, uint32_t(sourceMask), scanCode); +} + +static jint android_server_InputManager_nativeGetKeyCodeState(JNIEnv* env, jclass clazz, + jint deviceId, jint sourceMask, jint keyCode) { + if (checkInputManagerUnitialized(env)) { + return AKEY_STATE_UNKNOWN; + } + + return gNativeInputManager->getInputManager()->getReader()->getKeyCodeState( + deviceId, uint32_t(sourceMask), keyCode); +} + +static jint android_server_InputManager_nativeGetSwitchState(JNIEnv* env, jclass clazz, + jint deviceId, jint sourceMask, jint sw) { + if (checkInputManagerUnitialized(env)) { + return AKEY_STATE_UNKNOWN; + } + + return gNativeInputManager->getInputManager()->getReader()->getSwitchState( + deviceId, uint32_t(sourceMask), sw); +} + +static jboolean android_server_InputManager_nativeHasKeys(JNIEnv* env, jclass clazz, + jint deviceId, jint sourceMask, 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(keyCodes)) { + result = gNativeInputManager->getInputManager()->getReader()->hasKeys( + deviceId, uint32_t(sourceMask), 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()); + + if (gNativeInputManager != NULL) { + gNativeInputManager->unregisterInputChannel(env, inputChannel); + } +} + +static void android_server_InputManager_nativeRegisterInputChannel(JNIEnv* env, jclass clazz, + jobject inputChannelObj, jboolean monitor) { + if (checkInputManagerUnitialized(env)) { + return; + } + + sp<InputChannel> inputChannel = android_view_InputChannel_getInputChannel(env, + inputChannelObj); + if (inputChannel == NULL) { + throwInputChannelNotInitialized(env); + return; + } + + + status_t status = gNativeInputManager->registerInputChannel( + env, inputChannel, inputChannelObj, monitor); + if (status) { + jniThrowRuntimeException(env, "Failed to register input channel. " + "Check logs for details."); + return; + } + + if (! monitor) { + 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 = gNativeInputManager->unregisterInputChannel(env, inputChannel); + if (status) { + jniThrowRuntimeException(env, "Failed to unregister input channel. " + "Check logs for details."); + } +} + +static jint android_server_InputManager_nativeInjectInputEvent(JNIEnv* env, jclass clazz, + jobject inputEventObj, jint injectorPid, jint injectorUid, + jint syncMode, jint timeoutMillis) { + if (checkInputManagerUnitialized(env)) { + return INPUT_EVENT_INJECTION_FAILED; + } + + if (env->IsInstanceOf(inputEventObj, gKeyEventClassInfo.clazz)) { + KeyEvent keyEvent; + android_view_KeyEvent_toNative(env, inputEventObj, & keyEvent); + + return gNativeInputManager->getInputManager()->getDispatcher()->injectInputEvent( + & keyEvent, injectorPid, injectorUid, syncMode, timeoutMillis); + } else if (env->IsInstanceOf(inputEventObj, gMotionEventClassInfo.clazz)) { + MotionEvent motionEvent; + android_view_MotionEvent_toNative(env, inputEventObj, & motionEvent); + + return gNativeInputManager->getInputManager()->getDispatcher()->injectInputEvent( + & motionEvent, injectorPid, injectorUid, syncMode, timeoutMillis); + } else { + jniThrowRuntimeException(env, "Invalid input event type."); + return INPUT_EVENT_INJECTION_FAILED; + } +} + +static void android_server_InputManager_nativeSetInputWindows(JNIEnv* env, jclass clazz, + jobjectArray windowObjArray) { + if (checkInputManagerUnitialized(env)) { + return; + } + + gNativeInputManager->setInputWindows(env, windowObjArray); +} + +static void android_server_InputManager_nativeSetFocusedApplication(JNIEnv* env, jclass clazz, + jobject applicationObj) { + if (checkInputManagerUnitialized(env)) { + return; + } + + gNativeInputManager->setFocusedApplication(env, applicationObj); +} + +static void android_server_InputManager_nativeSetInputDispatchMode(JNIEnv* env, + jclass clazz, jboolean enabled, jboolean frozen) { + if (checkInputManagerUnitialized(env)) { + return; + } + + gNativeInputManager->setInputDispatchMode(enabled, frozen); +} + +static jobject android_server_InputManager_nativeGetInputDevice(JNIEnv* env, + jclass clazz, jint deviceId) { + if (checkInputManagerUnitialized(env)) { + return NULL; + } + + InputDeviceInfo deviceInfo; + status_t status = gNativeInputManager->getInputManager()->getReader()->getInputDeviceInfo( + deviceId, & deviceInfo); + if (status) { + return NULL; + } + + jobject deviceObj = env->NewObject(gInputDeviceClassInfo.clazz, gInputDeviceClassInfo.ctor); + if (! deviceObj) { + return NULL; + } + + jstring deviceNameObj = env->NewStringUTF(deviceInfo.getName().string()); + if (! deviceNameObj) { + return NULL; + } + + env->SetIntField(deviceObj, gInputDeviceClassInfo.mId, deviceInfo.getId()); + env->SetObjectField(deviceObj, gInputDeviceClassInfo.mName, deviceNameObj); + env->SetIntField(deviceObj, gInputDeviceClassInfo.mSources, deviceInfo.getSources()); + env->SetIntField(deviceObj, gInputDeviceClassInfo.mKeyboardType, deviceInfo.getKeyboardType()); + + const KeyedVector<int, InputDeviceInfo::MotionRange>& ranges = deviceInfo.getMotionRanges(); + for (size_t i = 0; i < ranges.size(); i++) { + int rangeType = ranges.keyAt(i); + const InputDeviceInfo::MotionRange& range = ranges.valueAt(i); + env->CallVoidMethod(deviceObj, gInputDeviceClassInfo.addMotionRange, + rangeType, range.min, range.max, range.flat, range.fuzz); + if (env->ExceptionCheck()) { + return NULL; + } + } + + return deviceObj; +} + +static jintArray android_server_InputManager_nativeGetInputDeviceIds(JNIEnv* env, + jclass clazz) { + if (checkInputManagerUnitialized(env)) { + return NULL; + } + + Vector<int> deviceIds; + gNativeInputManager->getInputManager()->getReader()->getInputDeviceIds(deviceIds); + + jintArray deviceIdsObj = env->NewIntArray(deviceIds.size()); + if (! deviceIdsObj) { + return NULL; + } + + env->SetIntArrayRegion(deviceIdsObj, 0, deviceIds.size(), deviceIds.array()); + return deviceIdsObj; +} + +static void android_server_InputManager_nativeGetInputConfiguration(JNIEnv* env, + jclass clazz, jobject configObj) { + if (checkInputManagerUnitialized(env)) { + return; + } + + InputConfiguration config; + gNativeInputManager->getInputManager()->getReader()->getInputConfiguration(& config); + + env->SetIntField(configObj, gConfigurationClassInfo.touchscreen, config.touchScreen); + env->SetIntField(configObj, gConfigurationClassInfo.keyboard, config.keyboard); + env->SetIntField(configObj, gConfigurationClassInfo.navigation, config.navigation); +} + +static jstring android_server_InputManager_nativeDump(JNIEnv* env, jclass clazz) { + if (checkInputManagerUnitialized(env)) { + return NULL; + } + + String8 dump; + gNativeInputManager->dump(dump); + return env->NewStringUTF(dump.string()); +} + +// ---------------------------------------------------------------------------- + +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", "(II[I[Z)Z", + (void*) android_server_InputManager_nativeHasKeys }, + { "nativeRegisterInputChannel", "(Landroid/view/InputChannel;Z)V", + (void*) android_server_InputManager_nativeRegisterInputChannel }, + { "nativeUnregisterInputChannel", "(Landroid/view/InputChannel;)V", + (void*) android_server_InputManager_nativeUnregisterInputChannel }, + { "nativeInjectInputEvent", "(Landroid/view/InputEvent;IIII)I", + (void*) android_server_InputManager_nativeInjectInputEvent }, + { "nativeSetInputWindows", "([Lcom/android/server/InputWindow;)V", + (void*) android_server_InputManager_nativeSetInputWindows }, + { "nativeSetFocusedApplication", "(Lcom/android/server/InputApplication;)V", + (void*) android_server_InputManager_nativeSetFocusedApplication }, + { "nativeSetInputDispatchMode", "(ZZ)V", + (void*) android_server_InputManager_nativeSetInputDispatchMode }, + { "nativeGetInputDevice", "(I)Landroid/view/InputDevice;", + (void*) android_server_InputManager_nativeGetInputDevice }, + { "nativeGetInputDeviceIds", "()[I", + (void*) android_server_InputManager_nativeGetInputDeviceIds }, + { "nativeGetInputConfiguration", "(Landroid/content/res/Configuration;)V", + (void*) android_server_InputManager_nativeGetInputConfiguration }, + { "nativeDump", "()Ljava/lang/String;", + (void*) android_server_InputManager_nativeDump }, +}; + +#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."); + + // Callbacks + + FIND_CLASS(gCallbacksClassInfo.clazz, "com/android/server/InputManager$Callbacks"); + + GET_METHOD_ID(gCallbacksClassInfo.notifyConfigurationChanged, gCallbacksClassInfo.clazz, + "notifyConfigurationChanged", "(J)V"); + + GET_METHOD_ID(gCallbacksClassInfo.notifyLidSwitchChanged, gCallbacksClassInfo.clazz, + "notifyLidSwitchChanged", "(JZ)V"); + + GET_METHOD_ID(gCallbacksClassInfo.notifyInputChannelBroken, gCallbacksClassInfo.clazz, + "notifyInputChannelBroken", "(Landroid/view/InputChannel;)V"); + + GET_METHOD_ID(gCallbacksClassInfo.notifyANR, gCallbacksClassInfo.clazz, + "notifyANR", "(Ljava/lang/Object;Landroid/view/InputChannel;)J"); + + GET_METHOD_ID(gCallbacksClassInfo.interceptKeyBeforeQueueing, gCallbacksClassInfo.clazz, + "interceptKeyBeforeQueueing", "(JIZIZ)I"); + + GET_METHOD_ID(gCallbacksClassInfo.interceptKeyBeforeDispatching, gCallbacksClassInfo.clazz, + "interceptKeyBeforeDispatching", "(Landroid/view/InputChannel;IIIIII)Z"); + + GET_METHOD_ID(gCallbacksClassInfo.checkInjectEventsPermission, gCallbacksClassInfo.clazz, + "checkInjectEventsPermission", "(II)Z"); + + 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.getInputDeviceCalibration, gCallbacksClassInfo.clazz, + "getInputDeviceCalibration", + "(Ljava/lang/String;)Lcom/android/server/InputManager$InputDeviceCalibration;"); + + GET_METHOD_ID(gCallbacksClassInfo.getExcludedDeviceNames, gCallbacksClassInfo.clazz, + "getExcludedDeviceNames", "()[Ljava/lang/String;"); + + GET_METHOD_ID(gCallbacksClassInfo.getMaxEventsPerSecond, gCallbacksClassInfo.clazz, + "getMaxEventsPerSecond", "()I"); + + // 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"); + + // InputDeviceCalibration + + FIND_CLASS(gInputDeviceCalibrationClassInfo.clazz, + "com/android/server/InputManager$InputDeviceCalibration"); + + GET_FIELD_ID(gInputDeviceCalibrationClassInfo.keys, gInputDeviceCalibrationClassInfo.clazz, + "keys", "[Ljava/lang/String;"); + + GET_FIELD_ID(gInputDeviceCalibrationClassInfo.values, gInputDeviceCalibrationClassInfo.clazz, + "values", "[Ljava/lang/String;"); + + // InputWindow + + FIND_CLASS(gInputWindowClassInfo.clazz, "com/android/server/InputWindow"); + + GET_FIELD_ID(gInputWindowClassInfo.inputChannel, gInputWindowClassInfo.clazz, + "inputChannel", "Landroid/view/InputChannel;"); + + GET_FIELD_ID(gInputWindowClassInfo.name, gInputWindowClassInfo.clazz, + "name", "Ljava/lang/String;"); + + GET_FIELD_ID(gInputWindowClassInfo.layoutParamsFlags, gInputWindowClassInfo.clazz, + "layoutParamsFlags", "I"); + + GET_FIELD_ID(gInputWindowClassInfo.layoutParamsType, gInputWindowClassInfo.clazz, + "layoutParamsType", "I"); + + GET_FIELD_ID(gInputWindowClassInfo.dispatchingTimeoutNanos, gInputWindowClassInfo.clazz, + "dispatchingTimeoutNanos", "J"); + + GET_FIELD_ID(gInputWindowClassInfo.frameLeft, gInputWindowClassInfo.clazz, + "frameLeft", "I"); + + GET_FIELD_ID(gInputWindowClassInfo.frameTop, gInputWindowClassInfo.clazz, + "frameTop", "I"); + + GET_FIELD_ID(gInputWindowClassInfo.frameRight, gInputWindowClassInfo.clazz, + "frameRight", "I"); + + GET_FIELD_ID(gInputWindowClassInfo.frameBottom, gInputWindowClassInfo.clazz, + "frameBottom", "I"); + + GET_FIELD_ID(gInputWindowClassInfo.visibleFrameLeft, gInputWindowClassInfo.clazz, + "visibleFrameLeft", "I"); + + GET_FIELD_ID(gInputWindowClassInfo.visibleFrameTop, gInputWindowClassInfo.clazz, + "visibleFrameTop", "I"); + + GET_FIELD_ID(gInputWindowClassInfo.visibleFrameRight, gInputWindowClassInfo.clazz, + "visibleFrameRight", "I"); + + GET_FIELD_ID(gInputWindowClassInfo.visibleFrameBottom, gInputWindowClassInfo.clazz, + "visibleFrameBottom", "I"); + + GET_FIELD_ID(gInputWindowClassInfo.touchableAreaLeft, gInputWindowClassInfo.clazz, + "touchableAreaLeft", "I"); + + GET_FIELD_ID(gInputWindowClassInfo.touchableAreaTop, gInputWindowClassInfo.clazz, + "touchableAreaTop", "I"); + + GET_FIELD_ID(gInputWindowClassInfo.touchableAreaRight, gInputWindowClassInfo.clazz, + "touchableAreaRight", "I"); + + GET_FIELD_ID(gInputWindowClassInfo.touchableAreaBottom, gInputWindowClassInfo.clazz, + "touchableAreaBottom", "I"); + + GET_FIELD_ID(gInputWindowClassInfo.visible, gInputWindowClassInfo.clazz, + "visible", "Z"); + + GET_FIELD_ID(gInputWindowClassInfo.canReceiveKeys, gInputWindowClassInfo.clazz, + "canReceiveKeys", "Z"); + + GET_FIELD_ID(gInputWindowClassInfo.hasFocus, gInputWindowClassInfo.clazz, + "hasFocus", "Z"); + + GET_FIELD_ID(gInputWindowClassInfo.hasWallpaper, gInputWindowClassInfo.clazz, + "hasWallpaper", "Z"); + + GET_FIELD_ID(gInputWindowClassInfo.paused, gInputWindowClassInfo.clazz, + "paused", "Z"); + + GET_FIELD_ID(gInputWindowClassInfo.layer, gInputWindowClassInfo.clazz, + "layer", "I"); + + GET_FIELD_ID(gInputWindowClassInfo.ownerPid, gInputWindowClassInfo.clazz, + "ownerPid", "I"); + + GET_FIELD_ID(gInputWindowClassInfo.ownerUid, gInputWindowClassInfo.clazz, + "ownerUid", "I"); + + // InputApplication + + FIND_CLASS(gInputApplicationClassInfo.clazz, "com/android/server/InputApplication"); + + GET_FIELD_ID(gInputApplicationClassInfo.name, gInputApplicationClassInfo.clazz, + "name", "Ljava/lang/String;"); + + GET_FIELD_ID(gInputApplicationClassInfo.dispatchingTimeoutNanos, + gInputApplicationClassInfo.clazz, + "dispatchingTimeoutNanos", "J"); + + GET_FIELD_ID(gInputApplicationClassInfo.token, gInputApplicationClassInfo.clazz, + "token", "Ljava/lang/Object;"); + + // KeyEvent + + FIND_CLASS(gKeyEventClassInfo.clazz, "android/view/KeyEvent"); + + // MotionEvent + + FIND_CLASS(gMotionEventClassInfo.clazz, "android/view/MotionEvent"); + + // InputDevice + + FIND_CLASS(gInputDeviceClassInfo.clazz, "android/view/InputDevice"); + + GET_METHOD_ID(gInputDeviceClassInfo.ctor, gInputDeviceClassInfo.clazz, + "<init>", "()V"); + + GET_METHOD_ID(gInputDeviceClassInfo.addMotionRange, gInputDeviceClassInfo.clazz, + "addMotionRange", "(IFFFF)V"); + + GET_FIELD_ID(gInputDeviceClassInfo.mId, gInputDeviceClassInfo.clazz, + "mId", "I"); + + GET_FIELD_ID(gInputDeviceClassInfo.mName, gInputDeviceClassInfo.clazz, + "mName", "Ljava/lang/String;"); + + GET_FIELD_ID(gInputDeviceClassInfo.mSources, gInputDeviceClassInfo.clazz, + "mSources", "I"); + + GET_FIELD_ID(gInputDeviceClassInfo.mKeyboardType, gInputDeviceClassInfo.clazz, + "mKeyboardType", "I"); + + GET_FIELD_ID(gInputDeviceClassInfo.mMotionRanges, gInputDeviceClassInfo.clazz, + "mMotionRanges", "[Landroid/view/InputDevice$MotionRange;"); + + // Configuration + + FIND_CLASS(gConfigurationClassInfo.clazz, "android/content/res/Configuration"); + + GET_FIELD_ID(gConfigurationClassInfo.touchscreen, gConfigurationClassInfo.clazz, + "touchscreen", "I"); + + GET_FIELD_ID(gConfigurationClassInfo.keyboard, gConfigurationClassInfo.clazz, + "keyboard", "I"); + + GET_FIELD_ID(gConfigurationClassInfo.navigation, gConfigurationClassInfo.clazz, + "navigation", "I"); + + return 0; +} + +} /* namespace android */ diff --git a/services/jni/com_android_server_KeyInputQueue.cpp b/services/jni/com_android_server_KeyInputQueue.cpp deleted file mode 100644 index c92f8df..0000000 --- a/services/jni/com_android_server_KeyInputQueue.cpp +++ /dev/null @@ -1,358 +0,0 @@ -/* - * Copyright (C) 2007 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 "Input" - -#include "jni.h" -#include "JNIHelp.h" -#include <utils/misc.h> -#include <utils/Log.h> - -#include <ui/EventHub.h> -#include <utils/threads.h> - -#include <stdio.h> - -namespace android { - -// ---------------------------------------------------------------------------- - -static struct input_offsets_t -{ - jfieldID mMinValue; - jfieldID mMaxValue; - jfieldID mFlat; - jfieldID mFuzz; - - jfieldID mDeviceId; - jfieldID mType; - jfieldID mScancode; - jfieldID mKeycode; - jfieldID mFlags; - jfieldID mValue; - jfieldID mWhen; -} gInputOffsets; - -// ---------------------------------------------------------------------------- - -static Mutex gLock; -static sp<EventHub> gHub; - -static jboolean -android_server_KeyInputQueue_readEvent(JNIEnv* env, jobject clazz, - jobject event) -{ - gLock.lock(); - sp<EventHub> hub = gHub; - if (hub == NULL) { - hub = new EventHub; - gHub = hub; - } - gLock.unlock(); - - int32_t deviceId; - int32_t type; - int32_t scancode, keycode; - uint32_t flags; - int32_t value; - nsecs_t when; - bool res = hub->getEvent(&deviceId, &type, &scancode, &keycode, - &flags, &value, &when); - - env->SetIntField(event, gInputOffsets.mDeviceId, (jint)deviceId); - env->SetIntField(event, gInputOffsets.mType, (jint)type); - env->SetIntField(event, gInputOffsets.mScancode, (jint)scancode); - env->SetIntField(event, gInputOffsets.mKeycode, (jint)keycode); - env->SetIntField(event, gInputOffsets.mFlags, (jint)flags); - env->SetIntField(event, gInputOffsets.mValue, value); - env->SetLongField(event, gInputOffsets.mWhen, - (jlong)(nanoseconds_to_milliseconds(when))); - - return res; -} - -static jint -android_server_KeyInputQueue_getDeviceClasses(JNIEnv* env, jobject clazz, - jint deviceId) -{ - jint classes = 0; - gLock.lock(); - if (gHub != NULL) classes = gHub->getDeviceClasses(deviceId); - gLock.unlock(); - return classes; -} - -static jstring -android_server_KeyInputQueue_getDeviceName(JNIEnv* env, jobject clazz, - jint deviceId) -{ - String8 name; - gLock.lock(); - if (gHub != NULL) name = gHub->getDeviceName(deviceId); - gLock.unlock(); - - if (name.size() > 0) { - return env->NewStringUTF(name.string()); - } - return NULL; -} - -static void -android_server_KeyInputQueue_addExcludedDevice(JNIEnv* env, jobject clazz, - jstring deviceName) -{ - gLock.lock(); - sp<EventHub> hub = gHub; - if (hub == NULL) { - hub = new EventHub; - gHub = hub; - } - gLock.unlock(); - - const char* nameStr = env->GetStringUTFChars(deviceName, NULL); - gHub->addExcludedDevice(nameStr); - env->ReleaseStringUTFChars(deviceName, nameStr); -} - -static jboolean -android_server_KeyInputQueue_getAbsoluteInfo(JNIEnv* env, jobject clazz, - jint deviceId, jint axis, - jobject info) -{ - int32_t minValue, maxValue, flat, fuzz; - int res = -1; - gLock.lock(); - if (gHub != NULL) { - res = gHub->getAbsoluteInfo(deviceId, axis, - &minValue, &maxValue, &flat, &fuzz); - } - gLock.unlock(); - - if (res < 0) return JNI_FALSE; - - env->SetIntField(info, gInputOffsets.mMinValue, (jint)minValue); - env->SetIntField(info, gInputOffsets.mMaxValue, (jint)maxValue); - env->SetIntField(info, gInputOffsets.mFlat, (jint)flat); - env->SetIntField(info, gInputOffsets.mFuzz, (jint)fuzz); - return JNI_TRUE; -} - -static jint -android_server_KeyInputQueue_getSwitchState(JNIEnv* env, jobject clazz, - jint sw) -{ - jint st = -1; - gLock.lock(); - if (gHub != NULL) st = gHub->getSwitchState(sw); - gLock.unlock(); - - return st; -} - -static jint -android_server_KeyInputQueue_getSwitchStateDevice(JNIEnv* env, jobject clazz, - jint deviceId, jint sw) -{ - jint st = -1; - gLock.lock(); - if (gHub != NULL) st = gHub->getSwitchState(deviceId, sw); - gLock.unlock(); - - return st; -} - -static jint -android_server_KeyInputQueue_getScancodeState(JNIEnv* env, jobject clazz, - jint sw) -{ - jint st = -1; - gLock.lock(); - if (gHub != NULL) st = gHub->getScancodeState(sw); - gLock.unlock(); - - return st; -} - -static jint -android_server_KeyInputQueue_getScancodeStateDevice(JNIEnv* env, jobject clazz, - jint deviceId, jint sw) -{ - jint st = -1; - gLock.lock(); - if (gHub != NULL) st = gHub->getScancodeState(deviceId, sw); - gLock.unlock(); - - return st; -} - -static jint -android_server_KeyInputQueue_getKeycodeState(JNIEnv* env, jobject clazz, - jint sw) -{ - jint st = -1; - gLock.lock(); - if (gHub != NULL) st = gHub->getKeycodeState(sw); - gLock.unlock(); - - return st; -} - -static jint -android_server_KeyInputQueue_getKeycodeStateDevice(JNIEnv* env, jobject clazz, - jint deviceId, jint sw) -{ - jint st = -1; - gLock.lock(); - if (gHub != NULL) st = gHub->getKeycodeState(deviceId, sw); - gLock.unlock(); - - return st; -} - -static jint -android_server_KeyInputQueue_scancodeToKeycode(JNIEnv* env, jobject clazz, - jint deviceId, jint scancode) -{ - jint res = 0; - gLock.lock(); - if (gHub != NULL) { - int32_t keycode; - uint32_t flags; - gHub->scancodeToKeycode(deviceId, scancode, &keycode, &flags); - res = keycode; - } - gLock.unlock(); - - return res; -} - -static jboolean -android_server_KeyInputQueue_hasKeys(JNIEnv* env, jobject clazz, - jintArray keyCodes, jbooleanArray outFlags) -{ - jboolean ret = JNI_FALSE; - - int32_t* codes = env->GetIntArrayElements(keyCodes, NULL); - uint8_t* flags = env->GetBooleanArrayElements(outFlags, NULL); - size_t numCodes = env->GetArrayLength(keyCodes); - if (numCodes == env->GetArrayLength(outFlags)) { - gLock.lock(); - if (gHub != NULL) ret = gHub->hasKeys(numCodes, codes, flags); - gLock.unlock(); - } - - env->ReleaseBooleanArrayElements(outFlags, flags, 0); - env->ReleaseIntArrayElements(keyCodes, codes, 0); - return ret; -} - -// ---------------------------------------------------------------------------- - -/* - * JNI registration. - */ -static JNINativeMethod gInputMethods[] = { - /* name, signature, funcPtr */ - { "readEvent", "(Landroid/view/RawInputEvent;)Z", - (void*) android_server_KeyInputQueue_readEvent }, - { "getDeviceClasses", "(I)I", - (void*) android_server_KeyInputQueue_getDeviceClasses }, - { "getDeviceName", "(I)Ljava/lang/String;", - (void*) android_server_KeyInputQueue_getDeviceName }, - { "addExcludedDevice", "(Ljava/lang/String;)V", - (void*) android_server_KeyInputQueue_addExcludedDevice }, - { "getAbsoluteInfo", "(IILcom/android/server/InputDevice$AbsoluteInfo;)Z", - (void*) android_server_KeyInputQueue_getAbsoluteInfo }, - { "getSwitchState", "(I)I", - (void*) android_server_KeyInputQueue_getSwitchState }, - { "getSwitchState", "(II)I", - (void*) android_server_KeyInputQueue_getSwitchStateDevice }, - { "nativeGetScancodeState", "(I)I", - (void*) android_server_KeyInputQueue_getScancodeState }, - { "nativeGetScancodeState", "(II)I", - (void*) android_server_KeyInputQueue_getScancodeStateDevice }, - { "nativeGetKeycodeState", "(I)I", - (void*) android_server_KeyInputQueue_getKeycodeState }, - { "nativeGetKeycodeState", "(II)I", - (void*) android_server_KeyInputQueue_getKeycodeStateDevice }, - { "hasKeys", "([I[Z)Z", - (void*) android_server_KeyInputQueue_hasKeys }, - { "scancodeToKeycode", "(II)I", - (void*) android_server_KeyInputQueue_scancodeToKeycode }, -}; - -int register_android_server_KeyInputQueue(JNIEnv* env) -{ - jclass input = env->FindClass("com/android/server/KeyInputQueue"); - LOG_FATAL_IF(input == NULL, "Unable to find class com/android/server/KeyInputQueue"); - int res = jniRegisterNativeMethods(env, "com/android/server/KeyInputQueue", - gInputMethods, NELEM(gInputMethods)); - - jclass absoluteInfo = env->FindClass("com/android/server/InputDevice$AbsoluteInfo"); - LOG_FATAL_IF(absoluteInfo == NULL, "Unable to find class com/android/server/InputDevice$AbsoluteInfo"); - - gInputOffsets.mMinValue - = env->GetFieldID(absoluteInfo, "minValue", "I"); - LOG_FATAL_IF(gInputOffsets.mMinValue == NULL, "Unable to find InputDevice.AbsoluteInfo.minValue"); - - gInputOffsets.mMaxValue - = env->GetFieldID(absoluteInfo, "maxValue", "I"); - LOG_FATAL_IF(gInputOffsets.mMaxValue == NULL, "Unable to find InputDevice.AbsoluteInfo.maxValue"); - - gInputOffsets.mFlat - = env->GetFieldID(absoluteInfo, "flat", "I"); - LOG_FATAL_IF(gInputOffsets.mFlat == NULL, "Unable to find InputDevice.AbsoluteInfo.flat"); - - gInputOffsets.mFuzz - = env->GetFieldID(absoluteInfo, "fuzz", "I"); - LOG_FATAL_IF(gInputOffsets.mFuzz == NULL, "Unable to find InputDevice.AbsoluteInfo.fuzz"); - - jclass inputEvent = env->FindClass("android/view/RawInputEvent"); - LOG_FATAL_IF(inputEvent == NULL, "Unable to find class android/view/RawInputEvent"); - - gInputOffsets.mDeviceId - = env->GetFieldID(inputEvent, "deviceId", "I"); - LOG_FATAL_IF(gInputOffsets.mDeviceId == NULL, "Unable to find RawInputEvent.deviceId"); - - gInputOffsets.mType - = env->GetFieldID(inputEvent, "type", "I"); - LOG_FATAL_IF(gInputOffsets.mType == NULL, "Unable to find RawInputEvent.type"); - - gInputOffsets.mScancode - = env->GetFieldID(inputEvent, "scancode", "I"); - LOG_FATAL_IF(gInputOffsets.mScancode == NULL, "Unable to find RawInputEvent.scancode"); - - gInputOffsets.mKeycode - = env->GetFieldID(inputEvent, "keycode", "I"); - LOG_FATAL_IF(gInputOffsets.mKeycode == NULL, "Unable to find RawInputEvent.keycode"); - - gInputOffsets.mFlags - = env->GetFieldID(inputEvent, "flags", "I"); - LOG_FATAL_IF(gInputOffsets.mFlags == NULL, "Unable to find RawInputEvent.flags"); - - gInputOffsets.mValue - = env->GetFieldID(inputEvent, "value", "I"); - LOG_FATAL_IF(gInputOffsets.mValue == NULL, "Unable to find RawInputEvent.value"); - - gInputOffsets.mWhen - = env->GetFieldID(inputEvent, "when", "J"); - LOG_FATAL_IF(gInputOffsets.mWhen == NULL, "Unable to find RawInputEvent.when"); - - return res; -} - -}; // namespace android - diff --git a/services/jni/com_android_server_PowerManagerService.cpp b/services/jni/com_android_server_PowerManagerService.cpp new file mode 100644 index 0000000..705be60 --- /dev/null +++ b/services/jni/com_android_server_PowerManagerService.cpp @@ -0,0 +1,182 @@ +/* + * 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 "PowerManagerService-JNI" + +//#define LOG_NDEBUG 0 + +#include "JNIHelp.h" +#include "jni.h" + +#include <limits.h> + +#include <android_runtime/AndroidRuntime.h> +#include <utils/Timers.h> +#include <surfaceflinger/ISurfaceComposer.h> +#include <surfaceflinger/SurfaceComposerClient.h> + +#include "com_android_server_PowerManagerService.h" + +namespace android { + +// ---------------------------------------------------------------------------- + +static struct { + jclass clazz; + + jmethodID goToSleep; + jmethodID userActivity; +} gPowerManagerServiceClassInfo; + +// ---------------------------------------------------------------------------- + +static jobject gPowerManagerServiceObj; + +static Mutex gPowerManagerLock; +static bool gScreenOn; +static bool gScreenBright; + +static nsecs_t gLastEventTime[POWER_MANAGER_LAST_EVENT + 1]; + +// Throttling interval for user activity calls. +static const nsecs_t MIN_TIME_BETWEEN_USERACTIVITIES = 500 * 1000000L; // 500ms + +// ---------------------------------------------------------------------------- + +static bool checkAndClearExceptionFromCallback(JNIEnv* env, const char* methodName) { + if (env->ExceptionCheck()) { + LOGE("An exception was thrown by callback '%s'.", methodName); + LOGE_EX(env); + env->ExceptionClear(); + return true; + } + return false; +} + +bool android_server_PowerManagerService_isScreenOn() { + AutoMutex _l(gPowerManagerLock); + return gScreenOn; +} + +bool android_server_PowerManagerService_isScreenBright() { + AutoMutex _l(gPowerManagerLock); + return gScreenBright; +} + +void android_server_PowerManagerService_userActivity(nsecs_t eventTime, int32_t eventType) { + if (gPowerManagerServiceObj) { + // Throttle calls into user activity by event type. + // We're a little conservative about argument checking here in case the caller + // passes in bad data which could corrupt system state. + if (eventType >= 0 && eventType <= POWER_MANAGER_LAST_EVENT) { + nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC); + if (eventTime > now) { + eventTime = now; + } + + if (gLastEventTime[eventType] + MIN_TIME_BETWEEN_USERACTIVITIES > eventTime) { + return; + } + gLastEventTime[eventType] = eventTime; + } + + JNIEnv* env = AndroidRuntime::getJNIEnv(); + + env->CallVoidMethod(gPowerManagerServiceObj, gPowerManagerServiceClassInfo.userActivity, + nanoseconds_to_milliseconds(eventTime), false, eventType, false); + checkAndClearExceptionFromCallback(env, "userActivity"); + } +} + +void android_server_PowerManagerService_goToSleep(nsecs_t eventTime) { + if (gPowerManagerServiceObj) { + JNIEnv* env = AndroidRuntime::getJNIEnv(); + + env->CallVoidMethod(gPowerManagerServiceObj, gPowerManagerServiceClassInfo.goToSleep, + nanoseconds_to_milliseconds(eventTime)); + checkAndClearExceptionFromCallback(env, "goToSleep"); + } +} + +// ---------------------------------------------------------------------------- + +static void android_server_PowerManagerService_nativeInit(JNIEnv* env, jobject obj) { + gPowerManagerServiceObj = env->NewGlobalRef(obj); +} + +static void android_server_PowerManagerService_nativeSetPowerState(JNIEnv* env, + jobject serviceObj, jboolean screenOn, jboolean screenBright) { + AutoMutex _l(gPowerManagerLock); + gScreenOn = screenOn; + gScreenBright = screenBright; +} + +static void android_server_PowerManagerService_nativeStartSurfaceFlingerAnimation(JNIEnv* env, + jobject obj, jint mode) { + sp<ISurfaceComposer> s(ComposerService::getComposerService()); + s->turnElectronBeamOff(mode); +} + +// ---------------------------------------------------------------------------- + +static JNINativeMethod gPowerManagerServiceMethods[] = { + /* name, signature, funcPtr */ + { "nativeInit", "()V", + (void*) android_server_PowerManagerService_nativeInit }, + { "nativeSetPowerState", "(ZZ)V", + (void*) android_server_PowerManagerService_nativeSetPowerState }, + { "nativeStartSurfaceFlingerAnimation", "(I)V", + (void*) android_server_PowerManagerService_nativeStartSurfaceFlingerAnimation }, +}; + +#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_PowerManagerService(JNIEnv* env) { + int res = jniRegisterNativeMethods(env, "com/android/server/PowerManagerService", + gPowerManagerServiceMethods, NELEM(gPowerManagerServiceMethods)); + LOG_FATAL_IF(res < 0, "Unable to register native methods."); + + // Callbacks + + FIND_CLASS(gPowerManagerServiceClassInfo.clazz, "com/android/server/PowerManagerService"); + + GET_METHOD_ID(gPowerManagerServiceClassInfo.goToSleep, gPowerManagerServiceClassInfo.clazz, + "goToSleep", "(J)V"); + + GET_METHOD_ID(gPowerManagerServiceClassInfo.userActivity, gPowerManagerServiceClassInfo.clazz, + "userActivity", "(JZIZ)V"); + + // Initialize + for (int i = 0; i < POWER_MANAGER_LAST_EVENT; i++) { + gLastEventTime[i] = LLONG_MIN; + } + gScreenOn = true; + gScreenBright = true; + return 0; +} + +} /* namespace android */ diff --git a/services/jni/com_android_server_PowerManagerService.h b/services/jni/com_android_server_PowerManagerService.h new file mode 100644 index 0000000..af10711 --- /dev/null +++ b/services/jni/com_android_server_PowerManagerService.h @@ -0,0 +1,34 @@ +/* + * 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. + */ + +#ifndef _ANDROID_SERVER_POWER_MANAGER_SERVICE_H +#define _ANDROID_SERVER_POWER_MANAGER_SERVICE_H + +#include "JNIHelp.h" +#include "jni.h" + +#include <ui/PowerManager.h> + +namespace android { + +extern bool android_server_PowerManagerService_isScreenOn(); +extern bool android_server_PowerManagerService_isScreenBright(); +extern void android_server_PowerManagerService_userActivity(nsecs_t eventTime, int32_t eventType); +extern void android_server_PowerManagerService_goToSleep(nsecs_t eventTime); + +} // namespace android + +#endif // _ANDROID_SERVER_POWER_MANAGER_SERVICE_H diff --git a/services/jni/com_android_server_SensorService.cpp b/services/jni/com_android_server_SensorService.cpp deleted file mode 100644 index 77db6da..0000000 --- a/services/jni/com_android_server_SensorService.cpp +++ /dev/null @@ -1,177 +0,0 @@ -/* - * Copyright 2008, 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 "SensorService" - -#include "utils/Log.h" - -#include <hardware/sensors.h> - -#include "jni.h" -#include "JNIHelp.h" - -namespace android { - -static struct file_descriptor_offsets_t -{ - jclass mClass; - jmethodID mConstructor; - jfieldID mDescriptor; -} gFileDescriptorOffsets; - -static struct parcel_file_descriptor_offsets_t -{ - jclass mClass; - jmethodID mConstructor; -} gParcelFileDescriptorOffsets; - -static struct bundle_descriptor_offsets_t -{ - jclass mClass; - jmethodID mConstructor; - jmethodID mPutIntArray; - jmethodID mPutParcelableArray; -} gBundleOffsets; - -/* - * The method below are not thread-safe and not intended to be - */ - -static sensors_control_device_t* sSensorDevice = 0; - -static jint -android_init(JNIEnv *env, jclass clazz) -{ - sensors_module_t* module; - if (hw_get_module(SENSORS_HARDWARE_MODULE_ID, (const hw_module_t**)&module) == 0) { - if (sensors_control_open(&module->common, &sSensorDevice) == 0) { - const struct sensor_t* list; - int count = module->get_sensors_list(module, &list); - return count; - } - } - return 0; -} - -static jobject -android_open(JNIEnv *env, jclass clazz) -{ - native_handle_t* handle = sSensorDevice->open_data_source(sSensorDevice); - if (!handle) { - return NULL; - } - - // new Bundle() - jobject bundle = env->NewObject( - gBundleOffsets.mClass, - gBundleOffsets.mConstructor); - - if (handle->numFds > 0) { - jobjectArray fdArray = env->NewObjectArray(handle->numFds, - gParcelFileDescriptorOffsets.mClass, NULL); - for (int i = 0; i < handle->numFds; i++) { - // new FileDescriptor() - jobject fd = env->NewObject(gFileDescriptorOffsets.mClass, - gFileDescriptorOffsets.mConstructor); - env->SetIntField(fd, gFileDescriptorOffsets.mDescriptor, handle->data[i]); - // new ParcelFileDescriptor() - jobject pfd = env->NewObject(gParcelFileDescriptorOffsets.mClass, - gParcelFileDescriptorOffsets.mConstructor, fd); - env->SetObjectArrayElement(fdArray, i, pfd); - } - // bundle.putParcelableArray("fds", fdArray); - env->CallVoidMethod(bundle, gBundleOffsets.mPutParcelableArray, - env->NewStringUTF("fds"), fdArray); - } - - if (handle->numInts > 0) { - jintArray intArray = env->NewIntArray(handle->numInts); - env->SetIntArrayRegion(intArray, 0, handle->numInts, &handle->data[handle->numInts]); - // bundle.putIntArray("ints", intArray); - env->CallVoidMethod(bundle, gBundleOffsets.mPutIntArray, - env->NewStringUTF("ints"), intArray); - } - - // delete the file handle, but don't close any file descriptors - native_handle_delete(handle); - return bundle; -} - -static jint -android_close(JNIEnv *env, jclass clazz) -{ - if (sSensorDevice->close_data_source) - return sSensorDevice->close_data_source(sSensorDevice); - else - return 0; -} - -static jboolean -android_activate(JNIEnv *env, jclass clazz, jint sensor, jboolean activate) -{ - int active = sSensorDevice->activate(sSensorDevice, sensor, activate); - return (active<0) ? false : true; -} - -static jint -android_set_delay(JNIEnv *env, jclass clazz, jint ms) -{ - return sSensorDevice->set_delay(sSensorDevice, ms); -} - -static jint -android_data_wake(JNIEnv *env, jclass clazz) -{ - int res = sSensorDevice->wake(sSensorDevice); - return res; -} - - -static JNINativeMethod gMethods[] = { - {"_sensors_control_init", "()I", (void*) android_init }, - {"_sensors_control_open", "()Landroid/os/Bundle;", (void*) android_open }, - {"_sensors_control_close", "()I", (void*) android_close }, - {"_sensors_control_activate", "(IZ)Z", (void*) android_activate }, - {"_sensors_control_wake", "()I", (void*) android_data_wake }, - {"_sensors_control_set_delay","(I)I", (void*) android_set_delay }, -}; - -int register_android_server_SensorService(JNIEnv *env) -{ - jclass clazz; - - clazz = env->FindClass("java/io/FileDescriptor"); - gFileDescriptorOffsets.mClass = (jclass)env->NewGlobalRef(clazz); - gFileDescriptorOffsets.mConstructor = env->GetMethodID(clazz, "<init>", "()V"); - gFileDescriptorOffsets.mDescriptor = env->GetFieldID(clazz, "descriptor", "I"); - - clazz = env->FindClass("android/os/ParcelFileDescriptor"); - gParcelFileDescriptorOffsets.mClass = (jclass) env->NewGlobalRef(clazz); - gParcelFileDescriptorOffsets.mConstructor = env->GetMethodID(clazz, "<init>", - "(Ljava/io/FileDescriptor;)V"); - - clazz = env->FindClass("android/os/Bundle"); - gBundleOffsets.mClass = (jclass) env->NewGlobalRef(clazz); - gBundleOffsets.mConstructor = env->GetMethodID(clazz, "<init>", "()V"); - gBundleOffsets.mPutIntArray = env->GetMethodID(clazz, "putIntArray", "(Ljava/lang/String;[I)V"); - gBundleOffsets.mPutParcelableArray = env->GetMethodID(clazz, "putParcelableArray", - "(Ljava/lang/String;[Landroid/os/Parcelable;)V"); - - return jniRegisterNativeMethods(env, "com/android/server/SensorService", - gMethods, NELEM(gMethods)); -} - -}; // namespace android diff --git a/services/jni/com_android_server_location_GpsLocationProvider.cpp b/services/jni/com_android_server_location_GpsLocationProvider.cpp new file mode 100755 index 0000000..f5e17f5 --- /dev/null +++ b/services/jni/com_android_server_location_GpsLocationProvider.cpp @@ -0,0 +1,638 @@ +/* + * Copyright (C) 2008 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 "GpsLocationProvider" + +#define LOG_NDEBUG 0 + +#include "JNIHelp.h" +#include "jni.h" +#include "hardware/hardware.h" +#include "hardware/gps.h" +#include "hardware_legacy/power.h" +#include "utils/Log.h" +#include "utils/misc.h" +#include "android_runtime/AndroidRuntime.h" + +#include <string.h> +#include <pthread.h> + +static jobject mCallbacksObj = NULL; + +static jmethodID method_reportLocation; +static jmethodID method_reportStatus; +static jmethodID method_reportSvStatus; +static jmethodID method_reportAGpsStatus; +static jmethodID method_reportNmea; +static jmethodID method_setEngineCapabilities; +static jmethodID method_xtraDownloadRequest; +static jmethodID method_reportNiNotification; +static jmethodID method_requestRefLocation; +static jmethodID method_requestSetID; + +static const GpsInterface* sGpsInterface = NULL; +static const GpsXtraInterface* sGpsXtraInterface = NULL; +static const AGpsInterface* sAGpsInterface = NULL; +static const GpsNiInterface* sGpsNiInterface = NULL; +static const GpsDebugInterface* sGpsDebugInterface = NULL; +static const AGpsRilInterface* sAGpsRilInterface = NULL; + +// temporary storage for GPS callbacks +static GpsSvStatus sGpsSvStatus; +static const char* sNmeaString; +static int sNmeaStringLength; + +#define WAKE_LOCK_NAME "GPS" + +namespace android { + +static void checkAndClearExceptionFromCallback(JNIEnv* env, const char* methodName) { + if (env->ExceptionCheck()) { + LOGE("An exception was thrown by callback '%s'.", methodName); + LOGE_EX(env); + env->ExceptionClear(); + } +} + +static void location_callback(GpsLocation* location) +{ + JNIEnv* env = AndroidRuntime::getJNIEnv(); + env->CallVoidMethod(mCallbacksObj, method_reportLocation, location->flags, + (jdouble)location->latitude, (jdouble)location->longitude, + (jdouble)location->altitude, + (jfloat)location->speed, (jfloat)location->bearing, + (jfloat)location->accuracy, (jlong)location->timestamp); + checkAndClearExceptionFromCallback(env, __FUNCTION__); +} + +static void status_callback(GpsStatus* status) +{ + JNIEnv* env = AndroidRuntime::getJNIEnv(); + env->CallVoidMethod(mCallbacksObj, method_reportStatus, status->status); + checkAndClearExceptionFromCallback(env, __FUNCTION__); +} + +static void sv_status_callback(GpsSvStatus* sv_status) +{ + JNIEnv* env = AndroidRuntime::getJNIEnv(); + memcpy(&sGpsSvStatus, sv_status, sizeof(sGpsSvStatus)); + env->CallVoidMethod(mCallbacksObj, method_reportSvStatus); + checkAndClearExceptionFromCallback(env, __FUNCTION__); +} + +static void nmea_callback(GpsUtcTime timestamp, const char* nmea, int length) +{ + JNIEnv* env = AndroidRuntime::getJNIEnv(); + // The Java code will call back to read these values + // We do this to avoid creating unnecessary String objects + sNmeaString = nmea; + sNmeaStringLength = length; + env->CallVoidMethod(mCallbacksObj, method_reportNmea, timestamp); + checkAndClearExceptionFromCallback(env, __FUNCTION__); +} + +static void set_capabilities_callback(uint32_t capabilities) +{ + LOGD("set_capabilities_callback: %ld\n", capabilities); + JNIEnv* env = AndroidRuntime::getJNIEnv(); + env->CallVoidMethod(mCallbacksObj, method_setEngineCapabilities, capabilities); + checkAndClearExceptionFromCallback(env, __FUNCTION__); +} + +static void acquire_wakelock_callback() +{ + acquire_wake_lock(PARTIAL_WAKE_LOCK, WAKE_LOCK_NAME); +} + +static void release_wakelock_callback() +{ + release_wake_lock(WAKE_LOCK_NAME); +} + +static pthread_t create_thread_callback(const char* name, void (*start)(void *), void* arg) +{ + return (pthread_t)AndroidRuntime::createJavaThread(name, start, arg); +} + +GpsCallbacks sGpsCallbacks = { + sizeof(GpsCallbacks), + location_callback, + status_callback, + sv_status_callback, + nmea_callback, + set_capabilities_callback, + acquire_wakelock_callback, + release_wakelock_callback, + create_thread_callback, +}; + +static void xtra_download_request_callback() +{ + JNIEnv* env = AndroidRuntime::getJNIEnv(); + env->CallVoidMethod(mCallbacksObj, method_xtraDownloadRequest); + checkAndClearExceptionFromCallback(env, __FUNCTION__); +} + +GpsXtraCallbacks sGpsXtraCallbacks = { + xtra_download_request_callback, + create_thread_callback, +}; + +static void agps_status_callback(AGpsStatus* agps_status) +{ + JNIEnv* env = AndroidRuntime::getJNIEnv(); + env->CallVoidMethod(mCallbacksObj, method_reportAGpsStatus, + agps_status->type, agps_status->status); + checkAndClearExceptionFromCallback(env, __FUNCTION__); +} + +AGpsCallbacks sAGpsCallbacks = { + agps_status_callback, + create_thread_callback, +}; + +static void gps_ni_notify_callback(GpsNiNotification *notification) +{ + LOGD("gps_ni_notify_callback\n"); + JNIEnv* env = AndroidRuntime::getJNIEnv(); + jstring requestor_id = env->NewStringUTF(notification->requestor_id); + jstring text = env->NewStringUTF(notification->text); + jstring extras = env->NewStringUTF(notification->extras); + + if (requestor_id && text && extras) { + env->CallVoidMethod(mCallbacksObj, method_reportNiNotification, + notification->notification_id, notification->ni_type, + notification->notify_flags, notification->timeout, + notification->default_response, requestor_id, text, + notification->requestor_id_encoding, + notification->text_encoding, extras); + } else { + LOGE("out of memory in gps_ni_notify_callback\n"); + } + + if (requestor_id) + env->DeleteLocalRef(requestor_id); + if (text) + env->DeleteLocalRef(text); + if (extras) + env->DeleteLocalRef(extras); + checkAndClearExceptionFromCallback(env, __FUNCTION__); +} + +GpsNiCallbacks sGpsNiCallbacks = { + gps_ni_notify_callback, + create_thread_callback, +}; + +static void agps_request_set_id(uint32_t flags) +{ + LOGD("agps_request_set_id: flags (%d)", flags); + + JNIEnv* env = AndroidRuntime::getJNIEnv(); + env->CallVoidMethod(mCallbacksObj, method_requestSetID, flags); + checkAndClearExceptionFromCallback(env, __FUNCTION__); +} + +static void agps_request_ref_location(uint32_t flags) +{ + LOGD("agps_ref_location: flags (%d)", flags); + + JNIEnv* env = AndroidRuntime::getJNIEnv(); + env->CallVoidMethod(mCallbacksObj, method_requestRefLocation, flags); + checkAndClearExceptionFromCallback(env, __FUNCTION__); +} + +AGpsRilCallbacks sAGpsRilCallbacks = { + agps_request_set_id, + agps_request_ref_location, + create_thread_callback, +}; + +static const GpsInterface* get_gps_interface() { + int err; + hw_module_t* module; + const GpsInterface* interface = NULL; + + err = hw_get_module(GPS_HARDWARE_MODULE_ID, (hw_module_t const**)&module); + if (err == 0) { + hw_device_t* device; + err = module->methods->open(module, GPS_HARDWARE_MODULE_ID, &device); + if (err == 0) { + gps_device_t* gps_device = (gps_device_t *)device; + interface = gps_device->get_gps_interface(gps_device); + } + } + + return interface; +} + +static const GpsInterface* GetGpsInterface(JNIEnv* env, jobject obj) { + // this must be set before calling into the HAL library + if (!mCallbacksObj) + mCallbacksObj = env->NewGlobalRef(obj); + + if (!sGpsInterface) { + sGpsInterface = get_gps_interface(); + if (!sGpsInterface || sGpsInterface->init(&sGpsCallbacks) != 0) { + sGpsInterface = NULL; + return NULL; + } + } + return sGpsInterface; +} + +static const AGpsInterface* GetAGpsInterface(JNIEnv* env, jobject obj) +{ + const GpsInterface* interface = GetGpsInterface(env, obj); + if (!interface) + return NULL; + + if (!sAGpsInterface) { + sAGpsInterface = (const AGpsInterface*)interface->get_extension(AGPS_INTERFACE); + if (sAGpsInterface) + sAGpsInterface->init(&sAGpsCallbacks); + } + return sAGpsInterface; +} + +static const GpsNiInterface* GetNiInterface(JNIEnv* env, jobject obj) +{ + const GpsInterface* interface = GetGpsInterface(env, obj); + if (!interface) + return NULL; + + if (!sGpsNiInterface) { + sGpsNiInterface = (const GpsNiInterface*)interface->get_extension(GPS_NI_INTERFACE); + if (sGpsNiInterface) + sGpsNiInterface->init(&sGpsNiCallbacks); + } + return sGpsNiInterface; +} + +static const AGpsRilInterface* GetAGpsRilInterface(JNIEnv* env, jobject obj) +{ + const GpsInterface* interface = GetGpsInterface(env, obj); + if (!interface) + return NULL; + + if (!sAGpsRilInterface) { + sAGpsRilInterface = (const AGpsRilInterface*)interface->get_extension(AGPS_RIL_INTERFACE); + if (sAGpsRilInterface) + sAGpsRilInterface->init(&sAGpsRilCallbacks); + } + return sAGpsRilInterface; +} + +static void android_location_GpsLocationProvider_class_init_native(JNIEnv* env, jclass clazz) { + method_reportLocation = env->GetMethodID(clazz, "reportLocation", "(IDDDFFFJ)V"); + method_reportStatus = env->GetMethodID(clazz, "reportStatus", "(I)V"); + method_reportSvStatus = env->GetMethodID(clazz, "reportSvStatus", "()V"); + method_reportAGpsStatus = env->GetMethodID(clazz, "reportAGpsStatus", "(II)V"); + method_reportNmea = env->GetMethodID(clazz, "reportNmea", "(J)V"); + method_setEngineCapabilities = env->GetMethodID(clazz, "setEngineCapabilities", "(I)V"); + method_xtraDownloadRequest = env->GetMethodID(clazz, "xtraDownloadRequest", "()V"); + method_reportNiNotification = env->GetMethodID(clazz, "reportNiNotification", "(IIIIILjava/lang/String;Ljava/lang/String;IILjava/lang/String;)V"); + method_requestRefLocation = env->GetMethodID(clazz,"requestRefLocation","(I)V"); + method_requestSetID = env->GetMethodID(clazz,"requestSetID","(I)V"); +} + +static jboolean android_location_GpsLocationProvider_is_supported(JNIEnv* env, jclass clazz) { + return (sGpsInterface != NULL || get_gps_interface() != NULL); +} + +static jboolean android_location_GpsLocationProvider_init(JNIEnv* env, jobject obj) +{ + const GpsInterface* interface = GetGpsInterface(env, obj); + if (!interface) + return false; + + if (!sGpsDebugInterface) + sGpsDebugInterface = (const GpsDebugInterface*)interface->get_extension(GPS_DEBUG_INTERFACE); + + return true; +} + +static void android_location_GpsLocationProvider_cleanup(JNIEnv* env, jobject obj) +{ + const GpsInterface* interface = GetGpsInterface(env, obj); + if (interface) + interface->cleanup(); +} + +static jboolean android_location_GpsLocationProvider_set_position_mode(JNIEnv* env, jobject obj, + jint mode, jint recurrence, jint min_interval, jint preferred_accuracy, jint preferred_time) +{ + const GpsInterface* interface = GetGpsInterface(env, obj); + if (interface) + return (interface->set_position_mode(mode, recurrence, min_interval, preferred_accuracy, + preferred_time) == 0); + else + return false; +} + +static jboolean android_location_GpsLocationProvider_start(JNIEnv* env, jobject obj) +{ + const GpsInterface* interface = GetGpsInterface(env, obj); + if (interface) + return (interface->start() == 0); + else + return false; +} + +static jboolean android_location_GpsLocationProvider_stop(JNIEnv* env, jobject obj) +{ + const GpsInterface* interface = GetGpsInterface(env, obj); + if (interface) + return (interface->stop() == 0); + else + return false; +} + +static void android_location_GpsLocationProvider_delete_aiding_data(JNIEnv* env, jobject obj, jint flags) +{ + const GpsInterface* interface = GetGpsInterface(env, obj); + if (interface) + interface->delete_aiding_data(flags); +} + +static jint android_location_GpsLocationProvider_read_sv_status(JNIEnv* env, jobject obj, + jintArray prnArray, jfloatArray snrArray, jfloatArray elevArray, jfloatArray azumArray, + jintArray maskArray) +{ + // this should only be called from within a call to reportSvStatus + + jint* prns = env->GetIntArrayElements(prnArray, 0); + jfloat* snrs = env->GetFloatArrayElements(snrArray, 0); + jfloat* elev = env->GetFloatArrayElements(elevArray, 0); + jfloat* azim = env->GetFloatArrayElements(azumArray, 0); + jint* mask = env->GetIntArrayElements(maskArray, 0); + + int num_svs = sGpsSvStatus.num_svs; + for (int i = 0; i < num_svs; i++) { + prns[i] = sGpsSvStatus.sv_list[i].prn; + snrs[i] = sGpsSvStatus.sv_list[i].snr; + elev[i] = sGpsSvStatus.sv_list[i].elevation; + azim[i] = sGpsSvStatus.sv_list[i].azimuth; + } + mask[0] = sGpsSvStatus.ephemeris_mask; + mask[1] = sGpsSvStatus.almanac_mask; + mask[2] = sGpsSvStatus.used_in_fix_mask; + + env->ReleaseIntArrayElements(prnArray, prns, 0); + env->ReleaseFloatArrayElements(snrArray, snrs, 0); + env->ReleaseFloatArrayElements(elevArray, elev, 0); + env->ReleaseFloatArrayElements(azumArray, azim, 0); + env->ReleaseIntArrayElements(maskArray, mask, 0); + return num_svs; +} + +static void android_location_GpsLocationProvider_agps_set_reference_location_cellid(JNIEnv* env, + jobject obj, jint type, jint mcc, jint mnc, jint lac, jint cid) +{ + AGpsRefLocation location; + const AGpsRilInterface* interface = GetAGpsRilInterface(env, obj); + if (!interface) { + LOGE("no AGPS RIL interface in agps_set_reference_location_cellid"); + return; + } + + switch(type) { + case AGPS_REF_LOCATION_TYPE_GSM_CELLID: + case AGPS_REF_LOCATION_TYPE_UMTS_CELLID: + location.type = type; + location.u.cellID.mcc = mcc; + location.u.cellID.mnc = mnc; + location.u.cellID.lac = lac; + location.u.cellID.cid = cid; + break; + default: + LOGE("Neither a GSM nor a UMTS cellid (%s:%d).",__FUNCTION__,__LINE__); + return; + break; + } + interface->set_ref_location(&location, sizeof(location)); +} + +static void android_location_GpsLocationProvider_agps_send_ni_message(JNIEnv* env, + jobject obj, jbyteArray ni_msg, jint size) +{ + size_t sz; + const AGpsRilInterface* interface = GetAGpsRilInterface(env, obj); + if (!interface) { + LOGE("no AGPS RIL interface in send_ni_message"); + return; + } + if (size < 0) + return; + sz = (size_t)size; + jbyte* b = env->GetByteArrayElements(ni_msg, 0); + interface->ni_message((uint8_t *)b,sz); + env->ReleaseByteArrayElements(ni_msg,b,0); +} + +static void android_location_GpsLocationProvider_agps_set_id(JNIEnv *env, + jobject obj, jint type, jstring setid_string) +{ + const AGpsRilInterface* interface = GetAGpsRilInterface(env, obj); + if (!interface) { + LOGE("no AGPS RIL interface in agps_set_id"); + return; + } + + const char *setid = env->GetStringUTFChars(setid_string, NULL); + interface->set_set_id(type, setid); + env->ReleaseStringUTFChars(setid_string, setid); +} + +static jint android_location_GpsLocationProvider_read_nmea(JNIEnv* env, jobject obj, + jbyteArray nmeaArray, jint buffer_size) +{ + // this should only be called from within a call to reportNmea + jbyte* nmea = (jbyte *)env->GetPrimitiveArrayCritical(nmeaArray, 0); + int length = sNmeaStringLength; + if (length > buffer_size) + length = buffer_size; + memcpy(nmea, sNmeaString, length); + env->ReleasePrimitiveArrayCritical(nmeaArray, nmea, JNI_ABORT); + return length; +} + +static void android_location_GpsLocationProvider_inject_time(JNIEnv* env, jobject obj, + jlong time, jlong timeReference, jint uncertainty) +{ + const GpsInterface* interface = GetGpsInterface(env, obj); + if (interface) + interface->inject_time(time, timeReference, uncertainty); +} + +static void android_location_GpsLocationProvider_inject_location(JNIEnv* env, jobject obj, + jdouble latitude, jdouble longitude, jfloat accuracy) +{ + const GpsInterface* interface = GetGpsInterface(env, obj); + if (interface) + interface->inject_location(latitude, longitude, accuracy); +} + +static jboolean android_location_GpsLocationProvider_supports_xtra(JNIEnv* env, jobject obj) +{ + if (!sGpsXtraInterface) { + const GpsInterface* interface = GetGpsInterface(env, obj); + if (!interface) + return false; + sGpsXtraInterface = (const GpsXtraInterface*)interface->get_extension(GPS_XTRA_INTERFACE); + if (sGpsXtraInterface) { + int result = sGpsXtraInterface->init(&sGpsXtraCallbacks); + if (result) { + sGpsXtraInterface = NULL; + } + } + } + + return (sGpsXtraInterface != NULL); +} + +static void android_location_GpsLocationProvider_inject_xtra_data(JNIEnv* env, jobject obj, + jbyteArray data, jint length) +{ + jbyte* bytes = (jbyte *)env->GetPrimitiveArrayCritical(data, 0); + sGpsXtraInterface->inject_xtra_data((char *)bytes, length); + env->ReleasePrimitiveArrayCritical(data, bytes, JNI_ABORT); +} + +static void android_location_GpsLocationProvider_agps_data_conn_open(JNIEnv* env, jobject obj, jstring apn) +{ + const AGpsInterface* interface = GetAGpsInterface(env, obj); + if (!interface) { + LOGE("no AGPS interface in agps_data_conn_open"); + return; + } + if (apn == NULL) { + jniThrowException(env, "java/lang/IllegalArgumentException", NULL); + return; + } + const char *apnStr = env->GetStringUTFChars(apn, NULL); + interface->data_conn_open(apnStr); + env->ReleaseStringUTFChars(apn, apnStr); +} + +static void android_location_GpsLocationProvider_agps_data_conn_closed(JNIEnv* env, jobject obj) +{ + const AGpsInterface* interface = GetAGpsInterface(env, obj); + if (!interface) { + LOGE("no AGPS interface in agps_data_conn_open"); + return; + } + interface->data_conn_closed(); +} + +static void android_location_GpsLocationProvider_agps_data_conn_failed(JNIEnv* env, jobject obj) +{ + const AGpsInterface* interface = GetAGpsInterface(env, obj); + if (!interface) { + LOGE("no AGPS interface in agps_data_conn_open"); + return; + } + interface->data_conn_failed(); +} + +static void android_location_GpsLocationProvider_set_agps_server(JNIEnv* env, jobject obj, + jint type, jstring hostname, jint port) +{ + const AGpsInterface* interface = GetAGpsInterface(env, obj); + if (!interface) { + LOGE("no AGPS interface in agps_data_conn_open"); + return; + } + const char *c_hostname = env->GetStringUTFChars(hostname, NULL); + interface->set_server(type, c_hostname, port); + env->ReleaseStringUTFChars(hostname, c_hostname); +} + +static void android_location_GpsLocationProvider_send_ni_response(JNIEnv* env, jobject obj, + jint notifId, jint response) +{ + const GpsNiInterface* interface = GetNiInterface(env, obj); + if (!interface) { + LOGE("no NI interface in send_ni_response"); + return; + } + + interface->respond(notifId, response); +} + +static jstring android_location_GpsLocationProvider_get_internal_state(JNIEnv* env, jobject obj) +{ + jstring result = NULL; + if (sGpsDebugInterface) { + const size_t maxLength = 2047; + char buffer[maxLength+1]; + size_t length = sGpsDebugInterface->get_internal_state(buffer, maxLength); + if (length > maxLength) length = maxLength; + buffer[length] = 0; + result = env->NewStringUTF(buffer); + } + return result; +} + +static void android_location_GpsLocationProvider_update_network_state(JNIEnv* env, jobject obj, + jboolean connected, int type, jboolean roaming, jstring extraInfo) +{ + const AGpsRilInterface* interface = GetAGpsRilInterface(env, obj); + if (interface && interface->update_network_state) { + if (extraInfo) { + const char *extraInfoStr = env->GetStringUTFChars(extraInfo, NULL); + interface->update_network_state(connected, type, roaming, extraInfoStr); + env->ReleaseStringUTFChars(extraInfo, extraInfoStr); + } else { + interface->update_network_state(connected, type, roaming, NULL); + } + } +} + +static JNINativeMethod sMethods[] = { + /* name, signature, funcPtr */ + {"class_init_native", "()V", (void *)android_location_GpsLocationProvider_class_init_native}, + {"native_is_supported", "()Z", (void*)android_location_GpsLocationProvider_is_supported}, + {"native_init", "()Z", (void*)android_location_GpsLocationProvider_init}, + {"native_cleanup", "()V", (void*)android_location_GpsLocationProvider_cleanup}, + {"native_set_position_mode", "(IIIII)Z", (void*)android_location_GpsLocationProvider_set_position_mode}, + {"native_start", "()Z", (void*)android_location_GpsLocationProvider_start}, + {"native_stop", "()Z", (void*)android_location_GpsLocationProvider_stop}, + {"native_delete_aiding_data", "(I)V", (void*)android_location_GpsLocationProvider_delete_aiding_data}, + {"native_read_sv_status", "([I[F[F[F[I)I", (void*)android_location_GpsLocationProvider_read_sv_status}, + {"native_read_nmea", "([BI)I", (void*)android_location_GpsLocationProvider_read_nmea}, + {"native_inject_time", "(JJI)V", (void*)android_location_GpsLocationProvider_inject_time}, + {"native_inject_location", "(DDF)V", (void*)android_location_GpsLocationProvider_inject_location}, + {"native_supports_xtra", "()Z", (void*)android_location_GpsLocationProvider_supports_xtra}, + {"native_inject_xtra_data", "([BI)V", (void*)android_location_GpsLocationProvider_inject_xtra_data}, + {"native_agps_data_conn_open", "(Ljava/lang/String;)V", (void*)android_location_GpsLocationProvider_agps_data_conn_open}, + {"native_agps_data_conn_closed", "()V", (void*)android_location_GpsLocationProvider_agps_data_conn_closed}, + {"native_agps_data_conn_failed", "()V", (void*)android_location_GpsLocationProvider_agps_data_conn_failed}, + {"native_agps_set_id","(ILjava/lang/String;)V",(void*)android_location_GpsLocationProvider_agps_set_id}, + {"native_agps_set_ref_location_cellid","(IIIII)V",(void*)android_location_GpsLocationProvider_agps_set_reference_location_cellid}, + {"native_set_agps_server", "(ILjava/lang/String;I)V", (void*)android_location_GpsLocationProvider_set_agps_server}, + {"native_send_ni_response", "(II)V", (void*)android_location_GpsLocationProvider_send_ni_response}, + {"native_agps_ni_message", "([BI)V", (void *)android_location_GpsLocationProvider_agps_send_ni_message}, + {"native_get_internal_state", "()Ljava/lang/String;", (void*)android_location_GpsLocationProvider_get_internal_state}, + {"native_update_network_state", "(ZIZLjava/lang/String;)V", (void*)android_location_GpsLocationProvider_update_network_state }, +}; + +int register_android_server_location_GpsLocationProvider(JNIEnv* env) +{ + return jniRegisterNativeMethods(env, "com/android/server/location/GpsLocationProvider", sMethods, NELEM(sMethods)); +} + +} /* namespace android */ diff --git a/services/jni/onload.cpp b/services/jni/onload.cpp index c16fdb8..cd4f0a4 100644 --- a/services/jni/onload.cpp +++ b/services/jni/onload.cpp @@ -6,11 +6,12 @@ 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_PowerManagerService(JNIEnv* env); int register_android_server_VibratorService(JNIEnv* env); int register_android_server_SystemServer(JNIEnv* env); +int register_android_server_location_GpsLocationProvider(JNIEnv* env); }; using namespace android; @@ -26,13 +27,14 @@ 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_PowerManagerService(env); + register_android_server_InputManager(env); register_android_server_LightsService(env); register_android_server_AlarmManagerService(env); register_android_server_BatteryService(env); - register_android_server_SensorService(env); register_android_server_VibratorService(env); register_android_server_SystemServer(env); + register_android_server_location_GpsLocationProvider(env); return JNI_VERSION_1_4; } |