| /* |
| * 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 android.server.wm; |
| |
| import static android.server.wm.ComponentNameUtils.getWindowName; |
| import static android.server.wm.DialogFrameTestActivity.DIALOG_WINDOW_NAME; |
| import static android.server.wm.DialogFrameTestActivity.TEST_EXPLICIT_POSITION_MATCH_PARENT; |
| import static android.server.wm.DialogFrameTestActivity.TEST_EXPLICIT_POSITION_MATCH_PARENT_NO_LIMITS; |
| import static android.server.wm.DialogFrameTestActivity.TEST_EXPLICIT_SIZE; |
| import static android.server.wm.DialogFrameTestActivity.TEST_EXPLICIT_SIZE_BOTTOM_RIGHT_GRAVITY; |
| import static android.server.wm.DialogFrameTestActivity.TEST_EXPLICIT_SIZE_TOP_LEFT_GRAVITY; |
| import static android.server.wm.DialogFrameTestActivity.TEST_MATCH_PARENT; |
| import static android.server.wm.DialogFrameTestActivity.TEST_NO_FOCUS; |
| import static android.server.wm.DialogFrameTestActivity.TEST_OVER_SIZED_DIMENSIONS; |
| import static android.server.wm.DialogFrameTestActivity.TEST_OVER_SIZED_DIMENSIONS_NO_LIMITS; |
| import static android.server.wm.DialogFrameTestActivity.TEST_WITH_MARGINS; |
| |
| import static androidx.test.InstrumentationRegistry.getInstrumentation; |
| |
| import static org.hamcrest.MatcherAssert.assertThat; |
| import static org.hamcrest.Matchers.greaterThan; |
| import static org.junit.Assert.assertEquals; |
| |
| import android.content.ComponentName; |
| import android.graphics.Insets; |
| import android.graphics.Rect; |
| import android.platform.test.annotations.AppModeFull; |
| import android.platform.test.annotations.Presubmit; |
| import android.server.wm.WindowManagerState.WindowState; |
| import android.view.WindowInsets; |
| |
| import androidx.test.rule.ActivityTestRule; |
| |
| import org.junit.Ignore; |
| import org.junit.Rule; |
| import org.junit.Test; |
| |
| import java.util.List; |
| |
| /** |
| * Build/Install/Run: |
| * atest CtsWindowManagerDeviceTestCases:DialogFrameTests |
| * |
| * TODO: Consolidate this class with {@link ParentChildTestBase}. |
| */ |
| @AppModeFull(reason = "Requires android.permission.MANAGE_ACTIVITY_TASKS") |
| @Presubmit |
| public class DialogFrameTests extends ParentChildTestBase<DialogFrameTestActivity> { |
| |
| private static final ComponentName DIALOG_FRAME_TEST_ACTIVITY = new ComponentName( |
| getInstrumentation().getContext(), DialogFrameTestActivity.class); |
| private Insets mContentInsets; |
| |
| @Rule |
| public final ActivityTestRule<DialogFrameTestActivity> mDialogTestActivity = |
| new ActivityTestRule<>(DialogFrameTestActivity.class, false /* initialTOuchMode */, |
| false /* launchActivity */); |
| |
| @Override |
| ComponentName activityName() { |
| return DIALOG_FRAME_TEST_ACTIVITY; |
| } |
| |
| @Override |
| ActivityTestRule<DialogFrameTestActivity> activityRule() { |
| return mDialogTestActivity; |
| } |
| |
| private WindowState getSingleWindow(final String windowName) { |
| final List<WindowState> windowList = |
| mWmState.getMatchingVisibleWindowState(windowName); |
| assertThat(windowList.size(), greaterThan(0)); |
| return windowList.get(0); |
| } |
| |
| @Override |
| void doSingleTest(ParentChildTest t) throws Exception { |
| mWmState.computeState(WaitForValidActivityState.forWindow(DIALOG_WINDOW_NAME)); |
| WindowState dialog = getSingleWindow(DIALOG_WINDOW_NAME); |
| WindowState parent = getSingleWindow(getWindowName(activityName())); |
| |
| t.doTest(parent, dialog); |
| } |
| |
| // With Width and Height as MATCH_PARENT we should fill |
| // the same content frame as the main activity window |
| @Test |
| public void testMatchParentDialog() throws Exception { |
| doParentChildTest(TEST_MATCH_PARENT, (parent, dialog) -> { ; |
| assertEquals(getParentFrameWithInsets(parent), dialog.getFrame()); |
| }); |
| } |
| |
| private static final int explicitDimension = 200; |
| |
| // The default gravity for dialogs should center them. |
| @Test |
| public void testExplicitSizeDefaultGravity() throws Exception { |
| doParentChildTest(TEST_EXPLICIT_SIZE, (parent, dialog) -> { |
| Rect parentFrame = getParentFrameWithInsets(parent); |
| Rect expectedFrame = new Rect( |
| parentFrame.left + (parentFrame.width() - explicitDimension) / 2, |
| parentFrame.top + (parentFrame.height() - explicitDimension) / 2, |
| parentFrame.left + (parentFrame.width() + explicitDimension) / 2, |
| parentFrame.top + (parentFrame.height() + explicitDimension) / 2); |
| assertEquals(expectedFrame, dialog.getFrame()); |
| }); |
| } |
| |
| @Test |
| public void testExplicitSizeTopLeftGravity() throws Exception { |
| doParentChildTest(TEST_EXPLICIT_SIZE_TOP_LEFT_GRAVITY, (parent, dialog) -> { |
| Rect parentFrame = getParentFrameWithInsets(parent); |
| Rect expectedFrame = new Rect( |
| parentFrame.left, |
| parentFrame.top, |
| parentFrame.left + explicitDimension, |
| parentFrame.top + explicitDimension); |
| assertEquals(expectedFrame, dialog.getFrame()); |
| }); |
| } |
| |
| @Test |
| public void testExplicitSizeBottomRightGravity() throws Exception { |
| doParentChildTest(TEST_EXPLICIT_SIZE_BOTTOM_RIGHT_GRAVITY, (parent, dialog) -> { |
| Rect parentFrame = getParentFrameWithInsets(parent); |
| Rect expectedFrame = new Rect( |
| parentFrame.left + parentFrame.width() - explicitDimension, |
| parentFrame.top + parentFrame.height() - explicitDimension, |
| parentFrame.left + parentFrame.width(), |
| parentFrame.top + parentFrame.height()); |
| assertEquals(expectedFrame, dialog.getFrame()); |
| }); |
| } |
| |
| // TODO(b/30127373): Commented out for now because it doesn't work. We end up insetting the |
| // decor on the bottom. I think this is a bug probably in the default dialog flags: |
| @Ignore |
| @Test |
| public void testOversizedDimensions() throws Exception { |
| doParentChildTest(TEST_OVER_SIZED_DIMENSIONS, (parent, dialog) -> |
| // With the default flags oversize should result in clipping to |
| // parent frame. |
| assertEquals(getParentFrameWithInsets(parent), dialog.getFrame()) |
| ); |
| } |
| |
| // TODO(b/63993863) : Disabled pending public API to fetch maximum surface size. |
| static final int oversizedDimension = 5000; |
| // With FLAG_LAYOUT_NO_LIMITS we should get the size we request, even if its much larger than |
| // the screen. |
| @Ignore |
| @Test |
| public void testOversizedDimensionsNoLimits() throws Exception { |
| // TODO(b/36890978): We only run this in fullscreen because of the |
| // unclear status of NO_LIMITS for non-child surfaces in MW modes |
| doFullscreenTest(TEST_OVER_SIZED_DIMENSIONS_NO_LIMITS, (parent, dialog) -> { |
| Rect parentFrame = getParentFrameWithInsets(parent); |
| Rect expectedFrame = new Rect(parentFrame.left, parentFrame.top, |
| parentFrame.left + oversizedDimension, |
| parentFrame.top + oversizedDimension); |
| assertEquals(expectedFrame, dialog.getFrame()); |
| }); |
| } |
| |
| // If we request the MATCH_PARENT and a non-zero position, we wouldn't be |
| // able to fit all of our content, so we should be adjusted to just fit the |
| // content frame. |
| @Test |
| public void testExplicitPositionMatchParent() throws Exception { |
| doParentChildTest(TEST_EXPLICIT_POSITION_MATCH_PARENT, (parent, dialog) -> |
| assertEquals(getParentFrameWithInsets(parent), dialog.getFrame()) |
| ); |
| } |
| |
| // Unless we pass NO_LIMITS in which case our requested position should |
| // be honored. |
| @Test |
| public void testExplicitPositionMatchParentNoLimits() throws Exception { |
| final int explicitPosition = 100; |
| doParentChildTest(TEST_EXPLICIT_POSITION_MATCH_PARENT_NO_LIMITS, (parent, dialog) -> { |
| Rect parentFrame = getParentFrameWithInsets(parent); |
| Rect expectedFrame = new Rect(parentFrame); |
| expectedFrame.offset(explicitPosition, explicitPosition); |
| assertEquals(expectedFrame, dialog.getFrame()); |
| }); |
| } |
| |
| // We run the two focus tests fullscreen only because switching to the |
| // docked stack will strip away focus from the task anyway. |
| @Test |
| public void testDialogReceivesFocus() throws Exception { |
| doFullscreenTest(TEST_MATCH_PARENT, (parent, dialog) -> |
| assertEquals(dialog.getName(), mWmState.getFocusedWindow()) |
| ); |
| } |
| |
| @Test |
| public void testNoFocusDialog() throws Exception { |
| doFullscreenTest(TEST_NO_FOCUS, (parent, dialog) -> |
| assertEquals(parent.getName(), mWmState.getFocusedWindow()) |
| ); |
| } |
| |
| @Test |
| public void testMarginsArePercentagesOfContentFrame() throws Exception { |
| float horizontalMargin = .10f; |
| float verticalMargin = .15f; |
| doParentChildTest(TEST_WITH_MARGINS, (parent, dialog) -> { |
| Rect frame = getParentFrameWithInsets(parent); |
| Rect expectedFrame = new Rect( |
| (int) (horizontalMargin * frame.width() + frame.left), |
| (int) (verticalMargin * frame.height() + frame.top), |
| (int) (horizontalMargin * frame.width() + frame.left) + explicitDimension, |
| (int) (verticalMargin * frame.height() + frame.top) + explicitDimension); |
| assertEquals(expectedFrame, dialog.getFrame()); |
| }); |
| } |
| |
| @Test |
| public void testDialogPlacedAboveParent() throws Exception { |
| final WindowManagerState wmState = mWmState; |
| doParentChildTest(TEST_MATCH_PARENT, (parent, dialog) -> |
| // Not only should the dialog be higher, but it should be leave multiple layers of |
| // space in between for DimLayers, etc... |
| assertThat(wmState.getZOrder(dialog), greaterThan(wmState.getZOrder(parent))) |
| ); |
| } |
| |
| private Rect getParentFrameWithInsets(WindowState parent) { |
| Rect parentFrame = parent.getFrame(); |
| return inset(parentFrame, getActivitySystemInsets()); |
| } |
| |
| private Insets getActivitySystemInsets() { |
| getInstrumentation().waitForIdleSync(); |
| getInstrumentation().runOnMainSync(() -> { |
| final Insets insets = mDialogTestActivity |
| .getActivity() |
| .getWindow() |
| .getDecorView() |
| .getRootWindowInsets() |
| .getInsets(WindowInsets.Type.systemBars()); |
| mContentInsets = Insets.of(insets.left, insets.top, insets.right, insets.bottom); |
| }); |
| return mContentInsets; |
| } |
| |
| private static Rect inset(Rect original, Insets insets) { |
| final int left = original.left + insets.left; |
| final int top = original.top + insets.top; |
| final int right = original.right - insets.right; |
| final int bottom = original.bottom - insets.bottom; |
| return new Rect(left, top, right, bottom); |
| } |
| } |