diff options
3 files changed, 70 insertions, 29 deletions
diff --git a/core/java/android/accounts/AccountManager.java b/core/java/android/accounts/AccountManager.java index 64c2fd0..6957435 100644 --- a/core/java/android/accounts/AccountManager.java +++ b/core/java/android/accounts/AccountManager.java @@ -1443,6 +1443,40 @@ public class AccountManager { } /** + * Copies an account from the primary user to another user. + * @param account the account to copy + * @param user the target user + * @param callback Callback to invoke when the request completes, + * null for no callback + * @param handler {@link Handler} identifying the callback thread, + * null for the main thread + * @return An {@link AccountManagerFuture} which resolves to a Boolean indicated wether it + * succeeded. + * @hide + */ + public AccountManagerFuture<Boolean> copyAccountToUser( + final Account account, final UserHandle user, + AccountManagerCallback<Boolean> callback, Handler handler) { + if (account == null) throw new IllegalArgumentException("account is null"); + if (user == null) throw new IllegalArgumentException("user is null"); + + return new Future2Task<Boolean>(handler, callback) { + @Override + public void doWork() throws RemoteException { + mService.copyAccountToUser( + mResponse, account, UserHandle.USER_OWNER, user.getIdentifier()); + } + @Override + public Boolean bundleToResult(Bundle bundle) throws AuthenticatorException { + if (!bundle.containsKey(KEY_BOOLEAN_RESULT)) { + throw new AuthenticatorException("no result in response"); + } + return bundle.getBoolean(KEY_BOOLEAN_RESULT); + } + }.start(); + } + + /** * @hide * Removes the shared account. * @param account the account to remove diff --git a/core/java/android/accounts/IAccountManager.aidl b/core/java/android/accounts/IAccountManager.aidl index bc75b9b..aa41161 100644 --- a/core/java/android/accounts/IAccountManager.aidl +++ b/core/java/android/accounts/IAccountManager.aidl @@ -42,6 +42,8 @@ interface IAccountManager { void removeAccountAsUser(in IAccountManagerResponse response, in Account account, boolean expectActivityLaunch, int userId); boolean removeAccountExplicitly(in Account account); + void copyAccountToUser(in IAccountManagerResponse response, in Account account, + int userFrom, int userTo); void invalidateAuthToken(String accountType, String authToken); String peekAuthToken(in Account account, String authTokenType); void setAuthToken(in Account account, String authTokenType, String authToken); diff --git a/services/core/java/com/android/server/accounts/AccountManagerService.java b/services/core/java/com/android/server/accounts/AccountManagerService.java index 85eed85..a2f4d56 100644 --- a/services/core/java/com/android/server/accounts/AccountManagerService.java +++ b/services/core/java/com/android/server/accounts/AccountManagerService.java @@ -486,7 +486,7 @@ public class AccountManagerService for (Account sa : sharedAccounts) { if (ArrayUtils.contains(accounts, sa)) continue; // Account doesn't exist. Copy it now. - copyAccountToUser(sa, UserHandle.USER_OWNER, userId); + copyAccountToUser(null /*no response*/, sa, UserHandle.USER_OWNER, userId); } } @@ -672,16 +672,31 @@ public class AccountManagerService } } - private boolean copyAccountToUser(final Account account, int userFrom, int userTo) { + @Override + public void copyAccountToUser(final IAccountManagerResponse response, final Account account, + int userFrom, int userTo) { + enforceCrossUserPermission(UserHandle.USER_ALL, "Calling copyAccountToUser requires " + + android.Manifest.permission.INTERACT_ACROSS_USERS_FULL); final UserAccounts fromAccounts = getUserAccounts(userFrom); final UserAccounts toAccounts = getUserAccounts(userTo); if (fromAccounts == null || toAccounts == null) { - return false; + if (response != null) { + Bundle result = new Bundle(); + result.putBoolean(AccountManager.KEY_BOOLEAN_RESULT, false); + try { + response.onResult(result); + } catch (RemoteException e) { + Slog.w(TAG, "Failed to report error back to the client." + e); + } + } + return; } + Slog.d(TAG, "Copying account " + account.name + + " from user " + userFrom + " to user " + userTo); long identityToken = clearCallingIdentity(); try { - new Session(fromAccounts, null, account.type, false, + new Session(fromAccounts, response, account.type, false, false /* stripAuthTokenFromResult */) { @Override protected String toDebugString(long now) { @@ -696,12 +711,10 @@ public class AccountManagerService @Override public void onResult(Bundle result) { - if (result != null) { - if (result.getBoolean(AccountManager.KEY_BOOLEAN_RESULT, false)) { - // Create a Session for the target user and pass in the bundle - completeCloningAccount(result, account, toAccounts); - } - return; + if (result != null + && result.getBoolean(AccountManager.KEY_BOOLEAN_RESULT, false)) { + // Create a Session for the target user and pass in the bundle + completeCloningAccount(response, result, account, toAccounts); } else { super.onResult(result); } @@ -710,14 +723,13 @@ public class AccountManagerService } finally { restoreCallingIdentity(identityToken); } - return true; } - void completeCloningAccount(final Bundle result, final Account account, - final UserAccounts targetUser) { + private void completeCloningAccount(IAccountManagerResponse response, + final Bundle accountCredentials, final Account account, final UserAccounts targetUser) { long id = clearCallingIdentity(); try { - new Session(targetUser, null, account.type, false, + new Session(targetUser, response, account.type, false, false /* stripAuthTokenFromResult */) { @Override protected String toDebugString(long now) { @@ -730,10 +742,10 @@ public class AccountManagerService // Confirm that the owner's account still exists before this step. UserAccounts owner = getUserAccounts(UserHandle.USER_OWNER); synchronized (owner.cacheLock) { - Account[] ownerAccounts = getAccounts(UserHandle.USER_OWNER); - for (Account acc : ownerAccounts) { + for (Account acc : getAccounts(UserHandle.USER_OWNER)) { if (acc.equals(account)) { - mAuthenticator.addAccountFromCredentials(this, account, result); + mAuthenticator.addAccountFromCredentials( + this, account, accountCredentials); break; } } @@ -742,17 +754,10 @@ public class AccountManagerService @Override public void onResult(Bundle result) { - if (result != null) { - if (result.getBoolean(AccountManager.KEY_BOOLEAN_RESULT, false)) { - // TODO: Anything? - } else { - // TODO: Show error notification - // TODO: Should we remove the shadow account to avoid retries? - } - return; - } else { - super.onResult(result); - } + // TODO: Anything to do if if succedded? + // TODO: If it failed: Show error notification? Should we remove the shadow + // account to avoid retries? + super.onResult(result); } @Override @@ -2740,7 +2745,7 @@ public class AccountManagerService break; case MESSAGE_COPY_SHARED_ACCOUNT: - copyAccountToUser((Account) msg.obj, msg.arg1, msg.arg2); + copyAccountToUser(/*no response*/ null, (Account) msg.obj, msg.arg1, msg.arg2); break; default: |