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.security; 18 19 import static com.google.common.truth.Truth.assertThat; 20 21 import static org.robolectric.Shadows.shadowOf; 22 23 import android.app.admin.DevicePolicyManager; 24 import android.content.Context; 25 import android.content.Intent; 26 import android.icu.text.MessageFormat; 27 import android.os.UserHandle; 28 import android.os.UserManager; 29 import android.provider.Settings; 30 31 import androidx.fragment.app.Fragment; 32 import androidx.test.core.app.ApplicationProvider; 33 34 import com.android.settings.R; 35 import com.android.settings.SettingsActivity; 36 import com.android.settings.testutils.shadow.ShadowLockPatternUtils; 37 import com.android.settingslib.search.SearchIndexableRaw; 38 import com.android.settingslib.widget.FooterPreference; 39 40 import org.junit.After; 41 import org.junit.Before; 42 import org.junit.Test; 43 import org.junit.runner.RunWith; 44 import org.robolectric.RobolectricTestRunner; 45 import org.robolectric.android.controller.ActivityController; 46 import org.robolectric.annotation.Config; 47 import org.robolectric.shadows.ShadowUserManager; 48 49 import java.util.List; 50 import java.util.function.Consumer; 51 52 @RunWith(RobolectricTestRunner.class) 53 @Config(shadows = ShadowLockPatternUtils.class) 54 public class ScreenPinningSettingsTest { 55 private static final String KEY_FOOTER = "screen_pinning_settings_screen_footer"; 56 private Context mContext; 57 private UserManager mUserManager; 58 59 @Before setUp()60 public void setUp() { 61 mContext = ApplicationProvider.getApplicationContext(); 62 mUserManager = mContext.getSystemService(UserManager.class); 63 } 64 65 @After tearDown()66 public void tearDown() { 67 ShadowLockPatternUtils.reset(); 68 } 69 70 @Test getDynamicRawDataToIndex_numericPassword_shouldIndexUnlockPinTitle()71 public void getDynamicRawDataToIndex_numericPassword_shouldIndexUnlockPinTitle() { 72 ShadowLockPatternUtils.setKeyguardStoredPasswordQuality( 73 DevicePolicyManager.PASSWORD_QUALITY_NUMERIC); 74 75 final List<SearchIndexableRaw> indexRaws = 76 ScreenPinningSettings.SEARCH_INDEX_DATA_PROVIDER.getDynamicRawDataToIndex( 77 mContext, /* enabled= */ true); 78 79 assertThat(indexRaws.size()).isEqualTo(1); 80 assertThat(indexRaws.get(0).title).isEqualTo( 81 mContext.getString(R.string.screen_pinning_unlock_pin)); 82 } 83 84 @Test getDynamicRawDataToIndex_alphabeticPassword_shouldIndexUnlockPasswordTitle()85 public void getDynamicRawDataToIndex_alphabeticPassword_shouldIndexUnlockPasswordTitle() { 86 ShadowLockPatternUtils.setKeyguardStoredPasswordQuality( 87 DevicePolicyManager.PASSWORD_QUALITY_ALPHABETIC); 88 89 final List<SearchIndexableRaw> indexRaws = 90 ScreenPinningSettings.SEARCH_INDEX_DATA_PROVIDER.getDynamicRawDataToIndex( 91 mContext, /* enabled= */ true); 92 93 assertThat(indexRaws.size()).isEqualTo(1); 94 assertThat(indexRaws.get(0).title).isEqualTo( 95 mContext.getString(R.string.screen_pinning_unlock_password)); 96 } 97 98 @Test getDynamicRawDataToIndex_patternPassword_shouldIndexUnlockPatternTitle()99 public void getDynamicRawDataToIndex_patternPassword_shouldIndexUnlockPatternTitle() { 100 ShadowLockPatternUtils.setKeyguardStoredPasswordQuality( 101 DevicePolicyManager.PASSWORD_QUALITY_SOMETHING); 102 ShadowLockPatternUtils.setIsLockPatternEnabled( 103 UserHandle.myUserId(), /* isLockPatternEnabled= */ true); 104 105 final List<SearchIndexableRaw> indexRaws = 106 ScreenPinningSettings.SEARCH_INDEX_DATA_PROVIDER.getDynamicRawDataToIndex( 107 mContext, /* enabled= */ true); 108 109 assertThat(indexRaws.size()).isEqualTo(1); 110 assertThat(indexRaws.get(0).title).isEqualTo( 111 mContext.getString(R.string.screen_pinning_unlock_pattern)); 112 } 113 114 @Test getDynamicRawDataToIndex_nonePassword_shouldIndexUnlockNoneTitle()115 public void getDynamicRawDataToIndex_nonePassword_shouldIndexUnlockNoneTitle() { 116 ShadowLockPatternUtils.setKeyguardStoredPasswordQuality( 117 DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED); 118 119 final List<SearchIndexableRaw> indexRaws = 120 ScreenPinningSettings.SEARCH_INDEX_DATA_PROVIDER.getDynamicRawDataToIndex( 121 mContext, /* enabled= */ true); 122 123 assertThat(indexRaws.size()).isEqualTo(1); 124 assertThat(indexRaws.get(0).title).isEqualTo( 125 mContext.getString(R.string.screen_pinning_unlock_none)); 126 } 127 128 @Test onCreate_lockToAppEnabled_guestModeSupported_verifyFooterText()129 public void onCreate_lockToAppEnabled_guestModeSupported_verifyFooterText() { 130 setupLockToAppState(/* enabled= */ true); 131 setupGuestModeState(/* supported= */ true); 132 133 launchFragmentAndRunTest(fragment -> { 134 FooterPreference footer = fragment.findPreference(KEY_FOOTER); 135 136 assertThat(footer.getSummary()) 137 .isEqualTo(getExpectedFooterText(/* guestModeSupported= */ true)); 138 }); 139 } 140 141 @Test onCreate_lockToAppEnabled_guestModeNotSupported_verifyFooterText()142 public void onCreate_lockToAppEnabled_guestModeNotSupported_verifyFooterText() { 143 setupLockToAppState(/* enabled= */ true); 144 setupGuestModeState(/* supported= */ false); 145 146 launchFragmentAndRunTest(fragment -> { 147 FooterPreference footer = fragment.findPreference(KEY_FOOTER); 148 149 assertThat(footer.getSummary()) 150 .isEqualTo(getExpectedFooterText(/* guestModeSupported= */ false)); 151 }); 152 } 153 154 @Test onCreate_lockToAppDisabled_guestModeSupported_verifyFooterText()155 public void onCreate_lockToAppDisabled_guestModeSupported_verifyFooterText() { 156 setupLockToAppState(/* enabled= */ false); 157 setupGuestModeState(/* supported= */ true); 158 159 launchFragmentAndRunTest(fragment -> { 160 FooterPreference footer = fragment.findPreference(KEY_FOOTER); 161 162 assertThat(footer.getSummary()) 163 .isEqualTo(getExpectedFooterText(/* guestModeSupported= */ true)); 164 }); 165 } 166 167 @Test onCreate_lockToAppDisabled_guestModeNotSupported_verifyFooterText()168 public void onCreate_lockToAppDisabled_guestModeNotSupported_verifyFooterText() { 169 setupLockToAppState(/* enabled= */ false); 170 setupGuestModeState(/* supported= */ false); 171 172 launchFragmentAndRunTest(fragment -> { 173 FooterPreference footer = fragment.findPreference(KEY_FOOTER); 174 175 assertThat(footer.getSummary()) 176 .isEqualTo(getExpectedFooterText(/* guestModeSupported= */ false)); 177 }); 178 } 179 getExpectedFooterText(boolean guestModeSupported)180 private CharSequence getExpectedFooterText(boolean guestModeSupported) { 181 final int stringResource = guestModeSupported 182 ? R.string.screen_pinning_guest_user_description 183 : R.string.screen_pinning_description; 184 return MessageFormat.format(mContext.getString(stringResource), 1, 2, 3); 185 } 186 setupLockToAppState(boolean enabled)187 private void setupLockToAppState(boolean enabled) { 188 Settings.System.putInt(mContext.getContentResolver(), Settings.System.LOCK_TO_APP_ENABLED, 189 enabled ? 1 : 0); 190 } 191 setupGuestModeState(boolean supported)192 private void setupGuestModeState(boolean supported) { 193 ShadowUserManager shadowUserManager = shadowOf(mUserManager); 194 shadowUserManager.setSupportsMultipleUsers(supported); 195 shadowUserManager.setUserRestriction( 196 UserHandle.of(UserHandle.myUserId()), UserManager.DISALLOW_USER_SWITCH, !supported); 197 } 198 launchFragmentAndRunTest(Consumer<ScreenPinningSettings> test)199 private void launchFragmentAndRunTest(Consumer<ScreenPinningSettings> test) { 200 Intent intent = new Intent(); 201 intent.putExtra(SettingsActivity.EXTRA_SHOW_FRAGMENT, 202 SecurityAdvancedSettings.class.getName()); 203 // ScreenPinningSettings is tightly coupled with the SettingsActivity 204 // In order to successfully launch the ScreenPinningSettings, have to use an indirect route 205 // to launch the SecurityAdvancedSetting first, then replace it with ScreenPinningSettings. 206 try (ActivityController<SettingsActivity> controller = 207 ActivityController.of(new SettingsActivity(), intent)) { 208 controller.create().start().resume(); 209 210 controller.get().getSupportFragmentManager().beginTransaction().replace( 211 R.id.main_content, ScreenPinningSettings.class, null).commitNow(); 212 Fragment fragment = controller.get().getSupportFragmentManager() 213 .findFragmentById(R.id.main_content); 214 assertThat(fragment).isNotNull(); 215 assertThat(fragment).isInstanceOf(ScreenPinningSettings.class); 216 217 test.accept((ScreenPinningSettings) fragment); 218 } 219 } 220 } 221