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