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 android.app.Activity;
20 import android.content.Context;
21 import android.content.pm.ActivityInfo;
22 import android.content.pm.PackageManager;
23 import android.content.res.AssetManager;
24 import android.graphics.Bitmap;
25 import android.graphics.BitmapFactory;
26 import android.graphics.Canvas;
27 import android.graphics.Point;
28 import android.graphics.Rect;
29 import android.os.Bundle;
30 import android.view.View;
31 import android.view.ViewTreeObserver.OnDrawListener;
32 
33 import java.io.IOException;
34 import java.io.InputStream;
35 import java.util.concurrent.CountDownLatch;
36 import java.util.concurrent.TimeUnit;
37 
38 import static org.junit.Assert.fail;
39 
40 public class PixelCopyWideGamutViewProducerActivity extends Activity implements OnDrawListener {
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 CountDownLatch mFence = new CountDownLatch(3);
51     private boolean mSupportsRotation;
52 
53     @Override
onCreate(Bundle savedInstanceState)54     protected void onCreate(Bundle savedInstanceState) {
55         super.onCreate(savedInstanceState);
56 
57         // Check if the device supports both of portrait and landscape orientation screens.
58         final PackageManager pm = getPackageManager();
59         mSupportsRotation = pm.hasSystemFeature(PackageManager.FEATURE_SCREEN_LANDSCAPE)
60                     && pm.hasSystemFeature(PackageManager.FEATURE_SCREEN_PORTRAIT);
61         if (mSupportsRotation) {
62             setRequestedOrientation(ORIENTATIONS[mCurrentOrientation]);
63         }
64 
65         mContent = new WideGamutBitmapView(this);
66         setContentView(mContent);
67         View view = this.getWindow().getDecorView();
68         view.setSystemUiVisibility(View.SYSTEM_UI_FLAG_HIDE_NAVIGATION);
69         mContent.getViewTreeObserver().addOnDrawListener(this);
70     }
71 
72     @Override
onDraw()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, offset.y,
88                     offset.x + mContent.getWidth(), offset.y + mContent.getHeight());
89             mFence.countDown();
90             if (mFence.getCount() > 0) {
91                 mContent.invalidate();
92             }
93         });
94     }
95 
waitForFirstDrawCompleted(int timeout, TimeUnit unit)96     public void waitForFirstDrawCompleted(int timeout, TimeUnit unit) {
97         try {
98             if (!mFence.await(timeout, unit)) {
99                 fail("Timeout");
100             }
101         } catch (InterruptedException ex) {
102             fail(ex.getMessage());
103         }
104     }
105 
rotate()106     public boolean rotate() {
107         if (!mSupportsRotation) {
108             // Do not rotate the screen if it is not supported.
109             return false;
110         }
111         mFence = new CountDownLatch(3);
112         runOnUiThread(() -> {
113             mCurrentOrientation = (mCurrentOrientation + 1) % ORIENTATIONS.length;
114             setRequestedOrientation(ORIENTATIONS[mCurrentOrientation]);
115         });
116         waitForFirstDrawCompleted(3, TimeUnit.SECONDS);
117         return mCurrentOrientation != 0;
118     }
119 
offsetForContent(Rect inOut)120     void offsetForContent(Rect inOut) {
121         inOut.offset(mContentBounds.left, mContentBounds.top);
122     }
123 
124     private static final class WideGamutBitmapView extends View {
125         private final Bitmap mBitmap;
126 
WideGamutBitmapView(Context context)127         WideGamutBitmapView(Context context) {
128             super(context);
129             // We use an asset to ensure aapt will not mess with the data
130             AssetManager assets = context.getResources().getAssets();
131             try (InputStream in = assets.open("prophoto.png")) {
132                 mBitmap = BitmapFactory.decodeStream(in);
133             } catch (IOException e) {
134                 throw new RuntimeException("Test failed: ", e);
135             }
136         }
137 
138         @Override
onDraw(Canvas canvas)139         protected void onDraw(Canvas canvas) {
140             canvas.drawBitmap(mBitmap, 0.0f, 0.0f, null);
141         }
142     }
143 }
144