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