1 /*
2  * Copyright (C) 2020 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.android.managedprovisioning.parser;
18 
19 import static android.app.admin.DevicePolicyManager.ACTION_PROVISION_FINANCED_DEVICE;
20 import static android.app.admin.DevicePolicyManager.ACTION_PROVISION_MANAGED_DEVICE;
21 import static android.app.admin.DevicePolicyManager.ACTION_PROVISION_MANAGED_DEVICE_FROM_TRUSTED_SOURCE;
22 import static android.app.admin.DevicePolicyManager.ACTION_PROVISION_MANAGED_PROFILE;
23 import static android.app.admin.DevicePolicyManager.EXTRA_PROVISIONING_TRIGGER;
24 import static android.app.admin.DevicePolicyManager.FLAG_SUPPORTED_MODES_DEVICE_OWNER;
25 import static android.app.admin.DevicePolicyManager.FLAG_SUPPORTED_MODES_ORGANIZATION_OWNED;
26 import static android.app.admin.DevicePolicyManager.FLAG_SUPPORTED_MODES_PERSONALLY_OWNED;
27 import static android.app.admin.DevicePolicyManager.MIME_TYPE_PROVISIONING_NFC;
28 import static android.app.admin.DevicePolicyManager.PROVISIONING_MODE_FULLY_MANAGED_DEVICE;
29 import static android.app.admin.DevicePolicyManager.PROVISIONING_MODE_MANAGED_PROFILE;
30 import static android.app.admin.DevicePolicyManager.PROVISIONING_MODE_MANAGED_PROFILE_ON_PERSONAL_DEVICE;
31 import static android.app.admin.DevicePolicyManager.PROVISIONING_TRIGGER_CLOUD_ENROLLMENT;
32 import static android.app.admin.DevicePolicyManager.PROVISIONING_TRIGGER_PERSISTENT_DEVICE_OWNER;
33 import static android.app.admin.DevicePolicyManager.PROVISIONING_TRIGGER_QR_CODE;
34 import static android.app.admin.DevicePolicyManager.PROVISIONING_TRIGGER_UNSPECIFIED;
35 import static android.nfc.NfcAdapter.ACTION_NDEF_DISCOVERED;
36 import static android.provider.Settings.Secure.USER_SETUP_COMPLETE;
37 
38 import static com.android.managedprovisioning.common.Globals.ACTION_PROVISION_MANAGED_DEVICE_SILENTLY;
39 import static com.android.managedprovisioning.model.ProvisioningParams.DEFAULT_EXTRA_PROVISIONING_SUPPORTED_MODES;
40 
41 import static com.google.common.truth.Truth.assertThat;
42 
43 import static org.robolectric.Shadows.shadowOf;
44 import static org.testng.Assert.assertThrows;
45 
46 import android.content.Context;
47 import android.content.Intent;
48 import android.content.pm.PackageManager;
49 import android.provider.Settings;
50 
51 import com.android.managedprovisioning.common.IllegalProvisioningArgumentException;
52 import com.android.managedprovisioning.common.SettingsFacade;
53 import com.android.managedprovisioning.common.Utils;
54 
55 import org.junit.Before;
56 import org.junit.Test;
57 import org.junit.runner.RunWith;
58 import org.robolectric.RobolectricTestRunner;
59 import org.robolectric.RuntimeEnvironment;
60 
61 /**
62  * Tests for {@link ParserUtils}.
63  */
64 @RunWith(RobolectricTestRunner.class)
65 public class ParserUtilsTest {
66 
67     private static final int INVALID_PROVISIONING_MODES = -1;
68     private static final int  INVALID_PROVISIONING_MODE_COMBINATION =
69             FLAG_SUPPORTED_MODES_PERSONALLY_OWNED | FLAG_SUPPORTED_MODES_DEVICE_OWNER;
70     private final ParserUtils mParserUtils = new ParserUtils();
71     private final SettingsFacade mSettingsFacade = new SettingsFacade();
72     private final Context mContext = RuntimeEnvironment.application;
73     private final Utils mUtils = new Utils();
74 
75     @Before
setUp()76     public void setUp() {
77         shadowOf(mContext.getPackageManager())
78                 .setSystemFeature(PackageManager.FEATURE_MANAGED_USERS, /* supported */ true);
79     }
80 
81     @Test
extractProvisioningTrigger_provisionManagedDeviceIntent_returnsUnspecified()82     public void extractProvisioningTrigger_provisionManagedDeviceIntent_returnsUnspecified() {
83         Intent intent = new Intent(ACTION_PROVISION_MANAGED_DEVICE);
84 
85         assertThat(mParserUtils.extractProvisioningTrigger(intent))
86                 .isEqualTo(PROVISIONING_TRIGGER_UNSPECIFIED);
87     }
88 
89     @Test
extractProvisioningTrigger_provisionTrustedSourceIntentWithNoProvisioningTrigger_returnsUnspecified()90     public void extractProvisioningTrigger_provisionTrustedSourceIntentWithNoProvisioningTrigger_returnsUnspecified() {
91         Intent intent = new Intent(ACTION_PROVISION_MANAGED_DEVICE_FROM_TRUSTED_SOURCE);
92 
93         assertThat(mParserUtils.extractProvisioningTrigger(intent))
94                 .isEqualTo(PROVISIONING_TRIGGER_UNSPECIFIED);
95     }
96 
97     @Test
98     public void
extractProvisioningTrigger_provisionTrustedSourceWithQrProvisioningTrigger_returnsQr()99     extractProvisioningTrigger_provisionTrustedSourceWithQrProvisioningTrigger_returnsQr() {
100         Intent intent = new Intent(ACTION_PROVISION_MANAGED_DEVICE_FROM_TRUSTED_SOURCE);
101         intent.putExtra(EXTRA_PROVISIONING_TRIGGER, PROVISIONING_TRIGGER_QR_CODE);
102 
103         assertThat(mParserUtils.extractProvisioningTrigger(intent))
104                 .isEqualTo(PROVISIONING_TRIGGER_QR_CODE);
105     }
106 
107     @Test
extractProvisioningTrigger_provisionTrustedSourceWithCloudEnrollmentProvisioningTrigger_returnsCloudEnrollment()108     public void extractProvisioningTrigger_provisionTrustedSourceWithCloudEnrollmentProvisioningTrigger_returnsCloudEnrollment() {
109         Intent intent = new Intent(ACTION_PROVISION_MANAGED_DEVICE_FROM_TRUSTED_SOURCE);
110         intent.putExtra(EXTRA_PROVISIONING_TRIGGER, PROVISIONING_TRIGGER_CLOUD_ENROLLMENT);
111 
112         assertThat(mParserUtils.extractProvisioningTrigger(intent))
113                 .isEqualTo(PROVISIONING_TRIGGER_CLOUD_ENROLLMENT);
114     }
115 
116     @Test
extractProvisioningTrigger_provisionTrustedSourceWithDeviceOwnerProvisioningTrigger_returnsPersistentDeviceOwner()117     public void extractProvisioningTrigger_provisionTrustedSourceWithDeviceOwnerProvisioningTrigger_returnsPersistentDeviceOwner() {
118         Intent intent = new Intent(ACTION_PROVISION_MANAGED_DEVICE_FROM_TRUSTED_SOURCE);
119         intent.putExtra(EXTRA_PROVISIONING_TRIGGER, PROVISIONING_TRIGGER_PERSISTENT_DEVICE_OWNER);
120 
121         assertThat(mParserUtils.extractProvisioningTrigger(intent))
122                 .isEqualTo(PROVISIONING_TRIGGER_PERSISTENT_DEVICE_OWNER);
123     }
124 
125     @Test
126     public void
extractProvisioningAction_provisionManagedDeviceIntent_returnsProvisionManagedDevice()127     extractProvisioningAction_provisionManagedDeviceIntent_returnsProvisionManagedDevice()
128             throws IllegalProvisioningArgumentException {
129         Intent intent = new Intent(ACTION_PROVISION_MANAGED_DEVICE);
130 
131         assertThat(mParserUtils.extractProvisioningAction(intent, mSettingsFacade, mContext))
132                 .isEqualTo(ACTION_PROVISION_MANAGED_DEVICE);
133     }
134 
135     @Test
136     public void
extractProvisioningAction_provisionManagedProfileIntent_returnsProvisionManagedProfile()137     extractProvisioningAction_provisionManagedProfileIntent_returnsProvisionManagedProfile()
138             throws IllegalProvisioningArgumentException {
139         Intent intent = new Intent(ACTION_PROVISION_MANAGED_PROFILE);
140 
141         assertThat(mParserUtils.extractProvisioningAction(intent, mSettingsFacade, mContext))
142                 .isEqualTo(ACTION_PROVISION_MANAGED_PROFILE);
143     }
144 
145     @Test
146     public void
extractProvisioningAction_provisionFinancedDeviceIntent_returnsProvisionFinancedDevice()147     extractProvisioningAction_provisionFinancedDeviceIntent_returnsProvisionFinancedDevice()
148             throws IllegalProvisioningArgumentException {
149         Intent intent = new Intent(ACTION_PROVISION_FINANCED_DEVICE);
150 
151         assertThat(mParserUtils.extractProvisioningAction(intent, mSettingsFacade, mContext))
152                 .isEqualTo(ACTION_PROVISION_FINANCED_DEVICE);
153     }
154 
155     @Test
156     public void
extractProvisioningAction_provisionManagedDeviceSilentlyIntent_returnsProvisionManagedDevice()157     extractProvisioningAction_provisionManagedDeviceSilentlyIntent_returnsProvisionManagedDevice()
158             throws IllegalProvisioningArgumentException {
159         Intent intent = new Intent(ACTION_PROVISION_MANAGED_DEVICE_SILENTLY);
160 
161         assertThat(mParserUtils.extractProvisioningAction(intent, mSettingsFacade, mContext))
162                 .isEqualTo(ACTION_PROVISION_MANAGED_DEVICE);
163     }
164 
165     @Test
extractProvisioningAction_nfcIntent_returnsProvisionManagedDevice()166     public void extractProvisioningAction_nfcIntent_returnsProvisionManagedDevice()
167             throws IllegalProvisioningArgumentException {
168         Intent intent = new Intent(ACTION_NDEF_DISCOVERED);
169         intent.setType(MIME_TYPE_PROVISIONING_NFC);
170 
171         assertThat(mParserUtils.extractProvisioningAction(intent, mSettingsFacade, mContext))
172                 .isEqualTo(ACTION_PROVISION_MANAGED_DEVICE);
173     }
174 
175     @Test(expected = IllegalProvisioningArgumentException.class)
testExtractProvisioningAction_nfcIntentWithNoMimeType_throwsException()176     public void testExtractProvisioningAction_nfcIntentWithNoMimeType_throwsException()
177             throws IllegalProvisioningArgumentException {
178         Intent intent = new Intent(ACTION_NDEF_DISCOVERED);
179 
180         mParserUtils.extractProvisioningAction(intent, mSettingsFacade, mContext);
181     }
182 
183     @Test(expected = IllegalProvisioningArgumentException.class)
extractProvisioningAction_nfcIntentWithWrongMimeType_throwsException()184     public void extractProvisioningAction_nfcIntentWithWrongMimeType_throwsException()
185             throws IllegalProvisioningArgumentException {
186         Intent intent = new Intent(ACTION_NDEF_DISCOVERED);
187         intent.setType("wrongMimeType");
188 
189         mParserUtils.extractProvisioningAction(intent, mSettingsFacade, mContext);
190     }
191 
192     @Test
193     public void
extractProvisioningAction_trustedSourceDuringSetupWizard_returnsProvisionManagedDevice()194             extractProvisioningAction_trustedSourceDuringSetupWizard_returnsProvisionManagedDevice()
195             throws IllegalProvisioningArgumentException {
196         Intent intent = new Intent(ACTION_PROVISION_MANAGED_DEVICE_FROM_TRUSTED_SOURCE);
197         markDuringSetupWizard();
198 
199         assertThat(mParserUtils.extractProvisioningAction(intent, mSettingsFacade, mContext))
200                 .isEqualTo(ACTION_PROVISION_MANAGED_DEVICE);
201     }
202 
203     @Test
204     public void
extractProvisioningAction_trustedSourceAfterSetupWizard_returnsProvisionManagedProfile()205             extractProvisioningAction_trustedSourceAfterSetupWizard_returnsProvisionManagedProfile()
206             throws IllegalProvisioningArgumentException {
207         Intent intent = new Intent(ACTION_PROVISION_MANAGED_DEVICE_FROM_TRUSTED_SOURCE);
208         markAfterSetupWizard();
209 
210         assertThat(mParserUtils.extractProvisioningAction(intent, mSettingsFacade, mContext))
211                 .isEqualTo(ACTION_PROVISION_MANAGED_PROFILE);
212     }
213 
214     @Test
215     public void
getAllowedProvisioningModes_organizationOwned_returnsManagedProfileAndManagedDevice()216             getAllowedProvisioningModes_organizationOwned_returnsManagedProfileAndManagedDevice() {
217         assertThat(mParserUtils.getAllowedProvisioningModes(mContext,
218                 FLAG_SUPPORTED_MODES_ORGANIZATION_OWNED, mUtils)).containsExactly(
219                         PROVISIONING_MODE_MANAGED_PROFILE,
220                         PROVISIONING_MODE_FULLY_MANAGED_DEVICE);
221     }
222 
223     @Test
224     public void
getAllowedProvisioningModes_personallyOwned_returnsManagedProfileOnly()225             getAllowedProvisioningModes_personallyOwned_returnsManagedProfileOnly() {
226         assertThat(mParserUtils.getAllowedProvisioningModes(mContext,
227                 FLAG_SUPPORTED_MODES_PERSONALLY_OWNED, mUtils)).containsExactly(
228                         PROVISIONING_MODE_MANAGED_PROFILE);
229     }
230 
231     @Test
getAllowedProvisioningModes_organizationAndPersonallyOwned_returnsManagedProfileManagedDevicePersonalManagedProfile()232     public void getAllowedProvisioningModes_organizationAndPersonallyOwned_returnsManagedProfileManagedDevicePersonalManagedProfile() {
233         assertThat(mParserUtils.getAllowedProvisioningModes(mContext,
234                 FLAG_SUPPORTED_MODES_ORGANIZATION_OWNED
235                         | FLAG_SUPPORTED_MODES_PERSONALLY_OWNED, mUtils)).containsExactly(
236                         PROVISIONING_MODE_MANAGED_PROFILE,
237                         PROVISIONING_MODE_FULLY_MANAGED_DEVICE,
238                         PROVISIONING_MODE_MANAGED_PROFILE_ON_PERSONAL_DEVICE);
239     }
240 
241     @Test
getAllowedProvisioningModes_deviceOwner_returnsManagedDevice()242     public void getAllowedProvisioningModes_deviceOwner_returnsManagedDevice() {
243         assertThat(mParserUtils.getAllowedProvisioningModes(mContext,
244                 FLAG_SUPPORTED_MODES_DEVICE_OWNER, mUtils)).containsExactly(
245                         PROVISIONING_MODE_FULLY_MANAGED_DEVICE);
246     }
247 
248     @Test
getAllowedProvisioningModes_invalidValue_throwsException()249     public void getAllowedProvisioningModes_invalidValue_throwsException() {
250         assertThrows(
251                 IllegalArgumentException.class,
252                 () -> mParserUtils
253                         .getAllowedProvisioningModes(mContext, INVALID_PROVISIONING_MODES, mUtils));
254     }
255 
256     @Test
getAllowedProvisioningModes_invalidBinaryCombination_throwsException()257     public void getAllowedProvisioningModes_invalidBinaryCombination_throwsException() {
258         assertThrows(
259                 IllegalArgumentException.class,
260                 () -> mParserUtils.getAllowedProvisioningModes(mContext,
261                         INVALID_PROVISIONING_MODE_COMBINATION, mUtils));
262     }
263 
264     @Test
265     public void
getAllowedProvisioningModes_organizationOwnedAndManagedUsersNotSupported_returnsManagedDeviceOnly()266             getAllowedProvisioningModes_organizationOwnedAndManagedUsersNotSupported_returnsManagedDeviceOnly() {
267         shadowOf(mContext.getPackageManager())
268                 .setSystemFeature(PackageManager.FEATURE_MANAGED_USERS, /* supported = */ false);
269 
270         assertThat(mParserUtils.getAllowedProvisioningModes(mContext,
271                 FLAG_SUPPORTED_MODES_ORGANIZATION_OWNED, mUtils)).containsExactly(
272                 PROVISIONING_MODE_FULLY_MANAGED_DEVICE);
273     }
274 
275     @Test
276     public void
getAllowedProvisioningModes_personallyOwnedAndManagedUsersNotSupported_throwsException()277             getAllowedProvisioningModes_personallyOwnedAndManagedUsersNotSupported_throwsException() {
278         shadowOf(mContext.getPackageManager())
279                 .setSystemFeature(PackageManager.FEATURE_MANAGED_USERS, /* supported */ false);
280 
281         assertThrows(
282                 IllegalArgumentException.class,
283                 () -> mParserUtils
284                         .getAllowedProvisioningModes(mContext,
285                                 FLAG_SUPPORTED_MODES_PERSONALLY_OWNED, mUtils));
286     }
287 
288     @Test
getAllowedProvisioningModes_defaultValue_returnsEmptyArray()289     public void getAllowedProvisioningModes_defaultValue_returnsEmptyArray() {
290         assertThat(mParserUtils.getAllowedProvisioningModes(mContext,
291                 DEFAULT_EXTRA_PROVISIONING_SUPPORTED_MODES, mUtils)).isEmpty();
292     }
293 
294     @Test
validateSupportedModes_personallyOwned_doesNothing()295     public void validateSupportedModes_personallyOwned_doesNothing() {
296         mParserUtils.getAllowedProvisioningModes(
297                 mContext, FLAG_SUPPORTED_MODES_PERSONALLY_OWNED, mUtils);
298     }
299 
300     @Test
validateSupportedModes_organizationOwned_doesNothing()301     public void validateSupportedModes_organizationOwned_doesNothing() {
302         mParserUtils.getAllowedProvisioningModes(
303                 mContext, FLAG_SUPPORTED_MODES_ORGANIZATION_OWNED, mUtils);
304     }
305 
306     @Test
validateSupportedModes_deviceOwner_doesNothing()307     public void validateSupportedModes_deviceOwner_doesNothing() {
308         mParserUtils.getAllowedProvisioningModes(
309                 mContext, FLAG_SUPPORTED_MODES_DEVICE_OWNER, mUtils);
310     }
311 
312     @Test
validateSupportedModes_personalAndOrganizationOwned_doesNothing()313     public void validateSupportedModes_personalAndOrganizationOwned_doesNothing() {
314         mParserUtils.getAllowedProvisioningModes(
315                 mContext,
316                 FLAG_SUPPORTED_MODES_ORGANIZATION_OWNED | FLAG_SUPPORTED_MODES_PERSONALLY_OWNED,
317                 mUtils);
318     }
319 
320     @Test
validateSupportedModes_invalidValue_throwsException()321     public void validateSupportedModes_invalidValue_throwsException() {
322         assertThrows(
323                 IllegalArgumentException.class,
324                 () -> mParserUtils
325                         .getAllowedProvisioningModes(mContext, INVALID_PROVISIONING_MODES, mUtils));
326     }
327 
328     @Test
validateSupportedModes_invalidBinaryCombination_throwsException()329     public void validateSupportedModes_invalidBinaryCombination_throwsException() {
330         assertThrows(
331                 IllegalArgumentException.class,
332                 () -> mParserUtils.validateSupportedModes(INVALID_PROVISIONING_MODE_COMBINATION));
333     }
334 
markDuringSetupWizard()335     private boolean markDuringSetupWizard() {
336         return Settings.Secure.putInt(mContext.getContentResolver(), USER_SETUP_COMPLETE, 0);
337     }
338 
markAfterSetupWizard()339     private boolean markAfterSetupWizard() {
340         return Settings.Secure.putInt(mContext.getContentResolver(), USER_SETUP_COMPLETE, 1);
341     }
342 }
343