blob: f10fe84c43251be7335210b806a76ac53753d0aa [file] [log] [blame]
/*
* Copyright (C) 2023 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 android.server.wm;
import static android.content.res.Configuration.UI_MODE_TYPE_DESK;
import static android.content.res.Configuration.UI_MODE_TYPE_MASK;
import static android.content.res.Configuration.UI_MODE_TYPE_NORMAL;
import static android.server.wm.app.Components.TEST_ACTIVITY;
import static android.server.wm.deskresources.Components.DESK_RESOURCES_ACTIVITY;
import static com.android.compatibility.common.util.SystemUtil.runShellCommand;
import static org.junit.Assume.assumeTrue;
import android.content.ComponentName;
import android.content.Intent;
import android.content.res.Resources;
import android.platform.test.annotations.Presubmit;
import android.view.Surface;
import org.junit.Test;
/**
* Build/Install/Run:
* atest CtsWindowManagerDeviceTestCases:DockConfigChangeTests
*/
@Presubmit
public class DockConfigChangeTests extends ActivityManagerTestBase {
@Test
public void testDeskMode_noConfigChange() {
// Test only applies to behavior when the config_skipActivityRelaunchWhenDocking flag is
// enabled.
assumeTrue(getConfigSkipRelaunchOnDock());
// Set rotation to the same rotation as the device would be rotated to after docking. This
// prevents an extraneous config change from the device rotating when docked/undocked.
RotationSession rotationSession = createManagedRotationSession();
rotateToDockRotation(rotationSession);
launchActivity(TEST_ACTIVITY);
waitAndAssertResumedActivity(TEST_ACTIVITY, "Activity must be resumed");
separateTestJournal();
final DockTestSession dockTestSession = mObjectTracker.manage(new DockTestSession());
// Dock the device.
dockTestSession.dock();
dockTestSession.waitForDeskUiMode(TEST_ACTIVITY);
// The activity receives a configuration change instead of relaunching.
assertRelaunchOrConfigChanged(TEST_ACTIVITY, 0 /* numRelaunch */, 1 /* numConfigChange */);
// Undock the device.
separateTestJournal();
dockTestSession.undock();
dockTestSession.waitForNormalUiMode(TEST_ACTIVITY);
// The activity receives another configuration change.
assertRelaunchOrConfigChanged(TEST_ACTIVITY, 0 /* numRelaunch */, 1 /* numConfigChange */);
}
@Test
public void testDeskMode_hasDeskResources_relaunches() {
// Test only applies to behavior when the config_skipActivityRelaunchWhenDocking flag is
// enabled.
assumeTrue(getConfigSkipRelaunchOnDock());
// Set rotation to the same rotation as the device would be rotated to after docking. This
// prevents an extraneous config change from the device rotating when docked/undocked.
RotationSession rotationSession = createManagedRotationSession();
rotateToDockRotation(rotationSession);
launchActivity(DESK_RESOURCES_ACTIVITY);
waitAndAssertResumedActivity(DESK_RESOURCES_ACTIVITY, "Activity must be resumed");
separateTestJournal();
final DockTestSession dockTestSession = mObjectTracker.manage(new DockTestSession());
// Dock the device.
dockTestSession.dock();
dockTestSession.waitForDeskUiMode(DESK_RESOURCES_ACTIVITY);
// The activity is relaunched since the app has -desk resources.
assertRelaunchOrConfigChanged(DESK_RESOURCES_ACTIVITY, 1 /* numRelaunch */,
0 /* numConfigChange */);
// Undock the device.
separateTestJournal();
dockTestSession.undock();
dockTestSession.waitForNormalUiMode(DESK_RESOURCES_ACTIVITY);
// The activity is relaunched again.
assertRelaunchOrConfigChanged(DESK_RESOURCES_ACTIVITY, 1 /* numRelaunch */,
0 /* numConfigChange */);
}
boolean getConfigSkipRelaunchOnDock() {
return mContext.getResources().getBoolean(
Resources.getSystem().getIdentifier("config_skipActivityRelaunchWhenDocking",
"bool", "android"));
}
/**
* Rotates the device to the same rotation as it would rotate to when docked.
*
* Dock rotation is read from config_deskDockRotation.
*/
void rotateToDockRotation(RotationSession rotationSession) {
int rotation = rotationDegreesToConst(mContext.getResources().getInteger(
Resources.getSystem().getIdentifier("config_deskDockRotation",
"integer", "android")));
if (rotation == -1) {
// -1 could come from the const itself, which means no rotation on dock, or from
// rotationDegreesToConst, which means we got an unexpected value from the resource.
return;
}
rotationSession.set(rotation);
}
/**
* Converts from a rotation in degrees to a {@link Surface.Rotation} constant.
*
* Returns -1 if a value that doesn't match a {@link Surface.Rotation} constant is provided.
*/
private int rotationDegreesToConst(int rotationDegrees) {
switch (rotationDegrees) {
case 0:
return Surface.ROTATION_0;
case 90:
return Surface.ROTATION_90;
case 180:
return Surface.ROTATION_180;
case 270:
return Surface.ROTATION_270;
}
return -1;
}
private class DockTestSession implements AutoCloseable {
private void dock() {
runShellCommand("dumpsys DockObserver set state "
+ Intent.EXTRA_DOCK_STATE_HE_DESK);
}
private void undock() {
runShellCommand("dumpsys DockObserver set state "
+ Intent.EXTRA_DOCK_STATE_UNDOCKED);
}
private void waitForDeskUiMode(ComponentName activity) {
waitForUiMode(activity, UI_MODE_TYPE_DESK);
}
private void waitForNormalUiMode(ComponentName activity) {
waitForUiMode(activity, UI_MODE_TYPE_NORMAL);
}
/**
* Waits until the activity has received the expected uiMode in a configuration change.
*/
private void waitForUiMode(ComponentName activity, int expectedUiMode) {
mWmState.waitFor(state -> {
int actualUiMode = state.getActivity(activity).getUiMode();
return (actualUiMode & UI_MODE_TYPE_MASK) == actualUiMode;
}, "Didn't enter expected uiMode in time: " + expectedUiMode);
}
@Override
public void close() throws Exception {
runShellCommand("dumpsys DockObserver reset");
}
}
}