Cloud save: working implementation, no dialog to select your games yet
This commit is contained in:
@@ -19,8 +19,24 @@ package com.google.example.games.basegameutils;
|
||||
import android.content.Intent;
|
||||
import android.os.Bundle;
|
||||
import android.util.Log;
|
||||
import android.graphics.BitmapFactory;
|
||||
import android.graphics.Bitmap;
|
||||
|
||||
import java.io.*;
|
||||
|
||||
import com.google.android.gms.common.api.GoogleApiClient;
|
||||
import com.google.android.gms.common.api.ResultCallback;
|
||||
import com.google.android.gms.auth.GoogleAuthException;
|
||||
import com.google.android.gms.auth.GoogleAuthUtil;
|
||||
import com.google.android.gms.auth.UserRecoverableAuthException;
|
||||
import com.google.android.gms.common.Scopes;
|
||||
import com.google.android.gms.games.Games;
|
||||
import com.google.android.gms.games.GamesStatusCodes;
|
||||
import com.google.android.gms.games.snapshot.Snapshot;
|
||||
import com.google.android.gms.games.snapshot.SnapshotMetadata;
|
||||
import com.google.android.gms.games.snapshot.SnapshotMetadataBuffer;
|
||||
import com.google.android.gms.games.snapshot.SnapshotMetadataChange;
|
||||
import com.google.android.gms.games.snapshot.Snapshots;
|
||||
|
||||
public class CloudSave implements GameHelper.GameHelperListener {
|
||||
|
||||
@@ -40,54 +56,225 @@ public class CloudSave implements GameHelper.GameHelperListener {
|
||||
mHelper.setup(this);
|
||||
}
|
||||
|
||||
public GameHelper getGameHelper() {
|
||||
return mHelper;
|
||||
}
|
||||
|
||||
public void onStart() {
|
||||
public void onStart()
|
||||
{
|
||||
mHelper.onStart(parent);
|
||||
}
|
||||
|
||||
public void onStop() {
|
||||
public void onStop()
|
||||
{
|
||||
mHelper.onStop();
|
||||
}
|
||||
|
||||
public boolean save(String filename, String description, String imageFile)
|
||||
public void onActivityResult(int request, int response, Intent data)
|
||||
{
|
||||
mHelper.onActivityResult(request, response, data);
|
||||
}
|
||||
|
||||
public synchronized boolean save(String filename, String saveId, String dialogTitle, String description, String imageFile, long playedTimeMs)
|
||||
{
|
||||
Log.d("SDL", "CloudSave: save: file " + filename + " saveId " + saveId + " dialogTitle " + dialogTitle + " desc " + description + " imageFile " + imageFile + " playedTime " + playedTimeMs);
|
||||
|
||||
if( !signIn() )
|
||||
return false;
|
||||
|
||||
if( !filename.startsWith("/") )
|
||||
filename = Globals.DataDir + "/" + filename;
|
||||
if( imageFile.length() > 0 && !imageFile.startsWith("/") )
|
||||
imageFile = Globals.DataDir + "/" + imageFile;
|
||||
|
||||
try
|
||||
{
|
||||
if( saveId == null || saveId.length() == 0 )
|
||||
{
|
||||
Log.i("SDL", "CloudSave: save: user dialog is not supported yet");
|
||||
return false;
|
||||
}
|
||||
|
||||
Snapshots.OpenSnapshotResult result = Games.Snapshots.open(getApiClient(), saveId, true).await();
|
||||
Snapshot crapshot = processSnapshotOpenResult(result, 0);
|
||||
if( crapshot == null )
|
||||
return false;
|
||||
|
||||
crapshot.writeBytes(readFile(filename));
|
||||
|
||||
Bitmap bmp = BitmapFactory.decodeFile(imageFile);
|
||||
while( bmp != null && bmp.getByteCount() > Games.Snapshots.getMaxCoverImageSize(getApiClient()) )
|
||||
bmp = Bitmap.createScaledBitmap(bmp, bmp.getWidth() * 3 / 4, bmp.getHeight() * 3 / 4, true);
|
||||
|
||||
SnapshotMetadataChange.Builder metadataChange = new SnapshotMetadataChange.Builder()
|
||||
.setDescription(description)
|
||||
.setPlayedTimeMillis(playedTimeMs);
|
||||
if( bmp != null )
|
||||
metadataChange.setCoverImage(bmp);
|
||||
|
||||
Games.Snapshots.commitAndClose(getApiClient(), crapshot, metadataChange.build())
|
||||
.setResultCallback(new ResultCallback<Snapshots.CommitSnapshotResult>()
|
||||
{
|
||||
public void onResult(Snapshots.CommitSnapshotResult r)
|
||||
{
|
||||
Log.i("SDL", "CloudSave: save final net sync result: " + r.getStatus().toString());
|
||||
}
|
||||
});
|
||||
|
||||
Log.i("SDL", "CloudSave: save succeeded");
|
||||
return true;
|
||||
}
|
||||
catch(Exception e)
|
||||
{
|
||||
Log.i("SDL", "CloudSave: save failed: " + e.toString());
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public boolean load (String filename)
|
||||
public synchronized boolean load(String filename, String saveId, String dialogTitle)
|
||||
{
|
||||
Log.d("SDL", "CloudSave: load: file " + filename + " saveId " + saveId + " dialogTitle " + dialogTitle);
|
||||
|
||||
if( !signIn() )
|
||||
return false;
|
||||
|
||||
if( !filename.startsWith("/") )
|
||||
filename = Globals.DataDir + "/" + filename;
|
||||
|
||||
try
|
||||
{
|
||||
if( saveId == null || saveId.length() == 0 )
|
||||
{
|
||||
Log.i("SDL", "CloudSave: load: user dialog is not supported yet");
|
||||
return false;
|
||||
}
|
||||
|
||||
Snapshots.OpenSnapshotResult result = Games.Snapshots.open(getApiClient(), saveId, false).await();
|
||||
if (result.getStatus().getStatusCode() != GamesStatusCodes.STATUS_OK)
|
||||
{
|
||||
Log.i("SDL", "CloudSave: load: failed to load game " + saveId + ": " + result.getStatus());
|
||||
return false;
|
||||
}
|
||||
|
||||
boolean written = writeFile(filename, result.getSnapshot().readFully());
|
||||
Log.i("SDL", "CloudSave: load: status: " + written);
|
||||
return written;
|
||||
}
|
||||
catch(Exception e)
|
||||
{
|
||||
Log.i("SDL", "CloudSave: load failed: " + e.toString());
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public class loadDialogResult
|
||||
{
|
||||
public boolean status = false;
|
||||
public String filename = "";
|
||||
}
|
||||
|
||||
public loadDialogResult loadDialog(String filename, String dialogTitle)
|
||||
{
|
||||
loadDialogResult res = new loadDialogResult();
|
||||
res.status = false;
|
||||
res.filename = "";
|
||||
return res;
|
||||
}
|
||||
|
||||
// ===== Private API =====
|
||||
|
||||
public void onActivityResult(int request, int response, Intent data) {
|
||||
mHelper.onActivityResult(request, response, data);
|
||||
boolean signInSucceeded = false;
|
||||
boolean signInFailed = false;
|
||||
public boolean signIn()
|
||||
{
|
||||
//Log.i("SDL", "CloudSave: signIn()");
|
||||
if( !isSignedIn() )
|
||||
{
|
||||
signInSucceeded = false;
|
||||
signInFailed = false;
|
||||
Log.i("SDL", "CloudSave: beginUserInitiatedSignIn()");
|
||||
beginUserInitiatedSignIn();
|
||||
Log.i("SDL", "CloudSave: beginUserInitiatedSignIn() exit");
|
||||
while (!signInSucceeded && !signInFailed)
|
||||
{
|
||||
try { Thread.sleep(300); } catch( Exception e ) {}
|
||||
}
|
||||
return signInSucceeded;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
public void onSignInSucceeded() {
|
||||
Log.i("SDL", "CloudSave: onSignInSucceeded()");
|
||||
signInSucceeded = true;
|
||||
}
|
||||
|
||||
public void onSignInFailed() {
|
||||
Log.i("SDL", "CloudSave: onSignInFailed()");
|
||||
signInFailed = true;
|
||||
}
|
||||
|
||||
public Snapshot processSnapshotOpenResult(Snapshots.OpenSnapshotResult result, int retryCount)
|
||||
{
|
||||
Snapshot mResolvedSnapshot = null;
|
||||
retryCount++;
|
||||
int status = result.getStatus().getStatusCode();
|
||||
|
||||
Log.i("SDL", "CloudSave: processSnapshotOpenResult status: " + result.getStatus());
|
||||
|
||||
if (status == GamesStatusCodes.STATUS_OK) {
|
||||
return result.getSnapshot();
|
||||
} else if (status == GamesStatusCodes.STATUS_SNAPSHOT_CONTENTS_UNAVAILABLE) {
|
||||
return result.getSnapshot();
|
||||
} else if (status == GamesStatusCodes.STATUS_SNAPSHOT_CONFLICT) {
|
||||
Snapshot snapshot = result.getSnapshot();
|
||||
Snapshot conflictSnapshot = result.getConflictingSnapshot();
|
||||
|
||||
// Resolve between conflicts by selecting the newest of the conflicting snapshots.
|
||||
mResolvedSnapshot = snapshot;
|
||||
|
||||
if (snapshot.getMetadata().getPlayedTime() == conflictSnapshot.getMetadata().getPlayedTime()) {
|
||||
if (snapshot.getMetadata().getLastModifiedTimestamp() < conflictSnapshot.getMetadata().getLastModifiedTimestamp()) {
|
||||
mResolvedSnapshot = conflictSnapshot;
|
||||
}
|
||||
} else if (snapshot.getMetadata().getPlayedTime() < conflictSnapshot.getMetadata().getPlayedTime()) {
|
||||
mResolvedSnapshot = conflictSnapshot;
|
||||
}
|
||||
|
||||
Snapshots.OpenSnapshotResult resolveResult = Games.Snapshots.resolveConflict(
|
||||
getApiClient(), result.getConflictId(), mResolvedSnapshot)
|
||||
.await();
|
||||
|
||||
if (retryCount < 3) {
|
||||
return processSnapshotOpenResult(resolveResult, retryCount);
|
||||
} else {
|
||||
Log.i("SDL", "CloudSave: could not resolve snapshot conflict");
|
||||
}
|
||||
}
|
||||
Log.i("SDL", "CloudSave: could not get savegame snapshot");
|
||||
return null;
|
||||
}
|
||||
|
||||
static public byte[] readFile(String filename)
|
||||
{
|
||||
int len = (int)(new File(filename).length());
|
||||
if( len == 0 )
|
||||
return new byte[0];
|
||||
try
|
||||
{
|
||||
byte buf[] = new byte[len];
|
||||
if( new FileInputStream(filename).read(buf, 0, len) != len )
|
||||
return new byte[0];
|
||||
return buf;
|
||||
}
|
||||
catch( Exception e )
|
||||
{
|
||||
Log.i("SDL", "CloudSave: readFile() error: " + e.toString());
|
||||
}
|
||||
return new byte[0];
|
||||
}
|
||||
|
||||
static public boolean writeFile(String filename, byte[] data)
|
||||
{
|
||||
try
|
||||
{
|
||||
BufferedOutputStream out = new BufferedOutputStream(new FileOutputStream(filename));
|
||||
out.write(data, 0, data.length);
|
||||
out.close();
|
||||
return true;
|
||||
}
|
||||
catch( Exception e )
|
||||
{
|
||||
Log.i("SDL", "CloudSave: writeFile() error: " + e.toString() + " file " + filename);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public GameHelper getGameHelper() {
|
||||
return mHelper;
|
||||
}
|
||||
|
||||
public GoogleApiClient getApiClient() {
|
||||
|
||||
Reference in New Issue
Block a user