1 /**
2  * Copyright (C) 2017 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
5  * in compliance with the License. You may obtain a copy of the License at
6  *
7  * http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software distributed under the
10  * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
11  * express or implied. See the License for the specific language governing permissions and
12  * limitations under the License.
13  */
14 
15 package android.accessibilityservice.cts.utils;
16 
17 import static android.hardware.display.DisplayManager.VIRTUAL_DISPLAY_FLAG_OWN_CONTENT_ONLY;
18 import static android.hardware.display.DisplayManager.VIRTUAL_DISPLAY_FLAG_PUBLIC;
19 import static android.view.Display.DEFAULT_DISPLAY;
20 
21 import android.app.Activity;
22 import android.content.Context;
23 import android.graphics.PixelFormat;
24 import android.graphics.Rect;
25 import android.hardware.display.DisplayManager;
26 import android.hardware.display.VirtualDisplay;
27 import android.media.ImageReader;
28 import android.os.Looper;
29 import android.util.DisplayMetrics;
30 import android.view.Display;
31 import android.view.Window;
32 
33 import com.android.compatibility.common.util.TestUtils;
34 
35 /**
36  * Utilities needed when interacting with the display
37  */
38 public class DisplayUtils {
39     private static final int DISPLAY_ADDED_TIMEOUT_MS = 5000;
40 
getStatusBarHeight(Activity activity)41     public static int getStatusBarHeight(Activity activity) {
42         final Rect rect = new Rect();
43         Window window = activity.getWindow();
44         window.getDecorView().getWindowVisibleDisplayFrame(rect);
45         return rect.top;
46     }
47 
48     public static class VirtualDisplaySession implements AutoCloseable {
49         private VirtualDisplay mVirtualDisplay;
50         private ImageReader mReader;
51 
createDisplay(Context context, int width, int height, int density, boolean isPrivate)52         public Display createDisplay(Context context, int width, int height, int density,
53                 boolean isPrivate) {
54             if (mReader != null) {
55                 throw new IllegalStateException(
56                         "Only one display can be created during this session.");
57             }
58             mReader = ImageReader.newInstance(width, height, PixelFormat.RGBA_8888,
59                     1 /* maxImages */);
60             int flags = isPrivate ? 0
61                     :(VIRTUAL_DISPLAY_FLAG_OWN_CONTENT_ONLY | VIRTUAL_DISPLAY_FLAG_PUBLIC);
62             mVirtualDisplay = context.getSystemService(DisplayManager.class).createVirtualDisplay(
63                     "A11yDisplay", width, height, density, mReader.getSurface(), flags);
64             return mVirtualDisplay.getDisplay();
65         }
66 
67         @Override
close()68         public void close() {
69             if (mVirtualDisplay != null) {
70                 mVirtualDisplay.release();
71             }
72             if (mReader != null) {
73                 mReader.close();
74             }
75         }
76 
77         /**
78          * Creates a virtual display having same size with default display and waits until it's
79          * in display list. The density of the virtual display is based on
80          * {@link DisplayMetrics#xdpi} so that the threshold of gesture detection is same as
81          * the default display's.
82          *
83          * @param context
84          * @param isPrivate if this display is a private display.
85          * @return virtual display.
86          *
87          * @throws IllegalStateException if called from main thread.
88          */
createDisplayWithDefaultDisplayMetricsAndWait(Context context, boolean isPrivate)89         public Display createDisplayWithDefaultDisplayMetricsAndWait(Context context,
90                 boolean isPrivate) {
91             if (Looper.myLooper() == Looper.getMainLooper()) {
92                 throw new IllegalStateException("Should not call from main thread");
93             }
94 
95             final Object waitObject = new Object();
96             final DisplayManager.DisplayListener listener = new DisplayManager.DisplayListener() {
97                 @Override
98                 public void onDisplayAdded(int i) {
99                     synchronized (waitObject) {
100                         waitObject.notifyAll();
101                     }
102                 }
103 
104                 @Override
105                 public void onDisplayRemoved(int i) {
106                 }
107 
108                 @Override
109                 public void onDisplayChanged(int i) {
110                 }
111             };
112             final DisplayManager displayManager = (DisplayManager) context.getSystemService(
113                     Context.DISPLAY_SERVICE);
114             displayManager.registerDisplayListener(listener, null);
115 
116             final DisplayMetrics metrics = new DisplayMetrics();
117             displayManager.getDisplay(DEFAULT_DISPLAY).getRealMetrics(metrics);
118             final Display display = createDisplay(context, metrics.widthPixels,
119                     metrics.heightPixels, (int) metrics.xdpi, isPrivate);
120 
121             try {
122                 TestUtils.waitOn(waitObject,
123                         () -> displayManager.getDisplay(display.getDisplayId()) != null,
124                         DISPLAY_ADDED_TIMEOUT_MS,
125                         String.format("wait for virtual display %d adding", display.getDisplayId()));
126             } finally {
127                 displayManager.unregisterDisplayListener(listener);
128             }
129             return display;
130         }
131     }
132 }
133