Handle choosing and adding accounts for a managed profile
The user id can now be passed through the app as a fragment argument.
Bug: 15466880
Change-Id: I0e2be20551b4ec8c9226640ac74ea74115156ccd
diff --git a/src/com/android/settings/Utils.java b/src/com/android/settings/Utils.java
index 8211816..d03305d 100644
--- a/src/com/android/settings/Utils.java
+++ b/src/com/android/settings/Utils.java
@@ -16,7 +16,11 @@
package com.android.settings;
+import static android.content.Intent.EXTRA_USER;
+
+import android.annotation.Nullable;
import android.app.ActivityManager;
+import android.app.ActivityManagerNative;
import android.app.AlertDialog;
import android.app.Dialog;
import android.app.Fragment;
@@ -61,6 +65,7 @@
import android.view.ViewGroup;
import android.widget.ListView;
import android.widget.TabWidget;
+
import com.android.settings.dashboard.DashboardCategory;
import com.android.settings.dashboard.DashboardTile;
@@ -73,6 +78,7 @@
public final class Utils {
private static final String TAG = "Settings";
+
/**
* Set the preference's title to the matching activity's label.
*/
@@ -110,6 +116,8 @@
*/
private static final String META_DATA_PREFERENCE_SUMMARY = "com.android.settings.summary";
+ private static final String SETTINGS_PACKAGE_NAME = "com.android.settings";
+
/**
* Finds a matching activity for a preference's intent. If a matching
* activity is not found, it will remove the preference.
@@ -613,28 +621,100 @@
}
/**
- * Returns the {@link UserHandle} of the profile that a settings screen should refer to.
+ * Returns the target user for a Settings activity.
*
- * <p> This takes into account the id of the user that triggered the settings screen.
+ * The target user can be either the current user, the user that launched this activity or
+ * the user contained as an extra in the arguments or intent extras.
+ *
+ * Note: This is secure in the sense that it only returns a target user different to the current
+ * one if the app launching this activity is the Settings app itself, running in the same user
+ * or in one that is in the same profile group, or if the user id is provided by the system.
*/
- public static UserHandle getProfileToDisplay(IActivityManager am, IBinder activityToken,
- Bundle arguments) {
- int currentUser = UserHandle.getCallingUserId();
- // Check to see if it was called from a different user
+ public static UserHandle getSecureTargetUser(IBinder activityToken,
+ UserManager um, @Nullable Bundle arguments, @Nullable Bundle intentExtras) {
+ UserHandle currentUser = new UserHandle(UserHandle.myUserId());
+ IActivityManager am = ActivityManagerNative.getDefault();
+ try {
+ String launchedFromPackage = am.getLaunchedFromPackage(activityToken);
+ boolean launchedFromSettingsApp = SETTINGS_PACKAGE_NAME.equals(launchedFromPackage);
+
+ UserHandle launchedFromUser = new UserHandle(UserHandle.getUserId(
+ am.getLaunchedFromUid(activityToken)));
+ if (launchedFromUser != null && !launchedFromUser.equals(currentUser)) {
+ // Check it's secure
+ if (isProfileOf(um, launchedFromUser)) {
+ return launchedFromUser;
+ }
+ }
+ UserHandle extrasUser = intentExtras != null
+ ? (UserHandle) intentExtras.getParcelable(EXTRA_USER) : null;
+ if (extrasUser != null && !extrasUser.equals(currentUser)) {
+ // Check it's secure
+ if (launchedFromSettingsApp && isProfileOf(um, extrasUser)) {
+ return extrasUser;
+ }
+ }
+ UserHandle argumentsUser = arguments != null
+ ? (UserHandle) arguments.getParcelable(EXTRA_USER) : null;
+ if (argumentsUser != null && !argumentsUser.equals(currentUser)) {
+ // Check it's secure
+ if (launchedFromSettingsApp && isProfileOf(um, argumentsUser)) {
+ return argumentsUser;
+ }
+ }
+ } catch (RemoteException e) {
+ // Should not happen
+ Log.v(TAG, "Could not talk to activity manager.", e);
+ }
+ return currentUser;
+ }
+
+ /**
+ * Returns the target user for a Settings activity.
+ *
+ * The target user can be either the current user, the user that launched this activity or
+ * the user contained as an extra in the arguments or intent extras.
+ *
+ * You should use {@link #getSecureTargetUser(IBinder, UserManager, Bundle, Bundle)} if
+ * possible.
+ *
+ * @see #getInsecureTargetUser(IBinder, Bundle, Bundle)
+ */
+ public static UserHandle getInsecureTargetUser(IBinder activityToken, @Nullable Bundle arguments,
+ @Nullable Bundle intentExtras) {
+ UserHandle currentUser = new UserHandle(UserHandle.myUserId());
+ IActivityManager am = ActivityManagerNative.getDefault();
try {
- int launchedFromUser = UserHandle.getUserId(am.getLaunchedFromUid(activityToken));
- if (launchedFromUser != currentUser) {
- // This is a forwarded intent
- return new UserHandle(launchedFromUser);
+ UserHandle launchedFromUser = new UserHandle(UserHandle.getUserId(
+ am.getLaunchedFromUid(activityToken)));
+ if (launchedFromUser != null && !launchedFromUser.equals(currentUser)) {
+ return launchedFromUser;
+ }
+ UserHandle extrasUser = intentExtras != null
+ ? (UserHandle) intentExtras.getParcelable(EXTRA_USER) : null;
+ if (extrasUser != null && !extrasUser.equals(currentUser)) {
+ return extrasUser;
+ }
+ UserHandle argumentsUser = arguments != null
+ ? (UserHandle) arguments.getParcelable(EXTRA_USER) : null;
+ if (argumentsUser != null && !argumentsUser.equals(currentUser)) {
+ return argumentsUser;
}
} catch (RemoteException e) {
// Should not happen
- Log.v(TAG, "Could not get launching user.");
+ Log.v(TAG, "Could not talk to activity manager.", e);
+ return null;
}
- // TODO: Check fragment arguments. See: http://b/15466880
+ return currentUser;
+ }
- // Default to current profile
- return new UserHandle(currentUser);
+ /**
+ * Returns true if the user provided is in the same profiles group as the current user.
+ */
+ private static boolean isProfileOf(UserManager um, UserHandle otherUser) {
+ if (um == null || otherUser == null) return false;
+ return (UserHandle.myUserId() == otherUser.getIdentifier())
+ || um.getUserProfiles().contains(otherUser);
}
/**