1 /*
2  * Copyright (C) 2023 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.accessibilityservice.cts.utils;
18 
19 import static android.accessibilityservice.cts.utils.AccessibilityEventFilterUtils.filterWindowsChangedWithChangeTypes;
20 import static android.accessibilityservice.cts.utils.DisplayUtils.getStatusBarHeight;
21 import static android.view.accessibility.AccessibilityEvent.WINDOWS_CHANGE_REMOVED;
22 
23 import android.app.Activity;
24 import android.app.Instrumentation;
25 import android.app.UiAutomation;
26 import android.view.Gravity;
27 import android.view.View;
28 import android.view.WindowManager;
29 
30 import java.util.concurrent.TimeoutException;
31 
32 /**
33  * Utility class for launching and positioning new windows given an already-launched Activity.
34  * This is useful when testing interactions where multiple AccessibilityWindowInfos are on screen,
35  * and an activity has already been launched.
36  */
37 public class WindowCreationUtils {
38     public static final CharSequence TOP_WINDOW_TITLE =
39             "android.accessibilityservice.cts.TOP_WINDOW_TITLE";
40 
41     /**
42      * Returns the layout specifications for a test window of type TYPE_APPLICATION_PANEL that lies
43      * at the top of the screen.
44      * @param instrumentation the test instrumentation.
45      * @param activity the activity to specify the layout params against.
46      * @param windowTitle the title of the test window.
47      * @return the layout params.
48      */
layoutParamsForWindowOnTop( Instrumentation instrumentation, Activity activity, CharSequence windowTitle)49     public static WindowManager.LayoutParams layoutParamsForWindowOnTop(
50             Instrumentation instrumentation, Activity activity, CharSequence windowTitle) {
51         return layoutParamsForWindowOnTop(instrumentation, activity, windowTitle,
52                 WindowManager.LayoutParams.MATCH_PARENT,
53                 WindowManager.LayoutParams.WRAP_CONTENT);
54     }
55 
56     /**
57      * Returns the layout specifications for a test window of type TYPE_APPLICATION_PANEL that lies
58      * at the top of the screen.
59      * @param instrumentation the test instrumentation.
60      * @param activity the activity to specify the layout params against.
61      * @param windowTitle the title of the test window.
62      * @return the layout params.
63      */
layoutParamsForWindowOnTop( Instrumentation instrumentation, Activity activity, CharSequence windowTitle, int width, int height)64     public static WindowManager.LayoutParams layoutParamsForWindowOnTop(
65             Instrumentation instrumentation, Activity activity, CharSequence windowTitle,
66             int width, int height) {
67         final WindowManager.LayoutParams params =
68                 layoutParamsForTestWindow(instrumentation, activity, width, height);
69         params.gravity = Gravity.TOP;
70         params.setTitle(windowTitle);
71         instrumentation.runOnMainSync(() -> {
72             params.y = getStatusBarHeight(activity);
73         });
74         return params;
75     }
76 
77     /**
78      * Returns the layout params for a test window of type TYPE_APPLICATION_PANEL.
79      * @param instrumentation the test instrumentation.
80      * @param activity the activity whose window token will be used for the test window.
81      * @return the layout params.
82      */
layoutParamsForTestWindow( Instrumentation instrumentation, Activity activity)83     public static WindowManager.LayoutParams layoutParamsForTestWindow(
84             Instrumentation instrumentation, Activity activity) {
85         return layoutParamsForTestWindow(instrumentation, activity,
86                 WindowManager.LayoutParams.MATCH_PARENT,
87                 WindowManager.LayoutParams.WRAP_CONTENT);
88     }
89 
90     /**
91      * Returns the layout params for a test window of type TYPE_APPLICATION_PANEL.
92      * @param instrumentation the test instrumentation.
93      * @param activity the activity whose window token will be used for the test window.
94      * @param width the width of the window.
95      * @param height the height of the window.
96      * @return the layout params.
97      */
layoutParamsForTestWindow( Instrumentation instrumentation, Activity activity, int width, int height)98     public static WindowManager.LayoutParams layoutParamsForTestWindow(
99             Instrumentation instrumentation, Activity activity, int width, int height) {
100         final WindowManager.LayoutParams params = new WindowManager.LayoutParams();
101         params.width = width;
102         params.height = height;
103         params.flags = WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN
104                 | WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL
105                 | WindowManager.LayoutParams.FLAG_LAYOUT_INSET_DECOR;
106         params.type = WindowManager.LayoutParams.TYPE_APPLICATION_PANEL;
107         instrumentation.runOnMainSync(() -> {
108             params.token = activity.getWindow().getDecorView().getWindowToken();
109         });
110         return params;
111     }
112 
113     /**
114      * Adds a new window of type TYPE_APPLICATION_PANEL.
115      *
116      * <p> Note: Pair with removeWindowAndWaitForEvent to avoid a leaked window. </p>
117      *
118      * @param uiAutomation the test automation.
119      * @param instrumentation the test instrumentation.
120      * @param activity the activity whose window manager will add the window.
121      * @param view the test window to add.
122      * @param params the test window layout params.
123      * @param filter the filter to determine when the test window has been added.
124      * @throws TimeoutException
125      */
addWindowAndWaitForEvent(UiAutomation uiAutomation, Instrumentation instrumentation, Activity activity, View view, WindowManager.LayoutParams params, UiAutomation.AccessibilityEventFilter filter)126     public static void addWindowAndWaitForEvent(UiAutomation uiAutomation,
127             Instrumentation instrumentation, Activity activity, View view,
128             WindowManager.LayoutParams params,
129             UiAutomation.AccessibilityEventFilter filter)
130             throws TimeoutException {
131         uiAutomation.executeAndWaitForEvent(() -> instrumentation.runOnMainSync(
132                 () -> activity.getWindowManager().addView(view, params)), filter,
133                 AsyncUtils.DEFAULT_TIMEOUT_MS);
134     }
135 
136     /**
137      * Removes a window.
138      *
139      * @param uiAutomation the test automation.
140      * @param instrumentation the test instrumentation.
141      * @param activity the activity whose window manager will remove the window.
142      * @param view the test window to remove.
143      * @throws TimeoutException
144      */
removeWindow(UiAutomation uiAutomation, Instrumentation instrumentation, Activity activity, View view)145     public static void removeWindow(UiAutomation uiAutomation, Instrumentation instrumentation,
146             Activity activity, View view) throws TimeoutException {
147         uiAutomation.executeAndWaitForEvent(() -> instrumentation.runOnMainSync(
148                 () -> activity.getWindowManager().removeView(view)),
149                 filterWindowsChangedWithChangeTypes(WINDOWS_CHANGE_REMOVED),
150                 AsyncUtils.DEFAULT_TIMEOUT_MS);
151     }
152 }
153