• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2025 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.safetycenter;
18 
19 import static android.safetycenter.SafetyEvent.SAFETY_EVENT_TYPE_SOURCE_STATE_CHANGED;
20 
21 import static com.google.common.truth.Truth.assertThat;
22 
23 import static org.mockito.ArgumentMatchers.any;
24 import static org.mockito.ArgumentMatchers.anyInt;
25 import static org.mockito.ArgumentMatchers.eq;
26 import static org.mockito.Mockito.doReturn;
27 import static org.mockito.Mockito.any;
28 import static org.mockito.Mockito.anyInt;
29 import static org.mockito.Mockito.anyString;
30 import static org.mockito.Mockito.never;
31 import static org.mockito.Mockito.spy;
32 import static org.mockito.Mockito.verify;
33 import static org.mockito.Mockito.when;
34 
35 import android.app.admin.DevicePolicyManager;
36 import android.content.ComponentName;
37 import android.content.Context;
38 import android.content.Intent;
39 import android.content.pm.ActivityInfo;
40 import android.content.pm.ApplicationInfo;
41 import android.content.pm.PackageManager;
42 import android.content.pm.ProviderInfo;
43 import android.content.pm.ResolveInfo;
44 import android.hardware.fingerprint.FingerprintManager;
45 import android.os.UserHandle;
46 import android.platform.test.annotations.RequiresFlagsDisabled;
47 import android.platform.test.annotations.RequiresFlagsEnabled;
48 import android.platform.test.flag.junit.CheckFlagsRule;
49 import android.platform.test.flag.junit.DeviceFlagsValueProvider;
50 import android.provider.DeviceConfig;
51 import android.provider.Settings;
52 import android.safetycenter.SafetyEvent;
53 import android.safetycenter.SafetySourceData;
54 import android.safetycenter.SafetySourceStatus;
55 
56 import androidx.test.core.app.ApplicationProvider;
57 import androidx.test.ext.junit.runners.AndroidJUnit4;
58 
59 import com.android.internal.widget.LockPatternUtils;
60 import com.android.settings.biometrics.activeunlock.ActiveUnlockStatusUtils;
61 import com.android.settings.flags.Flags;
62 import com.android.settings.testutils.FakeFeatureFactory;
63 import com.android.settings.testutils.ResourcesUtils;
64 
65 import org.junit.After;
66 import org.junit.Before;
67 import org.junit.Rule;
68 import org.junit.Test;
69 import org.junit.runner.RunWith;
70 import org.mockito.ArgumentCaptor;
71 import org.mockito.Mock;
72 import org.mockito.MockitoAnnotations;
73 
74 @RunWith(AndroidJUnit4.class)
75 public class WearSafetySourceTest {
76 
77     private static final ComponentName COMPONENT_NAME = new ComponentName("package", "class");
78     private static final UserHandle USER_HANDLE = new UserHandle(UserHandle.myUserId());
79     private static final SafetyEvent EVENT_SOURCE_STATE_CHANGED =
80             new SafetyEvent.Builder(SAFETY_EVENT_TYPE_SOURCE_STATE_CHANGED).build();
81     public static final String TARGET = "com.active.unlock.target";
82     public static final String PROVIDER = "com.active.unlock.provider";
83     public static final String TARGET_SETTING = "active_unlock_target";
84     public static final String PROVIDER_SETTING = "active_unlock_provider";
85     public static final String SUMMARY = "Wear Summary";
86 
87     @Rule
88     public final CheckFlagsRule mCheckFlagsRule = DeviceFlagsValueProvider.createCheckFlagsRule();
89 
90     private Context mApplicationContext;
91 
92     @Mock private PackageManager mPackageManager;
93     @Mock private DevicePolicyManager mDevicePolicyManager;
94     @Mock private FingerprintManager mFingerprintManager;
95     @Mock private LockPatternUtils mLockPatternUtils;
96     @Mock private SafetyCenterManagerWrapper mSafetyCenterManagerWrapper;
97 
98     @Before
setUp()99     public void setUp() {
100         MockitoAnnotations.initMocks(this);
101         mApplicationContext = spy(ApplicationProvider.getApplicationContext());
102         when(mApplicationContext.getPackageManager()).thenReturn(mPackageManager);
103         when(mPackageManager.hasSystemFeature(PackageManager.FEATURE_FINGERPRINT)).thenReturn(true);
104         when(mPackageManager.hasSystemFeature(PackageManager.FEATURE_FACE)).thenReturn(true);
105         when(mDevicePolicyManager.getProfileOwnerOrDeviceOwnerSupervisionComponent(USER_HANDLE))
106                 .thenReturn(COMPONENT_NAME);
107         when(mApplicationContext.getSystemService(Context.FINGERPRINT_SERVICE))
108                 .thenReturn(mFingerprintManager);
109         when(mApplicationContext.getSystemService(Context.DEVICE_POLICY_SERVICE))
110                 .thenReturn(mDevicePolicyManager);
111         FakeFeatureFactory featureFactory = FakeFeatureFactory.setupForTest();
112         when(featureFactory.securityFeatureProvider.getLockPatternUtils(mApplicationContext))
113                 .thenReturn(mLockPatternUtils);
114         doReturn(true).when(mLockPatternUtils).isSecure(anyInt());
115         SafetyCenterManagerWrapper.sInstance = mSafetyCenterManagerWrapper;
116     }
117 
118     @After
tearDown()119     public void tearDown() {
120         SafetyCenterManagerWrapper.sInstance = null;
121     }
122 
123     @Test
124     @RequiresFlagsEnabled(Flags.FLAG_BIOMETRICS_ONBOARDING_EDUCATION)
setSafetyData_whenSafetyCenterIsDisabled_doesNotSetData()125     public void setSafetyData_whenSafetyCenterIsDisabled_doesNotSetData() {
126         when(mSafetyCenterManagerWrapper.isEnabled(mApplicationContext)).thenReturn(false);
127 
128         WearSafetySource.setSafetySourceData(
129                 mApplicationContext, EVENT_SOURCE_STATE_CHANGED);
130 
131         verify(mSafetyCenterManagerWrapper, never())
132                 .setSafetySourceData(any(), any(), any(), any());
133     }
134 
135     @Test
136     @RequiresFlagsDisabled(Flags.FLAG_BIOMETRICS_ONBOARDING_EDUCATION)
setSafetySourceData_whenSeparateBiometricsFlagOff_setsNullData()137     public void setSafetySourceData_whenSeparateBiometricsFlagOff_setsNullData() {
138         when(mSafetyCenterManagerWrapper.isEnabled(mApplicationContext)).thenReturn(true);
139 
140         WearSafetySource.setSafetySourceData(
141                 mApplicationContext, EVENT_SOURCE_STATE_CHANGED);
142 
143         verify(mSafetyCenterManagerWrapper)
144                 .setSafetySourceData(
145                         any(), eq(WearSafetySource.SAFETY_SOURCE_ID), eq(null), any());
146     }
147 
148     @Test
149     @RequiresFlagsEnabled(Flags.FLAG_BIOMETRICS_ONBOARDING_EDUCATION)
setSafetySourceData_whenSafetyCenterIsEnabled_activeUnlockDisabled_setsNullData()150     public void setSafetySourceData_whenSafetyCenterIsEnabled_activeUnlockDisabled_setsNullData() {
151         disableActiveUnlock(mApplicationContext);
152         when(mSafetyCenterManagerWrapper.isEnabled(mApplicationContext)).thenReturn(true);
153 
154         WearSafetySource.setSafetySourceData(
155                 mApplicationContext, EVENT_SOURCE_STATE_CHANGED);
156 
157         verify(mSafetyCenterManagerWrapper)
158                 .setSafetySourceData(
159                         any(), eq(WearSafetySource.SAFETY_SOURCE_ID), eq(null), any());
160     }
161 
162     @Test
163     @RequiresFlagsEnabled(Flags.FLAG_BIOMETRICS_ONBOARDING_EDUCATION)
setSafetySourceData_setsDataWithCorrectSafetyEvent()164     public void setSafetySourceData_setsDataWithCorrectSafetyEvent() {
165         when(mSafetyCenterManagerWrapper.isEnabled(mApplicationContext)).thenReturn(true);
166 
167         WearSafetySource.setSafetySourceData(
168                 mApplicationContext, EVENT_SOURCE_STATE_CHANGED);
169 
170         verify(mSafetyCenterManagerWrapper)
171                 .setSafetySourceData(any(), any(), any(), eq(EVENT_SOURCE_STATE_CHANGED));
172     }
173 
174 
175     @Test
176     @RequiresFlagsEnabled(Flags.FLAG_BIOMETRICS_ONBOARDING_EDUCATION)
setSafetySourceData_withWearEnabled_whenWearEnrolled_setsData()177     public void setSafetySourceData_withWearEnabled_whenWearEnrolled_setsData() {
178         enableActiveUnlock(mApplicationContext);
179         when(mSafetyCenterManagerWrapper.isEnabled(mApplicationContext)).thenReturn(true);
180         when(mFingerprintManager.isHardwareDetected()).thenReturn(true);
181         when(mFingerprintManager.hasEnrolledFingerprints(anyInt())).thenReturn(false);
182 
183         WearSafetySource.setHasEnrolledForTesting(true);
184         WearSafetySource.setSummaryForTesting(SUMMARY);
185 
186         WearSafetySource.setSafetySourceData(
187                 mApplicationContext, EVENT_SOURCE_STATE_CHANGED);
188 
189         assertSafetySourceEnabledDataSet(
190                 ResourcesUtils.getResourcesString(mApplicationContext,
191                 "security_settings_activeunlock"),
192                 SUMMARY);
193     }
194 
195     @Test
196     @RequiresFlagsEnabled(Flags.FLAG_BIOMETRICS_ONBOARDING_EDUCATION)
setSafetySourceData_withWearEnabled_whenWearNotEnrolled_setsData()197     public void setSafetySourceData_withWearEnabled_whenWearNotEnrolled_setsData() {
198         enableActiveUnlock(mApplicationContext);
199         when(mSafetyCenterManagerWrapper.isEnabled(mApplicationContext)).thenReturn(true);
200         when(mFingerprintManager.isHardwareDetected()).thenReturn(true);
201         when(mFingerprintManager.hasEnrolledFingerprints(anyInt())).thenReturn(false);
202         when(mDevicePolicyManager.getKeyguardDisabledFeatures(COMPONENT_NAME)).thenReturn(0);
203 
204         WearSafetySource.setHasEnrolledForTesting(false);
205         WearSafetySource.setSummaryForTesting(SUMMARY);
206 
207         WearSafetySource.setSafetySourceData(
208                 mApplicationContext, EVENT_SOURCE_STATE_CHANGED);
209 
210         assertSafetySourceDisabledDataSet(
211                 ResourcesUtils.getResourcesString(mApplicationContext,
212                 "security_settings_activeunlock"),
213                 SUMMARY);
214     }
215 
disableActiveUnlock(Context context)216     private static void disableActiveUnlock(Context context) {
217         DeviceConfig.setProperty(
218                 DeviceConfig.NAMESPACE_REMOTE_AUTH,
219                 ActiveUnlockStatusUtils.CONFIG_FLAG_NAME,
220                 /* value= */ null,
221                 /* makeDefault=*/ false);
222         Settings.Secure.putString(context.getContentResolver(), TARGET_SETTING, null);
223         Settings.Secure.putString(context.getContentResolver(), PROVIDER_SETTING, null);
224     }
225 
enableActiveUnlock(Context context)226     private static void enableActiveUnlock(Context context) {
227         Settings.Secure.putString(
228                 context.getContentResolver(), TARGET_SETTING, TARGET);
229         Settings.Secure.putString(
230                 context.getContentResolver(), PROVIDER_SETTING, PROVIDER);
231 
232         PackageManager packageManager = context.getPackageManager();
233         ApplicationInfo applicationInfo = new ApplicationInfo();
234         applicationInfo.flags = ApplicationInfo.FLAG_SYSTEM;
235 
236         ResolveInfo resolveInfo = new ResolveInfo();
237         resolveInfo.activityInfo = new ActivityInfo();
238         resolveInfo.activityInfo.applicationInfo = applicationInfo;
239         when(packageManager.resolveActivity(any(), anyInt())).thenReturn(resolveInfo);
240 
241         ProviderInfo providerInfo = new ProviderInfo();
242         providerInfo.authority = PROVIDER;
243         providerInfo.applicationInfo = applicationInfo;
244         when(packageManager.resolveContentProvider(anyString(), any())).thenReturn(providerInfo);
245 
246         DeviceConfig.setProperty(
247                 DeviceConfig.NAMESPACE_REMOTE_AUTH,
248                 ActiveUnlockStatusUtils.CONFIG_FLAG_NAME,
249                 "unlock_intent_layout",
250                 false /* makeDefault */);
251     }
252 
assertSafetySourceDisabledDataSet(String expectedTitle, String expectedSummary)253     private void assertSafetySourceDisabledDataSet(String expectedTitle, String expectedSummary) {
254         ArgumentCaptor<SafetySourceData> captor = ArgumentCaptor.forClass(SafetySourceData.class);
255         verify(mSafetyCenterManagerWrapper)
256                 .setSafetySourceData(
257                         any(),
258                         eq(WearSafetySource.SAFETY_SOURCE_ID),
259                         captor.capture(),
260                         any());
261         SafetySourceData safetySourceData = captor.getValue();
262         SafetySourceStatus safetySourceStatus = safetySourceData.getStatus();
263 
264         assertThat(safetySourceStatus.getTitle().toString()).isEqualTo(expectedTitle);
265         assertThat(safetySourceStatus.getSummary().toString()).isEqualTo(expectedSummary);
266         assertThat(safetySourceStatus.isEnabled()).isTrue();
267         assertThat(safetySourceStatus.getSeverityLevel())
268                 .isEqualTo(SafetySourceData.SEVERITY_LEVEL_UNSPECIFIED);
269 
270         Intent clickIntent = safetySourceStatus.getPendingIntent().getIntent();
271         assertThat(clickIntent).isNotNull();
272         assertThat(clickIntent.getAction()).isEqualTo(TARGET);
273     }
274 
assertSafetySourceEnabledDataSet( String expectedTitle, String expectedSummary)275     private void assertSafetySourceEnabledDataSet(
276             String expectedTitle, String expectedSummary) {
277         ArgumentCaptor<SafetySourceData> captor = ArgumentCaptor.forClass(SafetySourceData.class);
278         verify(mSafetyCenterManagerWrapper)
279                 .setSafetySourceData(
280                         any(),
281                         eq(WearSafetySource.SAFETY_SOURCE_ID),
282                         captor.capture(),
283                         any());
284         SafetySourceData safetySourceData = captor.getValue();
285         SafetySourceStatus safetySourceStatus = safetySourceData.getStatus();
286 
287         assertThat(safetySourceStatus.getTitle().toString()).isEqualTo(expectedTitle);
288         assertThat(safetySourceStatus.getSummary().toString()).isEqualTo(expectedSummary);
289         assertThat(safetySourceStatus.isEnabled()).isTrue();
290         assertThat(safetySourceStatus.getSeverityLevel())
291                 .isEqualTo(SafetySourceData.SEVERITY_LEVEL_INFORMATION);
292         Intent clickIntent = safetySourceStatus.getPendingIntent().getIntent();
293         assertThat(clickIntent).isNotNull();
294     }
295 }
296