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