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 17 package com.android.server.wm; 18 19 import static android.app.WindowConfiguration.ACTIVITY_TYPE_HOME; 20 import static android.app.WindowConfiguration.ACTIVITY_TYPE_RECENTS; 21 import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD; 22 import static android.app.WindowConfiguration.ACTIVITY_TYPE_UNDEFINED; 23 import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM; 24 import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN; 25 import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED; 26 import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE; 27 import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_PORTRAIT; 28 import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_REVERSE_LANDSCAPE; 29 import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_REVERSE_PORTRAIT; 30 import static android.content.res.Configuration.EMPTY; 31 import static org.junit.Assert.assertEquals; 32 import static org.junit.Assert.assertTrue; 33 34 import android.content.res.Configuration; 35 import android.platform.test.annotations.Presubmit; 36 import android.support.test.filters.SmallTest; 37 import android.support.test.runner.AndroidJUnit4; 38 import org.junit.Test; 39 import org.junit.runner.RunWith; 40 41 import java.util.ArrayList; 42 import java.util.List; 43 44 /** 45 * Test class for {@link ConfigurationContainer}. 46 * 47 * Build/Install/Run: 48 * bit FrameworksServicesTests:com.android.server.wm.ConfigurationContainerTests 49 */ 50 @SmallTest 51 @Presubmit 52 @RunWith(AndroidJUnit4.class) 53 public class ConfigurationContainerTests { 54 55 @Test 56 public void testConfigurationInit() throws Exception { 57 // Check root container initial config. 58 final TestConfigurationContainer root = new TestConfigurationContainer(); 59 assertEquals(EMPTY, root.getOverrideConfiguration()); 60 assertEquals(EMPTY, root.getMergedOverrideConfiguration()); 61 assertEquals(EMPTY, root.getConfiguration()); 62 63 // Check child initial config. 64 final TestConfigurationContainer child1 = root.addChild(); 65 assertEquals(EMPTY, child1.getOverrideConfiguration()); 66 assertEquals(EMPTY, child1.getMergedOverrideConfiguration()); 67 assertEquals(EMPTY, child1.getConfiguration()); 68 69 // Check child initial config if root has overrides. 70 final Configuration rootOverrideConfig = new Configuration(); 71 rootOverrideConfig.fontScale = 1.3f; 72 root.onOverrideConfigurationChanged(rootOverrideConfig); 73 final TestConfigurationContainer child2 = root.addChild(); 74 assertEquals(EMPTY, child2.getOverrideConfiguration()); 75 assertEquals(rootOverrideConfig, child2.getMergedOverrideConfiguration()); 76 assertEquals(rootOverrideConfig, child2.getConfiguration()); 77 78 // Check child initial config if root has parent config set. 79 final Configuration rootParentConfig = new Configuration(); 80 rootParentConfig.fontScale = 0.8f; 81 rootParentConfig.orientation = SCREEN_ORIENTATION_LANDSCAPE; 82 root.onConfigurationChanged(rootParentConfig); 83 final Configuration rootFullConfig = new Configuration(rootParentConfig); 84 rootFullConfig.updateFrom(rootOverrideConfig); 85 86 final TestConfigurationContainer child3 = root.addChild(); 87 assertEquals(EMPTY, child3.getOverrideConfiguration()); 88 assertEquals(rootOverrideConfig, child3.getMergedOverrideConfiguration()); 89 assertEquals(rootFullConfig, child3.getConfiguration()); 90 } 91 92 @Test 93 public void testConfigurationChangeOnAddRemove() throws Exception { 94 // Init root's config. 95 final TestConfigurationContainer root = new TestConfigurationContainer(); 96 final Configuration rootOverrideConfig = new Configuration(); 97 rootOverrideConfig.fontScale = 1.3f; 98 root.onOverrideConfigurationChanged(rootOverrideConfig); 99 100 // Init child's config. 101 final TestConfigurationContainer child = root.addChild(); 102 final Configuration childOverrideConfig = new Configuration(); 103 childOverrideConfig.densityDpi = 320; 104 child.onOverrideConfigurationChanged(childOverrideConfig); 105 final Configuration mergedOverrideConfig = new Configuration(root.getConfiguration()); 106 mergedOverrideConfig.updateFrom(childOverrideConfig); 107 108 // Check configuration update when child is removed from parent. 109 root.removeChild(child); 110 assertEquals(childOverrideConfig, child.getOverrideConfiguration()); 111 assertEquals(mergedOverrideConfig, child.getMergedOverrideConfiguration()); 112 assertEquals(mergedOverrideConfig, child.getConfiguration()); 113 114 // It may be paranoia... but let's check if parent's config didn't change after removal. 115 assertEquals(rootOverrideConfig, root.getOverrideConfiguration()); 116 assertEquals(rootOverrideConfig, root.getMergedOverrideConfiguration()); 117 assertEquals(rootOverrideConfig, root.getConfiguration()); 118 119 // Init different root 120 final TestConfigurationContainer root2 = new TestConfigurationContainer(); 121 final Configuration rootOverrideConfig2 = new Configuration(); 122 rootOverrideConfig2.fontScale = 1.1f; 123 root2.onOverrideConfigurationChanged(rootOverrideConfig2); 124 125 // Check configuration update when child is added to different parent. 126 mergedOverrideConfig.setTo(rootOverrideConfig2); 127 mergedOverrideConfig.updateFrom(childOverrideConfig); 128 root2.addChild(child); 129 assertEquals(childOverrideConfig, child.getOverrideConfiguration()); 130 assertEquals(mergedOverrideConfig, child.getMergedOverrideConfiguration()); 131 assertEquals(mergedOverrideConfig, child.getConfiguration()); 132 } 133 134 @Test 135 public void testConfigurationChangePropagation() throws Exception { 136 // Builds 3-level vertical hierarchy with one configuration container on each level. 137 // In addition to different overrides on each level, everyone in hierarchy will have one 138 // common overridden value - orientation; 139 140 // Init root's config. 141 final TestConfigurationContainer root = new TestConfigurationContainer(); 142 final Configuration rootOverrideConfig = new Configuration(); 143 rootOverrideConfig.fontScale = 1.3f; 144 rootOverrideConfig.orientation = SCREEN_ORIENTATION_REVERSE_LANDSCAPE; 145 root.onOverrideConfigurationChanged(rootOverrideConfig); 146 147 // Init children. 148 final TestConfigurationContainer child1 = root.addChild(); 149 final Configuration childOverrideConfig1 = new Configuration(); 150 childOverrideConfig1.densityDpi = 320; 151 childOverrideConfig1.orientation = SCREEN_ORIENTATION_LANDSCAPE; 152 child1.onOverrideConfigurationChanged(childOverrideConfig1); 153 154 final TestConfigurationContainer child2 = child1.addChild(); 155 final Configuration childOverrideConfig2 = new Configuration(); 156 childOverrideConfig2.screenWidthDp = 150; 157 childOverrideConfig2.orientation = SCREEN_ORIENTATION_PORTRAIT; 158 child2.onOverrideConfigurationChanged(childOverrideConfig2); 159 160 // Check configuration on all levels when root override is updated. 161 rootOverrideConfig.smallestScreenWidthDp = 200; 162 root.onOverrideConfigurationChanged(rootOverrideConfig); 163 164 final Configuration mergedOverrideConfig1 = new Configuration(rootOverrideConfig); 165 mergedOverrideConfig1.updateFrom(childOverrideConfig1); 166 final Configuration mergedConfig1 = new Configuration(mergedOverrideConfig1); 167 168 final Configuration mergedOverrideConfig2 = new Configuration(mergedOverrideConfig1); 169 mergedOverrideConfig2.updateFrom(childOverrideConfig2); 170 final Configuration mergedConfig2 = new Configuration(mergedOverrideConfig2); 171 172 assertEquals(rootOverrideConfig, root.getOverrideConfiguration()); 173 assertEquals(rootOverrideConfig, root.getMergedOverrideConfiguration()); 174 assertEquals(rootOverrideConfig, root.getConfiguration()); 175 176 assertEquals(childOverrideConfig1, child1.getOverrideConfiguration()); 177 assertEquals(mergedOverrideConfig1, child1.getMergedOverrideConfiguration()); 178 assertEquals(mergedConfig1, child1.getConfiguration()); 179 180 assertEquals(childOverrideConfig2, child2.getOverrideConfiguration()); 181 assertEquals(mergedOverrideConfig2, child2.getMergedOverrideConfiguration()); 182 assertEquals(mergedConfig2, child2.getConfiguration()); 183 184 // Check configuration on all levels when root parent config is updated. 185 final Configuration rootParentConfig = new Configuration(); 186 rootParentConfig.screenHeightDp = 100; 187 rootParentConfig.orientation = SCREEN_ORIENTATION_REVERSE_PORTRAIT; 188 root.onConfigurationChanged(rootParentConfig); 189 final Configuration mergedRootConfig = new Configuration(rootParentConfig); 190 mergedRootConfig.updateFrom(rootOverrideConfig); 191 192 mergedConfig1.setTo(mergedRootConfig); 193 mergedConfig1.updateFrom(mergedOverrideConfig1); 194 195 mergedConfig2.setTo(mergedConfig1); 196 mergedConfig2.updateFrom(mergedOverrideConfig2); 197 198 assertEquals(rootOverrideConfig, root.getOverrideConfiguration()); 199 assertEquals(rootOverrideConfig, root.getMergedOverrideConfiguration()); 200 assertEquals(mergedRootConfig, root.getConfiguration()); 201 202 assertEquals(childOverrideConfig1, child1.getOverrideConfiguration()); 203 assertEquals(mergedOverrideConfig1, child1.getMergedOverrideConfiguration()); 204 assertEquals(mergedConfig1, child1.getConfiguration()); 205 206 assertEquals(childOverrideConfig2, child2.getOverrideConfiguration()); 207 assertEquals(mergedOverrideConfig2, child2.getMergedOverrideConfiguration()); 208 assertEquals(mergedConfig2, child2.getConfiguration()); 209 } 210 211 @Test 212 public void testSetWindowingMode() throws Exception { 213 final TestConfigurationContainer root = new TestConfigurationContainer(); 214 root.setWindowingMode(WINDOWING_MODE_UNDEFINED); 215 final TestConfigurationContainer child = root.addChild(); 216 child.setWindowingMode(WINDOWING_MODE_FREEFORM); 217 assertEquals(WINDOWING_MODE_UNDEFINED, root.getWindowingMode()); 218 assertEquals(WINDOWING_MODE_FREEFORM, child.getWindowingMode()); 219 220 root.setWindowingMode(WINDOWING_MODE_FULLSCREEN); 221 assertEquals(WINDOWING_MODE_FULLSCREEN, root.getWindowingMode()); 222 assertEquals(WINDOWING_MODE_FREEFORM, child.getWindowingMode()); 223 } 224 225 @Test 226 public void testSetActivityType() throws Exception { 227 final TestConfigurationContainer root = new TestConfigurationContainer(); 228 root.setActivityType(ACTIVITY_TYPE_UNDEFINED); 229 final TestConfigurationContainer child = root.addChild(); 230 child.setActivityType(ACTIVITY_TYPE_STANDARD); 231 assertEquals(ACTIVITY_TYPE_UNDEFINED, root.getActivityType()); 232 assertEquals(ACTIVITY_TYPE_STANDARD, child.getActivityType()); 233 234 boolean gotException = false; 235 try { 236 // Can't change activity type once set. 237 child.setActivityType(ACTIVITY_TYPE_HOME); 238 } catch (IllegalStateException e) { 239 gotException = true; 240 } 241 assertTrue("Can't change activity type once set.", gotException); 242 243 // TODO: Commenting out for now until we figure-out a good way to test these rules that 244 // should only apply to system process. 245 /* 246 gotException = false; 247 try { 248 // Parent can't change child's activity type once set. 249 root.setActivityType(ACTIVITY_TYPE_HOME); 250 } catch (IllegalStateException e) { 251 gotException = true; 252 } 253 assertTrue("Parent can't change activity type once set.", gotException); 254 assertEquals(ACTIVITY_TYPE_HOME, root.getActivityType()); 255 256 final TestConfigurationContainer child2 = new TestConfigurationContainer(); 257 child2.setActivityType(ACTIVITY_TYPE_RECENTS); 258 259 gotException = false; 260 try { 261 // Can't re-parent to a different activity type. 262 root.addChild(child2); 263 } catch (IllegalStateException e) { 264 gotException = true; 265 } 266 assertTrue("Can't re-parent to a different activity type.", gotException); 267 */ 268 269 } 270 271 @Test 272 public void testRegisterConfigurationChangeListener() throws Exception { 273 final TestConfigurationContainer container = new TestConfigurationContainer(); 274 final TestConfigurationChangeListener listener = new TestConfigurationChangeListener(); 275 final Configuration config = new Configuration(); 276 config.windowConfiguration.setWindowingMode(WINDOWING_MODE_FREEFORM); 277 config.windowConfiguration.setAppBounds(10, 10, 10, 10); 278 container.onOverrideConfigurationChanged(config); 279 container.registerConfigurationChangeListener(listener); 280 // Assert listener got the current config. of the container after it was registered. 281 assertEquals(config, listener.mOverrideConfiguration); 282 // Assert listener gets changes to override configuration. 283 container.onOverrideConfigurationChanged(EMPTY); 284 assertEquals(EMPTY, listener.mOverrideConfiguration); 285 } 286 287 /** 288 * Contains minimal implementation of {@link ConfigurationContainer}'s abstract behavior needed 289 * for testing. 290 */ 291 private class TestConfigurationContainer 292 extends ConfigurationContainer<TestConfigurationContainer> { 293 private List<TestConfigurationContainer> mChildren = new ArrayList<>(); 294 private TestConfigurationContainer mParent; 295 296 TestConfigurationContainer addChild(TestConfigurationContainer childContainer) { 297 childContainer.mParent = this; 298 childContainer.onParentChanged(); 299 mChildren.add(childContainer); 300 return childContainer; 301 } 302 303 TestConfigurationContainer addChild() { 304 return addChild(new TestConfigurationContainer()); 305 } 306 307 void removeChild(TestConfigurationContainer child) { 308 child.mParent = null; 309 child.onParentChanged(); 310 } 311 312 @Override 313 protected int getChildCount() { 314 return mChildren.size(); 315 } 316 317 @Override 318 protected TestConfigurationContainer getChildAt(int index) { 319 return mChildren.get(index); 320 } 321 322 @Override 323 protected ConfigurationContainer getParent() { 324 return mParent; 325 } 326 } 327 328 private class TestConfigurationChangeListener implements ConfigurationContainerListener { 329 330 final Configuration mOverrideConfiguration = new Configuration(); 331 332 public void onOverrideConfigurationChanged(Configuration overrideConfiguration) { 333 mOverrideConfiguration.setTo(overrideConfiguration); 334 } 335 } 336 } 337