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