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