diff options
-rw-r--r-- | core/java/android/view/WindowManager.java | 5 | ||||
-rw-r--r-- | include/ui/EventHub.h | 4 | ||||
-rw-r--r-- | include/ui/InputReader.h | 21 | ||||
-rw-r--r-- | include/ui/PointerController.h | 63 | ||||
-rw-r--r-- | include/utils/PropertyMap.h | 6 | ||||
-rw-r--r-- | libs/ui/EventHub.cpp | 4 | ||||
-rw-r--r-- | libs/ui/InputDispatcher.cpp | 8 | ||||
-rw-r--r-- | libs/ui/InputReader.cpp | 183 | ||||
-rw-r--r-- | libs/ui/tests/InputReader_test.cpp | 228 | ||||
-rw-r--r-- | libs/utils/PropertyMap.cpp | 6 | ||||
-rwxr-xr-x | policy/src/com/android/internal/policy/impl/PhoneWindowManager.java | 5 | ||||
-rw-r--r-- | services/java/com/android/server/InputManager.java | 9 | ||||
-rw-r--r-- | services/jni/com_android_server_InputManager.cpp | 453 |
13 files changed, 846 insertions, 149 deletions
diff --git a/core/java/android/view/WindowManager.java b/core/java/android/view/WindowManager.java index e8792ff..c435c43 100644 --- a/core/java/android/view/WindowManager.java +++ b/core/java/android/view/WindowManager.java @@ -381,6 +381,11 @@ public interface WindowManager extends ViewManager { */ public static final int TYPE_STATUS_BAR_SUB_PANEL = FIRST_SYSTEM_WINDOW+17; + /** + * Window type: (mouse) pointer + * @hide + */ + public static final int TYPE_POINTER = FIRST_SYSTEM_WINDOW+18; /** * End of types of system windows. diff --git a/include/ui/EventHub.h b/include/ui/EventHub.h index 6c6c297..8f922a5 100644 --- a/include/ui/EventHub.h +++ b/include/ui/EventHub.h @@ -109,8 +109,8 @@ enum { /* The input device is a touchscreen (either single-touch or multi-touch). */ INPUT_DEVICE_CLASS_TOUCHSCREEN = 0x00000004, - /* The input device is a trackball. */ - INPUT_DEVICE_CLASS_TRACKBALL = 0x00000008, + /* The input device is a cursor device such as a trackball or mouse. */ + INPUT_DEVICE_CLASS_CURSOR = 0x00000008, /* The input device is a multi-touch touchscreen. */ INPUT_DEVICE_CLASS_TOUCHSCREEN_MT= 0x00000010, diff --git a/include/ui/InputReader.h b/include/ui/InputReader.h index b466ff1..00a06be 100644 --- a/include/ui/InputReader.h +++ b/include/ui/InputReader.h @@ -20,6 +20,7 @@ #include <ui/EventHub.h> #include <ui/Input.h> #include <ui/InputDispatcher.h> +#include <ui/PointerController.h> #include <utils/KeyedVector.h> #include <utils/threads.h> #include <utils/Timers.h> @@ -77,6 +78,9 @@ public: /* Gets the excluded device names for the platform. */ virtual void getExcludedDeviceNames(Vector<String8>& outExcludedDeviceNames) = 0; + + /* Gets a pointer controller associated with the specified cursor device (ie. a mouse). */ + virtual sp<PointerControllerInterface> obtainPointerController(int32_t deviceId) = 0; }; @@ -421,10 +425,10 @@ private: }; -class TrackballInputMapper : public InputMapper { +class CursorInputMapper : public InputMapper { public: - TrackballInputMapper(InputDevice* device); - virtual ~TrackballInputMapper(); + CursorInputMapper(InputDevice* device); + virtual ~CursorInputMapper(); virtual uint32_t getSources(); virtual void populateDeviceInfo(InputDeviceInfo* deviceInfo); @@ -443,6 +447,12 @@ private: // Immutable configuration parameters. struct Parameters { + enum Mode { + MODE_POINTER, + MODE_NAVIGATION, + }; + + Mode mode; int32_t associatedDisplayId; bool orientationAware; } mParameters; @@ -465,10 +475,12 @@ private: } } mAccumulator; + int32_t mSources; float mXScale; float mYScale; float mXPrecision; float mYPrecision; + sp<PointerControllerInterface> mPointerController; struct LockedState { bool down; @@ -572,6 +584,9 @@ protected: } }; + // Input sources supported by the device. + int32_t mSources; + // Immutable configuration parameters. struct Parameters { enum DeviceType { diff --git a/include/ui/PointerController.h b/include/ui/PointerController.h new file mode 100644 index 0000000..4db24e5 --- /dev/null +++ b/include/ui/PointerController.h @@ -0,0 +1,63 @@ +/* + * 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 _UI_POINTER_CONTROLLER_H +#define _UI_POINTER_CONTROLLER_H + +#include <utils/RefBase.h> + +namespace android { + +enum { + POINTER_BUTTON_1 = 1 << 0, +}; + +/** + * Interface for tracking a single (mouse) pointer. + * + * The pointer controller is responsible for providing synchronization and for tracking + * display orientation changes if needed. + */ +class PointerControllerInterface : public virtual RefBase { +protected: + PointerControllerInterface() { } + virtual ~PointerControllerInterface() { } + +public: + /* Gets the bounds of the region that the pointer can traverse. + * Returns true if the bounds are available. */ + virtual bool getBounds(float* outMinX, float* outMinY, + float* outMaxX, float* outMaxY) const = 0; + + /* Move the pointer. */ + virtual void move(float deltaX, float deltaY) = 0; + + /* Sets a mask that indicates which buttons are pressed. */ + virtual void setButtonState(uint32_t buttonState) = 0; + + /* Gets a mask that indicates which buttons are pressed. */ + virtual uint32_t getButtonState() const = 0; + + /* Sets the absolute location of the pointer. */ + virtual void setPosition(float x, float y) = 0; + + /* Gets the absolute location of the pointer. */ + virtual void getPosition(float* outX, float* outY) const = 0; +}; + +} // namespace android + +#endif // _UI_POINTER_CONTROLLER_H diff --git a/include/utils/PropertyMap.h b/include/utils/PropertyMap.h index a54f819..a9e674f 100644 --- a/include/utils/PropertyMap.h +++ b/include/utils/PropertyMap.h @@ -71,6 +71,12 @@ public: bool tryGetProperty(const String8& key, int32_t& outValue) const; bool tryGetProperty(const String8& key, float& outValue) const; + /* Adds all values from the specified property map. */ + void addAll(const PropertyMap* map); + + /* Gets the underlying property map. */ + inline const KeyedVector<String8, String8>& getProperties() const { return mProperties; } + /* Loads a property map from a file. */ static status_t load(const String8& filename, PropertyMap** outMap); diff --git a/libs/ui/EventHub.cpp b/libs/ui/EventHub.cpp index 8f4bac6..4e9fad0 100644 --- a/libs/ui/EventHub.cpp +++ b/libs/ui/EventHub.cpp @@ -755,14 +755,14 @@ int EventHub::openDevice(const char *devicePath) { } } - // See if this is a trackball (or mouse). + // See if this is a cursor device such as a trackball or mouse. if (test_bit(BTN_MOUSE, key_bitmask)) { uint8_t rel_bitmask[sizeof_bit_array(REL_MAX + 1)]; memset(rel_bitmask, 0, sizeof(rel_bitmask)); LOGV("Getting relative controllers..."); if (ioctl(fd, EVIOCGBIT(EV_REL, sizeof(rel_bitmask)), rel_bitmask) >= 0) { if (test_bit(REL_X, rel_bitmask) && test_bit(REL_Y, rel_bitmask)) { - device->classes |= INPUT_DEVICE_CLASS_TRACKBALL; + device->classes |= INPUT_DEVICE_CLASS_CURSOR; } } } diff --git a/libs/ui/InputDispatcher.cpp b/libs/ui/InputDispatcher.cpp index ed0cb8e..0548e61 100644 --- a/libs/ui/InputDispatcher.cpp +++ b/libs/ui/InputDispatcher.cpp @@ -1443,11 +1443,11 @@ void InputDispatcher::prepareDispatchCycleLocked(nsecs_t currentTime, #if DEBUG_DISPATCH_CYCLE LOGD("channel '%s' ~ prepareDispatchCycle - flags=%d, " "xOffset=%f, yOffset=%f, " - "windowType=%d, pointerIds=0x%x, " + "pointerIds=0x%x, " "resumeWithAppendedMotionSample=%s", connection->getInputChannelName(), inputTarget->flags, inputTarget->xOffset, inputTarget->yOffset, - inputTarget->windowType, inputTarget->pointerIds.value, + inputTarget->pointerIds.value, toString(resumeWithAppendedMotionSample)); #endif @@ -1826,8 +1826,8 @@ void InputDispatcher::startNextDispatchCycleLocked(nsecs_t currentTime, void InputDispatcher::abortBrokenDispatchCycleLocked(nsecs_t currentTime, const sp<Connection>& connection) { #if DEBUG_DISPATCH_CYCLE - LOGD("channel '%s' ~ abortBrokenDispatchCycle - broken=%s", - connection->getInputChannelName(), toString(broken)); + LOGD("channel '%s' ~ abortBrokenDispatchCycle", + connection->getInputChannelName()); #endif // Clear the outbound queue. diff --git a/libs/ui/InputReader.cpp b/libs/ui/InputReader.cpp index 51ed09f..a11a010 100644 --- a/libs/ui/InputReader.cpp +++ b/libs/ui/InputReader.cpp @@ -239,9 +239,9 @@ InputDevice* InputReader::createDevice(int32_t deviceId, const String8& name, ui device->addMapper(new KeyboardInputMapper(device, keyboardSources, keyboardType)); } - // Trackball-like devices. - if (classes & INPUT_DEVICE_CLASS_TRACKBALL) { - device->addMapper(new TrackballInputMapper(device)); + // Cursor-like devices. + if (classes & INPUT_DEVICE_CLASS_CURSOR) { + device->addMapper(new CursorInputMapper(device)); } // Touchscreen-like devices. @@ -914,7 +914,7 @@ void KeyboardInputMapper::processKey(nsecs_t when, bool down, int32_t keyCode, if (policyFlags & POLICY_FLAG_FUNCTION) { newMetaState |= AMETA_FUNCTION_ON; } - getDispatcher()->notifyKey(when, getDeviceId(), AINPUT_SOURCE_KEYBOARD, policyFlags, + getDispatcher()->notifyKey(when, getDeviceId(), mSources, policyFlags, down ? AKEY_EVENT_ACTION_DOWN : AKEY_EVENT_ACTION_UP, AKEY_EVENT_FLAG_FROM_SYSTEM, keyCode, scanCode, newMetaState, downTime); } @@ -983,36 +983,40 @@ void KeyboardInputMapper::updateLedStateForModifierLocked(LockedState::LedState& } -// --- TrackballInputMapper --- +// --- CursorInputMapper --- -TrackballInputMapper::TrackballInputMapper(InputDevice* device) : +CursorInputMapper::CursorInputMapper(InputDevice* device) : InputMapper(device) { - mXPrecision = TRACKBALL_MOVEMENT_THRESHOLD; - mYPrecision = TRACKBALL_MOVEMENT_THRESHOLD; - mXScale = 1.0f / TRACKBALL_MOVEMENT_THRESHOLD; - mYScale = 1.0f / TRACKBALL_MOVEMENT_THRESHOLD; - initializeLocked(); } -TrackballInputMapper::~TrackballInputMapper() { +CursorInputMapper::~CursorInputMapper() { } -uint32_t TrackballInputMapper::getSources() { - return AINPUT_SOURCE_TRACKBALL; +uint32_t CursorInputMapper::getSources() { + return mSources; } -void TrackballInputMapper::populateDeviceInfo(InputDeviceInfo* info) { +void CursorInputMapper::populateDeviceInfo(InputDeviceInfo* info) { InputMapper::populateDeviceInfo(info); - info->addMotionRange(AINPUT_MOTION_RANGE_X, -1.0f, 1.0f, 0.0f, mXScale); - info->addMotionRange(AINPUT_MOTION_RANGE_Y, -1.0f, 1.0f, 0.0f, mYScale); + if (mParameters.mode == Parameters::MODE_POINTER) { + float minX, minY, maxX, maxY; + if (mPointerController->getBounds(&minX, &minY, &maxX, &maxY)) { + info->addMotionRange(AINPUT_MOTION_RANGE_X, minX, maxX, 0.0f, 0.0f); + info->addMotionRange(AINPUT_MOTION_RANGE_Y, minY, maxY, 0.0f, 0.0f); + } + } else { + info->addMotionRange(AINPUT_MOTION_RANGE_X, -1.0f, 1.0f, 0.0f, mXScale); + info->addMotionRange(AINPUT_MOTION_RANGE_Y, -1.0f, 1.0f, 0.0f, mYScale); + } + info->addMotionRange(AINPUT_MOTION_RANGE_PRESSURE, 0.0f, 1.0f, 0.0f, 0.0f); } -void TrackballInputMapper::dump(String8& dump) { +void CursorInputMapper::dump(String8& dump) { { // acquire lock AutoMutex _l(mLock); - dump.append(INDENT2 "Trackball Input Mapper:\n"); + dump.append(INDENT2 "Cursor Input Mapper:\n"); dumpParameters(dump); dump.appendFormat(INDENT3 "XPrecision: %0.3f\n", mXPrecision); dump.appendFormat(INDENT3 "YPrecision: %0.3f\n", mYPrecision); @@ -1021,37 +1025,79 @@ void TrackballInputMapper::dump(String8& dump) { } // release lock } -void TrackballInputMapper::configure() { +void CursorInputMapper::configure() { InputMapper::configure(); // Configure basic parameters. configureParameters(); + + // Configure device mode. + switch (mParameters.mode) { + case Parameters::MODE_POINTER: + mSources = AINPUT_SOURCE_MOUSE; + mXPrecision = 1.0f; + mYPrecision = 1.0f; + mXScale = 1.0f; + mYScale = 1.0f; + mPointerController = getPolicy()->obtainPointerController(getDeviceId()); + break; + case Parameters::MODE_NAVIGATION: + mSources = AINPUT_SOURCE_TRACKBALL; + mXPrecision = TRACKBALL_MOVEMENT_THRESHOLD; + mYPrecision = TRACKBALL_MOVEMENT_THRESHOLD; + mXScale = 1.0f / TRACKBALL_MOVEMENT_THRESHOLD; + mYScale = 1.0f / TRACKBALL_MOVEMENT_THRESHOLD; + break; + } } -void TrackballInputMapper::configureParameters() { +void CursorInputMapper::configureParameters() { + mParameters.mode = Parameters::MODE_POINTER; + String8 cursorModeString; + if (getDevice()->getConfiguration().tryGetProperty(String8("cursor.mode"), cursorModeString)) { + if (cursorModeString == "navigation") { + mParameters.mode = Parameters::MODE_NAVIGATION; + } else if (cursorModeString != "pointer" && cursorModeString != "default") { + LOGW("Invalid value for cursor.mode: '%s'", cursorModeString.string()); + } + } + mParameters.orientationAware = false; - getDevice()->getConfiguration().tryGetProperty(String8("trackball.orientationAware"), + getDevice()->getConfiguration().tryGetProperty(String8("cursor.orientationAware"), mParameters.orientationAware); - mParameters.associatedDisplayId = mParameters.orientationAware ? 0 : -1; + mParameters.associatedDisplayId = mParameters.mode == Parameters::MODE_POINTER + || mParameters.orientationAware ? 0 : -1; } -void TrackballInputMapper::dumpParameters(String8& dump) { +void CursorInputMapper::dumpParameters(String8& dump) { dump.append(INDENT3 "Parameters:\n"); dump.appendFormat(INDENT4 "AssociatedDisplayId: %d\n", mParameters.associatedDisplayId); + + switch (mParameters.mode) { + case Parameters::MODE_POINTER: + dump.append(INDENT4 "Mode: pointer\n"); + break; + case Parameters::MODE_NAVIGATION: + dump.append(INDENT4 "Mode: navigation\n"); + break; + default: + assert(false); + } + dump.appendFormat(INDENT4 "OrientationAware: %s\n", toString(mParameters.orientationAware)); } -void TrackballInputMapper::initializeLocked() { +void CursorInputMapper::initializeLocked() { mAccumulator.clear(); mLocked.down = false; mLocked.downTime = 0; } -void TrackballInputMapper::reset() { +void CursorInputMapper::reset() { for (;;) { { // acquire lock AutoMutex _l(mLock); @@ -1062,7 +1108,7 @@ void TrackballInputMapper::reset() { } } // release lock - // Synthesize trackball button up event on reset. + // Synthesize button up event on reset. nsecs_t when = systemTime(SYSTEM_TIME_MONOTONIC); mAccumulator.fields = Accumulator::FIELD_BTN_MOUSE; mAccumulator.btnMouse = false; @@ -1072,7 +1118,7 @@ void TrackballInputMapper::reset() { InputMapper::reset(); } -void TrackballInputMapper::process(const RawEvent* rawEvent) { +void CursorInputMapper::process(const RawEvent* rawEvent) { switch (rawEvent->type) { case EV_KEY: switch (rawEvent->scanCode) { @@ -1109,7 +1155,7 @@ void TrackballInputMapper::process(const RawEvent* rawEvent) { } } -void TrackballInputMapper::sync(nsecs_t when) { +void CursorInputMapper::sync(nsecs_t when) { uint32_t fields = mAccumulator.fields; if (fields == 0) { return; // no new state changes, so nothing to do @@ -1133,8 +1179,8 @@ void TrackballInputMapper::sync(nsecs_t when) { } downTime = mLocked.downTime; - float x = fields & Accumulator::FIELD_REL_X ? mAccumulator.relX * mXScale : 0.0f; - float y = fields & Accumulator::FIELD_REL_Y ? mAccumulator.relY * mYScale : 0.0f; + float deltaX = fields & Accumulator::FIELD_REL_X ? mAccumulator.relX * mXScale : 0.0f; + float deltaY = fields & Accumulator::FIELD_REL_Y ? mAccumulator.relY * mYScale : 0.0f; if (downChanged) { motionEventAction = mLocked.down ? AMOTION_EVENT_ACTION_DOWN : AMOTION_EVENT_ACTION_UP; @@ -1142,18 +1188,8 @@ void TrackballInputMapper::sync(nsecs_t when) { motionEventAction = AMOTION_EVENT_ACTION_MOVE; } - pointerCoords.x = x; - pointerCoords.y = y; - pointerCoords.pressure = mLocked.down ? 1.0f : 0.0f; - pointerCoords.size = 0; - pointerCoords.touchMajor = 0; - pointerCoords.touchMinor = 0; - pointerCoords.toolMajor = 0; - pointerCoords.toolMinor = 0; - pointerCoords.orientation = 0; - if (mParameters.orientationAware && mParameters.associatedDisplayId >= 0 - && (x != 0.0f || y != 0.0f)) { + && (deltaX != 0.0f || deltaY != 0.0f)) { // Rotate motion based on display orientation if needed. // Note: getDisplayInfo is non-reentrant so we can continue holding the lock. int32_t orientation; @@ -1165,35 +1201,54 @@ void TrackballInputMapper::sync(nsecs_t when) { float temp; switch (orientation) { case InputReaderPolicyInterface::ROTATION_90: - temp = pointerCoords.x; - pointerCoords.x = pointerCoords.y; - pointerCoords.y = - temp; + temp = deltaX; + deltaX = deltaY; + deltaY = -temp; break; case InputReaderPolicyInterface::ROTATION_180: - pointerCoords.x = - pointerCoords.x; - pointerCoords.y = - pointerCoords.y; + deltaX = -deltaX; + deltaY = -deltaY; break; case InputReaderPolicyInterface::ROTATION_270: - temp = pointerCoords.x; - pointerCoords.x = - pointerCoords.y; - pointerCoords.y = temp; + temp = deltaX; + deltaX = -deltaY; + deltaY = temp; break; } } + + if (mPointerController != NULL) { + mPointerController->move(deltaX, deltaY); + if (downChanged) { + mPointerController->setButtonState(mLocked.down ? POINTER_BUTTON_1 : 0); + } + mPointerController->getPosition(&pointerCoords.x, &pointerCoords.y); + } else { + pointerCoords.x = deltaX; + pointerCoords.y = deltaY; + } + + pointerCoords.pressure = mLocked.down ? 1.0f : 0.0f; + pointerCoords.size = 0; + pointerCoords.touchMajor = 0; + pointerCoords.touchMinor = 0; + pointerCoords.toolMajor = 0; + pointerCoords.toolMinor = 0; + pointerCoords.orientation = 0; } // release lock int32_t metaState = mContext->getGlobalMetaState(); int32_t pointerId = 0; - getDispatcher()->notifyMotion(when, getDeviceId(), AINPUT_SOURCE_TRACKBALL, 0, + getDispatcher()->notifyMotion(when, getDeviceId(), mSources, 0, motionEventAction, 0, metaState, AMOTION_EVENT_EDGE_FLAG_NONE, 1, &pointerId, &pointerCoords, mXPrecision, mYPrecision, downTime); mAccumulator.clear(); } -int32_t TrackballInputMapper::getScanCodeState(uint32_t sourceMask, int32_t scanCode) { +int32_t CursorInputMapper::getScanCodeState(uint32_t sourceMask, int32_t scanCode) { if (scanCode >= BTN_MOUSE && scanCode < BTN_JOYSTICK) { return getEventHub()->getScanCodeState(getDeviceId(), scanCode); } else { @@ -1217,15 +1272,7 @@ TouchInputMapper::~TouchInputMapper() { } uint32_t TouchInputMapper::getSources() { - switch (mParameters.deviceType) { - case Parameters::DEVICE_TYPE_TOUCH_SCREEN: - return AINPUT_SOURCE_TOUCHSCREEN; - case Parameters::DEVICE_TYPE_TOUCH_PAD: - return AINPUT_SOURCE_TOUCHPAD; - default: - assert(false); - return AINPUT_SOURCE_UNKNOWN; - } + return mSources; } void TouchInputMapper::populateDeviceInfo(InputDeviceInfo* info) { @@ -1326,6 +1373,18 @@ void TouchInputMapper::configure() { // Configure basic parameters. configureParameters(); + // Configure sources. + switch (mParameters.deviceType) { + case Parameters::DEVICE_TYPE_TOUCH_SCREEN: + mSources = AINPUT_SOURCE_TOUCHSCREEN; + break; + case Parameters::DEVICE_TYPE_TOUCH_PAD: + mSources = AINPUT_SOURCE_TOUCHPAD; + break; + default: + assert(false); + } + // Configure absolute axis information. configureRawAxes(); @@ -2560,7 +2619,7 @@ void TouchInputMapper::dispatchTouch(nsecs_t when, uint32_t policyFlags, yPrecision = mLocked.orientedYPrecision; } // release lock - getDispatcher()->notifyMotion(when, getDeviceId(), getSources(), policyFlags, + getDispatcher()->notifyMotion(when, getDeviceId(), mSources, policyFlags, motionEventAction, 0, getContext()->getGlobalMetaState(), motionEventEdgeFlags, pointerCount, pointerIds, pointerCoords, xPrecision, yPrecision, mDownTime); diff --git a/libs/ui/tests/InputReader_test.cpp b/libs/ui/tests/InputReader_test.cpp index 97cbc25..50d3383 100644 --- a/libs/ui/tests/InputReader_test.cpp +++ b/libs/ui/tests/InputReader_test.cpp @@ -30,6 +30,56 @@ static inline float avg(float x, float y) { } +// --- FakePointerController --- + +class FakePointerController : public PointerControllerInterface { + bool mHaveBounds; + float mMinX, mMinY, mMaxX, mMaxY; + +protected: + virtual ~FakePointerController() { } + +public: + FakePointerController() { + } + + void setBounds(float minX, float minY, float maxX, float maxY) { + mHaveBounds = true; + mMinX = minX; + mMinY = minY; + mMaxX = maxX; + mMaxY = maxY; + } + +private: + virtual bool getBounds(float* outMinX, float* outMinY, float* outMaxX, float* outMaxY) const { + *outMinX = mMinX; + *outMaxX = mMinX; + *outMinY = mMinY; + *outMaxY = mMaxY; + return mHaveBounds; + } + + virtual void move(float deltaX, float deltaY) { + } + + virtual void setButtonState(uint32_t buttonState) { + } + + virtual uint32_t getButtonState() const { + return 0; + } + + virtual void setPosition(float x, float y) { + } + + virtual void getPosition(float* outX, float* outY) const { + *outX = 0; + *outY = 0; + } +}; + + // --- FakeInputReaderPolicy --- class FakeInputReaderPolicy : public InputReaderPolicyInterface { @@ -43,6 +93,7 @@ class FakeInputReaderPolicy : public InputReaderPolicyInterface { bool mFilterTouchEvents; bool mFilterJumpyTouchEvents; Vector<String8> mExcludedDeviceNames; + KeyedVector<int32_t, sp<FakePointerController> > mPointerControllers; protected: virtual ~FakeInputReaderPolicy() { } @@ -78,6 +129,10 @@ public: mExcludedDeviceNames.push(deviceName); } + void setPointerController(int32_t deviceId, const sp<FakePointerController>& controller) { + mPointerControllers.add(deviceId, controller); + } + private: virtual bool getDisplayInfo(int32_t displayId, int32_t* width, int32_t* height, int32_t* orientation) { @@ -109,6 +164,10 @@ private: virtual void getExcludedDeviceNames(Vector<String8>& outExcludedDeviceNames) { outExcludedDeviceNames.appendVector(mExcludedDeviceNames); } + + virtual sp<PointerControllerInterface> obtainPointerController(int32_t deviceId) { + return mPointerControllers.valueFor(deviceId); + } }; @@ -381,6 +440,11 @@ public: device->configuration.addProperty(key, value); } + void addConfigurationMap(int32_t deviceId, const PropertyMap* configuration) { + Device* device = getDevice(deviceId); + device->configuration.addAll(configuration); + } + void addAxis(int32_t deviceId, int axis, int32_t minValue, int32_t maxValue, int flat, int fuzz) { Device* device = getDevice(deviceId); @@ -851,8 +915,12 @@ protected: mFakeEventHub.clear(); } - void addDevice(int32_t deviceId, const String8& name, uint32_t classes) { + void addDevice(int32_t deviceId, const String8& name, uint32_t classes, + const PropertyMap* configuration) { mFakeEventHub->addDevice(deviceId, name, classes); + if (configuration) { + mFakeEventHub->addConfigurationMap(deviceId, configuration); + } mFakeEventHub->finishDeviceScan(); mReader->loopOnce(); mReader->loopOnce(); @@ -860,12 +928,13 @@ protected: } FakeInputMapper* addDeviceWithFakeInputMapper(int32_t deviceId, - const String8& name, uint32_t classes, uint32_t sources) { + const String8& name, uint32_t classes, uint32_t sources, + const PropertyMap* configuration) { InputDevice* device = new InputDevice(mReader.get(), deviceId, name); FakeInputMapper* mapper = new FakeInputMapper(device, sources); device->addMapper(mapper); mReader->setNextDevice(device); - addDevice(deviceId, name, classes); + addDevice(deviceId, name, classes, configuration); return mapper; } }; @@ -881,7 +950,7 @@ TEST_F(InputReaderTest, GetInputConfiguration_WhenNoDevices_ReturnsDefaults) { TEST_F(InputReaderTest, GetInputConfiguration_WhenAlphabeticKeyboardPresent_ReturnsQwertyKeyboard) { ASSERT_NO_FATAL_FAILURE(addDevice(0, String8("keyboard"), - INPUT_DEVICE_CLASS_KEYBOARD | INPUT_DEVICE_CLASS_ALPHAKEY)); + INPUT_DEVICE_CLASS_KEYBOARD | INPUT_DEVICE_CLASS_ALPHAKEY, NULL)); InputConfiguration config; mReader->getInputConfiguration(&config); @@ -893,7 +962,7 @@ TEST_F(InputReaderTest, GetInputConfiguration_WhenAlphabeticKeyboardPresent_Retu TEST_F(InputReaderTest, GetInputConfiguration_WhenTouchScreenPresent_ReturnsFingerTouchScreen) { ASSERT_NO_FATAL_FAILURE(addDevice(0, String8("touchscreen"), - INPUT_DEVICE_CLASS_TOUCHSCREEN)); + INPUT_DEVICE_CLASS_TOUCHSCREEN, NULL)); InputConfiguration config; mReader->getInputConfiguration(&config); @@ -903,9 +972,25 @@ TEST_F(InputReaderTest, GetInputConfiguration_WhenTouchScreenPresent_ReturnsFing ASSERT_EQ(InputConfiguration::TOUCHSCREEN_FINGER, config.touchScreen); } +TEST_F(InputReaderTest, GetInputConfiguration_WhenMousePresent_ReturnsNoNavigation) { + PropertyMap configuration; + configuration.addProperty(String8("cursor.mode"), String8("pointer")); + ASSERT_NO_FATAL_FAILURE(addDevice(0, String8("mouse"), + INPUT_DEVICE_CLASS_CURSOR, &configuration)); + + InputConfiguration config; + mReader->getInputConfiguration(&config); + + ASSERT_EQ(InputConfiguration::KEYBOARD_NOKEYS, config.keyboard); + ASSERT_EQ(InputConfiguration::NAVIGATION_NONAV, config.navigation); + ASSERT_EQ(InputConfiguration::TOUCHSCREEN_NOTOUCH, config.touchScreen); +} + TEST_F(InputReaderTest, GetInputConfiguration_WhenTrackballPresent_ReturnsTrackballNavigation) { + PropertyMap configuration; + configuration.addProperty(String8("cursor.mode"), String8("navigation")); ASSERT_NO_FATAL_FAILURE(addDevice(0, String8("trackball"), - INPUT_DEVICE_CLASS_TRACKBALL)); + INPUT_DEVICE_CLASS_CURSOR, &configuration)); InputConfiguration config; mReader->getInputConfiguration(&config); @@ -917,7 +1002,7 @@ TEST_F(InputReaderTest, GetInputConfiguration_WhenTrackballPresent_ReturnsTrackb TEST_F(InputReaderTest, GetInputConfiguration_WhenDPadPresent_ReturnsDPadNavigation) { ASSERT_NO_FATAL_FAILURE(addDevice(0, String8("dpad"), - INPUT_DEVICE_CLASS_DPAD)); + INPUT_DEVICE_CLASS_DPAD, NULL)); InputConfiguration config; mReader->getInputConfiguration(&config); @@ -929,7 +1014,7 @@ TEST_F(InputReaderTest, GetInputConfiguration_WhenDPadPresent_ReturnsDPadNavigat TEST_F(InputReaderTest, GetInputDeviceInfo_WhenDeviceIdIsValid) { ASSERT_NO_FATAL_FAILURE(addDevice(1, String8("keyboard"), - INPUT_DEVICE_CLASS_KEYBOARD)); + INPUT_DEVICE_CLASS_KEYBOARD, NULL)); InputDeviceInfo info; status_t result = mReader->getInputDeviceInfo(1, &info); @@ -950,7 +1035,7 @@ TEST_F(InputReaderTest, GetInputDeviceInfo_WhenDeviceIdIsInvalid) { } TEST_F(InputReaderTest, GetInputDeviceInfo_WhenDeviceIdIsIgnored) { - addDevice(1, String8("ignored"), 0); // no classes so device will be ignored + addDevice(1, String8("ignored"), 0, NULL); // no classes so device will be ignored InputDeviceInfo info; status_t result = mReader->getInputDeviceInfo(1, &info); @@ -960,9 +1045,9 @@ TEST_F(InputReaderTest, GetInputDeviceInfo_WhenDeviceIdIsIgnored) { TEST_F(InputReaderTest, GetInputDeviceIds) { ASSERT_NO_FATAL_FAILURE(addDevice(1, String8("keyboard"), - INPUT_DEVICE_CLASS_KEYBOARD | INPUT_DEVICE_CLASS_ALPHAKEY)); - ASSERT_NO_FATAL_FAILURE(addDevice(2, String8("trackball"), - INPUT_DEVICE_CLASS_TRACKBALL)); + INPUT_DEVICE_CLASS_KEYBOARD | INPUT_DEVICE_CLASS_ALPHAKEY, NULL)); + ASSERT_NO_FATAL_FAILURE(addDevice(2, String8("mouse"), + INPUT_DEVICE_CLASS_CURSOR, NULL)); Vector<int32_t> ids; mReader->getInputDeviceIds(ids); @@ -975,7 +1060,7 @@ TEST_F(InputReaderTest, GetInputDeviceIds) { TEST_F(InputReaderTest, GetKeyCodeState_ForwardsRequestsToMappers) { FakeInputMapper* mapper = NULL; ASSERT_NO_FATAL_FAILURE(mapper = addDeviceWithFakeInputMapper(1, String8("fake"), - INPUT_DEVICE_CLASS_KEYBOARD, AINPUT_SOURCE_KEYBOARD)); + INPUT_DEVICE_CLASS_KEYBOARD, AINPUT_SOURCE_KEYBOARD, NULL)); mapper->setKeyCodeState(AKEYCODE_A, AKEY_STATE_DOWN); ASSERT_EQ(AKEY_STATE_UNKNOWN, mReader->getKeyCodeState(0, @@ -1002,7 +1087,7 @@ TEST_F(InputReaderTest, GetKeyCodeState_ForwardsRequestsToMappers) { TEST_F(InputReaderTest, GetScanCodeState_ForwardsRequestsToMappers) { FakeInputMapper* mapper = NULL; ASSERT_NO_FATAL_FAILURE(mapper = addDeviceWithFakeInputMapper(1, String8("fake"), - INPUT_DEVICE_CLASS_KEYBOARD, AINPUT_SOURCE_KEYBOARD)); + INPUT_DEVICE_CLASS_KEYBOARD, AINPUT_SOURCE_KEYBOARD, NULL)); mapper->setScanCodeState(KEY_A, AKEY_STATE_DOWN); ASSERT_EQ(AKEY_STATE_UNKNOWN, mReader->getScanCodeState(0, @@ -1029,7 +1114,7 @@ TEST_F(InputReaderTest, GetScanCodeState_ForwardsRequestsToMappers) { TEST_F(InputReaderTest, GetSwitchState_ForwardsRequestsToMappers) { FakeInputMapper* mapper = NULL; ASSERT_NO_FATAL_FAILURE(mapper = addDeviceWithFakeInputMapper(1, String8("fake"), - INPUT_DEVICE_CLASS_KEYBOARD, AINPUT_SOURCE_KEYBOARD)); + INPUT_DEVICE_CLASS_KEYBOARD, AINPUT_SOURCE_KEYBOARD, NULL)); mapper->setSwitchState(SW_LID, AKEY_STATE_DOWN); ASSERT_EQ(AKEY_STATE_UNKNOWN, mReader->getSwitchState(0, @@ -1056,7 +1141,7 @@ TEST_F(InputReaderTest, GetSwitchState_ForwardsRequestsToMappers) { TEST_F(InputReaderTest, MarkSupportedKeyCodes_ForwardsRequestsToMappers) { FakeInputMapper* mapper = NULL; ASSERT_NO_FATAL_FAILURE(mapper = addDeviceWithFakeInputMapper(1, String8("fake"), - INPUT_DEVICE_CLASS_KEYBOARD, AINPUT_SOURCE_KEYBOARD)); + INPUT_DEVICE_CLASS_KEYBOARD, AINPUT_SOURCE_KEYBOARD, NULL)); mapper->addSupportedKeyCode(AKEYCODE_A); mapper->addSupportedKeyCode(AKEYCODE_B); @@ -1089,7 +1174,7 @@ TEST_F(InputReaderTest, MarkSupportedKeyCodes_ForwardsRequestsToMappers) { } TEST_F(InputReaderTest, LoopOnce_WhenDeviceScanFinished_SendsConfigurationChanged) { - addDevice(1, String8("ignored"), INPUT_DEVICE_CLASS_KEYBOARD); + addDevice(1, String8("ignored"), INPUT_DEVICE_CLASS_KEYBOARD, NULL); FakeInputDispatcher::NotifyConfigurationChangedArgs args; ASSERT_NO_FATAL_FAILURE(mFakeDispatcher->assertNotifyConfigurationChangedWasCalled(&args)); @@ -1099,7 +1184,7 @@ TEST_F(InputReaderTest, LoopOnce_WhenDeviceScanFinished_SendsConfigurationChange TEST_F(InputReaderTest, LoopOnce_ForwardsRawEventsToMappers) { FakeInputMapper* mapper = NULL; ASSERT_NO_FATAL_FAILURE(mapper = addDeviceWithFakeInputMapper(1, String8("fake"), - INPUT_DEVICE_CLASS_KEYBOARD, AINPUT_SOURCE_KEYBOARD)); + INPUT_DEVICE_CLASS_KEYBOARD, AINPUT_SOURCE_KEYBOARD, NULL)); mFakeEventHub->enqueueEvent(0, 1, EV_KEY, KEY_A, AKEYCODE_A, 1, POLICY_FLAG_WAKE); mReader->loopOnce(); @@ -1792,19 +1877,28 @@ TEST_F(KeyboardInputMapperTest, Process_LockedKeysShouldToggleMetaStateAndLeds) } -// --- TrackballInputMapperTest --- +// --- CursorInputMapperTest --- -class TrackballInputMapperTest : public InputMapperTest { +class CursorInputMapperTest : public InputMapperTest { protected: static const int32_t TRACKBALL_MOVEMENT_THRESHOLD; - void testMotionRotation(TrackballInputMapper* mapper, + sp<FakePointerController> mFakePointerController; + + virtual void SetUp() { + InputMapperTest::SetUp(); + + mFakePointerController = new FakePointerController(); + mFakePolicy->setPointerController(DEVICE_ID, mFakePointerController); + } + + void testMotionRotation(CursorInputMapper* mapper, int32_t originalX, int32_t originalY, int32_t rotatedX, int32_t rotatedY); }; -const int32_t TrackballInputMapperTest::TRACKBALL_MOVEMENT_THRESHOLD = 6; +const int32_t CursorInputMapperTest::TRACKBALL_MOVEMENT_THRESHOLD = 6; -void TrackballInputMapperTest::testMotionRotation(TrackballInputMapper* mapper, +void CursorInputMapperTest::testMotionRotation(CursorInputMapper* mapper, int32_t originalX, int32_t originalY, int32_t rotatedX, int32_t rotatedY) { FakeInputDispatcher::NotifyMotionArgs args; @@ -1819,15 +1913,53 @@ void TrackballInputMapperTest::testMotionRotation(TrackballInputMapper* mapper, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f)); } -TEST_F(TrackballInputMapperTest, GetSources) { - TrackballInputMapper* mapper = new TrackballInputMapper(mDevice); +TEST_F(CursorInputMapperTest, WhenModeIsPointer_GetSources_ReturnsMouse) { + CursorInputMapper* mapper = new CursorInputMapper(mDevice); + addConfigurationProperty("cursor.mode", "pointer"); + addMapperAndConfigure(mapper); + + ASSERT_EQ(AINPUT_SOURCE_MOUSE, mapper->getSources()); +} + +TEST_F(CursorInputMapperTest, WhenModeIsNavigation_GetSources_ReturnsTrackball) { + CursorInputMapper* mapper = new CursorInputMapper(mDevice); + addConfigurationProperty("cursor.mode", "navigation"); addMapperAndConfigure(mapper); ASSERT_EQ(AINPUT_SOURCE_TRACKBALL, mapper->getSources()); } -TEST_F(TrackballInputMapperTest, PopulateDeviceInfo) { - TrackballInputMapper* mapper = new TrackballInputMapper(mDevice); +TEST_F(CursorInputMapperTest, WhenModeIsPointer_PopulateDeviceInfo_ReturnsRangeFromPointerController) { + CursorInputMapper* mapper = new CursorInputMapper(mDevice); + addConfigurationProperty("cursor.mode", "pointer"); + addMapperAndConfigure(mapper); + + InputDeviceInfo info; + mapper->populateDeviceInfo(&info); + + // Initially there may not be a valid motion range. + ASSERT_EQ(NULL, info.getMotionRange(AINPUT_MOTION_RANGE_X)); + ASSERT_EQ(NULL, info.getMotionRange(AINPUT_MOTION_RANGE_Y)); + ASSERT_NO_FATAL_FAILURE(assertMotionRange(info, AINPUT_MOTION_RANGE_PRESSURE, + 0.0f, 1.0f, 0.0f, 1.0f)); + + // When the bounds are set, then there should be a valid motion range. + mFakePointerController->setBounds(1, 2, 800, 480); + + InputDeviceInfo info2; + mapper->populateDeviceInfo(&info2); + + ASSERT_NO_FATAL_FAILURE(assertMotionRange(info2, AINPUT_MOTION_RANGE_X, + 1, 800, 0.0f, 1.0f)); + ASSERT_NO_FATAL_FAILURE(assertMotionRange(info2, AINPUT_MOTION_RANGE_Y, + 2, 480, 0.0f, 1.0f)); + ASSERT_NO_FATAL_FAILURE(assertMotionRange(info2, AINPUT_MOTION_RANGE_PRESSURE, + 0.0f, 1.0f, 0.0f, 1.0f)); +} + +TEST_F(CursorInputMapperTest, WhenModeIsNavigation_PopulateDeviceInfo_ReturnsScaledRange) { + CursorInputMapper* mapper = new CursorInputMapper(mDevice); + addConfigurationProperty("cursor.mode", "navigation"); addMapperAndConfigure(mapper); InputDeviceInfo info; @@ -1839,8 +1971,9 @@ TEST_F(TrackballInputMapperTest, PopulateDeviceInfo) { -1.0f, 1.0f, 0.0f, 1.0f / TRACKBALL_MOVEMENT_THRESHOLD)); } -TEST_F(TrackballInputMapperTest, Process_ShouldSetAllFieldsAndIncludeGlobalMetaState) { - TrackballInputMapper* mapper = new TrackballInputMapper(mDevice); +TEST_F(CursorInputMapperTest, Process_ShouldSetAllFieldsAndIncludeGlobalMetaState) { + CursorInputMapper* mapper = new CursorInputMapper(mDevice); + addConfigurationProperty("cursor.mode", "navigation"); addMapperAndConfigure(mapper); mFakeContext->setGlobalMetaState(AMETA_SHIFT_LEFT_ON | AMETA_SHIFT_ON); @@ -1887,8 +2020,9 @@ TEST_F(TrackballInputMapperTest, Process_ShouldSetAllFieldsAndIncludeGlobalMetaS ASSERT_EQ(ARBITRARY_TIME, args.downTime); } -TEST_F(TrackballInputMapperTest, Process_ShouldHandleIndependentXYUpdates) { - TrackballInputMapper* mapper = new TrackballInputMapper(mDevice); +TEST_F(CursorInputMapperTest, Process_ShouldHandleIndependentXYUpdates) { + CursorInputMapper* mapper = new CursorInputMapper(mDevice); + addConfigurationProperty("cursor.mode", "navigation"); addMapperAndConfigure(mapper); FakeInputDispatcher::NotifyMotionArgs args; @@ -1911,8 +2045,9 @@ TEST_F(TrackballInputMapperTest, Process_ShouldHandleIndependentXYUpdates) { 0.0f, -2.0f / TRACKBALL_MOVEMENT_THRESHOLD, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f)); } -TEST_F(TrackballInputMapperTest, Process_ShouldHandleIndependentButtonUpdates) { - TrackballInputMapper* mapper = new TrackballInputMapper(mDevice); +TEST_F(CursorInputMapperTest, Process_ShouldHandleIndependentButtonUpdates) { + CursorInputMapper* mapper = new CursorInputMapper(mDevice); + addConfigurationProperty("cursor.mode", "navigation"); addMapperAndConfigure(mapper); FakeInputDispatcher::NotifyMotionArgs args; @@ -1932,8 +2067,9 @@ TEST_F(TrackballInputMapperTest, Process_ShouldHandleIndependentButtonUpdates) { 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f)); } -TEST_F(TrackballInputMapperTest, Process_ShouldHandleCombinedXYAndButtonUpdates) { - TrackballInputMapper* mapper = new TrackballInputMapper(mDevice); +TEST_F(CursorInputMapperTest, Process_ShouldHandleCombinedXYAndButtonUpdates) { + CursorInputMapper* mapper = new CursorInputMapper(mDevice); + addConfigurationProperty("cursor.mode", "navigation"); addMapperAndConfigure(mapper); FakeInputDispatcher::NotifyMotionArgs args; @@ -1967,8 +2103,9 @@ TEST_F(TrackballInputMapperTest, Process_ShouldHandleCombinedXYAndButtonUpdates) 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f)); } -TEST_F(TrackballInputMapperTest, Reset_WhenButtonIsNotDown_ShouldNotSynthesizeButtonUp) { - TrackballInputMapper* mapper = new TrackballInputMapper(mDevice); +TEST_F(CursorInputMapperTest, Reset_WhenButtonIsNotDown_ShouldNotSynthesizeButtonUp) { + CursorInputMapper* mapper = new CursorInputMapper(mDevice); + addConfigurationProperty("cursor.mode", "navigation"); addMapperAndConfigure(mapper); FakeInputDispatcher::NotifyMotionArgs args; @@ -1987,8 +2124,9 @@ TEST_F(TrackballInputMapperTest, Reset_WhenButtonIsNotDown_ShouldNotSynthesizeBu ASSERT_NO_FATAL_FAILURE(mFakeDispatcher->assertNotifyMotionWasNotCalled()); } -TEST_F(TrackballInputMapperTest, Reset_WhenButtonIsDown_ShouldSynthesizeButtonUp) { - TrackballInputMapper* mapper = new TrackballInputMapper(mDevice); +TEST_F(CursorInputMapperTest, Reset_WhenButtonIsDown_ShouldSynthesizeButtonUp) { + CursorInputMapper* mapper = new CursorInputMapper(mDevice); + addConfigurationProperty("cursor.mode", "navigation"); addMapperAndConfigure(mapper); FakeInputDispatcher::NotifyMotionArgs args; @@ -2006,8 +2144,9 @@ TEST_F(TrackballInputMapperTest, Reset_WhenButtonIsDown_ShouldSynthesizeButtonUp 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f)); } -TEST_F(TrackballInputMapperTest, Process_WhenNotOrientationAware_ShouldNotRotateMotions) { - TrackballInputMapper* mapper = new TrackballInputMapper(mDevice); +TEST_F(CursorInputMapperTest, Process_WhenNotOrientationAware_ShouldNotRotateMotions) { + CursorInputMapper* mapper = new CursorInputMapper(mDevice); + addConfigurationProperty("cursor.mode", "navigation"); addMapperAndConfigure(mapper); mFakePolicy->setDisplayInfo(DISPLAY_ID, @@ -2023,9 +2162,10 @@ TEST_F(TrackballInputMapperTest, Process_WhenNotOrientationAware_ShouldNotRotate ASSERT_NO_FATAL_FAILURE(testMotionRotation(mapper, -1, 1, -1, 1)); } -TEST_F(TrackballInputMapperTest, Process_WhenOrientationAware_ShouldRotateMotions) { - TrackballInputMapper* mapper = new TrackballInputMapper(mDevice); - addConfigurationProperty("trackball.orientationAware", "1"); +TEST_F(CursorInputMapperTest, Process_WhenOrientationAware_ShouldRotateMotions) { + CursorInputMapper* mapper = new CursorInputMapper(mDevice); + addConfigurationProperty("cursor.mode", "navigation"); + addConfigurationProperty("cursor.orientationAware", "1"); addMapperAndConfigure(mapper); mFakePolicy->setDisplayInfo(DISPLAY_ID, diff --git a/libs/utils/PropertyMap.cpp b/libs/utils/PropertyMap.cpp index fd7edec..d472d45 100644 --- a/libs/utils/PropertyMap.cpp +++ b/libs/utils/PropertyMap.cpp @@ -109,6 +109,12 @@ bool PropertyMap::tryGetProperty(const String8& key, float& outValue) const { return true; } +void PropertyMap::addAll(const PropertyMap* map) { + for (size_t i = 0; i < map->mProperties.size(); i++) { + mProperties.add(map->mProperties.keyAt(i), map->mProperties.valueAt(i)); + } +} + status_t PropertyMap::load(const String8& filename, PropertyMap** outMap) { *outMap = NULL; diff --git a/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java b/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java index 2e89a21..281ac2e 100755 --- a/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java +++ b/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java @@ -112,6 +112,7 @@ import static android.view.WindowManager.LayoutParams.TYPE_INPUT_METHOD_DIALOG; import static android.view.WindowManager.LayoutParams.TYPE_SYSTEM_OVERLAY; import static android.view.WindowManager.LayoutParams.TYPE_TOAST; import static android.view.WindowManager.LayoutParams.TYPE_WALLPAPER; +import static android.view.WindowManager.LayoutParams.TYPE_POINTER; import android.view.WindowManagerImpl; import android.view.WindowManagerPolicy; import android.view.animation.Animation; @@ -176,6 +177,8 @@ public class PhoneWindowManager implements WindowManagerPolicy { // things in here CAN NOT take focus, but are shown on top of everything else. static final int SYSTEM_OVERLAY_LAYER = 18; static final int SECURE_SYSTEM_OVERLAY_LAYER = 19; + // the (mouse) pointer layer + static final int POINTER_LAYER = 20; static final int APPLICATION_MEDIA_SUBLAYER = -2; static final int APPLICATION_MEDIA_OVERLAY_SUBLAYER = -1; @@ -950,6 +953,8 @@ public class PhoneWindowManager implements WindowManagerPolicy { return WALLPAPER_LAYER; case TYPE_DRAG: return DRAG_LAYER; + case TYPE_POINTER: + return POINTER_LAYER; } Log.e(TAG, "Unknown window type: " + type); return APPLICATION_LAYER; diff --git a/services/java/com/android/server/InputManager.java b/services/java/com/android/server/InputManager.java index 4c499cd..b5becb5 100644 --- a/services/java/com/android/server/InputManager.java +++ b/services/java/com/android/server/InputManager.java @@ -32,6 +32,7 @@ import android.view.InputDevice; import android.view.InputEvent; import android.view.KeyEvent; import android.view.Surface; +import android.view.WindowManager; import java.io.BufferedReader; import java.io.File; @@ -475,5 +476,13 @@ public class InputManager { } return result; } + + @SuppressWarnings("unused") + public int getPointerLayer() { + return mWindowManagerService.mPolicy.windowTypeToLayerLw( + WindowManager.LayoutParams.TYPE_DRAG) + * WindowManagerService.TYPE_LAYER_MULTIPLIER + + WindowManagerService.TYPE_LAYER_OFFSET; + } } } diff --git a/services/jni/com_android_server_InputManager.cpp b/services/jni/com_android_server_InputManager.cpp index 9156249..c757ada 100644 --- a/services/jni/com_android_server_InputManager.cpp +++ b/services/jni/com_android_server_InputManager.cpp @@ -24,6 +24,10 @@ // Log debug messages about InputDispatcherPolicy #define DEBUG_INPUT_DISPATCHER_POLICY 0 +// Log debug messages about PointerController +#define DEBUG_POINTER_CONTROLLER 1 + + #include "JNIHelp.h" #include "jni.h" #include <limits.h> @@ -34,6 +38,10 @@ #include <ui/InputTransport.h> #include <utils/Log.h> #include <utils/threads.h> +#include <surfaceflinger/Surface.h> +#include <surfaceflinger/SurfaceComposerClient.h> +#include <surfaceflinger/ISurfaceComposer.h> + #include "../../core/jni/android_view_KeyEvent.h" #include "../../core/jni/android_view_MotionEvent.h" #include "../../core/jni/android_view_InputChannel.h" @@ -58,6 +66,7 @@ static struct { jmethodID filterJumpyTouchEvents; jmethodID getExcludedDeviceNames; jmethodID getMaxEventsPerSecond; + jmethodID getPointerLayer; } gCallbacksClassInfo; static struct { @@ -135,6 +144,52 @@ static inline nsecs_t now() { // ---------------------------------------------------------------------------- +class PointerController : public PointerControllerInterface { +protected: + virtual ~PointerController(); + +public: + PointerController(int32_t pointerLayer); + + virtual bool getBounds(float* outMinX, float* outMinY, + float* outMaxX, float* outMaxY) const; + virtual void move(float deltaX, float deltaY); + virtual void setButtonState(uint32_t buttonState); + virtual uint32_t getButtonState() const; + virtual void setPosition(float x, float y); + virtual void getPosition(float* outX, float* outY) const; + + void setDisplaySize(int32_t width, int32_t height); + void setDisplayOrientation(int32_t orientation); + +private: + mutable Mutex mLock; + + int32_t mPointerLayer; + sp<SurfaceComposerClient> mSurfaceComposerClient; + sp<SurfaceControl> mSurfaceControl; + + struct Locked { + int32_t displayWidth; + int32_t displayHeight; + int32_t displayOrientation; + + float pointerX; + float pointerY; + uint32_t buttonState; + + bool wantVisible; + bool visible; + bool drawn; + } mLocked; + + bool getBoundsLocked(float* outMinX, float* outMinY, float* outMaxX, float* outMaxY) const; + void setPositionLocked(float x, float y); + void updateLocked(); +}; + +// ---------------------------------------------------------------------------- + class NativeInputManager : public virtual RefBase, public virtual InputReaderPolicyInterface, public virtual InputDispatcherPolicyInterface { @@ -166,6 +221,7 @@ public: virtual bool filterTouchEvents(); virtual bool filterJumpyTouchEvents(); virtual void getExcludedDeviceNames(Vector<String8>& outExcludedDeviceNames); + virtual sp<PointerControllerInterface> obtainPointerController(int32_t deviceId); /* --- InputDispatcherPolicyInterface implementation --- */ @@ -215,19 +271,23 @@ private: // Cached throttling policy. int32_t mMaxEventsPerSecond; - // Cached display state. (lock mDisplayLock) - Mutex mDisplayLock; - int32_t mDisplayWidth, mDisplayHeight; - int32_t mDisplayOrientation; + Mutex mLock; + struct Locked { + // Display size information. + int32_t displayWidth, displayHeight; // -1 when initialized + int32_t displayOrientation; + + // Pointer controller singleton, created and destroyed as needed. + wp<PointerController> pointerController; + + // Weak references to all currently registered input channels by connection pointer. + KeyedVector<InputChannel*, jweak> inputChannelObjWeakTable; + } mLocked; // 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); @@ -243,12 +303,18 @@ private: NativeInputManager::NativeInputManager(jobject callbacksObj) : mFilterTouchEvents(-1), mFilterJumpyTouchEvents(-1), - mMaxEventsPerSecond(-1), - mDisplayWidth(-1), mDisplayHeight(-1), mDisplayOrientation(ROTATION_0) { + mMaxEventsPerSecond(-1) { JNIEnv* env = jniEnv(); mCallbacksObj = env->NewGlobalRef(callbacksObj); + { + AutoMutex _l(mLock); + mLocked.displayWidth = -1; + mLocked.displayHeight = -1; + mLocked.displayOrientation = ROTATION_0; + } + sp<EventHub> eventHub = new EventHub(); mInputManager = new InputManager(eventHub, this, this); } @@ -279,18 +345,32 @@ bool NativeInputManager::checkAndClearExceptionFromCallback(JNIEnv* env, const c void NativeInputManager::setDisplaySize(int32_t displayId, int32_t width, int32_t height) { if (displayId == 0) { - AutoMutex _l(mDisplayLock); + AutoMutex _l(mLock); - mDisplayWidth = width; - mDisplayHeight = height; + if (mLocked.displayWidth != width || mLocked.displayHeight != height) { + mLocked.displayWidth = width; + mLocked.displayHeight = height; + + sp<PointerController> controller = mLocked.pointerController.promote(); + if (controller != NULL) { + controller->setDisplaySize(width, height); + } + } } } void NativeInputManager::setDisplayOrientation(int32_t displayId, int32_t orientation) { if (displayId == 0) { - AutoMutex _l(mDisplayLock); + AutoMutex _l(mLock); + + if (mLocked.displayOrientation != orientation) { + mLocked.displayOrientation = orientation; - mDisplayOrientation = orientation; + sp<PointerController> controller = mLocked.pointerController.promote(); + if (controller != NULL) { + controller->setDisplayOrientation(orientation); + } + } } } @@ -305,9 +385,9 @@ status_t NativeInputManager::registerInputChannel(JNIEnv* env, status_t status; { - AutoMutex _l(mInputChannelRegistryLock); + AutoMutex _l(mLock); - ssize_t index = mInputChannelObjWeakTable.indexOfKey(inputChannel.get()); + ssize_t index = mLocked.inputChannelObjWeakTable.indexOfKey(inputChannel.get()); if (index >= 0) { LOGE("Input channel object '%s' has already been registered", inputChannel->getName().string()); @@ -315,7 +395,7 @@ status_t NativeInputManager::registerInputChannel(JNIEnv* env, goto DeleteWeakRef; } - mInputChannelObjWeakTable.add(inputChannel.get(), inputChannelObjWeak); + mLocked.inputChannelObjWeakTable.add(inputChannel.get(), inputChannelObjWeak); } status = mInputManager->getDispatcher()->registerInputChannel(inputChannel, monitor); @@ -326,8 +406,8 @@ status_t NativeInputManager::registerInputChannel(JNIEnv* env, // Failed! { - AutoMutex _l(mInputChannelRegistryLock); - mInputChannelObjWeakTable.removeItem(inputChannel.get()); + AutoMutex _l(mLock); + mLocked.inputChannelObjWeakTable.removeItem(inputChannel.get()); } DeleteWeakRef: @@ -339,17 +419,17 @@ status_t NativeInputManager::unregisterInputChannel(JNIEnv* env, const sp<InputChannel>& inputChannel) { jweak inputChannelObjWeak; { - AutoMutex _l(mInputChannelRegistryLock); + AutoMutex _l(mLock); - ssize_t index = mInputChannelObjWeakTable.indexOfKey(inputChannel.get()); + ssize_t index = mLocked.inputChannelObjWeakTable.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); + inputChannelObjWeak = mLocked.inputChannelObjWeakTable.valueAt(index); + mLocked.inputChannelObjWeakTable.removeItemsAt(index); } env->DeleteWeakGlobalRef(inputChannelObjWeak); @@ -365,14 +445,14 @@ jobject NativeInputManager::getInputChannelObjLocal(JNIEnv* env, } { - AutoMutex _l(mInputChannelRegistryLock); + AutoMutex _l(mLock); - ssize_t index = mInputChannelObjWeakTable.indexOfKey(inputChannelPtr); + ssize_t index = mLocked.inputChannelObjWeakTable.indexOfKey(inputChannelPtr); if (index < 0) { return NULL; } - jweak inputChannelObjWeak = mInputChannelObjWeakTable.valueAt(index); + jweak inputChannelObjWeak = mLocked.inputChannelObjWeakTable.valueAt(index); return env->NewLocalRef(inputChannelObjWeak); } } @@ -381,17 +461,17 @@ bool NativeInputManager::getDisplayInfo(int32_t displayId, int32_t* width, int32_t* height, int32_t* orientation) { bool result = false; if (displayId == 0) { - AutoMutex _l(mDisplayLock); + AutoMutex _l(mLock); - if (mDisplayWidth > 0) { + if (mLocked.displayWidth > 0 && mLocked.displayHeight > 0) { if (width) { - *width = mDisplayWidth; + *width = mLocked.displayWidth; } if (height) { - *height = mDisplayHeight; + *height = mLocked.displayHeight; } if (orientation) { - *orientation = mDisplayOrientation; + *orientation = mLocked.displayOrientation; } result = true; } @@ -451,6 +531,24 @@ void NativeInputManager::getExcludedDeviceNames(Vector<String8>& outExcludedDevi } } +sp<PointerControllerInterface> NativeInputManager::obtainPointerController(int32_t deviceId) { + AutoMutex _l(mLock); + + sp<PointerController> controller = mLocked.pointerController.promote(); + if (controller == NULL) { + JNIEnv* env = jniEnv(); + jint layer = env->CallIntMethod(mCallbacksObj, gCallbacksClassInfo.getPointerLayer); + checkAndClearExceptionFromCallback(env, "getPointerLayer"); + + controller = new PointerController(layer); + mLocked.pointerController = controller; + + controller->setDisplaySize(mLocked.displayWidth, mLocked.displayHeight); + controller->setDisplayOrientation(mLocked.displayOrientation); + } + return controller; +} + void NativeInputManager::notifySwitch(nsecs_t when, int32_t switchCode, int32_t switchValue, uint32_t policyFlags) { #if DEBUG_INPUT_DISPATCHER_POLICY @@ -886,6 +984,294 @@ bool NativeInputManager::checkInjectEventsPermissionNonReentrant( return result; } +// --- PointerController --- + +PointerController::PointerController(int32_t pointerLayer) : + mPointerLayer(pointerLayer) { + AutoMutex _l(mLock); + + mLocked.displayWidth = -1; + mLocked.displayHeight = -1; + mLocked.displayOrientation = InputReaderPolicyInterface::ROTATION_0; + + mLocked.pointerX = 0; + mLocked.pointerY = 0; + mLocked.buttonState = 0; + + mLocked.wantVisible = false; + mLocked.visible = false; + mLocked.drawn = false; +} + +PointerController::~PointerController() { + mSurfaceControl.clear(); + mSurfaceComposerClient.clear(); +} + +bool PointerController::getBounds(float* outMinX, float* outMinY, + float* outMaxX, float* outMaxY) const { + AutoMutex _l(mLock); + + return getBoundsLocked(outMinX, outMinY, outMaxX, outMaxY); +} + +bool PointerController::getBoundsLocked(float* outMinX, float* outMinY, + float* outMaxX, float* outMaxY) const { + if (mLocked.displayWidth <= 0 || mLocked.displayHeight <= 0) { + return false; + } + + *outMinX = 0; + *outMinY = 0; + switch (mLocked.displayOrientation) { + case InputReaderPolicyInterface::ROTATION_90: + case InputReaderPolicyInterface::ROTATION_270: + *outMaxX = mLocked.displayHeight; + *outMaxY = mLocked.displayWidth; + break; + default: + *outMaxX = mLocked.displayWidth; + *outMaxY = mLocked.displayHeight; + break; + } + return true; +} + +void PointerController::move(float deltaX, float deltaY) { +#if DEBUG_POINTER_CONTROLLER + LOGD("Move pointer by deltaX=%0.3f, deltaY=%0.3f", deltaX, deltaY); +#endif + if (deltaX == 0.0f && deltaY == 0.0f) { + return; + } + + AutoMutex _l(mLock); + + setPositionLocked(mLocked.pointerX + deltaX, mLocked.pointerY + deltaY); +} + +void PointerController::setButtonState(uint32_t buttonState) { + AutoMutex _l(mLock); + + if (mLocked.buttonState != buttonState) { + mLocked.buttonState = buttonState; + mLocked.wantVisible = true; + updateLocked(); + } +} + +uint32_t PointerController::getButtonState() const { + AutoMutex _l(mLock); + + return mLocked.buttonState; +} + +void PointerController::setPosition(float x, float y) { + AutoMutex _l(mLock); + + setPositionLocked(x, y); +} + +void PointerController::setPositionLocked(float x, float y) { + float minX, minY, maxX, maxY; + if (getBoundsLocked(&minX, &minY, &maxX, &maxY)) { + if (x <= minX) { + mLocked.pointerX = minX; + } else if (x >= maxX) { + mLocked.pointerX = maxX; + } else { + mLocked.pointerX = x; + } + if (y <= minY) { + mLocked.pointerY = minY; + } else if (y >= maxY) { + mLocked.pointerY = maxY; + } else { + mLocked.pointerY = y; + } + mLocked.wantVisible = true; + updateLocked(); + } +} + +void PointerController::getPosition(float* outX, float* outY) const { + AutoMutex _l(mLock); + + *outX = mLocked.pointerX; + *outY = mLocked.pointerY; +} + +void PointerController::updateLocked() { +#if DEBUG_POINTER_CONTROLLER + LOGD("Pointer at (%f, %f).", mLocked.pointerX, mLocked.pointerY); +#endif + + if (!mLocked.wantVisible && !mLocked.visible) { + return; + } + + if (mSurfaceComposerClient == NULL) { + mSurfaceComposerClient = new SurfaceComposerClient(); + } + + if (mSurfaceControl == NULL) { + mSurfaceControl = mSurfaceComposerClient->createSurface(getpid(), + String8("Pointer"), 0, 16, 16, PIXEL_FORMAT_RGBA_8888); + if (mSurfaceControl == NULL) { + LOGE("Error creating pointer surface."); + return; + } + } + + status_t status = mSurfaceComposerClient->openTransaction(); + if (status) { + LOGE("Error opening surface transaction to update pointer surface."); + return; + } + + if (mLocked.wantVisible) { + if (!mLocked.drawn) { + mLocked.drawn = true; + + sp<Surface> surface = mSurfaceControl->getSurface(); + Surface::SurfaceInfo surfaceInfo; + status = surface->lock(&surfaceInfo); + if (status) { + LOGE("Error %d locking pointer surface before drawing.", status); + goto CloseTransaction; + } + + // TODO: Load pointers from assets and allow them to be set. + char* bitmap = (char*)surfaceInfo.bits; + ssize_t bpr = surfaceInfo.s * 4; + for (int y = 0; y < surfaceInfo.h; y++) { + for (int x = 0; x < surfaceInfo.w; x++) { + bitmap[y * bpr + x * 4] = 128; + bitmap[y * bpr + x * 4 + 1] = 255; + bitmap[y * bpr + x * 4 + 2] = 128; + bitmap[y * bpr + x * 4 + 3] = 255; + } + } + + status = surface->unlockAndPost(); + if (status) { + LOGE("Error %d unlocking pointer surface after drawing.", status); + goto CloseTransaction; + } + } + + status = mSurfaceControl->setPosition(mLocked.pointerX, mLocked.pointerY); + if (status) { + LOGE("Error %d moving pointer surface.", status); + goto CloseTransaction; + } + + if (!mLocked.visible) { + mLocked.visible = true; + + mSurfaceControl->setLayer(mPointerLayer); + + LOGD("XXX Show"); + status = mSurfaceControl->show(mPointerLayer); + if (status) { + LOGE("Error %d showing pointer surface.", status); + goto CloseTransaction; + } + } + } else { + if (mLocked.visible) { + mLocked.visible = false; + + if (mSurfaceControl != NULL) { + status = mSurfaceControl->hide(); + if (status) { + LOGE("Error %d hiding pointer surface.", status); + goto CloseTransaction; + } + } + } + } + +CloseTransaction: + status = mSurfaceComposerClient->closeTransaction(); + if (status) { + LOGE("Error closing surface transaction to update pointer surface."); + } +} + +void PointerController::setDisplaySize(int32_t width, int32_t height) { + AutoMutex _l(mLock); + + if (mLocked.displayWidth != width || mLocked.displayHeight != height) { + mLocked.displayWidth = width; + mLocked.displayHeight = height; + + float minX, minY, maxX, maxY; + if (getBoundsLocked(&minX, &minY, &maxX, &maxY)) { + mLocked.pointerX = (minX + maxX) * 0.5f; + mLocked.pointerY = (minY + maxY) * 0.5f; + } else { + mLocked.pointerX = 0; + mLocked.pointerY = 0; + } + + updateLocked(); + } +} + +void PointerController::setDisplayOrientation(int32_t orientation) { + AutoMutex _l(mLock); + + if (mLocked.displayOrientation != orientation) { + float absoluteX, absoluteY; + + // Map from oriented display coordinates to absolute display coordinates. + switch (mLocked.displayOrientation) { + case InputReaderPolicyInterface::ROTATION_90: + absoluteX = mLocked.displayWidth - mLocked.pointerY; + absoluteY = mLocked.pointerX; + break; + case InputReaderPolicyInterface::ROTATION_180: + absoluteX = mLocked.displayWidth - mLocked.pointerX; + absoluteY = mLocked.displayHeight - mLocked.pointerY; + break; + case InputReaderPolicyInterface::ROTATION_270: + absoluteX = mLocked.pointerY; + absoluteY = mLocked.displayHeight - mLocked.pointerX; + break; + default: + absoluteX = mLocked.pointerX; + absoluteY = mLocked.pointerY; + break; + } + + // Map from absolute display coordinates to oriented display coordinates. + switch (orientation) { + case InputReaderPolicyInterface::ROTATION_90: + mLocked.pointerX = absoluteY; + mLocked.pointerY = mLocked.displayWidth - absoluteX; + break; + case InputReaderPolicyInterface::ROTATION_180: + mLocked.pointerX = mLocked.displayWidth - absoluteX; + mLocked.pointerY = mLocked.displayHeight - absoluteY; + break; + case InputReaderPolicyInterface::ROTATION_270: + mLocked.pointerX = mLocked.displayHeight - absoluteY; + mLocked.pointerY = absoluteX; + break; + default: + mLocked.pointerX = absoluteX; + mLocked.pointerY = absoluteY; + break; + } + + mLocked.displayOrientation = orientation; + + updateLocked(); + } +} + + // ---------------------------------------------------------------------------- static sp<NativeInputManager> gNativeInputManager; @@ -1326,6 +1712,9 @@ int register_android_server_InputManager(JNIEnv* env) { GET_METHOD_ID(gCallbacksClassInfo.getMaxEventsPerSecond, gCallbacksClassInfo.clazz, "getMaxEventsPerSecond", "()I"); + GET_METHOD_ID(gCallbacksClassInfo.getPointerLayer, gCallbacksClassInfo.clazz, + "getPointerLayer", "()I"); + // InputWindow FIND_CLASS(gInputWindowClassInfo.clazz, "com/android/server/InputWindow"); |