RetailDemoModeService.java revision ade08cfaa3853388dd1de65f6e4f29239aeb58ff
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 android.Manifest;
20import android.app.ActivityManager;
21import android.app.ActivityManagerInternal;
22import android.app.AppGlobals;
23import android.app.Notification;
24import android.app.NotificationManager;
25import android.app.PendingIntent;
26import android.app.RetailDemoModeServiceInternal;
27import android.content.BroadcastReceiver;
28import android.content.ComponentName;
29import android.content.ContentResolver;
30import android.content.Context;
31import android.content.DialogInterface;
32import android.content.Intent;
33import android.content.IntentFilter;
34import android.content.pm.IPackageManager;
35import android.content.pm.PackageManager;
36import android.content.pm.ResolveInfo;
37import android.content.pm.UserInfo;
38import android.content.res.Configuration;
39import android.database.ContentObserver;
40import android.hardware.camera2.CameraAccessException;
41import android.hardware.camera2.CameraCharacteristics;
42import android.hardware.camera2.CameraManager;
43import android.media.AudioManager;
44import android.media.AudioSystem;
45import android.net.Uri;
46import android.net.wifi.WifiManager;
47import android.os.Environment;
48import android.os.FileUtils;
49import android.os.Handler;
50import android.os.Looper;
51import android.os.Message;
52import android.os.PowerManager;
53import android.os.RemoteException;
54import android.os.SystemClock;
55import android.os.SystemProperties;
56import android.os.UserHandle;
57import android.os.UserManager;
58import android.provider.CallLog;
59import android.provider.MediaStore;
60import android.provider.Settings;
61import android.text.TextUtils;
62import android.util.KeyValueListParser;
63import android.util.Slog;
64
65import com.android.internal.messages.nano.SystemMessageProto.SystemMessage;
66import com.android.internal.notification.SystemNotificationChannels;
67import com.android.internal.os.BackgroundThread;
68import com.android.internal.R;
69import com.android.internal.annotations.GuardedBy;
70import com.android.internal.annotations.VisibleForTesting;
71import com.android.internal.logging.MetricsLogger;
72import com.android.internal.widget.LockPatternUtils;
73import com.android.server.LocalServices;
74import com.android.server.PreloadsFileCacheExpirationJobService;
75import com.android.server.ServiceThread;
76import com.android.server.SystemService;
77import com.android.server.am.ActivityManagerService;
78import com.android.server.retaildemo.UserInactivityCountdownDialog.OnCountDownExpiredListener;
79
80import java.io.File;
81import java.util.ArrayList;
82
83public class RetailDemoModeService extends SystemService {
84    private static final boolean DEBUG = false;
85
86    private static final String TAG = RetailDemoModeService.class.getSimpleName();
87    private static final String DEMO_USER_NAME = "Demo";
88    private static final String ACTION_RESET_DEMO =
89            "com.android.server.retaildemo.ACTION_RESET_DEMO";
90    @VisibleForTesting
91    static final String SYSTEM_PROPERTY_RETAIL_DEMO_ENABLED = "sys.retaildemo.enabled";
92
93    private static final int MSG_TURN_SCREEN_ON = 0;
94    private static final int MSG_INACTIVITY_TIME_OUT = 1;
95    private static final int MSG_START_NEW_SESSION = 2;
96
97    private static final long SCREEN_WAKEUP_DELAY = 2500;
98    private static final long USER_INACTIVITY_TIMEOUT_MIN = 10000;
99    private static final long USER_INACTIVITY_TIMEOUT_DEFAULT = 90000;
100    private static final long WARNING_DIALOG_TIMEOUT_DEFAULT = 0;
101    private static final long MILLIS_PER_SECOND = 1000;
102
103    @VisibleForTesting
104    static final int[] VOLUME_STREAMS_TO_MUTE = {
105            AudioSystem.STREAM_RING,
106            AudioSystem.STREAM_MUSIC
107    };
108
109    // Tron Vars
110    private static final String DEMO_SESSION_COUNT = "retail_demo_session_count";
111    private static final String DEMO_SESSION_DURATION = "retail_demo_session_duration";
112
113    boolean mDeviceInDemoMode;
114    boolean mIsCarrierDemoMode;
115    int mCurrentUserId = UserHandle.USER_SYSTEM;
116    long mUserInactivityTimeout;
117    long mWarningDialogTimeout;
118    private Injector mInjector;
119    Handler mHandler;
120    private ServiceThread mHandlerThread;
121    private String[] mCameraIdsWithFlash;
122    private PreloadAppsInstaller mPreloadAppsInstaller;
123
124    final Object mActivityLock = new Object();
125    // Whether the newly created demo user has interacted with the screen yet
126    @GuardedBy("mActivityLock")
127    boolean mUserUntouched;
128    @GuardedBy("mActivityLock")
129    long mFirstUserActivityTime;
130    @GuardedBy("mActivityLock")
131    long mLastUserActivityTime;
132
133    private boolean mSafeBootRestrictionInitialState;
134    private int mPackageVerifierEnableInitialState;
135
136    private IntentReceiver mBroadcastReceiver = null;
137
138    private final class IntentReceiver extends BroadcastReceiver {
139        @Override
140        public void onReceive(Context context, Intent intent) {
141            if (!mDeviceInDemoMode) {
142                return;
143            }
144            final String action = intent.getAction();
145            switch (action) {
146                case Intent.ACTION_SCREEN_OFF:
147                    mHandler.removeMessages(MSG_TURN_SCREEN_ON);
148                    mHandler.sendEmptyMessageDelayed(MSG_TURN_SCREEN_ON, SCREEN_WAKEUP_DELAY);
149                    break;
150                case ACTION_RESET_DEMO:
151                    mHandler.sendEmptyMessage(MSG_START_NEW_SESSION);
152                    break;
153            }
154        }
155    };
156
157    final class MainHandler extends Handler {
158
159        MainHandler(Looper looper) {
160            super(looper, null, true);
161        }
162
163        @Override
164        public void handleMessage(Message msg) {
165            if (!mDeviceInDemoMode) {
166                return;
167            }
168            switch (msg.what) {
169                case MSG_TURN_SCREEN_ON:
170                    if (mInjector.isWakeLockHeld()) {
171                        mInjector.releaseWakeLock();
172                    }
173                    mInjector.acquireWakeLock();
174                    break;
175                case MSG_INACTIVITY_TIME_OUT:
176                    if (!mIsCarrierDemoMode && isDemoLauncherDisabled()) {
177                        Slog.i(TAG, "User inactivity timeout reached");
178                        showInactivityCountdownDialog();
179                    }
180                    break;
181                case MSG_START_NEW_SESSION:
182                    if (DEBUG) {
183                        Slog.d(TAG, "Switching to a new demo user");
184                    }
185                    removeMessages(MSG_START_NEW_SESSION);
186                    removeMessages(MSG_INACTIVITY_TIME_OUT);
187                    if (!mIsCarrierDemoMode && mCurrentUserId != UserHandle.USER_SYSTEM) {
188                        logSessionDuration();
189                    }
190
191                    final UserManager um = mInjector.getUserManager();
192                    UserInfo demoUser = null;
193                    if (mIsCarrierDemoMode) {
194                        // Re-use the existing demo user in carrier demo mode.
195                        for (UserInfo user : um.getUsers()) {
196                            if (user.isDemo()) {
197                                demoUser = user;
198                                break;
199                            }
200                        }
201                    }
202
203                    if (demoUser == null) {
204                        // User in carrier demo mode should survive reboots.
205                        final int flags = UserInfo.FLAG_DEMO
206                                | (mIsCarrierDemoMode ? 0 : UserInfo.FLAG_EPHEMERAL);
207                        demoUser = um.createUser(DEMO_USER_NAME, flags);
208                    }
209
210                    if (demoUser != null && mCurrentUserId != demoUser.id) {
211                        setupDemoUser(demoUser);
212                        mInjector.switchUser(demoUser.id);
213                    }
214                    break;
215            }
216        }
217    }
218
219    @VisibleForTesting
220    class SettingsObserver extends ContentObserver {
221
222        private final static String KEY_USER_INACTIVITY_TIMEOUT = "user_inactivity_timeout_ms";
223        private final static String KEY_WARNING_DIALOG_TIMEOUT = "warning_dialog_timeout_ms";
224
225        private final Uri mDeviceDemoModeUri = Settings.Global
226                .getUriFor(Settings.Global.DEVICE_DEMO_MODE);
227        private final Uri mDeviceProvisionedUri = Settings.Global
228                .getUriFor(Settings.Global.DEVICE_PROVISIONED);
229        private final Uri mRetailDemoConstantsUri = Settings.Global
230                .getUriFor(Settings.Global.RETAIL_DEMO_MODE_CONSTANTS);
231
232        private final KeyValueListParser mParser = new KeyValueListParser(',');
233
234        public SettingsObserver(Handler handler) {
235            super(handler);
236        }
237
238        public void register() {
239            final ContentResolver cr = mInjector.getContentResolver();
240            cr.registerContentObserver(mDeviceDemoModeUri, false, this, UserHandle.USER_SYSTEM);
241            cr.registerContentObserver(mDeviceProvisionedUri, false, this, UserHandle.USER_SYSTEM);
242            cr.registerContentObserver(mRetailDemoConstantsUri, false, this,
243                    UserHandle.USER_SYSTEM);
244        }
245
246        @Override
247        public void onChange(boolean selfChange, Uri uri) {
248            if (mRetailDemoConstantsUri.equals(uri)) {
249                refreshTimeoutConstants();
250                return;
251            }
252
253            // If device is provisioned and left demo mode - run the cleanup in demo folder
254            if (isDeviceProvisioned()) {
255                if (UserManager.isDeviceInDemoMode(getContext())) {
256                    startDemoMode();
257                } else {
258                    mInjector.systemPropertiesSet(SYSTEM_PROPERTY_RETAIL_DEMO_ENABLED, "0");
259
260                    // Run on the bg thread to not block the fg thread
261                    BackgroundThread.getHandler().post(() -> {
262                        if (!deletePreloadsFolderContents()) {
263                            Slog.w(TAG, "Failed to delete preloads folder contents");
264                        }
265                        PreloadsFileCacheExpirationJobService.schedule(mInjector.getContext());
266                    });
267
268                    stopDemoMode();
269
270                    if (mInjector.isWakeLockHeld()) {
271                        mInjector.releaseWakeLock();
272                    }
273                }
274            }
275        }
276
277        private void refreshTimeoutConstants() {
278            try {
279                mParser.setString(Settings.Global.getString(mInjector.getContentResolver(),
280                        Settings.Global.RETAIL_DEMO_MODE_CONSTANTS));
281            } catch (IllegalArgumentException exc) {
282                Slog.e(TAG, "Invalid string passed to KeyValueListParser");
283                // Consuming the exception to fall back to default values.
284            }
285            mWarningDialogTimeout = mParser.getLong(KEY_WARNING_DIALOG_TIMEOUT,
286                    WARNING_DIALOG_TIMEOUT_DEFAULT);
287            mUserInactivityTimeout = mParser.getLong(KEY_USER_INACTIVITY_TIMEOUT,
288                    USER_INACTIVITY_TIMEOUT_DEFAULT);
289            mUserInactivityTimeout = Math.max(mUserInactivityTimeout, USER_INACTIVITY_TIMEOUT_MIN);
290        }
291    }
292
293    private void showInactivityCountdownDialog() {
294        UserInactivityCountdownDialog dialog = new UserInactivityCountdownDialog(getContext(),
295                mWarningDialogTimeout, MILLIS_PER_SECOND);
296        dialog.setNegativeButtonClickListener(null);
297        dialog.setPositiveButtonClickListener(new DialogInterface.OnClickListener() {
298            @Override
299            public void onClick(DialogInterface dialog, int which) {
300                mHandler.sendEmptyMessage(MSG_START_NEW_SESSION);
301            }
302        });
303        dialog.setOnCountDownExpiredListener(new OnCountDownExpiredListener() {
304            @Override
305            public void onCountDownExpired() {
306                mHandler.sendEmptyMessage(MSG_START_NEW_SESSION);
307            }
308        });
309        dialog.show();
310    }
311
312    public RetailDemoModeService(Context context) {
313        this(new Injector(context));
314    }
315
316    @VisibleForTesting
317    RetailDemoModeService(Injector injector) {
318        super(injector.getContext());
319
320        mInjector = injector;
321        synchronized (mActivityLock) {
322            mFirstUserActivityTime = mLastUserActivityTime = SystemClock.uptimeMillis();
323        }
324    }
325
326    boolean isDemoLauncherDisabled() {
327        int enabledState = PackageManager.COMPONENT_ENABLED_STATE_DEFAULT;
328        try {
329            final IPackageManager iPm = mInjector.getIPackageManager();
330            final String demoLauncherComponent =
331                    getContext().getString(R.string.config_demoModeLauncherComponent);
332            enabledState = iPm.getComponentEnabledSetting(
333                    ComponentName.unflattenFromString(demoLauncherComponent), mCurrentUserId);
334        } catch (RemoteException re) {
335            Slog.e(TAG, "Error retrieving demo launcher enabled setting", re);
336        }
337        return enabledState == PackageManager.COMPONENT_ENABLED_STATE_DISABLED;
338    }
339
340    private void setupDemoUser(UserInfo userInfo) {
341        final UserManager um = mInjector.getUserManager();
342        final UserHandle user = UserHandle.of(userInfo.id);
343        um.setUserRestriction(UserManager.DISALLOW_CONFIG_WIFI, true, user);
344        um.setUserRestriction(UserManager.DISALLOW_INSTALL_UNKNOWN_SOURCES, true, user);
345        um.setUserRestriction(UserManager.DISALLOW_CONFIG_MOBILE_NETWORKS, true, user);
346        um.setUserRestriction(UserManager.DISALLOW_USB_FILE_TRANSFER, true, user);
347        um.setUserRestriction(UserManager.DISALLOW_MODIFY_ACCOUNTS, true, user);
348        um.setUserRestriction(UserManager.DISALLOW_CONFIG_BLUETOOTH, true, user);
349        // Set this to false because the default is true on user creation
350        um.setUserRestriction(UserManager.DISALLOW_OUTGOING_CALLS, false, user);
351        // Disallow rebooting in safe mode - controlled by user 0
352        um.setUserRestriction(UserManager.DISALLOW_SAFE_BOOT, true, UserHandle.SYSTEM);
353        if (mIsCarrierDemoMode) {
354            // Enable SMS in carrier demo mode.
355            um.setUserRestriction(UserManager.DISALLOW_SMS, false, user);
356        }
357
358        Settings.Secure.putIntForUser(mInjector.getContentResolver(),
359                Settings.Secure.SKIP_FIRST_USE_HINTS, 1, userInfo.id);
360        Settings.Global.putInt(mInjector.getContentResolver(),
361                Settings.Global.PACKAGE_VERIFIER_ENABLE, 0);
362
363        grantRuntimePermissionToCamera(user);
364        clearPrimaryCallLog();
365
366        if (!mIsCarrierDemoMode) {
367            // Enable demo launcher.
368            final String demoLauncher = getContext().getString(
369                    R.string.config_demoModeLauncherComponent);
370            if (!TextUtils.isEmpty(demoLauncher)) {
371                final ComponentName componentToEnable =
372                        ComponentName.unflattenFromString(demoLauncher);
373                final String packageName = componentToEnable.getPackageName();
374                try {
375                    final IPackageManager iPm = AppGlobals.getPackageManager();
376                    iPm.setComponentEnabledSetting(componentToEnable,
377                            PackageManager.COMPONENT_ENABLED_STATE_ENABLED, 0, userInfo.id);
378                    iPm.setApplicationEnabledSetting(packageName,
379                            PackageManager.COMPONENT_ENABLED_STATE_ENABLED, 0, userInfo.id, null);
380                } catch (RemoteException re) {
381                    // Internal, shouldn't happen
382                }
383            }
384        } else {
385            // Set the carrier demo mode setting for the demo user.
386            final String carrierDemoModeSetting = getContext().getString(
387                    R.string.config_carrierDemoModeSetting);
388            Settings.Secure.putIntForUser(getContext().getContentResolver(),
389                    carrierDemoModeSetting, 1, userInfo.id);
390
391            // Enable packages for carrier demo mode.
392            final String packageList = getContext().getString(
393                    R.string.config_carrierDemoModePackages);
394            final String[] packageNames = packageList == null ? new String[0]
395                    : TextUtils.split(packageList, ",");
396            final IPackageManager iPm = AppGlobals.getPackageManager();
397            for (String packageName : packageNames) {
398                try {
399                    iPm.setApplicationEnabledSetting(packageName,
400                            PackageManager.COMPONENT_ENABLED_STATE_ENABLED, 0, userInfo.id, null);
401                } catch (RemoteException re) {
402                    Slog.e(TAG, "Error enabling application: " + packageName, re);
403                }
404            }
405        }
406    }
407
408    private void grantRuntimePermissionToCamera(UserHandle user) {
409        final Intent cameraIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
410        final PackageManager pm = mInjector.getPackageManager();
411        final ResolveInfo handler = pm.resolveActivityAsUser(cameraIntent,
412                PackageManager.MATCH_DIRECT_BOOT_AWARE | PackageManager.MATCH_DIRECT_BOOT_UNAWARE,
413                user.getIdentifier());
414        if (handler == null || handler.activityInfo == null) {
415            return;
416        }
417        try {
418            pm.grantRuntimePermission(handler.activityInfo.packageName,
419                    Manifest.permission.ACCESS_FINE_LOCATION, user);
420        } catch (Exception e) {
421            // Ignore
422        }
423    }
424
425    private void clearPrimaryCallLog() {
426        final ContentResolver resolver = mInjector.getContentResolver();
427
428        // Deleting primary user call log so that it doesn't get copied to the new demo user
429        final Uri uri = CallLog.Calls.CONTENT_URI;
430        try {
431            resolver.delete(uri, null, null);
432        } catch (Exception e) {
433            Slog.w(TAG, "Deleting call log failed: " + e);
434        }
435    }
436
437    void logSessionDuration() {
438        final int sessionDuration;
439        synchronized (mActivityLock) {
440            sessionDuration = (int) ((mLastUserActivityTime - mFirstUserActivityTime) / 1000);
441        }
442        mInjector.logSessionDuration(sessionDuration);
443    }
444
445    private boolean isDeviceProvisioned() {
446        return Settings.Global.getInt(
447                mInjector.getContentResolver(), Settings.Global.DEVICE_PROVISIONED, 0) != 0;
448    }
449
450    /**
451     * Deletes contents of {@link Environment#getDataPreloadsDirectory()},
452     * but leave {@link Environment#getDataPreloadsFileCacheDirectory()}
453     * @return true if contents was sucessfully deleted
454     */
455    private boolean deletePreloadsFolderContents() {
456        final File dir = mInjector.getDataPreloadsDirectory();
457        final File[] files = FileUtils.listFilesOrEmpty(dir);
458        final File fileCacheDirectory = mInjector.getDataPreloadsFileCacheDirectory();
459        Slog.i(TAG, "Deleting contents of " + dir);
460        boolean success = true;
461        for (File file : files) {
462            if (file.isFile()) {
463                if (!file.delete()) {
464                    success = false;
465                    Slog.w(TAG, "Cannot delete file " + file);
466                }
467            } else {
468                // Do not remove file_cache dir
469                if (!file.equals(fileCacheDirectory)) {
470                    if (!FileUtils.deleteContentsAndDir(file)) {
471                        success = false;
472                        Slog.w(TAG, "Cannot delete dir and its content " + file);
473                    }
474                } else {
475                    Slog.i(TAG, "Skipping directory with file cache " + file);
476                }
477            }
478        }
479        return success;
480    }
481
482    private void registerBroadcastReceiver() {
483        if (mBroadcastReceiver != null) {
484            return;
485        }
486
487        final IntentFilter filter = new IntentFilter();
488        if (!mIsCarrierDemoMode) {
489            filter.addAction(Intent.ACTION_SCREEN_OFF);
490        }
491        filter.addAction(ACTION_RESET_DEMO);
492        mBroadcastReceiver = new IntentReceiver();
493        getContext().registerReceiver(mBroadcastReceiver, filter);
494    }
495
496    private void unregisterBroadcastReceiver() {
497        if (mBroadcastReceiver != null) {
498            getContext().unregisterReceiver(mBroadcastReceiver);
499            mBroadcastReceiver = null;
500        }
501    }
502
503    private String[] getCameraIdsWithFlash() {
504        ArrayList<String> cameraIdsList = new ArrayList<String>();
505        final CameraManager cm = mInjector.getCameraManager();
506        if (cm != null) {
507            try {
508                for (String cameraId : cm.getCameraIdList()) {
509                    CameraCharacteristics c = cm.getCameraCharacteristics(cameraId);
510                    if (Boolean.TRUE.equals(c.get(CameraCharacteristics.FLASH_INFO_AVAILABLE))) {
511                        cameraIdsList.add(cameraId);
512                    }
513                }
514            } catch (CameraAccessException e) {
515                Slog.e(TAG, "Unable to access camera while getting camera id list", e);
516            }
517        }
518        return cameraIdsList.toArray(new String[cameraIdsList.size()]);
519    }
520
521    private void muteVolumeStreams() {
522        for (int stream : VOLUME_STREAMS_TO_MUTE) {
523            mInjector.getAudioManager().setStreamVolume(stream,
524                    mInjector.getAudioManager().getStreamMinVolume(stream), 0);
525        }
526    }
527
528    private void startDemoMode() {
529        mDeviceInDemoMode = true;
530
531        mPreloadAppsInstaller = mInjector.getPreloadAppsInstaller();
532        mInjector.initializeWakeLock();
533        if (mCameraIdsWithFlash == null) {
534            mCameraIdsWithFlash = getCameraIdsWithFlash();
535        }
536        registerBroadcastReceiver();
537
538        final String carrierDemoModeSetting =
539                getContext().getString(R.string.config_carrierDemoModeSetting);
540        mIsCarrierDemoMode = !TextUtils.isEmpty(carrierDemoModeSetting)
541                && (Settings.Secure.getInt(getContext().getContentResolver(),
542                        carrierDemoModeSetting, 0) == 1);
543
544        mInjector.systemPropertiesSet(SYSTEM_PROPERTY_RETAIL_DEMO_ENABLED, "1");
545        mHandler.sendEmptyMessage(MSG_START_NEW_SESSION);
546
547        mSafeBootRestrictionInitialState = mInjector.getUserManager().hasUserRestriction(
548                UserManager.DISALLOW_SAFE_BOOT, UserHandle.SYSTEM);
549        mPackageVerifierEnableInitialState = Settings.Global.getInt(mInjector.getContentResolver(),
550                Settings.Global.PACKAGE_VERIFIER_ENABLE, 1);
551    }
552
553    private void stopDemoMode() {
554        mPreloadAppsInstaller = null;
555        mCameraIdsWithFlash = null;
556        mInjector.destroyWakeLock();
557        unregisterBroadcastReceiver();
558
559        if (mDeviceInDemoMode) {
560            mInjector.getUserManager().setUserRestriction(UserManager.DISALLOW_SAFE_BOOT,
561                    mSafeBootRestrictionInitialState, UserHandle.SYSTEM);
562            Settings.Global.putInt(mInjector.getContentResolver(),
563                        Settings.Global.PACKAGE_VERIFIER_ENABLE,
564                        mPackageVerifierEnableInitialState);
565        }
566
567        mDeviceInDemoMode = false;
568        mIsCarrierDemoMode = false;
569    }
570
571    @Override
572    public void onStart() {
573        if (DEBUG) {
574            Slog.d(TAG, "Service starting up");
575        }
576        mHandlerThread = new ServiceThread(TAG, android.os.Process.THREAD_PRIORITY_FOREGROUND,
577                false);
578        mHandlerThread.start();
579        mHandler = new MainHandler(mHandlerThread.getLooper());
580        mInjector.publishLocalService(this, mLocalService);
581    }
582
583    @Override
584    public void onBootPhase(int bootPhase) {
585        switch (bootPhase) {
586            case PHASE_THIRD_PARTY_APPS_CAN_START:
587                final SettingsObserver settingsObserver = new SettingsObserver(mHandler);
588                settingsObserver.register();
589                settingsObserver.refreshTimeoutConstants();
590                break;
591            case PHASE_BOOT_COMPLETED:
592                if (UserManager.isDeviceInDemoMode(getContext())) {
593                    startDemoMode();
594                }
595                break;
596        }
597    }
598
599    @Override
600    public void onSwitchUser(int userId) {
601        if (!mDeviceInDemoMode) {
602            return;
603        }
604        if (DEBUG) {
605            Slog.d(TAG, "onSwitchUser: " + userId);
606        }
607        final UserInfo ui = mInjector.getUserManager().getUserInfo(userId);
608        if (!ui.isDemo()) {
609            Slog.wtf(TAG, "Should not allow switch to non-demo user in demo mode");
610            return;
611        }
612        if (!mIsCarrierDemoMode && !mInjector.isWakeLockHeld()) {
613            mInjector.acquireWakeLock();
614        }
615        mCurrentUserId = userId;
616        mInjector.getActivityManagerInternal().updatePersistentConfigurationForUser(
617                mInjector.getSystemUsersConfiguration(), userId);
618
619        mInjector.turnOffAllFlashLights(mCameraIdsWithFlash);
620        muteVolumeStreams();
621        if (!mInjector.getWifiManager().isWifiEnabled()) {
622            mInjector.getWifiManager().setWifiEnabled(true);
623        }
624
625        // Disable lock screen for demo users.
626        mInjector.getLockPatternUtils().setLockScreenDisabled(true, userId);
627
628        if (!mIsCarrierDemoMode) {
629            // Show reset notification (except in carrier demo mode).
630            mInjector.getNotificationManager().notifyAsUser(TAG, SystemMessage.NOTE_RETAIL_RESET,
631                    mInjector.createResetNotification(), UserHandle.of(userId));
632
633            synchronized (mActivityLock) {
634                mUserUntouched = true;
635            }
636            mInjector.logSessionCount(1);
637            mHandler.removeMessages(MSG_INACTIVITY_TIME_OUT);
638            mHandler.post(new Runnable() {
639                @Override
640                public void run() {
641                    mPreloadAppsInstaller.installApps(userId);
642                }
643            });
644        }
645    }
646
647    private RetailDemoModeServiceInternal mLocalService = new RetailDemoModeServiceInternal() {
648        private static final long USER_ACTIVITY_DEBOUNCE_TIME = 2000;
649
650        @Override
651        public void onUserActivity() {
652            if (!mDeviceInDemoMode || mIsCarrierDemoMode) {
653                return;
654            }
655            long timeOfActivity = SystemClock.uptimeMillis();
656            synchronized (mActivityLock) {
657                if (timeOfActivity < mLastUserActivityTime + USER_ACTIVITY_DEBOUNCE_TIME) {
658                    return;
659                }
660                mLastUserActivityTime = timeOfActivity;
661                if (mUserUntouched && isDemoLauncherDisabled()) {
662                    Slog.d(TAG, "retail_demo first touch");
663                    mUserUntouched = false;
664                    mFirstUserActivityTime = timeOfActivity;
665                }
666            }
667            mHandler.removeMessages(MSG_INACTIVITY_TIME_OUT);
668            mHandler.sendEmptyMessageDelayed(MSG_INACTIVITY_TIME_OUT, mUserInactivityTimeout);
669        }
670    };
671
672    static class Injector {
673        private Context mContext;
674        private UserManager mUm;
675        private PackageManager mPm;
676        private NotificationManager mNm;
677        private ActivityManagerService mAms;
678        private ActivityManagerInternal mAmi;
679        private AudioManager mAudioManager;
680        private PowerManager mPowerManager;
681        private CameraManager mCameraManager;
682        private PowerManager.WakeLock mWakeLock;
683        private WifiManager mWifiManager;
684        private Configuration mSystemUserConfiguration;
685        private PendingIntent mResetDemoPendingIntent;
686        private PreloadAppsInstaller mPreloadAppsInstaller;
687
688        Injector(Context context) {
689            mContext = context;
690        }
691
692        Context getContext() {
693            return mContext;
694        }
695
696        WifiManager getWifiManager() {
697            if (mWifiManager == null) {
698                mWifiManager = (WifiManager) mContext.getSystemService(Context.WIFI_SERVICE);
699            }
700            return mWifiManager;
701        }
702
703        UserManager getUserManager() {
704            if (mUm == null) {
705                mUm = getContext().getSystemService(UserManager.class);
706            }
707            return mUm;
708        }
709
710        void switchUser(int userId) {
711            if (mAms == null) {
712                mAms = (ActivityManagerService) ActivityManager.getService();
713            }
714            mAms.switchUser(userId);
715        }
716
717        AudioManager getAudioManager() {
718            if (mAudioManager == null) {
719                mAudioManager = getContext().getSystemService(AudioManager.class);
720            }
721            return mAudioManager;
722        }
723
724        private PowerManager getPowerManager() {
725            if (mPowerManager == null) {
726                mPowerManager = (PowerManager) getContext().getSystemService(
727                        Context.POWER_SERVICE);
728            }
729            return mPowerManager;
730        }
731
732        NotificationManager getNotificationManager() {
733            if (mNm == null) {
734                mNm = NotificationManager.from(getContext());
735            }
736            return mNm;
737        }
738
739        ActivityManagerInternal getActivityManagerInternal() {
740            if (mAmi == null) {
741                mAmi = LocalServices.getService(ActivityManagerInternal.class);
742            }
743            return mAmi;
744        }
745
746        CameraManager getCameraManager() {
747            if (mCameraManager == null) {
748                mCameraManager = (CameraManager) getContext().getSystemService(
749                        Context.CAMERA_SERVICE);
750            }
751            return mCameraManager;
752        }
753
754        PackageManager getPackageManager() {
755            if (mPm == null) {
756                mPm = getContext().getPackageManager();
757            }
758            return mPm;
759        }
760
761        IPackageManager getIPackageManager() {
762            return AppGlobals.getPackageManager();
763        }
764
765        ContentResolver getContentResolver() {
766            return getContext().getContentResolver();
767        }
768
769        PreloadAppsInstaller getPreloadAppsInstaller() {
770            if (mPreloadAppsInstaller == null) {
771                mPreloadAppsInstaller = new PreloadAppsInstaller(getContext());
772            }
773            return mPreloadAppsInstaller;
774        }
775
776        void systemPropertiesSet(String key, String value) {
777            SystemProperties.set(key, value);
778        }
779
780        void turnOffAllFlashLights(String[] cameraIdsWithFlash) {
781            for (String cameraId : cameraIdsWithFlash) {
782                try {
783                    getCameraManager().setTorchMode(cameraId, false);
784                } catch (CameraAccessException e) {
785                    Slog.e(TAG, "Unable to access camera " + cameraId
786                            + " while turning off flash", e);
787                }
788            }
789        }
790
791        void initializeWakeLock() {
792            if (mWakeLock == null) {
793                mWakeLock = getPowerManager().newWakeLock(
794                        PowerManager.FULL_WAKE_LOCK | PowerManager.ACQUIRE_CAUSES_WAKEUP, TAG);
795            }
796        }
797
798        void destroyWakeLock() {
799            mWakeLock = null;
800        }
801
802        boolean isWakeLockHeld() {
803            return mWakeLock != null && mWakeLock.isHeld();
804        }
805
806        void acquireWakeLock() {
807            mWakeLock.acquire();
808        }
809
810        void releaseWakeLock() {
811            mWakeLock.release();
812        }
813
814        void logSessionDuration(int duration) {
815            MetricsLogger.histogram(getContext(), DEMO_SESSION_DURATION, duration);
816        }
817
818        void logSessionCount(int count) {
819            MetricsLogger.count(getContext(), DEMO_SESSION_COUNT, count);
820        }
821
822        Configuration getSystemUsersConfiguration() {
823            if (mSystemUserConfiguration == null) {
824                Settings.System.getConfiguration(getContentResolver(),
825                        mSystemUserConfiguration = new Configuration());
826            }
827            return mSystemUserConfiguration;
828        }
829
830        LockPatternUtils getLockPatternUtils() {
831            return new LockPatternUtils(getContext());
832        }
833
834        Notification createResetNotification() {
835            return new Notification.Builder(getContext(), SystemNotificationChannels.RETAIL_MODE)
836                    .setContentTitle(getContext().getString(R.string.reset_retail_demo_mode_title))
837                    .setContentText(getContext().getString(R.string.reset_retail_demo_mode_text))
838                    .setOngoing(true)
839                    .setSmallIcon(R.drawable.platlogo)
840                    .setShowWhen(false)
841                    .setVisibility(Notification.VISIBILITY_PUBLIC)
842                    .setContentIntent(getResetDemoPendingIntent())
843                    .setColor(getContext().getColor(R.color.system_notification_accent_color))
844                    .build();
845        }
846
847        private PendingIntent getResetDemoPendingIntent() {
848            if (mResetDemoPendingIntent == null) {
849                Intent intent = new Intent(ACTION_RESET_DEMO);
850                mResetDemoPendingIntent = PendingIntent.getBroadcast(getContext(), 0, intent, 0);
851            }
852            return mResetDemoPendingIntent;
853        }
854
855        File getDataPreloadsDirectory() {
856            return Environment.getDataPreloadsDirectory();
857        }
858
859        File getDataPreloadsFileCacheDirectory() {
860            return Environment.getDataPreloadsFileCacheDirectory();
861        }
862
863        void publishLocalService(RetailDemoModeService service,
864                RetailDemoModeServiceInternal localService) {
865            service.publishLocalService(RetailDemoModeServiceInternal.class, localService);
866        }
867    }
868}
869