package com.example.projectwithappandlib.lib; import android.content.Intent; import android.content.IntentSender; import android.os.Bundle; import android.support.v7.app.ActionBarActivity; 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; /** * A base class to wrap communication with the Google Play Services PlusClient. */ public abstract class PlusBaseActivity extends ActionBarActivity 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_PROFILE).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; } }