gt:             mSignInFailureReason = null; // cancelling is not a failure!
context: /*
   * Copyright (C) 2013 Google Inc.
   *
   * Licensed under the Apache License, Version 2.0 (the "License");
   * you may not use this file except in compliance with the License.
   * You may obtain a copy of the License at
   *
   *      http://www.apache.org/licenses/LICENSE-2.0
   *
   * Unless required by applicable law or agreed to in writing, software
   * distributed under the License is distributed on an "AS IS" BASIS,
   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   * See the License for the specific language governing permissions and
   * limitations under the License.
   */
  
  package net.redlinesoft.taptaptapfree;
  
  import android.app.Activity;
  import android.app.AlertDialog;
  import android.app.Dialog;
  import android.content.Context;
  import android.content.Intent;
  import android.content.IntentSender.SendIntentException;
  import android.content.SharedPreferences;
  import android.os.Bundle;
  import android.os.Handler;
  import android.util.Log;
  
  import com.google.android.gms.appstate.AppStateManager;
  import com.google.android.gms.common.ConnectionResult;
  import com.google.android.gms.common.GooglePlayServicesUtil;
  import com.google.android.gms.common.api.Api.ApiOptions.NoOptions;
  import com.google.android.gms.common.api.GoogleApiClient;
  import com.google.android.gms.drive.Drive;
  import com.google.android.gms.games.Games;
  import com.google.android.gms.games.Games.GamesOptions;
  import com.google.android.gms.games.GamesActivityResultCodes;
  import com.google.android.gms.games.multiplayer.Invitation;
  import com.google.android.gms.games.multiplayer.Multiplayer;
  import com.google.android.gms.games.multiplayer.turnbased.TurnBasedMatch;
  import com.google.android.gms.games.request.GameRequest;
  import com.google.android.gms.plus.Plus;
  import com.google.android.gms.plus.Plus.PlusOptions;
  
  import java.util.ArrayList;
  
  public class GameHelper implements GoogleApiClient.ConnectionCallbacks,
          GoogleApiClient.OnConnectionFailedListener {
  
      // Client request flags
      public final static int CLIENT_NONE = 0x00;
      // What clients were requested? (bit flags)
      int mRequestedClients = CLIENT_NONE;
      public final static int CLIENT_GAMES = 0x01;
      public final static int CLIENT_PLUS = 0x02;
      public final static int CLIENT_APPSTATE = 0x04;
      public final static int CLIENT_SNAPSHOT = 0x08;
      public final static int CLIENT_ALL = CLIENT_GAMES | CLIENT_PLUS
              | CLIENT_APPSTATE | CLIENT_SNAPSHOT;
      static final String TAG = "GameHelper";
      // Request code we use when invoking other Activities to complete the
      // sign-in flow.
      final static int RC_RESOLVE = 9001;
  
      // Request code when invoking Activities whose result we don't care about.
      final static int RC_UNUSED = 9002;
      // Should we start the flow to sign the user in automatically on startup? If
      // so, up to
      // how many times in the life of the application?
      static final int DEFAULT_MAX_SIGN_IN_ATTEMPTS = 5;
      int mMaxAutoSignInAttempts = DEFAULT_MAX_SIGN_IN_ATTEMPTS;
      private final String GAMEHELPER_SHARED_PREFS = "GAMEHELPER_SHARED_PREFS";
      private final String KEY_SIGN_IN_CANCELLATIONS = "KEY_SIGN_IN_CANCELLATIONS";
      // Are we expecting the result of a resolution flow?
      boolean mExpectingResolution = false;
      // was the sign-in flow cancelled when we tried it?
      // if true, we know not to try again automatically.
      boolean mSignInCancelled = false;
      /**
       * The Activity we are bound to. We need to keep a reference to the Activity
       * because some games methods require an Activity (a Context won't do). We
       * are careful not to leak these references: we release them on onStop().
       */
      Activity mActivity = null;
      // app context
      Context mAppContext = null;
      // the Google API client builder we will use to create GoogleApiClient
      GoogleApiClient.Builder mGoogleApiClientBuilder = null;
      // Api options to use when adding each API, null for none
      GamesOptions mGamesApiOptions = GamesOptions.builder().build();
      PlusOptions mPlusApiOptions = null;
      NoOptions mAppStateApiOptions = null;
      // Google API client object we manage.
      GoogleApiClient mGoogleApiClient = null;
      // Whether to automatically try to sign in on onStart(). We only set this
      // to true when the sign-in process fails or the user explicitly signs out.
      // We set it back to false when the user initiates the sign in process.
      boolean mConnectOnStart = true;
      /*
       * Whether user has specifically requested that the sign-in process begin.
       * If mUserInitiatedSignIn is false, we're in the automatic sign-in attempt
       * that we try once the Activity is started -- if true, then the user has
       * already clicked a "Sign-In" button or something similar
       */
      boolean mUserInitiatedSignIn = false;
      // The connection result we got from our last attempt to sign-in.
      ConnectionResult mConnectionResult = null;
      // The error that happened during sign-in.
      SignInFailureReason mSignInFailureReason = null;
      // Should we show error dialog boxes?
      boolean mShowErrorDialogs = true;
      // Print debug logs?
      boolean mDebugLog = false;
      Handler mHandler;
      /*
       * If we got an invitation when we connected to the games client, it's here.
       * Otherwise, it's null.
       */
      Invitation mInvitation;
      /*
       * If we got turn-based match when we connected to the games client, it's
       * here. Otherwise, it's null.
       */
      TurnBasedMatch mTurnBasedMatch;
      /*
       * If we have incoming requests when we connected to the games client, they
       * are here. Otherwise, it's null.
       */
      ArrayList<GameRequest> mRequests;
      // Listener
      GameHelperListener mListener = null;
      // configuration done?
      private boolean mSetupDone = false;
      // are we currently connecting?
      private boolean mConnecting = false;
  
      /**
       * Construct a GameHelper object, initially tied to the given Activity.
       * After constructing this object, call @link{setup} from the onCreate()
       * method of your Activity.
       *
       * @param clientsToUse the API clients to use (a combination of the CLIENT_* flags,
       *                     or CLIENT_ALL to mean all clients).
       */
      public GameHelper(Activity activity, int clientsToUse) {
          mActivity = activity;
          mAppContext = activity.getApplicationContext();
          mRequestedClients = clientsToUse;
          mHandler = new Handler();
      }
  
      /**
       * Shows an error dialog that's appropriate for the failure reason.
       */
      public static void showFailureDialog(Activity activity, int actResp,
                                           int errorCode) {
          if (activity == null) {
              Log.e("GameHelper", "*** No Activity. Can't show failure dialog!");
              return;
          }
          Dialog errorDialog = null;
  
          switch (actResp) {
              case GamesActivityResultCodes.RESULT_APP_MISCONFIGURED:
                  errorDialog = makeSimpleDialog(activity, GameHelperUtils.getString(
                          activity, GameHelperUtils.R_APP_MISCONFIGURED));
                  break;
              case GamesActivityResultCodes.RESULT_SIGN_IN_FAILED:
                  errorDialog = makeSimpleDialog(activity, GameHelperUtils.getString(
                          activity, GameHelperUtils.R_SIGN_IN_FAILED));
                  break;
              case GamesActivityResultCodes.RESULT_LICENSE_FAILED:
                  errorDialog = makeSimpleDialog(activity, GameHelperUtils.getString(
                          activity, GameHelperUtils.R_LICENSE_FAILED));
                  break;
              default:
                  // No meaningful Activity response code, so generate default Google
                  // Play services dialog
                  errorDialog = GooglePlayServicesUtil.getErrorDialog(errorCode,
                          activity, RC_UNUSED, null);
                  if (errorDialog == null) {
                      // get fallback dialog
                      Log.e("GameHelper",
                              "No standard error dialog available. Making fallback dialog.");
                      errorDialog = makeSimpleDialog(
                              activity,
                              GameHelperUtils.getString(activity,
                                      GameHelperUtils.R_UNKNOWN_ERROR)
                                      + " "
                                      + GameHelperUtils.errorCodeToString(errorCode));
                  }
          }
  
          errorDialog.show();
      }
  
      static Dialog makeSimpleDialog(Activity activity, String text) {
          return (new AlertDialog.Builder(activity)).setMessage(text)
                  .setNeutralButton(android.R.string.ok, null).create();
      }
  
      static Dialog
      makeSimpleDialog(Activity activity, String title, String text) {
          return (new AlertDialog.Builder(activity)).setMessage(text)
                  .setTitle(title).setNeutralButton(android.R.string.ok, null)
                  .create();
      }
  
      /**
       * Sets the maximum number of automatic sign-in attempts to be made on
       * application startup. This maximum is over the lifetime of the application
       * (it is stored in a SharedPreferences file). So, for example, if you
       * specify 2, then it means that the user will be prompted to sign in on app
       * startup the first time and, if they cancel, a second time the next time
       * the app starts, and, if they cancel that one, never again. Set to 0 if
       * you do not want the user to be prompted to sign in on application
       * startup.
       */
      public void setMaxAutoSignInAttempts(int max) {
          mMaxAutoSignInAttempts = max;
      }
  
      void assertConfigured(String operation) {
          if (!mSetupDone) {
              String error = "GameHelper error: Operation attempted without setup: "
                      + operation
                      + ". The setup() method must be called before attempting any other operation.";
              logError(error);
              throw new IllegalStateException(error);
          }
      }
  
      private void doApiOptionsPreCheck() {
          if (mGoogleApiClientBuilder != null) {
              String error = "GameHelper: you cannot call set*ApiOptions after the client "
                      + "builder has been created. Call it before calling createApiClientBuilder() "
                      + "or setup().";
              logError(error);
              throw new IllegalStateException(error);
          }
      }
  
      /**
       * Sets the options to pass when setting up the Games API. Call before
       * setup().
       */
      public void setGamesApiOptions(GamesOptions options) {
          doApiOptionsPreCheck();
          mGamesApiOptions = options;
      }
  
      /**
       * Sets the options to pass when setting up the AppState API. Call before
       * setup().
       */
      public void setAppStateApiOptions(NoOptions options) {
          doApiOptionsPreCheck();
          mAppStateApiOptions = options;
      }
  
      /**
       * Sets the options to pass when setting up the Plus API. Call before
       * setup().
       */
      public void setPlusApiOptions(PlusOptions options) {
          doApiOptionsPreCheck();
          mPlusApiOptions = options;
      }
  
      /**
       * Creates a GoogleApiClient.Builder for use with @link{#setup}. Normally,
       * you do not have to do this; use this method only if you need to make
       * nonstandard setup (e.g. adding extra scopes for other APIs) on the
       * GoogleApiClient.Builder before calling @link{#setup}.
       */
      public GoogleApiClient.Builder createApiClientBuilder() {
          if (mSetupDone) {
              String error = "GameHelper: you called GameHelper.createApiClientBuilder() after "
                      + "calling setup. You can only get a client builder BEFORE performing setup.";
              logError(error);
              throw new IllegalStateException(error);
          }
  
          GoogleApiClient.Builder builder = new GoogleApiClient.Builder(
                  mActivity, this, this);
  
          if (0 != (mRequestedClients & CLIENT_GAMES)) {
              builder.addApi(Games.API, mGamesApiOptions);
              builder.addScope(Games.SCOPE_GAMES);
          }
  
          if (0 != (mRequestedClients & CLIENT_PLUS)) {
              builder.addApi(Plus.API);
              builder.addScope(Plus.SCOPE_PLUS_LOGIN);
          }
  
          if (0 != (mRequestedClients & CLIENT_APPSTATE)) {
              builder.addApi(AppStateManager.API);
              builder.addScope(AppStateManager.SCOPE_APP_STATE);
          }
  
          if (0 != (mRequestedClients & CLIENT_SNAPSHOT)) {
              builder.addScope(Drive.SCOPE_APPFOLDER);
              builder.addApi(Drive.API);
          }
  
          mGoogleApiClientBuilder = builder;
          return builder;
      }
  
      /**
       * Performs setup on this GameHelper object. Call this from the onCreate()
       * method of your Activity. This will create the clients and do a few other
       * initialization tasks. Next, call @link{#onStart} from the onStart()
       * method of your Activity.
       *
       * @param listener The listener to be notified of sign-in events.
       */
      public void setup(GameHelperListener listener) {
          if (mSetupDone) {
              String error = "GameHelper: you cannot call GameHelper.setup() more than once!";
              logError(error);
              throw new IllegalStateException(error);
          }
          mListener = listener;
          debugLog("Setup: requested clients: " + mRequestedClients);
  
          if (mGoogleApiClientBuilder == null) {
              // we don't have a builder yet, so create one
              createApiClientBuilder();
          }
  
          mGoogleApiClient = mGoogleApiClientBuilder.build();
          mGoogleApiClientBuilder = null;
          mSetupDone = true;
      }
  
      /**
       * Returns the GoogleApiClient object. In order to call this method, you
       * must have called @link{setup}.
       */
      public GoogleApiClient getApiClient() {
          if (mGoogleApiClient == null) {
              throw new IllegalStateException(
                      "No GoogleApiClient. Did you call setup()?");
          }
          return mGoogleApiClient;
      }
  
      /**
       * Returns whether or not the user is signed in.
       */
      public boolean isSignedIn() {
          return mGoogleApiClient != null && mGoogleApiClient.isConnected();
      }
  
      /**
       * Returns whether or not we are currently connecting
       */
      public boolean isConnecting() {
          return mConnecting;
      }
  
      /**
       * Returns whether or not there was a (non-recoverable) error during the
       * sign-in process.
       */
      public boolean hasSignInError() {
          return mSignInFailureReason != null;
      }
  
      /**
       * Returns the error that happened during the sign-in process, null if no
       * error occurred.
       */
      public SignInFailureReason getSignInError() {
          return mSignInFailureReason;
      }
  
      // Set whether to show error dialogs or not.
      public void setShowErrorDialogs(boolean show) {
          mShowErrorDialogs = show;
      }
  
      /**
       * Call this method from your Activity's onStart().
       */
      public void onStart(Activity act) {
          mActivity = act;
          mAppContext = act.getApplicationContext();
  
          debugLog("onStart");
          assertConfigured("onStart");
  
          if (mConnectOnStart) {
              if (mGoogleApiClient.isConnected()) {
                  Log.w(TAG,
                          "GameHelper: client was already connected on onStart()");
              } else {
                  debugLog("Connecting client.");
                  mConnecting = true;
                  mGoogleApiClient.connect();
              }
          } else {
              debugLog("Not attempting to connect becase mConnectOnStart=false");
              debugLog("Instead, reporting a sign-in failure.");
              mHandler.postDelayed(new Runnable() {
                  @Override
                  public void run() {
                      notifyListener(false);
                  }
              }, 1000);
          }
      }
  
      /**
       * Call this method from your Activity's onStop().
       */
      public void onStop() {
          debugLog("onStop");
          assertConfigured("onStop");
          if (mGoogleApiClient.isConnected()) {
              debugLog("Disconnecting client due to onStop");
              mGoogleApiClient.disconnect();
          } else {
              debugLog("Client already disconnected when we got onStop.");
          }
          mConnecting = false;
          mExpectingResolution = false;
  
          // let go of the Activity reference
          mActivity = null;
      }
  
      /**
       * Returns the invitation ID received through an invitation notification.
       * This should be called from your GameHelperListener's
       *
       * @return The id of the invitation, or null if none was received.
       * @link{GameHelperListener#onSignInSucceeded method, to check if there's an
       * invitation available. In that
       * case, accept the invitation.
       */
      public String getInvitationId() {
          if (!mGoogleApiClient.isConnected()) {
              Log.w(TAG,
                      "Warning: getInvitationId() should only be called when signed in, "
                              + "that is, after getting onSignInSuceeded()");
          }
          return mInvitation == null ? null : mInvitation.getInvitationId();
      }
  
      /**
       * Returns the invitation received through an invitation notification. This
       * should be called from your GameHelperListener's
       *
       * @return The invitation, or null if none was received.
       * @link{GameHelperListener#onSignInSucceeded method, to check if there's an
       * invitation available. In that
       * case, accept the invitation.
       */
      public Invitation getInvitation() {
          if (!mGoogleApiClient.isConnected()) {
              Log.w(TAG,
                      "Warning: getInvitation() should only be called when signed in, "
                              + "that is, after getting onSignInSuceeded()");
          }
          return mInvitation;
      }
  
      public boolean hasInvitation() {
          return mInvitation != null;
      }
  
      public boolean hasTurnBasedMatch() {
          return mTurnBasedMatch != null;
      }
  
      public boolean hasRequests() {
          return mRequests != null;
      }
  
      public void clearInvitation() {
          mInvitation = null;
      }
  
      public void clearTurnBasedMatch() {
          mTurnBasedMatch = null;
      }
  
      public void clearRequests() {
          mRequests = null;
      }
  
      /**
       * Returns the tbmp match received through an invitation notification. This
       * should be called from your GameHelperListener's
       *
       * @return The match, or null if none was received.
       * @link{GameHelperListener#onSignInSucceeded method, to check if there's a
       * match available.
       */
      public TurnBasedMatch getTurnBasedMatch() {
          if (!mGoogleApiClient.isConnected()) {
              Log.w(TAG,
                      "Warning: getTurnBasedMatch() should only be called when signed in, "
                              + "that is, after getting onSignInSuceeded()");
          }
          return mTurnBasedMatch;
      }
  
      /**
       * Returns the requests received through the onConnected bundle. This should
       * be called from your GameHelperListener's
       *
       * @return The requests, or null if none were received.
       * @link{GameHelperListener#onSignInSucceeded method, to check if there are
       * incoming requests that must be
       * handled.
       */
      public ArrayList<GameRequest> getRequests() {
          if (!mGoogleApiClient.isConnected()) {
              Log.w(TAG, "Warning: getRequests() should only be called "
                      + "when signed in, "
                      + "that is, after getting onSignInSuceeded()");
          }
          return mRequests;
      }
  
      /**
       * Enables debug logging
       */
      public void enableDebugLog(boolean enabled) {
          mDebugLog = enabled;
          if (enabled) {
              debugLog("Debug log enabled.");
          }
      }
  
      @Deprecated
      public void enableDebugLog(boolean enabled, String tag) {
          Log.w(TAG, "GameHelper.enableDebugLog(boolean,String) is deprecated. "
                  + "Use GameHelper.enableDebugLog(boolean)");
          enableDebugLog(enabled);
      }
  
      /**
       * Sign out and disconnect from the APIs.
       */
      public void signOut() {
          if (!mGoogleApiClient.isConnected()) {
              // nothing to do
              debugLog("signOut: was already disconnected, ignoring.");
              return;
          }
  
          // for Plus, "signing out" means clearing the default account and
          // then disconnecting
          if (0 != (mRequestedClients & CLIENT_PLUS)) {
              debugLog("Clearing default account on PlusClient.");
              Plus.AccountApi.clearDefaultAccount(mGoogleApiClient);
          }
  
          // For the games client, signing out means calling signOut and
          // disconnecting
          if (0 != (mRequestedClients & CLIENT_GAMES)) {
              debugLog("Signing out from the Google API Client.");
              Games.signOut(mGoogleApiClient);
          }
  
          // Ready to disconnect
          debugLog("Disconnecting client.");
          mConnectOnStart = false;
          mConnecting = false;
          mGoogleApiClient.disconnect();
      }
  
      /**
       * Handle activity result. Call this method from your Activity's
       * onActivityResult callback. If the activity result pertains to the sign-in
       * process, processes it appropriately.
       */
      public void onActivityResult(int requestCode, int responseCode,
                                   Intent intent) {
          debugLog("onActivityResult: req="
                  + (requestCode == RC_RESOLVE ? "RC_RESOLVE" : String
                  .valueOf(requestCode)) + ", resp="
                  + GameHelperUtils.activityResponseCodeToString(responseCode));
          if (requestCode != RC_RESOLVE) {
              debugLog("onActivityResult: request code not meant for us. Ignoring.");
              return;
          }
  
          // no longer expecting a resolution
          mExpectingResolution = false;
  
          if (!mConnecting) {
              debugLog("onActivityResult: ignoring because we are not connecting.");
              return;
          }
  
          // We're coming back from an activity that was launched to resolve a
          // connection problem. For example, the sign-in UI.
          if (responseCode == Activity.RESULT_OK) {
              // Ready to try to connect again.
              debugLog("onAR: Resolution was RESULT_OK, so connecting current client again.");
              connect();
          } else if (responseCode == GamesActivityResultCodes.RESULT_RECONNECT_REQUIRED) {
              debugLog("onAR: Resolution was RECONNECT_REQUIRED, so reconnecting.");
              connect();
          } else if (responseCode == Activity.RESULT_CANCELED) {
              // User cancelled.
              debugLog("onAR: Got a cancellation result, so disconnecting.");
              mSignInCancelled = true;
              mConnectOnStart = false;
              mUserInitiatedSignIn = false;
  