Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit a698f427 authored by Fred Quintana's avatar Fred Quintana Committed by The Android Open Source Project
Browse files

AI 145177: phase two of the AccountManager

  - added an AccountManagerActivity, a base Activity that can be
  used by activities that are launched by AccountAuthenticator
  intents. This makes it easy for an Activity to send a result
  using an AccountAuthenticatorResponse
  - added debug strings to the AccountAuthenticatorCache
  - improved the API for the AccountAuthenticatorResponse and
  made it Parcelable so that it can be passed to an Activity
  via an Intent
  - changed the AccountManager to use Futures for the
  asynchronous calls and to notify the user via a callback
  when the request is complete
  - changed the AccountManager to convert any errors that are
  returned into Exceptions
  - added constants for the error codes that are passed across
  the IAccountManagerResponse and
  IAccountAuthenticatorResponse interfaces
  - added a dump() method to the AccountManagerService so that
  it can display the list of active sessions and registered
  authenticators
  - added an way to interrogate the AccountManagerService for
  the list of registered authenticators
  - removed more methods from the GoogleLoginServiceHelper and
  GoogleLoginServiceBlockingHelper and changed the callers to
  use the AccountManager

Automated import of CL 145177
parent 44e4aaf1
Loading
Loading
Loading
Loading
+1196 −420

File changed.

Preview size limit exceeded, changes collapsed.

+117 −69
Original line number Diff line number Diff line
@@ -16,6 +16,7 @@

package android.accounts;

import android.os.Bundle;
import android.os.RemoteException;

/**
@@ -24,54 +25,113 @@ import android.os.RemoteException;
 * AccountAuthenticators.
 */
public abstract class AbstractAccountAuthenticator {
    private static final String TAG = "AccountAuthenticator";

    class Transport extends IAccountAuthenticator.Stub {
        public void addAccount(IAccountAuthenticatorResponse response, String accountType)
        public void addAccount(IAccountAuthenticatorResponse response, String accountType,
                String authTokenType, Bundle options)
                throws RemoteException {
            AbstractAccountAuthenticator.this.addAccount(new AccountAuthenticatorResponse(response),
                    accountType);
            final Bundle result;
            try {
                result = AbstractAccountAuthenticator.this.addAccount(
                    new AccountAuthenticatorResponse(response),
                        accountType, authTokenType, options);
            } catch (NetworkErrorException e) {
                response.onError(Constants.ERROR_CODE_NETWORK_ERROR, e.getMessage());
                return;
            } catch (UnsupportedOperationException e) {
                response.onError(Constants.ERROR_CODE_UNSUPPORTED_OPERATION,
                        "addAccount not supported");
                return;
            }
            if (result != null) {
                response.onResult(result);
            }

        public void authenticateAccount(IAccountAuthenticatorResponse
                response, String name, String type, String password)
                throws RemoteException {
            AbstractAccountAuthenticator.this.authenticateAccount(
                    new AccountAuthenticatorResponse(response), new Account(name, type), password);
        }

        public void getAuthToken(IAccountAuthenticatorResponse response,
                String name, String type, String authTokenType)
                throws RemoteException {
            AbstractAccountAuthenticator.this.getAuthToken(
        public void confirmPassword(IAccountAuthenticatorResponse response,
                Account account, String password) throws RemoteException {
            boolean result;
            try {
                result = AbstractAccountAuthenticator.this.confirmPassword(
                    new AccountAuthenticatorResponse(response),
                    new Account(name, type), authTokenType);
                        account, password);
            } catch (UnsupportedOperationException e) {
                response.onError(Constants.ERROR_CODE_UNSUPPORTED_OPERATION,
                        "confirmPassword not supported");
                return;
            } catch (NetworkErrorException e) {
                response.onError(Constants.ERROR_CODE_NETWORK_ERROR, e.getMessage());
                return;
            }
            Bundle bundle = new Bundle();
            bundle.putBoolean(Constants.BOOLEAN_RESULT_KEY, result);
            response.onResult(bundle);
        }

        public void getPasswordStrength(IAccountAuthenticatorResponse response,
                String accountType, String password)
                throws RemoteException {
            AbstractAccountAuthenticator.this.getPasswordStrength(
                    new AccountAuthenticatorResponse(response), accountType, password);
        public void confirmCredentials(IAccountAuthenticatorResponse response,
                Account account) throws RemoteException {
            final Bundle result;
            try {
                result = AbstractAccountAuthenticator.this.confirmCredentials(
                    new AccountAuthenticatorResponse(response), account);
            } catch (UnsupportedOperationException e) {
                response.onError(Constants.ERROR_CODE_UNSUPPORTED_OPERATION,
                        "confirmCredentials not supported");
                return;
            }
            if (result != null) {
                response.onResult(result);
            }
        }

        public void checkUsernameExistence(IAccountAuthenticatorResponse response,
                String accountType, String username)
        public void getAuthToken(IAccountAuthenticatorResponse response,
                Account account, String authTokenType, Bundle loginOptions)
                throws RemoteException {
            AbstractAccountAuthenticator.this.checkUsernameExistence(
                    new AccountAuthenticatorResponse(response), accountType, username);
            try {
                final Bundle result = AbstractAccountAuthenticator.this.getAuthToken(
                        new AccountAuthenticatorResponse(response), account,
                        authTokenType, loginOptions);
                if (result != null) {
                    response.onResult(result);
                }
            } catch (UnsupportedOperationException e) {
                response.onError(Constants.ERROR_CODE_UNSUPPORTED_OPERATION,
                        "getAuthToken not supported");
            } catch (NetworkErrorException e) {
                response.onError(Constants.ERROR_CODE_NETWORK_ERROR, e.getMessage());
            }
        }

        public void updatePassword(IAccountAuthenticatorResponse response, String name, String type)
                throws RemoteException {
            AbstractAccountAuthenticator.this.updatePassword(
                    new AccountAuthenticatorResponse(response), new Account(name, type));
        public void updateCredentials(IAccountAuthenticatorResponse response, Account account,
                String authTokenType, Bundle loginOptions) throws RemoteException {
            final Bundle result;
            try {
                result = AbstractAccountAuthenticator.this.updateCredentials(
                    new AccountAuthenticatorResponse(response), account,
                        authTokenType, loginOptions);
            } catch (UnsupportedOperationException e) {
                response.onError(Constants.ERROR_CODE_UNSUPPORTED_OPERATION,
                        "updateCredentials not supported");
                return;
            }
            if (result != null) {
                response.onResult(result);
            }
        }

        public void editProperties(IAccountAuthenticatorResponse response, String accountType)
                throws RemoteException {
            AbstractAccountAuthenticator.this.editProperties(
        public void editProperties(IAccountAuthenticatorResponse response,
                String accountType) throws RemoteException {
            final Bundle result;
            try {
                result = AbstractAccountAuthenticator.this.editProperties(
                    new AccountAuthenticatorResponse(response), accountType);
            } catch (UnsupportedOperationException e) {
                response.onError(Constants.ERROR_CODE_UNSUPPORTED_OPERATION,
                        "editProperties not supported");
                return;
            }
            if (result != null) {
                response.onResult(result);
            }
        }
    }

@@ -86,41 +146,29 @@ public abstract class AbstractAccountAuthenticator {
    }

    /**
     * prompts the user for account information and adds the result to the IAccountManager
     */
    public abstract void addAccount(AccountAuthenticatorResponse response, String accountType);

    /**
     * prompts the user for the credentials of the account
     */
    public abstract void authenticateAccount(AccountAuthenticatorResponse response,
            Account account, String password);

    /**
     * gets the password by either prompting the user or querying the IAccountManager
     */
    public abstract void getAuthToken(AccountAuthenticatorResponse response,
            Account account, String authTokenType);

    /**
     * does local analysis or uses a service in the cloud
     */
    public abstract void getPasswordStrength(AccountAuthenticatorResponse response,
        String accountType, String password);

    /**
     * checks with the login service in the cloud
     */
    public abstract void checkUsernameExistence(AccountAuthenticatorResponse response,
        String accountType, String username);

    /**
     * prompts the user for a new password and writes it to the IAccountManager
     */
    public abstract void updatePassword(AccountAuthenticatorResponse response, Account account);

    /**
     * launches an activity that lets the user edit and set the properties for an authenticator
     * Returns a Bundle that contains the Intent of the activity that can be used to edit the
     * properties. In order to indicate success the activity should call response.setResult()
     * with a non-null Bundle.
     * @param response used to set the result for the request. If the Constants.INTENT_KEY
     *   is set in the bundle then this response field is to be used for sending future
     *   results if and when the Intent is started.
     * @param accountType the AccountType whose properties are to be edited.
     * @return a Bundle containing the result or the Intent to start to continue the request.
     *   If this is null then the request is considered to still be active and the result should
     *   sent later using response.
     */
    public abstract void editProperties(AccountAuthenticatorResponse response, String accountType);
    public abstract Bundle editProperties(AccountAuthenticatorResponse response,
            String accountType);
    public abstract Bundle addAccount(AccountAuthenticatorResponse response, String accountType,
            String authTokenType, Bundle options) throws NetworkErrorException;
    /* @deprecated */
    public abstract boolean confirmPassword(AccountAuthenticatorResponse response,
            Account account, String password) throws NetworkErrorException;
    public abstract Bundle confirmCredentials(AccountAuthenticatorResponse response,
            Account account);
    public abstract Bundle getAuthToken(AccountAuthenticatorResponse response,
            Account account, String authTokenType, Bundle loginOptions)
            throws NetworkErrorException;
    public abstract Bundle updateCredentials(AccountAuthenticatorResponse response,
            Account account, String authTokenType, Bundle loginOptions);
}
+7 −0
Original line number Diff line number Diff line
@@ -18,6 +18,7 @@ package android.accounts;

import android.os.Parcelable;
import android.os.Parcel;
import android.text.TextUtils;

/**
 * Value type that represents an Account in the {@link AccountManager}. This object is
@@ -43,6 +44,12 @@ public class Account implements Parcelable {
    }

    public Account(String name, String type) {
        if (TextUtils.isEmpty(name)) {
            throw new IllegalArgumentException("the name must not be empty: " + name);
        }
        if (TextUtils.isEmpty(type)) {
            throw new IllegalArgumentException("the type must not be empty: " + type);
        }
        mName = name;
        mType = type;
    }
+102 −0
Original line number Diff line number Diff line
/*
 * 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.app.Activity;
import android.content.Intent;
import android.os.Bundle;

/**
 * Base class for implementing an Activity that is used to help implement an
 * AbstractAccountAuthenticator. If the AbstractAccountAuthenticator needs to return an Intent
 * that is to be used to launch an Activity that needs to return results to satisfy an
 * AbstractAccountAuthenticator request, it should store the AccountAuthenticatorResponse
 * inside of the Intent as follows:
 * <p>
 *      intent.putExtra(Constants.ACCOUNT_AUTHENTICATOR_RESPONSE_KEY, response);
 * <p>
 * The activity that it launches should extend the AccountAuthenticatorActivity. If this
 * activity has a result that satisfies the original request it sets it via:
 * <p>
 *       setAccountAuthenticatorResult(result)
 * <p>
 * This result will be sent as the result of the request when the activity finishes. If this
 * is never set or if it is set to null then the request will be canceled when the activity
 * finishes.
 */
public class AccountAuthenticatorActivity extends Activity {
    private AccountAuthenticatorResponse mAccountAuthenticatorResponse = null;
    private Bundle mResultBundle = null;

    /**
     * Set the result that is to be sent as the result of the request that caused this
     * Activity to be launched. If result is null or this method is never called then
     * the request will be canceled.
     * @param result this is returned as the result of the AbstractAccountAuthenticator request
     */
    public final void setAccountAuthenticatorResult(Bundle result) {
        mResultBundle = result;
    }

    /**
     * Retreives the AccountAuthenticatorResponse from either the intent of the icicle, if the
     * icicle is non-zero.
     * @param icicle the save instance data of this Activity, may be null
     */
    protected void onCreate(Bundle icicle) {
        super.onCreate(icicle);

        if (icicle == null) {
            Intent intent = getIntent();
            mAccountAuthenticatorResponse =
                    intent.getParcelableExtra(Constants.ACCOUNT_AUTHENTICATOR_RESPONSE_KEY);
        } else {
            mAccountAuthenticatorResponse =
                    icicle.getParcelable(Constants.ACCOUNT_AUTHENTICATOR_RESPONSE_KEY);
        }

        if (mAccountAuthenticatorResponse != null) {
            mAccountAuthenticatorResponse.onRequestContinued();
        }
    }

    /**
     * Saves the AccountAuthenticatorResponse in the instance state.
     * @param outState where to store any instance data
     */
    protected void onSaveInstanceState(Bundle outState) {
        outState.putParcelable(Constants.ACCOUNT_AUTHENTICATOR_RESPONSE_KEY,
                mAccountAuthenticatorResponse);
        super.onSaveInstanceState(outState);
    }

    /**
     * Sends the result or a Constants.ERROR_CODE_CANCELED error if a result isn't present.
     */
    public void finish() {
        if (mAccountAuthenticatorResponse != null) {
            // send the result bundle back if set, otherwise send an error.
            if (mResultBundle != null) {
                mAccountAuthenticatorResponse.onResult(mResultBundle);
            } else {
                mAccountAuthenticatorResponse.onError(Constants.ERROR_CODE_CANCELED, "canceled");
            }
            mAccountAuthenticatorResponse = null;
        }
        super.finish();
    }
}
+26 −6
Original line number Diff line number Diff line
@@ -16,18 +16,27 @@

package android.accounts;

import android.content.*;
import android.content.res.XmlResourceParser;
import android.content.res.TypedArray;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
import android.content.pm.ServiceInfo;
import android.content.res.XmlResourceParser;
import android.content.res.TypedArray;
import android.content.BroadcastReceiver;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.util.Log;
import android.util.AttributeSet;
import android.util.Xml;

import java.util.*;
import java.io.IOException;
import java.io.FileDescriptor;
import java.io.PrintWriter;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.Map;

import com.google.android.collect.Maps;
import org.xmlpull.v1.XmlPullParserException;
@@ -59,6 +68,15 @@ public class AccountAuthenticatorCache {
        };
    }

    protected void dump(FileDescriptor fd, PrintWriter fout, String[] args) {
        getAllAuthenticators();
        Map<String, AuthenticatorInfo> authenticators = mAuthenticators;
        fout.println("AccountAuthenticatorCache: " + authenticators.size() + " authenticators");
        for (AuthenticatorInfo info : authenticators.values()) {
            fout.println("  " + info);
        }
    }

    private void monitorPackageChanges() {
        IntentFilter intentFilter = new IntentFilter();
        intentFilter.addAction(Intent.ACTION_PACKAGE_ADDED);
@@ -73,13 +91,15 @@ public class AccountAuthenticatorCache {
     */
    public class AuthenticatorInfo {
        public final String mType;
        public final String mComponentShortName;
        public final ComponentName mComponentName;

        private AuthenticatorInfo(String type, ComponentName componentName) {
            mType = type;
            mComponentName = componentName;
            mComponentShortName = componentName.flattenToShortString();
        }

        public String toString() {
            return "AuthenticatorInfo: " + mType + ", " + mComponentName;
        }
    }

Loading