1 /* 2 * Copyright (C) 2021 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 17 package com.android.tv.settings.users; 18 19 import android.app.ActivityManager; 20 import android.content.Context; 21 import android.content.pm.UserInfo; 22 import android.os.UserHandle; 23 import android.os.UserManager; 24 import android.provider.Settings; 25 import android.util.Log; 26 27 /** 28 * Manipulate and list restricted profiles on the device. 29 */ 30 public class RestrictedProfileModel { 31 private static final String TAG = "RestrictedProfile"; 32 33 private final Context mContext; 34 private final boolean mApplyRestrictions; 35 36 private final ActivityManager mActivityManager; 37 private final UserManager mUserManager; 38 39 /** Cache the UserInfo we're running as because, unlike other profiles, it won't change. */ 40 private final UserInfo mCurrentUserInfo; 41 RestrictedProfileModel(final Context context)42 public RestrictedProfileModel(final Context context) { 43 this(context, /* applyRestrictions= */ true); 44 } 45 RestrictedProfileModel(final Context context, final boolean applyRestrictions)46 public RestrictedProfileModel(final Context context, final boolean applyRestrictions) { 47 mContext = context; 48 mApplyRestrictions = applyRestrictions; 49 50 mActivityManager = (ActivityManager) mContext.getSystemService(Context.ACTIVITY_SERVICE); 51 mUserManager = (UserManager) mContext.getSystemService(Context.USER_SERVICE); 52 mCurrentUserInfo = mUserManager.getUserInfo(mContext.getUserId()); 53 } 54 55 /** Switch into the restricted profile. */ enterUser()56 public boolean enterUser() { 57 if (isCurrentUser()) { 58 Log.w(TAG, "Tried to switch into current user"); 59 return false; 60 } 61 final UserInfo restrictedUser = getUser(); 62 if (restrictedUser == null) { 63 Log.e(TAG, "Tried to enter non-existent restricted user"); 64 return false; 65 } 66 updateBackgroundRestriction(restrictedUser); 67 switchUserNow(restrictedUser.id); 68 return true; 69 } 70 71 /** Switch out of the restricted profile, back into the primary user. */ exitUser()72 public void exitUser() { 73 if (isCurrentUser()) { 74 switchUserNow(getOwnerUserId()); 75 } 76 } 77 78 /** 79 * Remove the restricted profile. 80 * 81 * Called from another user. Requires permission to MANAGE_USERS. 82 */ removeUser()83 public void removeUser() { 84 final UserInfo restrictedUser = getUser(); 85 if (restrictedUser == null) { 86 Log.w(TAG, "No restricted user to remove?"); 87 return; 88 } 89 final int restrictedUserHandle = restrictedUser.id; 90 mUserManager.removeUser(restrictedUserHandle); 91 } 92 93 /** @return {@code true} if the current user is the restricted profile. */ isCurrentUser()94 public boolean isCurrentUser() { 95 return mCurrentUserInfo.isRestricted(); 96 } 97 98 /** 99 * @return a @{link UserInfo} for the restricted profile, or {@code null} if there is no 100 * restricted profile on the device. 101 */ getUser()102 public UserInfo getUser() { 103 if (mCurrentUserInfo.isRestricted()) { 104 return mCurrentUserInfo; 105 } 106 for (UserInfo userInfo : mUserManager.getUsers()) { 107 if (userInfo.isRestricted()) { 108 return userInfo; 109 } 110 } 111 return null; 112 } 113 114 /** 115 * @return user ID for the current user, or parent of the current user if it exists. 116 */ getOwnerUserId()117 private int getOwnerUserId() { 118 if (!mCurrentUserInfo.isRestricted()) { 119 return mCurrentUserInfo.id; 120 } else if (mCurrentUserInfo.restrictedProfileParentId == UserInfo.NO_PROFILE_GROUP_ID) { 121 return UserHandle.USER_OWNER; 122 } else { 123 return mCurrentUserInfo.restrictedProfileParentId; 124 } 125 } 126 127 /** Switch to {@param userId} or log an exception if this fails. */ switchUserNow(int userId)128 private void switchUserNow(int userId) { 129 try { 130 mActivityManager.switchUser(userId); 131 } catch (RuntimeException e) { 132 Log.e(TAG, "Caught exception while switching user! ", e); 133 } 134 } 135 136 /** 137 * Profiles are allowed to run in the background by default, unless the device specifically 138 * sets a config flag and/or has the global setting overridden by something on-device. 139 */ updateBackgroundRestriction(UserInfo user)140 private void updateBackgroundRestriction(UserInfo user) { 141 if (!mApplyRestrictions) { 142 return; 143 } 144 final boolean allowedToRun = shouldAllowRunInBackground(); 145 mUserManager.setUserRestriction( 146 UserManager.DISALLOW_RUN_IN_BACKGROUND, !allowedToRun, user.getUserHandle()); 147 } 148 149 /** 150 * @see #updateBackgroundRestriction(UserInfo) 151 * @see Settings.Global#KEEP_PROFILE_IN_BACKGROUND 152 */ shouldAllowRunInBackground()153 private boolean shouldAllowRunInBackground() { 154 final boolean defaultValue = mContext.getResources().getBoolean( 155 mContext.getResources().getIdentifier("config_keepRestrictedProfilesInBackground", 156 "bool", "android")); 157 return Settings.Global.getInt(mContext.getContentResolver(), 158 Settings.Global.KEEP_PROFILE_IN_BACKGROUND, defaultValue ? 1 : 0) > 0; 159 } 160 } 161