RetailDemoModeServiceTest.java revision 233cc3ef10d025276ffa280e8d4b58969860ac24
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 17package com.android.server.retaildemo; 18 19import static com.android.server.retaildemo.RetailDemoModeService.SYSTEM_PROPERTY_RETAIL_DEMO_ENABLED; 20 21import static org.junit.Assert.assertEquals; 22import static org.junit.Assert.assertTrue; 23import static org.mockito.Matchers.any; 24import static org.mockito.Matchers.anyInt; 25import static org.mockito.Matchers.anyString; 26import static org.mockito.Matchers.argThat; 27import static org.mockito.Matchers.eq; 28import static org.mockito.Mockito.verify; 29import static org.mockito.Mockito.when; 30 31import android.Manifest; 32import android.app.ActivityManagerInternal; 33import android.app.Notification; 34import android.app.NotificationManager; 35import android.app.RetailDemoModeServiceInternal; 36import android.content.BroadcastReceiver; 37import android.content.ContentResolver; 38import android.content.Context; 39import android.content.Intent; 40import android.content.IntentFilter; 41import android.content.pm.ActivityInfo; 42import android.content.pm.IPackageManager; 43import android.content.pm.PackageManager; 44import android.content.pm.ResolveInfo; 45import android.content.pm.UserInfo; 46import android.content.res.Configuration; 47import android.media.AudioManager; 48import android.net.Uri; 49import android.os.FileUtils; 50import android.os.Handler; 51import android.os.Looper; 52import android.os.UserHandle; 53import android.os.UserManager; 54import android.provider.CallLog; 55import android.provider.MediaStore; 56import android.provider.Settings; 57import android.support.test.InstrumentationRegistry; 58import android.support.test.filters.SmallTest; 59import android.test.mock.MockContentProvider; 60import android.test.mock.MockContentResolver; 61import android.util.ArrayMap; 62 63import com.android.internal.util.FakeSettingsProvider; 64import com.android.internal.widget.LockPatternUtils; 65import com.android.server.LocalServices; 66import com.android.server.SystemService; 67import com.android.server.retaildemo.RetailDemoModeService.Injector; 68 69import org.hamcrest.Description; 70import org.junit.After; 71import org.junit.Before; 72import org.junit.Test; 73import org.junit.runner.RunWith; 74import org.junit.runners.JUnit4; 75import org.mockito.ArgumentCaptor; 76import org.mockito.ArgumentMatcher; 77import org.mockito.Mock; 78import org.mockito.Mockito; 79import org.mockito.MockitoAnnotations; 80 81import java.io.File; 82import java.util.concurrent.CountDownLatch; 83import java.util.concurrent.TimeUnit; 84 85@RunWith(JUnit4.class) 86@SmallTest 87public class RetailDemoModeServiceTest { 88 private static final int TEST_DEMO_USER = 111; 89 private static final long SETUP_COMPLETE_TIMEOUT_MS = 2000; // 2 sec 90 private static final String TEST_CAMERA_PKG = "test.cameraapp"; 91 private static final String TEST_PRELOADS_DIR_NAME = "test_preloads"; 92 93 private @Mock Context mContext; 94 private @Mock UserManager mUm; 95 private @Mock PackageManager mPm; 96 private @Mock IPackageManager mIpm; 97 private @Mock NotificationManager mNm; 98 private @Mock ActivityManagerInternal mAmi; 99 private @Mock AudioManager mAudioManager; 100 private @Mock LockPatternUtils mLockPatternUtils; 101 private MockPreloadAppsInstaller mPreloadAppsInstaller; 102 private MockContentResolver mContentResolver; 103 private MockContactsProvider mContactsProvider; 104 private Configuration mConfiguration; 105 private File mTestPreloadsDir; 106 private CountDownLatch mLatch; 107 108 private RetailDemoModeService mService; 109 private TestInjector mInjector; 110 111 @Before 112 public void setUp() throws Exception { 113 MockitoAnnotations.initMocks(this); 114 mContentResolver = new MockContentResolver(mContext); 115 mContentResolver.addProvider(Settings.AUTHORITY, new FakeSettingsProvider()); 116 mContactsProvider = new MockContactsProvider(mContext); 117 mContentResolver.addProvider(CallLog.AUTHORITY, mContactsProvider); 118 when(mContext.getContentResolver()).thenReturn(mContentResolver); 119 mPreloadAppsInstaller = new MockPreloadAppsInstaller(mContext); 120 mConfiguration = new Configuration(); 121 mTestPreloadsDir = new File(InstrumentationRegistry.getContext().getFilesDir(), 122 TEST_PRELOADS_DIR_NAME); 123 124 Settings.Global.putString(mContentResolver, 125 Settings.Global.RETAIL_DEMO_MODE_CONSTANTS, ""); 126 Settings.Global.putInt(mContentResolver, 127 Settings.Global.DEVICE_PROVISIONED, 1); 128 Settings.Global.putInt(mContentResolver, 129 Settings.Global.DEVICE_DEMO_MODE, 1); 130 // Initialize RetailDemoModeService 131 mInjector = new TestInjector(); 132 mService = new RetailDemoModeService(mInjector); 133 mService.onStart(); 134 } 135 136 @After 137 public void tearDown() { 138 // Remove the RetailDemoModeServiceInternal from LocalServices which would've been 139 // added during initialization of RetailDemoModeService in setUp(). 140 LocalServices.removeServiceForTest(RetailDemoModeServiceInternal.class); 141 FileUtils.deleteContentsAndDir(mTestPreloadsDir); 142 } 143 144 @Test 145 public void testDemoUserSetup() throws Exception { 146 mService.onBootPhase(SystemService.PHASE_THIRD_PARTY_APPS_CAN_START); 147 148 final ArgumentCaptor<IntentFilter> intentFilter = 149 ArgumentCaptor.forClass(IntentFilter.class); 150 verify(mContext).registerReceiver(any(BroadcastReceiver.class), intentFilter.capture()); 151 assertTrue("Not registered for " + Intent.ACTION_SCREEN_OFF, 152 intentFilter.getValue().hasAction(Intent.ACTION_SCREEN_OFF)); 153 154 mLatch = new CountDownLatch(1); 155 156 mService.onBootPhase(SystemService.PHASE_BOOT_COMPLETED); 157 assertEquals(SYSTEM_PROPERTY_RETAIL_DEMO_ENABLED + " property not set", 158 "1", mInjector.systemPropertiesGet(SYSTEM_PROPERTY_RETAIL_DEMO_ENABLED)); 159 160 final UserInfo userInfo = new UserInfo(); 161 userInfo.id = TEST_DEMO_USER; 162 when(mUm.createUser(anyString(), anyInt())).thenReturn(userInfo); 163 mInjector.setDemoUserId(TEST_DEMO_USER); 164 setCameraPackage(TEST_CAMERA_PKG); 165 // Wait for the setup to complete. 166 mLatch.await(SETUP_COMPLETE_TIMEOUT_MS, TimeUnit.MILLISECONDS); 167 ArgumentCaptor<Integer> flags = ArgumentCaptor.forClass(Integer.class); 168 verify(mUm).createUser(anyString(), flags.capture()); 169 assertTrue("FLAG_DEMO not set during user creation", 170 (flags.getValue() & UserInfo.FLAG_DEMO) != 0); 171 assertTrue("FLAG_EPHEMERAL not set during user creation", 172 (flags.getValue() & UserInfo.FLAG_EPHEMERAL) != 0); 173 // Verify if necessary restrictions are being set. 174 final UserHandle user = UserHandle.of(TEST_DEMO_USER); 175 verify(mUm).setUserRestriction(UserManager.DISALLOW_CONFIG_WIFI, true, user); 176 verify(mUm).setUserRestriction(UserManager.DISALLOW_INSTALL_UNKNOWN_SOURCES, true, user); 177 verify(mUm).setUserRestriction(UserManager.DISALLOW_CONFIG_MOBILE_NETWORKS, true, user); 178 verify(mUm).setUserRestriction(UserManager.DISALLOW_USB_FILE_TRANSFER, true, user); 179 verify(mUm).setUserRestriction(UserManager.DISALLOW_MODIFY_ACCOUNTS, true, user); 180 verify(mUm).setUserRestriction(UserManager.DISALLOW_CONFIG_BLUETOOTH, true, user); 181 verify(mUm).setUserRestriction(UserManager.DISALLOW_OUTGOING_CALLS, false, user); 182 verify(mUm).setUserRestriction(UserManager.DISALLOW_SAFE_BOOT, true, UserHandle.SYSTEM); 183 // Verify if necessary settings are updated. 184 assertEquals("SKIP_FIRST_USE_HINTS setting is not set for demo user", 185 Settings.Secure.getIntForUser(mContentResolver, 186 Settings.Secure.SKIP_FIRST_USE_HINTS, TEST_DEMO_USER), 187 1); 188 assertEquals("PACKAGE_VERIFIER_ENABLE settings should be set to 0 for demo user", 189 Settings.Global.getInt(mContentResolver, 190 Settings.Global.PACKAGE_VERIFIER_ENABLE), 191 0); 192 // Verify if camera is granted location permission. 193 verify(mPm).grantRuntimePermission(TEST_CAMERA_PKG, 194 Manifest.permission.ACCESS_FINE_LOCATION, user); 195 // Verify call logs are cleared. 196 assertTrue("Call logs should be deleted", mContactsProvider.isCallLogDeleted()); 197 } 198 199 @Test 200 public void testSettingsObserver() throws Exception { 201 final RetailDemoModeService.SettingsObserver observer = 202 mService.new SettingsObserver(new Handler(Looper.getMainLooper())); 203 final Uri deviceDemoModeUri = Settings.Global.getUriFor(Settings.Global.DEVICE_DEMO_MODE); 204 // Settings.Global.DEVICE_DEMO_MODE has been set to 1 initially. 205 observer.onChange(false, deviceDemoModeUri); 206 assertEquals(SYSTEM_PROPERTY_RETAIL_DEMO_ENABLED + " property not set", 207 "1", mInjector.systemPropertiesGet(SYSTEM_PROPERTY_RETAIL_DEMO_ENABLED)); 208 209 new File(mTestPreloadsDir, "dir1").mkdirs(); 210 new File(mTestPreloadsDir, "file1").createNewFile(); 211 Settings.Global.putInt(mContentResolver, Settings.Global.DEVICE_DEMO_MODE, 0); 212 observer.onChange(false, deviceDemoModeUri); 213 Thread.sleep(20); // Wait for the deletion to complete. 214 // verify that the preloaded directory is emptied. 215 assertEquals("Preloads directory is not emptied", 216 0, mTestPreloadsDir.list().length); 217 } 218 219 @Test 220 public void testSwitchToDemoUser() { 221 // To make the RetailDemoModeService update it's internal state. 222 mService.onBootPhase(SystemService.PHASE_THIRD_PARTY_APPS_CAN_START); 223 final RetailDemoModeService.SettingsObserver observer = 224 mService.new SettingsObserver(new Handler(Looper.getMainLooper())); 225 observer.onChange(false, Settings.Global.getUriFor(Settings.Global.DEVICE_DEMO_MODE)); 226 227 final UserInfo userInfo = new UserInfo(TEST_DEMO_USER, "demo_user", 228 UserInfo.FLAG_DEMO | UserInfo.FLAG_EPHEMERAL); 229 when(mUm.getUserInfo(TEST_DEMO_USER)).thenReturn(userInfo); 230 final int minVolume = -111; 231 for (int stream : RetailDemoModeService.VOLUME_STREAMS_TO_MUTE) { 232 when(mAudioManager.getStreamMinVolume(stream)).thenReturn(minVolume); 233 } 234 235 mService.onSwitchUser(TEST_DEMO_USER); 236 verify(mAmi).updatePersistentConfigurationForUser(mConfiguration, TEST_DEMO_USER); 237 for (int stream : RetailDemoModeService.VOLUME_STREAMS_TO_MUTE) { 238 verify(mAudioManager).setStreamVolume(stream, minVolume, 0); 239 } 240 verify(mLockPatternUtils).setLockScreenDisabled(true, TEST_DEMO_USER); 241 } 242 243 private void setCameraPackage(String pkgName) { 244 final ResolveInfo ri = new ResolveInfo(); 245 final ActivityInfo ai = new ActivityInfo(); 246 ai.packageName = pkgName; 247 ri.activityInfo = ai; 248 when(mPm.resolveActivityAsUser( 249 argThat(new IntentMatcher(MediaStore.ACTION_IMAGE_CAPTURE)), 250 anyInt(), 251 eq(TEST_DEMO_USER))).thenReturn(ri); 252 } 253 254 private class IntentMatcher extends ArgumentMatcher<Intent> { 255 private final Intent mIntent; 256 257 IntentMatcher(String action) { 258 mIntent = new Intent(action); 259 } 260 261 @Override 262 public boolean matches(Object argument) { 263 if (argument instanceof Intent) { 264 return ((Intent) argument).filterEquals(mIntent); 265 } 266 return false; 267 } 268 269 @Override 270 public void describeTo(Description description) { 271 description.appendText("Expected: " + mIntent); 272 } 273 } 274 275 private class MockContactsProvider extends MockContentProvider { 276 private boolean mCallLogDeleted; 277 278 MockContactsProvider(Context context) { 279 super(context); 280 } 281 282 @Override 283 public int delete(Uri uri, String selection, String[] selectionArgs) { 284 if (CallLog.Calls.CONTENT_URI.equals(uri)) { 285 mCallLogDeleted = true; 286 } 287 return 0; 288 } 289 290 public boolean isCallLogDeleted() { 291 return mCallLogDeleted; 292 } 293 } 294 295 private class MockPreloadAppsInstaller extends PreloadAppsInstaller { 296 MockPreloadAppsInstaller(Context context) { 297 super(context); 298 } 299 300 @Override 301 public void installApps(int userId) { 302 } 303 } 304 305 private class TestInjector extends Injector { 306 private ArrayMap<String, String> mSystemProperties = new ArrayMap<>(); 307 private int mDemoUserId = UserHandle.USER_NULL; 308 309 TestInjector() { 310 super(mContext); 311 } 312 313 @Override 314 Context getContext() { 315 return mContext; 316 } 317 318 @Override 319 UserManager getUserManager() { 320 return mUm; 321 } 322 323 @Override 324 void switchUser(int userId) { 325 if (mLatch != null) { 326 mLatch.countDown(); 327 } 328 } 329 330 @Override 331 AudioManager getAudioManager() { 332 return mAudioManager; 333 } 334 335 @Override 336 NotificationManager getNotificationManager() { 337 return mNm; 338 } 339 340 @Override 341 ActivityManagerInternal getActivityManagerInternal() { 342 return mAmi; 343 } 344 345 @Override 346 PackageManager getPackageManager() { 347 return mPm; 348 } 349 350 @Override 351 IPackageManager getIPackageManager() { 352 return mIpm; 353 } 354 355 @Override 356 ContentResolver getContentResolver() { 357 return mContentResolver; 358 } 359 360 @Override 361 PreloadAppsInstaller getPreloadAppsInstaller() { 362 return mPreloadAppsInstaller; 363 } 364 365 @Override 366 void systemPropertiesSet(String key, String value) { 367 mSystemProperties.put(key, value); 368 } 369 370 @Override 371 void turnOffAllFlashLights(String[] cameraIdsWithFlash) { 372 } 373 374 @Override 375 void initializeWakeLock() { 376 } 377 378 @Override 379 boolean isWakeLockHeld() { 380 return false; 381 } 382 383 @Override 384 void acquireWakeLock() { 385 } 386 387 @Override 388 void releaseWakeLock() { 389 } 390 391 @Override 392 void logSessionDuration(int duration) { 393 } 394 395 @Override 396 void logSessionCount(int count) { 397 } 398 399 @Override 400 Configuration getSystemUsersConfiguration() { 401 return mConfiguration; 402 } 403 404 @Override 405 LockPatternUtils getLockPatternUtils() { 406 return mLockPatternUtils; 407 } 408 409 @Override 410 Notification createResetNotification() { 411 return null; 412 } 413 414 @Override 415 File getDataPreloadsDirectory() { 416 return mTestPreloadsDir; 417 } 418 419 String systemPropertiesGet(String key) { 420 return mSystemProperties.get(key); 421 } 422 423 void setDemoUserId(int userId) { 424 mDemoUserId = userId; 425 } 426 } 427} 428