Home | History | Annotate | Download | only in testclasses
      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 
     17 package android.uirendering.cts.testclasses;
     18 
     19 import static org.junit.Assert.assertEquals;
     20 
     21 import android.animation.Animator;
     22 import android.animation.ValueAnimator;
     23 import android.content.Context;
     24 import android.graphics.Bitmap;
     25 import android.graphics.Canvas;
     26 import android.graphics.Color;
     27 import android.graphics.Paint;
     28 import android.graphics.Picture;
     29 import android.graphics.Rect;
     30 import android.os.Handler;
     31 import android.support.test.filters.LargeTest;
     32 import android.support.test.runner.AndroidJUnit4;
     33 import android.uirendering.cts.R;
     34 import android.uirendering.cts.bitmapcomparers.MSSIMComparer;
     35 import android.uirendering.cts.bitmapverifiers.BitmapVerifier;
     36 import android.uirendering.cts.bitmapverifiers.ColorCountVerifier;
     37 import android.uirendering.cts.bitmapverifiers.RectVerifier;
     38 import android.uirendering.cts.testinfrastructure.ActivityTestBase;
     39 import android.uirendering.cts.testinfrastructure.ViewInitializer;
     40 import android.view.FrameMetrics;
     41 import android.view.View;
     42 import android.view.ViewAnimationUtils;
     43 import android.view.Window;
     44 import android.widget.FrameLayout;
     45 
     46 import org.junit.Assert;
     47 import org.junit.Test;
     48 import org.junit.runner.RunWith;
     49 
     50 import java.util.Arrays;
     51 
     52 @LargeTest
     53 @RunWith(AndroidJUnit4.class)
     54 public class BitmapTests extends ActivityTestBase {
     55     class BitmapView extends View {
     56         private Bitmap mBitmap;
     57         private int mColor;
     58 
     59         public BitmapView(Context context) {
     60             super(context);
     61             mBitmap = Bitmap.createBitmap(1, 1, Bitmap.Config.ARGB_8888);
     62             setColor(Color.BLUE);
     63         }
     64 
     65         @Override
     66         protected void onDraw(Canvas canvas) {
     67             canvas.drawBitmap(mBitmap, new Rect(0, 0, 1, 1), canvas.getClipBounds(), null);
     68         }
     69 
     70         public void setColor(int color) {
     71             mColor = color;
     72             mBitmap.setPixel(0, 0, color);
     73         }
     74 
     75         public int getColor() {
     76             return mColor;
     77         }
     78     }
     79 
     80     /*
     81      * The following test verifies that bitmap changes during render thread animation won't
     82      * be visible: we changed a bitmap from blue to red during circular reveal (an RT animation),
     83      * and changed it back to blue before the end of the animation; we should never see any
     84      * red pixel.
     85      */
     86     @Test
     87     public void testChangeDuringRtAnimation() {
     88         class RtOnlyFrameCounter implements Window.OnFrameMetricsAvailableListener {
     89             private int count = 0;
     90 
     91             @Override
     92             public void onFrameMetricsAvailable(Window window, FrameMetrics frameMetrics,
     93                     int dropCountSinceLastInvocation) {
     94                 if (frameMetrics.getMetric(FrameMetrics.ANIMATION_DURATION) == 0
     95                         && frameMetrics.getMetric(FrameMetrics.INPUT_HANDLING_DURATION) == 0
     96                         && frameMetrics.getMetric(FrameMetrics.LAYOUT_MEASURE_DURATION) == 0) {
     97                     count++;
     98                 };
     99             }
    100 
    101             public boolean isLargeEnough() {
    102                 return count >= 5;
    103             }
    104         }
    105 
    106         RtOnlyFrameCounter counter = new RtOnlyFrameCounter();
    107 
    108         ViewInitializer initializer = new ViewInitializer() {
    109             Animator mAnimator;
    110 
    111             @Override
    112             public void initializeView(View view) {
    113                 FrameLayout root = (FrameLayout) view.findViewById(R.id.frame_layout);
    114 
    115                 final BitmapView child = new BitmapView(view.getContext());
    116                 child.setLayoutParams(new FrameLayout.LayoutParams(50, 50));
    117                 root.addView(child);
    118 
    119                 mAnimator = ViewAnimationUtils.createCircularReveal(child, 0, 0, 0, 90);
    120                 mAnimator.setDuration(3000);
    121                 mAnimator.start();
    122 
    123                 Handler handler = new Handler();
    124                 handler.postDelayed(new Runnable() {
    125                     @Override
    126                     public void run() {
    127                         child.setColor(Color.RED);
    128                         try {
    129                             Thread.sleep(1000);
    130                         } catch (Exception e) {
    131                             // do nothing
    132                         }
    133                         child.setColor(Color.BLUE);
    134                     }
    135                 }, 1000);
    136                 getActivity().getWindow().addOnFrameMetricsAvailableListener(counter, handler);
    137             }
    138 
    139             @Override
    140             public void teardownView() {
    141                 mAnimator.cancel();
    142                 getActivity().getWindow().removeOnFrameMetricsAvailableListener(counter);
    143             }
    144         };
    145 
    146         createTest()
    147                 .addLayout(R.layout.frame_layout, initializer, true)
    148                 .runWithAnimationVerifier(new ColorCountVerifier(Color.RED, 0));
    149 
    150         Assert.assertTrue(counter.isLargeEnough());
    151     }
    152 
    153     /*
    154      * The following test verifies that bitmap changes during UI thread animation are
    155      * visible: we keep changing a bitmap's color between red and blue in sync with the
    156      * background, and we should only see pure blue or red.
    157     */
    158     @Test
    159     public void testChangeDuringUiAnimation() {
    160         class BlueOrRedVerifier extends BitmapVerifier {
    161             @Override
    162             public boolean verify(int[] bitmap, int offset, int stride, int width, int height) {
    163                 MSSIMComparer comparer = new MSSIMComparer(0.99);
    164                 int[] red  = new int[offset + height * stride];
    165                 Arrays.fill(red, Color.RED);
    166                 int[] blue  = new int[offset + height * stride];
    167                 Arrays.fill(blue, Color.BLUE);
    168                 boolean isRed = comparer.verifySame(red, bitmap, offset, stride, width, height);
    169                 boolean isBlue = comparer.verifySame(blue, bitmap, offset, stride, width, height);
    170                 return isRed || isBlue;
    171             }
    172         }
    173 
    174         ViewInitializer initializer = new ViewInitializer() {
    175             ValueAnimator mAnimator;
    176 
    177             @Override
    178             public void initializeView(View view) {
    179                 FrameLayout root = (FrameLayout) view.findViewById(R.id.frame_layout);
    180                 root.setBackgroundColor(Color.BLUE);
    181 
    182                 final BitmapView child = new BitmapView(view.getContext());
    183 
    184                 // The child size is strictly less than the test canvas size,
    185                 // and we are moving it up and down inside the canvas.
    186                 child.setLayoutParams(new FrameLayout.LayoutParams(ActivityTestBase.TEST_WIDTH / 2,
    187                         ActivityTestBase.TEST_HEIGHT / 2));
    188                 root.addView(child);
    189                 child.setColor(Color.BLUE);
    190 
    191                 mAnimator = ValueAnimator.ofInt(0, ActivityTestBase.TEST_HEIGHT / 2);
    192                 mAnimator.setRepeatMode(mAnimator.REVERSE);
    193                 mAnimator.setRepeatCount(mAnimator.INFINITE);
    194                 mAnimator.setDuration(400);
    195                 mAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
    196                     @Override
    197                     public void onAnimationUpdate(ValueAnimator animation) {
    198                         int v = (Integer) mAnimator.getAnimatedValue();
    199                         child.setTranslationY(v);
    200                         if (child.getColor() == Color.BLUE) {
    201                             root.setBackgroundColor(Color.RED);
    202                             child.setColor(Color.RED);
    203                         } else {
    204                             root.setBackgroundColor(Color.BLUE);
    205                             child.setColor(Color.BLUE);
    206                         }
    207                     }
    208                 });
    209                 mAnimator.start();
    210             }
    211 
    212             @Override
    213             public void teardownView() {
    214                 mAnimator.cancel();
    215             }
    216         };
    217 
    218         createTest()
    219                 .addLayout(R.layout.frame_layout, initializer, true)
    220                 .runWithAnimationVerifier(new BlueOrRedVerifier());
    221     }
    222 
    223     @Test
    224     public void testCreateFromPicture() {
    225         final Rect rect = new Rect(10, 10, 80, 80);
    226         Picture picture = new Picture();
    227         {
    228             Canvas canvas = picture.beginRecording(TEST_WIDTH, TEST_HEIGHT);
    229             Paint p = new Paint();
    230             p.setAntiAlias(false);
    231             p.setColor(Color.BLUE);
    232             canvas.drawRect(rect, p);
    233             picture.endRecording();
    234         }
    235         Bitmap bitmap = Bitmap.createBitmap(picture, picture.getWidth(),
    236                 picture.getHeight(), Bitmap.Config.ARGB_8888);
    237         assertEquals(TEST_WIDTH, bitmap.getWidth());
    238         assertEquals(TEST_HEIGHT, bitmap.getHeight());
    239         assertEquals(Bitmap.Config.ARGB_8888, bitmap.getConfig());
    240         createTest().addCanvasClient((canvas, width, height) -> {
    241             canvas.drawBitmap(bitmap, 0, 0, null);
    242         }, true).runWithVerifier(new RectVerifier(Color.WHITE, Color.BLUE, rect));
    243     }
    244 }
    245