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 package com.android.settings.location; 17 18 import static com.google.common.truth.Truth.assertThat; 19 20 import static org.mockito.ArgumentMatchers.any; 21 import static org.mockito.ArgumentMatchers.anyInt; 22 import static org.mockito.ArgumentMatchers.eq; 23 import static org.mockito.Mockito.doReturn; 24 import static org.mockito.Mockito.spy; 25 import static org.mockito.Mockito.verify; 26 import static org.mockito.Mockito.when; 27 28 import android.app.admin.DevicePolicyManager; 29 import android.content.ComponentName; 30 import android.content.Context; 31 import android.content.pm.UserInfo; 32 import android.os.UserHandle; 33 import android.os.UserManager; 34 import android.platform.test.flag.junit.SetFlagsRule; 35 import android.provider.Settings; 36 import android.util.ArrayMap; 37 import android.util.ArraySet; 38 39 import androidx.lifecycle.LifecycleOwner; 40 import androidx.preference.Preference; 41 import androidx.preference.PreferenceCategory; 42 import androidx.preference.PreferenceScreen; 43 import androidx.test.core.app.ApplicationProvider; 44 45 import com.android.settings.testutils.shadow.ShadowDevicePolicyManager; 46 import com.android.settings.testutils.shadow.ShadowUserManager; 47 import com.android.settings.widget.RestrictedAppPreference; 48 import com.android.settingslib.core.lifecycle.Lifecycle; 49 50 import org.junit.Before; 51 import org.junit.Rule; 52 import org.junit.Test; 53 import org.junit.runner.RunWith; 54 import org.mockito.Answers; 55 import org.mockito.ArgumentCaptor; 56 import org.mockito.Mock; 57 import org.mockito.junit.MockitoJUnit; 58 import org.mockito.junit.MockitoRule; 59 import org.robolectric.RobolectricTestRunner; 60 import org.robolectric.annotation.Config; 61 62 import java.util.ArrayList; 63 import java.util.List; 64 import java.util.Map; 65 66 @RunWith(RobolectricTestRunner.class) 67 @Config(shadows = {ShadowUserManager.class, ShadowDevicePolicyManager.class}) 68 public class LocationInjectedServicesPreferenceControllerTest { 69 @Rule 70 public final MockitoRule mMockitoRule = MockitoJUnit.rule(); 71 @Rule 72 public final SetFlagsRule mSetFlagsRule = new SetFlagsRule(); 73 74 private static final String KEY_LOCATION_SERVICES = "location_service"; 75 76 @Mock(answer = Answers.RETURNS_DEEP_STUBS) 77 private LocationSettings mFragment; 78 @Mock 79 private PreferenceCategory mCategoryPrimary; 80 @Mock 81 private PreferenceScreen mScreen; 82 @Mock 83 private AppSettingsInjector mSettingsInjector; 84 @Mock 85 private DevicePolicyManager mDevicePolicyManager; 86 87 private Context mContext; 88 private LocationInjectedServicesPreferenceController mController; 89 private LifecycleOwner mLifecycleOwner; 90 private Lifecycle mLifecycle; 91 92 @Before setUp()93 public void setUp() { 94 mContext = spy(ApplicationProvider.getApplicationContext()); 95 mLifecycleOwner = () -> mLifecycle; 96 mLifecycle = new Lifecycle(mLifecycleOwner); 97 mController = spy( 98 new LocationInjectedServicesPreferenceController(mContext, KEY_LOCATION_SERVICES)); 99 when(mFragment.getSettingsLifecycle()).thenReturn(mLifecycle); 100 mController.init(mFragment); 101 mController.mInjector = mSettingsInjector; 102 final String key = mController.getPreferenceKey(); 103 when(mScreen.findPreference(key)).thenReturn(mCategoryPrimary); 104 when(mCategoryPrimary.getKey()).thenReturn(key); 105 when(mContext.getSystemService(Context.DEVICE_POLICY_SERVICE)) 106 .thenReturn(mDevicePolicyManager); 107 } 108 109 @Test onResume_shouldRegisterListener()110 public void onResume_shouldRegisterListener() { 111 mController.onResume(); 112 113 verify(mContext).registerReceiver(eq(mController.mInjectedSettingsReceiver), 114 eq(mController.INTENT_FILTER_INJECTED_SETTING_CHANGED), 115 anyInt()); 116 } 117 118 @Test onPause_shouldUnregisterListener()119 public void onPause_shouldUnregisterListener() { 120 mController.onResume(); 121 mController.onPause(); 122 123 verify(mContext).unregisterReceiver(mController.mInjectedSettingsReceiver); 124 } 125 126 @Test workProfileDisallowShareLocationOn_getParentUserLocationServicesOnly()127 public void workProfileDisallowShareLocationOn_getParentUserLocationServicesOnly() { 128 final int fakeWorkProfileId = 123; 129 ShadowUserManager.getShadow().setProfileIdsWithDisabled( 130 new int[]{UserHandle.myUserId(), fakeWorkProfileId}); 131 ShadowUserManager.getShadow().addProfile(new UserInfo(UserHandle.myUserId(), "", 0)); 132 ShadowUserManager.getShadow().addProfile(new UserInfo(fakeWorkProfileId, "", 133 UserInfo.FLAG_MANAGED_PROFILE | UserInfo.FLAG_PROFILE)); 134 135 // Mock RestrictedLockUtils.checkIfRestrictionEnforced and let it return non-null. 136 final List<UserManager.EnforcingUser> enforcingUsers = new ArrayList<>(); 137 enforcingUsers.add(new UserManager.EnforcingUser(fakeWorkProfileId, 138 UserManager.RESTRICTION_SOURCE_DEVICE_OWNER)); 139 final ComponentName componentName = new ComponentName("test", "test"); 140 // Ensure that RestrictedLockUtils.checkIfRestrictionEnforced doesn't return null. 141 ShadowUserManager.getShadow().setUserRestrictionSources( 142 UserManager.DISALLOW_SHARE_LOCATION, 143 UserHandle.of(fakeWorkProfileId), 144 enforcingUsers); 145 when(mDevicePolicyManager.getDeviceOwnerComponentOnAnyUser()).thenReturn(componentName); 146 147 mController.displayPreference(mScreen); 148 149 ArgumentCaptor<ArraySet<UserHandle>> profilesArgumentCaptor = 150 ArgumentCaptor.forClass(ArraySet.class); 151 verify(mSettingsInjector).getInjectedSettings( 152 any(Context.class), profilesArgumentCaptor.capture()); 153 assertThat(profilesArgumentCaptor.getValue()) 154 .doesNotContain(UserHandle.of(fakeWorkProfileId)); 155 } 156 157 @Test workProfileDisallowShareLocationOff_getAllUserLocationServices()158 public void workProfileDisallowShareLocationOff_getAllUserLocationServices() { 159 final int fakeWorkProfileId = 123; 160 ShadowUserManager.getShadow().setProfileIdsWithDisabled( 161 new int[]{UserHandle.myUserId(), fakeWorkProfileId}); 162 ShadowUserManager.getShadow().addProfile(new UserInfo(UserHandle.myUserId(), "", 0)); 163 ShadowUserManager.getShadow().addProfile(new UserInfo(fakeWorkProfileId, "", 164 UserInfo.FLAG_MANAGED_PROFILE | UserInfo.FLAG_PROFILE)); 165 166 // Mock RestrictedLockUtils.checkIfRestrictionEnforced and let it return null. 167 // Empty enforcing users. 168 final List<UserManager.EnforcingUser> enforcingUsers = new ArrayList<>(); 169 ShadowUserManager.getShadow().setUserRestrictionSources( 170 UserManager.DISALLOW_SHARE_LOCATION, 171 UserHandle.of(fakeWorkProfileId), 172 enforcingUsers); 173 174 mController.displayPreference(mScreen); 175 176 ArgumentCaptor<ArraySet<UserHandle>> profilesArgumentCaptor = 177 ArgumentCaptor.forClass(ArraySet.class); 178 verify(mSettingsInjector).getInjectedSettings( 179 any(Context.class), profilesArgumentCaptor.capture()); 180 assertThat(profilesArgumentCaptor.getValue()).contains(UserHandle.of(fakeWorkProfileId)); 181 } 182 183 @Test privateProfileDisallowShareLocationOn_getParentUserLocationServicesOnly()184 public void privateProfileDisallowShareLocationOn_getParentUserLocationServicesOnly() { 185 mSetFlagsRule.enableFlags( 186 android.os.Flags.FLAG_ALLOW_PRIVATE_PROFILE, 187 android.multiuser.Flags.FLAG_ENABLE_PRIVATE_SPACE_FEATURES, 188 android.multiuser.Flags.FLAG_HANDLE_INTERLEAVED_SETTINGS_FOR_PRIVATE_SPACE); 189 final int fakePrivateProfileId = 123; 190 ShadowUserManager.getShadow().setProfileIdsWithDisabled( 191 new int[]{UserHandle.myUserId(), fakePrivateProfileId}); 192 ShadowUserManager.getShadow().addProfile(new UserInfo(UserHandle.myUserId(), "", 0)); 193 ShadowUserManager.getShadow().setPrivateProfile(fakePrivateProfileId, "private", 0); 194 ShadowUserManager.getShadow().addUserProfile(UserHandle.of(fakePrivateProfileId)); 195 196 // Mock RestrictedLockUtils.checkIfRestrictionEnforced and let it return non-null. 197 final List<UserManager.EnforcingUser> enforcingUsers = new ArrayList<>(); 198 enforcingUsers.add(new UserManager.EnforcingUser(fakePrivateProfileId, 199 UserManager.RESTRICTION_SOURCE_DEVICE_OWNER)); 200 final ComponentName componentName = new ComponentName("test", "test"); 201 // Ensure that RestrictedLockUtils.checkIfRestrictionEnforced doesn't return null. 202 ShadowUserManager.getShadow().setUserRestrictionSources( 203 UserManager.DISALLOW_SHARE_LOCATION, 204 UserHandle.of(fakePrivateProfileId), 205 enforcingUsers); 206 when(mDevicePolicyManager.getDeviceOwnerComponentOnAnyUser()).thenReturn(componentName); 207 208 mController.displayPreference(mScreen); 209 210 ArgumentCaptor<ArraySet<UserHandle>> profilesArgumentCaptor = 211 ArgumentCaptor.forClass(ArraySet.class); 212 verify(mSettingsInjector).getInjectedSettings( 213 any(Context.class), profilesArgumentCaptor.capture()); 214 assertThat(profilesArgumentCaptor.getValue()) 215 .doesNotContain(UserHandle.of(fakePrivateProfileId)); 216 } 217 218 @Test privateProfileDisallowShareLocationOff_getAllUserLocationServices()219 public void privateProfileDisallowShareLocationOff_getAllUserLocationServices() { 220 mSetFlagsRule.enableFlags( 221 android.os.Flags.FLAG_ALLOW_PRIVATE_PROFILE, 222 android.multiuser.Flags.FLAG_ENABLE_PRIVATE_SPACE_FEATURES, 223 android.multiuser.Flags.FLAG_HANDLE_INTERLEAVED_SETTINGS_FOR_PRIVATE_SPACE); 224 final int fakePrivateProfileId = 123; 225 ShadowUserManager.getShadow().setProfileIdsWithDisabled( 226 new int[]{UserHandle.myUserId(), fakePrivateProfileId}); 227 ShadowUserManager.getShadow().addProfile(new UserInfo(UserHandle.myUserId(), "", 0)); 228 ShadowUserManager.getShadow().setPrivateProfile(fakePrivateProfileId, "private", 0); 229 ShadowUserManager.getShadow().addUserProfile(UserHandle.of(fakePrivateProfileId)); 230 231 // Mock RestrictedLockUtils.checkIfRestrictionEnforced and let it return null. 232 // Empty enforcing users. 233 final List<UserManager.EnforcingUser> enforcingUsers = new ArrayList<>(); 234 ShadowUserManager.getShadow().setUserRestrictionSources( 235 UserManager.DISALLOW_SHARE_LOCATION, 236 UserHandle.of(fakePrivateProfileId), 237 enforcingUsers); 238 239 mController.displayPreference(mScreen); 240 241 ArgumentCaptor<ArraySet<UserHandle>> profilesArgumentCaptor = 242 ArgumentCaptor.forClass(ArraySet.class); 243 verify(mSettingsInjector).getInjectedSettings( 244 any(Context.class), profilesArgumentCaptor.capture()); 245 assertThat(profilesArgumentCaptor.getValue()).contains(UserHandle.of(fakePrivateProfileId)); 246 } 247 248 @Test onLocationModeChanged_shouldRequestReloadInjectedSettigns()249 public void onLocationModeChanged_shouldRequestReloadInjectedSettigns() { 250 mController.onLocationModeChanged(Settings.Secure.LOCATION_MODE_BATTERY_SAVING, false); 251 252 verify(mSettingsInjector).reloadStatusMessages(); 253 } 254 255 @Test withUserRestriction_shouldDisableLocationAccuracy()256 public void withUserRestriction_shouldDisableLocationAccuracy() { 257 final List<Preference> preferences = new ArrayList<>(); 258 final RestrictedAppPreference pref = new RestrictedAppPreference(mContext, 259 UserManager.DISALLOW_CONFIG_LOCATION); 260 pref.setTitle("Location Accuracy"); 261 preferences.add(pref); 262 final Map<Integer, List<Preference>> map = new ArrayMap<>(); 263 map.put(UserHandle.myUserId(), preferences); 264 doReturn(map).when(mSettingsInjector) 265 .getInjectedSettings(any(Context.class), any(ArraySet.class)); 266 ShadowUserManager.getShadow().setProfileIdsWithDisabled(new int[]{UserHandle.myUserId()}); 267 268 final int userId = UserHandle.myUserId(); 269 List<UserManager.EnforcingUser> enforcingUsers = new ArrayList<>(); 270 enforcingUsers.add(new UserManager.EnforcingUser(userId, 271 UserManager.RESTRICTION_SOURCE_DEVICE_OWNER)); 272 ComponentName componentName = new ComponentName("test", "test"); 273 // Ensure that RestrictedLockUtils.checkIfRestrictionEnforced doesn't return null. 274 ShadowUserManager.getShadow().setUserRestrictionSources( 275 UserManager.DISALLOW_CONFIG_LOCATION, 276 UserHandle.of(userId), 277 enforcingUsers); 278 when(mDevicePolicyManager.getDeviceOwnerComponentOnAnyUser()).thenReturn(componentName); 279 280 mController.displayPreference(mScreen); 281 282 assertThat(pref.isEnabled()).isFalse(); 283 assertThat(pref.isDisabledByAdmin()).isTrue(); 284 } 285 } 286