Loading core/java/android/accounts/AccountManager.java +34 −0 Original line number Diff line number Diff line Loading @@ -1442,6 +1442,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. Loading core/java/android/accounts/IAccountManager.aidl +2 −0 Original line number Diff line number Diff line Loading @@ -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); Loading services/core/java/com/android/server/accounts/AccountManagerService.java +34 −29 Original line number Diff line number Diff line Loading @@ -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); } } Loading Loading @@ -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) { Loading @@ -696,12 +711,10 @@ public class AccountManagerService @Override public void onResult(Bundle result) { if (result != null) { if (result.getBoolean(AccountManager.KEY_BOOLEAN_RESULT, false)) { if (result != null && result.getBoolean(AccountManager.KEY_BOOLEAN_RESULT, false)) { // Create a Session for the target user and pass in the bundle completeCloningAccount(result, account, toAccounts); } return; completeCloningAccount(response, result, account, toAccounts); } else { super.onResult(result); } Loading @@ -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) { Loading @@ -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; } } Loading @@ -742,18 +754,11 @@ 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 { // 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 public void onError(int errorCode, String errorMessage) { Loading Loading @@ -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: Loading Loading
core/java/android/accounts/AccountManager.java +34 −0 Original line number Diff line number Diff line Loading @@ -1442,6 +1442,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. Loading
core/java/android/accounts/IAccountManager.aidl +2 −0 Original line number Diff line number Diff line Loading @@ -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); Loading
services/core/java/com/android/server/accounts/AccountManagerService.java +34 −29 Original line number Diff line number Diff line Loading @@ -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); } } Loading Loading @@ -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) { Loading @@ -696,12 +711,10 @@ public class AccountManagerService @Override public void onResult(Bundle result) { if (result != null) { if (result.getBoolean(AccountManager.KEY_BOOLEAN_RESULT, false)) { if (result != null && result.getBoolean(AccountManager.KEY_BOOLEAN_RESULT, false)) { // Create a Session for the target user and pass in the bundle completeCloningAccount(result, account, toAccounts); } return; completeCloningAccount(response, result, account, toAccounts); } else { super.onResult(result); } Loading @@ -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) { Loading @@ -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; } } Loading @@ -742,18 +754,11 @@ 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 { // 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 public void onError(int errorCode, String errorMessage) { Loading Loading @@ -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: Loading