Support for linking with Google Play Services, also fixed Proguard config

This commit is contained in:
Sergii Pylypenko
2014-07-07 23:44:50 +03:00
parent d9209f01d7
commit 7b694f3d7a
16 changed files with 1660 additions and 98 deletions
@@ -0,0 +1,169 @@
/*
* 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 com.google.example.games.basegameutils;
import android.content.Intent;
import android.os.Bundle;
import android.util.Log;
import com.google.android.gms.common.api.GoogleApiClient;
/**
* Example base class for games. This implementation takes care of setting up
* the API client object and managing its lifecycle. Subclasses only need to
* override the @link{#onSignInSucceeded} and @link{#onSignInFailed} abstract
* methods. To initiate the sign-in flow when the user clicks the sign-in
* button, subclasses should call @link{#beginUserInitiatedSignIn}. By default,
* this class only instantiates the GoogleApiClient object. If the PlusClient or
* AppStateClient objects are also wanted, call the BaseGameActivity(int)
* constructor and specify the requested clients. For example, to request
* PlusClient and GamesClient, use BaseGameActivity(CLIENT_GAMES | CLIENT_PLUS).
* To request all available clients, use BaseGameActivity(CLIENT_ALL).
* Alternatively, you can also specify the requested clients via
* @link{#setRequestedClients}, but you must do so before @link{#onCreate}
* gets called, otherwise the call will have no effect.
*
* @author Bruno Oliveira (Google)
*/
public class CloudSave implements GameHelper.GameHelperListener {
// The game helper object. This class is mainly a wrapper around this object.
protected GameHelper mHelper;
// We expose these constants here because we don't want users of this class
// to have to know about GameHelper at all.
public static final int CLIENT_GAMES = GameHelper.CLIENT_GAMES;
public static final int CLIENT_APPSTATE = GameHelper.CLIENT_APPSTATE;
public static final int CLIENT_PLUS = GameHelper.CLIENT_PLUS;
public static final int CLIENT_ALL = GameHelper.CLIENT_ALL;
// Requested clients. By default, that's just the games client.
public int mRequestedClients = CLIENT_GAMES;
private final static String TAG = "BaseGameActivity";
public boolean mDebugLog = false;
MainActivity parent;
/** Constructs a BaseGameActivity with default client (GamesClient). */
public CloudSave(MainActivity p)
{
parent = p;
setRequestedClients(CLIENT_GAMES);
getGameHelper().setup(this);
/*
// Add the Drive API and scope to the builder:
GoogleApiClient.Builder builder = helper.getApiClientBuilder();
GoogleApiClient.Builder builder = new GoogleApiClient.Builder(parent, this, this);
builder.addScope(Drive.SCOPE_APPFOLDER);
builder.addApi(Drive.API);
*/
}
/**
* Sets the requested clients. The preferred way to set the requested clients is
* via the constructor, but this method is available if for some reason your code
* cannot do this in the constructor. This must be called before onCreate or getGameHelper()
* in order to have any effect. If called after onCreate()/getGameHelper(), this method
* is a no-op.
*
* @param requestedClients A combination of the flags CLIENT_GAMES, CLIENT_PLUS
* and CLIENT_APPSTATE, or CLIENT_ALL to request all available clients.
*/
public void setRequestedClients(int requestedClients) {
mRequestedClients = requestedClients;
}
public GameHelper getGameHelper() {
if (mHelper == null) {
mHelper = new GameHelper(parent, mRequestedClients);
mHelper.enableDebugLog(mDebugLog);
}
return mHelper;
}
public void onStart() {
mHelper.onStart(parent);
}
public void onStop() {
mHelper.onStop();
}
public void onActivityResult(int request, int response, Intent data) {
mHelper.onActivityResult(request, response, data);
}
public void onSignInSucceeded() {
// TODO
}
public void onSignInFailed() {
// TODO
}
public GoogleApiClient getApiClient() {
return mHelper.getApiClient();
}
public boolean isSignedIn() {
return mHelper.isSignedIn();
}
public void beginUserInitiatedSignIn() {
mHelper.beginUserInitiatedSignIn();
}
public void signOut() {
mHelper.signOut();
}
public void showAlert(String message) {
mHelper.makeSimpleDialog(message).show();
}
public void showAlert(String title, String message) {
mHelper.makeSimpleDialog(title, message).show();
}
public void enableDebugLog(boolean enabled) {
mDebugLog = true;
if (mHelper != null) {
mHelper.enableDebugLog(enabled);
}
}
public void enableDebugLog(boolean enabled, String tag) {
enableDebugLog(enabled);
}
public String getInvitationId() {
return mHelper.getInvitationId();
}
public void reconnectClient() {
mHelper.reconnectClient();
}
public boolean hasSignInError() {
return mHelper.hasSignInError();
}
public GameHelper.SignInFailureReason getSignInError() {
return mHelper.getSignInError();
}
}
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,182 @@
package com.google.example.games.basegameutils;
import android.app.Activity;
import android.content.Context;
import android.content.pm.PackageManager;
import android.content.pm.Signature;
import android.content.res.Resources;
import android.util.Log;
import com.google.android.gms.common.ConnectionResult;
import com.google.android.gms.games.GamesActivityResultCodes;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
/**
* Created by btco on 2/10/14.
*/
class GameHelperUtils {
public static final int R_UNKNOWN_ERROR = 0;
public static final int R_SIGN_IN_FAILED = 1;
public static final int R_APP_MISCONFIGURED = 2;
public static final int R_LICENSE_FAILED = 3;
private final static String[] FALLBACK_STRINGS = {
"*Unknown error.",
"*Failed to sign in. Please check your network connection and try again.",
"*The application is incorrectly configured. Check that the package name and signing certificate match the client ID created in Developer Console. Also, if the application is not yet published, check that the account you are trying to sign in with is listed as a tester account. See logs for more information.",
"*License check failed."
};
private final static int[] RES_IDS = {
R.string.gamehelper_unknown_error, R.string.gamehelper_sign_in_failed,
R.string.gamehelper_app_misconfigured, R.string.gamehelper_license_failed
};
static String activityResponseCodeToString(int respCode) {
switch (respCode) {
case Activity.RESULT_OK:
return "RESULT_OK";
case Activity.RESULT_CANCELED:
return "RESULT_CANCELED";
case GamesActivityResultCodes.RESULT_APP_MISCONFIGURED:
return "RESULT_APP_MISCONFIGURED";
case GamesActivityResultCodes.RESULT_LEFT_ROOM:
return "RESULT_LEFT_ROOM";
case GamesActivityResultCodes.RESULT_LICENSE_FAILED:
return "RESULT_LICENSE_FAILED";
case GamesActivityResultCodes.RESULT_RECONNECT_REQUIRED:
return "RESULT_RECONNECT_REQUIRED";
case GamesActivityResultCodes.RESULT_SIGN_IN_FAILED:
return "SIGN_IN_FAILED";
default:
return String.valueOf(respCode);
}
}
static String errorCodeToString(int errorCode) {
switch (errorCode) {
case ConnectionResult.DEVELOPER_ERROR:
return "DEVELOPER_ERROR(" + errorCode + ")";
case ConnectionResult.INTERNAL_ERROR:
return "INTERNAL_ERROR(" + errorCode + ")";
case ConnectionResult.INVALID_ACCOUNT:
return "INVALID_ACCOUNT(" + errorCode + ")";
case ConnectionResult.LICENSE_CHECK_FAILED:
return "LICENSE_CHECK_FAILED(" + errorCode + ")";
case ConnectionResult.NETWORK_ERROR:
return "NETWORK_ERROR(" + errorCode + ")";
case ConnectionResult.RESOLUTION_REQUIRED:
return "RESOLUTION_REQUIRED(" + errorCode + ")";
case ConnectionResult.SERVICE_DISABLED:
return "SERVICE_DISABLED(" + errorCode + ")";
case ConnectionResult.SERVICE_INVALID:
return "SERVICE_INVALID(" + errorCode + ")";
case ConnectionResult.SERVICE_MISSING:
return "SERVICE_MISSING(" + errorCode + ")";
case ConnectionResult.SERVICE_VERSION_UPDATE_REQUIRED:
return "SERVICE_VERSION_UPDATE_REQUIRED(" + errorCode + ")";
case ConnectionResult.SIGN_IN_REQUIRED:
return "SIGN_IN_REQUIRED(" + errorCode + ")";
case ConnectionResult.SUCCESS:
return "SUCCESS(" + errorCode + ")";
default:
return "Unknown error code " + errorCode;
}
}
static void printMisconfiguredDebugInfo(Context ctx) {
Log.w("GameHelper", "****");
Log.w("GameHelper", "****");
Log.w("GameHelper", "**** APP NOT CORRECTLY CONFIGURED TO USE GOOGLE PLAY GAME SERVICES");
Log.w("GameHelper", "**** This is usually caused by one of these reasons:");
Log.w("GameHelper", "**** (1) Your package name and certificate fingerprint do not match");
Log.w("GameHelper", "**** the client ID you registered in Developer Console.");
Log.w("GameHelper", "**** (2) Your App ID was incorrectly entered.");
Log.w("GameHelper", "**** (3) Your game settings have not been published and you are ");
Log.w("GameHelper", "**** trying to log in with an account that is not listed as");
Log.w("GameHelper", "**** a test account.");
Log.w("GameHelper", "****");
if (ctx == null) {
Log.w("GameHelper", "*** (no Context, so can't print more debug info)");
return;
}
Log.w("GameHelper", "**** To help you debug, here is the information about this app");
Log.w("GameHelper", "**** Package name : " + ctx.getPackageName());
Log.w("GameHelper", "**** Cert SHA1 fingerprint: " + getSHA1CertFingerprint(ctx));
Log.w("GameHelper", "**** App ID from : " + getAppIdFromResource(ctx));
Log.w("GameHelper", "****");
Log.w("GameHelper", "**** Check that the above information matches your setup in ");
Log.w("GameHelper", "**** Developer Console. Also, check that you're logging in with the");
Log.w("GameHelper", "**** right account (it should be listed in the Testers section if");
Log.w("GameHelper", "**** your project is not yet published).");
Log.w("GameHelper", "****");
Log.w("GameHelper", "**** For more information, refer to the troubleshooting guide:");
Log.w("GameHelper", "**** http://developers.google.com/games/services/android/troubleshooting");
}
static String getAppIdFromResource(Context ctx) {
try {
Resources res = ctx.getResources();
String pkgName = ctx.getPackageName();
int res_id = res.getIdentifier("app_id", "string", pkgName);
return res.getString(res_id);
} catch (Exception ex) {
ex.printStackTrace();
return "??? (failed to retrieve APP ID)";
}
}
static String getSHA1CertFingerprint(Context ctx) {
try {
Signature[] sigs = ctx.getPackageManager().getPackageInfo(
ctx.getPackageName(), PackageManager.GET_SIGNATURES).signatures;
if (sigs.length == 0) {
return "ERROR: NO SIGNATURE.";
} else if (sigs.length > 1) {
return "ERROR: MULTIPLE SIGNATURES";
}
byte[] digest = MessageDigest.getInstance("SHA1").digest(sigs[0].toByteArray());
StringBuilder hexString = new StringBuilder();
for (int i = 0; i < digest.length; ++i) {
if (i > 0) {
hexString.append(":");
}
byteToString(hexString, digest[i]);
}
return hexString.toString();
} catch (PackageManager.NameNotFoundException ex) {
ex.printStackTrace();
return "(ERROR: package not found)";
} catch (NoSuchAlgorithmException ex) {
ex.printStackTrace();
return "(ERROR: SHA1 algorithm not found)";
}
}
static void byteToString(StringBuilder sb, byte b) {
int unsigned_byte = b < 0 ? b + 256 : b;
int hi = unsigned_byte / 16;
int lo = unsigned_byte % 16;
sb.append("0123456789ABCDEF".substring(hi, hi + 1));
sb.append("0123456789ABCDEF".substring(lo, lo + 1));
}
static String getString(Context ctx, int whichString) {
whichString = whichString >= 0 && whichString < RES_IDS.length ? whichString : 0;
int resId = RES_IDS[whichString];
try {
return ctx.getString(resId);
} catch (Exception ex) {
ex.printStackTrace();
Log.w(GameHelper.TAG, "*** GameHelper could not found resource id #" + resId + ". " +
"This probably happened because you included it as a stand-alone JAR. " +
"BaseGameUtils should be compiled as a LIBRARY PROJECT, so that it can access " +
"its resources. Using a fallback string.");
return FALLBACK_STRINGS[whichString];
}
}
}