diff --git a/res/values/strings.xml b/res/values/strings.xml
index ea6ece6657a..cc9a8dfbcc5 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -4942,6 +4942,15 @@
Delete user
Delete
+
+ Guest
+
+
+ Enable phone calls?
+
+ Enable phone calls and SMS?
+
+ Remove user
Allow apps and content
diff --git a/res/xml/user_details_settings.xml b/res/xml/user_details_settings.xml
new file mode 100644
index 00000000000..4353657f965
--- /dev/null
+++ b/res/xml/user_details_settings.xml
@@ -0,0 +1,28 @@
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/com/android/settings/users/AppRestrictionsFragment.java b/src/com/android/settings/users/AppRestrictionsFragment.java
index f1022b9a2eb..d1a5de32ce5 100644
--- a/src/com/android/settings/users/AppRestrictionsFragment.java
+++ b/src/com/android/settings/users/AppRestrictionsFragment.java
@@ -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)) {
diff --git a/src/com/android/settings/users/RemoveUserUtil.java b/src/com/android/settings/users/RemoveUserUtil.java
new file mode 100644
index 00000000000..ac74bfae3cc
--- /dev/null
+++ b/src/com/android/settings/users/RemoveUserUtil.java
@@ -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;
+ }
+}
diff --git a/src/com/android/settings/users/RestrictedProfileSettings.java b/src/com/android/settings/users/RestrictedProfileSettings.java
index 535e19672e0..41acda43bdf 100644
--- a/src/com/android/settings/users/RestrictedProfileSettings.java
+++ b/src/com/android/settings/users/RestrictedProfileSettings.java
@@ -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);
diff --git a/src/com/android/settings/users/UserDetailsSettings.java b/src/com/android/settings/users/UserDetailsSettings.java
new file mode 100644
index 00000000000..56b4598c21c
--- /dev/null
+++ b/src/com/android/settings/users/UserDetailsSettings.java
@@ -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();
+ }
+}
diff --git a/src/com/android/settings/users/UserPreference.java b/src/com/android/settings/users/UserPreference.java
index 56ca1143933..72aa9a4c583 100644
--- a/src/com/android/settings/users/UserPreference.java
+++ b/src/com/android/settings/users/UserPreference.java
@@ -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;
diff --git a/src/com/android/settings/users/UserSettings.java b/src/com/android/settings/users/UserSettings.java
index 8d27c65e425..42e1a5b7c9a 100644
--- a/src/com/android/settings/users/UserSettings.java
+++ b/src/com/android/settings/users/UserSettings.java
@@ -135,6 +135,7 @@ public class UserSettings extends SettingsPreferenceFragment
private UserManager mUserManager;
private SparseArray mUserIcons = new SparseArray();
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 users = mUserManager.getUsers(true);
+ final Context context = getActivity();
mUserListCategory.removeAll();
mUserListCategory.setOrderingAsAdded(false);
mUserListCategory.addPreference(mMePreference);
+ final boolean voiceCapable = Utils.isVoiceCapable(context);
final ArrayList missingIcons = new ArrayList();
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 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;
}