Add a re-parent function to re-parent a specific child.
This is similar to reparentChildren, but the reparentChild will
only re-parent a specific child to the new parent and not all
children.
Test: Added test in Transaction_test for reparentChild.
Change-Id: I4275e0d5f1d5601b489956753c78a56d1a5d4c1c
diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp
index e92565f..c406f74 100755
--- a/services/surfaceflinger/Layer.cpp
+++ b/services/surfaceflinger/Layer.cpp
@@ -2625,6 +2625,44 @@
return true;
}
+bool Layer::reparentChild(const sp<IBinder>& newParentHandle, const sp<IBinder>& childHandle) {
+ if (newParentHandle == nullptr || childHandle == nullptr) {
+ return false;
+ }
+
+ auto handle = static_cast<Handle*>(newParentHandle.get());
+ sp<Layer> newParent = handle->owner.promote();
+ if (newParent == nullptr) {
+ ALOGE("Unable to promote Layer handle");
+ return false;
+ }
+
+ handle = static_cast<Handle*>(childHandle.get());
+ sp<Layer> child = handle->owner.promote();
+ if (child == nullptr) {
+ ALOGE("Unable to promote child Layer handle");
+ return false;
+ }
+
+ if (mCurrentChildren.indexOf(child) < 0) {
+ ALOGE("Child layer is not child of current layer");
+ return false;
+ }
+
+ sp<Client> parentClient(mClientRef.promote());
+ sp<Client> childClient(child->mClientRef.promote());
+ sp<Client> newParentClient(newParent->mClientRef.promote());
+
+ if (parentClient != childClient || childClient != newParentClient) {
+ ALOGE("Current layer, child layer, and new parent layer must have the same client");
+ return false;
+ }
+
+ newParent->addChild(child);
+ mCurrentChildren.remove(child);
+ return true;
+}
+
bool Layer::detachChildren() {
traverseInZOrder(LayerVector::StateSet::Drawing, [this](Layer* child) {
if (child == this) {
diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h
index f7b82e4..f94833b 100644
--- a/services/surfaceflinger/Layer.h
+++ b/services/surfaceflinger/Layer.h
@@ -241,6 +241,7 @@
bool setOverrideScalingMode(int32_t overrideScalingMode);
void setInfo(uint32_t type, uint32_t appId);
bool reparentChildren(const sp<IBinder>& layer);
+ bool reparentChild(const sp<IBinder>& newParentHandle, const sp<IBinder>& childHandle);
bool detachChildren();
// If we have received a new buffer this frame, we will pass its surface
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index 6a01f30..4b079d6 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -3103,6 +3103,13 @@
// We don't trigger a traversal here because if no other state is
// changed, we don't want this to cause any more work
}
+ // Always re-parent the children that explicitly requested to get
+ // re-parented before the general re-parent of all children.
+ if (what & layer_state_t::eReparentChild) {
+ if (layer->reparentChild(s.parentHandleForChild, s.childHandle)) {
+ flags |= eTransactionNeeded|eTraversalNeeded;
+ }
+ }
if (what & layer_state_t::eReparentChildren) {
if (layer->reparentChildren(s.reparentHandle)) {
flags |= eTransactionNeeded|eTraversalNeeded;
diff --git a/services/surfaceflinger/SurfaceFlinger_hwc1.cpp b/services/surfaceflinger/SurfaceFlinger_hwc1.cpp
index a92e1f9..71aa52d 100644
--- a/services/surfaceflinger/SurfaceFlinger_hwc1.cpp
+++ b/services/surfaceflinger/SurfaceFlinger_hwc1.cpp
@@ -2679,6 +2679,13 @@
// We don't trigger a traversal here because if no other state is
// changed, we don't want this to cause any more work
}
+ // Always re-parent the children that explicitly requested to get
+ // re-parented before the general re-parent of all children.
+ if (what & layer_state_t::eReparentChild) {
+ if (layer->reparentChild(s.parentHandleForChild, s.childHandle)) {
+ flags |= eTransactionNeeded|eTraversalNeeded;
+ }
+ }
if (what & layer_state_t::eReparentChildren) {
if (layer->reparentChildren(s.reparentHandle)) {
flags |= eTransactionNeeded|eTraversalNeeded;
diff --git a/services/surfaceflinger/tests/Transaction_test.cpp b/services/surfaceflinger/tests/Transaction_test.cpp
index 4ce14f8..aef5a5f 100644
--- a/services/surfaceflinger/tests/Transaction_test.cpp
+++ b/services/surfaceflinger/tests/Transaction_test.cpp
@@ -1123,4 +1123,33 @@
fillSurfaceRGBA8(mFGSurfaceControl, 0, 255, 0);
}
+TEST_F(ChildLayerTest, ReparentChild) {
+ SurfaceComposerClient::openGlobalTransaction();
+ mChild->show();
+ mChild->setPosition(10, 10);
+ mFGSurfaceControl->setPosition(64, 64);
+ SurfaceComposerClient::closeGlobalTransaction(true);
+
+ {
+ ScreenCapture::captureScreen(&mCapture);
+ // Top left of foreground must now be visible
+ mCapture->expectFGColor(64, 64);
+ // But 10 pixels in we should see the child surface
+ mCapture->expectChildColor(74, 74);
+ // And 10 more pixels we should be back to the foreground surface
+ mCapture->expectFGColor(84, 84);
+ }
+ mFGSurfaceControl->reparentChild(mBGSurfaceControl->getHandle(), mChild->getHandle());
+ {
+ ScreenCapture::captureScreen(&mCapture);
+ mCapture->expectFGColor(64, 64);
+ // In reparenting we should have exposed the entire foreground surface.
+ mCapture->expectFGColor(74, 74);
+ // And the child layer should now begin at 10, 10 (since the BG
+ // layer is at (0, 0)).
+ mCapture->expectBGColor(9, 9);
+ mCapture->expectChildColor(10, 10);
+ }
+}
+
}