1/*
2 * Copyright (C) 2017 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
17package com.android.server.wm;
18
19import org.junit.Test;
20
21import android.app.WindowConfiguration;
22import android.content.res.Configuration;
23import android.graphics.Rect;
24import android.platform.test.annotations.Presubmit;
25import android.support.test.filters.FlakyTest;
26import android.support.test.filters.SmallTest;
27import android.support.test.runner.AndroidJUnit4;
28import android.view.DisplayInfo;
29
30import static android.app.WindowConfiguration.ACTIVITY_TYPE_HOME;
31import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD;
32import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM;
33import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
34import static android.app.WindowConfiguration.WINDOW_CONFIG_APP_BOUNDS;
35import static android.app.WindowConfiguration.WINDOW_CONFIG_WINDOWING_MODE;
36import static android.content.pm.ActivityInfo.CONFIG_WINDOW_CONFIGURATION;
37import static org.junit.Assert.assertEquals;
38import static org.junit.Assert.assertNotEquals;
39import static org.junit.Assert.assertTrue;
40
41/**
42 * Test class to for {@link android.app.WindowConfiguration}.
43 *
44 * Build/Install/Run:
45 *  bit FrameworksServicesTests:com.android.server.wm.WindowConfigurationTests
46 */
47@SmallTest
48@FlakyTest(bugId = 74078662)
49@Presubmit
50@org.junit.runner.RunWith(AndroidJUnit4.class)
51public class WindowConfigurationTests extends WindowTestsBase {
52    private Rect mParentBounds;
53
54    @Override
55    public void setUp() throws Exception {
56        super.setUp();
57        mParentBounds = new Rect(10 /*left*/, 30 /*top*/, 80 /*right*/, 60 /*bottom*/);
58    }
59
60    /** Tests {@link android.app.WindowConfiguration#diff(WindowConfiguration, boolean)}. */
61    @Test
62    public void testDiff() {
63        final Configuration config1 = new Configuration();
64        final WindowConfiguration winConfig1 = config1.windowConfiguration;
65        final Configuration config2 = new Configuration();
66        final WindowConfiguration winConfig2 = config2.windowConfiguration;
67        final Configuration config3 = new Configuration();
68        final WindowConfiguration winConfig3 = config3.windowConfiguration;
69
70        winConfig1.setAppBounds(0, 1, 1, 0);
71        winConfig2.setAppBounds(1, 2, 2, 1);
72        winConfig3.setAppBounds(winConfig1.getAppBounds());
73
74
75        assertEquals(CONFIG_WINDOW_CONFIGURATION, config1.diff(config2));
76        assertEquals(0, config1.diffPublicOnly(config2));
77        assertEquals(WINDOW_CONFIG_APP_BOUNDS,
78                winConfig1.diff(winConfig2, false /* compareUndefined */));
79
80        winConfig2.setWindowingMode(WINDOWING_MODE_FREEFORM);
81        assertEquals(WINDOW_CONFIG_APP_BOUNDS | WINDOW_CONFIG_WINDOWING_MODE,
82                winConfig1.diff(winConfig2, false /* compareUndefined */));
83
84        assertEquals(0, config1.diff(config3));
85        assertEquals(0, config1.diffPublicOnly(config3));
86        assertEquals(0, winConfig1.diff(winConfig3, false /* compareUndefined */));
87    }
88
89    /** Tests {@link android.app.WindowConfiguration#compareTo(WindowConfiguration)}. */
90    @Test
91    public void testConfigurationCompareTo() throws Exception {
92        final Configuration blankConfig = new Configuration();
93        final WindowConfiguration blankWinConfig = new WindowConfiguration();
94
95        final Configuration config1 = new Configuration();
96        final WindowConfiguration winConfig1 = config1.windowConfiguration;
97        winConfig1.setAppBounds(1, 2, 3, 4);
98
99        final Configuration config2 = new Configuration(config1);
100        final WindowConfiguration winConfig2 = config2.windowConfiguration;
101
102        assertEquals(config1.compareTo(config2), 0);
103        assertEquals(winConfig1.compareTo(winConfig2), 0);
104
105        // Different windowing mode
106        winConfig2.setWindowingMode(WINDOWING_MODE_FREEFORM);
107        assertNotEquals(config1.compareTo(config2), 0);
108        assertNotEquals(winConfig1.compareTo(winConfig2), 0);
109        winConfig2.setWindowingMode(winConfig1.getWindowingMode());
110
111        // Different bounds
112        winConfig2.setAppBounds(0, 2, 3, 4);
113        assertNotEquals(config1.compareTo(config2), 0);
114        assertNotEquals(winConfig1.compareTo(winConfig2), 0);
115
116        // No bounds
117        assertEquals(config1.compareTo(blankConfig), -1);
118        assertEquals(winConfig1.compareTo(blankWinConfig), -1);
119
120        assertEquals(blankConfig.compareTo(config1), 1);
121        assertEquals(blankWinConfig.compareTo(winConfig1), 1);
122    }
123
124    @Test
125    public void testSetActivityType() throws Exception {
126        final WindowConfiguration config = new WindowConfiguration();
127        config.setActivityType(ACTIVITY_TYPE_HOME);
128        assertEquals(ACTIVITY_TYPE_HOME, config.getActivityType());
129
130        // Allowed to change from app process.
131        config.setActivityType(ACTIVITY_TYPE_STANDARD);
132        assertEquals(ACTIVITY_TYPE_STANDARD, config.getActivityType());
133    }
134
135    /** Ensures the configuration app bounds at the root level match the app dimensions. */
136    @Test
137    public void testAppBounds_RootConfigurationBounds() throws Exception {
138        final DisplayInfo info = mDisplayContent.getDisplayInfo();
139        info.appWidth = 1024;
140        info.appHeight = 768;
141
142        final Rect appBounds = sWm.computeNewConfiguration(
143                mDisplayContent.getDisplayId()).windowConfiguration.getAppBounds();
144        // The bounds should always be positioned in the top left.
145        assertEquals(appBounds.left, 0);
146        assertEquals(appBounds.top, 0);
147
148        // The bounds should equal the defined app width and height
149        assertEquals(appBounds.width(), info.appWidth);
150        assertEquals(appBounds.height(), info.appHeight);
151    }
152
153    /** Ensures that bounds are clipped to their parent. */
154    @Test
155    public void testAppBounds_BoundsClipping() throws Exception {
156        final Rect shiftedBounds = new Rect(mParentBounds);
157        shiftedBounds.offset(10, 10);
158        final Rect expectedBounds = new Rect(mParentBounds);
159        expectedBounds.intersect(shiftedBounds);
160        testStackBoundsConfiguration(WINDOWING_MODE_FULLSCREEN, mParentBounds, shiftedBounds,
161                expectedBounds);
162    }
163
164    /** Ensures that empty bounds are not propagated to the configuration. */
165    @Test
166    public void testAppBounds_EmptyBounds() throws Exception {
167        final Rect emptyBounds = new Rect();
168        testStackBoundsConfiguration(WINDOWING_MODE_FULLSCREEN, mParentBounds, emptyBounds,
169                null /*ExpectedBounds*/);
170    }
171
172    /** Ensures that bounds on freeform stacks are not clipped. */
173    @Test
174    public void testAppBounds_FreeFormBounds() throws Exception {
175        final Rect freeFormBounds = new Rect(mParentBounds);
176        freeFormBounds.offset(10, 10);
177        testStackBoundsConfiguration(WINDOWING_MODE_FREEFORM, mParentBounds, freeFormBounds,
178                freeFormBounds);
179    }
180
181    /** Ensures that fully contained bounds are not clipped. */
182    @Test
183    public void testAppBounds_ContainedBounds() throws Exception {
184        final Rect insetBounds = new Rect(mParentBounds);
185        insetBounds.inset(5, 5, 5, 5);
186        testStackBoundsConfiguration(
187                WINDOWING_MODE_FULLSCREEN, mParentBounds, insetBounds, insetBounds);
188    }
189
190    /** Ensures that full screen free form bounds are clipped */
191    @Test
192    public void testAppBounds_FullScreenFreeFormBounds() throws Exception {
193        final Rect fullScreenBounds = new Rect(0, 0, mDisplayInfo.logicalWidth,
194                mDisplayInfo.logicalHeight);
195        testStackBoundsConfiguration(WINDOWING_MODE_FULLSCREEN, mParentBounds, fullScreenBounds,
196                mParentBounds);
197    }
198
199    private void testStackBoundsConfiguration(int windowingMode, Rect parentBounds, Rect bounds,
200            Rect expectedConfigBounds) {
201        final StackWindowController stackController = createStackControllerOnStackOnDisplay(
202                        windowingMode, ACTIVITY_TYPE_STANDARD, mDisplayContent);
203
204        final Configuration parentConfig = mDisplayContent.getConfiguration();
205        parentConfig.windowConfiguration.setAppBounds(parentBounds);
206
207        final Configuration config = new Configuration();
208        final WindowConfiguration winConfig = config.windowConfiguration;
209        stackController.adjustConfigurationForBounds(bounds, null /*insetBounds*/,
210                new Rect() /*nonDecorBounds*/, new Rect() /*stableBounds*/, false /*overrideWidth*/,
211                false /*overrideHeight*/, mDisplayInfo.logicalDensityDpi, config, parentConfig,
212                windowingMode);
213        // Assert that both expected and actual are null or are equal to each other
214
215        assertEquals(expectedConfigBounds, winConfig.getAppBounds());
216    }
217
218}
219