Merge "Accurately track the sequence numbers of batched events."
diff --git a/include/ui/InputTransport.h b/include/ui/InputTransport.h
index 46b56ff..1f738cd 100644
--- a/include/ui/InputTransport.h
+++ b/include/ui/InputTransport.h
@@ -306,12 +306,23 @@
 
     // Batched motion events per device and source.
     struct Batch {
-        uint32_t seq;
+        uint32_t seq; // sequence number of last input message batched in the event
         MotionEvent event;
     };
     Vector<Batch> mBatches;
 
+    // Chain of batched sequence numbers.  When multiple input messages are combined into
+    // a batch, we append a record here that associates the last sequence number in the
+    // batch with the previous one.  When the finished signal is sent, we traverse the
+    // chain to individually finish all input messages that were part of the batch.
+    struct SeqChain {
+        uint32_t seq;   // sequence number of batched input message
+        uint32_t chain; // sequence number of previous batched input message
+    };
+    Vector<SeqChain> mSeqChains;
+
     ssize_t findBatch(int32_t deviceId, int32_t source) const;
+    status_t sendUnchainedFinishedSignal(uint32_t seq, bool handled);
 
     static void initializeKeyEvent(KeyEvent* event, const InputMessage* msg);
     static void initializeMotionEvent(MotionEvent* event, const InputMessage* msg);
diff --git a/libs/ui/InputTransport.cpp b/libs/ui/InputTransport.cpp
index 44cb6db..ecb3fb5 100644
--- a/libs/ui/InputTransport.cpp
+++ b/libs/ui/InputTransport.cpp
@@ -401,17 +401,16 @@
             if (batchIndex >= 0) {
                 Batch& batch = mBatches.editItemAt(batchIndex);
                 if (canAppendSamples(&batch.event, &mMsg)) {
-                    // Send finished message for the earlier part of the batch.
-                    // Claim that we handled the event.  (The dispatcher doesn't care either
-                    // way at the moment.)
-                    status_t status = sendFinishedSignal(batch.seq, true);
-                    if (status) {
-                        return status;
-                    }
-
                     // Append to the batch and save the new sequence number for the tail end.
+                    uint32_t chain = batch.seq;
                     appendSamples(&batch.event, &mMsg);
                     batch.seq = mMsg.body.motion.seq;
+
+                    // Update the sequence number chain.
+                    SeqChain seqChain;
+                    seqChain.seq = batch.seq;
+                    seqChain.chain = chain;
+                    mSeqChains.push(seqChain);
 #if DEBUG_TRANSPORT_ACTIONS
                     ALOGD("channel '%s' consumer ~ appended to batch event",
                             mChannel->getName().string());
@@ -486,6 +485,41 @@
         return BAD_VALUE;
     }
 
+    // Send finished signals for the batch sequence chain first.
+    size_t seqChainCount = mSeqChains.size();
+    if (seqChainCount) {
+        uint32_t currentSeq = seq;
+        uint32_t chainSeqs[seqChainCount];
+        size_t chainIndex = 0;
+        for (size_t i = seqChainCount; i-- > 0; ) {
+             const SeqChain& seqChain = mSeqChains.itemAt(i);
+             if (seqChain.seq == currentSeq) {
+                 currentSeq = seqChain.chain;
+                 chainSeqs[chainIndex++] = currentSeq;
+                 mSeqChains.removeAt(i);
+             }
+        }
+        status_t status = OK;
+        while (!status && chainIndex-- > 0) {
+            status = sendUnchainedFinishedSignal(chainSeqs[chainIndex], handled);
+        }
+        if (status) {
+            // An error occurred so at least one signal was not sent, reconstruct the chain.
+            do {
+                SeqChain seqChain;
+                seqChain.seq = chainIndex != 0 ? chainSeqs[chainIndex - 1] : seq;
+                seqChain.chain = chainSeqs[chainIndex];
+                mSeqChains.push(seqChain);
+            } while (chainIndex-- > 0);
+            return status;
+        }
+    }
+
+    // Send finished signal for the last message in the batch.
+    return sendUnchainedFinishedSignal(seq, handled);
+}
+
+status_t InputConsumer::sendUnchainedFinishedSignal(uint32_t seq, bool handled) {
     InputMessage msg;
     msg.header.type = InputMessage::TYPE_FINISHED;
     msg.body.finished.seq = seq;