Merge "Fixed issue with IME displaying on-top of nav bar."
This commit is contained in:
committed by
Android (Google) Code Review
commit
782b247fdb
@@ -23,6 +23,7 @@ import java.util.ArrayDeque;
|
||||
|
||||
import static android.app.ActivityManager.StackId.DOCKED_STACK_ID;
|
||||
import static android.app.ActivityManager.StackId.PINNED_STACK_ID;
|
||||
import static android.view.Display.DEFAULT_DISPLAY;
|
||||
import static android.view.WindowManager.LayoutParams.TYPE_DOCK_DIVIDER;
|
||||
import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_LAYERS;
|
||||
import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
|
||||
@@ -63,17 +64,19 @@ class WindowLayersController {
|
||||
private int mCurBaseLayer;
|
||||
private int mCurLayer;
|
||||
private boolean mAnyLayerChanged;
|
||||
private int mHighestLayerInImeTargetBaseLayer;
|
||||
private WindowState mImeTarget;
|
||||
|
||||
final void assignWindowLayers(DisplayContent dc) {
|
||||
if (DEBUG_LAYERS) Slog.v(TAG_WM, "Assigning layers based",
|
||||
new RuntimeException("here").fillInStackTrace());
|
||||
|
||||
clear();
|
||||
reset();
|
||||
dc.forAllWindows((w) -> {
|
||||
boolean layerChanged = false;
|
||||
|
||||
int oldLayer = w.mLayer;
|
||||
if (w.mBaseLayer == mCurBaseLayer || w.mIsImWindow) {
|
||||
if (w.mBaseLayer == mCurBaseLayer) {
|
||||
mCurLayer += WINDOW_LAYER_MULTIPLIER;
|
||||
} else {
|
||||
mCurBaseLayer = mCurLayer = w.mBaseLayer;
|
||||
@@ -92,6 +95,11 @@ class WindowLayersController {
|
||||
mHighestApplicationLayer = Math.max(mHighestApplicationLayer,
|
||||
w.mWinAnimator.mAnimLayer);
|
||||
}
|
||||
if (mImeTarget != null && w.mBaseLayer == mImeTarget.mBaseLayer) {
|
||||
mHighestLayerInImeTargetBaseLayer = Math.max(mHighestLayerInImeTargetBaseLayer,
|
||||
w.mWinAnimator.mAnimLayer);
|
||||
}
|
||||
|
||||
collectSpecialWindows(w);
|
||||
|
||||
if (layerChanged) {
|
||||
@@ -103,7 +111,7 @@ class WindowLayersController {
|
||||
|
||||
//TODO (multidisplay): Magnification is supported only for the default display.
|
||||
if (mService.mAccessibilityController != null && mAnyLayerChanged
|
||||
&& dc.getDisplayId() == Display.DEFAULT_DISPLAY) {
|
||||
&& dc.getDisplayId() == DEFAULT_DISPLAY) {
|
||||
mService.mAccessibilityController.onWindowLayersChangedLocked();
|
||||
}
|
||||
|
||||
@@ -120,7 +128,7 @@ class WindowLayersController {
|
||||
}, false /* traverseTopToBottom */);
|
||||
}
|
||||
|
||||
private void clear() {
|
||||
private void reset() {
|
||||
mHighestApplicationLayer = 0;
|
||||
mPinnedWindows.clear();
|
||||
mInputMethodWindows.clear();
|
||||
@@ -132,6 +140,9 @@ class WindowLayersController {
|
||||
mCurBaseLayer = 0;
|
||||
mCurLayer = 0;
|
||||
mAnyLayerChanged = false;
|
||||
|
||||
mImeTarget = mService.mInputMethodTarget;
|
||||
mHighestLayerInImeTargetBaseLayer = (mImeTarget != null) ? mImeTarget.mBaseLayer : 0;
|
||||
}
|
||||
|
||||
private void collectSpecialWindows(WindowState w) {
|
||||
@@ -174,22 +185,10 @@ class WindowLayersController {
|
||||
|
||||
layer = assignAndIncreaseLayerIfNeeded(mDockDivider, layer);
|
||||
|
||||
boolean onTopLauncherVisible = !mOnTopLauncherWindows.isEmpty();
|
||||
while (!mOnTopLauncherWindows.isEmpty()) {
|
||||
layer = assignAndIncreaseLayerIfNeeded(mOnTopLauncherWindows.remove(), layer);
|
||||
}
|
||||
|
||||
// Make sure IME windows are showing above the dock divider and on-top launcher windows.
|
||||
if ((mDockDivider != null && mDockDivider.isVisibleLw()) || onTopLauncherVisible) {
|
||||
while (!mInputMethodWindows.isEmpty()) {
|
||||
final WindowState w = mInputMethodWindows.remove();
|
||||
// Only ever move IME windows up, else we brake IME for windows above the divider.
|
||||
if (layer > w.mLayer) {
|
||||
layer = assignAndIncreaseLayerIfNeeded(w, layer);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// We know that we will be animating a relaunching window in the near future, which will
|
||||
// receive a z-order increase. We want the replaced window to immediately receive the same
|
||||
// treatment, e.g. to be above the dock divider.
|
||||
@@ -200,12 +199,26 @@ class WindowLayersController {
|
||||
while (!mPinnedWindows.isEmpty()) {
|
||||
layer = assignAndIncreaseLayerIfNeeded(mPinnedWindows.remove(), layer);
|
||||
}
|
||||
|
||||
// Make sure IME is the highest window in the base layer of it's target.
|
||||
if (mImeTarget != null) {
|
||||
if (mImeTarget.mAppToken == null) {
|
||||
// For non-app ime targets adjust the layer we start from to match what we found
|
||||
// when assigning layers. Otherwise, just use the highest app layer we have some far.
|
||||
layer = mHighestLayerInImeTargetBaseLayer + WINDOW_LAYER_MULTIPLIER;
|
||||
}
|
||||
|
||||
while (!mInputMethodWindows.isEmpty()) {
|
||||
layer = assignAndIncreaseLayerIfNeeded(mInputMethodWindows.remove(), layer);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private int assignAndIncreaseLayerIfNeeded(WindowState win, int layer) {
|
||||
if (win != null) {
|
||||
assignAnimLayer(win, layer);
|
||||
// Make sure we leave space inbetween normal windows for dims and such.
|
||||
// Make sure we leave space in-between normal windows for dims and such.
|
||||
layer += WINDOW_LAYER_MULTIPLIER;
|
||||
}
|
||||
return layer;
|
||||
|
||||
@@ -1905,9 +1905,7 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
|
||||
}
|
||||
|
||||
int getAnimLayerAdjustment() {
|
||||
final boolean isImeType =
|
||||
mAttrs.type == TYPE_INPUT_METHOD || mAttrs.type == TYPE_INPUT_METHOD_DIALOG;
|
||||
if (isImeType && mService.mInputMethodTarget != null) {
|
||||
if (mIsImWindow && mService.mInputMethodTarget != null) {
|
||||
final AppWindowToken appToken = mService.mInputMethodTarget.mAppToken;
|
||||
if (appToken != null) {
|
||||
return appToken.mAppAnimator.animLayerAdjustment;
|
||||
|
||||
@@ -175,21 +175,6 @@ class WindowToken extends WindowContainer<WindowState> {
|
||||
return (WindowState) mChildren.get(mChildren.size() - 1).getTop();
|
||||
}
|
||||
|
||||
/**
|
||||
* Recursive search through a WindowList and all of its windows' children.
|
||||
* @param target The window to search for.
|
||||
* @return The index of win in windows or of the window that is an ancestor of win.
|
||||
*/
|
||||
int getWindowIndex(WindowState target) {
|
||||
for (int i = mChildren.size() - 1; i >= 0; --i) {
|
||||
final WindowState w = mChildren.get(i);
|
||||
if (w == target || w.hasChild(target)) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the new window is considered greater than the existing window in terms of
|
||||
* z-order.
|
||||
|
||||
@@ -45,16 +45,7 @@ import static org.junit.Assert.assertTrue;
|
||||
@SmallTest
|
||||
@Presubmit
|
||||
@RunWith(AndroidJUnit4.class)
|
||||
public class AppWindowTokenTests {
|
||||
|
||||
private static WindowManagerService sWm = null;
|
||||
private final IWindow mIWindow = new TestIWindow();
|
||||
|
||||
@Before
|
||||
public void setUp() throws Exception {
|
||||
final Context context = InstrumentationRegistry.getTargetContext();
|
||||
sWm = TestWindowManagerPolicy.getWindowManagerService(context);
|
||||
}
|
||||
public class AppWindowTokenTests extends WindowTestsBase {
|
||||
|
||||
@Test
|
||||
public void testAddWindow_Order() throws Exception {
|
||||
@@ -62,10 +53,11 @@ public class AppWindowTokenTests {
|
||||
|
||||
assertEquals(0, token.getWindowsCount());
|
||||
|
||||
final WindowState win1 = createWindow(null, TYPE_APPLICATION, token);
|
||||
final WindowState startingWin = createWindow(null, TYPE_APPLICATION_STARTING, token);
|
||||
final WindowState baseWin = createWindow(null, TYPE_BASE_APPLICATION, token);
|
||||
final WindowState win4 = createWindow(null, TYPE_APPLICATION, token);
|
||||
final WindowState win1 = createWindow(null, TYPE_APPLICATION, token, "win1");
|
||||
final WindowState startingWin = createWindow(null, TYPE_APPLICATION_STARTING, token,
|
||||
"startingWin");
|
||||
final WindowState baseWin = createWindow(null, TYPE_BASE_APPLICATION, token, "baseWin");
|
||||
final WindowState win4 = createWindow(null, TYPE_APPLICATION, token, "win4");
|
||||
|
||||
token.addWindow(win1);
|
||||
token.addWindow(startingWin);
|
||||
@@ -92,24 +84,18 @@ public class AppWindowTokenTests {
|
||||
|
||||
assertNull(token.findMainWindow());
|
||||
|
||||
final WindowState window1 = createWindow(null, TYPE_BASE_APPLICATION, token);
|
||||
final WindowState window11 = createWindow(window1, FIRST_SUB_WINDOW, token);
|
||||
final WindowState window12 = createWindow(window1, FIRST_SUB_WINDOW, token);
|
||||
final WindowState window1 = createWindow(null, TYPE_BASE_APPLICATION, token, "window1");
|
||||
final WindowState window11 = createWindow(window1, FIRST_SUB_WINDOW, token, "window11");
|
||||
final WindowState window12 = createWindow(window1, FIRST_SUB_WINDOW, token, "window12");
|
||||
token.addWindow(window1);
|
||||
assertEquals(window1, token.findMainWindow());
|
||||
window1.mAnimatingExit = true;
|
||||
assertEquals(window1, token.findMainWindow());
|
||||
final WindowState window2 = createWindow(null, TYPE_APPLICATION_STARTING, token);
|
||||
final WindowState window2 = createWindow(null, TYPE_APPLICATION_STARTING, token, "window2");
|
||||
token.addWindow(window2);
|
||||
assertEquals(window2, token.findMainWindow());
|
||||
}
|
||||
|
||||
private WindowState createWindow(WindowState parent, int type, WindowToken token) {
|
||||
final WindowManager.LayoutParams attrs = new WindowManager.LayoutParams(type);
|
||||
|
||||
return new WindowState(sWm, null, mIWindow, token, parent, 0, 0, attrs, 0, 0);
|
||||
}
|
||||
|
||||
/* Used so we can gain access to some protected members of the {@link AppWindowToken} class */
|
||||
private class TestAppWindowToken extends AppWindowToken {
|
||||
|
||||
|
||||
@@ -16,28 +16,15 @@
|
||||
|
||||
package com.android.server.wm;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.res.Configuration;
|
||||
import android.os.IBinder;
|
||||
import android.platform.test.annotations.Presubmit;
|
||||
import android.support.test.InstrumentationRegistry;
|
||||
import android.support.test.filters.SmallTest;
|
||||
import android.support.test.runner.AndroidJUnit4;
|
||||
import android.view.Display;
|
||||
import android.view.IWindow;
|
||||
import android.view.WindowManager;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
import static android.app.ActivityManager.StackId.FIRST_DYNAMIC_STACK_ID;
|
||||
import static android.app.AppOpsManager.OP_NONE;
|
||||
import static android.content.res.Configuration.EMPTY;
|
||||
import static android.view.WindowManager.LayoutParams.FIRST_APPLICATION_WINDOW;
|
||||
import static android.view.WindowManager.LayoutParams.LAST_APPLICATION_WINDOW;
|
||||
import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_ATTACHED_DIALOG;
|
||||
import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_MEDIA;
|
||||
import static android.view.WindowManager.LayoutParams.TYPE_BASE_APPLICATION;
|
||||
@@ -47,7 +34,6 @@ import static android.view.WindowManager.LayoutParams.TYPE_NAVIGATION_BAR;
|
||||
import static android.view.WindowManager.LayoutParams.TYPE_STATUS_BAR;
|
||||
import static android.view.WindowManager.LayoutParams.TYPE_WALLPAPER;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.mockito.Mockito.mock;
|
||||
|
||||
/**
|
||||
* Tests for the {@link DisplayContent} class.
|
||||
@@ -58,21 +44,7 @@ import static org.mockito.Mockito.mock;
|
||||
@SmallTest
|
||||
@Presubmit
|
||||
@RunWith(AndroidJUnit4.class)
|
||||
public class DisplayContentTests {
|
||||
|
||||
private static WindowManagerService sWm = null;
|
||||
private final IWindow mIWindow = new TestIWindow();
|
||||
private final Session mMockSession = mock(Session.class);
|
||||
private Display mDisplay;
|
||||
private int mNextStackId = FIRST_DYNAMIC_STACK_ID;
|
||||
private int mNextTaskId = 0;
|
||||
|
||||
@Before
|
||||
public void setUp() throws Exception {
|
||||
final Context context = InstrumentationRegistry.getTargetContext();
|
||||
sWm = TestWindowManagerPolicy.getWindowManagerService(context);
|
||||
mDisplay = context.getDisplay();
|
||||
}
|
||||
public class DisplayContentTests extends WindowTestsBase {
|
||||
|
||||
@Test
|
||||
public void testForAllWindows() throws Exception {
|
||||
@@ -124,36 +96,4 @@ public class DisplayContentTests {
|
||||
assertEquals(imeWindow, windows.get(1));
|
||||
assertEquals(imeDialogWindow, windows.get(0));
|
||||
}
|
||||
|
||||
private WindowToken createWindowToken(DisplayContent dc, int type) {
|
||||
if (type < FIRST_APPLICATION_WINDOW || type > LAST_APPLICATION_WINDOW) {
|
||||
return new WindowToken(sWm, mock(IBinder.class), type, false, dc);
|
||||
}
|
||||
|
||||
final int stackId = mNextStackId++;
|
||||
dc.addStackToDisplay(stackId, true);
|
||||
final TaskStack stack = sWm.mStackIdToStack.get(stackId);
|
||||
final Task task = new Task(mNextTaskId++, stack, 0, sWm, null, EMPTY, false);
|
||||
stack.addTask(task, true);
|
||||
final AppWindowToken token = new AppWindowToken(sWm, null, false, dc);
|
||||
task.addAppToken(0, token, 0, false);
|
||||
return token;
|
||||
}
|
||||
|
||||
private WindowState createWindow(WindowState parent, int type, DisplayContent dc, String name) {
|
||||
final WindowToken token = createWindowToken(dc, type);
|
||||
return createWindow(parent, type, token, name);
|
||||
}
|
||||
|
||||
private WindowState createWindow(WindowState parent, int type, WindowToken token, String name) {
|
||||
final WindowManager.LayoutParams attrs = new WindowManager.LayoutParams(type);
|
||||
attrs.setTitle(name);
|
||||
|
||||
final WindowState w = new WindowState(sWm, mMockSession, mIWindow, token, parent, OP_NONE,
|
||||
0, attrs, 0, 0);
|
||||
// TODO: Probably better to make this call in the WindowState ctor to avoid errors with
|
||||
// adding it to the token...
|
||||
token.addWindow(w);
|
||||
return w;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,149 @@
|
||||
/*
|
||||
* 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 org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
import android.platform.test.annotations.Presubmit;
|
||||
import android.support.test.filters.SmallTest;
|
||||
import android.support.test.runner.AndroidJUnit4;
|
||||
|
||||
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_DOCK_DIVIDER;
|
||||
import static android.view.WindowManager.LayoutParams.TYPE_INPUT_METHOD;
|
||||
import static android.view.WindowManager.LayoutParams.TYPE_INPUT_METHOD_DIALOG;
|
||||
import static android.view.WindowManager.LayoutParams.TYPE_NAVIGATION_BAR;
|
||||
import static android.view.WindowManager.LayoutParams.TYPE_STATUS_BAR;
|
||||
import static android.view.WindowManager.LayoutParams.TYPE_SYSTEM_OVERLAY;
|
||||
import static android.view.WindowManager.LayoutParams.TYPE_WALLPAPER;
|
||||
|
||||
/**
|
||||
* Tests for the {@link WindowLayersController} class.
|
||||
*
|
||||
* Build/Install/Run:
|
||||
* bit FrameworksServicesTests:com.android.server.wm.WindowLayersControllerTests
|
||||
*/
|
||||
@SmallTest
|
||||
@Presubmit
|
||||
@RunWith(AndroidJUnit4.class)
|
||||
public class WindowLayersControllerTests extends WindowTestsBase {
|
||||
|
||||
private static boolean sOneTimeSetupDone = false;
|
||||
private static WindowLayersController sLayersController;
|
||||
private static DisplayContent sDisplayContent;
|
||||
private static WindowState sImeWindow;
|
||||
private static WindowState sImeDialogWindow;
|
||||
private static WindowState sStatusBarWindow;
|
||||
private static WindowState sDockedDividerWindow;
|
||||
private static WindowState sNavBarWindow;
|
||||
private static WindowState sAppWindow;
|
||||
private static WindowState sChildAppWindow;
|
||||
|
||||
@Before
|
||||
public void setUp() throws Exception {
|
||||
super.setUp();
|
||||
|
||||
if (sOneTimeSetupDone) {
|
||||
return;
|
||||
}
|
||||
sOneTimeSetupDone = true;
|
||||
sLayersController = new WindowLayersController(sWm);
|
||||
sDisplayContent =
|
||||
new DisplayContent(mDisplay, sWm, sLayersController, new WallpaperController(sWm));
|
||||
final WindowState wallpaperWindow =
|
||||
createWindow(null, TYPE_WALLPAPER, sDisplayContent, "wallpaperWindow");
|
||||
sImeWindow = createWindow(null, TYPE_INPUT_METHOD, sDisplayContent, "sImeWindow");
|
||||
sImeDialogWindow =
|
||||
createWindow(null, TYPE_INPUT_METHOD_DIALOG, sDisplayContent, "sImeDialogWindow");
|
||||
sStatusBarWindow = createWindow(null, TYPE_STATUS_BAR, sDisplayContent, "sStatusBarWindow");
|
||||
sNavBarWindow =
|
||||
createWindow(null, TYPE_NAVIGATION_BAR, sStatusBarWindow.mToken, "sNavBarWindow");
|
||||
sDockedDividerWindow =
|
||||
createWindow(null, TYPE_DOCK_DIVIDER, sDisplayContent, "sDockedDividerWindow");
|
||||
sAppWindow = createWindow(null, TYPE_BASE_APPLICATION, sDisplayContent, "sAppWindow");
|
||||
sChildAppWindow = createWindow(sAppWindow,
|
||||
TYPE_APPLICATION_ATTACHED_DIALOG, sAppWindow.mToken, "sChildAppWindow");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAssignWindowLayers_ForImeWithNoTarget() throws Exception {
|
||||
sWm.mInputMethodTarget = null;
|
||||
sLayersController.assignWindowLayers(sDisplayContent);
|
||||
|
||||
// The Ime has an higher base layer than app windows and lower base layer than system
|
||||
// windows, so it should be above app windows and below system windows if there isn't an IME
|
||||
// target.
|
||||
assertWindowLayerGreaterThan(sImeWindow, sChildAppWindow);
|
||||
assertWindowLayerGreaterThan(sImeWindow, sAppWindow);
|
||||
assertWindowLayerGreaterThan(sImeWindow, sDockedDividerWindow);
|
||||
assertWindowLayerGreaterThan(sNavBarWindow, sImeWindow);
|
||||
assertWindowLayerGreaterThan(sStatusBarWindow, sImeWindow);
|
||||
|
||||
// And, IME dialogs should always have an higher layer than the IME.
|
||||
assertWindowLayerGreaterThan(sImeDialogWindow, sImeWindow);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAssignWindowLayers_ForImeWithAppTarget() throws Exception {
|
||||
final WindowState imeAppTarget =
|
||||
createWindow(null, TYPE_BASE_APPLICATION, sDisplayContent, "imeAppTarget");
|
||||
sWm.mInputMethodTarget = imeAppTarget;
|
||||
sLayersController.assignWindowLayers(sDisplayContent);
|
||||
|
||||
// Ime should be above all app windows and below system windows if it is targeting an app
|
||||
// window.
|
||||
assertWindowLayerGreaterThan(sImeWindow, imeAppTarget);
|
||||
assertWindowLayerGreaterThan(sImeWindow, sChildAppWindow);
|
||||
assertWindowLayerGreaterThan(sImeWindow, sAppWindow);
|
||||
assertWindowLayerGreaterThan(sImeWindow, sDockedDividerWindow);
|
||||
assertWindowLayerGreaterThan(sNavBarWindow, sImeWindow);
|
||||
assertWindowLayerGreaterThan(sStatusBarWindow, sImeWindow);
|
||||
|
||||
// And, IME dialogs should always have an higher layer than the IME.
|
||||
assertWindowLayerGreaterThan(sImeDialogWindow, sImeWindow);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAssignWindowLayers_ForImeNonAppImeTarget() throws Exception {
|
||||
final WindowState imeSystemOverlayTarget =
|
||||
createWindow(null, TYPE_SYSTEM_OVERLAY, sDisplayContent, "imeSystemOverlayTarget");
|
||||
|
||||
sWm.mInputMethodTarget = imeSystemOverlayTarget;
|
||||
sLayersController.assignWindowLayers(sDisplayContent);
|
||||
|
||||
// The IME target base layer is higher than all window except for the nav bar window, so the
|
||||
// IME should be above all windows except for the nav bar.
|
||||
assertWindowLayerGreaterThan(sImeWindow, imeSystemOverlayTarget);
|
||||
assertWindowLayerGreaterThan(sImeWindow, sChildAppWindow);
|
||||
assertWindowLayerGreaterThan(sImeWindow, sAppWindow);
|
||||
assertWindowLayerGreaterThan(sImeWindow, sDockedDividerWindow);
|
||||
assertWindowLayerGreaterThan(sImeWindow, sStatusBarWindow);
|
||||
assertWindowLayerGreaterThan(sNavBarWindow, sImeWindow);
|
||||
|
||||
// And, IME dialogs should always have an higher layer than the IME.
|
||||
assertWindowLayerGreaterThan(sImeDialogWindow, sImeWindow);
|
||||
}
|
||||
|
||||
private void assertWindowLayerGreaterThan(WindowState first, WindowState second)
|
||||
throws Exception {
|
||||
assertGreaterThan(first.mWinAnimator.mAnimLayer, second.mWinAnimator.mAnimLayer);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -46,25 +46,25 @@ import static org.junit.Assert.assertTrue;
|
||||
@SmallTest
|
||||
@Presubmit
|
||||
@RunWith(AndroidJUnit4.class)
|
||||
public class WindowStateTests {
|
||||
public class WindowStateTests extends WindowTestsBase {
|
||||
|
||||
private static WindowManagerService sWm = null;
|
||||
private WindowToken mWindowToken;
|
||||
private final IWindow mIWindow = new TestIWindow();
|
||||
|
||||
@Before
|
||||
public void setUp() throws Exception {
|
||||
final Context context = InstrumentationRegistry.getTargetContext();
|
||||
sWm = TestWindowManagerPolicy.getWindowManagerService(context);
|
||||
super.setUp();
|
||||
mWindowToken = new WindowToken(sWm, new Binder(), 0, false,
|
||||
sWm.getDefaultDisplayContentLocked());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testIsParentWindowHidden() throws Exception {
|
||||
final WindowState parentWindow = createWindow(null, TYPE_APPLICATION);
|
||||
final WindowState child1 = createWindow(parentWindow, FIRST_SUB_WINDOW);
|
||||
final WindowState child2 = createWindow(parentWindow, FIRST_SUB_WINDOW);
|
||||
final WindowState parentWindow =
|
||||
createWindow(null, TYPE_APPLICATION, mWindowToken, "parentWindow");
|
||||
final WindowState child1 =
|
||||
createWindow(parentWindow, FIRST_SUB_WINDOW, mWindowToken, "child1");
|
||||
final WindowState child2 =
|
||||
createWindow(parentWindow, FIRST_SUB_WINDOW, mWindowToken, "child2");
|
||||
|
||||
assertFalse(parentWindow.mHidden);
|
||||
assertFalse(parentWindow.isParentWindowHidden());
|
||||
@@ -79,10 +79,14 @@ public class WindowStateTests {
|
||||
|
||||
@Test
|
||||
public void testIsChildWindow() throws Exception {
|
||||
final WindowState parentWindow = createWindow(null, TYPE_APPLICATION);
|
||||
final WindowState child1 = createWindow(parentWindow, FIRST_SUB_WINDOW);
|
||||
final WindowState child2 = createWindow(parentWindow, FIRST_SUB_WINDOW);
|
||||
final WindowState randomWindow = createWindow(null, TYPE_APPLICATION);
|
||||
final WindowState parentWindow =
|
||||
createWindow(null, TYPE_APPLICATION, mWindowToken, "parentWindow");
|
||||
final WindowState child1 =
|
||||
createWindow(parentWindow, FIRST_SUB_WINDOW, mWindowToken, "child1");
|
||||
final WindowState child2 =
|
||||
createWindow(parentWindow, FIRST_SUB_WINDOW, mWindowToken, "child2");
|
||||
final WindowState randomWindow =
|
||||
createWindow(null, TYPE_APPLICATION, mWindowToken, "randomWindow");
|
||||
|
||||
assertFalse(parentWindow.isChildWindow());
|
||||
assertTrue(child1.isChildWindow());
|
||||
@@ -92,12 +96,13 @@ public class WindowStateTests {
|
||||
|
||||
@Test
|
||||
public void testHasChild() throws Exception {
|
||||
final WindowState win1 = createWindow(null, TYPE_APPLICATION);
|
||||
final WindowState win11 = createWindow(win1, FIRST_SUB_WINDOW);
|
||||
final WindowState win12 = createWindow(win1, FIRST_SUB_WINDOW);
|
||||
final WindowState win2 = createWindow(null, TYPE_APPLICATION);
|
||||
final WindowState win21 = createWindow(win2, FIRST_SUB_WINDOW);
|
||||
final WindowState randomWindow = createWindow(null, TYPE_APPLICATION);
|
||||
final WindowState win1 = createWindow(null, TYPE_APPLICATION, mWindowToken, "win1");
|
||||
final WindowState win11 = createWindow(win1, FIRST_SUB_WINDOW, mWindowToken, "win11");
|
||||
final WindowState win12 = createWindow(win1, FIRST_SUB_WINDOW, mWindowToken, "win12");
|
||||
final WindowState win2 = createWindow(null, TYPE_APPLICATION, mWindowToken, "win2");
|
||||
final WindowState win21 = createWindow(win2, FIRST_SUB_WINDOW, mWindowToken, "win21");
|
||||
final WindowState randomWindow =
|
||||
createWindow(null, TYPE_APPLICATION, mWindowToken, "randomWindow");
|
||||
|
||||
assertTrue(win1.hasChild(win11));
|
||||
assertTrue(win1.hasChild(win12));
|
||||
@@ -113,23 +118,28 @@ public class WindowStateTests {
|
||||
|
||||
@Test
|
||||
public void testGetBottomChild() throws Exception {
|
||||
final WindowState parentWindow = createWindow(null, TYPE_APPLICATION);
|
||||
final WindowState parentWindow =
|
||||
createWindow(null, TYPE_APPLICATION, mWindowToken, "parentWindow");
|
||||
assertNull(parentWindow.getBottomChild());
|
||||
|
||||
final WindowState child1 = createWindow(parentWindow, TYPE_APPLICATION_PANEL);
|
||||
final WindowState child1 =
|
||||
createWindow(parentWindow, TYPE_APPLICATION_PANEL, mWindowToken, "child1");
|
||||
assertEquals(child1, parentWindow.getBottomChild());
|
||||
|
||||
final WindowState child2 = createWindow(parentWindow, TYPE_APPLICATION_PANEL);
|
||||
final WindowState child2 =
|
||||
createWindow(parentWindow, TYPE_APPLICATION_PANEL, mWindowToken, "child2");
|
||||
// Since child1 and child2 are at the same layer, then child2 is expect to be added on top
|
||||
// on child1
|
||||
assertEquals(child1, parentWindow.getBottomChild());
|
||||
|
||||
final WindowState child3 = createWindow(parentWindow, TYPE_APPLICATION_MEDIA_OVERLAY);
|
||||
final WindowState child3 =
|
||||
createWindow(parentWindow, TYPE_APPLICATION_MEDIA_OVERLAY, mWindowToken, "child3");
|
||||
// Since child3 is a negative layer, we would expect it to be added below current children
|
||||
// with positive layers.
|
||||
assertEquals(child3, parentWindow.getBottomChild());
|
||||
|
||||
final WindowState child4 = createWindow(parentWindow, TYPE_APPLICATION_MEDIA_OVERLAY);
|
||||
final WindowState child4 =
|
||||
createWindow(parentWindow, TYPE_APPLICATION_MEDIA_OVERLAY, mWindowToken, "child4");
|
||||
// We would also expect additional negative layers to be added below existing negative
|
||||
// layers.
|
||||
assertEquals(child4, parentWindow.getBottomChild());
|
||||
@@ -137,9 +147,12 @@ public class WindowStateTests {
|
||||
|
||||
@Test
|
||||
public void testGetParentWindow() throws Exception {
|
||||
final WindowState parentWindow = createWindow(null, TYPE_APPLICATION);
|
||||
final WindowState child1 = createWindow(parentWindow, FIRST_SUB_WINDOW);
|
||||
final WindowState child2 = createWindow(parentWindow, FIRST_SUB_WINDOW);
|
||||
final WindowState parentWindow =
|
||||
createWindow(null, TYPE_APPLICATION, mWindowToken, "parentWindow");
|
||||
final WindowState child1 =
|
||||
createWindow(parentWindow, FIRST_SUB_WINDOW, mWindowToken, "child1");
|
||||
final WindowState child2 =
|
||||
createWindow(parentWindow, FIRST_SUB_WINDOW, mWindowToken, "child2");
|
||||
|
||||
assertNull(parentWindow.getParentWindow());
|
||||
assertEquals(parentWindow, child1.getParentWindow());
|
||||
@@ -148,9 +161,9 @@ public class WindowStateTests {
|
||||
|
||||
@Test
|
||||
public void testGetTopParentWindow() throws Exception {
|
||||
final WindowState root = createWindow(null, TYPE_APPLICATION);
|
||||
final WindowState child1 = createWindow(root, FIRST_SUB_WINDOW);
|
||||
final WindowState child2 = createWindow(child1, FIRST_SUB_WINDOW);
|
||||
final WindowState root = createWindow(null, TYPE_APPLICATION, mWindowToken, "root");
|
||||
final WindowState child1 = createWindow(root, FIRST_SUB_WINDOW, mWindowToken, "child1");
|
||||
final WindowState child2 = createWindow(child1, FIRST_SUB_WINDOW, mWindowToken, "child2");
|
||||
|
||||
assertEquals(root, root.getTopParentWindow());
|
||||
assertEquals(root, child1.getTopParentWindow());
|
||||
@@ -160,16 +173,10 @@ public class WindowStateTests {
|
||||
|
||||
@Test
|
||||
public void testIsOnScreen_hiddenByPolicy() {
|
||||
final WindowState window = createWindow(null, TYPE_APPLICATION);
|
||||
final WindowState window = createWindow(null, TYPE_APPLICATION, mWindowToken, "window");
|
||||
window.setHasSurface(true);
|
||||
assertTrue(window.isOnScreen());
|
||||
window.hideLw(false /* doAnimation */);
|
||||
assertFalse(window.isOnScreen());
|
||||
}
|
||||
|
||||
private WindowState createWindow(WindowState parent, int type) {
|
||||
final WindowManager.LayoutParams attrs = new WindowManager.LayoutParams(type);
|
||||
|
||||
return new WindowState(sWm, null, mIWindow, mWindowToken, parent, 0, 0, attrs, 0, 0);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,90 @@
|
||||
/*
|
||||
* 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 org.junit.Assert;
|
||||
import org.junit.Before;
|
||||
|
||||
import android.content.Context;
|
||||
import android.os.IBinder;
|
||||
import android.support.test.InstrumentationRegistry;
|
||||
import android.view.Display;
|
||||
import android.view.IWindow;
|
||||
import android.view.WindowManager;
|
||||
|
||||
import static android.app.ActivityManager.StackId.FIRST_DYNAMIC_STACK_ID;
|
||||
import static android.app.AppOpsManager.OP_NONE;
|
||||
import static android.content.res.Configuration.EMPTY;
|
||||
import static android.view.WindowManager.LayoutParams.FIRST_APPLICATION_WINDOW;
|
||||
import static android.view.WindowManager.LayoutParams.LAST_APPLICATION_WINDOW;
|
||||
import static org.mockito.Mockito.mock;
|
||||
|
||||
/**
|
||||
* Common base class for window manager unit test classes.
|
||||
*/
|
||||
public class WindowTestsBase {
|
||||
static WindowManagerService sWm = null;
|
||||
private final IWindow mIWindow = new TestIWindow();
|
||||
private final Session mMockSession = mock(Session.class);
|
||||
Display mDisplay;
|
||||
private static int sNextStackId = FIRST_DYNAMIC_STACK_ID;
|
||||
private static int sNextTaskId = 0;
|
||||
|
||||
@Before
|
||||
public void setUp() throws Exception {
|
||||
final Context context = InstrumentationRegistry.getTargetContext();
|
||||
sWm = TestWindowManagerPolicy.getWindowManagerService(context);
|
||||
mDisplay = context.getDisplay();
|
||||
}
|
||||
|
||||
/** Asserts that the first entry is greater than the second entry. */
|
||||
void assertGreaterThan(int first, int second) throws Exception {
|
||||
Assert.assertTrue("Excepted " + first + " to be greater than " + second, first > second);
|
||||
}
|
||||
|
||||
WindowToken createWindowToken(DisplayContent dc, int type) {
|
||||
if (type < FIRST_APPLICATION_WINDOW || type > LAST_APPLICATION_WINDOW) {
|
||||
return new WindowToken(sWm, mock(IBinder.class), type, false, dc);
|
||||
}
|
||||
|
||||
final int stackId = sNextStackId++;
|
||||
dc.addStackToDisplay(stackId, true);
|
||||
final TaskStack stack = sWm.mStackIdToStack.get(stackId);
|
||||
final Task task = new Task(sNextTaskId++, stack, 0, sWm, null, EMPTY, false);
|
||||
stack.addTask(task, true);
|
||||
final AppWindowToken token = new AppWindowToken(sWm, null, false, dc);
|
||||
task.addAppToken(0, token, 0, false);
|
||||
return token;
|
||||
}
|
||||
|
||||
WindowState createWindow(WindowState parent, int type, DisplayContent dc, String name) {
|
||||
final WindowToken token = createWindowToken(dc, type);
|
||||
return createWindow(parent, type, token, name);
|
||||
}
|
||||
|
||||
WindowState createWindow(WindowState parent, int type, WindowToken token, String name) {
|
||||
final WindowManager.LayoutParams attrs = new WindowManager.LayoutParams(type);
|
||||
attrs.setTitle(name);
|
||||
|
||||
final WindowState w = new WindowState(sWm, mMockSession, mIWindow, token, parent, OP_NONE,
|
||||
0, attrs, 0, 0);
|
||||
// TODO: Probably better to make this call in the WindowState ctor to avoid errors with
|
||||
// adding it to the token...
|
||||
token.addWindow(w);
|
||||
return w;
|
||||
}
|
||||
}
|
||||
@@ -47,17 +47,7 @@ import static org.mockito.Mockito.mock;
|
||||
@SmallTest
|
||||
@Presubmit
|
||||
@RunWith(AndroidJUnit4.class)
|
||||
public class WindowTokenTests {
|
||||
|
||||
private WindowManagerService mWm = null;
|
||||
private final IWindow mIWindow = new TestIWindow();
|
||||
private final Session mMockSession = mock(Session.class);
|
||||
|
||||
@Before
|
||||
public void setUp() throws Exception {
|
||||
final Context context = InstrumentationRegistry.getTargetContext();
|
||||
mWm = TestWindowManagerPolicy.getWindowManagerService(context);
|
||||
}
|
||||
public class WindowTokenTests extends WindowTestsBase {
|
||||
|
||||
@Test
|
||||
public void testAddWindow() throws Exception {
|
||||
@@ -65,11 +55,11 @@ public class WindowTokenTests {
|
||||
|
||||
assertEquals(0, token.getWindowsCount());
|
||||
|
||||
final WindowState window1 = createWindow(null, TYPE_APPLICATION, token);
|
||||
final WindowState window11 = createWindow(window1, FIRST_SUB_WINDOW, token);
|
||||
final WindowState window12 = createWindow(window1, FIRST_SUB_WINDOW, token);
|
||||
final WindowState window2 = createWindow(null, TYPE_APPLICATION, token);
|
||||
final WindowState window3 = createWindow(null, TYPE_APPLICATION, token);
|
||||
final WindowState window1 = createWindow(null, TYPE_APPLICATION, token, "window1");
|
||||
final WindowState window11 = createWindow(window1, FIRST_SUB_WINDOW, token, "window11");
|
||||
final WindowState window12 = createWindow(window1, FIRST_SUB_WINDOW, token, "window12");
|
||||
final WindowState window2 = createWindow(null, TYPE_APPLICATION, token, "window2");
|
||||
final WindowState window3 = createWindow(null, TYPE_APPLICATION, token, "window3");
|
||||
|
||||
token.addWindow(window1);
|
||||
// NOTE: Child windows will not be added to the token as window containers can only
|
||||
@@ -91,12 +81,12 @@ public class WindowTokenTests {
|
||||
@Test
|
||||
public void testChildRemoval() throws Exception {
|
||||
final TestWindowToken token = new TestWindowToken();
|
||||
final DisplayContent dc = mWm.getDefaultDisplayContentLocked();
|
||||
final DisplayContent dc = sWm.getDefaultDisplayContentLocked();
|
||||
|
||||
assertEquals(token, dc.getWindowToken(token.token));
|
||||
|
||||
final WindowState window1 = createWindow(null, TYPE_APPLICATION, token);
|
||||
final WindowState window2 = createWindow(null, TYPE_APPLICATION, token);
|
||||
final WindowState window1 = createWindow(null, TYPE_APPLICATION, token, "window1");
|
||||
final WindowState window2 = createWindow(null, TYPE_APPLICATION, token, "window2");
|
||||
token.addWindow(window1);
|
||||
token.addWindow(window2);
|
||||
|
||||
@@ -113,11 +103,11 @@ public class WindowTokenTests {
|
||||
@Test
|
||||
public void testAdjustAnimLayer() throws Exception {
|
||||
final TestWindowToken token = new TestWindowToken();
|
||||
final WindowState window1 = createWindow(null, TYPE_APPLICATION, token);
|
||||
final WindowState window11 = createWindow(window1, FIRST_SUB_WINDOW, token);
|
||||
final WindowState window12 = createWindow(window1, FIRST_SUB_WINDOW, token);
|
||||
final WindowState window2 = createWindow(null, TYPE_APPLICATION, token);
|
||||
final WindowState window3 = createWindow(null, TYPE_APPLICATION, token);
|
||||
final WindowState window1 = createWindow(null, TYPE_APPLICATION, token, "window1");
|
||||
final WindowState window11 = createWindow(window1, FIRST_SUB_WINDOW, token, "window11");
|
||||
final WindowState window12 = createWindow(window1, FIRST_SUB_WINDOW, token, "window12");
|
||||
final WindowState window2 = createWindow(null, TYPE_APPLICATION, token, "window2");
|
||||
final WindowState window3 = createWindow(null, TYPE_APPLICATION, token, "window3");
|
||||
|
||||
token.addWindow(window1);
|
||||
token.addWindow(window2);
|
||||
@@ -136,60 +126,11 @@ public class WindowTokenTests {
|
||||
assertEquals(window3StartLayer + adj, highestLayer);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetTopWindow() throws Exception {
|
||||
final TestWindowToken token = new TestWindowToken();
|
||||
|
||||
assertNull(token.getTopWindow());
|
||||
|
||||
final WindowState window1 = createWindow(null, TYPE_APPLICATION, token);
|
||||
token.addWindow(window1);
|
||||
assertEquals(window1, token.getTopWindow());
|
||||
final WindowState window11 = createWindow(window1, FIRST_SUB_WINDOW, token);
|
||||
final WindowState window12 = createWindow(window1, FIRST_SUB_WINDOW, token);
|
||||
assertEquals(window12, token.getTopWindow());
|
||||
|
||||
final WindowState window2 = createWindow(null, TYPE_APPLICATION, token);
|
||||
token.addWindow(window2);
|
||||
// Since new windows are added to the bottom of the token, we would still expect the
|
||||
// previous one to the top.
|
||||
assertEquals(window12, token.getTopWindow());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetWindowIndex() throws Exception {
|
||||
final TestWindowToken token = new TestWindowToken();
|
||||
|
||||
final WindowState window1 = createWindow(null, TYPE_APPLICATION, token);
|
||||
assertEquals(-1, token.getWindowIndex(window1));
|
||||
token.addWindow(window1);
|
||||
assertEquals(0, token.getWindowIndex(window1));
|
||||
final WindowState window11 = createWindow(window1, FIRST_SUB_WINDOW, token);
|
||||
final WindowState window12 = createWindow(window1, FIRST_SUB_WINDOW, token);
|
||||
// Child windows should report the same index as their parents.
|
||||
assertEquals(0, token.getWindowIndex(window11));
|
||||
assertEquals(0, token.getWindowIndex(window12));
|
||||
|
||||
final WindowState window2 = createWindow(null, TYPE_APPLICATION, token);
|
||||
assertEquals(-1, token.getWindowIndex(window2));
|
||||
token.addWindow(window2);
|
||||
// Since new windows are added to the bottom of the token, we would expect the added window
|
||||
// to be at index 0.
|
||||
assertEquals(0, token.getWindowIndex(window2));
|
||||
assertEquals(1, token.getWindowIndex(window1));
|
||||
}
|
||||
|
||||
private WindowState createWindow(WindowState parent, int type, WindowToken token) {
|
||||
final WindowManager.LayoutParams attrs = new WindowManager.LayoutParams(type);
|
||||
|
||||
return new WindowState(mWm, mMockSession, mIWindow, token, parent, OP_NONE, 0, attrs, 0, 0);
|
||||
}
|
||||
|
||||
/* Used so we can gain access to some protected members of the {@link WindowToken} class */
|
||||
private class TestWindowToken extends WindowToken {
|
||||
|
||||
TestWindowToken() {
|
||||
super(mWm, mock(IBinder.class), 0, false, mWm.getDefaultDisplayContentLocked());
|
||||
super(sWm, mock(IBinder.class), 0, false, sWm.getDefaultDisplayContentLocked());
|
||||
}
|
||||
|
||||
int getWindowsCount() {
|
||||
|
||||
Reference in New Issue
Block a user