| 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{} | 
| Pablo Gamito | 11dcc22 | 2020-09-12 15:49:39 +0000 | [diff] [blame] | 64 |             .setRelativeLayer(relative, mMainSurface, 1) | 
| chaviw | 5e1e8f2 | 2020-07-10 12:46:21 -0700 | [diff] [blame] | 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) | 
| Pablo Gamito | 11dcc22 | 2020-09-12 15:49:39 +0000 | [diff] [blame] | 207 |             .reparent(childNewClient, newParentSurface) | 
| chaviw | 5e1e8f2 | 2020-07-10 12:46:21 -0700 | [diff] [blame] | 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() | 
| Pablo Gamito | 11dcc22 | 2020-09-12 15:49:39 +0000 | [diff] [blame] | 241 |             .deferTransactionUntil_legacy(childNewClient, mMainSurface, | 
| chaviw | 5e1e8f2 | 2020-07-10 12:46:21 -0700 | [diff] [blame] | 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 |  | 
| Vishnu Nair | edbe6d2 | 2020-08-27 11:41:20 -0700 | [diff] [blame] | 259 | /** | 
 | 260 |  * Tests that a deferring transaction on an already detached layer will be dropped gracefully and | 
 | 261 |  * allow the barrier layer to dequeue buffers. | 
 | 262 |  * | 
 | 263 |  * Fixes b/150924737 - buffer cannot be latched because it waits for a detached layer | 
 | 264 |  * to commit its pending states. | 
 | 265 |  */ | 
 | 266 | TEST_F(DetachChildren, DeferredTransactionOnDetachedChildren) { | 
 | 267 |     Color childColor = {200, 200, 200, 255}; | 
 | 268 |     Rect childBounds = Rect(74, 74, 84, 84); | 
 | 269 |  | 
 | 270 |     sp<SurfaceComposerClient> newComposerClient = new SurfaceComposerClient; | 
 | 271 |     sp<SurfaceControl> childNewClient = | 
 | 272 |             createSurface(newComposerClient, "New Child Test Surface", childBounds.width(), | 
 | 273 |                           childBounds.height(), PIXEL_FORMAT_RGBA_8888, 0, mMainSurface.get()); | 
 | 274 |     ASSERT_TRUE(childNewClient->isValid()); | 
 | 275 |  | 
 | 276 |     TransactionUtils::fillSurfaceRGBA8(childNewClient, childColor); | 
 | 277 |  | 
 | 278 |     Transaction() | 
 | 279 |             .show(childNewClient) | 
 | 280 |             .setPosition(childNewClient, childBounds.left - mMainSurfaceBounds.left, | 
 | 281 |                          childBounds.top - mMainSurfaceBounds.top) | 
 | 282 |             .apply(); | 
 | 283 |  | 
 | 284 |     { | 
 | 285 |         mCapture = screenshot(); | 
 | 286 |         mCapture->expectBorder(childBounds, mMainSurfaceColor); | 
 | 287 |         mCapture->expectColor(childBounds, childColor); | 
 | 288 |     } | 
 | 289 |  | 
 | 290 |     Transaction().detachChildren(mMainSurface).apply(); | 
 | 291 |     Transaction() | 
 | 292 |             .setCrop_legacy(childNewClient, {0, 0, childBounds.width(), childBounds.height()}) | 
| Pablo Gamito | 11dcc22 | 2020-09-12 15:49:39 +0000 | [diff] [blame] | 293 |             .deferTransactionUntil_legacy(childNewClient, mMainSurface, | 
| Vishnu Nair | edbe6d2 | 2020-08-27 11:41:20 -0700 | [diff] [blame] | 294 |                                           mMainSurface->getSurface()->getNextFrameNumber()) | 
 | 295 |             .apply(); | 
 | 296 |  | 
 | 297 |     ASSERT_NO_FATAL_FAILURE(fillBufferQueueLayerColor(mMainSurface, Color::RED, | 
 | 298 |                                                       mMainSurfaceBounds.width(), | 
 | 299 |                                                       mMainSurfaceBounds.height())); | 
 | 300 |  | 
 | 301 |     // BufferLayer can still dequeue buffers even though there's a detached layer with a | 
 | 302 |     // deferred transaction. | 
 | 303 |     { | 
 | 304 |         SCOPED_TRACE("new buffer"); | 
 | 305 |         mCapture = screenshot(); | 
 | 306 |         mCapture->expectBorder(childBounds, Color::RED); | 
 | 307 |         mCapture->expectColor(childBounds, childColor); | 
 | 308 |     } | 
 | 309 | } | 
 | 310 |  | 
| chaviw | 5e1e8f2 | 2020-07-10 12:46:21 -0700 | [diff] [blame] | 311 | TEST_F(DetachChildren, ReparentParentLayerOfDetachedChildren) { | 
 | 312 |     Color childColor = {200, 200, 200, 255}; | 
 | 313 |     Rect childBounds = Rect(74, 74, 94, 94); | 
 | 314 |     Color grandchildColor = Color::RED; | 
 | 315 |     Rect grandchildBounds = Rect(80, 80, 90, 90); | 
 | 316 |  | 
 | 317 |     sp<SurfaceComposerClient> newClient1 = new SurfaceComposerClient; | 
 | 318 |     sp<SurfaceComposerClient> newClient2 = new SurfaceComposerClient; | 
 | 319 |  | 
 | 320 |     sp<SurfaceControl> childSurface = | 
 | 321 |             createSurface(newClient1, "Child surface", childBounds.width(), childBounds.height(), | 
 | 322 |                           PIXEL_FORMAT_RGBA_8888, 0, mMainSurface.get()); | 
 | 323 |     sp<SurfaceControl> grandchildSurface = | 
 | 324 |             createSurface(newClient2, "Grandchild Surface", grandchildBounds.width(), | 
 | 325 |                           grandchildBounds.height(), PIXEL_FORMAT_RGBA_8888, 0, childSurface.get()); | 
 | 326 |  | 
 | 327 |     TransactionUtils::fillSurfaceRGBA8(childSurface, childColor); | 
 | 328 |     TransactionUtils::fillSurfaceRGBA8(grandchildSurface, grandchildColor); | 
 | 329 |  | 
 | 330 |     Transaction() | 
 | 331 |             .show(childSurface) | 
 | 332 |             .show(grandchildSurface) | 
 | 333 |             .setPosition(childSurface, childBounds.left - mMainSurfaceBounds.left, | 
 | 334 |                          childBounds.top - mMainSurfaceBounds.top) | 
 | 335 |             .setPosition(grandchildSurface, grandchildBounds.left - childBounds.left, | 
 | 336 |                          grandchildBounds.top - childBounds.top) | 
 | 337 |             .apply(); | 
 | 338 |  | 
 | 339 |     { | 
 | 340 |         mCapture = screenshot(); | 
 | 341 |         mCapture->expectBorder(childBounds, mMainSurfaceColor); | 
 | 342 |         mCapture->expectBorder(grandchildBounds, childColor); | 
 | 343 |         mCapture->expectColor(grandchildBounds, grandchildColor); | 
 | 344 |     } | 
 | 345 |  | 
 | 346 |     Transaction().detachChildren(childSurface).apply(); | 
 | 347 |  | 
 | 348 |     // Remove main surface offscreen | 
 | 349 |     Transaction().reparent(mMainSurface, nullptr).apply(); | 
 | 350 |     { | 
 | 351 |         mCapture = screenshot(); | 
 | 352 |         mCapture->expectColor(mMainSurfaceBounds, Color::BLACK); | 
 | 353 |     } | 
 | 354 |  | 
| Pablo Gamito | 11dcc22 | 2020-09-12 15:49:39 +0000 | [diff] [blame] | 355 |     Transaction().reparent(mMainSurface, mBlackBgSurface).apply(); | 
| chaviw | 5e1e8f2 | 2020-07-10 12:46:21 -0700 | [diff] [blame] | 356 |     { | 
 | 357 |         mCapture = screenshot(); | 
 | 358 |         mCapture->expectBorder(childBounds, mMainSurfaceColor); | 
 | 359 |         mCapture->expectBorder(grandchildBounds, childColor); | 
 | 360 |         mCapture->expectColor(grandchildBounds, grandchildColor); | 
 | 361 |     } | 
 | 362 |  | 
 | 363 |     Transaction().hide(grandchildSurface).apply(); | 
 | 364 |  | 
 | 365 |     // grandchild is still detached so it will not hide | 
 | 366 |     { | 
 | 367 |         mCapture = screenshot(); | 
 | 368 |         mCapture->expectBorder(childBounds, mMainSurfaceColor); | 
 | 369 |         mCapture->expectBorder(grandchildBounds, childColor); | 
 | 370 |         mCapture->expectColor(grandchildBounds, grandchildColor); | 
 | 371 |     } | 
 | 372 | } | 
 | 373 |  | 
 | 374 | } // namespace android |