Merge "Added input support for cloned layers"
diff --git a/include/input/InputWindow.h b/include/input/InputWindow.h
index f852cd0..cbd64d5 100644
--- a/include/input/InputWindow.h
+++ b/include/input/InputWindow.h
@@ -119,7 +119,11 @@
     /* These values are filled in by the WM and passed through SurfaceFlinger
      * unless specified otherwise.
      */
+    // This value should NOT be used to uniquely identify the window. There may be different
+    // input windows that have the same token.
     sp<IBinder> token;
+    // This uniquely identifies the input window.
+    int32_t id = 0;
     std::string name;
     int32_t layoutParamsFlags;
     int32_t layoutParamsType;
@@ -203,6 +207,8 @@
 
     sp<IBinder> getToken() const;
 
+    int32_t getId() const { return mInfo.id; }
+
     sp<IBinder> getApplicationToken() {
         return mInfo.applicationInfo.token;
     }
diff --git a/libs/input/InputWindow.cpp b/libs/input/InputWindow.cpp
index ec28757..74a0505 100644
--- a/libs/input/InputWindow.cpp
+++ b/libs/input/InputWindow.cpp
@@ -73,6 +73,7 @@
     status_t s = output.writeStrongBinder(token);
     if (s != OK) return s;
 
+    output.writeInt32(id);
     output.writeString8(String8(name.c_str()));
     output.writeInt32(layoutParamsFlags);
     output.writeInt32(layoutParamsType);
@@ -116,6 +117,7 @@
     }
 
     ret.token = token;
+    ret.id = from.readInt32();
     ret.name = from.readString8().c_str();
     ret.layoutParamsFlags = from.readInt32();
     ret.layoutParamsType = from.readInt32();
diff --git a/libs/input/tests/InputWindow_test.cpp b/libs/input/tests/InputWindow_test.cpp
index 6db18ab..cdc81d2 100644
--- a/libs/input/tests/InputWindow_test.cpp
+++ b/libs/input/tests/InputWindow_test.cpp
@@ -40,6 +40,7 @@
     sp<IBinder> touchableRegionCropHandle = new BBinder();
     InputWindowInfo i;
     i.token = new BBinder();
+    i.id = 1;
     i.name = "Foobar";
     i.layoutParamsFlags = 7;
     i.layoutParamsType = 39;
@@ -72,6 +73,7 @@
     p.setDataPosition(0);
     InputWindowInfo i2 = InputWindowInfo::read(p);
     ASSERT_EQ(i.token, i2.token);
+    ASSERT_EQ(i.id, i2.id);
     ASSERT_EQ(i.name, i2.name);
     ASSERT_EQ(i.layoutParamsFlags, i2.layoutParamsFlags);
     ASSERT_EQ(i.layoutParamsType, i2.layoutParamsType);
diff --git a/services/inputflinger/dispatcher/InputDispatcher.cpp b/services/inputflinger/dispatcher/InputDispatcher.cpp
index 5a49b5e..116625c 100644
--- a/services/inputflinger/dispatcher/InputDispatcher.cpp
+++ b/services/inputflinger/dispatcher/InputDispatcher.cpp
@@ -240,6 +240,18 @@
     return removed;
 }
 
+static bool haveSameToken(const sp<InputWindowHandle>& first, const sp<InputWindowHandle>& second) {
+    if (first == second) {
+        return true;
+    }
+
+    if (first == nullptr || second == nullptr) {
+        return false;
+    }
+
+    return first->getToken() == second->getToken();
+}
+
 // --- InputDispatcherThread ---
 
 class InputDispatcher::InputDispatcherThread : public Thread {
@@ -3278,9 +3290,9 @@
     // Since we compare the pointer of input window handles across window updates, we need
     // to make sure the handle object for the same window stays unchanged across updates.
     const std::vector<sp<InputWindowHandle>>& oldHandles = getWindowHandlesLocked(displayId);
-    std::unordered_map<sp<IBinder>, sp<InputWindowHandle>, IBinderHash> oldHandlesByTokens;
+    std::unordered_map<int32_t /*id*/, sp<InputWindowHandle>> oldHandlesById;
     for (const sp<InputWindowHandle>& handle : oldHandles) {
-        oldHandlesByTokens[handle->getToken()] = handle;
+        oldHandlesById[handle->getId()] = handle;
     }
 
     std::vector<sp<InputWindowHandle>> newHandles;
@@ -3311,8 +3323,8 @@
             continue;
         }
 
-        if (oldHandlesByTokens.find(handle->getToken()) != oldHandlesByTokens.end()) {
-            const sp<InputWindowHandle> oldHandle = oldHandlesByTokens.at(handle->getToken());
+        if (oldHandlesById.find(handle->getId()) != oldHandlesById.end()) {
+            const sp<InputWindowHandle>& oldHandle = oldHandlesById.at(handle->getId());
             oldHandle->updateFrom(handle);
             newHandles.push_back(oldHandle);
         } else {
@@ -3370,7 +3382,7 @@
         sp<InputWindowHandle> oldFocusedWindowHandle =
                 getValueByKey(mFocusedWindowHandlesByDisplay, displayId);
 
-        if (oldFocusedWindowHandle != newFocusedWindowHandle) {
+        if (!haveSameToken(oldFocusedWindowHandle, newFocusedWindowHandle)) {
             if (oldFocusedWindowHandle != nullptr) {
                 if (DEBUG_FOCUS) {
                     ALOGD("Focus left window: %s in display %" PRId32,
diff --git a/services/inputflinger/tests/InputDispatcher_test.cpp b/services/inputflinger/tests/InputDispatcher_test.cpp
index b4d7608..c25122c 100644
--- a/services/inputflinger/tests/InputDispatcher_test.cpp
+++ b/services/inputflinger/tests/InputDispatcher_test.cpp
@@ -526,6 +526,7 @@
         mInfo.applicationInfo = *inputApplicationHandle->getInfo();
 
         mInfo.token = token;
+        mInfo.id = 0;
         mInfo.name = name;
         mInfo.layoutParamsFlags = 0;
         mInfo.layoutParamsType = InputWindowInfo::TYPE_APPLICATION;
@@ -564,6 +565,13 @@
 
     void setLayoutParamFlags(int32_t flags) { mInfo.layoutParamsFlags = flags; }
 
+    void setId(int32_t id) { mInfo.id = id; }
+
+    void setWindowScale(float xScale, float yScale) {
+        mInfo.windowXScale = xScale;
+        mInfo.windowYScale = yScale;
+    }
+
     void consumeKeyDown(int32_t expectedDisplayId, int32_t expectedFlags = 0) {
         consumeEvent(AINPUT_EVENT_TYPE_KEY, AKEY_EVENT_ACTION_DOWN, expectedDisplayId,
                      expectedFlags);
@@ -586,12 +594,21 @@
                                      expectedFlags);
     }
 
+    InputEvent* consume() {
+        if (mInputReceiver == nullptr) {
+            return nullptr;
+        }
+        return mInputReceiver->consume();
+    }
+
     void assertNoEvents() {
         ASSERT_NE(mInputReceiver, nullptr)
                 << "Call 'assertNoEvents' on a window with an InputReceiver";
         mInputReceiver->assertNoEvents();
     }
 
+    sp<IBinder> getToken() { return mInfo.token; }
+
 private:
     std::unique_ptr<FakeInputReceiver> mInputReceiver;
 };
@@ -667,6 +684,10 @@
 static NotifyMotionArgs generateMotionArgs(int32_t action, int32_t source, int32_t displayId,
                                            const std::vector<PointF>& points) {
     size_t pointerCount = points.size();
+    if (action == AMOTION_EVENT_ACTION_DOWN || action == AMOTION_EVENT_ACTION_UP) {
+        EXPECT_EQ(1U, pointerCount) << "Actions DOWN and UP can only contain a single pointer";
+    }
+
     PointerProperties pointerProperties[pointerCount];
     PointerCoords pointerCoords[pointerCount];
 
@@ -1291,4 +1312,132 @@
     mFakePolicy->assertOnPointerDownWasNotCalled();
 }
 
+// These tests ensures we can send touch events to a single client when there are multiple input
+// windows that point to the same client token.
+class InputDispatcherMultiWindowSameTokenTests : public InputDispatcherTest {
+    virtual void SetUp() override {
+        InputDispatcherTest::SetUp();
+
+        sp<FakeApplicationHandle> application = new FakeApplicationHandle();
+        mWindow1 = new FakeWindowHandle(application, mDispatcher, "Fake Window 1",
+                                        ADISPLAY_ID_DEFAULT);
+        // Adding FLAG_NOT_TOUCH_MODAL otherwise all taps will go to the top most window.
+        // We also need FLAG_SPLIT_TOUCH or we won't be able to get touches for both windows.
+        mWindow1->setLayoutParamFlags(InputWindowInfo::FLAG_NOT_TOUCH_MODAL |
+                                      InputWindowInfo::FLAG_SPLIT_TOUCH);
+        mWindow1->setId(0);
+        mWindow1->setFrame(Rect(0, 0, 100, 100));
+
+        mWindow2 = new FakeWindowHandle(application, mDispatcher, "Fake Window 2",
+                                        ADISPLAY_ID_DEFAULT, mWindow1->getToken());
+        mWindow2->setLayoutParamFlags(InputWindowInfo::FLAG_NOT_TOUCH_MODAL |
+                                      InputWindowInfo::FLAG_SPLIT_TOUCH);
+        mWindow2->setId(1);
+        mWindow2->setFrame(Rect(100, 100, 200, 200));
+
+        mDispatcher->setInputWindows({mWindow1, mWindow2}, ADISPLAY_ID_DEFAULT);
+    }
+
+protected:
+    sp<FakeWindowHandle> mWindow1;
+    sp<FakeWindowHandle> mWindow2;
+
+    // Helper function to convert the point from screen coordinates into the window's space
+    static PointF getPointInWindow(const InputWindowInfo* windowInfo, const PointF& point) {
+        float x = windowInfo->windowXScale * (point.x - windowInfo->frameLeft);
+        float y = windowInfo->windowYScale * (point.y - windowInfo->frameTop);
+        return {x, y};
+    }
+
+    void consumeMotionEvent(const sp<FakeWindowHandle>& window, int32_t expectedAction,
+                            const std::vector<PointF>& points) {
+        std::string name = window->mName;
+        InputEvent* event = window->consume();
+
+        ASSERT_NE(nullptr, event) << name.c_str()
+                                  << ": consumer should have returned non-NULL event.";
+
+        ASSERT_EQ(AINPUT_EVENT_TYPE_MOTION, event->getType())
+                << name.c_str() << "expected " << inputEventTypeToString(AINPUT_EVENT_TYPE_MOTION)
+                << " event, got " << inputEventTypeToString(event->getType()) << " event";
+
+        const MotionEvent& motionEvent = static_cast<const MotionEvent&>(*event);
+        EXPECT_EQ(expectedAction, motionEvent.getAction());
+
+        for (size_t i = 0; i < points.size(); i++) {
+            float expectedX = points[i].x;
+            float expectedY = points[i].y;
+
+            EXPECT_EQ(expectedX, motionEvent.getX(i))
+                    << "expected " << expectedX << " for x[" << i << "] coord of " << name.c_str()
+                    << ", got " << motionEvent.getX(i);
+            EXPECT_EQ(expectedY, motionEvent.getY(i))
+                    << "expected " << expectedY << " for y[" << i << "] coord of " << name.c_str()
+                    << ", got " << motionEvent.getY(i);
+        }
+    }
+};
+
+TEST_F(InputDispatcherMultiWindowSameTokenTests, SingleTouchSameScale) {
+    // Touch Window 1
+    PointF touchedPoint = {10, 10};
+    PointF expectedPoint = getPointInWindow(mWindow1->getInfo(), touchedPoint);
+
+    NotifyMotionArgs motionArgs =
+            generateMotionArgs(AMOTION_EVENT_ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN,
+                               ADISPLAY_ID_DEFAULT, {touchedPoint});
+    mDispatcher->notifyMotion(&motionArgs);
+    consumeMotionEvent(mWindow1, AMOTION_EVENT_ACTION_DOWN, {expectedPoint});
+
+    // Release touch on Window 1
+    motionArgs = generateMotionArgs(AMOTION_EVENT_ACTION_UP, AINPUT_SOURCE_TOUCHSCREEN,
+                                    ADISPLAY_ID_DEFAULT, {touchedPoint});
+    mDispatcher->notifyMotion(&motionArgs);
+    // consume the UP event
+    consumeMotionEvent(mWindow1, AMOTION_EVENT_ACTION_UP, {expectedPoint});
+
+    // Touch Window 2
+    touchedPoint = {150, 150};
+    expectedPoint = getPointInWindow(mWindow2->getInfo(), touchedPoint);
+
+    motionArgs = generateMotionArgs(AMOTION_EVENT_ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN,
+                                    ADISPLAY_ID_DEFAULT, {touchedPoint});
+    mDispatcher->notifyMotion(&motionArgs);
+
+    // Consuming from window1 since it's the window that has the InputReceiver
+    consumeMotionEvent(mWindow1, AMOTION_EVENT_ACTION_DOWN, {expectedPoint});
+}
+
+TEST_F(InputDispatcherMultiWindowSameTokenTests, SingleTouchDifferentScale) {
+    mWindow2->setWindowScale(0.5f, 0.5f);
+
+    // Touch Window 1
+    PointF touchedPoint = {10, 10};
+    PointF expectedPoint = getPointInWindow(mWindow1->getInfo(), touchedPoint);
+
+    NotifyMotionArgs motionArgs =
+            generateMotionArgs(AMOTION_EVENT_ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN,
+                               ADISPLAY_ID_DEFAULT, {touchedPoint});
+    mDispatcher->notifyMotion(&motionArgs);
+    consumeMotionEvent(mWindow1, AMOTION_EVENT_ACTION_DOWN, {expectedPoint});
+
+    // Release touch on Window 1
+    motionArgs = generateMotionArgs(AMOTION_EVENT_ACTION_UP, AINPUT_SOURCE_TOUCHSCREEN,
+                                    ADISPLAY_ID_DEFAULT, {touchedPoint});
+    mDispatcher->notifyMotion(&motionArgs);
+    // consume the UP event
+    consumeMotionEvent(mWindow1, AMOTION_EVENT_ACTION_UP, {expectedPoint});
+
+    // Touch Window 2
+    touchedPoint = {150, 150};
+    expectedPoint = getPointInWindow(mWindow2->getInfo(), touchedPoint);
+
+    motionArgs = generateMotionArgs(AMOTION_EVENT_ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN,
+                                    ADISPLAY_ID_DEFAULT, {touchedPoint});
+    mDispatcher->notifyMotion(&motionArgs);
+
+    // Consuming from window1 since it's the window that has the InputReceiver
+    consumeMotionEvent(mWindow1, AMOTION_EVENT_ACTION_DOWN, {expectedPoint});
+}
+
 } // namespace android::inputdispatcher
diff --git a/services/surfaceflinger/BufferLayer.cpp b/services/surfaceflinger/BufferLayer.cpp
index 054acc5..bdecdb7 100644
--- a/services/surfaceflinger/BufferLayer.cpp
+++ b/services/surfaceflinger/BufferLayer.cpp
@@ -770,17 +770,20 @@
 
     // After buffer info is updated, the drawingState from the real layer needs to be copied into
     // the cloned. This is because some properties of drawingState can change when latchBuffer is
-    // called. However, copying the drawingState would also overwrite the cloned layer's relatives.
-    // Therefore, temporarily store the relatives so they can be set in the cloned drawingState
-    // again.
+    // called. However, copying the drawingState would also overwrite the cloned layer's relatives
+    // and touchableRegionCrop. Therefore, temporarily store the relatives so they can be set in
+    // the cloned drawingState again.
     wp<Layer> tmpZOrderRelativeOf = mDrawingState.zOrderRelativeOf;
     SortedVector<wp<Layer>> tmpZOrderRelatives = mDrawingState.zOrderRelatives;
+    wp<Layer> tmpTouchableRegionCrop = mDrawingState.touchableRegionCrop;
+    InputWindowInfo tmpInputInfo = mDrawingState.inputInfo;
+
     mDrawingState = clonedFrom->mDrawingState;
-    // TODO: (b/140756730) Ignore input for now since InputDispatcher doesn't support multiple
-    // InputWindows per client token yet.
-    mDrawingState.inputInfo.token = nullptr;
+
+    mDrawingState.touchableRegionCrop = tmpTouchableRegionCrop;
     mDrawingState.zOrderRelativeOf = tmpZOrderRelativeOf;
     mDrawingState.zOrderRelatives = tmpZOrderRelatives;
+    mDrawingState.inputInfo = tmpInputInfo;
 }
 
 } // namespace android
diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp
index 57aa7f9..c7eb9c3 100644
--- a/services/surfaceflinger/Layer.cpp
+++ b/services/surfaceflinger/Layer.cpp
@@ -2030,6 +2030,7 @@
 
 InputWindowInfo Layer::fillInputInfo() {
     InputWindowInfo info = mDrawingState.inputInfo;
+    info.id = sequence;
 
     if (info.displayId == ADISPLAY_ID_NONE) {
         info.displayId = getLayerStack();
@@ -2086,9 +2087,29 @@
         info.touchableRegion = info.touchableRegion.intersect(Rect{cropLayer->mScreenBounds});
     }
 
+    // If the layer is a clone, we need to crop the input region to cloned root to prevent
+    // touches from going outside the cloned area.
+    if (isClone()) {
+        sp<Layer> clonedRoot = getClonedRoot();
+        if (clonedRoot != nullptr) {
+            Rect rect(clonedRoot->mScreenBounds);
+            info.touchableRegion = info.touchableRegion.intersect(rect);
+        }
+    }
+
     return info;
 }
 
+sp<Layer> Layer::getClonedRoot() {
+    if (mClonedChild != nullptr) {
+        return this;
+    }
+    if (mDrawingParent == nullptr || mDrawingParent.promote() == nullptr) {
+        return nullptr;
+    }
+    return mDrawingParent.promote()->getClonedRoot();
+}
+
 bool Layer::hasInput() const {
     return mDrawingState.inputInfo.token != nullptr;
 }
@@ -2124,10 +2145,6 @@
     // copy drawing state from cloned layer
     mDrawingState = clonedFrom->mDrawingState;
     mClonedFrom = clonedFrom;
-
-    // TODO: (b/140756730) Ignore input for now since InputDispatcher doesn't support multiple
-    // InputWindows per client token yet.
-    mDrawingState.inputInfo.token = nullptr;
 }
 
 void Layer::updateMirrorInfo() {
@@ -2162,9 +2179,6 @@
     if (isClonedFromAlive()) {
         sp<Layer> clonedFrom = getClonedFrom();
         mDrawingState = clonedFrom->mDrawingState;
-        // TODO: (b/140756730) Ignore input for now since InputDispatcher doesn't support multiple
-        // InputWindows per client token yet.
-        mDrawingState.inputInfo.token = nullptr;
         clonedLayersMap.emplace(clonedFrom, this);
     }
 
@@ -2203,7 +2217,24 @@
     }
 }
 
-void Layer::updateClonedRelatives(std::map<sp<Layer>, sp<Layer>> clonedLayersMap) {
+void Layer::updateClonedInputInfo(const std::map<sp<Layer>, sp<Layer>>& clonedLayersMap) {
+    auto cropLayer = mDrawingState.touchableRegionCrop.promote();
+    if (cropLayer != nullptr) {
+        if (clonedLayersMap.count(cropLayer) == 0) {
+            // Real layer had a crop layer but it's not in the cloned hierarchy. Just set to
+            // self as crop layer to avoid going outside bounds.
+            mDrawingState.touchableRegionCrop = this;
+        } else {
+            const sp<Layer>& clonedCropLayer = clonedLayersMap.at(cropLayer);
+            mDrawingState.touchableRegionCrop = clonedCropLayer;
+        }
+    }
+    // Cloned layers shouldn't handle watch outside since their z order is not determined by
+    // WM or the client.
+    mDrawingState.inputInfo.layoutParamsFlags &= ~InputWindowInfo::FLAG_WATCH_OUTSIDE_TOUCH;
+}
+
+void Layer::updateClonedRelatives(const std::map<sp<Layer>, sp<Layer>>& clonedLayersMap) {
     mDrawingState.zOrderRelativeOf = nullptr;
     mDrawingState.zOrderRelatives.clear();
 
@@ -2211,11 +2242,11 @@
         return;
     }
 
-    sp<Layer> clonedFrom = getClonedFrom();
+    const sp<Layer>& clonedFrom = getClonedFrom();
     for (wp<Layer>& relativeWeak : clonedFrom->mDrawingState.zOrderRelatives) {
-        sp<Layer> relative = relativeWeak.promote();
-        auto clonedRelative = clonedLayersMap[relative];
-        if (clonedRelative != nullptr) {
+        const sp<Layer>& relative = relativeWeak.promote();
+        if (clonedLayersMap.count(relative) > 0) {
+            auto& clonedRelative = clonedLayersMap.at(relative);
             mDrawingState.zOrderRelatives.add(clonedRelative);
         }
     }
@@ -2225,12 +2256,14 @@
     // In that case, we treat the layer as if the relativeOf has been removed. This way, it will
     // still traverse the children, but the layer with the missing relativeOf will not be shown
     // on screen.
-    sp<Layer> relativeOf = clonedFrom->mDrawingState.zOrderRelativeOf.promote();
-    sp<Layer> clonedRelativeOf = clonedLayersMap[relativeOf];
-    if (clonedRelativeOf != nullptr) {
+    const sp<Layer>& relativeOf = clonedFrom->mDrawingState.zOrderRelativeOf.promote();
+    if (clonedLayersMap.count(relativeOf) > 0) {
+        const sp<Layer>& clonedRelativeOf = clonedLayersMap.at(relativeOf);
         mDrawingState.zOrderRelativeOf = clonedRelativeOf;
     }
 
+    updateClonedInputInfo(clonedLayersMap);
+
     for (sp<Layer>& child : mDrawingChildren) {
         child->updateClonedRelatives(clonedLayersMap);
     }
diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h
index 843d3ae..d697a6a 100644
--- a/services/surfaceflinger/Layer.h
+++ b/services/surfaceflinger/Layer.h
@@ -497,8 +497,9 @@
     void updateClonedDrawingState(std::map<sp<Layer>, sp<Layer>>& clonedLayersMap);
     void updateClonedChildren(const sp<Layer>& mirrorRoot,
                               std::map<sp<Layer>, sp<Layer>>& clonedLayersMap);
-    void updateClonedRelatives(std::map<sp<Layer>, sp<Layer>> clonedLayersMap);
+    void updateClonedRelatives(const std::map<sp<Layer>, sp<Layer>>& clonedLayersMap);
     void addChildToDrawing(const sp<Layer>& layer);
+    void updateClonedInputInfo(const std::map<sp<Layer>, sp<Layer>>& clonedLayersMap);
 
 public:
     /*
@@ -972,6 +973,10 @@
 
     // Returns true if the layer can draw shadows on its border.
     virtual bool canDrawShadows() const { return true; }
+
+    // Find the root of the cloned hierarchy, this means the first non cloned parent.
+    // This will return null if first non cloned parent is not found.
+    sp<Layer> getClonedRoot();
 };
 
 } // namespace android