Move WindowManager tests to WmTests
Bug: 113800711
Test: All presubmit and non-flaky tests in WmTests pass
$ tradefed.sh run commandAndExit WmTests \
--include-annotation android.platform.test.annotations.Presubmit \
--exclude-annotation androidx.test.filters.FlakyTest
Change-Id: I593eb03c8ee3c297eae85e39434d04138a67ab15
diff --git a/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java b/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java
new file mode 100644
index 0000000..3b8d71d
--- /dev/null
+++ b/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java
@@ -0,0 +1,623 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.wm;
+
+import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE;
+import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_PORTRAIT;
+import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
+import static android.view.Display.DEFAULT_DISPLAY;
+import static android.view.DisplayCutout.BOUNDS_POSITION_LEFT;
+import static android.view.DisplayCutout.BOUNDS_POSITION_TOP;
+import static android.view.DisplayCutout.fromBoundingRect;
+import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION;
+import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_ATTACHED_DIALOG;
+import static android.view.WindowManager.LayoutParams.TYPE_BASE_APPLICATION;
+import static android.view.WindowManager.LayoutParams.TYPE_STATUS_BAR;
+import static android.view.WindowManager.LayoutParams.TYPE_VOICE_INTERACTION;
+
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.doNothing;
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.spy;
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.times;
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.verify;
+import static com.android.server.wm.WindowContainer.POSITION_TOP;
+import static com.android.server.wm.WindowManagerService.UPDATE_FOCUS_NORMAL;
+
+import static org.hamcrest.Matchers.is;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertThat;
+import static org.junit.Assert.assertTrue;
+
+import android.annotation.SuppressLint;
+import android.content.res.Configuration;
+import android.graphics.Rect;
+import android.os.SystemClock;
+import android.platform.test.annotations.Presubmit;
+import android.util.DisplayMetrics;
+import android.view.DisplayCutout;
+import android.view.Gravity;
+import android.view.MotionEvent;
+import android.view.Surface;
+
+import androidx.test.filters.FlakyTest;
+import androidx.test.filters.SmallTest;
+
+import com.android.server.wm.utils.WmDisplayCutout;
+
+import org.junit.Test;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.LinkedList;
+import java.util.List;
+
+/**
+ * Tests for the {@link DisplayContent} class.
+ *
+ * Build/Install/Run:
+ * atest FrameworksServicesTests:DisplayContentTests
+ */
+@SmallTest
+@Presubmit
+public class DisplayContentTests extends WindowTestsBase {
+
+ @Test
+ @FlakyTest(bugId = 77772044)
+ public void testForAllWindows() {
+ final WindowState exitingAppWindow = createWindow(null, TYPE_BASE_APPLICATION,
+ mDisplayContent, "exiting app");
+ final AppWindowToken exitingAppToken = exitingAppWindow.mAppToken;
+ exitingAppToken.mIsExiting = true;
+ exitingAppToken.getTask().mStack.mExitingAppTokens.add(exitingAppToken);
+
+ assertForAllWindowsOrder(Arrays.asList(
+ mWallpaperWindow,
+ exitingAppWindow,
+ mChildAppWindowBelow,
+ mAppWindow,
+ mChildAppWindowAbove,
+ mDockedDividerWindow,
+ mStatusBarWindow,
+ mNavBarWindow,
+ mImeWindow,
+ mImeDialogWindow));
+ }
+
+ @Test
+ public void testForAllWindows_WithAppImeTarget() {
+ final WindowState imeAppTarget =
+ createWindow(null, TYPE_BASE_APPLICATION, mDisplayContent, "imeAppTarget");
+
+ mDisplayContent.mInputMethodTarget = imeAppTarget;
+
+ assertForAllWindowsOrder(Arrays.asList(
+ mWallpaperWindow,
+ mChildAppWindowBelow,
+ mAppWindow,
+ mChildAppWindowAbove,
+ imeAppTarget,
+ mImeWindow,
+ mImeDialogWindow,
+ mDockedDividerWindow,
+ mStatusBarWindow,
+ mNavBarWindow));
+ }
+
+ @Test
+ public void testForAllWindows_WithChildWindowImeTarget() throws Exception {
+ mDisplayContent.mInputMethodTarget = mChildAppWindowAbove;
+
+ assertForAllWindowsOrder(Arrays.asList(
+ mWallpaperWindow,
+ mChildAppWindowBelow,
+ mAppWindow,
+ mChildAppWindowAbove,
+ mImeWindow,
+ mImeDialogWindow,
+ mDockedDividerWindow,
+ mStatusBarWindow,
+ mNavBarWindow));
+ }
+
+ @Test
+ public void testForAllWindows_WithStatusBarImeTarget() throws Exception {
+ mDisplayContent.mInputMethodTarget = mStatusBarWindow;
+
+ assertForAllWindowsOrder(Arrays.asList(
+ mWallpaperWindow,
+ mChildAppWindowBelow,
+ mAppWindow,
+ mChildAppWindowAbove,
+ mDockedDividerWindow,
+ mStatusBarWindow,
+ mImeWindow,
+ mImeDialogWindow,
+ mNavBarWindow));
+ }
+
+ @Test
+ public void testForAllWindows_WithInBetweenWindowToken() {
+ // This window is set-up to be z-ordered between some windows that go in the same token like
+ // the nav bar and status bar.
+ final WindowState voiceInteractionWindow = createWindow(null, TYPE_VOICE_INTERACTION,
+ mDisplayContent, "voiceInteractionWindow");
+
+ assertForAllWindowsOrder(Arrays.asList(
+ mWallpaperWindow,
+ mChildAppWindowBelow,
+ mAppWindow,
+ mChildAppWindowAbove,
+ mDockedDividerWindow,
+ voiceInteractionWindow,
+ mStatusBarWindow,
+ mNavBarWindow,
+ mImeWindow,
+ mImeDialogWindow));
+ }
+
+ @Test
+ public void testComputeImeTarget() {
+ // Verify that an app window can be an ime target.
+ final WindowState appWin = createWindow(null, TYPE_APPLICATION, mDisplayContent, "appWin");
+ appWin.setHasSurface(true);
+ assertTrue(appWin.canBeImeTarget());
+ WindowState imeTarget = mDisplayContent.computeImeTarget(false /* updateImeTarget */);
+ assertEquals(appWin, imeTarget);
+ appWin.mHidden = false;
+
+ // Verify that an child window can be an ime target.
+ final WindowState childWin = createWindow(appWin,
+ TYPE_APPLICATION_ATTACHED_DIALOG, "childWin");
+ childWin.setHasSurface(true);
+ assertTrue(childWin.canBeImeTarget());
+ imeTarget = mDisplayContent.computeImeTarget(false /* updateImeTarget */);
+ assertEquals(childWin, imeTarget);
+ }
+
+ /**
+ * This tests stack movement between displays and proper stack's, task's and app token's display
+ * container references updates.
+ */
+ @Test
+ public void testMoveStackBetweenDisplays() {
+ // Create a second display.
+ final DisplayContent dc = createNewDisplay();
+
+ // Add stack with activity.
+ final TaskStack stack = createTaskStackOnDisplay(dc);
+ assertEquals(dc.getDisplayId(), stack.getDisplayContent().getDisplayId());
+ assertEquals(dc, stack.getParent().getParent());
+ assertEquals(dc, stack.getDisplayContent());
+
+ final Task task = createTaskInStack(stack, 0 /* userId */);
+ final WindowTestUtils.TestAppWindowToken token = WindowTestUtils.createTestAppWindowToken(
+ dc);
+ task.addChild(token, 0);
+ assertEquals(dc, task.getDisplayContent());
+ assertEquals(dc, token.getDisplayContent());
+
+ // Move stack to first display.
+ mDisplayContent.moveStackToDisplay(stack, true /* onTop */);
+ assertEquals(mDisplayContent.getDisplayId(), stack.getDisplayContent().getDisplayId());
+ assertEquals(mDisplayContent, stack.getParent().getParent());
+ assertEquals(mDisplayContent, stack.getDisplayContent());
+ assertEquals(mDisplayContent, task.getDisplayContent());
+ assertEquals(mDisplayContent, token.getDisplayContent());
+ }
+
+ /**
+ * This tests override configuration updates for display content.
+ */
+ @Test
+ public void testDisplayOverrideConfigUpdate() {
+ final Configuration currentOverrideConfig = mDisplayContent.getOverrideConfiguration();
+
+ // Create new, slightly changed override configuration and apply it to the display.
+ final Configuration newOverrideConfig = new Configuration(currentOverrideConfig);
+ newOverrideConfig.densityDpi += 120;
+ newOverrideConfig.fontScale += 0.3;
+
+ mWm.setNewDisplayOverrideConfiguration(newOverrideConfig, mDisplayContent);
+
+ // Check that override config is applied.
+ assertEquals(newOverrideConfig, mDisplayContent.getOverrideConfiguration());
+ }
+
+ /**
+ * This tests global configuration updates when default display config is updated.
+ */
+ @Test
+ public void testDefaultDisplayOverrideConfigUpdate() {
+ DisplayContent defaultDisplay = mWm.mRoot.getDisplayContent(DEFAULT_DISPLAY);
+ final Configuration currentConfig = defaultDisplay.getConfiguration();
+
+ // Create new, slightly changed override configuration and apply it to the display.
+ final Configuration newOverrideConfig = new Configuration(currentConfig);
+ newOverrideConfig.densityDpi += 120;
+ newOverrideConfig.fontScale += 0.3;
+
+ mWm.setNewDisplayOverrideConfiguration(newOverrideConfig, defaultDisplay);
+
+ // Check that global configuration is updated, as we've updated default display's config.
+ Configuration globalConfig = mWm.mRoot.getConfiguration();
+ assertEquals(newOverrideConfig.densityDpi, globalConfig.densityDpi);
+ assertEquals(newOverrideConfig.fontScale, globalConfig.fontScale, 0.1 /* delta */);
+
+ // Return back to original values.
+ mWm.setNewDisplayOverrideConfiguration(currentConfig, defaultDisplay);
+ globalConfig = mWm.mRoot.getConfiguration();
+ assertEquals(currentConfig.densityDpi, globalConfig.densityDpi);
+ assertEquals(currentConfig.fontScale, globalConfig.fontScale, 0.1 /* delta */);
+ }
+
+ /**
+ * Tests tapping on a stack in different display results in window gaining focus.
+ */
+ @Test
+ public void testInputEventBringsCorrectDisplayInFocus() {
+ DisplayContent dc0 = mWm.getDefaultDisplayContentLocked();
+ // Create a second display
+ final DisplayContent dc1 = createNewDisplay();
+
+ // Add stack with activity.
+ final TaskStack stack0 = createTaskStackOnDisplay(dc0);
+ final Task task0 = createTaskInStack(stack0, 0 /* userId */);
+ final WindowTestUtils.TestAppWindowToken token =
+ WindowTestUtils.createTestAppWindowToken(dc0);
+ task0.addChild(token, 0);
+ dc0.configureDisplayPolicy();
+ assertNotNull(dc0.mTapDetector);
+
+ final TaskStack stack1 = createTaskStackOnDisplay(dc1);
+ final Task task1 = createTaskInStack(stack1, 0 /* userId */);
+ final WindowTestUtils.TestAppWindowToken token1 =
+ WindowTestUtils.createTestAppWindowToken(dc0);
+ task1.addChild(token1, 0);
+ dc1.configureDisplayPolicy();
+ assertNotNull(dc1.mTapDetector);
+
+ // tap on primary display.
+ tapOnDisplay(dc0);
+ // Check focus is on primary display.
+ assertEquals(mWm.mRoot.getTopFocusedDisplayContent().mCurrentFocus,
+ dc0.findFocusedWindow());
+
+ // Tap on secondary display.
+ tapOnDisplay(dc1);
+ // Check focus is on secondary.
+ assertEquals(mWm.mRoot.getTopFocusedDisplayContent().mCurrentFocus,
+ dc1.findFocusedWindow());
+ }
+
+ @Test
+ public void testFocusedWindowMultipleDisplays() {
+ // Create a focusable window and check that focus is calculated correctly
+ final WindowState window1 =
+ createWindow(null, TYPE_BASE_APPLICATION, mDisplayContent, "window1");
+ updateFocusedWindow();
+ assertTrue(window1.isFocused());
+ assertEquals(window1, mWm.mRoot.getTopFocusedDisplayContent().mCurrentFocus);
+
+ // Check that a new display doesn't affect focus
+ final DisplayContent dc = createNewDisplay();
+ updateFocusedWindow();
+ assertTrue(window1.isFocused());
+ assertEquals(window1, mWm.mRoot.getTopFocusedDisplayContent().mCurrentFocus);
+
+ // Add a window to the second display, and it should be focused
+ final WindowState window2 = createWindow(null, TYPE_BASE_APPLICATION, dc, "window2");
+ updateFocusedWindow();
+ assertTrue(window1.isFocused());
+ assertTrue(window2.isFocused());
+ assertEquals(window2, mWm.mRoot.getTopFocusedDisplayContent().mCurrentFocus);
+
+ // Move the first window to the to including parents, and make sure focus is updated
+ window1.getParent().positionChildAt(POSITION_TOP, window1, true);
+ updateFocusedWindow();
+ assertTrue(window1.isFocused());
+ assertTrue(window2.isFocused());
+ assertEquals(window1, mWm.mRoot.getTopFocusedDisplayContent().mCurrentFocus);
+ }
+
+ /**
+ * This tests setting the maximum ui width on a display.
+ */
+ @Test
+ public void testMaxUiWidth() {
+ // Prevent base display metrics for test from being updated to the value of real display.
+ final DisplayContent displayContent = createDisplayNoUpdateDisplayInfo();
+ final int baseWidth = 1440;
+ final int baseHeight = 2560;
+ final int baseDensity = 300;
+
+ displayContent.updateBaseDisplayMetrics(baseWidth, baseHeight, baseDensity);
+
+ final int maxWidth = 300;
+ final int resultingHeight = (maxWidth * baseHeight) / baseWidth;
+ final int resultingDensity = (maxWidth * baseDensity) / baseWidth;
+
+ displayContent.setMaxUiWidth(maxWidth);
+ verifySizes(displayContent, maxWidth, resultingHeight, resultingDensity);
+
+ // Assert setting values again does not change;
+ displayContent.updateBaseDisplayMetrics(baseWidth, baseHeight, baseDensity);
+ verifySizes(displayContent, maxWidth, resultingHeight, resultingDensity);
+
+ final int smallerWidth = 200;
+ final int smallerHeight = 400;
+ final int smallerDensity = 100;
+
+ // Specify smaller dimension, verify that it is honored
+ displayContent.updateBaseDisplayMetrics(smallerWidth, smallerHeight, smallerDensity);
+ verifySizes(displayContent, smallerWidth, smallerHeight, smallerDensity);
+
+ // Verify that setting the max width to a greater value than the base width has no effect
+ displayContent.setMaxUiWidth(maxWidth);
+ verifySizes(displayContent, smallerWidth, smallerHeight, smallerDensity);
+ }
+
+ @Test
+ public void testDisplayCutout_rot0() {
+ synchronized (mWm.getWindowManagerLock()) {
+ final DisplayContent dc = createNewDisplay();
+ dc.mInitialDisplayWidth = 200;
+ dc.mInitialDisplayHeight = 400;
+ Rect r = new Rect(80, 0, 120, 10);
+ final DisplayCutout cutout = new WmDisplayCutout(
+ fromBoundingRect(r.left, r.top, r.right, r.bottom, BOUNDS_POSITION_TOP), null)
+ .computeSafeInsets(200, 400).getDisplayCutout();
+
+ dc.mInitialDisplayCutout = cutout;
+ dc.setRotation(Surface.ROTATION_0);
+ dc.computeScreenConfiguration(new Configuration()); // recomputes dc.mDisplayInfo.
+
+ assertEquals(cutout, dc.getDisplayInfo().displayCutout);
+ }
+ }
+
+ @Test
+ public void testDisplayCutout_rot90() {
+ synchronized (mWm.getWindowManagerLock()) {
+ // Prevent mInitialDisplayCutout from being updated from real display (e.g. null
+ // if the device has no cutout).
+ final DisplayContent dc = createDisplayNoUpdateDisplayInfo();
+ // Rotation may use real display info to compute bound, so here also uses the
+ // same width and height.
+ final int displayWidth = dc.mInitialDisplayWidth;
+ final int displayHeight = dc.mInitialDisplayHeight;
+ final int cutoutWidth = 40;
+ final int cutoutHeight = 10;
+ final int left = (displayWidth - cutoutWidth) / 2;
+ final int top = 0;
+ final int right = (displayWidth + cutoutWidth) / 2;
+ final int bottom = cutoutHeight;
+
+ final Rect r1 = new Rect(left, top, right, bottom);
+ final DisplayCutout cutout = new WmDisplayCutout(
+ fromBoundingRect(r1.left, r1.top, r1.right, r1.bottom, BOUNDS_POSITION_TOP),
+ null)
+ .computeSafeInsets(displayWidth, displayHeight).getDisplayCutout();
+
+ dc.mInitialDisplayCutout = cutout;
+ dc.setRotation(Surface.ROTATION_90);
+ dc.computeScreenConfiguration(new Configuration()); // recomputes dc.mDisplayInfo.
+
+ // ----o---------- -------------
+ // | | | | |
+ // | ------o | o---
+ // | | | |
+ // | | -> | |
+ // | | ---o
+ // | | |
+ // | | -------------
+ final Rect r = new Rect(top, left, bottom, right);
+ assertEquals(new WmDisplayCutout(
+ fromBoundingRect(r.left, r.top, r.right, r.bottom, BOUNDS_POSITION_LEFT), null)
+ .computeSafeInsets(displayHeight, displayWidth)
+ .getDisplayCutout(), dc.getDisplayInfo().displayCutout);
+ }
+ }
+
+ @Test
+ public void testLayoutSeq_assignedDuringLayout() {
+ synchronized (mWm.getWindowManagerLock()) {
+
+ final DisplayContent dc = createNewDisplay();
+ final WindowState win = createWindow(null /* parent */, TYPE_BASE_APPLICATION, dc, "w");
+
+ dc.setLayoutNeeded();
+ dc.performLayout(true /* initial */, false /* updateImeWindows */);
+
+ assertThat(win.mLayoutSeq, is(dc.mLayoutSeq));
+ }
+ }
+
+ @Test
+ @SuppressLint("InlinedApi")
+ public void testOrientationDefinedByKeyguard() {
+ final DisplayContent dc = createNewDisplay();
+ // Create a window that requests landscape orientation. It will define device orientation
+ // by default.
+ final WindowState window = createWindow(null /* parent */, TYPE_BASE_APPLICATION, dc, "w");
+ window.mAppToken.setOrientation(SCREEN_ORIENTATION_LANDSCAPE);
+
+ final WindowState keyguard = createWindow(null, TYPE_STATUS_BAR, dc, "keyguard");
+ keyguard.mHasSurface = true;
+ keyguard.mAttrs.screenOrientation = SCREEN_ORIENTATION_UNSPECIFIED;
+
+ assertEquals("Screen orientation must be defined by the app window by default",
+ SCREEN_ORIENTATION_LANDSCAPE, dc.getOrientation());
+
+ keyguard.mAttrs.screenOrientation = SCREEN_ORIENTATION_PORTRAIT;
+ assertEquals("Visible keyguard must influence device orientation",
+ SCREEN_ORIENTATION_PORTRAIT, dc.getOrientation());
+
+ mWm.setKeyguardGoingAway(true);
+ assertEquals("Keyguard that is going away must not influence device orientation",
+ SCREEN_ORIENTATION_LANDSCAPE, dc.getOrientation());
+ }
+
+ @Test
+ public void testDisableDisplayInfoOverrideFromWindowManager() {
+ final DisplayContent dc = createNewDisplay();
+
+ assertTrue(dc.mShouldOverrideDisplayConfiguration);
+ mWm.dontOverrideDisplayInfo(dc.getDisplayId());
+
+ assertFalse(dc.mShouldOverrideDisplayConfiguration);
+ verify(mWm.mDisplayManagerInternal, times(1))
+ .setDisplayInfoOverrideFromWindowManager(dc.getDisplayId(), null);
+ }
+
+ @Test
+ public void testClearLastFocusWhenReparentingFocusedWindow() {
+ final DisplayContent defaultDisplay = mWm.getDefaultDisplayContentLocked();
+ final WindowState window = createWindow(null /* parent */, TYPE_BASE_APPLICATION,
+ defaultDisplay, "window");
+ defaultDisplay.mLastFocus = window;
+ mDisplayContent.mCurrentFocus = window;
+ mDisplayContent.reParentWindowToken(window.mToken);
+
+ assertNull(defaultDisplay.mLastFocus);
+ }
+
+ @Test
+ public void testGetPreferredOptionsPanelGravityFromDifferentDisplays() {
+ final DisplayContent portraitDisplay = createNewDisplay();
+ portraitDisplay.mInitialDisplayHeight = 2000;
+ portraitDisplay.mInitialDisplayWidth = 1000;
+
+ portraitDisplay.setRotation(Surface.ROTATION_0);
+ assertFalse(isOptionsPanelAtRight(portraitDisplay.getDisplayId()));
+ portraitDisplay.setRotation(Surface.ROTATION_90);
+ assertTrue(isOptionsPanelAtRight(portraitDisplay.getDisplayId()));
+
+ final DisplayContent landscapeDisplay = createNewDisplay();
+ landscapeDisplay.mInitialDisplayHeight = 1000;
+ landscapeDisplay.mInitialDisplayWidth = 2000;
+
+ landscapeDisplay.setRotation(Surface.ROTATION_0);
+ assertTrue(isOptionsPanelAtRight(landscapeDisplay.getDisplayId()));
+ landscapeDisplay.setRotation(Surface.ROTATION_90);
+ assertFalse(isOptionsPanelAtRight(landscapeDisplay.getDisplayId()));
+ }
+
+ @Test
+ public void testInputMethodTargetUpdateWhenSwitchingOnDisplays() {
+ final DisplayContent newDisplay = createNewDisplay();
+
+ final WindowState appWin = createWindow(null, TYPE_APPLICATION, mDisplayContent, "appWin");
+ final WindowState appWin1 = createWindow(null, TYPE_APPLICATION, newDisplay, "appWin1");
+ appWin.setHasSurface(true);
+ appWin1.setHasSurface(true);
+
+ // Set current input method window on default display, make sure the input method target
+ // is appWin & null on the other display.
+ mDisplayContent.setInputMethodWindowLocked(mImeWindow);
+ newDisplay.setInputMethodWindowLocked(null);
+ assertTrue("appWin should be IME target window",
+ appWin.equals(mDisplayContent.mInputMethodTarget));
+ assertNull("newDisplay Ime target: ", newDisplay.mInputMethodTarget);
+
+ // Switch input method window on new display & make sure the input method target also
+ // switched as expected.
+ newDisplay.setInputMethodWindowLocked(mImeWindow);
+ mDisplayContent.setInputMethodWindowLocked(null);
+ assertTrue("appWin1 should be IME target window",
+ appWin1.equals(newDisplay.mInputMethodTarget));
+ assertNull("default display Ime target: ", mDisplayContent.mInputMethodTarget);
+ }
+
+ private boolean isOptionsPanelAtRight(int displayId) {
+ return (mWm.getPreferredOptionsPanelGravity(displayId) & Gravity.RIGHT) == Gravity.RIGHT;
+ }
+
+ private static void verifySizes(DisplayContent displayContent, int expectedBaseWidth,
+ int expectedBaseHeight, int expectedBaseDensity) {
+ assertEquals(displayContent.mBaseDisplayWidth, expectedBaseWidth);
+ assertEquals(displayContent.mBaseDisplayHeight, expectedBaseHeight);
+ assertEquals(displayContent.mBaseDisplayDensity, expectedBaseDensity);
+ }
+
+ private void updateFocusedWindow() {
+ synchronized (mWm.mGlobalLock) {
+ mWm.updateFocusedWindowLocked(UPDATE_FOCUS_NORMAL, false);
+ }
+ }
+
+ /**
+ * Create DisplayContent that does not update display base/initial values from device to keep
+ * the values set by test.
+ */
+ private DisplayContent createDisplayNoUpdateDisplayInfo() {
+ final DisplayContent displayContent = spy(createNewDisplay());
+ doNothing().when(displayContent).updateDisplayInfo();
+ return displayContent;
+ }
+
+ private void assertForAllWindowsOrder(List<WindowState> expectedWindowsBottomToTop) {
+ final LinkedList<WindowState> actualWindows = new LinkedList<>();
+
+ // Test forward traversal.
+ mDisplayContent.forAllWindows(actualWindows::addLast, false /* traverseTopToBottom */);
+ assertThat("bottomToTop", actualWindows, is(expectedWindowsBottomToTop));
+
+ actualWindows.clear();
+
+ // Test backward traversal.
+ mDisplayContent.forAllWindows(actualWindows::addLast, true /* traverseTopToBottom */);
+ assertThat("topToBottom", actualWindows, is(reverseList(expectedWindowsBottomToTop)));
+ }
+
+ private static List<WindowState> reverseList(List<WindowState> list) {
+ final ArrayList<WindowState> result = new ArrayList<>(list);
+ Collections.reverse(result);
+ return result;
+ }
+
+ private void tapOnDisplay(final DisplayContent dc) {
+ final DisplayMetrics dm = dc.getDisplayMetrics();
+ final float x = dm.widthPixels / 2;
+ final float y = dm.heightPixels / 2;
+ final long downTime = SystemClock.uptimeMillis();
+ final long eventTime = SystemClock.uptimeMillis() + 100;
+ // sending ACTION_DOWN
+ final MotionEvent downEvent = MotionEvent.obtain(
+ downTime,
+ downTime,
+ MotionEvent.ACTION_DOWN,
+ x,
+ y,
+ 0 /*metaState*/);
+ downEvent.setDisplayId(dc.getDisplayId());
+ dc.mTapDetector.onPointerEvent(downEvent);
+
+ // sending ACTION_UP
+ final MotionEvent upEvent = MotionEvent.obtain(
+ downTime,
+ eventTime,
+ MotionEvent.ACTION_UP,
+ x,
+ y,
+ 0 /*metaState*/);
+ upEvent.setDisplayId(dc.getDisplayId());
+ dc.mTapDetector.onPointerEvent(upEvent);
+ }
+}