chaviw | 5e1e8f2 | 2020-07-10 12:46:21 -0700 | [diff] [blame^] | 1 | /* |
| 2 | * Copyright (C) 2020 The Android Open Source Project |
| 3 | * |
| 4 | * Licensed under the Apache License, Version 2.0 (the "License"); |
| 5 | * you may not use this file except in compliance with the License. |
| 6 | * You may obtain a copy of the License at |
| 7 | * |
| 8 | * http://www.apache.org/licenses/LICENSE-2.0 |
| 9 | * |
| 10 | * Unless required by applicable law or agreed to in writing, software |
| 11 | * distributed under the License is distributed on an "AS IS" BASIS, |
| 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| 13 | * See the License for the specific language governing permissions and |
| 14 | * limitations under the License. |
| 15 | */ |
| 16 | |
| 17 | #pragma clang diagnostic push |
| 18 | #pragma clang diagnostic ignored "-Wconversion" |
| 19 | |
| 20 | #include "LayerTransactionTest.h" |
| 21 | |
| 22 | namespace android { |
| 23 | |
| 24 | class DetachChildren : public LayerTransactionTest { |
| 25 | protected: |
| 26 | virtual void SetUp() { |
| 27 | LayerTransactionTest::SetUp(); |
| 28 | |
| 29 | mMainSurface = createLayer(String8("Main Test Surface"), mMainSurfaceBounds.width(), |
| 30 | mMainSurfaceBounds.height(), 0, mBlackBgSurface.get()); |
| 31 | |
| 32 | ASSERT_TRUE(mMainSurface != nullptr); |
| 33 | ASSERT_TRUE(mMainSurface->isValid()); |
| 34 | |
| 35 | TransactionUtils::fillSurfaceRGBA8(mMainSurface, mMainSurfaceColor); |
| 36 | |
| 37 | asTransaction([&](Transaction& t) { |
| 38 | t.setLayer(mMainSurface, INT32_MAX - 1) |
| 39 | .setPosition(mMainSurface, mMainSurfaceBounds.left, mMainSurfaceBounds.top) |
| 40 | .show(mMainSurface); |
| 41 | }); |
| 42 | } |
| 43 | |
| 44 | virtual void TearDown() { |
| 45 | LayerTransactionTest::TearDown(); |
| 46 | mMainSurface = 0; |
| 47 | } |
| 48 | |
| 49 | sp<SurfaceControl> mMainSurface; |
| 50 | Color mMainSurfaceColor = {195, 63, 63, 255}; |
| 51 | Rect mMainSurfaceBounds = Rect(64, 64, 128, 128); |
| 52 | std::unique_ptr<ScreenCapture> mCapture; |
| 53 | }; |
| 54 | |
| 55 | TEST_F(DetachChildren, RelativesAreNotDetached) { |
| 56 | Color relativeColor = {10, 10, 10, 255}; |
| 57 | Rect relBounds = Rect(64, 64, 74, 74); |
| 58 | |
| 59 | sp<SurfaceControl> relative = |
| 60 | createLayer(String8("relativeTestSurface"), relBounds.width(), relBounds.height(), 0); |
| 61 | TransactionUtils::fillSurfaceRGBA8(relative, relativeColor); |
| 62 | |
| 63 | Transaction{} |
| 64 | .setRelativeLayer(relative, mMainSurface->getHandle(), 1) |
| 65 | .setPosition(relative, relBounds.left, relBounds.top) |
| 66 | .apply(); |
| 67 | |
| 68 | { |
| 69 | // The relative should be on top of the FG control. |
| 70 | mCapture = screenshot(); |
| 71 | mCapture->expectColor(relBounds, relativeColor); |
| 72 | } |
| 73 | Transaction{}.detachChildren(mMainSurface).apply(); |
| 74 | |
| 75 | { |
| 76 | // Nothing should change at this point. |
| 77 | mCapture = screenshot(); |
| 78 | mCapture->expectColor(relBounds, relativeColor); |
| 79 | } |
| 80 | |
| 81 | Transaction{}.hide(relative).apply(); |
| 82 | |
| 83 | { |
| 84 | // Ensure that the relative was actually hidden, rather than |
| 85 | // being left in the detached but visible state. |
| 86 | mCapture = screenshot(); |
| 87 | mCapture->expectColor(mMainSurfaceBounds, mMainSurfaceColor); |
| 88 | } |
| 89 | } |
| 90 | |
| 91 | TEST_F(DetachChildren, DetachChildrenSameClient) { |
| 92 | Color childColor = {200, 200, 200, 255}; |
| 93 | Rect childBounds = Rect(74, 74, 84, 84); |
| 94 | sp<SurfaceControl> child = createLayer(String8("Child surface"), childBounds.width(), |
| 95 | childBounds.height(), 0, mMainSurface.get()); |
| 96 | ASSERT_TRUE(child->isValid()); |
| 97 | |
| 98 | TransactionUtils::fillSurfaceRGBA8(child, childColor); |
| 99 | |
| 100 | asTransaction([&](Transaction& t) { |
| 101 | t.show(child); |
| 102 | t.setPosition(child, childBounds.left - mMainSurfaceBounds.left, |
| 103 | childBounds.top - mMainSurfaceBounds.top); |
| 104 | }); |
| 105 | |
| 106 | { |
| 107 | mCapture = screenshot(); |
| 108 | // Expect main color around the child surface |
| 109 | mCapture->expectBorder(childBounds, mMainSurfaceColor); |
| 110 | mCapture->expectColor(childBounds, childColor); |
| 111 | } |
| 112 | |
| 113 | asTransaction([&](Transaction& t) { t.detachChildren(mMainSurface); }); |
| 114 | |
| 115 | asTransaction([&](Transaction& t) { t.hide(child); }); |
| 116 | |
| 117 | // Since the child has the same client as the parent, it will not get |
| 118 | // detached and will be hidden. |
| 119 | { |
| 120 | mCapture = screenshot(); |
| 121 | mCapture->expectColor(mMainSurfaceBounds, mMainSurfaceColor); |
| 122 | } |
| 123 | } |
| 124 | |
| 125 | TEST_F(DetachChildren, DetachChildrenDifferentClient) { |
| 126 | Color childColor = {200, 200, 200, 255}; |
| 127 | Rect childBounds = Rect(74, 74, 84, 84); |
| 128 | |
| 129 | sp<SurfaceComposerClient> newComposerClient = new SurfaceComposerClient; |
| 130 | sp<SurfaceControl> childNewClient = |
| 131 | createSurface(newComposerClient, "New Child Test Surface", childBounds.width(), |
| 132 | childBounds.height(), PIXEL_FORMAT_RGBA_8888, 0, mMainSurface.get()); |
| 133 | ASSERT_TRUE(childNewClient->isValid()); |
| 134 | |
| 135 | TransactionUtils::fillSurfaceRGBA8(childNewClient, childColor); |
| 136 | |
| 137 | asTransaction([&](Transaction& t) { |
| 138 | t.show(childNewClient); |
| 139 | t.setPosition(childNewClient, childBounds.left - mMainSurfaceBounds.left, |
| 140 | childBounds.top - mMainSurfaceBounds.top); |
| 141 | }); |
| 142 | |
| 143 | { |
| 144 | mCapture = screenshot(); |
| 145 | // Expect main color around the child surface |
| 146 | mCapture->expectBorder(childBounds, mMainSurfaceColor); |
| 147 | mCapture->expectColor(childBounds, childColor); |
| 148 | } |
| 149 | |
| 150 | asTransaction([&](Transaction& t) { t.detachChildren(mMainSurface); }); |
| 151 | |
| 152 | asTransaction([&](Transaction& t) { t.hide(childNewClient); }); |
| 153 | |
| 154 | // Nothing should have changed. |
| 155 | { |
| 156 | mCapture = screenshot(); |
| 157 | mCapture->expectBorder(childBounds, mMainSurfaceColor); |
| 158 | mCapture->expectColor(childBounds, childColor); |
| 159 | } |
| 160 | } |
| 161 | |
| 162 | TEST_F(DetachChildren, DetachChildrenThenAttach) { |
| 163 | Color childColor = {200, 200, 200, 255}; |
| 164 | Rect childBounds = Rect(74, 74, 84, 84); |
| 165 | |
| 166 | sp<SurfaceComposerClient> newComposerClient = new SurfaceComposerClient; |
| 167 | sp<SurfaceControl> childNewClient = |
| 168 | createSurface(newComposerClient, "New Child Test Surface", childBounds.width(), |
| 169 | childBounds.height(), PIXEL_FORMAT_RGBA_8888, 0, mMainSurface.get()); |
| 170 | ASSERT_TRUE(childNewClient->isValid()); |
| 171 | |
| 172 | TransactionUtils::fillSurfaceRGBA8(childNewClient, childColor); |
| 173 | |
| 174 | Transaction() |
| 175 | .show(childNewClient) |
| 176 | .setPosition(childNewClient, childBounds.left - mMainSurfaceBounds.left, |
| 177 | childBounds.top - mMainSurfaceBounds.top) |
| 178 | .apply(); |
| 179 | |
| 180 | { |
| 181 | mCapture = screenshot(); |
| 182 | // Expect main color around the child surface |
| 183 | mCapture->expectBorder(childBounds, mMainSurfaceColor); |
| 184 | mCapture->expectColor(childBounds, childColor); |
| 185 | } |
| 186 | |
| 187 | Transaction().detachChildren(mMainSurface).apply(); |
| 188 | Transaction().hide(childNewClient).apply(); |
| 189 | |
| 190 | // Nothing should have changed. |
| 191 | { |
| 192 | mCapture = screenshot(); |
| 193 | mCapture->expectBorder(childBounds, mMainSurfaceColor); |
| 194 | mCapture->expectColor(childBounds, childColor); |
| 195 | } |
| 196 | |
| 197 | Color newParentColor = Color::RED; |
| 198 | Rect newParentBounds = Rect(20, 20, 52, 52); |
| 199 | sp<SurfaceControl> newParentSurface = |
| 200 | createLayer(String8("New Parent Surface"), newParentBounds.width(), |
| 201 | newParentBounds.height(), 0); |
| 202 | TransactionUtils::fillSurfaceRGBA8(newParentSurface, newParentColor); |
| 203 | Transaction() |
| 204 | .setLayer(newParentSurface, INT32_MAX - 1) |
| 205 | .show(newParentSurface) |
| 206 | .setPosition(newParentSurface, newParentBounds.left, newParentBounds.top) |
| 207 | .reparent(childNewClient, newParentSurface->getHandle()) |
| 208 | .apply(); |
| 209 | { |
| 210 | mCapture = screenshot(); |
| 211 | // Child is now hidden. |
| 212 | mCapture->expectColor(newParentBounds, newParentColor); |
| 213 | } |
| 214 | } |
| 215 | |
| 216 | TEST_F(DetachChildren, DetachChildrenWithDeferredTransaction) { |
| 217 | Color childColor = {200, 200, 200, 255}; |
| 218 | Rect childBounds = Rect(74, 74, 84, 84); |
| 219 | |
| 220 | sp<SurfaceComposerClient> newComposerClient = new SurfaceComposerClient; |
| 221 | sp<SurfaceControl> childNewClient = |
| 222 | createSurface(newComposerClient, "New Child Test Surface", childBounds.width(), |
| 223 | childBounds.height(), PIXEL_FORMAT_RGBA_8888, 0, mMainSurface.get()); |
| 224 | ASSERT_TRUE(childNewClient->isValid()); |
| 225 | |
| 226 | TransactionUtils::fillSurfaceRGBA8(childNewClient, childColor); |
| 227 | |
| 228 | Transaction() |
| 229 | .show(childNewClient) |
| 230 | .setPosition(childNewClient, childBounds.left - mMainSurfaceBounds.left, |
| 231 | childBounds.top - mMainSurfaceBounds.top) |
| 232 | .apply(); |
| 233 | |
| 234 | { |
| 235 | mCapture = screenshot(); |
| 236 | mCapture->expectBorder(childBounds, mMainSurfaceColor); |
| 237 | mCapture->expectColor(childBounds, childColor); |
| 238 | } |
| 239 | |
| 240 | Transaction() |
| 241 | .deferTransactionUntil_legacy(childNewClient, mMainSurface->getHandle(), |
| 242 | mMainSurface->getSurface()->getNextFrameNumber()) |
| 243 | .apply(); |
| 244 | Transaction().detachChildren(mMainSurface).apply(); |
| 245 | ASSERT_NO_FATAL_FAILURE(fillBufferQueueLayerColor(mMainSurface, Color::RED, |
| 246 | mMainSurfaceBounds.width(), |
| 247 | mMainSurfaceBounds.height())); |
| 248 | |
| 249 | // BufferLayer can still dequeue buffers even though there's a detached layer with a |
| 250 | // deferred transaction. |
| 251 | { |
| 252 | SCOPED_TRACE("new buffer"); |
| 253 | mCapture = screenshot(); |
| 254 | mCapture->expectBorder(childBounds, Color::RED); |
| 255 | mCapture->expectColor(childBounds, childColor); |
| 256 | } |
| 257 | } |
| 258 | |
| 259 | TEST_F(DetachChildren, ReparentParentLayerOfDetachedChildren) { |
| 260 | Color childColor = {200, 200, 200, 255}; |
| 261 | Rect childBounds = Rect(74, 74, 94, 94); |
| 262 | Color grandchildColor = Color::RED; |
| 263 | Rect grandchildBounds = Rect(80, 80, 90, 90); |
| 264 | |
| 265 | sp<SurfaceComposerClient> newClient1 = new SurfaceComposerClient; |
| 266 | sp<SurfaceComposerClient> newClient2 = new SurfaceComposerClient; |
| 267 | |
| 268 | sp<SurfaceControl> childSurface = |
| 269 | createSurface(newClient1, "Child surface", childBounds.width(), childBounds.height(), |
| 270 | PIXEL_FORMAT_RGBA_8888, 0, mMainSurface.get()); |
| 271 | sp<SurfaceControl> grandchildSurface = |
| 272 | createSurface(newClient2, "Grandchild Surface", grandchildBounds.width(), |
| 273 | grandchildBounds.height(), PIXEL_FORMAT_RGBA_8888, 0, childSurface.get()); |
| 274 | |
| 275 | TransactionUtils::fillSurfaceRGBA8(childSurface, childColor); |
| 276 | TransactionUtils::fillSurfaceRGBA8(grandchildSurface, grandchildColor); |
| 277 | |
| 278 | Transaction() |
| 279 | .show(childSurface) |
| 280 | .show(grandchildSurface) |
| 281 | .setPosition(childSurface, childBounds.left - mMainSurfaceBounds.left, |
| 282 | childBounds.top - mMainSurfaceBounds.top) |
| 283 | .setPosition(grandchildSurface, grandchildBounds.left - childBounds.left, |
| 284 | grandchildBounds.top - childBounds.top) |
| 285 | .apply(); |
| 286 | |
| 287 | { |
| 288 | mCapture = screenshot(); |
| 289 | mCapture->expectBorder(childBounds, mMainSurfaceColor); |
| 290 | mCapture->expectBorder(grandchildBounds, childColor); |
| 291 | mCapture->expectColor(grandchildBounds, grandchildColor); |
| 292 | } |
| 293 | |
| 294 | Transaction().detachChildren(childSurface).apply(); |
| 295 | |
| 296 | // Remove main surface offscreen |
| 297 | Transaction().reparent(mMainSurface, nullptr).apply(); |
| 298 | { |
| 299 | mCapture = screenshot(); |
| 300 | mCapture->expectColor(mMainSurfaceBounds, Color::BLACK); |
| 301 | } |
| 302 | |
| 303 | Transaction().reparent(mMainSurface, mBlackBgSurface->getHandle()).apply(); |
| 304 | { |
| 305 | mCapture = screenshot(); |
| 306 | mCapture->expectBorder(childBounds, mMainSurfaceColor); |
| 307 | mCapture->expectBorder(grandchildBounds, childColor); |
| 308 | mCapture->expectColor(grandchildBounds, grandchildColor); |
| 309 | } |
| 310 | |
| 311 | Transaction().hide(grandchildSurface).apply(); |
| 312 | |
| 313 | // grandchild is still detached so it will not hide |
| 314 | { |
| 315 | mCapture = screenshot(); |
| 316 | mCapture->expectBorder(childBounds, mMainSurfaceColor); |
| 317 | mCapture->expectBorder(grandchildBounds, childColor); |
| 318 | mCapture->expectColor(grandchildBounds, grandchildColor); |
| 319 | } |
| 320 | } |
| 321 | |
| 322 | } // namespace android |