blob: f30a7d41b7c2839f60c055799a4788eb0e9e1f26 [file] [log] [blame]
/*
* Copyright (C) 2020 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.jetpack;
import static android.content.res.Configuration.ORIENTATION_LANDSCAPE;
import static android.content.res.Configuration.ORIENTATION_PORTRAIT;
import static android.server.wm.jetpack.utils.SidecarUtil.assertEqualWindowLayoutInfo;
import static android.server.wm.jetpack.utils.SidecarUtil.assumeHasDisplayFeatures;
import static android.server.wm.jetpack.utils.SidecarUtil.assumeSidecarSupportedDevice;
import static android.server.wm.jetpack.utils.SidecarUtil.getSidecarInterface;
import static com.google.common.truth.Truth.assertThat;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
import android.graphics.Rect;
import android.os.IBinder;
import android.platform.test.annotations.Presubmit;
import android.server.wm.jetpack.utils.SidecarCallbackCounter;
import android.server.wm.jetpack.utils.TestActivity;
import android.server.wm.jetpack.utils.TestConfigChangeHandlingActivity;
import android.server.wm.jetpack.utils.TestGetWindowLayoutInfoActivity;
import android.server.wm.jetpack.utils.WindowManagerJetpackTestBase;
import androidx.test.ext.junit.runners.AndroidJUnit4;
import androidx.test.filters.FlakyTest;
import androidx.test.filters.LargeTest;
import androidx.window.sidecar.SidecarDeviceState;
import androidx.window.sidecar.SidecarDisplayFeature;
import androidx.window.sidecar.SidecarInterface;
import androidx.window.sidecar.SidecarWindowLayoutInfo;
import com.google.common.collect.BoundType;
import com.google.common.collect.Range;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
/**
* Tests for the {@link androidx.window.sidecar} implementation provided on the device (and only
* if one is available).
*
* Build/Install/Run:
* atest CtsWindowManagerJetpackTestCases:SidecarTest
*/
@Presubmit
@LargeTest
@RunWith(AndroidJUnit4.class)
public class SidecarTest extends WindowManagerJetpackTestBase {
private static final String TAG = "SidecarTest";
private TestActivity mActivity;
private SidecarInterface mSidecarInterface;
private IBinder mWindowToken;
@Before
@Override
public void setUp() {
super.setUp();
assumeSidecarSupportedDevice(mContext);
mActivity = (TestActivity) startActivityNewTask(TestActivity.class);
mSidecarInterface = getSidecarInterface(mActivity);
assertThat(mSidecarInterface).isNotNull();
mWindowToken = getActivityWindowToken(mActivity);
assertThat(mWindowToken).isNotNull();
}
/**
* Test adding and removing a sidecar interface window layout change listener.
*/
@FlakyTest(bugId = 206697963)
@Test
public void testSidecarInterface_onWindowLayoutChangeListener() {
// Set activity to portrait
setActivityOrientationActivityDoesNotHandleOrientationChanges(mActivity,
ORIENTATION_PORTRAIT);
// Create the sidecar callback. onWindowLayoutChanged should only be called twice in this
// test, not the third time when the orientation will change because the listener will be
// removed.
SidecarCallbackCounter sidecarCallback = new SidecarCallbackCounter(mWindowToken,
2 /* expectedCallbackCount */);
mSidecarInterface.setSidecarCallback(sidecarCallback);
// Add window layout listener for mWindowToken - onWindowLayoutChanged should be called
mSidecarInterface.onWindowLayoutChangeListenerAdded(mWindowToken);
// Change the activity orientation - onWindowLayoutChanged should be called
setActivityOrientationActivityDoesNotHandleOrientationChanges(mActivity,
ORIENTATION_LANDSCAPE);
// Remove the listener
mSidecarInterface.onWindowLayoutChangeListenerRemoved(mWindowToken);
// Change the activity orientation - onWindowLayoutChanged should NOT be called
setActivityOrientationActivityDoesNotHandleOrientationChanges(mActivity,
ORIENTATION_PORTRAIT);
// Check that the countdown is zero
sidecarCallback.assertZeroCount();
}
@Test
public void testSidecarInterface_getWindowLayoutInfo() {
assumeHasDisplayFeatures(mSidecarInterface, mWindowToken);
// Layout must happen after launch
assertThat(mActivity.waitForLayout()).isTrue();
SidecarWindowLayoutInfo windowLayoutInfo = mSidecarInterface.getWindowLayoutInfo(
mWindowToken);
assertThat(windowLayoutInfo).isNotNull();
for (SidecarDisplayFeature displayFeature : windowLayoutInfo.displayFeatures) {
int featureType = displayFeature.getType();
assertThat(featureType).isAtLeast(SidecarDisplayFeature.TYPE_FOLD);
assertThat(featureType).isAtMost(SidecarDisplayFeature.TYPE_HINGE);
Rect featureRect = displayFeature.getRect();
// Feature cannot have negative area
assertHasNonNegativeDimensions(featureRect);
// Feature cannot have zero width and height, at most only one dimension can be zero
assertNotBothDimensionsZero(featureRect);
// Check that feature is within the activity bounds
assertTrue(getActivityBounds(mActivity).contains(featureRect));
}
}
@Test
public void testSidecarInterface_getDeviceState() {
SidecarDeviceState deviceState = mSidecarInterface.getDeviceState();
assertThat(deviceState).isNotNull();
assertThat(deviceState.posture).isIn(Range.range(
SidecarDeviceState.POSTURE_UNKNOWN, BoundType.CLOSED,
SidecarDeviceState.POSTURE_FLIPPED, BoundType.CLOSED));
}
@Test
public void testSidecarInterface_onDeviceStateListenersChanged() {
SidecarDeviceState deviceState1 = mSidecarInterface.getDeviceState();
mSidecarInterface.onDeviceStateListenersChanged(false /* isEmpty */);
SidecarDeviceState deviceState2 = mSidecarInterface.getDeviceState();
mSidecarInterface.onDeviceStateListenersChanged(true /* isEmpty */);
SidecarDeviceState deviceState3 = mSidecarInterface.getDeviceState();
assertEquals(deviceState1.posture, deviceState2.posture);
assertEquals(deviceState1.posture, deviceState3.posture);
}
/**
* Tests that before an activity is attached to a window,
* {@link SidecarInterface#getWindowLayoutInfo()} either returns the same value as it would
* after the activity is attached to a window or throws an exception.
*/
@Test
public void testGetWindowLayoutInfo_activityNotAttachedToWindow_returnsCorrectValue() {
assumeHasDisplayFeatures(mSidecarInterface, mWindowToken);
// The value is verified inside TestGetWindowLayoutInfoActivity
TestGetWindowLayoutInfoActivity.resetResumeCounter();
TestGetWindowLayoutInfoActivity testGetWindowLayoutInfoActivity = startActivityNewTask(
TestGetWindowLayoutInfoActivity.class);
// Make sure the activity has gone through all states.
assertThat(TestGetWindowLayoutInfoActivity.waitForOnResume()).isTrue();
assertThat(testGetWindowLayoutInfoActivity.waitForLayout()).isTrue();
}
@Test
public void testGetWindowLayoutInfo_configChanged_windowLayoutUpdates() {
assumeHasDisplayFeatures(mSidecarInterface, mWindowToken);
TestConfigChangeHandlingActivity configHandlingActivity = startActivityNewTask(
TestConfigChangeHandlingActivity.class);
SidecarInterface sidecar = getSidecarInterface(configHandlingActivity);
assertThat(sidecar).isNotNull();
IBinder configHandlingActivityWindowToken = getActivityWindowToken(configHandlingActivity);
assertThat(configHandlingActivityWindowToken).isNotNull();
setActivityOrientationActivityHandlesOrientationChanges(configHandlingActivity,
ORIENTATION_PORTRAIT);
SidecarWindowLayoutInfo portraitWindowLayoutInfo =
sidecar.getWindowLayoutInfo(configHandlingActivityWindowToken);
final Rect portraitBounds = getActivityBounds(configHandlingActivity);
final Rect portraitMaximumBounds = getMaximumActivityBounds(configHandlingActivity);
setActivityOrientationActivityHandlesOrientationChanges(configHandlingActivity,
ORIENTATION_LANDSCAPE);
SidecarWindowLayoutInfo landscapeWindowLayoutInfo =
sidecar.getWindowLayoutInfo(configHandlingActivityWindowToken);
final Rect landscapeBounds = getActivityBounds(configHandlingActivity);
final Rect landscapeMaximumBounds = getMaximumActivityBounds(configHandlingActivity);
final boolean doesDisplayRotateForOrientation = doesDisplayRotateForOrientation(
portraitMaximumBounds, landscapeMaximumBounds);
assertEqualWindowLayoutInfo(portraitWindowLayoutInfo, landscapeWindowLayoutInfo,
portraitBounds, landscapeBounds, doesDisplayRotateForOrientation);
}
@Test
public void testGetWindowLayoutInfo_windowRecreated_windowLayoutUpdates() {
assumeHasDisplayFeatures(mSidecarInterface, mWindowToken);
setActivityOrientationActivityDoesNotHandleOrientationChanges(mActivity,
ORIENTATION_PORTRAIT);
SidecarWindowLayoutInfo portraitWindowLayoutInfo =
mSidecarInterface.getWindowLayoutInfo(mWindowToken);
final Rect portraitBounds = getActivityBounds(mActivity);
final Rect portraitMaximumBounds = getMaximumActivityBounds(mActivity);
setActivityOrientationActivityDoesNotHandleOrientationChanges(mActivity,
ORIENTATION_LANDSCAPE);
mWindowToken = getActivityWindowToken(mActivity);
assertThat(mWindowToken).isNotNull();
SidecarWindowLayoutInfo landscapeWindowLayoutInfo =
mSidecarInterface.getWindowLayoutInfo(mWindowToken);
final Rect landscapeBounds = getActivityBounds(mActivity);
final Rect landscapeMaximumBounds = getMaximumActivityBounds(mActivity);
final boolean doesDisplayRotateForOrientation = doesDisplayRotateForOrientation(
portraitMaximumBounds, landscapeMaximumBounds);
assertEqualWindowLayoutInfo(portraitWindowLayoutInfo, landscapeWindowLayoutInfo,
portraitBounds, landscapeBounds, doesDisplayRotateForOrientation);
}
}