1/*
2 * Copyright (C) 2011 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package com.android.volley.toolbox;
18
19import com.android.volley.AuthFailureError;
20
21import android.accounts.Account;
22import android.accounts.AccountManager;
23import android.accounts.AccountManagerFuture;
24import android.content.Context;
25import android.content.Intent;
26import android.os.Bundle;
27
28/**
29 * An Authenticator that uses {@link AccountManager} to get auth
30 * tokens of a specified type for a specified account.
31 */
32public class AndroidAuthenticator implements Authenticator {
33    private final AccountManager mAccountManager;
34    private final Account mAccount;
35    private final String mAuthTokenType;
36    private final boolean mNotifyAuthFailure;
37
38    /**
39     * Creates a new authenticator.
40     * @param context Context for accessing AccountManager
41     * @param account Account to authenticate as
42     * @param authTokenType Auth token type passed to AccountManager
43     */
44    public AndroidAuthenticator(Context context, Account account, String authTokenType) {
45        this(context, account, authTokenType, false);
46    }
47
48    /**
49     * Creates a new authenticator.
50     * @param context Context for accessing AccountManager
51     * @param account Account to authenticate as
52     * @param authTokenType Auth token type passed to AccountManager
53     * @param notifyAuthFailure Whether to raise a notification upon auth failure
54     */
55    public AndroidAuthenticator(Context context, Account account, String authTokenType,
56            boolean notifyAuthFailure) {
57        this(AccountManager.get(context), account, authTokenType, notifyAuthFailure);
58    }
59
60    // Visible for testing. Allows injection of a mock AccountManager.
61    AndroidAuthenticator(AccountManager accountManager, Account account,
62            String authTokenType, boolean notifyAuthFailure) {
63        mAccountManager = accountManager;
64        mAccount = account;
65        mAuthTokenType = authTokenType;
66        mNotifyAuthFailure = notifyAuthFailure;
67    }
68
69    /**
70     * Returns the Account being used by this authenticator.
71     */
72    public Account getAccount() {
73        return mAccount;
74    }
75
76    /**
77     * Returns the Auth Token Type used by this authenticator.
78     */
79    public String getAuthTokenType() {
80        return mAuthTokenType;
81    }
82
83    // TODO: Figure out what to do about notifyAuthFailure
84    @SuppressWarnings("deprecation")
85    @Override
86    public String getAuthToken() throws AuthFailureError {
87        AccountManagerFuture<Bundle> future = mAccountManager.getAuthToken(mAccount,
88                mAuthTokenType, mNotifyAuthFailure, null, null);
89        Bundle result;
90        try {
91            result = future.getResult();
92        } catch (Exception e) {
93            throw new AuthFailureError("Error while retrieving auth token", e);
94        }
95        String authToken = null;
96        if (future.isDone() && !future.isCancelled()) {
97            if (result.containsKey(AccountManager.KEY_INTENT)) {
98                Intent intent = result.getParcelable(AccountManager.KEY_INTENT);
99                throw new AuthFailureError(intent);
100            }
101            authToken = result.getString(AccountManager.KEY_AUTHTOKEN);
102        }
103        if (authToken == null) {
104            throw new AuthFailureError("Got null auth token for type: " + mAuthTokenType);
105        }
106
107        return authToken;
108    }
109
110    @Override
111    public void invalidateAuthToken(String authToken) {
112        mAccountManager.invalidateAuthToken(mAccount.type, authToken);
113    }
114}
115