From eb437d4dffb310857e19bb619778dc5b6b7febff Mon Sep 17 00:00:00 2001 From: Amith Yamasani Date: Fri, 29 Apr 2016 09:31:25 -0700 Subject: [PATCH] Retail mode flag and some clients for it Bug: 27280140 Change-Id: Ide33e941b9c71eb925b5977d0b0d62198537ca14 --- core/java/android/content/pm/UserInfo.java | 13 +++++++-- core/java/android/os/UserManager.java | 12 +++++++++ core/java/android/provider/Settings.java | 9 +++++++ core/res/res/values/config.xml | 3 +++ core/res/res/values/symbols.xml | 1 + .../keyguard/KeyguardViewMediator.java | 15 ++++++----- .../com/android/server/am/UserController.java | 27 +++++++++++++++++++ .../android/server/pm/UserManagerService.java | 27 ++++++++++++++++++- 8 files changed, 97 insertions(+), 10 deletions(-) diff --git a/core/java/android/content/pm/UserInfo.java b/core/java/android/content/pm/UserInfo.java index dd3a36c7996c5..6cd84033da8c1 100644 --- a/core/java/android/content/pm/UserInfo.java +++ b/core/java/android/content/pm/UserInfo.java @@ -28,8 +28,8 @@ import android.os.UserManager; */ public class UserInfo implements Parcelable { - /** 8 bits for user type */ - public static final int FLAG_MASK_USER_TYPE = 0x000000FF; + /** 16 bits for user type */ + public static final int FLAG_MASK_USER_TYPE = 0x0000FFFF; /** * *************************** NOTE *************************** @@ -87,6 +87,11 @@ public class UserInfo implements Parcelable { */ public static final int FLAG_EPHEMERAL = 0x00000100; + /** + * User is for demo purposes only and can be removed at any time. + */ + public static final int FLAG_DEMO = 0x00000200; + public static final int NO_PROFILE_GROUP_ID = UserHandle.USER_NULL; public int id; @@ -153,6 +158,10 @@ public class UserInfo implements Parcelable { return (flags & FLAG_INITIALIZED) == FLAG_INITIALIZED; } + public boolean isDemo() { + return (flags & FLAG_DEMO) == FLAG_DEMO; + } + /** * Returns true if the user is a split system user. *

If {@link UserManager#isSplitSystemUser split system user mode} is not enabled, diff --git a/core/java/android/os/UserManager.java b/core/java/android/os/UserManager.java index dcec98246ab6c..2613994292ef5 100644 --- a/core/java/android/os/UserManager.java +++ b/core/java/android/os/UserManager.java @@ -1972,6 +1972,10 @@ public class UserManager { if (!supportsMultipleUsers()) { return false; } + // If Demo Mode is on, don't show user switcher + if (isDeviceInDemoMode(mContext)) { + return false; + } List users = getUsers(true); if (users == null) { return false; @@ -1987,6 +1991,14 @@ public class UserManager { return switchableUserCount > 1 || guestEnabled; } + /** + * @hide + */ + public static boolean isDeviceInDemoMode(Context context) { + return Settings.Global.getInt(context.getContentResolver(), + Settings.Global.DEVICE_DEMO_MODE, 0) > 0; + } + /** * Returns a serial number on this device for a given userHandle. User handles can be recycled * when deleting and creating users, but serial numbers are not reused until the device is wiped. diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java index f04b2d47e747d..a5c250006ca1c 100755 --- a/core/java/android/provider/Settings.java +++ b/core/java/android/provider/Settings.java @@ -8537,6 +8537,15 @@ public final class Settings { */ public static final String SAFE_BOOT_DISALLOWED = "safe_boot_disallowed"; + /** + * Whether this device is currently in retail demo mode. If true, device + * usage is severely limited. + *

+ * Type: int (0 for false, 1 for true) + * @hide + */ + public static final String DEVICE_DEMO_MODE = "device_demo_mode"; + /** * Settings to backup. This is here so that it's in the same place as the settings * keys and easy to update. diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml index e64d9056d828a..904523a680a79 100644 --- a/core/res/res/values/config.xml +++ b/core/res/res/values/config.xml @@ -2481,4 +2481,7 @@ + + + diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml index 9b7fbd8eeaeff..ae38fef8b91f2 100644 --- a/core/res/res/values/symbols.xml +++ b/core/res/res/values/symbols.xml @@ -1104,6 +1104,7 @@ + diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java index cad7f647e031f..c8e74ec1bf19f 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java +++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java @@ -399,8 +399,7 @@ public class KeyguardViewMediator extends SystemUI { sendUserPresentBroadcast(); synchronized (KeyguardViewMediator.this) { // If system user is provisioned, we might want to lock now to avoid showing launcher - if (UserManager.isSplitSystemUser() - && KeyguardUpdateMonitor.getCurrentUser() == UserHandle.USER_SYSTEM) { + if (mustNotUnlockCurrentUser()) { doKeyguardLocked(null); } } @@ -599,7 +598,6 @@ public class KeyguardViewMediator extends SystemUI { return KeyguardSecurityView.PROMPT_REASON_WRONG_CREDENTIAL; } - return KeyguardSecurityView.PROMPT_REASON_NONE; } }; @@ -608,6 +606,11 @@ public class KeyguardViewMediator extends SystemUI { mPM.userActivity(SystemClock.uptimeMillis(), false); } + boolean mustNotUnlockCurrentUser() { + return (UserManager.isSplitSystemUser() || UserManager.isDeviceInDemoMode(mContext)) + && KeyguardUpdateMonitor.getCurrentUser() == UserHandle.USER_SYSTEM; + } + private void setupLocked() { mPM = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE); mWM = WindowManagerGlobal.getWindowManagerService(); @@ -1176,8 +1179,7 @@ public class KeyguardViewMediator extends SystemUI { } // In split system user mode, we never unlock system user. - if (!UserManager.isSplitSystemUser() - || KeyguardUpdateMonitor.getCurrentUser() != UserHandle.USER_SYSTEM + if (!mustNotUnlockCurrentUser() || !mUpdateMonitor.isDeviceProvisioned()) { // if the setup wizard hasn't run yet, don't show @@ -1615,8 +1617,7 @@ public class KeyguardViewMediator extends SystemUI { synchronized (KeyguardViewMediator.this) { if (DEBUG) Log.d(TAG, "handleHide"); - if (UserManager.isSplitSystemUser() - && KeyguardUpdateMonitor.getCurrentUser() == UserHandle.USER_SYSTEM) { + if (mustNotUnlockCurrentUser()) { // In split system user mode, we never unlock system user. The end user has to // switch to another user. // TODO: We should stop it early by disabling the swipe up flow. Right now swipe up diff --git a/services/core/java/com/android/server/am/UserController.java b/services/core/java/com/android/server/am/UserController.java index c4e39c940e330..112a6beeb56af 100644 --- a/services/core/java/com/android/server/am/UserController.java +++ b/services/core/java/com/android/server/am/UserController.java @@ -223,6 +223,8 @@ final class UserController { private void finishUserBoot(UserState uss, IIntentReceiver resultTo) { final int userId = uss.mHandle.getIdentifier(); + boolean deviceInDemoMode = UserManager.isDeviceInDemoMode(mService.mContext); + boolean switchToDemoUser = false; Slog.d(TAG, "Finishing user boot " + userId); synchronized (mService) { // Bail if we ended up with a stale user @@ -259,7 +261,32 @@ final class UserController { } else { maybeUnlockUser(userId); } + if (deviceInDemoMode && mCurrentUserId == UserHandle.USER_SYSTEM) { + switchToDemoUser = true; + } } + + if (switchToDemoUser) { + doSwitchToDemoUser(); + } + } + + private void doSwitchToDemoUser() { + mHandler.post(new Runnable() { + @Override + public void run() { + // Remove any demo users first + for (UserInfo user: mUserManager.getUsers(true)) { + if (user.isDemo()) { + mUserManager.removeUser(user.id); + } + } + UserInfo demoUser = mUserManager.createUser("Demo", UserInfo.FLAG_DEMO); + if (demoUser != null) { + mService.switchUser(demoUser.id); + } + } + }); } /** diff --git a/services/core/java/com/android/server/pm/UserManagerService.java b/services/core/java/com/android/server/pm/UserManagerService.java index 33ccf160f8d0d..ff17552c0f020 100644 --- a/services/core/java/com/android/server/pm/UserManagerService.java +++ b/services/core/java/com/android/server/pm/UserManagerService.java @@ -28,6 +28,7 @@ import android.app.Activity; import android.app.ActivityManager; import android.app.ActivityManagerInternal; import android.app.ActivityManagerNative; +import android.app.AppGlobals; import android.app.IActivityManager; import android.app.IStopUserCallback; import android.app.KeyguardManager; @@ -70,6 +71,7 @@ import android.os.storage.StorageManager; import android.system.ErrnoException; import android.system.Os; import android.system.OsConstants; +import android.text.TextUtils; import android.util.AtomicFile; import android.util.IntArray; import android.util.Log; @@ -414,7 +416,9 @@ public class UserManagerService extends IUserManager.Stub { // user restriction was not a default guest restriction. setUserRestriction(UserManager.DISALLOW_CONFIG_WIFI, true, currentGuestUser.id); } - } + + maybeInitializeDemoMode(UserHandle.USER_SYSTEM); +} @Override public String getUserAccount(int userId) { @@ -2710,6 +2714,8 @@ public class UserManagerService extends IUserManager.Stub { mPm.onBeforeUserStartUninitialized(userId); } } + + maybeInitializeDemoMode(userId); } /** @@ -2724,6 +2730,7 @@ public class UserManagerService extends IUserManager.Stub { /** * Make a note of the last started time of a user and do some cleanup. + * This is called with ActivityManagerService lock held. * @param userId the user that was just foregrounded */ public void onUserLoggedIn(@UserIdInt int userId) { @@ -2741,6 +2748,24 @@ public class UserManagerService extends IUserManager.Stub { scheduleWriteUser(userData); } + private void maybeInitializeDemoMode(int userId) { + if (UserManager.isDeviceInDemoMode(mContext)) { + String demoLauncher = + mContext.getResources().getString( + com.android.internal.R.string.config_demoModeLauncherComponent); + if (!TextUtils.isEmpty(demoLauncher)) { + ComponentName componentToEnable = ComponentName.unflattenFromString(demoLauncher); + try { + AppGlobals.getPackageManager().setComponentEnabledSetting(componentToEnable, + PackageManager.COMPONENT_ENABLED_STATE_ENABLED, /* flags= */ 0, + /* userId= */ userId); + } catch (RemoteException re) { + // Internal, shouldn't happen + } + } + } + } + /** * Returns the next available user id, filling in any holes in the ids. * TODO: May not be a good idea to recycle ids, in case it results in confusion