WindowTestsBase.java revision 5cd907d3d6ceebf8731ef1f69347cce6f76109e9
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
17package com.android.server.wm;
18
19import android.app.ActivityManager.TaskDescription;
20import android.app.ActivityManagerInternal;
21import android.content.res.Configuration;
22import android.graphics.Rect;
23import android.hardware.display.DisplayManagerGlobal;
24import android.os.Binder;
25import android.view.Display;
26import android.view.DisplayInfo;
27import android.view.IApplicationToken;
28import org.junit.Assert;
29import org.junit.Before;
30import org.mockito.Mock;
31import org.mockito.Mockito;
32import org.mockito.MockitoAnnotations;
33
34import android.app.ActivityManager.TaskSnapshot;
35import android.content.Context;
36import android.os.IBinder;
37import android.support.test.InstrumentationRegistry;
38import android.view.IWindow;
39import android.view.WindowManager;
40
41import static android.app.ActivityManager.StackId.FIRST_DYNAMIC_STACK_ID;
42import static android.app.AppOpsManager.OP_NONE;
43import static android.content.pm.ActivityInfo.RESIZE_MODE_UNRESIZEABLE;
44import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
45import static android.content.res.Configuration.EMPTY;
46import static android.view.DisplayAdjustments.DEFAULT_DISPLAY_ADJUSTMENTS;
47import static android.view.WindowManager.LayoutParams.FIRST_APPLICATION_WINDOW;
48import static android.view.WindowManager.LayoutParams.LAST_APPLICATION_WINDOW;
49import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_ATTACHED_DIALOG;
50import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_MEDIA_OVERLAY;
51import static android.view.WindowManager.LayoutParams.TYPE_BASE_APPLICATION;
52import static android.view.WindowManager.LayoutParams.TYPE_DOCK_DIVIDER;
53import static android.view.WindowManager.LayoutParams.TYPE_INPUT_METHOD;
54import static android.view.WindowManager.LayoutParams.TYPE_INPUT_METHOD_DIALOG;
55import static android.view.WindowManager.LayoutParams.TYPE_NAVIGATION_BAR;
56import static android.view.WindowManager.LayoutParams.TYPE_STATUS_BAR;
57import static android.view.WindowManager.LayoutParams.TYPE_WALLPAPER;
58import static com.android.server.wm.WindowContainer.POSITION_TOP;
59import static org.mockito.Mockito.mock;
60
61import com.android.server.AttributeCache;
62import com.android.server.LocalServices;
63
64/**
65 * Common base class for window manager unit test classes.
66 */
67class WindowTestsBase {
68    static WindowManagerService sWm = null;
69    static TestWindowManagerPolicy sPolicy = null;
70    private final static IWindow sIWindow = new TestIWindow();
71    private final static Session sMockSession = mock(Session.class);
72    private static int sNextDisplayId = Display.DEFAULT_DISPLAY + 1;
73    static int sNextStackId = FIRST_DYNAMIC_STACK_ID;
74    private static int sNextTaskId = 0;
75
76    private static boolean sOneTimeSetupDone = false;
77    static DisplayContent sDisplayContent;
78    static DisplayInfo sDisplayInfo = new DisplayInfo();
79    static WindowLayersController sLayersController;
80    static WindowState sWallpaperWindow;
81    static WindowState sImeWindow;
82    static WindowState sImeDialogWindow;
83    static WindowState sStatusBarWindow;
84    static WindowState sDockedDividerWindow;
85    static WindowState sNavBarWindow;
86    static WindowState sAppWindow;
87    static WindowState sChildAppWindowAbove;
88    static WindowState sChildAppWindowBelow;
89    static @Mock ActivityManagerInternal sMockAm;
90
91    @Before
92    public void setUp() throws Exception {
93        if (sOneTimeSetupDone) {
94            Mockito.reset(sMockAm);
95            return;
96        }
97        sOneTimeSetupDone = true;
98        MockitoAnnotations.initMocks(this);
99        final Context context = InstrumentationRegistry.getTargetContext();
100        LocalServices.addService(ActivityManagerInternal.class, sMockAm);
101        AttributeCache.init(context);
102        sWm = TestWindowManagerPolicy.getWindowManagerService(context);
103        sPolicy = (TestWindowManagerPolicy) sWm.mPolicy;
104        sLayersController = new WindowLayersController(sWm);
105        sDisplayContent = sWm.mRoot.getDisplayContent(context.getDisplay().getDisplayId());
106        if (sDisplayContent != null) {
107            sDisplayContent.removeImmediately();
108        }
109        // Make sure that display ids don't overlap, so there won't be several displays with same
110        // ids among RootWindowContainer children.
111        for (DisplayContent dc : sWm.mRoot.mChildren) {
112            if (dc.getDisplayId() >= sNextDisplayId) {
113                sNextDisplayId = dc.getDisplayId() + 1;
114            }
115        }
116        context.getDisplay().getDisplayInfo(sDisplayInfo);
117        sDisplayContent = createNewDisplay();
118        sWm.mDisplayEnabled = true;
119        sWm.mDisplayReady = true;
120
121        // Set-up some common windows.
122        sWallpaperWindow = createWindow(null, TYPE_WALLPAPER, sDisplayContent, "wallpaperWindow");
123        sImeWindow = createWindow(null, TYPE_INPUT_METHOD, sDisplayContent, "sImeWindow");
124        sImeDialogWindow =
125                createWindow(null, TYPE_INPUT_METHOD_DIALOG, sDisplayContent, "sImeDialogWindow");
126        sStatusBarWindow = createWindow(null, TYPE_STATUS_BAR, sDisplayContent, "sStatusBarWindow");
127        sNavBarWindow =
128                createWindow(null, TYPE_NAVIGATION_BAR, sDisplayContent, "sNavBarWindow");
129        sDockedDividerWindow =
130                createWindow(null, TYPE_DOCK_DIVIDER, sDisplayContent, "sDockedDividerWindow");
131        sAppWindow = createWindow(null, TYPE_BASE_APPLICATION, sDisplayContent, "sAppWindow");
132        sChildAppWindowAbove = createWindow(sAppWindow,
133                TYPE_APPLICATION_ATTACHED_DIALOG, sAppWindow.mToken, "sChildAppWindowAbove");
134        sChildAppWindowBelow = createWindow(sAppWindow,
135                TYPE_APPLICATION_MEDIA_OVERLAY, sAppWindow.mToken, "sChildAppWindowBelow");
136    }
137
138    /** Asserts that the first entry is greater than the second entry. */
139    void assertGreaterThan(int first, int second) throws Exception {
140        Assert.assertTrue("Excepted " + first + " to be greater than " + second, first > second);
141    }
142
143    /**
144     * Waits until the main handler for WM has processed all messages.
145     */
146    void waitUntilHandlerIdle() {
147        sWm.mH.runWithScissors(() -> { }, 0);
148    }
149
150    private static WindowToken createWindowToken(DisplayContent dc, int type) {
151        if (type < FIRST_APPLICATION_WINDOW || type > LAST_APPLICATION_WINDOW) {
152            return new TestWindowToken(type, dc);
153        }
154
155        final TaskStack stack = createTaskStackOnDisplay(dc);
156        final Task task = createTaskInStack(stack, 0 /* userId */);
157        final TestAppWindowToken token = new TestAppWindowToken(dc);
158        task.addChild(token, 0);
159        return token;
160    }
161
162    static WindowState createWindow(WindowState parent, int type, String name) {
163        return (parent == null)
164                ? createWindow(parent, type, sDisplayContent, name)
165                : createWindow(parent, type, parent.mToken, name);
166    }
167
168    WindowState createAppWindow(Task task, int type, String name) {
169        final AppWindowToken token = new TestAppWindowToken(sDisplayContent);
170        task.addChild(token, 0);
171        return createWindow(null, type, token, name);
172    }
173
174    static WindowState createWindow(WindowState parent, int type, DisplayContent dc, String name) {
175        final WindowToken token = createWindowToken(dc, type);
176        return createWindow(parent, type, token, name);
177    }
178
179    static WindowState createWindow(WindowState parent, int type, WindowToken token, String name) {
180        final WindowManager.LayoutParams attrs = new WindowManager.LayoutParams(type);
181        attrs.setTitle(name);
182
183        final WindowState w = new WindowState(sWm, sMockSession, sIWindow, token, parent, OP_NONE,
184                0, attrs, 0, 0, false /* ownerCanAddInternalSystemWindow */);
185        // TODO: Probably better to make this call in the WindowState ctor to avoid errors with
186        // adding it to the token...
187        token.addWindow(w);
188        return w;
189    }
190
191    /** Creates a {@link TaskStack} and adds it to the specified {@link DisplayContent}. */
192    static TaskStack createTaskStackOnDisplay(DisplayContent dc) {
193        return createStackControllerOnDisplay(dc).mContainer;
194    }
195
196    static StackWindowController createStackControllerOnDisplay(DisplayContent dc) {
197        final int stackId = ++sNextStackId;
198        return new StackWindowController(stackId, null, dc.getDisplayId(),
199                true /* onTop */, new Rect(), sWm);
200    }
201
202    /** Creates a {@link Task} and adds it to the specified {@link TaskStack}. */
203    static Task createTaskInStack(TaskStack stack, int userId) {
204        final Task newTask = new Task(sNextTaskId++, stack, userId, sWm, null, EMPTY, false, 0,
205                false, false, new TaskDescription(), null);
206        stack.addTask(newTask, POSITION_TOP);
207        return newTask;
208    }
209
210    /** Creates a {@link DisplayContent} and adds it to the system. */
211    DisplayContent createNewDisplay() {
212        final int displayId = sNextDisplayId++;
213        final Display display = new Display(DisplayManagerGlobal.getInstance(), displayId,
214                sDisplayInfo, DEFAULT_DISPLAY_ADJUSTMENTS);
215        return new DisplayContent(display, sWm, sLayersController, new WallpaperController(sWm));
216    }
217
218    /* Used so we can gain access to some protected members of the {@link WindowToken} class */
219    static class TestWindowToken extends WindowToken {
220
221        TestWindowToken(int type, DisplayContent dc) {
222            this(type, dc, false /* persistOnEmpty */);
223        }
224
225        TestWindowToken(int type, DisplayContent dc, boolean persistOnEmpty) {
226            super(sWm, mock(IBinder.class), type, persistOnEmpty, dc,
227                    false /* ownerCanManageAppTokens */);
228        }
229
230        int getWindowsCount() {
231            return mChildren.size();
232        }
233
234        boolean hasWindow(WindowState w) {
235            return mChildren.contains(w);
236        }
237    }
238
239    /** Used so we can gain access to some protected members of the {@link AppWindowToken} class. */
240    static class TestAppWindowToken extends AppWindowToken {
241
242        TestAppWindowToken(DisplayContent dc) {
243            super(sWm, null, false, dc);
244        }
245
246        TestAppWindowToken(WindowManagerService service, IApplicationToken token,
247                boolean voiceInteraction, DisplayContent dc, long inputDispatchingTimeoutNanos,
248                boolean fullscreen, boolean showForAllUsers, int targetSdk, int orientation,
249                int rotationAnimationHint, int configChanges, boolean launchTaskBehind,
250                boolean alwaysFocusable, AppWindowContainerController controller) {
251            super(service, token, voiceInteraction, dc, inputDispatchingTimeoutNanos, fullscreen,
252                    showForAllUsers, targetSdk, orientation, rotationAnimationHint, configChanges,
253                    launchTaskBehind, alwaysFocusable, controller);
254        }
255
256        int getWindowsCount() {
257            return mChildren.size();
258        }
259
260        boolean hasWindow(WindowState w) {
261            return mChildren.contains(w);
262        }
263
264        WindowState getFirstChild() {
265            return mChildren.getFirst();
266        }
267
268        WindowState getLastChild() {
269            return mChildren.getLast();
270        }
271
272        int positionInParent() {
273            return getParent().mChildren.indexOf(this);
274        }
275    }
276
277    /* Used so we can gain access to some protected members of the {@link Task} class */
278    class TestTask extends Task {
279
280        boolean mShouldDeferRemoval = false;
281        boolean mOnDisplayChangedCalled = false;
282        private boolean mUseLocalIsAnimating = false;
283        private boolean mIsAnimating = false;
284
285        TestTask(int taskId, TaskStack stack, int userId, WindowManagerService service, Rect bounds,
286                Configuration overrideConfig, boolean isOnTopLauncher, int resizeMode,
287                boolean supportsPictureInPicture, boolean homeTask,
288                TaskWindowContainerController controller) {
289            super(taskId, stack, userId, service, bounds, overrideConfig, isOnTopLauncher,
290                    resizeMode, supportsPictureInPicture, homeTask, new TaskDescription(),
291                            controller);
292        }
293
294        boolean shouldDeferRemoval() {
295            return mShouldDeferRemoval;
296        }
297
298        int positionInParent() {
299            return getParent().mChildren.indexOf(this);
300        }
301
302        @Override
303        void onDisplayChanged(DisplayContent dc) {
304            super.onDisplayChanged(dc);
305            mOnDisplayChangedCalled = true;
306        }
307
308        @Override
309        boolean isAnimating() {
310            return mUseLocalIsAnimating ? mIsAnimating : super.isAnimating();
311        }
312
313        void setLocalIsAnimating(boolean isAnimating) {
314            mUseLocalIsAnimating = true;
315            mIsAnimating = isAnimating;
316        }
317    }
318
319    /**
320     * Used so we can gain access to some protected members of {@link TaskWindowContainerController}
321     * class.
322     */
323    class TestTaskWindowContainerController extends TaskWindowContainerController {
324
325        TestTaskWindowContainerController() {
326            this(createStackControllerOnDisplay(sDisplayContent));
327        }
328
329        TestTaskWindowContainerController(StackWindowController stackController) {
330            super(sNextTaskId++, new TaskWindowContainerListener() {
331                        @Override
332                        public void onSnapshotChanged(TaskSnapshot snapshot) {
333
334                        }
335
336                        @Override
337                        public void requestResize(Rect bounds, int resizeMode) {
338
339                        }
340                    }, stackController, 0 /* userId */, null /* bounds */,
341                    EMPTY /* overrideConfig*/, RESIZE_MODE_UNRESIZEABLE,
342                    false /* supportsPictureInPicture */, false /* homeTask*/,
343                    false /* isOnTopLauncher */, true /* toTop*/, true /* showForAllUsers */,
344                    new TaskDescription(), sWm);
345        }
346
347        @Override
348        TestTask createTask(int taskId, TaskStack stack, int userId, Rect bounds,
349                Configuration overrideConfig, int resizeMode, boolean supportsPictureInPicture,
350                boolean homeTask, boolean isOnTopLauncher, TaskDescription taskDescription) {
351            return new TestTask(taskId, stack, userId, mService, bounds, overrideConfig,
352                    isOnTopLauncher, resizeMode, supportsPictureInPicture, homeTask, this);
353        }
354    }
355
356    class TestAppWindowContainerController extends AppWindowContainerController {
357
358        final IApplicationToken mToken;
359
360        TestAppWindowContainerController(TestTaskWindowContainerController taskController) {
361            this(taskController, new TestIApplicationToken());
362        }
363
364        TestAppWindowContainerController(TestTaskWindowContainerController taskController,
365                IApplicationToken token) {
366            super(taskController, token, null /* listener */, 0 /* index */,
367                    SCREEN_ORIENTATION_UNSPECIFIED, true /* fullscreen */,
368                    true /* showForAllUsers */, 0 /* configChanges */, false /* voiceInteraction */,
369                    false /* launchTaskBehind */, false /* alwaysFocusable */,
370                    0 /* targetSdkVersion */, 0 /* rotationAnimationHint */,
371                    0 /* inputDispatchingTimeoutNanos */, sWm);
372            mToken = token;
373        }
374
375        @Override
376        AppWindowToken createAppWindow(WindowManagerService service, IApplicationToken token,
377                boolean voiceInteraction, DisplayContent dc, long inputDispatchingTimeoutNanos,
378                boolean fullscreen, boolean showForAllUsers, int targetSdk, int orientation,
379                int rotationAnimationHint, int configChanges, boolean launchTaskBehind,
380                boolean alwaysFocusable, AppWindowContainerController controller) {
381            return new TestAppWindowToken(service, token, voiceInteraction, dc,
382                    inputDispatchingTimeoutNanos, fullscreen, showForAllUsers, targetSdk,
383                    orientation,
384                    rotationAnimationHint, configChanges, launchTaskBehind, alwaysFocusable,
385                    controller);
386        }
387
388        AppWindowToken getAppWindowToken() {
389            return (AppWindowToken) sDisplayContent.getWindowToken(mToken.asBinder());
390        }
391    }
392
393    class TestIApplicationToken implements IApplicationToken {
394
395        private final Binder mBinder = new Binder();
396        @Override
397        public IBinder asBinder() {
398            return mBinder;
399        }
400    }
401
402    /** Used to track resize reports. */
403    class TestWindowState extends WindowState {
404        boolean resizeReported;
405
406        TestWindowState(WindowManager.LayoutParams attrs, WindowToken token) {
407            super(sWm, sMockSession, sIWindow, token, null, OP_NONE, 0, attrs, 0, 0,
408                    false /* ownerCanAddInternalSystemWindow */);
409        }
410
411        @Override
412        void reportResized() {
413            super.reportResized();
414            resizeReported = true;
415        }
416
417        @Override
418        public boolean isGoneForLayoutLw() {
419            return false;
420        }
421
422        @Override
423        void updateResizingWindowIfNeeded() {
424            // Used in AppWindowTokenTests#testLandscapeSeascapeRotationRelayout to deceive
425            // the system that it can actually update the window.
426            boolean hadSurface = mHasSurface;
427            mHasSurface = true;
428
429            super.updateResizingWindowIfNeeded();
430
431            mHasSurface = hadSurface;
432        }
433    }
434}
435