| /* |
| * Copyright (C) 2016 The Android Open Source Project |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| |
| package android.view.cts; |
| |
| import static org.junit.Assert.fail; |
| |
| import android.app.Activity; |
| import android.content.Context; |
| import android.content.pm.ActivityInfo; |
| import android.content.pm.PackageManager; |
| import android.graphics.Canvas; |
| import android.graphics.Color; |
| import android.graphics.Paint; |
| import android.graphics.Point; |
| import android.graphics.Rect; |
| import android.os.Bundle; |
| import android.view.View; |
| import android.view.ViewTreeObserver.OnDrawListener; |
| import android.view.WindowInsets; |
| import android.widget.FrameLayout; |
| |
| import java.util.concurrent.CountDownLatch; |
| import java.util.concurrent.TimeUnit; |
| |
| public class PixelCopyViewProducerActivity extends Activity implements OnDrawListener, |
| View.OnApplyWindowInsetsListener{ |
| private static final int[] ORIENTATIONS = { |
| ActivityInfo.SCREEN_ORIENTATION_PORTRAIT, |
| ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE, |
| ActivityInfo.SCREEN_ORIENTATION_REVERSE_PORTRAIT, |
| ActivityInfo.SCREEN_ORIENTATION_REVERSE_LANDSCAPE, |
| }; |
| private int mCurrentOrientation = 0; |
| private View mContent; |
| private Rect mContentBounds = new Rect(); |
| private Rect mOutsets = new Rect(); |
| private CountDownLatch mFence = new CountDownLatch(3); |
| private boolean mSupportsRotation; |
| |
| @Override |
| protected void onCreate(Bundle savedInstanceState) { |
| super.onCreate(savedInstanceState); |
| |
| // Check if the device supports both of portrait and landscape orientation screens. |
| final PackageManager pm = getPackageManager(); |
| mSupportsRotation = pm.hasSystemFeature(PackageManager.FEATURE_SCREEN_LANDSCAPE) |
| && pm.hasSystemFeature(PackageManager.FEATURE_SCREEN_PORTRAIT); |
| if (mSupportsRotation) { |
| setRequestedOrientation(ORIENTATIONS[mCurrentOrientation]); |
| } |
| |
| mContent = new ColoredGrid(this); |
| setContentView(mContent); |
| View view = this.getWindow().getDecorView(); |
| view.setSystemUiVisibility(View.SYSTEM_UI_FLAG_HIDE_NAVIGATION); |
| mContent.getViewTreeObserver().addOnDrawListener(this); |
| mContent.setOnApplyWindowInsetsListener(this); |
| } |
| |
| @Override |
| public void onDraw() { |
| final int requestedOrientation = ORIENTATIONS[mCurrentOrientation]; |
| boolean screenPortrait = |
| requestedOrientation == ActivityInfo.SCREEN_ORIENTATION_PORTRAIT |
| || requestedOrientation == ActivityInfo.SCREEN_ORIENTATION_REVERSE_PORTRAIT; |
| boolean contentPortrait = mContent.getHeight() > mContent.getWidth(); |
| if (mSupportsRotation && (screenPortrait != contentPortrait)) { |
| return; |
| } |
| mContent.post(() -> { |
| Point offset = new Point(); |
| // We pass mContentBounds here just as a throwaway rect, we don't care about |
| // the visible rect just the global offset. |
| mContent.getGlobalVisibleRect(mContentBounds, offset); |
| mContentBounds.set(offset.x - mOutsets.left, offset.y - mOutsets.top, |
| offset.x - mOutsets.left + mContent.getWidth(), |
| offset.y - mOutsets.top + mContent.getHeight()); |
| mFence.countDown(); |
| if (mFence.getCount() > 0) { |
| mContent.invalidate(); |
| } |
| }); |
| } |
| |
| @Override |
| public WindowInsets onApplyWindowInsets(View v, WindowInsets in) { |
| if (in.isRound()) { |
| FrameLayout.LayoutParams params = (FrameLayout.LayoutParams) mContent.getLayoutParams(); |
| params.setMargins(in.getSystemWindowInsetLeft(), in.getSystemWindowInsetTop(), |
| in.getSystemWindowInsetRight(), in.getSystemWindowInsetBottom()); |
| mOutsets = new Rect(in.getSystemWindowInsetLeft(), in.getSystemWindowInsetTop(), |
| in.getSystemWindowInsetRight(), in.getSystemWindowInsetBottom()); |
| mContent.setLayoutParams(params); |
| } |
| return in; |
| } |
| |
| public void waitForFirstDrawCompleted(int timeout, TimeUnit unit) { |
| try { |
| if (!mFence.await(timeout, unit)) { |
| fail("Timeout"); |
| } |
| } catch (InterruptedException ex) { |
| fail(ex.getMessage()); |
| } |
| } |
| |
| public boolean rotate() { |
| if (!mSupportsRotation) { |
| // Do not rotate the screen if it is not supported. |
| return false; |
| } |
| mFence = new CountDownLatch(3); |
| runOnUiThread(() -> { |
| mCurrentOrientation = (mCurrentOrientation + 1) % ORIENTATIONS.length; |
| setRequestedOrientation(ORIENTATIONS[mCurrentOrientation]); |
| }); |
| waitForFirstDrawCompleted(10, TimeUnit.SECONDS); |
| return mCurrentOrientation != 0; |
| } |
| |
| // Convert a rect in normalized 0-100 dimensions to the bounds of the actual View. |
| public void normalizedToSurface(Rect inOut) { |
| float sx = mContentBounds.width() / 100.0f; |
| float sy = mContentBounds.height() / 100.0f; |
| inOut.left = (int) (inOut.left * sx); |
| inOut.top = (int) (inOut.top * sy); |
| inOut.right = (int) (inOut.right * sx + 0.5f); |
| inOut.bottom = (int) (inOut.bottom * sy + 0.5f); |
| inOut.offset(mContentBounds.left, mContentBounds.top); |
| } |
| |
| private static final class ColoredGrid extends View { |
| private Paint mPaint = new Paint(); |
| private Rect mRect = new Rect(); |
| |
| ColoredGrid(Context context) { |
| super(context); |
| setWillNotDraw(false); |
| } |
| |
| @Override |
| protected void onDraw(Canvas canvas) { |
| int cx = getWidth() / 2; |
| int cy = getHeight() / 2; |
| |
| canvas.drawColor(Color.YELLOW); |
| |
| mRect.set(1, 1, cx, cy); |
| mPaint.setColor(Color.RED); |
| canvas.drawRect(mRect, mPaint); |
| |
| mRect.set(cx, 1, getWidth() - 1, cy); |
| mPaint.setColor(Color.GREEN); |
| canvas.drawRect(mRect, mPaint); |
| |
| mRect.set(1, cy, cx, getHeight() - 1); |
| mPaint.setColor(Color.BLUE); |
| canvas.drawRect(mRect, mPaint); |
| |
| mRect.set(cx, cy, getWidth() - 1, getHeight() - 1); |
| mPaint.setColor(Color.BLACK); |
| canvas.drawRect(mRect, mPaint); |
| } |
| } |
| } |