• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2016 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 package android.uirendering.cts.testclasses;
17 
18 import static org.junit.Assert.assertFalse;
19 import static org.junit.Assert.assertTrue;
20 
21 import android.animation.ObjectAnimator;
22 import android.graphics.Bitmap;
23 import android.graphics.Bitmap.Config;
24 import android.graphics.Canvas;
25 import android.graphics.Color;
26 import android.graphics.HardwareBufferRenderer;
27 import android.graphics.Rect;
28 import android.graphics.RenderNode;
29 import android.hardware.HardwareBuffer;
30 import android.os.Handler;
31 import android.os.Looper;
32 import android.uirendering.cts.R;
33 import android.uirendering.cts.bitmapverifiers.ColorVerifier;
34 import android.uirendering.cts.testinfrastructure.ActivityTestBase;
35 import android.uirendering.cts.testinfrastructure.CanvasClient;
36 import android.uirendering.cts.testinfrastructure.DrawActivity;
37 import android.uirendering.cts.testinfrastructure.Tracer;
38 import android.uirendering.cts.testinfrastructure.ViewInitializer;
39 import android.uirendering.cts.util.BitmapAsserter;
40 import android.view.AttachedSurfaceControl;
41 import android.view.Gravity;
42 import android.view.PixelCopy;
43 import android.view.SurfaceControl;
44 import android.view.SurfaceHolder;
45 import android.view.SurfaceView;
46 import android.view.View;
47 import android.view.animation.LinearInterpolator;
48 import android.widget.FrameLayout;
49 
50 import androidx.test.filters.FlakyTest;
51 import androidx.test.filters.LargeTest;
52 import androidx.test.runner.AndroidJUnit4;
53 
54 import com.android.compatibility.common.util.SynchronousPixelCopy;
55 import com.android.compatibility.common.util.WidgetTestUtils;
56 
57 import org.junit.Assert;
58 import org.junit.Rule;
59 import org.junit.Test;
60 import org.junit.runner.RunWith;
61 
62 import java.util.concurrent.CountDownLatch;
63 import java.util.concurrent.Executors;
64 import java.util.concurrent.TimeUnit;
65 
66 @LargeTest
67 @RunWith(AndroidJUnit4.class)
68 public class SurfaceViewTests extends ActivityTestBase {
69 
70     @Rule
71     public final Tracer name = new Tracer();
72 
73     static final CanvasCallback sGreenCanvasCallback =
74             new CanvasCallback((canvas, width, height) -> canvas.drawColor(Color.GREEN));
75     static final CanvasCallback sWhiteCanvasCallback =
76             new CanvasCallback((canvas, width, height) -> canvas.drawColor(Color.WHITE));
77     static final CanvasCallback sRedCanvasCallback =
78             new CanvasCallback((canvas, width, height) -> canvas.drawColor(Color.RED));
79 
80     private static class CanvasCallback implements SurfaceHolder.Callback {
81         final CanvasClient mCanvasClient;
82         private CountDownLatch mFirstDrawLatch;
83 
CanvasCallback(CanvasClient canvasClient)84         public CanvasCallback(CanvasClient canvasClient) {
85             mCanvasClient = canvasClient;
86         }
87 
88         @Override
surfaceCreated(SurfaceHolder holder)89         public void surfaceCreated(SurfaceHolder holder) {
90         }
91 
92         @Override
surfaceChanged(SurfaceHolder holder, int format, int width, int height)93         public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
94             Canvas canvas = holder.lockCanvas();
95             mCanvasClient.draw(canvas, width, height);
96             holder.unlockCanvasAndPost(canvas);
97 
98             if (mFirstDrawLatch != null) {
99                 mFirstDrawLatch.countDown();
100             }
101         }
102 
103         @Override
surfaceDestroyed(SurfaceHolder holder)104         public void surfaceDestroyed(SurfaceHolder holder) {
105         }
106 
setFence(CountDownLatch fence)107         public void setFence(CountDownLatch fence) {
108             mFirstDrawLatch = fence;
109         }
110     }
111 
createInfiniteAnimator(Object target, String prop, float start, float end)112     static ObjectAnimator createInfiniteAnimator(Object target, String prop,
113             float start, float end) {
114         ObjectAnimator a = ObjectAnimator.ofFloat(target, prop, start, end);
115         a.setRepeatMode(ObjectAnimator.REVERSE);
116         a.setRepeatCount(ObjectAnimator.INFINITE);
117         a.setDuration(200);
118         a.setInterpolator(new LinearInterpolator());
119         a.start();
120         return a;
121     }
122     private final Screenshotter mScreenshotter = testPositionInfo -> {
123         Bitmap source = getInstrumentation().getUiAutomation().takeScreenshot();
124         return Bitmap.createBitmap(source,
125                 testPositionInfo.screenOffset.x, testPositionInfo.screenOffset.y,
126                 TEST_WIDTH, TEST_HEIGHT);
127     };
128 
129     // waitForRedraw checks that HWUI finished drawing but SurfaceFlinger may be backpressured, so
130     // synchronizing by applying no-op transactions with UI draws instead.
waitForScreenshottable()131     private void waitForScreenshottable() throws InterruptedException {
132         AttachedSurfaceControl rootSurfaceControl =
133                 getActivity().getWindow().getRootSurfaceControl();
134 
135         CountDownLatch latch = new CountDownLatch(1);
136         SurfaceControl stub = new SurfaceControl.Builder().setName("test").build();
137         rootSurfaceControl.applyTransactionOnDraw(
138                 rootSurfaceControl.buildReparentTransaction(stub));
139         rootSurfaceControl.applyTransactionOnDraw(
140                 new SurfaceControl.Transaction().reparent(stub, null)
141                         .addTransactionCommittedListener(Runnable::run, latch::countDown));
142         getActivity().waitForRedraw();
143         assertTrue(latch.await(5, TimeUnit.SECONDS));
144     }
145 
146     @FlakyTest(bugId = 244426304)
147     @Test
testMovingWhiteSurfaceView()148     public void testMovingWhiteSurfaceView() {
149         // A moving SurfaceViews with white content against a white background should be invisible
150         ViewInitializer initializer = new ViewInitializer() {
151             ObjectAnimator mAnimator;
152             @Override
153             public void initializeView(View view) {
154                 FrameLayout root = (FrameLayout) view.findViewById(R.id.frame_layout);
155                 mAnimator = createInfiniteAnimator(root, "translationY", 0, 50);
156 
157                 SurfaceView surfaceViewA = new SurfaceView(view.getContext());
158                 surfaceViewA.getHolder().addCallback(sWhiteCanvasCallback);
159                 root.addView(surfaceViewA, new FrameLayout.LayoutParams(
160                         90, 40, Gravity.START | Gravity.TOP));
161             }
162             @Override
163             public void teardownView() {
164                 mAnimator.cancel();
165             }
166         };
167         createTest()
168                 .addLayout(R.layout.frame_layout, initializer, true)
169                 .withScreenshotter(mScreenshotter)
170                 .runWithAnimationVerifier(new ColorVerifier(Color.WHITE, 0 /* zero tolerance */));
171     }
172 
173     private static class SurfaceViewHelper implements ViewInitializer, Screenshotter, SurfaceHolder.Callback {
174         private final CanvasClient mCanvasClient;
175         private final CountDownLatch mFence = new CountDownLatch(1);
176         private SurfaceView mSurfaceView = null;
177         private boolean mHasSurface = false;
178 
SurfaceViewHelper(CanvasClient canvasClient)179         public SurfaceViewHelper(CanvasClient canvasClient) {
180             mCanvasClient = canvasClient;
181         }
182 
183         @Override
takeScreenshot(TestPositionInfo testPositionInfo)184         public Bitmap takeScreenshot(TestPositionInfo testPositionInfo) {
185             SynchronousPixelCopy copy = new SynchronousPixelCopy();
186             Bitmap dest = Bitmap.createBitmap(
187                     TEST_WIDTH, TEST_HEIGHT, Config.ARGB_8888);
188             Rect srcRect = new Rect(0, 0, TEST_WIDTH, TEST_HEIGHT);
189             int copyResult = copy.request(mSurfaceView, srcRect, dest);
190             Assert.assertEquals(PixelCopy.SUCCESS, copyResult);
191             return dest;
192         }
193 
194         @Override
initializeView(View view)195         public void initializeView(View view) {
196             FrameLayout root = (FrameLayout) view.findViewById(R.id.frame_layout);
197             mSurfaceView = new SurfaceView(view.getContext());
198             mSurfaceView.getHolder().addCallback(this);
199             onSurfaceViewCreated(mSurfaceView);
200             root.addView(mSurfaceView, new FrameLayout.LayoutParams(
201                     FrameLayout.LayoutParams.MATCH_PARENT,
202                     FrameLayout.LayoutParams.MATCH_PARENT));
203         }
204 
getSurfaceView()205         public SurfaceView getSurfaceView() {
206             return mSurfaceView;
207         }
208 
209 
hasSurface()210         public boolean hasSurface() {
211             return mHasSurface;
212         }
213 
214 
onSurfaceViewCreated(SurfaceView surfaceView)215         public void onSurfaceViewCreated(SurfaceView surfaceView) {
216 
217         }
218 
219         @Override
surfaceCreated(SurfaceHolder holder)220         public void surfaceCreated(SurfaceHolder holder) {
221             mHasSurface = true;
222         }
223 
224         @Override
surfaceChanged(SurfaceHolder holder, int format, int width, int height)225         public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
226             // TODO: Remove the post() which is a temporary workaround for b/32484713
227             mSurfaceView.post(() -> {
228                 Canvas canvas = holder.lockHardwareCanvas();
229                 mCanvasClient.draw(canvas, width, height);
230                 holder.unlockCanvasAndPost(canvas);
231                 mFence.countDown();
232             });
233         }
234 
235         @Override
surfaceDestroyed(SurfaceHolder holder)236         public void surfaceDestroyed(SurfaceHolder holder) {
237             mHasSurface = false;
238         }
239 
getFence()240         public CountDownLatch getFence() {
241             return mFence;
242         }
243     }
244 
245     @Test
testSurfaceHolderHardwareCanvas()246     public void testSurfaceHolderHardwareCanvas() {
247         SurfaceViewHelper helper = new SurfaceViewHelper((canvas, width, height) -> {
248             Assert.assertNotNull(canvas);
249             Assert.assertTrue(canvas.isHardwareAccelerated());
250             canvas.drawColor(Color.GREEN);
251         });
252         createTest()
253                 .addLayout(R.layout.frame_layout, helper, true, helper.getFence())
254                 .withScreenshotter(helper)
255                 .runWithVerifier(new ColorVerifier(Color.GREEN, 0 /* zero tolerance */));
256     }
257 
258     @Test
testSurfaceViewHolePunchWithLayer()259     public void testSurfaceViewHolePunchWithLayer() {
260         SurfaceViewHelper helper = new SurfaceViewHelper((canvas, width, height) -> {
261             Assert.assertNotNull(canvas);
262             Assert.assertTrue(canvas.isHardwareAccelerated());
263             canvas.drawColor(Color.GREEN);
264         }
265         ) {
266             @Override
267             public void onSurfaceViewCreated(SurfaceView surfaceView) {
268                 surfaceView.setLayerType(View.LAYER_TYPE_HARDWARE, null);
269             }
270         };
271         createTest()
272                 .addLayout(R.layout.frame_layout, helper, true, helper.getFence())
273                 .withScreenshotter(helper)
274                 .runWithVerifier(new ColorVerifier(Color.GREEN, 0 /* zero tolerance */));
275 
276     }
277 
278     @Test
surfaceViewMediaLayer()279     public void surfaceViewMediaLayer() {
280         // Add a shared latch which will fire after both callbacks are complete.
281         CountDownLatch latch = new CountDownLatch(2);
282         sGreenCanvasCallback.setFence(latch);
283         sRedCanvasCallback.setFence(latch);
284 
285         ViewInitializer initializer = new ViewInitializer() {
286             @Override
287             public void initializeView(View view) {
288                 FrameLayout root = (FrameLayout) view.findViewById(R.id.frame_layout);
289                 SurfaceView surfaceViewA = new SurfaceView(view.getContext());
290                 surfaceViewA.setZOrderMediaOverlay(true);
291                 surfaceViewA.getHolder().addCallback(sRedCanvasCallback);
292 
293                 root.addView(surfaceViewA, new FrameLayout.LayoutParams(
294                         FrameLayout.LayoutParams.MATCH_PARENT,
295                         FrameLayout.LayoutParams.MATCH_PARENT));
296 
297                 SurfaceView surfaceViewB = new SurfaceView(view.getContext());
298                 surfaceViewB.getHolder().addCallback(sGreenCanvasCallback);
299 
300                 root.addView(surfaceViewB, new FrameLayout.LayoutParams(
301                         FrameLayout.LayoutParams.MATCH_PARENT,
302                         FrameLayout.LayoutParams.MATCH_PARENT));
303             }
304         };
305 
306         createTest()
307                 .addLayout(R.layout.frame_layout, initializer, true, latch)
308                 .withScreenshotter(mScreenshotter)
309                 // The red layer is the media overlay, so it must be on top.
310                 .runWithVerifier(new ColorVerifier(Color.RED, 0 /* zero tolerance */));
311     }
312 
313     @Test
surfaceViewBlendZAbove()314     public void surfaceViewBlendZAbove() {
315         SurfaceViewHelper helper = new SurfaceViewHelper((canvas, width, height) -> {
316             Assert.assertNotNull(canvas);
317             Assert.assertTrue(canvas.isHardwareAccelerated());
318             canvas.drawColor(Color.BLACK);
319         }
320         ) {
321             @Override
322             public void onSurfaceViewCreated(SurfaceView surfaceView) {
323                 surfaceView.setAlpha(0.25f);
324                 surfaceView.setZOrderOnTop(true);
325             }
326         };
327         createTest()
328                 .addLayout(R.layout.frame_layout, helper, true, helper.getFence())
329                 .withScreenshotter(mScreenshotter)
330                 .runWithVerifier(new ColorVerifier(
331                         Color.rgb(191, 191, 191), 1 /* blending tolerance */));
332     }
333 
334     @Test
surfaceViewBlendZBelow()335     public void surfaceViewBlendZBelow() {
336         SurfaceViewHelper helper = new SurfaceViewHelper((canvas, width, height) -> {
337             Assert.assertNotNull(canvas);
338             Assert.assertTrue(canvas.isHardwareAccelerated());
339             canvas.drawColor(Color.BLACK);
340         }
341         ) {
342             @Override
343             public void onSurfaceViewCreated(SurfaceView surfaceView) {
344                 surfaceView.setAlpha(0.25f);
345             }
346         };
347         createTest()
348                 .addLayout(R.layout.frame_layout, helper, true, helper.getFence())
349                 .withScreenshotter(mScreenshotter)
350                 .runWithVerifier(new ColorVerifier(
351                         Color.rgb(191, 191, 191), 1 /* blending tolerance */));
352     }
353 
354     @Test
surfaceViewSurfaceLifecycleFollowsVisibilityByDefault()355     public void surfaceViewSurfaceLifecycleFollowsVisibilityByDefault() {
356         SurfaceViewHelper helper = new SurfaceViewHelper((canvas, width, height) -> {
357             Assert.assertNotNull(canvas);
358             canvas.drawColor(Color.BLACK);
359         });
360 
361         DrawActivity activity = getActivity();
362         try {
363             activity.enqueueRenderSpecAndWait(R.layout.frame_layout, null, helper, false, false);
364             assertTrue(helper.hasSurface());
365             activity.runOnUiThread(() -> helper.getSurfaceView().setVisibility(View.INVISIBLE));
366             activity.waitForRedraw();
367             assertFalse(helper.hasSurface());
368         } finally {
369             activity.reset();
370         }
371     }
372 
373     @Test
surfaceViewSurfaceLifecycleFollowsVisibility()374     public void surfaceViewSurfaceLifecycleFollowsVisibility() {
375         SurfaceViewHelper helper = new SurfaceViewHelper((canvas, width, height) -> {
376             Assert.assertNotNull(canvas);
377             canvas.drawColor(Color.BLACK);
378         });
379 
380         DrawActivity activity = getActivity();
381         try {
382             activity.enqueueRenderSpecAndWait(R.layout.frame_layout, null, helper, false, false);
383             assertTrue(helper.hasSurface());
384             activity.runOnUiThread(() -> {
385                 helper.getSurfaceView()
386                        .setSurfaceLifecycle(SurfaceView.SURFACE_LIFECYCLE_FOLLOWS_VISIBILITY);
387                 helper.getSurfaceView().setVisibility(View.INVISIBLE);
388             });
389             activity.waitForRedraw();
390             assertFalse(helper.hasSurface());
391         } finally {
392             activity.reset();
393         }
394     }
395 
396     @Test
surfaceViewSurfaceLifecycleFollowsAttachment()397     public void surfaceViewSurfaceLifecycleFollowsAttachment() {
398         SurfaceViewHelper helper = new SurfaceViewHelper((canvas, width, height) -> {
399             Assert.assertNotNull(canvas);
400             canvas.drawColor(Color.BLACK);
401         });
402 
403         DrawActivity activity = getActivity();
404         try {
405             activity.enqueueRenderSpecAndWait(R.layout.frame_layout, null, helper, false, false);
406             assertTrue(helper.hasSurface());
407             activity.runOnUiThread(() -> {
408                 helper.getSurfaceView()
409                         .setSurfaceLifecycle(SurfaceView.SURFACE_LIFECYCLE_FOLLOWS_ATTACHMENT);
410                 helper.getSurfaceView().setVisibility(View.INVISIBLE);
411             });
412             activity.waitForRedraw();
413             assertTrue(helper.hasSurface());
414         } finally {
415             activity.reset();
416         }
417     }
418 
419     @Test
surfaceViewSurfaceLifecycleFollowsAttachmentWithOverlaps()420     public void surfaceViewSurfaceLifecycleFollowsAttachmentWithOverlaps() {
421         // Add a shared latch which will fire after both callbacks are complete.
422         CountDownLatch latch = new CountDownLatch(2);
423         sGreenCanvasCallback.setFence(latch);
424         sRedCanvasCallback.setFence(latch);
425 
426         ViewInitializer initializer = new ViewInitializer() {
427             @Override
428             public void initializeView(View view) {
429                 FrameLayout root = (FrameLayout) view.findViewById(R.id.frame_layout);
430                 SurfaceView surfaceViewA = new SurfaceView(view.getContext());
431                 surfaceViewA.setVisibility(View.VISIBLE);
432                 surfaceViewA.setSurfaceLifecycle(SurfaceView.SURFACE_LIFECYCLE_FOLLOWS_VISIBILITY);
433                 surfaceViewA.getHolder().addCallback(sRedCanvasCallback);
434 
435                 root.addView(surfaceViewA, new FrameLayout.LayoutParams(
436                         FrameLayout.LayoutParams.MATCH_PARENT,
437                         FrameLayout.LayoutParams.MATCH_PARENT));
438 
439                 SurfaceView surfaceViewB = new SurfaceView(view.getContext());
440                 surfaceViewB.setVisibility(View.INVISIBLE);
441                 surfaceViewB.setSurfaceLifecycle(SurfaceView.SURFACE_LIFECYCLE_FOLLOWS_ATTACHMENT);
442                 surfaceViewB.getHolder().addCallback(sGreenCanvasCallback);
443 
444                 root.addView(surfaceViewB, new FrameLayout.LayoutParams(
445                         FrameLayout.LayoutParams.MATCH_PARENT,
446                         FrameLayout.LayoutParams.MATCH_PARENT));
447             }
448         };
449 
450         createTest()
451                 .addLayout(R.layout.frame_layout, initializer, true, latch)
452                 .withScreenshotter(mScreenshotter)
453                 .runWithVerifier(new ColorVerifier(Color.RED, 0 /* zero tolerance */));
454     }
455 
456     @Test
surfaceViewSurfaceLifecycleChangesFromFollowsAttachmentToFollowsVisibility()457     public void surfaceViewSurfaceLifecycleChangesFromFollowsAttachmentToFollowsVisibility() {
458         SurfaceViewHelper helper = new SurfaceViewHelper((canvas, width, height) -> {
459             Assert.assertNotNull(canvas);
460             canvas.drawColor(Color.BLACK);
461         });
462 
463         DrawActivity activity = getActivity();
464         try {
465             activity.enqueueRenderSpecAndWait(R.layout.frame_layout, null, helper, false, false);
466             assertTrue(helper.hasSurface());
467             activity.runOnUiThread(() -> {
468                 helper.getSurfaceView()
469                         .setSurfaceLifecycle(SurfaceView.SURFACE_LIFECYCLE_FOLLOWS_ATTACHMENT);
470                 helper.getSurfaceView().setVisibility(View.INVISIBLE);
471             });
472             activity.waitForRedraw();
473             assertTrue(helper.hasSurface());
474             activity.runOnUiThread(() -> {
475                 helper.getSurfaceView()
476                         .setSurfaceLifecycle(SurfaceView.SURFACE_LIFECYCLE_FOLLOWS_VISIBILITY);
477             });
478             activity.waitForRedraw();
479             assertFalse(helper.hasSurface());
480         } finally {
481             activity.reset();
482         }
483     }
484 
485     @Test
surfaceViewSurfaceLifecycleChangesFromFollowsVisibilityToFollowsAttachment()486     public void surfaceViewSurfaceLifecycleChangesFromFollowsVisibilityToFollowsAttachment() {
487         SurfaceViewHelper helper = new SurfaceViewHelper((canvas, width, height) -> {
488             Assert.assertNotNull(canvas);
489             canvas.drawColor(Color.BLACK);
490         });
491 
492         DrawActivity activity = getActivity();
493         try {
494             activity.enqueueRenderSpecAndWait(R.layout.frame_layout, null, helper, false, false);
495             assertTrue(helper.hasSurface());
496             activity.runOnUiThread(() -> {
497                 helper.getSurfaceView()
498                         .setSurfaceLifecycle(SurfaceView.SURFACE_LIFECYCLE_FOLLOWS_VISIBILITY);
499                 helper.getSurfaceView().setVisibility(View.INVISIBLE);
500             });
501             activity.waitForRedraw();
502             assertFalse(helper.hasSurface());
503             activity.runOnUiThread(() -> {
504                 helper.getSurfaceView()
505                         .setSurfaceLifecycle(SurfaceView.SURFACE_LIFECYCLE_FOLLOWS_ATTACHMENT);
506             });
507             activity.waitForRedraw();
508             assertTrue(helper.hasSurface());
509         } finally {
510             activity.reset();
511         }
512     }
513 
514     @Test
surfaceViewAppliesTransactionsToFrame()515     public void surfaceViewAppliesTransactionsToFrame()
516             throws InterruptedException {
517         SurfaceControl blueLayer = new SurfaceControl.Builder()
518                 .setName("SurfaceViewTests")
519                 .setHidden(false)
520                 .build();
521         SurfaceViewHelper helper = new SurfaceViewHelper((canvas, width, height) -> {
522             Assert.assertNotNull(canvas);
523             canvas.drawColor(Color.RED);
524         });
525 
526         DrawActivity activity = getActivity();
527         try {
528             TestPositionInfo testInfo = activity
529                     .enqueueRenderSpecAndWait(R.layout.frame_layout, null, helper, true, false);
530             assertTrue(helper.hasSurface());
531             helper.getFence().await(3, TimeUnit.SECONDS);
532             CountDownLatch latch = new CountDownLatch(1);
533             CountDownLatch transactionCommitted = new CountDownLatch(1);
534             activity.runOnUiThread(() -> {
535                 SurfaceControl.Transaction transaction = new SurfaceControl.Transaction()
536                         .reparent(blueLayer, helper.getSurfaceView().getSurfaceControl())
537                         .setLayer(blueLayer, 1)
538                         .addTransactionCommittedListener(Runnable::run,
539                                 transactionCommitted::countDown);
540 
541                 int width = helper.getSurfaceView().getWidth();
542                 int height = helper.getSurfaceView().getHeight();
543                 long usage = HardwareBuffer.USAGE_GPU_SAMPLED_IMAGE
544                         | HardwareBuffer.USAGE_GPU_COLOR_OUTPUT
545                         | HardwareBuffer.USAGE_COMPOSER_OVERLAY;
546                 HardwareBuffer buffer = HardwareBuffer.create(
547                         width, height, HardwareBuffer.RGBA_8888, 1, usage);
548                 HardwareBufferRenderer renderer = new HardwareBufferRenderer(buffer);
549                 RenderNode node = new RenderNode("content");
550                 node.setPosition(0, 0, width, height);
551                 Canvas canvas = node.beginRecording();
552                 canvas.drawColor(Color.BLUE);
553                 node.endRecording();
554                 renderer.setContentRoot(node);
555                 Handler handler = new Handler(Looper.getMainLooper());
556                 renderer.obtainRenderRequest().draw(Executors.newSingleThreadExecutor(), result -> {
557                     handler.post(() -> {
558                         transaction.setBuffer(blueLayer, buffer, result.getFence());
559                         helper.getSurfaceView().applyTransactionToFrame(transaction);
560                         latch.countDown();
561                     });
562                 });
563             });
564 
565             assertTrue(latch.await(5, TimeUnit.SECONDS));
566             // Wait for an additional second to ensure that the transaction reparenting the blue
567             // layer is not applied.
568             assertFalse(transactionCommitted.await(1, TimeUnit.SECONDS));
569             Bitmap screenshot = mScreenshotter.takeScreenshot(testInfo);
570             BitmapAsserter asserter =
571                     new BitmapAsserter(this.getClass().getSimpleName(), name.getMethodName());
572             asserter.assertBitmapIsVerified(
573                     screenshot, new ColorVerifier(Color.RED, 2), getName(), "");
574             activity.runOnUiThread(() -> {
575                 SurfaceHolder holder = helper.getSurfaceView().getHolder();
576                 Canvas canvas = holder.lockHardwareCanvas();
577                 canvas.drawColor(Color.GREEN);
578                 holder.unlockCanvasAndPost(canvas);
579             });
580             assertTrue(transactionCommitted.await(1, TimeUnit.SECONDS));
581             screenshot = mScreenshotter.takeScreenshot(testInfo);
582             // Now that a new frame was drawn, the blue layer should be overlaid now.
583             asserter.assertBitmapIsVerified(
584                     screenshot, new ColorVerifier(Color.BLUE, 2), getName(), "");
585         } finally {
586             activity.reset();
587         }
588     }
589 
590     // Regression test for b/269113414
591     @Test
surfaceViewOffscreenDoesNotPeekThrough()592     public void surfaceViewOffscreenDoesNotPeekThrough() throws InterruptedException {
593 
594         // Add a shared latch which will fire after both callbacks are complete.
595         CountDownLatch latch = new CountDownLatch(2);
596         sGreenCanvasCallback.setFence(latch);
597         sRedCanvasCallback.setFence(latch);
598 
599         DrawActivity activity = getActivity();
600 
601         SurfaceView surfaceViewRed = new SurfaceView(activity);
602         surfaceViewRed.getHolder().addCallback(sRedCanvasCallback);
603         SurfaceView surfaceViewGreen = new SurfaceView(activity);
604         surfaceViewGreen.setZOrderMediaOverlay(true);
605         surfaceViewGreen.getHolder().addCallback(sGreenCanvasCallback);
606 
607         int width = activity.getWindow().getDecorView().getWidth();
608         int height = activity.getWindow().getDecorView().getHeight();
609 
610         ViewInitializer initializer = (View view) -> {
611             FrameLayout root = view.findViewById(R.id.frame_layout);
612             root.addView(surfaceViewRed, new FrameLayout.LayoutParams(
613                     FrameLayout.LayoutParams.MATCH_PARENT,
614                     FrameLayout.LayoutParams.MATCH_PARENT));
615 
616             root.addView(surfaceViewGreen, new FrameLayout.LayoutParams(
617                     FrameLayout.LayoutParams.MATCH_PARENT,
618                     FrameLayout.LayoutParams.MATCH_PARENT));
619         };
620 
621         try {
622             TestPositionInfo testInfo = activity.enqueueRenderSpecAndWait(
623                     R.layout.frame_layout, null, initializer, true, false);
624             assertTrue(latch.await(5, TimeUnit.SECONDS));
625 
626             BitmapAsserter asserter =
627                     new BitmapAsserter(this.getClass().getSimpleName(), name.getMethodName());
628 
629             // Layout the SurfaceView way offscreen which would cause it to get quick rejected.
630             WidgetTestUtils.runOnMainAndDrawSync(surfaceViewGreen, () -> {
631                 surfaceViewGreen.layout(
632                         width * 2,
633                         height * 2,
634                         width * 2 + TEST_WIDTH,
635                         height * 2 + TEST_HEIGHT);
636             });
637             waitForScreenshottable();
638             Bitmap screenshot = mScreenshotter.takeScreenshot(testInfo);
639             asserter.assertBitmapIsVerified(
640                     screenshot,
641                     new ColorVerifier(Color.RED, 0), getName(),
642                     "Verifying red SurfaceControl");
643         } finally {
644             activity.reset();
645         }
646     }
647 
648 
649 }
650