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 android.animation.ObjectAnimator; 19 import android.graphics.Bitmap; 20 import android.graphics.Bitmap.Config; 21 import android.graphics.Canvas; 22 import android.graphics.Color; 23 import android.graphics.Rect; 24 import android.uirendering.cts.R; 25 import android.uirendering.cts.bitmapverifiers.ColorVerifier; 26 import android.uirendering.cts.testinfrastructure.ActivityTestBase; 27 import android.uirendering.cts.testinfrastructure.CanvasClient; 28 import android.uirendering.cts.testinfrastructure.ViewInitializer; 29 import android.view.Gravity; 30 import android.view.PixelCopy; 31 import android.view.SurfaceHolder; 32 import android.view.SurfaceView; 33 import android.view.View; 34 import android.view.animation.LinearInterpolator; 35 import android.widget.FrameLayout; 36 37 import androidx.test.filters.LargeTest; 38 import androidx.test.runner.AndroidJUnit4; 39 40 import com.android.compatibility.common.util.SynchronousPixelCopy; 41 42 import org.junit.Assert; 43 import org.junit.Test; 44 import org.junit.runner.RunWith; 45 46 import java.util.concurrent.CountDownLatch; 47 48 @LargeTest 49 @RunWith(AndroidJUnit4.class) 50 public class SurfaceViewTests extends ActivityTestBase { 51 52 static final CanvasCallback sGreenCanvasCallback = 53 new CanvasCallback((canvas, width, height) -> canvas.drawColor(Color.GREEN)); 54 static final CanvasCallback sWhiteCanvasCallback = 55 new CanvasCallback((canvas, width, height) -> canvas.drawColor(Color.WHITE)); 56 static final CanvasCallback sRedCanvasCallback = 57 new CanvasCallback((canvas, width, height) -> canvas.drawColor(Color.RED)); 58 59 private static class CanvasCallback implements SurfaceHolder.Callback { 60 final CanvasClient mCanvasClient; 61 CanvasCallback(CanvasClient canvasClient)62 public CanvasCallback(CanvasClient canvasClient) { 63 mCanvasClient = canvasClient; 64 } 65 66 @Override surfaceCreated(SurfaceHolder holder)67 public void surfaceCreated(SurfaceHolder holder) { 68 } 69 70 @Override surfaceChanged(SurfaceHolder holder, int format, int width, int height)71 public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) { 72 Canvas canvas = holder.lockCanvas(); 73 mCanvasClient.draw(canvas, width, height); 74 holder.unlockCanvasAndPost(canvas); 75 } 76 77 @Override surfaceDestroyed(SurfaceHolder holder)78 public void surfaceDestroyed(SurfaceHolder holder) { 79 } 80 } 81 createInfiniteAnimator(Object target, String prop, float start, float end)82 static ObjectAnimator createInfiniteAnimator(Object target, String prop, 83 float start, float end) { 84 ObjectAnimator a = ObjectAnimator.ofFloat(target, prop, start, end); 85 a.setRepeatMode(ObjectAnimator.REVERSE); 86 a.setRepeatCount(ObjectAnimator.INFINITE); 87 a.setDuration(200); 88 a.setInterpolator(new LinearInterpolator()); 89 a.start(); 90 return a; 91 } 92 93 @Test testMovingWhiteSurfaceView()94 public void testMovingWhiteSurfaceView() { 95 // A moving SurfaceViews with white content against a white background should be invisible 96 ViewInitializer initializer = new ViewInitializer() { 97 ObjectAnimator mAnimator; 98 @Override 99 public void initializeView(View view) { 100 FrameLayout root = (FrameLayout) view.findViewById(R.id.frame_layout); 101 mAnimator = createInfiniteAnimator(root, "translationY", 0, 50); 102 103 SurfaceView surfaceViewA = new SurfaceView(view.getContext()); 104 surfaceViewA.getHolder().addCallback(sWhiteCanvasCallback); 105 root.addView(surfaceViewA, new FrameLayout.LayoutParams( 106 90, 40, Gravity.START | Gravity.TOP)); 107 } 108 @Override 109 public void teardownView() { 110 mAnimator.cancel(); 111 } 112 }; 113 Screenshotter screenshotter = testPositionInfo -> { 114 Bitmap source = getInstrumentation().getUiAutomation().takeScreenshot(); 115 return Bitmap.createBitmap(source, 116 testPositionInfo.screenOffset.x, testPositionInfo.screenOffset.y, 117 TEST_WIDTH, TEST_HEIGHT); 118 }; 119 createTest() 120 .addLayout(R.layout.frame_layout, initializer, true) 121 .withScreenshotter(screenshotter) 122 .runWithAnimationVerifier(new ColorVerifier(Color.WHITE, 0 /* zero tolerance */)); 123 } 124 125 private static class SurfaceViewHelper implements ViewInitializer, Screenshotter, SurfaceHolder.Callback { 126 private final CanvasClient mCanvasClient; 127 private final CountDownLatch mFence = new CountDownLatch(1); 128 private SurfaceView mSurfaceView; 129 SurfaceViewHelper(CanvasClient canvasClient)130 public SurfaceViewHelper(CanvasClient canvasClient) { 131 mCanvasClient = canvasClient; 132 } 133 134 @Override takeScreenshot(TestPositionInfo testPositionInfo)135 public Bitmap takeScreenshot(TestPositionInfo testPositionInfo) { 136 SynchronousPixelCopy copy = new SynchronousPixelCopy(); 137 Bitmap dest = Bitmap.createBitmap( 138 TEST_WIDTH, TEST_HEIGHT, Config.ARGB_8888); 139 Rect srcRect = new Rect(0, 0, TEST_WIDTH, TEST_HEIGHT); 140 int copyResult = copy.request(mSurfaceView, srcRect, dest); 141 Assert.assertEquals(PixelCopy.SUCCESS, copyResult); 142 return dest; 143 } 144 145 @Override initializeView(View view)146 public void initializeView(View view) { 147 FrameLayout root = (FrameLayout) view.findViewById(R.id.frame_layout); 148 mSurfaceView = new SurfaceView(view.getContext()); 149 mSurfaceView.getHolder().addCallback(this); 150 onSurfaceViewCreated(mSurfaceView); 151 root.addView(mSurfaceView, new FrameLayout.LayoutParams( 152 FrameLayout.LayoutParams.MATCH_PARENT, 153 FrameLayout.LayoutParams.MATCH_PARENT)); 154 } 155 onSurfaceViewCreated(SurfaceView surfaceView)156 public void onSurfaceViewCreated(SurfaceView surfaceView) { 157 158 } 159 160 @Override surfaceCreated(SurfaceHolder holder)161 public void surfaceCreated(SurfaceHolder holder) { 162 } 163 164 @Override surfaceChanged(SurfaceHolder holder, int format, int width, int height)165 public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) { 166 // TODO: Remove the post() which is a temporary workaround for b/32484713 167 mSurfaceView.post(() -> { 168 Canvas canvas = holder.lockHardwareCanvas(); 169 mCanvasClient.draw(canvas, width, height); 170 holder.unlockCanvasAndPost(canvas); 171 mFence.countDown(); 172 }); 173 } 174 175 @Override surfaceDestroyed(SurfaceHolder holder)176 public void surfaceDestroyed(SurfaceHolder holder) { 177 } 178 getFence()179 public CountDownLatch getFence() { 180 return mFence; 181 } 182 } 183 184 @Test testSurfaceHolderHardwareCanvas()185 public void testSurfaceHolderHardwareCanvas() { 186 SurfaceViewHelper helper = new SurfaceViewHelper((canvas, width, height) -> { 187 Assert.assertNotNull(canvas); 188 Assert.assertTrue(canvas.isHardwareAccelerated()); 189 canvas.drawColor(Color.GREEN); 190 }); 191 createTest() 192 .addLayout(R.layout.frame_layout, helper, true, helper.getFence()) 193 .withScreenshotter(helper) 194 .runWithVerifier(new ColorVerifier(Color.GREEN, 0 /* zero tolerance */)); 195 } 196 197 @Test testSurfaceViewHolePunchWithLayer()198 public void testSurfaceViewHolePunchWithLayer() { 199 SurfaceViewHelper helper = new SurfaceViewHelper((canvas, width, height) -> { 200 Assert.assertNotNull(canvas); 201 Assert.assertTrue(canvas.isHardwareAccelerated()); 202 canvas.drawColor(Color.GREEN); 203 } 204 ) { 205 @Override 206 public void onSurfaceViewCreated(SurfaceView surfaceView) { 207 surfaceView.setLayerType(View.LAYER_TYPE_HARDWARE, null); 208 } 209 }; 210 createTest() 211 .addLayout(R.layout.frame_layout, helper, true, helper.getFence()) 212 .withScreenshotter(helper) 213 .runWithVerifier(new ColorVerifier(Color.GREEN, 0 /* zero tolerance */)); 214 215 } 216 } 217