blob: 45ea9a974ff50eccbd4e77c241d4b2493e7ae01a [file] [log] [blame]
package ${packageName};
import android.content.Intent;
import android.content.IntentSender;
import android.os.Bundle;
<#if minApiLevel lt 14>import android.support.v7.app.ActionBarActivity;</#if>
<#if minApiLevel gte 14>import android.app.Activity;</#if>
import android.util.Log;
import com.google.android.gms.common.ConnectionResult;
import com.google.android.gms.common.GooglePlayServicesClient;
import com.google.android.gms.common.Scopes;
import com.google.android.gms.plus.PlusClient;
<#if applicationPackage??>import ${applicationPackage}.R;</#if>
/**
* A base class to wrap communication with the Google Play Services PlusClient.
*/
public abstract class PlusBaseActivity extends <#if minApiLevel lt 14>ActionBar</#if>Activity
implements GooglePlayServicesClient.ConnectionCallbacks,
GooglePlayServicesClient.OnConnectionFailedListener {
private static final String TAG = PlusBaseActivity.class.getSimpleName();
// A magic number we will use to know that our sign-in error resolution activity has completed
private static final int OUR_REQUEST_CODE = 49404;
// A flag to stop multiple dialogues appearing for the user
private boolean mAutoResolveOnFail;
// A flag to track when a connection is already in progress
public boolean mPlusClientIsConnecting = false;
// This is the helper object that connects to Google Play Services.
private PlusClient mPlusClient;
// The saved result from {@link #onConnectionFailed(ConnectionResult)}. If a connection
// attempt has been made, this is non-null.
// If this IS null, then the connect method is still running.
private ConnectionResult mConnectionResult;
/**
* Called when the {@link PlusClient} revokes access to this app.
*/
protected abstract void onPlusClientRevokeAccess();
/**
* Called when the PlusClient is successfully connected.
*/
protected abstract void onPlusClientSignIn();
/**
* Called when the {@link PlusClient} is disconnected.
*/
protected abstract void onPlusClientSignOut();
/**
* Called when the {@link PlusClient} is blocking the UI. If you have a progress bar widget,
* this tells you when to show or hide it.
*/
protected abstract void onPlusClientBlockingUI(boolean show);
/**
* Called when there is a change in connection state. If you have "Sign in"/ "Connect",
* "Sign out"/ "Disconnect", or "Revoke access" buttons, this lets you know when their states
* need to be updated.
*/
protected abstract void updateConnectButtonState();
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// Initialize the PlusClient connection.
// Scopes indicate the information about the user your application will be able to access.
mPlusClient =
new PlusClient.Builder(this, this, this).setScopes(Scopes.PLUS_LOGIN,
Scopes.PLUS_ME).build();
}
/**
* Try to sign in the user.
*/
public void signIn() {
if (!mPlusClient.isConnected()) {
// Show the dialog as we are now signing in.
setProgressBarVisible(true);
// Make sure that we will start the resolution (e.g. fire the intent and pop up a
// dialog for the user) for any errors that come in.
mAutoResolveOnFail = true;
// We should always have a connection result ready to resolve,
// so we can start that process.
if (mConnectionResult != null) {
startResolution();
} else {
// If we don't have one though, we can start connect in
// order to retrieve one.
initiatePlusClientConnect();
}
}
updateConnectButtonState();
}
/**
* Connect the {@link PlusClient} only if a connection isn't already in progress. This will
* call back to {@link #onConnected(android.os.Bundle)} or
* {@link #onConnectionFailed(com.google.android.gms.common.ConnectionResult)}.
*/
private void initiatePlusClientConnect() {
if (!mPlusClient.isConnected() && !mPlusClient.isConnecting()) {
mPlusClient.connect();
}
}
/**
* Disconnect the {@link PlusClient} only if it is connected (otherwise, it can throw an error.)
* This will call back to {@link #onDisconnected()}.
*/
private void initiatePlusClientDisconnect() {
if (mPlusClient.isConnected()) {
mPlusClient.disconnect();
}
}
/**
* Sign out the user (so they can switch to another account).
*/
public void signOut() {
// We only want to sign out if we're connected.
if (mPlusClient.isConnected()) {
// Clear the default account in order to allow the user to potentially choose a
// different account from the account chooser.
mPlusClient.clearDefaultAccount();
// Disconnect from Google Play Services, then reconnect in order to restart the
// process from scratch.
initiatePlusClientDisconnect();
Log.v(TAG, "Sign out successful!");
}
updateConnectButtonState();
}
/**
* Revoke Google+ authorization completely.
*/
public void revokeAccess() {
if (mPlusClient.isConnected()) {
// Clear the default account as in the Sign Out.
mPlusClient.clearDefaultAccount();
// Revoke access to this entire application. This will call back to
// onAccessRevoked when it is complete, as it needs to reach the Google
// authentication servers to revoke all tokens.
mPlusClient.revokeAccessAndDisconnect(new PlusClient.OnAccessRevokedListener() {
public void onAccessRevoked(ConnectionResult result) {
updateConnectButtonState();
onPlusClientRevokeAccess();
}
});
}
}
@Override
protected void onStart() {
super.onStart();
initiatePlusClientConnect();
}
@Override
protected void onStop() {
super.onStop();
initiatePlusClientDisconnect();
}
public boolean isPlusClientConnecting() {
return mPlusClientIsConnecting;
}
private void setProgressBarVisible(boolean flag) {
mPlusClientIsConnecting = flag;
onPlusClientBlockingUI(flag);
}
/**
* A helper method to flip the mResolveOnFail flag and start the resolution
* of the ConnectionResult from the failed connect() call.
*/
private void startResolution() {
try {
// Don't start another resolution now until we have a result from the activity we're
// about to start.
mAutoResolveOnFail = false;
// If we can resolve the error, then call start resolution and pass it an integer tag
// we can use to track.
// This means that when we get the onActivityResult callback we'll know it's from
// being started here.
mConnectionResult.startResolutionForResult(this, OUR_REQUEST_CODE);
} catch (IntentSender.SendIntentException e) {
// Any problems, just try to connect() again so we get a new ConnectionResult.
mConnectionResult = null;
initiatePlusClientConnect();
}
}
/**
* An earlier connection failed, and we're now receiving the result of the resolution attempt
* by PlusClient.
*
* @see #onConnectionFailed(ConnectionResult)
*/
@Override
protected void onActivityResult(int requestCode, int responseCode, Intent intent) {
updateConnectButtonState();
if (requestCode == OUR_REQUEST_CODE && responseCode == RESULT_OK) {
// If we have a successful result, we will want to be able to resolve any further
// errors, so turn on resolution with our flag.
mAutoResolveOnFail = true;
// If we have a successful result, let's call connect() again. If there are any more
// errors to resolve we'll get our onConnectionFailed, but if not,
// we'll get onConnected.
initiatePlusClientConnect();
} else if (requestCode == OUR_REQUEST_CODE && responseCode != RESULT_OK) {
// If we've got an error we can't resolve, we're no longer in the midst of signing
// in, so we can stop the progress spinner.
setProgressBarVisible(false);
}
}
/**
* Successfully connected (called by PlusClient)
*/
@Override
public void onConnected(Bundle connectionHint) {
updateConnectButtonState();
setProgressBarVisible(false);
onPlusClientSignIn();
}
/**
* Successfully disconnected (called by PlusClient)
*/
@Override
public void onDisconnected() {
updateConnectButtonState();
onPlusClientSignOut();
}
/**
* Connection failed for some reason (called by PlusClient)
* Try and resolve the result. Failure here is usually not an indication of a serious error,
* just that the user's input is needed.
*
* @see #onActivityResult(int, int, Intent)
*/
@Override
public void onConnectionFailed(ConnectionResult result) {
updateConnectButtonState();
// Most of the time, the connection will fail with a user resolvable result. We can store
// that in our mConnectionResult property ready to be used when the user clicks the
// sign-in button.
if (result.hasResolution()) {
mConnectionResult = result;
if (mAutoResolveOnFail) {
// This is a local helper function that starts the resolution of the problem,
// which may be showing the user an account chooser or similar.
startResolution();
}
}
}
public PlusClient getPlusClient() {
return mPlusClient;
}
}