blob: a1e5b80eb2eda4915e8a45d47b9519ed514c37e3 [file] [log] [blame]
/*
* 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.app.AppOpsManager.OP_NONE;
import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD;
import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
import static android.os.Process.SYSTEM_UID;
import static android.view.View.VISIBLE;
import static android.view.WindowManager.LayoutParams.FIRST_APPLICATION_WINDOW;
import static android.view.WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
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_OVERLAY;
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_NOTIFICATION_SHADE;
import static android.view.WindowManager.LayoutParams.TYPE_STATUS_BAR;
import static android.view.WindowManager.LayoutParams.TYPE_WALLPAPER;
import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation;
import static org.mockito.Mockito.mock;
import android.content.Context;
import android.content.Intent;
import android.os.UserHandle;
import android.util.Log;
import android.view.Display;
import android.view.DisplayInfo;
import android.view.IWindow;
import android.view.SurfaceControl.Transaction;
import android.view.View;
import android.view.WindowManager;
import com.android.server.AttributeCache;
import org.junit.Before;
import org.junit.BeforeClass;
/** Common base class for window manager unit test classes. */
class WindowTestsBase extends SystemServiceTestsBase {
private static final String TAG = WindowTestsBase.class.getSimpleName();
WindowManagerService mWm;
private final IWindow mIWindow = new TestIWindow();
private Session mMockSession;
static int sNextStackId = 1000;
/** Non-default display. */
DisplayContent mDisplayContent;
DisplayInfo mDisplayInfo = new DisplayInfo();
WindowState mWallpaperWindow;
WindowState mImeWindow;
WindowState mImeDialogWindow;
WindowState mStatusBarWindow;
WindowState mNotificationShadeWindow;
WindowState mDockedDividerWindow;
WindowState mNavBarWindow;
WindowState mAppWindow;
WindowState mChildAppWindowAbove;
WindowState mChildAppWindowBelow;
/**
* Spied {@link Transaction} class than can be used to verify calls.
*/
Transaction mTransaction;
@BeforeClass
public static void setUpOnceBase() {
AttributeCache.init(getInstrumentation().getTargetContext());
}
@Before
public void setUpBase() {
mWm = mSystemServicesTestRule.getWindowManagerService();
SystemServicesTestRule.checkHoldsLock(mWm.mGlobalLock);
mTransaction = mSystemServicesTestRule.mTransaction;
mMockSession = mock(Session.class);
final Context context = getInstrumentation().getTargetContext();
// If @Before throws an exception, the error isn't logged. This will make sure any failures
// in the set up are clear. This can be removed when b/37850063 is fixed.
try {
beforeCreateDisplay();
context.getDisplay().getDisplayInfo(mDisplayInfo);
mDisplayContent = createNewDisplay(true /* supportIme */);
// Set-up some common windows.
mWallpaperWindow = createCommonWindow(null, TYPE_WALLPAPER, "wallpaperWindow");
mImeWindow = createCommonWindow(null, TYPE_INPUT_METHOD, "mImeWindow");
mDisplayContent.mInputMethodWindow = mImeWindow;
mImeDialogWindow = createCommonWindow(null, TYPE_INPUT_METHOD_DIALOG,
"mImeDialogWindow");
mStatusBarWindow = createCommonWindow(null, TYPE_STATUS_BAR, "mStatusBarWindow");
mNotificationShadeWindow = createCommonWindow(null, TYPE_NOTIFICATION_SHADE,
"mNotificationShadeWindow");
mNavBarWindow = createCommonWindow(null, TYPE_NAVIGATION_BAR, "mNavBarWindow");
mDockedDividerWindow = createCommonWindow(null, TYPE_DOCK_DIVIDER,
"mDockedDividerWindow");
mAppWindow = createCommonWindow(null, TYPE_BASE_APPLICATION, "mAppWindow");
mChildAppWindowAbove = createCommonWindow(mAppWindow,
TYPE_APPLICATION_ATTACHED_DIALOG,
"mChildAppWindowAbove");
mChildAppWindowBelow = createCommonWindow(mAppWindow,
TYPE_APPLICATION_MEDIA_OVERLAY,
"mChildAppWindowBelow");
mDisplayContent.getDisplayPolicy().setForceShowSystemBars(false);
// Adding a display will cause freezing the display. Make sure to wait until it's
// unfrozen to not run into race conditions with the tests.
waitUntilHandlersIdle();
} catch (Exception e) {
Log.e(TAG, "Failed to set up test", e);
throw e;
}
}
void beforeCreateDisplay() {
// Called before display is created.
}
private WindowState createCommonWindow(WindowState parent, int type, String name) {
final WindowState win = createWindow(parent, type, name);
// Prevent common windows from been IME targets.
win.mAttrs.flags |= FLAG_NOT_FOCUSABLE;
return win;
}
private WindowToken createWindowToken(
DisplayContent dc, int windowingMode, int activityType, int type) {
if (type < FIRST_APPLICATION_WINDOW || type > LAST_APPLICATION_WINDOW) {
return WindowTestUtils.createTestWindowToken(type, dc);
}
return createActivityRecord(dc, windowingMode, activityType);
}
ActivityRecord createActivityRecord(DisplayContent dc, int windowingMode, int activityType) {
return createTestActivityRecord(dc, windowingMode, activityType);
}
ActivityRecord createTestActivityRecord(DisplayContent dc, int
windowingMode, int activityType) {
final ActivityStack stack = createTaskStackOnDisplay(windowingMode, activityType, dc);
return WindowTestUtils.createTestActivityRecord(stack);
}
WindowState createWindow(WindowState parent, int type, String name) {
return (parent == null)
? createWindow(parent, type, mDisplayContent, name)
: createWindow(parent, type, parent.mToken, name);
}
WindowState createWindow(WindowState parent, int type, String name, int ownerId) {
return (parent == null)
? createWindow(parent, type, mDisplayContent, name, ownerId)
: createWindow(parent, type, parent.mToken, name, ownerId);
}
WindowState createWindowOnStack(WindowState parent, int windowingMode, int activityType,
int type, DisplayContent dc, String name) {
final WindowToken token = createWindowToken(dc, windowingMode, activityType, type);
return createWindow(parent, type, token, name);
}
WindowState createAppWindow(Task task, int type, String name) {
final ActivityRecord activity =
WindowTestUtils.createTestActivityRecord(task.getDisplayContent());
task.addChild(activity, 0);
return createWindow(null, type, activity, name);
}
WindowState createWindow(WindowState parent, int type, DisplayContent dc, String name) {
final WindowToken token = createWindowToken(
dc, WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, type);
return createWindow(parent, type, token, name, 0 /* ownerId */);
}
WindowState createWindow(WindowState parent, int type, DisplayContent dc, String name,
int ownerId) {
final WindowToken token = createWindowToken(
dc, WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, type);
return createWindow(parent, type, token, name, ownerId);
}
WindowState createWindow(WindowState parent, int type, DisplayContent dc, String name,
boolean ownerCanAddInternalSystemWindow) {
final WindowToken token = createWindowToken(
dc, WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, type);
return createWindow(parent, type, token, name, 0 /* ownerId */,
ownerCanAddInternalSystemWindow);
}
WindowState createWindow(WindowState parent, int type, WindowToken token, String name) {
return createWindow(parent, type, token, name, 0 /* ownerId */,
false /* ownerCanAddInternalSystemWindow */);
}
WindowState createWindow(WindowState parent, int type, WindowToken token, String name,
int ownerId) {
return createWindow(parent, type, token, name, ownerId,
false /* ownerCanAddInternalSystemWindow */);
}
WindowState createWindow(WindowState parent, int type, WindowToken token, String name,
int ownerId, boolean ownerCanAddInternalSystemWindow) {
return createWindow(parent, type, token, name, ownerId, UserHandle.getUserId(ownerId),
ownerCanAddInternalSystemWindow, mWm, mMockSession, mIWindow,
mSystemServicesTestRule.getPowerManagerWrapper());
}
static WindowState createWindow(WindowState parent, int type, WindowToken token,
String name, int ownerId, int userId, boolean ownerCanAddInternalSystemWindow,
WindowManagerService service, Session session, IWindow iWindow,
WindowState.PowerManagerWrapper powerManagerWrapper) {
SystemServicesTestRule.checkHoldsLock(service.mGlobalLock);
final WindowManager.LayoutParams attrs = new WindowManager.LayoutParams(type);
attrs.setTitle(name);
final WindowState w = new WindowState(service, session, iWindow, token, parent,
OP_NONE, 0, attrs, VISIBLE, ownerId, userId,
ownerCanAddInternalSystemWindow,
powerManagerWrapper);
// 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;
}
static void makeWindowVisible(WindowState... windows) {
for (WindowState win : windows) {
win.mViewVisibility = View.VISIBLE;
win.mRelayoutCalled = true;
win.mHasSurface = true;
win.mHidden = false;
win.showLw(false /* doAnimation */, false /* requestAnim */);
}
}
/** Creates a {@link ActivityStack} and adds it to the specified {@link DisplayContent}. */
ActivityStack createTaskStackOnDisplay(DisplayContent dc) {
return createTaskStackOnDisplay(WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, dc);
}
ActivityStack createTaskStackOnDisplay(int windowingMode, int activityType, DisplayContent dc) {
return new ActivityTestsBase.StackBuilder(dc.mWmService.mRoot)
.setDisplay(dc)
.setWindowingMode(windowingMode)
.setActivityType(activityType)
.setCreateActivity(false)
.setIntent(new Intent())
.build();
}
ActivityStack createTaskStackOnTaskDisplayArea(int windowingMode, int activityType,
TaskDisplayArea tda) {
return new ActivityTestsBase.StackBuilder(tda.mWmService.mRoot)
.setTaskDisplayArea(tda)
.setWindowingMode(windowingMode)
.setActivityType(activityType)
.setCreateActivity(false)
.setIntent(new Intent())
.build();
}
/** Creates a {@link Task} and adds it to the specified {@link ActivityStack}. */
Task createTaskInStack(ActivityStack stack, int userId) {
return WindowTestUtils.createTaskInStack(mWm, stack, userId);
}
/** Creates a {@link DisplayContent} that supports IME and adds it to the system. */
DisplayContent createNewDisplay() {
return createNewDisplay(true /* supportIme */);
}
/** Creates a {@link DisplayContent} and adds it to the system. */
private DisplayContent createNewDisplay(boolean supportIme) {
return createNewDisplay(mDisplayInfo, supportIme);
}
/** Creates a {@link DisplayContent} that supports IME and adds it to the system. */
DisplayContent createNewDisplay(DisplayInfo info) {
return createNewDisplay(info, true /* supportIme */);
}
/** Creates a {@link DisplayContent} and adds it to the system. */
private DisplayContent createNewDisplay(DisplayInfo info, boolean supportIme) {
final DisplayContent display =
new TestDisplayContent.Builder(mWm.mAtmService, info).build();
final DisplayContent dc = display.mDisplayContent;
// this display can show IME.
dc.mWmService.mDisplayWindowSettings.setShouldShowImeLocked(dc, supportIme);
return dc;
}
/**
* Creates a {@link DisplayContent} with given display state and adds it to the system.
*
* @param displayState For initializing the state of the display. See
* {@link Display#getState()}.
*/
DisplayContent createNewDisplay(int displayState) {
// Leverage main display info & initialize it with display state for given displayId.
DisplayInfo displayInfo = new DisplayInfo();
displayInfo.copyFrom(mDisplayInfo);
displayInfo.state = displayState;
return createNewDisplay(displayInfo, true /* supportIme */);
}
/** Creates a {@link com.android.server.wm.WindowTestUtils.TestWindowState} */
WindowTestUtils.TestWindowState createWindowState(WindowManager.LayoutParams attrs,
WindowToken token) {
SystemServicesTestRule.checkHoldsLock(mWm.mGlobalLock);
return new WindowTestUtils.TestWindowState(mWm, mMockSession, mIWindow, attrs, token);
}
/** Creates a {@link DisplayContent} as parts of simulate display info for test. */
DisplayContent createMockSimulatedDisplay() {
DisplayInfo displayInfo = new DisplayInfo();
displayInfo.copyFrom(mDisplayInfo);
displayInfo.type = Display.TYPE_VIRTUAL;
displayInfo.ownerUid = SYSTEM_UID;
return createNewDisplay(displayInfo, false /* supportIme */);
}
/** Sets the default minimum task size to 1 so that tests can use small task sizes */
void removeGlobalMinSizeRestriction() {
mWm.mAtmService.mRootWindowContainer.mDefaultMinSizeOfResizeableTaskDp = 1;
}
}