Multiuser settings revamp for L, first pass

Include Guest settings
Ability to switch users from Settings
Manage user settings like telephony access

Bug: 15761405
Change-Id: I2cfdc7bc2703ed202aa8bf1261c304c51ce48b29
This commit is contained in:
Amith Yamasani
2014-06-30 15:31:37 +05:30
parent 5b3c3c00b0
commit 9e6ac3d25f
8 changed files with 337 additions and 35 deletions

View File

@@ -683,7 +683,7 @@ public class AppRestrictionsFragment extends SettingsPreferenceFragment implemen
app.masterEntry.activityName));
}
p.setKey(getKeyForPackage(packageName));
p.setSettingsEnabled(hasSettings || isSettingsApp);
p.setSettingsEnabled((hasSettings || isSettingsApp) && app.masterEntry == null);
p.setPersistent(false);
p.setOnPreferenceChangeListener(this);
p.setOnPreferenceClickListener(this);
@@ -702,7 +702,8 @@ public class AppRestrictionsFragment extends SettingsPreferenceFragment implemen
// Get and populate the defaults, since the user is not going to be
// able to toggle this app ON (it's ON by default and immutable).
// Only do this for restricted profiles, not single-user restrictions
if (hasSettings) {
// Also don't do this for slave icons
if (hasSettings && app.masterEntry == null) {
requestRestrictionsForApp(packageName, p, false);
}
} else if (!mNewUser && isAppEnabledForUser(pi)) {

View File

@@ -0,0 +1,52 @@
/*
* Copyright (C) 2014 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.settings.users;
import android.app.AlertDialog;
import android.app.Dialog;
import android.content.Context;
import android.content.DialogInterface;
import android.content.pm.UserInfo;
import android.os.UserHandle;
import android.os.UserManager;
import com.android.settings.R;
public class RemoveUserUtil {
static Dialog createConfirmationDialog(Context context, int removingUserId,
DialogInterface.OnClickListener onConfirmListener) {
final UserManager um = (UserManager) context.getSystemService(Context.USER_SERVICE);
final UserInfo userInfo = um.getUserInfo(removingUserId);
Dialog dlg = new AlertDialog.Builder(context)
.setTitle(UserHandle.myUserId() == removingUserId
? R.string.user_confirm_remove_self_title
: (userInfo.isRestricted()
? R.string.user_profile_confirm_remove_title
: R.string.user_confirm_remove_title))
.setMessage(UserHandle.myUserId() == removingUserId
? R.string.user_confirm_remove_self_message
: (userInfo.isRestricted()
? R.string.user_profile_confirm_remove_message
: R.string.user_confirm_remove_message))
.setPositiveButton(R.string.user_delete_button,
onConfirmListener)
.setNegativeButton(android.R.string.cancel, null)
.create();
return dlg;
}
}

View File

@@ -101,7 +101,7 @@ public class RestrictedProfileSettings extends AppRestrictionsFragment {
mHeaderView.setOnClickListener(this);
mUserIconView = (ImageView) mHeaderView.findViewById(android.R.id.icon);
mUserNameView = (TextView) mHeaderView.findViewById(android.R.id.title);
getListView().setFastScrollEnabled(true);
//getListView().setFastScrollEnabled(true);
}
// This is going to bind the preferences.
super.onActivityCreated(savedInstanceState);

View File

@@ -0,0 +1,152 @@
/*
* Copyright (C) 2014 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.settings.users;
import android.app.Dialog;
import android.content.Context;
import android.content.DialogInterface;
import android.content.pm.UserInfo;
import android.os.Bundle;
import android.os.UserHandle;
import android.os.UserManager;
import android.preference.Preference;
import android.preference.SwitchPreference;
import com.android.settings.R;
import com.android.settings.SettingsPreferenceFragment;
import com.android.settings.Utils;
/**
* Settings screen for configuring a specific user. It can contain user restrictions
* and deletion controls. It is shown when you tap on the settings icon in the
* user management (UserSettings) screen.
* Arguments to this fragment must include the userId of the user (in EXTRA_USER_ID) for whom
* to display controls, or should contain the EXTRA_USER_GUEST = true.
*/
public class UserDetailsSettings extends SettingsPreferenceFragment
implements Preference.OnPreferenceClickListener, Preference.OnPreferenceChangeListener {
private static final String TAG = UserDetailsSettings.class.getSimpleName();
private static final String KEY_ENABLE_TELEPHONY = "enable_calling";
private static final String KEY_REMOVE_USER = "remove_user";
/** Integer extra containing the userId to manage */
static final String EXTRA_USER_ID = "user_id";
/** Boolean extra to indicate guest preferences */
static final String EXTRA_USER_GUEST = "guest_user";
private static final int DIALOG_CONFIRM_REMOVE = 1;
private static final int DIALOG_CONFIRM_ENABLE_CALLING = 2;
private static final int DIALOG_CONFIRM_ENABLE_CALLING_SMS = 3;
private UserManager mUserManager;
private SwitchPreference mPhonePref;
private Preference mRemoveUserPref;
private UserInfo mUserInfo;
private boolean mGuestUser;
private Bundle mDefaultGuestRestrictions;
@Override
public void onCreate(Bundle icicle) {
super.onCreate(icicle);
final Context context = getActivity();
mUserManager = (UserManager) context.getSystemService(Context.USER_SERVICE);
addPreferencesFromResource(R.xml.user_details_settings);
mPhonePref = (SwitchPreference) findPreference(KEY_ENABLE_TELEPHONY);
mRemoveUserPref = findPreference(KEY_REMOVE_USER);
mGuestUser = getArguments().getBoolean(EXTRA_USER_GUEST, false);
if (!mGuestUser) {
// Regular user. Get the user id from the caller.
final int userId = getArguments().getInt(EXTRA_USER_ID, -1);
if (userId == -1) {
throw new RuntimeException("Arguments to this fragment must contain the user id");
}
mUserInfo = mUserManager.getUserInfo(userId);
mPhonePref.setChecked(!mUserManager.hasUserRestriction(UserManager.DISALLOW_TELEPHONY,
new UserHandle(userId)));
mRemoveUserPref.setOnPreferenceClickListener(this);
} else {
// These are not for an existing user, just general Guest settings.
removePreference(KEY_REMOVE_USER);
// Default title is for calling and SMS. Change to calling-only here
mPhonePref.setTitle(R.string.user_enable_calling);
mDefaultGuestRestrictions = mUserManager.getDefaultGuestRestrictions();
mPhonePref.setChecked(
!mDefaultGuestRestrictions.getBoolean(UserManager.DISALLOW_TELEPHONY));
}
mPhonePref.setOnPreferenceChangeListener(this);
}
@Override
public boolean onPreferenceClick(Preference preference) {
if (preference == mRemoveUserPref) {
if (UserHandle.myUserId() != UserHandle.USER_OWNER) {
throw new RuntimeException("Only the owner can remove a user");
}
showDialog(DIALOG_CONFIRM_REMOVE);
return true;
}
return false;
}
@Override
public boolean onPreferenceChange(Preference preference, Object newValue) {
if (mGuestUser) {
// TODO: Show confirmation dialog: b/15761405
mDefaultGuestRestrictions.putBoolean(UserManager.DISALLOW_TELEPHONY,
!((Boolean) newValue));
mUserManager.setDefaultGuestRestrictions(mDefaultGuestRestrictions);
} else {
// TODO: Show confirmation dialog: b/15761405
mUserManager.setUserRestriction(UserManager.DISALLOW_TELEPHONY, !((Boolean) newValue),
new UserHandle(mUserInfo.id));
}
return true;
}
@Override
public Dialog onCreateDialog(int dialogId) {
Context context = getActivity();
if (context == null) return null;
switch (dialogId) {
case DIALOG_CONFIRM_REMOVE: {
Dialog dlg = RemoveUserUtil.createConfirmationDialog(getActivity(), mUserInfo.id,
new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
removeUser();
}
});
return dlg;
}
case DIALOG_CONFIRM_ENABLE_CALLING:
case DIALOG_CONFIRM_ENABLE_CALLING_SMS:
// TODO: b/15761405
}
return null;
}
void removeUser() {
mUserManager.removeUser(mUserInfo.id);
finishFragment();
}
}

View File

@@ -30,6 +30,7 @@ import android.view.View.OnClickListener;
public class UserPreference extends Preference {
public static final int USERID_UNKNOWN = -10;
public static final int USERID_GUEST_DEFAULTS = -11;
private OnClickListener mDeleteClickListener;
private OnClickListener mSettingsClickListener;
@@ -92,7 +93,11 @@ public class UserPreference extends Preference {
if (mUserId == UserHandle.myUserId()) return Integer.MIN_VALUE;
if (mSerialNumber < 0) {
// If the userId is unknown
if (mUserId == USERID_UNKNOWN) return Integer.MAX_VALUE;
if (mUserId == USERID_UNKNOWN) {
return Integer.MAX_VALUE;
} else if (mUserId == USERID_GUEST_DEFAULTS) {
return Integer.MAX_VALUE - 1;
}
mSerialNumber = ((UserManager) getContext().getSystemService(Context.USER_SERVICE))
.getUserSerialNumber(mUserId);
if (mSerialNumber < 0) return mUserId;

View File

@@ -135,6 +135,7 @@ public class UserSettings extends SettingsPreferenceFragment
private UserManager mUserManager;
private SparseArray<Bitmap> mUserIcons = new SparseArray<Bitmap>();
private boolean mIsOwner = UserHandle.myUserId() == UserHandle.USER_OWNER;
private boolean mIsGuest;
private Handler mHandler = new Handler() {
@Override
@@ -189,9 +190,12 @@ public class UserSettings extends SettingsPreferenceFragment
return;
}
final int myUserId = UserHandle.myUserId();
mIsGuest = mUserManager.getUserInfo(myUserId).isGuest();
addPreferencesFromResource(R.xml.user_settings);
mUserListCategory = (PreferenceGroup) findPreference(KEY_USER_LIST);
mMePreference = new UserPreference(context, null, UserHandle.myUserId(),
mMePreference = new UserPreference(context, null, myUserId,
mUserManager.isLinkedUser() ? null : this, null);
mMePreference.setKey(KEY_USER_ME);
mMePreference.setOnPreferenceClickListener(this);
@@ -207,7 +211,10 @@ public class UserSettings extends SettingsPreferenceFragment
mAddUser.setOnPreferenceClickListener(this);
DevicePolicyManager dpm = (DevicePolicyManager) context.getSystemService(
Context.DEVICE_POLICY_SERVICE);
if (dpm.getDeviceOwner() != null) {
// No restricted profiles for tablets with a device owner, or
// phones.
if (dpm.getDeviceOwner() != null
|| Utils.isVoiceCapable(context)) {
mCanAddRestrictedProfile = false;
mAddUser.setTitle(R.string.user_add_user_menu);
}
@@ -216,7 +223,7 @@ public class UserSettings extends SettingsPreferenceFragment
setHasOptionsMenu(true);
IntentFilter filter = new IntentFilter(Intent.ACTION_USER_REMOVED);
filter.addAction(Intent.ACTION_USER_INFO_CHANGED);
getActivity().registerReceiverAsUser(mUserChangeReceiver, UserHandle.ALL, filter, null,
context.registerReceiverAsUser(mUserChangeReceiver, UserHandle.ALL, filter, null,
mHandler);
}
@@ -390,6 +397,14 @@ public class UserSettings extends SettingsPreferenceFragment
}
private void onManageUserClicked(int userId, boolean newUser) {
if (userId == UserPreference.USERID_GUEST_DEFAULTS) {
Bundle extras = new Bundle();
extras.putBoolean(UserDetailsSettings.EXTRA_USER_GUEST, true);
((SettingsActivity) getActivity()).startPreferencePanel(
UserDetailsSettings.class.getName(),
extras, R.string.user_guest, null, null, 0);
return;
}
UserInfo info = mUserManager.getUserInfo(userId);
if (info.isRestricted() && mIsOwner) {
Bundle extras = new Bundle();
@@ -411,6 +426,12 @@ public class UserSettings extends SettingsPreferenceFragment
((SettingsActivity) getActivity()).startPreferencePanel(
OwnerInfoSettings.class.getName(),
extras, titleResId, null, null, 0);
} else if (mIsOwner) {
Bundle extras = new Bundle();
extras.putInt(UserDetailsSettings.EXTRA_USER_ID, userId);
((SettingsActivity) getActivity()).startPreferencePanel(
UserDetailsSettings.class.getName(),
extras, -1, info.name, null, 0);
}
}
@@ -436,25 +457,14 @@ public class UserSettings extends SettingsPreferenceFragment
if (context == null) return null;
switch (dialogId) {
case DIALOG_CONFIRM_REMOVE: {
Dialog dlg = new AlertDialog.Builder(getActivity())
.setTitle(UserHandle.myUserId() == mRemovingUserId
? R.string.user_confirm_remove_self_title
: (mUserManager.getUserInfo(mRemovingUserId).isRestricted()
? R.string.user_profile_confirm_remove_title
: R.string.user_confirm_remove_title))
.setMessage(UserHandle.myUserId() == mRemovingUserId
? R.string.user_confirm_remove_self_message
: (mUserManager.getUserInfo(mRemovingUserId).isRestricted()
? R.string.user_profile_confirm_remove_message
: R.string.user_confirm_remove_message))
.setPositiveButton(R.string.user_delete_button,
new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
removeUserNow();
}
})
.setNegativeButton(android.R.string.cancel, null)
.create();
Dialog dlg =
RemoveUserUtil.createConfirmationDialog(getActivity(), mRemovingUserId,
new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
removeUserNow();
}
}
);
return dlg;
}
case DIALOG_USER_CANNOT_MANAGE:
@@ -625,20 +635,38 @@ public class UserSettings extends SettingsPreferenceFragment
private void updateUserList() {
if (getActivity() == null) return;
List<UserInfo> users = mUserManager.getUsers(true);
final Context context = getActivity();
mUserListCategory.removeAll();
mUserListCategory.setOrderingAsAdded(false);
mUserListCategory.addPreference(mMePreference);
final boolean voiceCapable = Utils.isVoiceCapable(context);
final ArrayList<Integer> missingIcons = new ArrayList<Integer>();
for (UserInfo user : users) {
Preference pref;
if (user.id == UserHandle.myUserId()) {
pref = mMePreference;
} else if (user.isGuest()) {
// Skip over Guest. We add generic Guest settings after this loop
continue;
} else {
pref = new UserPreference(getActivity(), null, user.id,
mIsOwner && user.isRestricted() ? this : null,
mIsOwner ? this : null);
// With Telephony:
// Secondary user: Settings
// Guest: Settings
// Restricted Profile: There is no Restricted Profile
// Without Telephony:
// Secondary user: Delete
// Guest: Nothing
// Restricted Profile: Settings
final boolean showSettings = mIsOwner && (voiceCapable || user.isRestricted());
final boolean showDelete = mIsOwner
&& (!voiceCapable && !user.isRestricted() && !user.isGuest());
pref = new UserPreference(context, null, user.id,
showSettings ? this : null,
showDelete ? this : null);
//mIsOwner && user.isRestricted() ? this : null,
//mIsOwner ? this : null);
pref.setOnPreferenceClickListener(this);
pref.setKey("id=" + user.id);
mUserListCategory.addPreference(pref);
@@ -682,6 +710,17 @@ public class UserSettings extends SettingsPreferenceFragment
pref.setIcon(encircle(R.drawable.avatar_default_1));
mUserListCategory.addPreference(pref);
}
if (!mIsGuest) {
// Add a virtual Guest user for guest defaults
Preference pref = new UserPreference(getActivity(), null,
UserPreference.USERID_GUEST_DEFAULTS, mIsOwner ? this : null, null);
pref.setTitle(R.string.user_guest);
pref.setIcon(encircle(R.drawable.ic_settings_accounts));
pref.setOnPreferenceClickListener(this);
mUserListCategory.addPreference(pref);
}
getActivity().invalidateOptionsMenu();
// Load the icons
@@ -767,16 +806,16 @@ public class UserSettings extends SettingsPreferenceFragment
}
} else if (pref instanceof UserPreference) {
int userId = ((UserPreference) pref).getUserId();
// Get the latest status of the user
UserInfo user = mUserManager.getUserInfo(userId);
if (UserHandle.myUserId() != UserHandle.USER_OWNER) {
showDialog(DIALOG_USER_CANNOT_MANAGE);
if (userId == UserPreference.USERID_GUEST_DEFAULTS) {
createAndSwitchToGuestUser();
} else {
// Get the latest status of the user
UserInfo user = mUserManager.getUserInfo(userId);
if (!isInitialized(user)) {
mHandler.sendMessage(mHandler.obtainMessage(
MESSAGE_SETUP_USER, user.id, user.serialNumber));
} else if (user.isRestricted()) {
onManageUserClicked(user.id, false);
} else if (!user.isManagedProfile()) {
switchUserNow(userId);
}
}
} else if (pref == mAddUser) {
@@ -791,6 +830,22 @@ public class UserSettings extends SettingsPreferenceFragment
return false;
}
private void createAndSwitchToGuestUser() {
List<UserInfo> users = mUserManager.getUsers();
for (UserInfo user : users) {
if (user.isGuest()) {
switchUserNow(user.id);
return;
}
}
// No guest user. Create one.
UserInfo guestUser = mUserManager.createGuest(getActivity(),
getResources().getString(R.string.user_guest));
if (guestUser != null) {
switchUserNow(guestUser.id);
}
}
private boolean isInitialized(UserInfo user) {
return (user.flags & UserInfo.FLAG_INITIALIZED) != 0;
}