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