Modifies APIs for retrieving managed profile accounts.

This is needed for Account Settings UI.

Bug: 13656853
Change-Id: I33129e4b7b33b428a7bf670259accacb60f62d9b
diff --git a/core/java/android/accounts/AccountManager.java b/core/java/android/accounts/AccountManager.java
index 12fcdcf..806a55b 100644
--- a/core/java/android/accounts/AccountManager.java
+++ b/core/java/android/accounts/AccountManager.java
@@ -359,7 +359,29 @@
      */
     public AuthenticatorDescription[] getAuthenticatorTypes() {
         try {
-            return mService.getAuthenticatorTypes();
+            return mService.getAuthenticatorTypes(UserHandle.getCallingUserId());
+        } catch (RemoteException e) {
+            // will never happen
+            throw new RuntimeException(e);
+        }
+    }
+
+    /**
+     * @hide
+     * Lists the currently registered authenticators for a given user id.
+     *
+     * <p>It is safe to call this method from the main thread.
+     *
+     * <p>The caller has to be in the same user or have the permission
+     * {@link android.Manifest.permission#INTERACT_ACROSS_USERS_FULL}.
+     *
+     * @return An array of {@link AuthenticatorDescription} for every
+     *     authenticator known to the AccountManager service.  Empty (never
+     *     null) if no authenticators are known.
+     */
+    public AuthenticatorDescription[] getAuthenticatorTypesAsUser(int userId) {
+        try {
+            return mService.getAuthenticatorTypes(userId);
         } catch (RemoteException e) {
             // will never happen
             throw new RuntimeException(e);
@@ -389,6 +411,28 @@
 
     /**
      * @hide
+     * Lists all accounts of any type registered on the device for a given
+     * user id. Equivalent to getAccountsByType(null).
+     *
+     * <p>It is safe to call this method from the main thread.
+     *
+     * <p>This method requires the caller to hold the permission
+     * {@link android.Manifest.permission#GET_ACCOUNTS}.
+     *
+     * @return An array of {@link Account}, one for each account.  Empty
+     *     (never null) if no accounts have been added.
+     */
+    public Account[] getAccountsAsUser(int userId) {
+        try {
+            return mService.getAccountsAsUser(null, userId);
+        } catch (RemoteException e) {
+            // won't ever happen
+            throw new RuntimeException(e);
+        }
+    }
+
+    /**
+     * @hide
      * For use by internal activities. Returns the list of accounts that the calling package
      * is authorized to use, particularly for shared accounts.
      * @param packageName package name of the calling app.
diff --git a/core/java/android/accounts/IAccountManager.aidl b/core/java/android/accounts/IAccountManager.aidl
index 86e279f..1373dc8 100644
--- a/core/java/android/accounts/IAccountManager.aidl
+++ b/core/java/android/accounts/IAccountManager.aidl
@@ -29,7 +29,7 @@
 interface IAccountManager {
     String getPassword(in Account account);
     String getUserData(in Account account, String key);
-    AuthenticatorDescription[] getAuthenticatorTypes();
+    AuthenticatorDescription[] getAuthenticatorTypes(int userId);
     Account[] getAccounts(String accountType);
     Account[] getAccountsForPackage(String packageName, int uid);
     Account[] getAccountsByTypeForPackage(String type, String packageName);
diff --git a/core/java/android/os/UserHandle.java b/core/java/android/os/UserHandle.java
index 914c170..afbf983 100644
--- a/core/java/android/os/UserHandle.java
+++ b/core/java/android/os/UserHandle.java
@@ -16,7 +16,10 @@
 
 package android.os;
 
+import android.util.SparseArray;
+
 import java.io.PrintWriter;
+import java.util.HashMap;
 
 /**
  * Representation of a user on the device.
@@ -66,6 +69,8 @@
 
     final int mHandle;
 
+    private static final SparseArray<UserHandle> userHandles = new SparseArray<UserHandle>();
+
     /**
      * Checks to see if the user id is the same for the two uids, i.e., they belong to the same
      * user.
@@ -124,6 +129,18 @@
         return getUserId(Binder.getCallingUid());
     }
 
+    /** @hide */
+    public static final UserHandle getCallingUserHandle() {
+        int userId = getUserId(Binder.getCallingUid());
+        UserHandle userHandle = userHandles.get(userId);
+        // Intentionally not synchronized to save time
+        if (userHandle == null) {
+            userHandle = new UserHandle(userId);
+            userHandles.put(userId, userHandle);
+        }
+        return userHandle;
+    }
+
     /**
      * Returns the uid that is composed from the userId and the appId.
      * @hide
diff --git a/services/core/java/com/android/server/accounts/AccountManagerService.java b/services/core/java/com/android/server/accounts/AccountManagerService.java
index b2aaf74..e152ebe 100644
--- a/services/core/java/com/android/server/accounts/AccountManagerService.java
+++ b/services/core/java/com/android/server/accounts/AccountManagerService.java
@@ -537,13 +537,16 @@
     }
 
     @Override
-    public AuthenticatorDescription[] getAuthenticatorTypes() {
+    public AuthenticatorDescription[] getAuthenticatorTypes(int userId) {
         if (Log.isLoggable(TAG, Log.VERBOSE)) {
             Log.v(TAG, "getAuthenticatorTypes: "
+                    + "for user id " + userId
                     + "caller's uid " + Binder.getCallingUid()
                     + ", pid " + Binder.getCallingPid());
         }
-        final int userId = UserHandle.getCallingUserId();
+        // Only allow the system process to read accounts of other users
+        enforceCrossUserPermission(userId, "User " + UserHandle.getCallingUserId()
+                + " trying get authenticator types for " + userId);
         final long identityToken = clearCallingIdentity();
         try {
             Collection<AccountAuthenticatorCache.ServiceInfo<AuthenticatorDescription>>
@@ -562,6 +565,16 @@
         }
     }
 
+    private void enforceCrossUserPermission(int userId, String errorMessage) {
+        if (userId != UserHandle.getCallingUserId()
+                && Binder.getCallingUid() != Process.myUid()
+                && mContext.checkCallingOrSelfPermission(
+                    android.Manifest.permission.INTERACT_ACROSS_USERS_FULL)
+                    != PackageManager.PERMISSION_GRANTED) {
+            throw new SecurityException(errorMessage);
+        }
+    }
+
     @Override
     public boolean addAccountExplicitly(Account account, String password, Bundle extras) {
         if (Log.isLoggable(TAG, Log.VERBOSE)) {
@@ -1567,14 +1580,8 @@
             final Account account, final Bundle options, final boolean expectActivityLaunch,
             int userId) {
         // Only allow the system process to read accounts of other users
-        if (userId != UserHandle.getCallingUserId()
-                && Binder.getCallingUid() != Process.myUid()
-                && mContext.checkCallingOrSelfPermission(
-                    android.Manifest.permission.INTERACT_ACROSS_USERS_FULL)
-                    != PackageManager.PERMISSION_GRANTED) {
-            throw new SecurityException("User " + UserHandle.getCallingUserId()
+        enforceCrossUserPermission(userId, "User " + UserHandle.getCallingUserId()
                     + " trying to confirm account credentials for " + userId);
-        }
 
         if (Log.isLoggable(TAG, Log.VERBOSE)) {
             Log.v(TAG, "confirmCredentials: " + account