Cloud save: working implementation, no dialog to select your games yet

This commit is contained in:
Sergii Pylypenko
2014-07-09 20:50:16 +03:00
parent ed57fac3c9
commit 8e2ad620d8
18 changed files with 663 additions and 53 deletions

View File

@@ -39,4 +39,14 @@ class CloudSave
public void onActivityResult(int request, int response, Intent data) {
}
public boolean save(String filename, String saveId, String dialogTitle, String description, String imageFile, long playedTimeMs)
{
return false;
}
public boolean load(String filename, String saveId, String dialogTitle)
{
return false;
}
}

View File

@@ -80,6 +80,8 @@ import android.view.Display;
import android.text.InputType;
import android.util.Log;
import android.view.Surface;
import android.app.ProgressDialog;
public class MainActivity extends Activity
@@ -106,6 +108,8 @@ public class MainActivity extends Activity
_layout.setLayoutParams(new LinearLayout.LayoutParams(ViewGroup.LayoutParams.FILL_PARENT, ViewGroup.LayoutParams.FILL_PARENT));
_layout2 = new LinearLayout(this);
_layout2.setLayoutParams(new LinearLayout.LayoutParams(ViewGroup.LayoutParams.FILL_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT));
loadingDialog = new ProgressDialog(this);
loadingDialog.setMessage(getString(R.string.accessing_network));
final Semaphore loadedLibraries = new Semaphore(0);
@@ -220,7 +224,7 @@ public class MainActivity extends Activity
Intent intent = new Intent(this, DummyService.class);
startService(intent);
}
_cloudSave = new CloudSave(this);
cloudSave = new CloudSave(this);
}
public void setUpStatusLabel()
@@ -429,19 +433,19 @@ public class MainActivity extends Activity
@Override
protected void onStart() {
super.onStart();
_cloudSave.onStart();
cloudSave.onStart();
}
@Override
protected void onStop() {
super.onStart();
_cloudSave.onStop();
cloudSave.onStop();
}
@Override
public void onActivityResult(int request, int response, Intent data) {
super.onActivityResult(request, response, data);
_cloudSave.onActivityResult(request, response, data);
cloudSave.onActivityResult(request, response, data);
}
public void showScreenKeyboardWithoutTextInputField()
@@ -1235,7 +1239,8 @@ public class MainActivity extends Activity
private LinearLayout _layout = null;
private LinearLayout _layout2 = null;
private Advertisement _ad = null;
public CloudSave _cloudSave = null;
public CloudSave cloudSave = null;
public ProgressDialog loadingDialog = null;
private FrameLayout _videoLayout = null;
private EditText _screenKeyboard = null;

View File

@@ -834,6 +834,52 @@ class DemoRenderer extends GLSurfaceView_SDL.Renderer
context.requestNewAdvertisement();
}
public boolean cloudSave(String filename, String saveId, String dialogTitle, String description, String imageFile, long playedTimeMs)
{
context.runOnUiThread(new Runnable()
{
public void run()
{
context.loadingDialog.show();
}
});
boolean ret = context.cloudSave.save(filename, saveId, dialogTitle, description, imageFile, playedTimeMs);
context.runOnUiThread(new Runnable()
{
public void run()
{
context.loadingDialog.dismiss();
}
});
return ret;
}
public boolean cloudLoad(String filename, String saveId, String dialogTitle)
{
context.runOnUiThread(new Runnable()
{
public void run()
{
context.loadingDialog.show();
}
});
boolean ret = context.cloudSave.load(filename, saveId, dialogTitle);
context.runOnUiThread(new Runnable()
{
public void run()
{
context.loadingDialog.dismiss();
}
});
return ret;
}
private int PowerOf2(int i)
{
int value = 1;

View File

@@ -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() {

View File

@@ -2,6 +2,8 @@
grep '<string name=' values/strings.xml | while read str; do
if echo "$str" | grep 'translatable="false"' ; then continue; fi
var=`echo $str | sed 's/<string name=["]\([^"]*\).*/\1/'`
text=`echo $str | sed 's/<string name=["][^"]*["]>\([^<]*\).*/\1/'`
if [ "$var" = "app_name" ]; then

View File

@@ -188,4 +188,5 @@
<string name="gamehelper_app_misconfigured">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.</string>
<string name="gamehelper_license_failed">License check failed.</string>
<string name="gamehelper_unknown_error">Unknown error.</string>
<string name="accessing_network">Accessing network, please wait</string>
</resources>

View File

@@ -161,4 +161,5 @@
<string name="gamehelper_app_misconfigured">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.</string>
<string name="gamehelper_license_failed">License check failed.</string>
<string name="gamehelper_unknown_error">Unknown error.</string>
<string name="accessing_network">Accessing network, please wait</string>
</resources>

View File

@@ -160,4 +160,5 @@
<string name="gamehelper_app_misconfigured">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.</string>
<string name="gamehelper_license_failed">License check failed.</string>
<string name="gamehelper_unknown_error">Unknown error.</string>
<string name="accessing_network">Accessing network, please wait</string>
</resources>

View File

@@ -192,6 +192,8 @@
<string name="gamehelper_app_misconfigured">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.</string>
<string name="gamehelper_license_failed">License check failed.</string>
<string name="gamehelper_unknown_error">Unknown error.</string>
<string name="accessing_network">Accessing network, please wait</string>
<string name="google_play_game_services_app_id" translatable="false">==GOOGLEPLAYGAMESERVICES_APP_ID==</string>
</resources>