summaryrefslogtreecommitdiffstats
path: root/services
diff options
context:
space:
mode:
Diffstat (limited to 'services')
-rw-r--r--services/inputflinger/Android.mk2
-rw-r--r--services/inputflinger/EventHub.cpp37
-rw-r--r--services/inputflinger/EventHub.h7
-rw-r--r--services/inputflinger/InputDispatcher.cpp97
-rw-r--r--services/inputflinger/InputDispatcher.h10
-rw-r--r--services/inputflinger/InputListener.cpp12
-rw-r--r--services/inputflinger/InputListener.h4
-rw-r--r--services/inputflinger/InputReader.cpp1178
-rw-r--r--services/inputflinger/InputReader.h204
-rw-r--r--services/inputflinger/host/Android.mk62
-rw-r--r--services/inputflinger/host/InputDriver.cpp146
-rw-r--r--services/inputflinger/host/InputDriver.h117
-rw-r--r--services/inputflinger/host/InputFlinger.cpp71
-rw-r--r--services/inputflinger/host/InputFlinger.h53
-rw-r--r--services/inputflinger/host/InputHost.cpp42
-rw-r--r--services/inputflinger/host/InputHost.h62
-rw-r--r--services/inputflinger/host/main.cpp26
-rw-r--r--services/inputflinger/tests/Android.mk3
-rw-r--r--services/inputflinger/tests/InputDispatcher_test.cpp20
-rw-r--r--services/inputflinger/tests/InputReader_test.cpp8
-rw-r--r--services/sensorservice/SensorDevice.cpp137
-rw-r--r--services/sensorservice/SensorDevice.h14
-rw-r--r--services/sensorservice/SensorService.cpp715
-rw-r--r--services/sensorservice/SensorService.h155
-rw-r--r--services/sensorservice/tests/sensorservicetest.cpp9
-rw-r--r--services/surfaceflinger/Client.cpp2
-rw-r--r--services/surfaceflinger/DdmConnection.cpp2
-rw-r--r--services/surfaceflinger/DispSync.h2
-rw-r--r--services/surfaceflinger/DisplayHardware/HWComposer.cpp11
-rw-r--r--services/surfaceflinger/DisplayHardware/HWComposer.h2
-rw-r--r--services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.cpp9
-rw-r--r--services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.h2
-rw-r--r--services/surfaceflinger/Layer.cpp132
-rw-r--r--services/surfaceflinger/Layer.h12
-rw-r--r--services/surfaceflinger/MonitoredProducer.cpp8
-rw-r--r--services/surfaceflinger/MonitoredProducer.h2
-rw-r--r--services/surfaceflinger/RenderEngine/Description.cpp4
-rw-r--r--services/surfaceflinger/RenderEngine/Description.h1
-rw-r--r--services/surfaceflinger/RenderEngine/GLES11RenderEngine.cpp8
-rw-r--r--services/surfaceflinger/RenderEngine/GLES11RenderEngine.h3
-rw-r--r--services/surfaceflinger/RenderEngine/GLES20RenderEngine.cpp78
-rw-r--r--services/surfaceflinger/RenderEngine/GLES20RenderEngine.h4
-rw-r--r--services/surfaceflinger/RenderEngine/Mesh.cpp30
-rw-r--r--services/surfaceflinger/RenderEngine/ProgramCache.cpp2
-rw-r--r--services/surfaceflinger/RenderEngine/RenderEngine.h10
-rw-r--r--services/surfaceflinger/SurfaceFlinger.cpp113
-rw-r--r--services/surfaceflinger/SurfaceFlinger.h13
-rw-r--r--services/surfaceflinger/SurfaceFlingerConsumer.cpp12
-rw-r--r--services/surfaceflinger/SurfaceFlingerConsumer.h8
-rw-r--r--services/surfaceflinger/tests/Transaction_test.cpp46
50 files changed, 2871 insertions, 836 deletions
diff --git a/services/inputflinger/Android.mk b/services/inputflinger/Android.mk
index 1af59a3..ed867d8 100644
--- a/services/inputflinger/Android.mk
+++ b/services/inputflinger/Android.mk
@@ -45,3 +45,5 @@ LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH)
LOCAL_MODULE := libinputflinger
include $(BUILD_SHARED_LIBRARY)
+
+include $(call all-makefiles-under,$(LOCAL_PATH))
diff --git a/services/inputflinger/EventHub.cpp b/services/inputflinger/EventHub.cpp
index 93ce010..6b60c7c 100644
--- a/services/inputflinger/EventHub.cpp
+++ b/services/inputflinger/EventHub.cpp
@@ -131,6 +131,13 @@ uint32_t getAbsAxisUsage(int32_t axis, uint32_t deviceClasses) {
}
}
+ // External stylus gets the pressure axis
+ if (deviceClasses & INPUT_DEVICE_CLASS_EXTERNAL_STYLUS) {
+ if (axis == ABS_PRESSURE) {
+ return INPUT_DEVICE_CLASS_EXTERNAL_STYLUS;
+ }
+ }
+
// Joystick devices get the rest.
return deviceClasses & INPUT_DEVICE_CLASS_JOYSTICK;
}
@@ -1185,6 +1192,16 @@ status_t EventHub::openDeviceLocked(const char *devicePath) {
&& test_bit(ABS_X, device->absBitmask)
&& test_bit(ABS_Y, device->absBitmask)) {
device->classes |= INPUT_DEVICE_CLASS_TOUCH;
+ // Is this a BT stylus?
+ } else if ((test_bit(ABS_PRESSURE, device->absBitmask) ||
+ test_bit(BTN_TOUCH, device->keyBitmask))
+ && !test_bit(ABS_X, device->absBitmask)
+ && !test_bit(ABS_Y, device->absBitmask)) {
+ device->classes |= INPUT_DEVICE_CLASS_EXTERNAL_STYLUS;
+ // Keyboard will try to claim some of the buttons but we really want to reserve those so we
+ // can fuse it with the touch screen data, so just take them back. Note this means an
+ // external stylus cannot also be a keyboard device.
+ device->classes &= ~INPUT_DEVICE_CLASS_KEYBOARD;
}
// See if this device is a joystick.
@@ -1279,6 +1296,11 @@ status_t EventHub::openDeviceLocked(const char *devicePath) {
return -1;
}
+ // Determine whether the device has a mic.
+ if (deviceHasMicLocked(device)) {
+ device->classes |= INPUT_DEVICE_CLASS_MIC;
+ }
+
// Determine whether the device is external or internal.
if (isExternalDeviceLocked(device)) {
device->classes |= INPUT_DEVICE_CLASS_EXTERNAL;
@@ -1293,7 +1315,10 @@ status_t EventHub::openDeviceLocked(const char *devicePath) {
// Register with epoll.
struct epoll_event eventItem;
memset(&eventItem, 0, sizeof(eventItem));
- eventItem.events = mUsingEpollWakeup ? EPOLLIN : EPOLLIN | EPOLLWAKEUP;
+ eventItem.events = EPOLLIN;
+ if (mUsingEpollWakeup) {
+ eventItem.events |= EPOLLWAKEUP;
+ }
eventItem.data.u32 = deviceId;
if (epoll_ctl(mEpollFd, EPOLL_CTL_ADD, fd, &eventItem)) {
ALOGE("Could not add device fd to epoll instance. errno=%d", errno);
@@ -1412,6 +1437,16 @@ bool EventHub::isExternalDeviceLocked(Device* device) {
return device->identifier.bus == BUS_USB || device->identifier.bus == BUS_BLUETOOTH;
}
+bool EventHub::deviceHasMicLocked(Device* device) {
+ if (device->configuration) {
+ bool value;
+ if (device->configuration->tryGetProperty(String8("audio.mic"), value)) {
+ return value;
+ }
+ }
+ return false;
+}
+
int32_t EventHub::getNextControllerNumberLocked(Device* device) {
if (mControllerNumbers.isFull()) {
ALOGI("Maximum number of controllers reached, assigning controller number 0 to device %s",
diff --git a/services/inputflinger/EventHub.h b/services/inputflinger/EventHub.h
index 20179ae..3ec4910 100644
--- a/services/inputflinger/EventHub.h
+++ b/services/inputflinger/EventHub.h
@@ -131,6 +131,12 @@ enum {
/* The input device has a vibrator (supports FF_RUMBLE). */
INPUT_DEVICE_CLASS_VIBRATOR = 0x00000200,
+ /* The input device has a microphone. */
+ INPUT_DEVICE_CLASS_MIC = 0x00000400,
+
+ /* The input device is an external stylus (has data we want to fuse with touch data). */
+ INPUT_DEVICE_CLASS_EXTERNAL_STYLUS = 0x00000800,
+
/* The input device is virtual (not a real device, not part of UI configuration). */
INPUT_DEVICE_CLASS_VIRTUAL = 0x40000000,
@@ -394,6 +400,7 @@ private:
status_t loadKeyMapLocked(Device* device);
bool isExternalDeviceLocked(Device* device);
+ bool deviceHasMicLocked(Device* device);
int32_t getNextControllerNumberLocked(Device* device);
void releaseControllerNumberLocked(Device* device);
diff --git a/services/inputflinger/InputDispatcher.cpp b/services/inputflinger/InputDispatcher.cpp
index 9157bc1..0fba1bf 100644
--- a/services/inputflinger/InputDispatcher.cpp
+++ b/services/inputflinger/InputDispatcher.cpp
@@ -119,7 +119,7 @@ static bool validateKeyEvent(int32_t action) {
return true;
}
-static bool isValidMotionAction(int32_t action, size_t pointerCount) {
+static bool isValidMotionAction(int32_t action, int32_t actionButton, int32_t pointerCount) {
switch (action & AMOTION_EVENT_ACTION_MASK) {
case AMOTION_EVENT_ACTION_DOWN:
case AMOTION_EVENT_ACTION_UP:
@@ -136,14 +136,17 @@ static bool isValidMotionAction(int32_t action, size_t pointerCount) {
int32_t index = getMotionEventActionPointerIndex(action);
return index >= 0 && size_t(index) < pointerCount;
}
+ case AMOTION_EVENT_ACTION_BUTTON_PRESS:
+ case AMOTION_EVENT_ACTION_BUTTON_RELEASE:
+ return actionButton != 0;
default:
return false;
}
}
-static bool validateMotionEvent(int32_t action, size_t pointerCount,
+static bool validateMotionEvent(int32_t action, int32_t actionButton, size_t pointerCount,
const PointerProperties* pointerProperties) {
- if (! isValidMotionAction(action, pointerCount)) {
+ if (! isValidMotionAction(action, actionButton, pointerCount)) {
ALOGE("Motion event has invalid action code 0x%x", action);
return false;
}
@@ -198,7 +201,8 @@ static void dumpRegion(String8& dump, const Region& region) {
InputDispatcher::InputDispatcher(const sp<InputDispatcherPolicyInterface>& policy) :
mPolicy(policy),
- mPendingEvent(NULL), mAppSwitchSawKeyDown(false), mAppSwitchDueTime(LONG_LONG_MAX),
+ mPendingEvent(NULL), mLastDropReason(DROP_REASON_NOT_DROPPED),
+ mAppSwitchSawKeyDown(false), mAppSwitchDueTime(LONG_LONG_MAX),
mNextUnblockedEvent(NULL),
mDispatchEnabled(false), mDispatchFrozen(false), mInputFilterEnabled(false),
mInputTargetWaitCause(INPUT_TARGET_WAIT_CAUSE_NONE) {
@@ -394,6 +398,7 @@ void InputDispatcher::dispatchOnceInnerLocked(nsecs_t* nextWakeupTime) {
if (dropReason != DROP_REASON_NOT_DROPPED) {
dropInboundEventLocked(mPendingEvent, dropReason);
}
+ mLastDropReason = dropReason;
releasePendingEventLocked();
*nextWakeupTime = LONG_LONG_MIN; // force next poll to wake up immediately
@@ -503,7 +508,9 @@ void InputDispatcher::dropInboundEventLocked(EventEntry* entry, DropReason dropR
reason = "inbound event was dropped because the policy consumed it";
break;
case DROP_REASON_DISABLED:
- ALOGI("Dropped event because input dispatch is disabled.");
+ if (mLastDropReason != DROP_REASON_DISABLED) {
+ ALOGI("Dropped event because input dispatch is disabled.");
+ }
reason = "inbound event was dropped because input dispatch is disabled";
break;
case DROP_REASON_APP_SWITCH:
@@ -852,6 +859,13 @@ bool InputDispatcher::dispatchMotionLocked(
setInjectionResultLocked(entry, injectionResult);
if (injectionResult != INPUT_EVENT_INJECTION_SUCCEEDED) {
+ if (injectionResult != INPUT_EVENT_INJECTION_PERMISSION_DENIED) {
+ CancelationOptions::Mode mode(isPointerEvent ?
+ CancelationOptions::CANCEL_POINTER_EVENTS :
+ CancelationOptions::CANCEL_NON_POINTER_EVENTS);
+ CancelationOptions options(mode, "input event injection failed");
+ synthesizeCancelationEventsForMonitorsLocked(options);
+ }
return true;
}
@@ -874,12 +888,12 @@ bool InputDispatcher::dispatchMotionLocked(
void InputDispatcher::logOutboundMotionDetailsLocked(const char* prefix, const MotionEntry* entry) {
#if DEBUG_OUTBOUND_EVENT_DETAILS
ALOGD("%seventTime=%lld, deviceId=%d, source=0x%x, policyFlags=0x%x, "
- "action=0x%x, flags=0x%x, "
- "metaState=0x%x, buttonState=0x%x, "
+ "action=0x%x, actionButton=0x%x, flags=0x%x, "
+ "metaState=0x%x, buttonState=0x%x,"
"edgeFlags=0x%x, xPrecision=%f, yPrecision=%f, downTime=%lld",
prefix,
entry->eventTime, entry->deviceId, entry->source, entry->policyFlags,
- entry->action, entry->flags,
+ entry->action, entry->actionButton, entry->flags,
entry->metaState, entry->buttonState,
entry->edgeFlags, entry->xPrecision, entry->yPrecision,
entry->downTime);
@@ -1981,10 +1995,10 @@ void InputDispatcher::startDispatchCycleLocked(nsecs_t currentTime,
// Publish the motion event.
status = connection->inputPublisher.publishMotionEvent(dispatchEntry->seq,
motionEntry->deviceId, motionEntry->source,
- dispatchEntry->resolvedAction, dispatchEntry->resolvedFlags,
- motionEntry->edgeFlags, motionEntry->metaState, motionEntry->buttonState,
- xOffset, yOffset,
- motionEntry->xPrecision, motionEntry->yPrecision,
+ dispatchEntry->resolvedAction, motionEntry->actionButton,
+ dispatchEntry->resolvedFlags, motionEntry->edgeFlags,
+ motionEntry->metaState, motionEntry->buttonState,
+ xOffset, yOffset, motionEntry->xPrecision, motionEntry->yPrecision,
motionEntry->downTime, motionEntry->eventTime,
motionEntry->pointerCount, motionEntry->pointerProperties,
usingCoords);
@@ -2160,6 +2174,13 @@ void InputDispatcher::synthesizeCancelationEventsForAllConnectionsLocked(
}
}
+void InputDispatcher::synthesizeCancelationEventsForMonitorsLocked(
+ const CancelationOptions& options) {
+ for (size_t i = 0; i < mMonitoringChannels.size(); i++) {
+ synthesizeCancelationEventsForInputChannelLocked(mMonitoringChannels[i], options);
+ }
+}
+
void InputDispatcher::synthesizeCancelationEventsForInputChannelLocked(
const sp<InputChannel>& channel, const CancelationOptions& options) {
ssize_t index = getConnectionIndexLocked(channel);
@@ -2298,6 +2319,7 @@ InputDispatcher::splitMotionEvent(const MotionEntry* originalMotionEntry, BitSet
originalMotionEntry->source,
originalMotionEntry->policyFlags,
action,
+ originalMotionEntry->actionButton,
originalMotionEntry->flags,
originalMotionEntry->metaState,
originalMotionEntry->buttonState,
@@ -2432,10 +2454,10 @@ bool InputDispatcher::shouldSendKeyToInputFilterLocked(const NotifyKeyArgs* args
void InputDispatcher::notifyMotion(const NotifyMotionArgs* args) {
#if DEBUG_INBOUND_EVENT_DETAILS
ALOGD("notifyMotion - eventTime=%lld, deviceId=%d, source=0x%x, policyFlags=0x%x, "
- "action=0x%x, flags=0x%x, metaState=0x%x, buttonState=0x%x, edgeFlags=0x%x, "
- "xPrecision=%f, yPrecision=%f, downTime=%lld",
+ "action=0x%x, actionButton=0x%x, flags=0x%x, metaState=0x%x, buttonState=0x%x,"
+ "edgeFlags=0x%x, xPrecision=%f, yPrecision=%f, downTime=%lld",
args->eventTime, args->deviceId, args->source, args->policyFlags,
- args->action, args->flags, args->metaState, args->buttonState,
+ args->action, args->actionButton, args->flags, args->metaState, args->buttonState,
args->edgeFlags, args->xPrecision, args->yPrecision, args->downTime);
for (uint32_t i = 0; i < args->pointerCount; i++) {
ALOGD(" Pointer %d: id=%d, toolType=%d, "
@@ -2455,7 +2477,8 @@ void InputDispatcher::notifyMotion(const NotifyMotionArgs* args) {
args->pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_ORIENTATION));
}
#endif
- if (!validateMotionEvent(args->action, args->pointerCount, args->pointerProperties)) {
+ if (!validateMotionEvent(args->action, args->actionButton,
+ args->pointerCount, args->pointerProperties)) {
return;
}
@@ -2471,9 +2494,9 @@ void InputDispatcher::notifyMotion(const NotifyMotionArgs* args) {
mLock.unlock();
MotionEvent event;
- event.initialize(args->deviceId, args->source, args->action, args->flags,
- args->edgeFlags, args->metaState, args->buttonState, 0, 0,
- args->xPrecision, args->yPrecision,
+ event.initialize(args->deviceId, args->source, args->action, args->actionButton,
+ args->flags, args->edgeFlags, args->metaState, args->buttonState,
+ 0, 0, args->xPrecision, args->yPrecision,
args->downTime, args->eventTime,
args->pointerCount, args->pointerProperties, args->pointerCoords);
@@ -2488,7 +2511,8 @@ void InputDispatcher::notifyMotion(const NotifyMotionArgs* args) {
// Just enqueue a new motion event.
MotionEntry* newEntry = new MotionEntry(args->eventTime,
args->deviceId, args->source, policyFlags,
- args->action, args->flags, args->metaState, args->buttonState,
+ args->action, args->actionButton, args->flags,
+ args->metaState, args->buttonState,
args->edgeFlags, args->xPrecision, args->yPrecision, args->downTime,
args->displayId,
args->pointerCount, args->pointerProperties, args->pointerCoords, 0, 0);
@@ -2589,7 +2613,8 @@ int32_t InputDispatcher::injectInputEvent(const InputEvent* event, int32_t displ
int32_t action = motionEvent->getAction();
size_t pointerCount = motionEvent->getPointerCount();
const PointerProperties* pointerProperties = motionEvent->getPointerProperties();
- if (! validateMotionEvent(action, pointerCount, pointerProperties)) {
+ int32_t actionButton = motionEvent->getActionButton();
+ if (! validateMotionEvent(action, actionButton, pointerCount, pointerProperties)) {
return INPUT_EVENT_INJECTION_FAILED;
}
@@ -2603,7 +2628,7 @@ int32_t InputDispatcher::injectInputEvent(const InputEvent* event, int32_t displ
const PointerCoords* samplePointerCoords = motionEvent->getSamplePointerCoords();
firstInjectedEntry = new MotionEntry(*sampleEventTimes,
motionEvent->getDeviceId(), motionEvent->getSource(), policyFlags,
- action, motionEvent->getFlags(),
+ action, actionButton, motionEvent->getFlags(),
motionEvent->getMetaState(), motionEvent->getButtonState(),
motionEvent->getEdgeFlags(),
motionEvent->getXPrecision(), motionEvent->getYPrecision(),
@@ -2616,7 +2641,7 @@ int32_t InputDispatcher::injectInputEvent(const InputEvent* event, int32_t displ
samplePointerCoords += pointerCount;
MotionEntry* nextInjectedEntry = new MotionEntry(*sampleEventTimes,
motionEvent->getDeviceId(), motionEvent->getSource(), policyFlags,
- action, motionEvent->getFlags(),
+ action, actionButton, motionEvent->getFlags(),
motionEvent->getMetaState(), motionEvent->getButtonState(),
motionEvent->getEdgeFlags(),
motionEvent->getXPrecision(), motionEvent->getYPrecision(),
@@ -3907,18 +3932,18 @@ void InputDispatcher::KeyEntry::recycle() {
// --- InputDispatcher::MotionEntry ---
-InputDispatcher::MotionEntry::MotionEntry(nsecs_t eventTime,
- int32_t deviceId, uint32_t source, uint32_t policyFlags, int32_t action, int32_t flags,
- int32_t metaState, int32_t buttonState,
- int32_t edgeFlags, float xPrecision, float yPrecision,
- nsecs_t downTime, int32_t displayId, uint32_t pointerCount,
+InputDispatcher::MotionEntry::MotionEntry(nsecs_t eventTime, int32_t deviceId,
+ uint32_t source, uint32_t policyFlags, int32_t action, int32_t actionButton,
+ int32_t flags, int32_t metaState, int32_t buttonState, int32_t edgeFlags,
+ float xPrecision, float yPrecision, nsecs_t downTime,
+ int32_t displayId, uint32_t pointerCount,
const PointerProperties* pointerProperties, const PointerCoords* pointerCoords,
float xOffset, float yOffset) :
EventEntry(TYPE_MOTION, eventTime, policyFlags),
eventTime(eventTime),
- deviceId(deviceId), source(source), action(action), flags(flags),
- metaState(metaState), buttonState(buttonState), edgeFlags(edgeFlags),
- xPrecision(xPrecision), yPrecision(yPrecision),
+ deviceId(deviceId), source(source), action(action), actionButton(actionButton),
+ flags(flags), metaState(metaState), buttonState(buttonState),
+ edgeFlags(edgeFlags), xPrecision(xPrecision), yPrecision(yPrecision),
downTime(downTime), displayId(displayId), pointerCount(pointerCount) {
for (uint32_t i = 0; i < pointerCount; i++) {
this->pointerProperties[i].copyFrom(pointerProperties[i]);
@@ -3933,10 +3958,10 @@ InputDispatcher::MotionEntry::~MotionEntry() {
}
void InputDispatcher::MotionEntry::appendDescription(String8& msg) const {
- msg.appendFormat("MotionEvent(deviceId=%d, source=0x%08x, action=%d, "
- "flags=0x%08x, metaState=0x%08x, buttonState=0x%08x, edgeFlags=0x%08x, "
- "xPrecision=%.1f, yPrecision=%.1f, displayId=%d, pointers=[",
- deviceId, source, action, flags, metaState, buttonState, edgeFlags,
+ msg.appendFormat("MotionEvent(deviceId=%d, source=0x%08x, action=%d, actionButton=0x%08x, "
+ "flags=0x%08x, metaState=0x%08x, buttonState=0x%08x, "
+ "edgeFlags=0x%08x, xPrecision=%.1f, yPrecision=%.1f, displayId=%d, pointers=[",
+ deviceId, source, action, actionButton, flags, metaState, buttonState, edgeFlags,
xPrecision, yPrecision, displayId);
for (uint32_t i = 0; i < pointerCount; i++) {
if (i) {
@@ -4237,7 +4262,7 @@ void InputDispatcher::InputState::synthesizeCancelationEvents(nsecs_t currentTim
memento.hovering
? AMOTION_EVENT_ACTION_HOVER_EXIT
: AMOTION_EVENT_ACTION_CANCEL,
- memento.flags, 0, 0, 0,
+ memento.flags, 0, 0, 0, 0,
memento.xPrecision, memento.yPrecision, memento.downTime,
memento.displayId,
memento.pointerCount, memento.pointerProperties, memento.pointerCoords,
diff --git a/services/inputflinger/InputDispatcher.h b/services/inputflinger/InputDispatcher.h
index 8c78a44..98355c6 100644
--- a/services/inputflinger/InputDispatcher.h
+++ b/services/inputflinger/InputDispatcher.h
@@ -504,6 +504,7 @@ private:
int32_t deviceId;
uint32_t source;
int32_t action;
+ int32_t actionButton;
int32_t flags;
int32_t metaState;
int32_t buttonState;
@@ -518,10 +519,10 @@ private:
MotionEntry(nsecs_t eventTime,
int32_t deviceId, uint32_t source, uint32_t policyFlags,
- int32_t action, int32_t flags,
+ int32_t action, int32_t actionButton, int32_t flags,
int32_t metaState, int32_t buttonState, int32_t edgeFlags,
- float xPrecision, float yPrecision,
- nsecs_t downTime, int32_t displayId, uint32_t pointerCount,
+ float xPrecision, float yPrecision, nsecs_t downTime,
+ int32_t displayId, uint32_t pointerCount,
const PointerProperties* pointerProperties, const PointerCoords* pointerCoords,
float xOffset, float yOffset);
virtual void appendDescription(String8& msg) const;
@@ -856,6 +857,8 @@ private:
Queue<EventEntry> mRecentQueue;
Queue<CommandEntry> mCommandQueue;
+ DropReason mLastDropReason;
+
void dispatchOnceInnerLocked(nsecs_t* nextWakeupTime);
// Enqueues an inbound event. Returns true if mLooper->wake() should be called.
@@ -1073,6 +1076,7 @@ private:
void synthesizeCancelationEventsForAllConnectionsLocked(
const CancelationOptions& options);
+ void synthesizeCancelationEventsForMonitorsLocked(const CancelationOptions& options);
void synthesizeCancelationEventsForInputChannelLocked(const sp<InputChannel>& channel,
const CancelationOptions& options);
void synthesizeCancelationEventsForConnectionLocked(const sp<Connection>& connection,
diff --git a/services/inputflinger/InputListener.cpp b/services/inputflinger/InputListener.cpp
index 85bb0ed..dded47d 100644
--- a/services/inputflinger/InputListener.cpp
+++ b/services/inputflinger/InputListener.cpp
@@ -68,12 +68,13 @@ void NotifyKeyArgs::notify(const sp<InputListenerInterface>& listener) const {
NotifyMotionArgs::NotifyMotionArgs(nsecs_t eventTime, int32_t deviceId, uint32_t source,
uint32_t policyFlags,
- int32_t action, int32_t flags, int32_t metaState, int32_t buttonState,
- int32_t edgeFlags, int32_t displayId, uint32_t pointerCount,
+ int32_t action, int32_t actionButton, int32_t flags, int32_t metaState,
+ int32_t buttonState, int32_t edgeFlags, int32_t displayId, uint32_t pointerCount,
const PointerProperties* pointerProperties, const PointerCoords* pointerCoords,
float xPrecision, float yPrecision, nsecs_t downTime) :
eventTime(eventTime), deviceId(deviceId), source(source), policyFlags(policyFlags),
- action(action), flags(flags), metaState(metaState), buttonState(buttonState),
+ action(action), actionButton(actionButton),
+ flags(flags), metaState(metaState), buttonState(buttonState),
edgeFlags(edgeFlags), displayId(displayId), pointerCount(pointerCount),
xPrecision(xPrecision), yPrecision(yPrecision), downTime(downTime) {
for (uint32_t i = 0; i < pointerCount; i++) {
@@ -85,10 +86,9 @@ NotifyMotionArgs::NotifyMotionArgs(nsecs_t eventTime, int32_t deviceId, uint32_t
NotifyMotionArgs::NotifyMotionArgs(const NotifyMotionArgs& other) :
eventTime(other.eventTime), deviceId(other.deviceId), source(other.source),
policyFlags(other.policyFlags),
- action(other.action), flags(other.flags),
+ action(other.action), actionButton(other.actionButton), flags(other.flags),
metaState(other.metaState), buttonState(other.buttonState),
- edgeFlags(other.edgeFlags), displayId(other.displayId),
- pointerCount(other.pointerCount),
+ edgeFlags(other.edgeFlags), displayId(other.displayId), pointerCount(other.pointerCount),
xPrecision(other.xPrecision), yPrecision(other.yPrecision), downTime(other.downTime) {
for (uint32_t i = 0; i < pointerCount; i++) {
pointerProperties[i].copyFrom(other.pointerProperties[i]);
diff --git a/services/inputflinger/InputListener.h b/services/inputflinger/InputListener.h
index 78ae10f..1ec09ce 100644
--- a/services/inputflinger/InputListener.h
+++ b/services/inputflinger/InputListener.h
@@ -84,6 +84,7 @@ struct NotifyMotionArgs : public NotifyArgs {
uint32_t source;
uint32_t policyFlags;
int32_t action;
+ int32_t actionButton;
int32_t flags;
int32_t metaState;
int32_t buttonState;
@@ -99,7 +100,8 @@ struct NotifyMotionArgs : public NotifyArgs {
inline NotifyMotionArgs() { }
NotifyMotionArgs(nsecs_t eventTime, int32_t deviceId, uint32_t source, uint32_t policyFlags,
- int32_t action, int32_t flags, int32_t metaState, int32_t buttonState,
+ int32_t action, int32_t actionButton, int32_t flags,
+ int32_t metaState, int32_t buttonState,
int32_t edgeFlags, int32_t displayId, uint32_t pointerCount,
const PointerProperties* pointerProperties, const PointerCoords* pointerCoords,
float xPrecision, float yPrecision, nsecs_t downTime);
diff --git a/services/inputflinger/InputReader.cpp b/services/inputflinger/InputReader.cpp
index ccf8ced..bd74b02 100644
--- a/services/inputflinger/InputReader.cpp
+++ b/services/inputflinger/InputReader.cpp
@@ -39,12 +39,16 @@
// Log debug messages about the vibrator.
#define DEBUG_VIBRATOR 0
+// Log debug messages about fusing stylus data.
+#define DEBUG_STYLUS_FUSION 0
+
#include "InputReader.h"
#include <cutils/log.h>
#include <input/Keyboard.h>
#include <input/VirtualKeyMap.h>
+#include <inttypes.h>
#include <stddef.h>
#include <stdlib.h>
#include <unistd.h>
@@ -65,6 +69,17 @@ namespace android {
// Maximum number of slots supported when using the slot-based Multitouch Protocol B.
static const size_t MAX_SLOTS = 32;
+// Maximum amount of latency to add to touch events while waiting for data from an
+// external stylus.
+static const nsecs_t EXTERNAL_STYLUS_DATA_TIMEOUT = ms2ns(72);
+
+// Maximum amount of time to wait on touch data before pushing out new pressure data.
+static const nsecs_t TOUCH_DATA_TIMEOUT = ms2ns(20);
+
+// Artificial latency on synthetic events created from stylus data without corresponding touch
+// data.
+static const nsecs_t STYLUS_DATA_LATENCY = ms2ns(10);
+
// --- Static Functions ---
template<typename T>
@@ -381,6 +396,10 @@ void InputReader::addDeviceLocked(nsecs_t when, int32_t deviceId) {
mDevices.add(deviceId, device);
bumpGenerationLocked();
+
+ if (device->getClasses() & INPUT_DEVICE_CLASS_EXTERNAL_STYLUS) {
+ notifyExternalStylusPresenceChanged();
+ }
}
void InputReader::removeDeviceLocked(nsecs_t when, int32_t deviceId) {
@@ -403,6 +422,10 @@ void InputReader::removeDeviceLocked(nsecs_t when, int32_t deviceId) {
device->getId(), device->getName().string(), device->getSources());
}
+ if (device->getClasses() & INPUT_DEVICE_CLASS_EXTERNAL_STYLUS) {
+ notifyExternalStylusPresenceChanged();
+ }
+
device->reset(when);
delete device;
}
@@ -417,6 +440,11 @@ InputDevice* InputReader::createDeviceLocked(int32_t deviceId, int32_t controlle
device->setExternal(true);
}
+ // Devices with mics.
+ if (classes & INPUT_DEVICE_CLASS_MIC) {
+ device->setMic(true);
+ }
+
// Switch-like devices.
if (classes & INPUT_DEVICE_CLASS_SWITCH) {
device->addMapper(new SwitchInputMapper(device));
@@ -464,6 +492,11 @@ InputDevice* InputReader::createDeviceLocked(int32_t deviceId, int32_t controlle
device->addMapper(new JoystickInputMapper(device));
}
+ // External stylus-like devices.
+ if (classes & INPUT_DEVICE_CLASS_EXTERNAL_STYLUS) {
+ device->addMapper(new ExternalStylusInputMapper(device));
+ }
+
return device;
}
@@ -534,6 +567,27 @@ int32_t InputReader::getGlobalMetaStateLocked() {
return mGlobalMetaState;
}
+void InputReader::notifyExternalStylusPresenceChanged() {
+ refreshConfigurationLocked(InputReaderConfiguration::CHANGE_EXTERNAL_STYLUS_PRESENCE);
+}
+
+void InputReader::getExternalStylusDevicesLocked(Vector<InputDeviceInfo>& outDevices) {
+ for (size_t i = 0; i < mDevices.size(); i++) {
+ InputDevice* device = mDevices.valueAt(i);
+ if (device->getClasses() & INPUT_DEVICE_CLASS_EXTERNAL_STYLUS && !device->isIgnored()) {
+ outDevices.push();
+ device->getDeviceInfo(&outDevices.editTop());
+ }
+ }
+}
+
+void InputReader::dispatchExternalStylusState(const StylusState& state) {
+ for (size_t i = 0; i < mDevices.size(); i++) {
+ InputDevice* device = mDevices.valueAt(i);
+ device->updateExternalStylusState(state);
+ }
+}
+
void InputReader::disableVirtualKeysUntilLocked(nsecs_t time) {
mDisableVirtualKeysTimeout = time;
}
@@ -824,6 +878,15 @@ int32_t InputReader::ContextImpl::bumpGeneration() {
return mReader->bumpGenerationLocked();
}
+void InputReader::ContextImpl::getExternalStylusDevices(Vector<InputDeviceInfo>& outDevices) {
+ // lock is already held by whatever called refreshConfigurationLocked
+ mReader->getExternalStylusDevicesLocked(outDevices);
+}
+
+void InputReader::ContextImpl::dispatchExternalStylusState(const StylusState& state) {
+ mReader->dispatchExternalStylusState(state);
+}
+
InputReaderPolicyInterface* InputReader::ContextImpl::getPolicy() {
return mReader->mPolicy.get();
}
@@ -858,7 +921,7 @@ InputDevice::InputDevice(InputReaderContext* context, int32_t id, int32_t genera
int32_t controllerNumber, const InputDeviceIdentifier& identifier, uint32_t classes) :
mContext(context), mId(id), mGeneration(generation), mControllerNumber(controllerNumber),
mIdentifier(identifier), mClasses(classes),
- mSources(0), mIsExternal(false), mDropUntilNextSync(false) {
+ mSources(0), mIsExternal(false), mHasMic(false), mDropUntilNextSync(false) {
}
InputDevice::~InputDevice() {
@@ -877,6 +940,7 @@ void InputDevice::dump(String8& dump) {
deviceInfo.getDisplayName().string());
dump.appendFormat(INDENT2 "Generation: %d\n", mGeneration);
dump.appendFormat(INDENT2 "IsExternal: %s\n", toString(mIsExternal));
+ dump.appendFormat(INDENT2 "HasMic: %s\n", toString(mHasMic));
dump.appendFormat(INDENT2 "Sources: 0x%08x\n", deviceInfo.getSources());
dump.appendFormat(INDENT2 "KeyboardType: %d\n", deviceInfo.getKeyboardType());
@@ -1006,10 +1070,17 @@ void InputDevice::timeoutExpired(nsecs_t when) {
}
}
+void InputDevice::updateExternalStylusState(const StylusState& state) {
+ size_t numMappers = mMappers.size();
+ for (size_t i = 0; i < numMappers; i++) {
+ InputMapper* mapper = mMappers[i];
+ mapper->updateExternalStylusState(state);
+ }
+}
+
void InputDevice::getDeviceInfo(InputDeviceInfo* outDeviceInfo) {
outDeviceInfo->initialize(mId, mGeneration, mControllerNumber, mIdentifier, mAlias,
- mIsExternal);
-
+ mIsExternal, mHasMic);
size_t numMappers = mMappers.size();
for (size_t i = 0; i < numMappers; i++) {
InputMapper* mapper = mMappers[i];
@@ -1285,7 +1356,9 @@ void TouchButtonAccumulator::configure(InputDevice* device) {
void TouchButtonAccumulator::reset(InputDevice* device) {
mBtnTouch = device->isKeyPressed(BTN_TOUCH);
mBtnStylus = device->isKeyPressed(BTN_STYLUS);
- mBtnStylus2 = device->isKeyPressed(BTN_STYLUS);
+ // BTN_0 is what gets mapped for the HID usage Digitizers.SecondaryBarrelSwitch
+ mBtnStylus2 =
+ device->isKeyPressed(BTN_STYLUS2) || device->isKeyPressed(BTN_0);
mBtnToolFinger = device->isKeyPressed(BTN_TOOL_FINGER);
mBtnToolPen = device->isKeyPressed(BTN_TOOL_PEN);
mBtnToolRubber = device->isKeyPressed(BTN_TOOL_RUBBER);
@@ -1326,6 +1399,7 @@ void TouchButtonAccumulator::process(const RawEvent* rawEvent) {
mBtnStylus = rawEvent->value;
break;
case BTN_STYLUS2:
+ case BTN_0:// BTN_0 is what gets mapped for the HID usage Digitizers.SecondaryBarrelSwitch
mBtnStylus2 = rawEvent->value;
break;
case BTN_TOOL_FINGER:
@@ -1368,10 +1442,10 @@ void TouchButtonAccumulator::process(const RawEvent* rawEvent) {
uint32_t TouchButtonAccumulator::getButtonState() const {
uint32_t result = 0;
if (mBtnStylus) {
- result |= AMOTION_EVENT_BUTTON_SECONDARY;
+ result |= AMOTION_EVENT_BUTTON_STYLUS_PRIMARY;
}
if (mBtnStylus2) {
- result |= AMOTION_EVENT_BUTTON_TERTIARY;
+ result |= AMOTION_EVENT_BUTTON_STYLUS_SECONDARY;
}
return result;
}
@@ -1801,6 +1875,10 @@ int32_t InputMapper::getMetaState() {
return 0;
}
+void InputMapper::updateExternalStylusState(const StylusState& state) {
+
+}
+
void InputMapper::fadePointer() {
}
@@ -1822,6 +1900,12 @@ void InputMapper::dumpRawAbsoluteAxisInfo(String8& dump,
}
}
+void InputMapper::dumpStylusState(String8& dump, const StylusState& state) {
+ dump.appendFormat(INDENT4 "When: %" PRId64 "\n", state.when);
+ dump.appendFormat(INDENT4 "Pressure: %f\n", state.pressure);
+ dump.appendFormat(INDENT4 "Button State: 0x%08x\n", state.buttons);
+ dump.appendFormat(INDENT4 "Tool Type: %" PRId32 "\n", state.toolType);
+}
// --- SwitchInputMapper ---
@@ -2463,7 +2547,8 @@ void CursorInputMapper::sync(nsecs_t when) {
}
nsecs_t downTime = mDownTime;
bool buttonsChanged = currentButtonState != lastButtonState;
- bool buttonsPressed = currentButtonState & ~lastButtonState;
+ int32_t buttonsPressed = currentButtonState & ~lastButtonState;
+ int32_t buttonsReleased = lastButtonState & ~currentButtonState;
float deltaX = mCursorMotionAccumulator.getRelativeX() * mXScale;
float deltaY = mCursorMotionAccumulator.getRelativeY() * mYScale;
@@ -2539,6 +2624,7 @@ void CursorInputMapper::sync(nsecs_t when) {
// Send motion event.
if (downChanged || moved || scrolled || buttonsChanged) {
int32_t metaState = mContext->getGlobalMetaState();
+ int32_t buttonState = lastButtonState;
int32_t motionEventAction;
if (downChanged) {
motionEventAction = down ? AMOTION_EVENT_ACTION_DOWN : AMOTION_EVENT_ACTION_UP;
@@ -2548,17 +2634,48 @@ void CursorInputMapper::sync(nsecs_t when) {
motionEventAction = AMOTION_EVENT_ACTION_HOVER_MOVE;
}
+ if (buttonsReleased) {
+ BitSet32 released(buttonsReleased);
+ while (!released.isEmpty()) {
+ int32_t actionButton = BitSet32::valueForBit(released.clearFirstMarkedBit());
+ buttonState &= ~actionButton;
+ NotifyMotionArgs releaseArgs(when, getDeviceId(), mSource, policyFlags,
+ AMOTION_EVENT_ACTION_BUTTON_RELEASE, actionButton, 0,
+ metaState, buttonState, AMOTION_EVENT_EDGE_FLAG_NONE,
+ displayId, 1, &pointerProperties, &pointerCoords,
+ mXPrecision, mYPrecision, downTime);
+ getListener()->notifyMotion(&releaseArgs);
+ }
+ }
+
NotifyMotionArgs args(when, getDeviceId(), mSource, policyFlags,
- motionEventAction, 0, metaState, currentButtonState, 0,
+ motionEventAction, 0, 0, metaState, currentButtonState,
+ AMOTION_EVENT_EDGE_FLAG_NONE,
displayId, 1, &pointerProperties, &pointerCoords,
mXPrecision, mYPrecision, downTime);
getListener()->notifyMotion(&args);
+ if (buttonsPressed) {
+ BitSet32 pressed(buttonsPressed);
+ while (!pressed.isEmpty()) {
+ int32_t actionButton = BitSet32::valueForBit(pressed.clearFirstMarkedBit());
+ buttonState |= actionButton;
+ NotifyMotionArgs pressArgs(when, getDeviceId(), mSource, policyFlags,
+ AMOTION_EVENT_ACTION_BUTTON_PRESS, actionButton, 0,
+ metaState, buttonState, AMOTION_EVENT_EDGE_FLAG_NONE,
+ displayId, 1, &pointerProperties, &pointerCoords,
+ mXPrecision, mYPrecision, downTime);
+ getListener()->notifyMotion(&pressArgs);
+ }
+ }
+
+ ALOG_ASSERT(buttonState == currentButtonState);
+
// Send hover move after UP to tell the application that the mouse is hovering now.
if (motionEventAction == AMOTION_EVENT_ACTION_UP
&& mPointerController != NULL) {
NotifyMotionArgs hoverArgs(when, getDeviceId(), mSource, policyFlags,
- AMOTION_EVENT_ACTION_HOVER_MOVE, 0,
+ AMOTION_EVENT_ACTION_HOVER_MOVE, 0, 0,
metaState, currentButtonState, AMOTION_EVENT_EDGE_FLAG_NONE,
displayId, 1, &pointerProperties, &pointerCoords,
mXPrecision, mYPrecision, downTime);
@@ -2571,7 +2688,7 @@ void CursorInputMapper::sync(nsecs_t when) {
pointerCoords.setAxisValue(AMOTION_EVENT_AXIS_HSCROLL, hscroll);
NotifyMotionArgs scrollArgs(when, getDeviceId(), mSource, policyFlags,
- AMOTION_EVENT_ACTION_SCROLL, 0, metaState, currentButtonState,
+ AMOTION_EVENT_ACTION_SCROLL, 0, 0, metaState, currentButtonState,
AMOTION_EVENT_EDGE_FLAG_NONE,
displayId, 1, &pointerProperties, &pointerCoords,
mXPrecision, mYPrecision, downTime);
@@ -2703,12 +2820,11 @@ void TouchInputMapper::dump(String8& dump) {
dump.appendFormat(INDENT4 "TiltYCenter: %0.3f\n", mTiltYCenter);
dump.appendFormat(INDENT4 "TiltYScale: %0.3f\n", mTiltYScale);
- dump.appendFormat(INDENT3 "Last Button State: 0x%08x\n", mLastButtonState);
-
+ dump.appendFormat(INDENT3 "Last Raw Button State: 0x%08x\n", mLastRawState.buttonState);
dump.appendFormat(INDENT3 "Last Raw Touch: pointerCount=%d\n",
- mLastRawPointerData.pointerCount);
- for (uint32_t i = 0; i < mLastRawPointerData.pointerCount; i++) {
- const RawPointerData::Pointer& pointer = mLastRawPointerData.pointers[i];
+ mLastRawState.rawPointerData.pointerCount);
+ for (uint32_t i = 0; i < mLastRawState.rawPointerData.pointerCount; i++) {
+ const RawPointerData::Pointer& pointer = mLastRawState.rawPointerData.pointers[i];
dump.appendFormat(INDENT4 "[%d]: id=%d, x=%d, y=%d, pressure=%d, "
"touchMajor=%d, touchMinor=%d, toolMajor=%d, toolMinor=%d, "
"orientation=%d, tiltX=%d, tiltY=%d, distance=%d, "
@@ -2720,11 +2836,13 @@ void TouchInputMapper::dump(String8& dump) {
pointer.toolType, toString(pointer.isHovering));
}
+ dump.appendFormat(INDENT3 "Last Cooked Button State: 0x%08x\n", mLastCookedState.buttonState);
dump.appendFormat(INDENT3 "Last Cooked Touch: pointerCount=%d\n",
- mLastCookedPointerData.pointerCount);
- for (uint32_t i = 0; i < mLastCookedPointerData.pointerCount; i++) {
- const PointerProperties& pointerProperties = mLastCookedPointerData.pointerProperties[i];
- const PointerCoords& pointerCoords = mLastCookedPointerData.pointerCoords[i];
+ mLastCookedState.cookedPointerData.pointerCount);
+ for (uint32_t i = 0; i < mLastCookedState.cookedPointerData.pointerCount; i++) {
+ const PointerProperties& pointerProperties =
+ mLastCookedState.cookedPointerData.pointerProperties[i];
+ const PointerCoords& pointerCoords = mLastCookedState.cookedPointerData.pointerCoords[i];
dump.appendFormat(INDENT4 "[%d]: id=%d, x=%0.3f, y=%0.3f, pressure=%0.3f, "
"touchMajor=%0.3f, touchMinor=%0.3f, toolMajor=%0.3f, toolMinor=%0.3f, "
"orientation=%0.3f, tilt=%0.3f, distance=%0.3f, "
@@ -2741,9 +2859,18 @@ void TouchInputMapper::dump(String8& dump) {
pointerCoords.getAxisValue(AMOTION_EVENT_AXIS_TILT),
pointerCoords.getAxisValue(AMOTION_EVENT_AXIS_DISTANCE),
pointerProperties.toolType,
- toString(mLastCookedPointerData.isHovering(i)));
+ toString(mLastCookedState.cookedPointerData.isHovering(i)));
}
+ dump.append(INDENT3 "Stylus Fusion:\n");
+ dump.appendFormat(INDENT4 "ExternalStylusConnected: %s\n",
+ toString(mExternalStylusConnected));
+ dump.appendFormat(INDENT4 "External Stylus ID: %" PRId64 "\n", mExternalStylusId);
+ dump.appendFormat(INDENT4 "External Stylus Data Timeout: %" PRId64 "\n",
+ mExternalStylusFusionTimeout);
+ dump.append(INDENT3 "External Stylus State:\n");
+ dumpStylusState(dump, mExternalStylusState);
+
if (mDeviceMode == DEVICE_MODE_POINTER) {
dump.appendFormat(INDENT3 "Pointer Gesture Detector:\n");
dump.appendFormat(INDENT4 "XMovementScale: %0.3f\n",
@@ -2781,7 +2908,7 @@ void TouchInputMapper::configure(nsecs_t when,
resolveCalibration();
}
- if (!changes || (changes & InputReaderConfiguration::TOUCH_AFFINE_TRANSFORMATION)) {
+ if (!changes || (changes & InputReaderConfiguration::CHANGE_TOUCH_AFFINE_TRANSFORMATION)) {
// Update location calibration to reflect current settings
updateAffineTransformation();
}
@@ -2796,7 +2923,8 @@ void TouchInputMapper::configure(nsecs_t when,
bool resetNeeded = false;
if (!changes || (changes & (InputReaderConfiguration::CHANGE_DISPLAY_INFO
| InputReaderConfiguration::CHANGE_POINTER_GESTURE_ENABLEMENT
- | InputReaderConfiguration::CHANGE_SHOW_TOUCHES))) {
+ | InputReaderConfiguration::CHANGE_SHOW_TOUCHES
+ | InputReaderConfiguration::CHANGE_EXTERNAL_STYLUS_PRESENCE))) {
// Configure device sources, surface dimensions, orientation and
// scaling factors.
configureSurface(when, &resetNeeded);
@@ -2809,6 +2937,16 @@ void TouchInputMapper::configure(nsecs_t when,
}
}
+void TouchInputMapper::resolveExternalStylusPresence() {
+ Vector<InputDeviceInfo> devices;
+ mContext->getExternalStylusDevices(devices);
+ mExternalStylusConnected = !devices.isEmpty();
+
+ if (!mExternalStylusConnected) {
+ resetExternalStylus();
+ }
+}
+
void TouchInputMapper::configureParameters() {
// Use the pointer presentation mode for devices that do not support distinct
// multitouch. The spot-based presentation relies on being able to accurately
@@ -2945,9 +3083,15 @@ void TouchInputMapper::dumpRawPointerAxes(String8& dump) {
dumpRawAbsoluteAxisInfo(dump, mRawPointerAxes.slot, "Slot");
}
+bool TouchInputMapper::hasExternalStylus() const {
+ return mExternalStylusConnected;
+}
+
void TouchInputMapper::configureSurface(nsecs_t when, bool* outResetNeeded) {
int32_t oldDeviceMode = mDeviceMode;
+ resolveExternalStylusPresence();
+
// Determine device mode.
if (mParameters.deviceType == Parameters::DEVICE_TYPE_POINTER
&& mConfig.pointerGesturesEnabled) {
@@ -2963,6 +3107,9 @@ void TouchInputMapper::configureSurface(nsecs_t when, bool* outResetNeeded) {
if (hasStylus()) {
mSource |= AINPUT_SOURCE_STYLUS;
}
+ if (hasExternalStylus()) {
+ mSource |= AINPUT_SOURCE_BLUETOOTH_STYLUS;
+ }
} else if (mParameters.deviceType == Parameters::DEVICE_TYPE_TOUCH_NAVIGATION) {
mSource = AINPUT_SOURCE_TOUCH_NAVIGATION;
mDeviceMode = DEVICE_MODE_NAVIGATION;
@@ -3705,28 +3852,22 @@ void TouchInputMapper::reset(nsecs_t when) {
mWheelXVelocityControl.reset();
mWheelYVelocityControl.reset();
- mCurrentRawPointerData.clear();
- mLastRawPointerData.clear();
- mCurrentCookedPointerData.clear();
- mLastCookedPointerData.clear();
- mCurrentButtonState = 0;
- mLastButtonState = 0;
- mCurrentRawVScroll = 0;
- mCurrentRawHScroll = 0;
- mCurrentFingerIdBits.clear();
- mLastFingerIdBits.clear();
- mCurrentStylusIdBits.clear();
- mLastStylusIdBits.clear();
- mCurrentMouseIdBits.clear();
- mLastMouseIdBits.clear();
+ mRawStatesPending.clear();
+ mCurrentRawState.clear();
+ mCurrentCookedState.clear();
+ mLastRawState.clear();
+ mLastCookedState.clear();
mPointerUsage = POINTER_USAGE_NONE;
mSentHoverEnter = false;
+ mHavePointerIds = false;
+ mCurrentMotionAborted = false;
mDownTime = 0;
mCurrentVirtualKey.down = false;
mPointerGesture.reset();
mPointerSimple.reset();
+ resetExternalStylus();
if (mPointerController != NULL) {
mPointerController->fade(PointerControllerInterface::TRANSITION_GRADUAL);
@@ -3736,6 +3877,18 @@ void TouchInputMapper::reset(nsecs_t when) {
InputMapper::reset(when);
}
+void TouchInputMapper::resetExternalStylus() {
+ mExternalStylusState.clear();
+ mExternalStylusId = -1;
+ mExternalStylusFusionTimeout = LLONG_MAX;
+ mExternalStylusDataPending = false;
+}
+
+void TouchInputMapper::clearStylusDataPendingFlags() {
+ mExternalStylusDataPending = false;
+ mExternalStylusFusionTimeout = LLONG_MAX;
+}
+
void TouchInputMapper::process(const RawEvent* rawEvent) {
mCursorButtonAccumulator.process(rawEvent);
mCursorScrollAccumulator.process(rawEvent);
@@ -3747,155 +3900,288 @@ void TouchInputMapper::process(const RawEvent* rawEvent) {
}
void TouchInputMapper::sync(nsecs_t when) {
+ const RawState* last = mRawStatesPending.isEmpty() ?
+ &mCurrentRawState : &mRawStatesPending.top();
+
+ // Push a new state.
+ mRawStatesPending.push();
+ RawState* next = &mRawStatesPending.editTop();
+ next->clear();
+ next->when = when;
+
// Sync button state.
- mCurrentButtonState = mTouchButtonAccumulator.getButtonState()
+ next->buttonState = mTouchButtonAccumulator.getButtonState()
| mCursorButtonAccumulator.getButtonState();
- // Sync scroll state.
- mCurrentRawVScroll = mCursorScrollAccumulator.getRelativeVWheel();
- mCurrentRawHScroll = mCursorScrollAccumulator.getRelativeHWheel();
+ // Sync scroll
+ next->rawVScroll = mCursorScrollAccumulator.getRelativeVWheel();
+ next->rawHScroll = mCursorScrollAccumulator.getRelativeHWheel();
mCursorScrollAccumulator.finishSync();
- // Sync touch state.
- bool havePointerIds = true;
- mCurrentRawPointerData.clear();
- syncTouch(when, &havePointerIds);
+ // Sync touch
+ syncTouch(when, next);
-#if DEBUG_RAW_EVENTS
- if (!havePointerIds) {
- ALOGD("syncTouch: pointerCount %d -> %d, no pointer ids",
- mLastRawPointerData.pointerCount,
- mCurrentRawPointerData.pointerCount);
- } else {
- ALOGD("syncTouch: pointerCount %d -> %d, touching ids 0x%08x -> 0x%08x, "
- "hovering ids 0x%08x -> 0x%08x",
- mLastRawPointerData.pointerCount,
- mCurrentRawPointerData.pointerCount,
- mLastRawPointerData.touchingIdBits.value,
- mCurrentRawPointerData.touchingIdBits.value,
- mLastRawPointerData.hoveringIdBits.value,
- mCurrentRawPointerData.hoveringIdBits.value);
+ // Assign pointer ids.
+ if (!mHavePointerIds) {
+ assignPointerIds(last, next);
}
+
+#if DEBUG_RAW_EVENTS
+ ALOGD("syncTouch: pointerCount %d -> %d, touching ids 0x%08x -> 0x%08x, "
+ "hovering ids 0x%08x -> 0x%08x",
+ last->rawPointerData.pointerCount,
+ next->rawPointerData.pointerCount,
+ last->rawPointerData.touchingIdBits.value,
+ next->rawPointerData.touchingIdBits.value,
+ last->rawPointerData.hoveringIdBits.value,
+ next->rawPointerData.hoveringIdBits.value);
#endif
- // Reset state that we will compute below.
- mCurrentFingerIdBits.clear();
- mCurrentStylusIdBits.clear();
- mCurrentMouseIdBits.clear();
- mCurrentCookedPointerData.clear();
+ processRawTouches(false /*timeout*/);
+}
+void TouchInputMapper::processRawTouches(bool timeout) {
if (mDeviceMode == DEVICE_MODE_DISABLED) {
// Drop all input if the device is disabled.
- mCurrentRawPointerData.clear();
- mCurrentButtonState = 0;
- } else {
- // Preprocess pointer data.
- if (!havePointerIds) {
- assignPointerIds();
- }
-
- // Handle policy on initial down or hover events.
- uint32_t policyFlags = 0;
- bool initialDown = mLastRawPointerData.pointerCount == 0
- && mCurrentRawPointerData.pointerCount != 0;
- bool buttonsPressed = mCurrentButtonState & ~mLastButtonState;
- if (initialDown || buttonsPressed) {
- // If this is a touch screen, hide the pointer on an initial down.
- if (mDeviceMode == DEVICE_MODE_DIRECT) {
- getContext()->fadePointer();
- }
+ mCurrentRawState.clear();
+ mRawStatesPending.clear();
+ return;
+ }
- if (mParameters.wake) {
- policyFlags |= POLICY_FLAG_WAKE;
- }
+ // Drain any pending touch states. The invariant here is that the mCurrentRawState is always
+ // valid and must go through the full cook and dispatch cycle. This ensures that anything
+ // touching the current state will only observe the events that have been dispatched to the
+ // rest of the pipeline.
+ const size_t N = mRawStatesPending.size();
+ size_t count;
+ for(count = 0; count < N; count++) {
+ const RawState& next = mRawStatesPending[count];
+
+ // A failure to assign the stylus id means that we're waiting on stylus data
+ // and so should defer the rest of the pipeline.
+ if (assignExternalStylusId(next, timeout)) {
+ break;
+ }
+
+ // All ready to go.
+ clearStylusDataPendingFlags();
+ mCurrentRawState.copyFrom(next);
+ if (mCurrentRawState.when < mLastRawState.when) {
+ mCurrentRawState.when = mLastRawState.when;
+ }
+ cookAndDispatch(mCurrentRawState.when);
+ }
+ if (count != 0) {
+ mRawStatesPending.removeItemsAt(0, count);
+ }
+
+ if (mExternalStylusDataPending) {
+ if (timeout) {
+ nsecs_t when = mExternalStylusFusionTimeout - STYLUS_DATA_LATENCY;
+ clearStylusDataPendingFlags();
+ mCurrentRawState.copyFrom(mLastRawState);
+#if DEBUG_STYLUS_FUSION
+ ALOGD("Timeout expired, synthesizing event with new stylus data");
+#endif
+ cookAndDispatch(when);
+ } else if (mExternalStylusFusionTimeout == LLONG_MAX) {
+ mExternalStylusFusionTimeout = mExternalStylusState.when + TOUCH_DATA_TIMEOUT;
+ getContext()->requestTimeoutAtTime(mExternalStylusFusionTimeout);
}
+ }
+}
+
+void TouchInputMapper::cookAndDispatch(nsecs_t when) {
+ // Always start with a clean state.
+ mCurrentCookedState.clear();
+
+ // Apply stylus buttons to current raw state.
+ applyExternalStylusButtonState(when);
+
+ // Handle policy on initial down or hover events.
+ bool initialDown = mLastRawState.rawPointerData.pointerCount == 0
+ && mCurrentRawState.rawPointerData.pointerCount != 0;
- // Synthesize key down from raw buttons if needed.
- synthesizeButtonKeys(getContext(), AKEY_EVENT_ACTION_DOWN, when, getDeviceId(), mSource,
- policyFlags, mLastButtonState, mCurrentButtonState);
+ uint32_t policyFlags = 0;
+ bool buttonsPressed = mCurrentRawState.buttonState & ~mLastRawState.buttonState;
+ if (initialDown || buttonsPressed) {
+ // If this is a touch screen, hide the pointer on an initial down.
+ if (mDeviceMode == DEVICE_MODE_DIRECT) {
+ getContext()->fadePointer();
+ }
- // Consume raw off-screen touches before cooking pointer data.
- // If touches are consumed, subsequent code will not receive any pointer data.
- if (consumeRawTouches(when, policyFlags)) {
- mCurrentRawPointerData.clear();
+ if (mParameters.wake) {
+ policyFlags |= POLICY_FLAG_WAKE;
}
+ }
- // Cook pointer data. This call populates the mCurrentCookedPointerData structure
- // with cooked pointer data that has the same ids and indices as the raw data.
- // The following code can use either the raw or cooked data, as needed.
- cookPointerData();
+ // Consume raw off-screen touches before cooking pointer data.
+ // If touches are consumed, subsequent code will not receive any pointer data.
+ if (consumeRawTouches(when, policyFlags)) {
+ mCurrentRawState.rawPointerData.clear();
+ }
- // Dispatch the touches either directly or by translation through a pointer on screen.
- if (mDeviceMode == DEVICE_MODE_POINTER) {
- for (BitSet32 idBits(mCurrentRawPointerData.touchingIdBits); !idBits.isEmpty(); ) {
- uint32_t id = idBits.clearFirstMarkedBit();
- const RawPointerData::Pointer& pointer = mCurrentRawPointerData.pointerForId(id);
- if (pointer.toolType == AMOTION_EVENT_TOOL_TYPE_STYLUS
- || pointer.toolType == AMOTION_EVENT_TOOL_TYPE_ERASER) {
- mCurrentStylusIdBits.markBit(id);
- } else if (pointer.toolType == AMOTION_EVENT_TOOL_TYPE_FINGER
- || pointer.toolType == AMOTION_EVENT_TOOL_TYPE_UNKNOWN) {
- mCurrentFingerIdBits.markBit(id);
- } else if (pointer.toolType == AMOTION_EVENT_TOOL_TYPE_MOUSE) {
- mCurrentMouseIdBits.markBit(id);
- }
+ // Cook pointer data. This call populates the mCurrentCookedState.cookedPointerData structure
+ // with cooked pointer data that has the same ids and indices as the raw data.
+ // The following code can use either the raw or cooked data, as needed.
+ cookPointerData();
+
+ // Apply stylus pressure to current cooked state.
+ applyExternalStylusTouchState(when);
+
+ // Synthesize key down from raw buttons if needed.
+ synthesizeButtonKeys(getContext(), AKEY_EVENT_ACTION_DOWN, when, getDeviceId(), mSource,
+ policyFlags, mLastCookedState.buttonState, mCurrentCookedState.buttonState);
+
+ // Dispatch the touches either directly or by translation through a pointer on screen.
+ if (mDeviceMode == DEVICE_MODE_POINTER) {
+ for (BitSet32 idBits(mCurrentRawState.rawPointerData.touchingIdBits);
+ !idBits.isEmpty(); ) {
+ uint32_t id = idBits.clearFirstMarkedBit();
+ const RawPointerData::Pointer& pointer =
+ mCurrentRawState.rawPointerData.pointerForId(id);
+ if (pointer.toolType == AMOTION_EVENT_TOOL_TYPE_STYLUS
+ || pointer.toolType == AMOTION_EVENT_TOOL_TYPE_ERASER) {
+ mCurrentCookedState.stylusIdBits.markBit(id);
+ } else if (pointer.toolType == AMOTION_EVENT_TOOL_TYPE_FINGER
+ || pointer.toolType == AMOTION_EVENT_TOOL_TYPE_UNKNOWN) {
+ mCurrentCookedState.fingerIdBits.markBit(id);
+ } else if (pointer.toolType == AMOTION_EVENT_TOOL_TYPE_MOUSE) {
+ mCurrentCookedState.mouseIdBits.markBit(id);
}
- for (BitSet32 idBits(mCurrentRawPointerData.hoveringIdBits); !idBits.isEmpty(); ) {
- uint32_t id = idBits.clearFirstMarkedBit();
- const RawPointerData::Pointer& pointer = mCurrentRawPointerData.pointerForId(id);
- if (pointer.toolType == AMOTION_EVENT_TOOL_TYPE_STYLUS
- || pointer.toolType == AMOTION_EVENT_TOOL_TYPE_ERASER) {
- mCurrentStylusIdBits.markBit(id);
- }
+ }
+ for (BitSet32 idBits(mCurrentRawState.rawPointerData.hoveringIdBits);
+ !idBits.isEmpty(); ) {
+ uint32_t id = idBits.clearFirstMarkedBit();
+ const RawPointerData::Pointer& pointer =
+ mCurrentRawState.rawPointerData.pointerForId(id);
+ if (pointer.toolType == AMOTION_EVENT_TOOL_TYPE_STYLUS
+ || pointer.toolType == AMOTION_EVENT_TOOL_TYPE_ERASER) {
+ mCurrentCookedState.stylusIdBits.markBit(id);
}
+ }
- // Stylus takes precedence over all tools, then mouse, then finger.
- PointerUsage pointerUsage = mPointerUsage;
- if (!mCurrentStylusIdBits.isEmpty()) {
- mCurrentMouseIdBits.clear();
- mCurrentFingerIdBits.clear();
- pointerUsage = POINTER_USAGE_STYLUS;
- } else if (!mCurrentMouseIdBits.isEmpty()) {
- mCurrentFingerIdBits.clear();
- pointerUsage = POINTER_USAGE_MOUSE;
- } else if (!mCurrentFingerIdBits.isEmpty() || isPointerDown(mCurrentButtonState)) {
- pointerUsage = POINTER_USAGE_GESTURES;
- }
+ // Stylus takes precedence over all tools, then mouse, then finger.
+ PointerUsage pointerUsage = mPointerUsage;
+ if (!mCurrentCookedState.stylusIdBits.isEmpty()) {
+ mCurrentCookedState.mouseIdBits.clear();
+ mCurrentCookedState.fingerIdBits.clear();
+ pointerUsage = POINTER_USAGE_STYLUS;
+ } else if (!mCurrentCookedState.mouseIdBits.isEmpty()) {
+ mCurrentCookedState.fingerIdBits.clear();
+ pointerUsage = POINTER_USAGE_MOUSE;
+ } else if (!mCurrentCookedState.fingerIdBits.isEmpty() ||
+ isPointerDown(mCurrentRawState.buttonState)) {
+ pointerUsage = POINTER_USAGE_GESTURES;
+ }
- dispatchPointerUsage(when, policyFlags, pointerUsage);
- } else {
- if (mDeviceMode == DEVICE_MODE_DIRECT
- && mConfig.showTouches && mPointerController != NULL) {
- mPointerController->setPresentation(PointerControllerInterface::PRESENTATION_SPOT);
- mPointerController->fade(PointerControllerInterface::TRANSITION_GRADUAL);
-
- mPointerController->setButtonState(mCurrentButtonState);
- mPointerController->setSpots(mCurrentCookedPointerData.pointerCoords,
- mCurrentCookedPointerData.idToIndex,
- mCurrentCookedPointerData.touchingIdBits);
- }
+ dispatchPointerUsage(when, policyFlags, pointerUsage);
+ } else {
+ if (mDeviceMode == DEVICE_MODE_DIRECT
+ && mConfig.showTouches && mPointerController != NULL) {
+ mPointerController->setPresentation(PointerControllerInterface::PRESENTATION_SPOT);
+ mPointerController->fade(PointerControllerInterface::TRANSITION_GRADUAL);
+ mPointerController->setButtonState(mCurrentRawState.buttonState);
+ mPointerController->setSpots(mCurrentCookedState.cookedPointerData.pointerCoords,
+ mCurrentCookedState.cookedPointerData.idToIndex,
+ mCurrentCookedState.cookedPointerData.touchingIdBits);
+ }
+
+ if (!mCurrentMotionAborted) {
+ dispatchButtonRelease(when, policyFlags);
dispatchHoverExit(when, policyFlags);
dispatchTouches(when, policyFlags);
dispatchHoverEnterAndMove(when, policyFlags);
+ dispatchButtonPress(when, policyFlags);
}
- // Synthesize key up from raw buttons if needed.
- synthesizeButtonKeys(getContext(), AKEY_EVENT_ACTION_UP, when, getDeviceId(), mSource,
- policyFlags, mLastButtonState, mCurrentButtonState);
+ if (mCurrentCookedState.cookedPointerData.pointerCount == 0) {
+ mCurrentMotionAborted = false;
+ }
}
- // Copy current touch to last touch in preparation for the next cycle.
- mLastRawPointerData.copyFrom(mCurrentRawPointerData);
- mLastCookedPointerData.copyFrom(mCurrentCookedPointerData);
- mLastButtonState = mCurrentButtonState;
- mLastFingerIdBits = mCurrentFingerIdBits;
- mLastStylusIdBits = mCurrentStylusIdBits;
- mLastMouseIdBits = mCurrentMouseIdBits;
+ // Synthesize key up from raw buttons if needed.
+ synthesizeButtonKeys(getContext(), AKEY_EVENT_ACTION_UP, when, getDeviceId(), mSource,
+ policyFlags, mLastCookedState.buttonState, mCurrentCookedState.buttonState);
// Clear some transient state.
- mCurrentRawVScroll = 0;
- mCurrentRawHScroll = 0;
+ mCurrentRawState.rawVScroll = 0;
+ mCurrentRawState.rawHScroll = 0;
+
+ // Copy current touch to last touch in preparation for the next cycle.
+ mLastRawState.copyFrom(mCurrentRawState);
+ mLastCookedState.copyFrom(mCurrentCookedState);
+}
+
+void TouchInputMapper::applyExternalStylusButtonState(nsecs_t when) {
+ if (mDeviceMode == DEVICE_MODE_DIRECT && hasExternalStylus() && mExternalStylusId != -1) {
+ mCurrentRawState.buttonState |= mExternalStylusState.buttons;
+ }
+}
+
+void TouchInputMapper::applyExternalStylusTouchState(nsecs_t when) {
+ CookedPointerData& currentPointerData = mCurrentCookedState.cookedPointerData;
+ const CookedPointerData& lastPointerData = mLastCookedState.cookedPointerData;
+
+ if (mExternalStylusId != -1 && currentPointerData.isTouching(mExternalStylusId)) {
+ float pressure = mExternalStylusState.pressure;
+ if (pressure == 0.0f && lastPointerData.isTouching(mExternalStylusId)) {
+ const PointerCoords& coords = lastPointerData.pointerCoordsForId(mExternalStylusId);
+ pressure = coords.getAxisValue(AMOTION_EVENT_AXIS_PRESSURE);
+ }
+ PointerCoords& coords = currentPointerData.editPointerCoordsWithId(mExternalStylusId);
+ coords.setAxisValue(AMOTION_EVENT_AXIS_PRESSURE, pressure);
+
+ PointerProperties& properties =
+ currentPointerData.editPointerPropertiesWithId(mExternalStylusId);
+ if (mExternalStylusState.toolType != AMOTION_EVENT_TOOL_TYPE_UNKNOWN) {
+ properties.toolType = mExternalStylusState.toolType;
+ }
+ }
+}
+
+bool TouchInputMapper::assignExternalStylusId(const RawState& state, bool timeout) {
+ if (mDeviceMode != DEVICE_MODE_DIRECT || !hasExternalStylus()) {
+ return false;
+ }
+
+ const bool initialDown = mLastRawState.rawPointerData.pointerCount == 0
+ && state.rawPointerData.pointerCount != 0;
+ if (initialDown) {
+ if (mExternalStylusState.pressure != 0.0f) {
+#if DEBUG_STYLUS_FUSION
+ ALOGD("Have both stylus and touch data, beginning fusion");
+#endif
+ mExternalStylusId = state.rawPointerData.touchingIdBits.firstMarkedBit();
+ } else if (timeout) {
+#if DEBUG_STYLUS_FUSION
+ ALOGD("Timeout expired, assuming touch is not a stylus.");
+#endif
+ resetExternalStylus();
+ } else {
+ if (mExternalStylusFusionTimeout == LLONG_MAX) {
+ mExternalStylusFusionTimeout = state.when + EXTERNAL_STYLUS_DATA_TIMEOUT;
+ }
+#if DEBUG_STYLUS_FUSION
+ ALOGD("No stylus data but stylus is connected, requesting timeout "
+ "(%" PRId64 "ms)", mExternalStylusFusionTimeout);
+#endif
+ getContext()->requestTimeoutAtTime(mExternalStylusFusionTimeout);
+ return true;
+ }
+ }
+
+ // Check if the stylus pointer has gone up.
+ if (mExternalStylusId != -1 &&
+ !state.rawPointerData.touchingIdBits.hasBit(mExternalStylusId)) {
+#if DEBUG_STYLUS_FUSION
+ ALOGD("Stylus pointer is going up");
+#endif
+ mExternalStylusId = -1;
+ }
+
+ return false;
}
void TouchInputMapper::timeoutExpired(nsecs_t when) {
@@ -3903,13 +4189,30 @@ void TouchInputMapper::timeoutExpired(nsecs_t when) {
if (mPointerUsage == POINTER_USAGE_GESTURES) {
dispatchPointerGestures(when, 0 /*policyFlags*/, true /*isTimeout*/);
}
+ } else if (mDeviceMode == DEVICE_MODE_DIRECT) {
+ if (mExternalStylusFusionTimeout < when) {
+ processRawTouches(true /*timeout*/);
+ } else if (mExternalStylusFusionTimeout != LLONG_MAX) {
+ getContext()->requestTimeoutAtTime(mExternalStylusFusionTimeout);
+ }
+ }
+}
+
+void TouchInputMapper::updateExternalStylusState(const StylusState& state) {
+ mExternalStylusState.copyFrom(state);
+ if (mExternalStylusId != -1 || mExternalStylusFusionTimeout != LLONG_MAX) {
+ // We're either in the middle of a fused stream of data or we're waiting on data before
+ // dispatching the initial down, so go ahead and dispatch now that we have fresh stylus
+ // data.
+ mExternalStylusDataPending = true;
+ processRawTouches(false /*timeout*/);
}
}
bool TouchInputMapper::consumeRawTouches(nsecs_t when, uint32_t policyFlags) {
// Check for release of a virtual key.
if (mCurrentVirtualKey.down) {
- if (mCurrentRawPointerData.touchingIdBits.isEmpty()) {
+ if (mCurrentRawState.rawPointerData.touchingIdBits.isEmpty()) {
// Pointer went up while virtual key was down.
mCurrentVirtualKey.down = false;
if (!mCurrentVirtualKey.ignored) {
@@ -3924,9 +4227,10 @@ bool TouchInputMapper::consumeRawTouches(nsecs_t when, uint32_t policyFlags) {
return true;
}
- if (mCurrentRawPointerData.touchingIdBits.count() == 1) {
- uint32_t id = mCurrentRawPointerData.touchingIdBits.firstMarkedBit();
- const RawPointerData::Pointer& pointer = mCurrentRawPointerData.pointerForId(id);
+ if (mCurrentRawState.rawPointerData.touchingIdBits.count() == 1) {
+ uint32_t id = mCurrentRawState.rawPointerData.touchingIdBits.firstMarkedBit();
+ const RawPointerData::Pointer& pointer =
+ mCurrentRawState.rawPointerData.pointerForId(id);
const VirtualKey* virtualKey = findVirtualKeyHit(pointer.x, pointer.y);
if (virtualKey && virtualKey->keyCode == mCurrentVirtualKey.keyCode) {
// Pointer is still within the space of the virtual key.
@@ -3951,15 +4255,15 @@ bool TouchInputMapper::consumeRawTouches(nsecs_t when, uint32_t policyFlags) {
}
}
- if (mLastRawPointerData.touchingIdBits.isEmpty()
- && !mCurrentRawPointerData.touchingIdBits.isEmpty()) {
+ if (mLastRawState.rawPointerData.touchingIdBits.isEmpty()
+ && !mCurrentRawState.rawPointerData.touchingIdBits.isEmpty()) {
// Pointer just went down. Check for virtual key press or off-screen touches.
- uint32_t id = mCurrentRawPointerData.touchingIdBits.firstMarkedBit();
- const RawPointerData::Pointer& pointer = mCurrentRawPointerData.pointerForId(id);
+ uint32_t id = mCurrentRawState.rawPointerData.touchingIdBits.firstMarkedBit();
+ const RawPointerData::Pointer& pointer = mCurrentRawState.rawPointerData.pointerForId(id);
if (!isPointInsideSurface(pointer.x, pointer.y)) {
// If exactly one pointer went down, check for virtual key hit.
// Otherwise we will drop the entire stroke.
- if (mCurrentRawPointerData.touchingIdBits.count() == 1) {
+ if (mCurrentRawState.rawPointerData.touchingIdBits.count() == 1) {
const VirtualKey* virtualKey = findVirtualKeyHit(pointer.x, pointer.y);
if (virtualKey) {
mCurrentVirtualKey.down = true;
@@ -3999,7 +4303,8 @@ bool TouchInputMapper::consumeRawTouches(nsecs_t when, uint32_t policyFlags) {
// area and accidentally triggers a virtual key. This often happens when virtual keys
// are layed out below the screen near to where the on screen keyboard's space bar
// is displayed.
- if (mConfig.virtualKeyQuietTime > 0 && !mCurrentRawPointerData.touchingIdBits.isEmpty()) {
+ if (mConfig.virtualKeyQuietTime > 0 &&
+ !mCurrentRawState.rawPointerData.touchingIdBits.isEmpty()) {
mContext->disableVirtualKeysUntil(when + mConfig.virtualKeyQuietTime);
}
return false;
@@ -4018,22 +4323,38 @@ void TouchInputMapper::dispatchVirtualKey(nsecs_t when, uint32_t policyFlags,
getListener()->notifyKey(&args);
}
+void TouchInputMapper::abortTouches(nsecs_t when, uint32_t policyFlags) {
+ BitSet32 currentIdBits = mCurrentCookedState.cookedPointerData.touchingIdBits;
+ if (!currentIdBits.isEmpty()) {
+ int32_t metaState = getContext()->getGlobalMetaState();
+ int32_t buttonState = mCurrentCookedState.buttonState;
+ dispatchMotion(when, policyFlags, mSource, AMOTION_EVENT_ACTION_CANCEL, 0, 0,
+ metaState, buttonState, AMOTION_EVENT_EDGE_FLAG_NONE,
+ mCurrentCookedState.cookedPointerData.pointerProperties,
+ mCurrentCookedState.cookedPointerData.pointerCoords,
+ mCurrentCookedState.cookedPointerData.idToIndex,
+ currentIdBits, -1,
+ mOrientedXPrecision, mOrientedYPrecision, mDownTime);
+ mCurrentMotionAborted = true;
+ }
+}
+
void TouchInputMapper::dispatchTouches(nsecs_t when, uint32_t policyFlags) {
- BitSet32 currentIdBits = mCurrentCookedPointerData.touchingIdBits;
- BitSet32 lastIdBits = mLastCookedPointerData.touchingIdBits;
+ BitSet32 currentIdBits = mCurrentCookedState.cookedPointerData.touchingIdBits;
+ BitSet32 lastIdBits = mLastCookedState.cookedPointerData.touchingIdBits;
int32_t metaState = getContext()->getGlobalMetaState();
- int32_t buttonState = mCurrentButtonState;
+ int32_t buttonState = mCurrentCookedState.buttonState;
if (currentIdBits == lastIdBits) {
if (!currentIdBits.isEmpty()) {
// No pointer id changes so this is a move event.
// The listener takes care of batching moves so we don't have to deal with that here.
dispatchMotion(when, policyFlags, mSource,
- AMOTION_EVENT_ACTION_MOVE, 0, metaState, buttonState,
+ AMOTION_EVENT_ACTION_MOVE, 0, 0, metaState, buttonState,
AMOTION_EVENT_EDGE_FLAG_NONE,
- mCurrentCookedPointerData.pointerProperties,
- mCurrentCookedPointerData.pointerCoords,
- mCurrentCookedPointerData.idToIndex,
+ mCurrentCookedState.cookedPointerData.pointerProperties,
+ mCurrentCookedState.cookedPointerData.pointerCoords,
+ mCurrentCookedState.cookedPointerData.idToIndex,
currentIdBits, -1,
mOrientedXPrecision, mOrientedYPrecision, mDownTime);
}
@@ -4048,14 +4369,14 @@ void TouchInputMapper::dispatchTouches(nsecs_t when, uint32_t policyFlags) {
// Update last coordinates of pointers that have moved so that we observe the new
// pointer positions at the same time as other pointers that have just gone up.
bool moveNeeded = updateMovedPointers(
- mCurrentCookedPointerData.pointerProperties,
- mCurrentCookedPointerData.pointerCoords,
- mCurrentCookedPointerData.idToIndex,
- mLastCookedPointerData.pointerProperties,
- mLastCookedPointerData.pointerCoords,
- mLastCookedPointerData.idToIndex,
+ mCurrentCookedState.cookedPointerData.pointerProperties,
+ mCurrentCookedState.cookedPointerData.pointerCoords,
+ mCurrentCookedState.cookedPointerData.idToIndex,
+ mLastCookedState.cookedPointerData.pointerProperties,
+ mLastCookedState.cookedPointerData.pointerCoords,
+ mLastCookedState.cookedPointerData.idToIndex,
moveIdBits);
- if (buttonState != mLastButtonState) {
+ if (buttonState != mLastCookedState.buttonState) {
moveNeeded = true;
}
@@ -4064,27 +4385,25 @@ void TouchInputMapper::dispatchTouches(nsecs_t when, uint32_t policyFlags) {
uint32_t upId = upIdBits.clearFirstMarkedBit();
dispatchMotion(when, policyFlags, mSource,
- AMOTION_EVENT_ACTION_POINTER_UP, 0, metaState, buttonState, 0,
- mLastCookedPointerData.pointerProperties,
- mLastCookedPointerData.pointerCoords,
- mLastCookedPointerData.idToIndex,
- dispatchedIdBits, upId,
- mOrientedXPrecision, mOrientedYPrecision, mDownTime);
+ AMOTION_EVENT_ACTION_POINTER_UP, 0, 0, metaState, buttonState, 0,
+ mLastCookedState.cookedPointerData.pointerProperties,
+ mLastCookedState.cookedPointerData.pointerCoords,
+ mLastCookedState.cookedPointerData.idToIndex,
+ dispatchedIdBits, upId, mOrientedXPrecision, mOrientedYPrecision, mDownTime);
dispatchedIdBits.clearBit(upId);
}
// Dispatch move events if any of the remaining pointers moved from their old locations.
// Although applications receive new locations as part of individual pointer up
// events, they do not generally handle them except when presented in a move event.
- if (moveNeeded) {
+ if (moveNeeded && !moveIdBits.isEmpty()) {
ALOG_ASSERT(moveIdBits.value == dispatchedIdBits.value);
dispatchMotion(when, policyFlags, mSource,
- AMOTION_EVENT_ACTION_MOVE, 0, metaState, buttonState, 0,
- mCurrentCookedPointerData.pointerProperties,
- mCurrentCookedPointerData.pointerCoords,
- mCurrentCookedPointerData.idToIndex,
- dispatchedIdBits, -1,
- mOrientedXPrecision, mOrientedYPrecision, mDownTime);
+ AMOTION_EVENT_ACTION_MOVE, 0, 0, metaState, buttonState, 0,
+ mCurrentCookedState.cookedPointerData.pointerProperties,
+ mCurrentCookedState.cookedPointerData.pointerCoords,
+ mCurrentCookedState.cookedPointerData.idToIndex,
+ dispatchedIdBits, -1, mOrientedXPrecision, mOrientedYPrecision, mDownTime);
}
// Dispatch pointer down events using the new pointer locations.
@@ -4098,69 +4417,119 @@ void TouchInputMapper::dispatchTouches(nsecs_t when, uint32_t policyFlags) {
}
dispatchMotion(when, policyFlags, mSource,
- AMOTION_EVENT_ACTION_POINTER_DOWN, 0, metaState, buttonState, 0,
- mCurrentCookedPointerData.pointerProperties,
- mCurrentCookedPointerData.pointerCoords,
- mCurrentCookedPointerData.idToIndex,
- dispatchedIdBits, downId,
- mOrientedXPrecision, mOrientedYPrecision, mDownTime);
+ AMOTION_EVENT_ACTION_POINTER_DOWN, 0, 0, metaState, buttonState, 0,
+ mCurrentCookedState.cookedPointerData.pointerProperties,
+ mCurrentCookedState.cookedPointerData.pointerCoords,
+ mCurrentCookedState.cookedPointerData.idToIndex,
+ dispatchedIdBits, downId, mOrientedXPrecision, mOrientedYPrecision, mDownTime);
}
}
}
void TouchInputMapper::dispatchHoverExit(nsecs_t when, uint32_t policyFlags) {
if (mSentHoverEnter &&
- (mCurrentCookedPointerData.hoveringIdBits.isEmpty()
- || !mCurrentCookedPointerData.touchingIdBits.isEmpty())) {
+ (mCurrentCookedState.cookedPointerData.hoveringIdBits.isEmpty()
+ || !mCurrentCookedState.cookedPointerData.touchingIdBits.isEmpty())) {
int32_t metaState = getContext()->getGlobalMetaState();
dispatchMotion(when, policyFlags, mSource,
- AMOTION_EVENT_ACTION_HOVER_EXIT, 0, metaState, mLastButtonState, 0,
- mLastCookedPointerData.pointerProperties,
- mLastCookedPointerData.pointerCoords,
- mLastCookedPointerData.idToIndex,
- mLastCookedPointerData.hoveringIdBits, -1,
+ AMOTION_EVENT_ACTION_HOVER_EXIT, 0, 0, metaState, mLastCookedState.buttonState, 0,
+ mLastCookedState.cookedPointerData.pointerProperties,
+ mLastCookedState.cookedPointerData.pointerCoords,
+ mLastCookedState.cookedPointerData.idToIndex,
+ mLastCookedState.cookedPointerData.hoveringIdBits, -1,
mOrientedXPrecision, mOrientedYPrecision, mDownTime);
mSentHoverEnter = false;
}
}
void TouchInputMapper::dispatchHoverEnterAndMove(nsecs_t when, uint32_t policyFlags) {
- if (mCurrentCookedPointerData.touchingIdBits.isEmpty()
- && !mCurrentCookedPointerData.hoveringIdBits.isEmpty()) {
+ if (mCurrentCookedState.cookedPointerData.touchingIdBits.isEmpty()
+ && !mCurrentCookedState.cookedPointerData.hoveringIdBits.isEmpty()) {
int32_t metaState = getContext()->getGlobalMetaState();
if (!mSentHoverEnter) {
- dispatchMotion(when, policyFlags, mSource,
- AMOTION_EVENT_ACTION_HOVER_ENTER, 0, metaState, mCurrentButtonState, 0,
- mCurrentCookedPointerData.pointerProperties,
- mCurrentCookedPointerData.pointerCoords,
- mCurrentCookedPointerData.idToIndex,
- mCurrentCookedPointerData.hoveringIdBits, -1,
+ dispatchMotion(when, policyFlags, mSource, AMOTION_EVENT_ACTION_HOVER_ENTER,
+ 0, 0, metaState, mCurrentRawState.buttonState, 0,
+ mCurrentCookedState.cookedPointerData.pointerProperties,
+ mCurrentCookedState.cookedPointerData.pointerCoords,
+ mCurrentCookedState.cookedPointerData.idToIndex,
+ mCurrentCookedState.cookedPointerData.hoveringIdBits, -1,
mOrientedXPrecision, mOrientedYPrecision, mDownTime);
mSentHoverEnter = true;
}
dispatchMotion(when, policyFlags, mSource,
- AMOTION_EVENT_ACTION_HOVER_MOVE, 0, metaState, mCurrentButtonState, 0,
- mCurrentCookedPointerData.pointerProperties,
- mCurrentCookedPointerData.pointerCoords,
- mCurrentCookedPointerData.idToIndex,
- mCurrentCookedPointerData.hoveringIdBits, -1,
+ AMOTION_EVENT_ACTION_HOVER_MOVE, 0, 0, metaState,
+ mCurrentRawState.buttonState, 0,
+ mCurrentCookedState.cookedPointerData.pointerProperties,
+ mCurrentCookedState.cookedPointerData.pointerCoords,
+ mCurrentCookedState.cookedPointerData.idToIndex,
+ mCurrentCookedState.cookedPointerData.hoveringIdBits, -1,
mOrientedXPrecision, mOrientedYPrecision, mDownTime);
}
}
+void TouchInputMapper::dispatchButtonRelease(nsecs_t when, uint32_t policyFlags) {
+ BitSet32 releasedButtons(mLastCookedState.buttonState & ~mCurrentCookedState.buttonState);
+ const BitSet32& idBits = findActiveIdBits(mLastCookedState.cookedPointerData);
+ const int32_t metaState = getContext()->getGlobalMetaState();
+ int32_t buttonState = mLastCookedState.buttonState;
+ while (!releasedButtons.isEmpty()) {
+ int32_t actionButton = BitSet32::valueForBit(releasedButtons.clearFirstMarkedBit());
+ buttonState &= ~actionButton;
+ dispatchMotion(when, policyFlags, mSource,
+ AMOTION_EVENT_ACTION_BUTTON_RELEASE, actionButton,
+ 0, metaState, buttonState, 0,
+ mCurrentCookedState.cookedPointerData.pointerProperties,
+ mCurrentCookedState.cookedPointerData.pointerCoords,
+ mCurrentCookedState.cookedPointerData.idToIndex, idBits, -1,
+ mOrientedXPrecision, mOrientedYPrecision, mDownTime);
+ }
+}
+
+void TouchInputMapper::dispatchButtonPress(nsecs_t when, uint32_t policyFlags) {
+ BitSet32 pressedButtons(mCurrentCookedState.buttonState & ~mLastCookedState.buttonState);
+ const BitSet32& idBits = findActiveIdBits(mCurrentCookedState.cookedPointerData);
+ const int32_t metaState = getContext()->getGlobalMetaState();
+ int32_t buttonState = mLastCookedState.buttonState;
+ while (!pressedButtons.isEmpty()) {
+ int32_t actionButton = BitSet32::valueForBit(pressedButtons.clearFirstMarkedBit());
+ buttonState |= actionButton;
+ dispatchMotion(when, policyFlags, mSource, AMOTION_EVENT_ACTION_BUTTON_PRESS, actionButton,
+ 0, metaState, buttonState, 0,
+ mCurrentCookedState.cookedPointerData.pointerProperties,
+ mCurrentCookedState.cookedPointerData.pointerCoords,
+ mCurrentCookedState.cookedPointerData.idToIndex, idBits, -1,
+ mOrientedXPrecision, mOrientedYPrecision, mDownTime);
+ }
+}
+
+const BitSet32& TouchInputMapper::findActiveIdBits(const CookedPointerData& cookedPointerData) {
+ if (!cookedPointerData.touchingIdBits.isEmpty()) {
+ return cookedPointerData.touchingIdBits;
+ }
+ return cookedPointerData.hoveringIdBits;
+}
+
void TouchInputMapper::cookPointerData() {
- uint32_t currentPointerCount = mCurrentRawPointerData.pointerCount;
+ uint32_t currentPointerCount = mCurrentRawState.rawPointerData.pointerCount;
+
+ mCurrentCookedState.cookedPointerData.clear();
+ mCurrentCookedState.cookedPointerData.pointerCount = currentPointerCount;
+ mCurrentCookedState.cookedPointerData.hoveringIdBits =
+ mCurrentRawState.rawPointerData.hoveringIdBits;
+ mCurrentCookedState.cookedPointerData.touchingIdBits =
+ mCurrentRawState.rawPointerData.touchingIdBits;
- mCurrentCookedPointerData.clear();
- mCurrentCookedPointerData.pointerCount = currentPointerCount;
- mCurrentCookedPointerData.hoveringIdBits = mCurrentRawPointerData.hoveringIdBits;
- mCurrentCookedPointerData.touchingIdBits = mCurrentRawPointerData.touchingIdBits;
+ if (mCurrentCookedState.cookedPointerData.pointerCount == 0) {
+ mCurrentCookedState.buttonState = 0;
+ } else {
+ mCurrentCookedState.buttonState = mCurrentRawState.buttonState;
+ }
// Walk through the the active pointers and map device coordinates onto
// surface coordinates and adjust for display orientation.
for (uint32_t i = 0; i < currentPointerCount; i++) {
- const RawPointerData::Pointer& in = mCurrentRawPointerData.pointers[i];
+ const RawPointerData::Pointer& in = mCurrentRawState.rawPointerData.pointers[i];
// Size
float touchMajor, touchMinor, toolMajor, toolMinor, size;
@@ -4199,7 +4568,8 @@ void TouchInputMapper::cookPointerData() {
}
if (mCalibration.haveSizeIsSummed && mCalibration.sizeIsSummed) {
- uint32_t touchingCount = mCurrentRawPointerData.touchingIdBits.count();
+ uint32_t touchingCount =
+ mCurrentRawState.rawPointerData.touchingIdBits.count();
if (touchingCount > 1) {
touchMajor /= touchingCount;
touchMinor /= touchingCount;
@@ -4368,7 +4738,7 @@ void TouchInputMapper::cookPointerData() {
}
// Write output coords.
- PointerCoords& out = mCurrentCookedPointerData.pointerCoords[i];
+ PointerCoords& out = mCurrentCookedState.cookedPointerData.pointerCoords[i];
out.clear();
out.setAxisValue(AMOTION_EVENT_AXIS_X, x);
out.setAxisValue(AMOTION_EVENT_AXIS_Y, y);
@@ -4390,14 +4760,15 @@ void TouchInputMapper::cookPointerData() {
}
// Write output properties.
- PointerProperties& properties = mCurrentCookedPointerData.pointerProperties[i];
+ PointerProperties& properties =
+ mCurrentCookedState.cookedPointerData.pointerProperties[i];
uint32_t id = in.id;
properties.clear();
properties.id = id;
properties.toolType = in.toolType;
// Write id index.
- mCurrentCookedPointerData.idToIndex[id] = i;
+ mCurrentCookedState.cookedPointerData.idToIndex[id] = i;
}
}
@@ -4501,7 +4872,7 @@ void TouchInputMapper::dispatchPointerGestures(nsecs_t when, uint32_t policyFlag
// Send events!
int32_t metaState = getContext()->getGlobalMetaState();
- int32_t buttonState = mCurrentButtonState;
+ int32_t buttonState = mCurrentCookedState.buttonState;
// Update last coordinates of pointers that have moved so that we observe the new
// pointer positions at the same time as other pointers that have just gone up.
@@ -4522,7 +4893,7 @@ void TouchInputMapper::dispatchPointerGestures(nsecs_t when, uint32_t policyFlag
mPointerGesture.lastGestureProperties,
mPointerGesture.lastGestureCoords, mPointerGesture.lastGestureIdToIndex,
movedGestureIdBits);
- if (buttonState != mLastButtonState) {
+ if (buttonState != mLastCookedState.buttonState) {
moveNeeded = true;
}
}
@@ -4532,12 +4903,12 @@ void TouchInputMapper::dispatchPointerGestures(nsecs_t when, uint32_t policyFlag
if (!dispatchedGestureIdBits.isEmpty()) {
if (cancelPreviousGesture) {
dispatchMotion(when, policyFlags, mSource,
- AMOTION_EVENT_ACTION_CANCEL, 0, metaState, buttonState,
+ AMOTION_EVENT_ACTION_CANCEL, 0, 0, metaState, buttonState,
AMOTION_EVENT_EDGE_FLAG_NONE,
mPointerGesture.lastGestureProperties,
mPointerGesture.lastGestureCoords, mPointerGesture.lastGestureIdToIndex,
- dispatchedGestureIdBits, -1,
- 0, 0, mPointerGesture.downTime);
+ dispatchedGestureIdBits, -1, 0,
+ 0, mPointerGesture.downTime);
dispatchedGestureIdBits.clear();
} else {
@@ -4552,7 +4923,7 @@ void TouchInputMapper::dispatchPointerGestures(nsecs_t when, uint32_t policyFlag
uint32_t id = upGestureIdBits.clearFirstMarkedBit();
dispatchMotion(when, policyFlags, mSource,
- AMOTION_EVENT_ACTION_POINTER_UP, 0,
+ AMOTION_EVENT_ACTION_POINTER_UP, 0, 0,
metaState, buttonState, AMOTION_EVENT_EDGE_FLAG_NONE,
mPointerGesture.lastGestureProperties,
mPointerGesture.lastGestureCoords, mPointerGesture.lastGestureIdToIndex,
@@ -4567,7 +4938,8 @@ void TouchInputMapper::dispatchPointerGestures(nsecs_t when, uint32_t policyFlag
// Send motion events for all pointers that moved.
if (moveNeeded) {
dispatchMotion(when, policyFlags, mSource,
- AMOTION_EVENT_ACTION_MOVE, 0, metaState, buttonState, AMOTION_EVENT_EDGE_FLAG_NONE,
+ AMOTION_EVENT_ACTION_MOVE, 0, 0, metaState, buttonState,
+ AMOTION_EVENT_EDGE_FLAG_NONE,
mPointerGesture.currentGestureProperties,
mPointerGesture.currentGestureCoords, mPointerGesture.currentGestureIdToIndex,
dispatchedGestureIdBits, -1,
@@ -4587,7 +4959,7 @@ void TouchInputMapper::dispatchPointerGestures(nsecs_t when, uint32_t policyFlag
}
dispatchMotion(when, policyFlags, mSource,
- AMOTION_EVENT_ACTION_POINTER_DOWN, 0, metaState, buttonState, 0,
+ AMOTION_EVENT_ACTION_POINTER_DOWN, 0, 0, metaState, buttonState, 0,
mPointerGesture.currentGestureProperties,
mPointerGesture.currentGestureCoords, mPointerGesture.currentGestureIdToIndex,
dispatchedGestureIdBits, id,
@@ -4598,7 +4970,7 @@ void TouchInputMapper::dispatchPointerGestures(nsecs_t when, uint32_t policyFlag
// Send motion events for hover.
if (mPointerGesture.currentGestureMode == PointerGesture::HOVER) {
dispatchMotion(when, policyFlags, mSource,
- AMOTION_EVENT_ACTION_HOVER_MOVE, 0,
+ AMOTION_EVENT_ACTION_HOVER_MOVE, 0, 0,
metaState, buttonState, AMOTION_EVENT_EDGE_FLAG_NONE,
mPointerGesture.currentGestureProperties,
mPointerGesture.currentGestureCoords, mPointerGesture.currentGestureIdToIndex,
@@ -4624,7 +4996,7 @@ void TouchInputMapper::dispatchPointerGestures(nsecs_t when, uint32_t policyFlag
pointerCoords.setAxisValue(AMOTION_EVENT_AXIS_Y, y);
NotifyMotionArgs args(when, getDeviceId(), mSource, policyFlags,
- AMOTION_EVENT_ACTION_HOVER_MOVE, 0,
+ AMOTION_EVENT_ACTION_HOVER_MOVE, 0, 0,
metaState, buttonState, AMOTION_EVENT_EDGE_FLAG_NONE,
mViewport.displayId, 1, &pointerProperties, &pointerCoords,
0, 0, mPointerGesture.downTime);
@@ -4653,9 +5025,9 @@ void TouchInputMapper::abortPointerGestures(nsecs_t when, uint32_t policyFlags)
// Cancel previously dispatches pointers.
if (!mPointerGesture.lastGestureIdBits.isEmpty()) {
int32_t metaState = getContext()->getGlobalMetaState();
- int32_t buttonState = mCurrentButtonState;
+ int32_t buttonState = mCurrentRawState.buttonState;
dispatchMotion(when, policyFlags, mSource,
- AMOTION_EVENT_ACTION_CANCEL, 0, metaState, buttonState,
+ AMOTION_EVENT_ACTION_CANCEL, 0, 0, metaState, buttonState,
AMOTION_EVENT_EDGE_FLAG_NONE,
mPointerGesture.lastGestureProperties,
mPointerGesture.lastGestureCoords, mPointerGesture.lastGestureIdToIndex,
@@ -4710,21 +5082,22 @@ bool TouchInputMapper::preparePointerGestures(nsecs_t when,
return false;
}
- const uint32_t currentFingerCount = mCurrentFingerIdBits.count();
- const uint32_t lastFingerCount = mLastFingerIdBits.count();
+ const uint32_t currentFingerCount = mCurrentCookedState.fingerIdBits.count();
+ const uint32_t lastFingerCount = mLastCookedState.fingerIdBits.count();
// Update the velocity tracker.
{
VelocityTracker::Position positions[MAX_POINTERS];
uint32_t count = 0;
- for (BitSet32 idBits(mCurrentFingerIdBits); !idBits.isEmpty(); count++) {
+ for (BitSet32 idBits(mCurrentCookedState.fingerIdBits); !idBits.isEmpty(); count++) {
uint32_t id = idBits.clearFirstMarkedBit();
- const RawPointerData::Pointer& pointer = mCurrentRawPointerData.pointerForId(id);
+ const RawPointerData::Pointer& pointer =
+ mCurrentRawState.rawPointerData.pointerForId(id);
positions[count].x = pointer.x * mPointerXMovementScale;
positions[count].y = pointer.y * mPointerYMovementScale;
}
mPointerGesture.velocityTracker.addMovement(when,
- mCurrentFingerIdBits, positions);
+ mCurrentCookedState.fingerIdBits, positions);
}
// If the gesture ever enters a mode other than TAP, HOVER or TAP_DRAG, without first returning
@@ -4744,17 +5117,17 @@ bool TouchInputMapper::preparePointerGestures(nsecs_t when,
int32_t lastActiveTouchId = mPointerGesture.activeTouchId;
int32_t activeTouchId = lastActiveTouchId;
if (activeTouchId < 0) {
- if (!mCurrentFingerIdBits.isEmpty()) {
+ if (!mCurrentCookedState.fingerIdBits.isEmpty()) {
activeTouchChanged = true;
activeTouchId = mPointerGesture.activeTouchId =
- mCurrentFingerIdBits.firstMarkedBit();
+ mCurrentCookedState.fingerIdBits.firstMarkedBit();
mPointerGesture.firstTouchTime = when;
}
- } else if (!mCurrentFingerIdBits.hasBit(activeTouchId)) {
+ } else if (!mCurrentCookedState.fingerIdBits.hasBit(activeTouchId)) {
activeTouchChanged = true;
- if (!mCurrentFingerIdBits.isEmpty()) {
+ if (!mCurrentCookedState.fingerIdBits.isEmpty()) {
activeTouchId = mPointerGesture.activeTouchId =
- mCurrentFingerIdBits.firstMarkedBit();
+ mCurrentCookedState.fingerIdBits.firstMarkedBit();
} else {
activeTouchId = mPointerGesture.activeTouchId = -1;
}
@@ -4777,7 +5150,7 @@ bool TouchInputMapper::preparePointerGestures(nsecs_t when,
isQuietTime = true;
} else if (mPointerGesture.lastGestureMode == PointerGesture::BUTTON_CLICK_OR_DRAG
&& currentFingerCount >= 2
- && !isPointerDown(mCurrentButtonState)) {
+ && !isPointerDown(mCurrentRawState.buttonState)) {
// Enter quiet time when releasing the button and there are still two or more
// fingers down. This may indicate that one finger was used to press the button
// but it has not gone up yet.
@@ -4805,7 +5178,7 @@ bool TouchInputMapper::preparePointerGestures(nsecs_t when,
mPointerGesture.currentGestureIdBits.clear();
mPointerVelocityControl.reset();
- } else if (isPointerDown(mCurrentButtonState)) {
+ } else if (isPointerDown(mCurrentRawState.buttonState)) {
// Case 2: Button is pressed. (BUTTON_CLICK_OR_DRAG)
// The pointer follows the active touch point.
// Emit DOWN, MOVE, UP events at the pointer location.
@@ -4834,7 +5207,7 @@ bool TouchInputMapper::preparePointerGestures(nsecs_t when,
if (activeTouchId >= 0 && currentFingerCount > 1) {
int32_t bestId = -1;
float bestSpeed = mConfig.pointerGestureDragMinSwitchSpeed;
- for (BitSet32 idBits(mCurrentFingerIdBits); !idBits.isEmpty(); ) {
+ for (BitSet32 idBits(mCurrentCookedState.fingerIdBits); !idBits.isEmpty(); ) {
uint32_t id = idBits.clearFirstMarkedBit();
float vx, vy;
if (mPointerGesture.velocityTracker.getVelocity(id, &vx, &vy)) {
@@ -4855,11 +5228,11 @@ bool TouchInputMapper::preparePointerGestures(nsecs_t when,
}
}
- if (activeTouchId >= 0 && mLastFingerIdBits.hasBit(activeTouchId)) {
+ if (activeTouchId >= 0 && mLastCookedState.fingerIdBits.hasBit(activeTouchId)) {
const RawPointerData::Pointer& currentPointer =
- mCurrentRawPointerData.pointerForId(activeTouchId);
+ mCurrentRawState.rawPointerData.pointerForId(activeTouchId);
const RawPointerData::Pointer& lastPointer =
- mLastRawPointerData.pointerForId(activeTouchId);
+ mLastRawState.rawPointerData.pointerForId(activeTouchId);
float deltaX = (currentPointer.x - lastPointer.x) * mPointerXMovementScale;
float deltaY = (currentPointer.y - lastPointer.y) * mPointerYMovementScale;
@@ -4995,11 +5368,11 @@ bool TouchInputMapper::preparePointerGestures(nsecs_t when,
mPointerGesture.currentGestureMode = PointerGesture::TAP_DRAG;
}
- if (mLastFingerIdBits.hasBit(activeTouchId)) {
+ if (mLastCookedState.fingerIdBits.hasBit(activeTouchId)) {
const RawPointerData::Pointer& currentPointer =
- mCurrentRawPointerData.pointerForId(activeTouchId);
+ mCurrentRawState.rawPointerData.pointerForId(activeTouchId);
const RawPointerData::Pointer& lastPointer =
- mLastRawPointerData.pointerForId(activeTouchId);
+ mLastRawState.rawPointerData.pointerForId(activeTouchId);
float deltaX = (currentPointer.x - lastPointer.x)
* mPointerXMovementScale;
float deltaY = (currentPointer.y - lastPointer.y)
@@ -5104,7 +5477,7 @@ bool TouchInputMapper::preparePointerGestures(nsecs_t when,
+ mConfig.pointerGestureMultitouchSettleInterval - when)
* 0.000001f);
#endif
- mCurrentRawPointerData.getCentroidOfTouchingPointers(
+ mCurrentRawState.rawPointerData.getCentroidOfTouchingPointers(
&mPointerGesture.referenceTouchX,
&mPointerGesture.referenceTouchY);
mPointerController->getPosition(&mPointerGesture.referenceGestureX,
@@ -5112,23 +5485,23 @@ bool TouchInputMapper::preparePointerGestures(nsecs_t when,
}
// Clear the reference deltas for fingers not yet included in the reference calculation.
- for (BitSet32 idBits(mCurrentFingerIdBits.value
+ for (BitSet32 idBits(mCurrentCookedState.fingerIdBits.value
& ~mPointerGesture.referenceIdBits.value); !idBits.isEmpty(); ) {
uint32_t id = idBits.clearFirstMarkedBit();
mPointerGesture.referenceDeltas[id].dx = 0;
mPointerGesture.referenceDeltas[id].dy = 0;
}
- mPointerGesture.referenceIdBits = mCurrentFingerIdBits;
+ mPointerGesture.referenceIdBits = mCurrentCookedState.fingerIdBits;
// Add delta for all fingers and calculate a common movement delta.
float commonDeltaX = 0, commonDeltaY = 0;
- BitSet32 commonIdBits(mLastFingerIdBits.value
- & mCurrentFingerIdBits.value);
+ BitSet32 commonIdBits(mLastCookedState.fingerIdBits.value
+ & mCurrentCookedState.fingerIdBits.value);
for (BitSet32 idBits(commonIdBits); !idBits.isEmpty(); ) {
bool first = (idBits == commonIdBits);
uint32_t id = idBits.clearFirstMarkedBit();
- const RawPointerData::Pointer& cpd = mCurrentRawPointerData.pointerForId(id);
- const RawPointerData::Pointer& lpd = mLastRawPointerData.pointerForId(id);
+ const RawPointerData::Pointer& cpd = mCurrentRawState.rawPointerData.pointerForId(id);
+ const RawPointerData::Pointer& lpd = mLastRawState.rawPointerData.pointerForId(id);
PointerGesture::Delta& delta = mPointerGesture.referenceDeltas[id];
delta.dx += cpd.x - lpd.x;
delta.dy += cpd.y - lpd.y;
@@ -5169,11 +5542,13 @@ bool TouchInputMapper::preparePointerGestures(nsecs_t when,
mPointerGesture.currentGestureMode = PointerGesture::FREEFORM;
} else {
// There are exactly two pointers.
- BitSet32 idBits(mCurrentFingerIdBits);
+ BitSet32 idBits(mCurrentCookedState.fingerIdBits);
uint32_t id1 = idBits.clearFirstMarkedBit();
uint32_t id2 = idBits.firstMarkedBit();
- const RawPointerData::Pointer& p1 = mCurrentRawPointerData.pointerForId(id1);
- const RawPointerData::Pointer& p2 = mCurrentRawPointerData.pointerForId(id2);
+ const RawPointerData::Pointer& p1 =
+ mCurrentRawState.rawPointerData.pointerForId(id1);
+ const RawPointerData::Pointer& p2 =
+ mCurrentRawState.rawPointerData.pointerForId(id2);
float mutualDistance = distance(p1.x, p1.y, p2.x, p2.y);
if (mutualDistance > mPointerGestureMaxSwipeWidth) {
// There are two pointers but they are too far apart for a SWIPE,
@@ -5319,14 +5694,14 @@ bool TouchInputMapper::preparePointerGestures(nsecs_t when,
} else {
// Otherwise, assume we mapped all touches from the previous frame.
// Reuse all mappings that are still applicable.
- mappedTouchIdBits.value = mLastFingerIdBits.value
- & mCurrentFingerIdBits.value;
+ mappedTouchIdBits.value = mLastCookedState.fingerIdBits.value
+ & mCurrentCookedState.fingerIdBits.value;
usedGestureIdBits = mPointerGesture.lastGestureIdBits;
// Check whether we need to choose a new active gesture id because the
// current went went up.
- for (BitSet32 upTouchIdBits(mLastFingerIdBits.value
- & ~mCurrentFingerIdBits.value);
+ for (BitSet32 upTouchIdBits(mLastCookedState.fingerIdBits.value
+ & ~mCurrentCookedState.fingerIdBits.value);
!upTouchIdBits.isEmpty(); ) {
uint32_t upTouchId = upTouchIdBits.clearFirstMarkedBit();
uint32_t upGestureId = mPointerGesture.freeformTouchToGestureIdMap[upTouchId];
@@ -5345,7 +5720,7 @@ bool TouchInputMapper::preparePointerGestures(nsecs_t when,
mPointerGesture.activeGestureId);
#endif
- BitSet32 idBits(mCurrentFingerIdBits);
+ BitSet32 idBits(mCurrentCookedState.fingerIdBits);
for (uint32_t i = 0; i < currentFingerCount; i++) {
uint32_t touchId = idBits.clearFirstMarkedBit();
uint32_t gestureId;
@@ -5369,7 +5744,7 @@ bool TouchInputMapper::preparePointerGestures(nsecs_t when,
mPointerGesture.currentGestureIdToIndex[gestureId] = i;
const RawPointerData::Pointer& pointer =
- mCurrentRawPointerData.pointerForId(touchId);
+ mCurrentRawState.rawPointerData.pointerForId(touchId);
float deltaX = (pointer.x - mPointerGesture.referenceTouchX)
* mPointerXZoomScale;
float deltaY = (pointer.y - mPointerGesture.referenceTouchY)
@@ -5400,7 +5775,7 @@ bool TouchInputMapper::preparePointerGestures(nsecs_t when,
}
}
- mPointerController->setButtonState(mCurrentButtonState);
+ mPointerController->setButtonState(mCurrentRawState.buttonState);
#if DEBUG_GESTURES
ALOGD("Gestures: finishPreviousGesture=%s, cancelPreviousGesture=%s, "
@@ -5442,23 +5817,24 @@ void TouchInputMapper::dispatchPointerStylus(nsecs_t when, uint32_t policyFlags)
mPointerSimple.currentProperties.clear();
bool down, hovering;
- if (!mCurrentStylusIdBits.isEmpty()) {
- uint32_t id = mCurrentStylusIdBits.firstMarkedBit();
- uint32_t index = mCurrentCookedPointerData.idToIndex[id];
- float x = mCurrentCookedPointerData.pointerCoords[index].getX();
- float y = mCurrentCookedPointerData.pointerCoords[index].getY();
+ if (!mCurrentCookedState.stylusIdBits.isEmpty()) {
+ uint32_t id = mCurrentCookedState.stylusIdBits.firstMarkedBit();
+ uint32_t index = mCurrentCookedState.cookedPointerData.idToIndex[id];
+ float x = mCurrentCookedState.cookedPointerData.pointerCoords[index].getX();
+ float y = mCurrentCookedState.cookedPointerData.pointerCoords[index].getY();
mPointerController->setPosition(x, y);
- hovering = mCurrentCookedPointerData.hoveringIdBits.hasBit(id);
+ hovering = mCurrentCookedState.cookedPointerData.hoveringIdBits.hasBit(id);
down = !hovering;
mPointerController->getPosition(&x, &y);
- mPointerSimple.currentCoords.copyFrom(mCurrentCookedPointerData.pointerCoords[index]);
+ mPointerSimple.currentCoords.copyFrom(
+ mCurrentCookedState.cookedPointerData.pointerCoords[index]);
mPointerSimple.currentCoords.setAxisValue(AMOTION_EVENT_AXIS_X, x);
mPointerSimple.currentCoords.setAxisValue(AMOTION_EVENT_AXIS_Y, y);
mPointerSimple.currentProperties.id = 0;
mPointerSimple.currentProperties.toolType =
- mCurrentCookedPointerData.pointerProperties[index].toolType;
+ mCurrentCookedState.cookedPointerData.pointerProperties[index].toolType;
} else {
down = false;
hovering = false;
@@ -5476,16 +5852,16 @@ void TouchInputMapper::dispatchPointerMouse(nsecs_t when, uint32_t policyFlags)
mPointerSimple.currentProperties.clear();
bool down, hovering;
- if (!mCurrentMouseIdBits.isEmpty()) {
- uint32_t id = mCurrentMouseIdBits.firstMarkedBit();
- uint32_t currentIndex = mCurrentRawPointerData.idToIndex[id];
- if (mLastMouseIdBits.hasBit(id)) {
- uint32_t lastIndex = mCurrentRawPointerData.idToIndex[id];
- float deltaX = (mCurrentRawPointerData.pointers[currentIndex].x
- - mLastRawPointerData.pointers[lastIndex].x)
+ if (!mCurrentCookedState.mouseIdBits.isEmpty()) {
+ uint32_t id = mCurrentCookedState.mouseIdBits.firstMarkedBit();
+ uint32_t currentIndex = mCurrentRawState.rawPointerData.idToIndex[id];
+ if (mLastCookedState.mouseIdBits.hasBit(id)) {
+ uint32_t lastIndex = mCurrentRawState.rawPointerData.idToIndex[id];
+ float deltaX = (mCurrentRawState.rawPointerData.pointers[currentIndex].x
+ - mLastRawState.rawPointerData.pointers[lastIndex].x)
* mPointerXMovementScale;
- float deltaY = (mCurrentRawPointerData.pointers[currentIndex].y
- - mLastRawPointerData.pointers[lastIndex].y)
+ float deltaY = (mCurrentRawState.rawPointerData.pointers[currentIndex].y
+ - mLastRawState.rawPointerData.pointers[lastIndex].y)
* mPointerYMovementScale;
rotateDelta(mSurfaceOrientation, &deltaX, &deltaY);
@@ -5496,20 +5872,20 @@ void TouchInputMapper::dispatchPointerMouse(nsecs_t when, uint32_t policyFlags)
mPointerVelocityControl.reset();
}
- down = isPointerDown(mCurrentButtonState);
+ down = isPointerDown(mCurrentRawState.buttonState);
hovering = !down;
float x, y;
mPointerController->getPosition(&x, &y);
mPointerSimple.currentCoords.copyFrom(
- mCurrentCookedPointerData.pointerCoords[currentIndex]);
+ mCurrentCookedState.cookedPointerData.pointerCoords[currentIndex]);
mPointerSimple.currentCoords.setAxisValue(AMOTION_EVENT_AXIS_X, x);
mPointerSimple.currentCoords.setAxisValue(AMOTION_EVENT_AXIS_Y, y);
mPointerSimple.currentCoords.setAxisValue(AMOTION_EVENT_AXIS_PRESSURE,
hovering ? 0.0f : 1.0f);
mPointerSimple.currentProperties.id = 0;
mPointerSimple.currentProperties.toolType =
- mCurrentCookedPointerData.pointerProperties[currentIndex].toolType;
+ mCurrentCookedState.cookedPointerData.pointerProperties[currentIndex].toolType;
} else {
mPointerVelocityControl.reset();
@@ -5534,7 +5910,7 @@ void TouchInputMapper::dispatchPointerSimple(nsecs_t when, uint32_t policyFlags,
if (down || hovering) {
mPointerController->setPresentation(PointerControllerInterface::PRESENTATION_POINTER);
mPointerController->clearSpots();
- mPointerController->setButtonState(mCurrentButtonState);
+ mPointerController->setButtonState(mCurrentRawState.buttonState);
mPointerController->unfade(PointerControllerInterface::TRANSITION_IMMEDIATE);
} else if (!down && !hovering && (mPointerSimple.down || mPointerSimple.hovering)) {
mPointerController->fade(PointerControllerInterface::TRANSITION_GRADUAL);
@@ -5546,7 +5922,7 @@ void TouchInputMapper::dispatchPointerSimple(nsecs_t when, uint32_t policyFlags,
// Send up.
NotifyMotionArgs args(when, getDeviceId(), mSource, policyFlags,
- AMOTION_EVENT_ACTION_UP, 0, metaState, mLastButtonState, 0,
+ AMOTION_EVENT_ACTION_UP, 0, 0, metaState, mLastRawState.buttonState, 0,
mViewport.displayId,
1, &mPointerSimple.lastProperties, &mPointerSimple.lastCoords,
mOrientedXPrecision, mOrientedYPrecision,
@@ -5559,7 +5935,7 @@ void TouchInputMapper::dispatchPointerSimple(nsecs_t when, uint32_t policyFlags,
// Send hover exit.
NotifyMotionArgs args(when, getDeviceId(), mSource, policyFlags,
- AMOTION_EVENT_ACTION_HOVER_EXIT, 0, metaState, mLastButtonState, 0,
+ AMOTION_EVENT_ACTION_HOVER_EXIT, 0, 0, metaState, mLastRawState.buttonState, 0,
mViewport.displayId,
1, &mPointerSimple.lastProperties, &mPointerSimple.lastCoords,
mOrientedXPrecision, mOrientedYPrecision,
@@ -5574,7 +5950,7 @@ void TouchInputMapper::dispatchPointerSimple(nsecs_t when, uint32_t policyFlags,
// Send down.
NotifyMotionArgs args(when, getDeviceId(), mSource, policyFlags,
- AMOTION_EVENT_ACTION_DOWN, 0, metaState, mCurrentButtonState, 0,
+ AMOTION_EVENT_ACTION_DOWN, 0, 0, metaState, mCurrentRawState.buttonState, 0,
mViewport.displayId,
1, &mPointerSimple.currentProperties, &mPointerSimple.currentCoords,
mOrientedXPrecision, mOrientedYPrecision,
@@ -5584,7 +5960,7 @@ void TouchInputMapper::dispatchPointerSimple(nsecs_t when, uint32_t policyFlags,
// Send move.
NotifyMotionArgs args(when, getDeviceId(), mSource, policyFlags,
- AMOTION_EVENT_ACTION_MOVE, 0, metaState, mCurrentButtonState, 0,
+ AMOTION_EVENT_ACTION_MOVE, 0, 0, metaState, mCurrentRawState.buttonState, 0,
mViewport.displayId,
1, &mPointerSimple.currentProperties, &mPointerSimple.currentCoords,
mOrientedXPrecision, mOrientedYPrecision,
@@ -5598,7 +5974,8 @@ void TouchInputMapper::dispatchPointerSimple(nsecs_t when, uint32_t policyFlags,
// Send hover enter.
NotifyMotionArgs args(when, getDeviceId(), mSource, policyFlags,
- AMOTION_EVENT_ACTION_HOVER_ENTER, 0, metaState, mCurrentButtonState, 0,
+ AMOTION_EVENT_ACTION_HOVER_ENTER, 0, 0, metaState,
+ mCurrentRawState.buttonState, 0,
mViewport.displayId,
1, &mPointerSimple.currentProperties, &mPointerSimple.currentCoords,
mOrientedXPrecision, mOrientedYPrecision,
@@ -5608,7 +5985,8 @@ void TouchInputMapper::dispatchPointerSimple(nsecs_t when, uint32_t policyFlags,
// Send hover move.
NotifyMotionArgs args(when, getDeviceId(), mSource, policyFlags,
- AMOTION_EVENT_ACTION_HOVER_MOVE, 0, metaState, mCurrentButtonState, 0,
+ AMOTION_EVENT_ACTION_HOVER_MOVE, 0, 0, metaState,
+ mCurrentRawState.buttonState, 0,
mViewport.displayId,
1, &mPointerSimple.currentProperties, &mPointerSimple.currentCoords,
mOrientedXPrecision, mOrientedYPrecision,
@@ -5616,9 +5994,9 @@ void TouchInputMapper::dispatchPointerSimple(nsecs_t when, uint32_t policyFlags,
getListener()->notifyMotion(&args);
}
- if (mCurrentRawVScroll || mCurrentRawHScroll) {
- float vscroll = mCurrentRawVScroll;
- float hscroll = mCurrentRawHScroll;
+ if (mCurrentRawState.rawVScroll || mCurrentRawState.rawHScroll) {
+ float vscroll = mCurrentRawState.rawVScroll;
+ float hscroll = mCurrentRawState.rawHScroll;
mWheelYVelocityControl.move(when, NULL, &vscroll);
mWheelXVelocityControl.move(when, &hscroll, NULL);
@@ -5629,7 +6007,7 @@ void TouchInputMapper::dispatchPointerSimple(nsecs_t when, uint32_t policyFlags,
pointerCoords.setAxisValue(AMOTION_EVENT_AXIS_HSCROLL, hscroll);
NotifyMotionArgs args(when, getDeviceId(), mSource, policyFlags,
- AMOTION_EVENT_ACTION_SCROLL, 0, metaState, mCurrentButtonState, 0,
+ AMOTION_EVENT_ACTION_SCROLL, 0, 0, metaState, mCurrentRawState.buttonState, 0,
mViewport.displayId,
1, &mPointerSimple.currentProperties, &pointerCoords,
mOrientedXPrecision, mOrientedYPrecision,
@@ -5654,10 +6032,11 @@ void TouchInputMapper::abortPointerSimple(nsecs_t when, uint32_t policyFlags) {
}
void TouchInputMapper::dispatchMotion(nsecs_t when, uint32_t policyFlags, uint32_t source,
- int32_t action, int32_t flags, int32_t metaState, int32_t buttonState, int32_t edgeFlags,
+ int32_t action, int32_t actionButton, int32_t flags,
+ int32_t metaState, int32_t buttonState, int32_t edgeFlags,
const PointerProperties* properties, const PointerCoords* coords,
- const uint32_t* idToIndex, BitSet32 idBits,
- int32_t changedId, float xPrecision, float yPrecision, nsecs_t downTime) {
+ const uint32_t* idToIndex, BitSet32 idBits, int32_t changedId,
+ float xPrecision, float yPrecision, nsecs_t downTime) {
PointerCoords pointerCoords[MAX_POINTERS];
PointerProperties pointerProperties[MAX_POINTERS];
uint32_t pointerCount = 0;
@@ -5691,7 +6070,7 @@ void TouchInputMapper::dispatchMotion(nsecs_t when, uint32_t policyFlags, uint32
}
NotifyMotionArgs args(when, getDeviceId(), source, policyFlags,
- action, flags, metaState, buttonState, edgeFlags,
+ action, actionButton, flags, metaState, buttonState, edgeFlags,
mViewport.displayId, pointerCount, pointerProperties, pointerCoords,
xPrecision, yPrecision, downTime);
getListener()->notifyMotion(&args);
@@ -5733,6 +6112,7 @@ void TouchInputMapper::fadePointer() {
void TouchInputMapper::cancelTouch(nsecs_t when) {
abortPointerUsage(when, 0 /*policyFlags*/);
+ abortTouches(when, 0 /* policyFlags*/);
}
bool TouchInputMapper::isPointInsideSurface(int32_t x, int32_t y) {
@@ -5763,11 +6143,11 @@ const TouchInputMapper::VirtualKey* TouchInputMapper::findVirtualKeyHit(
return NULL;
}
-void TouchInputMapper::assignPointerIds() {
- uint32_t currentPointerCount = mCurrentRawPointerData.pointerCount;
- uint32_t lastPointerCount = mLastRawPointerData.pointerCount;
+void TouchInputMapper::assignPointerIds(const RawState* last, RawState* current) {
+ uint32_t currentPointerCount = current->rawPointerData.pointerCount;
+ uint32_t lastPointerCount = last->rawPointerData.pointerCount;
- mCurrentRawPointerData.clearIdBits();
+ current->rawPointerData.clearIdBits();
if (currentPointerCount == 0) {
// No pointers to assign.
@@ -5778,21 +6158,21 @@ void TouchInputMapper::assignPointerIds() {
// All pointers are new.
for (uint32_t i = 0; i < currentPointerCount; i++) {
uint32_t id = i;
- mCurrentRawPointerData.pointers[i].id = id;
- mCurrentRawPointerData.idToIndex[id] = i;
- mCurrentRawPointerData.markIdBit(id, mCurrentRawPointerData.isHovering(i));
+ current->rawPointerData.pointers[i].id = id;
+ current->rawPointerData.idToIndex[id] = i;
+ current->rawPointerData.markIdBit(id, current->rawPointerData.isHovering(i));
}
return;
}
if (currentPointerCount == 1 && lastPointerCount == 1
- && mCurrentRawPointerData.pointers[0].toolType
- == mLastRawPointerData.pointers[0].toolType) {
+ && current->rawPointerData.pointers[0].toolType
+ == last->rawPointerData.pointers[0].toolType) {
// Only one pointer and no change in count so it must have the same id as before.
- uint32_t id = mLastRawPointerData.pointers[0].id;
- mCurrentRawPointerData.pointers[0].id = id;
- mCurrentRawPointerData.idToIndex[id] = 0;
- mCurrentRawPointerData.markIdBit(id, mCurrentRawPointerData.isHovering(0));
+ uint32_t id = last->rawPointerData.pointers[0].id;
+ current->rawPointerData.pointers[0].id = id;
+ current->rawPointerData.idToIndex[id] = 0;
+ current->rawPointerData.markIdBit(id, current->rawPointerData.isHovering(0));
return;
}
@@ -5810,9 +6190,9 @@ void TouchInputMapper::assignPointerIds() {
for (uint32_t lastPointerIndex = 0; lastPointerIndex < lastPointerCount;
lastPointerIndex++) {
const RawPointerData::Pointer& currentPointer =
- mCurrentRawPointerData.pointers[currentPointerIndex];
+ current->rawPointerData.pointers[currentPointerIndex];
const RawPointerData::Pointer& lastPointer =
- mLastRawPointerData.pointers[lastPointerIndex];
+ last->rawPointerData.pointers[lastPointerIndex];
if (currentPointer.toolType == lastPointer.toolType) {
int64_t deltaX = currentPointer.x - lastPointer.x;
int64_t deltaY = currentPointer.y - lastPointer.y;
@@ -5918,11 +6298,11 @@ void TouchInputMapper::assignPointerIds() {
matchedCurrentBits.markBit(currentPointerIndex);
matchedLastBits.markBit(lastPointerIndex);
- uint32_t id = mLastRawPointerData.pointers[lastPointerIndex].id;
- mCurrentRawPointerData.pointers[currentPointerIndex].id = id;
- mCurrentRawPointerData.idToIndex[id] = currentPointerIndex;
- mCurrentRawPointerData.markIdBit(id,
- mCurrentRawPointerData.isHovering(currentPointerIndex));
+ uint32_t id = last->rawPointerData.pointers[lastPointerIndex].id;
+ current->rawPointerData.pointers[currentPointerIndex].id = id;
+ current->rawPointerData.idToIndex[id] = currentPointerIndex;
+ current->rawPointerData.markIdBit(id,
+ current->rawPointerData.isHovering(currentPointerIndex));
usedIdBits.markBit(id);
#if DEBUG_POINTER_ASSIGNMENT
@@ -5938,10 +6318,10 @@ void TouchInputMapper::assignPointerIds() {
uint32_t currentPointerIndex = matchedCurrentBits.markFirstUnmarkedBit();
uint32_t id = usedIdBits.markFirstUnmarkedBit();
- mCurrentRawPointerData.pointers[currentPointerIndex].id = id;
- mCurrentRawPointerData.idToIndex[id] = currentPointerIndex;
- mCurrentRawPointerData.markIdBit(id,
- mCurrentRawPointerData.isHovering(currentPointerIndex));
+ current->rawPointerData.pointers[currentPointerIndex].id = id;
+ current->rawPointerData.idToIndex[id] = currentPointerIndex;
+ current->rawPointerData.markIdBit(id,
+ current->rawPointerData.isHovering(currentPointerIndex));
#if DEBUG_POINTER_ASSIGNMENT
ALOGD("assignPointerIds - assigned: cur=%d, id=%d",
@@ -6020,18 +6400,18 @@ void SingleTouchInputMapper::process(const RawEvent* rawEvent) {
mSingleTouchMotionAccumulator.process(rawEvent);
}
-void SingleTouchInputMapper::syncTouch(nsecs_t when, bool* outHavePointerIds) {
+void SingleTouchInputMapper::syncTouch(nsecs_t when, RawState* outState) {
if (mTouchButtonAccumulator.isToolActive()) {
- mCurrentRawPointerData.pointerCount = 1;
- mCurrentRawPointerData.idToIndex[0] = 0;
+ outState->rawPointerData.pointerCount = 1;
+ outState->rawPointerData.idToIndex[0] = 0;
bool isHovering = mTouchButtonAccumulator.getToolType() != AMOTION_EVENT_TOOL_TYPE_MOUSE
&& (mTouchButtonAccumulator.isHovering()
|| (mRawPointerAxes.pressure.valid
&& mSingleTouchMotionAccumulator.getAbsolutePressure() <= 0));
- mCurrentRawPointerData.markIdBit(0, isHovering);
+ outState->rawPointerData.markIdBit(0, isHovering);
- RawPointerData::Pointer& outPointer = mCurrentRawPointerData.pointers[0];
+ RawPointerData::Pointer& outPointer = outState->rawPointerData.pointers[0];
outPointer.id = 0;
outPointer.x = mSingleTouchMotionAccumulator.getAbsoluteX();
outPointer.y = mSingleTouchMotionAccumulator.getAbsoluteY();
@@ -6092,7 +6472,7 @@ void MultiTouchInputMapper::process(const RawEvent* rawEvent) {
mMultiTouchMotionAccumulator.process(rawEvent);
}
-void MultiTouchInputMapper::syncTouch(nsecs_t when, bool* outHavePointerIds) {
+void MultiTouchInputMapper::syncTouch(nsecs_t when, RawState* outState) {
size_t inCount = mMultiTouchMotionAccumulator.getSlotCount();
size_t outCount = 0;
BitSet32 newPointerIdBits;
@@ -6113,7 +6493,7 @@ void MultiTouchInputMapper::syncTouch(nsecs_t when, bool* outHavePointerIds) {
break; // too many fingers!
}
- RawPointerData::Pointer& outPointer = mCurrentRawPointerData.pointers[outCount];
+ RawPointerData::Pointer& outPointer = outState->rawPointerData.pointers[outCount];
outPointer.x = inSlot->getX();
outPointer.y = inSlot->getY();
outPointer.pressure = inSlot->getPressure();
@@ -6140,38 +6520,37 @@ void MultiTouchInputMapper::syncTouch(nsecs_t when, bool* outHavePointerIds) {
outPointer.isHovering = isHovering;
// Assign pointer id using tracking id if available.
- if (*outHavePointerIds) {
- int32_t trackingId = inSlot->getTrackingId();
- int32_t id = -1;
- if (trackingId >= 0) {
- for (BitSet32 idBits(mPointerIdBits); !idBits.isEmpty(); ) {
- uint32_t n = idBits.clearFirstMarkedBit();
- if (mPointerTrackingIdMap[n] == trackingId) {
- id = n;
- }
- }
-
- if (id < 0 && !mPointerIdBits.isFull()) {
- id = mPointerIdBits.markFirstUnmarkedBit();
- mPointerTrackingIdMap[id] = trackingId;
+ mHavePointerIds = true;
+ int32_t trackingId = inSlot->getTrackingId();
+ int32_t id = -1;
+ if (trackingId >= 0) {
+ for (BitSet32 idBits(mPointerIdBits); !idBits.isEmpty(); ) {
+ uint32_t n = idBits.clearFirstMarkedBit();
+ if (mPointerTrackingIdMap[n] == trackingId) {
+ id = n;
}
}
- if (id < 0) {
- *outHavePointerIds = false;
- mCurrentRawPointerData.clearIdBits();
- newPointerIdBits.clear();
- } else {
- outPointer.id = id;
- mCurrentRawPointerData.idToIndex[id] = outCount;
- mCurrentRawPointerData.markIdBit(id, isHovering);
- newPointerIdBits.markBit(id);
+
+ if (id < 0 && !mPointerIdBits.isFull()) {
+ id = mPointerIdBits.markFirstUnmarkedBit();
+ mPointerTrackingIdMap[id] = trackingId;
}
}
+ if (id < 0) {
+ mHavePointerIds = false;
+ outState->rawPointerData.clearIdBits();
+ newPointerIdBits.clear();
+ } else {
+ outPointer.id = id;
+ outState->rawPointerData.idToIndex[id] = outCount;
+ outState->rawPointerData.markIdBit(id, isHovering);
+ newPointerIdBits.markBit(id);
+ }
outCount += 1;
}
- mCurrentRawPointerData.pointerCount = outCount;
+ outState->rawPointerData.pointerCount = outCount;
mPointerIdBits = newPointerIdBits;
mMultiTouchMotionAccumulator.finishSync();
@@ -6215,6 +6594,77 @@ bool MultiTouchInputMapper::hasStylus() const {
|| mTouchButtonAccumulator.hasStylus();
}
+// --- ExternalStylusInputMapper
+
+ExternalStylusInputMapper::ExternalStylusInputMapper(InputDevice* device) :
+ InputMapper(device) {
+
+}
+
+uint32_t ExternalStylusInputMapper::getSources() {
+ return AINPUT_SOURCE_STYLUS;
+}
+
+void ExternalStylusInputMapper::populateDeviceInfo(InputDeviceInfo* info) {
+ InputMapper::populateDeviceInfo(info);
+ info->addMotionRange(AMOTION_EVENT_AXIS_PRESSURE, AINPUT_SOURCE_STYLUS,
+ 0.0f, 1.0f, 0.0f, 0.0f, 0.0f);
+}
+
+void ExternalStylusInputMapper::dump(String8& dump) {
+ dump.append(INDENT2 "External Stylus Input Mapper:\n");
+ dump.append(INDENT3 "Raw Stylus Axes:\n");
+ dumpRawAbsoluteAxisInfo(dump, mRawPressureAxis, "Pressure");
+ dump.append(INDENT3 "Stylus State:\n");
+ dumpStylusState(dump, mStylusState);
+}
+
+void ExternalStylusInputMapper::configure(nsecs_t when,
+ const InputReaderConfiguration* config, uint32_t changes) {
+ getAbsoluteAxisInfo(ABS_PRESSURE, &mRawPressureAxis);
+ mTouchButtonAccumulator.configure(getDevice());
+}
+
+void ExternalStylusInputMapper::reset(nsecs_t when) {
+ InputDevice* device = getDevice();
+ mSingleTouchMotionAccumulator.reset(device);
+ mTouchButtonAccumulator.reset(device);
+ InputMapper::reset(when);
+}
+
+void ExternalStylusInputMapper::process(const RawEvent* rawEvent) {
+ mSingleTouchMotionAccumulator.process(rawEvent);
+ mTouchButtonAccumulator.process(rawEvent);
+
+ if (rawEvent->type == EV_SYN && rawEvent->code == SYN_REPORT) {
+ sync(rawEvent->when);
+ }
+}
+
+void ExternalStylusInputMapper::sync(nsecs_t when) {
+ mStylusState.clear();
+
+ mStylusState.when = when;
+
+ mStylusState.toolType = mTouchButtonAccumulator.getToolType();
+ if (mStylusState.toolType == AMOTION_EVENT_TOOL_TYPE_UNKNOWN) {
+ mStylusState.toolType = AMOTION_EVENT_TOOL_TYPE_STYLUS;
+ }
+
+ int32_t pressure = mSingleTouchMotionAccumulator.getAbsolutePressure();
+ if (mRawPressureAxis.valid) {
+ mStylusState.pressure = float(pressure) / mRawPressureAxis.maxValue;
+ } else if (mTouchButtonAccumulator.isToolActive()) {
+ mStylusState.pressure = 1.0f;
+ } else {
+ mStylusState.pressure = 0.0f;
+ }
+
+ mStylusState.buttons = mTouchButtonAccumulator.getButtonState();
+
+ mContext->dispatchExternalStylusState(mStylusState);
+}
+
// --- JoystickInputMapper ---
@@ -6538,7 +6988,7 @@ void JoystickInputMapper::sync(nsecs_t when, bool force) {
uint32_t policyFlags = 0;
NotifyMotionArgs args(when, getDeviceId(), AINPUT_SOURCE_JOYSTICK, policyFlags,
- AMOTION_EVENT_ACTION_MOVE, 0, metaState, buttonState, AMOTION_EVENT_EDGE_FLAG_NONE,
+ AMOTION_EVENT_ACTION_MOVE, 0, 0, metaState, buttonState, AMOTION_EVENT_EDGE_FLAG_NONE,
ADISPLAY_ID_NONE, 1, &pointerProperties, &pointerCoords, 0, 0, 0);
getListener()->notifyMotion(&args);
}
diff --git a/services/inputflinger/InputReader.h b/services/inputflinger/InputReader.h
index 34f20af..7cb4680 100644
--- a/services/inputflinger/InputReader.h
+++ b/services/inputflinger/InputReader.h
@@ -139,7 +139,10 @@ struct InputReaderConfiguration {
CHANGE_DEVICE_ALIAS = 1 << 5,
// The location calibration matrix changed.
- TOUCH_AFFINE_TRANSFORMATION = 1 << 6,
+ CHANGE_TOUCH_AFFINE_TRANSFORMATION = 1 << 6,
+
+ // The presence of an external stylus has changed.
+ CHANGE_EXTERNAL_STYLUS_PRESENCE = 1 << 7,
// All devices must be reopened.
CHANGE_MUST_REOPEN = 1 << 31,
@@ -371,6 +374,31 @@ public:
virtual void cancelVibrate(int32_t deviceId, int32_t token) = 0;
};
+struct StylusState {
+ /* Time the stylus event was received. */
+ nsecs_t when;
+ /* Pressure as reported by the stylus, normalized to the range [0, 1.0]. */
+ float pressure;
+ /* The state of the stylus buttons as a bitfield (e.g. AMOTION_EVENT_BUTTON_SECONDARY). */
+ uint32_t buttons;
+ /* Which tool type the stylus is currently using (e.g. AMOTION_EVENT_TOOL_TYPE_ERASER). */
+ int32_t toolType;
+
+ void copyFrom(const StylusState& other) {
+ when = other.when;
+ pressure = other.pressure;
+ buttons = other.buttons;
+ toolType = other.toolType;
+ }
+
+ void clear() {
+ when = LLONG_MAX;
+ pressure = 0.f;
+ buttons = 0;
+ toolType = AMOTION_EVENT_TOOL_TYPE_UNKNOWN;
+ }
+};
+
/* Internal interface used by individual input devices to access global input device state
* and parameters maintained by the input reader.
@@ -392,6 +420,9 @@ public:
virtual void requestTimeoutAtTime(nsecs_t when) = 0;
virtual int32_t bumpGeneration() = 0;
+ virtual void getExternalStylusDevices(Vector<InputDeviceInfo>& outDevices) = 0;
+ virtual void dispatchExternalStylusState(const StylusState& outState) = 0;
+
virtual InputReaderPolicyInterface* getPolicy() = 0;
virtual InputListenerInterface* getListener() = 0;
virtual EventHubInterface* getEventHub() = 0;
@@ -458,6 +489,8 @@ protected:
virtual void fadePointer();
virtual void requestTimeoutAtTime(nsecs_t when);
virtual int32_t bumpGeneration();
+ virtual void getExternalStylusDevices(Vector<InputDeviceInfo>& outDevices);
+ virtual void dispatchExternalStylusState(const StylusState& outState);
virtual InputReaderPolicyInterface* getPolicy();
virtual InputListenerInterface* getListener();
virtual EventHubInterface* getEventHub();
@@ -496,6 +529,10 @@ private:
void updateGlobalMetaStateLocked();
int32_t getGlobalMetaStateLocked();
+ void notifyExternalStylusPresenceChanged();
+ void getExternalStylusDevicesLocked(Vector<InputDeviceInfo>& outDevices);
+ void dispatchExternalStylusState(const StylusState& state);
+
void fadePointerLocked();
int32_t mGeneration;
@@ -555,6 +592,9 @@ public:
inline bool isExternal() { return mIsExternal; }
inline void setExternal(bool external) { mIsExternal = external; }
+ inline void setMic(bool hasMic) { mHasMic = hasMic; }
+ inline bool hasMic() const { return mHasMic; }
+
inline bool isIgnored() { return mMappers.isEmpty(); }
void dump(String8& dump);
@@ -563,6 +603,7 @@ public:
void reset(nsecs_t when);
void process(const RawEvent* rawEvents, size_t count);
void timeoutExpired(nsecs_t when);
+ void updateExternalStylusState(const StylusState& state);
void getDeviceInfo(InputDeviceInfo* outDeviceInfo);
int32_t getKeyCodeState(uint32_t sourceMask, int32_t keyCode);
@@ -618,6 +659,7 @@ private:
uint32_t mSources;
bool mIsExternal;
+ bool mHasMic;
bool mDropUntilNextSync;
typedef int32_t (InputMapper::*GetStateFunc)(uint32_t sourceMask, int32_t code);
@@ -831,9 +873,21 @@ struct CookedPointerData {
return pointerCoords[idToIndex[id]];
}
- inline bool isHovering(uint32_t pointerIndex) {
+ inline PointerCoords& editPointerCoordsWithId(uint32_t id) {
+ return pointerCoords[idToIndex[id]];
+ }
+
+ inline PointerProperties& editPointerPropertiesWithId(uint32_t id) {
+ return pointerProperties[idToIndex[id]];
+ }
+
+ inline bool isHovering(uint32_t pointerIndex) const {
return hoveringIdBits.hasBit(pointerProperties[pointerIndex].id);
}
+
+ inline bool isTouching(uint32_t pointerIndex) const {
+ return touchingIdBits.hasBit(pointerProperties[pointerIndex].id);
+ }
};
@@ -978,6 +1032,8 @@ public:
virtual int32_t getMetaState();
+ virtual void updateExternalStylusState(const StylusState& state);
+
virtual void fadePointer();
protected:
@@ -989,6 +1045,7 @@ protected:
static void dumpRawAbsoluteAxisInfo(String8& dump,
const RawAbsoluteAxisInfo& axis, const char* name);
+ static void dumpStylusState(String8& dump, const StylusState& state);
};
@@ -1195,6 +1252,7 @@ public:
virtual void fadePointer();
virtual void cancelTouch(nsecs_t when);
virtual void timeoutExpired(nsecs_t when);
+ virtual void updateExternalStylusState(const StylusState& state);
protected:
CursorButtonAccumulator mCursorButtonAccumulator;
@@ -1334,36 +1392,86 @@ protected:
// Affine location transformation/calibration
struct TouchAffineTransformation mAffineTransform;
- // Raw pointer axis information from the driver.
RawPointerAxes mRawPointerAxes;
- // Raw pointer sample data.
- RawPointerData mCurrentRawPointerData;
- RawPointerData mLastRawPointerData;
+ struct RawState {
+ nsecs_t when;
+
+ // Raw pointer sample data.
+ RawPointerData rawPointerData;
+
+ int32_t buttonState;
+
+ // Scroll state.
+ int32_t rawVScroll;
+ int32_t rawHScroll;
+
+ void copyFrom(const RawState& other) {
+ when = other.when;
+ rawPointerData.copyFrom(other.rawPointerData);
+ buttonState = other.buttonState;
+ rawVScroll = other.rawVScroll;
+ rawHScroll = other.rawHScroll;
+ }
+
+ void clear() {
+ when = 0;
+ rawPointerData.clear();
+ buttonState = 0;
+ rawVScroll = 0;
+ rawHScroll = 0;
+ }
+ };
+
+ struct CookedState {
+ // Cooked pointer sample data.
+ CookedPointerData cookedPointerData;
- // Cooked pointer sample data.
- CookedPointerData mCurrentCookedPointerData;
- CookedPointerData mLastCookedPointerData;
+ // Id bits used to differentiate fingers, stylus and mouse tools.
+ BitSet32 fingerIdBits;
+ BitSet32 stylusIdBits;
+ BitSet32 mouseIdBits;
- // Button state.
- int32_t mCurrentButtonState;
- int32_t mLastButtonState;
+ int32_t buttonState;
- // Scroll state.
- int32_t mCurrentRawVScroll;
- int32_t mCurrentRawHScroll;
+ void copyFrom(const CookedState& other) {
+ cookedPointerData.copyFrom(other.cookedPointerData);
+ fingerIdBits = other.fingerIdBits;
+ stylusIdBits = other.stylusIdBits;
+ mouseIdBits = other.mouseIdBits;
+ buttonState = other.buttonState;
+ }
- // Id bits used to differentiate fingers, stylus and mouse tools.
- BitSet32 mCurrentFingerIdBits; // finger or unknown
- BitSet32 mLastFingerIdBits;
- BitSet32 mCurrentStylusIdBits; // stylus or eraser
- BitSet32 mLastStylusIdBits;
- BitSet32 mCurrentMouseIdBits; // mouse or lens
- BitSet32 mLastMouseIdBits;
+ void clear() {
+ cookedPointerData.clear();
+ fingerIdBits.clear();
+ stylusIdBits.clear();
+ mouseIdBits.clear();
+ buttonState = 0;
+ }
+ };
+
+ Vector<RawState> mRawStatesPending;
+ RawState mCurrentRawState;
+ CookedState mCurrentCookedState;
+ RawState mLastRawState;
+ CookedState mLastCookedState;
+
+ // State provided by an external stylus
+ StylusState mExternalStylusState;
+ int64_t mExternalStylusId;
+ nsecs_t mExternalStylusFusionTimeout;
+ bool mExternalStylusDataPending;
// True if we sent a HOVER_ENTER event.
bool mSentHoverEnter;
+ // Have we assigned pointer IDs for this stream
+ bool mHavePointerIds;
+
+ // Is the current stream of direct touch events aborted
+ bool mCurrentMotionAborted;
+
// The time the primary pointer last went down.
nsecs_t mDownTime;
@@ -1383,11 +1491,13 @@ protected:
virtual void parseCalibration();
virtual void resolveCalibration();
virtual void dumpCalibration(String8& dump);
+ virtual void updateAffineTransformation();
virtual void dumpAffineTransformation(String8& dump);
+ virtual void resolveExternalStylusPresence();
virtual bool hasStylus() const = 0;
- virtual void updateAffineTransformation();
+ virtual bool hasExternalStylus() const;
- virtual void syncTouch(nsecs_t when, bool* outHavePointerIds) = 0;
+ virtual void syncTouch(nsecs_t when, RawState* outState) = 0;
private:
// The current viewport.
@@ -1433,6 +1543,8 @@ private:
float mTiltYCenter;
float mTiltYScale;
+ bool mExternalStylusConnected;
+
// Oriented motion ranges for input device info.
struct OrientedRanges {
InputDeviceInfo::MotionRange x;
@@ -1675,16 +1787,25 @@ private:
VelocityControl mWheelXVelocityControl;
VelocityControl mWheelYVelocityControl;
+ void resetExternalStylus();
+ void clearStylusDataPendingFlags();
+
void sync(nsecs_t when);
bool consumeRawTouches(nsecs_t when, uint32_t policyFlags);
+ void processRawTouches(bool timeout);
+ void cookAndDispatch(nsecs_t when);
void dispatchVirtualKey(nsecs_t when, uint32_t policyFlags,
int32_t keyEventAction, int32_t keyEventFlags);
void dispatchTouches(nsecs_t when, uint32_t policyFlags);
void dispatchHoverExit(nsecs_t when, uint32_t policyFlags);
void dispatchHoverEnterAndMove(nsecs_t when, uint32_t policyFlags);
+ void dispatchButtonRelease(nsecs_t when, uint32_t policyFlags);
+ void dispatchButtonPress(nsecs_t when, uint32_t policyFlags);
+ const BitSet32& findActiveIdBits(const CookedPointerData& cookedPointerData);
void cookPointerData();
+ void abortTouches(nsecs_t when, uint32_t policyFlags);
void dispatchPointerUsage(nsecs_t when, uint32_t policyFlags, PointerUsage pointerUsage);
void abortPointerUsage(nsecs_t when, uint32_t policyFlags);
@@ -1705,13 +1826,17 @@ private:
bool down, bool hovering);
void abortPointerSimple(nsecs_t when, uint32_t policyFlags);
+ bool assignExternalStylusId(const RawState& state, bool timeout);
+ void applyExternalStylusButtonState(nsecs_t when);
+ void applyExternalStylusTouchState(nsecs_t when);
+
// Dispatches a motion event.
// If the changedId is >= 0 and the action is POINTER_DOWN or POINTER_UP, the
// method will take care of setting the index and transmuting the action to DOWN or UP
// it is the first / last pointer to go down / up.
void dispatchMotion(nsecs_t when, uint32_t policyFlags, uint32_t source,
- int32_t action, int32_t flags, int32_t metaState, int32_t buttonState,
- int32_t edgeFlags,
+ int32_t action, int32_t actionButton,
+ int32_t flags, int32_t metaState, int32_t buttonState, int32_t edgeFlags,
const PointerProperties* properties, const PointerCoords* coords,
const uint32_t* idToIndex, BitSet32 idBits,
int32_t changedId, float xPrecision, float yPrecision, nsecs_t downTime);
@@ -1726,7 +1851,7 @@ private:
bool isPointInsideSurface(int32_t x, int32_t y);
const VirtualKey* findVirtualKeyHit(int32_t x, int32_t y);
- void assignPointerIds();
+ static void assignPointerIds(const RawState* last, RawState* current);
};
@@ -1739,7 +1864,7 @@ public:
virtual void process(const RawEvent* rawEvent);
protected:
- virtual void syncTouch(nsecs_t when, bool* outHavePointerIds);
+ virtual void syncTouch(nsecs_t when, RawState* outState);
virtual void configureRawPointerAxes();
virtual bool hasStylus() const;
@@ -1757,7 +1882,7 @@ public:
virtual void process(const RawEvent* rawEvent);
protected:
- virtual void syncTouch(nsecs_t when, bool* outHavePointerIds);
+ virtual void syncTouch(nsecs_t when, RawState* outState);
virtual void configureRawPointerAxes();
virtual bool hasStylus() const;
@@ -1769,6 +1894,27 @@ private:
int32_t mPointerTrackingIdMap[MAX_POINTER_ID + 1];
};
+class ExternalStylusInputMapper : public InputMapper {
+public:
+ ExternalStylusInputMapper(InputDevice* device);
+ virtual ~ExternalStylusInputMapper() = default;
+
+ virtual uint32_t getSources();
+ virtual void populateDeviceInfo(InputDeviceInfo* deviceInfo);
+ virtual void dump(String8& dump);
+ virtual void configure(nsecs_t when, const InputReaderConfiguration* config, uint32_t changes);
+ virtual void reset(nsecs_t when);
+ virtual void process(const RawEvent* rawEvent);
+ virtual void sync(nsecs_t when);
+
+private:
+ SingleTouchMotionAccumulator mSingleTouchMotionAccumulator;
+ RawAbsoluteAxisInfo mRawPressureAxis;
+ TouchButtonAccumulator mTouchButtonAccumulator;
+
+ StylusState mStylusState;
+};
+
class JoystickInputMapper : public InputMapper {
public:
diff --git a/services/inputflinger/host/Android.mk b/services/inputflinger/host/Android.mk
new file mode 100644
index 0000000..b828175
--- /dev/null
+++ b/services/inputflinger/host/Android.mk
@@ -0,0 +1,62 @@
+# Copyright (C) 2015 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.
+
+LOCAL_PATH:= $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_CLANG := true
+
+LOCAL_SRC_FILES:= \
+ InputFlinger.cpp \
+ InputDriver.cpp \
+ InputHost.cpp
+
+LOCAL_SHARED_LIBRARIES := \
+ libbinder \
+ libcrypto \
+ libcutils \
+ libinput \
+ liblog \
+ libutils \
+ libhardware
+
+
+# TODO: Move inputflinger to its own process and mark it hidden
+#LOCAL_CFLAGS += -fvisibility=hidden
+
+LOCAL_CFLAGS += -Wno-unused-parameter
+
+LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH)
+
+LOCAL_MODULE := libinputflingerhost
+
+include $(BUILD_SHARED_LIBRARY)
+
+########################################################################
+# build input flinger executable
+include $(CLEAR_VARS)
+
+LOCAL_CLANG := true
+
+LOCAL_SRC_FILES:= \
+ main.cpp
+
+LOCAL_SHARED_LIBRARIES := \
+ libbinder \
+ libinputflingerhost \
+ libutils
+
+LOCAL_MODULE := inputflinger
+
+include $(BUILD_EXECUTABLE)
diff --git a/services/inputflinger/host/InputDriver.cpp b/services/inputflinger/host/InputDriver.cpp
new file mode 100644
index 0000000..630a596
--- /dev/null
+++ b/services/inputflinger/host/InputDriver.cpp
@@ -0,0 +1,146 @@
+/*
+ * Copyright (C) 2015 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.
+ */
+
+#include <stdint.h>
+#include <sys/types.h>
+
+#define LOG_TAG "InputDriver"
+
+#define LOG_NDEBUG 0
+
+#include "InputDriver.h"
+#include "InputHost.h"
+
+#include <hardware/input.h>
+#include <utils/Log.h>
+#include <utils/String8.h>
+
+#define INDENT2 " "
+
+namespace android {
+
+static input_host_callbacks_t kCallbacks = {
+ .create_device_identifier = create_device_identifier,
+ .create_device_definition = create_device_definition,
+ .create_input_report_definition = create_input_report_definition,
+ .create_output_report_definition = create_output_report_definition,
+ .input_device_definition_add_report = input_device_definition_add_report,
+ .input_report_definition_add_collection = input_report_definition_add_collection,
+ .input_report_definition_declare_usage_int = input_report_definition_declare_usage_int,
+ .input_report_definition_declare_usages_bool = input_report_definition_declare_usages_bool,
+ .register_device = register_device,
+ .input_allocate_report = input_allocate_report,
+ .input_report_set_usage_int = input_report_set_usage_int,
+ .input_report_set_usage_bool = input_report_set_usage_bool,
+ .report_event = report_event,
+ .input_get_device_property_map = input_get_device_property_map,
+ .input_get_device_property = input_get_device_property,
+ .input_get_property_key = input_get_property_key,
+ .input_get_property_value = input_get_property_value,
+ .input_free_device_property = input_free_device_property,
+ .input_free_device_property_map = input_free_device_property_map,
+};
+
+InputDriver::InputDriver(const char* name) : mName(String8(name)) {
+ const hw_module_t* module;
+ int err = input_open(&module, name);
+ LOG_ALWAYS_FATAL_IF(err != 0, "Input module %s not found", name);
+ mHal = reinterpret_cast<const input_module_t*>(module);
+}
+
+void InputDriver::init(InputHostInterface* host) {
+ mHal->init(mHal, static_cast<input_host_t*>(host), kCallbacks);
+}
+
+void InputDriver::dump(String8& result) {
+ result.appendFormat(INDENT2 "HAL Input Driver (%s)\n", mName.string());
+}
+
+
+// HAL wrapper functions
+
+input_device_identifier_t* create_device_identifier(input_host_t* host,
+ const char* name, int32_t product_id, int32_t vendor_id,
+ input_bus_t bus, const char* unique_id) {
+ return nullptr;
+}
+
+input_device_definition_t* create_device_definition(input_host_t* host) {
+ return nullptr;
+}
+
+input_report_definition_t* create_input_report_definition(input_host_t* host) {
+ return nullptr;
+}
+
+input_report_definition_t* create_output_report_definition(input_host_t* host) {
+ return nullptr;
+}
+
+void input_device_definition_add_report(input_host_t* host,
+ input_device_definition_t* d, input_report_definition_t* r) { }
+
+void input_report_definition_add_collection(input_host_t* host,
+ input_report_definition_t* report, input_collection_id_t id, int32_t arity) { }
+
+void input_report_definition_declare_usage_int(input_host_t* host,
+ input_report_definition_t* report, input_collection_id_t id,
+ input_usage_t usage, int32_t min, int32_t max, float resolution) { }
+
+void input_report_definition_declare_usages_bool(input_host_t* host,
+ input_report_definition_t* report, input_collection_id_t id,
+ input_usage_t* usage, size_t usage_count) { }
+
+
+input_device_handle_t* register_device(input_host_t* host,
+ input_device_identifier_t* id, input_device_definition_t* d) {
+ return nullptr;
+}
+
+input_report_t* input_allocate_report(input_host_t* host, input_report_definition_t* r) {
+ return nullptr;
+}
+void input_report_set_usage_int(input_host_t* host, input_report_t* r,
+ input_collection_id_t id, input_usage_t usage, int32_t value, int32_t arity_index) { }
+
+void input_report_set_usage_bool(input_host_t* host, input_report_t* r,
+ input_collection_id_t id, input_usage_t usage, bool value, int32_t arity_index) { }
+
+void report_event(input_host_t* host, input_device_handle_t* d, input_report_t* report) { }
+
+input_property_map_t* input_get_device_property_map(input_host_t* host,
+ input_device_identifier_t* id) {
+ return nullptr;
+}
+
+input_property_t* input_get_device_property(input_host_t* host, input_property_map_t* map,
+ const char* key) {
+ return nullptr;
+}
+
+const char* input_get_property_key(input_host_t* host, input_property_t* property) {
+ return nullptr;
+}
+
+const char* input_get_property_value(input_host_t* host, input_property_t* property) {
+ return nullptr;
+}
+
+void input_free_device_property(input_host_t* host, input_property_t* property) { }
+
+void input_free_device_property_map(input_host_t* host, input_property_map_t* map) { }
+
+} // namespace android
diff --git a/services/inputflinger/host/InputDriver.h b/services/inputflinger/host/InputDriver.h
new file mode 100644
index 0000000..7734ac2
--- /dev/null
+++ b/services/inputflinger/host/InputDriver.h
@@ -0,0 +1,117 @@
+/*
+ * Copyright (C) 2015 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_INPUT_DRIVER_H
+#define ANDROID_INPUT_DRIVER_H
+
+#include <stdint.h>
+#include <sys/types.h>
+
+#include "InputHost.h"
+
+#include <hardware/input.h>
+#include <utils/RefBase.h>
+#include <utils/String8.h>
+
+namespace android {
+
+class InputHostInterface;
+
+class InputDriverInterface : public virtual RefBase {
+protected:
+ InputDriverInterface() = default;
+ virtual ~InputDriverInterface() = default;
+
+public:
+ virtual void init(InputHostInterface* host) = 0;
+
+ virtual void dump(String8& result) = 0;
+};
+
+class InputDriver : public InputDriverInterface {
+public:
+ InputDriver(const char* name);
+ virtual ~InputDriver() = default;
+
+ virtual void init(InputHostInterface* host) override;
+
+ virtual void dump(String8& result) override;
+
+private:
+ String8 mName;
+ const input_module_t* mHal;
+};
+
+
+extern "C" {
+
+input_device_identifier_t* create_device_identifier(input_host_t* host,
+ const char* name, int32_t product_id, int32_t vendor_id,
+ input_bus_t bus, const char* unique_id);
+
+input_device_definition_t* create_device_definition(input_host_t* host);
+
+input_report_definition_t* create_input_report_definition(input_host_t* host);
+
+input_report_definition_t* create_output_report_definition(input_host_t* host);
+
+void input_device_definition_add_report(input_host_t* host,
+ input_device_definition_t* d, input_report_definition_t* r);
+
+void input_report_definition_add_collection(input_host_t* host,
+ input_report_definition_t* report, input_collection_id_t id, int32_t arity);
+
+void input_report_definition_declare_usage_int(input_host_t* host,
+ input_report_definition_t* report, input_collection_id_t id,
+ input_usage_t usage, int32_t min, int32_t max, float resolution);
+
+void input_report_definition_declare_usages_bool(input_host_t* host,
+ input_report_definition_t* report, input_collection_id_t id,
+ input_usage_t* usage, size_t usage_count);
+
+
+input_device_handle_t* register_device(input_host_t* host,
+ input_device_identifier_t* id, input_device_definition_t* d);
+
+void unregister_device(input_host_t* host, input_device_handle_t* handle);
+
+input_report_t* input_allocate_report(input_host_t* host, input_report_definition_t* r);
+
+void input_report_set_usage_int(input_host_t* host, input_report_t* r,
+ input_collection_id_t id, input_usage_t usage, int32_t value, int32_t arity_index);
+
+void input_report_set_usage_bool(input_host_t* host, input_report_t* r,
+ input_collection_id_t id, input_usage_t usage, bool value, int32_t arity_index);
+
+void report_event(input_host_t* host, input_device_handle_t* d, input_report_t* report);
+
+input_property_map_t* input_get_device_property_map(input_host_t* host,
+ input_device_identifier_t* id);
+
+input_property_t* input_get_device_property(input_host_t* host, input_property_map_t* map,
+ const char* key);
+
+const char* input_get_property_key(input_host_t* host, input_property_t* property);
+
+const char* input_get_property_value(input_host_t* host, input_property_t* property);
+
+void input_free_device_property(input_host_t* host, input_property_t* property);
+
+void input_free_device_property_map(input_host_t* host, input_property_map_t* map);
+}
+
+} // namespace android
+#endif // ANDROID_INPUT_DRIVER_H
diff --git a/services/inputflinger/host/InputFlinger.cpp b/services/inputflinger/host/InputFlinger.cpp
new file mode 100644
index 0000000..859c3b8
--- /dev/null
+++ b/services/inputflinger/host/InputFlinger.cpp
@@ -0,0 +1,71 @@
+/*
+ * Copyright (C) 2013 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 "InputFlinger"
+
+
+#include <stdint.h>
+#include <unistd.h>
+
+#include <sys/types.h>
+
+#include "InputFlinger.h"
+#include "InputDriver.h"
+
+#include <binder/IPCThreadState.h>
+#include <binder/PermissionCache.h>
+#include <hardware/input.h>
+#include <cutils/log.h>
+#include <private/android_filesystem_config.h>
+
+namespace android {
+
+const String16 sAccessInputFlingerPermission("android.permission.ACCESS_INPUT_FLINGER");
+const String16 sDumpPermission("android.permission.DUMP");
+
+
+InputFlinger::InputFlinger() :
+ BnInputFlinger() {
+ ALOGI("InputFlinger is starting");
+ mHost = new InputHost();
+ mHost->registerInputDriver(new InputDriver(INPUT_INSTANCE_EVDEV));
+}
+
+InputFlinger::~InputFlinger() {
+}
+
+status_t InputFlinger::dump(int fd, const Vector<String16>& args) {
+ String8 result;
+ const IPCThreadState* ipc = IPCThreadState::self();
+ const int pid = ipc->getCallingPid();
+ const int uid = ipc->getCallingUid();
+ if ((uid != AID_SHELL)
+ && !PermissionCache::checkPermission(sDumpPermission, pid, uid)) {
+ result.appendFormat("Permission Denial: "
+ "can't dump SurfaceFlinger from pid=%d, uid=%d\n", pid, uid);
+ } else {
+ dumpInternal(result);
+ }
+ write(fd, result.string(), result.size());
+ return OK;
+}
+
+void InputFlinger::dumpInternal(String8& result) {
+ result.append("INPUT FLINGER (dumpsys inputflinger)\n");
+ mHost->dump(result);
+}
+
+}; // namespace android
diff --git a/services/inputflinger/host/InputFlinger.h b/services/inputflinger/host/InputFlinger.h
new file mode 100644
index 0000000..39e69e5
--- /dev/null
+++ b/services/inputflinger/host/InputFlinger.h
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) 2013 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_INPUT_FLINGER_H
+#define ANDROID_INPUT_FLINGER_H
+
+#include <stdint.h>
+#include <sys/types.h>
+
+#include "InputHost.h"
+
+#include <cutils/compiler.h>
+#include <input/IInputFlinger.h>
+#include <utils/String8.h>
+#include <utils/String16.h>
+#include <utils/StrongPointer.h>
+
+namespace android {
+
+class InputFlinger : public BnInputFlinger {
+public:
+ static char const* getServiceName() ANDROID_API {
+ return "inputflinger";
+ }
+
+ InputFlinger() ANDROID_API;
+
+ virtual status_t dump(int fd, const Vector<String16>& args);
+
+private:
+ virtual ~InputFlinger();
+
+ void dumpInternal(String8& result);
+
+ sp<InputHostInterface> mHost;
+};
+
+} // namespace android
+
+#endif // ANDROID_INPUT_FLINGER_H
diff --git a/services/inputflinger/host/InputHost.cpp b/services/inputflinger/host/InputHost.cpp
new file mode 100644
index 0000000..51d3e6b
--- /dev/null
+++ b/services/inputflinger/host/InputHost.cpp
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2015 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.
+ */
+
+#include <vector>
+
+#include "InputDriver.h"
+#include "InputHost.h"
+
+#include <utils/Log.h>
+#include <utils/String8.h>
+
+#define INDENT " "
+
+namespace android {
+
+void InputHost::registerInputDriver(InputDriverInterface* driver) {
+ LOG_ALWAYS_FATAL_IF(driver == nullptr, "Cannot register a nullptr as an InputDriver!");
+ driver->init(this);
+ mDrivers.push_back(driver);
+}
+
+void InputHost::dump(String8& result) {
+ result.append(INDENT "Input Drivers:\n");
+ for (size_t i = 0; i < mDrivers.size(); i++) {
+ mDrivers[i]->dump(result);
+ }
+}
+
+} // namespace android
diff --git a/services/inputflinger/host/InputHost.h b/services/inputflinger/host/InputHost.h
new file mode 100644
index 0000000..42a66e0
--- /dev/null
+++ b/services/inputflinger/host/InputHost.h
@@ -0,0 +1,62 @@
+/*
+ * Copyright (C) 2015 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_INPUT_HOST_H
+#define ANDROID_INPUT_HOST_H
+
+#include <vector>
+
+#include <hardware/input.h>
+#include <utils/RefBase.h>
+#include <utils/String8.h>
+#include <utils/StrongPointer.h>
+
+#include "InputDriver.h"
+
+// Declare a concrete type for the HAL
+struct input_host {
+};
+
+namespace android {
+
+class InputDriverInterface;
+
+class InputHostInterface : public input_host_t, public virtual RefBase {
+protected:
+ InputHostInterface() = default;
+ virtual ~InputHostInterface() = default;
+
+public:
+
+ virtual void registerInputDriver(InputDriverInterface* driver) = 0;
+
+ virtual void dump(String8& result) = 0;
+};
+
+class InputHost : public InputHostInterface {
+public:
+ InputHost() = default;
+
+ virtual void registerInputDriver(InputDriverInterface* driver) override;
+
+ virtual void dump(String8& result) override;
+
+private:
+ std::vector<sp<InputDriverInterface>> mDrivers;
+};
+
+} // namespace android
+#endif // ANDRIOD_INPUT_HOST_H
diff --git a/services/inputflinger/host/main.cpp b/services/inputflinger/host/main.cpp
new file mode 100644
index 0000000..0a517cc
--- /dev/null
+++ b/services/inputflinger/host/main.cpp
@@ -0,0 +1,26 @@
+/*
+ * Copyright (C) 2013 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.
+ */
+
+#include <binder/BinderService.h>
+#include "InputFlinger.h"
+
+using namespace android;
+
+int main(int, char**) {
+ ProcessState::self()->setThreadPoolMaxThreadCount(4);
+ BinderService<InputFlinger>::publishAndJoinThreadPool(true);
+ return 0;
+}
diff --git a/services/inputflinger/tests/Android.mk b/services/inputflinger/tests/Android.mk
index 0742a08..4c43392 100644
--- a/services/inputflinger/tests/Android.mk
+++ b/services/inputflinger/tests/Android.mk
@@ -10,7 +10,6 @@ test_src_files := \
shared_libraries := \
libcutils \
liblog \
- libandroidfw \
libutils \
libhardware \
libhardware_legacy \
@@ -24,7 +23,7 @@ c_includes := \
external/skia/include/core
-module_tags := eng tests
+module_tags := tests
$(foreach file,$(test_src_files), \
$(eval include $(CLEAR_VARS)) \
diff --git a/services/inputflinger/tests/InputDispatcher_test.cpp b/services/inputflinger/tests/InputDispatcher_test.cpp
index 9b68986..2d8eaef 100644
--- a/services/inputflinger/tests/InputDispatcher_test.cpp
+++ b/services/inputflinger/tests/InputDispatcher_test.cpp
@@ -150,7 +150,7 @@ TEST_F(InputDispatcherTest, InjectInputEvent_ValidatesMotionEvents) {
// Rejects undefined motion actions.
event.initialize(DEVICE_ID, AINPUT_SOURCE_TOUCHSCREEN,
- /*action*/ -1, 0, 0, AMETA_NONE, 0, 0, 0, 0, 0,
+ /*action*/ -1, 0, 0, 0, AMETA_NONE, 0, 0, 0, 0, 0,
ARBITRARY_TIME, ARBITRARY_TIME,
/*pointerCount*/ 1, pointerProperties, pointerCoords);
ASSERT_EQ(INPUT_EVENT_INJECTION_FAILED, mDispatcher->injectInputEvent(
@@ -161,7 +161,7 @@ TEST_F(InputDispatcherTest, InjectInputEvent_ValidatesMotionEvents) {
// Rejects pointer down with invalid index.
event.initialize(DEVICE_ID, AINPUT_SOURCE_TOUCHSCREEN,
AMOTION_EVENT_ACTION_POINTER_DOWN | (1 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT),
- 0, 0, AMETA_NONE, 0, 0, 0, 0, 0,
+ 0, 0, 0, AMETA_NONE, 0, 0, 0, 0, 0,
ARBITRARY_TIME, ARBITRARY_TIME,
/*pointerCount*/ 1, pointerProperties, pointerCoords);
ASSERT_EQ(INPUT_EVENT_INJECTION_FAILED, mDispatcher->injectInputEvent(
@@ -171,7 +171,7 @@ TEST_F(InputDispatcherTest, InjectInputEvent_ValidatesMotionEvents) {
event.initialize(DEVICE_ID, AINPUT_SOURCE_TOUCHSCREEN,
AMOTION_EVENT_ACTION_POINTER_DOWN | (-1 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT),
- 0, 0, AMETA_NONE, 0, 0, 0, 0, 0,
+ 0, 0, 0, AMETA_NONE, 0, 0, 0, 0, 0,
ARBITRARY_TIME, ARBITRARY_TIME,
/*pointerCount*/ 1, pointerProperties, pointerCoords);
ASSERT_EQ(INPUT_EVENT_INJECTION_FAILED, mDispatcher->injectInputEvent(
@@ -182,7 +182,7 @@ TEST_F(InputDispatcherTest, InjectInputEvent_ValidatesMotionEvents) {
// Rejects pointer up with invalid index.
event.initialize(DEVICE_ID, AINPUT_SOURCE_TOUCHSCREEN,
AMOTION_EVENT_ACTION_POINTER_UP | (1 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT),
- 0, 0, AMETA_NONE, 0, 0, 0, 0, 0,
+ 0, 0, 0, AMETA_NONE, 0, 0, 0, 0, 0,
ARBITRARY_TIME, ARBITRARY_TIME,
/*pointerCount*/ 1, pointerProperties, pointerCoords);
ASSERT_EQ(INPUT_EVENT_INJECTION_FAILED, mDispatcher->injectInputEvent(
@@ -192,7 +192,7 @@ TEST_F(InputDispatcherTest, InjectInputEvent_ValidatesMotionEvents) {
event.initialize(DEVICE_ID, AINPUT_SOURCE_TOUCHSCREEN,
AMOTION_EVENT_ACTION_POINTER_UP | (-1 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT),
- 0, 0, AMETA_NONE, 0, 0, 0, 0, 0,
+ 0, 0, 0, AMETA_NONE, 0, 0, 0, 0, 0,
ARBITRARY_TIME, ARBITRARY_TIME,
/*pointerCount*/ 1, pointerProperties, pointerCoords);
ASSERT_EQ(INPUT_EVENT_INJECTION_FAILED, mDispatcher->injectInputEvent(
@@ -202,7 +202,7 @@ TEST_F(InputDispatcherTest, InjectInputEvent_ValidatesMotionEvents) {
// Rejects motion events with invalid number of pointers.
event.initialize(DEVICE_ID, AINPUT_SOURCE_TOUCHSCREEN,
- AMOTION_EVENT_ACTION_DOWN, 0, 0, AMETA_NONE, 0, 0, 0, 0, 0,
+ AMOTION_EVENT_ACTION_DOWN, 0, 0, 0, AMETA_NONE, 0, 0, 0, 0, 0,
ARBITRARY_TIME, ARBITRARY_TIME,
/*pointerCount*/ 0, pointerProperties, pointerCoords);
ASSERT_EQ(INPUT_EVENT_INJECTION_FAILED, mDispatcher->injectInputEvent(
@@ -211,7 +211,7 @@ TEST_F(InputDispatcherTest, InjectInputEvent_ValidatesMotionEvents) {
<< "Should reject motion events with 0 pointers.";
event.initialize(DEVICE_ID, AINPUT_SOURCE_TOUCHSCREEN,
- AMOTION_EVENT_ACTION_DOWN, 0, 0, AMETA_NONE, 0, 0, 0, 0, 0,
+ AMOTION_EVENT_ACTION_DOWN, 0, 0, 0, AMETA_NONE, 0, 0, 0, 0, 0,
ARBITRARY_TIME, ARBITRARY_TIME,
/*pointerCount*/ MAX_POINTERS + 1, pointerProperties, pointerCoords);
ASSERT_EQ(INPUT_EVENT_INJECTION_FAILED, mDispatcher->injectInputEvent(
@@ -222,7 +222,7 @@ TEST_F(InputDispatcherTest, InjectInputEvent_ValidatesMotionEvents) {
// Rejects motion events with invalid pointer ids.
pointerProperties[0].id = -1;
event.initialize(DEVICE_ID, AINPUT_SOURCE_TOUCHSCREEN,
- AMOTION_EVENT_ACTION_DOWN, 0, 0, AMETA_NONE, 0, 0, 0, 0, 0,
+ AMOTION_EVENT_ACTION_DOWN, 0, 0, 0, AMETA_NONE, 0, 0, 0, 0, 0,
ARBITRARY_TIME, ARBITRARY_TIME,
/*pointerCount*/ 1, pointerProperties, pointerCoords);
ASSERT_EQ(INPUT_EVENT_INJECTION_FAILED, mDispatcher->injectInputEvent(
@@ -232,7 +232,7 @@ TEST_F(InputDispatcherTest, InjectInputEvent_ValidatesMotionEvents) {
pointerProperties[0].id = MAX_POINTER_ID + 1;
event.initialize(DEVICE_ID, AINPUT_SOURCE_TOUCHSCREEN,
- AMOTION_EVENT_ACTION_DOWN, 0, 0, AMETA_NONE, 0, 0, 0, 0, 0,
+ AMOTION_EVENT_ACTION_DOWN, 0, 0, 0, AMETA_NONE, 0, 0, 0, 0, 0,
ARBITRARY_TIME, ARBITRARY_TIME,
/*pointerCount*/ 1, pointerProperties, pointerCoords);
ASSERT_EQ(INPUT_EVENT_INJECTION_FAILED, mDispatcher->injectInputEvent(
@@ -244,7 +244,7 @@ TEST_F(InputDispatcherTest, InjectInputEvent_ValidatesMotionEvents) {
pointerProperties[0].id = 1;
pointerProperties[1].id = 1;
event.initialize(DEVICE_ID, AINPUT_SOURCE_TOUCHSCREEN,
- AMOTION_EVENT_ACTION_DOWN, 0, 0, AMETA_NONE, 0, 0, 0, 0, 0,
+ AMOTION_EVENT_ACTION_DOWN, 0, 0, 0, AMETA_NONE, 0, 0, 0, 0, 0,
ARBITRARY_TIME, ARBITRARY_TIME,
/*pointerCount*/ 2, pointerProperties, pointerCoords);
ASSERT_EQ(INPUT_EVENT_INJECTION_FAILED, mDispatcher->injectInputEvent(
diff --git a/services/inputflinger/tests/InputReader_test.cpp b/services/inputflinger/tests/InputReader_test.cpp
index 40f51b6..f34b810 100644
--- a/services/inputflinger/tests/InputReader_test.cpp
+++ b/services/inputflinger/tests/InputReader_test.cpp
@@ -777,6 +777,14 @@ private:
virtual int32_t bumpGeneration() {
return ++mGeneration;
}
+
+ virtual void getExternalStylusDevices(Vector<InputDeviceInfo>& outDevices) {
+
+ }
+
+ virtual void dispatchExternalStylusState(const StylusState&) {
+
+ }
};
diff --git a/services/sensorservice/SensorDevice.cpp b/services/sensorservice/SensorDevice.cpp
index 80845a2..dd1bccf 100644
--- a/services/sensorservice/SensorDevice.cpp
+++ b/services/sensorservice/SensorDevice.cpp
@@ -79,16 +79,17 @@ void SensorDevice::dump(String8& result)
sensor_t const* list;
ssize_t count = mSensorModule->get_sensors_list(mSensorModule, &list);
- result.appendFormat("halVersion %d\n", getHalDeviceVersion());
+ result.appendFormat("halVersion 0x%08x\n", getHalDeviceVersion());
result.appendFormat("%d h/w sensors:\n", int(count));
Mutex::Autolock _l(mLock);
for (size_t i=0 ; i<size_t(count) ; i++) {
const Info& info = mActivationCount.valueFor(list[i].handle);
+ if (info.batchParams.isEmpty()) continue;
result.appendFormat("handle=0x%08x, active-count=%zu, batch_period(ms)={ ", list[i].handle,
info.batchParams.size());
for (size_t j = 0; j < info.batchParams.size(); j++) {
- BatchParams params = info.batchParams.valueAt(j);
+ const BatchParams& params = info.batchParams.valueAt(j);
result.appendFormat("%4.1f%s", params.batchDelay / 1e6f,
j < info.batchParams.size() - 1 ? ", " : "");
}
@@ -147,8 +148,12 @@ status_t SensorDevice::activate(void* ident, int handle, int enabled)
if (enabled) {
ALOGD_IF(DEBUG_CONNECTIONS, "enable index=%zd", info.batchParams.indexOfKey(ident));
+ if (isClientDisabledLocked(ident)) {
+ return INVALID_OPERATION;
+ }
+
if (info.batchParams.indexOfKey(ident) >= 0) {
- if (info.batchParams.size() == 1) {
+ if (info.numActiveClients() == 1) {
// This is the first connection, we need to activate the underlying h/w sensor.
actuateHardware = true;
}
@@ -160,7 +165,7 @@ status_t SensorDevice::activate(void* ident, int handle, int enabled)
ALOGD_IF(DEBUG_CONNECTIONS, "disable index=%zd", info.batchParams.indexOfKey(ident));
if (info.removeBatchParamsForIdent(ident) >= 0) {
- if (info.batchParams.size() == 0) {
+ if (info.numActiveClients() == 0) {
// This is the last connection, we need to de-activate the underlying h/w sensor.
actuateHardware = true;
} else {
@@ -181,10 +186,15 @@ status_t SensorDevice::activate(void* ident, int handle, int enabled)
} else {
// sensor wasn't enabled for this ident
}
+
+ if (isClientDisabledLocked(ident)) {
+ return NO_ERROR;
+ }
}
if (actuateHardware) {
- ALOGD_IF(DEBUG_CONNECTIONS, "\t>>> actuating h/w activate handle=%d enabled=%d", handle, enabled);
+ ALOGD_IF(DEBUG_CONNECTIONS, "\t>>> actuating h/w activate handle=%d enabled=%d", handle,
+ enabled);
err = mSensorDevice->activate(
reinterpret_cast<struct sensors_poll_device_t *> (mSensorDevice), handle, enabled);
ALOGE_IF(err, "Error %s sensor %d (%s)", enabled ? "activating" : "disabling", handle,
@@ -197,7 +207,7 @@ status_t SensorDevice::activate(void* ident, int handle, int enabled)
}
// On older devices which do not support batch, call setDelay().
- if (getHalDeviceVersion() < SENSORS_DEVICE_API_VERSION_1_1 && info.batchParams.size() > 0) {
+ if (getHalDeviceVersion() < SENSORS_DEVICE_API_VERSION_1_1 && info.numActiveClients() > 0) {
ALOGD_IF(DEBUG_CONNECTIONS, "\t>>> actuating h/w setDelay %d %" PRId64, handle,
info.bestBatchParams.batchDelay);
mSensorDevice->setDelay(
@@ -279,6 +289,7 @@ status_t SensorDevice::setDelay(void* ident, int handle, int64_t samplingPeriodN
samplingPeriodNs = MINIMUM_EVENTS_PERIOD;
}
Mutex::Autolock _l(mLock);
+ if (isClientDisabledLocked(ident)) return INVALID_OPERATION;
Info& info( mActivationCount.editValueFor(handle) );
// If the underlying sensor is NOT in continuous mode, setDelay() should return an error.
// Calling setDelay() in batch mode is an invalid operation.
@@ -298,7 +309,6 @@ status_t SensorDevice::setDelay(void* ident, int handle, int64_t samplingPeriodN
int SensorDevice::getHalDeviceVersion() const {
if (!mSensorDevice) return -1;
-
return mSensorDevice->common.version;
}
@@ -306,12 +316,110 @@ status_t SensorDevice::flush(void* ident, int handle) {
if (getHalDeviceVersion() < SENSORS_DEVICE_API_VERSION_1_1) {
return INVALID_OPERATION;
}
+ if (isClientDisabled(ident)) return INVALID_OPERATION;
ALOGD_IF(DEBUG_CONNECTIONS, "\t>>> actuating h/w flush %d", handle);
return mSensorDevice->flush(mSensorDevice, handle);
}
+bool SensorDevice::isClientDisabled(void* ident) {
+ Mutex::Autolock _l(mLock);
+ return isClientDisabledLocked(ident);
+}
+
+bool SensorDevice::isClientDisabledLocked(void* ident) {
+ return mDisabledClients.indexOf(ident) >= 0;
+}
+
+void SensorDevice::enableAllSensors() {
+ Mutex::Autolock _l(mLock);
+ mDisabledClients.clear();
+ const int halVersion = getHalDeviceVersion();
+ for (size_t i = 0; i< mActivationCount.size(); ++i) {
+ Info& info = mActivationCount.editValueAt(i);
+ if (info.batchParams.isEmpty()) continue;
+ info.selectBatchParams();
+ const int sensor_handle = mActivationCount.keyAt(i);
+ ALOGD_IF(DEBUG_CONNECTIONS, "\t>> reenable actuating h/w sensor enable handle=%d ",
+ sensor_handle);
+ status_t err(NO_ERROR);
+ if (halVersion > SENSORS_DEVICE_API_VERSION_1_0) {
+ err = mSensorDevice->batch(mSensorDevice, sensor_handle,
+ info.bestBatchParams.flags, info.bestBatchParams.batchDelay,
+ info.bestBatchParams.batchTimeout);
+ ALOGE_IF(err, "Error calling batch on sensor %d (%s)", sensor_handle, strerror(-err));
+ }
+
+ if (err == NO_ERROR) {
+ err = mSensorDevice->activate(
+ reinterpret_cast<struct sensors_poll_device_t *>(mSensorDevice),
+ sensor_handle, 1);
+ ALOGE_IF(err, "Error activating sensor %d (%s)", sensor_handle, strerror(-err));
+ }
+
+ if (halVersion <= SENSORS_DEVICE_API_VERSION_1_0) {
+ err = mSensorDevice->setDelay(
+ reinterpret_cast<struct sensors_poll_device_t *>(mSensorDevice),
+ sensor_handle, info.bestBatchParams.batchDelay);
+ ALOGE_IF(err, "Error calling setDelay sensor %d (%s)", sensor_handle, strerror(-err));
+ }
+ }
+}
+
+void SensorDevice::disableAllSensors() {
+ Mutex::Autolock _l(mLock);
+ for (size_t i = 0; i< mActivationCount.size(); ++i) {
+ const Info& info = mActivationCount.valueAt(i);
+ // Check if this sensor has been activated previously and disable it.
+ if (info.batchParams.size() > 0) {
+ const int sensor_handle = mActivationCount.keyAt(i);
+ ALOGD_IF(DEBUG_CONNECTIONS, "\t>> actuating h/w sensor disable handle=%d ",
+ sensor_handle);
+ mSensorDevice->activate(
+ reinterpret_cast<struct sensors_poll_device_t *> (mSensorDevice),
+ sensor_handle, 0);
+ // Add all the connections that were registered for this sensor to the disabled
+ // clients list.
+ for (size_t j = 0; j < info.batchParams.size(); ++j) {
+ mDisabledClients.add(info.batchParams.keyAt(j));
+ }
+ }
+ }
+}
+
+status_t SensorDevice::injectSensorData(const sensors_event_t *injected_sensor_event) {
+ ALOGD_IF(DEBUG_CONNECTIONS,
+ "sensor_event handle=%d ts=%lld data=%.2f, %.2f, %.2f %.2f %.2f %.2f",
+ injected_sensor_event->sensor,
+ injected_sensor_event->timestamp, injected_sensor_event->data[0],
+ injected_sensor_event->data[1], injected_sensor_event->data[2],
+ injected_sensor_event->data[3], injected_sensor_event->data[4],
+ injected_sensor_event->data[5]);
+ if (getHalDeviceVersion() < SENSORS_DEVICE_API_VERSION_1_4) {
+ return INVALID_OPERATION;
+ }
+ return mSensorDevice->inject_sensor_data(mSensorDevice, injected_sensor_event);
+}
+
+status_t SensorDevice::setMode(uint32_t mode) {
+ if (getHalDeviceVersion() < SENSORS_DEVICE_API_VERSION_1_4) {
+ return INVALID_OPERATION;
+ }
+ return mSensorModule->set_operation_mode(mode);
+}
+
// ---------------------------------------------------------------------------
+int SensorDevice::Info::numActiveClients() {
+ SensorDevice& device(SensorDevice::getInstance());
+ int num = 0;
+ for (size_t i = 0; i < batchParams.size(); ++i) {
+ if (!device.isClientDisabledLocked(batchParams.keyAt(i))) {
+ ++num;
+ }
+ }
+ return num;
+}
+
status_t SensorDevice::Info::setBatchParamsForIdent(void* ident, int flags,
int64_t samplingPeriodNs,
int64_t maxBatchReportLatencyNs) {
@@ -329,19 +437,16 @@ status_t SensorDevice::Info::setBatchParamsForIdent(void* ident, int flags,
}
void SensorDevice::Info::selectBatchParams() {
- BatchParams bestParams(-1, -1, -1);
-
- if (batchParams.size() > 0) {
- BatchParams params = batchParams.valueAt(0);
- bestParams = params;
- }
+ BatchParams bestParams(0, -1, -1);
+ SensorDevice& device(SensorDevice::getInstance());
- for (size_t i = 1; i < batchParams.size(); ++i) {
+ for (size_t i = 0; i < batchParams.size(); ++i) {
+ if (device.isClientDisabledLocked(batchParams.keyAt(i))) continue;
BatchParams params = batchParams.valueAt(i);
- if (params.batchDelay < bestParams.batchDelay) {
+ if (bestParams.batchDelay == -1 || params.batchDelay < bestParams.batchDelay) {
bestParams.batchDelay = params.batchDelay;
}
- if (params.batchTimeout < bestParams.batchTimeout) {
+ if (bestParams.batchTimeout == -1 || params.batchTimeout < bestParams.batchTimeout) {
bestParams.batchTimeout = params.batchTimeout;
}
}
diff --git a/services/sensorservice/SensorDevice.h b/services/sensorservice/SensorDevice.h
index 761b48c..c484849 100644
--- a/services/sensorservice/SensorDevice.h
+++ b/services/sensorservice/SensorDevice.h
@@ -42,6 +42,7 @@ class SensorDevice : public Singleton<SensorDevice> {
// Struct to store all the parameters(samplingPeriod, maxBatchReportLatency and flags) from
// batch call. For continous mode clients, maxBatchReportLatency is set to zero.
struct BatchParams {
+ // TODO: Get rid of flags parameter everywhere.
int flags;
nsecs_t batchDelay, batchTimeout;
BatchParams() : flags(0), batchDelay(0), batchTimeout(0) {}
@@ -65,7 +66,7 @@ class SensorDevice : public Singleton<SensorDevice> {
// requested by the client.
KeyedVector<void*, BatchParams> batchParams;
- Info() : bestBatchParams(-1, -1, -1) {}
+ Info() : bestBatchParams(0, -1, -1) {}
// Sets batch parameters for this ident. Returns error if this ident is not already present
// in the KeyedVector above.
status_t setBatchParamsForIdent(void* ident, int flags, int64_t samplingPeriodNs,
@@ -75,10 +76,17 @@ class SensorDevice : public Singleton<SensorDevice> {
// Removes batchParams for an ident and re-computes bestBatchParams. Returns the index of
// the removed ident. If index >=0, ident is present and successfully removed.
ssize_t removeBatchParamsForIdent(void* ident);
+
+ int numActiveClients();
};
DefaultKeyedVector<int, Info> mActivationCount;
+ // Use this vector to determine which client is activated or deactivated.
+ SortedVector<void *> mDisabledClients;
SensorDevice();
+
+ bool isClientDisabled(void* ident);
+ bool isClientDisabledLocked(void* ident);
public:
ssize_t getSensorList(sensor_t const** list);
status_t initCheck() const;
@@ -90,7 +98,11 @@ public:
// Call batch with timeout zero instead of calling setDelay() for newer devices.
status_t setDelay(void* ident, int handle, int64_t ns);
status_t flush(void* ident, int handle);
+ status_t setMode(uint32_t mode);
+ void disableAllSensors();
+ void enableAllSensors();
void autoDisable(void *ident, int handle);
+ status_t injectSensorData(const sensors_event_t *event);
void dump(String8& result);
};
diff --git a/services/sensorservice/SensorService.cpp b/services/sensorservice/SensorService.cpp
index a857366..40b21a9 100644
--- a/services/sensorservice/SensorService.cpp
+++ b/services/sensorservice/SensorService.cpp
@@ -31,6 +31,7 @@
#include <utils/Singleton.h>
#include <utils/String16.h>
+#include <binder/AppOpsManager.h>
#include <binder/BinderService.h>
#include <binder/IServiceManager.h>
#include <binder/PermissionCache.h>
@@ -63,7 +64,9 @@ namespace android {
*
*/
-const char* SensorService::WAKE_LOCK_NAME = "SensorService";
+const char* SensorService::WAKE_LOCK_NAME = "SensorService_wakelock";
+// Permissions.
+static const String16 sDump("android.permission.DUMP");
SensorService::SensorService()
: mInitCheck(NO_INIT), mSocketBufferSize(SOCKET_BUFFER_SIZE_NON_BATCHED),
@@ -74,7 +77,6 @@ SensorService::SensorService()
void SensorService::onFirstRef()
{
ALOGD("nuSensorService starting...");
-
SensorDevice& dev(SensorDevice::getInstance());
if (dev.initCheck() == NO_ERROR) {
@@ -82,7 +84,7 @@ void SensorService::onFirstRef()
ssize_t count = dev.getSensorList(&list);
if (count > 0) {
ssize_t orientationIndex = -1;
- bool hasGyro = false;
+ bool hasGyro = false, hasAccel = false, hasMag = false;
uint32_t virtualSensorsNeeds =
(1<<SENSOR_TYPE_GRAVITY) |
(1<<SENSOR_TYPE_LINEAR_ACCELERATION) |
@@ -92,6 +94,12 @@ void SensorService::onFirstRef()
for (ssize_t i=0 ; i<count ; i++) {
registerSensor( new HardwareSensor(list[i]) );
switch (list[i].type) {
+ case SENSOR_TYPE_ACCELEROMETER:
+ hasAccel = true;
+ break;
+ case SENSOR_TYPE_MAGNETIC_FIELD:
+ hasMag = true;
+ break;
case SENSOR_TYPE_ORIENTATION:
orientationIndex = i;
break;
@@ -115,7 +123,7 @@ void SensorService::onFirstRef()
// build the sensor list returned to users
mUserSensorList = mSensorList;
- if (hasGyro) {
+ if (hasGyro && hasAccel && hasMag) {
Sensor aSensor;
// Add Android virtual sensors if they're not already
@@ -154,7 +162,7 @@ void SensorService::onFirstRef()
// Check if the device really supports batching by looking at the FIFO event
// counts for each sensor.
bool batchingSupported = false;
- for (int i = 0; i < mSensorList.size(); ++i) {
+ for (size_t i = 0; i < mSensorList.size(); ++i) {
if (mSensorList[i].getFifoMaxEventCount() > 0) {
batchingSupported = true;
break;
@@ -190,10 +198,16 @@ void SensorService::onFirstRef()
mSensorEventBuffer = new sensors_event_t[minBufferSize];
mSensorEventScratch = new sensors_event_t[minBufferSize];
mMapFlushEventsToConnections = new SensorEventConnection const * [minBufferSize];
+ mCurrentOperatingMode = NORMAL;
+
+ mNextSensorRegIndex = 0;
+ for (int i = 0; i < SENSOR_REGISTRATIONS_BUF_SIZE; ++i) {
+ mLastNSensorRegistrations.push();
+ }
+ mInitCheck = NO_ERROR;
mAckReceiver = new SensorEventAckReceiver(this);
mAckReceiver->run("SensorEventAckReceiver", PRIORITY_URGENT_DISPLAY);
- mInitCheck = NO_ERROR;
run("SensorService", PRIORITY_URGENT_DISPLAY);
}
}
@@ -210,7 +224,7 @@ Sensor SensorService::registerSensor(SensorInterface* s)
// add to our handle->SensorInterface mapping
mSensorMap.add(sensor.getHandle(), s);
// create an entry in the mLastEventSeen array
- mLastEventSeen.add(sensor.getHandle(), event);
+ mLastEventSeen.add(sensor.getHandle(), NULL);
return sensor;
}
@@ -228,9 +242,7 @@ SensorService::~SensorService()
delete mSensorMap.valueAt(i);
}
-static const String16 sDump("android.permission.DUMP");
-
-status_t SensorService::dump(int fd, const Vector<String16>& /*args*/)
+status_t SensorService::dump(int fd, const Vector<String16>& args)
{
String8 result;
if (!PermissionCache::checkCallingPermission(sDump)) {
@@ -239,116 +251,188 @@ status_t SensorService::dump(int fd, const Vector<String16>& /*args*/)
IPCThreadState::self()->getCallingPid(),
IPCThreadState::self()->getCallingUid());
} else {
+ if (args.size() > 2) {
+ return INVALID_OPERATION;
+ }
Mutex::Autolock _l(mLock);
- result.append("Sensor List:\n");
- for (size_t i=0 ; i<mSensorList.size() ; i++) {
- const Sensor& s(mSensorList[i]);
- const sensors_event_t& e(mLastEventSeen.valueFor(s.getHandle()));
- result.appendFormat(
- "%-15s| %-10s| version=%d |%-20s| 0x%08x | \"%s\" | type=%d |",
- s.getName().string(),
- s.getVendor().string(),
- s.getVersion(),
- s.getStringType().string(),
- s.getHandle(),
- s.getRequiredPermission().string(),
- s.getType());
-
- const int reportingMode = s.getReportingMode();
- if (reportingMode == AREPORTING_MODE_CONTINUOUS) {
- result.append(" continuous | ");
- } else if (reportingMode == AREPORTING_MODE_ON_CHANGE) {
- result.append(" on-change | ");
- } else if (reportingMode == AREPORTING_MODE_ONE_SHOT) {
- result.append(" one-shot | ");
- } else {
- result.append(" special-trigger | ");
+ SensorDevice& dev(SensorDevice::getInstance());
+ if (args.size() == 2 && args[0] == String16("restrict")) {
+ // If already in restricted mode. Ignore.
+ if (mCurrentOperatingMode == RESTRICTED) {
+ return status_t(NO_ERROR);
}
-
- if (s.getMaxDelay() > 0) {
- result.appendFormat("minRate=%.2fHz | ", 1e6f / s.getMaxDelay());
- } else {
- result.appendFormat("maxDelay=%dus |", s.getMaxDelay());
+ // If in any mode other than normal, ignore.
+ if (mCurrentOperatingMode != NORMAL) {
+ return INVALID_OPERATION;
}
-
- if (s.getMinDelay() > 0) {
- result.appendFormat("maxRate=%.2fHz | ", 1e6f / s.getMinDelay());
- } else {
- result.appendFormat("minDelay=%dus |", s.getMinDelay());
+ mCurrentOperatingMode = RESTRICTED;
+ dev.disableAllSensors();
+ // Clear all pending flush connections for all active sensors. If one of the active
+ // connections has called flush() and the underlying sensor has been disabled before a
+ // flush complete event is returned, we need to remove the connection from this queue.
+ for (size_t i=0 ; i< mActiveSensors.size(); ++i) {
+ mActiveSensors.valueAt(i)->clearAllPendingFlushConnections();
}
-
- if (s.getFifoMaxEventCount() > 0) {
- result.appendFormat("FifoMax=%d events | ",
- s.getFifoMaxEventCount());
- } else {
- result.append("no batching | ");
+ mWhiteListedPackage.setTo(String8(args[1]));
+ return status_t(NO_ERROR);
+ } else if (args.size() == 1 && args[0] == String16("enable")) {
+ // If currently in restricted mode, reset back to NORMAL mode else ignore.
+ if (mCurrentOperatingMode == RESTRICTED) {
+ mCurrentOperatingMode = NORMAL;
+ dev.enableAllSensors();
}
-
- if (s.isWakeUpSensor()) {
- result.appendFormat("wakeUp | ");
+ if (mCurrentOperatingMode == DATA_INJECTION) {
+ resetToNormalModeLocked();
+ }
+ mWhiteListedPackage.clear();
+ return status_t(NO_ERROR);
+ } else if (args.size() == 2 && args[0] == String16("data_injection")) {
+ if (mCurrentOperatingMode == NORMAL) {
+ dev.disableAllSensors();
+ status_t err = dev.setMode(DATA_INJECTION);
+ if (err == NO_ERROR) {
+ mCurrentOperatingMode = DATA_INJECTION;
+ } else {
+ // Re-enable sensors.
+ dev.enableAllSensors();
+ }
+ mWhiteListedPackage.setTo(String8(args[1]));
+ return NO_ERROR;
+ } else if (mCurrentOperatingMode == DATA_INJECTION) {
+ // Already in DATA_INJECTION mode. Treat this as a no_op.
+ return NO_ERROR;
} else {
- result.appendFormat("non-wakeUp | ");
+ // Transition to data injection mode supported only from NORMAL mode.
+ return INVALID_OPERATION;
}
+ } else if (mSensorList.size() == 0) {
+ result.append("No Sensors on the device\n");
+ } else {
+ // Default dump the sensor list and debugging information.
+ result.append("Sensor List:\n");
+ for (size_t i=0 ; i<mSensorList.size() ; i++) {
+ const Sensor& s(mSensorList[i]);
+ result.appendFormat(
+ "%-15s| %-10s| version=%d |%-20s| 0x%08x | \"%s\" | type=%d |",
+ s.getName().string(),
+ s.getVendor().string(),
+ s.getVersion(),
+ s.getStringType().string(),
+ s.getHandle(),
+ s.getRequiredPermission().string(),
+ s.getType());
+
+ const int reportingMode = s.getReportingMode();
+ if (reportingMode == AREPORTING_MODE_CONTINUOUS) {
+ result.append(" continuous | ");
+ } else if (reportingMode == AREPORTING_MODE_ON_CHANGE) {
+ result.append(" on-change | ");
+ } else if (reportingMode == AREPORTING_MODE_ONE_SHOT) {
+ result.append(" one-shot | ");
+ } else {
+ result.append(" special-trigger | ");
+ }
- switch (s.getType()) {
- case SENSOR_TYPE_ROTATION_VECTOR:
- case SENSOR_TYPE_GEOMAGNETIC_ROTATION_VECTOR:
- result.appendFormat(
- "last=<%5.1f,%5.1f,%5.1f,%5.1f,%5.1f, %" PRId64 ">\n",
- e.data[0], e.data[1], e.data[2], e.data[3], e.data[4], e.timestamp);
- break;
- case SENSOR_TYPE_MAGNETIC_FIELD_UNCALIBRATED:
- case SENSOR_TYPE_GYROSCOPE_UNCALIBRATED:
- result.appendFormat(
- "last=<%5.1f,%5.1f,%5.1f,%5.1f,%5.1f,%5.1f, %" PRId64 ">\n",
- e.data[0], e.data[1], e.data[2], e.data[3], e.data[4], e.data[5],
- e.timestamp);
- break;
- case SENSOR_TYPE_GAME_ROTATION_VECTOR:
- result.appendFormat(
- "last=<%5.1f,%5.1f,%5.1f,%5.1f, %" PRId64 ">\n",
- e.data[0], e.data[1], e.data[2], e.data[3], e.timestamp);
- break;
- case SENSOR_TYPE_SIGNIFICANT_MOTION:
- case SENSOR_TYPE_STEP_DETECTOR:
- result.appendFormat( "last=<%f %" PRId64 ">\n", e.data[0], e.timestamp);
- break;
- case SENSOR_TYPE_STEP_COUNTER:
- result.appendFormat( "last=<%" PRIu64 ", %" PRId64 ">\n", e.u64.step_counter,
- e.timestamp);
- break;
- default:
- // default to 3 values
- result.appendFormat(
- "last=<%5.1f,%5.1f,%5.1f, %" PRId64 ">\n",
- e.data[0], e.data[1], e.data[2], e.timestamp);
- break;
+ if (s.getMaxDelay() > 0) {
+ result.appendFormat("minRate=%.2fHz | ", 1e6f / s.getMaxDelay());
+ } else {
+ result.appendFormat("maxDelay=%dus |", s.getMaxDelay());
+ }
+
+ if (s.getMinDelay() > 0) {
+ result.appendFormat("maxRate=%.2fHz | ", 1e6f / s.getMinDelay());
+ } else {
+ result.appendFormat("minDelay=%dus |", s.getMinDelay());
+ }
+
+ if (s.getFifoMaxEventCount() > 0) {
+ result.appendFormat("FifoMax=%d events | ",
+ s.getFifoMaxEventCount());
+ } else {
+ result.append("no batching | ");
+ }
+
+ if (s.isWakeUpSensor()) {
+ result.appendFormat("wakeUp | ");
+ } else {
+ result.appendFormat("non-wakeUp | ");
+ }
+
+ int bufIndex = mLastEventSeen.indexOfKey(s.getHandle());
+ if (bufIndex >= 0) {
+ const CircularBuffer* buf = mLastEventSeen.valueAt(bufIndex);
+ if (buf != NULL && s.getRequiredPermission().isEmpty()) {
+ buf->printBuffer(result);
+ } else {
+ result.append("last=<> \n");
+ }
+ }
+ result.append("\n");
+ }
+ SensorFusion::getInstance().dump(result);
+ SensorDevice::getInstance().dump(result);
+
+ result.append("Active sensors:\n");
+ for (size_t i=0 ; i<mActiveSensors.size() ; i++) {
+ int handle = mActiveSensors.keyAt(i);
+ result.appendFormat("%s (handle=0x%08x, connections=%zu)\n",
+ getSensorName(handle).string(),
+ handle,
+ mActiveSensors.valueAt(i)->getNumConnections());
}
- result.append("\n");
- }
- SensorFusion::getInstance().dump(result);
- SensorDevice::getInstance().dump(result);
-
- result.append("Active sensors:\n");
- for (size_t i=0 ; i<mActiveSensors.size() ; i++) {
- int handle = mActiveSensors.keyAt(i);
- result.appendFormat("%s (handle=0x%08x, connections=%zu)\n",
- getSensorName(handle).string(),
- handle,
- mActiveSensors.valueAt(i)->getNumConnections());
- }
- result.appendFormat("Socket Buffer size = %d events\n",
- mSocketBufferSize/sizeof(sensors_event_t));
- result.appendFormat("WakeLock Status: %s \n", mWakeLockAcquired ? "acquired" : "not held");
- result.appendFormat("%zd active connections\n", mActiveConnections.size());
+ result.appendFormat("Socket Buffer size = %d events\n",
+ mSocketBufferSize/sizeof(sensors_event_t));
+ result.appendFormat("WakeLock Status: %s \n", mWakeLockAcquired ? "acquired" :
+ "not held");
+ result.appendFormat("Mode :");
+ switch(mCurrentOperatingMode) {
+ case NORMAL:
+ result.appendFormat(" NORMAL\n");
+ break;
+ case RESTRICTED:
+ result.appendFormat(" RESTRICTED : %s\n", mWhiteListedPackage.string());
+ break;
+ case DATA_INJECTION:
+ result.appendFormat(" DATA_INJECTION : %s\n", mWhiteListedPackage.string());
+ }
+ result.appendFormat("%zd active connections\n", mActiveConnections.size());
- for (size_t i=0 ; i < mActiveConnections.size() ; i++) {
- sp<SensorEventConnection> connection(mActiveConnections[i].promote());
- if (connection != 0) {
- result.appendFormat("Connection Number: %zu \n", i);
- connection->dump(result);
+ for (size_t i=0 ; i < mActiveConnections.size() ; i++) {
+ sp<SensorEventConnection> connection(mActiveConnections[i].promote());
+ if (connection != 0) {
+ result.appendFormat("Connection Number: %zu \n", i);
+ connection->dump(result);
+ }
}
+
+ result.appendFormat("Previous Registrations:\n");
+ // Log in the reverse chronological order.
+ int currentIndex = (mNextSensorRegIndex - 1 + SENSOR_REGISTRATIONS_BUF_SIZE) %
+ SENSOR_REGISTRATIONS_BUF_SIZE;
+ const int startIndex = currentIndex;
+ do {
+ const SensorRegistrationInfo& reg_info = mLastNSensorRegistrations[currentIndex];
+ if (SensorRegistrationInfo::isSentinel(reg_info)) {
+ // Ignore sentinel, proceed to next item.
+ currentIndex = (currentIndex - 1 + SENSOR_REGISTRATIONS_BUF_SIZE) %
+ SENSOR_REGISTRATIONS_BUF_SIZE;
+ continue;
+ }
+ if (reg_info.mActivated) {
+ result.appendFormat("%02d:%02d:%02d activated package=%s handle=0x%08x "
+ "samplingRate=%dus maxReportLatency=%dus\n",
+ reg_info.mHour, reg_info.mMin, reg_info.mSec,
+ reg_info.mPackageName.string(), reg_info.mSensorHandle,
+ reg_info.mSamplingRateUs, reg_info.mMaxReportLatencyUs);
+ } else {
+ result.appendFormat("%02d:%02d:%02d de-activated package=%s handle=0x%08x\n",
+ reg_info.mHour, reg_info.mMin, reg_info.mSec,
+ reg_info.mPackageName.string(), reg_info.mSensorHandle);
+ }
+ currentIndex = (currentIndex - 1 + SENSOR_REGISTRATIONS_BUF_SIZE) %
+ SENSOR_REGISTRATIONS_BUF_SIZE;
+ } while(startIndex != currentIndex);
}
}
write(fd, result.string(), result.size());
@@ -371,8 +455,9 @@ void SensorService::cleanupAutoDisabledSensorLocked(const sp<SensorEventConnecti
sensor->autoDisable(connection.get(), handle);
cleanupWithoutDisableLocked(connection, handle);
}
+
}
- }
+ }
}
bool SensorService::threadLoop()
@@ -554,7 +639,6 @@ void SensorService::setWakeLockAcquiredLocked(bool acquire) {
}
}
-
bool SensorService::isWakeLockAcquired() {
Mutex::Autolock _l(mLock);
return mWakeLockAcquired;
@@ -577,19 +661,15 @@ bool SensorService::SensorEventAckReceiver::threadLoop() {
void SensorService::recordLastValueLocked(
const sensors_event_t* buffer, size_t count) {
- const sensors_event_t* last = NULL;
for (size_t i = 0; i < count; i++) {
- const sensors_event_t* event = &buffer[i];
- if (event->type != SENSOR_TYPE_META_DATA) {
- if (last && event->sensor != last->sensor) {
- mLastEventSeen.editValueFor(last->sensor) = *last;
+ if (buffer[i].type != SENSOR_TYPE_META_DATA) {
+ CircularBuffer* &circular_buf = mLastEventSeen.editValueFor(buffer[i].sensor);
+ if (circular_buf == NULL) {
+ circular_buf = new CircularBuffer(buffer[i].type);
}
- last = event;
+ circular_buf->addEvent(buffer[i]);
}
}
- if (last) {
- mLastEventSeen.editValueFor(last->sensor) = *last;
- }
}
void SensorService::sortEventBuffer(sensors_event_t* buffer, size_t count)
@@ -630,12 +710,11 @@ bool SensorService::isWakeUpSensorEvent(const sensors_event_t& event) const {
return sensor != NULL && sensor->getSensor().isWakeUpSensor();
}
-
SensorService::SensorRecord * SensorService::getSensorRecord(int handle) {
return mActiveSensors.valueFor(handle);
}
-Vector<Sensor> SensorService::getSensorList()
+Vector<Sensor> SensorService::getSensorList(const String16& opPackageName)
{
char value[PROPERTY_VALUE_MAX];
property_get("debug.sensors", value, "0");
@@ -644,24 +723,65 @@ Vector<Sensor> SensorService::getSensorList()
Vector<Sensor> accessibleSensorList;
for (size_t i = 0; i < initialSensorList.size(); i++) {
Sensor sensor = initialSensorList[i];
- if (canAccessSensor(sensor)) {
+ if (canAccessSensor(sensor, "getSensorList", opPackageName)) {
accessibleSensorList.add(sensor);
} else {
- ALOGI("Skipped sensor %s because it requires permission %s",
+ ALOGI("Skipped sensor %s because it requires permission %s and app op %d",
sensor.getName().string(),
- sensor.getRequiredPermission().string());
+ sensor.getRequiredPermission().string(),
+ sensor.getRequiredAppOp());
}
}
return accessibleSensorList;
}
-sp<ISensorEventConnection> SensorService::createSensorEventConnection()
-{
+sp<ISensorEventConnection> SensorService::createSensorEventConnection(const String8& packageName,
+ int requestedMode, const String16& opPackageName) {
+ // Only 2 modes supported for a SensorEventConnection ... NORMAL and DATA_INJECTION.
+ if (requestedMode != NORMAL && requestedMode != DATA_INJECTION) {
+ return NULL;
+ }
+
+ Mutex::Autolock _l(mLock);
+ // To create a client in DATA_INJECTION mode to inject data, SensorService should already be
+ // operating in DI mode.
+ if (requestedMode == DATA_INJECTION) {
+ if (mCurrentOperatingMode != DATA_INJECTION) return NULL;
+ if (!isWhiteListedPackage(packageName)) return NULL;
+ }
+
uid_t uid = IPCThreadState::self()->getCallingUid();
- sp<SensorEventConnection> result(new SensorEventConnection(this, uid));
+ sp<SensorEventConnection> result(new SensorEventConnection(this, uid, packageName,
+ requestedMode == DATA_INJECTION, opPackageName));
+ if (requestedMode == DATA_INJECTION) {
+ if (mActiveConnections.indexOf(result) < 0) {
+ mActiveConnections.add(result);
+ }
+ // Add the associated file descriptor to the Looper for polling whenever there is data to
+ // be injected.
+ result->updateLooperRegistration(mLooper);
+ }
return result;
}
+int SensorService::isDataInjectionEnabled() {
+ Mutex::Autolock _l(mLock);
+ return (mCurrentOperatingMode == DATA_INJECTION);
+}
+
+status_t SensorService::resetToNormalMode() {
+ Mutex::Autolock _l(mLock);
+ return resetToNormalModeLocked();
+}
+
+status_t SensorService::resetToNormalModeLocked() {
+ SensorDevice& dev(SensorDevice::getInstance());
+ dev.enableAllSensors();
+ status_t err = dev.setMode(NORMAL);
+ mCurrentOperatingMode = NORMAL;
+ return err;
+}
+
void SensorService::cleanupConnection(SensorEventConnection* c)
{
Mutex::Autolock _l(mLock);
@@ -708,7 +828,8 @@ Sensor SensorService::getSensorFromHandle(int handle) const {
}
status_t SensorService::enable(const sp<SensorEventConnection>& connection,
- int handle, nsecs_t samplingPeriodNs, nsecs_t maxBatchReportLatencyNs, int reservedFlags)
+ int handle, nsecs_t samplingPeriodNs, nsecs_t maxBatchReportLatencyNs, int reservedFlags,
+ const String16& opPackageName)
{
if (mInitCheck != NO_ERROR)
return mInitCheck;
@@ -718,11 +839,16 @@ status_t SensorService::enable(const sp<SensorEventConnection>& connection,
return BAD_VALUE;
}
- if (!verifyCanAccessSensor(sensor->getSensor(), "Tried enabling")) {
+ if (!canAccessSensor(sensor->getSensor(), "Tried enabling", opPackageName)) {
return BAD_VALUE;
}
Mutex::Autolock _l(mLock);
+ if ((mCurrentOperatingMode == RESTRICTED || mCurrentOperatingMode == DATA_INJECTION)
+ && !isWhiteListedPackage(connection->getPackageName())) {
+ return INVALID_OPERATION;
+ }
+
SensorRecord* rec = mActiveSensors.valueFor(handle);
if (rec == 0) {
rec = new SensorRecord(connection);
@@ -738,14 +864,24 @@ status_t SensorService::enable(const sp<SensorEventConnection>& connection,
if (sensor->getSensor().getReportingMode() == AREPORTING_MODE_ON_CHANGE) {
// NOTE: The wake_up flag of this event may get set to
// WAKE_UP_SENSOR_EVENT_NEEDS_ACK if this is a wake_up event.
- sensors_event_t& event(mLastEventSeen.editValueFor(handle));
- if (event.version == sizeof(sensors_event_t)) {
- if (isWakeUpSensorEvent(event) && !mWakeLockAcquired) {
- setWakeLockAcquiredLocked(true);
- }
- connection->sendEvents(&event, 1, NULL);
- if (!connection->needsWakeLock() && mWakeLockAcquired) {
- checkWakeLockStateLocked();
+ CircularBuffer *circular_buf = mLastEventSeen.valueFor(handle);
+ if (circular_buf) {
+ sensors_event_t event;
+ memset(&event, 0, sizeof(event));
+ // It is unlikely that this buffer is empty as the sensor is already active.
+ // One possible corner case may be two applications activating an on-change
+ // sensor at the same time.
+ if(circular_buf->populateLastEvent(&event)) {
+ event.sensor = handle;
+ if (event.version == sizeof(sensors_event_t)) {
+ if (isWakeUpSensorEvent(event) && !mWakeLockAcquired) {
+ setWakeLockAcquiredLocked(true);
+ }
+ connection->sendEvents(&event, 1, NULL);
+ if (!connection->needsWakeLock() && mWakeLockAcquired) {
+ checkWakeLockStateLocked();
+ }
+ }
}
}
}
@@ -773,7 +909,7 @@ status_t SensorService::enable(const sp<SensorEventConnection>& connection,
"rate=%" PRId64 " timeout== %" PRId64"",
handle, reservedFlags, samplingPeriodNs, maxBatchReportLatencyNs);
- status_t err = sensor->batch(connection.get(), handle, reservedFlags, samplingPeriodNs,
+ status_t err = sensor->batch(connection.get(), handle, 0, samplingPeriodNs,
maxBatchReportLatencyNs);
// Call flush() before calling activate() on the sensor. Wait for a first flush complete
@@ -798,6 +934,19 @@ status_t SensorService::enable(const sp<SensorEventConnection>& connection,
if (err == NO_ERROR) {
connection->updateLooperRegistration(mLooper);
+ SensorRegistrationInfo &reg_info =
+ mLastNSensorRegistrations.editItemAt(mNextSensorRegIndex);
+ reg_info.mSensorHandle = handle;
+ reg_info.mSamplingRateUs = samplingPeriodNs/1000;
+ reg_info.mMaxReportLatencyUs = maxBatchReportLatencyNs/1000;
+ reg_info.mActivated = true;
+ reg_info.mPackageName = connection->getPackageName();
+ time_t rawtime = time(NULL);
+ struct tm * timeinfo = localtime(&rawtime);
+ reg_info.mHour = timeinfo->tm_hour;
+ reg_info.mMin = timeinfo->tm_min;
+ reg_info.mSec = timeinfo->tm_sec;
+ mNextSensorRegIndex = (mNextSensorRegIndex + 1) % SENSOR_REGISTRATIONS_BUF_SIZE;
}
if (err != NO_ERROR) {
@@ -818,6 +967,20 @@ status_t SensorService::disable(const sp<SensorEventConnection>& connection,
if (err == NO_ERROR) {
SensorInterface* sensor = mSensorMap.valueFor(handle);
err = sensor ? sensor->activate(connection.get(), false) : status_t(BAD_VALUE);
+
+ }
+ if (err == NO_ERROR) {
+ SensorRegistrationInfo &reg_info =
+ mLastNSensorRegistrations.editItemAt(mNextSensorRegIndex);
+ reg_info.mActivated = false;
+ reg_info.mPackageName= connection->getPackageName();
+ reg_info.mSensorHandle = handle;
+ time_t rawtime = time(NULL);
+ struct tm * timeinfo = localtime(&rawtime);
+ reg_info.mHour = timeinfo->tm_hour;
+ reg_info.mMin = timeinfo->tm_min;
+ reg_info.mSec = timeinfo->tm_sec;
+ mNextSensorRegIndex = (mNextSensorRegIndex + 1) % SENSOR_REGISTRATIONS_BUF_SIZE;
}
return err;
}
@@ -852,7 +1015,7 @@ status_t SensorService::cleanupWithoutDisableLocked(
}
status_t SensorService::setEventRate(const sp<SensorEventConnection>& connection,
- int handle, nsecs_t ns)
+ int handle, nsecs_t ns, const String16& opPackageName)
{
if (mInitCheck != NO_ERROR)
return mInitCheck;
@@ -861,7 +1024,7 @@ status_t SensorService::setEventRate(const sp<SensorEventConnection>& connection
if (!sensor)
return BAD_VALUE;
- if (!verifyCanAccessSensor(sensor->getSensor(), "Tried configuring")) {
+ if (!canAccessSensor(sensor->getSensor(), "Tried configuring", opPackageName)) {
return BAD_VALUE;
}
@@ -876,7 +1039,8 @@ status_t SensorService::setEventRate(const sp<SensorEventConnection>& connection
return sensor->setDelay(connection.get(), handle, ns);
}
-status_t SensorService::flushSensor(const sp<SensorEventConnection>& connection) {
+status_t SensorService::flushSensor(const sp<SensorEventConnection>& connection,
+ const String16& opPackageName) {
if (mInitCheck != NO_ERROR) return mInitCheck;
SensorDevice& dev(SensorDevice::getInstance());
const int halVersion = dev.getHalDeviceVersion();
@@ -896,6 +1060,10 @@ status_t SensorService::flushSensor(const sp<SensorEventConnection>& connection)
// flush complete event.
connection->incrementPendingFlushCount(handle);
} else {
+ if (!canAccessSensor(sensor->getSensor(), "Tried flushing", opPackageName)) {
+ err = INVALID_OPERATION;
+ continue;
+ }
status_t err_flush = sensor->flush(connection.get(), handle);
if (err_flush == NO_ERROR) {
SensorRecord* rec = mActiveSensors.valueFor(handle);
@@ -907,23 +1075,42 @@ status_t SensorService::flushSensor(const sp<SensorEventConnection>& connection)
return err;
}
-bool SensorService::canAccessSensor(const Sensor& sensor) {
- return (sensor.getRequiredPermission().isEmpty()) ||
- PermissionCache::checkCallingPermission(String16(sensor.getRequiredPermission()));
-}
+bool SensorService::canAccessSensor(const Sensor& sensor, const char* operation,
+ const String16& opPackageName) {
+ const String8& requiredPermission = sensor.getRequiredPermission();
-bool SensorService::verifyCanAccessSensor(const Sensor& sensor, const char* operation) {
- if (canAccessSensor(sensor)) {
+ if (requiredPermission.length() <= 0) {
return true;
+ }
+
+ bool hasPermission = false;
+
+ // Runtime permissions can't use the cache as they may change.
+ if (sensor.isRequiredPermissionRuntime()) {
+ hasPermission = checkPermission(String16(requiredPermission),
+ IPCThreadState::self()->getCallingPid(), IPCThreadState::self()->getCallingUid());
} else {
- String8 errorMessage;
- errorMessage.appendFormat(
- "%s a sensor (%s) without holding its required permission: %s",
- operation,
- sensor.getName().string(),
- sensor.getRequiredPermission().string());
+ hasPermission = PermissionCache::checkCallingPermission(String16(requiredPermission));
+ }
+
+ if (!hasPermission) {
+ ALOGE("%s a sensor (%s) without holding its required permission: %s",
+ operation, sensor.getName().string(), sensor.getRequiredPermission().string());
return false;
}
+
+ const int32_t opCode = sensor.getRequiredAppOp();
+ if (opCode >= 0) {
+ AppOpsManager appOps;
+ if (appOps.noteOp(opCode, IPCThreadState::self()->getCallingUid(), opPackageName)
+ != AppOpsManager::MODE_ALLOWED) {
+ ALOGE("%s a sensor (%s) without enabled required app op: %D",
+ operation, sensor.getName().string(), opCode);
+ return false;
+ }
+ }
+
+ return true;
}
void SensorService::checkWakeLockState() {
@@ -969,6 +1156,33 @@ void SensorService::populateActiveConnections(
}
}
+bool SensorService::isWhiteListedPackage(const String8& packageName) {
+ return (packageName.contains(mWhiteListedPackage.string()));
+}
+
+int SensorService::getNumEventsForSensorType(int sensor_event_type) {
+ switch (sensor_event_type) {
+ case SENSOR_TYPE_ROTATION_VECTOR:
+ case SENSOR_TYPE_GEOMAGNETIC_ROTATION_VECTOR:
+ return 5;
+
+ case SENSOR_TYPE_MAGNETIC_FIELD_UNCALIBRATED:
+ case SENSOR_TYPE_GYROSCOPE_UNCALIBRATED:
+ return 6;
+
+ case SENSOR_TYPE_GAME_ROTATION_VECTOR:
+ return 4;
+
+ case SENSOR_TYPE_SIGNIFICANT_MOTION:
+ case SENSOR_TYPE_STEP_DETECTOR:
+ case SENSOR_TYPE_STEP_COUNTER:
+ return 1;
+
+ default:
+ return 3;
+ }
+}
+
// ---------------------------------------------------------------------------
SensorService::SensorRecord::SensorRecord(
const sp<SensorEventConnection>& connection)
@@ -1025,12 +1239,121 @@ SensorService::SensorRecord::getFirstPendingFlushConnection() {
return NULL;
}
+void SensorService::SensorRecord::clearAllPendingFlushConnections() {
+ mPendingFlushConnections.clear();
+}
+
+
+// ---------------------------------------------------------------------------
+SensorService::TrimmedSensorEvent::TrimmedSensorEvent(int sensorType) {
+ mTimestamp = -1;
+ const int numData = SensorService::getNumEventsForSensorType(sensorType);
+ if (sensorType == SENSOR_TYPE_STEP_COUNTER) {
+ mStepCounter = 0;
+ } else {
+ mData = new float[numData];
+ for (int i = 0; i < numData; ++i) {
+ mData[i] = -1.0;
+ }
+ }
+ mHour = mMin = mSec = INT32_MIN;
+}
+
+bool SensorService::TrimmedSensorEvent::isSentinel(const TrimmedSensorEvent& event) {
+ return (event.mHour == INT32_MIN && event.mMin == INT32_MIN && event.mSec == INT32_MIN);
+}
+// --------------------------------------------------------------------------
+SensorService::CircularBuffer::CircularBuffer(int sensor_event_type) {
+ mNextInd = 0;
+ mBufSize = CIRCULAR_BUF_SIZE;
+ if (sensor_event_type == SENSOR_TYPE_STEP_COUNTER ||
+ sensor_event_type == SENSOR_TYPE_SIGNIFICANT_MOTION ||
+ sensor_event_type == SENSOR_TYPE_ACCELEROMETER) {
+ mBufSize = CIRCULAR_BUF_SIZE * 5;
+ }
+ mTrimmedSensorEventArr = new TrimmedSensorEvent *[mBufSize];
+ mSensorType = sensor_event_type;
+ for (int i = 0; i < mBufSize; ++i) {
+ mTrimmedSensorEventArr[i] = new TrimmedSensorEvent(mSensorType);
+ }
+}
+
+void SensorService::CircularBuffer::addEvent(const sensors_event_t& sensor_event) {
+ TrimmedSensorEvent *curr_event = mTrimmedSensorEventArr[mNextInd];
+ curr_event->mTimestamp = sensor_event.timestamp;
+ if (mSensorType == SENSOR_TYPE_STEP_COUNTER) {
+ curr_event->mStepCounter = sensor_event.u64.step_counter;
+ } else {
+ memcpy(curr_event->mData, sensor_event.data,
+ sizeof(float) * SensorService::getNumEventsForSensorType(mSensorType));
+ }
+ time_t rawtime = time(NULL);
+ struct tm * timeinfo = localtime(&rawtime);
+ curr_event->mHour = timeinfo->tm_hour;
+ curr_event->mMin = timeinfo->tm_min;
+ curr_event->mSec = timeinfo->tm_sec;
+ mNextInd = (mNextInd + 1) % mBufSize;
+}
+
+void SensorService::CircularBuffer::printBuffer(String8& result) const {
+ const int numData = SensorService::getNumEventsForSensorType(mSensorType);
+ int i = mNextInd, eventNum = 1;
+ result.appendFormat("last %d events = < ", mBufSize);
+ do {
+ if (TrimmedSensorEvent::isSentinel(*mTrimmedSensorEventArr[i])) {
+ // Sentinel, ignore.
+ i = (i + 1) % mBufSize;
+ continue;
+ }
+ result.appendFormat("%d) ", eventNum++);
+ if (mSensorType == SENSOR_TYPE_STEP_COUNTER) {
+ result.appendFormat("%llu,", mTrimmedSensorEventArr[i]->mStepCounter);
+ } else {
+ for (int j = 0; j < numData; ++j) {
+ result.appendFormat("%5.1f,", mTrimmedSensorEventArr[i]->mData[j]);
+ }
+ }
+ result.appendFormat("%lld %02d:%02d:%02d ", mTrimmedSensorEventArr[i]->mTimestamp,
+ mTrimmedSensorEventArr[i]->mHour, mTrimmedSensorEventArr[i]->mMin,
+ mTrimmedSensorEventArr[i]->mSec);
+ i = (i + 1) % mBufSize;
+ } while (i != mNextInd);
+ result.appendFormat(">\n");
+}
+
+bool SensorService::CircularBuffer::populateLastEvent(sensors_event_t *event) {
+ int lastEventInd = (mNextInd - 1 + mBufSize) % mBufSize;
+ // Check if the buffer is empty.
+ if (TrimmedSensorEvent::isSentinel(*mTrimmedSensorEventArr[lastEventInd])) {
+ return false;
+ }
+ event->version = sizeof(sensors_event_t);
+ event->type = mSensorType;
+ event->timestamp = mTrimmedSensorEventArr[lastEventInd]->mTimestamp;
+ if (mSensorType == SENSOR_TYPE_STEP_COUNTER) {
+ event->u64.step_counter = mTrimmedSensorEventArr[lastEventInd]->mStepCounter;
+ } else {
+ memcpy(event->data, mTrimmedSensorEventArr[lastEventInd]->mData,
+ sizeof(float) * SensorService::getNumEventsForSensorType(mSensorType));
+ }
+ return true;
+}
+
+SensorService::CircularBuffer::~CircularBuffer() {
+ for (int i = 0; i < mBufSize; ++i) {
+ delete mTrimmedSensorEventArr[i];
+ }
+ delete [] mTrimmedSensorEventArr;
+}
+
// ---------------------------------------------------------------------------
SensorService::SensorEventConnection::SensorEventConnection(
- const sp<SensorService>& service, uid_t uid)
+ const sp<SensorService>& service, uid_t uid, String8 packageName, bool isDataInjectionMode,
+ const String16& opPackageName)
: mService(service), mUid(uid), mWakeLockRefCount(0), mHasLooperCallbacks(false),
- mDead(false), mEventCache(NULL), mCacheSize(0), mMaxCacheSize(0) {
+ mDead(false), mDataInjectionMode(isDataInjectionMode), mEventCache(NULL),
+ mCacheSize(0), mMaxCacheSize(0), mPackageName(packageName), mOpPackageName(opPackageName) {
mChannel = new BitTube(mService->mSocketBufferSize);
#if DEBUG_CONNECTIONS
mEventsReceived = mEventsSentFromCache = mEventsSent = 0;
@@ -1062,8 +1385,10 @@ void SensorService::SensorEventConnection::resetWakeLockRefCount() {
void SensorService::SensorEventConnection::dump(String8& result) {
Mutex::Autolock _l(mConnectionLock);
- result.appendFormat("\t WakeLockRefCount %d | uid %d | cache size %d | max cache size %d\n",
- mWakeLockRefCount, mUid, mCacheSize, mMaxCacheSize);
+ result.appendFormat("\tOperating Mode: %s\n",mDataInjectionMode ? "DATA_INJECTION" : "NORMAL");
+ result.appendFormat("\t %s | WakeLockRefCount %d | uid %d | cache size %d | "
+ "max cache size %d\n", mPackageName.string(), mWakeLockRefCount, mUid, mCacheSize,
+ mMaxCacheSize);
for (size_t i = 0; i < mSensorInfo.size(); ++i) {
const FlushInfo& flushInfo = mSensorInfo.valueAt(i);
result.appendFormat("\t %s 0x%08x | status: %s | pending flush events %d \n",
@@ -1087,7 +1412,8 @@ void SensorService::SensorEventConnection::dump(String8& result) {
bool SensorService::SensorEventConnection::addSensor(int32_t handle) {
Mutex::Autolock _l(mConnectionLock);
- if (!verifyCanAccessSensor(mService->getSensorFromHandle(handle), "Tried adding")) {
+ if (!canAccessSensor(mService->getSensorFromHandle(handle),
+ "Tried adding", mOpPackageName)) {
return false;
}
if (mSensorInfo.indexOfKey(handle) < 0) {
@@ -1126,6 +1452,10 @@ bool SensorService::SensorEventConnection::hasOneShotSensors() const {
return false;
}
+String8 SensorService::SensorEventConnection::getPackageName() const {
+ return mPackageName;
+}
+
void SensorService::SensorEventConnection::setFirstFlushPending(int32_t handle,
bool value) {
Mutex::Autolock _l(mConnectionLock);
@@ -1143,7 +1473,8 @@ void SensorService::SensorEventConnection::updateLooperRegistration(const sp<Loo
void SensorService::SensorEventConnection::updateLooperRegistrationLocked(
const sp<Looper>& looper) {
- bool isConnectionActive = mSensorInfo.size() > 0;
+ bool isConnectionActive = (mSensorInfo.size() > 0 && !mDataInjectionMode) ||
+ mDataInjectionMode;
// If all sensors are unregistered OR Looper has encountered an error, we
// can remove the Fd from the Looper if it has been previously added.
if (!isConnectionActive || mDead) {
@@ -1157,6 +1488,7 @@ void SensorService::SensorEventConnection::updateLooperRegistrationLocked(
int looper_flags = 0;
if (mCacheSize > 0) looper_flags |= ALOOPER_EVENT_OUTPUT;
+ if (mDataInjectionMode) looper_flags |= ALOOPER_EVENT_INPUT;
for (size_t i = 0; i < mSensorInfo.size(); ++i) {
const int handle = mSensorInfo.keyAt(i);
if (mService->getSensorFromHandle(handle).isWakeUpSensor()) {
@@ -1200,7 +1532,7 @@ status_t SensorService::SensorEventConnection::sendEvents(
sensors_event_t* scratch,
SensorEventConnection const * const * mapFlushEventsToConnections) {
// filter out events not for this connection
- size_t count = 0;
+ int count = 0;
Mutex::Autolock _l(mConnectionLock);
if (scratch) {
size_t i=0;
@@ -1492,7 +1824,7 @@ status_t SensorService::SensorEventConnection::enableDisable(
status_t err;
if (enabled) {
err = mService->enable(this, handle, samplingPeriodNs, maxBatchReportLatencyNs,
- reservedFlags);
+ reservedFlags, mOpPackageName);
} else {
err = mService->disable(this, handle);
@@ -1503,11 +1835,11 @@ status_t SensorService::SensorEventConnection::enableDisable(
status_t SensorService::SensorEventConnection::setEventRate(
int handle, nsecs_t samplingPeriodNs)
{
- return mService->setEventRate(this, handle, samplingPeriodNs);
+ return mService->setEventRate(this, handle, samplingPeriodNs, mOpPackageName);
}
status_t SensorService::SensorEventConnection::flush() {
- return mService->flushSensor(this);
+ return mService->flushSensor(this, mOpPackageName);
}
int SensorService::SensorEventConnection::handleEvent(int fd, int events, void* /*data*/) {
@@ -1523,26 +1855,55 @@ int SensorService::SensorEventConnection::handleEvent(int fd, int events, void*
updateLooperRegistrationLocked(mService->getLooper());
}
mService->checkWakeLockState();
+ if (mDataInjectionMode) {
+ // If the Looper has encountered some error in data injection mode, reset SensorService
+ // back to normal mode.
+ mService->resetToNormalMode();
+ mDataInjectionMode = false;
+ }
return 1;
}
if (events & ALOOPER_EVENT_INPUT) {
- uint32_t numAcks = 0;
- ssize_t ret = ::recv(fd, &numAcks, sizeof(numAcks), MSG_DONTWAIT);
+ unsigned char buf[sizeof(sensors_event_t)];
+ ssize_t numBytesRead = ::recv(fd, buf, sizeof(buf), MSG_DONTWAIT);
{
Mutex::Autolock _l(mConnectionLock);
- // Sanity check to ensure there are no read errors in recv, numAcks is always
- // within the range and not zero. If any of the above don't hold reset mWakeLockRefCount
- // to zero.
- if (ret != sizeof(numAcks) || numAcks > mWakeLockRefCount || numAcks == 0) {
- ALOGE("Looper read error ret=%d numAcks=%d", ret, numAcks);
- mWakeLockRefCount = 0;
- } else {
- mWakeLockRefCount -= numAcks;
- }
+ if (numBytesRead == sizeof(sensors_event_t)) {
+ if (!mDataInjectionMode) {
+ ALOGE("Data injected in normal mode, dropping event"
+ "package=%s uid=%d", mPackageName.string(), mUid);
+ // Unregister call backs.
+ return 0;
+ }
+ SensorDevice& dev(SensorDevice::getInstance());
+ sensors_event_t sensor_event;
+ memset(&sensor_event, 0, sizeof(sensor_event));
+ memcpy(&sensor_event, buf, sizeof(sensors_event_t));
+ Sensor sensor = mService->getSensorFromHandle(sensor_event.sensor);
+ sensor_event.type = sensor.getType();
+ dev.injectSensorData(&sensor_event);
#if DEBUG_CONNECTIONS
- mTotalAcksReceived += numAcks;
+ ++mEventsReceived;
#endif
+ } else if (numBytesRead == sizeof(uint32_t)) {
+ uint32_t numAcks = 0;
+ memcpy(&numAcks, buf, numBytesRead);
+ // Sanity check to ensure there are no read errors in recv, numAcks is always
+ // within the range and not zero. If any of the above don't hold reset
+ // mWakeLockRefCount to zero.
+ if (numAcks > 0 && numAcks < mWakeLockRefCount) {
+ mWakeLockRefCount -= numAcks;
+ } else {
+ mWakeLockRefCount = 0;
+ }
+#if DEBUG_CONNECTIONS
+ mTotalAcksReceived += numAcks;
+#endif
+ } else {
+ // Read error, reset wakelock refcount.
+ mWakeLockRefCount = 0;
+ }
}
// Check if wakelock can be released by sensorservice. mConnectionLock needs to be released
// here as checkWakeLockState() will need it.
@@ -1561,8 +1922,8 @@ int SensorService::SensorEventConnection::handleEvent(int fd, int events, void*
}
int SensorService::SensorEventConnection::computeMaxCacheSizeLocked() const {
- int fifoWakeUpSensors = 0;
- int fifoNonWakeUpSensors = 0;
+ size_t fifoWakeUpSensors = 0;
+ size_t fifoNonWakeUpSensors = 0;
for (size_t i = 0; i < mSensorInfo.size(); ++i) {
const Sensor& sensor = mService->getSensorFromHandle(mSensorInfo.keyAt(i));
if (sensor.getFifoReservedEventCount() == sensor.getFifoMaxEventCount()) {
diff --git a/services/sensorservice/SensorService.h b/services/sensorservice/SensorService.h
index e9ca3a5..9a573ae 100644
--- a/services/sensorservice/SensorService.h
+++ b/services/sensorservice/SensorService.h
@@ -27,6 +27,7 @@
#include <utils/AndroidThreads.h>
#include <utils/RefBase.h>
#include <utils/Looper.h>
+#include <utils/String8.h>
#include <binder/BinderService.h>
@@ -52,6 +53,9 @@
// For older HALs which don't support batching, use a smaller socket buffer size.
#define SOCKET_BUFFER_SIZE_NON_BATCHED 4 * 1024
+#define CIRCULAR_BUF_SIZE 10
+#define SENSOR_REGISTRATIONS_BUF_SIZE 20
+
struct sensors_poll_device_t;
struct sensors_module_t;
@@ -65,6 +69,51 @@ class SensorService :
{
friend class BinderService<SensorService>;
+ enum Mode {
+ // The regular operating mode where any application can register/unregister/call flush on
+ // sensors.
+ NORMAL = 0,
+ // This mode is only used for testing purposes. Not all HALs support this mode. In this
+ // mode, the HAL ignores the sensor data provided by physical sensors and accepts the data
+ // that is injected from the SensorService as if it were the real sensor data. This mode
+ // is primarily used for testing various algorithms like vendor provided SensorFusion,
+ // Step Counter and Step Detector etc. Typically in this mode, there will be a client
+ // (a SensorEventConnection) which will be injecting sensor data into the HAL. Normal apps
+ // can unregister and register for any sensor that supports injection. Registering to sensors
+ // that do not support injection will give an error.
+ // TODO(aakella) : Allow exactly one client to inject sensor data at a time.
+ DATA_INJECTION = 1,
+ // This mode is used only for testing sensors. Each sensor can be tested in isolation with
+ // the required sampling_rate and maxReportLatency parameters without having to think about
+ // the data rates requested by other applications. End user devices are always expected to be
+ // in NORMAL mode. When this mode is first activated, all active sensors from all connections
+ // are disabled. Calling flush() will return an error. In this mode, only the requests from
+ // selected apps whose package names are whitelisted are allowed (typically CTS apps). Only
+ // these apps can register/unregister/call flush() on sensors. If SensorService switches to
+ // NORMAL mode again, all sensors that were previously registered to are activated with the
+ // corresponding paramaters if the application hasn't unregistered for sensors in the mean
+ // time.
+ // NOTE: Non whitelisted app whose sensors were previously deactivated may still receive
+ // events if a whitelisted app requests data from the same sensor.
+ RESTRICTED = 2
+
+ // State Transitions supported.
+ // RESTRICTED <--- NORMAL ---> DATA_INJECTION
+ // ---> <---
+
+ // Shell commands to switch modes in SensorService.
+ // 1) Put SensorService in RESTRICTED mode with packageName .cts. If it is already in
+ // restricted mode it is treated as a NO_OP (and packageName is NOT changed).
+ // $ adb shell dumpsys sensorservice restrict .cts.
+ //
+ // 2) Put SensorService in DATA_INJECTION mode with packageName .xts. If it is already in
+ // data_injection mode it is treated as a NO_OP (and packageName is NOT changed).
+ // $ adb shell dumpsys sensorservice data_injection .xts.
+ //
+ // 3) Reset sensorservice back to NORMAL mode.
+ // $ adb shell dumpsys sensorservice enable
+ };
+
static const char* WAKE_LOCK_NAME;
static char const* getServiceName() ANDROID_API { return "sensorservice"; }
@@ -77,8 +126,10 @@ class SensorService :
virtual bool threadLoop();
// ISensorServer interface
- virtual Vector<Sensor> getSensorList();
- virtual sp<ISensorEventConnection> createSensorEventConnection();
+ virtual Vector<Sensor> getSensorList(const String16& opPackageName);
+ virtual sp<ISensorEventConnection> createSensorEventConnection(const String8& packageName,
+ int requestedMode, const String16& opPackageName);
+ virtual int isDataInjectionEnabled();
virtual status_t dump(int fd, const Vector<String16>& args);
class SensorEventConnection : public BnSensorEventConnection, public LooperCallback {
@@ -133,7 +184,6 @@ class SensorService :
// connection FD may be added to the Looper. The flags to set are determined by the internal
// state of the connection. FDs are added to the looper when wake-up sensors are registered
// (to poll for acknowledgements) and when write fails on the socket when there are too many
- // events (to poll when the FD is available for writing). FDs are removed when there is an
// error and the other end hangs up or when this client unregisters for this connection.
void updateLooperRegistration(const sp<Looper>& looper);
void updateLooperRegistrationLocked(const sp<Looper>& looper);
@@ -156,6 +206,8 @@ class SensorService :
// mWakeLockRefCount is reset to zero. needsWakeLock method will always return false, if
// this flag is set.
bool mDead;
+
+ bool mDataInjectionMode;
struct FlushInfo {
// The number of flush complete events dropped for this sensor is stored here.
// They are sent separately before the next batch of events.
@@ -169,14 +221,16 @@ class SensorService :
KeyedVector<int, FlushInfo> mSensorInfo;
sensors_event_t *mEventCache;
int mCacheSize, mMaxCacheSize;
-
+ String8 mPackageName;
+ const String16 mOpPackageName;
#if DEBUG_CONNECTIONS
int mEventsReceived, mEventsSent, mEventsSentFromCache;
int mTotalAcksNeeded, mTotalAcksReceived;
#endif
public:
- SensorEventConnection(const sp<SensorService>& service, uid_t uid);
+ SensorEventConnection(const sp<SensorService>& service, uid_t uid, String8 packageName,
+ bool isDataInjectionMode, const String16& opPackageName);
status_t sendEvents(sensors_event_t const* buffer, size_t count,
sensors_event_t* scratch,
@@ -190,6 +244,7 @@ class SensorService :
void dump(String8& result);
bool needsWakeLock();
void resetWakeLockRefCount();
+ String8 getPackageName() const;
uid_t getUid() const { return mUid; }
};
@@ -208,6 +263,7 @@ class SensorService :
void addPendingFlushConnection(const sp<SensorEventConnection>& connection);
void removeFirstPendingFlushConnection();
SensorEventConnection * getFirstPendingFlushConnection();
+ void clearAllPendingFlushConnections();
};
class SensorEventAckReceiver : public Thread {
@@ -217,6 +273,63 @@ class SensorService :
SensorEventAckReceiver(const sp<SensorService>& service): mService(service) {}
};
+ // sensor_event_t with only the data and the timestamp.
+ struct TrimmedSensorEvent {
+ union {
+ float *mData;
+ uint64_t mStepCounter;
+ };
+ // Timestamp from the sensor_event.
+ int64_t mTimestamp;
+ // HH:MM:SS local time at which this sensor event is read at SensorService. Useful
+ // for debugging.
+ int32_t mHour, mMin, mSec;
+
+ TrimmedSensorEvent(int sensorType);
+ static bool isSentinel(const TrimmedSensorEvent& event);
+
+ ~TrimmedSensorEvent() {
+ delete [] mData;
+ }
+ };
+
+ // A circular buffer of TrimmedSensorEvents. The size of this buffer is typically 10. The
+ // last N events generated from the sensor are stored in this buffer. The buffer is NOT
+ // cleared when the sensor unregisters and as a result one may see very old data in the
+ // dumpsys output but this is WAI.
+ class CircularBuffer {
+ int mNextInd;
+ int mSensorType;
+ int mBufSize;
+ TrimmedSensorEvent ** mTrimmedSensorEventArr;
+ public:
+ CircularBuffer(int sensor_event_type);
+ void addEvent(const sensors_event_t& sensor_event);
+ void printBuffer(String8& buffer) const;
+ bool populateLastEvent(sensors_event_t *event);
+ ~CircularBuffer();
+ };
+
+ struct SensorRegistrationInfo {
+ int32_t mSensorHandle;
+ String8 mPackageName;
+ bool mActivated;
+ int32_t mSamplingRateUs;
+ int32_t mMaxReportLatencyUs;
+ int32_t mHour, mMin, mSec;
+
+ SensorRegistrationInfo() : mPackageName() {
+ mSensorHandle = mSamplingRateUs = mMaxReportLatencyUs = INT32_MIN;
+ mHour = mMin = mSec = INT32_MIN;
+ mActivated = false;
+ }
+
+ static bool isSentinel(const SensorRegistrationInfo& info) {
+ return (info.mHour == INT32_MIN && info.mMin == INT32_MIN && info.mSec == INT32_MIN);
+ }
+ };
+
+ static int getNumEventsForSensorType(int sensor_event_type);
String8 getSensorName(int handle) const;
bool isVirtualSensor(int handle) const;
Sensor getSensorFromHandle(int handle) const;
@@ -231,8 +344,8 @@ class SensorService :
const sp<SensorEventConnection>& connection, int handle);
void cleanupAutoDisabledSensorLocked(const sp<SensorEventConnection>& connection,
sensors_event_t const* buffer, const int count);
- static bool canAccessSensor(const Sensor& sensor);
- static bool verifyCanAccessSensor(const Sensor& sensor, const char* operation);
+ static bool canAccessSensor(const Sensor& sensor, const char* operation,
+ const String16& opPackageName);
// SensorService acquires a partial wakelock for delivering events from wake up sensors. This
// method checks whether all the events from these wake up sensors have been delivered to the
// corresponding applications, if yes the wakelock is released.
@@ -261,6 +374,15 @@ class SensorService :
// to the output vector.
void populateActiveConnections(SortedVector< sp<SensorEventConnection> >* activeConnections);
+ // If SensorService is operating in RESTRICTED mode, only select whitelisted packages are
+ // allowed to register for or call flush on sensors. Typically only cts test packages are
+ // allowed.
+ bool isWhiteListedPackage(const String8& packageName);
+
+ // Reset the state of SensorService to NORMAL mode.
+ status_t resetToNormalMode();
+ status_t resetToNormalModeLocked();
+
// constants
Vector<Sensor> mSensorList;
Vector<Sensor> mUserSensorListDebug;
@@ -282,17 +404,28 @@ class SensorService :
bool mWakeLockAcquired;
sensors_event_t *mSensorEventBuffer, *mSensorEventScratch;
SensorEventConnection const **mMapFlushEventsToConnections;
+ Mode mCurrentOperatingMode;
+ // This packagaName is set when SensorService is in RESTRICTED or DATA_INJECTION mode. Only
+ // applications with this packageName are allowed to activate/deactivate or call flush on
+ // sensors. To run CTS this is can be set to ".cts." and only CTS tests will get access to
+ // sensors.
+ String8 mWhiteListedPackage;
// The size of this vector is constant, only the items are mutable
- KeyedVector<int32_t, sensors_event_t> mLastEventSeen;
+ KeyedVector<int32_t, CircularBuffer *> mLastEventSeen;
+ int mNextSensorRegIndex;
+ Vector<SensorRegistrationInfo> mLastNSensorRegistrations;
public:
void cleanupConnection(SensorEventConnection* connection);
status_t enable(const sp<SensorEventConnection>& connection, int handle,
- nsecs_t samplingPeriodNs, nsecs_t maxBatchReportLatencyNs, int reservedFlags);
+ nsecs_t samplingPeriodNs, nsecs_t maxBatchReportLatencyNs, int reservedFlags,
+ const String16& opPackageName);
status_t disable(const sp<SensorEventConnection>& connection, int handle);
- status_t setEventRate(const sp<SensorEventConnection>& connection, int handle, nsecs_t ns);
- status_t flushSensor(const sp<SensorEventConnection>& connection);
+ status_t setEventRate(const sp<SensorEventConnection>& connection, int handle, nsecs_t ns,
+ const String16& opPackageName);
+ status_t flushSensor(const sp<SensorEventConnection>& connection,
+ const String16& opPackageName);
};
// ---------------------------------------------------------------------------
diff --git a/services/sensorservice/tests/sensorservicetest.cpp b/services/sensorservice/tests/sensorservicetest.cpp
index 1025fa8..cfdf6a3 100644
--- a/services/sensorservice/tests/sensorservicetest.cpp
+++ b/services/sensorservice/tests/sensorservicetest.cpp
@@ -14,6 +14,7 @@
* limitations under the License.
*/
+#include <inttypes.h>
#include <android/sensor.h>
#include <gui/Sensor.h>
#include <gui/SensorManager.h>
@@ -25,7 +26,7 @@ using namespace android;
static nsecs_t sStartTime = 0;
-int receiver(int fd, int events, void* data)
+int receiver(__unused int fd, __unused int events, void* data)
{
sp<SensorEventQueue> q((SensorEventQueue*)data);
ssize_t n;
@@ -44,7 +45,7 @@ int receiver(int fd, int events, void* data)
oldTimeStamp = buffer[i].timestamp;
if (buffer[i].type == Sensor::TYPE_ACCELEROMETER) {
- printf("%lld\t%8f\t%8f\t%8f\t%f\n",
+ printf("%" PRId64 "\t%8f\t%8f\t%8f\t%f\n",
buffer[i].timestamp,
buffer[i].data[0], buffer[i].data[1], buffer[i].data[2],
1.0/t);
@@ -59,9 +60,9 @@ int receiver(int fd, int events, void* data)
}
-int main(int argc, char** argv)
+int main()
{
- SensorManager& mgr(SensorManager::getInstance());
+ SensorManager mgr(String16("Sensor Service Test"));
Sensor const* const* list;
ssize_t count = mgr.getSensorList(&list);
diff --git a/services/surfaceflinger/Client.cpp b/services/surfaceflinger/Client.cpp
index f7d32d0..49389e0 100644
--- a/services/surfaceflinger/Client.cpp
+++ b/services/surfaceflinger/Client.cpp
@@ -93,7 +93,7 @@ status_t Client::onTransact(
const int pid = ipc->getCallingPid();
const int uid = ipc->getCallingUid();
const int self_pid = getpid();
- if (CC_UNLIKELY(pid != self_pid && uid != AID_GRAPHICS && uid != 0)) {
+ if (CC_UNLIKELY(pid != self_pid && uid != AID_GRAPHICS && uid != AID_SYSTEM && uid != 0)) {
// we're called from a different process, do the real check
if (!PermissionCache::checkCallingPermission(sAccessSurfaceFlinger))
{
diff --git a/services/surfaceflinger/DdmConnection.cpp b/services/surfaceflinger/DdmConnection.cpp
index a000a84..659c2c8 100644
--- a/services/surfaceflinger/DdmConnection.cpp
+++ b/services/surfaceflinger/DdmConnection.cpp
@@ -66,7 +66,7 @@ void DdmConnection::start(const char* name) {
jint (*registerNatives)(JNIEnv* env, jclass clazz);
registerNatives = reinterpret_cast<decltype(registerNatives)>(
dlsym(libandroid_runtime_dso,
- "Java_com_android_internal_util_WithFramework_registerNatives"));
+ "Java_com_android_internal_util_WithFramework_registerNatives"));
ALOGE_IF(!registerNatives, "DdmConnection: %s", dlerror());
if (!JNI_CreateJavaVM || !registerNatives) {
diff --git a/services/surfaceflinger/DispSync.h b/services/surfaceflinger/DispSync.h
index 96efc34..67142b6 100644
--- a/services/surfaceflinger/DispSync.h
+++ b/services/surfaceflinger/DispSync.h
@@ -139,7 +139,7 @@ private:
enum { MAX_RESYNC_SAMPLES = 32 };
enum { MIN_RESYNC_SAMPLES_FOR_UPDATE = 3 };
enum { NUM_PRESENT_SAMPLES = 8 };
- enum { MAX_RESYNC_SAMPLES_WITHOUT_PRESENT = 12 };
+ enum { MAX_RESYNC_SAMPLES_WITHOUT_PRESENT = 4 };
// mPeriod is the computed period of the modeled vsync events in
// nanoseconds.
diff --git a/services/surfaceflinger/DisplayHardware/HWComposer.cpp b/services/surfaceflinger/DisplayHardware/HWComposer.cpp
index c8b36ec..2dad005 100644
--- a/services/surfaceflinger/DisplayHardware/HWComposer.cpp
+++ b/services/surfaceflinger/DisplayHardware/HWComposer.cpp
@@ -305,13 +305,16 @@ void HWComposer::vsync(int disp, int64_t timestamp) {
}
void HWComposer::hotplug(int disp, int connected) {
- if (disp == HWC_DISPLAY_PRIMARY || disp >= VIRTUAL_DISPLAY_ID_BASE) {
+ if (disp >= VIRTUAL_DISPLAY_ID_BASE) {
ALOGE("hotplug event received for invalid display: disp=%d connected=%d",
disp, connected);
return;
}
queryDisplayProperties(disp);
- mEventHandler.onHotplugReceived(disp, bool(connected));
+ // Do not teardown or recreate the primary display
+ if (disp != HWC_DISPLAY_PRIMARY) {
+ mEventHandler.onHotplugReceived(disp, bool(connected));
+ }
}
static float getDefaultDensity(uint32_t width, uint32_t height) {
@@ -461,7 +464,7 @@ sp<Fence> HWComposer::getDisplayFence(int disp) const {
}
uint32_t HWComposer::getFormat(int disp) const {
- if (uint32_t(disp)>31 || !mAllocatedDisplayIDs.hasBit(disp)) {
+ if (static_cast<uint32_t>(disp) >= MAX_HWC_DISPLAYS || !mAllocatedDisplayIDs.hasBit(disp)) {
return HAL_PIXEL_FORMAT_RGBA_8888;
} else {
return mDisplayData[disp].format;
@@ -632,6 +635,7 @@ status_t HWComposer::setFramebufferTarget(int32_t id,
}
status_t HWComposer::prepare() {
+ Mutex::Autolock _l(mDisplayLock);
for (size_t i=0 ; i<mNumDisplays ; i++) {
DisplayData& disp(mDisplayData[i]);
if (disp.framebufferTarget) {
@@ -1142,6 +1146,7 @@ static String8 getFormatStr(PixelFormat format) {
}
void HWComposer::dump(String8& result) const {
+ Mutex::Autolock _l(mDisplayLock);
if (mHwc) {
result.appendFormat("Hardware Composer state (version %08x):\n", hwcApiVersion(mHwc));
result.appendFormat(" mDebugForceFakeVSync=%d\n", mDebugForceFakeVSync);
diff --git a/services/surfaceflinger/DisplayHardware/HWComposer.h b/services/surfaceflinger/DisplayHardware/HWComposer.h
index 28d8c65..cc98b4c 100644
--- a/services/surfaceflinger/DisplayHardware/HWComposer.h
+++ b/services/surfaceflinger/DisplayHardware/HWComposer.h
@@ -354,6 +354,8 @@ private:
// mLists[i>0] can be NULL. that display is to be ignored
struct hwc_display_contents_1* mLists[MAX_HWC_DISPLAYS];
DisplayData mDisplayData[MAX_HWC_DISPLAYS];
+ // protect mDisplayData from races between prepare and dump
+ mutable Mutex mDisplayLock;
size_t mNumDisplays;
cb_context* mCBContext;
diff --git a/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.cpp b/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.cpp
index 11cbdc6..ba4c198 100644
--- a/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.cpp
+++ b/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.cpp
@@ -530,6 +530,15 @@ status_t VirtualDisplaySurface::allowAllocation(bool /* allow */) {
return INVALID_OPERATION;
}
+status_t VirtualDisplaySurface::setGenerationNumber(uint32_t /* generation */) {
+ ALOGE("setGenerationNumber not supported on VirtualDisplaySurface");
+ return INVALID_OPERATION;
+}
+
+String8 VirtualDisplaySurface::getConsumerName() const {
+ return String8("VirtualDisplaySurface");
+}
+
void VirtualDisplaySurface::updateQueueBufferOutput(
const QueueBufferOutput& qbo) {
uint32_t w, h, transformHint, numPendingBuffers;
diff --git a/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.h b/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.h
index 97af980..6298751 100644
--- a/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.h
+++ b/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.h
@@ -116,6 +116,8 @@ private:
virtual void allocateBuffers(bool async, uint32_t width, uint32_t height,
PixelFormat format, uint32_t usage);
virtual status_t allowAllocation(bool allow);
+ virtual status_t setGenerationNumber(uint32_t generationNumber);
+ virtual String8 getConsumerName() const override;
//
// Utility methods
diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp
index 2944c63..5ff79a9 100644
--- a/services/surfaceflinger/Layer.cpp
+++ b/services/surfaceflinger/Layer.cpp
@@ -76,11 +76,15 @@ Layer::Layer(SurfaceFlinger* flinger, const sp<Client>& client,
mFiltering(false),
mNeedsFiltering(false),
mMesh(Mesh::TRIANGLE_FAN, 4, 2, 2),
- mSecure(false),
mProtectedByApp(false),
mHasSurface(false),
mClientRef(client),
- mPotentialCursor(false)
+ mPotentialCursor(false),
+ mQueueItemLock(),
+ mQueueItemCondition(),
+ mQueueItems(),
+ mLastFrameNumberReceived(0),
+ mUpdateTexImageFailed(false)
{
mCurrentCrop.makeInvalid();
mFlinger->getRenderEngine().genTextures(1, &mTextureName);
@@ -91,6 +95,8 @@ Layer::Layer(SurfaceFlinger* flinger, const sp<Client>& client,
layerFlags |= layer_state_t::eLayerHidden;
if (flags & ISurfaceComposerClient::eOpaque)
layerFlags |= layer_state_t::eLayerOpaque;
+ if (flags & ISurfaceComposerClient::eSecure)
+ layerFlags |= layer_state_t::eLayerSecure;
if (flags & ISurfaceComposerClient::eNonPremultiplied)
mPremultipliedAlpha = false;
@@ -163,20 +169,54 @@ void Layer::onFrameAvailable(const BufferItem& item) {
// Add this buffer from our internal queue tracker
{ // Autolock scope
Mutex::Autolock lock(mQueueItemLock);
+
+ // Reset the frame number tracker when we receive the first buffer after
+ // a frame number reset
+ if (item.mFrameNumber == 1) {
+ mLastFrameNumberReceived = 0;
+ }
+
+ // Ensure that callbacks are handled in order
+ while (item.mFrameNumber != mLastFrameNumberReceived + 1) {
+ status_t result = mQueueItemCondition.waitRelative(mQueueItemLock,
+ ms2ns(500));
+ if (result != NO_ERROR) {
+ ALOGE("[%s] Timed out waiting on callback", mName.string());
+ }
+ }
+
mQueueItems.push_back(item);
+ android_atomic_inc(&mQueuedFrames);
+
+ // Wake up any pending callbacks
+ mLastFrameNumberReceived = item.mFrameNumber;
+ mQueueItemCondition.broadcast();
}
- android_atomic_inc(&mQueuedFrames);
mFlinger->signalLayerUpdate();
}
void Layer::onFrameReplaced(const BufferItem& item) {
Mutex::Autolock lock(mQueueItemLock);
+
+ // Ensure that callbacks are handled in order
+ while (item.mFrameNumber != mLastFrameNumberReceived + 1) {
+ status_t result = mQueueItemCondition.waitRelative(mQueueItemLock,
+ ms2ns(500));
+ if (result != NO_ERROR) {
+ ALOGE("[%s] Timed out waiting on callback", mName.string());
+ }
+ }
+
if (mQueueItems.empty()) {
ALOGE("Can't replace a frame on an empty queue");
return;
}
mQueueItems.editItemAt(0) = item;
+
+ // Wake up any pending callbacks
+ mLastFrameNumberReceived = item.mFrameNumber;
+ mQueueItemCondition.broadcast();
}
void Layer::onSidebandStreamChanged() {
@@ -217,7 +257,6 @@ status_t Layer::setBuffers( uint32_t w, uint32_t h,
mFormat = format;
mPotentialCursor = (flags & ISurfaceComposerClient::eCursorWindow) ? true : false;
- mSecure = (flags & ISurfaceComposerClient::eSecure) ? true : false;
mProtectedByApp = (flags & ISurfaceComposerClient::eProtectedByApp) ? true : false;
mCurrentOpacity = getOpacityForFormat(format);
@@ -512,16 +551,7 @@ void Layer::setPerFrameData(const sp<const DisplayDevice>& hw,
const Transform& tr = hw->getTransform();
Region visible = tr.transform(visibleRegion.intersect(hw->getViewport()));
layer.setVisibleRegionScreen(visible);
-
- // Pass full-surface damage down untouched
- if (surfaceDamageRegion.isRect() &&
- surfaceDamageRegion.getBounds() == Rect::INVALID_RECT) {
- layer.setSurfaceDamage(surfaceDamageRegion);
- } else {
- Region surfaceDamage =
- tr.transform(surfaceDamageRegion.intersect(hw->getViewport()));
- layer.setSurfaceDamage(surfaceDamage);
- }
+ layer.setSurfaceDamage(surfaceDamageRegion);
if (mSidebandStream.get()) {
layer.setSidebandStream(mSidebandStream);
@@ -821,6 +851,12 @@ bool Layer::isOpaque(const Layer::State& s) const
return ((s.flags & layer_state_t::eLayerOpaque) != 0) || mCurrentOpacity;
}
+bool Layer::isSecure() const
+{
+ const Layer::State& s(mDrawingState);
+ return (s.flags & layer_state_t::eLayerSecure);
+}
+
bool Layer::isProtected() const
{
const sp<GraphicBuffer>& activeBuffer(mActiveBuffer);
@@ -1065,11 +1101,26 @@ void Layer::useEmptyDamage() {
// ----------------------------------------------------------------------------
bool Layer::shouldPresentNow(const DispSync& dispSync) const {
+ if (mSidebandStreamChanged) {
+ return true;
+ }
+
Mutex::Autolock lock(mQueueItemLock);
+ if (mQueueItems.empty()) {
+ return false;
+ }
+ auto timestamp = mQueueItems[0].mTimestamp;
nsecs_t expectedPresent =
mSurfaceFlingerConsumer->computeExpectedPresent(dispSync);
- return mQueueItems.empty() ?
- false : mQueueItems[0].mTimestamp < expectedPresent;
+
+ // Ignore timestamps more than a second in the future
+ bool isPlausible = timestamp < (expectedPresent + s2ns(1));
+ ALOGW_IF(!isPlausible, "[%s] Timestamp %" PRId64 " seems implausible "
+ "relative to expectedPresent %" PRId64, mName.string(), timestamp,
+ expectedPresent);
+
+ bool isDue = timestamp < expectedPresent;
+ return isDue || !isPlausible;
}
bool Layer::onPreComposition() {
@@ -1120,6 +1171,10 @@ Region Layer::latchBuffer(bool& recomputeVisibleRegions)
if (android_atomic_acquire_cas(true, false, &mSidebandStreamChanged) == 0) {
// mSidebandStreamChanged was true
mSidebandStream = mSurfaceFlingerConsumer->getSidebandStream();
+ if (mSidebandStream != NULL) {
+ setTransactionFlags(eTransactionNeeded);
+ mFlinger->setTransactionFlags(eTraversalNeeded);
+ }
recomputeVisibleRegions = true;
const State& s(getDrawingState());
@@ -1252,21 +1307,62 @@ Region Layer::latchBuffer(bool& recomputeVisibleRegions)
Reject r(mDrawingState, getCurrentState(), recomputeVisibleRegions,
getProducerStickyTransform() != 0);
+ uint64_t maxFrameNumber = 0;
+ {
+ Mutex::Autolock lock(mQueueItemLock);
+ maxFrameNumber = mLastFrameNumberReceived;
+ }
+
status_t updateResult = mSurfaceFlingerConsumer->updateTexImage(&r,
- mFlinger->mPrimaryDispSync);
+ mFlinger->mPrimaryDispSync, maxFrameNumber);
if (updateResult == BufferQueue::PRESENT_LATER) {
// Producer doesn't want buffer to be displayed yet. Signal a
// layer update so we check again at the next opportunity.
mFlinger->signalLayerUpdate();
return outDirtyRegion;
+ } else if (updateResult == SurfaceFlingerConsumer::BUFFER_REJECTED) {
+ // If the buffer has been rejected, remove it from the shadow queue
+ // and return early
+ Mutex::Autolock lock(mQueueItemLock);
+ mQueueItems.removeAt(0);
+ android_atomic_dec(&mQueuedFrames);
+ return outDirtyRegion;
+ } else if (updateResult != NO_ERROR || mUpdateTexImageFailed) {
+ // This can occur if something goes wrong when trying to create the
+ // EGLImage for this buffer. If this happens, the buffer has already
+ // been released, so we need to clean up the queue and bug out
+ // early.
+ {
+ Mutex::Autolock lock(mQueueItemLock);
+ mQueueItems.clear();
+ android_atomic_and(0, &mQueuedFrames);
+ }
+
+ // Once we have hit this state, the shadow queue may no longer
+ // correctly reflect the incoming BufferQueue's contents, so even if
+ // updateTexImage starts working, the only safe course of action is
+ // to continue to ignore updates.
+ mUpdateTexImageFailed = true;
+
+ return outDirtyRegion;
}
- // Remove this buffer from our internal queue tracker
{ // Autolock scope
+ auto currentFrameNumber = mSurfaceFlingerConsumer->getFrameNumber();
+
Mutex::Autolock lock(mQueueItemLock);
+
+ // Remove any stale buffers that have been dropped during
+ // updateTexImage
+ while (mQueueItems[0].mFrameNumber != currentFrameNumber) {
+ mQueueItems.removeAt(0);
+ android_atomic_dec(&mQueuedFrames);
+ }
+
mQueueItems.removeAt(0);
}
+
// Decrement the queued-frames count. Signal another event if we
// have more frames pending.
if (android_atomic_dec(&mQueuedFrames) > 1) {
diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h
index 46c17e5..c1e5e9f 100644
--- a/services/surfaceflinger/Layer.h
+++ b/services/surfaceflinger/Layer.h
@@ -174,7 +174,7 @@ public:
* isSecure - true if this surface is secure, that is if it prevents
* screenshots or VNC servers.
*/
- virtual bool isSecure() const { return mSecure; }
+ virtual bool isSecure() const;
/*
* isProtected - true if the layer may contain protected content in the
@@ -339,9 +339,9 @@ protected:
private:
// Interface implementation for SurfaceFlingerConsumer::ContentsChangedListener
- virtual void onFrameAvailable(const BufferItem& item);
- virtual void onFrameReplaced(const BufferItem& item);
- virtual void onSidebandStreamChanged();
+ virtual void onFrameAvailable(const BufferItem& item) override;
+ virtual void onFrameReplaced(const BufferItem& item) override;
+ virtual void onSidebandStreamChanged() override;
void commitTransaction();
@@ -402,7 +402,6 @@ private:
mutable Texture mTexture;
// page-flip thread (currently main thread)
- bool mSecure; // no screenshots
bool mProtectedByApp; // application requires protected path to external sink
// protected by mLock
@@ -416,7 +415,10 @@ private:
// Local copy of the queued contents of the incoming BufferQueue
mutable Mutex mQueueItemLock;
+ Condition mQueueItemCondition;
Vector<BufferItem> mQueueItems;
+ uint64_t mLastFrameNumberReceived;
+ bool mUpdateTexImageFailed; // This is only modified from the main thread
};
// ---------------------------------------------------------------------------
diff --git a/services/surfaceflinger/MonitoredProducer.cpp b/services/surfaceflinger/MonitoredProducer.cpp
index 9fb555b..fb7af97 100644
--- a/services/surfaceflinger/MonitoredProducer.cpp
+++ b/services/surfaceflinger/MonitoredProducer.cpp
@@ -114,6 +114,14 @@ status_t MonitoredProducer::allowAllocation(bool allow) {
return mProducer->allowAllocation(allow);
}
+status_t MonitoredProducer::setGenerationNumber(uint32_t generationNumber) {
+ return mProducer->setGenerationNumber(generationNumber);
+}
+
+String8 MonitoredProducer::getConsumerName() const {
+ return mProducer->getConsumerName();
+}
+
IBinder* MonitoredProducer::onAsBinder() {
return IInterface::asBinder(mProducer).get();
}
diff --git a/services/surfaceflinger/MonitoredProducer.h b/services/surfaceflinger/MonitoredProducer.h
index b2f8293..da95766 100644
--- a/services/surfaceflinger/MonitoredProducer.h
+++ b/services/surfaceflinger/MonitoredProducer.h
@@ -54,6 +54,8 @@ public:
virtual void allocateBuffers(bool async, uint32_t width, uint32_t height,
PixelFormat format, uint32_t usage);
virtual status_t allowAllocation(bool allow);
+ virtual status_t setGenerationNumber(uint32_t generationNumber);
+ virtual String8 getConsumerName() const override;
virtual IBinder* onAsBinder();
private:
diff --git a/services/surfaceflinger/RenderEngine/Description.cpp b/services/surfaceflinger/RenderEngine/Description.cpp
index 1adcd1f..0dab872 100644
--- a/services/surfaceflinger/RenderEngine/Description.cpp
+++ b/services/surfaceflinger/RenderEngine/Description.cpp
@@ -88,5 +88,9 @@ void Description::setColorMatrix(const mat4& mtx) {
mColorMatrixEnabled = (mtx != identity);
}
+const mat4& Description::getColorMatrix() const {
+ return mColorMatrix;
+}
+
} /* namespace android */
diff --git a/services/surfaceflinger/RenderEngine/Description.h b/services/surfaceflinger/RenderEngine/Description.h
index 43b835f..8a3447c 100644
--- a/services/surfaceflinger/RenderEngine/Description.h
+++ b/services/surfaceflinger/RenderEngine/Description.h
@@ -66,6 +66,7 @@ public:
void setColor(GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha);
void setProjectionMatrix(const mat4& mtx);
void setColorMatrix(const mat4& mtx);
+ const mat4& getColorMatrix() const;
private:
bool mUniformsDirty;
diff --git a/services/surfaceflinger/RenderEngine/GLES11RenderEngine.cpp b/services/surfaceflinger/RenderEngine/GLES11RenderEngine.cpp
index 2e6af49..1a9f59b 100644
--- a/services/surfaceflinger/RenderEngine/GLES11RenderEngine.cpp
+++ b/services/surfaceflinger/RenderEngine/GLES11RenderEngine.cpp
@@ -262,14 +262,6 @@ void GLES11RenderEngine::drawMesh(const Mesh& mesh) {
}
}
-void GLES11RenderEngine::beginGroup(const mat4& /*colorTransform*/) {
- // doesn't do anything in GLES 1.1
-}
-
-void GLES11RenderEngine::endGroup() {
- // doesn't do anything in GLES 1.1
-}
-
void GLES11RenderEngine::dump(String8& result) {
RenderEngine::dump(result);
}
diff --git a/services/surfaceflinger/RenderEngine/GLES11RenderEngine.h b/services/surfaceflinger/RenderEngine/GLES11RenderEngine.h
index 87eb3e4..08de646 100644
--- a/services/surfaceflinger/RenderEngine/GLES11RenderEngine.h
+++ b/services/surfaceflinger/RenderEngine/GLES11RenderEngine.h
@@ -62,9 +62,6 @@ protected:
virtual void drawMesh(const Mesh& mesh);
- virtual void beginGroup(const mat4& colorTransform);
- virtual void endGroup();
-
virtual size_t getMaxTextureSize() const;
virtual size_t getMaxViewportDims() const;
};
diff --git a/services/surfaceflinger/RenderEngine/GLES20RenderEngine.cpp b/services/surfaceflinger/RenderEngine/GLES20RenderEngine.cpp
index 8712c9a..1fabaf5 100644
--- a/services/surfaceflinger/RenderEngine/GLES20RenderEngine.cpp
+++ b/services/surfaceflinger/RenderEngine/GLES20RenderEngine.cpp
@@ -169,6 +169,12 @@ void GLES20RenderEngine::setupLayerBlackedOut() {
mState.setTexture(texture);
}
+mat4 GLES20RenderEngine::setupColorTransform(const mat4& colorTransform) {
+ mat4 oldTransform = mState.getColorMatrix();
+ mState.setColorMatrix(colorTransform);
+ return oldTransform;
+}
+
void GLES20RenderEngine::disableTexturing() {
mState.disableTexture();
}
@@ -237,78 +243,6 @@ void GLES20RenderEngine::drawMesh(const Mesh& mesh) {
}
}
-void GLES20RenderEngine::beginGroup(const mat4& colorTransform) {
-
- GLuint tname, name;
- // create the texture
- glGenTextures(1, &tname);
- glBindTexture(GL_TEXTURE_2D, tname);
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
- glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, mVpWidth, mVpHeight, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0);
-
- // create a Framebuffer Object to render into
- glGenFramebuffers(1, &name);
- glBindFramebuffer(GL_FRAMEBUFFER, name);
- glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, tname, 0);
-
- Group group;
- group.texture = tname;
- group.fbo = name;
- group.width = mVpWidth;
- group.height = mVpHeight;
- group.colorTransform = colorTransform;
-
- mGroupStack.push(group);
-}
-
-void GLES20RenderEngine::endGroup() {
-
- const Group group(mGroupStack.top());
- mGroupStack.pop();
-
- // activate the previous render target
- GLuint fbo = 0;
- if (!mGroupStack.isEmpty()) {
- fbo = mGroupStack.top().fbo;
- }
- glBindFramebuffer(GL_FRAMEBUFFER, fbo);
-
- // set our state
- Texture texture(Texture::TEXTURE_2D, group.texture);
- texture.setDimensions(group.width, group.height);
- glBindTexture(GL_TEXTURE_2D, group.texture);
-
- mState.setPlaneAlpha(1.0f);
- mState.setPremultipliedAlpha(true);
- mState.setOpaque(false);
- mState.setTexture(texture);
- mState.setColorMatrix(group.colorTransform);
- glDisable(GL_BLEND);
-
- Mesh mesh(Mesh::TRIANGLE_FAN, 4, 2, 2);
- Mesh::VertexArray<vec2> position(mesh.getPositionArray<vec2>());
- Mesh::VertexArray<vec2> texCoord(mesh.getTexCoordArray<vec2>());
- position[0] = vec2(0, 0);
- position[1] = vec2(group.width, 0);
- position[2] = vec2(group.width, group.height);
- position[3] = vec2(0, group.height);
- texCoord[0] = vec2(0, 0);
- texCoord[1] = vec2(1, 0);
- texCoord[2] = vec2(1, 1);
- texCoord[3] = vec2(0, 1);
- drawMesh(mesh);
-
- // reset color matrix
- mState.setColorMatrix(mat4());
-
- // free our fbo and texture
- glDeleteFramebuffers(1, &group.fbo);
- glDeleteTextures(1, &group.texture);
-}
-
void GLES20RenderEngine::dump(String8& result) {
RenderEngine::dump(result);
}
diff --git a/services/surfaceflinger/RenderEngine/GLES20RenderEngine.h b/services/surfaceflinger/RenderEngine/GLES20RenderEngine.h
index 3d6243e..819356a 100644
--- a/services/surfaceflinger/RenderEngine/GLES20RenderEngine.h
+++ b/services/surfaceflinger/RenderEngine/GLES20RenderEngine.h
@@ -72,14 +72,12 @@ protected:
virtual void setupLayerTexturing(const Texture& texture);
virtual void setupLayerBlackedOut();
virtual void setupFillWithColor(float r, float g, float b, float a);
+ virtual mat4 setupColorTransform(const mat4& colorTransform);
virtual void disableTexturing();
virtual void disableBlending();
virtual void drawMesh(const Mesh& mesh);
- virtual void beginGroup(const mat4& colorTransform);
- virtual void endGroup();
-
virtual size_t getMaxTextureSize() const;
virtual size_t getMaxViewportDims() const;
};
diff --git a/services/surfaceflinger/RenderEngine/Mesh.cpp b/services/surfaceflinger/RenderEngine/Mesh.cpp
index 3f50cb0..ffd9be2 100644
--- a/services/surfaceflinger/RenderEngine/Mesh.cpp
+++ b/services/surfaceflinger/RenderEngine/Mesh.cpp
@@ -16,14 +16,40 @@
#include "Mesh.h"
+#include <utils/Log.h>
+
namespace android {
Mesh::Mesh(Primitive primitive, size_t vertexCount, size_t vertexSize, size_t texCoordSize)
: mVertexCount(vertexCount), mVertexSize(vertexSize), mTexCoordsSize(texCoordSize),
mPrimitive(primitive)
{
- mVertices = new float[(vertexSize + texCoordSize) * vertexCount];
- mStride = mVertexSize + mTexCoordsSize;
+ if (vertexCount == 0) {
+ mVertices = new float[1];
+ mVertices[0] = 0.0f;
+ mStride = 0;
+ return;
+ }
+
+ size_t stride = vertexSize + texCoordSize;
+ size_t remainder = (stride * vertexCount) / vertexCount;
+ // Since all of the input parameters are unsigned, if stride is less than
+ // either vertexSize or texCoordSize, it must have overflowed. remainder
+ // will be equal to stride as long as stride * vertexCount doesn't overflow.
+ if ((stride < vertexSize) || (remainder != stride)) {
+ ALOGE("Overflow in Mesh(..., %zu, %zu, %zu)", vertexCount, vertexSize,
+ texCoordSize);
+ mVertices = new float[1];
+ mVertices[0] = 0.0f;
+ mVertexCount = 0;
+ mVertexSize = 0;
+ mTexCoordsSize = 0;
+ mStride = 0;
+ return;
+ }
+
+ mVertices = new float[stride * vertexCount];
+ mStride = stride;
}
Mesh::~Mesh() {
diff --git a/services/surfaceflinger/RenderEngine/ProgramCache.cpp b/services/surfaceflinger/RenderEngine/ProgramCache.cpp
index 0de5cca..ba11259 100644
--- a/services/surfaceflinger/RenderEngine/ProgramCache.cpp
+++ b/services/surfaceflinger/RenderEngine/ProgramCache.cpp
@@ -199,10 +199,8 @@ String8 ProgramCache::generateFragmentShader(const Key& needs) {
// un-premultiply if needed before linearization
fs << "gl_FragColor.rgb = gl_FragColor.rgb/gl_FragColor.a;";
}
- fs << "gl_FragColor.rgb = pow(gl_FragColor.rgb, vec3(2.2));";
fs << "vec4 transformed = colorMatrix * vec4(gl_FragColor.rgb, 1);";
fs << "gl_FragColor.rgb = transformed.rgb/transformed.a;";
- fs << "gl_FragColor.rgb = pow(gl_FragColor.rgb, vec3(1.0 / 2.2));";
if (!needs.isOpaque() && needs.isPremultiplied()) {
// and re-premultiply if needed after gamma correction
fs << "gl_FragColor.rgb = gl_FragColor.rgb*gl_FragColor.a;";
diff --git a/services/surfaceflinger/RenderEngine/RenderEngine.h b/services/surfaceflinger/RenderEngine/RenderEngine.h
index 8d7529c..31a961e 100644
--- a/services/surfaceflinger/RenderEngine/RenderEngine.h
+++ b/services/surfaceflinger/RenderEngine/RenderEngine.h
@@ -99,18 +99,16 @@ public:
virtual void setupLayerBlackedOut() = 0;
virtual void setupFillWithColor(float r, float g, float b, float a) = 0;
+ virtual mat4 setupColorTransform(const mat4& /* colorTransform */) {
+ return mat4();
+ }
+
virtual void disableTexturing() = 0;
virtual void disableBlending() = 0;
// drawing
virtual void drawMesh(const Mesh& mesh) = 0;
- // grouping
- // creates a color-transform group, everything drawn in the group will be
- // transformed by the given color transform when endGroup() is called.
- virtual void beginGroup(const mat4& colorTransform) = 0;
- virtual void endGroup() = 0;
-
// queries
virtual size_t getMaxTextureSize() const = 0;
virtual size_t getMaxViewportDims() const = 0;
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index df4ac2e..de0f921 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -149,7 +149,11 @@ SurfaceFlinger::SurfaceFlinger()
mPrimaryHWVsyncEnabled(false),
mHWVsyncAvailable(false),
mDaltonize(false),
- mHasColorMatrix(false)
+ mHasColorMatrix(false),
+ mHasPoweredOff(false),
+ mFrameBuckets(),
+ mTotalTime(0),
+ mLastSwapTime(0)
{
ALOGI("SurfaceFlinger is starting");
@@ -546,7 +550,7 @@ bool SurfaceFlinger::authenticateSurfaceTexture(
status_t SurfaceFlinger::getDisplayConfigs(const sp<IBinder>& display,
Vector<DisplayInfo>* configs) {
- if (configs == NULL) {
+ if ((configs == NULL) || (display.get() == NULL)) {
return BAD_VALUE;
}
@@ -997,8 +1001,8 @@ void SurfaceFlinger::postComposition()
}
}
+ const sp<const DisplayDevice> hw(getDefaultDisplayDevice());
if (kIgnorePresentFences) {
- const sp<const DisplayDevice> hw(getDefaultDisplayDevice());
if (hw->isDisplayOn()) {
enableHardwareVsync();
}
@@ -1017,6 +1021,26 @@ void SurfaceFlinger::postComposition()
}
mAnimFrameTracker.advanceFrame();
}
+
+ if (hw->getPowerMode() == HWC_POWER_MODE_OFF) {
+ return;
+ }
+
+ nsecs_t currentTime = systemTime();
+ if (mHasPoweredOff) {
+ mHasPoweredOff = false;
+ } else {
+ nsecs_t period = mPrimaryDispSync.getPeriod();
+ nsecs_t elapsedTime = currentTime - mLastSwapTime;
+ size_t numPeriods = static_cast<size_t>(elapsedTime / period);
+ if (numPeriods < NUM_BUCKETS - 1) {
+ mFrameBuckets[numPeriods] += elapsedTime;
+ } else {
+ mFrameBuckets[NUM_BUCKETS - 1] += elapsedTime;
+ }
+ mTotalTime += elapsedTime;
+ }
+ mLastSwapTime = currentTime;
}
void SurfaceFlinger::rebuildLayerStacks() {
@@ -1848,9 +1872,9 @@ void SurfaceFlinger::doDisplayComposition(const sp<const DisplayDevice>& hw,
if (mDaltonize) {
colorMatrix = colorMatrix * mDaltonizer();
}
- engine.beginGroup(colorMatrix);
+ mat4 oldMatrix = engine.setupColorTransform(colorMatrix);
doComposeSurfaces(hw, dirtyRegion);
- engine.endGroup();
+ engine.setupColorTransform(oldMatrix);
}
// update the swap region and clear the dirty region
@@ -1994,18 +2018,25 @@ void SurfaceFlinger::drawWormhole(const sp<const DisplayDevice>& hw, const Regio
engine.fillRegionWithColor(region, height, 0, 0, 0, 0);
}
-void SurfaceFlinger::addClientLayer(const sp<Client>& client,
+status_t SurfaceFlinger::addClientLayer(const sp<Client>& client,
const sp<IBinder>& handle,
const sp<IGraphicBufferProducer>& gbc,
const sp<Layer>& lbc)
{
+ // add this layer to the current state list
+ {
+ Mutex::Autolock _l(mStateLock);
+ if (mCurrentState.layersSortedByZ.size() >= MAX_LAYERS) {
+ return NO_MEMORY;
+ }
+ mCurrentState.layersSortedByZ.add(lbc);
+ mGraphicBufferProducerList.add(IInterface::asBinder(gbc));
+ }
+
// attach this layer to the client
client->attachLayer(handle, lbc);
- // add this layer to the current state list
- Mutex::Autolock _l(mStateLock);
- mCurrentState.layersSortedByZ.add(lbc);
- mGraphicBufferProducerList.add(IInterface::asBinder(gbc));
+ return NO_ERROR;
}
status_t SurfaceFlinger::removeLayer(const sp<Layer>& layer) {
@@ -2204,9 +2235,7 @@ uint32_t SurfaceFlinger::setClientStateLocked(
if (layer->setTransparentRegionHint(s.transparentRegion))
flags |= eTraversalNeeded;
}
- if ((what & layer_state_t::eVisibilityChanged) ||
- (what & layer_state_t::eOpacityChanged)) {
- // TODO: should we just use an eFlagsChanged for this?
+ if (what & layer_state_t::eFlagsChanged) {
if (layer->setFlags(s.flags, s.mask))
flags |= eTraversalNeeded;
}
@@ -2262,10 +2291,16 @@ status_t SurfaceFlinger::createLayer(
break;
}
- if (result == NO_ERROR) {
- addClientLayer(client, *handle, *gbp, layer);
- setTransactionFlags(eTransactionNeeded);
+ if (result != NO_ERROR) {
+ return result;
+ }
+
+ result = addClientLayer(client, *handle, *gbp, layer);
+ if (result != NO_ERROR) {
+ return result;
}
+
+ setTransactionFlags(eTransactionNeeded);
return result;
}
@@ -2398,6 +2433,7 @@ void SurfaceFlinger::setPowerModeInternal(const sp<DisplayDevice>& hw,
}
mVisibleRegionsDirty = true;
+ mHasPoweredOff = true;
repaintEverything();
} else if (mode == HWC_POWER_MODE_OFF) {
if (type == DisplayDevice::DISPLAY_PRIMARY) {
@@ -2498,6 +2534,13 @@ status_t SurfaceFlinger::dump(int fd, const Vector<String16>& args)
mPrimaryDispSync.dump(result);
dumpAll = false;
}
+
+ if ((index < numArgs) &&
+ (args[index] == String16("--static-screen"))) {
+ index++;
+ dumpStaticScreenStats(result);
+ dumpAll = false;
+ }
}
if (dumpAll) {
@@ -2601,6 +2644,23 @@ void SurfaceFlinger::logFrameStats() {
result.append(config);
}
+void SurfaceFlinger::dumpStaticScreenStats(String8& result) const
+{
+ result.appendFormat("Static screen stats:\n");
+ for (size_t b = 0; b < NUM_BUCKETS - 1; ++b) {
+ float bucketTimeSec = mFrameBuckets[b] / 1e9;
+ float percent = 100.0f *
+ static_cast<float>(mFrameBuckets[b]) / mTotalTime;
+ result.appendFormat(" < %zd frames: %.3f s (%.1f%%)\n",
+ b + 1, bucketTimeSec, percent);
+ }
+ float bucketTimeSec = mFrameBuckets[NUM_BUCKETS - 1] / 1e9;
+ float percent = 100.0f *
+ static_cast<float>(mFrameBuckets[NUM_BUCKETS - 1]) / mTotalTime;
+ result.appendFormat(" %zd+ frames: %.3f s (%.1f%%)\n",
+ NUM_BUCKETS - 1, bucketTimeSec, percent);
+}
+
void SurfaceFlinger::dumpAllLocked(const Vector<String16>& args, size_t& index,
String8& result) const
{
@@ -2647,6 +2707,11 @@ void SurfaceFlinger::dumpAllLocked(const Vector<String16>& args, size_t& index,
mHwc->getRefreshPeriod(HWC_DISPLAY_PRIMARY));
result.append("\n");
+ // Dump static screen stats
+ result.append("\n");
+ dumpStaticScreenStats(result);
+ result.append("\n");
+
/*
* Dump the visible layer list
*/
@@ -2794,7 +2859,7 @@ status_t SurfaceFlinger::onTransact(
IPCThreadState* ipc = IPCThreadState::self();
const int pid = ipc->getCallingPid();
const int uid = ipc->getCallingUid();
- if ((uid != AID_GRAPHICS) &&
+ if ((uid != AID_GRAPHICS && uid != AID_SYSTEM) &&
!PermissionCache::checkPermission(sAccessSurfaceFlinger, pid, uid)) {
ALOGE("Permission Denial: "
"can't access SurfaceFlinger pid=%d, uid=%d", pid, uid);
@@ -3253,8 +3318,12 @@ status_t SurfaceFlinger::captureScreenImplLocked(
ATRACE_CALL();
// get screen geometry
- const uint32_t hw_w = hw->getWidth();
- const uint32_t hw_h = hw->getHeight();
+ uint32_t hw_w = hw->getWidth();
+ uint32_t hw_h = hw->getHeight();
+
+ if (rotation & Transform::ROT_90) {
+ std::swap(hw_w, hw_h);
+ }
if ((reqWidth > hw_w) || (reqHeight > hw_h)) {
ALOGE("size mismatch (%d, %d) > (%d, %d)",
@@ -3270,8 +3339,8 @@ status_t SurfaceFlinger::captureScreenImplLocked(
sp<Surface> sur = new Surface(producer, false);
ANativeWindow* window = sur.get();
- status_t result = NO_ERROR;
- if (native_window_api_connect(window, NATIVE_WINDOW_API_EGL) == NO_ERROR) {
+ status_t result = native_window_api_connect(window, NATIVE_WINDOW_API_EGL);
+ if (result == NO_ERROR) {
uint32_t usage = GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN |
GRALLOC_USAGE_HW_RENDER | GRALLOC_USAGE_HW_TEXTURE;
@@ -3361,7 +3430,7 @@ status_t SurfaceFlinger::captureScreenImplLocked(
result = BAD_VALUE;
}
// queueBuffer takes ownership of syncFd
- window->queueBuffer(window, buffer, syncFd);
+ result = window->queueBuffer(window, buffer, syncFd);
}
} else {
result = BAD_VALUE;
diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h
index a06d1be..3759a92 100644
--- a/services/surfaceflinger/SurfaceFlinger.h
+++ b/services/surfaceflinger/SurfaceFlinger.h
@@ -144,6 +144,8 @@ private:
// every half hour.
enum { LOG_FRAME_STATS_PERIOD = 30*60*60 };
+ static const size_t MAX_LAYERS = 4096;
+
// We're reference counted, never destroy SurfaceFlinger directly
virtual ~SurfaceFlinger();
@@ -305,7 +307,7 @@ private:
status_t removeLayer(const sp<Layer>& layer);
// add a layer to SurfaceFlinger
- void addClientLayer(const sp<Client>& client,
+ status_t addClientLayer(const sp<Client>& client,
const sp<IBinder>& handle,
const sp<IGraphicBufferProducer>& gbc,
const sp<Layer>& lbc);
@@ -416,6 +418,8 @@ private:
void logFrameStats();
+ void dumpStaticScreenStats(String8& result) const;
+
/* ------------------------------------------------------------------------
* Attributes
*/
@@ -494,6 +498,13 @@ private:
mat4 mColorMatrix;
bool mHasColorMatrix;
+
+ // Static screen stats
+ bool mHasPoweredOff;
+ static const size_t NUM_BUCKETS = 8; // < 1-7, 7+
+ nsecs_t mFrameBuckets[NUM_BUCKETS];
+ nsecs_t mTotalTime;
+ nsecs_t mLastSwapTime;
};
}; // namespace android
diff --git a/services/surfaceflinger/SurfaceFlingerConsumer.cpp b/services/surfaceflinger/SurfaceFlingerConsumer.cpp
index 19c497a..ed1f31b 100644
--- a/services/surfaceflinger/SurfaceFlingerConsumer.cpp
+++ b/services/surfaceflinger/SurfaceFlingerConsumer.cpp
@@ -32,7 +32,7 @@ namespace android {
// ---------------------------------------------------------------------------
status_t SurfaceFlingerConsumer::updateTexImage(BufferRejecter* rejecter,
- const DispSync& dispSync)
+ const DispSync& dispSync, uint64_t maxFrameNumber)
{
ATRACE_CALL();
ALOGV("updateTexImage");
@@ -54,7 +54,8 @@ status_t SurfaceFlingerConsumer::updateTexImage(BufferRejecter* rejecter,
// Acquire the next buffer.
// In asynchronous mode the list is guaranteed to be one buffer
// deep, while in synchronous mode we use the oldest buffer.
- err = acquireBufferLocked(&item, computeExpectedPresent(dispSync));
+ err = acquireBufferLocked(&item, computeExpectedPresent(dispSync),
+ maxFrameNumber);
if (err != NO_ERROR) {
if (err == BufferQueue::NO_BUFFER_AVAILABLE) {
err = NO_ERROR;
@@ -74,7 +75,7 @@ status_t SurfaceFlingerConsumer::updateTexImage(BufferRejecter* rejecter,
int buf = item.mBuf;
if (rejecter && rejecter->reject(mSlots[buf].mGraphicBuffer, item)) {
releaseBufferLocked(buf, mSlots[buf].mGraphicBuffer, EGL_NO_SYNC_KHR);
- return NO_ERROR;
+ return BUFFER_REJECTED;
}
// Release the previous buffer.
@@ -104,8 +105,9 @@ status_t SurfaceFlingerConsumer::bindTextureImage()
}
status_t SurfaceFlingerConsumer::acquireBufferLocked(BufferItem* item,
- nsecs_t presentWhen) {
- status_t result = GLConsumer::acquireBufferLocked(item, presentWhen);
+ nsecs_t presentWhen, uint64_t maxFrameNumber) {
+ status_t result = GLConsumer::acquireBufferLocked(item, presentWhen,
+ maxFrameNumber);
if (result == NO_ERROR) {
mTransformToDisplayInverse = item->mTransformToDisplayInverse;
mSurfaceDamage = item->mSurfaceDamage;
diff --git a/services/surfaceflinger/SurfaceFlingerConsumer.h b/services/surfaceflinger/SurfaceFlingerConsumer.h
index 1aaba18..779e5b7 100644
--- a/services/surfaceflinger/SurfaceFlingerConsumer.h
+++ b/services/surfaceflinger/SurfaceFlingerConsumer.h
@@ -28,6 +28,8 @@ namespace android {
*/
class SurfaceFlingerConsumer : public GLConsumer {
public:
+ static const status_t BUFFER_REJECTED = UNKNOWN_ERROR + 8;
+
struct ContentsChangedListener: public FrameAvailableListener {
virtual void onSidebandStreamChanged() = 0;
};
@@ -47,13 +49,15 @@ public:
virtual ~BufferRejecter() { }
};
- virtual status_t acquireBufferLocked(BufferItem *item, nsecs_t presentWhen);
+ virtual status_t acquireBufferLocked(BufferItem *item, nsecs_t presentWhen,
+ uint64_t maxFrameNumber = 0) override;
// This version of updateTexImage() takes a functor that may be used to
// reject the newly acquired buffer. Unlike the GLConsumer version,
// this does not guarantee that the buffer has been bound to the GL
// texture.
- status_t updateTexImage(BufferRejecter* rejecter, const DispSync& dispSync);
+ status_t updateTexImage(BufferRejecter* rejecter, const DispSync& dispSync,
+ uint64_t maxFrameNumber = 0);
// See GLConsumer::bindTextureImageLocked().
status_t bindTextureImage();
diff --git a/services/surfaceflinger/tests/Transaction_test.cpp b/services/surfaceflinger/tests/Transaction_test.cpp
index 4d363c8..dcde512 100644
--- a/services/surfaceflinger/tests/Transaction_test.cpp
+++ b/services/surfaceflinger/tests/Transaction_test.cpp
@@ -16,6 +16,8 @@
#include <gtest/gtest.h>
+#include <android/native_window.h>
+
#include <binder/IMemory.h>
#include <gui/ISurfaceComposer.h>
@@ -53,21 +55,23 @@ static void fillSurfaceRGBA8(const sp<SurfaceControl>& sc,
class ScreenCapture : public RefBase {
public:
static void captureScreen(sp<ScreenCapture>* sc) {
- sp<IMemoryHeap> heap;
- uint32_t w=0, h=0;
- PixelFormat fmt=0;
+ sp<IGraphicBufferProducer> producer;
+ sp<IGraphicBufferConsumer> consumer;
+ BufferQueue::createBufferQueue(&producer, &consumer);
+ IGraphicBufferProducer::QueueBufferOutput bufferOutput;
+ sp<CpuConsumer> cpuConsumer = new CpuConsumer(consumer, 1);
sp<ISurfaceComposer> sf(ComposerService::getComposerService());
- sp<IBinder> display(sf->getBuiltInDisplay(ISurfaceComposer::eDisplayIdMain));
- ASSERT_EQ(NO_ERROR, sf->captureScreen(display, &heap, &w, &h, &fmt, 0, 0,
- 0, INT_MAX));
- ASSERT_TRUE(heap != NULL);
- ASSERT_EQ(PIXEL_FORMAT_RGBA_8888, fmt);
- *sc = new ScreenCapture(w, h, heap);
+ sp<IBinder> display(sf->getBuiltInDisplay(
+ ISurfaceComposer::eDisplayIdMain));
+ ASSERT_EQ(NO_ERROR, sf->captureScreen(display, producer, Rect(), 0, 0,
+ 0, INT_MAX, false));
+ *sc = new ScreenCapture(cpuConsumer);
}
void checkPixel(uint32_t x, uint32_t y, uint8_t r, uint8_t g, uint8_t b) {
- const uint8_t* img = reinterpret_cast<const uint8_t*>(mHeap->base());
- const uint8_t* pixel = img + (4 * (y*mWidth + x));
+ ASSERT_EQ(HAL_PIXEL_FORMAT_RGBA_8888, mBuf.format);
+ const uint8_t* img = static_cast<const uint8_t*>(mBuf.data);
+ const uint8_t* pixel = img + (4 * (y * mBuf.stride + x));
if (r != pixel[0] || g != pixel[1] || b != pixel[2]) {
String8 err(String8::format("pixel @ (%3d, %3d): "
"expected [%3d, %3d, %3d], got [%3d, %3d, %3d]",
@@ -77,15 +81,17 @@ public:
}
private:
- ScreenCapture(uint32_t w, uint32_t h, const sp<IMemoryHeap>& heap) :
- mWidth(w),
- mHeight(h),
- mHeap(heap)
- {}
-
- const uint32_t mWidth;
- const uint32_t mHeight;
- sp<IMemoryHeap> mHeap;
+ ScreenCapture(const sp<CpuConsumer>& cc) :
+ mCC(cc) {
+ EXPECT_EQ(NO_ERROR, mCC->lockNextBuffer(&mBuf));
+ }
+
+ ~ScreenCapture() {
+ mCC->unlockBuffer(mBuf);
+ }
+
+ sp<CpuConsumer> mCC;
+ CpuConsumer::LockedBuffer mBuf;
};
class LayerUpdateTest : public ::testing::Test {