blob: 054de455cfc3a8a09051f83a5b94835b9f352391 [file] [log] [blame]
/*
* 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);
}
}
}