Merge changes I53f65dae,I4bbfe4c5 into main

* changes:
  Count active touches in MultiTouchMotionAccumulator
  Record last keypress timestamp on physical keyboard while typing
diff --git a/services/inputflinger/reader/InputReader.cpp b/services/inputflinger/reader/InputReader.cpp
index 5766b14..0582649 100644
--- a/services/inputflinger/reader/InputReader.cpp
+++ b/services/inputflinger/reader/InputReader.cpp
@@ -1046,6 +1046,14 @@
     return mReader->mPreventingTouchpadTaps;
 }
 
+void InputReader::ContextImpl::setLastKeyDownTimestamp(nsecs_t when) {
+    mReader->mLastKeyDownTimestamp = when;
+}
+
+nsecs_t InputReader::ContextImpl::getLastKeyDownTimestamp() {
+    return mReader->mLastKeyDownTimestamp;
+}
+
 void InputReader::ContextImpl::disableVirtualKeysUntil(nsecs_t time) {
     // lock is already held by the input loop
     mReader->disableVirtualKeysUntilLocked(time);
diff --git a/services/inputflinger/reader/include/InputReader.h b/services/inputflinger/reader/include/InputReader.h
index 9a297c9..4c78db3 100644
--- a/services/inputflinger/reader/include/InputReader.h
+++ b/services/inputflinger/reader/include/InputReader.h
@@ -158,6 +158,9 @@
         void setPreventingTouchpadTaps(bool prevent) REQUIRES(mReader->mLock)
                 REQUIRES(mLock) override;
         bool isPreventingTouchpadTaps() REQUIRES(mReader->mLock) REQUIRES(mLock) override;
+        void setLastKeyDownTimestamp(nsecs_t when) REQUIRES(mReader->mLock)
+                REQUIRES(mLock) override;
+        nsecs_t getLastKeyDownTimestamp() REQUIRES(mReader->mLock) REQUIRES(mLock) override;
     } mContext;
 
     friend class ContextImpl;
@@ -198,6 +201,9 @@
     // true if tap-to-click on touchpad currently disabled
     bool mPreventingTouchpadTaps GUARDED_BY(mLock){false};
 
+    // records timestamp of the last key press on the physical keyboard
+    nsecs_t mLastKeyDownTimestamp GUARDED_BY(mLock){0};
+
     // low-level input event decoding and device management
     [[nodiscard]] std::list<NotifyArgs> processEventsLocked(const RawEvent* rawEvents, size_t count)
             REQUIRES(mLock);
diff --git a/services/inputflinger/reader/include/InputReaderContext.h b/services/inputflinger/reader/include/InputReaderContext.h
index aed7563..69b2315 100644
--- a/services/inputflinger/reader/include/InputReaderContext.h
+++ b/services/inputflinger/reader/include/InputReaderContext.h
@@ -65,6 +65,9 @@
 
     virtual void setPreventingTouchpadTaps(bool prevent) = 0;
     virtual bool isPreventingTouchpadTaps() = 0;
+
+    virtual void setLastKeyDownTimestamp(nsecs_t when) = 0;
+    virtual nsecs_t getLastKeyDownTimestamp() = 0;
 };
 
 } // namespace android
diff --git a/services/inputflinger/reader/mapper/KeyboardInputMapper.cpp b/services/inputflinger/reader/mapper/KeyboardInputMapper.cpp
index 531fc67..f068cc8 100644
--- a/services/inputflinger/reader/mapper/KeyboardInputMapper.cpp
+++ b/services/inputflinger/reader/mapper/KeyboardInputMapper.cpp
@@ -270,7 +270,7 @@
             keyDown.flags = flags;
             mKeyDowns.push_back(keyDown);
         }
-        onKeyDownProcessed();
+        onKeyDownProcessed(downTime);
     } else {
         // Remove key down.
         if (keyDownIndex) {
@@ -448,8 +448,9 @@
     return out;
 }
 
-void KeyboardInputMapper::onKeyDownProcessed() {
+void KeyboardInputMapper::onKeyDownProcessed(nsecs_t downTime) {
     InputReaderContext& context = *getContext();
+    context.setLastKeyDownTimestamp(downTime);
     if (context.isPreventingTouchpadTaps()) {
         // avoid pinging java service unnecessarily, just fade pointer again if it became visible
         context.fadePointer();
diff --git a/services/inputflinger/reader/mapper/KeyboardInputMapper.h b/services/inputflinger/reader/mapper/KeyboardInputMapper.h
index 09808df..500256b 100644
--- a/services/inputflinger/reader/mapper/KeyboardInputMapper.h
+++ b/services/inputflinger/reader/mapper/KeyboardInputMapper.h
@@ -107,7 +107,7 @@
     void updateLedStateForModifier(LedState& ledState, int32_t led, int32_t modifier, bool reset);
     std::optional<DisplayViewport> findViewport(const InputReaderConfiguration& readerConfig);
     [[nodiscard]] std::list<NotifyArgs> cancelAllDownKeys(nsecs_t when);
-    void onKeyDownProcessed();
+    void onKeyDownProcessed(nsecs_t downTime);
 };
 
 } // namespace android
diff --git a/services/inputflinger/reader/mapper/accumulator/MultiTouchMotionAccumulator.cpp b/services/inputflinger/reader/mapper/accumulator/MultiTouchMotionAccumulator.cpp
index f70be72..b0fc903 100644
--- a/services/inputflinger/reader/mapper/accumulator/MultiTouchMotionAccumulator.cpp
+++ b/services/inputflinger/reader/mapper/accumulator/MultiTouchMotionAccumulator.cpp
@@ -152,6 +152,14 @@
     }
 }
 
+size_t MultiTouchMotionAccumulator::getActiveSlotsCount() const {
+    if (!mUsingSlotsProtocol) {
+        return mCurrentSlot < 0 ? 0 : mCurrentSlot;
+    }
+    return std::count_if(mSlots.begin(), mSlots.end(),
+                         [](const Slot& slot) { return slot.mInUse; });
+}
+
 // --- MultiTouchMotionAccumulator::Slot ---
 
 ToolType MultiTouchMotionAccumulator::Slot::getToolType() const {
diff --git a/services/inputflinger/reader/mapper/accumulator/MultiTouchMotionAccumulator.h b/services/inputflinger/reader/mapper/accumulator/MultiTouchMotionAccumulator.h
index 943dde5..0e3e2bb 100644
--- a/services/inputflinger/reader/mapper/accumulator/MultiTouchMotionAccumulator.h
+++ b/services/inputflinger/reader/mapper/accumulator/MultiTouchMotionAccumulator.h
@@ -77,6 +77,7 @@
     void process(const RawEvent* rawEvent);
     void finishSync();
 
+    size_t getActiveSlotsCount() const;
     inline size_t getSlotCount() const { return mSlots.size(); }
     inline const Slot& getSlot(size_t index) const {
         LOG_ALWAYS_FATAL_IF(index < 0 || index >= mSlots.size(), "Invalid index: %zu", index);
diff --git a/services/inputflinger/tests/Android.bp b/services/inputflinger/tests/Android.bp
index 64e8825..db31ded 100644
--- a/services/inputflinger/tests/Android.bp
+++ b/services/inputflinger/tests/Android.bp
@@ -58,6 +58,7 @@
         "InputReader_test.cpp",
         "InstrumentedInputReader.cpp",
         "LatencyTracker_test.cpp",
+        "MultiTouchMotionAccumulator_test.cpp",
         "NotifyArgs_test.cpp",
         "PointerChoreographer_test.cpp",
         "PreferStylusOverTouch_test.cpp",
diff --git a/services/inputflinger/tests/InputMapperTest.cpp b/services/inputflinger/tests/InputMapperTest.cpp
index dac4ea0..787444c 100644
--- a/services/inputflinger/tests/InputMapperTest.cpp
+++ b/services/inputflinger/tests/InputMapperTest.cpp
@@ -80,9 +80,15 @@
 }
 
 std::list<NotifyArgs> InputMapperUnitTest::process(int32_t type, int32_t code, int32_t value) {
+    nsecs_t when = systemTime(SYSTEM_TIME_MONOTONIC);
+    return process(when, type, code, value);
+}
+
+std::list<NotifyArgs> InputMapperUnitTest::process(nsecs_t when, int32_t type, int32_t code,
+                                                   int32_t value) {
     RawEvent event;
-    event.when = systemTime(SYSTEM_TIME_MONOTONIC);
-    event.readTime = event.when;
+    event.when = when;
+    event.readTime = when;
     event.deviceId = mMapper->getDeviceContext().getEventHubId();
     event.type = type;
     event.code = code;
diff --git a/services/inputflinger/tests/InputMapperTest.h b/services/inputflinger/tests/InputMapperTest.h
index c2ac258..3f9061f 100644
--- a/services/inputflinger/tests/InputMapperTest.h
+++ b/services/inputflinger/tests/InputMapperTest.h
@@ -52,6 +52,7 @@
     void setKeyCodeState(KeyState state, std::set<int> keyCodes);
 
     std::list<NotifyArgs> process(int32_t type, int32_t code, int32_t value);
+    std::list<NotifyArgs> process(nsecs_t when, int32_t type, int32_t code, int32_t value);
 
     MockEventHubInterface mMockEventHub;
     std::shared_ptr<FakePointerController> mFakePointerController;
diff --git a/services/inputflinger/tests/InstrumentedInputReader.h b/services/inputflinger/tests/InstrumentedInputReader.h
index ca85558..e9c7bb4 100644
--- a/services/inputflinger/tests/InstrumentedInputReader.h
+++ b/services/inputflinger/tests/InstrumentedInputReader.h
@@ -106,6 +106,9 @@
         void setPreventingTouchpadTaps(bool prevent) override { mPreventingTouchpadTaps = prevent; }
         bool isPreventingTouchpadTaps() override { return mPreventingTouchpadTaps; }
 
+        void setLastKeyDownTimestamp(nsecs_t when) override { mLastKeyDownTimestamp = when; };
+        nsecs_t getLastKeyDownTimestamp() override { return mLastKeyDownTimestamp; };
+
     private:
         int32_t mGlobalMetaState;
         bool mUpdateGlobalMetaStateWasCalled;
@@ -113,6 +116,7 @@
         std::optional<nsecs_t> mRequestedTimeout;
         std::vector<InputDeviceInfo> mExternalStylusDevices;
         bool mPreventingTouchpadTaps{false};
+        nsecs_t mLastKeyDownTimestamp;
     } mFakeContext;
 
     friend class InputReaderTest;
diff --git a/services/inputflinger/tests/InterfaceMocks.h b/services/inputflinger/tests/InterfaceMocks.h
index 05823cd..7394913 100644
--- a/services/inputflinger/tests/InterfaceMocks.h
+++ b/services/inputflinger/tests/InterfaceMocks.h
@@ -77,6 +77,9 @@
     MOCK_METHOD(void, setPreventingTouchpadTaps, (bool prevent), (override));
     MOCK_METHOD(bool, isPreventingTouchpadTaps, (), (override));
 
+    MOCK_METHOD(void, setLastKeyDownTimestamp, (nsecs_t when));
+    MOCK_METHOD(nsecs_t, getLastKeyDownTimestamp, ());
+
 private:
     int32_t mGeneration = 0;
 };
diff --git a/services/inputflinger/tests/KeyboardInputMapper_test.cpp b/services/inputflinger/tests/KeyboardInputMapper_test.cpp
index 48f5673..2ef7999 100644
--- a/services/inputflinger/tests/KeyboardInputMapper_test.cpp
+++ b/services/inputflinger/tests/KeyboardInputMapper_test.cpp
@@ -26,6 +26,7 @@
 namespace android {
 
 using testing::_;
+using testing::Args;
 using testing::DoAll;
 using testing::Return;
 using testing::SetArgPointee;
@@ -158,4 +159,18 @@
     testTouchpadTapStateForKeys(metaKeys, /* expectPrevent= */ false);
 }
 
+TEST_F(KeyboardInputMapperUnitTest, KeyPressTimestampRecorded) {
+    nsecs_t when = ARBITRARY_TIME;
+    std::vector<int32_t> keyCodes{KEY_0, KEY_A, KEY_LEFTCTRL, KEY_RIGHTALT, KEY_LEFTSHIFT};
+    EXPECT_CALL(mMockInputReaderContext, setLastKeyDownTimestamp)
+            .With(Args<0>(when))
+            .Times(keyCodes.size());
+    for (int32_t keyCode : keyCodes) {
+        process(when, EV_KEY, keyCode, 1);
+        process(when, EV_SYN, SYN_REPORT, 0);
+        process(when, EV_KEY, keyCode, 0);
+        process(when, EV_SYN, SYN_REPORT, 0);
+    }
+}
+
 } // namespace android
diff --git a/services/inputflinger/tests/MultiTouchMotionAccumulator_test.cpp b/services/inputflinger/tests/MultiTouchMotionAccumulator_test.cpp
new file mode 100644
index 0000000..9fa6cdd
--- /dev/null
+++ b/services/inputflinger/tests/MultiTouchMotionAccumulator_test.cpp
@@ -0,0 +1,87 @@
+/*
+ * Copyright 2023 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 "MultiTouchMotionAccumulator.h"
+#include "InputMapperTest.h"
+
+namespace android {
+
+class MultiTouchMotionAccumulatorTest : public InputMapperUnitTest {
+protected:
+    static constexpr size_t SLOT_COUNT = 8;
+
+    MultiTouchMotionAccumulator mMotionAccumulator;
+
+    void processMotionEvent(int32_t type, int32_t code, int32_t value) {
+        RawEvent event;
+        event.when = ARBITRARY_TIME;
+        event.readTime = READ_TIME;
+        event.deviceId = EVENTHUB_ID;
+        event.type = type;
+        event.code = code;
+        event.value = value;
+        mMotionAccumulator.process(&event);
+    }
+};
+
+TEST_F(MultiTouchMotionAccumulatorTest, ActiveSlotCountUsingSlotsProtocol) {
+    mMotionAccumulator.configure(*mDeviceContext, SLOT_COUNT, /*usingSlotsProtocol=*/true);
+    // We expect active slot count to match the touches being tracked
+    // first touch
+    processMotionEvent(EV_ABS, ABS_MT_SLOT, 0);
+    processMotionEvent(EV_ABS, ABS_MT_TRACKING_ID, 123);
+    processMotionEvent(EV_SYN, SYN_REPORT, 0);
+    ASSERT_EQ(1u, mMotionAccumulator.getActiveSlotsCount());
+
+    // second touch
+    processMotionEvent(EV_ABS, ABS_MT_SLOT, 1);
+    processMotionEvent(EV_ABS, ABS_MT_TRACKING_ID, 456);
+    processMotionEvent(EV_SYN, SYN_REPORT, 0);
+    ASSERT_EQ(2u, mMotionAccumulator.getActiveSlotsCount());
+
+    // second lifted
+    processMotionEvent(EV_ABS, ABS_MT_TRACKING_ID, -1);
+    processMotionEvent(EV_SYN, SYN_REPORT, 0);
+    ASSERT_EQ(1u, mMotionAccumulator.getActiveSlotsCount());
+
+    // first lifted
+    processMotionEvent(EV_ABS, ABS_MT_SLOT, 0);
+    processMotionEvent(EV_ABS, ABS_MT_TRACKING_ID, -1);
+    processMotionEvent(EV_SYN, SYN_REPORT, 0);
+    ASSERT_EQ(0u, mMotionAccumulator.getActiveSlotsCount());
+}
+
+TEST_F(MultiTouchMotionAccumulatorTest, ActiveSlotCountNotUsingSlotsProtocol) {
+    mMotionAccumulator.configure(*mDeviceContext, SLOT_COUNT, /*usingSlotsProtocol=*/false);
+
+    // first touch
+    processMotionEvent(EV_ABS, ABS_MT_POSITION_X, 0);
+    processMotionEvent(EV_ABS, ABS_MT_POSITION_Y, 0);
+    processMotionEvent(EV_SYN, SYN_MT_REPORT, 0);
+    ASSERT_EQ(1u, mMotionAccumulator.getActiveSlotsCount());
+
+    // second touch
+    processMotionEvent(EV_ABS, ABS_MT_POSITION_X, 50);
+    processMotionEvent(EV_ABS, ABS_MT_POSITION_Y, 50);
+    processMotionEvent(EV_SYN, SYN_MT_REPORT, 0);
+    ASSERT_EQ(2u, mMotionAccumulator.getActiveSlotsCount());
+
+    // reset
+    mMotionAccumulator.finishSync();
+    ASSERT_EQ(0u, mMotionAccumulator.getActiveSlotsCount());
+}
+
+} // namespace android
diff --git a/services/inputflinger/tests/fuzzers/MapperHelpers.h b/services/inputflinger/tests/fuzzers/MapperHelpers.h
index bdedfdf..e1c0fe2 100644
--- a/services/inputflinger/tests/fuzzers/MapperHelpers.h
+++ b/services/inputflinger/tests/fuzzers/MapperHelpers.h
@@ -360,6 +360,12 @@
 
     void setPreventingTouchpadTaps(bool prevent) {}
     bool isPreventingTouchpadTaps() { return mFdp->ConsumeBool(); };
+
+    void setLastKeyDownTimestamp(nsecs_t when) { mLastKeyDownTimestamp = when; };
+    nsecs_t getLastKeyDownTimestamp() { return mLastKeyDownTimestamp; };
+
+private:
+    nsecs_t mLastKeyDownTimestamp;
 };
 
 template <class Fdp>