• 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 
getContentView()77     public View getContentView() {
78         return mContent;
79     }
80 
81     @Override
onDraw()82     public void onDraw() {
83         final int requestedOrientation = ORIENTATIONS[mCurrentOrientation];
84         boolean isRequestingPortrait =
85                 requestedOrientation == ActivityInfo.SCREEN_ORIENTATION_PORTRAIT
86                 || requestedOrientation == ActivityInfo.SCREEN_ORIENTATION_REVERSE_PORTRAIT;
87         if (mSupportsRotation && (isRequestingPortrait != DisplayUtils.isDevicePortrait(this))) {
88             return;
89         }
90         mContent.post(() -> {
91             Point offset = new Point();
92             // We pass mContentBounds here just as a throwaway rect, we don't care about
93             // the visible rect just the global offset.
94             mContent.getGlobalVisibleRect(mContentBounds, offset);
95             mContentBounds.set(offset.x - mOutsets.left, offset.y - mOutsets.top,
96                     offset.x - mOutsets.left + mContent.getWidth(),
97                     offset.y - mOutsets.top + mContent.getHeight());
98             mFence.countDown();
99             if (mFence.getCount() > 0) {
100                 mContent.invalidate();
101             }
102         });
103     }
104 
105     @Override
onApplyWindowInsets(View v, WindowInsets in)106     public WindowInsets onApplyWindowInsets(View v, WindowInsets in) {
107         if (in.isRound()) {
108             FrameLayout.LayoutParams params = (FrameLayout.LayoutParams) mContent.getLayoutParams();
109             params.setMargins(in.getSystemWindowInsetLeft(), in.getSystemWindowInsetTop(),
110                     in.getSystemWindowInsetRight(), in.getSystemWindowInsetBottom());
111             mOutsets = new Rect(in.getSystemWindowInsetLeft(), in.getSystemWindowInsetTop(),
112                     in.getSystemWindowInsetRight(), in.getSystemWindowInsetBottom());
113             mContent.setLayoutParams(params);
114         }
115         return in;
116     }
117 
waitForFirstDrawCompleted(int timeout, TimeUnit unit)118     public void waitForFirstDrawCompleted(int timeout, TimeUnit unit) {
119         try {
120             if (!mFence.await(timeout, unit)) {
121                 fail("Timeout");
122             }
123         } catch (InterruptedException ex) {
124             fail(ex.getMessage());
125         }
126     }
127 
rotate()128     public boolean rotate() {
129         if (!mSupportsRotation) {
130             // Do not rotate the screen if it is not supported.
131             return false;
132         }
133         mFence = new CountDownLatch(DRAW_FRAME_COUNT_BEFORE_CAPTURE);
134         runOnUiThread(() -> {
135             mCurrentOrientation = (mCurrentOrientation + 1) % ORIENTATIONS.length;
136             Log.d("PixelCopyTest", "Setting orientation index = " + mCurrentOrientation);
137             setRequestedOrientation(ORIENTATIONS[mCurrentOrientation]);
138         });
139         waitForFirstDrawCompleted(10, TimeUnit.SECONDS);
140         return mCurrentOrientation != 0;
141     }
142 
143     // Convert a rect in normalized 0-100 dimensions to the bounds of the actual View.
normalizedToSurface(Rect inOut)144     public void normalizedToSurface(Rect inOut) {
145         float sx = mContentBounds.width() / 100.0f;
146         float sy = mContentBounds.height() / 100.0f;
147         inOut.left = (int) (inOut.left * sx);
148         inOut.top = (int) (inOut.top * sy);
149         inOut.right = (int) (inOut.right * sx + 0.5f);
150         inOut.bottom = (int) (inOut.bottom * sy + 0.5f);
151         inOut.offset(mContentBounds.left, mContentBounds.top);
152     }
153 
154     private static final class ColoredGrid extends View {
155         private Paint mPaint = new Paint();
156         private Rect mRect = new Rect();
157 
ColoredGrid(Context context)158         ColoredGrid(Context context) {
159             super(context);
160             setWillNotDraw(false);
161         }
162 
163         @Override
onDraw(Canvas canvas)164         protected void onDraw(Canvas canvas) {
165             int cx = getWidth() / 2;
166             int cy = getHeight() / 2;
167             final int BORDER_WIDTH = 2;
168 
169             canvas.drawColor(Color.YELLOW);
170 
171             mRect.set(BORDER_WIDTH, BORDER_WIDTH, cx, cy);
172             mPaint.setColor(Color.RED);
173             canvas.drawRect(mRect, mPaint);
174 
175             mRect.set(cx, BORDER_WIDTH, getWidth() - BORDER_WIDTH, cy);
176             mPaint.setColor(Color.GREEN);
177             canvas.drawRect(mRect, mPaint);
178 
179             mRect.set(BORDER_WIDTH, cy, cx, getHeight() - BORDER_WIDTH);
180             mPaint.setColor(Color.BLUE);
181             canvas.drawRect(mRect, mPaint);
182 
183             mRect.set(cx, cy, getWidth() - BORDER_WIDTH, getHeight() - BORDER_WIDTH);
184             mPaint.setColor(Color.BLACK);
185             canvas.drawRect(mRect, mPaint);
186         }
187     }
188 }
189