RetailDemoModeServiceTest.java revision 28537b6ae92a3211b5993ac00482ef905a911244
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.net.wifi.WifiManager;
50import android.os.FileUtils;
51import android.os.Handler;
52import android.os.Looper;
53import android.os.UserHandle;
54import android.os.UserManager;
55import android.provider.CallLog;
56import android.provider.MediaStore;
57import android.provider.Settings;
58import android.support.test.InstrumentationRegistry;
59import android.support.test.filters.SmallTest;
60import android.test.mock.MockContentProvider;
61import android.test.mock.MockContentResolver;
62import android.util.ArrayMap;
63
64import com.android.internal.util.FakeSettingsProvider;
65import com.android.internal.widget.LockPatternUtils;
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.MockitoAnnotations;
79
80import java.io.File;
81import java.util.concurrent.CountDownLatch;
82import java.util.concurrent.TimeUnit;
83
84@RunWith(JUnit4.class)
85@SmallTest
86public class RetailDemoModeServiceTest {
87    private static final int TEST_DEMO_USER = 111;
88    private static final long SETUP_COMPLETE_TIMEOUT_MS = 2000; // 2 sec
89    private static final String TEST_CAMERA_PKG = "test.cameraapp";
90    private static final String TEST_PRELOADS_DIR_NAME = "test_preloads";
91
92    private @Mock Context mContext;
93    private @Mock UserManager mUm;
94    private @Mock PackageManager mPm;
95    private @Mock IPackageManager mIpm;
96    private @Mock NotificationManager mNm;
97    private @Mock ActivityManagerInternal mAmi;
98    private @Mock AudioManager mAudioManager;
99    private @Mock WifiManager mWifiManager;
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        FileUtils.deleteContentsAndDir(mTestPreloadsDir);
139    }
140
141    @Test
142    public void testDemoUserSetup() throws Exception {
143        mService.onBootPhase(SystemService.PHASE_THIRD_PARTY_APPS_CAN_START);
144
145        mLatch = new CountDownLatch(1);
146        final UserInfo userInfo = new UserInfo();
147        userInfo.id = TEST_DEMO_USER;
148        when(mUm.createUser(anyString(), anyInt())).thenReturn(userInfo);
149
150        mService.onBootPhase(SystemService.PHASE_BOOT_COMPLETED);
151        assertEquals(SYSTEM_PROPERTY_RETAIL_DEMO_ENABLED + " property not set",
152                "1", mInjector.systemPropertiesGet(SYSTEM_PROPERTY_RETAIL_DEMO_ENABLED));
153
154        final ArgumentCaptor<IntentFilter> intentFilter =
155                ArgumentCaptor.forClass(IntentFilter.class);
156        verify(mContext).registerReceiver(any(BroadcastReceiver.class), intentFilter.capture());
157        assertTrue("Not registered for " + Intent.ACTION_SCREEN_OFF,
158                intentFilter.getValue().hasAction(Intent.ACTION_SCREEN_OFF));
159
160        setCameraPackage(TEST_CAMERA_PKG);
161        // Wait for the setup to complete.
162        mLatch.await(SETUP_COMPLETE_TIMEOUT_MS, TimeUnit.MILLISECONDS);
163        ArgumentCaptor<Integer> flags = ArgumentCaptor.forClass(Integer.class);
164        verify(mUm).createUser(anyString(), flags.capture());
165        assertTrue("FLAG_DEMO not set during user creation",
166                (flags.getValue() & UserInfo.FLAG_DEMO) != 0);
167        assertTrue("FLAG_EPHEMERAL not set during user creation",
168                (flags.getValue() & UserInfo.FLAG_EPHEMERAL) != 0);
169        // Verify if necessary restrictions are being set.
170        final UserHandle user = UserHandle.of(TEST_DEMO_USER);
171        verify(mUm).setUserRestriction(UserManager.DISALLOW_CONFIG_WIFI, true, user);
172        verify(mUm).setUserRestriction(UserManager.DISALLOW_INSTALL_UNKNOWN_SOURCES, true, user);
173        verify(mUm).setUserRestriction(UserManager.DISALLOW_CONFIG_MOBILE_NETWORKS, true, user);
174        verify(mUm).setUserRestriction(UserManager.DISALLOW_USB_FILE_TRANSFER, true, user);
175        verify(mUm).setUserRestriction(UserManager.DISALLOW_MODIFY_ACCOUNTS, true, user);
176        verify(mUm).setUserRestriction(UserManager.DISALLOW_CONFIG_BLUETOOTH, true, user);
177        verify(mUm).setUserRestriction(UserManager.DISALLOW_OUTGOING_CALLS, false, user);
178        verify(mUm).setUserRestriction(UserManager.DISALLOW_SAFE_BOOT, true, UserHandle.SYSTEM);
179        // Verify if necessary settings are updated.
180        assertEquals("SKIP_FIRST_USE_HINTS setting is not set for demo user",
181                Settings.Secure.getIntForUser(mContentResolver,
182                        Settings.Secure.SKIP_FIRST_USE_HINTS, TEST_DEMO_USER),
183                1);
184        assertEquals("PACKAGE_VERIFIER_ENABLE settings should be set to 0 for demo user",
185                Settings.Global.getInt(mContentResolver,
186                        Settings.Global.PACKAGE_VERIFIER_ENABLE),
187                0);
188        // Verify if camera is granted location permission.
189        verify(mPm).grantRuntimePermission(TEST_CAMERA_PKG,
190                Manifest.permission.ACCESS_FINE_LOCATION, user);
191        // Verify call logs are cleared.
192        assertTrue("Call logs should be deleted", mContactsProvider.isCallLogDeleted());
193    }
194
195    @Test
196    public void testSettingsObserver_disableDemoMode() throws Exception {
197        final RetailDemoModeService.SettingsObserver observer =
198                mService.new SettingsObserver(new Handler(Looper.getMainLooper()));
199        final Uri deviceDemoModeUri = Settings.Global.getUriFor(Settings.Global.DEVICE_DEMO_MODE);
200        when(mUm.hasUserRestriction(UserManager.DISALLOW_SAFE_BOOT, UserHandle.SYSTEM))
201                .thenReturn(false);
202        Settings.Global.putInt(mContentResolver, Settings.Global.PACKAGE_VERIFIER_ENABLE, 1);
203        // Settings.Global.DEVICE_DEMO_MODE has been set to 1 initially.
204        observer.onChange(false, deviceDemoModeUri);
205        final ArgumentCaptor<BroadcastReceiver> receiver =
206                ArgumentCaptor.forClass(BroadcastReceiver.class);
207        verify(mContext).registerReceiver(receiver.capture(), any(IntentFilter.class));
208
209        Settings.Global.putInt(mContentResolver, Settings.Global.PACKAGE_VERIFIER_ENABLE, 0);
210        new File(mTestPreloadsDir, "dir1").mkdirs();
211        new File(mTestPreloadsDir, "file1").createNewFile();
212        Settings.Global.putInt(mContentResolver, Settings.Global.DEVICE_DEMO_MODE, 0);
213        observer.onChange(false, deviceDemoModeUri);
214        verify(mContext).unregisterReceiver(receiver.getValue());
215        verify(mUm).setUserRestriction(UserManager.DISALLOW_SAFE_BOOT, false, UserHandle.SYSTEM);
216        assertEquals("Package verifier enable value has not been reset", 1,
217                Settings.Global.getInt(mContentResolver, Settings.Global.PACKAGE_VERIFIER_ENABLE));
218        Thread.sleep(20); // Wait for the deletion to complete.
219        // verify that the preloaded directory is emptied.
220        assertEquals("Preloads directory is not emptied",
221                0, mTestPreloadsDir.list().length);
222    }
223
224    @Test
225    public void testSettingsObserver_enableDemoMode() throws Exception {
226        final RetailDemoModeService.SettingsObserver observer =
227                mService.new SettingsObserver(new Handler(Looper.getMainLooper()));
228        final Uri deviceDemoModeUri = Settings.Global.getUriFor(Settings.Global.DEVICE_DEMO_MODE);
229        // Settings.Global.DEVICE_DEMO_MODE has been set to 1 initially.
230        observer.onChange(false, deviceDemoModeUri);
231        assertEquals(SYSTEM_PROPERTY_RETAIL_DEMO_ENABLED + " property not set",
232                "1", mInjector.systemPropertiesGet(SYSTEM_PROPERTY_RETAIL_DEMO_ENABLED));
233
234        final ArgumentCaptor<IntentFilter> intentFilter =
235                ArgumentCaptor.forClass(IntentFilter.class);
236        verify(mContext).registerReceiver(any(BroadcastReceiver.class), intentFilter.capture());
237        assertTrue("Not registered for " + Intent.ACTION_SCREEN_OFF,
238                intentFilter.getValue().hasAction(Intent.ACTION_SCREEN_OFF));
239    }
240
241    @Test
242    public void testSwitchToDemoUser() {
243        // To make the RetailDemoModeService update it's internal state.
244        mService.onBootPhase(SystemService.PHASE_THIRD_PARTY_APPS_CAN_START);
245        final RetailDemoModeService.SettingsObserver observer =
246                mService.new SettingsObserver(new Handler(Looper.getMainLooper()));
247        observer.onChange(false, Settings.Global.getUriFor(Settings.Global.DEVICE_DEMO_MODE));
248
249        final UserInfo userInfo = new UserInfo(TEST_DEMO_USER, "demo_user",
250                UserInfo.FLAG_DEMO | UserInfo.FLAG_EPHEMERAL);
251        when(mUm.getUserInfo(TEST_DEMO_USER)).thenReturn(userInfo);
252        when(mWifiManager.isWifiEnabled()).thenReturn(false);
253        final int minVolume = -111;
254        for (int stream : RetailDemoModeService.VOLUME_STREAMS_TO_MUTE) {
255            when(mAudioManager.getStreamMinVolume(stream)).thenReturn(minVolume);
256        }
257
258        mService.onSwitchUser(TEST_DEMO_USER);
259        verify(mAmi).updatePersistentConfigurationForUser(mConfiguration, TEST_DEMO_USER);
260        for (int stream : RetailDemoModeService.VOLUME_STREAMS_TO_MUTE) {
261            verify(mAudioManager).setStreamVolume(stream, minVolume, 0);
262        }
263        verify(mLockPatternUtils).setLockScreenDisabled(true, TEST_DEMO_USER);
264        verify(mWifiManager).setWifiEnabled(true);
265    }
266
267    private void setCameraPackage(String pkgName) {
268        final ResolveInfo ri = new ResolveInfo();
269        final ActivityInfo ai = new ActivityInfo();
270        ai.packageName = pkgName;
271        ri.activityInfo = ai;
272        when(mPm.resolveActivityAsUser(
273                argThat(new IntentMatcher(MediaStore.ACTION_IMAGE_CAPTURE)),
274                anyInt(),
275                eq(TEST_DEMO_USER))).thenReturn(ri);
276    }
277
278    private class IntentMatcher extends ArgumentMatcher<Intent> {
279        private final Intent mIntent;
280
281        IntentMatcher(String action) {
282            mIntent = new Intent(action);
283        }
284
285        @Override
286        public boolean matches(Object argument) {
287            if (argument instanceof Intent) {
288                return ((Intent) argument).filterEquals(mIntent);
289            }
290            return false;
291        }
292
293        @Override
294        public void describeTo(Description description) {
295            description.appendText("Expected: " + mIntent);
296        }
297    }
298
299    private class MockContactsProvider extends MockContentProvider {
300        private boolean mCallLogDeleted;
301
302        MockContactsProvider(Context context) {
303            super(context);
304        }
305
306        @Override
307        public int delete(Uri uri, String selection, String[] selectionArgs) {
308            if (CallLog.Calls.CONTENT_URI.equals(uri)) {
309                mCallLogDeleted = true;
310            }
311            return 0;
312        }
313
314        public boolean isCallLogDeleted() {
315            return mCallLogDeleted;
316        }
317    }
318
319    private class MockPreloadAppsInstaller extends PreloadAppsInstaller {
320        MockPreloadAppsInstaller(Context context) {
321            super(context);
322        }
323
324        @Override
325        public void installApps(int userId) {
326        }
327    }
328
329    private class TestInjector extends Injector {
330        private ArrayMap<String, String> mSystemProperties = new ArrayMap<>();
331
332        TestInjector() {
333            super(mContext);
334        }
335
336        @Override
337        Context getContext() {
338            return mContext;
339        }
340
341        @Override
342        UserManager getUserManager() {
343            return mUm;
344        }
345
346        @Override
347        WifiManager getWifiManager() {
348            return mWifiManager;
349        }
350
351        @Override
352        void switchUser(int userId) {
353            if (mLatch != null) {
354                mLatch.countDown();
355            }
356        }
357
358        @Override
359        AudioManager getAudioManager() {
360            return mAudioManager;
361        }
362
363        @Override
364        NotificationManager getNotificationManager() {
365            return mNm;
366        }
367
368        @Override
369        ActivityManagerInternal getActivityManagerInternal() {
370            return mAmi;
371        }
372
373        @Override
374        PackageManager getPackageManager() {
375            return mPm;
376        }
377
378        @Override
379        IPackageManager getIPackageManager() {
380            return mIpm;
381        }
382
383        @Override
384        ContentResolver getContentResolver() {
385            return mContentResolver;
386        }
387
388        @Override
389        PreloadAppsInstaller getPreloadAppsInstaller() {
390            return mPreloadAppsInstaller;
391        }
392
393        @Override
394        void systemPropertiesSet(String key, String value) {
395            mSystemProperties.put(key, value);
396        }
397
398        @Override
399        void turnOffAllFlashLights(String[] cameraIdsWithFlash) {
400        }
401
402        @Override
403        void initializeWakeLock() {
404        }
405
406        @Override
407        void destroyWakeLock() {
408        }
409
410        @Override
411        boolean isWakeLockHeld() {
412            return false;
413        }
414
415        @Override
416        void acquireWakeLock() {
417        }
418
419        @Override
420        void releaseWakeLock() {
421        }
422
423        @Override
424        void logSessionDuration(int duration) {
425        }
426
427        @Override
428        void logSessionCount(int count) {
429        }
430
431        @Override
432        Configuration getSystemUsersConfiguration() {
433            return mConfiguration;
434        }
435
436        @Override
437        LockPatternUtils getLockPatternUtils() {
438            return mLockPatternUtils;
439        }
440
441        @Override
442        Notification createResetNotification() {
443            return null;
444        }
445
446        @Override
447        File getDataPreloadsDirectory() {
448            return mTestPreloadsDir;
449        }
450
451        @Override
452        void publishLocalService(RetailDemoModeService service,
453                RetailDemoModeServiceInternal localService) {
454        }
455
456        String systemPropertiesGet(String key) {
457            return mSystemProperties.get(key);
458        }
459    }
460}
461