1 /*
2  * Copyright 2018, 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.finalization;
17 
18 import static android.app.admin.DeviceAdminReceiver.ACTION_PROFILE_PROVISIONING_COMPLETE;
19 import static android.app.admin.DevicePolicyManager.ACTION_ADMIN_POLICY_COMPLIANCE;
20 import static android.app.admin.DevicePolicyManager.ACTION_PROVISIONING_SUCCESSFUL;
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_ADMIN_EXTRAS_BUNDLE;
24 import static android.app.admin.DevicePolicyManager.PROVISIONING_TRIGGER_MANAGED_ACCOUNT;
25 
26 import static com.google.common.truth.Truth.assertThat;
27 
28 import static org.mockito.ArgumentMatchers.any;
29 import static org.mockito.ArgumentMatchers.anyInt;
30 import static org.mockito.ArgumentMatchers.anyString;
31 import static org.mockito.ArgumentMatchers.eq;
32 import static org.mockito.Mockito.never;
33 import static org.mockito.Mockito.verify;
34 import static org.mockito.Mockito.when;
35 
36 import android.content.ComponentName;
37 import android.content.Context;
38 import android.content.Intent;
39 import android.content.SharedPreferences;
40 import android.os.PersistableBundle;
41 import android.os.UserHandle;
42 
43 import androidx.test.InstrumentationRegistry;
44 
45 import com.android.managedprovisioning.analytics.ProvisioningAnalyticsTracker;
46 import com.android.managedprovisioning.common.IllegalProvisioningArgumentException;
47 import com.android.managedprovisioning.common.PolicyComplianceUtils;
48 import com.android.managedprovisioning.common.SettingsFacade;
49 import com.android.managedprovisioning.common.Utils;
50 import com.android.managedprovisioning.model.ProvisioningParams;
51 
52 import org.junit.Before;
53 import org.junit.Test;
54 import org.mockito.ArgumentCaptor;
55 import org.mockito.Mock;
56 import org.mockito.MockitoAnnotations;
57 
58 /**
59  * Unit tests for {@link ProvisioningIntentProvider}.
60  */
61 public class ProvisioningIntentProviderTest {
62 
63     private static final String DEVICE_ADMIN_PACKAGE_NAME = "com.example.package";
64     private static final ComponentName DEVICE_ADMIN_COMPONENT_NAME =
65             new ComponentName(DEVICE_ADMIN_PACKAGE_NAME, "com.android.AdminReceiver");
66     private static final PersistableBundle ADMIN_EXTRAS_BUNDLE =
67             PersistableBundle.forPair("test_key", "test_value");
68     private static final UserHandle WORK_PROFILE_USER_HANDLE = UserHandle.of(10);
69     private static final ProvisioningParams ADMIN_INTEGRATED_FLOW_PARAMS =
70             new ProvisioningParams.Builder()
71                     .setProvisioningAction(ACTION_PROVISION_MANAGED_DEVICE_FROM_TRUSTED_SOURCE)
72                     .setDeviceAdminComponentName(DEVICE_ADMIN_COMPONENT_NAME)
73                     .setAdminExtrasBundle(ADMIN_EXTRAS_BUNDLE)
74                     .setStartedByTrustedSource(true)
75                     .setFlowType(ProvisioningParams.FLOW_TYPE_ADMIN_INTEGRATED)
76                     .build();
77     private static final ProvisioningParams LEGACY_FLOW_PARAMS = new ProvisioningParams.Builder()
78             .setDeviceAdminComponentName(DEVICE_ADMIN_COMPONENT_NAME)
79             .setProvisioningAction(ACTION_PROVISION_MANAGED_PROFILE)
80             .setAdminExtrasBundle(ADMIN_EXTRAS_BUNDLE)
81             .build();
82     private static final ProvisioningParams LEGACY_FLOW_PARAMS_WITH_PROVISIONING_TRIGGER =
83             new ProvisioningParams.Builder()
84                     .setDeviceAdminComponentName(DEVICE_ADMIN_COMPONENT_NAME)
85                     .setProvisioningAction(ACTION_PROVISION_MANAGED_PROFILE)
86                     .setAdminExtrasBundle(ADMIN_EXTRAS_BUNDLE)
87                     .setProvisioningTrigger(PROVISIONING_TRIGGER_MANAGED_ACCOUNT)
88                     .build();
89 
90     @Mock private Context mContext;
91     @Mock private Utils mUtils;
92     @Mock private ProvisioningAnalyticsTracker mProvisioningAnalyticsTracker;
93     @Mock private PolicyComplianceUtils mPolicyComplianceUtils;
94     @Mock private SettingsFacade mSettingsFacade;
95     @Mock private SharedPreferences mSharedPreferences;
96 
97     private final ProvisioningIntentProvider mProvisioningIntentProvider =
98             new ProvisioningIntentProvider();
99     private final Context mTargetContext = InstrumentationRegistry.getTargetContext();
100 
101     @Before
setUp()102     public void setUp() {
103         MockitoAnnotations.initMocks(this);
104         when(mContext.getSharedPreferences(anyString(), anyInt())).thenReturn(mSharedPreferences);
105         when(mContext.getResources()).thenReturn(mTargetContext.getResources());
106     }
107 
108     @Test
maybeLaunchDpc_adminIntegratedFlow_policyComplianceActionLaunched()109     public void maybeLaunchDpc_adminIntegratedFlow_policyComplianceActionLaunched() {
110         when(mUtils.canResolveIntentAsUser(any(), any(), anyInt())).thenReturn(true);
111         PolicyComplianceUtils policyComplianceUtils = new PolicyComplianceUtils();
112 
113         mProvisioningIntentProvider.maybeLaunchDpc(ADMIN_INTEGRATED_FLOW_PARAMS, 0, mUtils,
114                 mContext, mProvisioningAnalyticsTracker, policyComplianceUtils, mSettingsFacade);
115 
116         ArgumentCaptor<Intent> intentCaptor = ArgumentCaptor.forClass(Intent.class);
117         verify(mContext).startActivityAsUser(intentCaptor.capture(), any());
118         verify(mProvisioningAnalyticsTracker).logDpcSetupStarted(any(), any());
119         assertThat(intentCaptor.getValue().getAction()).isEqualTo(ACTION_ADMIN_POLICY_COMPLIANCE);
120     }
121 
122     @Test
maybeLaunchDpc_legacyFlow_provisioningSuccessfulLaunched()123     public void maybeLaunchDpc_legacyFlow_provisioningSuccessfulLaunched() {
124         makeProvisioningSuccessfulIntentResolvable();
125         PolicyComplianceUtils policyComplianceUtils = new PolicyComplianceUtils();
126 
127         mProvisioningIntentProvider.maybeLaunchDpc(LEGACY_FLOW_PARAMS, 0, mUtils, mContext,
128                 mProvisioningAnalyticsTracker, policyComplianceUtils, mSettingsFacade);
129 
130         ArgumentCaptor<Intent> intentCaptor = ArgumentCaptor.forClass(Intent.class);
131         verify(mContext).startActivityAsUser(intentCaptor.capture(), any());
132         verify(mProvisioningAnalyticsTracker).logDpcSetupStarted(any(), any());
133         assertThat(intentCaptor.getValue().getAction()).isEqualTo(ACTION_PROVISIONING_SUCCESSFUL);
134     }
135 
136     @Test
maybeLaunchDpc_legacyFlow_duringSetupWizard_provisioningSuccessfulLaunched()137     public void maybeLaunchDpc_legacyFlow_duringSetupWizard_provisioningSuccessfulLaunched() {
138         when(mUtils.canResolveIntentAsUser(any(), any(), anyInt())).thenReturn(true);
139         when(mSettingsFacade.isDuringSetupWizard(mContext)).thenReturn(false);
140         PolicyComplianceUtils policyComplianceUtils = new PolicyComplianceUtils();
141 
142         mProvisioningIntentProvider.maybeLaunchDpc(LEGACY_FLOW_PARAMS, 0, mUtils, mContext,
143                 mProvisioningAnalyticsTracker, policyComplianceUtils, mSettingsFacade);
144 
145         ArgumentCaptor<Intent> intentCaptor = ArgumentCaptor.forClass(Intent.class);
146         verify(mContext).startActivityAsUser(intentCaptor.capture(), any());
147         verify(mProvisioningAnalyticsTracker).logDpcSetupStarted(any(), any());
148         assertThat(intentCaptor.getValue().getAction()).isEqualTo(ACTION_PROVISIONING_SUCCESSFUL);
149     }
150 
151     @Test
maybeLaunchDpc_legacyFlow_duringSetupWizard_policyComplianceResolvable_policyComplianceLaunched()152     public void maybeLaunchDpc_legacyFlow_duringSetupWizard_policyComplianceResolvable_policyComplianceLaunched() {
153         when(mUtils.canResolveIntentAsUser(any(), any(), anyInt())).thenReturn(true);
154         when(mUtils.getManagedProfile(mContext)).thenReturn(WORK_PROFILE_USER_HANDLE);
155         when(mSettingsFacade.isDuringSetupWizard(mContext)).thenReturn(true);
156         PolicyComplianceUtils policyComplianceUtils = new PolicyComplianceUtils();
157 
158         mProvisioningIntentProvider.maybeLaunchDpc(
159                 LEGACY_FLOW_PARAMS, WORK_PROFILE_USER_HANDLE.getIdentifier(), mUtils, mContext,
160                 mProvisioningAnalyticsTracker, policyComplianceUtils, mSettingsFacade);
161 
162         ArgumentCaptor<Intent> intentCaptor = ArgumentCaptor.forClass(Intent.class);
163         verify(mContext).startActivityAsUser(intentCaptor.capture(), any());
164         verify(mProvisioningAnalyticsTracker).logDpcSetupStarted(any(), any());
165         assertThat(intentCaptor.getValue().getAction()).isEqualTo(ACTION_ADMIN_POLICY_COMPLIANCE);
166     }
167 
168     @Test
maybeLaunchDpc_legacyFlow_policyComplianceResolvable_hasProvisioningTrigger_provisioningSuccessfulLaunched()169     public void maybeLaunchDpc_legacyFlow_policyComplianceResolvable_hasProvisioningTrigger_provisioningSuccessfulLaunched() {
170         when(mUtils.canResolveIntentAsUser(any(), any(), anyInt())).thenReturn(true);
171         when(mUtils.getManagedProfile(mContext)).thenReturn(WORK_PROFILE_USER_HANDLE);
172         when(mSettingsFacade.isDuringSetupWizard(mContext)).thenReturn(true);
173         PolicyComplianceUtils policyComplianceUtils = new PolicyComplianceUtils();
174 
175         mProvisioningIntentProvider.maybeLaunchDpc(
176                 LEGACY_FLOW_PARAMS_WITH_PROVISIONING_TRIGGER,
177                 WORK_PROFILE_USER_HANDLE.getIdentifier(), mUtils, mContext,
178                 mProvisioningAnalyticsTracker, policyComplianceUtils, mSettingsFacade);
179 
180         ArgumentCaptor<Intent> intentCaptor = ArgumentCaptor.forClass(Intent.class);
181         verify(mContext).startActivityAsUser(intentCaptor.capture(), any());
182         verify(mProvisioningAnalyticsTracker).logDpcSetupStarted(any(), any());
183         assertThat(intentCaptor.getValue().getAction()).isEqualTo(ACTION_PROVISIONING_SUCCESSFUL);
184     }
185 
186     @Test
maybeLaunchDpc_cannotResolveIntent()187     public void maybeLaunchDpc_cannotResolveIntent() {
188         when(mUtils.canResolveIntentAsUser(any(), any(), anyInt())).thenReturn(false);
189 
190         mProvisioningIntentProvider.maybeLaunchDpc(LEGACY_FLOW_PARAMS, 0, mUtils, mContext,
191                 mProvisioningAnalyticsTracker, mPolicyComplianceUtils, mSettingsFacade);
192 
193         verify(mContext, never()).startActivityAsUser(any(), any());
194         verify(mProvisioningAnalyticsTracker, never()).logDpcSetupStarted(any(), any());
195     }
196 
197     @Test
createProvisioningIntent_success()198     public void createProvisioningIntent_success() {
199         Intent intent = mProvisioningIntentProvider
200                 .createProvisioningCompleteIntent(LEGACY_FLOW_PARAMS, 0, mUtils, mContext);
201 
202         assertThat(intent.getAction()).isEqualTo(ACTION_PROFILE_PROVISIONING_COMPLETE);
203         assertThat(intent.getComponent()).isEqualTo(DEVICE_ADMIN_COMPONENT_NAME);
204         assertThat(intent.<PersistableBundle>getParcelableExtra(
205                 EXTRA_PROVISIONING_ADMIN_EXTRAS_BUNDLE)).isEqualTo(ADMIN_EXTRAS_BUNDLE);
206     }
207 
208     @Test
createProvisioningIntent_cannotFindAdmin()209     public void createProvisioningIntent_cannotFindAdmin()
210             throws IllegalProvisioningArgumentException {
211         ProvisioningParams provisioningParams = new ProvisioningParams.Builder()
212                 .setDeviceAdminPackageName(DEVICE_ADMIN_PACKAGE_NAME)
213                 .setProvisioningAction(ACTION_PROVISION_MANAGED_PROFILE)
214                 .build();
215         when(mUtils.findDeviceAdmin(eq(DEVICE_ADMIN_PACKAGE_NAME), any(), any(), anyInt()))
216                 .thenThrow(IllegalProvisioningArgumentException.class);
217 
218         assertThat(mProvisioningIntentProvider.createProvisioningCompleteIntent(
219                 provisioningParams, 0, mUtils, mContext)).isNull();
220     }
221 
makeProvisioningSuccessfulIntentResolvable()222     private void makeProvisioningSuccessfulIntentResolvable() {
223         when(mUtils.canResolveIntentAsUser(any(), any(Intent.class), anyInt()))
224                 .thenAnswer(invocation -> {
225                     Intent intentArgument = invocation.getArgument(/* index= */ 1);
226                     return intentArgument.getAction().equals(ACTION_PROVISIONING_SUCCESSFUL);
227                 });
228     }
229 }
230