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