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.ActivityManager.StackId.PINNED_STACK_ID;
     20 import static android.view.Display.DEFAULT_DISPLAY;
     21 import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION;
     22 import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_ATTACHED_DIALOG;
     23 import static android.view.WindowManager.LayoutParams.TYPE_BASE_APPLICATION;
     24 import static android.view.WindowManager.LayoutParams.TYPE_VOICE_INTERACTION;
     25 import static com.android.server.wm.WindowContainer.POSITION_TOP;
     26 import static org.junit.Assert.assertEquals;
     27 import static org.junit.Assert.assertTrue;
     28 
     29 import org.junit.Ignore;
     30 import org.junit.Test;
     31 import org.junit.runner.RunWith;
     32 
     33 import android.content.res.Configuration;
     34 import android.platform.test.annotations.Presubmit;
     35 import android.support.test.filters.SmallTest;
     36 import android.support.test.runner.AndroidJUnit4;
     37 import android.util.SparseIntArray;
     38 
     39 import java.util.Arrays;
     40 import java.util.LinkedList;
     41 import java.util.List;
     42 
     43 /**
     44  * Tests for the {@link DisplayContent} class.
     45  *
     46  * Build/Install/Run:
     47  *  bit FrameworksServicesTests:com.android.server.wm.DisplayContentTests
     48  */
     49 @SmallTest
     50 @Presubmit
     51 @RunWith(AndroidJUnit4.class)
     52 public class DisplayContentTests extends WindowTestsBase {
     53 
     54     @Test
     55     public void testForAllWindows() throws Exception {
     56         final WindowState exitingAppWindow = createWindow(null, TYPE_BASE_APPLICATION,
     57                 mDisplayContent, "exiting app");
     58         final AppWindowToken exitingAppToken = exitingAppWindow.mAppToken;
     59         exitingAppToken.mIsExiting = true;
     60         exitingAppToken.getTask().mStack.mExitingAppTokens.add(exitingAppToken);
     61 
     62         assertForAllWindowsOrder(Arrays.asList(
     63                 mWallpaperWindow,
     64                 exitingAppWindow,
     65                 mChildAppWindowBelow,
     66                 mAppWindow,
     67                 mChildAppWindowAbove,
     68                 mDockedDividerWindow,
     69                 mStatusBarWindow,
     70                 mNavBarWindow,
     71                 mImeWindow,
     72                 mImeDialogWindow));
     73     }
     74 
     75     @Test
     76     public void testForAllWindows_WithAppImeTarget() throws Exception {
     77         final WindowState imeAppTarget =
     78                 createWindow(null, TYPE_BASE_APPLICATION, mDisplayContent, "imeAppTarget");
     79 
     80         sWm.mInputMethodTarget = imeAppTarget;
     81 
     82         assertForAllWindowsOrder(Arrays.asList(
     83                 mWallpaperWindow,
     84                 mChildAppWindowBelow,
     85                 mAppWindow,
     86                 mChildAppWindowAbove,
     87                 imeAppTarget,
     88                 mImeWindow,
     89                 mImeDialogWindow,
     90                 mDockedDividerWindow,
     91                 mStatusBarWindow,
     92                 mNavBarWindow));
     93     }
     94 
     95     @Test
     96     public void testForAllWindows_WithChildWindowImeTarget() throws Exception {
     97         sWm.mInputMethodTarget = mChildAppWindowAbove;
     98 
     99         assertForAllWindowsOrder(Arrays.asList(
    100                 mWallpaperWindow,
    101                 mChildAppWindowBelow,
    102                 mAppWindow,
    103                 mChildAppWindowAbove,
    104                 mImeWindow,
    105                 mImeDialogWindow,
    106                 mDockedDividerWindow,
    107                 mStatusBarWindow,
    108                 mNavBarWindow));
    109     }
    110 
    111     @Test
    112     public void testForAllWindows_WithStatusBarImeTarget() throws Exception {
    113         sWm.mInputMethodTarget = mStatusBarWindow;
    114 
    115         assertForAllWindowsOrder(Arrays.asList(
    116                 mWallpaperWindow,
    117                 mChildAppWindowBelow,
    118                 mAppWindow,
    119                 mChildAppWindowAbove,
    120                 mDockedDividerWindow,
    121                 mStatusBarWindow,
    122                 mImeWindow,
    123                 mImeDialogWindow,
    124                 mNavBarWindow));
    125     }
    126 
    127     @Test
    128     public void testForAllWindows_WithInBetweenWindowToken() throws Exception {
    129         // This window is set-up to be z-ordered between some windows that go in the same token like
    130         // the nav bar and status bar.
    131         final WindowState voiceInteractionWindow = createWindow(null, TYPE_VOICE_INTERACTION,
    132                 mDisplayContent, "voiceInteractionWindow");
    133 
    134         assertForAllWindowsOrder(Arrays.asList(
    135                 mWallpaperWindow,
    136                 mChildAppWindowBelow,
    137                 mAppWindow,
    138                 mChildAppWindowAbove,
    139                 mDockedDividerWindow,
    140                 voiceInteractionWindow,
    141                 mStatusBarWindow,
    142                 mNavBarWindow,
    143                 mImeWindow,
    144                 mImeDialogWindow));
    145     }
    146 
    147     @Test
    148     public void testComputeImeTarget() throws Exception {
    149         // Verify that an app window can be an ime target.
    150         final WindowState appWin = createWindow(null, TYPE_APPLICATION, mDisplayContent, "appWin");
    151         appWin.setHasSurface(true);
    152         assertTrue(appWin.canBeImeTarget());
    153         WindowState imeTarget = mDisplayContent.computeImeTarget(false /* updateImeTarget */);
    154         assertEquals(appWin, imeTarget);
    155 
    156         // Verify that an child window can be an ime target.
    157         final WindowState childWin = createWindow(appWin,
    158                 TYPE_APPLICATION_ATTACHED_DIALOG, "childWin");
    159         childWin.setHasSurface(true);
    160         assertTrue(childWin.canBeImeTarget());
    161         imeTarget = mDisplayContent.computeImeTarget(false /* updateImeTarget */);
    162         assertEquals(childWin, imeTarget);
    163     }
    164 
    165     /**
    166      * This tests stack movement between displays and proper stack's, task's and app token's display
    167      * container references updates.
    168      */
    169     @Test
    170     public void testMoveStackBetweenDisplays() throws Exception {
    171         // Create a second display.
    172         final DisplayContent dc = createNewDisplay();
    173 
    174         // Add stack with activity.
    175         final TaskStack stack = createTaskStackOnDisplay(dc);
    176         assertEquals(dc.getDisplayId(), stack.getDisplayContent().getDisplayId());
    177         assertEquals(dc, stack.getParent().getParent());
    178         assertEquals(dc, stack.getDisplayContent());
    179 
    180         final Task task = createTaskInStack(stack, 0 /* userId */);
    181         final WindowTestUtils.TestAppWindowToken token = new WindowTestUtils.TestAppWindowToken(dc);
    182         task.addChild(token, 0);
    183         assertEquals(dc, task.getDisplayContent());
    184         assertEquals(dc, token.getDisplayContent());
    185 
    186         // Move stack to first display.
    187         mDisplayContent.moveStackToDisplay(stack, true /* onTop */);
    188         assertEquals(mDisplayContent.getDisplayId(), stack.getDisplayContent().getDisplayId());
    189         assertEquals(mDisplayContent, stack.getParent().getParent());
    190         assertEquals(mDisplayContent, stack.getDisplayContent());
    191         assertEquals(mDisplayContent, task.getDisplayContent());
    192         assertEquals(mDisplayContent, token.getDisplayContent());
    193     }
    194 
    195     /**
    196      * This tests override configuration updates for display content.
    197      */
    198     @Test
    199     public void testDisplayOverrideConfigUpdate() throws Exception {
    200         final int displayId = mDisplayContent.getDisplayId();
    201         final Configuration currentOverrideConfig = mDisplayContent.getOverrideConfiguration();
    202 
    203         // Create new, slightly changed override configuration and apply it to the display.
    204         final Configuration newOverrideConfig = new Configuration(currentOverrideConfig);
    205         newOverrideConfig.densityDpi += 120;
    206         newOverrideConfig.fontScale += 0.3;
    207 
    208         sWm.setNewDisplayOverrideConfiguration(newOverrideConfig, displayId);
    209 
    210         // Check that override config is applied.
    211         assertEquals(newOverrideConfig, mDisplayContent.getOverrideConfiguration());
    212     }
    213 
    214     /**
    215      * This tests global configuration updates when default display config is updated.
    216      */
    217     @Test
    218     public void testDefaultDisplayOverrideConfigUpdate() throws Exception {
    219         final Configuration currentConfig = mDisplayContent.getConfiguration();
    220 
    221         // Create new, slightly changed override configuration and apply it to the display.
    222         final Configuration newOverrideConfig = new Configuration(currentConfig);
    223         newOverrideConfig.densityDpi += 120;
    224         newOverrideConfig.fontScale += 0.3;
    225 
    226         sWm.setNewDisplayOverrideConfiguration(newOverrideConfig, DEFAULT_DISPLAY);
    227 
    228         // Check that global configuration is updated, as we've updated default display's config.
    229         Configuration globalConfig = sWm.mRoot.getConfiguration();
    230         assertEquals(newOverrideConfig.densityDpi, globalConfig.densityDpi);
    231         assertEquals(newOverrideConfig.fontScale, globalConfig.fontScale, 0.1 /* delta */);
    232 
    233         // Return back to original values.
    234         sWm.setNewDisplayOverrideConfiguration(currentConfig, DEFAULT_DISPLAY);
    235         globalConfig = sWm.mRoot.getConfiguration();
    236         assertEquals(currentConfig.densityDpi, globalConfig.densityDpi);
    237         assertEquals(currentConfig.fontScale, globalConfig.fontScale, 0.1 /* delta */);
    238     }
    239 
    240     @Test
    241     @Ignore
    242     public void testFocusedWindowMultipleDisplays() throws Exception {
    243         // Create a focusable window and check that focus is calculated correctly
    244         final WindowState window1 =
    245                 createWindow(null, TYPE_BASE_APPLICATION, mDisplayContent, "window1");
    246         assertEquals(window1, sWm.mRoot.computeFocusedWindow());
    247 
    248         // Check that a new display doesn't affect focus
    249         final DisplayContent dc = createNewDisplay();
    250         assertEquals(window1, sWm.mRoot.computeFocusedWindow());
    251 
    252         // Add a window to the second display, and it should be focused
    253         final WindowState window2 = createWindow(null, TYPE_BASE_APPLICATION, dc, "window2");
    254         assertEquals(window2, sWm.mRoot.computeFocusedWindow());
    255 
    256         // Move the first window to the to including parents, and make sure focus is updated
    257         window1.getParent().positionChildAt(POSITION_TOP, window1, true);
    258         assertEquals(window1, sWm.mRoot.computeFocusedWindow());
    259     }
    260 
    261     /**
    262      * This tests setting the maximum ui width on a display.
    263      */
    264     @Test
    265     public void testMaxUiWidth() throws Exception {
    266         final int baseWidth = 1440;
    267         final int baseHeight = 2560;
    268         final int baseDensity = 300;
    269 
    270         mDisplayContent.updateBaseDisplayMetrics(baseWidth, baseHeight, baseDensity);
    271 
    272         final int maxWidth = 300;
    273         final int resultingHeight = (maxWidth * baseHeight) / baseWidth;
    274         final int resultingDensity = (maxWidth * baseDensity) / baseWidth;
    275 
    276         mDisplayContent.setMaxUiWidth(maxWidth);
    277         verifySizes(mDisplayContent, maxWidth, resultingHeight, resultingDensity);
    278 
    279         // Assert setting values again does not change;
    280         mDisplayContent.updateBaseDisplayMetrics(baseWidth, baseHeight, baseDensity);
    281         verifySizes(mDisplayContent, maxWidth, resultingHeight, resultingDensity);
    282 
    283         final int smallerWidth = 200;
    284         final int smallerHeight = 400;
    285         final int smallerDensity = 100;
    286 
    287         // Specify smaller dimension, verify that it is honored
    288         mDisplayContent.updateBaseDisplayMetrics(smallerWidth, smallerHeight, smallerDensity);
    289         verifySizes(mDisplayContent, smallerWidth, smallerHeight, smallerDensity);
    290 
    291         // Verify that setting the max width to a greater value than the base width has no effect
    292         mDisplayContent.setMaxUiWidth(maxWidth);
    293         verifySizes(mDisplayContent, smallerWidth, smallerHeight, smallerDensity);
    294     }
    295 
    296     /**
    297      * This test enforces that the pinned stack is always kept as the top stack.
    298      */
    299     @Test
    300     public void testPinnedStackLocation() {
    301         createStackControllerOnStackOnDisplay(PINNED_STACK_ID, mDisplayContent);
    302         final int initialStackCount = mDisplayContent.getStackCount();
    303         // Ensure that the pinned stack was placed at the end
    304         assertEquals(initialStackCount - 1, mDisplayContent.getStaskPosById(PINNED_STACK_ID));
    305         // By default, this should try to create a new stack on top
    306         createTaskStackOnDisplay(mDisplayContent);
    307         final int afterStackCount = mDisplayContent.getStackCount();
    308         // Make sure the stack count has increased
    309         assertEquals(initialStackCount + 1, afterStackCount);
    310         // Ensure that the pinned stack is still on top
    311         assertEquals(afterStackCount - 1, mDisplayContent.getStaskPosById(PINNED_STACK_ID));
    312     }
    313 
    314     /**
    315      * Test that WM does not report displays to AM that are pending to be removed.
    316      */
    317     @Test
    318     public void testDontReportDeferredRemoval() {
    319         // Create a display and add an animating window to it.
    320         final DisplayContent dc = createNewDisplay();
    321         final WindowState window = createWindow(null /* parent */, TYPE_BASE_APPLICATION, dc, "w");
    322         window.mAnimatingExit = true;
    323         // Request display removal, it should be deferred.
    324         dc.removeIfPossible();
    325         // Request ordered display ids from WM.
    326         final SparseIntArray orderedDisplayIds = new SparseIntArray();
    327         sWm.getDisplaysInFocusOrder(orderedDisplayIds);
    328         // Make sure that display that is marked for removal is not reported.
    329         assertEquals(-1, orderedDisplayIds.indexOfValue(dc.getDisplayId()));
    330     }
    331 
    332     private static void verifySizes(DisplayContent displayContent, int expectedBaseWidth,
    333                              int expectedBaseHeight, int expectedBaseDensity) {
    334         assertEquals(displayContent.mBaseDisplayWidth, expectedBaseWidth);
    335         assertEquals(displayContent.mBaseDisplayHeight, expectedBaseHeight);
    336         assertEquals(displayContent.mBaseDisplayDensity, expectedBaseDensity);
    337     }
    338 
    339     private void assertForAllWindowsOrder(List<WindowState> expectedWindows) {
    340         final LinkedList<WindowState> actualWindows = new LinkedList();
    341 
    342         // Test forward traversal.
    343         mDisplayContent.forAllWindows(actualWindows::addLast, false /* traverseTopToBottom */);
    344         assertEquals(expectedWindows.size(), actualWindows.size());
    345         for (WindowState w : expectedWindows) {
    346             assertEquals(w, actualWindows.pollFirst());
    347         }
    348         assertTrue(actualWindows.isEmpty());
    349 
    350         // Test backward traversal.
    351         mDisplayContent.forAllWindows(actualWindows::addLast, true /* traverseTopToBottom */);
    352         assertEquals(expectedWindows.size(), actualWindows.size());
    353         for (WindowState w : expectedWindows) {
    354             assertEquals(w, actualWindows.pollLast());
    355         }
    356         assertTrue(actualWindows.isEmpty());
    357     }
    358 }
    359