Added input support for cloned layers
This was done with a few changes:
1. Added a layerId in the input info so the InputInfo objects can be
uniquely identified as per layer
2. When setting input info in InputDispatcher, compare InputInfo objects
using layer id instead of input token.
3. Updated the crop region for layers based on the cloned hierarchy so
the input is cropped to the correct region.
Bug: 140756730
Test: InputDispatcherMultiWindowSameTokenTests
Change-Id: I980f5d29d091fecb407f5cd6a289615505800927
diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp
index 35fc4be..e7572f0 100644
--- a/services/surfaceflinger/Layer.cpp
+++ b/services/surfaceflinger/Layer.cpp
@@ -2025,6 +2025,7 @@
InputWindowInfo Layer::fillInputInfo() {
InputWindowInfo info = mDrawingState.inputInfo;
+ info.id = sequence;
if (info.displayId == ADISPLAY_ID_NONE) {
info.displayId = getLayerStack();
@@ -2081,9 +2082,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;
}
@@ -2119,10 +2140,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() {
@@ -2157,9 +2174,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);
}
@@ -2198,7 +2212,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();
@@ -2206,11 +2237,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);
}
}
@@ -2220,12 +2251,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);
}