• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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.wm.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_NO_FOCUS;
28 import static android.server.wm.DialogFrameTestActivity.TEST_OVER_SIZED_DIMENSIONS;
29 import static android.server.wm.DialogFrameTestActivity.TEST_OVER_SIZED_DIMENSIONS_NO_LIMITS;
30 import static android.server.wm.DialogFrameTestActivity.TEST_WITH_MARGINS;
31 import static android.view.WindowInsets.Type.captionBar;
32 
33 import static androidx.test.InstrumentationRegistry.getInstrumentation;
34 
35 import static org.hamcrest.MatcherAssert.assertThat;
36 import static org.hamcrest.Matchers.greaterThan;
37 import static org.junit.Assert.assertEquals;
38 
39 import android.content.ComponentName;
40 import android.graphics.Insets;
41 import android.graphics.Rect;
42 import android.platform.test.annotations.AppModeFull;
43 import android.platform.test.annotations.Presubmit;
44 import android.server.wm.WindowManagerState.WindowState;
45 import android.view.WindowInsets;
46 
47 import androidx.test.rule.ActivityTestRule;
48 
49 import org.junit.Ignore;
50 import org.junit.Rule;
51 import org.junit.Test;
52 
53 import java.util.List;
54 
55 /**
56  * Build/Install/Run:
57  *     atest CtsWindowManagerDeviceTestCases:DialogFrameTests
58  *
59  * TODO: Consolidate this class with {@link ParentChildTestBase}.
60  */
61 @AppModeFull(reason = "Requires android.permission.MANAGE_ACTIVITY_TASKS")
62 @Presubmit
63 @android.server.wm.annotation.Group2
64 public class DialogFrameTests extends ParentChildTestBase<DialogFrameTestActivity> {
65 
66     private static final ComponentName DIALOG_FRAME_TEST_ACTIVITY = new ComponentName(
67             getInstrumentation().getContext(), DialogFrameTestActivity.class);
68     private Insets mContentInsets;
69 
70     @Rule
71     public final ActivityTestRule<DialogFrameTestActivity> mDialogTestActivity =
72             new ActivityTestRule<>(DialogFrameTestActivity.class, false /* initialTOuchMode */,
73                     false /* launchActivity */);
74 
75     @Override
activityName()76     ComponentName activityName() {
77         return DIALOG_FRAME_TEST_ACTIVITY;
78     }
79 
80     @Override
activityRule()81     ActivityTestRule<DialogFrameTestActivity> activityRule() {
82         return mDialogTestActivity;
83     }
84 
getSingleWindow(final String windowName)85     private WindowState getSingleWindow(final String windowName) {
86         final List<WindowState> windowList =
87                 mWmState.getMatchingVisibleWindowState(windowName);
88         assertThat(windowList.size(), greaterThan(0));
89         return windowList.get(0);
90     }
91 
92     @Override
doSingleTest(ParentChildTest t)93     void doSingleTest(ParentChildTest t) throws Exception {
94         mWmState.computeState(WaitForValidActivityState.forWindow(DIALOG_WINDOW_NAME));
95         WindowState dialog = getSingleWindow(DIALOG_WINDOW_NAME);
96         WindowState parent = getSingleWindow(getWindowName(activityName()));
97 
98         t.doTest(parent, dialog);
99     }
100 
101     // With Width and Height as MATCH_PARENT we should fill
102     // the same content frame as the main activity window
103     @Test
testMatchParentDialog()104     public void testMatchParentDialog() throws Exception {
105         doParentChildTest(TEST_MATCH_PARENT, (parent, dialog) -> { ;
106             assertEquals(getParentFrameWithInsets(parent), dialog.getFrame());
107         });
108     }
109 
110     private static final int explicitDimension = 200;
111 
112     // The default gravity for dialogs should center them.
113     @Test
testExplicitSizeDefaultGravity()114     public void testExplicitSizeDefaultGravity() throws Exception {
115         doParentChildTest(TEST_EXPLICIT_SIZE, (parent, dialog) -> {
116             Rect parentFrame = getParentFrameWithInsets(parent);
117             Rect expectedFrame = new Rect(
118                     parentFrame.left + (parentFrame.width() - explicitDimension) / 2,
119                     parentFrame.top + (parentFrame.height() - explicitDimension) / 2,
120                     parentFrame.left + (parentFrame.width() + explicitDimension) / 2,
121                     parentFrame.top + (parentFrame.height() + explicitDimension) / 2);
122             assertEquals(expectedFrame, dialog.getFrame());
123         });
124     }
125 
126     @Test
testExplicitSizeTopLeftGravity()127     public void testExplicitSizeTopLeftGravity() throws Exception {
128         doParentChildTest(TEST_EXPLICIT_SIZE_TOP_LEFT_GRAVITY, (parent, dialog) -> {
129             Rect parentFrame = getParentFrameWithInsets(parent);
130             Rect expectedFrame = new Rect(
131                     parentFrame.left,
132                     parentFrame.top,
133                     parentFrame.left + explicitDimension,
134                     parentFrame.top + explicitDimension);
135             assertEquals(expectedFrame, dialog.getFrame());
136         });
137     }
138 
139     @Test
testExplicitSizeBottomRightGravity()140     public void testExplicitSizeBottomRightGravity() throws Exception {
141         doParentChildTest(TEST_EXPLICIT_SIZE_BOTTOM_RIGHT_GRAVITY, (parent, dialog) -> {
142             Rect parentFrame = getParentFrameWithInsets(parent);
143             Rect expectedFrame = new Rect(
144                     parentFrame.left + parentFrame.width() - explicitDimension,
145                     parentFrame.top + parentFrame.height() - explicitDimension,
146                     parentFrame.left + parentFrame.width(),
147                     parentFrame.top + parentFrame.height());
148             assertEquals(expectedFrame, dialog.getFrame());
149         });
150     }
151 
152     // TODO(b/30127373): Commented out for now because it doesn't work. We end up insetting the
153     // decor on the bottom. I think this is a bug probably in the default dialog flags:
154     @Ignore
155     @Test
testOversizedDimensions()156     public void testOversizedDimensions() throws Exception {
157         doParentChildTest(TEST_OVER_SIZED_DIMENSIONS, (parent, dialog) ->
158                 // With the default flags oversize should result in clipping to
159                 // parent frame.
160                 assertEquals(getParentFrameWithInsets(parent), dialog.getFrame())
161         );
162     }
163 
164     // TODO(b/63993863) : Disabled pending public API to fetch maximum surface size.
165     static final int oversizedDimension = 5000;
166     // With FLAG_LAYOUT_NO_LIMITS  we should get the size we request, even if its much larger than
167     // the screen.
168     @Ignore
169     @Test
testOversizedDimensionsNoLimits()170     public void testOversizedDimensionsNoLimits() throws Exception {
171         // TODO(b/36890978): We only run this in fullscreen because of the
172         // unclear status of NO_LIMITS for non-child surfaces in MW modes
173         doFullscreenTest(TEST_OVER_SIZED_DIMENSIONS_NO_LIMITS, (parent, dialog) -> {
174             Rect parentFrame = getParentFrameWithInsets(parent);
175             Rect expectedFrame = new Rect(parentFrame.left, parentFrame.top,
176                     parentFrame.left + oversizedDimension,
177                     parentFrame.top + oversizedDimension);
178             assertEquals(expectedFrame, dialog.getFrame());
179         });
180     }
181 
182     // If we request the MATCH_PARENT and a non-zero position, we wouldn't be
183     // able to fit all of our content, so we should be adjusted to just fit the
184     // content frame.
185     @Test
testExplicitPositionMatchParent()186     public void testExplicitPositionMatchParent() throws Exception {
187         doParentChildTest(TEST_EXPLICIT_POSITION_MATCH_PARENT, (parent, dialog) ->
188                 assertEquals(getParentFrameWithInsets(parent), dialog.getFrame())
189         );
190     }
191 
192     // Unless we pass NO_LIMITS in which case our requested position should
193     // be honored.
194     @Test
testExplicitPositionMatchParentNoLimits()195     public void testExplicitPositionMatchParentNoLimits() throws Exception {
196         final int explicitPosition = 100;
197         doParentChildTest(TEST_EXPLICIT_POSITION_MATCH_PARENT_NO_LIMITS, (parent, dialog) -> {
198             Rect parentFrame = getParentFrameWithInsets(parent);
199             Rect expectedFrame = new Rect(parentFrame);
200             expectedFrame.offset(explicitPosition, explicitPosition);
201             assertEquals(expectedFrame, dialog.getFrame());
202         });
203     }
204 
205     // We run the two focus tests fullscreen only because switching to the
206     // docked stack will strip away focus from the task anyway.
207     @Test
testDialogReceivesFocus()208     public void testDialogReceivesFocus() throws Exception {
209         doFullscreenTest(TEST_MATCH_PARENT, (parent, dialog) ->
210                 assertEquals(dialog.getName(), mWmState.getFocusedWindow())
211         );
212     }
213 
214     @Test
testNoFocusDialog()215     public void testNoFocusDialog() throws Exception {
216         doFullscreenTest(TEST_NO_FOCUS, (parent, dialog) ->
217                 assertEquals(parent.getName(), mWmState.getFocusedWindow())
218         );
219     }
220 
221     @Test
testMarginsArePercentagesOfContentFrame()222     public void testMarginsArePercentagesOfContentFrame() throws Exception {
223         float horizontalMargin = .10f;
224         float verticalMargin = .15f;
225         doParentChildTest(TEST_WITH_MARGINS, (parent, dialog) -> {
226             Rect frame = getParentFrameWithInsets(parent);
227             Rect expectedFrame = new Rect(
228                     (int) (horizontalMargin * frame.width() + frame.left),
229                     (int) (verticalMargin * frame.height() + frame.top),
230                     (int) (horizontalMargin * frame.width() + frame.left) + explicitDimension,
231                     (int) (verticalMargin * frame.height() + frame.top) + explicitDimension);
232             assertEquals(expectedFrame, dialog.getFrame());
233         });
234     }
235 
236     @Test
testDialogPlacedAboveParent()237     public void testDialogPlacedAboveParent() throws Exception {
238         final WindowManagerState wmState = mWmState;
239         doParentChildTest(TEST_MATCH_PARENT, (parent, dialog) ->
240                 // Not only should the dialog be higher, but it should be leave multiple layers of
241                 // space in between for DimLayers, etc...
242                 assertThat(wmState.getZOrder(dialog), greaterThan(wmState.getZOrder(parent)))
243         );
244     }
245 
getParentFrameWithInsets(WindowState parent)246     private Rect getParentFrameWithInsets(WindowState parent) {
247         Rect parentFrame = parent.getFrame();
248         return inset(parentFrame, getActivitySystemInsets());
249     }
250 
getActivitySystemInsets()251     private Insets getActivitySystemInsets() {
252         getInstrumentation().waitForIdleSync();
253         getInstrumentation().runOnMainSync(() -> {
254             // Excluding caption bar from system bars to fix freeform windowing mode test failures.
255             // Non-freeform windowing modes will not be affected due to having zero caption bar.
256             final Insets insets = mDialogTestActivity
257                 .getActivity()
258                 .getWindow()
259                 .getDecorView()
260                 .getRootWindowInsets()
261                 .getInsets(WindowInsets.Type.systemBars() & ~captionBar());
262             mContentInsets = Insets.of(insets.left, insets.top, insets.right, insets.bottom);
263       });
264       return mContentInsets;
265     }
266 
inset(Rect original, Insets insets)267     private static Rect inset(Rect original, Insets insets) {
268         final int left = original.left + insets.left;
269         final int top = original.top + insets.top;
270         final int right = original.right - insets.right;
271         final int bottom = original.bottom - insets.bottom;
272         return new Rect(left, top, right, bottom);
273     }
274 }
275