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