/* * Copyright (C) 2021 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.android.tv.settings.users; import android.app.ActivityManager; import android.content.Context; import android.content.pm.UserInfo; import android.os.UserHandle; import android.os.UserManager; import android.provider.Settings; import android.util.Log; /** * Manipulate and list restricted profiles on the device. */ public class RestrictedProfileModel { private static final String TAG = "RestrictedProfile"; private final Context mContext; private final boolean mApplyRestrictions; private final ActivityManager mActivityManager; private final UserManager mUserManager; /** Cache the UserInfo we're running as because, unlike other profiles, it won't change. */ private final UserInfo mCurrentUserInfo; public RestrictedProfileModel(final Context context) { this(context, /* applyRestrictions= */ true); } public RestrictedProfileModel(final Context context, final boolean applyRestrictions) { mContext = context; mApplyRestrictions = applyRestrictions; mActivityManager = (ActivityManager) mContext.getSystemService(Context.ACTIVITY_SERVICE); mUserManager = (UserManager) mContext.getSystemService(Context.USER_SERVICE); mCurrentUserInfo = mUserManager.getUserInfo(mContext.getUserId()); } /** Switch into the restricted profile. */ public boolean enterUser() { if (isCurrentUser()) { Log.w(TAG, "Tried to switch into current user"); return false; } final UserInfo restrictedUser = getUser(); if (restrictedUser == null) { Log.e(TAG, "Tried to enter non-existent restricted user"); return false; } updateBackgroundRestriction(restrictedUser); switchUserNow(restrictedUser.id); return true; } /** Switch out of the restricted profile, back into the primary user. */ public void exitUser() { if (isCurrentUser()) { switchUserNow(getOwnerUserId()); } } /** * Remove the restricted profile. * * Called from another user. Requires permission to MANAGE_USERS. */ public void removeUser() { final UserInfo restrictedUser = getUser(); if (restrictedUser == null) { Log.w(TAG, "No restricted user to remove?"); return; } final int restrictedUserHandle = restrictedUser.id; mUserManager.removeUser(restrictedUserHandle); } /** @return {@code true} if the current user is the restricted profile. */ public boolean isCurrentUser() { return mCurrentUserInfo.isRestricted(); } /** * @return a @{link UserInfo} for the restricted profile, or {@code null} if there is no * restricted profile on the device. */ public UserInfo getUser() { if (mCurrentUserInfo.isRestricted()) { return mCurrentUserInfo; } for (UserInfo userInfo : mUserManager.getUsers()) { if (userInfo.isRestricted()) { return userInfo; } } return null; } /** * @return user ID for the current user, or parent of the current user if it exists. */ private int getOwnerUserId() { if (!mCurrentUserInfo.isRestricted()) { return mCurrentUserInfo.id; } else if (mCurrentUserInfo.restrictedProfileParentId == UserInfo.NO_PROFILE_GROUP_ID) { return UserHandle.USER_OWNER; } else { return mCurrentUserInfo.restrictedProfileParentId; } } /** Switch to {@param userId} or log an exception if this fails. */ private void switchUserNow(int userId) { try { mActivityManager.switchUser(userId); } catch (RuntimeException e) { Log.e(TAG, "Caught exception while switching user! ", e); } } /** * Profiles are allowed to run in the background by default, unless the device specifically * sets a config flag and/or has the global setting overridden by something on-device. */ private void updateBackgroundRestriction(UserInfo user) { if (!mApplyRestrictions) { return; } final boolean allowedToRun = shouldAllowRunInBackground(); mUserManager.setUserRestriction( UserManager.DISALLOW_RUN_IN_BACKGROUND, !allowedToRun, user.getUserHandle()); } /** * @see #updateBackgroundRestriction(UserInfo) * @see Settings.Global#KEEP_PROFILE_IN_BACKGROUND */ private boolean shouldAllowRunInBackground() { final boolean defaultValue = mContext.getResources().getBoolean( mContext.getResources().getIdentifier("config_keepRestrictedProfilesInBackground", "bool", "android")); return Settings.Global.getInt(mContext.getContentResolver(), Settings.Global.KEEP_PROFILE_IN_BACKGROUND, defaultValue ? 1 : 0) > 0; } }