package org.edx.mobile.social.google;
import android.accounts.AccountManager;
import android.app.Activity;
import android.content.ActivityNotFoundException;
import android.content.Intent;
import android.os.AsyncTask;
import com.google.android.gms.auth.GoogleAuthException;
import com.google.android.gms.auth.GoogleAuthUtil;
import com.google.android.gms.auth.GooglePlayServicesAvailabilityException;
import com.google.android.gms.auth.UserRecoverableAuthException;
import com.google.android.gms.common.AccountPicker;
import com.google.android.gms.common.ConnectionResult;
import com.google.android.gms.common.GooglePlayServicesUtil;
import com.google.android.gms.common.api.GoogleApiClient;
import org.edx.mobile.social.ISocialImpl;
import java.io.IOException;
public class GoogleOauth2 extends ISocialImpl{
private String accessToken;
private String mEmail; // Received from newChooseAccountIntent(); passed to getToken()
private static final int REQUEST_AUTHORIZATION = 343;
public GoogleOauth2(Activity activity) {
super(activity);
}
static final int REQUEST_CODE_PICK_ACCOUNT = 1000;
//TODO - should we merg GoogleApiActivity code with this class?
/* Client used to interact with Google APIs. */
private GoogleApiClient mGoogleApiClient;
private void pickUserAccount() {
try {
String[] accountTypes = new String[]{"com.google"};
Intent intent = AccountPicker.newChooseAccountIntent(null, null,
accountTypes, true, null, null, null, null);
if ( activity == null )
return;
// check if play-services are installed
int result = GooglePlayServicesUtil.isGooglePlayServicesAvailable(activity);
if (ConnectionResult.SUCCESS == result) {
activity.startActivityForResult(intent, REQUEST_CODE_PICK_ACCOUNT);
logger.debug("Launching google account picker ...");
} else {
// display user friendly error message
logger.debug("Play services are missing ...");
GooglePlayServicesUtil.getErrorDialog(result, activity, 100).show();
}
} catch (ActivityNotFoundException ex) {
logger.debug("Google-play-services are missing? cannot login by google");
}
}
/**
* Attempts to retrieve the username.
* If the account is not yet known, invoke the picker. Once the account is known,
* start an instance of the AsyncTask to get the auth token and do work with it.
*/
private void getUsername() {
if (mEmail == null) {
pickUserAccount();
} else {
if ( activity == null )
return;
new FetchGoogleTokenTask(activity, mEmail, getScopes()).execute();
}
}
public class FetchGoogleTokenTask extends AsyncTask<Object, Object, Object> {
Activity mActivity;
String mScope;
String mEmail;
FetchGoogleTokenTask(Activity activity, String name, String scope) {
this.mActivity = activity;
this.mScope = scope;
this.mEmail = name;
}
/**
* Executes the asynchronous job. This runs when you call execute()
* on the AsyncTask instance.
*/
@Override
protected Object doInBackground(Object... params) {
try {
String token = fetchToken();
if (token != null) {
// Insert the good stuff here.
// Use the token to access the user's Google data.
return token;
}
} catch (IOException e) {
// The fetchToken() method handles Google-specific exceptions,
// so this indicates something went wrong at a higher level.
// TIP: Check for network connectivity before starting the AsyncTask.
logger.error(e);
}
return null;
}
@Override
protected void onPostExecute(Object result) {
super.onPostExecute(result);
if (result != null && result instanceof String) {
accessToken = (String) result;
logger.debug("Google oauth2: accessToken: " + accessToken);
if (callback != null) {
callback.onLogin(accessToken);
}
}
}
/**
* Gets an authentication token from Google and handles any
* GoogleAuthException that may occur.
*/
protected String fetchToken() throws IOException {
if ( activity == null )
return null;
try {
logger.debug("Fetching google oauth2 token ...");
return GoogleAuthUtil.getToken(activity, mEmail, mScope);
} catch (UserRecoverableAuthException userRecoverableException) {
// GooglePlayServices.apk is either old, disabled, or not present
// so we need to show the user some UI in the activity to recover.
logger.debug("User recoverable error occurred");
logger.error(userRecoverableException);
// Requesting an authorization code will always throw
// UserRecoverableAuthException on the first call to GoogleAuthUtil.getToken
// because the user must consent to offline access to their data. After
// consent is granted control is returned to your activity in onActivityResult
// and the second call to GoogleAuthUtil.getToken will succeed.
activity.startActivityForResult(userRecoverableException.getIntent(), REQUEST_AUTHORIZATION);
} catch (GoogleAuthException fatalException) {
logger.warn("google auth error occurred");
// Some other type of unrecoverable exception has occurred.
// Report and log the error as appropriate for your app.
logger.error(fatalException);
}
return null;
}
}
@Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
if (requestCode == REQUEST_CODE_PICK_ACCOUNT) {
// Receiving a result from the AccountPicker
if (resultCode == Activity.RESULT_OK) {
mEmail = data.getStringExtra(AccountManager.KEY_ACCOUNT_NAME);
logger.debug(data.toString());
// With the account name acquired, go get the auth token
getUsername();
} else if (resultCode == Activity.RESULT_CANCELED) {
// The account picker dialog closed without selecting an account.
// Notify users that they must pick an account to proceed.
// Toast.makeText(this, R.string.pick_account, Toast.LENGTH_SHORT).show();
}
}
else if (requestCode == REQUEST_AUTHORIZATION) {
// after authorization, try to get token again
if (resultCode == Activity.RESULT_OK) {
// re-try go get the auth token
getUsername();
}
}
}
@Override
public void login() {
pickUserAccount();
}
@Override
public void logout() {
if (accessToken != null) {
try {
if ( activity == null )
return;
GoogleAuthUtil.clearToken(activity, accessToken);
logger.debug("Google logged out");
} catch (GooglePlayServicesAvailabilityException e) {
logger.error(e);
} catch (GoogleAuthException e) {
logger.error(e);
} catch (IOException e) {
logger.error(e);
}
}
}
public String getEmail(){
return mEmail;
}
private String getScopes() {
String login = "https://www.googleapis.com/auth/plus.login";
//TODO- this scope is deprecated
String email = "https://www.googleapis.com/auth/userinfo.email";
String scope = "oauth2:" + login + " " + email;
logger.debug("Scopes= " + scope);
return scope;
}
}