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