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