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