Home | History | Annotate | Download | only in wm
      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 
     17 package com.android.server.wm;
     18 
     19 import static android.view.Display.DEFAULT_DISPLAY;
     20 import static android.view.View.VISIBLE;
     21 
     22 import android.graphics.Rect;
     23 import android.hardware.display.DisplayManagerGlobal;
     24 import android.view.Display;
     25 import android.view.DisplayInfo;
     26 import org.junit.Assert;
     27 import org.junit.After;
     28 import org.junit.Before;
     29 import org.mockito.MockitoAnnotations;
     30 
     31 import android.content.Context;
     32 import android.support.test.InstrumentationRegistry;
     33 import android.view.IWindow;
     34 import android.view.WindowManager;
     35 
     36 import static android.app.ActivityManager.StackId.FIRST_DYNAMIC_STACK_ID;
     37 import static android.app.ActivityManager.StackId.INVALID_STACK_ID;
     38 import static android.app.AppOpsManager.OP_NONE;
     39 import static android.view.DisplayAdjustments.DEFAULT_DISPLAY_ADJUSTMENTS;
     40 import static android.view.WindowManager.LayoutParams.FIRST_APPLICATION_WINDOW;
     41 import static android.view.WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
     42 import static android.view.WindowManager.LayoutParams.LAST_APPLICATION_WINDOW;
     43 import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_ATTACHED_DIALOG;
     44 import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_MEDIA_OVERLAY;
     45 import static android.view.WindowManager.LayoutParams.TYPE_BASE_APPLICATION;
     46 import static android.view.WindowManager.LayoutParams.TYPE_DOCK_DIVIDER;
     47 import static android.view.WindowManager.LayoutParams.TYPE_INPUT_METHOD;
     48 import static android.view.WindowManager.LayoutParams.TYPE_INPUT_METHOD_DIALOG;
     49 import static android.view.WindowManager.LayoutParams.TYPE_NAVIGATION_BAR;
     50 import static android.view.WindowManager.LayoutParams.TYPE_STATUS_BAR;
     51 import static android.view.WindowManager.LayoutParams.TYPE_WALLPAPER;
     52 import static org.mockito.Mockito.mock;
     53 
     54 import com.android.server.AttributeCache;
     55 
     56 import java.util.HashSet;
     57 import java.util.LinkedList;
     58 
     59 /**
     60  * Common base class for window manager unit test classes.
     61  */
     62 class WindowTestsBase {
     63     static WindowManagerService sWm = null;
     64     private static final IWindow sIWindow = new TestIWindow();
     65     private static final Session sMockSession = mock(Session.class);
     66     // The default display is removed in {@link #setUp} and then we iterate over all displays to
     67     // make sure we don't collide with any existing display. If we run into no other display, the
     68     // added display should be treated as default. This cannot be the default display
     69     private static int sNextDisplayId = DEFAULT_DISPLAY + 1;
     70     private static int sNextStackId = FIRST_DYNAMIC_STACK_ID;
     71 
     72     private static boolean sOneTimeSetupDone = false;
     73     DisplayContent mDisplayContent;
     74     DisplayInfo mDisplayInfo = new DisplayInfo();
     75     WindowLayersController mLayersController;
     76     WindowState mWallpaperWindow;
     77     WindowState mImeWindow;
     78     WindowState mImeDialogWindow;
     79     WindowState mStatusBarWindow;
     80     WindowState mDockedDividerWindow;
     81     WindowState mNavBarWindow;
     82     WindowState mAppWindow;
     83     WindowState mChildAppWindowAbove;
     84     WindowState mChildAppWindowBelow;
     85     HashSet<WindowState> mCommonWindows;
     86 
     87     @Before
     88     public void setUp() throws Exception {
     89         if (!sOneTimeSetupDone) {
     90             sOneTimeSetupDone = true;
     91             MockitoAnnotations.initMocks(this);
     92         }
     93 
     94         final Context context = InstrumentationRegistry.getTargetContext();
     95         AttributeCache.init(context);
     96         sWm = TestWindowManagerPolicy.getWindowManagerService(context);
     97         mLayersController = new WindowLayersController(sWm);
     98 
     99         context.getDisplay().getDisplayInfo(mDisplayInfo);
    100         mDisplayContent = createNewDisplay();
    101         sWm.mDisplayEnabled = true;
    102         sWm.mDisplayReady = true;
    103 
    104         // Set-up some common windows.
    105         mCommonWindows = new HashSet();
    106         mWallpaperWindow = createCommonWindow(null, TYPE_WALLPAPER, "wallpaperWindow");
    107         mImeWindow = createCommonWindow(null, TYPE_INPUT_METHOD, "mImeWindow");
    108         sWm.mInputMethodWindow = mImeWindow;
    109         mImeDialogWindow = createCommonWindow(null, TYPE_INPUT_METHOD_DIALOG, "mImeDialogWindow");
    110         mStatusBarWindow = createCommonWindow(null, TYPE_STATUS_BAR, "mStatusBarWindow");
    111         mNavBarWindow = createCommonWindow(null, TYPE_NAVIGATION_BAR, "mNavBarWindow");
    112         mDockedDividerWindow = createCommonWindow(null, TYPE_DOCK_DIVIDER, "mDockedDividerWindow");
    113         mAppWindow = createCommonWindow(null, TYPE_BASE_APPLICATION, "mAppWindow");
    114         mChildAppWindowAbove = createCommonWindow(mAppWindow, TYPE_APPLICATION_ATTACHED_DIALOG,
    115                 "mChildAppWindowAbove");
    116         mChildAppWindowBelow = createCommonWindow(mAppWindow, TYPE_APPLICATION_MEDIA_OVERLAY,
    117                 "mChildAppWindowBelow");
    118 
    119         // Adding a display will cause freezing the display. Make sure to wait until it's unfrozen
    120         // to not run into race conditions with the tests.
    121         waitUntilHandlersIdle();
    122     }
    123 
    124     @After
    125     public void tearDown() throws Exception {
    126         final LinkedList<WindowState> nonCommonWindows = new LinkedList();
    127 
    128         synchronized (sWm.mWindowMap) {
    129             sWm.mRoot.forAllWindows(w -> {
    130                 if (!mCommonWindows.contains(w)) {
    131                     nonCommonWindows.addLast(w);
    132                 }
    133             }, true /* traverseTopToBottom */);
    134 
    135             while (!nonCommonWindows.isEmpty()) {
    136                 nonCommonWindows.pollLast().removeImmediately();
    137             }
    138 
    139             mDisplayContent.removeImmediately();
    140             sWm.mInputMethodTarget = null;
    141         }
    142 
    143         // Wait until everything is really cleaned up.
    144         waitUntilHandlersIdle();
    145     }
    146 
    147     private WindowState createCommonWindow(WindowState parent, int type, String name) {
    148         final WindowState win = createWindow(parent, type, name);
    149         mCommonWindows.add(win);
    150         // Prevent common windows from been IMe targets
    151         win.mAttrs.flags |= FLAG_NOT_FOCUSABLE;
    152         return win;
    153     }
    154 
    155     /** Asserts that the first entry is greater than the second entry. */
    156     void assertGreaterThan(int first, int second) throws Exception {
    157         Assert.assertTrue("Excepted " + first + " to be greater than " + second, first > second);
    158     }
    159 
    160     /**
    161      * Waits until the main handler for WM has processed all messages.
    162      */
    163     void waitUntilHandlersIdle() {
    164         sWm.mH.runWithScissors(() -> { }, 0);
    165         sWm.mAnimationHandler.runWithScissors(() -> { }, 0);
    166     }
    167 
    168     private WindowToken createWindowToken(DisplayContent dc, int stackId, int type) {
    169         if (type < FIRST_APPLICATION_WINDOW || type > LAST_APPLICATION_WINDOW) {
    170             return new WindowTestUtils.TestWindowToken(type, dc);
    171         }
    172 
    173         final TaskStack stack = stackId == INVALID_STACK_ID
    174                 ? createTaskStackOnDisplay(dc)
    175                 : createStackControllerOnStackOnDisplay(stackId, dc).mContainer;
    176         final Task task = createTaskInStack(stack, 0 /* userId */);
    177         final WindowTestUtils.TestAppWindowToken token = new WindowTestUtils.TestAppWindowToken(dc);
    178         task.addChild(token, 0);
    179         return token;
    180     }
    181 
    182     WindowState createWindow(WindowState parent, int type, String name) {
    183         return (parent == null)
    184                 ? createWindow(parent, type, mDisplayContent, name)
    185                 : createWindow(parent, type, parent.mToken, name);
    186     }
    187 
    188     WindowState createWindowOnStack(WindowState parent, int stackId, int type,
    189             DisplayContent dc, String name) {
    190         final WindowToken token = createWindowToken(dc, stackId, type);
    191         return createWindow(parent, type, token, name);
    192     }
    193 
    194     WindowState createAppWindow(Task task, int type, String name) {
    195         final AppWindowToken token = new WindowTestUtils.TestAppWindowToken(mDisplayContent);
    196         task.addChild(token, 0);
    197         return createWindow(null, type, token, name);
    198     }
    199 
    200     WindowState createWindow(WindowState parent, int type, DisplayContent dc, String name) {
    201         final WindowToken token = createWindowToken(dc, INVALID_STACK_ID, type);
    202         return createWindow(parent, type, token, name);
    203     }
    204 
    205     WindowState createWindow(WindowState parent, int type, DisplayContent dc, String name,
    206             boolean ownerCanAddInternalSystemWindow) {
    207         final WindowToken token = createWindowToken(dc, INVALID_STACK_ID, type);
    208         return createWindow(parent, type, token, name, ownerCanAddInternalSystemWindow);
    209     }
    210 
    211     static WindowState createWindow(WindowState parent, int type, WindowToken token, String name) {
    212         return createWindow(parent, type, token, name, false /* ownerCanAddInternalSystemWindow */);
    213     }
    214 
    215     static WindowState createWindow(WindowState parent, int type, WindowToken token, String name,
    216             boolean ownerCanAddInternalSystemWindow) {
    217         final WindowManager.LayoutParams attrs = new WindowManager.LayoutParams(type);
    218         attrs.setTitle(name);
    219 
    220         final WindowState w = new WindowState(sWm, sMockSession, sIWindow, token, parent, OP_NONE,
    221                 0, attrs, VISIBLE, 0, ownerCanAddInternalSystemWindow);
    222         // TODO: Probably better to make this call in the WindowState ctor to avoid errors with
    223         // adding it to the token...
    224         token.addWindow(w);
    225         return w;
    226     }
    227 
    228     /** Creates a {@link TaskStack} and adds it to the specified {@link DisplayContent}. */
    229     TaskStack createTaskStackOnDisplay(DisplayContent dc) {
    230         return createStackControllerOnDisplay(dc).mContainer;
    231     }
    232 
    233     StackWindowController createStackControllerOnDisplay(DisplayContent dc) {
    234         final int stackId = ++sNextStackId;
    235         return createStackControllerOnStackOnDisplay(stackId, dc);
    236     }
    237 
    238     StackWindowController createStackControllerOnStackOnDisplay(int stackId,
    239             DisplayContent dc) {
    240         return new StackWindowController(stackId, null, dc.getDisplayId(),
    241                 true /* onTop */, new Rect(), sWm);
    242     }
    243 
    244     /** Creates a {@link Task} and adds it to the specified {@link TaskStack}. */
    245     Task createTaskInStack(TaskStack stack, int userId) {
    246         return WindowTestUtils.createTaskInStack(sWm, stack, userId);
    247     }
    248 
    249     /** Creates a {@link DisplayContent} and adds it to the system. */
    250     DisplayContent createNewDisplay() {
    251         final int displayId = sNextDisplayId++;
    252         final Display display = new Display(DisplayManagerGlobal.getInstance(), displayId,
    253                 mDisplayInfo, DEFAULT_DISPLAY_ADJUSTMENTS);
    254         return new DisplayContent(display, sWm, mLayersController, new WallpaperController(sWm));
    255     }
    256 
    257     /** Creates a {@link com.android.server.wm.WindowTestUtils.TestWindowState} */
    258     WindowTestUtils.TestWindowState createWindowState(WindowManager.LayoutParams attrs,
    259             WindowToken token) {
    260         return new WindowTestUtils.TestWindowState(sWm, sMockSession, sIWindow, attrs, token);
    261     }
    262 
    263 }
    264