1 /* 2 * Copyright (C) 2024 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.settings.development.desktopexperience; 18 19 import static android.provider.Settings.Global.DEVELOPMENT_OVERRIDE_DESKTOP_MODE_FEATURES; 20 import static android.window.DesktopModeFlags.ToggleOverride.OVERRIDE_ON; 21 import static android.window.DesktopModeFlags.ToggleOverride.OVERRIDE_OFF; 22 import static android.window.DesktopModeFlags.ToggleOverride.OVERRIDE_UNSET; 23 24 import static com.google.common.truth.Truth.assertThat; 25 26 import static org.mockito.ArgumentMatchers.any; 27 import static org.mockito.Mockito.doReturn; 28 import static org.mockito.Mockito.spy; 29 import static org.mockito.Mockito.verify; 30 import static org.mockito.Mockito.when; 31 32 import android.content.Context; 33 import android.content.res.Resources; 34 import android.platform.test.annotations.DisableFlags; 35 import android.platform.test.annotations.EnableFlags; 36 import android.platform.test.flag.junit.SetFlagsRule; 37 import android.provider.Settings; 38 39 import androidx.fragment.app.FragmentActivity; 40 import androidx.fragment.app.FragmentManager; 41 import androidx.fragment.app.FragmentTransaction; 42 import androidx.preference.PreferenceScreen; 43 import androidx.preference.SwitchPreference; 44 import androidx.test.core.app.ApplicationProvider; 45 46 import com.android.internal.R; 47 import com.android.settings.development.DevelopmentSettingsDashboardFragment; 48 import com.android.settings.development.RebootConfirmationDialogFragment; 49 import com.android.window.flags.Flags; 50 51 import org.junit.Before; 52 import org.junit.Rule; 53 import org.junit.Test; 54 import org.junit.runner.RunWith; 55 import org.mockito.Mock; 56 import org.mockito.MockitoAnnotations; 57 import org.robolectric.Robolectric; 58 import org.robolectric.RobolectricTestRunner; 59 import org.robolectric.annotation.Config; 60 import org.robolectric.shadows.ShadowSystemProperties; 61 62 @RunWith(RobolectricTestRunner.class) 63 @Config(shadows = { 64 com.android.settings.testutils.shadow.ShadowFragment.class, 65 }) 66 @EnableFlags(Flags.FLAG_SHOW_DESKTOP_WINDOWING_DEV_OPTION) 67 @DisableFlags(Flags.FLAG_ENABLE_DESKTOP_MODE_THROUGH_DEV_OPTION) 68 public class DesktopModePreferenceControllerTest { 69 70 @Rule 71 public final SetFlagsRule mSetFlagsRule = new SetFlagsRule(); 72 73 @Mock 74 private SwitchPreference mPreference; 75 @Mock 76 private PreferenceScreen mScreen; 77 @Mock 78 private DevelopmentSettingsDashboardFragment mFragment; 79 @Mock 80 private FragmentManager mFragmentManager; 81 @Mock 82 private FragmentTransaction mTransaction; 83 84 private Resources mResources; 85 private Context mContext; 86 private DesktopModePreferenceController mController; 87 88 @Before setup()89 public void setup() { 90 MockitoAnnotations.initMocks(this); 91 92 FragmentActivity activity = spy(Robolectric.buildActivity( 93 FragmentActivity.class).create().get()); 94 95 mContext = spy(ApplicationProvider.getApplicationContext()); 96 doReturn(mTransaction).when(mFragmentManager).beginTransaction(); 97 doReturn(mFragmentManager).when(activity).getSupportFragmentManager(); 98 doReturn(activity).when(mFragment).requireActivity(); 99 100 mResources = spy(mContext.getResources()); 101 when(mContext.getResources()).thenReturn(mResources); 102 103 mController = new DesktopModePreferenceController(mContext, mFragment); 104 105 when(mScreen.findPreference(mController.getPreferenceKey())).thenReturn(mPreference); 106 mController.displayPreference(mScreen); 107 108 // Set desktop mode available 109 when(mResources.getBoolean(R.bool.config_isDesktopModeSupported)) 110 .thenReturn(true); 111 when(mResources 112 .getBoolean(com.android.internal.R.bool.config_canInternalDisplayHostDesktops)) 113 .thenReturn(true); 114 ShadowSystemProperties.override("persist.wm.debug.desktop_mode_enforce_device_restrictions", 115 "false"); 116 } 117 118 @Test 119 @DisableFlags(Flags.FLAG_SHOW_DESKTOP_EXPERIENCE_DEV_OPTION) isAvailable_desktopModeDevOptionNotSupported_returnsFalse()120 public void isAvailable_desktopModeDevOptionNotSupported_returnsFalse() { 121 mController = spy(mController); 122 // Dev option is not supported if Desktop mode is not supported 123 when(mResources.getBoolean(R.bool.config_isDesktopModeSupported)).thenReturn(false); 124 ShadowSystemProperties.override("persist.wm.debug.desktop_mode_enforce_device_restrictions", 125 "true"); 126 127 assertThat(mController.isAvailable()).isFalse(); 128 } 129 130 @Test 131 @DisableFlags(Flags.FLAG_SHOW_DESKTOP_EXPERIENCE_DEV_OPTION) isAvailable_desktopModeDevOptionSupported_returnsTrue()132 public void isAvailable_desktopModeDevOptionSupported_returnsTrue() { 133 mController = spy(mController); 134 135 assertThat(mController.isAvailable()).isTrue(); 136 } 137 138 @EnableFlags(Flags.FLAG_SHOW_DESKTOP_EXPERIENCE_DEV_OPTION) 139 @Test isAvailable_whenDesktopExperienceDevOptionIsEnabled_returnsFalse()140 public void isAvailable_whenDesktopExperienceDevOptionIsEnabled_returnsFalse() { 141 mController = spy(mController); 142 143 assertThat(mController.isAvailable()).isFalse(); 144 } 145 146 @Test onPreferenceChange_switchEnabled_putsSettingsOverrideOnAndTriggersRestart()147 public void onPreferenceChange_switchEnabled_putsSettingsOverrideOnAndTriggersRestart() { 148 mController.onPreferenceChange(mPreference, true /* new value */); 149 150 final int mode = Settings.Global.getInt(mContext.getContentResolver(), 151 DEVELOPMENT_OVERRIDE_DESKTOP_MODE_FEATURES, -1 /* default */); 152 assertThat(mode).isEqualTo(OVERRIDE_ON.getSetting()); 153 verify(mTransaction).add(any(RebootConfirmationDialogFragment.class), any()); 154 } 155 156 @Test onPreferenceChange_switchDisabled_putsSettingsOverrideOffAndTriggersRestart()157 public void onPreferenceChange_switchDisabled_putsSettingsOverrideOffAndTriggersRestart() { 158 mController.onPreferenceChange(mPreference, false /* new value */); 159 160 int mode = Settings.Global.getInt(mContext.getContentResolver(), 161 DEVELOPMENT_OVERRIDE_DESKTOP_MODE_FEATURES, -1 /* default */); 162 assertThat(mode).isEqualTo(OVERRIDE_OFF.getSetting()); 163 verify(mTransaction).add(any(RebootConfirmationDialogFragment.class), any()); 164 } 165 166 @Test updateState_overrideOn_checksPreference()167 public void updateState_overrideOn_checksPreference() { 168 Settings.Global.putInt(mContext.getContentResolver(), 169 DEVELOPMENT_OVERRIDE_DESKTOP_MODE_FEATURES, OVERRIDE_ON.getSetting()); 170 171 mController.updateState(mPreference); 172 173 verify(mPreference).setChecked(true); 174 } 175 176 @Test updateState_overrideOff_unchecksPreference()177 public void updateState_overrideOff_unchecksPreference() { 178 Settings.Global.putInt(mContext.getContentResolver(), 179 DEVELOPMENT_OVERRIDE_DESKTOP_MODE_FEATURES, OVERRIDE_OFF.getSetting()); 180 181 mController.updateState(mPreference); 182 183 verify(mPreference).setChecked(false); 184 } 185 186 @Test 187 @EnableFlags(Flags.FLAG_ENABLE_DESKTOP_WINDOWING_MODE) updateState_overrideUnset_defaultDevOptionStatusOn_checksPreference()188 public void updateState_overrideUnset_defaultDevOptionStatusOn_checksPreference() { 189 Settings.Global.putInt(mContext.getContentResolver(), 190 DEVELOPMENT_OVERRIDE_DESKTOP_MODE_FEATURES, OVERRIDE_UNSET.getSetting()); 191 192 mController.updateState(mPreference); 193 194 verify(mPreference).setChecked(true); 195 } 196 197 @Test 198 @DisableFlags(Flags.FLAG_ENABLE_DESKTOP_WINDOWING_MODE) updateState_overrideUnset_defaultDevOptionStatusOff_unchecksPreference()199 public void updateState_overrideUnset_defaultDevOptionStatusOff_unchecksPreference() { 200 Settings.Global.putInt(mContext.getContentResolver(), 201 DEVELOPMENT_OVERRIDE_DESKTOP_MODE_FEATURES, OVERRIDE_UNSET.getSetting()); 202 203 mController.updateState(mPreference); 204 205 verify(mPreference).setChecked(false); 206 } 207 208 @Test 209 @EnableFlags(Flags.FLAG_ENABLE_DESKTOP_WINDOWING_MODE) updateState_noOverride_defaultDevOptionStatusOn_checksPreference()210 public void updateState_noOverride_defaultDevOptionStatusOn_checksPreference() { 211 // Set no override 212 Settings.Global.putString(mContext.getContentResolver(), 213 DEVELOPMENT_OVERRIDE_DESKTOP_MODE_FEATURES, null); 214 215 mController.updateState(mPreference); 216 217 verify(mPreference).setChecked(true); 218 } 219 220 @Test 221 @DisableFlags(Flags.FLAG_ENABLE_DESKTOP_WINDOWING_MODE) updateState_noOverride_defaultDevOptionStatusOff_unchecksPreference()222 public void updateState_noOverride_defaultDevOptionStatusOff_unchecksPreference() { 223 // Set no override 224 Settings.Global.putString(mContext.getContentResolver(), 225 DEVELOPMENT_OVERRIDE_DESKTOP_MODE_FEATURES, null); 226 227 mController.updateState(mPreference); 228 229 verify(mPreference).setChecked(false); 230 } 231 232 @Test updateState_noOverride_noNewSettingsOverride()233 public void updateState_noOverride_noNewSettingsOverride() { 234 // Set no override 235 Settings.Global.putString(mContext.getContentResolver(), 236 DEVELOPMENT_OVERRIDE_DESKTOP_MODE_FEATURES, null); 237 238 mController.updateState(mPreference); 239 240 int mode = Settings.Global.getInt(mContext.getContentResolver(), 241 DEVELOPMENT_OVERRIDE_DESKTOP_MODE_FEATURES, -2 /* default */); 242 assertThat(mode).isEqualTo(-2); 243 } 244 245 @Test 246 @EnableFlags(Flags.FLAG_ENABLE_DESKTOP_WINDOWING_MODE) updateState_overrideUnknown_defaultDevOptionStatusOn_checksPreference()247 public void updateState_overrideUnknown_defaultDevOptionStatusOn_checksPreference() { 248 Settings.Global.putInt(mContext.getContentResolver(), 249 DEVELOPMENT_OVERRIDE_DESKTOP_MODE_FEATURES, -2); 250 251 mController.updateState(mPreference); 252 253 verify(mPreference).setChecked(true); 254 } 255 256 @Test 257 @DisableFlags(Flags.FLAG_ENABLE_DESKTOP_WINDOWING_MODE) updateState_overrideUnknown_defaultDevOptionStatusOff_unchecksPreference()258 public void updateState_overrideUnknown_defaultDevOptionStatusOff_unchecksPreference() { 259 Settings.Global.putInt(mContext.getContentResolver(), 260 DEVELOPMENT_OVERRIDE_DESKTOP_MODE_FEATURES, -2); 261 262 mController.updateState(mPreference); 263 264 verify(mPreference).setChecked(false); 265 } 266 267 @Test onDeveloperOptionsSwitchDisabled_putsSettingsOverrideOff()268 public void onDeveloperOptionsSwitchDisabled_putsSettingsOverrideOff() { 269 mController.onDeveloperOptionsSwitchDisabled(); 270 271 final int mode = Settings.Global.getInt(mContext.getContentResolver(), 272 DEVELOPMENT_OVERRIDE_DESKTOP_MODE_FEATURES, -2 /* default */); 273 assertThat(mode).isEqualTo(OVERRIDE_UNSET.getSetting()); 274 } 275 } 276