1 /*
2  * Copyright (C) 2017 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 com.android.server.wm;
18 
19 import android.app.ActivityManager;
20 import android.content.Context;
21 import android.content.res.Configuration;
22 import android.graphics.Rect;
23 import android.os.Binder;
24 import android.os.IBinder;
25 import android.view.IApplicationToken;
26 import android.view.IWindow;
27 import android.view.WindowManager;
28 
29 import static android.app.AppOpsManager.OP_NONE;
30 import static android.content.pm.ActivityInfo.RESIZE_MODE_UNRESIZEABLE;
31 import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
32 import static android.content.res.Configuration.EMPTY;
33 import static com.android.server.wm.WindowContainer.POSITION_TOP;
34 import static org.mockito.Mockito.mock;
35 
36 /**
37  * A collection of static functions that can be referenced by other test packages to provide access
38  * to WindowManager related test functionality.
39  */
40 public class WindowTestUtils {
41     public static int sNextTaskId = 0;
42 
43     /**
44      * Retrieves an instance of {@link WindowManagerService}, creating it if necessary.
45      */
getWindowManagerService(Context context)46     public static WindowManagerService getWindowManagerService(Context context) {
47         return TestWindowManagerPolicy.getWindowManagerService(context);
48     }
49 
50     /**
51      * Retrieves an instance of a mock {@link WindowManagerService}.
52      */
getMockWindowManagerService()53     public static WindowManagerService getMockWindowManagerService() {
54         return mock(WindowManagerService.class);
55     }
56 
57     /**
58      * Creates a mock instance of {@link StackWindowController}.
59      */
createMockStackWindowContainerController()60     public static StackWindowController createMockStackWindowContainerController() {
61         StackWindowController controller = mock(StackWindowController.class);
62         controller.mContainer = mock(TestTaskStack.class);
63         return controller;
64     }
65 
66     /** Creates a {@link Task} and adds it to the specified {@link TaskStack}. */
createTaskInStack(WindowManagerService service, TaskStack stack, int userId)67     public static Task createTaskInStack(WindowManagerService service, TaskStack stack,
68             int userId) {
69         final Task newTask = new Task(sNextTaskId++, stack, userId, service, null, EMPTY, 0, false,
70                 false, new ActivityManager.TaskDescription(), null);
71         stack.addTask(newTask, POSITION_TOP);
72         return newTask;
73     }
74 
75     /**
76      * An extension of {@link TestTaskStack}, which overrides package scoped methods that would not
77      * normally be mocked out.
78      */
79     public static class TestTaskStack extends TaskStack {
TestTaskStack(WindowManagerService service, int stackId)80         TestTaskStack(WindowManagerService service, int stackId) {
81             super(service, stackId);
82         }
83 
84         @Override
addTask(Task task, int position, boolean showForAllUsers, boolean moveParents)85         void addTask(Task task, int position, boolean showForAllUsers, boolean moveParents) {
86             // Do nothing.
87         }
88     }
89 
90     /** Used so we can gain access to some protected members of the {@link AppWindowToken} class. */
91     public static class TestAppWindowToken extends AppWindowToken {
92 
TestAppWindowToken(DisplayContent dc)93         TestAppWindowToken(DisplayContent dc) {
94             super(dc.mService, new IApplicationToken.Stub() {}, false, dc, true /* fillsParent */,
95                     null /* overrideConfig */, null /* bounds */);
96         }
97 
TestAppWindowToken(WindowManagerService service, IApplicationToken token, boolean voiceInteraction, DisplayContent dc, long inputDispatchingTimeoutNanos, boolean fullscreen, boolean showForAllUsers, int targetSdk, int orientation, int rotationAnimationHint, int configChanges, boolean launchTaskBehind, boolean alwaysFocusable, AppWindowContainerController controller, Configuration overrideConfig, Rect bounds)98         TestAppWindowToken(WindowManagerService service, IApplicationToken token,
99                 boolean voiceInteraction, DisplayContent dc, long inputDispatchingTimeoutNanos,
100                 boolean fullscreen, boolean showForAllUsers, int targetSdk, int orientation,
101                 int rotationAnimationHint, int configChanges, boolean launchTaskBehind,
102                 boolean alwaysFocusable, AppWindowContainerController controller,
103                 Configuration overrideConfig, Rect bounds) {
104             super(service, token, voiceInteraction, dc, inputDispatchingTimeoutNanos, fullscreen,
105                     showForAllUsers, targetSdk, orientation, rotationAnimationHint, configChanges,
106                     launchTaskBehind, alwaysFocusable, controller, overrideConfig, bounds);
107         }
108 
getWindowsCount()109         int getWindowsCount() {
110             return mChildren.size();
111         }
112 
hasWindow(WindowState w)113         boolean hasWindow(WindowState w) {
114             return mChildren.contains(w);
115         }
116 
getFirstChild()117         WindowState getFirstChild() {
118             return mChildren.peekFirst();
119         }
120 
getLastChild()121         WindowState getLastChild() {
122             return mChildren.peekLast();
123         }
124 
positionInParent()125         int positionInParent() {
126             return getParent().mChildren.indexOf(this);
127         }
128     }
129 
130     /* Used so we can gain access to some protected members of the {@link WindowToken} class */
131     public static class TestWindowToken extends WindowToken {
132         int adj = 0;
133 
TestWindowToken(int type, DisplayContent dc)134         TestWindowToken(int type, DisplayContent dc) {
135             this(type, dc, false /* persistOnEmpty */);
136         }
137 
TestWindowToken(int type, DisplayContent dc, boolean persistOnEmpty)138         TestWindowToken(int type, DisplayContent dc, boolean persistOnEmpty) {
139             super(dc.mService, mock(IBinder.class), type, persistOnEmpty, dc,
140                     false /* ownerCanManageAppTokens */);
141         }
142 
getWindowsCount()143         int getWindowsCount() {
144             return mChildren.size();
145         }
146 
hasWindow(WindowState w)147         boolean hasWindow(WindowState w) {
148             return mChildren.contains(w);
149         }
150 
151         @Override
getAnimLayerAdjustment()152         int getAnimLayerAdjustment() {
153             return adj;
154         }
155     }
156 
157     /* Used so we can gain access to some protected members of the {@link Task} class */
158     public static class TestTask extends Task {
159         boolean mShouldDeferRemoval = false;
160         boolean mOnDisplayChangedCalled = false;
161         private boolean mUseLocalIsAnimating = false;
162         private boolean mIsAnimating = false;
163 
TestTask(int taskId, TaskStack stack, int userId, WindowManagerService service, Rect bounds, Configuration overrideConfig, int resizeMode, boolean supportsPictureInPicture, boolean homeTask, TaskWindowContainerController controller)164         TestTask(int taskId, TaskStack stack, int userId, WindowManagerService service, Rect bounds,
165                 Configuration overrideConfig, int resizeMode, boolean supportsPictureInPicture,
166                 boolean homeTask, TaskWindowContainerController controller) {
167             super(taskId, stack, userId, service, bounds, overrideConfig, resizeMode,
168                     supportsPictureInPicture, homeTask, new ActivityManager.TaskDescription(),
169                     controller);
170         }
171 
shouldDeferRemoval()172         boolean shouldDeferRemoval() {
173             return mShouldDeferRemoval;
174         }
175 
positionInParent()176         int positionInParent() {
177             return getParent().mChildren.indexOf(this);
178         }
179 
180         @Override
onDisplayChanged(DisplayContent dc)181         void onDisplayChanged(DisplayContent dc) {
182             super.onDisplayChanged(dc);
183             mOnDisplayChangedCalled = true;
184         }
185 
186         @Override
isAnimating()187         boolean isAnimating() {
188             return mUseLocalIsAnimating ? mIsAnimating : super.isAnimating();
189         }
190 
setLocalIsAnimating(boolean isAnimating)191         void setLocalIsAnimating(boolean isAnimating) {
192             mUseLocalIsAnimating = true;
193             mIsAnimating = isAnimating;
194         }
195     }
196 
197     /**
198      * Used so we can gain access to some protected members of {@link TaskWindowContainerController}
199      * class.
200      */
201     public static class TestTaskWindowContainerController extends TaskWindowContainerController {
202 
TestTaskWindowContainerController(WindowTestsBase testsBase)203         TestTaskWindowContainerController(WindowTestsBase testsBase) {
204             this(testsBase.createStackControllerOnDisplay(testsBase.mDisplayContent));
205         }
206 
TestTaskWindowContainerController(StackWindowController stackController)207         TestTaskWindowContainerController(StackWindowController stackController) {
208             super(sNextTaskId++, new TaskWindowContainerListener() {
209                         @Override
210                         public void onSnapshotChanged(ActivityManager.TaskSnapshot snapshot) {
211 
212                         }
213 
214                         @Override
215                         public void requestResize(Rect bounds, int resizeMode) {
216 
217                         }
218                     }, stackController, 0 /* userId */, null /* bounds */,
219                     EMPTY /* overrideConfig*/, RESIZE_MODE_UNRESIZEABLE,
220                     false /* supportsPictureInPicture */, false /* homeTask*/, true /* toTop*/,
221                     true /* showForAllUsers */, new ActivityManager.TaskDescription(),
222                     stackController.mService);
223         }
224 
225         @Override
createTask(int taskId, TaskStack stack, int userId, Rect bounds, Configuration overrideConfig, int resizeMode, boolean supportsPictureInPicture, boolean homeTask, ActivityManager.TaskDescription taskDescription)226         TestTask createTask(int taskId, TaskStack stack, int userId, Rect bounds,
227                 Configuration overrideConfig, int resizeMode, boolean supportsPictureInPicture,
228                 boolean homeTask, ActivityManager.TaskDescription taskDescription) {
229             return new TestTask(taskId, stack, userId, mService, bounds, overrideConfig, resizeMode,
230                     supportsPictureInPicture, homeTask, this);
231         }
232     }
233 
234     public static class TestAppWindowContainerController extends AppWindowContainerController {
235 
236         final IApplicationToken mToken;
237 
TestAppWindowContainerController(TestTaskWindowContainerController taskController)238         TestAppWindowContainerController(TestTaskWindowContainerController taskController) {
239             this(taskController, new TestIApplicationToken());
240         }
241 
TestAppWindowContainerController(TestTaskWindowContainerController taskController, IApplicationToken token)242         TestAppWindowContainerController(TestTaskWindowContainerController taskController,
243                 IApplicationToken token) {
244             super(taskController, token, null /* listener */, 0 /* index */,
245                     SCREEN_ORIENTATION_UNSPECIFIED, true /* fullscreen */,
246                     true /* showForAllUsers */, 0 /* configChanges */, false /* voiceInteraction */,
247                     false /* launchTaskBehind */, false /* alwaysFocusable */,
248                     0 /* targetSdkVersion */, 0 /* rotationAnimationHint */,
249                     0 /* inputDispatchingTimeoutNanos */, taskController.mService,
250                     null /* overrideConfig */, null /* bounds */);
251             mToken = token;
252         }
253 
254         @Override
createAppWindow(WindowManagerService service, IApplicationToken token, boolean voiceInteraction, DisplayContent dc, long inputDispatchingTimeoutNanos, boolean fullscreen, boolean showForAllUsers, int targetSdk, int orientation, int rotationAnimationHint, int configChanges, boolean launchTaskBehind, boolean alwaysFocusable, AppWindowContainerController controller, Configuration overrideConfig, Rect bounds)255         AppWindowToken createAppWindow(WindowManagerService service, IApplicationToken token,
256                 boolean voiceInteraction, DisplayContent dc, long inputDispatchingTimeoutNanos,
257                 boolean fullscreen, boolean showForAllUsers, int targetSdk, int orientation,
258                 int rotationAnimationHint, int configChanges, boolean launchTaskBehind,
259                 boolean alwaysFocusable, AppWindowContainerController controller,
260                 Configuration overrideConfig, Rect bounds) {
261             return new TestAppWindowToken(service, token, voiceInteraction, dc,
262                     inputDispatchingTimeoutNanos, fullscreen, showForAllUsers, targetSdk,
263                     orientation,
264                     rotationAnimationHint, configChanges, launchTaskBehind, alwaysFocusable,
265                     controller, overrideConfig, bounds);
266         }
267 
getAppWindowToken(DisplayContent dc)268         AppWindowToken getAppWindowToken(DisplayContent dc) {
269             return (AppWindowToken) dc.getWindowToken(mToken.asBinder());
270         }
271     }
272 
273     public static class TestIApplicationToken implements IApplicationToken {
274 
275         private final Binder mBinder = new Binder();
276         @Override
asBinder()277         public IBinder asBinder() {
278             return mBinder;
279         }
280     }
281 
282     /** Used to track resize reports. */
283     public static class TestWindowState extends WindowState {
284         boolean resizeReported;
285 
TestWindowState(WindowManagerService service, Session session, IWindow window, WindowManager.LayoutParams attrs, WindowToken token)286         TestWindowState(WindowManagerService service, Session session, IWindow window,
287                 WindowManager.LayoutParams attrs, WindowToken token) {
288             super(service, session, window, token, null, OP_NONE, 0, attrs, 0, 0,
289                     false /* ownerCanAddInternalSystemWindow */);
290         }
291 
292         @Override
reportResized()293         void reportResized() {
294             super.reportResized();
295             resizeReported = true;
296         }
297 
298         @Override
isGoneForLayoutLw()299         public boolean isGoneForLayoutLw() {
300             return false;
301         }
302 
303         @Override
updateResizingWindowIfNeeded()304         void updateResizingWindowIfNeeded() {
305             // Used in AppWindowTokenTests#testLandscapeSeascapeRotationRelayout to deceive
306             // the system that it can actually update the window.
307             boolean hadSurface = mHasSurface;
308             mHasSurface = true;
309 
310             super.updateResizingWindowIfNeeded();
311 
312             mHasSurface = hadSurface;
313         }
314     }
315 }
316