Home | History | Annotate | Download | only in cts
      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.view.cts;
     18 
     19 import static org.junit.Assert.fail;
     20 
     21 import android.app.Activity;
     22 import android.content.Context;
     23 import android.content.pm.ActivityInfo;
     24 import android.content.pm.PackageManager;
     25 import android.graphics.Canvas;
     26 import android.graphics.Color;
     27 import android.graphics.Paint;
     28 import android.graphics.Point;
     29 import android.graphics.Rect;
     30 import android.os.Bundle;
     31 import android.view.View;
     32 import android.view.ViewTreeObserver.OnDrawListener;
     33 import android.view.WindowInsets;
     34 import android.widget.FrameLayout;
     35 
     36 import java.util.concurrent.CountDownLatch;
     37 import java.util.concurrent.TimeUnit;
     38 
     39 public class PixelCopyViewProducerActivity extends Activity implements OnDrawListener,
     40         View.OnApplyWindowInsetsListener{
     41     private static final int[] ORIENTATIONS = {
     42             ActivityInfo.SCREEN_ORIENTATION_PORTRAIT,
     43             ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE,
     44             ActivityInfo.SCREEN_ORIENTATION_REVERSE_PORTRAIT,
     45             ActivityInfo.SCREEN_ORIENTATION_REVERSE_LANDSCAPE,
     46     };
     47     private int mCurrentOrientation = 0;
     48     private View mContent;
     49     private Rect mContentBounds = new Rect();
     50     private Rect mOutsets = new Rect();
     51     private CountDownLatch mFence = new CountDownLatch(3);
     52     private boolean mSupportsRotation;
     53 
     54     @Override
     55     protected void onCreate(Bundle savedInstanceState) {
     56         super.onCreate(savedInstanceState);
     57 
     58         // Check if the device supports both of portrait and landscape orientation screens.
     59         final PackageManager pm = getPackageManager();
     60         mSupportsRotation = pm.hasSystemFeature(PackageManager.FEATURE_SCREEN_LANDSCAPE)
     61                     && pm.hasSystemFeature(PackageManager.FEATURE_SCREEN_PORTRAIT);
     62         if (mSupportsRotation) {
     63             setRequestedOrientation(ORIENTATIONS[mCurrentOrientation]);
     64         }
     65 
     66         mContent = new ColoredGrid(this);
     67         setContentView(mContent);
     68         mContent.getViewTreeObserver().addOnDrawListener(this);
     69         mContent.setOnApplyWindowInsetsListener(this);
     70     }
     71 
     72     @Override
     73     public void onDraw() {
     74         final int requestedOrientation = ORIENTATIONS[mCurrentOrientation];
     75         boolean screenPortrait =
     76                 requestedOrientation == ActivityInfo.SCREEN_ORIENTATION_PORTRAIT
     77                 || requestedOrientation == ActivityInfo.SCREEN_ORIENTATION_REVERSE_PORTRAIT;
     78         boolean contentPortrait = mContent.getHeight() > mContent.getWidth();
     79         if (mSupportsRotation && (screenPortrait != contentPortrait)) {
     80             return;
     81         }
     82         mContent.post(() -> {
     83             Point offset = new Point();
     84             // We pass mContentBounds here just as a throwaway rect, we don't care about
     85             // the visible rect just the global offset.
     86             mContent.getGlobalVisibleRect(mContentBounds, offset);
     87             mContentBounds.set(offset.x - mOutsets.left, offset.y - mOutsets.top,
     88                     offset.x - mOutsets.left + mContent.getWidth(),
     89                     offset.y - mOutsets.top + mContent.getHeight());
     90             mFence.countDown();
     91             if (mFence.getCount() > 0) {
     92                 mContent.invalidate();
     93             }
     94         });
     95     }
     96 
     97     @Override
     98     public WindowInsets onApplyWindowInsets(View v, WindowInsets in) {
     99         if (in.isRound()) {
    100             FrameLayout.LayoutParams params = (FrameLayout.LayoutParams) mContent.getLayoutParams();
    101             params.setMargins(in.getSystemWindowInsetLeft(), in.getSystemWindowInsetTop(),
    102                     in.getSystemWindowInsetRight(), in.getSystemWindowInsetBottom());
    103             mOutsets = new Rect(in.getSystemWindowInsetLeft(), in.getSystemWindowInsetTop(),
    104                     in.getSystemWindowInsetRight(), in.getSystemWindowInsetBottom());
    105             mContent.setLayoutParams(params);
    106         }
    107         return in;
    108     }
    109 
    110     public void waitForFirstDrawCompleted(int timeout, TimeUnit unit) {
    111         try {
    112             if (!mFence.await(timeout, unit)) {
    113                 fail("Timeout");
    114             }
    115         } catch (InterruptedException ex) {
    116             fail(ex.getMessage());
    117         }
    118     }
    119 
    120     public boolean rotate() {
    121         if (!mSupportsRotation) {
    122             // Do not rotate the screen if it is not supported.
    123             return false;
    124         }
    125         mFence = new CountDownLatch(3);
    126         runOnUiThread(() -> {
    127             mCurrentOrientation = (mCurrentOrientation + 1) % ORIENTATIONS.length;
    128             setRequestedOrientation(ORIENTATIONS[mCurrentOrientation]);
    129         });
    130         waitForFirstDrawCompleted(10, TimeUnit.SECONDS);
    131         return mCurrentOrientation != 0;
    132     }
    133 
    134     // Convert a rect in normalized 0-100 dimensions to the bounds of the actual View.
    135     public void normalizedToSurface(Rect inOut) {
    136         float sx = mContentBounds.width() / 100.0f;
    137         float sy = mContentBounds.height() / 100.0f;
    138         inOut.left = (int) (inOut.left * sx);
    139         inOut.top = (int) (inOut.top * sy);
    140         inOut.right = (int) (inOut.right * sx + 0.5f);
    141         inOut.bottom = (int) (inOut.bottom * sy + 0.5f);
    142         inOut.offset(mContentBounds.left, mContentBounds.top);
    143     }
    144 
    145     private static final class ColoredGrid extends View {
    146         private Paint mPaint = new Paint();
    147         private Rect mRect = new Rect();
    148 
    149         ColoredGrid(Context context) {
    150             super(context);
    151             setWillNotDraw(false);
    152         }
    153 
    154         @Override
    155         protected void onDraw(Canvas canvas) {
    156             int cx = getWidth() / 2;
    157             int cy = getHeight() / 2;
    158 
    159             canvas.drawColor(Color.YELLOW);
    160 
    161             mRect.set(1, 1, cx, cy);
    162             mPaint.setColor(Color.RED);
    163             canvas.drawRect(mRect, mPaint);
    164 
    165             mRect.set(cx, 1, getWidth() - 1, cy);
    166             mPaint.setColor(Color.GREEN);
    167             canvas.drawRect(mRect, mPaint);
    168 
    169             mRect.set(1, cy, cx, getHeight() - 1);
    170             mPaint.setColor(Color.BLUE);
    171             canvas.drawRect(mRect, mPaint);
    172 
    173             mRect.set(cx, cy, getWidth() - 1, getHeight() - 1);
    174             mPaint.setColor(Color.BLACK);
    175             canvas.drawRect(mRect, mPaint);
    176         }
    177     }
    178 }
    179