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