• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2016 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.managedprovisioning.preprovisioning;
17 
18 import static android.app.admin.DevicePolicyManager.ACTION_PROVISION_MANAGED_DEVICE;
19 import static android.app.admin.DevicePolicyManager.ACTION_PROVISION_MANAGED_DEVICE_FROM_TRUSTED_SOURCE;
20 import static android.app.admin.DevicePolicyManager.ACTION_PROVISION_MANAGED_PROFILE;
21 import static android.app.admin.DevicePolicyManager.CODE_MANAGED_USERS_NOT_SUPPORTED;
22 import static android.app.admin.DevicePolicyManager.CODE_OK;
23 import static android.nfc.NfcAdapter.ACTION_NDEF_DISCOVERED;
24 
25 import static com.android.managedprovisioning.common.Globals.ACTION_RESUME_PROVISIONING;
26 
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.eq;
31 import static org.mockito.Mockito.never;
32 import static org.mockito.Mockito.verify;
33 import static org.mockito.Mockito.verifyNoMoreInteractions;
34 import static org.mockito.Mockito.verifyZeroInteractions;
35 import static org.mockito.Mockito.when;
36 
37 import static java.util.Collections.emptyList;
38 
39 import android.app.ActivityManager;
40 import android.app.KeyguardManager;
41 import android.app.admin.DevicePolicyManager;
42 import android.content.ComponentName;
43 import android.content.Context;
44 import android.content.Intent;
45 import android.content.pm.ApplicationInfo;
46 import android.content.pm.PackageInfo;
47 import android.content.pm.PackageManager;
48 import android.content.res.Resources;
49 import android.graphics.drawable.VectorDrawable;
50 import android.os.UserHandle;
51 import android.os.UserManager;
52 import android.service.persistentdata.PersistentDataBlockManager;
53 import android.support.test.InstrumentationRegistry;
54 import android.support.test.filters.SmallTest;
55 import android.test.AndroidTestCase;
56 import android.text.TextUtils;
57 
58 import com.android.managedprovisioning.R;
59 import com.android.managedprovisioning.analytics.TimeLogger;
60 import com.android.managedprovisioning.common.IllegalProvisioningArgumentException;
61 import com.android.managedprovisioning.common.SettingsFacade;
62 import com.android.managedprovisioning.common.Utils;
63 import com.android.managedprovisioning.model.ProvisioningParams;
64 import com.android.managedprovisioning.model.WifiInfo;
65 import com.android.managedprovisioning.parser.MessageParser;
66 
67 import org.mockito.Mock;
68 import org.mockito.MockitoAnnotations;
69 
70 @SmallTest
71 public class PreProvisioningControllerTest extends AndroidTestCase {
72     private static final String TEST_MDM_PACKAGE = "com.test.mdm";
73     private static final String TEST_MDM_PACKAGE_LABEL = "Test MDM";
74     private static final ComponentName TEST_MDM_COMPONENT_NAME = new ComponentName(TEST_MDM_PACKAGE,
75             "com.test.mdm.DeviceAdmin");
76     private static final String TEST_BOGUS_PACKAGE = "com.test.bogus";
77     private static final String TEST_WIFI_SSID = "TestNet";
78     private static final String MP_PACKAGE_NAME = "com.android.managedprovisioning";
79     private static final int TEST_USER_ID = 10;
80 
81     @Mock
82     private Context mContext;
83     @Mock
84     Resources mResources;
85     @Mock
86     private DevicePolicyManager mDevicePolicyManager;
87     @Mock
88     private UserManager mUserManager;
89     @Mock
90     private PackageManager mPackageManager;
91     @Mock
92     private ActivityManager mActivityManager;
93     @Mock
94     private KeyguardManager mKeyguardManager;
95     @Mock
96     private PersistentDataBlockManager mPdbManager;
97     @Mock
98     private PreProvisioningController.Ui mUi;
99     @Mock
100     private MessageParser mMessageParser;
101     @Mock
102     private Utils mUtils;
103     @Mock
104     private SettingsFacade mSettingsFacade;
105     @Mock
106     private Intent mIntent;
107     @Mock
108     private EncryptionController mEncryptionController;
109     @Mock
110     private TimeLogger mTimeLogger;
111 
112     private ProvisioningParams mParams;
113 
114     private PreProvisioningController mController;
115 
116     @Override
setUp()117     public void setUp() throws PackageManager.NameNotFoundException {
118         // this is necessary for mockito to work
119         System.setProperty("dexmaker.dexcache", getContext().getCacheDir().toString());
120 
121         MockitoAnnotations.initMocks(this);
122 
123         when(mContext.getSystemService(Context.DEVICE_POLICY_SERVICE))
124                 .thenReturn(mDevicePolicyManager);
125         when(mContext.getSystemService(Context.USER_SERVICE)).thenReturn(mUserManager);
126         when(mContext.getPackageManager()).thenReturn(mPackageManager);
127         when(mContext.getSystemService(Context.ACTIVITY_SERVICE)).thenReturn(mActivityManager);
128         when(mContext.getSystemService(Context.KEYGUARD_SERVICE)).thenReturn(mKeyguardManager);
129         when(mContext.getSystemService(Context.PERSISTENT_DATA_BLOCK_SERVICE))
130                 .thenReturn(mPdbManager);
131         when(mContext.getPackageName()).thenReturn(MP_PACKAGE_NAME);
132         when(mContext.getResources()).thenReturn(
133                 InstrumentationRegistry.getTargetContext().getResources());
134 
135         when(mUserManager.getUserHandle()).thenReturn(TEST_USER_ID);
136 
137         when(mUtils.isSplitSystemUser()).thenReturn(false);
138         when(mUtils.isEncryptionRequired()).thenReturn(false);
139         when(mUtils.currentLauncherSupportsManagedProfiles(mContext)).thenReturn(true);
140         when(mUtils.alreadyHasManagedProfile(mContext)).thenReturn(-1);
141 
142         when(mPackageManager.getApplicationIcon(anyString())).thenReturn(new VectorDrawable());
143         when(mPackageManager.getApplicationLabel(any())).thenReturn(TEST_MDM_PACKAGE_LABEL);
144 
145         when(mKeyguardManager.inKeyguardRestrictedInputMode()).thenReturn(false);
146         when(mDevicePolicyManager.getStorageEncryptionStatus())
147                 .thenReturn(DevicePolicyManager.ENCRYPTION_STATUS_INACTIVE);
148         mController = new PreProvisioningController(mContext, mUi, mTimeLogger, mMessageParser,
149                 mUtils, mSettingsFacade, mEncryptionController);
150     }
151 
testManagedProfile()152     public void testManagedProfile() throws Exception {
153         // GIVEN an intent to provision a managed profile
154         prepareMocksForManagedProfileIntent(false);
155         // WHEN initiating provisioning
156         mController.initiateProvisioning(mIntent, null, TEST_MDM_PACKAGE);
157         // THEN the UI elements should be updated accordingly
158         verifyInitiateProfileOwnerUi();
159         // WHEN the user consents
160         mController.continueProvisioningAfterUserConsent();
161         // THEN start profile provisioning
162         verify(mUi).startProvisioning(mUserManager.getUserHandle(), mParams);
163         verify(mEncryptionController).cancelEncryptionReminder();
164         verifyNoMoreInteractions(mUi);
165     }
166 
testManagedProfile_provisioningNotAllowed()167     public void testManagedProfile_provisioningNotAllowed() throws Exception {
168         // GIVEN an intent to provision a managed profile, but provisioning mode is not allowed
169         prepareMocksForManagedProfileIntent(false);
170         when(mDevicePolicyManager.checkProvisioningPreCondition(
171                 ACTION_PROVISION_MANAGED_PROFILE, TEST_MDM_PACKAGE))
172                 .thenReturn(CODE_MANAGED_USERS_NOT_SUPPORTED);
173         // WHEN initiating provisioning
174         mController.initiateProvisioning(mIntent, null, TEST_MDM_PACKAGE);
175         // THEN show an error dialog
176         verify(mUi).showErrorAndClose(eq(R.string.cant_add_work_profile),
177                 eq(R.string.work_profile_cant_be_added_contact_admin), any());
178         verifyNoMoreInteractions(mUi);
179     }
180 
testManagedProfile_nullCallingPackage()181     public void testManagedProfile_nullCallingPackage() throws Exception {
182         // GIVEN a device that is not currently encrypted
183         prepareMocksForManagedProfileIntent(false);
184         // WHEN initiating provisioning
185         mController.initiateProvisioning(mIntent, null, null);
186         // THEN error is shown
187         verify(mUi).showErrorAndClose(eq(R.string.cant_set_up_device),
188                 eq(R.string.contact_your_admin_for_help), any(String.class));
189         verifyNoMoreInteractions(mUi);
190     }
191 
testManagedProfile_invalidCallingPackage()192     public void testManagedProfile_invalidCallingPackage() throws Exception {
193         // GIVEN a device that is not currently encrypted
194         prepareMocksForManagedProfileIntent(false);
195         // WHEN initiating provisioning
196         mController.initiateProvisioning(mIntent, null, "com.android.invalid.dpc");
197         // THEN error is shown
198         verify(mUi).showErrorAndClose(eq(R.string.cant_set_up_device),
199                 eq(R.string.contact_your_admin_for_help), any(String.class));
200         verifyNoMoreInteractions(mUi);
201     }
202 
testManagedProfile_withEncryption()203     public void testManagedProfile_withEncryption() throws Exception {
204         // GIVEN a device that is not currently encrypted
205         prepareMocksForManagedProfileIntent(false);
206         when(mUtils.isEncryptionRequired()).thenReturn(true);
207         // WHEN initiating managed profile provisioning
208         mController.initiateProvisioning(mIntent, null, TEST_MDM_PACKAGE);
209         // WHEN the user consents
210         mController.continueProvisioningAfterUserConsent();
211         // THEN the UI elements should be updated accordingly
212         verifyInitiateProfileOwnerUi();
213         // THEN show encryption screen
214         verify(mUi).requestEncryption(mParams);
215         verifyNoMoreInteractions(mUi);
216     }
217 
testManagedProfile_afterEncryption()218     public void testManagedProfile_afterEncryption() throws Exception {
219         // GIVEN managed profile provisioning continues after successful encryption. In this case
220         // we don't set the startedByTrustedSource flag.
221         prepareMocksForAfterEncryption(ACTION_PROVISION_MANAGED_PROFILE, false);
222         // WHEN initiating with a continuation intent
223         mController.initiateProvisioning(mIntent, null, MP_PACKAGE_NAME);
224         // THEN the UI elements should be updated accordingly
225         verifyInitiateProfileOwnerUi();
226         // WHEN the user consents
227         mController.continueProvisioningAfterUserConsent();
228         // THEN start profile provisioning
229         verify(mUi).startProvisioning(mUserManager.getUserHandle(), mParams);
230         verify(mEncryptionController).cancelEncryptionReminder();
231         verifyNoMoreInteractions(mUi);
232     }
233 
testManagedProfile_withExistingProfile()234     public void testManagedProfile_withExistingProfile() throws Exception {
235         // GIVEN a managed profile currently exist on the device
236         prepareMocksForManagedProfileIntent(false);
237         when(mUtils.alreadyHasManagedProfile(mContext)).thenReturn(TEST_USER_ID);
238         // WHEN initiating managed profile provisioning
239         mController.initiateProvisioning(mIntent, null, TEST_MDM_PACKAGE);
240         // THEN the UI elements should be updated accordingly and a dialog to remove the existing
241         // profile should be shown
242         verifyInitiateProfileOwnerUi();
243         verify(mUi).showDeleteManagedProfileDialog(any(), any(), eq(TEST_USER_ID));
244         // WHEN the user consents
245         mController.continueProvisioningAfterUserConsent();
246         // THEN start profile provisioning
247         verify(mUi).startProvisioning(mUserManager.getUserHandle(), mParams);
248         verify(mEncryptionController).cancelEncryptionReminder();
249         verifyNoMoreInteractions(mUi);
250     }
251 
testManagedProfile_badLauncher()252     public void testManagedProfile_badLauncher() throws Exception {
253         // GIVEN that the current launcher does not support managed profiles
254         prepareMocksForManagedProfileIntent(false);
255         when(mUtils.currentLauncherSupportsManagedProfiles(mContext)).thenReturn(false);
256         // WHEN initiating managed profile provisioning
257         mController.initiateProvisioning(mIntent, null, TEST_MDM_PACKAGE);
258         // THEN the UI elements should be updated accordingly
259         verifyInitiateProfileOwnerUi();
260         // WHEN the user consents
261         mController.continueProvisioningAfterUserConsent();
262         // THEN show a dialog indicating that the current launcher is invalid
263         verify(mUi).showCurrentLauncherInvalid();
264         verifyNoMoreInteractions(mUi);
265     }
266 
testManagedProfile_wrongPackage()267     public void testManagedProfile_wrongPackage() throws Exception {
268         // GIVEN that the provisioning intent tries to set a package different from the caller
269         // as owner of the profile
270         prepareMocksForManagedProfileIntent(false);
271         // WHEN initiating managed profile provisioning
272         mController.initiateProvisioning(mIntent, null, TEST_BOGUS_PACKAGE);
273         // THEN show an error dialog and do not continue
274         verify(mUi).showErrorAndClose(eq(R.string.cant_set_up_device),
275                 eq(R.string.contact_your_admin_for_help), any());
276         verifyNoMoreInteractions(mUi);
277     }
278 
testManagedProfile_frp()279     public void testManagedProfile_frp() throws Exception {
280         // GIVEN managed profile provisioning is invoked from SUW with FRP active
281         prepareMocksForManagedProfileIntent(false);
282         when(mSettingsFacade.isDeviceProvisioned(mContext)).thenReturn(false);
283         // setting the data block size to any number greater than 0 should invoke FRP.
284         when(mPdbManager.getDataBlockSize()).thenReturn(4);
285         // WHEN initiating managed profile provisioning
286         mController.initiateProvisioning(mIntent, null, TEST_MDM_PACKAGE);
287         // THEN show an error dialog and do not continue
288         verify(mUi).showErrorAndClose(eq(R.string.cant_set_up_device),
289                 eq(R.string.device_has_reset_protection_contact_admin), any());
290         verifyNoMoreInteractions(mUi);
291     }
292 
testCheckFactoryResetProtection_skipFrp()293     public void testCheckFactoryResetProtection_skipFrp() throws Exception {
294         // GIVEN managed profile provisioning is invoked from SUW with FRP active
295         when(mSettingsFacade.isDeviceProvisioned(mContext)).thenReturn(false);
296         // setting the data block size to any number greater than 0 to simulate FRP.
297         when(mPdbManager.getDataBlockSize()).thenReturn(4);
298         // GIVEN there is a persistent data package.
299         when(mContext.getResources()).thenReturn(mResources);
300         when(mResources.getString(anyInt())).thenReturn("test.persistent.data");
301         // GIVEN the persistent data package is a system app.
302         PackageInfo packageInfo = new PackageInfo();
303         ApplicationInfo applicationInfo = new ApplicationInfo();
304         applicationInfo.flags = ApplicationInfo.FLAG_SYSTEM;
305         packageInfo.applicationInfo = applicationInfo;
306         when(mPackageManager.getPackageInfo(eq("test.persistent.data"), anyInt()))
307                 .thenReturn(packageInfo);
308 
309         // WHEN factory reset protection is checked for trusted source device provisioning.
310         ProvisioningParams provisioningParams = createParams(true, false, null,
311                 ACTION_PROVISION_MANAGED_DEVICE_FROM_TRUSTED_SOURCE, TEST_MDM_PACKAGE);
312         boolean result = mController.checkFactoryResetProtection(
313                 provisioningParams, "test.persistent.data");
314 
315         // THEN the check is successful despite the FRP data presence.
316         assertTrue(result);
317     }
318 
testManagedProfile_skipEncryption()319     public void testManagedProfile_skipEncryption() throws Exception {
320         // GIVEN an intent to provision a managed profile with skip encryption
321         prepareMocksForManagedProfileIntent(true);
322         when(mUtils.isEncryptionRequired()).thenReturn(true);
323         // WHEN initiating provisioning
324         mController.initiateProvisioning(mIntent, null, TEST_MDM_PACKAGE);
325         // THEN the UI elements should be updated accordingly
326         verifyInitiateProfileOwnerUi();
327         // WHEN the user consents
328         mController.continueProvisioningAfterUserConsent();
329         // THEN start profile provisioning
330         verify(mUi).startProvisioning(mUserManager.getUserHandle(), mParams);
331         verify(mUi, never()).requestEncryption(any(ProvisioningParams.class));
332         verify(mEncryptionController).cancelEncryptionReminder();
333         verifyNoMoreInteractions(mUi);
334     }
335 
testManagedProfile_encryptionNotSupported()336     public void testManagedProfile_encryptionNotSupported() throws Exception {
337         // GIVEN an intent to provision a managed profile on an unencrypted device that does not
338         // support encryption
339         prepareMocksForManagedProfileIntent(false);
340         when(mUtils.isEncryptionRequired()).thenReturn(true);
341         when(mDevicePolicyManager.getStorageEncryptionStatus())
342                 .thenReturn(DevicePolicyManager.ENCRYPTION_STATUS_UNSUPPORTED);
343         // WHEN initiating provisioning
344         mController.initiateProvisioning(mIntent, null, TEST_MDM_PACKAGE);
345         // WHEN the user consents
346         mController.continueProvisioningAfterUserConsent();
347         // THEN the UI elements should be updated accordingly
348         verifyInitiateProfileOwnerUi();
349         // THEN show an error indicating that this device does not support encryption
350         verify(mUi).showErrorAndClose(eq(R.string.cant_set_up_device),
351                 eq(R.string.device_doesnt_allow_encryption_contact_admin), any());
352         verifyNoMoreInteractions(mUi);
353     }
354 
testNfc()355     public void testNfc() throws Exception {
356         // GIVEN provisioning was started via an NFC tap and device is already encrypted
357         prepareMocksForNfcIntent(ACTION_PROVISION_MANAGED_DEVICE, false);
358         // WHEN initiating NFC provisioning
359         mController.initiateProvisioning(mIntent, null, null);
360         // WHEN the user consents
361         mController.continueProvisioningAfterUserConsent();
362         // THEN start device owner provisioning
363         verifyInitiateDeviceOwnerUi();
364         verify(mUi).startProvisioning(mUserManager.getUserHandle(), mParams);
365         verify(mEncryptionController).cancelEncryptionReminder();
366         verifyNoMoreInteractions(mUi);
367     }
368 
testNfc_skipEncryption()369     public void testNfc_skipEncryption() throws Exception {
370         // GIVEN provisioning was started via an NFC tap with encryption skipped
371         prepareMocksForNfcIntent(ACTION_PROVISION_MANAGED_DEVICE, true);
372         when(mUtils.isEncryptionRequired()).thenReturn(true);
373         // WHEN initiating NFC provisioning
374 
375         mController.initiateProvisioning(mIntent, null, null);
376         // WHEN the user consents
377         mController.continueProvisioningAfterUserConsent();
378         // THEN start device owner provisioning
379         verifyInitiateDeviceOwnerUi();
380         verify(mUi).startProvisioning(mUserManager.getUserHandle(), mParams);
381         verify(mUi, never()).requestEncryption(any(ProvisioningParams.class));
382         verify(mEncryptionController).cancelEncryptionReminder();
383         verifyNoMoreInteractions(mUi);
384     }
385 
testNfc_withEncryption()386     public void testNfc_withEncryption() throws Exception {
387         // GIVEN provisioning was started via an NFC tap with encryption necessary
388         prepareMocksForNfcIntent(ACTION_PROVISION_MANAGED_DEVICE, false);
389         when(mUtils.isEncryptionRequired()).thenReturn(true);
390         // WHEN initiating NFC provisioning
391         mController.initiateProvisioning(mIntent, null, null);
392         // WHEN the user consents
393         mController.continueProvisioningAfterUserConsent();
394         // THEN show encryption screen
395         verifyInitiateDeviceOwnerUi();
396         verify(mUi).requestEncryption(mParams);
397         verifyNoMoreInteractions(mUi);
398     }
399 
testNfc_afterEncryption()400     public void testNfc_afterEncryption() throws Exception {
401         // GIVEN provisioning was started via an NFC tap and we have gone through encryption
402         // in this case the device gets resumed with the DO intent and startedByTrustedSource flag
403         // set
404         prepareMocksForAfterEncryption(ACTION_PROVISION_MANAGED_DEVICE, true);
405         // WHEN continuing NFC provisioning after encryption
406         mController.initiateProvisioning(mIntent, null, null);
407         // WHEN the user consents
408         mController.continueProvisioningAfterUserConsent();
409         // THEN start device owner provisioning
410         verifyInitiateDeviceOwnerUi();
411         verify(mUi).startProvisioning(mUserManager.getUserHandle(), mParams);
412         verifyNoMoreInteractions(mUi);
413     }
414 
testNfc_frp()415     public void testNfc_frp() throws Exception {
416         // GIVEN provisioning was started via an NFC tap, but the device is locked with FRP
417         prepareMocksForNfcIntent(ACTION_PROVISION_MANAGED_DEVICE, false);
418         // setting the data block size to any number greater than 0 should invoke FRP.
419         when(mPdbManager.getDataBlockSize()).thenReturn(4);
420         // WHEN initiating NFC provisioning
421         mController.initiateProvisioning(mIntent, null, null);
422         // THEN show an error dialog
423         verify(mUi).showErrorAndClose(eq(R.string.cant_set_up_device),
424                 eq(R.string.device_has_reset_protection_contact_admin), any());
425         verifyNoMoreInteractions(mUi);
426     }
427 
testNfc_encryptionNotSupported()428     public void testNfc_encryptionNotSupported() throws Exception {
429         // GIVEN provisioning was started via an NFC tap, the device is not encrypted and encryption
430         // is not supported on the device
431         prepareMocksForNfcIntent(ACTION_PROVISION_MANAGED_DEVICE, false);
432         when(mUtils.isEncryptionRequired()).thenReturn(true);
433         when(mDevicePolicyManager.getStorageEncryptionStatus())
434                 .thenReturn(DevicePolicyManager.ENCRYPTION_STATUS_UNSUPPORTED);
435         // WHEN initiating NFC provisioning
436         mController.initiateProvisioning(mIntent, null, null);
437         // WHEN the user consents
438         mController.continueProvisioningAfterUserConsent();
439         // THEN show an error dialog
440         verifyInitiateDeviceOwnerUi();
441         verify(mUi).showErrorAndClose(eq(R.string.cant_set_up_device),
442                 eq(R.string.device_doesnt_allow_encryption_contact_admin), any());
443         verifyNoMoreInteractions(mUi);
444     }
445 
testQr()446     public void testQr() throws Exception {
447         // GIVEN provisioning was started via a QR code and device is already encrypted
448         prepareMocksForQrIntent(ACTION_PROVISION_MANAGED_DEVICE, false);
449         // WHEN initiating QR provisioning
450         mController.initiateProvisioning(mIntent, null, null);
451         // WHEN the user consents
452         mController.continueProvisioningAfterUserConsent();
453         // THEN start device owner provisioning
454         verifyInitiateDeviceOwnerUi();
455         verify(mUi).startProvisioning(mUserManager.getUserHandle(), mParams);
456         verifyNoMoreInteractions(mUi);
457     }
458 
testQr_skipEncryption()459     public void testQr_skipEncryption() throws Exception {
460         // GIVEN provisioning was started via a QR code with encryption skipped
461         prepareMocksForQrIntent(ACTION_PROVISION_MANAGED_DEVICE, true);
462         when(mUtils.isEncryptionRequired()).thenReturn(true);
463         // WHEN initiating QR provisioning
464         mController.initiateProvisioning(mIntent, null, null);
465         // WHEN the user consents
466         mController.continueProvisioningAfterUserConsent();
467         // THEN start device owner provisioning
468         verifyInitiateDeviceOwnerUi();
469         verify(mUi).startProvisioning(mUserManager.getUserHandle(), mParams);
470         verify(mUi, never()).requestEncryption(any());
471         verifyNoMoreInteractions(mUi);
472     }
473 
testQr_withEncryption()474     public void testQr_withEncryption() throws Exception {
475         // GIVEN provisioning was started via a QR code with encryption necessary
476         prepareMocksForQrIntent(ACTION_PROVISION_MANAGED_DEVICE, false);
477         when(mUtils.isEncryptionRequired()).thenReturn(true);
478         // WHEN initiating QR provisioning
479         mController.initiateProvisioning(mIntent, null, null);
480         // WHEN the user consents
481         mController.continueProvisioningAfterUserConsent();
482         // THEN show encryption screen
483         verifyInitiateDeviceOwnerUi();
484         verify(mUi).requestEncryption(mParams);
485         verifyNoMoreInteractions(mUi);
486     }
487 
testQr_frp()488     public void testQr_frp() throws Exception {
489         // GIVEN provisioning was started via a QR code, but the device is locked with FRP
490         prepareMocksForQrIntent(ACTION_PROVISION_MANAGED_DEVICE, false);
491         // setting the data block size to any number greater than 0 should invoke FRP.
492         when(mPdbManager.getDataBlockSize()).thenReturn(4);
493         // WHEN initiating QR provisioning
494         mController.initiateProvisioning(mIntent, null, null);
495         // THEN show an error dialog
496         verify(mUi).showErrorAndClose(eq(R.string.cant_set_up_device),
497                 eq(R.string.device_has_reset_protection_contact_admin), any());
498         verifyNoMoreInteractions(mUi);
499     }
500 
testDeviceOwner()501     public void testDeviceOwner() throws Exception {
502         // GIVEN device owner provisioning was started and device is already encrypted
503         prepareMocksForDoIntent(true);
504         // WHEN initiating provisioning
505         mController.initiateProvisioning(mIntent, null, TEST_MDM_PACKAGE);
506         // THEN the UI elements should be updated accordingly
507         verifyInitiateDeviceOwnerUi();
508         // WHEN the user consents
509         mController.continueProvisioningAfterUserConsent();
510         // THEN start device owner provisioning
511         verify(mUi).startProvisioning(mUserManager.getUserHandle(), mParams);
512         verify(mEncryptionController).cancelEncryptionReminder();
513         verifyNoMoreInteractions(mUi);
514     }
515 
testDeviceOwner_skipEncryption()516     public void testDeviceOwner_skipEncryption() throws Exception {
517         // GIVEN device owner provisioning was started with skip encryption flag
518         prepareMocksForDoIntent(true);
519         when(mUtils.isEncryptionRequired()).thenReturn(true);
520         // WHEN initiating provisioning
521         mController.initiateProvisioning(mIntent, null, TEST_MDM_PACKAGE);
522         // THEN the UI elements should be updated accordingly
523         verifyInitiateDeviceOwnerUi();
524         // WHEN the user consents
525         mController.continueProvisioningAfterUserConsent();
526         // THEN start device owner provisioning
527         verify(mUi).startProvisioning(mUserManager.getUserHandle(), mParams);
528         verify(mUi, never()).requestEncryption(any());
529         verify(mEncryptionController).cancelEncryptionReminder();
530         verifyNoMoreInteractions(mUi);
531     }
532 
533     // TODO: There is a difference in behaviour here between the managed profile and the device
534     // owner case: In managed profile case, we invoke encryption after user clicks next, but in
535     // device owner mode we invoke it straight away. Also in theory no need to update
536     // the UI elements if we're moving away from this activity straight away.
testDeviceOwner_withEncryption()537     public void testDeviceOwner_withEncryption() throws Exception {
538         // GIVEN device owner provisioning is started with encryption needed
539         prepareMocksForDoIntent(false);
540         when(mUtils.isEncryptionRequired()).thenReturn(true);
541         // WHEN initiating provisioning
542         mController.initiateProvisioning(mIntent, null, TEST_MDM_PACKAGE);
543         // WHEN the user consents
544         mController.continueProvisioningAfterUserConsent();
545         // THEN update the UI elements and show encryption screen
546         verifyInitiateDeviceOwnerUi();
547         verify(mUi).requestEncryption(mParams);
548         verifyNoMoreInteractions(mUi);
549     }
550 
testDeviceOwner_afterEncryption()551     public void testDeviceOwner_afterEncryption() throws Exception {
552         // GIVEN device owner provisioning is continued after encryption. In this case we do not set
553         // the startedByTrustedSource flag.
554         prepareMocksForAfterEncryption(ACTION_PROVISION_MANAGED_DEVICE, false);
555         // WHEN provisioning is continued
556         mController.initiateProvisioning(mIntent, null, null);
557         // THEN the UI elements should be updated accordingly
558         verifyInitiateDeviceOwnerUi();
559         // WHEN the user consents
560         mController.continueProvisioningAfterUserConsent();
561         // THEN start device owner provisioning
562         verify(mUi).startProvisioning(mUserManager.getUserHandle(), mParams);
563         verify(mEncryptionController).cancelEncryptionReminder();
564         verifyNoMoreInteractions(mUi);
565     }
566 
testNullParams()567     public void testNullParams() throws Exception {
568         // THEN verifying params is null initially
569         assertNull(mController.getParams());
570     }
571 
testDeviceOwner_frp()572     public void testDeviceOwner_frp() throws Exception {
573         // GIVEN device owner provisioning is invoked with FRP active
574         prepareMocksForDoIntent(false);
575         // setting the data block size to any number greater than 0 should invoke FRP.
576         when(mPdbManager.getDataBlockSize()).thenReturn(4);
577         // WHEN initiating provisioning
578         mController.initiateProvisioning(mIntent, null, TEST_MDM_PACKAGE);
579         // THEN show an error dialog
580         verify(mUi).showErrorAndClose(eq(R.string.cant_set_up_device),
581                 eq(R.string.device_has_reset_protection_contact_admin), any());
582         verifyNoMoreInteractions(mUi);
583     }
584 
testMaybeStartProfileOwnerProvisioningIfSkipUserConsent_continueProvisioning()585     public void testMaybeStartProfileOwnerProvisioningIfSkipUserConsent_continueProvisioning()
586             throws Exception {
587         // GIVEN skipping user consent and encryption
588         prepareMocksForMaybeStartProvisioning(true, true, false);
589         // WHEN calling initiateProvisioning
590         mController.initiateProvisioning(mIntent, null, TEST_MDM_PACKAGE);
591         // THEN start profile owner provisioning
592         verify(mUi).startProvisioning(mUserManager.getUserHandle(), mParams);
593     }
594 
testMaybeStartProfileOwnerProvisioningIfSkipUserConsent_notSkipUserConsent()595     public void testMaybeStartProfileOwnerProvisioningIfSkipUserConsent_notSkipUserConsent()
596             throws Exception {
597         // GIVEN not skipping user consent
598         prepareMocksForMaybeStartProvisioning(false, true, false);
599         // WHEN calling initiateProvisioning
600         mController.initiateProvisioning(mIntent, null, TEST_MDM_PACKAGE);
601         // THEN not starting profile owner provisioning
602         verify(mUi, never()).startProvisioning(mUserManager.getUserHandle(), mParams);
603     }
604 
testMaybeStartProfileOwnerProvisioningIfSkipUserConsent_requireEncryption()605     public void testMaybeStartProfileOwnerProvisioningIfSkipUserConsent_requireEncryption()
606             throws Exception {
607         // GIVEN skipping user consent and encryption
608         prepareMocksForMaybeStartProvisioning(true, false, false);
609         // WHEN calling initiateProvisioning
610         mController.initiateProvisioning(mIntent, null, TEST_MDM_PACKAGE);
611         // THEN not starting profile owner provisioning
612         verify(mUi, never()).startProvisioning(anyInt(), any());
613         // THEN show encryption ui
614         verify(mUi).requestEncryption(mParams);
615         verifyNoMoreInteractions(mUi);
616     }
617 
testMaybeStartProfileOwnerProvisioningIfSkipUserConsent_managedProfileExists()618     public void testMaybeStartProfileOwnerProvisioningIfSkipUserConsent_managedProfileExists()
619             throws Exception {
620         // GIVEN skipping user consent and encryption, but current managed profile exists
621         prepareMocksForMaybeStartProvisioning(true, true, true);
622         // WHEN calling initiateProvisioning
623         mController.initiateProvisioning(mIntent, null, TEST_MDM_PACKAGE);
624         // THEN not starting profile owner provisioning
625         verify(mUi, never()).startProvisioning(mUserManager.getUserHandle(), mParams);
626         // THEN show UI to delete user
627         verify(mUi).showDeleteManagedProfileDialog(any(), any(), anyInt());
628         // WHEN user agrees to remove the current profile and continue provisioning
629         mController.continueProvisioningAfterUserConsent();
630         // THEN start profile owner provisioning
631         verify(mUi).startProvisioning(mUserManager.getUserHandle(), mParams);
632     }
633 
prepareMocksForMaybeStartProvisioning( boolean skipUserConsent, boolean skipEncryption, boolean managedProfileExists)634     private void prepareMocksForMaybeStartProvisioning(
635             boolean skipUserConsent, boolean skipEncryption, boolean managedProfileExists)
636             throws IllegalProvisioningArgumentException {
637         String action = ACTION_PROVISION_MANAGED_PROFILE;
638         when(mDevicePolicyManager.checkProvisioningPreCondition(action, TEST_MDM_PACKAGE))
639                 .thenReturn(CODE_OK);
640         mParams = ProvisioningParams.Builder.builder()
641                 .setProvisioningAction(action)
642                 .setDeviceAdminComponentName(TEST_MDM_COMPONENT_NAME)
643                 .setSkipUserConsent(skipUserConsent)
644                 .build();
645 
646         when(mUtils.alreadyHasManagedProfile(mContext)).thenReturn(
647                 managedProfileExists ? 10 : -1);
648         when(mUtils.isEncryptionRequired()).thenReturn(!skipEncryption);
649 
650 
651         when(mMessageParser.parse(mIntent)).thenReturn(mParams);
652     }
653 
prepareMocksForManagedProfileIntent(boolean skipEncryption)654     private void prepareMocksForManagedProfileIntent(boolean skipEncryption) throws Exception {
655         final String action = ACTION_PROVISION_MANAGED_PROFILE;
656         when(mIntent.getAction()).thenReturn(action);
657         when(mUtils.findDeviceAdmin(TEST_MDM_PACKAGE, null, mContext, UserHandle.myUserId()))
658                 .thenReturn(TEST_MDM_COMPONENT_NAME);
659         when(mSettingsFacade.isDeviceProvisioned(mContext)).thenReturn(true);
660         when(mDevicePolicyManager.checkProvisioningPreCondition(action, TEST_MDM_PACKAGE))
661                 .thenReturn(CODE_OK);
662         when(mMessageParser.parse(mIntent)).thenReturn(
663                 createParams(false, skipEncryption, null, action, TEST_MDM_PACKAGE));
664     }
665 
prepareMocksForNfcIntent(String action, boolean skipEncryption)666     private void prepareMocksForNfcIntent(String action, boolean skipEncryption) throws Exception {
667         when(mIntent.getAction()).thenReturn(ACTION_NDEF_DISCOVERED);
668         when(mIntent.getComponent()).thenReturn(ComponentName.createRelative(MP_PACKAGE_NAME,
669                 ".PreProvisioningActivityViaNfc"));
670         when(mDevicePolicyManager.checkProvisioningPreCondition(action, TEST_MDM_PACKAGE))
671                 .thenReturn(CODE_OK);
672         when(mMessageParser.parse(mIntent)).thenReturn(
673                 createParams(true, skipEncryption, TEST_WIFI_SSID, action, TEST_MDM_PACKAGE));
674     }
675 
prepareMocksForQrIntent(String action, boolean skipEncryption)676     private void prepareMocksForQrIntent(String action, boolean skipEncryption) throws Exception {
677         when(mIntent.getAction())
678                 .thenReturn(ACTION_PROVISION_MANAGED_DEVICE_FROM_TRUSTED_SOURCE);
679         when(mIntent.getComponent()).thenReturn(ComponentName.createRelative(MP_PACKAGE_NAME,
680                 ".PreProvisioningActivityViaTrustedApp"));
681         when(mDevicePolicyManager.checkProvisioningPreCondition(action, TEST_MDM_PACKAGE))
682                 .thenReturn(CODE_OK);
683         when(mMessageParser.parse(mIntent)).thenReturn(
684                 createParams(true, skipEncryption, TEST_WIFI_SSID, action, TEST_MDM_PACKAGE));
685     }
686 
prepareMocksForDoIntent(boolean skipEncryption)687     private void prepareMocksForDoIntent(boolean skipEncryption) throws Exception {
688         final String action = ACTION_PROVISION_MANAGED_DEVICE;
689         when(mIntent.getAction()).thenReturn(action);
690         when(mDevicePolicyManager.checkProvisioningPreCondition(action, TEST_MDM_PACKAGE))
691                 .thenReturn(CODE_OK);
692         when(mMessageParser.parse(mIntent)).thenReturn(
693                 createParams(false, skipEncryption, TEST_WIFI_SSID, action, TEST_MDM_PACKAGE));
694     }
695 
prepareMocksForAfterEncryption(String action, boolean startedByTrustedSource)696     private void prepareMocksForAfterEncryption(String action, boolean startedByTrustedSource)
697             throws Exception {
698         when(mIntent.getAction()).thenReturn(ACTION_RESUME_PROVISIONING);
699         when(mIntent.getComponent()).thenReturn(ComponentName.createRelative(MP_PACKAGE_NAME,
700                 ".PreProvisioningActivityAfterEncryption"));
701         when(mDevicePolicyManager.checkProvisioningPreCondition(action, TEST_MDM_PACKAGE))
702                 .thenReturn(CODE_OK);
703         when(mMessageParser.parse(mIntent)).thenReturn(
704                 createParams(
705                         startedByTrustedSource, false, TEST_WIFI_SSID, action, TEST_MDM_PACKAGE));
706     }
707 
createParams(boolean startedByTrustedSource, boolean skipEncryption, String wifiSsid, String action, String packageName)708     private ProvisioningParams createParams(boolean startedByTrustedSource, boolean skipEncryption,
709             String wifiSsid, String action, String packageName) {
710         ProvisioningParams.Builder builder = ProvisioningParams.Builder.builder()
711                 .setStartedByTrustedSource(startedByTrustedSource)
712                 .setSkipEncryption(skipEncryption)
713                 .setProvisioningAction(action)
714                 .setDeviceAdminPackageName(packageName);
715         if (!TextUtils.isEmpty(wifiSsid)) {
716             builder.setWifiInfo(WifiInfo.Builder.builder().setSsid(wifiSsid).build());
717         }
718         return mParams = builder.build();
719     }
720 
verifyInitiateProfileOwnerUi()721     private void verifyInitiateProfileOwnerUi() {
722         verify(mUi).initiateUi(eq(R.layout.intro_profile_owner),
723                 eq(R.string.setup_profile), any(), any(), eq(true),
724                 eq(false), eq(emptyList()), any());
725     }
726 
verifyInitiateDeviceOwnerUi()727     private void verifyInitiateDeviceOwnerUi() {
728         verify(mUi).initiateUi(eq(R.layout.intro_device_owner),
729                 eq(R.string.setup_device), eq(TEST_MDM_PACKAGE_LABEL), any(), eq(false),
730                 eq(false), eq(emptyList()), any());
731     }
732 }