Merge "Use Holo background and proper padding for App Permissions UI." into honeycomb-mr2
diff --git a/include/ui/Input.h b/include/ui/Input.h
index bc5b718..fb6152e 100644
--- a/include/ui/Input.h
+++ b/include/ui/Input.h
@@ -27,6 +27,7 @@
#include <utils/Timers.h>
#include <utils/RefBase.h>
#include <utils/String8.h>
+#include <utils/BitSet.h>
#ifdef HAVE_ANDROID_OS
class SkMatrix;
@@ -210,6 +211,13 @@
status_t writeToParcel(Parcel* parcel) const;
#endif
+ bool operator==(const PointerCoords& other) const;
+ inline bool operator!=(const PointerCoords& other) const {
+ return !(*this == other);
+ }
+
+ void copyFrom(const PointerCoords& other);
+
private:
void tooManyAxes(int axis);
};
@@ -305,6 +313,13 @@
inline int32_t getAction() const { return mAction; }
+ inline int32_t getActionMasked() const { return mAction & AMOTION_EVENT_ACTION_MASK; }
+
+ inline int32_t getActionIndex() const {
+ return (mAction & AMOTION_EVENT_ACTION_POINTER_INDEX_MASK)
+ >> AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT;
+ }
+
inline void setAction(int32_t action) { mAction = action; }
inline int32_t getFlags() const { return mFlags; }
@@ -452,6 +467,8 @@
AMOTION_EVENT_AXIS_ORIENTATION, pointerIndex, historicalIndex);
}
+ ssize_t findPointerIndex(int32_t pointerId) const;
+
void initialize(
int32_t deviceId,
int32_t source,
@@ -545,6 +562,72 @@
};
/*
+ * Calculates the velocity of pointer movements over time.
+ */
+class VelocityTracker {
+public:
+ struct Position {
+ float x, y;
+ };
+
+ VelocityTracker();
+
+ // Resets the velocity tracker state.
+ void clear();
+
+ // Resets the velocity tracker state for specific pointers.
+ // Call this method when some pointers have changed and may be reusing
+ // an id that was assigned to a different pointer earlier.
+ void clearPointers(BitSet32 idBits);
+
+ // Adds movement information for a set of pointers.
+ // The idBits bitfield specifies the pointer ids of the pointers whose positions
+ // are included in the movement.
+ // The positions array contains position information for each pointer in order by
+ // increasing id. Its size should be equal to the number of one bits in idBits.
+ void addMovement(nsecs_t eventTime, BitSet32 idBits, const Position* positions);
+
+ // Adds movement information for all pointers in a MotionEvent, including historical samples.
+ void addMovement(const MotionEvent* event);
+
+ // Gets the velocity of the specified pointer id in position units per second.
+ // Returns false and sets the velocity components to zero if there is no movement
+ // information for the pointer.
+ bool getVelocity(uint32_t id, float* outVx, float* outVy) const;
+
+ // Gets the active pointer id, or -1 if none.
+ inline int32_t getActivePointerId() const { return mActivePointerId; }
+
+ // Gets a bitset containing all pointer ids from the most recent movement.
+ inline BitSet32 getCurrentPointerIdBits() const { return mMovements[mIndex].idBits; }
+
+private:
+ // Number of samples to keep.
+ static const uint32_t HISTORY_SIZE = 10;
+
+ // Oldest sample to consider when calculating the velocity.
+ static const nsecs_t MAX_AGE = 200 * 1000000; // 200 ms
+
+ // When the total duration of the window of samples being averaged is less
+ // than the window size, the resulting velocity is scaled to reduce the impact
+ // of overestimation in short traces.
+ static const nsecs_t MIN_WINDOW = 100 * 1000000; // 100 ms
+
+ // The minimum duration between samples when estimating velocity.
+ static const nsecs_t MIN_DURATION = 10 * 1000000; // 10 ms
+
+ struct Movement {
+ nsecs_t eventTime;
+ BitSet32 idBits;
+ Position positions[MAX_POINTERS];
+ };
+
+ uint32_t mIndex;
+ Movement mMovements[HISTORY_SIZE];
+ int32_t mActivePointerId;
+};
+
+/*
* Describes the characteristics and capabilities of an input device.
*/
class InputDeviceInfo {
diff --git a/include/utils/BitSet.h b/include/utils/BitSet.h
index f5dbcd9..de748b5 100644
--- a/include/utils/BitSet.h
+++ b/include/utils/BitSet.h
@@ -61,6 +61,16 @@
// Result is undefined if all bits are marked.
inline uint32_t firstUnmarkedBit() const { return __builtin_clz(~ value); }
+ // Finds the last marked bit in the set.
+ // Result is undefined if all bits are unmarked.
+ inline uint32_t lastMarkedBit() const { return 31 - __builtin_ctz(value); }
+
+ // Gets the index of the specified bit in the set, which is the number of
+ // marked bits that appear before the specified bit.
+ inline uint32_t getIndexOfBit(uint32_t n) const {
+ return __builtin_popcount(value & ~(0xffffffffUL >> n));
+ }
+
inline bool operator== (const BitSet32& other) const { return value == other.value; }
inline bool operator!= (const BitSet32& other) const { return value != other.value; }
};
diff --git a/include/utils/ResourceTypes.h b/include/utils/ResourceTypes.h
index c02d8ac..d1d9844 100644
--- a/include/utils/ResourceTypes.h
+++ b/include/utils/ResourceTypes.h
@@ -841,6 +841,7 @@
DENSITY_DEFAULT = ACONFIGURATION_DENSITY_DEFAULT,
DENSITY_LOW = ACONFIGURATION_DENSITY_LOW,
DENSITY_MEDIUM = ACONFIGURATION_DENSITY_MEDIUM,
+ DENSITY_TV = ACONFIGURATION_DENSITY_TV,
DENSITY_HIGH = ACONFIGURATION_DENSITY_HIGH,
DENSITY_NONE = ACONFIGURATION_DENSITY_NONE
};
@@ -1452,24 +1453,20 @@
// settings is the requested settings
inline bool match(const ResTable_config& settings) const {
if (imsi != 0) {
- if ((settings.mcc != 0 && mcc != 0
- && mcc != settings.mcc) ||
- (settings.mcc == 0 && mcc != 0)) {
+ if (mcc != 0 && mcc != settings.mcc) {
return false;
}
- if ((settings.mnc != 0 && mnc != 0
- && mnc != settings.mnc) ||
- (settings.mnc == 0 && mnc != 0)) {
+ if (mnc != 0 && mnc != settings.mnc) {
return false;
}
}
if (locale != 0) {
- if (settings.language[0] != 0 && language[0] != 0
+ if (language[0] != 0
&& (language[0] != settings.language[0]
|| language[1] != settings.language[1])) {
return false;
}
- if (settings.country[0] != 0 && country[0] != 0
+ if (country[0] != 0
&& (country[0] != settings.country[0]
|| country[1] != settings.country[1])) {
return false;
@@ -1480,66 +1477,56 @@
const int setScreenSize = settings.screenLayout&MASK_SCREENSIZE;
// Any screen sizes for larger screens than the setting do not
// match.
- if ((setScreenSize != 0 && screenSize != 0
- && screenSize > setScreenSize) ||
- (setScreenSize == 0 && screenSize != 0)) {
+ if (screenSize != 0 && screenSize > setScreenSize) {
return false;
}
const int screenLong = screenLayout&MASK_SCREENLONG;
const int setScreenLong = settings.screenLayout&MASK_SCREENLONG;
- if (setScreenLong != 0 && screenLong != 0
- && screenLong != setScreenLong) {
+ if (screenLong != 0 && screenLong != setScreenLong) {
return false;
}
const int uiModeType = uiMode&MASK_UI_MODE_TYPE;
const int setUiModeType = settings.uiMode&MASK_UI_MODE_TYPE;
- if (setUiModeType != 0 && uiModeType != 0
- && uiModeType != setUiModeType) {
+ if (uiModeType != 0 && uiModeType != setUiModeType) {
return false;
}
const int uiModeNight = uiMode&MASK_UI_MODE_NIGHT;
const int setUiModeNight = settings.uiMode&MASK_UI_MODE_NIGHT;
- if (setUiModeNight != 0 && uiModeNight != 0
- && uiModeNight != setUiModeNight) {
+ if (uiModeNight != 0 && uiModeNight != setUiModeNight) {
return false;
}
- if (settings.smallestScreenWidthDp != 0 && smallestScreenWidthDp != 0
+ if (smallestScreenWidthDp != 0
&& smallestScreenWidthDp > settings.smallestScreenWidthDp) {
return false;
}
}
if (screenSizeDp != 0) {
- if (settings.screenWidthDp != 0 && screenWidthDp != 0
- && screenWidthDp > settings.screenWidthDp) {
+ if (screenWidthDp != 0 && screenWidthDp > settings.screenWidthDp) {
//LOGI("Filtering out width %d in requested %d", screenWidthDp, settings.screenWidthDp);
return false;
}
- if (settings.screenHeightDp != 0 && screenHeightDp != 0
- && screenHeightDp > settings.screenHeightDp) {
+ if (screenHeightDp != 0 && screenHeightDp > settings.screenHeightDp) {
//LOGI("Filtering out height %d in requested %d", screenHeightDp, settings.screenHeightDp);
return false;
}
}
if (screenType != 0) {
- if (settings.orientation != 0 && orientation != 0
- && orientation != settings.orientation) {
+ if (orientation != 0 && orientation != settings.orientation) {
return false;
}
// density always matches - we can scale it. See isBetterThan
- if (settings.touchscreen != 0 && touchscreen != 0
- && touchscreen != settings.touchscreen) {
+ if (touchscreen != 0 && touchscreen != settings.touchscreen) {
return false;
}
}
if (input != 0) {
const int keysHidden = inputFlags&MASK_KEYSHIDDEN;
const int setKeysHidden = settings.inputFlags&MASK_KEYSHIDDEN;
- if (setKeysHidden != 0 && keysHidden != 0
- && keysHidden != setKeysHidden) {
+ if (keysHidden != 0 && keysHidden != setKeysHidden) {
// For compatibility, we count a request for KEYSHIDDEN_NO as also
// matching the more recent KEYSHIDDEN_SOFT. Basically
// KEYSHIDDEN_NO means there is some kind of keyboard available.
@@ -1551,36 +1538,29 @@
}
const int navHidden = inputFlags&MASK_NAVHIDDEN;
const int setNavHidden = settings.inputFlags&MASK_NAVHIDDEN;
- if (setNavHidden != 0 && navHidden != 0
- && navHidden != setNavHidden) {
+ if (navHidden != 0 && navHidden != setNavHidden) {
return false;
}
- if (settings.keyboard != 0 && keyboard != 0
- && keyboard != settings.keyboard) {
+ if (keyboard != 0 && keyboard != settings.keyboard) {
return false;
}
- if (settings.navigation != 0 && navigation != 0
- && navigation != settings.navigation) {
+ if (navigation != 0 && navigation != settings.navigation) {
return false;
}
}
if (screenSize != 0) {
- if (settings.screenWidth != 0 && screenWidth != 0
- && screenWidth > settings.screenWidth) {
+ if (screenWidth != 0 && screenWidth > settings.screenWidth) {
return false;
}
- if (settings.screenHeight != 0 && screenHeight != 0
- && screenHeight > settings.screenHeight) {
+ if (screenHeight != 0 && screenHeight > settings.screenHeight) {
return false;
}
}
if (version != 0) {
- if (settings.sdkVersion != 0 && sdkVersion != 0
- && sdkVersion > settings.sdkVersion) {
+ if (sdkVersion != 0 && sdkVersion > settings.sdkVersion) {
return false;
}
- if (settings.minorVersion != 0 && minorVersion != 0
- && minorVersion != settings.minorVersion) {
+ if (minorVersion != 0 && minorVersion != settings.minorVersion) {
return false;
}
}
diff --git a/include/utils/Timers.h b/include/utils/Timers.h
index 9a9e07c..8b4d322 100644
--- a/include/utils/Timers.h
+++ b/include/utils/Timers.h
@@ -88,6 +88,16 @@
nsecs_t systemTime(int clock);
#endif // def __cplusplus
+/**
+ * Returns the number of milliseconds to wait between the reference time and the timeout time.
+ * If the timeout is in the past relative to the reference time, returns 0.
+ * If the timeout is more than INT_MAX milliseconds in the future relative to the reference time,
+ * such as when timeoutTime == LLONG_MAX, returns -1 to indicate an infinite timeout delay.
+ * Otherwise, returns the difference between the reference time and timeout time
+ * rounded up to the next millisecond.
+ */
+int toMillisecondTimeoutDelay(nsecs_t referenceTime, nsecs_t timeoutTime);
+
#ifdef __cplusplus
} // extern "C"
#endif
diff --git a/libs/ui/Input.cpp b/libs/ui/Input.cpp
index 19d590a..684c332 100644
--- a/libs/ui/Input.cpp
+++ b/libs/ui/Input.cpp
@@ -7,8 +7,12 @@
//#define LOG_NDEBUG 0
+// Log debug messages about keymap probing.
#define DEBUG_PROBE 0
+// Log debug messages about velocity tracking.
+#define DEBUG_VELOCITY 0
+
#include <stdlib.h>
#include <unistd.h>
#include <ctype.h>
@@ -347,6 +351,27 @@
"cannot contain more than %d axis values.", axis, int(MAX_AXES));
}
+bool PointerCoords::operator==(const PointerCoords& other) const {
+ if (bits != other.bits) {
+ return false;
+ }
+ uint32_t count = __builtin_popcountll(bits);
+ for (uint32_t i = 0; i < count; i++) {
+ if (values[i] != other.values[i]) {
+ return false;
+ }
+ }
+ return true;
+}
+
+void PointerCoords::copyFrom(const PointerCoords& other) {
+ bits = other.bits;
+ uint32_t count = __builtin_popcountll(bits);
+ for (uint32_t i = 0; i < count; i++) {
+ values[i] = other.values[i];
+ }
+}
+
// --- MotionEvent ---
@@ -458,6 +483,16 @@
return value;
}
+ssize_t MotionEvent::findPointerIndex(int32_t pointerId) const {
+ size_t pointerCount = mPointerIds.size();
+ for (size_t i = 0; i < pointerCount; i++) {
+ if (mPointerIds.itemAt(i) == pointerId) {
+ return i;
+ }
+ }
+ return -1;
+}
+
void MotionEvent::offsetLocation(float xOffset, float yOffset) {
mXOffset += xOffset;
mYOffset += yOffset;
@@ -633,6 +668,217 @@
}
+// --- VelocityTracker ---
+
+VelocityTracker::VelocityTracker() {
+ clear();
+}
+
+void VelocityTracker::clear() {
+ mIndex = 0;
+ mMovements[0].idBits.clear();
+ mActivePointerId = -1;
+}
+
+void VelocityTracker::clearPointers(BitSet32 idBits) {
+ BitSet32 remainingIdBits(mMovements[mIndex].idBits.value & ~idBits.value);
+ mMovements[mIndex].idBits = remainingIdBits;
+
+ if (mActivePointerId >= 0 && idBits.hasBit(mActivePointerId)) {
+ mActivePointerId = !remainingIdBits.isEmpty() ? remainingIdBits.firstMarkedBit() : -1;
+ }
+}
+
+void VelocityTracker::addMovement(nsecs_t eventTime, BitSet32 idBits, const Position* positions) {
+ if (++mIndex == HISTORY_SIZE) {
+ mIndex = 0;
+ }
+
+ while (idBits.count() > MAX_POINTERS) {
+ idBits.clearBit(idBits.lastMarkedBit());
+ }
+
+ Movement& movement = mMovements[mIndex];
+ movement.eventTime = eventTime;
+ movement.idBits = idBits;
+ uint32_t count = idBits.count();
+ for (uint32_t i = 0; i < count; i++) {
+ movement.positions[i] = positions[i];
+ }
+
+ if (mActivePointerId < 0 || !idBits.hasBit(mActivePointerId)) {
+ mActivePointerId = count != 0 ? idBits.firstMarkedBit() : -1;
+ }
+
+#if DEBUG_VELOCITY
+ LOGD("VelocityTracker: addMovement eventTime=%lld, idBits=0x%08x, activePointerId=%d",
+ eventTime, idBits.value, mActivePointerId);
+ for (BitSet32 iterBits(idBits); !iterBits.isEmpty(); ) {
+ uint32_t id = iterBits.firstMarkedBit();
+ uint32_t index = idBits.getIndexOfBit(id);
+ iterBits.clearBit(id);
+ float vx, vy;
+ bool available = getVelocity(id, &vx, &vy);
+ if (available) {
+ LOGD(" %d: position (%0.3f, %0.3f), vx=%0.3f, vy=%0.3f, speed=%0.3f",
+ id, positions[index].x, positions[index].y, vx, vy, sqrtf(vx * vx + vy * vy));
+ } else {
+ assert(vx == 0 && vy == 0);
+ LOGD(" %d: position (%0.3f, %0.3f), velocity not available",
+ id, positions[index].x, positions[index].y);
+ }
+ }
+#endif
+}
+
+void VelocityTracker::addMovement(const MotionEvent* event) {
+ int32_t actionMasked = event->getActionMasked();
+
+ switch (actionMasked) {
+ case AMOTION_EVENT_ACTION_DOWN:
+ // Clear all pointers on down before adding the new movement.
+ clear();
+ break;
+ case AMOTION_EVENT_ACTION_POINTER_DOWN: {
+ // Start a new movement trace for a pointer that just went down.
+ // We do this on down instead of on up because the client may want to query the
+ // final velocity for a pointer that just went up.
+ BitSet32 downIdBits;
+ downIdBits.markBit(event->getActionIndex());
+ clearPointers(downIdBits);
+ break;
+ }
+ case AMOTION_EVENT_ACTION_OUTSIDE:
+ case AMOTION_EVENT_ACTION_CANCEL:
+ case AMOTION_EVENT_ACTION_SCROLL:
+ case AMOTION_EVENT_ACTION_UP:
+ case AMOTION_EVENT_ACTION_POINTER_UP:
+ // Ignore these actions because they do not convey any new information about
+ // pointer movement. We also want to preserve the last known velocity of the pointers.
+ // Note that ACTION_UP and ACTION_POINTER_UP always report the last known position
+ // of the pointers that went up. ACTION_POINTER_UP does include the new position of
+ // pointers that remained down but we will also receive an ACTION_MOVE with this
+ // information if any of them actually moved. Since we don't know how many pointers
+ // will be going up at once it makes sense to just wait for the following ACTION_MOVE
+ // before adding the movement.
+ return;
+ }
+
+ size_t pointerCount = event->getPointerCount();
+ if (pointerCount > MAX_POINTERS) {
+ pointerCount = MAX_POINTERS;
+ }
+
+ BitSet32 idBits;
+ for (size_t i = 0; i < pointerCount; i++) {
+ idBits.markBit(event->getPointerId(i));
+ }
+
+ nsecs_t eventTime;
+ Position positions[pointerCount];
+
+ size_t historySize = event->getHistorySize();
+ for (size_t h = 0; h < historySize; h++) {
+ eventTime = event->getHistoricalEventTime(h);
+ for (size_t i = 0; i < pointerCount; i++) {
+ positions[i].x = event->getHistoricalX(i, h);
+ positions[i].y = event->getHistoricalY(i, h);
+ }
+ addMovement(eventTime, idBits, positions);
+ }
+
+ eventTime = event->getEventTime();
+ for (size_t i = 0; i < pointerCount; i++) {
+ positions[i].x = event->getX(i);
+ positions[i].y = event->getY(i);
+ }
+ addMovement(eventTime, idBits, positions);
+}
+
+bool VelocityTracker::getVelocity(uint32_t id, float* outVx, float* outVy) const {
+ const Movement& newestMovement = mMovements[mIndex];
+ if (newestMovement.idBits.hasBit(id)) {
+ // Find the oldest sample that contains the pointer and that is not older than MAX_AGE.
+ nsecs_t minTime = newestMovement.eventTime - MAX_AGE;
+ uint32_t oldestIndex = mIndex;
+ uint32_t numTouches = 1;
+ do {
+ uint32_t nextOldestIndex = (oldestIndex == 0 ? HISTORY_SIZE : oldestIndex) - 1;
+ const Movement& nextOldestMovement = mMovements[nextOldestIndex];
+ if (!nextOldestMovement.idBits.hasBit(id)
+ || nextOldestMovement.eventTime < minTime) {
+ break;
+ }
+ oldestIndex = nextOldestIndex;
+ } while (++numTouches < HISTORY_SIZE);
+
+ // Calculate an exponentially weighted moving average of the velocity estimate
+ // at different points in time measured relative to the oldest sample.
+ // This is essentially an IIR filter. Newer samples are weighted more heavily
+ // than older samples. Samples at equal time points are weighted more or less
+ // equally.
+ //
+ // One tricky problem is that the sample data may be poorly conditioned.
+ // Sometimes samples arrive very close together in time which can cause us to
+ // overestimate the velocity at that time point. Most samples might be measured
+ // 16ms apart but some consecutive samples could be only 0.5sm apart because
+ // the hardware or driver reports them irregularly or in bursts.
+ float accumVx = 0;
+ float accumVy = 0;
+ uint32_t index = oldestIndex;
+ uint32_t samplesUsed = 0;
+ const Movement& oldestMovement = mMovements[oldestIndex];
+ const Position& oldestPosition =
+ oldestMovement.positions[oldestMovement.idBits.getIndexOfBit(id)];
+ nsecs_t lastDuration = 0;
+
+ while (numTouches-- > 1) {
+ if (++index == HISTORY_SIZE) {
+ index = 0;
+ }
+ const Movement& movement = mMovements[index];
+ nsecs_t duration = movement.eventTime - oldestMovement.eventTime;
+
+ // If the duration between samples is small, we may significantly overestimate
+ // the velocity. Consequently, we impose a minimum duration constraint on the
+ // samples that we include in the calculation.
+ if (duration >= MIN_DURATION) {
+ const Position& position = movement.positions[movement.idBits.getIndexOfBit(id)];
+ float scale = 1000000000.0f / duration; // one over time delta in seconds
+ float vx = (position.x - oldestPosition.x) * scale;
+ float vy = (position.y - oldestPosition.y) * scale;
+
+ accumVx = (accumVx * lastDuration + vx * duration) / (duration + lastDuration);
+ accumVy = (accumVy * lastDuration + vy * duration) / (duration + lastDuration);
+
+ lastDuration = duration;
+ samplesUsed += 1;
+ }
+ }
+
+ // Make sure we used at least one sample.
+ if (samplesUsed != 0) {
+ // Scale the velocity linearly if the window of samples is small.
+ nsecs_t totalDuration = newestMovement.eventTime - oldestMovement.eventTime;
+ if (totalDuration < MIN_WINDOW) {
+ float scale = float(totalDuration) / float(MIN_WINDOW);
+ accumVx *= scale;
+ accumVy *= scale;
+ }
+
+ *outVx = accumVx;
+ *outVy = accumVy;
+ return true;
+ }
+ }
+
+ // No data available for this pointer.
+ *outVx = 0;
+ *outVy = 0;
+ return false;
+}
+
+
// --- InputDeviceInfo ---
InputDeviceInfo::InputDeviceInfo() {
diff --git a/libs/ui/InputTransport.cpp b/libs/ui/InputTransport.cpp
index 5c57a76..93d0d1f 100644
--- a/libs/ui/InputTransport.cpp
+++ b/libs/ui/InputTransport.cpp
@@ -27,8 +27,14 @@
namespace android {
+#define ROUND_UP(value, boundary) (((value) + (boundary) - 1) & ~((boundary) - 1))
+#define MIN_HISTORY_DEPTH 20
+
// Must be at least sizeof(InputMessage) + sufficient space for pointer data
-static const int DEFAULT_MESSAGE_BUFFER_SIZE = 16384;
+static const int DEFAULT_MESSAGE_BUFFER_SIZE = ROUND_UP(
+ sizeof(InputMessage) + MIN_HISTORY_DEPTH
+ * (sizeof(InputMessage::SampleData) + MAX_POINTERS * sizeof(PointerCoords)),
+ 4096);
// Signal sent by the producer to the consumer to inform it that a new message is
// available to be consumed in the shared memory buffer.
@@ -406,7 +412,7 @@
for (size_t i = 0; i < pointerCount; i++) {
mSharedMessage->motion.pointerIds[i] = pointerIds[i];
- mSharedMessage->motion.sampleData[0].coords[i] = pointerCoords[i];
+ mSharedMessage->motion.sampleData[0].coords[i].copyFrom(pointerCoords[i]);
}
// Cache essential information about the motion event to ensure that a malicious consumer
@@ -475,7 +481,7 @@
mMotionEventSampleDataTail->eventTime = eventTime;
for (size_t i = 0; i < mMotionEventPointerCount; i++) {
- mMotionEventSampleDataTail->coords[i] = pointerCoords[i];
+ mMotionEventSampleDataTail->coords[i].copyFrom(pointerCoords[i]);
}
mMotionEventSampleDataTail = newTail;
diff --git a/libs/utils/Looper.cpp b/libs/utils/Looper.cpp
index 18f858b..b54fb9d 100644
--- a/libs/utils/Looper.cpp
+++ b/libs/utils/Looper.cpp
@@ -218,14 +218,10 @@
// Adjust the timeout based on when the next message is due.
if (timeoutMillis != 0 && mNextMessageUptime != LLONG_MAX) {
nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC);
- if (mNextMessageUptime <= now) {
- timeoutMillis = 0;
- } else {
- uint64_t delay = (mNextMessageUptime - now + 999999LL) / 1000000LL;
- if (delay < INT_MAX
- && (timeoutMillis < 0 || int(delay) < timeoutMillis)) {
- timeoutMillis = int(delay);
- }
+ int messageTimeoutMillis = toMillisecondTimeoutDelay(now, mNextMessageUptime);
+ if (messageTimeoutMillis >= 0
+ && (timeoutMillis < 0 || messageTimeoutMillis < timeoutMillis)) {
+ timeoutMillis = messageTimeoutMillis;
}
#if DEBUG_POLL_AND_WAKE
LOGD("%p ~ pollOnce - next message in %lldns, adjusted timeout: timeoutMillis=%d",
@@ -444,12 +440,11 @@
return result;
}
- nsecs_t timeoutNanos = endTime - systemTime(SYSTEM_TIME_MONOTONIC);
- if (timeoutNanos <= 0) {
+ nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC);
+ timeoutMillis = toMillisecondTimeoutDelay(now, endTime);
+ if (timeoutMillis == 0) {
return ALOOPER_POLL_TIMEOUT;
}
-
- timeoutMillis = int(nanoseconds_to_milliseconds(timeoutNanos + 999999LL));
}
}
}
@@ -667,7 +662,8 @@
#endif
void Looper::sendMessage(const sp<MessageHandler>& handler, const Message& message) {
- sendMessageAtTime(LLONG_MIN, handler, message);
+ nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC);
+ sendMessageAtTime(now, handler, message);
}
void Looper::sendMessageDelayed(nsecs_t uptimeDelay, const sp<MessageHandler>& handler,
diff --git a/libs/utils/Timers.cpp b/libs/utils/Timers.cpp
index 784f035..64a29f5 100644
--- a/libs/utils/Timers.cpp
+++ b/libs/utils/Timers.cpp
@@ -26,6 +26,7 @@
#include <sys/time.h>
#include <time.h>
#include <errno.h>
+#include <limits.h>
#ifdef HAVE_WIN32_THREADS
#include <windows.h>
@@ -53,6 +54,23 @@
#endif
}
+int toMillisecondTimeoutDelay(nsecs_t referenceTime, nsecs_t timeoutTime)
+{
+ int timeoutDelayMillis;
+ if (timeoutTime > referenceTime) {
+ uint64_t timeoutDelay = uint64_t(timeoutTime - referenceTime);
+ if (timeoutDelay > uint64_t((INT_MAX - 1) * 1000000LL)) {
+ timeoutDelayMillis = -1;
+ } else {
+ timeoutDelayMillis = (timeoutDelay + 999999LL) / 1000000LL;
+ }
+ } else {
+ timeoutDelayMillis = 0;
+ }
+ return timeoutDelayMillis;
+}
+
+
/*
* ===========================================================================
* DurationTimer