1 /*
2  * Copyright (C) 2016 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package android.server.wm;
18 
19 import static android.server.am.ComponentNameUtils.getWindowName;
20 import static android.server.wm.DialogFrameTestActivity.DIALOG_WINDOW_NAME;
21 import static android.server.wm.DialogFrameTestActivity.TEST_EXPLICIT_POSITION_MATCH_PARENT;
22 import static android.server.wm.DialogFrameTestActivity.TEST_EXPLICIT_POSITION_MATCH_PARENT_NO_LIMITS;
23 import static android.server.wm.DialogFrameTestActivity.TEST_EXPLICIT_SIZE;
24 import static android.server.wm.DialogFrameTestActivity.TEST_EXPLICIT_SIZE_BOTTOM_RIGHT_GRAVITY;
25 import static android.server.wm.DialogFrameTestActivity.TEST_EXPLICIT_SIZE_TOP_LEFT_GRAVITY;
26 import static android.server.wm.DialogFrameTestActivity.TEST_MATCH_PARENT;
27 import static android.server.wm.DialogFrameTestActivity.TEST_MATCH_PARENT_LAYOUT_IN_OVERSCAN;
28 import static android.server.wm.DialogFrameTestActivity.TEST_NO_FOCUS;
29 import static android.server.wm.DialogFrameTestActivity.TEST_OVER_SIZED_DIMENSIONS;
30 import static android.server.wm.DialogFrameTestActivity.TEST_OVER_SIZED_DIMENSIONS_NO_LIMITS;
31 import static android.server.wm.DialogFrameTestActivity.TEST_WITH_MARGINS;
32 
33 import static org.hamcrest.MatcherAssert.assertThat;
34 import static org.hamcrest.Matchers.greaterThan;
35 import static org.junit.Assert.assertEquals;
36 
37 import android.content.ComponentName;
38 import android.graphics.Rect;
39 import android.platform.test.annotations.AppModeFull;
40 import android.server.am.WaitForValidActivityState;
41 import android.server.am.WindowManagerState;
42 import android.server.am.WindowManagerState.WindowState;
43 import android.support.test.InstrumentationRegistry;
44 import android.support.test.rule.ActivityTestRule;
45 
46 import org.junit.Ignore;
47 import org.junit.Rule;
48 import org.junit.Test;
49 
50 import java.util.List;
51 
52 /**
53  * Build/Install/Run:
54  *     atest CtsWindowManagerDeviceTestCases:DialogFrameTests
55  *
56  * TODO: Consolidate this class with {@link ParentChildTestBase}.
57  */
58 @AppModeFull(reason = "Requires android.permission.MANAGE_ACTIVITY_STACKS")
59 public class DialogFrameTests extends ParentChildTestBase<DialogFrameTestActivity> {
60 
61     private static final ComponentName DIALOG_FRAME_TEST_ACTIVITY = new ComponentName(
62             InstrumentationRegistry.getContext(), DialogFrameTestActivity.class);
63 
64     @Rule
65     public final ActivityTestRule<DialogFrameTestActivity> mDialogTestActivity =
66             new ActivityTestRule<>(DialogFrameTestActivity.class, false /* initialTOuchMode */,
67                     false /* launchActivity */);
68 
69     @Override
activityName()70     ComponentName activityName() {
71         return DIALOG_FRAME_TEST_ACTIVITY;
72     }
73 
74     @Override
activityRule()75     ActivityTestRule<DialogFrameTestActivity> activityRule() {
76         return mDialogTestActivity;
77     }
78 
getSingleWindow(final String windowName)79     private WindowState getSingleWindow(final String windowName) {
80         final List<WindowState> windowList =
81                 mAmWmState.getWmState().getMatchingVisibleWindowState(windowName);
82         assertThat(windowList.size(), greaterThan(0));
83         return windowList.get(0);
84     }
85 
86     @Override
doSingleTest(ParentChildTest t)87     void doSingleTest(ParentChildTest t) throws Exception {
88         mAmWmState.computeState(WaitForValidActivityState.forWindow(DIALOG_WINDOW_NAME));
89         WindowState dialog = getSingleWindow(DIALOG_WINDOW_NAME);
90         WindowState parent = getSingleWindow(getWindowName(activityName()));
91 
92         t.doTest(parent, dialog);
93     }
94 
95     // With Width and Height as MATCH_PARENT we should fill
96     // the same content frame as the main activity window
97     @Test
testMatchParentDialog()98     public void testMatchParentDialog() throws Exception {
99         doParentChildTest(TEST_MATCH_PARENT, (parent, dialog) ->
100                 assertEquals(parent.getContentFrame(), dialog.getFrame())
101         );
102     }
103 
104     // If we have LAYOUT_IN_SCREEN and LAYOUT_IN_OVERSCAN with MATCH_PARENT,
105     // we will not be constrained to the insets and so we will be the same size
106     // as the main window main frame.
107     @Test
testMatchParentDialogLayoutInOverscan()108     public void testMatchParentDialogLayoutInOverscan() throws Exception {
109         doParentChildTest(TEST_MATCH_PARENT_LAYOUT_IN_OVERSCAN, (parent, dialog) ->
110                 assertEquals(parent.getFrame(), dialog.getFrame())
111         );
112     }
113 
114     private static final int explicitDimension = 200;
115 
116     // The default gravity for dialogs should center them.
117     @Test
testExplicitSizeDefaultGravity()118     public void testExplicitSizeDefaultGravity() throws Exception {
119         doParentChildTest(TEST_EXPLICIT_SIZE, (parent, dialog) -> {
120             Rect contentFrame = parent.getContentFrame();
121             Rect expectedFrame = new Rect(
122                     contentFrame.left + (contentFrame.width() - explicitDimension) / 2,
123                     contentFrame.top + (contentFrame.height() - explicitDimension) / 2,
124                     contentFrame.left + (contentFrame.width() + explicitDimension) / 2,
125                     contentFrame.top + (contentFrame.height() + explicitDimension) / 2);
126             assertEquals(expectedFrame, dialog.getFrame());
127         });
128     }
129 
130     @Test
testExplicitSizeTopLeftGravity()131     public void testExplicitSizeTopLeftGravity() throws Exception {
132         doParentChildTest(TEST_EXPLICIT_SIZE_TOP_LEFT_GRAVITY, (parent, dialog) -> {
133             Rect contentFrame = parent.getContentFrame();
134             Rect expectedFrame = new Rect(
135                     contentFrame.left,
136                     contentFrame.top,
137                     contentFrame.left + explicitDimension,
138                     contentFrame.top + explicitDimension);
139             assertEquals(expectedFrame, dialog.getFrame());
140         });
141     }
142 
143     @Test
testExplicitSizeBottomRightGravity()144     public void testExplicitSizeBottomRightGravity() throws Exception {
145         doParentChildTest(TEST_EXPLICIT_SIZE_BOTTOM_RIGHT_GRAVITY, (parent, dialog) -> {
146             Rect contentFrame = parent.getContentFrame();
147             Rect expectedFrame = new Rect(
148                     contentFrame.left + contentFrame.width() - explicitDimension,
149                     contentFrame.top + contentFrame.height() - explicitDimension,
150                     contentFrame.left + contentFrame.width(),
151                     contentFrame.top + contentFrame.height());
152             assertEquals(expectedFrame, dialog.getFrame());
153         });
154     }
155 
156     // TODO(b/30127373): Commented out for now because it doesn't work. We end up insetting the
157     // decor on the bottom. I think this is a bug probably in the default dialog flags:
158     @Ignore
159     @Test
testOversizedDimensions()160     public void testOversizedDimensions() throws Exception {
161         doParentChildTest(TEST_OVER_SIZED_DIMENSIONS, (parent, dialog) ->
162                 // With the default flags oversize should result in clipping to
163                 // parent frame.
164                 assertEquals(parent.getContentFrame(), dialog.getFrame())
165         );
166     }
167 
168     // TODO(b/63993863) : Disabled pending public API to fetch maximum surface size.
169     static final int oversizedDimension = 5000;
170     // With FLAG_LAYOUT_NO_LIMITS  we should get the size we request, even if its much larger than
171     // the screen.
172     @Ignore
173     @Test
testOversizedDimensionsNoLimits()174     public void testOversizedDimensionsNoLimits() throws Exception {
175         // TODO(b/36890978): We only run this in fullscreen because of the
176         // unclear status of NO_LIMITS for non-child surfaces in MW modes
177         doFullscreenTest(TEST_OVER_SIZED_DIMENSIONS_NO_LIMITS, (parent, dialog) -> {
178             Rect contentFrame = parent.getContentFrame();
179             Rect expectedFrame = new Rect(contentFrame.left, contentFrame.top,
180                     contentFrame.left + oversizedDimension,
181                     contentFrame.top + oversizedDimension);
182             assertEquals(expectedFrame, dialog.getFrame());
183         });
184     }
185 
186     // If we request the MATCH_PARENT and a non-zero position, we wouldn't be
187     // able to fit all of our content, so we should be adjusted to just fit the
188     // content frame.
189     @Test
testExplicitPositionMatchParent()190     public void testExplicitPositionMatchParent() throws Exception {
191         doParentChildTest(TEST_EXPLICIT_POSITION_MATCH_PARENT, (parent, dialog) ->
192                 assertEquals(parent.getContentFrame(), dialog.getFrame())
193         );
194     }
195 
196     // Unless we pass NO_LIMITS in which case our requested position should
197     // be honored.
198     @Test
testExplicitPositionMatchParentNoLimits()199     public void testExplicitPositionMatchParentNoLimits() throws Exception {
200         final int explicitPosition = 100;
201         doParentChildTest(TEST_EXPLICIT_POSITION_MATCH_PARENT_NO_LIMITS, (parent, dialog) -> {
202             Rect contentFrame = parent.getContentFrame();
203             Rect expectedFrame = new Rect(contentFrame);
204             expectedFrame.offset(explicitPosition, explicitPosition);
205             assertEquals(expectedFrame, dialog.getFrame());
206         });
207     }
208 
209     // We run the two focus tests fullscreen only because switching to the
210     // docked stack will strip away focus from the task anyway.
211     @Test
testDialogReceivesFocus()212     public void testDialogReceivesFocus() throws Exception {
213         doFullscreenTest(TEST_MATCH_PARENT, (parent, dialog) ->
214                 assertEquals(dialog.getName(), mAmWmState.getWmState().getFocusedWindow())
215         );
216     }
217 
218     @Test
testNoFocusDialog()219     public void testNoFocusDialog() throws Exception {
220         doFullscreenTest(TEST_NO_FOCUS, (parent, dialog) ->
221                 assertEquals(parent.getName(), mAmWmState.getWmState().getFocusedWindow())
222         );
223     }
224 
225     @Test
testMarginsArePercentagesOfContentFrame()226     public void testMarginsArePercentagesOfContentFrame() throws Exception {
227         float horizontalMargin = .25f;
228         float verticalMargin = .35f;
229         doParentChildTest(TEST_WITH_MARGINS, (parent, dialog) -> {
230             Rect frame = parent.getContentFrame();
231             Rect expectedFrame = new Rect(
232                     (int) (horizontalMargin * frame.width() + frame.left),
233                     (int) (verticalMargin * frame.height() + frame.top),
234                     (int) (horizontalMargin * frame.width() + frame.left) + explicitDimension,
235                     (int) (verticalMargin * frame.height() + frame.top) + explicitDimension);
236             assertEquals(expectedFrame, dialog.getFrame());
237         });
238     }
239 
240     @Test
testDialogPlacedAboveParent()241     public void testDialogPlacedAboveParent() throws Exception {
242         final WindowManagerState wmState = mAmWmState.getWmState();
243         doParentChildTest(TEST_MATCH_PARENT, (parent, dialog) ->
244                 // Not only should the dialog be higher, but it should be leave multiple layers of
245                 // space in between for DimLayers, etc...
246                 assertThat(wmState.getZOrder(dialog), greaterThan(wmState.getZOrder(parent)))
247         );
248     }
249 }
250