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.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD;
     20 import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
     21 import static android.view.Display.DEFAULT_DISPLAY;
     22 import static android.view.View.VISIBLE;
     23 
     24 import android.content.res.Configuration;
     25 import android.graphics.Rect;
     26 import android.hardware.display.DisplayManagerGlobal;
     27 import android.testing.DexmakerShareClassLoaderRule;
     28 import android.util.Log;
     29 import android.view.Display;
     30 import android.view.DisplayInfo;
     31 import org.junit.Assert;
     32 import org.junit.After;
     33 import org.junit.Before;
     34 import org.junit.Rule;
     35 
     36 import android.content.Context;
     37 import android.support.test.InstrumentationRegistry;
     38 import android.view.IWindow;
     39 import android.view.WindowManager;
     40 
     41 import static android.app.AppOpsManager.OP_NONE;
     42 import static android.view.DisplayAdjustments.DEFAULT_DISPLAY_ADJUSTMENTS;
     43 import static android.view.WindowManager.LayoutParams.FIRST_APPLICATION_WINDOW;
     44 import static android.view.WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
     45 import static android.view.WindowManager.LayoutParams.LAST_APPLICATION_WINDOW;
     46 import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_ATTACHED_DIALOG;
     47 import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_MEDIA_OVERLAY;
     48 import static android.view.WindowManager.LayoutParams.TYPE_BASE_APPLICATION;
     49 import static android.view.WindowManager.LayoutParams.TYPE_DOCK_DIVIDER;
     50 import static android.view.WindowManager.LayoutParams.TYPE_INPUT_METHOD;
     51 import static android.view.WindowManager.LayoutParams.TYPE_INPUT_METHOD_DIALOG;
     52 import static android.view.WindowManager.LayoutParams.TYPE_NAVIGATION_BAR;
     53 import static android.view.WindowManager.LayoutParams.TYPE_STATUS_BAR;
     54 import static android.view.WindowManager.LayoutParams.TYPE_WALLPAPER;
     55 import static org.mockito.Mockito.mock;
     56 
     57 import com.android.server.AttributeCache;
     58 
     59 import java.util.HashSet;
     60 import java.util.LinkedList;
     61 
     62 /**
     63  * Common base class for window manager unit test classes.
     64  *
     65  * Make sure any requests to WM hold the WM lock if needed b/73966377
     66  */
     67 class WindowTestsBase {
     68     private static final String TAG = WindowTestsBase.class.getSimpleName();
     69     WindowManagerService sWm = null;  // TODO(roosa): rename to mWm in follow-up CL
     70     private final IWindow mIWindow = new TestIWindow();
     71     private Session mMockSession;
     72     // The default display is removed in {@link #setUp} and then we iterate over all displays to
     73     // make sure we don't collide with any existing display. If we run into no other display, the
     74     // added display should be treated as default. This cannot be the default display
     75     private static int sNextDisplayId = DEFAULT_DISPLAY + 1;
     76     static int sNextStackId = 1000;
     77 
     78     DisplayContent mDisplayContent;
     79     DisplayInfo mDisplayInfo = new DisplayInfo();
     80     WindowState mWallpaperWindow;
     81     WindowState mImeWindow;
     82     WindowState mImeDialogWindow;
     83     WindowState mStatusBarWindow;
     84     WindowState mDockedDividerWindow;
     85     WindowState mNavBarWindow;
     86     WindowState mAppWindow;
     87     WindowState mChildAppWindowAbove;
     88     WindowState mChildAppWindowBelow;
     89     HashSet<WindowState> mCommonWindows;
     90     WallpaperController mWallpaperController;
     91 
     92     @Rule
     93     public final DexmakerShareClassLoaderRule mDexmakerShareClassLoaderRule =
     94             new DexmakerShareClassLoaderRule();
     95 
     96     @Rule
     97     public final WindowManagerServiceRule mWmRule = new WindowManagerServiceRule();
     98 
     99     static WindowState.PowerManagerWrapper mPowerManagerWrapper;  // TODO(roosa): make non-static.
    100 
    101     @Before
    102     public void setUp() throws Exception {
    103         // If @Before throws an exception, the error isn't logged. This will make sure any failures
    104         // in the set up are clear. This can be removed when b/37850063 is fixed.
    105         try {
    106             mMockSession = mock(Session.class);
    107             mPowerManagerWrapper = mock(WindowState.PowerManagerWrapper.class);
    108 
    109             final Context context = InstrumentationRegistry.getTargetContext();
    110             AttributeCache.init(context);
    111 
    112             sWm = mWmRule.getWindowManagerService();
    113             beforeCreateDisplay();
    114 
    115             mWallpaperController = new WallpaperController(sWm);
    116 
    117             context.getDisplay().getDisplayInfo(mDisplayInfo);
    118             mDisplayContent = createNewDisplay();
    119             sWm.mDisplayEnabled = true;
    120             sWm.mDisplayReady = true;
    121 
    122             // Set-up some common windows.
    123             mCommonWindows = new HashSet();
    124             synchronized (sWm.mWindowMap) {
    125                 mWallpaperWindow = createCommonWindow(null, TYPE_WALLPAPER, "wallpaperWindow");
    126                 mImeWindow = createCommonWindow(null, TYPE_INPUT_METHOD, "mImeWindow");
    127                 sWm.mInputMethodWindow = mImeWindow;
    128                 mImeDialogWindow = createCommonWindow(null, TYPE_INPUT_METHOD_DIALOG,
    129                         "mImeDialogWindow");
    130                 mStatusBarWindow = createCommonWindow(null, TYPE_STATUS_BAR, "mStatusBarWindow");
    131                 mNavBarWindow = createCommonWindow(null, TYPE_NAVIGATION_BAR, "mNavBarWindow");
    132                 mDockedDividerWindow = createCommonWindow(null, TYPE_DOCK_DIVIDER,
    133                         "mDockedDividerWindow");
    134                 mAppWindow = createCommonWindow(null, TYPE_BASE_APPLICATION, "mAppWindow");
    135                 mChildAppWindowAbove = createCommonWindow(mAppWindow,
    136                         TYPE_APPLICATION_ATTACHED_DIALOG,
    137                         "mChildAppWindowAbove");
    138                 mChildAppWindowBelow = createCommonWindow(mAppWindow,
    139                         TYPE_APPLICATION_MEDIA_OVERLAY,
    140                         "mChildAppWindowBelow");
    141             }
    142             // Adding a display will cause freezing the display. Make sure to wait until it's
    143             // unfrozen to not run into race conditions with the tests.
    144             waitUntilHandlersIdle();
    145         } catch (Exception e) {
    146             Log.e(TAG, "Failed to set up test", e);
    147             throw e;
    148         }
    149     }
    150 
    151     void beforeCreateDisplay() {
    152         // Called before display is created.
    153     }
    154 
    155     @After
    156     public void tearDown() throws Exception {
    157         // If @After throws an exception, the error isn't logged. This will make sure any failures
    158         // in the tear down are clear. This can be removed when b/37850063 is fixed.
    159         try {
    160             final LinkedList<WindowState> nonCommonWindows = new LinkedList();
    161 
    162             synchronized (sWm.mWindowMap) {
    163                 sWm.mRoot.forAllWindows(w -> {
    164                     if (!mCommonWindows.contains(w)) {
    165                         nonCommonWindows.addLast(w);
    166                     }
    167                 }, true /* traverseTopToBottom */);
    168 
    169                 while (!nonCommonWindows.isEmpty()) {
    170                     nonCommonWindows.pollLast().removeImmediately();
    171                 }
    172 
    173                 mDisplayContent.removeImmediately();
    174                 sWm.mInputMethodTarget = null;
    175                 sWm.mClosingApps.clear();
    176                 sWm.mOpeningApps.clear();
    177             }
    178 
    179             // Wait until everything is really cleaned up.
    180             waitUntilHandlersIdle();
    181         } catch (Exception e) {
    182             Log.e(TAG, "Failed to tear down test", e);
    183             throw e;
    184         }
    185     }
    186 
    187     /**
    188      * @return A SurfaceBuilderFactory to inject in to the WindowManagerService during
    189      *         set-up (or null).
    190      */
    191     SurfaceBuilderFactory getSurfaceBuilderFactory() {
    192         return null;
    193     }
    194 
    195     private WindowState createCommonWindow(WindowState parent, int type, String name) {
    196         synchronized (sWm.mWindowMap) {
    197             final WindowState win = createWindow(parent, type, name);
    198             mCommonWindows.add(win);
    199             // Prevent common windows from been IMe targets
    200             win.mAttrs.flags |= FLAG_NOT_FOCUSABLE;
    201             return win;
    202         }
    203     }
    204 
    205     /** Asserts that the first entry is greater than the second entry. */
    206     void assertGreaterThan(int first, int second) throws Exception {
    207         Assert.assertTrue("Excepted " + first + " to be greater than " + second, first > second);
    208     }
    209 
    210     /** Asserts that the first entry is greater than the second entry. */
    211     void assertLessThan(int first, int second) throws Exception {
    212         Assert.assertTrue("Excepted " + first + " to be less than " + second, first < second);
    213     }
    214 
    215     /**
    216      * Waits until the main handler for WM has processed all messages.
    217      */
    218     void waitUntilHandlersIdle() {
    219         mWmRule.waitUntilWindowManagerHandlersIdle();
    220     }
    221 
    222     private WindowToken createWindowToken(
    223             DisplayContent dc, int windowingMode, int activityType, int type) {
    224         synchronized (sWm.mWindowMap) {
    225             if (type < FIRST_APPLICATION_WINDOW || type > LAST_APPLICATION_WINDOW) {
    226                 return WindowTestUtils.createTestWindowToken(type, dc);
    227             }
    228 
    229             return createAppWindowToken(dc, windowingMode, activityType);
    230         }
    231     }
    232 
    233     AppWindowToken createAppWindowToken(DisplayContent dc, int windowingMode, int activityType) {
    234         final TaskStack stack = createStackControllerOnStackOnDisplay(windowingMode, activityType,
    235                 dc).mContainer;
    236         final Task task = createTaskInStack(stack, 0 /* userId */);
    237         final WindowTestUtils.TestAppWindowToken appWindowToken =
    238                 WindowTestUtils.createTestAppWindowToken(dc);
    239         task.addChild(appWindowToken, 0);
    240         return appWindowToken;
    241     }
    242 
    243     WindowState createWindow(WindowState parent, int type, String name) {
    244         synchronized (sWm.mWindowMap) {
    245             return (parent == null)
    246                     ? createWindow(parent, type, mDisplayContent, name)
    247                     : createWindow(parent, type, parent.mToken, name);
    248         }
    249     }
    250 
    251     WindowState createWindowOnStack(WindowState parent, int windowingMode, int activityType,
    252             int type, DisplayContent dc, String name) {
    253         synchronized (sWm.mWindowMap) {
    254             final WindowToken token = createWindowToken(dc, windowingMode, activityType, type);
    255             return createWindow(parent, type, token, name);
    256         }
    257     }
    258 
    259     WindowState createAppWindow(Task task, int type, String name) {
    260         synchronized (sWm.mWindowMap) {
    261             final AppWindowToken token = WindowTestUtils.createTestAppWindowToken(mDisplayContent);
    262             task.addChild(token, 0);
    263             return createWindow(null, type, token, name);
    264         }
    265     }
    266 
    267     WindowState createWindow(WindowState parent, int type, DisplayContent dc, String name) {
    268         synchronized (sWm.mWindowMap) {
    269             final WindowToken token = createWindowToken(
    270                     dc, WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, type);
    271             return createWindow(parent, type, token, name);
    272         }
    273     }
    274 
    275     WindowState createWindow(WindowState parent, int type, DisplayContent dc, String name,
    276             boolean ownerCanAddInternalSystemWindow) {
    277         synchronized (sWm.mWindowMap) {
    278             final WindowToken token = createWindowToken(
    279                     dc, WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, type);
    280             return createWindow(parent, type, token, name, 0 /* ownerId */,
    281                     ownerCanAddInternalSystemWindow);
    282         }
    283     }
    284 
    285     WindowState createWindow(WindowState parent, int type, WindowToken token, String name) {
    286         synchronized (sWm.mWindowMap) {
    287             return createWindow(parent, type, token, name, 0 /* ownerId */,
    288                     false /* ownerCanAddInternalSystemWindow */);
    289         }
    290     }
    291 
    292     WindowState createWindow(WindowState parent, int type, WindowToken token, String name,
    293             int ownerId, boolean ownerCanAddInternalSystemWindow) {
    294         return createWindow(parent, type, token, name, ownerId, ownerCanAddInternalSystemWindow,
    295                 sWm, mMockSession, mIWindow);
    296     }
    297 
    298     static WindowState createWindow(WindowState parent, int type, WindowToken token,
    299             String name, int ownerId, boolean ownerCanAddInternalSystemWindow,
    300             WindowManagerService service, Session session, IWindow iWindow) {
    301         synchronized (service.mWindowMap) {
    302             final WindowManager.LayoutParams attrs = new WindowManager.LayoutParams(type);
    303             attrs.setTitle(name);
    304 
    305             final WindowState w = new WindowState(service, session, iWindow, token, parent,
    306                     OP_NONE,
    307                     0, attrs, VISIBLE, ownerId, ownerCanAddInternalSystemWindow,
    308                     mPowerManagerWrapper);
    309             // TODO: Probably better to make this call in the WindowState ctor to avoid errors with
    310             // adding it to the token...
    311             token.addWindow(w);
    312             return w;
    313         }
    314     }
    315 
    316     /** Creates a {@link TaskStack} and adds it to the specified {@link DisplayContent}. */
    317     TaskStack createTaskStackOnDisplay(DisplayContent dc) {
    318         synchronized (sWm.mWindowMap) {
    319             return createStackControllerOnDisplay(dc).mContainer;
    320         }
    321     }
    322 
    323     StackWindowController createStackControllerOnDisplay(DisplayContent dc) {
    324         synchronized (sWm.mWindowMap) {
    325             return createStackControllerOnStackOnDisplay(
    326                     WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, dc);
    327         }
    328     }
    329 
    330     StackWindowController createStackControllerOnStackOnDisplay(
    331             int windowingMode, int activityType, DisplayContent dc) {
    332         synchronized (sWm.mWindowMap) {
    333             final Configuration overrideConfig = new Configuration();
    334             overrideConfig.windowConfiguration.setWindowingMode(windowingMode);
    335             overrideConfig.windowConfiguration.setActivityType(activityType);
    336             final int stackId = ++sNextStackId;
    337             final StackWindowController controller = new StackWindowController(stackId, null,
    338                     dc.getDisplayId(), true /* onTop */, new Rect(), sWm);
    339             controller.onOverrideConfigurationChanged(overrideConfig);
    340             return controller;
    341         }
    342     }
    343 
    344     /** Creates a {@link Task} and adds it to the specified {@link TaskStack}. */
    345     Task createTaskInStack(TaskStack stack, int userId) {
    346         return WindowTestUtils.createTaskInStack(sWm, stack, userId);
    347     }
    348 
    349     /** Creates a {@link DisplayContent} and adds it to the system. */
    350     DisplayContent createNewDisplay() {
    351         final int displayId = sNextDisplayId++;
    352         final Display display = new Display(DisplayManagerGlobal.getInstance(), displayId,
    353                 mDisplayInfo, DEFAULT_DISPLAY_ADJUSTMENTS);
    354         synchronized (sWm.mWindowMap) {
    355             return new DisplayContent(display, sWm, mWallpaperController,
    356                     mock(DisplayWindowController.class));
    357         }
    358     }
    359 
    360     /** Creates a {@link com.android.server.wm.WindowTestUtils.TestWindowState} */
    361     WindowTestUtils.TestWindowState createWindowState(WindowManager.LayoutParams attrs,
    362             WindowToken token) {
    363         synchronized (sWm.mWindowMap) {
    364             return new WindowTestUtils.TestWindowState(sWm, mMockSession, mIWindow, attrs, token);
    365         }
    366     }
    367 
    368 }
    369