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.settings.development; 18 19 import static com.google.common.truth.Truth.assertThat; 20 21 import static org.mockito.Mockito.doReturn; 22 import static org.mockito.Mockito.mock; 23 import static org.mockito.Mockito.spy; 24 import static org.mockito.Mockito.verify; 25 import static org.mockito.Mockito.when; 26 27 import android.content.Context; 28 import android.provider.SearchIndexableResource; 29 import android.provider.Settings; 30 31 import androidx.appcompat.app.AlertDialog; 32 import androidx.fragment.app.FragmentActivity; 33 34 import com.android.internal.logging.nano.MetricsProto; 35 import com.android.settings.R; 36 import com.android.settings.testutils.shadow.ShadowAlertDialogCompat; 37 import com.android.settings.testutils.shadow.ShadowUserManager; 38 import com.android.settings.widget.SettingsMainSwitchBar; 39 import com.android.settingslib.development.AbstractEnableAdbPreferenceController; 40 import com.android.settingslib.development.DevelopmentSettingsEnabler; 41 42 import org.junit.After; 43 import org.junit.Before; 44 import org.junit.Ignore; 45 import org.junit.Test; 46 import org.junit.runner.RunWith; 47 import org.mockito.MockitoAnnotations; 48 import org.robolectric.RobolectricTestRunner; 49 import org.robolectric.RuntimeEnvironment; 50 import org.robolectric.annotation.Config; 51 import org.robolectric.annotation.Implementation; 52 import org.robolectric.annotation.Implements; 53 import org.robolectric.shadow.api.Shadow; 54 import org.robolectric.shadows.androidx.fragment.FragmentController; 55 import org.robolectric.util.ReflectionHelpers; 56 57 import java.util.List; 58 59 @RunWith(RobolectricTestRunner.class) 60 @Config(shadows = { 61 ShadowAlertDialogCompat.class, 62 ShadowUserManager.class, 63 ShadowUserManager.class, 64 }) 65 public class DevelopmentSettingsDashboardFragmentTest { 66 67 private Context mContext; 68 private ShadowUserManager mShadowUserManager; 69 private DevelopmentSettingsDashboardFragment mDashboard; 70 71 @Before setUp()72 public void setUp() { 73 MockitoAnnotations.initMocks(this); 74 mContext = RuntimeEnvironment.application; 75 SettingsMainSwitchBar switchBar = new SettingsMainSwitchBar(mContext); 76 mDashboard = spy(new DevelopmentSettingsDashboardFragment()); 77 ReflectionHelpers.setField(mDashboard, "mSwitchBar", switchBar); 78 mShadowUserManager = Shadow.extract(mContext.getSystemService(Context.USER_SERVICE)); 79 mShadowUserManager.setIsAdminUser(true); 80 } 81 82 @After tearDown()83 public void tearDown() { 84 ShadowEnableDevelopmentSettingWarningDialog.reset(); 85 } 86 87 @Test shouldNotHaveHelpResource()88 public void shouldNotHaveHelpResource() { 89 assertThat(mDashboard.getHelpResource()).isEqualTo(0); 90 } 91 92 @Test shouldLogAsFeatureFlagPage()93 public void shouldLogAsFeatureFlagPage() { 94 assertThat(mDashboard.getMetricsCategory()) 95 .isEqualTo(MetricsProto.MetricsEvent.DEVELOPMENT); 96 } 97 98 @Test searchIndex_shouldIndexFromPrefXml()99 public void searchIndex_shouldIndexFromPrefXml() { 100 final List<SearchIndexableResource> index = 101 DevelopmentSettingsDashboardFragment.SEARCH_INDEX_DATA_PROVIDER 102 .getXmlResourcesToIndex(RuntimeEnvironment.application, true); 103 104 assertThat(index.size()).isEqualTo(1); 105 assertThat(index.get(0).xmlResId).isEqualTo(R.xml.development_settings); 106 } 107 108 @Test 109 @Ignore searchIndex_pageDisabledBySetting_shouldAddAllKeysToNonIndexable()110 public void searchIndex_pageDisabledBySetting_shouldAddAllKeysToNonIndexable() { 111 final Context appContext = RuntimeEnvironment.application; 112 DevelopmentSettingsEnabler.setDevelopmentSettingsEnabled(appContext, false); 113 114 final List<String> nonIndexableKeys = 115 DevelopmentSettingsDashboardFragment.SEARCH_INDEX_DATA_PROVIDER 116 .getNonIndexableKeys(appContext); 117 118 assertThat(nonIndexableKeys).contains("enable_adb"); 119 } 120 121 @Test 122 @Ignore searchIndex_pageDisabledForNonAdmin_shouldAddAllKeysToNonIndexable()123 public void searchIndex_pageDisabledForNonAdmin_shouldAddAllKeysToNonIndexable() { 124 final Context appContext = RuntimeEnvironment.application; 125 DevelopmentSettingsEnabler.setDevelopmentSettingsEnabled(appContext, true); 126 mShadowUserManager.setIsAdminUser(false); 127 mShadowUserManager.setIsDemoUser(false); 128 129 final List<String> nonIndexableKeys = 130 DevelopmentSettingsDashboardFragment.SEARCH_INDEX_DATA_PROVIDER 131 .getNonIndexableKeys(appContext); 132 133 assertThat(nonIndexableKeys).contains("enable_adb"); 134 } 135 136 @Test 137 @Ignore 138 @Config(shadows = { 139 ShadowPictureColorModePreferenceController.class, 140 ShadowAdbPreferenceController.class, 141 ShadowClearAdbKeysPreferenceController.class, 142 ShadowWirelessDebuggingPreferenceController.class 143 }) searchIndex_pageEnabled_shouldNotAddKeysToNonIndexable()144 public void searchIndex_pageEnabled_shouldNotAddKeysToNonIndexable() { 145 final Context appContext = RuntimeEnvironment.application; 146 DevelopmentSettingsEnabler.setDevelopmentSettingsEnabled(appContext, true); 147 148 final List<String> nonIndexableKeys = 149 DevelopmentSettingsDashboardFragment.SEARCH_INDEX_DATA_PROVIDER 150 .getNonIndexableKeys(appContext); 151 152 assertThat(nonIndexableKeys).doesNotContain("development_prefs_screen"); 153 } 154 155 @Test 156 @Ignore 157 @Config(shadows = ShadowEnableDevelopmentSettingWarningDialog.class) onSwitchChanged_sameState_shouldDoNothing()158 public void onSwitchChanged_sameState_shouldDoNothing() { 159 when(mDashboard.getContext()).thenReturn(mContext); 160 Settings.Global.putInt(mContext.getContentResolver(), 161 Settings.Global.DEVELOPMENT_SETTINGS_ENABLED, 0); 162 163 mDashboard.onCheckedChanged(null, false /* isChecked */); 164 assertThat(ShadowEnableDevelopmentSettingWarningDialog.mShown).isFalse(); 165 } 166 167 @Test 168 @Ignore 169 @Config(shadows = ShadowEnableDevelopmentSettingWarningDialog.class) onSwitchChanged_turnOn_shouldShowWarningDialog()170 public void onSwitchChanged_turnOn_shouldShowWarningDialog() { 171 when(mDashboard.getContext()).thenReturn(mContext); 172 Settings.Global.putInt(mContext.getContentResolver(), 173 Settings.Global.DEVELOPMENT_SETTINGS_ENABLED, 0); 174 175 mDashboard.onCheckedChanged(null, true /* isChecked */); 176 assertThat(ShadowEnableDevelopmentSettingWarningDialog.mShown).isTrue(); 177 } 178 179 @Test 180 @Ignore 181 @Config(shadows = ShadowEnableDevelopmentSettingWarningDialog.class) onSwitchChanged_turnOff_shouldTurnOff()182 public void onSwitchChanged_turnOff_shouldTurnOff() { 183 when(mDashboard.getContext()).thenReturn(mContext); 184 Settings.Global.putInt(mContext.getContentResolver(), 185 Settings.Global.DEVELOPMENT_SETTINGS_ENABLED, 1); 186 187 mDashboard.onCheckedChanged(null, false /* isChecked */); 188 189 assertThat(ShadowEnableDevelopmentSettingWarningDialog.mShown).isFalse(); 190 assertThat(DevelopmentSettingsEnabler.isDevelopmentSettingsEnabled(mContext)).isFalse(); 191 } 192 193 @Test 194 @Ignore 195 @Config(shadows = ShadowDisableDevSettingsDialogFragment.class) onSwitchChanged_turnOff_andOffloadIsNotDefaultValue_shouldShowWarningDialog()196 public void onSwitchChanged_turnOff_andOffloadIsNotDefaultValue_shouldShowWarningDialog() { 197 final BluetoothA2dpHwOffloadPreferenceController controller = 198 mock(BluetoothA2dpHwOffloadPreferenceController.class); 199 when(mDashboard.getContext()).thenReturn(mContext); 200 when(mDashboard.getDevelopmentOptionsController( 201 BluetoothA2dpHwOffloadPreferenceController.class)).thenReturn(controller); 202 when(controller.isDefaultValue()).thenReturn(false); 203 Settings.Global.putInt(mContext.getContentResolver(), 204 Settings.Global.DEVELOPMENT_SETTINGS_ENABLED, 1); 205 206 mDashboard.onCheckedChanged(null, false /* isChecked */); 207 208 AlertDialog dialog = ShadowAlertDialogCompat.getLatestAlertDialog(); 209 assertThat(dialog).isNotNull(); 210 ShadowAlertDialogCompat shadowDialog = ShadowAlertDialogCompat.shadowOf(dialog); 211 assertThat(shadowDialog.getTitle()).isEqualTo( 212 mContext.getString(R.string.bluetooth_disable_hw_offload_dialog_title)); 213 assertThat(shadowDialog.getMessage()).isEqualTo( 214 mContext.getString(R.string.bluetooth_disable_hw_offload_dialog_message)); 215 } 216 217 @Test onOemUnlockDialogConfirmed_shouldCallControllerOemConfirmed()218 public void onOemUnlockDialogConfirmed_shouldCallControllerOemConfirmed() { 219 final OemUnlockPreferenceController controller = mock(OemUnlockPreferenceController.class); 220 doReturn(controller).when(mDashboard) 221 .getDevelopmentOptionsController(OemUnlockPreferenceController.class); 222 mDashboard.onOemUnlockDialogConfirmed(); 223 verify(controller).onOemUnlockConfirmed(); 224 } 225 226 @Test onOemUnlockDialogConfirmed_shouldCallControllerOemDismissed()227 public void onOemUnlockDialogConfirmed_shouldCallControllerOemDismissed() { 228 final OemUnlockPreferenceController controller = mock(OemUnlockPreferenceController.class); 229 doReturn(controller).when(mDashboard) 230 .getDevelopmentOptionsController(OemUnlockPreferenceController.class); 231 mDashboard.onOemUnlockDialogDismissed(); 232 verify(controller).onOemUnlockDismissed(); 233 } 234 235 @Test onAdbDialogConfirmed_shouldCallControllerDialogConfirmed()236 public void onAdbDialogConfirmed_shouldCallControllerDialogConfirmed() { 237 final AdbPreferenceController controller = mock(AdbPreferenceController.class); 238 doReturn(controller).when(mDashboard) 239 .getDevelopmentOptionsController(AdbPreferenceController.class); 240 mDashboard.onEnableAdbDialogConfirmed(); 241 242 verify(controller).onAdbDialogConfirmed(); 243 } 244 245 @Test onAdbDialogDismissed_shouldCallControllerOemDismissed()246 public void onAdbDialogDismissed_shouldCallControllerOemDismissed() { 247 final AdbPreferenceController controller = mock(AdbPreferenceController.class); 248 doReturn(controller).when(mDashboard) 249 .getDevelopmentOptionsController(AdbPreferenceController.class); 250 mDashboard.onEnableAdbDialogDismissed(); 251 252 verify(controller).onAdbDialogDismissed(); 253 } 254 255 @Test onAdbClearKeysDialogConfirmed_shouldCallControllerDialogConfirmed()256 public void onAdbClearKeysDialogConfirmed_shouldCallControllerDialogConfirmed() { 257 final ClearAdbKeysPreferenceController controller = 258 mock(ClearAdbKeysPreferenceController.class); 259 doReturn(controller).when(mDashboard) 260 .getDevelopmentOptionsController(ClearAdbKeysPreferenceController.class); 261 mDashboard.onAdbClearKeysDialogConfirmed(); 262 263 verify(controller).onClearAdbKeysConfirmed(); 264 } 265 266 @Test onDisableLogPersistDialogConfirmed_shouldCallControllerDialogConfirmed()267 public void onDisableLogPersistDialogConfirmed_shouldCallControllerDialogConfirmed() { 268 final LogPersistPreferenceController controller = 269 mock(LogPersistPreferenceController.class); 270 doReturn(controller).when(mDashboard) 271 .getDevelopmentOptionsController(LogPersistPreferenceController.class); 272 mDashboard.onDisableLogPersistDialogConfirmed(); 273 274 verify(controller).onDisableLogPersistDialogConfirmed(); 275 } 276 277 @Test onDisableLogPersistDialogRejected_shouldCallControllerDialogRejected()278 public void onDisableLogPersistDialogRejected_shouldCallControllerDialogRejected() { 279 final LogPersistPreferenceController controller = 280 mock(LogPersistPreferenceController.class); 281 doReturn(controller).when(mDashboard) 282 .getDevelopmentOptionsController(LogPersistPreferenceController.class); 283 mDashboard.onDisableLogPersistDialogRejected(); 284 285 verify(controller).onDisableLogPersistDialogRejected(); 286 } 287 288 @Test shouldSkipForInitialSUW_returnTrue()289 public void shouldSkipForInitialSUW_returnTrue() { 290 assertThat(mDashboard.shouldSkipForInitialSUW()).isTrue(); 291 } 292 293 @Implements(EnableDevelopmentSettingWarningDialog.class) 294 public static class ShadowEnableDevelopmentSettingWarningDialog { 295 296 static boolean mShown; 297 reset()298 public static void reset() { 299 mShown = false; 300 } 301 302 @Implementation show(DevelopmentSettingsDashboardFragment host)303 protected static void show(DevelopmentSettingsDashboardFragment host) { 304 mShown = true; 305 } 306 } 307 308 @Implements(DisableDevSettingsDialogFragment.class) 309 public static class ShadowDisableDevSettingsDialogFragment { 310 311 @Implementation show(DevelopmentSettingsDashboardFragment host)312 public static void show(DevelopmentSettingsDashboardFragment host) { 313 DisableDevSettingsDialogFragment mFragment = 314 spy(DisableDevSettingsDialogFragment.newInstance()); 315 FragmentController.setupFragment(mFragment, FragmentActivity.class, 316 0 /* containerViewId */, null /* bundle */); 317 } 318 } 319 320 @Implements(PictureColorModePreferenceController.class) 321 public static class ShadowPictureColorModePreferenceController { 322 @Implementation isAvailable()323 protected boolean isAvailable() { 324 return true; 325 } 326 } 327 328 @Implements(AbstractEnableAdbPreferenceController.class) 329 public static class ShadowAdbPreferenceController { 330 @Implementation isAvailable()331 protected boolean isAvailable() { 332 return true; 333 } 334 } 335 336 @Implements(ClearAdbKeysPreferenceController.class) 337 public static class ShadowClearAdbKeysPreferenceController { 338 @Implementation isAvailable()339 protected boolean isAvailable() { 340 return true; 341 } 342 } 343 344 @Implements(WirelessDebuggingPreferenceController.class) 345 public static class ShadowWirelessDebuggingPreferenceController { 346 @Implementation isAvailable()347 protected boolean isAvailable() { 348 return true; 349 } 350 } 351 } 352