1 // Copyright 2015 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 package org
.chromium
.chromoting
;
7 import android
.app
.Activity
;
8 import android
.os
.AsyncTask
;
10 import com
.google
.android
.gms
.auth
.GoogleAuthException
;
11 import com
.google
.android
.gms
.auth
.GoogleAuthUtil
;
12 import com
.google
.android
.gms
.auth
.UserRecoverableAuthException
;
14 import java
.io
.IOException
;
17 * This helper class fetches an OAuth token on a separate thread, and properly handles the various
18 * error-conditions that can occur (such as, starting an Activity to prompt user for input).
20 public class OAuthTokenFetcher
{
22 * Callback interface to receive the token, or an error notification. These will be called
23 * on the application's main thread. Note that if a user-recoverable error occurs, neither of
24 * these callback will be triggered. Instead, a new Activity will be launched, and the calling
25 * Activity must override
26 * {@link android.app.Activity#onActivityResult} and handle the result code
27 * {@link REQUEST_CODE_RECOVER_FROM_OAUTH_ERROR} to re-attempt or cancel fetching the token.
29 public interface Callback
{
30 /** Called when a token is obtained. */
31 void onTokenFetched(String token
);
34 * Called if an unrecoverable error prevents fetching a token.
35 * @param errorResource String resource of error-message to be displayed.
37 void onError(int errorResource
);
40 /** Request code used for starting the OAuth recovery activity. */
41 public static final int REQUEST_CODE_RECOVER_FROM_OAUTH_ERROR
= 100;
43 /** Scopes at which the authentication token we request will be valid. */
44 private static final String TOKEN_SCOPE
= "oauth2:https://www.googleapis.com/auth/chromoting "
45 + "https://www.googleapis.com/auth/googletalk";
48 * Reference to the main activity. Used for running tasks on the main thread, and for
49 * starting other activities to handle user-recoverable errors.
51 private Activity mActivity
;
53 /** Account name (e-mail) for which the token will be fetched. */
54 private String mAccountName
;
56 private Callback mCallback
;
58 public OAuthTokenFetcher(Activity activity
, String accountName
, Callback callback
) {
60 mAccountName
= accountName
;
64 /** Begins fetching a token. Should be called on the main thread. */
70 * Begins fetching a token, clearing an existing token from the cache. Should be called on the
72 * @param expiredToken A previously-fetched token which has expired.
74 public void clearAndFetch(String expiredToken
) {
75 fetchImpl(expiredToken
);
78 private void fetchImpl(final String expiredToken
) {
79 new AsyncTask
<Void
, Void
, Void
>() {
81 protected Void
doInBackground(Void
... params
) {
83 if (expiredToken
!= null) {
84 GoogleAuthUtil
.clearToken(mActivity
, expiredToken
);
87 // This method is deprecated but its replacement is not yet available.
88 // TODO(lambroslambrou): Fix this by replacing |mAccountName| with an instance
89 // of android.accounts.Account.
90 String token
= GoogleAuthUtil
.getToken(mActivity
, mAccountName
, TOKEN_SCOPE
);
91 handleTokenReceived(token
);
92 } catch (IOException ioException
) {
93 handleError(R
.string
.error_network_error
);
94 } catch (UserRecoverableAuthException recoverableException
) {
95 handleRecoverableException(recoverableException
);
96 } catch (GoogleAuthException fatalException
) {
97 handleError(R
.string
.error_unexpected
);
104 private void handleTokenReceived(final String token
) {
105 mActivity
.runOnUiThread(new Runnable() {
108 mCallback
.onTokenFetched(token
);
113 private void handleError(final int error
) {
114 mActivity
.runOnUiThread(new Runnable() {
117 mCallback
.onError(error
);
122 private void handleRecoverableException(final UserRecoverableAuthException exception
) {
123 mActivity
.runOnUiThread(new Runnable() {
126 mActivity
.startActivityForResult(exception
.getIntent(),
127 REQUEST_CODE_RECOVER_FROM_OAUTH_ERROR
);