Clear cooked state and touch spots when disabled

Bug: 177403144
Test: Touch spots are gone after pressing power button with a finger on
the display.

Change-Id: I8c7991d728ba3ff84f982185ac6a30d1e2cae33e
diff --git a/services/inputflinger/reader/mapper/TouchInputMapper.cpp b/services/inputflinger/reader/mapper/TouchInputMapper.cpp
index fb30b88..b748bfe 100644
--- a/services/inputflinger/reader/mapper/TouchInputMapper.cpp
+++ b/services/inputflinger/reader/mapper/TouchInputMapper.cpp
@@ -608,8 +608,7 @@
         if (hasStylus()) {
             mSource |= AINPUT_SOURCE_STYLUS;
         }
-    } else if (mParameters.deviceType == Parameters::DeviceType::TOUCH_SCREEN &&
-               mParameters.hasAssociatedDisplay) {
+    } else if (isTouchScreen()) {
         mSource = AINPUT_SOURCE_TOUCHSCREEN;
         mDeviceMode = DeviceMode::DIRECT;
         if (hasStylus()) {
@@ -1453,8 +1452,11 @@
 void TouchInputMapper::processRawTouches(bool timeout) {
     if (mDeviceMode == DeviceMode::DISABLED) {
         // Drop all input if the device is disabled.
+        cancelTouch(mCurrentRawState.when);
         mCurrentRawState.clear();
         mRawStatesPending.clear();
+        mCurrentCookedState.clear();
+        updateTouchSpots();
         return;
     }
 
@@ -1586,17 +1588,7 @@
 
         dispatchPointerUsage(when, policyFlags, pointerUsage);
     } else {
-        if (mDeviceMode == DeviceMode::DIRECT && mConfig.showTouches &&
-            mPointerController != nullptr) {
-            mPointerController->setPresentation(PointerControllerInterface::Presentation::SPOT);
-            mPointerController->fade(PointerControllerInterface::Transition::GRADUAL);
-
-            mPointerController->setButtonState(mCurrentRawState.buttonState);
-            mPointerController->setSpots(mCurrentCookedState.cookedPointerData.pointerCoords,
-                                         mCurrentCookedState.cookedPointerData.idToIndex,
-                                         mCurrentCookedState.cookedPointerData.touchingIdBits,
-                                         mViewport.displayId);
-        }
+        updateTouchSpots();
 
         if (!mCurrentMotionAborted) {
             dispatchButtonRelease(when, policyFlags);
@@ -1625,6 +1617,33 @@
     mLastCookedState.copyFrom(mCurrentCookedState);
 }
 
+void TouchInputMapper::updateTouchSpots() {
+    if (!mConfig.showTouches || mPointerController == nullptr) {
+        return;
+    }
+
+    // Update touch spots when this is a touchscreen even when it's not enabled so that we can
+    // clear touch spots.
+    if (mDeviceMode != DeviceMode::DIRECT &&
+        (mDeviceMode != DeviceMode::DISABLED || !isTouchScreen())) {
+        return;
+    }
+
+    mPointerController->setPresentation(PointerControllerInterface::Presentation::SPOT);
+    mPointerController->fade(PointerControllerInterface::Transition::GRADUAL);
+
+    mPointerController->setButtonState(mCurrentRawState.buttonState);
+    mPointerController->setSpots(mCurrentCookedState.cookedPointerData.pointerCoords,
+                                 mCurrentCookedState.cookedPointerData.idToIndex,
+                                 mCurrentCookedState.cookedPointerData.touchingIdBits,
+                                 mViewport.displayId);
+}
+
+bool TouchInputMapper::isTouchScreen() {
+    return mParameters.deviceType == Parameters::DeviceType::TOUCH_SCREEN &&
+            mParameters.hasAssociatedDisplay;
+}
+
 void TouchInputMapper::applyExternalStylusButtonState(nsecs_t when) {
     if (mDeviceMode == DeviceMode::DIRECT && hasExternalStylus() && mExternalStylusId != -1) {
         mCurrentRawState.buttonState |= mExternalStylusState.buttons;
diff --git a/services/inputflinger/reader/mapper/TouchInputMapper.h b/services/inputflinger/reader/mapper/TouchInputMapper.h
index df6581d..6621825 100644
--- a/services/inputflinger/reader/mapper/TouchInputMapper.h
+++ b/services/inputflinger/reader/mapper/TouchInputMapper.h
@@ -757,6 +757,12 @@
                              PointerCoords* outCoords, const uint32_t* outIdToIndex,
                              BitSet32 idBits) const;
 
+    // Returns if this touch device is a touch screen with an associated display.
+    bool isTouchScreen();
+    // Updates touch spots if they are enabled. Should only be used when this device is a
+    // touchscreen.
+    void updateTouchSpots();
+
     bool isPointInsideSurface(int32_t x, int32_t y);
     const VirtualKey* findVirtualKeyHit(int32_t x, int32_t y);
 
diff --git a/services/inputflinger/tests/InputReader_test.cpp b/services/inputflinger/tests/InputReader_test.cpp
index 91d5864..36da8dd 100644
--- a/services/inputflinger/tests/InputReader_test.cpp
+++ b/services/inputflinger/tests/InputReader_test.cpp
@@ -7362,6 +7362,57 @@
     mFakeListener->assertNotifyMotionWasNotCalled();
 }
 
+TEST_F(MultiTouchInputMapperTest, Process_DeactivateViewport_AbortTouches) {
+    addConfigurationProperty("touch.deviceType", "touchScreen");
+    mFakePolicy->addDisplayViewport(DISPLAY_ID, DISPLAY_WIDTH, DISPLAY_HEIGHT,
+                                    DISPLAY_ORIENTATION_0, true /*isActive*/, UNIQUE_ID, NO_PORT,
+                                    ViewportType::INTERNAL);
+    std::optional<DisplayViewport> optionalDisplayViewport =
+            mFakePolicy->getDisplayViewportByUniqueId(UNIQUE_ID);
+    ASSERT_TRUE(optionalDisplayViewport.has_value());
+    DisplayViewport displayViewport = *optionalDisplayViewport;
+
+    configureDevice(InputReaderConfiguration::CHANGE_DISPLAY_INFO);
+    prepareAxes(POSITION);
+    MultiTouchInputMapper& mapper = addMapperAndConfigure<MultiTouchInputMapper>();
+
+    // Finger down
+    int32_t x = 100, y = 100;
+    processPosition(mapper, x, y);
+    processSync(mapper);
+
+    NotifyMotionArgs motionArgs;
+    ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs));
+    EXPECT_EQ(AMOTION_EVENT_ACTION_DOWN, motionArgs.action);
+
+    // Deactivate display viewport
+    displayViewport.isActive = false;
+    ASSERT_TRUE(mFakePolicy->updateViewport(displayViewport));
+    configureDevice(InputReaderConfiguration::CHANGE_DISPLAY_INFO);
+
+    // Finger move
+    x += 10, y += 10;
+    processPosition(mapper, x, y);
+    processSync(mapper);
+
+    ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs));
+    EXPECT_EQ(AMOTION_EVENT_ACTION_CANCEL, motionArgs.action);
+
+    // Reactivate display viewport
+    displayViewport.isActive = true;
+    ASSERT_TRUE(mFakePolicy->updateViewport(displayViewport));
+    configureDevice(InputReaderConfiguration::CHANGE_DISPLAY_INFO);
+
+    // Finger move again
+    x += 10, y += 10;
+    processPosition(mapper, x, y);
+    processSync(mapper);
+
+    // Gesture is aborted, so events after display is activated won't be dispatched until there is
+    // no pointer on the touch device.
+    mFakeListener->assertNotifyMotionWasNotCalled();
+}
+
 TEST_F(MultiTouchInputMapperTest, Process_Pointer_ShowTouches) {
     // Setup the first touch screen device.
     prepareAxes(POSITION | ID | SLOT);