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