RetailDemoModeService.java revision d912d9357dc2f7c7540c6297b2a2bb9427fb7761
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.ActivityManagerInternal;
21import android.app.ActivityManagerNative;
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.util.KeyValueListParser;
62import android.util.Slog;
63import com.android.internal.os.BackgroundThread;
64import com.android.internal.R;
65import com.android.internal.annotations.GuardedBy;
66import com.android.internal.annotations.VisibleForTesting;
67import com.android.internal.logging.MetricsLogger;
68import com.android.internal.widget.LockPatternUtils;
69import com.android.server.LocalServices;
70import com.android.server.ServiceThread;
71import com.android.server.SystemService;
72import com.android.server.am.ActivityManagerService;
73import com.android.server.retaildemo.UserInactivityCountdownDialog.OnCountDownExpiredListener;
74
75import java.io.File;
76import java.util.ArrayList;
77
78public class RetailDemoModeService extends SystemService {
79    private static final boolean DEBUG = false;
80
81    private static final String TAG = RetailDemoModeService.class.getSimpleName();
82    private static final String DEMO_USER_NAME = "Demo";
83    private static final String ACTION_RESET_DEMO =
84            "com.android.server.retaildemo.ACTION_RESET_DEMO";
85    @VisibleForTesting
86    static final String SYSTEM_PROPERTY_RETAIL_DEMO_ENABLED = "sys.retaildemo.enabled";
87
88    private static final int MSG_TURN_SCREEN_ON = 0;
89    private static final int MSG_INACTIVITY_TIME_OUT = 1;
90    private static final int MSG_START_NEW_SESSION = 2;
91
92    private static final long SCREEN_WAKEUP_DELAY = 2500;
93    private static final long USER_INACTIVITY_TIMEOUT_MIN = 10000;
94    private static final long USER_INACTIVITY_TIMEOUT_DEFAULT = 90000;
95    private static final long WARNING_DIALOG_TIMEOUT_DEFAULT = 0;
96    private static final long MILLIS_PER_SECOND = 1000;
97
98    @VisibleForTesting
99    static final int[] VOLUME_STREAMS_TO_MUTE = {
100            AudioSystem.STREAM_RING,
101            AudioSystem.STREAM_MUSIC
102    };
103
104    // Tron Vars
105    private static final String DEMO_SESSION_COUNT = "retail_demo_session_count";
106    private static final String DEMO_SESSION_DURATION = "retail_demo_session_duration";
107
108    boolean mDeviceInDemoMode = false;
109    int mCurrentUserId = UserHandle.USER_SYSTEM;
110    long mUserInactivityTimeout;
111    long mWarningDialogTimeout;
112    private Injector mInjector;
113    Handler mHandler;
114    private ServiceThread mHandlerThread;
115    private String[] mCameraIdsWithFlash;
116    private PreloadAppsInstaller mPreloadAppsInstaller;
117
118    final Object mActivityLock = new Object();
119    // Whether the newly created demo user has interacted with the screen yet
120    @GuardedBy("mActivityLock")
121    boolean mUserUntouched;
122    @GuardedBy("mActivityLock")
123    long mFirstUserActivityTime;
124    @GuardedBy("mActivityLock")
125    long mLastUserActivityTime;
126
127    private BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
128        @Override
129        public void onReceive(Context context, Intent intent) {
130            if (!mDeviceInDemoMode) {
131                return;
132            }
133            switch (intent.getAction()) {
134                case Intent.ACTION_SCREEN_OFF:
135                    mHandler.removeMessages(MSG_TURN_SCREEN_ON);
136                    mHandler.sendEmptyMessageDelayed(MSG_TURN_SCREEN_ON, SCREEN_WAKEUP_DELAY);
137                    break;
138                case ACTION_RESET_DEMO:
139                    mHandler.sendEmptyMessage(MSG_START_NEW_SESSION);
140                    break;
141            }
142        }
143    };
144
145    final class MainHandler extends Handler {
146
147        MainHandler(Looper looper) {
148            super(looper, null, true);
149        }
150
151        @Override
152        public void handleMessage(Message msg) {
153            switch (msg.what) {
154                case MSG_TURN_SCREEN_ON:
155                    if (mInjector.isWakeLockHeld()) {
156                        mInjector.releaseWakeLock();
157                    }
158                    mInjector.acquireWakeLock();
159                    break;
160                case MSG_INACTIVITY_TIME_OUT:
161                    if (isDemoLauncherDisabled()) {
162                        Slog.i(TAG, "User inactivity timeout reached");
163                        showInactivityCountdownDialog();
164                    }
165                    break;
166                case MSG_START_NEW_SESSION:
167                    if (DEBUG) {
168                        Slog.d(TAG, "Switching to a new demo user");
169                    }
170                    removeMessages(MSG_START_NEW_SESSION);
171                    removeMessages(MSG_INACTIVITY_TIME_OUT);
172                    if (mCurrentUserId != UserHandle.USER_SYSTEM) {
173                        logSessionDuration();
174                    }
175                    final UserInfo demoUser = mInjector.getUserManager().createUser(DEMO_USER_NAME,
176                            UserInfo.FLAG_DEMO | UserInfo.FLAG_EPHEMERAL);
177                    if (demoUser != null) {
178                        setupDemoUser(demoUser);
179                        mInjector.switchUser(demoUser.id);
180                    }
181                    break;
182            }
183        }
184    }
185
186    @VisibleForTesting
187    class SettingsObserver extends ContentObserver {
188
189        private final static String KEY_USER_INACTIVITY_TIMEOUT = "user_inactivity_timeout_ms";
190        private final static String KEY_WARNING_DIALOG_TIMEOUT = "warning_dialog_timeout_ms";
191
192        private final Uri mDeviceDemoModeUri = Settings.Global
193                .getUriFor(Settings.Global.DEVICE_DEMO_MODE);
194        private final Uri mDeviceProvisionedUri = Settings.Global
195                .getUriFor(Settings.Global.DEVICE_PROVISIONED);
196        private final Uri mRetailDemoConstantsUri = Settings.Global
197                .getUriFor(Settings.Global.RETAIL_DEMO_MODE_CONSTANTS);
198
199        private final KeyValueListParser mParser = new KeyValueListParser(',');
200
201        public SettingsObserver(Handler handler) {
202            super(handler);
203        }
204
205        public void register() {
206            ContentResolver cr = mInjector.getContentResolver();
207            cr.registerContentObserver(mDeviceDemoModeUri, false, this, UserHandle.USER_SYSTEM);
208            cr.registerContentObserver(mDeviceProvisionedUri, false, this, UserHandle.USER_SYSTEM);
209            cr.registerContentObserver(mRetailDemoConstantsUri, false, this,
210                    UserHandle.USER_SYSTEM);
211        }
212
213        @Override
214        public void onChange(boolean selfChange, Uri uri) {
215            if (mRetailDemoConstantsUri.equals(uri)) {
216                refreshTimeoutConstants();
217                return;
218            }
219            if (mDeviceDemoModeUri.equals(uri)) {
220                mDeviceInDemoMode = UserManager.isDeviceInDemoMode(getContext());
221                if (mDeviceInDemoMode) {
222                    putDeviceInDemoMode();
223                } else {
224                    mInjector.systemPropertiesSet(SYSTEM_PROPERTY_RETAIL_DEMO_ENABLED, "0");
225                    if (mInjector.isWakeLockHeld()) {
226                        mInjector.releaseWakeLock();
227                    }
228                }
229            }
230            // If device is provisioned and left demo mode - run the cleanup in demo folder
231            if (!mDeviceInDemoMode && isDeviceProvisioned()) {
232                // Run on the bg thread to not block the fg thread
233                BackgroundThread.getHandler().post(new Runnable() {
234                    @Override
235                    public void run() {
236                        if (!deletePreloadsFolderContents()) {
237                            Slog.w(TAG, "Failed to delete preloads folder contents");
238                        }
239                    }
240                });
241            }
242        }
243
244        private void refreshTimeoutConstants() {
245            try {
246                mParser.setString(Settings.Global.getString(mInjector.getContentResolver(),
247                        Settings.Global.RETAIL_DEMO_MODE_CONSTANTS));
248            } catch (IllegalArgumentException exc) {
249                Slog.e(TAG, "Invalid string passed to KeyValueListParser");
250                // Consuming the exception to fall back to default values.
251            }
252            mWarningDialogTimeout = mParser.getLong(KEY_WARNING_DIALOG_TIMEOUT,
253                    WARNING_DIALOG_TIMEOUT_DEFAULT);
254            mUserInactivityTimeout = mParser.getLong(KEY_USER_INACTIVITY_TIMEOUT,
255                    USER_INACTIVITY_TIMEOUT_DEFAULT);
256            mUserInactivityTimeout = Math.max(mUserInactivityTimeout, USER_INACTIVITY_TIMEOUT_MIN);
257        }
258    }
259
260    private void showInactivityCountdownDialog() {
261        UserInactivityCountdownDialog dialog = new UserInactivityCountdownDialog(getContext(),
262                mWarningDialogTimeout, MILLIS_PER_SECOND);
263        dialog.setNegativeButtonClickListener(null);
264        dialog.setPositiveButtonClickListener(new DialogInterface.OnClickListener() {
265            @Override
266            public void onClick(DialogInterface dialog, int which) {
267                mHandler.sendEmptyMessage(MSG_START_NEW_SESSION);
268            }
269        });
270        dialog.setOnCountDownExpiredListener(new OnCountDownExpiredListener() {
271            @Override
272            public void onCountDownExpired() {
273                mHandler.sendEmptyMessage(MSG_START_NEW_SESSION);
274            }
275        });
276        dialog.show();
277    }
278
279    public RetailDemoModeService(Context context) {
280        this(new Injector(context));
281    }
282
283    @VisibleForTesting
284    RetailDemoModeService(Injector injector) {
285        super(injector.getContext());
286
287        mInjector = injector;
288        synchronized (mActivityLock) {
289            mFirstUserActivityTime = mLastUserActivityTime = SystemClock.uptimeMillis();
290        }
291    }
292
293    boolean isDemoLauncherDisabled() {
294        IPackageManager pm = mInjector.getIPackageManager();
295        int enabledState = PackageManager.COMPONENT_ENABLED_STATE_DEFAULT;
296        String demoLauncherComponent = getContext().getResources()
297                .getString(R.string.config_demoModeLauncherComponent);
298        try {
299            enabledState = pm.getComponentEnabledSetting(
300                    ComponentName.unflattenFromString(demoLauncherComponent),
301                    mCurrentUserId);
302        } catch (RemoteException exc) {
303            Slog.e(TAG, "Unable to talk to Package Manager", exc);
304        }
305        return enabledState == PackageManager.COMPONENT_ENABLED_STATE_DISABLED;
306    }
307
308    private void setupDemoUser(UserInfo userInfo) {
309        UserManager um = mInjector.getUserManager();
310        UserHandle user = UserHandle.of(userInfo.id);
311        um.setUserRestriction(UserManager.DISALLOW_CONFIG_WIFI, true, user);
312        um.setUserRestriction(UserManager.DISALLOW_INSTALL_UNKNOWN_SOURCES, true, user);
313        um.setUserRestriction(UserManager.DISALLOW_CONFIG_MOBILE_NETWORKS, true, user);
314        um.setUserRestriction(UserManager.DISALLOW_USB_FILE_TRANSFER, true, user);
315        um.setUserRestriction(UserManager.DISALLOW_MODIFY_ACCOUNTS, true, user);
316        um.setUserRestriction(UserManager.DISALLOW_CONFIG_BLUETOOTH, true, user);
317        // Set this to false because the default is true on user creation
318        um.setUserRestriction(UserManager.DISALLOW_OUTGOING_CALLS, false, user);
319        // Disallow rebooting in safe mode - controlled by user 0
320        um.setUserRestriction(UserManager.DISALLOW_SAFE_BOOT, true, UserHandle.SYSTEM);
321        Settings.Secure.putIntForUser(mInjector.getContentResolver(),
322                Settings.Secure.SKIP_FIRST_USE_HINTS, 1, userInfo.id);
323        Settings.Global.putInt(mInjector.getContentResolver(),
324                Settings.Global.PACKAGE_VERIFIER_ENABLE, 0);
325
326        grantRuntimePermissionToCamera(user);
327        clearPrimaryCallLog();
328    }
329
330    private void grantRuntimePermissionToCamera(UserHandle user) {
331        final Intent cameraIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
332        final PackageManager pm = mInjector.getPackageManager();
333        final ResolveInfo handler = pm.resolveActivityAsUser(cameraIntent,
334                PackageManager.MATCH_DIRECT_BOOT_AWARE | PackageManager.MATCH_DIRECT_BOOT_UNAWARE,
335                user.getIdentifier());
336        if (handler == null || handler.activityInfo == null) {
337            return;
338        }
339        try {
340            pm.grantRuntimePermission(handler.activityInfo.packageName,
341                    Manifest.permission.ACCESS_FINE_LOCATION, user);
342        } catch (Exception e) {
343            // Ignore
344        }
345    }
346
347    private void clearPrimaryCallLog() {
348        final ContentResolver resolver = mInjector.getContentResolver();
349
350        // Deleting primary user call log so that it doesn't get copied to the new demo user
351        final Uri uri = CallLog.Calls.CONTENT_URI;
352        try {
353            resolver.delete(uri, null, null);
354        } catch (Exception e) {
355            Slog.w(TAG, "Deleting call log failed: " + e);
356        }
357    }
358
359    void logSessionDuration() {
360        final int sessionDuration;
361        synchronized (mActivityLock) {
362            sessionDuration = (int) ((mLastUserActivityTime - mFirstUserActivityTime) / 1000);
363        }
364        mInjector.logSessionDuration(sessionDuration);
365    }
366
367    private boolean isDeviceProvisioned() {
368        return Settings.Global.getInt(
369                mInjector.getContentResolver(), Settings.Global.DEVICE_PROVISIONED, 0) != 0;
370    }
371
372    private boolean deletePreloadsFolderContents() {
373        final File dir = mInjector.getDataPreloadsDirectory();
374        Slog.i(TAG, "Deleting contents of " + dir);
375        return FileUtils.deleteContents(dir);
376    }
377
378    private void registerBroadcastReceiver() {
379        final IntentFilter filter = new IntentFilter();
380        filter.addAction(Intent.ACTION_SCREEN_OFF);
381        filter.addAction(ACTION_RESET_DEMO);
382        getContext().registerReceiver(mBroadcastReceiver, filter);
383    }
384
385    private String[] getCameraIdsWithFlash() {
386        ArrayList<String> cameraIdsList = new ArrayList<String>();
387        final CameraManager cm = mInjector.getCameraManager();
388        if (cm != null) {
389            try {
390                for (String cameraId : cm.getCameraIdList()) {
391                    CameraCharacteristics c = cm.getCameraCharacteristics(cameraId);
392                    if (Boolean.TRUE.equals(c.get(CameraCharacteristics.FLASH_INFO_AVAILABLE))) {
393                        cameraIdsList.add(cameraId);
394                    }
395                }
396            } catch (CameraAccessException e) {
397                Slog.e(TAG, "Unable to access camera while getting camera id list", e);
398            }
399        }
400        return cameraIdsList.toArray(new String[cameraIdsList.size()]);
401    }
402
403    private void muteVolumeStreams() {
404        for (int stream : VOLUME_STREAMS_TO_MUTE) {
405            mInjector.getAudioManager().setStreamVolume(stream,
406                    mInjector.getAudioManager().getStreamMinVolume(stream), 0);
407        }
408    }
409
410    private void putDeviceInDemoMode() {
411        mInjector.systemPropertiesSet(SYSTEM_PROPERTY_RETAIL_DEMO_ENABLED, "1");
412        mHandler.sendEmptyMessage(MSG_START_NEW_SESSION);
413    }
414
415    @Override
416    public void onStart() {
417        if (DEBUG) {
418            Slog.d(TAG, "Service starting up");
419        }
420        mHandlerThread = new ServiceThread(TAG, android.os.Process.THREAD_PRIORITY_FOREGROUND,
421                false);
422        mHandlerThread.start();
423        mHandler = new MainHandler(mHandlerThread.getLooper());
424        publishLocalService(RetailDemoModeServiceInternal.class, mLocalService);
425    }
426
427    @Override
428    public void onBootPhase(int bootPhase) {
429        switch (bootPhase) {
430            case PHASE_THIRD_PARTY_APPS_CAN_START:
431                mPreloadAppsInstaller = mInjector.getPreloadAppsInstaller();
432                mInjector.initializeWakeLock();
433                mCameraIdsWithFlash = getCameraIdsWithFlash();
434                SettingsObserver settingsObserver = new SettingsObserver(mHandler);
435                settingsObserver.register();
436                settingsObserver.refreshTimeoutConstants();
437                registerBroadcastReceiver();
438                break;
439            case PHASE_BOOT_COMPLETED:
440                if (UserManager.isDeviceInDemoMode(getContext())) {
441                    mDeviceInDemoMode = true;
442                    putDeviceInDemoMode();
443                }
444                break;
445        }
446    }
447
448    @Override
449    public void onSwitchUser(int userId) {
450        if (!mDeviceInDemoMode) {
451            return;
452        }
453        if (DEBUG) {
454            Slog.d(TAG, "onSwitchUser: " + userId);
455        }
456        final UserInfo ui = mInjector.getUserManager().getUserInfo(userId);
457        if (!ui.isDemo()) {
458            Slog.wtf(TAG, "Should not allow switch to non-demo user in demo mode");
459            return;
460        }
461        if (!mInjector.isWakeLockHeld()) {
462            mInjector.acquireWakeLock();
463        }
464        mCurrentUserId = userId;
465        mInjector.getActivityManagerInternal().updatePersistentConfigurationForUser(
466                mInjector.getSystemUsersConfiguration(), userId);
467        mInjector.turnOffAllFlashLights(mCameraIdsWithFlash);
468        muteVolumeStreams();
469        if (!mInjector.isWifiEnabled()) {
470            mInjector.enableWifi();
471        }
472        // Disable lock screen for demo users.
473        mInjector.getLockPatternUtils().setLockScreenDisabled(true, userId);
474        mInjector.getNotificationManager().notifyAsUser(TAG,
475                1, mInjector.createResetNotification(), UserHandle.of(userId));
476
477        synchronized (mActivityLock) {
478            mUserUntouched = true;
479        }
480        mInjector.logSessionCount(1);
481        mHandler.removeMessages(MSG_INACTIVITY_TIME_OUT);
482        mHandler.post(new Runnable() {
483            @Override
484            public void run() {
485                mPreloadAppsInstaller.installApps(userId);
486            }
487        });
488    }
489
490    private RetailDemoModeServiceInternal mLocalService = new RetailDemoModeServiceInternal() {
491        private static final long USER_ACTIVITY_DEBOUNCE_TIME = 2000;
492
493        @Override
494        public void onUserActivity() {
495            if (!mDeviceInDemoMode) {
496                return;
497            }
498            long timeOfActivity = SystemClock.uptimeMillis();
499            synchronized (mActivityLock) {
500                if (timeOfActivity < mLastUserActivityTime + USER_ACTIVITY_DEBOUNCE_TIME) {
501                    return;
502                }
503                mLastUserActivityTime = timeOfActivity;
504                if (mUserUntouched && isDemoLauncherDisabled()) {
505                    Slog.d(TAG, "retail_demo first touch");
506                    mUserUntouched = false;
507                    mFirstUserActivityTime = timeOfActivity;
508                }
509            }
510            mHandler.removeMessages(MSG_INACTIVITY_TIME_OUT);
511            mHandler.sendEmptyMessageDelayed(MSG_INACTIVITY_TIME_OUT, mUserInactivityTimeout);
512        }
513    };
514
515    static class Injector {
516        private Context mContext;
517        private UserManager mUm;
518        private PackageManager mPm;
519        private NotificationManager mNm;
520        private ActivityManagerService mAms;
521        private ActivityManagerInternal mAmi;
522        private AudioManager mAudioManager;
523        private PowerManager mPowerManager;
524        private CameraManager mCameraManager;
525        private PowerManager.WakeLock mWakeLock;
526        private WifiManager mWifiManager;
527        private Configuration mSystemUserConfiguration;
528        private PendingIntent mResetDemoPendingIntent;
529
530        Injector(Context context) {
531            mContext = context;
532        }
533
534        Context getContext() {
535            return mContext;
536        }
537
538        private WifiManager getWifiManager() {
539            if (mWifiManager == null) {
540                mWifiManager = (WifiManager) mContext.getSystemService(Context.WIFI_SERVICE);
541            }
542            return mWifiManager;
543        }
544
545        UserManager getUserManager() {
546            if (mUm == null) {
547                mUm = getContext().getSystemService(UserManager.class);
548            }
549            return mUm;
550        }
551
552        void switchUser(int userId) {
553            if (mAms == null) {
554                mAms = (ActivityManagerService) ActivityManagerNative.getDefault();
555            }
556            mAms.switchUser(userId);
557        }
558
559        AudioManager getAudioManager() {
560            if (mAudioManager == null) {
561                mAudioManager = getContext().getSystemService(AudioManager.class);
562            }
563            return mAudioManager;
564        }
565
566        private PowerManager getPowerManager() {
567            if (mPowerManager == null) {
568                mPowerManager = (PowerManager) getContext().getSystemService(
569                        Context.POWER_SERVICE);
570            }
571            return mPowerManager;
572        }
573
574        NotificationManager getNotificationManager() {
575            if (mNm == null) {
576                mNm = NotificationManager.from(getContext());
577            }
578            return mNm;
579        }
580
581        ActivityManagerInternal getActivityManagerInternal() {
582            if (mAmi == null) {
583                mAmi = LocalServices.getService(ActivityManagerInternal.class);
584            }
585            return mAmi;
586        }
587
588        CameraManager getCameraManager() {
589            if (mCameraManager == null) {
590                mCameraManager = (CameraManager) getContext().getSystemService(
591                        Context.CAMERA_SERVICE);
592            }
593            return mCameraManager;
594        }
595
596        PackageManager getPackageManager() {
597            if (mPm == null) {
598                mPm = getContext().getPackageManager();
599            }
600            return mPm;
601        }
602
603        IPackageManager getIPackageManager() {
604            return AppGlobals.getPackageManager();
605        }
606
607        ContentResolver getContentResolver() {
608            return getContext().getContentResolver();
609        }
610
611        PreloadAppsInstaller getPreloadAppsInstaller() {
612            return new PreloadAppsInstaller(getContext());
613        }
614
615        void systemPropertiesSet(String key, String value) {
616            SystemProperties.set(key, value);
617        }
618
619        void turnOffAllFlashLights(String[] cameraIdsWithFlash) {
620            for (String cameraId : cameraIdsWithFlash) {
621                try {
622                    getCameraManager().setTorchMode(cameraId, false);
623                } catch (CameraAccessException e) {
624                    Slog.e(TAG, "Unable to access camera " + cameraId
625                            + " while turning off flash", e);
626                }
627            }
628        }
629
630        void initializeWakeLock() {
631            mWakeLock = getPowerManager().newWakeLock(
632                    PowerManager.FULL_WAKE_LOCK | PowerManager.ACQUIRE_CAUSES_WAKEUP, TAG);
633        }
634
635        boolean isWakeLockHeld() {
636            return mWakeLock.isHeld();
637        }
638
639        void acquireWakeLock() {
640            mWakeLock.acquire();
641        }
642
643        void releaseWakeLock() {
644            mWakeLock.release();
645        }
646
647        boolean isWifiEnabled() {
648            return getWifiManager().isWifiEnabled();
649        }
650
651        void enableWifi() {
652            getWifiManager().setWifiEnabled(true);
653        }
654
655        void logSessionDuration(int duration) {
656            MetricsLogger.histogram(getContext(), DEMO_SESSION_DURATION, duration);
657        }
658
659        void logSessionCount(int count) {
660            MetricsLogger.count(getContext(), DEMO_SESSION_COUNT, count);
661        }
662
663        Configuration getSystemUsersConfiguration() {
664            if (mSystemUserConfiguration == null) {
665                Settings.System.getConfiguration(getContentResolver(),
666                        mSystemUserConfiguration = new Configuration());
667            }
668            return mSystemUserConfiguration;
669        }
670
671        LockPatternUtils getLockPatternUtils() {
672            return new LockPatternUtils(getContext());
673        }
674
675        Notification createResetNotification() {
676            return new Notification.Builder(getContext())
677                    .setContentTitle(getContext().getString(R.string.reset_retail_demo_mode_title))
678                    .setContentText(getContext().getString(R.string.reset_retail_demo_mode_text))
679                    .setOngoing(true)
680                    .setSmallIcon(R.drawable.platlogo)
681                    .setShowWhen(false)
682                    .setVisibility(Notification.VISIBILITY_PUBLIC)
683                    .setContentIntent(getResetDemoPendingIntent())
684                    .setColor(getContext().getColor(R.color.system_notification_accent_color))
685                    .build();
686        }
687
688        private PendingIntent getResetDemoPendingIntent() {
689            if (mResetDemoPendingIntent == null) {
690                Intent intent = new Intent(ACTION_RESET_DEMO);
691                mResetDemoPendingIntent = PendingIntent.getBroadcast(getContext(), 0, intent, 0);
692            }
693            return mResetDemoPendingIntent;
694        }
695
696        File getDataPreloadsDirectory() {
697            return Environment.getDataPreloadsDirectory();
698        }
699    }
700}
701