Add initial API for stylus and mouse buttons.

Added the concept of pointer properties in a MotionEvent.
This is currently used to track the pointer tool type to enable
applications to distinguish finger touches from a stylus.

Button states are also reported to application as part of touch events.

There are no new actions for detecting changes in button states.
The application should instead query the button state from the
MotionEvent and take appropriate action as needed.

A good time to check the button state is on ACTION_DOWN.

As a side-effect, applications that do not support multiple buttons
will treat primary, secondary and tertiary buttons identically
for all touch events.

The back button on the mouse is mapped to KEYCODE_BACK
and the forward button is mapped to KEYCODE_FORWARD.

Added basic plumbing for the secondary mouse button to invoke
the context menu, particularly in lists.

Added clamp and split methods on MotionEvent to take care of
common filtering operations so we don't have them scattered
in multiple places across the framework.

Bug: 4260011
Change-Id: Ie992b4d4e00c8f2e76b961da0a902145b27f6d83
diff --git a/libs/ui/Input.cpp b/libs/ui/Input.cpp
index d811dd7..1ba38a7 100644
--- a/libs/ui/Input.cpp
+++ b/libs/ui/Input.cpp
@@ -373,6 +373,19 @@
 }
 
 
+// --- PointerProperties ---
+
+bool PointerProperties::operator==(const PointerProperties& other) const {
+    return id == other.id
+            && toolType == other.toolType;
+}
+
+void PointerProperties::copyFrom(const PointerProperties& other) {
+    id = other.id;
+    toolType = other.toolType;
+}
+
+
 // --- MotionEvent ---
 
 void MotionEvent::initialize(
@@ -382,6 +395,7 @@
         int32_t flags,
         int32_t edgeFlags,
         int32_t metaState,
+        int32_t buttonState,
         float xOffset,
         float yOffset,
         float xPrecision,
@@ -389,20 +403,21 @@
         nsecs_t downTime,
         nsecs_t eventTime,
         size_t pointerCount,
-        const int32_t* pointerIds,
+        const PointerProperties* pointerProperties,
         const PointerCoords* pointerCoords) {
     InputEvent::initialize(deviceId, source);
     mAction = action;
     mFlags = flags;
     mEdgeFlags = edgeFlags;
     mMetaState = metaState;
+    mButtonState = buttonState;
     mXOffset = xOffset;
     mYOffset = yOffset;
     mXPrecision = xPrecision;
     mYPrecision = yPrecision;
     mDownTime = downTime;
-    mPointerIds.clear();
-    mPointerIds.appendArray(pointerIds, pointerCount);
+    mPointerProperties.clear();
+    mPointerProperties.appendArray(pointerProperties, pointerCount);
     mSampleEventTimes.clear();
     mSamplePointerCoords.clear();
     addSample(eventTime, pointerCoords);
@@ -414,12 +429,13 @@
     mFlags = other->mFlags;
     mEdgeFlags = other->mEdgeFlags;
     mMetaState = other->mMetaState;
+    mButtonState = other->mButtonState;
     mXOffset = other->mXOffset;
     mYOffset = other->mYOffset;
     mXPrecision = other->mXPrecision;
     mYPrecision = other->mYPrecision;
     mDownTime = other->mDownTime;
-    mPointerIds = other->mPointerIds;
+    mPointerProperties = other->mPointerProperties;
 
     if (keepHistory) {
         mSampleEventTimes = other->mSampleEventTimes;
@@ -484,9 +500,9 @@
 }
 
 ssize_t MotionEvent::findPointerIndex(int32_t pointerId) const {
-    size_t pointerCount = mPointerIds.size();
+    size_t pointerCount = mPointerProperties.size();
     for (size_t i = 0; i < pointerCount; i++) {
-        if (mPointerIds.itemAt(i) == pointerId) {
+        if (mPointerProperties.itemAt(i).id == pointerId) {
             return i;
         }
     }
@@ -583,21 +599,25 @@
     mFlags = parcel->readInt32();
     mEdgeFlags = parcel->readInt32();
     mMetaState = parcel->readInt32();
+    mButtonState = parcel->readInt32();
     mXOffset = parcel->readFloat();
     mYOffset = parcel->readFloat();
     mXPrecision = parcel->readFloat();
     mYPrecision = parcel->readFloat();
     mDownTime = parcel->readInt64();
 
-    mPointerIds.clear();
-    mPointerIds.setCapacity(pointerCount);
+    mPointerProperties.clear();
+    mPointerProperties.setCapacity(pointerCount);
     mSampleEventTimes.clear();
     mSampleEventTimes.setCapacity(sampleCount);
     mSamplePointerCoords.clear();
     mSamplePointerCoords.setCapacity(sampleCount * pointerCount);
 
     for (size_t i = 0; i < pointerCount; i++) {
-        mPointerIds.push(parcel->readInt32());
+        mPointerProperties.push();
+        PointerProperties& properties = mPointerProperties.editTop();
+        properties.id = parcel->readInt32();
+        properties.toolType = parcel->readInt32();
     }
 
     while (sampleCount-- > 0) {
@@ -614,7 +634,7 @@
 }
 
 status_t MotionEvent::writeToParcel(Parcel* parcel) const {
-    size_t pointerCount = mPointerIds.size();
+    size_t pointerCount = mPointerProperties.size();
     size_t sampleCount = mSampleEventTimes.size();
 
     parcel->writeInt32(pointerCount);
@@ -626,6 +646,7 @@
     parcel->writeInt32(mFlags);
     parcel->writeInt32(mEdgeFlags);
     parcel->writeInt32(mMetaState);
+    parcel->writeInt32(mButtonState);
     parcel->writeFloat(mXOffset);
     parcel->writeFloat(mYOffset);
     parcel->writeFloat(mXPrecision);
@@ -633,7 +654,9 @@
     parcel->writeInt64(mDownTime);
 
     for (size_t i = 0; i < pointerCount; i++) {
-        parcel->writeInt32(mPointerIds.itemAt(i));
+        const PointerProperties& properties = mPointerProperties.itemAt(i);
+        parcel->writeInt32(properties.id);
+        parcel->writeInt32(properties.toolType);
     }
 
     const PointerCoords* pc = mSamplePointerCoords.array();
diff --git a/libs/ui/InputTransport.cpp b/libs/ui/InputTransport.cpp
index 93d0d1f..ffdfe66 100644
--- a/libs/ui/InputTransport.cpp
+++ b/libs/ui/InputTransport.cpp
@@ -366,6 +366,7 @@
         int32_t flags,
         int32_t edgeFlags,
         int32_t metaState,
+        int32_t buttonState,
         float xOffset,
         float yOffset,
         float xPrecision,
@@ -373,16 +374,17 @@
         nsecs_t downTime,
         nsecs_t eventTime,
         size_t pointerCount,
-        const int32_t* pointerIds,
+        const PointerProperties* pointerProperties,
         const PointerCoords* pointerCoords) {
 #if DEBUG_TRANSPORT_ACTIONS
     LOGD("channel '%s' publisher ~ publishMotionEvent: deviceId=%d, source=0x%x, "
-            "action=0x%x, flags=0x%x, edgeFlags=0x%x, metaState=0x%x, xOffset=%f, yOffset=%f, "
+            "action=0x%x, flags=0x%x, edgeFlags=0x%x, metaState=0x%x, buttonState=0x%x, "
+            "xOffset=%f, yOffset=%f, "
             "xPrecision=%f, yPrecision=%f, downTime=%lld, eventTime=%lld, "
             "pointerCount=%d",
             mChannel->getName().string(),
-            deviceId, source, action, flags, edgeFlags, metaState, xOffset, yOffset,
-            xPrecision, yPrecision, downTime, eventTime, pointerCount);
+            deviceId, source, action, flags, edgeFlags, metaState, buttonState,
+            xOffset, yOffset, xPrecision, yPrecision, downTime, eventTime, pointerCount);
 #endif
 
     if (pointerCount > MAX_POINTERS || pointerCount < 1) {
@@ -400,6 +402,7 @@
     mSharedMessage->motion.flags = flags;
     mSharedMessage->motion.edgeFlags = edgeFlags;
     mSharedMessage->motion.metaState = metaState;
+    mSharedMessage->motion.buttonState = buttonState;
     mSharedMessage->motion.xOffset = xOffset;
     mSharedMessage->motion.yOffset = yOffset;
     mSharedMessage->motion.xPrecision = xPrecision;
@@ -411,7 +414,7 @@
     mSharedMessage->motion.sampleData[0].eventTime = eventTime;
 
     for (size_t i = 0; i < pointerCount; i++) {
-        mSharedMessage->motion.pointerIds[i] = pointerIds[i];
+        mSharedMessage->motion.pointerProperties[i].copyFrom(pointerProperties[i]);
         mSharedMessage->motion.sampleData[0].coords[i].copyFrom(pointerCoords[i]);
     }
 
@@ -694,6 +697,7 @@
             mSharedMessage->motion.flags,
             mSharedMessage->motion.edgeFlags,
             mSharedMessage->motion.metaState,
+            mSharedMessage->motion.buttonState,
             mSharedMessage->motion.xOffset,
             mSharedMessage->motion.yOffset,
             mSharedMessage->motion.xPrecision,
@@ -701,7 +705,7 @@
             mSharedMessage->motion.downTime,
             mSharedMessage->motion.sampleData[0].eventTime,
             mSharedMessage->motion.pointerCount,
-            mSharedMessage->motion.pointerIds,
+            mSharedMessage->motion.pointerProperties,
             mSharedMessage->motion.sampleData[0].coords);
 
     size_t sampleCount = mSharedMessage->motion.sampleCount;
diff --git a/libs/ui/tests/InputEvent_test.cpp b/libs/ui/tests/InputEvent_test.cpp
index b77489e..e48d5b7 100644
--- a/libs/ui/tests/InputEvent_test.cpp
+++ b/libs/ui/tests/InputEvent_test.cpp
@@ -232,7 +232,14 @@
 const float MotionEventTest::Y_OFFSET = 1.1f;
 
 void MotionEventTest::initializeEventWithHistory(MotionEvent* event) {
-    int32_t pointerIds[] = { 1, 2 };
+    PointerProperties pointerProperties[2];
+    pointerProperties[0].clear();
+    pointerProperties[0].id = 1;
+    pointerProperties[0].toolType = AMOTION_EVENT_TOOL_TYPE_FINGER;
+    pointerProperties[1].clear();
+    pointerProperties[1].id = 2;
+    pointerProperties[1].toolType = AMOTION_EVENT_TOOL_TYPE_STYLUS;
+
     PointerCoords pointerCoords[2];
     pointerCoords[0].clear();
     pointerCoords[0].setAxisValue(AMOTION_EVENT_AXIS_X, 10);
@@ -256,10 +263,10 @@
     pointerCoords[1].setAxisValue(AMOTION_EVENT_AXIS_ORIENTATION, 28);
     event->initialize(2, AINPUT_SOURCE_TOUCHSCREEN, AMOTION_EVENT_ACTION_MOVE,
             AMOTION_EVENT_FLAG_WINDOW_IS_OBSCURED,
-            AMOTION_EVENT_EDGE_FLAG_TOP, AMETA_ALT_ON,
+            AMOTION_EVENT_EDGE_FLAG_TOP, AMETA_ALT_ON, AMOTION_EVENT_BUTTON_PRIMARY,
             X_OFFSET, Y_OFFSET, 2.0f, 2.1f,
             ARBITRARY_DOWN_TIME, ARBITRARY_EVENT_TIME,
-            2, pointerIds, pointerCoords);
+            2, pointerProperties, pointerCoords);
 
     pointerCoords[0].setAxisValue(AMOTION_EVENT_AXIS_X, 110);
     pointerCoords[0].setAxisValue(AMOTION_EVENT_AXIS_Y, 111);
@@ -311,6 +318,7 @@
     ASSERT_EQ(AMOTION_EVENT_FLAG_WINDOW_IS_OBSCURED, event->getFlags());
     ASSERT_EQ(AMOTION_EVENT_EDGE_FLAG_TOP, event->getEdgeFlags());
     ASSERT_EQ(AMETA_ALT_ON, event->getMetaState());
+    ASSERT_EQ(AMOTION_EVENT_BUTTON_PRIMARY, event->getButtonState());
     ASSERT_EQ(X_OFFSET, event->getXOffset());
     ASSERT_EQ(Y_OFFSET, event->getYOffset());
     ASSERT_EQ(2.0f, event->getXPrecision());
@@ -319,7 +327,9 @@
 
     ASSERT_EQ(2U, event->getPointerCount());
     ASSERT_EQ(1, event->getPointerId(0));
+    ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_FINGER, event->getToolType(0));
     ASSERT_EQ(2, event->getPointerId(1));
+    ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_STYLUS, event->getToolType(1));
 
     ASSERT_EQ(2U, event->getHistorySize());
 
@@ -534,19 +544,20 @@
     const float ROTATION = ARC * 2;
 
     const size_t pointerCount = 11;
-    int pointerIds[pointerCount];
+    PointerProperties pointerProperties[pointerCount];
     PointerCoords pointerCoords[pointerCount];
     for (size_t i = 0; i < pointerCount; i++) {
         float angle = float(i * ARC * PI_180);
-        pointerIds[i] = i;
+        pointerProperties[i].clear();
+        pointerProperties[i].id = i;
         pointerCoords[i].clear();
         pointerCoords[i].setAxisValue(AMOTION_EVENT_AXIS_X, sinf(angle) * RADIUS + 3);
         pointerCoords[i].setAxisValue(AMOTION_EVENT_AXIS_Y, -cosf(angle) * RADIUS + 2);
         pointerCoords[i].setAxisValue(AMOTION_EVENT_AXIS_ORIENTATION, angle);
     }
     MotionEvent event;
-    event.initialize(0, 0, AMOTION_EVENT_ACTION_MOVE, 0, 0, 0,
-            0, 0, 0, 0, 0, 0, pointerCount, pointerIds, pointerCoords);
+    event.initialize(0, 0, AMOTION_EVENT_ACTION_MOVE, 0, 0, 0, 0,
+            0, 0, 0, 0, 0, 0, pointerCount, pointerProperties, pointerCoords);
     float originalRawX = 0 + 3;
     float originalRawY = -RADIUS + 2;
 
diff --git a/libs/ui/tests/InputPublisherAndConsumer_test.cpp b/libs/ui/tests/InputPublisherAndConsumer_test.cpp
index 6e18a4f..fcc4cad 100644
--- a/libs/ui/tests/InputPublisherAndConsumer_test.cpp
+++ b/libs/ui/tests/InputPublisherAndConsumer_test.cpp
@@ -156,13 +156,19 @@
     const int32_t flags = AMOTION_EVENT_FLAG_WINDOW_IS_OBSCURED;
     const int32_t edgeFlags = AMOTION_EVENT_EDGE_FLAG_TOP;
     const int32_t metaState = AMETA_ALT_LEFT_ON | AMETA_ALT_ON;
+    const int32_t buttonState = AMOTION_EVENT_BUTTON_PRIMARY;
     const float xOffset = -10;
     const float yOffset = -20;
     const float xPrecision = 0.25;
     const float yPrecision = 0.5;
     const nsecs_t downTime = 3;
     const size_t pointerCount = 3;
-    const int32_t pointerIds[pointerCount] = { 2, 0, 1 };
+    PointerProperties pointerProperties[pointerCount];
+    for (size_t i = 0; i < pointerCount; i++) {
+        pointerProperties[i].clear();
+        pointerProperties[i].id = (i + 2) % pointerCount;
+        pointerProperties[i].toolType = AMOTION_EVENT_TOOL_TYPE_FINGER;
+    }
 
     Vector<nsecs_t> sampleEventTimes;
     Vector<PointerCoords> samplePointerCoords;
@@ -186,8 +192,9 @@
     }
 
     status = mPublisher->publishMotionEvent(deviceId, source, action, flags, edgeFlags,
-            metaState, xOffset, yOffset, xPrecision, yPrecision,
-            downTime, sampleEventTimes[0], pointerCount, pointerIds, samplePointerCoords.array());
+            metaState, buttonState, xOffset, yOffset, xPrecision, yPrecision,
+            downTime, sampleEventTimes[0], pointerCount,
+            pointerProperties, samplePointerCoords.array());
     ASSERT_EQ(OK, status)
             << "publisher publishMotionEvent should return OK";
 
@@ -234,6 +241,7 @@
     EXPECT_EQ(flags, motionEvent->getFlags());
     EXPECT_EQ(edgeFlags, motionEvent->getEdgeFlags());
     EXPECT_EQ(metaState, motionEvent->getMetaState());
+    EXPECT_EQ(buttonState, motionEvent->getButtonState());
     EXPECT_EQ(xPrecision, motionEvent->getXPrecision());
     EXPECT_EQ(yPrecision, motionEvent->getYPrecision());
     EXPECT_EQ(downTime, motionEvent->getDownTime());
@@ -243,7 +251,8 @@
 
     for (size_t i = 0; i < pointerCount; i++) {
         SCOPED_TRACE(i);
-        EXPECT_EQ(pointerIds[i], motionEvent->getPointerId(i));
+        EXPECT_EQ(pointerProperties[i].id, motionEvent->getPointerId(i));
+        EXPECT_EQ(pointerProperties[i].toolType, motionEvent->getToolType(i));
     }
 
     for (size_t sampleIndex = 0; sampleIndex < lastSampleIndex; sampleIndex++) {
@@ -352,17 +361,20 @@
     ASSERT_NO_FATAL_FAILURE(Initialize());
 
     const size_t pointerCount = 1;
-    int32_t pointerIds[pointerCount] = { 0 };
+    PointerProperties pointerProperties[pointerCount];
     PointerCoords pointerCoords[pointerCount];
-    pointerCoords[0].clear();
+    for (size_t i = 0; i < pointerCount; i++) {
+        pointerProperties[i].clear();
+        pointerCoords[i].clear();
+    }
 
-    status = mPublisher->publishMotionEvent(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-            pointerCount, pointerIds, pointerCoords);
+    status = mPublisher->publishMotionEvent(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+            pointerCount, pointerProperties, pointerCoords);
     ASSERT_EQ(OK, status)
             << "publisher publishMotionEvent should return OK";
 
-    status = mPublisher->publishMotionEvent(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-            pointerCount, pointerIds, pointerCoords);
+    status = mPublisher->publishMotionEvent(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+            pointerCount, pointerProperties, pointerCoords);
     ASSERT_EQ(INVALID_OPERATION, status)
             << "publisher publishMotionEvent should return INVALID_OPERATION because ";
                     "the publisher was not reset";
@@ -373,11 +385,11 @@
     ASSERT_NO_FATAL_FAILURE(Initialize());
 
     const size_t pointerCount = 0;
-    int32_t pointerIds[pointerCount];
+    PointerProperties pointerProperties[pointerCount];
     PointerCoords pointerCoords[pointerCount];
 
-    status = mPublisher->publishMotionEvent(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-            pointerCount, pointerIds, pointerCoords);
+    status = mPublisher->publishMotionEvent(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+            pointerCount, pointerProperties, pointerCoords);
     ASSERT_EQ(BAD_VALUE, status)
             << "publisher publishMotionEvent should return BAD_VALUE";
 }
@@ -387,11 +399,15 @@
     ASSERT_NO_FATAL_FAILURE(Initialize());
 
     const size_t pointerCount = MAX_POINTERS + 1;
-    int32_t pointerIds[pointerCount];
+    PointerProperties pointerProperties[pointerCount];
     PointerCoords pointerCoords[pointerCount];
+    for (size_t i = 0; i < pointerCount; i++) {
+        pointerProperties[i].clear();
+        pointerCoords[i].clear();
+    }
 
-    status = mPublisher->publishMotionEvent(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-            pointerCount, pointerIds, pointerCoords);
+    status = mPublisher->publishMotionEvent(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+            pointerCount, pointerProperties, pointerCoords);
     ASSERT_EQ(BAD_VALUE, status)
             << "publisher publishMotionEvent should return BAD_VALUE";
 }
@@ -432,11 +448,15 @@
     ASSERT_NO_FATAL_FAILURE(Initialize());
 
     const size_t pointerCount = MAX_POINTERS;
-    int32_t pointerIds[pointerCount];
+    PointerProperties pointerProperties[pointerCount];
     PointerCoords pointerCoords[pointerCount];
+    for (size_t i = 0; i < pointerCount; i++) {
+        pointerProperties[i].clear();
+        pointerCoords[i].clear();
+    }
 
     status = mPublisher->publishMotionEvent(0, 0, AMOTION_EVENT_ACTION_DOWN,
-            0, 0, 0, 0, 0, 0, 0, 0, 0, pointerCount, pointerIds, pointerCoords);
+            0, 0, 0, 0, 0, 0, 0, 0, 0, 0, pointerCount, pointerProperties, pointerCoords);
     ASSERT_EQ(OK, status);
 
     status = mPublisher->appendMotionSample(0, pointerCoords);
@@ -449,11 +469,15 @@
     ASSERT_NO_FATAL_FAILURE(Initialize());
 
     const size_t pointerCount = MAX_POINTERS;
-    int32_t pointerIds[pointerCount];
+    PointerProperties pointerProperties[pointerCount];
     PointerCoords pointerCoords[pointerCount];
+    for (size_t i = 0; i < pointerCount; i++) {
+        pointerProperties[i].clear();
+        pointerCoords[i].clear();
+    }
 
     status = mPublisher->publishMotionEvent(0, 0, AMOTION_EVENT_ACTION_MOVE,
-            0, 0, 0, 0, 0, 0, 0, 0, 0, pointerCount, pointerIds, pointerCoords);
+            0, 0, 0, 0, 0, 0, 0, 0, 0, 0, pointerCount, pointerProperties, pointerCoords);
     ASSERT_EQ(OK, status);
 
     status = mPublisher->sendDispatchSignal();
@@ -476,11 +500,15 @@
     ASSERT_NO_FATAL_FAILURE(Initialize());
 
     const size_t pointerCount = MAX_POINTERS;
-    int32_t pointerIds[pointerCount];
+    PointerProperties pointerProperties[pointerCount];
     PointerCoords pointerCoords[pointerCount];
+    for (size_t i = 0; i < pointerCount; i++) {
+        pointerProperties[i].clear();
+        pointerCoords[i].clear();
+    }
 
     status = mPublisher->publishMotionEvent(0, 0, AMOTION_EVENT_ACTION_MOVE,
-            0, 0, 0, 0, 0, 0, 0, 0, 0, pointerCount, pointerIds, pointerCoords);
+            0, 0, 0, 0, 0, 0, 0, 0, 0, 0, pointerCount, pointerProperties, pointerCoords);
     ASSERT_EQ(OK, status);
 
     for (int count = 1;; count++) {