Merge "DO NOT MERGE Correctly implement the CLEAR xfermode." 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 35792dc..c02d8ac 100644
--- a/include/utils/ResourceTypes.h
+++ b/include/utils/ResourceTypes.h
@@ -953,6 +953,7 @@
         UI_MODE_TYPE_NORMAL = ACONFIGURATION_UI_MODE_TYPE_NORMAL,
         UI_MODE_TYPE_DESK = ACONFIGURATION_UI_MODE_TYPE_DESK,
         UI_MODE_TYPE_CAR = ACONFIGURATION_UI_MODE_TYPE_CAR,
+        UI_MODE_TYPE_TELEVISION = ACONFIGURATION_UI_MODE_TYPE_TELEVISION,
 
         // uiMode bits for the night switch.
         MASK_UI_MODE_NIGHT = 0x30,
@@ -966,8 +967,7 @@
         struct {
             uint8_t screenLayout;
             uint8_t uiMode;
-            uint8_t screenConfigPad1;
-            uint8_t screenConfigPad2;
+            uint16_t smallestScreenWidthDp;
         };
         uint32_t screenConfig;
     };
@@ -1000,6 +1000,7 @@
         screenHeight = dtohs(screenHeight);
         sdkVersion = dtohs(sdkVersion);
         minorVersion = dtohs(minorVersion);
+        smallestScreenWidthDp = dtohs(smallestScreenWidthDp);
         screenWidthDp = dtohs(screenWidthDp);
         screenHeightDp = dtohs(screenHeightDp);
     }
@@ -1013,6 +1014,7 @@
         screenHeight = htods(screenHeight);
         sdkVersion = htods(sdkVersion);
         minorVersion = htods(minorVersion);
+        smallestScreenWidthDp = htods(smallestScreenWidthDp);
         screenWidthDp = htods(screenWidthDp);
         screenHeightDp = htods(screenHeightDp);
     }
@@ -1034,6 +1036,8 @@
         if (diff != 0) return diff;
         diff = (int32_t)(uiMode - o.uiMode);
         if (diff != 0) return diff;
+        diff = (int32_t)(smallestScreenWidthDp - o.smallestScreenWidthDp);
+        if (diff != 0) return diff;
         diff = (int32_t)(screenSizeDp - o.screenSizeDp);
         return (int)diff;
     }
@@ -1052,6 +1056,7 @@
         CONFIG_ORIENTATION = ACONFIGURATION_ORIENTATION,
         CONFIG_DENSITY = ACONFIGURATION_DENSITY,
         CONFIG_SCREEN_SIZE = ACONFIGURATION_SCREEN_SIZE,
+        CONFIG_SMALLEST_SCREEN_SIZE = ACONFIGURATION_SMALLEST_SCREEN_SIZE,
         CONFIG_VERSION = ACONFIGURATION_VERSION,
         CONFIG_SCREEN_LAYOUT = ACONFIGURATION_SCREEN_LAYOUT,
         CONFIG_UI_MODE = ACONFIGURATION_UI_MODE
@@ -1075,6 +1080,7 @@
         if (version != o.version) diffs |= CONFIG_VERSION;
         if (screenLayout != o.screenLayout) diffs |= CONFIG_SCREEN_LAYOUT;
         if (uiMode != o.uiMode) diffs |= CONFIG_UI_MODE;
+        if (smallestScreenWidthDp != o.smallestScreenWidthDp) diffs |= CONFIG_SMALLEST_SCREEN_SIZE;
         if (screenSizeDp != o.screenSizeDp) diffs |= CONFIG_SCREEN_SIZE;
         return diffs;
     }
@@ -1109,14 +1115,10 @@
             }
         }
 
-        if (screenLayout || o.screenLayout) {
-            if (((screenLayout^o.screenLayout) & MASK_SCREENSIZE) != 0) {
-                if (!(screenLayout & MASK_SCREENSIZE)) return false;
-                if (!(o.screenLayout & MASK_SCREENSIZE)) return true;
-            }
-            if (((screenLayout^o.screenLayout) & MASK_SCREENLONG) != 0) {
-                if (!(screenLayout & MASK_SCREENLONG)) return false;
-                if (!(o.screenLayout & MASK_SCREENLONG)) return true;
+        if (smallestScreenWidthDp || o.smallestScreenWidthDp) {
+            if (smallestScreenWidthDp != o.smallestScreenWidthDp) {
+                if (!smallestScreenWidthDp) return false;
+                if (!o.smallestScreenWidthDp) return true;
             }
         }
 
@@ -1132,6 +1134,17 @@
             }
         }
 
+        if (screenLayout || o.screenLayout) {
+            if (((screenLayout^o.screenLayout) & MASK_SCREENSIZE) != 0) {
+                if (!(screenLayout & MASK_SCREENSIZE)) return false;
+                if (!(o.screenLayout & MASK_SCREENSIZE)) return true;
+            }
+            if (((screenLayout^o.screenLayout) & MASK_SCREENLONG) != 0) {
+                if (!(screenLayout & MASK_SCREENLONG)) return false;
+                if (!(o.screenLayout & MASK_SCREENLONG)) return true;
+            }
+        }
+
         if (orientation != o.orientation) {
             if (!orientation) return false;
             if (!o.orientation) return true;
@@ -1238,6 +1251,37 @@
                 }
             }
 
+            if (smallestScreenWidthDp || o.smallestScreenWidthDp) {
+                // The configuration closest to the actual size is best.
+                // We assume that larger configs have already been filtered
+                // out at this point.  That means we just want the largest one.
+                return smallestScreenWidthDp >= o.smallestScreenWidthDp;
+            }
+
+            if (screenSizeDp || o.screenSizeDp) {
+                // "Better" is based on the sum of the difference between both
+                // width and height from the requested dimensions.  We are
+                // assuming the invalid configs (with smaller dimens) have
+                // already been filtered.  Note that if a particular dimension
+                // is unspecified, we will end up with a large value (the
+                // difference between 0 and the requested dimension), which is
+                // good since we will prefer a config that has specified a
+                // dimension value.
+                int myDelta = 0, otherDelta = 0;
+                if (requested->screenWidthDp) {
+                    myDelta += requested->screenWidthDp - screenWidthDp;
+                    otherDelta += requested->screenWidthDp - o.screenWidthDp;
+                }
+                if (requested->screenHeightDp) {
+                    myDelta += requested->screenHeightDp - screenHeightDp;
+                    otherDelta += requested->screenHeightDp - o.screenHeightDp;
+                }
+                //LOGI("Comparing this %dx%d to other %dx%d in %dx%d: myDelta=%d otherDelta=%d",
+                //    screenWidthDp, screenHeightDp, o.screenWidthDp, o.screenHeightDp,
+                //    requested->screenWidthDp, requested->screenHeightDp, myDelta, otherDelta);
+                return (myDelta <= otherDelta);
+            }
+
             if (screenLayout || o.screenLayout) {
                 if (((screenLayout^o.screenLayout) & MASK_SCREENSIZE) != 0
                         && (requested->screenLayout & MASK_SCREENSIZE)) {
@@ -1270,30 +1314,6 @@
                 }
             }
 
-            if (screenSizeDp || o.screenSizeDp) {
-                // Better is based on the sum of the difference between both
-                // width and height from the requested dimensions.  We are
-                // assuming the invalid configs (with smaller dimens) have
-                // already been filtered.  Note that if a particular dimension
-                // is unspecified, we will end up with a large value (the
-                // difference between 0 and the requested dimension), which is
-                // good since we will prefer a config that has specified a
-                // dimension value.
-                int myDelta = 0, otherDelta = 0;
-                if (requested->screenWidthDp) {
-                    myDelta += requested->screenWidthDp - screenWidthDp;
-                    otherDelta += requested->screenWidthDp - o.screenWidthDp;
-                }
-                if (requested->screenHeightDp) {
-                    myDelta += requested->screenHeightDp - screenHeightDp;
-                    otherDelta += requested->screenHeightDp - o.screenHeightDp;
-                }
-                //LOGI("Comparing this %dx%d to other %dx%d in %dx%d: myDelta=%d otherDelta=%d",
-                //    screenWidthDp, screenHeightDp, o.screenWidthDp, o.screenHeightDp,
-                //    requested->screenWidthDp, requested->screenHeightDp, myDelta, otherDelta);
-                return (myDelta <= otherDelta);
-            }
-
             if ((orientation != o.orientation) && requested->orientation) {
                 return (orientation);
             }
@@ -1388,14 +1408,24 @@
             }
 
             if (screenSize || o.screenSize) {
-                if ((screenWidth != o.screenWidth) && requested->screenWidth) {
-                    return (screenWidth);
+                // "Better" is based on the sum of the difference between both
+                // width and height from the requested dimensions.  We are
+                // assuming the invalid configs (with smaller sizes) have
+                // already been filtered.  Note that if a particular dimension
+                // is unspecified, we will end up with a large value (the
+                // difference between 0 and the requested dimension), which is
+                // good since we will prefer a config that has specified a
+                // size value.
+                int myDelta = 0, otherDelta = 0;
+                if (requested->screenWidth) {
+                    myDelta += requested->screenWidth - screenWidth;
+                    otherDelta += requested->screenWidth - o.screenWidth;
                 }
-
-                if ((screenHeight != o.screenHeight) &&
-                        requested->screenHeight) {
-                    return (screenHeight);
+                if (requested->screenHeight) {
+                    myDelta += requested->screenHeight - screenHeight;
+                    otherDelta += requested->screenHeight - o.screenHeight;
                 }
+                return (myDelta <= otherDelta);
             }
 
             if (version || o.version) {
@@ -1476,15 +1506,20 @@
                     && uiModeNight != setUiModeNight) {
                 return false;
             }
+
+            if (settings.smallestScreenWidthDp != 0 && smallestScreenWidthDp != 0
+                    && smallestScreenWidthDp > settings.smallestScreenWidthDp) {
+                return false;
+            }
         }
         if (screenSizeDp != 0) {
             if (settings.screenWidthDp != 0 && screenWidthDp != 0
-                && screenWidthDp > settings.screenWidthDp) {
+                    && 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) {
+                    && screenHeightDp > settings.screenHeightDp) {
                 //LOGI("Filtering out height %d in requested %d", screenHeightDp, settings.screenHeightDp);
                 return false;
             }
@@ -1531,11 +1566,11 @@
         }
         if (screenSize != 0) {
             if (settings.screenWidth != 0 && screenWidth != 0
-                && screenWidth != settings.screenWidth) {
+                && screenWidth > settings.screenWidth) {
                 return false;
             }
             if (settings.screenHeight != 0 && screenHeight != 0
-                && screenHeight != settings.screenHeight) {
+                && screenHeight > settings.screenHeight) {
                 return false;
             }
         }
@@ -1568,13 +1603,13 @@
     String8 toString() const {
         char buf[200];
         sprintf(buf, "imsi=%d/%d lang=%c%c reg=%c%c orient=%d touch=%d dens=%d "
-                "kbd=%d nav=%d input=%d ssz=%dx%d %ddp x %ddp sz=%d long=%d "
+                "kbd=%d nav=%d input=%d ssz=%dx%d sw%ddp w%ddp h%ddp sz=%d long=%d "
                 "ui=%d night=%d vers=%d.%d",
                 mcc, mnc,
                 language[0] ? language[0] : '-', language[1] ? language[1] : '-',
                 country[0] ? country[0] : '-', country[1] ? country[1] : '-',
                 orientation, touchscreen, density, keyboard, navigation, inputFlags,
-                screenWidth, screenHeight, screenWidthDp, screenHeightDp,
+                screenWidth, screenHeight, smallestScreenWidthDp, screenWidthDp, screenHeightDp,
                 screenLayout&MASK_SCREENSIZE, screenLayout&MASK_SCREENLONG,
                 uiMode&MASK_UI_MODE_TYPE, uiMode&MASK_UI_MODE_NIGHT,
                 sdkVersion, minorVersion);
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/ResourceTypes.cpp b/libs/utils/ResourceTypes.cpp
index ac9cdf9..a64918d 100644
--- a/libs/utils/ResourceTypes.cpp
+++ b/libs/utils/ResourceTypes.cpp
@@ -2424,7 +2424,7 @@
 {
     mLock.lock();
     TABLE_GETENTRY(LOGI("Setting parameters: imsi:%d/%d lang:%c%c cnt:%c%c "
-                        "orien:%d touch:%d density:%d key:%d inp:%d nav:%d sz:%dx%d %ddp x %ddp\n",
+                        "orien:%d touch:%d density:%d key:%d inp:%d nav:%d sz:%dx%d sw%ddp w%ddp h%ddp\n",
                        params->mcc, params->mnc,
                        params->language[0] ? params->language[0] : '-',
                        params->language[1] ? params->language[1] : '-',
@@ -2438,6 +2438,7 @@
                        params->navigation,
                        params->screenWidth,
                        params->screenHeight,
+                       params->smallestScreenWidthDp,
                        params->screenWidthDp,
                        params->screenHeightDp));
     mParams = *params;
@@ -3763,7 +3764,7 @@
         TABLE_GETENTRY(LOGI("Match entry 0x%x in type 0x%x (sz 0x%x): imsi:%d/%d=%d/%d "
                             "lang:%c%c=%c%c cnt:%c%c=%c%c orien:%d=%d touch:%d=%d "
                             "density:%d=%d key:%d=%d inp:%d=%d nav:%d=%d w:%d=%d h:%d=%d "
-                            "wdp:%d=%d hdp:%d=%d\n",
+                            "swdp:%d=%d wdp:%d=%d hdp:%d=%d\n",
                            entryIndex, typeIndex+1, dtohl(thisType->config.size),
                            thisConfig.mcc, thisConfig.mnc,
                            config ? config->mcc : 0, config ? config->mnc : 0,
@@ -3791,6 +3792,8 @@
                            config ? config->screenWidth : 0,
                            thisConfig.screenHeight,
                            config ? config->screenHeight : 0,
+                           thisConfig.smallestScreenWidthDp,
+                           config ? config->smallestScreenWidthDp : 0,
                            thisConfig.screenWidthDp,
                            config ? config->screenWidthDp : 0,
                            thisConfig.screenHeightDp,
@@ -4076,7 +4079,7 @@
                 thisConfig.copyFromDtoH(type->config);
                 LOGI("Adding config to type %d: imsi:%d/%d lang:%c%c cnt:%c%c "
                      "orien:%d touch:%d density:%d key:%d inp:%d nav:%d w:%d h:%d "
-                     "wdp:%d hdp:%d\n",
+                     "swdp:%d wdp:%d hdp:%d\n",
                       type->id,
                       thisConfig.mcc, thisConfig.mnc,
                       thisConfig.language[0] ? thisConfig.language[0] : '-',
@@ -4091,6 +4094,7 @@
                       thisConfig.navigation,
                       thisConfig.screenWidth,
                       thisConfig.screenHeight,
+                      thisConfig.smallestScreenWidthDp,
                       thisConfig.screenWidthDp,
                       thisConfig.screenHeightDp));
             t->configs.add(type);
@@ -4455,6 +4459,9 @@
                     if (type->config.screenHeight != 0) {
                         printf(" h=%d", dtohs(type->config.screenHeight));
                     }
+                    if (type->config.smallestScreenWidthDp != 0) {
+                        printf(" swdp=%d", dtohs(type->config.smallestScreenWidthDp));
+                    }
                     if (type->config.screenWidthDp != 0) {
                         printf(" wdp=%d", dtohs(type->config.screenWidthDp));
                     }
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