michael@0: /* michael@0: * Copyright (C) 2010 The Android Open Source Project michael@0: * michael@0: * Licensed under the Apache License, Version 2.0 (the "License"); michael@0: * you may not use this file except in compliance with the License. michael@0: * You may obtain a copy of the License at michael@0: * michael@0: * http://www.apache.org/licenses/LICENSE-2.0 michael@0: * michael@0: * Unless required by applicable law or agreed to in writing, software michael@0: * distributed under the License is distributed on an "AS IS" BASIS, michael@0: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. michael@0: * See the License for the specific language governing permissions and michael@0: * limitations under the License. michael@0: */ michael@0: michael@0: #define LOG_TAG "Input" michael@0: //#define LOG_NDEBUG 0 michael@0: #include "cutils_log.h" michael@0: michael@0: #include michael@0: #include michael@0: michael@0: #include "Input.h" michael@0: michael@0: #ifdef HAVE_ANDROID_OS michael@0: #include michael@0: michael@0: #include "SkPoint.h" michael@0: #include "SkMatrix.h" michael@0: #include "SkScalar.h" michael@0: #endif michael@0: michael@0: namespace android { michael@0: michael@0: // --- InputEvent --- michael@0: michael@0: void InputEvent::initialize(int32_t deviceId, int32_t source) { michael@0: mDeviceId = deviceId; michael@0: mSource = source; michael@0: } michael@0: michael@0: void InputEvent::initialize(const InputEvent& from) { michael@0: mDeviceId = from.mDeviceId; michael@0: mSource = from.mSource; michael@0: } michael@0: michael@0: // --- KeyEvent --- michael@0: michael@0: bool KeyEvent::hasDefaultAction(int32_t keyCode) { michael@0: switch (keyCode) { michael@0: case AKEYCODE_HOME: michael@0: case AKEYCODE_BACK: michael@0: case AKEYCODE_CALL: michael@0: case AKEYCODE_ENDCALL: michael@0: case AKEYCODE_VOLUME_UP: michael@0: case AKEYCODE_VOLUME_DOWN: michael@0: case AKEYCODE_VOLUME_MUTE: michael@0: case AKEYCODE_POWER: michael@0: case AKEYCODE_CAMERA: michael@0: case AKEYCODE_HEADSETHOOK: michael@0: case AKEYCODE_MENU: michael@0: case AKEYCODE_NOTIFICATION: michael@0: case AKEYCODE_FOCUS: michael@0: case AKEYCODE_SEARCH: michael@0: case AKEYCODE_MEDIA_PLAY: michael@0: case AKEYCODE_MEDIA_PAUSE: michael@0: case AKEYCODE_MEDIA_PLAY_PAUSE: michael@0: case AKEYCODE_MEDIA_STOP: michael@0: case AKEYCODE_MEDIA_NEXT: michael@0: case AKEYCODE_MEDIA_PREVIOUS: michael@0: case AKEYCODE_MEDIA_REWIND: michael@0: case AKEYCODE_MEDIA_RECORD: michael@0: case AKEYCODE_MEDIA_FAST_FORWARD: michael@0: case AKEYCODE_MUTE: michael@0: case AKEYCODE_BRIGHTNESS_DOWN: michael@0: case AKEYCODE_BRIGHTNESS_UP: michael@0: return true; michael@0: } michael@0: michael@0: return false; michael@0: } michael@0: michael@0: bool KeyEvent::hasDefaultAction() const { michael@0: return hasDefaultAction(getKeyCode()); michael@0: } michael@0: michael@0: bool KeyEvent::isSystemKey(int32_t keyCode) { michael@0: switch (keyCode) { michael@0: case AKEYCODE_MENU: michael@0: case AKEYCODE_SOFT_RIGHT: michael@0: case AKEYCODE_HOME: michael@0: case AKEYCODE_BACK: michael@0: case AKEYCODE_CALL: michael@0: case AKEYCODE_ENDCALL: michael@0: case AKEYCODE_VOLUME_UP: michael@0: case AKEYCODE_VOLUME_DOWN: michael@0: case AKEYCODE_VOLUME_MUTE: michael@0: case AKEYCODE_MUTE: michael@0: case AKEYCODE_POWER: michael@0: case AKEYCODE_HEADSETHOOK: michael@0: case AKEYCODE_MEDIA_PLAY: michael@0: case AKEYCODE_MEDIA_PAUSE: michael@0: case AKEYCODE_MEDIA_PLAY_PAUSE: michael@0: case AKEYCODE_MEDIA_STOP: michael@0: case AKEYCODE_MEDIA_NEXT: michael@0: case AKEYCODE_MEDIA_PREVIOUS: michael@0: case AKEYCODE_MEDIA_REWIND: michael@0: case AKEYCODE_MEDIA_RECORD: michael@0: case AKEYCODE_MEDIA_FAST_FORWARD: michael@0: case AKEYCODE_CAMERA: michael@0: case AKEYCODE_FOCUS: michael@0: case AKEYCODE_SEARCH: michael@0: case AKEYCODE_BRIGHTNESS_DOWN: michael@0: case AKEYCODE_BRIGHTNESS_UP: michael@0: return true; michael@0: } michael@0: michael@0: return false; michael@0: } michael@0: michael@0: bool KeyEvent::isSystemKey() const { michael@0: return isSystemKey(getKeyCode()); michael@0: } michael@0: michael@0: void KeyEvent::initialize( michael@0: int32_t deviceId, michael@0: int32_t source, michael@0: int32_t action, michael@0: int32_t flags, michael@0: int32_t keyCode, michael@0: int32_t scanCode, michael@0: int32_t metaState, michael@0: int32_t repeatCount, michael@0: nsecs_t downTime, michael@0: nsecs_t eventTime) { michael@0: InputEvent::initialize(deviceId, source); michael@0: mAction = action; michael@0: mFlags = flags; michael@0: mKeyCode = keyCode; michael@0: mScanCode = scanCode; michael@0: mMetaState = metaState; michael@0: mRepeatCount = repeatCount; michael@0: mDownTime = downTime; michael@0: mEventTime = eventTime; michael@0: } michael@0: michael@0: void KeyEvent::initialize(const KeyEvent& from) { michael@0: InputEvent::initialize(from); michael@0: mAction = from.mAction; michael@0: mFlags = from.mFlags; michael@0: mKeyCode = from.mKeyCode; michael@0: mScanCode = from.mScanCode; michael@0: mMetaState = from.mMetaState; michael@0: mRepeatCount = from.mRepeatCount; michael@0: mDownTime = from.mDownTime; michael@0: mEventTime = from.mEventTime; michael@0: } michael@0: michael@0: michael@0: // --- PointerCoords --- michael@0: michael@0: float PointerCoords::getAxisValue(int32_t axis) const { michael@0: if (axis < 0 || axis > 63) { michael@0: return 0; michael@0: } michael@0: michael@0: uint64_t axisBit = 1LL << axis; michael@0: if (!(bits & axisBit)) { michael@0: return 0; michael@0: } michael@0: uint32_t index = __builtin_popcountll(bits & (axisBit - 1LL)); michael@0: return values[index]; michael@0: } michael@0: michael@0: status_t PointerCoords::setAxisValue(int32_t axis, float value) { michael@0: if (axis < 0 || axis > 63) { michael@0: return NAME_NOT_FOUND; michael@0: } michael@0: michael@0: uint64_t axisBit = 1LL << axis; michael@0: uint32_t index = __builtin_popcountll(bits & (axisBit - 1LL)); michael@0: if (!(bits & axisBit)) { michael@0: if (value == 0) { michael@0: return OK; // axes with value 0 do not need to be stored michael@0: } michael@0: uint32_t count = __builtin_popcountll(bits); michael@0: if (count >= MAX_AXES) { michael@0: tooManyAxes(axis); michael@0: return NO_MEMORY; michael@0: } michael@0: bits |= axisBit; michael@0: for (uint32_t i = count; i > index; i--) { michael@0: values[i] = values[i - 1]; michael@0: } michael@0: } michael@0: values[index] = value; michael@0: return OK; michael@0: } michael@0: michael@0: static inline void scaleAxisValue(PointerCoords& c, int axis, float scaleFactor) { michael@0: float value = c.getAxisValue(axis); michael@0: if (value != 0) { michael@0: c.setAxisValue(axis, value * scaleFactor); michael@0: } michael@0: } michael@0: michael@0: void PointerCoords::scale(float scaleFactor) { michael@0: // No need to scale pressure or size since they are normalized. michael@0: // No need to scale orientation since it is meaningless to do so. michael@0: scaleAxisValue(*this, AMOTION_EVENT_AXIS_X, scaleFactor); michael@0: scaleAxisValue(*this, AMOTION_EVENT_AXIS_Y, scaleFactor); michael@0: scaleAxisValue(*this, AMOTION_EVENT_AXIS_TOUCH_MAJOR, scaleFactor); michael@0: scaleAxisValue(*this, AMOTION_EVENT_AXIS_TOUCH_MINOR, scaleFactor); michael@0: scaleAxisValue(*this, AMOTION_EVENT_AXIS_TOOL_MAJOR, scaleFactor); michael@0: scaleAxisValue(*this, AMOTION_EVENT_AXIS_TOOL_MINOR, scaleFactor); michael@0: } michael@0: michael@0: #ifdef HAVE_ANDROID_OS michael@0: status_t PointerCoords::readFromParcel(Parcel* parcel) { michael@0: bits = parcel->readInt64(); michael@0: michael@0: uint32_t count = __builtin_popcountll(bits); michael@0: if (count > MAX_AXES) { michael@0: return BAD_VALUE; michael@0: } michael@0: michael@0: for (uint32_t i = 0; i < count; i++) { michael@0: values[i] = parcel->readFloat(); michael@0: } michael@0: return OK; michael@0: } michael@0: michael@0: status_t PointerCoords::writeToParcel(Parcel* parcel) const { michael@0: parcel->writeInt64(bits); michael@0: michael@0: uint32_t count = __builtin_popcountll(bits); michael@0: for (uint32_t i = 0; i < count; i++) { michael@0: parcel->writeFloat(values[i]); michael@0: } michael@0: return OK; michael@0: } michael@0: #endif michael@0: michael@0: void PointerCoords::tooManyAxes(int axis) { michael@0: ALOGW("Could not set value for axis %d because the PointerCoords structure is full and " michael@0: "cannot contain more than %d axis values.", axis, int(MAX_AXES)); michael@0: } michael@0: michael@0: bool PointerCoords::operator==(const PointerCoords& other) const { michael@0: if (bits != other.bits) { michael@0: return false; michael@0: } michael@0: uint32_t count = __builtin_popcountll(bits); michael@0: for (uint32_t i = 0; i < count; i++) { michael@0: if (values[i] != other.values[i]) { michael@0: return false; michael@0: } michael@0: } michael@0: return true; michael@0: } michael@0: michael@0: void PointerCoords::copyFrom(const PointerCoords& other) { michael@0: bits = other.bits; michael@0: uint32_t count = __builtin_popcountll(bits); michael@0: for (uint32_t i = 0; i < count; i++) { michael@0: values[i] = other.values[i]; michael@0: } michael@0: } michael@0: michael@0: michael@0: // --- PointerProperties --- michael@0: michael@0: bool PointerProperties::operator==(const PointerProperties& other) const { michael@0: return id == other.id michael@0: && toolType == other.toolType; michael@0: } michael@0: michael@0: void PointerProperties::copyFrom(const PointerProperties& other) { michael@0: id = other.id; michael@0: toolType = other.toolType; michael@0: } michael@0: michael@0: michael@0: // --- MotionEvent --- michael@0: michael@0: void MotionEvent::initialize( michael@0: int32_t deviceId, michael@0: int32_t source, michael@0: int32_t action, michael@0: int32_t flags, michael@0: int32_t edgeFlags, michael@0: int32_t metaState, michael@0: int32_t buttonState, michael@0: float xOffset, michael@0: float yOffset, michael@0: float xPrecision, michael@0: float yPrecision, michael@0: nsecs_t downTime, michael@0: nsecs_t eventTime, michael@0: size_t pointerCount, michael@0: const PointerProperties* pointerProperties, michael@0: const PointerCoords* pointerCoords) { michael@0: InputEvent::initialize(deviceId, source); michael@0: mAction = action; michael@0: mFlags = flags; michael@0: mEdgeFlags = edgeFlags; michael@0: mMetaState = metaState; michael@0: mButtonState = buttonState; michael@0: mXOffset = xOffset; michael@0: mYOffset = yOffset; michael@0: mXPrecision = xPrecision; michael@0: mYPrecision = yPrecision; michael@0: mDownTime = downTime; michael@0: mPointerProperties.clear(); michael@0: mPointerProperties.appendArray(pointerProperties, pointerCount); michael@0: mSampleEventTimes.clear(); michael@0: mSamplePointerCoords.clear(); michael@0: addSample(eventTime, pointerCoords); michael@0: } michael@0: michael@0: void MotionEvent::copyFrom(const MotionEvent* other, bool keepHistory) { michael@0: InputEvent::initialize(other->mDeviceId, other->mSource); michael@0: mAction = other->mAction; michael@0: mFlags = other->mFlags; michael@0: mEdgeFlags = other->mEdgeFlags; michael@0: mMetaState = other->mMetaState; michael@0: mButtonState = other->mButtonState; michael@0: mXOffset = other->mXOffset; michael@0: mYOffset = other->mYOffset; michael@0: mXPrecision = other->mXPrecision; michael@0: mYPrecision = other->mYPrecision; michael@0: mDownTime = other->mDownTime; michael@0: mPointerProperties = other->mPointerProperties; michael@0: michael@0: if (keepHistory) { michael@0: mSampleEventTimes = other->mSampleEventTimes; michael@0: mSamplePointerCoords = other->mSamplePointerCoords; michael@0: } else { michael@0: mSampleEventTimes.clear(); michael@0: mSampleEventTimes.push(other->getEventTime()); michael@0: mSamplePointerCoords.clear(); michael@0: size_t pointerCount = other->getPointerCount(); michael@0: size_t historySize = other->getHistorySize(); michael@0: mSamplePointerCoords.appendArray(other->mSamplePointerCoords.array() michael@0: + (historySize * pointerCount), pointerCount); michael@0: } michael@0: } michael@0: michael@0: void MotionEvent::addSample( michael@0: int64_t eventTime, michael@0: const PointerCoords* pointerCoords) { michael@0: mSampleEventTimes.push(eventTime); michael@0: mSamplePointerCoords.appendArray(pointerCoords, getPointerCount()); michael@0: } michael@0: michael@0: const PointerCoords* MotionEvent::getRawPointerCoords(size_t pointerIndex) const { michael@0: return &mSamplePointerCoords[getHistorySize() * getPointerCount() + pointerIndex]; michael@0: } michael@0: michael@0: float MotionEvent::getRawAxisValue(int32_t axis, size_t pointerIndex) const { michael@0: return getRawPointerCoords(pointerIndex)->getAxisValue(axis); michael@0: } michael@0: michael@0: float MotionEvent::getAxisValue(int32_t axis, size_t pointerIndex) const { michael@0: float value = getRawPointerCoords(pointerIndex)->getAxisValue(axis); michael@0: switch (axis) { michael@0: case AMOTION_EVENT_AXIS_X: michael@0: return value + mXOffset; michael@0: case AMOTION_EVENT_AXIS_Y: michael@0: return value + mYOffset; michael@0: } michael@0: return value; michael@0: } michael@0: michael@0: const PointerCoords* MotionEvent::getHistoricalRawPointerCoords( michael@0: size_t pointerIndex, size_t historicalIndex) const { michael@0: return &mSamplePointerCoords[historicalIndex * getPointerCount() + pointerIndex]; michael@0: } michael@0: michael@0: float MotionEvent::getHistoricalRawAxisValue(int32_t axis, size_t pointerIndex, michael@0: size_t historicalIndex) const { michael@0: return getHistoricalRawPointerCoords(pointerIndex, historicalIndex)->getAxisValue(axis); michael@0: } michael@0: michael@0: float MotionEvent::getHistoricalAxisValue(int32_t axis, size_t pointerIndex, michael@0: size_t historicalIndex) const { michael@0: float value = getHistoricalRawPointerCoords(pointerIndex, historicalIndex)->getAxisValue(axis); michael@0: switch (axis) { michael@0: case AMOTION_EVENT_AXIS_X: michael@0: return value + mXOffset; michael@0: case AMOTION_EVENT_AXIS_Y: michael@0: return value + mYOffset; michael@0: } michael@0: return value; michael@0: } michael@0: michael@0: ssize_t MotionEvent::findPointerIndex(int32_t pointerId) const { michael@0: size_t pointerCount = mPointerProperties.size(); michael@0: for (size_t i = 0; i < pointerCount; i++) { michael@0: if (mPointerProperties.itemAt(i).id == pointerId) { michael@0: return i; michael@0: } michael@0: } michael@0: return -1; michael@0: } michael@0: michael@0: void MotionEvent::offsetLocation(float xOffset, float yOffset) { michael@0: mXOffset += xOffset; michael@0: mYOffset += yOffset; michael@0: } michael@0: michael@0: void MotionEvent::scale(float scaleFactor) { michael@0: mXOffset *= scaleFactor; michael@0: mYOffset *= scaleFactor; michael@0: mXPrecision *= scaleFactor; michael@0: mYPrecision *= scaleFactor; michael@0: michael@0: size_t numSamples = mSamplePointerCoords.size(); michael@0: for (size_t i = 0; i < numSamples; i++) { michael@0: mSamplePointerCoords.editItemAt(i).scale(scaleFactor); michael@0: } michael@0: } michael@0: michael@0: #ifdef HAVE_ANDROID_OS michael@0: static inline float transformAngle(const SkMatrix* matrix, float angleRadians) { michael@0: // Construct and transform a vector oriented at the specified clockwise angle from vertical. michael@0: // Coordinate system: down is increasing Y, right is increasing X. michael@0: SkPoint vector; michael@0: vector.fX = SkFloatToScalar(sinf(angleRadians)); michael@0: vector.fY = SkFloatToScalar(-cosf(angleRadians)); michael@0: matrix->mapVectors(& vector, 1); michael@0: michael@0: // Derive the transformed vector's clockwise angle from vertical. michael@0: float result = atan2f(SkScalarToFloat(vector.fX), SkScalarToFloat(-vector.fY)); michael@0: if (result < - M_PI_2) { michael@0: result += M_PI; michael@0: } else if (result > M_PI_2) { michael@0: result -= M_PI; michael@0: } michael@0: return result; michael@0: } michael@0: michael@0: void MotionEvent::transform(const SkMatrix* matrix) { michael@0: float oldXOffset = mXOffset; michael@0: float oldYOffset = mYOffset; michael@0: michael@0: // The tricky part of this implementation is to preserve the value of michael@0: // rawX and rawY. So we apply the transformation to the first point michael@0: // then derive an appropriate new X/Y offset that will preserve rawX and rawY. michael@0: SkPoint point; michael@0: float rawX = getRawX(0); michael@0: float rawY = getRawY(0); michael@0: matrix->mapXY(SkFloatToScalar(rawX + oldXOffset), SkFloatToScalar(rawY + oldYOffset), michael@0: & point); michael@0: float newX = SkScalarToFloat(point.fX); michael@0: float newY = SkScalarToFloat(point.fY); michael@0: float newXOffset = newX - rawX; michael@0: float newYOffset = newY - rawY; michael@0: michael@0: mXOffset = newXOffset; michael@0: mYOffset = newYOffset; michael@0: michael@0: // Apply the transformation to all samples. michael@0: size_t numSamples = mSamplePointerCoords.size(); michael@0: for (size_t i = 0; i < numSamples; i++) { michael@0: PointerCoords& c = mSamplePointerCoords.editItemAt(i); michael@0: float x = c.getAxisValue(AMOTION_EVENT_AXIS_X) + oldXOffset; michael@0: float y = c.getAxisValue(AMOTION_EVENT_AXIS_Y) + oldYOffset; michael@0: matrix->mapXY(SkFloatToScalar(x), SkFloatToScalar(y), &point); michael@0: c.setAxisValue(AMOTION_EVENT_AXIS_X, SkScalarToFloat(point.fX) - newXOffset); michael@0: c.setAxisValue(AMOTION_EVENT_AXIS_Y, SkScalarToFloat(point.fY) - newYOffset); michael@0: michael@0: float orientation = c.getAxisValue(AMOTION_EVENT_AXIS_ORIENTATION); michael@0: c.setAxisValue(AMOTION_EVENT_AXIS_ORIENTATION, transformAngle(matrix, orientation)); michael@0: } michael@0: } michael@0: michael@0: status_t MotionEvent::readFromParcel(Parcel* parcel) { michael@0: size_t pointerCount = parcel->readInt32(); michael@0: size_t sampleCount = parcel->readInt32(); michael@0: if (pointerCount == 0 || pointerCount > MAX_POINTERS || sampleCount == 0) { michael@0: return BAD_VALUE; michael@0: } michael@0: michael@0: mDeviceId = parcel->readInt32(); michael@0: mSource = parcel->readInt32(); michael@0: mAction = parcel->readInt32(); michael@0: mFlags = parcel->readInt32(); michael@0: mEdgeFlags = parcel->readInt32(); michael@0: mMetaState = parcel->readInt32(); michael@0: mButtonState = parcel->readInt32(); michael@0: mXOffset = parcel->readFloat(); michael@0: mYOffset = parcel->readFloat(); michael@0: mXPrecision = parcel->readFloat(); michael@0: mYPrecision = parcel->readFloat(); michael@0: mDownTime = parcel->readInt64(); michael@0: michael@0: mPointerProperties.clear(); michael@0: mPointerProperties.setCapacity(pointerCount); michael@0: mSampleEventTimes.clear(); michael@0: mSampleEventTimes.setCapacity(sampleCount); michael@0: mSamplePointerCoords.clear(); michael@0: mSamplePointerCoords.setCapacity(sampleCount * pointerCount); michael@0: michael@0: for (size_t i = 0; i < pointerCount; i++) { michael@0: mPointerProperties.push(); michael@0: PointerProperties& properties = mPointerProperties.editTop(); michael@0: properties.id = parcel->readInt32(); michael@0: properties.toolType = parcel->readInt32(); michael@0: } michael@0: michael@0: while (sampleCount-- > 0) { michael@0: mSampleEventTimes.push(parcel->readInt64()); michael@0: for (size_t i = 0; i < pointerCount; i++) { michael@0: mSamplePointerCoords.push(); michael@0: status_t status = mSamplePointerCoords.editTop().readFromParcel(parcel); michael@0: if (status) { michael@0: return status; michael@0: } michael@0: } michael@0: } michael@0: return OK; michael@0: } michael@0: michael@0: status_t MotionEvent::writeToParcel(Parcel* parcel) const { michael@0: size_t pointerCount = mPointerProperties.size(); michael@0: size_t sampleCount = mSampleEventTimes.size(); michael@0: michael@0: parcel->writeInt32(pointerCount); michael@0: parcel->writeInt32(sampleCount); michael@0: michael@0: parcel->writeInt32(mDeviceId); michael@0: parcel->writeInt32(mSource); michael@0: parcel->writeInt32(mAction); michael@0: parcel->writeInt32(mFlags); michael@0: parcel->writeInt32(mEdgeFlags); michael@0: parcel->writeInt32(mMetaState); michael@0: parcel->writeInt32(mButtonState); michael@0: parcel->writeFloat(mXOffset); michael@0: parcel->writeFloat(mYOffset); michael@0: parcel->writeFloat(mXPrecision); michael@0: parcel->writeFloat(mYPrecision); michael@0: parcel->writeInt64(mDownTime); michael@0: michael@0: for (size_t i = 0; i < pointerCount; i++) { michael@0: const PointerProperties& properties = mPointerProperties.itemAt(i); michael@0: parcel->writeInt32(properties.id); michael@0: parcel->writeInt32(properties.toolType); michael@0: } michael@0: michael@0: const PointerCoords* pc = mSamplePointerCoords.array(); michael@0: for (size_t h = 0; h < sampleCount; h++) { michael@0: parcel->writeInt64(mSampleEventTimes.itemAt(h)); michael@0: for (size_t i = 0; i < pointerCount; i++) { michael@0: status_t status = (pc++)->writeToParcel(parcel); michael@0: if (status) { michael@0: return status; michael@0: } michael@0: } michael@0: } michael@0: return OK; michael@0: } michael@0: #endif michael@0: michael@0: bool MotionEvent::isTouchEvent(int32_t source, int32_t action) { michael@0: if (source & AINPUT_SOURCE_CLASS_POINTER) { michael@0: // Specifically excludes HOVER_MOVE and SCROLL. michael@0: switch (action & AMOTION_EVENT_ACTION_MASK) { michael@0: case AMOTION_EVENT_ACTION_DOWN: michael@0: case AMOTION_EVENT_ACTION_MOVE: michael@0: case AMOTION_EVENT_ACTION_UP: michael@0: case AMOTION_EVENT_ACTION_POINTER_DOWN: michael@0: case AMOTION_EVENT_ACTION_POINTER_UP: michael@0: case AMOTION_EVENT_ACTION_CANCEL: michael@0: case AMOTION_EVENT_ACTION_OUTSIDE: michael@0: return true; michael@0: } michael@0: } michael@0: return false; michael@0: } michael@0: michael@0: michael@0: // --- PooledInputEventFactory --- michael@0: michael@0: PooledInputEventFactory::PooledInputEventFactory(size_t maxPoolSize) : michael@0: mMaxPoolSize(maxPoolSize) { michael@0: } michael@0: michael@0: PooledInputEventFactory::~PooledInputEventFactory() { michael@0: for (size_t i = 0; i < mKeyEventPool.size(); i++) { michael@0: delete mKeyEventPool.itemAt(i); michael@0: } michael@0: for (size_t i = 0; i < mMotionEventPool.size(); i++) { michael@0: delete mMotionEventPool.itemAt(i); michael@0: } michael@0: } michael@0: michael@0: KeyEvent* PooledInputEventFactory::createKeyEvent() { michael@0: if (!mKeyEventPool.isEmpty()) { michael@0: KeyEvent* event = mKeyEventPool.top(); michael@0: mKeyEventPool.pop(); michael@0: return event; michael@0: } michael@0: return new KeyEvent(); michael@0: } michael@0: michael@0: MotionEvent* PooledInputEventFactory::createMotionEvent() { michael@0: if (!mMotionEventPool.isEmpty()) { michael@0: MotionEvent* event = mMotionEventPool.top(); michael@0: mMotionEventPool.pop(); michael@0: return event; michael@0: } michael@0: return new MotionEvent(); michael@0: } michael@0: michael@0: void PooledInputEventFactory::recycle(InputEvent* event) { michael@0: switch (event->getType()) { michael@0: case AINPUT_EVENT_TYPE_KEY: michael@0: if (mKeyEventPool.size() < mMaxPoolSize) { michael@0: mKeyEventPool.push(static_cast(event)); michael@0: return; michael@0: } michael@0: break; michael@0: case AINPUT_EVENT_TYPE_MOTION: michael@0: if (mMotionEventPool.size() < mMaxPoolSize) { michael@0: mMotionEventPool.push(static_cast(event)); michael@0: return; michael@0: } michael@0: break; michael@0: } michael@0: delete event; michael@0: } michael@0: michael@0: } // namespace android