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 android.Manifest.permission.WRITE_SECURE_SETTINGS; 19 import static com.google.common.truth.Truth.assertThat; 20 import static org.mockito.ArgumentMatchers.anyBoolean; 21 import static org.mockito.ArgumentMatchers.anyInt; 22 import static org.mockito.ArgumentMatchers.anyString; 23 import static org.mockito.ArgumentMatchers.argThat; 24 import static org.mockito.ArgumentMatchers.eq; 25 import static org.mockito.Mockito.doReturn; 26 import static org.mockito.Mockito.mock; 27 import static org.mockito.Mockito.reset; 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.app.ActivityManager; 33 import android.arch.lifecycle.LifecycleOwner; 34 import android.content.Context; 35 import android.content.Intent; 36 import android.content.pm.UserInfo; 37 import android.location.LocationManager; 38 import android.os.UserHandle; 39 import android.os.UserManager; 40 import android.provider.Settings; 41 import android.text.TextUtils; 42 43 import com.android.settings.testutils.SettingsRobolectricTestRunner; 44 import com.android.settings.testutils.shadow.ShadowSecureSettings; 45 import com.android.settingslib.core.lifecycle.Lifecycle; 46 import com.android.settingslib.wrapper.LocationManagerWrapper; 47 48 import org.junit.Before; 49 import org.junit.Test; 50 import org.junit.runner.RunWith; 51 import org.mockito.ArgumentMatcher; 52 import org.mockito.Mock; 53 import org.mockito.MockitoAnnotations; 54 import org.robolectric.RuntimeEnvironment; 55 import org.robolectric.annotation.Config; 56 import org.robolectric.annotation.Implementation; 57 import org.robolectric.annotation.Implements; 58 59 import java.util.ArrayList; 60 import java.util.List; 61 62 @RunWith(SettingsRobolectricTestRunner.class) 63 @Config(shadows = { 64 ShadowSecureSettings.class, 65 LocationEnablerTest.ShadowLocationManagerWrapper.class}) 66 public class LocationEnablerTest { 67 68 @Mock 69 private UserManager mUserManager; 70 @Mock 71 private LocationEnabler.LocationModeChangeListener mListener; 72 73 private Context mContext; 74 private LocationEnabler mEnabler; 75 private LifecycleOwner mLifecycleOwner; 76 private Lifecycle mLifecycle; 77 78 @Before 79 public void setUp() { 80 MockitoAnnotations.initMocks(this); 81 mContext = spy(RuntimeEnvironment.application); 82 when(mContext.getSystemService(Context.USER_SERVICE)).thenReturn(mUserManager); 83 mLifecycleOwner = () -> mLifecycle; 84 mLifecycle = new Lifecycle(mLifecycleOwner); 85 mEnabler = spy(new LocationEnabler(mContext, mListener, mLifecycle)); 86 } 87 88 @Test 89 public void onResume_shouldSetActiveAndRegisterListener() { 90 mEnabler.onResume(); 91 92 verify(mContext).registerReceiver(eq(mEnabler.mReceiver), 93 eq(LocationEnabler.INTENT_FILTER_LOCATION_MODE_CHANGED)); 94 } 95 96 @Test 97 public void onResume_shouldRefreshLocationMode() { 98 mEnabler.onResume(); 99 100 verify(mEnabler).refreshLocationMode(); 101 } 102 103 @Test 104 public void onPause_shouldUnregisterListener() { 105 mEnabler.onPause(); 106 107 verify(mContext).unregisterReceiver(mEnabler.mReceiver); 108 } 109 110 @Test 111 public void onReceive_shouldRefreshLocationMode() { 112 mEnabler.onResume(); 113 reset(mListener); 114 mEnabler.mReceiver.onReceive(mContext, new Intent()); 115 116 verify(mListener).onLocationModeChanged(anyInt(), anyBoolean()); 117 } 118 119 @Test 120 public void isEnabled_locationOff_shouldReturnFalse() { 121 assertThat(mEnabler.isEnabled(Settings.Secure.LOCATION_MODE_OFF)).isFalse(); 122 } 123 124 @Test 125 public void isEnabled_restricted_shouldReturnFalse() { 126 when(mUserManager.hasUserRestriction(anyString())).thenReturn(true); 127 128 assertThat(mEnabler.isEnabled(Settings.Secure.LOCATION_MODE_OFF)).isFalse(); 129 } 130 131 @Test 132 public void isEnabled_locationNotRestricted_shouldReturnTrue() { 133 when(mUserManager.hasUserRestriction(anyString())).thenReturn(false); 134 135 assertThat(mEnabler.isEnabled(Settings.Secure.LOCATION_MODE_BATTERY_SAVING)).isTrue(); 136 } 137 138 @Test 139 public void refreshLocationMode_shouldCallOnLocationModeChanged() { 140 mEnabler.refreshLocationMode(); 141 142 verify(mListener).onLocationModeChanged(anyInt(), anyBoolean()); 143 } 144 145 @Test 146 public void setLocationMode_restricted_shouldSetCurrentMode() { 147 when(mUserManager.hasUserRestriction(anyString())).thenReturn(true); 148 Settings.Secure.putInt(mContext.getContentResolver(), 149 Settings.Secure.LOCATION_MODE, Settings.Secure.LOCATION_MODE_BATTERY_SAVING); 150 151 mEnabler.setLocationMode(Settings.Secure.LOCATION_MODE_HIGH_ACCURACY); 152 153 verify(mListener).onLocationModeChanged(Settings.Secure.LOCATION_MODE_BATTERY_SAVING, true); 154 } 155 156 @Test 157 public void setLocationMode_notRestricted_shouldUpdateSecureSettings() { 158 when(mUserManager.hasUserRestriction(anyString())).thenReturn(false); 159 Settings.Secure.putInt(mContext.getContentResolver(), 160 Settings.Secure.LOCATION_MODE, Settings.Secure.LOCATION_MODE_BATTERY_SAVING); 161 162 mEnabler.setLocationMode(Settings.Secure.LOCATION_MODE_HIGH_ACCURACY); 163 164 assertThat(Settings.Secure.getInt(mContext.getContentResolver(), 165 Settings.Secure.LOCATION_MODE, Settings.Secure.LOCATION_MODE_BATTERY_SAVING)) 166 .isEqualTo(Settings.Secure.LOCATION_MODE_HIGH_ACCURACY); 167 } 168 169 @Test 170 public void setLocationMode_notRestricted_shouldRefreshLocation() { 171 when(mUserManager.hasUserRestriction(anyString())).thenReturn(false); 172 Settings.Secure.putInt(mContext.getContentResolver(), 173 Settings.Secure.LOCATION_MODE, Settings.Secure.LOCATION_MODE_BATTERY_SAVING); 174 175 mEnabler.setLocationMode(Settings.Secure.LOCATION_MODE_HIGH_ACCURACY); 176 177 verify(mEnabler).refreshLocationMode(); 178 } 179 180 @Test 181 public void setLocationMode_notRestricted_shouldBroadcastUpdateAndSetChanger() { 182 when(mUserManager.hasUserRestriction(anyString())).thenReturn(false); 183 Settings.Secure.putInt(mContext.getContentResolver(), 184 Settings.Secure.LOCATION_MODE, Settings.Secure.LOCATION_MODE_BATTERY_SAVING); 185 mEnabler.setLocationMode(Settings.Secure.LOCATION_MODE_HIGH_ACCURACY); 186 187 verify(mContext).sendBroadcastAsUser( 188 argThat(actionMatches(LocationManager.MODE_CHANGING_ACTION)), 189 eq(UserHandle.of(ActivityManager.getCurrentUser())), 190 eq(WRITE_SECURE_SETTINGS)); 191 assertThat(Settings.Secure.getInt(mContext.getContentResolver(), 192 Settings.Secure.LOCATION_CHANGER, Settings.Secure.LOCATION_CHANGER_UNKNOWN)) 193 .isEqualTo(Settings.Secure.LOCATION_CHANGER_SYSTEM_SETTINGS); 194 } 195 196 @Test 197 public void setLocationEnabled_notRestricted_shouldRefreshLocation() { 198 when(mUserManager.hasUserRestriction(anyString())).thenReturn(false); 199 Settings.Secure.putInt(mContext.getContentResolver(), 200 Settings.Secure.LOCATION_MODE, Settings.Secure.LOCATION_MODE_OFF); 201 mEnabler.setLocationEnabled(true); 202 203 verify(mEnabler).refreshLocationMode(); 204 } 205 206 @Test 207 public void setLocationEnabled_notRestricted_shouldBroadcastUpdateAndSetChanger() { 208 when(mUserManager.hasUserRestriction(anyString())).thenReturn(false); 209 Settings.Secure.putInt(mContext.getContentResolver(), 210 Settings.Secure.LOCATION_MODE, Settings.Secure.LOCATION_MODE_OFF); 211 mEnabler.setLocationEnabled(true); 212 213 verify(mContext).sendBroadcastAsUser( 214 argThat(actionMatches(LocationManager.MODE_CHANGING_ACTION)), 215 eq(UserHandle.of(ActivityManager.getCurrentUser())), 216 eq(WRITE_SECURE_SETTINGS)); 217 assertThat(Settings.Secure.getInt(mContext.getContentResolver(), 218 Settings.Secure.LOCATION_CHANGER, Settings.Secure.LOCATION_CHANGER_UNKNOWN)) 219 .isEqualTo(Settings.Secure.LOCATION_CHANGER_SYSTEM_SETTINGS); 220 } 221 222 @Test 223 public void isManagedProfileRestrictedByBase_notManagedProfile_shouldReturnFalse() { 224 assertThat(mEnabler.isManagedProfileRestrictedByBase()).isFalse(); 225 } 226 227 @Test 228 public void isManagedProfileRestrictedByBase_notRestricted_shouldReturnFalse() { 229 mockManagedProfile(); 230 doReturn(false).when(mEnabler).hasShareLocationRestriction(anyInt()); 231 232 assertThat(mEnabler.isManagedProfileRestrictedByBase()).isFalse(); 233 } 234 235 @Test 236 public void isManagedProfileRestrictedByBase_hasManagedProfile_shouldReturnFalse() { 237 mockManagedProfile(); 238 doReturn(true).when(mEnabler).hasShareLocationRestriction(anyInt()); 239 240 assertThat(mEnabler.isManagedProfileRestrictedByBase()).isTrue(); 241 } 242 243 @Test 244 public void setRestriction_getShareLocationEnforcedAdmin_shouldReturnEnforcedAdmin() { 245 int userId = UserHandle.myUserId(); 246 List<UserManager.EnforcingUser> enforcingUsers = new ArrayList<>(); 247 // Add two enforcing users so that RestrictedLockUtils.checkIfRestrictionEnforced returns 248 // non-null. 249 enforcingUsers.add(new UserManager.EnforcingUser(userId, 250 UserManager.RESTRICTION_SOURCE_DEVICE_OWNER)); 251 enforcingUsers.add(new UserManager.EnforcingUser(userId, 252 UserManager.RESTRICTION_SOURCE_PROFILE_OWNER)); 253 when(mUserManager.getUserRestrictionSources( 254 UserManager.DISALLOW_CONFIG_LOCATION, UserHandle.of(userId))) 255 .thenReturn(enforcingUsers); 256 257 assertThat(mEnabler.getShareLocationEnforcedAdmin(userId) != null).isTrue(); 258 } 259 260 private void mockManagedProfile() { 261 final List<UserHandle> userProfiles = new ArrayList<>(); 262 final UserHandle userHandle = mock(UserHandle.class); 263 when(userHandle.getIdentifier()).thenReturn(5); 264 userProfiles.add(userHandle); 265 when(mUserManager.getUserProfiles()).thenReturn(userProfiles); 266 when(mUserManager.getUserHandle()).thenReturn(1); 267 when(mUserManager.getUserInfo(5)) 268 .thenReturn(new UserInfo(5, "user 5", UserInfo.FLAG_MANAGED_PROFILE)); 269 } 270 271 private static ArgumentMatcher<Intent> actionMatches(String expected) { 272 return intent -> TextUtils.equals(expected, intent.getAction()); 273 } 274 275 @Implements(value = LocationManagerWrapper.class) 276 public static class ShadowLocationManagerWrapper { 277 278 @Implementation 279 public void setLocationEnabledForUser(boolean enabled, UserHandle userHandle) { 280 // Do nothing 281 } 282 } 283 } 284