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 */
16package com.android.managedprovisioning.preprovisioning;
17
18import static android.app.admin.DevicePolicyManager.ACTION_PROVISION_MANAGED_DEVICE;
19import static android.app.admin.DevicePolicyManager.ACTION_PROVISION_MANAGED_DEVICE_FROM_TRUSTED_SOURCE;
20import static android.app.admin.DevicePolicyManager.ACTION_PROVISION_MANAGED_PROFILE;
21import static android.app.admin.DevicePolicyManager.CODE_MANAGED_USERS_NOT_SUPPORTED;
22import static android.app.admin.DevicePolicyManager.CODE_OK;
23import static android.nfc.NfcAdapter.ACTION_NDEF_DISCOVERED;
24
25import static com.android.managedprovisioning.common.Globals.ACTION_RESUME_PROVISIONING;
26
27import static org.mockito.Mockito.any;
28import static org.mockito.Mockito.anyInt;
29import static org.mockito.Mockito.anyString;
30import static org.mockito.Mockito.eq;
31import static org.mockito.Mockito.never;
32import static org.mockito.Mockito.verify;
33import static org.mockito.Mockito.verifyNoMoreInteractions;
34import static org.mockito.Mockito.verifyZeroInteractions;
35import static org.mockito.Mockito.when;
36
37import static java.util.Collections.emptyList;
38
39import android.app.ActivityManager;
40import android.app.KeyguardManager;
41import android.app.admin.DevicePolicyManager;
42import android.content.ComponentName;
43import android.content.Context;
44import android.content.Intent;
45import android.content.pm.ApplicationInfo;
46import android.content.pm.PackageInfo;
47import android.content.pm.PackageManager;
48import android.content.res.Resources;
49import android.graphics.drawable.VectorDrawable;
50import android.os.UserHandle;
51import android.os.UserManager;
52import android.service.persistentdata.PersistentDataBlockManager;
53import android.support.test.InstrumentationRegistry;
54import android.support.test.filters.SmallTest;
55import android.test.AndroidTestCase;
56import android.text.TextUtils;
57
58import com.android.managedprovisioning.R;
59import com.android.managedprovisioning.analytics.TimeLogger;
60import com.android.managedprovisioning.common.IllegalProvisioningArgumentException;
61import com.android.managedprovisioning.common.SettingsFacade;
62import com.android.managedprovisioning.common.Utils;
63import com.android.managedprovisioning.model.ProvisioningParams;
64import com.android.managedprovisioning.model.WifiInfo;
65import com.android.managedprovisioning.parser.MessageParser;
66
67import org.mockito.Mock;
68import org.mockito.MockitoAnnotations;
69
70@SmallTest
71public 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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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.
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
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
567    public void testNullParams() throws Exception {
568        // THEN verifying params is null initially
569        assertNull(mController.getParams());
570    }
571
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
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
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
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
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
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
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
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
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
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
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
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
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
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}