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.uiflows;
17 
18 import static android.app.admin.DevicePolicyManager.ACTION_PROVISION_MANAGED_DEVICE;
19 import static android.app.admin.DevicePolicyManager.ACTION_PROVISION_MANAGED_PROFILE;
20 import static org.mockito.Mockito.any;
21 import static org.mockito.Mockito.anyInt;
22 import static org.mockito.Mockito.eq;
23 import static org.mockito.Mockito.never;
24 import static org.mockito.Mockito.verify;
25 import static org.mockito.Mockito.when;
26 
27 import android.app.Notification;
28 import android.app.NotificationManager;
29 import android.content.ComponentName;
30 import android.content.Context;
31 import android.content.Intent;
32 import android.content.res.Resources;
33 import android.content.pm.ApplicationInfo;
34 import android.content.pm.PackageManager;
35 import android.os.Handler;
36 import android.os.Looper;
37 import android.test.AndroidTestCase;
38 import android.test.suitebuilder.annotation.SmallTest;
39 
40 import com.android.managedprovisioning.IntentStore;
41 import com.android.managedprovisioning.common.Globals;
42 import com.android.managedprovisioning.common.Utils;
43 import com.android.managedprovisioning.model.ProvisioningParams;
44 import com.android.managedprovisioning.parser.MessageParser;
45 
46 import java.util.concurrent.Semaphore;
47 import java.util.concurrent.TimeUnit;
48 import org.mockito.ArgumentCaptor;
49 import org.mockito.Mock;
50 import org.mockito.MockitoAnnotations;
51 
52 @SmallTest
53 public class EncryptionControllerTest extends AndroidTestCase {
54     private static final int TEST_USER_ID = 10;
55     private static final String MP_PACKAGE_NAME = "com.android.managedprovisioning";
56     private static final ComponentName TEST_HOME_RECEIVER = new ComponentName(MP_PACKAGE_NAME,
57             ".HomeReceiverActivity");
58     private static final String TEST_MDM_PACKAGE = "com.admin.test";
59     private static final String TEST_STRING = "Test";
60     private static final int RESUME_PROVISIONING_TIMEOUT_MS = 1000;
61 
62     @Mock private Context mContext;
63     @Mock private IntentStore mIntentStore;
64     @Mock private Utils mUtils;
65     @Mock private Resources mResources;
66     @Mock private PackageManager mPackageManager;
67     @Mock private EncryptionController.ResumeNotificationHelper mResumeNotificationHelper;
68 
69     private EncryptionController mController;
70     private MessageParser mMessageParser;
71     private Intent mIntent;
72 
73     @Override
setUp()74     public void setUp() {
75         // this is necessary for mockito to work
76         System.setProperty("dexmaker.dexcache", getContext().getCacheDir().toString());
77 
78         MockitoAnnotations.initMocks(this);
79 
80         mMessageParser = new MessageParser();
81 
82         when(mUtils.isPhysicalDeviceEncrypted()).thenReturn(true);
83         when(mContext.getApplicationContext()).thenReturn(mContext);
84         when(mContext.getPackageManager()).thenReturn(mPackageManager);
85 
86         mController = new EncryptionController(mContext, mIntentStore, mUtils, mMessageParser,
87                 TEST_HOME_RECEIVER, mResumeNotificationHelper, TEST_USER_ID);
88     }
89 
testSetEncryptionReminder_duringSuw()90     public void testSetEncryptionReminder_duringSuw() {
91         final String action = ACTION_PROVISION_MANAGED_DEVICE;
92         // GIVEN a set of parameters to be stored for resumption
93         // WHEN setting an encryption reminder
94         mController.setEncryptionReminder(createAndStoreProvisioningParams(action));
95         // THEN the intent is stored in IntentStore and the HOME receiver is enabled
96         ArgumentCaptor<Intent> intentCaptor = ArgumentCaptor.forClass(Intent.class);
97         verify(mIntentStore).save(intentCaptor.capture());
98         Intent intent = intentCaptor.getValue();
99         assertEquals(Globals.ACTION_RESUME_PROVISIONING, intent.getAction());
100         assertEquals(action, intent.getStringExtra(MessageParser.EXTRA_PROVISIONING_ACTION));
101         verify(mUtils).enableComponent(TEST_HOME_RECEIVER, TEST_USER_ID);
102         verify(mPackageManager).flushPackageRestrictionsAsUser(TEST_USER_ID);
103     }
104 
testSetEncryptionReminder_afterSuw()105     public void testSetEncryptionReminder_afterSuw() {
106         final String action = ACTION_PROVISION_MANAGED_PROFILE;
107         // GIVEN a set of parameters to be stored for resumption and user setup has been completed
108         // on the given user
109         when(mUtils.isUserSetupCompleted(mContext)).thenReturn(true);
110         // WHEN setting an encryption reminder
111         mController.setEncryptionReminder(createAndStoreProvisioningParams(action));
112         // THEN the intent is stored in IntentStore and the HOME receiver is enabled
113         ArgumentCaptor<Intent> intentCaptor = ArgumentCaptor.forClass(Intent.class);
114         verify(mIntentStore).save(intentCaptor.capture());
115         Intent intent = intentCaptor.getValue();
116         assertEquals(Globals.ACTION_RESUME_PROVISIONING, intent.getAction());
117         assertEquals(action, intent.getStringExtra(MessageParser.EXTRA_PROVISIONING_ACTION));
118         verify(mUtils, never()).enableComponent(any(ComponentName.class), anyInt());
119     }
120 
testResumeProvisioning_profileOwnerAfterSuw()121     public void testResumeProvisioning_profileOwnerAfterSuw() throws Exception {
122         // GIVEN an intent was stored to resume managed profile provisioning after SUW
123         when(mUtils.isUserSetupCompleted(mContext)).thenReturn(true);
124         createAndStoreProvisioningParams(ACTION_PROVISION_MANAGED_PROFILE);
125         // WHEN resuming provisioning
126         runResumeProvisioningOnUiThread();
127         // THEN a resume notification should be posted and no activity should be started
128         verify(mResumeNotificationHelper).showResumeNotification(any(Intent.class));
129         verify(mContext, never()).startActivity(any(Intent.class));
130     }
131 
testResumeProvisioning_profileOwnerDuringSuw()132     public void testResumeProvisioning_profileOwnerDuringSuw() throws Exception {
133         // GIVEN an intent was stored to resume managed profile provisioning during SUW
134         createAndStoreProvisioningParams(ACTION_PROVISION_MANAGED_PROFILE);
135         // WHEN resuming provisioning
136         runResumeProvisioningOnUiThread();
137         // THEN the PreProvisioningActivity should be started and no notification should be posted
138         verify(mContext).startActivity(mIntent);
139         verify(mResumeNotificationHelper, never()).showResumeNotification(any(Intent.class));
140     }
141 
testResumeProvisioningTwice_profileOwnerDuringSuw()142     public void testResumeProvisioningTwice_profileOwnerDuringSuw() throws Exception {
143         // GIVEN an intent was stored to resume managed profile provisioning during SUW
144         createAndStoreProvisioningParams(ACTION_PROVISION_MANAGED_PROFILE);
145         // GIVEN resuming provisioning was called once.
146         runResumeProvisioningOnUiThread();
147         // // WHEN resuming provisioning is called again.
148         runResumeProvisioningOnUiThread();
149         // THEN the PreProvisioningActivity should only be started once and no notification should
150         // be posted
151         verify(mContext).startActivity(mIntent);
152         verify(mResumeNotificationHelper, never()).showResumeNotification(any(Intent.class));
153     }
154 
testResumeProvisioning_deviceOwner()155     public void testResumeProvisioning_deviceOwner() throws Exception {
156         // GIVEN an intent was stored to resume device owner provisioning during SUW
157         createAndStoreProvisioningParams(ACTION_PROVISION_MANAGED_DEVICE);
158         // WHEN resuming provisioning
159         runResumeProvisioningOnUiThread();
160         // THEN the PreProvisioningActivity should be started and no notification should be posted
161         verify(mContext).startActivity(mIntent);
162         verify(mResumeNotificationHelper, never()).showResumeNotification(any(Intent.class));
163     }
164 
testResumeProvisioning_deviceNotEncrypted()165     public void testResumeProvisioning_deviceNotEncrypted() throws Exception {
166         // GIVEN an intent was stored to resume device owner provisioning, but the device
167         // is not encrypted
168         when(mUtils.isPhysicalDeviceEncrypted()).thenReturn(false);
169         createAndStoreProvisioningParams(ACTION_PROVISION_MANAGED_DEVICE);
170         // WHEN resuming provisioning
171         runResumeProvisioningOnUiThread();
172         // THEN nothing should happen
173         verify(mContext, never()).startActivity(any(Intent.class));
174         verify(mResumeNotificationHelper, never()).showResumeNotification(any(Intent.class));
175     }
176 
testResumeProvisioning_noIntent()177     public void testResumeProvisioning_noIntent() throws Exception {
178         // GIVEN an intent was stored to resume device owner provisioning, but the device
179         // is not encrypted
180         when(mIntentStore.load()).thenReturn(null);
181         // WHEN resuming provisioning
182         runResumeProvisioningOnUiThread();
183         // THEN nothing should happen
184         verify(mContext, never()).startActivity(any(Intent.class));
185         verify(mResumeNotificationHelper, never()).showResumeNotification(any(Intent.class));
186     }
187 
testCancelProvisioningReminder()188     public void testCancelProvisioningReminder() {
189         // WHEN cancelling the provisioning reminder
190         mController.cancelEncryptionReminder();
191         // THEN the intent store should be cleared and the HOME receiver disabled
192         verify(mIntentStore).clear();
193         verify(mUtils).disableComponent(TEST_HOME_RECEIVER, TEST_USER_ID);
194     }
195 
createAndStoreProvisioningParams(String action)196     private ProvisioningParams createAndStoreProvisioningParams(String action) {
197         ProvisioningParams params = new ProvisioningParams.Builder()
198                 .setProvisioningAction(action)
199                 .setDeviceAdminPackageName(TEST_MDM_PACKAGE)
200                 .build();
201         mIntent = mMessageParser.getIntentFromProvisioningParams(params);
202         assertEquals(action, mIntent.getStringExtra(MessageParser.EXTRA_PROVISIONING_ACTION));
203         when(mIntentStore.load()).thenReturn(mIntent);
204         return params;
205     }
206 
runResumeProvisioningOnUiThread()207     private void runResumeProvisioningOnUiThread() throws InterruptedException {
208         final Semaphore semaphore = new Semaphore(0);
209         new Handler(Looper.getMainLooper()).post(new Runnable() {
210             @Override
211             public void run() {
212                 mController.resumeProvisioning();
213                 semaphore.release();
214             }
215         });
216         assertTrue("Timeout trying to resume provisioning",
217                 semaphore.tryAcquire(RESUME_PROVISIONING_TIMEOUT_MS, TimeUnit.MILLISECONDS));
218     }
219 }
220