1 /*
2  * Copyright (C) 2019 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.provider.Settings.Global.DEVELOPMENT_ENABLE_FREEFORM_WINDOWS_SUPPORT;
20 import static android.provider.Settings.Global.DEVELOPMENT_ENABLE_NON_RESIZABLE_MULTI_WINDOW;
21 import static android.provider.Settings.Global.DEVELOPMENT_FORCE_DESKTOP_MODE_ON_EXTERNAL_DISPLAYS;
22 import static android.provider.Settings.Global.DEVELOPMENT_FORCE_RESIZABLE_ACTIVITIES;
23 import static android.provider.Settings.Global.DEVELOPMENT_WM_DISPLAY_SETTINGS_PATH;
24 
25 import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation;
26 
27 import static org.junit.Assert.assertEquals;
28 import static org.junit.Assert.assertTrue;
29 import static org.mockito.Mockito.atLeastOnce;
30 import static org.mockito.Mockito.clearInvocations;
31 import static org.mockito.Mockito.never;
32 import static org.mockito.Mockito.times;
33 import static org.mockito.Mockito.verify;
34 
35 import android.content.ContentResolver;
36 import android.net.Uri;
37 import android.platform.test.annotations.Presubmit;
38 import android.provider.Settings;
39 
40 import androidx.test.filters.SmallTest;
41 
42 import org.junit.Test;
43 import org.junit.runner.RunWith;
44 import org.mockito.ArgumentCaptor;
45 
46 import java.util.List;
47 
48 /**
49  * Test for {@link WindowManagerService.SettingsObserver}.
50  *
51  * Build/Install/Run:
52  *  atest WmTests:WindowManagerSettingsTests
53  */
54 @Presubmit
55 @SmallTest
56 @RunWith(WindowTestRunner.class)
57 public class WindowManagerSettingsTests extends WindowTestsBase {
58 
59     @Test
testForceDesktopModeOnExternalDisplays()60     public void testForceDesktopModeOnExternalDisplays() {
61         try (BoolSettingsSession forceDesktopModeSession = new
62                 BoolSettingsSession(DEVELOPMENT_FORCE_DESKTOP_MODE_ON_EXTERNAL_DISPLAYS)) {
63             final boolean forceDesktopMode = !forceDesktopModeSession.getSetting();
64             final Uri forceDesktopModeUri = forceDesktopModeSession.setSetting(forceDesktopMode);
65             mWm.mSettingsObserver.onChange(false, forceDesktopModeUri);
66 
67             assertEquals(mWm.mForceDesktopModeOnExternalDisplays, forceDesktopMode);
68         }
69     }
70 
71     @Test
testFreeformWindow()72     public void testFreeformWindow() {
73         try (BoolSettingsSession freeformWindowSession = new
74                 BoolSettingsSession(DEVELOPMENT_ENABLE_FREEFORM_WINDOWS_SUPPORT)) {
75             final boolean curFreeformWindow = freeformWindowSession.getSetting();
76             final boolean newFreeformWindow = !curFreeformWindow;
77             final Uri freeformWindowUri = freeformWindowSession.setSetting(newFreeformWindow);
78             mWm.mAtmService.mSupportsFreeformWindowManagement = curFreeformWindow;
79             mWm.mSettingsObserver.onChange(false, freeformWindowUri);
80 
81             assertEquals(mWm.mAtmService.mSupportsFreeformWindowManagement, newFreeformWindow);
82         }
83     }
84 
85     @Test
testFreeformWindow_valueChanged_updatesDisplaySettings()86     public void testFreeformWindow_valueChanged_updatesDisplaySettings() {
87         try (BoolSettingsSession freeformWindowSession = new
88                 BoolSettingsSession(DEVELOPMENT_ENABLE_FREEFORM_WINDOWS_SUPPORT)) {
89             final boolean curFreeformWindow = freeformWindowSession.getSetting();
90             final boolean newFreeformWindow = !curFreeformWindow;
91             final Uri freeformWindowUri = freeformWindowSession.setSetting(newFreeformWindow);
92             mWm.mAtmService.mSupportsFreeformWindowManagement = curFreeformWindow;
93             clearInvocations(mWm.mRoot);
94             mWm.mSettingsObserver.onChange(false, freeformWindowUri);
95 
96             // Changed value should update display settings.
97             verify(mWm.mRoot).onSettingsRetrieved();
98 
99             clearInvocations(mWm.mRoot);
100             mWm.mSettingsObserver.onChange(false, freeformWindowUri);
101 
102             // Unchanged value should not update display settings.
103             verify(mWm.mRoot, never()).onSettingsRetrieved();
104         }
105     }
106 
107     @Test
testForceResizableMode()108     public void testForceResizableMode() {
109         try (BoolSettingsSession forceResizableSession = new
110                 BoolSettingsSession(DEVELOPMENT_FORCE_RESIZABLE_ACTIVITIES)) {
111             final boolean forceResizableMode = !forceResizableSession.getSetting();
112             final Uri forceResizableUri = forceResizableSession.setSetting(forceResizableMode);
113 
114             mWm.mSettingsObserver.onChange(false, forceResizableUri);
115 
116             assertEquals(mWm.mAtmService.mForceResizableActivities, forceResizableMode);
117         }
118     }
119 
120     @Test
testSupportsNonResizableMultiWindow()121     public void testSupportsNonResizableMultiWindow() {
122         try (BoolSettingsSession supportsNonResizableMultiWindowSession = new
123                 BoolSettingsSession(DEVELOPMENT_ENABLE_NON_RESIZABLE_MULTI_WINDOW)) {
124             final boolean supportsNonResizableMultiWindow =
125                     !supportsNonResizableMultiWindowSession.getSetting();
126             final Uri supportsNonResizableMultiWindowUri = supportsNonResizableMultiWindowSession
127                     .setSetting(supportsNonResizableMultiWindow);
128             mWm.mSettingsObserver.onChange(false, supportsNonResizableMultiWindowUri);
129 
130             assertEquals(mWm.mAtmService.mDevEnableNonResizableMultiWindow,
131                     supportsNonResizableMultiWindow);
132         }
133     }
134 
135     @Test
testChangeBaseDisplaySettingsPath()136     public void testChangeBaseDisplaySettingsPath() {
137         try (StringSettingsSession baseDisplaySettingsPathSession = new
138                 StringSettingsSession(DEVELOPMENT_WM_DISPLAY_SETTINGS_PATH)) {
139             final String path = baseDisplaySettingsPathSession.getSetting() + "-test";
140             final Uri baseDisplaySettingsPathUri = baseDisplaySettingsPathSession.setSetting(path);
141 
142             clearInvocations(mWm.mRoot);
143             clearInvocations(mWm.mDisplayWindowSettings);
144             clearInvocations(mWm.mDisplayWindowSettingsProvider);
145 
146             mWm.mSettingsObserver.onChange(false /* selfChange */, baseDisplaySettingsPathUri);
147 
148             ArgumentCaptor<String> pathCaptor = ArgumentCaptor.forClass(String.class);
149             verify(mWm.mDisplayWindowSettingsProvider).setBaseSettingsFilePath(
150                     pathCaptor.capture());
151             assertEquals(path, pathCaptor.getValue());
152 
153             ArgumentCaptor<DisplayContent> captor =
154                     ArgumentCaptor.forClass(DisplayContent.class);
155             verify(mWm.mDisplayWindowSettings, times(mWm.mRoot.mChildren.size()))
156                     .applySettingsToDisplayLocked(captor.capture());
157             List<DisplayContent> configuredDisplays = captor.getAllValues();
158             for (DisplayContent dc : mWm.mRoot.mChildren) {
159                 assertTrue(configuredDisplays.contains(dc));
160             }
161 
162             verify(mWm.mRoot, atLeastOnce()).performSurfacePlacement();
163         }
164     }
165 
166     private class BoolSettingsSession implements AutoCloseable {
167 
168         private static final int SETTING_VALUE_OFF = 0;
169         private static final int SETTING_VALUE_ON = 1;
170         private final String mSettingName;
171         private final int mInitialValue;
172 
BoolSettingsSession(String name)173         BoolSettingsSession(String name) {
174             mSettingName = name;
175             mInitialValue = getSetting() ? SETTING_VALUE_ON : SETTING_VALUE_OFF;
176         }
177 
getSetting()178         boolean getSetting() {
179             return Settings.Global.getInt(getContentResolver(), mSettingName, 0) != 0;
180         }
181 
setSetting(boolean enable)182         Uri setSetting(boolean enable) {
183             Settings.Global.putInt(getContentResolver(), mSettingName,
184                     enable ? SETTING_VALUE_ON : SETTING_VALUE_OFF);
185             return Settings.Global.getUriFor(mSettingName);
186         }
187 
getContentResolver()188         private ContentResolver getContentResolver() {
189             return getInstrumentation().getTargetContext().getContentResolver();
190         }
191 
192         @Override
close()193         public void close() {
194             setSetting(mInitialValue == SETTING_VALUE_ON);
195         }
196     }
197 
198     private class StringSettingsSession implements AutoCloseable {
199         private final String mSettingName;
200         private final String mInitialValue;
201 
StringSettingsSession(String name)202         StringSettingsSession(String name) {
203             mSettingName = name;
204             mInitialValue = getSetting();
205         }
206 
getSetting()207         String getSetting() {
208             return Settings.Global.getString(getContentResolver(), mSettingName);
209         }
210 
setSetting(String value)211         Uri setSetting(String value) {
212             Settings.Global.putString(getContentResolver(), mSettingName, value);
213             return Settings.Global.getUriFor(mSettingName);
214         }
215 
getContentResolver()216         private ContentResolver getContentResolver() {
217             return getInstrumentation().getTargetContext().getContentResolver();
218         }
219 
220         @Override
close()221         public void close() {
222             setSetting(mInitialValue);
223         }
224     }
225 }
226