/* * Copyright (C) 2016 Google Inc. All Rights Reserved. * * 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 com.google.android.apps.santatracker.games; import android.app.Activity; import android.content.DialogInterface; import android.content.Intent; import android.content.IntentSender; import android.os.Bundle; import android.support.v4.app.Fragment; import android.support.v4.app.FragmentActivity; import android.support.v4.app.FragmentManager; import android.support.v4.app.FragmentTransaction; import android.util.Log; import com.google.android.apps.santatracker.common.BuildConfig; import com.google.android.gms.common.ConnectionResult; import com.google.android.gms.common.GoogleApiAvailability; import com.google.android.gms.common.api.GoogleApiClient; import com.google.android.gms.games.Games; /** * Non-visible fragment to encapsulate Google Play Game Services logic. */ public class PlayGamesFragment extends Fragment implements GoogleApiClient.ConnectionCallbacks, GoogleApiClient.OnConnectionFailedListener{ private static final String TAG = "PlayGamesFragment"; private static final String FRAGMENT_TAG = "PlayGamesFragment_Tag"; /** Key to store mIsResolving in SharedPreferences. **/ private static final String KEY_IS_RESOLVING = "is_resolving"; /** Key to store mShouldResolve in SharedPreferences. **/ private static final String KEY_SHOULD_RESOLVE = "should_resolve"; /** Request code used for resolving Games sign-in failures. **/ private static final int RC_GAMES = 9001; /** Should debug-level log messages be printed? **/ private boolean mDebugLogEnabled = false; /** GoogleApiClient used for interacting with Play Game Services. **/ private GoogleApiClient mGamesApiClient; /** Is a resolution already in progress? **/ private boolean mIsResolving = false; /** Should connection failures be automatically resolved? **/ private boolean mShouldResolve = false; /** Listener for sign-in events. **/ private SignInListener mListener; /** * Get or create an instance of the Fragment attached to an Activity. * @param activity FragmentActivity to host the Fragment. * @param listener SignInListener to respond to changes in sign-in state. * @return instance of PlayGamesFragment. */ public static PlayGamesFragment getInstance(FragmentActivity activity, SignInListener listener) { FragmentManager fm = activity.getSupportFragmentManager(); FragmentTransaction ft = fm.beginTransaction(); PlayGamesFragment result = null; Fragment fragment = fm.findFragmentByTag(FRAGMENT_TAG); if (fragment == null) { result = new PlayGamesFragment(); ft.add(result, FRAGMENT_TAG).disallowAddToBackStack().commit(); } else { result = (PlayGamesFragment) fragment; } result.setListener(listener); return result; } @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); // Restore state of in-progress sign-in in the case of rotation or other // Activity recreation. if (savedInstanceState != null) { mIsResolving = savedInstanceState.getBoolean(KEY_IS_RESOLVING, false); mShouldResolve = savedInstanceState.getBoolean(KEY_SHOULD_RESOLVE, false); } } @Override public void onStart() { super.onStart(); mGamesApiClient.connect(); } @Override public void onStop() { super.onStop(); mGamesApiClient.disconnect(); } @Override public void onActivityCreated(Bundle savedInstanceState) { super.onActivityCreated(savedInstanceState); // Only log debug messages when enabled mDebugLogEnabled = BuildConfig.DEBUG; // Api client for interacting with Google Play Games mGamesApiClient = new GoogleApiClient.Builder(getActivity()) .addConnectionCallbacks(this) .addOnConnectionFailedListener(this) .addApi(Games.API, Games.GamesOptions.builder().build()) .addScope(Games.SCOPE_GAMES) .build(); } @Override public void onActivityResult(int requestCode, int resultCode, Intent data) { if (requestCode == RC_GAMES) { debugLog("onActivityResult:RC_GAMES:" + resultCode + ":" + data); // If the error resolution was not successful we should not resolve further. if (resultCode != Activity.RESULT_OK) { mShouldResolve = false; } mIsResolving = false; mGamesApiClient.connect(); } } @Override public void onConnected(Bundle bundle) { debugLog("onConnected:" + bundle); mShouldResolve = false; mListener.onSignInSucceeded(); } @Override public void onConnectionSuspended(int i) { debugLog("onConnectionSuspended:" + i); } @Override public void onConnectionFailed(ConnectionResult connectionResult) { debugLog("onConnectionFailed:" + connectionResult); if (!mIsResolving && mShouldResolve) { if (connectionResult.hasResolution()) { try { connectionResult.startResolutionForResult(getActivity(), RC_GAMES); mIsResolving = true; } catch (IntentSender.SendIntentException e) { debugLog("onConnectionFailed:SendIntentException:" + e.getMessage()); mIsResolving = false; mGamesApiClient.connect(); } } else { // Could not resolve the connection result, show the user an // error dialog. showErrorDialog(connectionResult); } } else { // Show the signed-out UI mListener.onSignInFailed(); } } /** * Show error dialog for Google Play Services errors that cannot be resolved. * @param connectionResult the connection result from onConnectionFailed. */ private void showErrorDialog(ConnectionResult connectionResult) { GoogleApiAvailability apiAvailability = GoogleApiAvailability.getInstance(); int resultCode = apiAvailability.isGooglePlayServicesAvailable(getActivity()); if (resultCode != ConnectionResult.SUCCESS) { if (apiAvailability.isUserResolvableError(resultCode)) { apiAvailability.getErrorDialog(getActivity(), resultCode, RC_GAMES, new DialogInterface.OnCancelListener() { @Override public void onCancel(DialogInterface dialog) { mShouldResolve = false; mListener.onSignInFailed(); } }).show(); } else { String errorString = apiAvailability.getErrorString(resultCode); debugLog("Google Play Services Error:" + connectionResult + ":" + errorString);; mShouldResolve = false; mListener.onSignInFailed(); } } } public boolean isSignedIn() { return (mGamesApiClient != null && mGamesApiClient.isConnected()); } public void beginUserInitiatedSignIn() { mShouldResolve = true; mGamesApiClient.connect(); } public GoogleApiClient getGamesApiClient() { return mGamesApiClient; } private void debugLog(String message) { if (!mDebugLogEnabled) { return; } Log.d(TAG, message); } private void setListener(SignInListener listener) { mListener = listener; } }