do not merge: cherrypicked 3710f390968e683a0ad3adf0b517dfcade3564ce from master branch
diff --git a/core/java/android/accounts/AbstractAccountAuthenticator.java b/core/java/android/accounts/AbstractAccountAuthenticator.java
index 3ce3ca3..38ae962 100644
--- a/core/java/android/accounts/AbstractAccountAuthenticator.java
+++ b/core/java/android/accounts/AbstractAccountAuthenticator.java
@@ -188,6 +188,25 @@
                 response.onResult(result);
             }
         }
+
+        public void getAccountRemovalAllowed(IAccountAuthenticatorResponse response,
+                Account account) throws RemoteException {
+            checkBinderPermission();
+            try {
+                final Bundle result = AbstractAccountAuthenticator.this.getAccountRemovalAllowed(
+                    new AccountAuthenticatorResponse(response), account);
+                if (result != null) {
+                    response.onResult(result);
+                }
+            } catch (UnsupportedOperationException e) {
+                response.onError(Constants.ERROR_CODE_UNSUPPORTED_OPERATION,
+                        "getAccountRemovalAllowed not supported");
+                return;
+            } catch (NetworkErrorException e) {
+                response.onError(Constants.ERROR_CODE_NETWORK_ERROR, e.getMessage());
+                return;
+            }
+        }
     }
 
     private void checkBinderPermission() {
@@ -238,4 +257,10 @@
             Account account, String authTokenType, Bundle loginOptions);
     public abstract Bundle hasFeatures(AccountAuthenticatorResponse response,
             Account account, String[] features) throws NetworkErrorException;
+    public Bundle getAccountRemovalAllowed(AccountAuthenticatorResponse response,
+            Account account) throws NetworkErrorException {
+        final Bundle result = new Bundle();
+        result.putBoolean(Constants.BOOLEAN_RESULT_KEY, true);
+        return result;
+    }
 }
diff --git a/core/java/android/accounts/Account.java b/core/java/android/accounts/Account.java
index 30c91b0..7b83a30 100644
--- a/core/java/android/accounts/Account.java
+++ b/core/java/android/accounts/Account.java
@@ -26,20 +26,20 @@
  * suitable for use as the key of a {@link java.util.Map}
  */
 public class Account implements Parcelable {
-    public final String mName;
-    public final String mType;
+    public final String name;
+    public final String type;
 
     public boolean equals(Object o) {
         if (o == this) return true;
         if (!(o instanceof Account)) return false;
         final Account other = (Account)o;
-        return mName.equals(other.mName) && mType.equals(other.mType);
+        return name.equals(other.name) && type.equals(other.type);
     }
 
     public int hashCode() {
         int result = 17;
-        result = 31 * result + mName.hashCode();
-        result = 31 * result + mType.hashCode();
+        result = 31 * result + name.hashCode();
+        result = 31 * result + type.hashCode();
         return result;
     }
 
@@ -50,13 +50,13 @@
         if (TextUtils.isEmpty(type)) {
             throw new IllegalArgumentException("the type must not be empty: " + type);
         }
-        mName = name;
-        mType = type;
+        this.name = name;
+        this.type = type;
     }
 
     public Account(Parcel in) {
-        mName = in.readString();
-        mType = in.readString();
+        this.name = in.readString();
+        this.type = in.readString();
     }
 
     public int describeContents() {
@@ -64,8 +64,8 @@
     }
 
     public void writeToParcel(Parcel dest, int flags) {
-        dest.writeString(mName);
-        dest.writeString(mType);
+        dest.writeString(name);
+        dest.writeString(type);
     }
 
     public static final Creator<Account> CREATOR = new Creator<Account>() {
@@ -79,6 +79,6 @@
     };
 
     public String toString() {
-        return "Account {name=" + mName + ", type=" + mType + "}";
+        return "Account {name=" + name + ", type=" + type + "}";
     }
 }
diff --git a/core/java/android/accounts/AccountManager.java b/core/java/android/accounts/AccountManager.java
index 502abbb..9f70534 100644
--- a/core/java/android/accounts/AccountManager.java
+++ b/core/java/android/accounts/AccountManager.java
@@ -26,8 +26,6 @@
 import android.os.Looper;
 import android.os.RemoteException;
 import android.os.Parcelable;
-import android.util.Config;
-import android.util.Log;
 
 import java.io.IOException;
 import java.util.concurrent.Callable;
@@ -80,258 +78,132 @@
         return (AccountManager) context.getSystemService(Context.ACCOUNT_SERVICE);
     }
 
-    public String blockingGetPassword(Account account) {
-        ensureNotOnMainThread();
+    public String getPassword(final Account account) {
         try {
             return mService.getPassword(account);
         } catch (RemoteException e) {
-            // if this happens the entire runtime will restart
+            // will never happen
             throw new RuntimeException(e);
         }
     }
 
-    public Future1<String> getPassword(final Future1Callback<String> callback,
-            final Account account, final Handler handler) {
-        return startAsFuture(callback, handler, new Callable<String>() {
-            public String call() throws Exception {
-                return blockingGetPassword(account);
-            }
-        });
-    }
-
-    public String blockingGetUserData(Account account, String key) {
-        ensureNotOnMainThread();
+    public String getUserData(final Account account, final String key) {
         try {
             return mService.getUserData(account, key);
         } catch (RemoteException e) {
-            // if this happens the entire runtime will restart
+            // will never happen
             throw new RuntimeException(e);
         }
     }
 
-    public Future1<String> getUserData(Future1Callback<String> callback,
-            final Account account, final String key, Handler handler) {
-        return startAsFuture(callback, handler, new Callable<String>() {
-            public String call() throws Exception {
-                return blockingGetUserData(account, key);
-            }
-        });
-    }
-
-    public AuthenticatorDescription[] blockingGetAuthenticatorTypes() {
-        ensureNotOnMainThread();
+    public AuthenticatorDescription[] getAuthenticatorTypes() {
         try {
             return mService.getAuthenticatorTypes();
         } catch (RemoteException e) {
-            // if this happens the entire runtime will restart
+            // will never happen
             throw new RuntimeException(e);
         }
     }
 
-    public Future1<AuthenticatorDescription[]> getAuthenticatorTypes(
-            Future1Callback<AuthenticatorDescription[]> callback, Handler handler) {
-        return startAsFuture(callback, handler, new Callable<AuthenticatorDescription[]>() {
-            public AuthenticatorDescription[] call() throws Exception {
-                return blockingGetAuthenticatorTypes();
-            }
-        });
-    }
-
-    public Account[] blockingGetAccounts() {
-        ensureNotOnMainThread();
+    public Account[] getAccounts() {
         try {
-            return mService.getAccounts();
+            return mService.getAccounts(null);
         } catch (RemoteException e) {
-            // if this happens the entire runtime will restart
+            // won't ever happen
             throw new RuntimeException(e);
         }
     }
 
-    public Account[] blockingGetAccountsByType(String accountType) {
-        ensureNotOnMainThread();
+    public Account[] getAccountsByType(String type) {
         try {
-            return mService.getAccountsByType(accountType);
+            return mService.getAccounts(type);
         } catch (RemoteException e) {
-            // if this happens the entire runtime will restart
+            // won't ever happen
             throw new RuntimeException(e);
         }
     }
 
-    public Future1<Account[]> getAccounts(Future1Callback<Account[]> callback, Handler handler) {
-        return startAsFuture(callback, handler, new Callable<Account[]>() {
-            public Account[] call() throws Exception {
-                return blockingGetAccounts();
-            }
-        });
-    }
-
-    public Future1<Account[]> getAccountsByType(Future1Callback<Account[]> callback,
-            final String type, Handler handler) {
-        return startAsFuture(callback, handler, new Callable<Account[]>() {
-            public Account[] call() throws Exception {
-                return blockingGetAccountsByType(type);
-            }
-        });
-    }
-
-    public boolean blockingAddAccountExplicitly(Account account, String password, Bundle extras) {
-        ensureNotOnMainThread();
+    public boolean addAccountExplicitly(Account account, String password, Bundle extras) {
         try {
             return mService.addAccount(account, password, extras);
         } catch (RemoteException e) {
-            // if this happens the entire runtime will restart
+            // won't ever happen
             throw new RuntimeException(e);
         }
     }
 
-    public Future1<Boolean> addAccountExplicitly(final Future1Callback<Boolean> callback,
-            final Account account, final String password, final Bundle extras,
-            final Handler handler) {
-        return startAsFuture(callback, handler, new Callable<Boolean>() {
-            public Boolean call() throws Exception {
-                return blockingAddAccountExplicitly(account, password, extras);
+    public AccountManagerFuture<Boolean> removeAccount(final Account account,
+            AccountManagerCallback<Boolean> callback, Handler handler) {
+        return new Future2Task<Boolean>(handler, callback) {
+            public void doWork() throws RemoteException {
+                mService.removeAccount(mResponse, account);
             }
-        });
-    }
-
-    public void blockingRemoveAccount(Account account) {
-        ensureNotOnMainThread();
-        try {
-            mService.removeAccount(account);
-        } catch (RemoteException e) {
-            // if this happens the entire runtime will restart
-        }
-    }
-
-    public Future1<Void> removeAccount(Future1Callback<Void> callback, final Account account,
-            final Handler handler) {
-        return startAsFuture(callback, handler, new Callable<Void>() {
-            public Void call() throws Exception {
-                blockingRemoveAccount(account);
-                return null;
+            public Boolean bundleToResult(Bundle bundle) throws AuthenticatorException {
+                if (!bundle.containsKey(Constants.BOOLEAN_RESULT_KEY)) {
+                    throw new AuthenticatorException("no result in response");
+                }
+                return bundle.getBoolean(Constants.BOOLEAN_RESULT_KEY);
             }
-        });
+        }.start();
     }
 
-    public void blockingInvalidateAuthToken(String accountType, String authToken) {
-        ensureNotOnMainThread();
+    public void invalidateAuthToken(final String accountType, final String authToken) {
         try {
             mService.invalidateAuthToken(accountType, authToken);
         } catch (RemoteException e) {
-            // if this happens the entire runtime will restart
-        }
-    }
-
-    public Future1<Void> invalidateAuthToken(Future1Callback<Void> callback,
-            final String accountType, final String authToken, final Handler handler) {
-        return startAsFuture(callback, handler, new Callable<Void>() {
-            public Void call() throws Exception {
-                blockingInvalidateAuthToken(accountType, authToken);
-                return null;
-            }
-        });
-    }
-
-    public String blockingPeekAuthToken(Account account, String authTokenType) {
-        ensureNotOnMainThread();
-        try {
-            return mService.peekAuthToken(account, authTokenType);
-        } catch (RemoteException e) {
-            // if this happens the entire runtime will restart
+            // won't ever happen
             throw new RuntimeException(e);
         }
     }
 
-    public Future1<String> peekAuthToken(Future1Callback<String> callback,
-            final Account account, final String authTokenType, final Handler handler) {
-        return startAsFuture(callback, handler, new Callable<String>() {
-            public String call() throws Exception {
-                return blockingPeekAuthToken(account, authTokenType);
-            }
-        });
+    public String peekAuthToken(final Account account, final String authTokenType) {
+        try {
+            return mService.peekAuthToken(account, authTokenType);
+        } catch (RemoteException e) {
+            // won't ever happen
+            throw new RuntimeException(e);
+        }
     }
 
-    public void blockingSetPassword(Account account, String password) {
-        ensureNotOnMainThread();
+    public void setPassword(final Account account, final String password) {
         try {
             mService.setPassword(account, password);
         } catch (RemoteException e) {
-            // if this happens the entire runtime will restart
+            // won't ever happen
+            throw new RuntimeException(e);
         }
     }
 
-    public Future1<Void> setPassword(Future1Callback<Void> callback,
-            final Account account, final String password, final Handler handler) {
-        return startAsFuture(callback, handler, new Callable<Void>() {
-            public Void call() throws Exception {
-                blockingSetPassword(account, password);
-                return null;
-            }
-        });
-    }
-
-    public void blockingClearPassword(Account account) {
-        ensureNotOnMainThread();
+    public void clearPassword(final Account account) {
         try {
             mService.clearPassword(account);
         } catch (RemoteException e) {
-            // if this happens the entire runtime will restart
+            // won't ever happen
+            throw new RuntimeException(e);
         }
     }
 
-    public Future1<Void> clearPassword(final Future1Callback<Void> callback, final Account account,
-            final Handler handler) {
-        return startAsFuture(callback, handler, new Callable<Void>() {
-            public Void call() throws Exception {
-                blockingClearPassword(account);
-                return null;
-            }
-        });
-    }
-
-    public void blockingSetUserData(Account account, String key, String value) {
-        ensureNotOnMainThread();
+    public void setUserData(final Account account, final String key, final String value) {
         try {
             mService.setUserData(account, key, value);
         } catch (RemoteException e) {
-            // if this happens the entire runtime will restart
+            // won't ever happen
+            throw new RuntimeException(e);
         }
     }
 
-    public Future1<Void> setUserData(Future1Callback<Void> callback,
-            final Account account, final String key, final String value, final Handler handler) {
-        return startAsFuture(callback, handler, new Callable<Void>() {
-            public Void call() throws Exception {
-                blockingSetUserData(account, key, value);
-                return null;
-            }
-        });
-    }
-
-    public void blockingSetAuthToken(Account account, String authTokenType, String authToken) {
-        ensureNotOnMainThread();
+    public void setAuthToken(Account account, final String authTokenType, final String authToken) {
         try {
             mService.setAuthToken(account, authTokenType, authToken);
         } catch (RemoteException e) {
-            // if this happens the entire runtime will restart
+            // won't ever happen
+            throw new RuntimeException(e);
         }
     }
 
-    public Future1<Void> setAuthToken(Future1Callback<Void> callback,
-            final Account account, final String authTokenType, final String authToken,
-            final Handler handler) {
-        return startAsFuture(callback, handler, new Callable<Void>() {
-            public Void call() throws Exception {
-                blockingSetAuthToken(account, authTokenType, authToken);
-                return null;
-            }
-        });
-    }
-
     public String blockingGetAuthToken(Account account, String authTokenType,
             boolean notifyAuthFailure)
             throws OperationCanceledException, IOException, AuthenticatorException {
-        ensureNotOnMainThread();
         Bundle bundle = getAuthToken(account, authTokenType, notifyAuthFailure, null /* callback */,
                 null /* handler */).getResult();
         return bundle.getString(Constants.AUTHTOKEN_KEY);
@@ -349,9 +221,9 @@
      * @param loginOptions
      * @param activity the activity to launch the login intent, if necessary, and to which
      */
-    public Future2 getAuthToken(
+    public AccountManagerFuture<Bundle> getAuthToken(
             final Account account, final String authTokenType, final Bundle loginOptions,
-            final Activity activity, Future2Callback callback, Handler handler) {
+            final Activity activity, AccountManagerCallback<Bundle> callback, Handler handler) {
         if (activity == null) throw new IllegalArgumentException("activity is null");
         if (authTokenType == null) throw new IllegalArgumentException("authTokenType is null");
         return new AmsTask(activity, handler, callback) {
@@ -363,9 +235,9 @@
         }.start();
     }
 
-    public Future2 getAuthToken(
+    public AccountManagerFuture<Bundle> getAuthToken(
             final Account account, final String authTokenType, final boolean notifyAuthFailure,
-            Future2Callback callback, Handler handler) {
+            AccountManagerCallback<Bundle> callback, Handler handler) {
         if (account == null) throw new IllegalArgumentException("account is null");
         if (authTokenType == null) throw new IllegalArgumentException("authTokenType is null");
         return new AmsTask(null, handler, callback) {
@@ -376,10 +248,10 @@
         }.start();
     }
 
-    public Future2 addAccount(final String accountType,
+    public AccountManagerFuture<Bundle> addAccount(final String accountType,
             final String authTokenType, final String[] requiredFeatures,
             final Bundle addAccountOptions,
-            final Activity activity, Future2Callback callback, Handler handler) {
+            final Activity activity, AccountManagerCallback<Bundle> callback, Handler handler) {
         return new AmsTask(activity, handler, callback) {
             public void doWork() throws RemoteException {
                 mService.addAcount(mResponse, accountType, authTokenType,
@@ -389,44 +261,45 @@
     }
 
     /** @deprecated use {@link #confirmCredentials} instead */
-    public Future1<Boolean> confirmPassword(final Account account, final String password,
-            Future1Callback<Boolean> callback, Handler handler) {
-        return new AMSTaskBoolean(handler, callback) {
+    public AccountManagerFuture<Boolean> confirmPassword(final Account account, final String password,
+            AccountManagerCallback<Boolean> callback, Handler handler) {
+        return new Future2Task<Boolean>(handler, callback) {
             public void doWork() throws RemoteException {
-                mService.confirmPassword(response, account, password);
+                mService.confirmPassword(mResponse, account, password);
             }
-        };
-    }
-
-    public Account[] blockingGetAccountsWithTypeAndFeatures(String type, String[] features)
-            throws AuthenticatorException, IOException, OperationCanceledException {
-        Future2 future = getAccountsWithTypeAndFeatures(type, features,
-                null /* callback */, null /* handler */);
-        Bundle result = future.getResult();
-        Parcelable[] accountsTemp = result.getParcelableArray(Constants.ACCOUNTS_KEY);
-        if (accountsTemp == null) {
-            throw new AuthenticatorException("accounts should not be null");
-        }
-        Account[] accounts = new Account[accountsTemp.length];
-        for (int i = 0; i < accountsTemp.length; i++) {
-            accounts[i] = (Account) accountsTemp[i];
-        }
-        return accounts;
-    }
-
-    public Future2 getAccountsWithTypeAndFeatures(
-            final String type, final String[] features,
-            Future2Callback callback, Handler handler) {
-        if (type == null) throw new IllegalArgumentException("type is null");
-        return new AmsTask(null /* activity */, handler, callback) {
-            public void doWork() throws RemoteException {
-                mService.getAccountsByTypeAndFeatures(mResponse, type, features);
+            public Boolean bundleToResult(Bundle bundle) throws AuthenticatorException {
+                if (!bundle.containsKey(Constants.BOOLEAN_RESULT_KEY)) {
+                    throw new AuthenticatorException("no result in response");
+                }
+                return bundle.getBoolean(Constants.BOOLEAN_RESULT_KEY);
             }
         }.start();
     }
 
-    public Future2 confirmCredentials(final Account account, final Activity activity,
-            final Future2Callback callback,
+    public AccountManagerFuture<Account[]> getAccountsByTypeAndFeatures(
+            final String type, final String[] features,
+            AccountManagerCallback<Account[]> callback, Handler handler) {
+        if (type == null) throw new IllegalArgumentException("type is null");
+        return new Future2Task<Account[]>(handler, callback) {
+            public void doWork() throws RemoteException {
+                mService.getAccountsByFeatures(mResponse, type, features);
+            }
+            public Account[] bundleToResult(Bundle bundle) throws AuthenticatorException {
+                if (!bundle.containsKey(Constants.ACCOUNTS_KEY)) {
+                    throw new AuthenticatorException("no result in response");
+                }
+                final Parcelable[] parcelables = bundle.getParcelableArray(Constants.ACCOUNTS_KEY);
+                Account[] descs = new Account[parcelables.length];
+                for (int i = 0; i < parcelables.length; i++) {
+                    descs[i] = (Account) parcelables[i];
+                }
+                return descs;
+            }
+        }.start();
+    }
+
+    public AccountManagerFuture<Bundle> confirmCredentials(final Account account, final Activity activity,
+            final AccountManagerCallback<Bundle> callback,
             final Handler handler) {
         return new AmsTask(activity, handler, callback) {
             public void doWork() throws RemoteException {
@@ -435,9 +308,9 @@
         }.start();
     }
 
-    public Future2 updateCredentials(final Account account, final String authTokenType,
+    public AccountManagerFuture<Bundle> updateCredentials(final Account account, final String authTokenType,
             final Bundle loginOptions, final Activity activity,
-            final Future2Callback callback,
+            final AccountManagerCallback<Bundle> callback,
             final Handler handler) {
         return new AmsTask(activity, handler, callback) {
             public void doWork() throws RemoteException {
@@ -447,8 +320,8 @@
         }.start();
     }
 
-    public Future2 editProperties(final String accountType, final Activity activity,
-            final Future2Callback callback,
+    public AccountManagerFuture<Bundle> editProperties(final String accountType, final Activity activity,
+            final AccountManagerCallback<Bundle> callback,
             final Handler handler) {
         return new AmsTask(activity, handler, callback) {
             public void doWork() throws RemoteException {
@@ -471,8 +344,8 @@
         }
     }
 
-    private void postToHandler(Handler handler, final Future2Callback callback,
-            final Future2 future) {
+    private void postToHandler(Handler handler, final AccountManagerCallback<Bundle> callback,
+            final AccountManagerFuture<Bundle> future) {
         handler = handler == null ? mMainHandler : handler;
         handler.post(new Runnable() {
             public void run() {
@@ -483,87 +356,24 @@
 
     private void postToHandler(Handler handler, final OnAccountsUpdatedListener listener,
             final Account[] accounts) {
-        handler = handler == null ? mMainHandler : handler;
+        final Account[] accountsCopy = new Account[accounts.length];
+        // send a copy to make sure that one doesn't
+        // change what another sees
+        System.arraycopy(accounts, 0, accountsCopy, 0, accountsCopy.length);
+        handler = (handler == null) ? mMainHandler : handler;
         handler.post(new Runnable() {
             public void run() {
-                listener.onAccountsUpdated(accounts);
+                listener.onAccountsUpdated(accountsCopy);
             }
         });
     }
 
-    private <V> void postToHandler(Handler handler, final Future1Callback<V> callback,
-            final Future1<V> future) {
-        handler = handler == null ? mMainHandler : handler;
-        handler.post(new Runnable() {
-            public void run() {
-                callback.run(future);
-            }
-        });
-    }
-
-    private <V> Future1<V> startAsFuture(Future1Callback<V> callback, Handler handler,
-            Callable<V> callable) {
-        final FutureTaskWithCallback<V> task =
-                new FutureTaskWithCallback<V>(callback, callable, handler);
-        new Thread(task).start();
-        return task;
-    }
-
-    private class FutureTaskWithCallback<V> extends FutureTask<V> implements Future1<V> {
-        final Future1Callback<V> mCallback;
-        final Handler mHandler;
-
-        public FutureTaskWithCallback(Future1Callback<V> callback, Callable<V> callable,
-                Handler handler) {
-            super(callable);
-            mCallback = callback;
-            mHandler = handler;
-        }
-
-        protected void done() {
-            if (mCallback != null) {
-                postToHandler(mHandler, mCallback, this);
-            }
-        }
-
-        public V internalGetResult(Long timeout, TimeUnit unit) throws OperationCanceledException {
-            try {
-                if (timeout == null) {
-                    return get();
-                } else {
-                    return get(timeout, unit);
-                }
-            } catch (InterruptedException e) {
-                // we will cancel the task below
-            } catch (CancellationException e) {
-                // we will cancel the task below
-            } catch (TimeoutException e) {
-                // we will cancel the task below
-            } catch (ExecutionException e) {
-                // this should never happen
-                throw new IllegalStateException(e.getCause());
-            } finally {
-                cancel(true /* interruptIfRunning */);
-            }
-            throw new OperationCanceledException();
-        }
-
-        public V getResult() throws OperationCanceledException {
-            return internalGetResult(null, null);
-        }
-
-        public V getResult(long timeout, TimeUnit unit) throws OperationCanceledException {
-            return internalGetResult(null, null);
-        }
-    }
-
-    private abstract class AmsTask extends FutureTask<Bundle> implements Future2 {
+    private abstract class AmsTask extends FutureTask<Bundle> implements AccountManagerFuture<Bundle> {
         final IAccountManagerResponse mResponse;
         final Handler mHandler;
-        final Future2Callback mCallback;
+        final AccountManagerCallback<Bundle> mCallback;
         final Activity mActivity;
-        final Thread mThread;
-        public AmsTask(Activity activity, Handler handler, Future2Callback callback) {
+        public AmsTask(Activity activity, Handler handler, AccountManagerCallback<Bundle> callback) {
             super(new Callable<Bundle>() {
                 public Bundle call() throws Exception {
                     throw new IllegalStateException("this should never be called");
@@ -574,19 +384,14 @@
             mCallback = callback;
             mActivity = activity;
             mResponse = new Response();
-            mThread = new Thread(new Runnable() {
-                public void run() {
-                    try {
-                        doWork();
-                    } catch (RemoteException e) {
-                        // never happens
-                    }
-                }
-            }, "AmsTask");
         }
 
-        public final Future2 start() {
-            mThread.start();
+        public final AccountManagerFuture<Bundle> start() {
+            try {
+                doWork();
+            } catch (RemoteException e) {
+                setException(e);
+            }
             return this;
         }
 
@@ -594,6 +399,7 @@
 
         private Bundle internalGetResult(Long timeout, TimeUnit unit)
                 throws OperationCanceledException, IOException, AuthenticatorException {
+            ensureNotOnMainThread();
             try {
                 if (timeout == null) {
                     return get();
@@ -676,92 +482,50 @@
 
     }
 
-    private abstract class AMSTaskBoolean extends FutureTask<Boolean> implements Future1<Boolean> {
-        final IAccountManagerResponse response;
+    private abstract class BaseFutureTask<T> extends FutureTask<T> {
+        final public IAccountManagerResponse mResponse;
         final Handler mHandler;
-        final Future1Callback<Boolean> mCallback;
-        public AMSTaskBoolean(Handler handler, Future1Callback<Boolean> callback) {
-            super(new Callable<Boolean>() {
-                public Boolean call() throws Exception {
+
+        public BaseFutureTask(Handler handler) {
+            super(new Callable<T>() {
+                public T call() throws Exception {
                     throw new IllegalStateException("this should never be called");
                 }
             });
-
             mHandler = handler;
-            mCallback = callback;
-            response = new Response();
-
-            new Thread(new Runnable() {
-                public void run() {
-                    try {
-                        doWork();
-                    } catch (RemoteException e) {
-                        // never happens
-                    }
-                }
-            }).start();
+            mResponse = new Response();
         }
 
         public abstract void doWork() throws RemoteException;
 
+        public abstract T bundleToResult(Bundle bundle) throws AuthenticatorException;
 
-        protected void done() {
-            if (mCallback != null) {
-                postToHandler(mHandler, mCallback, this);
-            }
+        protected void postRunnableToHandler(Runnable runnable) {
+            Handler handler = (mHandler == null) ? mMainHandler : mHandler;
+            handler.post(runnable);
         }
 
-        private Boolean internalGetResult(Long timeout, TimeUnit unit) {
+        protected void startTask() {
             try {
-                if (timeout == null) {
-                    return get();
-                } else {
-                    return get(timeout, unit);
-                }
-            } catch (InterruptedException e) {
-                // fall through and cancel
-            } catch (TimeoutException e) {
-                // fall through and cancel
-            } catch (CancellationException e) {
-                return false;
-            } catch (ExecutionException e) {
-                final Throwable cause = e.getCause();
-                if (cause instanceof IOException) {
-                    return false;
-                } else if (cause instanceof UnsupportedOperationException) {
-                    return false;
-                } else if (cause instanceof AuthenticatorException) {
-                    return false;
-                } else if (cause instanceof RuntimeException) {
-                    throw (RuntimeException) cause;
-                } else if (cause instanceof Error) {
-                    throw (Error) cause;
-                } else {
-                    throw new IllegalStateException(cause);
-                }
-            } finally {
-                cancel(true /* interrupt if running */);
+                doWork();
+            } catch (RemoteException e) {
+                setException(e);
             }
-            return false;
         }
 
-        public Boolean getResult() throws OperationCanceledException {
-            return internalGetResult(null, null);
-        }
-
-        public Boolean getResult(long timeout, TimeUnit unit) throws OperationCanceledException {
-            return internalGetResult(timeout, unit);
-        }
-
-        private class Response extends IAccountManagerResponse.Stub {
+        protected class Response extends IAccountManagerResponse.Stub {
             public void onResult(Bundle bundle) {
                 try {
-                    if (bundle.containsKey(Constants.BOOLEAN_RESULT_KEY)) {
-                        set(bundle.getBoolean(Constants.BOOLEAN_RESULT_KEY));
+                    T result = bundleToResult(bundle);
+                    if (result == null) {
                         return;
                     }
+                    set(result);
+                    return;
                 } catch (ClassCastException e) {
                     // we will set the exception below
+                } catch (AuthenticatorException e) {
+                    // we will set the exception below
                 }
                 onError(Constants.ERROR_CODE_INVALID_RESPONSE, "no result in response");
             }
@@ -774,6 +538,76 @@
                 setException(convertErrorToException(code, message));
             }
         }
+    }
+
+    private abstract class Future2Task<T>
+            extends BaseFutureTask<T> implements AccountManagerFuture<T> {
+        final AccountManagerCallback<T> mCallback;
+        public Future2Task(Handler handler, AccountManagerCallback<T> callback) {
+            super(handler);
+            mCallback = callback;
+        }
+
+        protected void done() {
+            if (mCallback != null) {
+                postRunnableToHandler(new Runnable() {
+                    public void run() {
+                        mCallback.run(Future2Task.this);
+                    }
+                });
+            }
+        }
+
+        public Future2Task<T> start() {
+            startTask();
+            return this;
+        }
+
+        private T internalGetResult(Long timeout, TimeUnit unit)
+                throws OperationCanceledException, IOException, AuthenticatorException {
+            ensureNotOnMainThread();
+            try {
+                if (timeout == null) {
+                    return get();
+                } else {
+                    return get(timeout, unit);
+                }
+            } catch (InterruptedException e) {
+                // fall through and cancel
+            } catch (TimeoutException e) {
+                // fall through and cancel
+            } catch (CancellationException e) {
+                // fall through and cancel
+            } catch (ExecutionException e) {
+                final Throwable cause = e.getCause();
+                if (cause instanceof IOException) {
+                    throw (IOException) cause;
+                } else if (cause instanceof UnsupportedOperationException) {
+                    throw new AuthenticatorException(cause);
+                } else if (cause instanceof AuthenticatorException) {
+                    throw (AuthenticatorException) cause;
+                } else if (cause instanceof RuntimeException) {
+                    throw (RuntimeException) cause;
+                } else if (cause instanceof Error) {
+                    throw (Error) cause;
+                } else {
+                    throw new IllegalStateException(cause);
+                }
+            } finally {
+                cancel(true /* interrupt if running */);
+            }
+            throw new OperationCanceledException();
+        }
+
+        public T getResult()
+                throws OperationCanceledException, IOException, AuthenticatorException {
+            return internalGetResult(null, null);
+        }
+
+        public T getResult(long timeout, TimeUnit unit)
+                throws OperationCanceledException, IOException, AuthenticatorException {
+            return internalGetResult(timeout, unit);
+        }
 
     }
 
@@ -797,11 +631,12 @@
         return new AuthenticatorException(message);
     }
 
-    private class GetAuthTokenByTypeAndFeaturesTask extends AmsTask implements Future2Callback {
+    private class GetAuthTokenByTypeAndFeaturesTask
+            extends AmsTask implements AccountManagerCallback<Bundle> {
         GetAuthTokenByTypeAndFeaturesTask(final String accountType, final String authTokenType,
                 final String[] features, Activity activityForPrompting,
                 final Bundle addAccountOptions, final Bundle loginOptions,
-                Future2Callback callback, Handler handler) {
+                AccountManagerCallback<Bundle> callback, Handler handler) {
             super(activityForPrompting, handler, callback);
             if (accountType == null) throw new IllegalArgumentException("account type is null");
             mAccountType = accountType;
@@ -811,101 +646,100 @@
             mLoginOptions = loginOptions;
             mMyCallback = this;
         }
-        volatile Future2 mFuture = null;
+        volatile AccountManagerFuture<Bundle> mFuture = null;
         final String mAccountType;
         final String mAuthTokenType;
         final String[] mFeatures;
         final Bundle mAddAccountOptions;
         final Bundle mLoginOptions;
-        final Future2Callback mMyCallback;
+        final AccountManagerCallback<Bundle> mMyCallback;
 
         public void doWork() throws RemoteException {
-            getAccountsWithTypeAndFeatures(mAccountType, mFeatures, new Future2Callback() {
-                public void run(Future2 future) {
-                    Bundle getAccountsResult;
-                    try {
-                        getAccountsResult = future.getResult();
-                    } catch (OperationCanceledException e) {
-                        setException(e);
-                        return;
-                    } catch (IOException e) {
-                        setException(e);
-                        return;
-                    } catch (AuthenticatorException e) {
-                        setException(e);
-                        return;
-                    }
-
-                    Parcelable[] accounts =
-                            getAccountsResult.getParcelableArray(Constants.ACCOUNTS_KEY);
-                    if (accounts.length == 0) {
-                        if (mActivity != null) {
-                            // no accounts, add one now. pretend that the user directly
-                            // made this request
-                            mFuture = addAccount(mAccountType, mAuthTokenType, mFeatures,
-                                    mAddAccountOptions, mActivity, mMyCallback, mHandler);
-                        } else {
-                            // send result since we can't prompt to add an account
-                            Bundle result = new Bundle();
-                            result.putString(Constants.ACCOUNT_NAME_KEY, null);
-                            result.putString(Constants.ACCOUNT_TYPE_KEY, null);
-                            result.putString(Constants.AUTHTOKEN_KEY, null);
+            getAccountsByTypeAndFeatures(mAccountType, mFeatures,
+                    new AccountManagerCallback<Account[]>() {
+                        public void run(AccountManagerFuture<Account[]> future) {
+                            Account[] accounts;
                             try {
-                                mResponse.onResult(result);
-                            } catch (RemoteException e) {
-                                // this will never happen
+                                accounts = future.getResult();
+                            } catch (OperationCanceledException e) {
+                                setException(e);
+                                return;
+                            } catch (IOException e) {
+                                setException(e);
+                                return;
+                            } catch (AuthenticatorException e) {
+                                setException(e);
+                                return;
                             }
-                            // we are done
-                        }
-                    } else if (accounts.length == 1) {
-                        // have a single account, return an authtoken for it
-                        if (mActivity == null) {
-                            mFuture = getAuthToken((Account) accounts[0], mAuthTokenType,
-                                    false /* notifyAuthFailure */, mMyCallback, mHandler);
-                        } else {
-                            mFuture = getAuthToken((Account) accounts[0],
-                                    mAuthTokenType, mLoginOptions,
-                                    mActivity, mMyCallback, mHandler);
-                        }
-                    } else {
-                        if (mActivity != null) {
-                            IAccountManagerResponse chooseResponse =
-                                    new IAccountManagerResponse.Stub() {
-                                public void onResult(Bundle value) throws RemoteException {
-                                    Account account = new Account(
-                                            value.getString(Constants.ACCOUNT_NAME_KEY),
-                                            value.getString(Constants.ACCOUNT_TYPE_KEY));
-                                    mFuture = getAuthToken(account, mAuthTokenType, mLoginOptions,
+
+                            if (accounts.length == 0) {
+                                if (mActivity != null) {
+                                    // no accounts, add one now. pretend that the user directly
+                                    // made this request
+                                    mFuture = addAccount(mAccountType, mAuthTokenType, mFeatures,
+                                            mAddAccountOptions, mActivity, mMyCallback, mHandler);
+                                } else {
+                                    // send result since we can't prompt to add an account
+                                    Bundle result = new Bundle();
+                                    result.putString(Constants.ACCOUNT_NAME_KEY, null);
+                                    result.putString(Constants.ACCOUNT_TYPE_KEY, null);
+                                    result.putString(Constants.AUTHTOKEN_KEY, null);
+                                    try {
+                                        mResponse.onResult(result);
+                                    } catch (RemoteException e) {
+                                        // this will never happen
+                                    }
+                                    // we are done
+                                }
+                            } else if (accounts.length == 1) {
+                                // have a single account, return an authtoken for it
+                                if (mActivity == null) {
+                                    mFuture = getAuthToken(accounts[0], mAuthTokenType,
+                                            false /* notifyAuthFailure */, mMyCallback, mHandler);
+                                } else {
+                                    mFuture = getAuthToken(accounts[0],
+                                            mAuthTokenType, mLoginOptions,
                                             mActivity, mMyCallback, mHandler);
                                 }
+                            } else {
+                                if (mActivity != null) {
+                                    IAccountManagerResponse chooseResponse =
+                                            new IAccountManagerResponse.Stub() {
+                                        public void onResult(Bundle value) throws RemoteException {
+                                            Account account = new Account(
+                                                    value.getString(Constants.ACCOUNT_NAME_KEY),
+                                                    value.getString(Constants.ACCOUNT_TYPE_KEY));
+                                            mFuture = getAuthToken(account, mAuthTokenType, mLoginOptions,
+                                                    mActivity, mMyCallback, mHandler);
+                                        }
 
-                                public void onError(int errorCode, String errorMessage)
-                                        throws RemoteException {
-                                    mResponse.onError(errorCode, errorMessage);
+                                        public void onError(int errorCode, String errorMessage)
+                                                throws RemoteException {
+                                            mResponse.onError(errorCode, errorMessage);
+                                        }
+                                    };
+                                    // have many accounts, launch the chooser
+                                    Intent intent = new Intent();
+                                    intent.setClassName("android",
+                                            "android.accounts.ChooseAccountActivity");
+                                    intent.putExtra(Constants.ACCOUNTS_KEY, accounts);
+                                    intent.putExtra(Constants.ACCOUNT_MANAGER_RESPONSE_KEY,
+                                            new AccountManagerResponse(chooseResponse));
+                                    mActivity.startActivity(intent);
+                                    // the result will arrive via the IAccountManagerResponse
+                                } else {
+                                    // send result since we can't prompt to select an account
+                                    Bundle result = new Bundle();
+                                    result.putString(Constants.ACCOUNTS_KEY, null);
+                                    try {
+                                        mResponse.onResult(result);
+                                    } catch (RemoteException e) {
+                                        // this will never happen
+                                    }
+                                    // we are done
                                 }
-                            };
-                            // have many accounts, launch the chooser
-                            Intent intent = new Intent();
-                            intent.setClassName("android",
-                                    "android.accounts.ChooseAccountActivity");
-                            intent.putExtra(Constants.ACCOUNTS_KEY, accounts);
-                            intent.putExtra(Constants.ACCOUNT_MANAGER_RESPONSE_KEY,
-                                    new AccountManagerResponse(chooseResponse));
-                            mActivity.startActivity(intent);
-                            // the result will arrive via the IAccountManagerResponse
-                        } else {
-                            // send result since we can't prompt to select an account
-                            Bundle result = new Bundle();
-                            result.putString(Constants.ACCOUNTS_KEY, null);
-                            try {
-                                mResponse.onResult(result);
-                            } catch (RemoteException e) {
-                                // this will never happen
                             }
-                            // we are done
-                        }
-                    }
-                }}, mHandler);
+                        }}, mHandler);
         }
 
 
@@ -915,7 +749,7 @@
         // or to cause this to be canceled if mFuture isn't set.
         // Once this is done then getAuthTokenByFeatures can be changed to return a Future2.
 
-        public void run(Future2 future) {
+        public void run(AccountManagerFuture<Bundle> future) {
             try {
                 set(future.get());
             } catch (InterruptedException e) {
@@ -932,7 +766,7 @@
             final String accountType, final String authTokenType, final String[] features,
             final Activity activityForPrompting, final Bundle addAccountOptions,
             final Bundle loginOptions,
-            final Future2Callback callback, final Handler handler) {
+            final AccountManagerCallback<Bundle> callback, final Handler handler) {
         if (accountType == null) throw new IllegalArgumentException("account type is null");
         if (authTokenType == null) throw new IllegalArgumentException("authTokenType is null");
         new GetAuthTokenByTypeAndFeaturesTask(accountType, authTokenType,  features,
@@ -942,13 +776,6 @@
     private final HashMap<OnAccountsUpdatedListener, Handler> mAccountsUpdatedListeners =
             Maps.newHashMap();
 
-    // These variable are only used from the LOGIN_ACCOUNTS_CHANGED_ACTION BroadcastReceiver
-    // and its getAccounts() callback which are both invoked only on the main thread. As a
-    // result we don't need to protect against concurrent accesses and any changes are guaranteed
-    // to be visible when used. Basically, these two variables are thread-confined.
-    private Future1<Account[]> mAccountsLookupFuture = null;
-    private boolean mAccountLookupPending = false;
-
     /**
      * BroadcastReceiver that listens for the LOGIN_ACCOUNTS_CHANGED_ACTION intent
      * so that it can read the updated list of accounts and send them to the listener
@@ -956,58 +783,14 @@
      */
     private final BroadcastReceiver mAccountsChangedBroadcastReceiver = new BroadcastReceiver() {
         public void onReceive(final Context context, final Intent intent) {
-            if (mAccountsLookupFuture != null) {
-                // an accounts lookup is already in progress,
-                // don't bother starting another request
-                mAccountLookupPending = true;
-                return;
-            }
-            // initiate a read of the accounts
-            mAccountsLookupFuture = getAccounts(new Future1Callback<Account[]>() {
-                public void run(Future1<Account[]> future) {
-                    // clear the future so that future receives will try the lookup again
-                    mAccountsLookupFuture = null;
-
-                    // get the accounts array
-                    Account[] accounts;
-                    try {
-                        accounts = future.getResult();
-                    } catch (OperationCanceledException e) {
-                        // this should never happen, but if it does pretend we got another
-                        // accounts changed broadcast
-                        if (Config.LOGD) {
-                            Log.d(TAG, "the accounts lookup for listener notifications was "
-                                    + "canceled, try again by simulating the receipt of "
-                                    + "a LOGIN_ACCOUNTS_CHANGED_ACTION broadcast");
-                        }
-                        onReceive(context, intent);
-                        return;
-                    }
-
-                    // send the result to the listeners
-                    synchronized (mAccountsUpdatedListeners) {
-                        for (Map.Entry<OnAccountsUpdatedListener, Handler> entry :
-                                mAccountsUpdatedListeners.entrySet()) {
-                            Account[] accountsCopy = new Account[accounts.length];
-                            // send the listeners a copy to make sure that one doesn't
-                            // change what another sees
-                            System.arraycopy(accounts, 0, accountsCopy, 0, accountsCopy.length);
-                            postToHandler(entry.getValue(), entry.getKey(), accountsCopy);
-                        }
-                    }
-
-                    // If mAccountLookupPending was set when the account lookup finished it
-                    // means that we had previously ignored a LOGIN_ACCOUNTS_CHANGED_ACTION
-                    // intent because a lookup was already in progress. Now that we are done
-                    // with this lookup and notification pretend that another intent
-                    // was received by calling onReceive() directly.
-                    if (mAccountLookupPending) {
-                        mAccountLookupPending = false;
-                        onReceive(context, intent);
-                        return;
-                    }
+            final Account[] accounts = getAccounts();
+            // send the result to the listeners
+            synchronized (mAccountsUpdatedListeners) {
+                for (Map.Entry<OnAccountsUpdatedListener, Handler> entry :
+                        mAccountsUpdatedListeners.entrySet()) {
+                    postToHandler(entry.getValue(), entry.getKey(), accounts);
                 }
-            }, mMainHandler);
+            }
         }
     };
 
@@ -1045,15 +828,7 @@
         }
 
         if (updateImmediately) {
-            getAccounts(new Future1Callback<Account[]>() {
-                public void run(Future1<Account[]> future) {
-                    try {
-                        listener.onAccountsUpdated(future.getResult());
-                    } catch (OperationCanceledException e) {
-                        // ignore
-                    }
-                }
-            }, handler);
+            postToHandler(handler, listener, getAccounts());
         }
     }
 
diff --git a/core/java/android/accounts/Future2Callback.java b/core/java/android/accounts/AccountManagerCallback.java
similarity index 87%
rename from core/java/android/accounts/Future2Callback.java
rename to core/java/android/accounts/AccountManagerCallback.java
index 7ef0c94..4aa7169 100644
--- a/core/java/android/accounts/Future2Callback.java
+++ b/core/java/android/accounts/AccountManagerCallback.java
@@ -15,6 +15,6 @@
  */
 package android.accounts;
 
-public interface Future2Callback {
-    void run(Future2 future);
+public interface AccountManagerCallback<V> {
+    void run(AccountManagerFuture<V> future);
 }
\ No newline at end of file
diff --git a/core/java/android/accounts/AccountManagerFuture.java b/core/java/android/accounts/AccountManagerFuture.java
new file mode 100644
index 0000000..9939398
--- /dev/null
+++ b/core/java/android/accounts/AccountManagerFuture.java
@@ -0,0 +1,65 @@
+/*
+ * Copyright (C) 2009 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 android.accounts;
+
+import java.util.concurrent.Future;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.TimeoutException;
+import java.io.IOException;
+
+/**
+ * An extension of {@link java.util.concurrent.Future} that provides wrappers for {@link #get()}
+ * that handle the various
+ * exceptions that  {@link #get()} may return and rethrows them as exceptions specific to
+ * {@link android.accounts.AccountManager}.
+ */
+public interface AccountManagerFuture<V> extends Future<V> {
+    /**
+     * Wrapper for {@link java.util.concurrent.Future#get()}. If the get() throws
+     * {@link InterruptedException} then the
+     * {@link AccountManagerFuture} is canceled and
+     * {@link android.accounts.OperationCanceledException} is thrown.
+     * @return the {@link android.os.Bundle} that is returned by get()
+     * @throws android.accounts.OperationCanceledException if get() throws the unchecked
+     * CancellationException
+     * or if the Future was interrupted.
+     */
+    V getResult() throws OperationCanceledException, IOException, AuthenticatorException;
+
+    /**
+     * Wrapper for {@link java.util.concurrent.Future#get()}. If the get() throws
+     * {@link InterruptedException} then the
+     * {@link AccountManagerFuture} is canceled and
+     * {@link android.accounts.OperationCanceledException} is thrown.
+     * @param timeout the maximum time to wait
+     * @param unit the time unit of the timeout argument
+     * @return the {@link android.os.Bundle} that is returned by
+     * {@link java.util.concurrent.Future#get()}
+     * @throws android.accounts.OperationCanceledException if get() throws the unchecked
+     * {@link java.util.concurrent.CancellationException} or if the {@link AccountManagerFuture}
+     * was interrupted.
+     */
+    V getResult(long timeout, TimeUnit unit)
+            throws OperationCanceledException, IOException, AuthenticatorException;
+
+    @Deprecated
+    V get() throws InterruptedException, ExecutionException;
+
+    @Deprecated
+    V get(long timeout, TimeUnit unit)
+            throws InterruptedException, ExecutionException, TimeoutException;
+}
\ No newline at end of file
diff --git a/core/java/android/accounts/AccountManagerService.java b/core/java/android/accounts/AccountManagerService.java
index 0c941be..140c814 100644
--- a/core/java/android/accounts/AccountManagerService.java
+++ b/core/java/android/accounts/AccountManagerService.java
@@ -214,10 +214,48 @@
 
         long identityToken = clearCallingIdentity();
         try {
-            SQLiteDatabase db = mOpenHelper.getReadableDatabase();
-            Cursor cursor = db.query(TABLE_ACCOUNTS, new String[]{ACCOUNTS_PASSWORD},
-                    ACCOUNTS_NAME + "=? AND " + ACCOUNTS_TYPE+ "=?",
-                    new String[]{account.mName, account.mType}, null, null, null);
+            return readPasswordFromDatabase(account);
+        } finally {
+            restoreCallingIdentity(identityToken);
+        }
+    }
+
+    private String readPasswordFromDatabase(Account account) {
+        SQLiteDatabase db = mOpenHelper.getReadableDatabase();
+        Cursor cursor = db.query(TABLE_ACCOUNTS, new String[]{ACCOUNTS_PASSWORD},
+                ACCOUNTS_NAME + "=? AND " + ACCOUNTS_TYPE+ "=?",
+                new String[]{account.name, account.type}, null, null, null);
+        try {
+            if (cursor.moveToNext()) {
+                return cursor.getString(0);
+            }
+            return null;
+        } finally {
+            cursor.close();
+        }
+    }
+
+    public String getUserData(Account account, String key) {
+        checkAuthenticateAccountsPermission(account);
+        long identityToken = clearCallingIdentity();
+        try {
+            return readUserDataFromDatabase(account, key);
+        } finally {
+            restoreCallingIdentity(identityToken);
+        }
+    }
+
+    private String readUserDataFromDatabase(Account account, String key) {
+        SQLiteDatabase db = mOpenHelper.getReadableDatabase();
+        db.beginTransaction();
+        try {
+            long accountId = getAccountId(db, account);
+            if (accountId < 0) {
+                return null;
+            }
+            Cursor cursor = db.query(TABLE_EXTRAS, new String[]{EXTRAS_VALUE},
+                    EXTRAS_ACCOUNTS_ID + "=" + accountId + " AND " + EXTRAS_KEY + "=?",
+                    new String[]{key}, null, null, null);
             try {
                 if (cursor.moveToNext()) {
                     return cursor.getString(0);
@@ -227,37 +265,7 @@
                 cursor.close();
             }
         } finally {
-            restoreCallingIdentity(identityToken);
-        }
-    }
-
-    public String getUserData(Account account, String key) {
-        checkAuthenticateAccountsPermission(account);
-        long identityToken = clearCallingIdentity();
-        try {
-            SQLiteDatabase db = mOpenHelper.getReadableDatabase();
-            db.beginTransaction();
-            try {
-                long accountId = getAccountId(db, account);
-                if (accountId < 0) {
-                    return null;
-                }
-                Cursor cursor = db.query(TABLE_EXTRAS, new String[]{EXTRAS_VALUE},
-                        EXTRAS_ACCOUNTS_ID + "=" + accountId + " AND " + EXTRAS_KEY + "=?",
-                        new String[]{key}, null, null, null);
-                try {
-                    if (cursor.moveToNext()) {
-                        return cursor.getString(0);
-                    }
-                    return null;
-                } finally {
-                    cursor.close();
-                }
-            } finally {
-                db.endTransaction();
-            }
-        } finally {
-            restoreCallingIdentity(identityToken);
+            db.endTransaction();
         }
     }
 
@@ -280,39 +288,23 @@
         }
     }
 
-    public Account[] getAccounts() {
-        checkReadAccountsPermission();
-        long identityToken = clearCallingIdentity();
-        try {
-            return getAccountsByType(null);
-        } finally {
-            restoreCallingIdentity(identityToken);
-        }
-    }
-
     public Account[] getAccountsByType(String accountType) {
-        checkReadAccountsPermission();
-        long identityToken = clearCallingIdentity();
-        try {
-            SQLiteDatabase db = mOpenHelper.getReadableDatabase();
+        SQLiteDatabase db = mOpenHelper.getReadableDatabase();
 
-            final String selection = accountType == null ? null : (ACCOUNTS_TYPE + "=?");
-            final String[] selectionArgs = accountType == null ? null : new String[]{accountType};
-            Cursor cursor = db.query(TABLE_ACCOUNTS, ACCOUNT_NAME_TYPE_PROJECTION,
-                    selection, selectionArgs, null, null, null);
-            try {
-                int i = 0;
-                Account[] accounts = new Account[cursor.getCount()];
-                while (cursor.moveToNext()) {
-                    accounts[i] = new Account(cursor.getString(1), cursor.getString(2));
-                    i++;
-                }
-                return accounts;
-            } finally {
-                cursor.close();
+        final String selection = accountType == null ? null : (ACCOUNTS_TYPE + "=?");
+        final String[] selectionArgs = accountType == null ? null : new String[]{accountType};
+        Cursor cursor = db.query(TABLE_ACCOUNTS, ACCOUNT_NAME_TYPE_PROJECTION,
+                selection, selectionArgs, null, null, null);
+        try {
+            int i = 0;
+            Account[] accounts = new Account[cursor.getCount()];
+            while (cursor.moveToNext()) {
+                accounts[i] = new Account(cursor.getString(1), cursor.getString(2));
+                i++;
             }
+            return accounts;
         } finally {
-            restoreCallingIdentity(identityToken);
+            cursor.close();
         }
     }
 
@@ -322,43 +314,47 @@
         // fails if the account already exists
         long identityToken = clearCallingIdentity();
         try {
-            SQLiteDatabase db = mOpenHelper.getWritableDatabase();
-            db.beginTransaction();
-            try {
-                long numMatches = DatabaseUtils.longForQuery(db,
-                        "select count(*) from " + TABLE_ACCOUNTS
-                                + " WHERE " + ACCOUNTS_NAME + "=? AND " + ACCOUNTS_TYPE+ "=?",
-                        new String[]{account.mName, account.mType});
-                if (numMatches > 0) {
-                    return false;
-                }
-                ContentValues values = new ContentValues();
-                values.put(ACCOUNTS_NAME, account.mName);
-                values.put(ACCOUNTS_TYPE, account.mType);
-                values.put(ACCOUNTS_PASSWORD, password);
-                long accountId = db.insert(TABLE_ACCOUNTS, ACCOUNTS_NAME, values);
-                if (accountId < 0) {
-                    return false;
-                }
-                if (extras != null) {
-                    for (String key : extras.keySet()) {
-                        final String value = extras.getString(key);
-                        if (insertExtra(db, accountId, key, value) < 0) {
-                            return false;
-                        }
-                    }
-                }
-                db.setTransactionSuccessful();
-                sendAccountsChangedBroadcast();
-                return true;
-            } finally {
-                db.endTransaction();
-            }
+            return insertAccountIntoDatabase(account, password, extras);
         } finally {
             restoreCallingIdentity(identityToken);
         }
     }
 
+    private boolean insertAccountIntoDatabase(Account account, String password, Bundle extras) {
+        SQLiteDatabase db = mOpenHelper.getWritableDatabase();
+        db.beginTransaction();
+        try {
+            long numMatches = DatabaseUtils.longForQuery(db,
+                    "select count(*) from " + TABLE_ACCOUNTS
+                            + " WHERE " + ACCOUNTS_NAME + "=? AND " + ACCOUNTS_TYPE+ "=?",
+                    new String[]{account.name, account.type});
+            if (numMatches > 0) {
+                return false;
+            }
+            ContentValues values = new ContentValues();
+            values.put(ACCOUNTS_NAME, account.name);
+            values.put(ACCOUNTS_TYPE, account.type);
+            values.put(ACCOUNTS_PASSWORD, password);
+            long accountId = db.insert(TABLE_ACCOUNTS, ACCOUNTS_NAME, values);
+            if (accountId < 0) {
+                return false;
+            }
+            if (extras != null) {
+                for (String key : extras.keySet()) {
+                    final String value = extras.getString(key);
+                    if (insertExtra(db, accountId, key, value) < 0) {
+                        return false;
+                    }
+                }
+            }
+            db.setTransactionSuccessful();
+            sendAccountsChangedBroadcast();
+            return true;
+        } finally {
+            db.endTransaction();
+        }
+    }
+
     private long insertExtra(SQLiteDatabase db, long accountId, String key, String value) {
         ContentValues values = new ContentValues();
         values.put(EXTRAS_KEY, key);
@@ -367,19 +363,61 @@
         return db.insert(TABLE_EXTRAS, EXTRAS_KEY, values);
     }
 
-    public void removeAccount(Account account) {
+    public void removeAccount(IAccountManagerResponse response, Account account) {
         checkManageAccountsPermission();
         long identityToken = clearCallingIdentity();
         try {
-            final SQLiteDatabase db = mOpenHelper.getWritableDatabase();
-            db.delete(TABLE_ACCOUNTS, ACCOUNTS_NAME + "=? AND " + ACCOUNTS_TYPE+ "=?",
-                    new String[]{account.mName, account.mType});
-            sendAccountsChangedBroadcast();
+            new RemoveAccountSession(response, account).bind();
         } finally {
             restoreCallingIdentity(identityToken);
         }
     }
 
+    private class RemoveAccountSession extends Session {
+        final Account mAccount;
+        public RemoveAccountSession(IAccountManagerResponse response, Account account) {
+            super(response, account.type, false /* expectActivityLaunch */);
+            mAccount = account;
+        }
+
+        protected String toDebugString(long now) {
+            return super.toDebugString(now) + ", removeAccount"
+                    + ", account " + mAccount;
+        }
+
+        public void run() throws RemoteException {
+            mAuthenticator.getAccountRemovalAllowed(this, mAccount);
+        }
+
+        public void onResult(Bundle result) {
+            if (result != null && result.containsKey(Constants.BOOLEAN_RESULT_KEY)
+                    && !result.containsKey(Constants.INTENT_KEY)) {
+                final boolean removalAllowed = result.getBoolean(Constants.BOOLEAN_RESULT_KEY);
+                if (removalAllowed) {
+                    removeAccount(mAccount);
+                }
+                IAccountManagerResponse response = getResponseAndClose();
+                if (response != null) {
+                    Bundle result2 = new Bundle();
+                    result2.putBoolean(Constants.BOOLEAN_RESULT_KEY, removalAllowed);
+                    try {
+                        response.onResult(result2);
+                    } catch (RemoteException e) {
+                        // ignore
+                    }
+                }
+            }
+            super.onResult(result);
+        }
+    }
+
+    private void removeAccount(Account account) {
+        final SQLiteDatabase db = mOpenHelper.getWritableDatabase();
+        db.delete(TABLE_ACCOUNTS, ACCOUNTS_NAME + "=? AND " + ACCOUNTS_TYPE+ "=?",
+                new String[]{account.name, account.type});
+        sendAccountsChangedBroadcast();
+    }
+
     public void invalidateAuthToken(String accountType, String authToken) {
         checkManageAccountsPermission();
         long identityToken = clearCallingIdentity();
@@ -398,6 +436,9 @@
     }
 
     private void invalidateAuthToken(SQLiteDatabase db, String accountType, String authToken) {
+        if (authToken == null || accountType == null) {
+            return;
+        }
         Cursor cursor = db.rawQuery(
                 "SELECT " + TABLE_AUTHTOKENS + "." + AUTHTOKENS_ID
                         + ", " + TABLE_ACCOUNTS + "." + ACCOUNTS_NAME
@@ -488,7 +529,7 @@
             values.put(ACCOUNTS_PASSWORD, password);
             mOpenHelper.getWritableDatabase().update(TABLE_ACCOUNTS, values,
                     ACCOUNTS_NAME + "=? AND " + ACCOUNTS_TYPE+ "=?",
-                    new String[]{account.mName, account.mType});
+                    new String[]{account.name, account.type});
             sendAccountsChangedBroadcast();
         } finally {
             restoreCallingIdentity(identityToken);
@@ -509,40 +550,58 @@
         }
     }
 
+    private void sendResult(IAccountManagerResponse response, Bundle bundle) {
+        if (response != null) {
+            try {
+                response.onResult(bundle);
+            } catch (RemoteException e) {
+                // if the caller is dead then there is no one to care about remote
+                // exceptions
+                if (Log.isLoggable(TAG, Log.VERBOSE)) {
+                    Log.v(TAG, "failure while notifying response", e);
+                }
+            }
+        }
+    }
+
     public void setUserData(Account account, String key, String value) {
         checkAuthenticateAccountsPermission(account);
         long identityToken = clearCallingIdentity();
         try {
-            SQLiteDatabase db = mOpenHelper.getWritableDatabase();
-            db.beginTransaction();
-            try {
-                long accountId = getAccountId(db, account);
-                if (accountId < 0) {
-                    return;
-                }
-                long extrasId = getExtrasId(db, accountId, key);
-                if (extrasId < 0 ) {
-                    extrasId = insertExtra(db, accountId, key, value);
-                    if (extrasId < 0) {
-                        return;
-                    }
-                } else {
-                    ContentValues values = new ContentValues();
-                    values.put(EXTRAS_VALUE, value);
-                    if (1 != db.update(TABLE_EXTRAS, values, EXTRAS_ID + "=" + extrasId, null)) {
-                        return;
-                    }
-
-                }
-                db.setTransactionSuccessful();
-            } finally {
-                db.endTransaction();
-            }
+            writeUserdataIntoDatabase(account, key, value);
         } finally {
             restoreCallingIdentity(identityToken);
         }
     }
 
+    private void writeUserdataIntoDatabase(Account account, String key, String value) {
+        SQLiteDatabase db = mOpenHelper.getWritableDatabase();
+        db.beginTransaction();
+        try {
+            long accountId = getAccountId(db, account);
+            if (accountId < 0) {
+                return;
+            }
+            long extrasId = getExtrasId(db, accountId, key);
+            if (extrasId < 0 ) {
+                extrasId = insertExtra(db, accountId, key, value);
+                if (extrasId < 0) {
+                    return;
+                }
+            } else {
+                ContentValues values = new ContentValues();
+                values.put(EXTRAS_VALUE, value);
+                if (1 != db.update(TABLE_EXTRAS, values, EXTRAS_ID + "=" + extrasId, null)) {
+                    return;
+                }
+
+            }
+            db.setTransactionSuccessful();
+        } finally {
+            db.endTransaction();
+        }
+    }
+
     private void onResult(IAccountManagerResponse response, Bundle result) {
         try {
             response.onResult(result);
@@ -571,14 +630,14 @@
                 if (authToken != null) {
                     Bundle result = new Bundle();
                     result.putString(Constants.AUTHTOKEN_KEY, authToken);
-                    result.putString(Constants.ACCOUNT_NAME_KEY, account.mName);
-                    result.putString(Constants.ACCOUNT_TYPE_KEY, account.mType);
+                    result.putString(Constants.ACCOUNT_NAME_KEY, account.name);
+                    result.putString(Constants.ACCOUNT_TYPE_KEY, account.type);
                     onResult(response, result);
                     return;
                 }
             }
 
-            new Session(response, account.mType, expectActivityLaunch) {
+            new Session(response, account.type, expectActivityLaunch) {
                 protected String toDebugString(long now) {
                     if (loginOptions != null) loginOptions.keySet();
                     return super.toDebugString(now) + ", getAuthToken"
@@ -651,7 +710,7 @@
                 mContext.getText(R.string.permission_request_notification_subtitle);
         n.setLatestEventInfo(mContext,
                 mContext.getText(R.string.permission_request_notification_title),
-                String.format(subtitleFormatString.toString(), account.mName),
+                String.format(subtitleFormatString.toString(), account.name),
                 PendingIntent.getActivity(mContext, 0, intent, PendingIntent.FLAG_CANCEL_CURRENT));
         ((NotificationManager) mContext.getSystemService(Context.NOTIFICATION_SERVICE))
                 .notify(getCredentialPermissionNotificationId(account, authTokenType, uid), n);
@@ -661,9 +720,9 @@
             AccountAuthenticatorResponse response, String authTokenType, String authTokenLabel) {
         RegisteredServicesCache.ServiceInfo<AuthenticatorDescription> serviceInfo =
                 mAuthenticatorCache.getServiceInfo(
-                        AuthenticatorDescription.newKey(account.mType));
+                        AuthenticatorDescription.newKey(account.type));
         if (serviceInfo == null) {
-            throw new IllegalArgumentException("unknown account type: " + account.mType);
+            throw new IllegalArgumentException("unknown account type: " + account.type);
         }
 
         final Context authContext;
@@ -671,7 +730,7 @@
             authContext = mContext.createPackageContext(
                 serviceInfo.type.packageName, 0);
         } catch (PackageManager.NameNotFoundException e) {
-            throw new IllegalArgumentException("unknown account type: " + account.mType);
+            throw new IllegalArgumentException("unknown account type: " + account.type);
         }
 
         Intent intent = new Intent(mContext, GrantCredentialsPermissionActivity.class);
@@ -750,7 +809,7 @@
         checkManageAccountsPermission();
         long identityToken = clearCallingIdentity();
         try {
-            new Session(response, account.mType, expectActivityLaunch) {
+            new Session(response, account.type, expectActivityLaunch) {
                 public void run() throws RemoteException {
                     mAuthenticator.confirmCredentials(this, account);
                 }
@@ -769,7 +828,7 @@
         checkManageAccountsPermission();
         long identityToken = clearCallingIdentity();
         try {
-            new Session(response, account.mType, false /* expectActivityLaunch */) {
+            new Session(response, account.type, false /* expectActivityLaunch */) {
                 public void run() throws RemoteException {
                     mAuthenticator.confirmPassword(this, account, password);
                 }
@@ -789,7 +848,7 @@
         checkManageAccountsPermission();
         long identityToken = clearCallingIdentity();
         try {
-            new Session(response, account.mType, expectActivityLaunch) {
+            new Session(response, account.type, expectActivityLaunch) {
                 public void run() throws RemoteException {
                     mAuthenticator.updateCredentials(this, account, authTokenType, loginOptions);
                 }
@@ -898,10 +957,21 @@
                     + ", " + (mFeatures != null ? TextUtils.join(",", mFeatures) : null);
         }
     }
-    public void getAccountsByTypeAndFeatures(IAccountManagerResponse response,
+
+    public Account[] getAccounts(String type) {
+        checkReadAccountsPermission();
+        long identityToken = clearCallingIdentity();
+        try {
+            return getAccountsByType(type);
+        } finally {
+            restoreCallingIdentity(identityToken);
+        }
+    }
+
+    public void getAccountsByFeatures(IAccountManagerResponse response,
             String type, String[] features) {
         checkReadAccountsPermission();
-        if (type == null) {
+        if (features != null && type == null) {
             if (response != null) {
                 try {
                     response.onError(Constants.ERROR_CODE_BAD_ARGUMENTS, "type is null");
@@ -913,6 +983,10 @@
         }
         long identityToken = clearCallingIdentity();
         try {
+            if (features == null || features.length == 0) {
+                getAccountsByType(type);
+                return;
+            }
             new GetAccountsByTypeAndFeatureSession(response, type, features).bind();
         } finally {
             restoreCallingIdentity(identityToken);
@@ -925,7 +999,7 @@
 
     private long getAccountId(SQLiteDatabase db, Account account) {
         Cursor cursor = db.query(TABLE_ACCOUNTS, new String[]{ACCOUNTS_ID},
-                "name=? AND type=?", new String[]{account.mName, account.mType}, null, null, null);
+                "name=? AND type=?", new String[]{account.name, account.type}, null, null, null);
         try {
             if (cursor.moveToNext()) {
                 return cursor.getLong(0);
@@ -1401,7 +1475,7 @@
     }
 
     private boolean permissionIsGranted(Account account, String authTokenType, int callerUid) {
-        final boolean fromAuthenticator = hasAuthenticatorUid(account.mType, callerUid);
+        final boolean fromAuthenticator = hasAuthenticatorUid(account.type, callerUid);
         final boolean hasExplicitGrants = hasExplicitlyGrantedPermission(account, authTokenType);
         if (Log.isLoggable(TAG, Log.VERBOSE)) {
             Log.v(TAG, "checkGrantsOrCallingUidAgainstAuthenticator: caller uid "
@@ -1416,7 +1490,9 @@
         for (RegisteredServicesCache.ServiceInfo<AuthenticatorDescription> serviceInfo :
                 mAuthenticatorCache.getAllServices()) {
             if (serviceInfo.type.type.equals(accountType)) {
-                return serviceInfo.uid == callingUid;
+                return (serviceInfo.uid == callingUid) ||
+                        (mContext.getPackageManager().checkSignatures(serviceInfo.uid, callingUid)
+                                == PackageManager.SIGNATURE_MATCH);
             }
         }
         return false;
@@ -1428,7 +1504,7 @@
         }
         SQLiteDatabase db = mOpenHelper.getReadableDatabase();
         String[] args = {String.valueOf(Binder.getCallingUid()), authTokenType,
-                account.mName, account.mType};
+                account.name, account.type};
         final boolean permissionGranted =
                 DatabaseUtils.longForQuery(db, COUNT_OF_MATCHING_GRANTS, args) != 0;
         if (!permissionGranted && isDebuggableMonkeyBuild) {
@@ -1444,7 +1520,7 @@
 
     private void checkCallingUidAgainstAuthenticator(Account account) {
         final int uid = Binder.getCallingUid();
-        if (!hasAuthenticatorUid(account.mType, uid)) {
+        if (!hasAuthenticatorUid(account.type, uid)) {
             String msg = "caller uid " + uid + " is different than the authenticator's uid";
             Log.w(TAG, msg);
             throw new SecurityException(msg);
diff --git a/core/java/android/accounts/ChooseAccountActivity.java b/core/java/android/accounts/ChooseAccountActivity.java
index 83377f3..bd6f205 100644
--- a/core/java/android/accounts/ChooseAccountActivity.java
+++ b/core/java/android/accounts/ChooseAccountActivity.java
@@ -45,7 +45,7 @@
 
         String[] mAccountNames = new String[mAccounts.length];
         for (int i = 0; i < mAccounts.length; i++) {
-            mAccountNames[i] = ((Account) mAccounts[i]).mName;
+            mAccountNames[i] = ((Account) mAccounts[i]).name;
         }
 
         // Use an existing ListAdapter that will map an array
@@ -59,8 +59,8 @@
         Account account = (Account) mAccounts[position];
         Log.d(TAG, "selected account " + account);
         Bundle bundle = new Bundle();
-        bundle.putString(Constants.ACCOUNT_NAME_KEY, account.mName);
-        bundle.putString(Constants.ACCOUNT_TYPE_KEY, account.mType);
+        bundle.putString(Constants.ACCOUNT_NAME_KEY, account.name);
+        bundle.putString(Constants.ACCOUNT_TYPE_KEY, account.type);
         mResult = bundle;
         finish();
     }
diff --git a/core/java/android/accounts/Constants.java b/core/java/android/accounts/Constants.java
index da8173f..8736f41 100644
--- a/core/java/android/accounts/Constants.java
+++ b/core/java/android/accounts/Constants.java
@@ -31,6 +31,7 @@
     public static final String AUTHENTICATOR_TYPES_KEY = "authenticator_types";
     public static final String USERDATA_KEY = "userdata";
     public static final String AUTHTOKEN_KEY = "authtoken";
+    public static final String PASSWORD_KEY = "password";
     public static final String ACCOUNT_NAME_KEY = "authAccount";
     public static final String ACCOUNT_TYPE_KEY = "accountType";
     public static final String ERROR_CODE_KEY = "errorCode";
diff --git a/core/java/android/accounts/Future1.java b/core/java/android/accounts/Future1.java
deleted file mode 100644
index 386cb6e..0000000
--- a/core/java/android/accounts/Future1.java
+++ /dev/null
@@ -1,46 +0,0 @@
-/*
- * Copyright (C) 2009 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 android.accounts;
-
-import java.util.concurrent.Future;
-import java.util.concurrent.TimeUnit;
-
-/**
- * An extension of {@link Future} that provides wrappers for {@link #get()} that handle the various
- * exceptions that  {@link #get()} may return and rethrows them as exceptions specific to
- * {@link AccountManager}.
- */
-public interface Future1<V> extends Future<V> {
-    /**
-     * Wrapper for {@link Future#get()}. If the get() throws {@link InterruptedException} then the
-     * {@link Future1} is canceled and {@link OperationCanceledException} is thrown.
-     * @return the {@link android.os.Bundle} that is returned by get()
-     * @throws OperationCanceledException if get() throws the unchecked CancellationException
-     * or if the Future was interrupted.
-     */
-    V getResult() throws OperationCanceledException;
-
-    /**
-     * Wrapper for {@link Future#get()}. If the get() throws {@link InterruptedException} then the
-     * {@link Future1} is canceled and {@link OperationCanceledException} is thrown.
-     * @param timeout the maximum time to wait
-     * @param unit the time unit of the timeout argument
-     * @return the {@link android.os.Bundle} that is returned by {@link Future#get()}
-     * @throws OperationCanceledException if get() throws the unchecked
-     * {@link java.util.concurrent.CancellationException} or if the {@link Future1} was interrupted.
-     */
-    V getResult(long timeout, TimeUnit unit) throws OperationCanceledException;
-}
\ No newline at end of file
diff --git a/core/java/android/accounts/Future1Callback.java b/core/java/android/accounts/Future1Callback.java
deleted file mode 100644
index 886671b..0000000
--- a/core/java/android/accounts/Future1Callback.java
+++ /dev/null
@@ -1,20 +0,0 @@
-/*
- * Copyright (C) 2009 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 android.accounts;
-
-public interface Future1Callback<V> {
-    void run(Future1<V> future);
-}
diff --git a/core/java/android/accounts/Future2.java b/core/java/android/accounts/Future2.java
deleted file mode 100644
index b2ea84f..0000000
--- a/core/java/android/accounts/Future2.java
+++ /dev/null
@@ -1,57 +0,0 @@
-/*
- * Copyright (C) 2009 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 android.accounts;
-
-import android.os.Bundle;
-
-import java.io.IOException;
-import java.util.concurrent.Future;
-import java.util.concurrent.TimeUnit;
-
-/**
- * An extension of {@link Future} that provides wrappers for {@link #get()} that handle the various
- * exceptions that  {@link #get()} may return and rethrows them as exceptions specific to
- * {@link AccountManager}.
- */
-public interface Future2 extends Future<Bundle> {
-    /**
-     * Wrapper for {@link Future#get()}. If the get() throws {@link InterruptedException} then the
-     * {@link Future2} is canceled and {@link OperationCanceledException} is thrown.
-     * @return the {@link android.os.Bundle} that is returned by {@link Future#get()}
-     * @throws OperationCanceledException if get() throws the unchecked
-     * {@link java.util.concurrent.CancellationException} or if the {@link Future2} was interrupted.
-     * @throws IOException if the request was unable to complete due to a network error
-     * @throws AuthenticatorException if there was an error communicating with the
-     * {@link AbstractAccountAuthenticator}.
-     */
-    Bundle getResult()
-            throws OperationCanceledException, IOException, AuthenticatorException;
-
-    /**
-     * Wrapper for {@link Future#get()}. If the get() throws {@link InterruptedException} then the
-     * {@link Future2} is canceled and {@link OperationCanceledException} is thrown.
-     * @param timeout the maximum time to wait
-     * @param unit the time unit of the timeout argument
-     * @return the {@link android.os.Bundle} that is returned by {@link Future#get()}
-     * @throws OperationCanceledException if get() throws the unchecked
-     * {@link java.util.concurrent.CancellationException} or if the {@link Future2} was interrupted.
-     * @throws IOException if the request was unable to complete due to a network error
-     * @throws AuthenticatorException if there was an error communicating with the
-     * {@link AbstractAccountAuthenticator}.
-     */
-    Bundle getResult(long timeout, TimeUnit unit)
-            throws OperationCanceledException, IOException, AuthenticatorException;
-}
diff --git a/core/java/android/accounts/GrantCredentialsPermissionActivity.java b/core/java/android/accounts/GrantCredentialsPermissionActivity.java
index f92d43f..e06afb4 100644
--- a/core/java/android/accounts/GrantCredentialsPermissionActivity.java
+++ b/core/java/android/accounts/GrantCredentialsPermissionActivity.java
@@ -63,12 +63,12 @@
             CharSequence grantCredentialsPermissionFormat = getResources().getText(
                     R.string.grant_credentials_permission_message_desc);
             messageView.setText(String.format(grantCredentialsPermissionFormat.toString(),
-                    mAccount.mName, accountTypeLabel));
+                    mAccount.name, accountTypeLabel));
         } else {
             CharSequence grantCredentialsPermissionFormat = getResources().getText(
                     R.string.grant_credentials_permission_message_with_authtokenlabel_desc);
             messageView.setText(String.format(grantCredentialsPermissionFormat.toString(),
-                    authTokenLabel, mAccount.mName, accountTypeLabel));
+                    authTokenLabel, mAccount.name, accountTypeLabel));
         }
 
         String[] packageLabels = new String[packages.length];
diff --git a/core/java/android/accounts/IAccountAuthenticator.aidl b/core/java/android/accounts/IAccountAuthenticator.aidl
index 7d4de39..48f053c 100644
--- a/core/java/android/accounts/IAccountAuthenticator.aidl
+++ b/core/java/android/accounts/IAccountAuthenticator.aidl
@@ -70,4 +70,9 @@
      */
     void hasFeatures(in IAccountAuthenticatorResponse response, in Account account, 
         in String[] features);
+
+    /**
+     * Gets whether or not the account is allowed to be removed.
+     */
+    void getAccountRemovalAllowed(in IAccountAuthenticatorResponse response, in Account account);
 }
diff --git a/core/java/android/accounts/IAccountManager.aidl b/core/java/android/accounts/IAccountManager.aidl
index 15ab4e8..411952b 100644
--- a/core/java/android/accounts/IAccountManager.aidl
+++ b/core/java/android/accounts/IAccountManager.aidl
@@ -21,6 +21,7 @@
 import android.accounts.AuthenticatorDescription;
 import android.os.Bundle;
 
+
 /**
  * Central application service that provides account management.
  * @hide
@@ -29,10 +30,10 @@
     String getPassword(in Account account);
     String getUserData(in Account account, String key);
     AuthenticatorDescription[] getAuthenticatorTypes();
-    Account[] getAccounts();
-    Account[] getAccountsByType(String accountType);
+    Account[] getAccounts(String accountType);
+    void getAccountsByFeatures(in IAccountManagerResponse response, String accountType, in String[] features);
     boolean addAccount(in Account account, String password, in Bundle extras);
-    void removeAccount(in Account account);
+    void removeAccount(in IAccountManagerResponse response, in Account account);
     void invalidateAuthToken(String accountType, String authToken);
     String peekAuthToken(in Account account, String authTokenType);
     void setAuthToken(in Account account, String authTokenType, String authToken);
@@ -52,8 +53,6 @@
         boolean expectActivityLaunch);
     void confirmCredentials(in IAccountManagerResponse response, in Account account,
         boolean expectActivityLaunch);
-    void getAccountsByTypeAndFeatures(in IAccountManagerResponse response, String accountType,
-        in String[] features);
 
     /*
      * @deprecated
diff --git a/core/java/android/content/AbstractSyncableContentProvider.java b/core/java/android/content/AbstractSyncableContentProvider.java
index 218f501..808f30c 100644
--- a/core/java/android/content/AbstractSyncableContentProvider.java
+++ b/core/java/android/content/AbstractSyncableContentProvider.java
@@ -170,7 +170,7 @@
                         // AbstractGDataSyncAdapter, which will put acore into a crash loop
                         ArrayList<Account> gaiaAccounts = new ArrayList<Account>();
                         for (Account acct: accounts) {
-                            if (acct.mType.equals("com.google.GAIA")) {
+                            if (acct.type.equals("com.google.GAIA")) {
                                 gaiaAccounts.add(acct);
                             }
                         }
@@ -693,7 +693,7 @@
                 if (!accounts.containsKey(account)) {
                     int numDeleted;
                     numDeleted = db.delete(table, "_sync_account=? AND _sync_account_type=?",
-                            new String[]{account.mName, account.mType});
+                            new String[]{account.name, account.type});
                     if (Config.LOGV) {
                         Log.v(TAG, "deleted " + numDeleted
                                 + " records from table " + table
@@ -726,7 +726,7 @@
             // remove the data in the synced tables
             for (String table : tables) {
                 db.delete(table, SYNC_ACCOUNT_WHERE_CLAUSE,
-                        new String[]{account.mName, account.mType});
+                        new String[]{account.name, account.type});
             }
             db.setTransactionSuccessful();
         } finally {
diff --git a/core/java/android/content/AbstractTableMerger.java b/core/java/android/content/AbstractTableMerger.java
index a3daa01..9545fd7f 100644
--- a/core/java/android/content/AbstractTableMerger.java
+++ b/core/java/android/content/AbstractTableMerger.java
@@ -174,7 +174,7 @@
         Cursor diffsCursor = null;
         try {
             // load the local database entries, so we can merge them with the server
-            final String[] accountSelectionArgs = new String[]{account.mName, account.mType};
+            final String[] accountSelectionArgs = new String[]{account.name, account.type};
             localCursor = mDb.query(mTable, syncDirtyProjection,
                     SELECT_MARKED, accountSelectionArgs, null, null,
                     mTable + "." + _SYNC_ID);
@@ -487,7 +487,7 @@
         try {
             if (deleteBySyncId) {
                 selectionArgs = new String[]{diffsCursor.getString(serverSyncIdColumn),
-                        account.mName, account.mType};
+                        account.name, account.type};
                 c = mDb.query(mTable, new String[]{BaseColumns._ID}, SELECT_BY_SYNC_ID_AND_ACCOUNT,
                         selectionArgs, null, null, null);
             } else {
@@ -534,7 +534,7 @@
         SyncableContentProvider clientDiffs = mergeResult.tempContentProvider;
         if (Log.isLoggable(TAG, Log.VERBOSE)) Log.v(TAG, "generating client updates");
 
-        final String[] accountSelectionArgs = new String[]{account.mName, account.mType};
+        final String[] accountSelectionArgs = new String[]{account.name, account.type};
 
         // Generate the client updates and insertions
         // Create a cursor for dirty records
diff --git a/core/java/android/content/SyncManager.java b/core/java/android/content/SyncManager.java
index d54e260..f256394 100644
--- a/core/java/android/content/SyncManager.java
+++ b/core/java/android/content/SyncManager.java
@@ -596,7 +596,7 @@
 
         for (String authority : syncableAuthorities) {
             for (Account account : accounts) {
-                if (mSyncAdapters.getServiceInfo(new SyncAdapterType(authority, account.mType))
+                if (mSyncAdapters.getServiceInfo(new SyncAdapterType(authority, account.type))
                         != null) {
                     scheduleSyncOperation(
                             new SyncOperation(account, source, authority, extras, delay));
@@ -1094,8 +1094,8 @@
             for (int i=0; i<N; i++) {
                 SyncStorageEngine.PendingOperation op = ops.get(i);
                 pw.print("  #"); pw.print(i); pw.print(": account=");
-                pw.print(op.account.mName); pw.print(":");
-                pw.print(op.account.mType); pw.print(" authority=");
+                pw.print(op.account.name); pw.print(":");
+                pw.print(op.account.type); pw.print(" authority=");
                 pw.println(op.authority);
                 if (op.extras != null && op.extras.size() > 0) {
                     sb.setLength(0);
@@ -1125,8 +1125,8 @@
                     
                     processedAccounts.add(curAccount);
                     
-                    pw.print("  Account "); pw.print(authority.account.mName);
-                            pw.print(" "); pw.print(authority.account.mType);
+                    pw.print("  Account "); pw.print(authority.account.name);
+                            pw.print(" "); pw.print(authority.account.type);
                             pw.println(":");
                     for (int j=i; j<N; j++) {
                         status = statuses.get(j);
@@ -1248,9 +1248,9 @@
                         = mSyncStorageEngine.getAuthority(item.authorityId);
                 pw.print("  #"); pw.print(i+1); pw.print(": ");
                         if (authority != null) {
-                            pw.print(authority.account.mName);
+                            pw.print(authority.account.name);
                             pw.print(":");
-                            pw.print(authority.account.mType);
+                            pw.print(authority.account.type);
                             pw.print(" ");
                             pw.print(authority.authority);
                         } else {
@@ -1636,7 +1636,7 @@
 
             // connect to the sync adapter
             SyncAdapterType syncAdapterType = new SyncAdapterType(op.authority,
-                    op.account.mType);
+                    op.account.type);
             RegisteredServicesCache.ServiceInfo<SyncAdapterType> syncAdapterInfo =
                     mSyncAdapters.getServiceInfo(syncAdapterType);
             if (syncAdapterInfo == null) {
diff --git a/core/java/android/content/SyncStateContentProviderHelper.java b/core/java/android/content/SyncStateContentProviderHelper.java
index dc728ec..64bbe25 100644
--- a/core/java/android/content/SyncStateContentProviderHelper.java
+++ b/core/java/android/content/SyncStateContentProviderHelper.java
@@ -172,7 +172,7 @@
      */
     public void copySyncState(SQLiteDatabase dbSrc, SQLiteDatabase dbDest,
             Account account) {
-        final String[] whereArgs = new String[]{account.mName, account.mType};
+        final String[] whereArgs = new String[]{account.name, account.type};
         Cursor c = dbSrc.query(SYNC_STATE_TABLE,
                 new String[]{"_sync_account", "_sync_account_type", "data"},
                 ACCOUNT_WHERE, whereArgs, null, null, null);
@@ -209,7 +209,7 @@
 
     public void discardSyncData(SQLiteDatabase db, Account account) {
         if (account != null) {
-            db.delete(SYNC_STATE_TABLE, ACCOUNT_WHERE, new String[]{account.mName, account.mType});
+            db.delete(SYNC_STATE_TABLE, ACCOUNT_WHERE, new String[]{account.name, account.type});
         } else {
             db.delete(SYNC_STATE_TABLE, null, null);
         }
@@ -220,7 +220,7 @@
      */
     public byte[] readSyncDataBytes(SQLiteDatabase db, Account account) {
         Cursor c = db.query(SYNC_STATE_TABLE, null, ACCOUNT_WHERE,
-                new String[]{account.mName, account.mType}, null, null, null);
+                new String[]{account.name, account.type}, null, null, null);
         try {
             if (c.moveToFirst()) {
                 return c.getBlob(c.getColumnIndexOrThrow("data"));
@@ -238,6 +238,6 @@
         ContentValues values = new ContentValues();
         values.put("data", data);
         db.update(SYNC_STATE_TABLE, values, ACCOUNT_WHERE,
-                new String[]{account.mName, account.mType});
+                new String[]{account.name, account.type});
     }
 }
diff --git a/core/java/android/content/SyncStorageEngine.java b/core/java/android/content/SyncStorageEngine.java
index 8cc0642..b3f9bbb 100644
--- a/core/java/android/content/SyncStorageEngine.java
+++ b/core/java/android/content/SyncStorageEngine.java
@@ -1127,8 +1127,8 @@
                 AuthorityInfo authority = mAuthorities.get(i);
                 out.startTag(null, "authority");
                 out.attribute(null, "id", Integer.toString(authority.ident));
-                out.attribute(null, "account", authority.account.mName);
-                out.attribute(null, "type", authority.account.mType);
+                out.attribute(null, "account", authority.account.name);
+                out.attribute(null, "type", authority.account.type);
                 out.attribute(null, "authority", authority.authority);
                 if (!authority.enabled) {
                     out.attribute(null, "enabled", "false");
diff --git a/core/java/android/provider/Calendar.java b/core/java/android/provider/Calendar.java
index 489d936..fab3f3d 100644
--- a/core/java/android/provider/Calendar.java
+++ b/core/java/android/provider/Calendar.java
@@ -174,7 +174,7 @@
             return Calendar.Calendars.delete(cr,
                     Calendar.Calendars._SYNC_ACCOUNT + "=? AND "
                             + Calendar.Calendars._SYNC_ACCOUNT_TYPE + "=?",
-                    new String[] {account.mName, account.mType});
+                    new String[] {account.name, account.type});
         }
 
         /**
diff --git a/core/java/android/provider/SubscribedFeeds.java b/core/java/android/provider/SubscribedFeeds.java
index f94b442..8e9f402 100644
--- a/core/java/android/provider/SubscribedFeeds.java
+++ b/core/java/android/provider/SubscribedFeeds.java
@@ -119,8 +119,8 @@
             String authority, String service) {
         ContentValues values = new ContentValues();
         values.put(SubscribedFeeds.Feeds.FEED, feed);
-        values.put(SubscribedFeeds.Feeds._SYNC_ACCOUNT, account.mName);
-        values.put(SubscribedFeeds.Feeds._SYNC_ACCOUNT_TYPE, account.mType);
+        values.put(SubscribedFeeds.Feeds._SYNC_ACCOUNT, account.name);
+        values.put(SubscribedFeeds.Feeds._SYNC_ACCOUNT_TYPE, account.type);
         values.put(SubscribedFeeds.Feeds.AUTHORITY, authority);
         values.put(SubscribedFeeds.Feeds.SERVICE, service);
         return resolver.insert(SubscribedFeeds.Feeds.CONTENT_URI, values);
@@ -134,7 +134,7 @@
         where.append(" AND " + SubscribedFeeds.Feeds.FEED + "=?");
         where.append(" AND " + SubscribedFeeds.Feeds.AUTHORITY + "=?");
         return resolver.delete(SubscribedFeeds.Feeds.CONTENT_URI,
-                where.toString(), new String[] {account.mName, account.mType, feed, authority});
+                where.toString(), new String[] {account.name, account.type, feed, authority});
     }
 
     public static int deleteFeeds(ContentResolver resolver,
@@ -144,7 +144,7 @@
         where.append(" AND " + SubscribedFeeds.Feeds._SYNC_ACCOUNT_TYPE + "=?");
         where.append(" AND " + SubscribedFeeds.Feeds.AUTHORITY + "=?");
         return resolver.delete(SubscribedFeeds.Feeds.CONTENT_URI,
-                where.toString(), new String[] {account.mName, account.mType, authority});
+                where.toString(), new String[] {account.name, account.type, authority});
     }
 
     /**
diff --git a/core/java/android/provider/SyncStateContract.java b/core/java/android/provider/SyncStateContract.java
index 7927e28..5c93af0 100644
--- a/core/java/android/provider/SyncStateContract.java
+++ b/core/java/android/provider/SyncStateContract.java
@@ -71,7 +71,7 @@
         public static byte[] get(ContentProviderClient provider, Uri uri,
                 Account account) throws RemoteException {
             Cursor c = provider.query(uri, DATA_PROJECTION, SELECT_BY_ACCOUNT,
-                    new String[]{account.mName, account.mType}, null);
+                    new String[]{account.name, account.type}, null);
             try {
                 if (c.moveToNext()) {
                     return c.getBlob(c.getColumnIndexOrThrow(Columns.DATA));
@@ -96,8 +96,8 @@
                 Account account, byte[] data) throws RemoteException {
             ContentValues values = new ContentValues();
             values.put(Columns.DATA, data);
-            values.put(Columns.ACCOUNT_NAME, account.mName);
-            values.put(Columns.ACCOUNT_TYPE, account.mType);
+            values.put(Columns.ACCOUNT_NAME, account.name);
+            values.put(Columns.ACCOUNT_TYPE, account.type);
             provider.insert(uri, values);
         }
 
@@ -116,8 +116,8 @@
             values.put(Columns.DATA, data);
             return ContentProviderOperation
                     .newInsert(uri)
-                    .withValue(Columns.ACCOUNT_NAME, account.mName)
-                    .withValue(Columns.ACCOUNT_TYPE, account.mType)
+                    .withValue(Columns.ACCOUNT_NAME, account.name)
+                    .withValue(Columns.ACCOUNT_TYPE, account.type)
                     .withValues(values)
                     .build();
         }