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.app.WindowConfiguration.WINDOWING_MODE_FREEFORM;
20 import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_PRIMARY;
21 import static android.server.wm.ActivityAndWindowManagersState.dpToPx;
22 import static android.server.wm.ComponentNameUtils.getWindowName;
23 import static android.server.wm.app.Components.BOTTOM_LEFT_LAYOUT_ACTIVITY;
24 import static android.server.wm.app.Components.BOTTOM_RIGHT_LAYOUT_ACTIVITY;
25 import static android.server.wm.app.Components.TEST_ACTIVITY;
26 import static android.server.wm.app.Components.TOP_LEFT_LAYOUT_ACTIVITY;
27 import static android.server.wm.app.Components.TOP_RIGHT_LAYOUT_ACTIVITY;
28 
29 import static org.junit.Assert.assertEquals;
30 import static org.junit.Assert.assertNotNull;
31 import static org.junit.Assume.assumeTrue;
32 
33 import android.content.ComponentName;
34 import android.graphics.Rect;
35 import android.platform.test.annotations.Presubmit;
36 import android.server.wm.WindowManagerState.Display;
37 import android.server.wm.WindowManagerState.WindowState;
38 
39 import org.junit.Test;
40 
41 import java.util.List;
42 
43 /**
44  * Build/Install/Run:
45  *     atest CtsWindowManagerDeviceTestCases:ManifestLayoutTests
46  */
47 @Presubmit
48 public class ManifestLayoutTests extends ActivityManagerTestBase {
49 
50     // Test parameters
51     private static final int DEFAULT_WIDTH_DP = 240;
52     private static final int DEFAULT_HEIGHT_DP = 160;
53     private static final float DEFAULT_WIDTH_FRACTION = 0.50f;
54     private static final float DEFAULT_HEIGHT_FRACTION = 0.70f;
55     private static final int MIN_WIDTH_DP = 100;
56     private static final int MIN_HEIGHT_DP = 80;
57 
58     private static final int GRAVITY_VER_CENTER = 0x01;
59     private static final int GRAVITY_VER_TOP    = 0x02;
60     private static final int GRAVITY_VER_BOTTOM = 0x04;
61     private static final int GRAVITY_HOR_CENTER = 0x10;
62     private static final int GRAVITY_HOR_LEFT   = 0x20;
63     private static final int GRAVITY_HOR_RIGHT  = 0x40;
64 
65     private Display mDisplay;
66     private WindowState mWindowState;
67 
68     @Test
testGravityAndDefaultSizeTopLeft()69     public void testGravityAndDefaultSizeTopLeft() throws Exception {
70         testLayout(GRAVITY_VER_TOP, GRAVITY_HOR_LEFT, false /*fraction*/);
71     }
72 
73     @Test
testGravityAndDefaultSizeTopRight()74     public void testGravityAndDefaultSizeTopRight() throws Exception {
75         testLayout(GRAVITY_VER_TOP, GRAVITY_HOR_RIGHT, true /*fraction*/);
76     }
77 
78     @Test
testGravityAndDefaultSizeBottomLeft()79     public void testGravityAndDefaultSizeBottomLeft() throws Exception {
80         testLayout(GRAVITY_VER_BOTTOM, GRAVITY_HOR_LEFT, true /*fraction*/);
81     }
82 
83     @Test
testGravityAndDefaultSizeBottomRight()84     public void testGravityAndDefaultSizeBottomRight() throws Exception {
85         testLayout(GRAVITY_VER_BOTTOM, GRAVITY_HOR_RIGHT, false /*fraction*/);
86     }
87 
88     @Test
testMinimalSizeFreeform()89     public void testMinimalSizeFreeform() throws Exception {
90         assumeTrue("Skipping test: no freeform support", supportsFreeform());
91 
92         testMinimalSize(WINDOWING_MODE_FREEFORM);
93     }
94 
95     @Test
96     @Presubmit
testMinimalSizeDocked()97     public void testMinimalSizeDocked() throws Exception {
98         assumeTrue("Skipping test: no multi-window support", supportsSplitScreenMultiWindow());
99 
100         testMinimalSize(WINDOWING_MODE_SPLIT_SCREEN_PRIMARY);
101     }
102 
testMinimalSize(int windowingMode)103     private void testMinimalSize(int windowingMode) throws Exception {
104         // Issue command to resize to <0,0,1,1>. We expect the size to be floored at
105         // MIN_WIDTH_DPxMIN_HEIGHT_DP.
106         if (windowingMode == WINDOWING_MODE_FREEFORM) {
107             launchActivity(BOTTOM_RIGHT_LAYOUT_ACTIVITY, WINDOWING_MODE_FREEFORM);
108             resizeActivityTask(BOTTOM_RIGHT_LAYOUT_ACTIVITY, 0, 0, 1, 1);
109         } else { // stackId == DOCKED_STACK_ID
110             launchActivitiesInSplitScreen(
111                     getLaunchActivityBuilder().setTargetActivity(BOTTOM_RIGHT_LAYOUT_ACTIVITY),
112                     getLaunchActivityBuilder().setTargetActivity(TEST_ACTIVITY));
113             resizeDockedStack(1, 1, 1, 1);
114         }
115         getDisplayAndWindowState(BOTTOM_RIGHT_LAYOUT_ACTIVITY, false);
116 
117         final int minWidth = dpToPx(MIN_WIDTH_DP, mDisplay.getDpi());
118         final int minHeight = dpToPx(MIN_HEIGHT_DP, mDisplay.getDpi());
119         final Rect containingRect = mWindowState.getContainingFrame();
120 
121         assertEquals("Min width is incorrect", minWidth, containingRect.width());
122         assertEquals("Min height is incorrect", minHeight, containingRect.height());
123     }
124 
testLayout( int vGravity, int hGravity, boolean fraction)125     private void testLayout(
126             int vGravity, int hGravity, boolean fraction) throws Exception {
127         assumeTrue("Skipping test: no freeform support", supportsFreeform());
128 
129         final ComponentName activityName;
130         if (vGravity == GRAVITY_VER_TOP) {
131             activityName = (hGravity == GRAVITY_HOR_LEFT) ? TOP_LEFT_LAYOUT_ACTIVITY
132                     : TOP_RIGHT_LAYOUT_ACTIVITY;
133         } else {
134             activityName = (hGravity == GRAVITY_HOR_LEFT) ? BOTTOM_LEFT_LAYOUT_ACTIVITY
135                     : BOTTOM_RIGHT_LAYOUT_ACTIVITY;
136         }
137 
138         // Launch in freeform stack
139         launchActivity(activityName, WINDOWING_MODE_FREEFORM);
140 
141         getDisplayAndWindowState(activityName, true);
142 
143         final Rect containingRect = mWindowState.getContainingFrame();
144         final Rect appRect = mDisplay.getAppRect();
145         final int expectedWidthPx, expectedHeightPx;
146         // Evaluate the expected window size in px. If we're using fraction dimensions,
147         // calculate the size based on the app rect size. Otherwise, convert the expected
148         // size in dp to px.
149         if (fraction) {
150             expectedWidthPx = (int) (appRect.width() * DEFAULT_WIDTH_FRACTION);
151             expectedHeightPx = (int) (appRect.height() * DEFAULT_HEIGHT_FRACTION);
152         } else {
153             final int densityDpi = mDisplay.getDpi();
154             expectedWidthPx = dpToPx(DEFAULT_WIDTH_DP, densityDpi);
155             expectedHeightPx = dpToPx(DEFAULT_HEIGHT_DP, densityDpi);
156         }
157 
158         verifyFrameSizeAndPosition(
159                 vGravity, hGravity, expectedWidthPx, expectedHeightPx, containingRect, appRect);
160     }
161 
getDisplayAndWindowState(ComponentName activityName, boolean checkFocus)162     private void getDisplayAndWindowState(ComponentName activityName, boolean checkFocus)
163             throws Exception {
164         final String windowName = getWindowName(activityName);
165 
166         mAmWmState.computeState(activityName);
167 
168         if (checkFocus) {
169             mAmWmState.assertFocusedWindow("Test window must be the front window.", windowName);
170         } else {
171             mAmWmState.assertVisibility(activityName, true);
172         }
173 
174         final List<WindowState> windowList =
175                 mAmWmState.getWmState().getMatchingVisibleWindowState(windowName);
176 
177         assertEquals("Should have exactly one window state for the activity.",
178                 1, windowList.size());
179 
180         mWindowState = windowList.get(0);
181         assertNotNull("Should have a valid window", mWindowState);
182 
183         mDisplay = mAmWmState.getWmState().getDisplay(mWindowState.getDisplayId());
184         assertNotNull("Should be on a display", mDisplay);
185     }
186 
verifyFrameSizeAndPosition( int vGravity, int hGravity, int expectedWidthPx, int expectedHeightPx, Rect containingFrame, Rect parentFrame)187     private void verifyFrameSizeAndPosition(
188             int vGravity, int hGravity, int expectedWidthPx, int expectedHeightPx,
189             Rect containingFrame, Rect parentFrame) {
190         assertEquals("Width is incorrect", expectedWidthPx, containingFrame.width());
191         assertEquals("Height is incorrect", expectedHeightPx, containingFrame.height());
192 
193         if (vGravity == GRAVITY_VER_TOP) {
194             assertEquals("Should be on the top", parentFrame.top, containingFrame.top);
195         } else if (vGravity == GRAVITY_VER_BOTTOM) {
196             assertEquals("Should be on the bottom", parentFrame.bottom, containingFrame.bottom);
197         }
198 
199         if (hGravity == GRAVITY_HOR_LEFT) {
200             assertEquals("Should be on the left", parentFrame.left, containingFrame.left);
201         } else if (hGravity == GRAVITY_HOR_RIGHT){
202             assertEquals("Should be on the right", parentFrame.right, containingFrame.right);
203         }
204     }
205 }
206