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