diff --git a/.gitignore b/.gitignore
index cffbd2e8..fdd42c17 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,4 +1,10 @@
-/.gradle/
+.gradle/
.settings/
bin/
+gen/
build/
+.project
+.DS_Store
+.idea/
+*.iml
+local.properties
diff --git a/BasicSamples/.gitignore b/BasicSamples/.gitignore
deleted file mode 100644
index ef624861..00000000
--- a/BasicSamples/.gitignore
+++ /dev/null
@@ -1,4 +0,0 @@
-.gradle/
-.idea/
-*.iml
-local.properties
diff --git a/BasicSamples/.gradle/1.6/taskArtifacts/cache.properties b/BasicSamples/.gradle/1.6/taskArtifacts/cache.properties
deleted file mode 100644
index bf2f2993..00000000
--- a/BasicSamples/.gradle/1.6/taskArtifacts/cache.properties
+++ /dev/null
@@ -1 +0,0 @@
-#Wed Dec 11 17:04:15 PST 2013
diff --git a/BasicSamples/.gradle/1.6/taskArtifacts/cache.properties.lock b/BasicSamples/.gradle/1.6/taskArtifacts/cache.properties.lock
deleted file mode 100644
index 40fdece9..00000000
--- a/BasicSamples/.gradle/1.6/taskArtifacts/cache.properties.lock
+++ /dev/null
@@ -1 +0,0 @@
-
\ No newline at end of file
diff --git a/BasicSamples/.gradle/1.6/taskArtifacts/fileHashes.bin b/BasicSamples/.gradle/1.6/taskArtifacts/fileHashes.bin
deleted file mode 100644
index 594d724b..00000000
Binary files a/BasicSamples/.gradle/1.6/taskArtifacts/fileHashes.bin and /dev/null differ
diff --git a/BasicSamples/.gradle/1.6/taskArtifacts/fileSnapshots.bin b/BasicSamples/.gradle/1.6/taskArtifacts/fileSnapshots.bin
deleted file mode 100644
index 5061886d..00000000
Binary files a/BasicSamples/.gradle/1.6/taskArtifacts/fileSnapshots.bin and /dev/null differ
diff --git a/BasicSamples/.gradle/1.6/taskArtifacts/outputFileStates.bin b/BasicSamples/.gradle/1.6/taskArtifacts/outputFileStates.bin
deleted file mode 100644
index d1f78e1f..00000000
Binary files a/BasicSamples/.gradle/1.6/taskArtifacts/outputFileStates.bin and /dev/null differ
diff --git a/BasicSamples/.gradle/1.6/taskArtifacts/taskArtifacts.bin b/BasicSamples/.gradle/1.6/taskArtifacts/taskArtifacts.bin
deleted file mode 100644
index 973ed6ba..00000000
Binary files a/BasicSamples/.gradle/1.6/taskArtifacts/taskArtifacts.bin and /dev/null differ
diff --git a/BasicSamples/BeGenerous/.gitignore b/BasicSamples/BeGenerous/.gitignore
deleted file mode 100644
index 47036e4a..00000000
--- a/BasicSamples/BeGenerous/.gitignore
+++ /dev/null
@@ -1,3 +0,0 @@
-/build/
-/bin/
-/gen/
diff --git a/BasicSamples/BeGenerous/build.gradle b/BasicSamples/BeGenerous/build.gradle
deleted file mode 100644
index b3ef39c9..00000000
--- a/BasicSamples/BeGenerous/build.gradle
+++ /dev/null
@@ -1,32 +0,0 @@
-apply plugin: 'android'
-
-android {
- compileSdkVersion 20
- buildToolsVersion '20'
-
- defaultConfig {
- minSdkVersion 9
- targetSdkVersion 20
- versionCode 1
- versionName "1.0"
- }
- buildTypes {
- release {
- minifyEnabled false
- proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.txt'
- }
- }
-}
-
-dependencies {
- compile project(':libraries:BaseGameUtils')
- compile 'com.android.support:appcompat-v7:20.0.+'
- compile 'com.android.support:support-v4:20.0.+'
- compile 'com.google.android.gms:play-services:5+'
-}
-
-buildscript {
- repositories {
- mavenCentral()
- }
-}
diff --git a/BasicSamples/BeGenerous/src/main/AndroidManifest.xml b/BasicSamples/BeGenerous/src/main/AndroidManifest.xml
deleted file mode 100644
index b1419e0c..00000000
--- a/BasicSamples/BeGenerous/src/main/AndroidManifest.xml
+++ /dev/null
@@ -1,72 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/BasicSamples/BeGenerous/src/main/java/com/google/example/games/bg/BeGenerousActivity.java b/BasicSamples/BeGenerous/src/main/java/com/google/example/games/bg/BeGenerousActivity.java
deleted file mode 100644
index 92ac19ba..00000000
--- a/BasicSamples/BeGenerous/src/main/java/com/google/example/games/bg/BeGenerousActivity.java
+++ /dev/null
@@ -1,558 +0,0 @@
-/* Copyright (C) 2014 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.bg;
-
-import java.io.IOException;
-import java.io.InputStream;
-import java.net.URL;
-import java.util.ArrayList;
-import java.util.HashMap;
-
-import android.app.Activity;
-import android.app.AlertDialog;
-import android.content.DialogInterface;
-import android.content.Intent;
-import android.graphics.Bitmap;
-import android.graphics.BitmapFactory;
-import android.os.AsyncTask;
-import android.os.Bundle;
-import android.util.Log;
-import android.view.View;
-import android.widget.ImageView;
-import android.widget.TextView;
-import android.widget.Toast;
-
-import com.google.android.gms.common.ConnectionResult;
-import com.google.android.gms.common.api.GoogleApiClient;
-import com.google.android.gms.common.api.PendingResult;
-import com.google.android.gms.common.api.ResultCallback;
-import com.google.android.gms.games.Game;
-import com.google.android.gms.games.Games;
-import com.google.android.gms.games.GamesActivityResultCodes;
-import com.google.android.gms.games.Player;
-import com.google.android.gms.games.request.GameRequest;
-import com.google.android.gms.games.request.GameRequestBuffer;
-import com.google.android.gms.games.request.OnRequestReceivedListener;
-import com.google.android.gms.games.request.Requests;
-import com.google.android.gms.games.request.Requests.LoadRequestsResult;
-import com.google.android.gms.games.request.Requests.UpdateRequestsResult;
-import com.google.android.gms.plus.Plus;
-import com.google.example.games.basegameutils.BaseGameUtils;
-
-/**
- * Be Generous. A sample game that sets up the Google Play game services API and
- * allows the user to click buttons to give gifts, request gifts, and accept
- * gifts. Win by being the most generous!
- *
- * @author Dan Galpin (Google) and Wolff Dobson (Google)
- */
-public class BeGenerousActivity extends Activity
- implements GoogleApiClient.ConnectionCallbacks, GoogleApiClient.OnConnectionFailedListener,
- View.OnClickListener {
-
- private static final String TAG = "BeGenerous";
-
- private static final int SHOW_INBOX = 1;
-
- private static final int SEND_GIFT_CODE = 2;
-
- private static final int SEND_REQUEST_CODE = 3;
-
- /** Default lifetime of a request, 1 week. */
- private static final int DEFAULT_LIFETIME = 7;
-
- /** Icon to be used to send gifts/requests */
- private Bitmap mGiftIcon;
-
- // Request code used to invoke sign in user interactions.
- private static final int RC_SIGN_IN = 9001;
-
- // Client used to interact with Google APIs.
- private GoogleApiClient mGoogleApiClient;
-
- // Are we currently resolving a connection failure?
- private boolean mResolvingConnectionFailure = false;
-
- // Has the user clicked the sign-in button?
- private boolean mSignInClicked = false;
-
- // Set to true to automatically start the sign in flow when the Activity starts.
- // Set to false to require the user to click the button in order to sign in.
- private boolean mAutoStartSignInFlow = true;
-
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- Log.d(TAG, "onCreate()");
-
- // Create the Google Api Client with access to Plus and Games
- mGoogleApiClient = new GoogleApiClient.Builder(this)
- .addConnectionCallbacks(this)
- .addOnConnectionFailedListener(this)
- .addApi(Plus.API).addScope(Plus.SCOPE_PLUS_LOGIN)
- .addApi(Games.API).addScope(Games.SCOPE_GAMES)
- .build();
-
- // Set up click listeners
- setContentView(R.layout.activity_main);
- findViewById(R.id.button_open_inbox).setOnClickListener(this);
- findViewById(R.id.button_send_gift).setOnClickListener(this);
- findViewById(R.id.button_send_request).setOnClickListener(this);
- findViewById(R.id.button_sign_in).setOnClickListener(this);
- findViewById(R.id.button_sign_out).setOnClickListener(this);
-
- mGiftIcon = BitmapFactory.decodeResource(getResources(),
- R.drawable.ic_send_gift);
- }
-
- // Shows the "sign in" bar (explanation and button).
- private void showSignInBar() {
- findViewById(R.id.sign_in_bar).setVisibility(View.VISIBLE);
- findViewById(R.id.sign_out_bar).setVisibility(View.GONE);
- ImageView vw = (ImageView) findViewById(R.id.avatar);
- vw.setImageBitmap(null);
- TextView name = (TextView)findViewById(R.id.playerName);
- name.setText("");
- TextView email = (TextView)findViewById((R.id.playerEmail));
- email.setText("");
-
- }
-
- // Shows the "sign out" bar (explanation and button).
- private void showSignOutBar() {
- findViewById(R.id.sign_in_bar).setVisibility(View.GONE);
- findViewById(R.id.sign_out_bar).setVisibility(View.VISIBLE);
-
- Player player = Games.Players.getCurrentPlayer(mGoogleApiClient);
- String url = player.getIconImageUrl();
- TextView name = (TextView)findViewById(R.id.playerName);
- name.setText(player.getDisplayName());
- if (url != null) {
- ImageView vw = (ImageView) findViewById(R.id.avatar);
-
- // load the image in the background.
- new DownloadImageTask(vw).execute(url);
- }
- String email = Plus.AccountApi.getAccountName(mGoogleApiClient);
- TextView emailView = (TextView)findViewById((R.id.playerEmail));
- emailView.setText(email);
- }
-
- /**
- * AsyncTask to download an image from a URL and set the image to the
- * ImageView that is passed in on the constructor.
- */
- class DownloadImageTask extends AsyncTask {
- ImageView bmImage;
-
- public DownloadImageTask(ImageView bmImage) {
- this.bmImage = bmImage;
- }
-
- @Override
- protected Bitmap doInBackground(String... strings) {
- Bitmap mIcon11 = null;
- String url = strings[0];
- try {
- InputStream in = new URL(url).openStream();
- mIcon11 = BitmapFactory.decodeStream(in);
- } catch (IOException e) {
- Log.e(TAG, e.getMessage());
- }
- return mIcon11;
- }
- protected void onPostExecute(Bitmap result) {
- bmImage.setImageBitmap(result);
- bmImage.setVisibility(View.VISIBLE);
- }
- }
-
- // Count GameRequests in a GameRequestBuffer that have not yet expired
- private int countNotExpired(GameRequestBuffer buf) {
- if (buf == null) {
- return 0;
- }
-
- int giftCount = 0;
- for (GameRequest gr : buf) {
- if (gr.getExpirationTimestamp() > System.currentTimeMillis()) {
- giftCount++;
- }
- }
- return giftCount;
- }
-
- // Called back after you load the current requests
- private final ResultCallback mLoadRequestsCallback =
- new ResultCallback() {
-
- @Override
- public void onResult(LoadRequestsResult result) {
- int giftCount = countNotExpired(result.getRequests(GameRequest.TYPE_GIFT));
- int wishCount = countNotExpired(result.getRequests(GameRequest.TYPE_WISH));
-
- ((TextView) findViewById(R.id.tv_gift_count)).setText(String
- .format(getString(R.string.gift_count), giftCount));
- ((TextView) findViewById(R.id.tv_request_count)).setText(String
- .format(getString(R.string.request_count), wishCount));
- }
-
- };
-
- // Changes the numbers at the top of the layout
- private void updateRequestCounts() {
- PendingResult result = Games.Requests
- .loadRequests(mGoogleApiClient,
- Requests.REQUEST_DIRECTION_INBOUND,
- GameRequest.TYPE_ALL,
- Requests.SORT_ORDER_EXPIRING_SOON_FIRST);
- result.setResultCallback(mLoadRequestsCallback);
- }
-
- // This shows how to set up a listener for requests received. It is not
- // necessary; it only is useful if you do not want the default notifications
- // to happen when someone sends a request to someone.
- private final OnRequestReceivedListener mRequestListener = new OnRequestReceivedListener() {
-
- /*
- * (non-Javadoc)
- *
- * @see com.google.android.gms.games.request.OnRequestReceivedListener#
- * onRequestReceived(com.google.android.gms.games.request.GameRequest)
- */
- @Override
- public void onRequestReceived(GameRequest request) {
- int requestStringResource;
- switch (request.getType()) {
- case GameRequest.TYPE_GIFT:
- requestStringResource = R.string.new_gift_received;
- break;
- case GameRequest.TYPE_WISH:
- requestStringResource = R.string.new_request_received;
- break;
- default:
- return;
- }
- Toast.makeText(BeGenerousActivity.this, requestStringResource,
- Toast.LENGTH_LONG).show();
- updateRequestCounts();
- }
-
- /*
- * (non-Javadoc)
- *
- * @see com.google.android.gms.games.request.OnRequestReceivedListener#
- * onRequestRemoved(java.lang.String)
- */
- @Override
- public void onRequestRemoved(String requestId) {
- updateRequestCounts();
- }
- };
-
-
- @Override
- public void onConnected(Bundle connectionHint) {
- Log.d(TAG, "onConnected() called. Sign in successful!");
- showSignOutBar();
- // This is *NOT* required; if you do not register a handler for
- // request events, you will get standard notifications instead.
- Games.Requests.registerRequestListener(mGoogleApiClient, mRequestListener);
-
- if (connectionHint != null) {
-
- ArrayList requests;
- // Do we have any requests pending? (getGameRequestsFromBundle never returns null
- requests = Games.Requests.getGameRequestsFromBundle(connectionHint);
- if (!requests.isEmpty()) {
- // We have requests in onConnected's connectionHint.
- Log.d(TAG, "onConnected: connection hint has " + requests.size() + " request(s)");
- }
- Log.d(TAG, "===========\nRequests count " + requests.size());
- // Use regular handler
- handleRequests(requests);
- }
-
- // Our sample displays the request counts.
- updateRequestCounts();
- }
-
- @Override
- public void onConnectionSuspended(int i) {
- Log.d(TAG, "onConnectionSuspended() called. Trying to reconnect.");
- mGoogleApiClient.connect();
- }
-
- @Override
- public void onConnectionFailed(ConnectionResult connectionResult) {
- Log.d(TAG, "onConnectionFailed() called, result: " + connectionResult);
-
- if (mResolvingConnectionFailure) {
- Log.d(TAG, "onConnectionFailed() ignoring connection failure; already resolving.");
- return;
- }
-
- if (mSignInClicked || mAutoStartSignInFlow) {
- mAutoStartSignInFlow = false;
- mSignInClicked = false;
- mResolvingConnectionFailure = BaseGameUtils
- .resolveConnectionFailure(this, mGoogleApiClient,
- connectionResult, RC_SIGN_IN, getString(R.string.signin_other_error));
- }
- showSignInBar();
- }
-
- /**
- * Show a send gift or send wish request using startActivityForResult.
- *
- * @param type
- * the type of GameRequest (gift or wish) to show
- */
- private void showSendIntent(int type) {
- // Make sure we have a valid API client.
- if (mGoogleApiClient != null && mGoogleApiClient.isConnected()) {
-
- String description;
- int intentCode;
- Bitmap icon;
- switch (type) {
- case GameRequest.TYPE_GIFT:
- description = getString(R.string.send_gift_description);
- intentCode = SEND_GIFT_CODE;
- icon = mGiftIcon;
- break;
- case GameRequest.TYPE_WISH:
- description = getString(R.string.send_request_description);
- intentCode = SEND_REQUEST_CODE;
- icon = mGiftIcon;
- break;
- default:
- return;
- }
- Intent intent = Games.Requests.getSendIntent(mGoogleApiClient, type,
- "".getBytes(), DEFAULT_LIFETIME, icon, description);
- startActivityForResult(intent, intentCode);
- }
- }
-
- private String getRequestsString(ArrayList requests) {
- if (requests.size() == 0) {
- return "You have no requests to accept.";
- }
-
- if (requests.size() == 1) {
- return "Do you want to accept this request from "
- + requests.get(0).getSender().getDisplayName() + "?";
- }
-
- StringBuffer retVal = new StringBuffer(
- "Do you want to accept the following requests?\n\n");
-
- for (GameRequest request : requests) {
- retVal.append(" A "
- + (request.getType() == GameRequest.TYPE_GIFT ? "gift"
- : "game request") + " from "
- + request.getSender().getDisplayName() + "\n");
- }
-
- return retVal.toString();
- }
-
- // Actually accepts the requests
- private void acceptRequests(ArrayList requests) {
- // Attempt to accept these requests.
- ArrayList requestIds = new ArrayList();
-
- /**
- * Map of cached game request ID to its corresponding game request
- * object.
- */
- final HashMap gameRequestMap = new HashMap();
-
- // Cache the requests.
- for (GameRequest request : requests) {
- String requestId = request.getRequestId();
- requestIds.add(requestId);
- gameRequestMap.put(requestId, request);
-
- Log.d(TAG, "Processing request " + requestId);
- }
- // Accept the requests.
- Games.Requests.acceptRequests(mGoogleApiClient, requestIds).setResultCallback(
- new ResultCallback() {
- @Override
- public void onResult(UpdateRequestsResult result) {
- int numGifts = 0;
- int numRequests = 0;
- // Scan each result outcome.
- for (String requestId : result.getRequestIds()) {
- // We must have a local cached copy of the request
- // and the request needs to be a
- // success in order to continue.
- if (!gameRequestMap.containsKey(requestId)
- || result.getRequestOutcome(requestId) != Requests.REQUEST_UPDATE_OUTCOME_SUCCESS) {
- continue;
- }
- // Update succeeded here. Find the type of request
- // and act accordingly. For wishes, a
- // responding gift will be automatically sent.
- switch (gameRequestMap.get(requestId).getType()) {
- case GameRequest.TYPE_GIFT:
- // Toast the player!
- ++numGifts;
- break;
- case GameRequest.TYPE_WISH:
- ++numRequests;
- break;
- }
- }
-
- if (numGifts != 0) {
- // Toast our gifts.
- Toast.makeText(
- BeGenerousActivity.this,
- String.format(
- getString(R.string.gift_toast),
- numGifts), Toast.LENGTH_LONG)
- .show();
- }
- if (numGifts != 0 || numRequests != 0) {
- // if the user accepted any gifts or requests,
- // update
- // the displayed counts
- updateRequestCounts();
- }
- }
- });
-
- }
-
- // Deal with any requests that are incoming, either from a bundle from the
- // app starting via notification, or from the inbox. Players should give
- // explicit approval to accept any gift or request, so we pop up a dialog.
- private void handleRequests(ArrayList requests) {
- if (requests == null) {
- return;
- }
-
- // Must have final for anonymous function
- final ArrayList theRequests = requests;
-
- AlertDialog.Builder builder = new AlertDialog.Builder(this);
- builder.setMessage(getRequestsString(requests))
- .setPositiveButton("Absolutely!",
- new DialogInterface.OnClickListener() {
- @Override
- public void onClick(DialogInterface dialog, int id) {
- acceptRequests(theRequests);
- }
- })
- .setNegativeButton("No thanks",
- new DialogInterface.OnClickListener() {
- @Override
- public void onClick(DialogInterface dialog, int id) {
- // Do nothing---requests will remain un-created.
- }
- });
- // Create the AlertDialog object and return it
- builder.create().show();
-
- }
-
- // Response to inbox check
- @Override
- public void onActivityResult(int requestCode, int resultCode, Intent data) {
- switch (requestCode) {
- case SEND_REQUEST_CODE:
- if (resultCode == GamesActivityResultCodes.RESULT_SEND_REQUEST_FAILED) {
- Toast.makeText(this, "FAILED TO SEND REQUEST!",
- Toast.LENGTH_LONG).show();
- }
- break;
- case SEND_GIFT_CODE:
- if (resultCode == GamesActivityResultCodes.RESULT_SEND_REQUEST_FAILED) {
- Toast.makeText(this, "FAILED TO SEND GIFT!", Toast.LENGTH_LONG)
- .show();
- }
- break;
- case SHOW_INBOX:
- if (resultCode == Activity.RESULT_OK && data != null) {
- handleRequests(Games.Requests
- .getGameRequestsFromInboxResponse(data));
- } else {
- Log.e(TAG, "Failed to process inbox result: resultCode = "
- + resultCode + ", data = "
- + (data == null ? "null" : "valid"));
- }
- break;
- case RC_SIGN_IN:
- Log.d(TAG, "onActivityResult with requestCode == RC_SIGN_IN, responseCode="
- + resultCode + ", intent=" + data);
- mSignInClicked = false;
- mResolvingConnectionFailure = false;
- if (resultCode == RESULT_OK) {
- mGoogleApiClient.connect();
- } else {
- BaseGameUtils.showActivityResultError(this, requestCode, resultCode, R.string.signin_other_error);
- }
- break;
- }
- super.onActivityResult(requestCode, resultCode, data);
- }
-
- @Override
- public void onClick(View view) {
- switch (view.getId()) {
- case R.id.button_sign_in:
- // Check to see the developer who's running this sample code read the instructions :-)
- // NOTE: this check is here only because this is a sample! Don't include this
- // check in your actual production app.
- if (!BaseGameUtils.verifySampleSetup(this, R.string.app_id)) {
- Log.w(TAG, "*** Warning: setup problems detected. Sign in may not work!");
- }
-
- // start the sign-in flow
- Log.d(TAG, "Sign-in button clicked");
- mSignInClicked = true;
- mGoogleApiClient.connect();
- break;
- case R.id.button_sign_out:
- // sign out.
- Log.d(TAG, "Sign-out button clicked");
- mSignInClicked = false;
- Games.signOut(mGoogleApiClient);
- mGoogleApiClient.disconnect();
- showSignInBar();
- break;
- case R.id.button_send_gift:
- // send gift!
- showSendIntent(GameRequest.TYPE_GIFT);
- break;
- case R.id.button_send_request:
- // request gift!
- showSendIntent(GameRequest.TYPE_WISH);
- break;
- case R.id.button_open_inbox:
- // show inbox!
- if (mGoogleApiClient != null && mGoogleApiClient.isConnected()) {
- startActivityForResult(
- Games.Requests.getInboxIntent(mGoogleApiClient),
- SHOW_INBOX);
- }
- break;
- }
- }
-}
diff --git a/BasicSamples/BeGenerous/src/main/res/drawable-hdpi/ic_launcher.png b/BasicSamples/BeGenerous/src/main/res/drawable-hdpi/ic_launcher.png
deleted file mode 100644
index 1da0110a..00000000
Binary files a/BasicSamples/BeGenerous/src/main/res/drawable-hdpi/ic_launcher.png and /dev/null differ
diff --git a/BasicSamples/BeGenerous/src/main/res/drawable-hdpi/ic_open_inbox.png b/BasicSamples/BeGenerous/src/main/res/drawable-hdpi/ic_open_inbox.png
deleted file mode 100644
index bd490e2c..00000000
Binary files a/BasicSamples/BeGenerous/src/main/res/drawable-hdpi/ic_open_inbox.png and /dev/null differ
diff --git a/BasicSamples/BeGenerous/src/main/res/drawable-hdpi/ic_send_gift.png b/BasicSamples/BeGenerous/src/main/res/drawable-hdpi/ic_send_gift.png
deleted file mode 100644
index a40fe505..00000000
Binary files a/BasicSamples/BeGenerous/src/main/res/drawable-hdpi/ic_send_gift.png and /dev/null differ
diff --git a/BasicSamples/BeGenerous/src/main/res/drawable-hdpi/ic_send_request.png b/BasicSamples/BeGenerous/src/main/res/drawable-hdpi/ic_send_request.png
deleted file mode 100644
index fcfdd74d..00000000
Binary files a/BasicSamples/BeGenerous/src/main/res/drawable-hdpi/ic_send_request.png and /dev/null differ
diff --git a/BasicSamples/BeGenerous/src/main/res/drawable-mdpi/ic_launcher.png b/BasicSamples/BeGenerous/src/main/res/drawable-mdpi/ic_launcher.png
deleted file mode 100644
index 3d4811f6..00000000
Binary files a/BasicSamples/BeGenerous/src/main/res/drawable-mdpi/ic_launcher.png and /dev/null differ
diff --git a/BasicSamples/BeGenerous/src/main/res/drawable-mdpi/ic_open_inbox.png b/BasicSamples/BeGenerous/src/main/res/drawable-mdpi/ic_open_inbox.png
deleted file mode 100644
index 470b67ef..00000000
Binary files a/BasicSamples/BeGenerous/src/main/res/drawable-mdpi/ic_open_inbox.png and /dev/null differ
diff --git a/BasicSamples/BeGenerous/src/main/res/drawable-mdpi/ic_send_gift.png b/BasicSamples/BeGenerous/src/main/res/drawable-mdpi/ic_send_gift.png
deleted file mode 100644
index 98492720..00000000
Binary files a/BasicSamples/BeGenerous/src/main/res/drawable-mdpi/ic_send_gift.png and /dev/null differ
diff --git a/BasicSamples/BeGenerous/src/main/res/drawable-mdpi/ic_send_request.png b/BasicSamples/BeGenerous/src/main/res/drawable-mdpi/ic_send_request.png
deleted file mode 100644
index a3fda387..00000000
Binary files a/BasicSamples/BeGenerous/src/main/res/drawable-mdpi/ic_send_request.png and /dev/null differ
diff --git a/BasicSamples/BeGenerous/src/main/res/drawable-xhdpi/ic_launcher.png b/BasicSamples/BeGenerous/src/main/res/drawable-xhdpi/ic_launcher.png
deleted file mode 100644
index 1549781f..00000000
Binary files a/BasicSamples/BeGenerous/src/main/res/drawable-xhdpi/ic_launcher.png and /dev/null differ
diff --git a/BasicSamples/BeGenerous/src/main/res/drawable-xhdpi/ic_open_inbox.png b/BasicSamples/BeGenerous/src/main/res/drawable-xhdpi/ic_open_inbox.png
deleted file mode 100644
index b47038fa..00000000
Binary files a/BasicSamples/BeGenerous/src/main/res/drawable-xhdpi/ic_open_inbox.png and /dev/null differ
diff --git a/BasicSamples/BeGenerous/src/main/res/drawable-xhdpi/ic_send_gift.png b/BasicSamples/BeGenerous/src/main/res/drawable-xhdpi/ic_send_gift.png
deleted file mode 100644
index 5ff53371..00000000
Binary files a/BasicSamples/BeGenerous/src/main/res/drawable-xhdpi/ic_send_gift.png and /dev/null differ
diff --git a/BasicSamples/BeGenerous/src/main/res/drawable-xhdpi/ic_send_request.png b/BasicSamples/BeGenerous/src/main/res/drawable-xhdpi/ic_send_request.png
deleted file mode 100644
index 72cf7a8c..00000000
Binary files a/BasicSamples/BeGenerous/src/main/res/drawable-xhdpi/ic_send_request.png and /dev/null differ
diff --git a/BasicSamples/BeGenerous/src/main/res/drawable-xxhdpi/ic_launcher.png b/BasicSamples/BeGenerous/src/main/res/drawable-xxhdpi/ic_launcher.png
deleted file mode 100644
index 39cd9b73..00000000
Binary files a/BasicSamples/BeGenerous/src/main/res/drawable-xxhdpi/ic_launcher.png and /dev/null differ
diff --git a/BasicSamples/BeGenerous/src/main/res/drawable-xxhdpi/ic_open_inbox.png b/BasicSamples/BeGenerous/src/main/res/drawable-xxhdpi/ic_open_inbox.png
deleted file mode 100644
index 62b6b629..00000000
Binary files a/BasicSamples/BeGenerous/src/main/res/drawable-xxhdpi/ic_open_inbox.png and /dev/null differ
diff --git a/BasicSamples/BeGenerous/src/main/res/drawable-xxhdpi/ic_send_gift.png b/BasicSamples/BeGenerous/src/main/res/drawable-xxhdpi/ic_send_gift.png
deleted file mode 100644
index 112e9156..00000000
Binary files a/BasicSamples/BeGenerous/src/main/res/drawable-xxhdpi/ic_send_gift.png and /dev/null differ
diff --git a/BasicSamples/BeGenerous/src/main/res/drawable-xxhdpi/ic_send_request.png b/BasicSamples/BeGenerous/src/main/res/drawable-xxhdpi/ic_send_request.png
deleted file mode 100644
index 848be1d8..00000000
Binary files a/BasicSamples/BeGenerous/src/main/res/drawable-xxhdpi/ic_send_request.png and /dev/null differ
diff --git a/BasicSamples/BeGenerous/src/main/res/drawable-xxxhdpi/ic_launcher.png b/BasicSamples/BeGenerous/src/main/res/drawable-xxxhdpi/ic_launcher.png
deleted file mode 100644
index 447a8b2e..00000000
Binary files a/BasicSamples/BeGenerous/src/main/res/drawable-xxxhdpi/ic_launcher.png and /dev/null differ
diff --git a/BasicSamples/BeGenerous/src/main/res/drawable-xxxhdpi/ic_open_inbox.png b/BasicSamples/BeGenerous/src/main/res/drawable-xxxhdpi/ic_open_inbox.png
deleted file mode 100644
index 05753b5f..00000000
Binary files a/BasicSamples/BeGenerous/src/main/res/drawable-xxxhdpi/ic_open_inbox.png and /dev/null differ
diff --git a/BasicSamples/BeGenerous/src/main/res/drawable-xxxhdpi/ic_send_gift.png b/BasicSamples/BeGenerous/src/main/res/drawable-xxxhdpi/ic_send_gift.png
deleted file mode 100644
index e667b603..00000000
Binary files a/BasicSamples/BeGenerous/src/main/res/drawable-xxxhdpi/ic_send_gift.png and /dev/null differ
diff --git a/BasicSamples/BeGenerous/src/main/res/drawable-xxxhdpi/ic_send_request.png b/BasicSamples/BeGenerous/src/main/res/drawable-xxxhdpi/ic_send_request.png
deleted file mode 100644
index 73cbe328..00000000
Binary files a/BasicSamples/BeGenerous/src/main/res/drawable-xxxhdpi/ic_send_request.png and /dev/null differ
diff --git a/BasicSamples/BeGenerous/src/main/res/layout/activity_main.xml b/BasicSamples/BeGenerous/src/main/res/layout/activity_main.xml
deleted file mode 100644
index 1eacf5c4..00000000
--- a/BasicSamples/BeGenerous/src/main/res/layout/activity_main.xml
+++ /dev/null
@@ -1,137 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/BasicSamples/BeGenerous/src/main/res/values-v11/styles.xml b/BasicSamples/BeGenerous/src/main/res/values-v11/styles.xml
deleted file mode 100644
index 3d45cb70..00000000
--- a/BasicSamples/BeGenerous/src/main/res/values-v11/styles.xml
+++ /dev/null
@@ -1,28 +0,0 @@
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/BasicSamples/BeGenerous/src/main/res/values-v14/styles.xml b/BasicSamples/BeGenerous/src/main/res/values-v14/styles.xml
deleted file mode 100644
index 9e1013d7..00000000
--- a/BasicSamples/BeGenerous/src/main/res/values-v14/styles.xml
+++ /dev/null
@@ -1,29 +0,0 @@
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/BasicSamples/BeGenerous/src/main/res/values/ids.xml b/BasicSamples/BeGenerous/src/main/res/values/ids.xml
deleted file mode 100644
index e1339fcf..00000000
--- a/BasicSamples/BeGenerous/src/main/res/values/ids.xml
+++ /dev/null
@@ -1,21 +0,0 @@
-
-
-
-
-
- ReplaceMe
-
diff --git a/BasicSamples/BeGenerous/src/main/res/values/strings.xml b/BasicSamples/BeGenerous/src/main/res/values/strings.xml
deleted file mode 100644
index cbd81f7b..00000000
--- a/BasicSamples/BeGenerous/src/main/res/values/strings.xml
+++ /dev/null
@@ -1,44 +0,0 @@
-
-
-
-
- Signing in with Google
- Signing out
- Be Generous
- Sign with Google to send and receive gifts!
- You are signed in with Google.
- Sign Out
- Click me!
- Victory
- OK! You won!
- Open Inbox
- Send Gift
- A Generous Gift
- Send Request
- A Generous Gift
- Gifts Received: %d
- New Gift Received
- New Request Received
- Incoming Gifts/Requests
- …
- Gift Icon
- Request Icon
- Incoming: %d
- Incoming: %d
- There was an issue with sign in. Please try again later.
-
-
diff --git a/BasicSamples/BeGenerous/src/main/res/values/styles.xml b/BasicSamples/BeGenerous/src/main/res/values/styles.xml
deleted file mode 100644
index e4a79ada..00000000
--- a/BasicSamples/BeGenerous/src/main/res/values/styles.xml
+++ /dev/null
@@ -1,86 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/BasicSamples/ButtonClicker/.gitignore b/BasicSamples/ButtonClicker/.gitignore
deleted file mode 100644
index 9006481f..00000000
--- a/BasicSamples/ButtonClicker/.gitignore
+++ /dev/null
@@ -1,4 +0,0 @@
-/bin/
-/gen/
-*.iml
-/build/
diff --git a/BasicSamples/ButtonClicker/build.gradle b/BasicSamples/ButtonClicker/build.gradle
deleted file mode 100644
index ae95ed23..00000000
--- a/BasicSamples/ButtonClicker/build.gradle
+++ /dev/null
@@ -1,32 +0,0 @@
-apply plugin: 'android'
-
-android {
- compileSdkVersion 20
- buildToolsVersion '20'
-
- defaultConfig {
- minSdkVersion 9
- targetSdkVersion 20
- versionCode 1
- versionName "1.0"
- }
- buildTypes {
- release {
- minifyEnabled false
- proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.txt'
- }
- }
-}
-
-dependencies {
- compile project(':libraries:BaseGameUtils')
- compile 'com.android.support:support-v4:20.0.+'
- compile 'com.android.support:appcompat-v7:20.0.+'
- compile 'com.google.android.gms:play-services:5+'
-}
-
-buildscript {
- repositories {
- mavenCentral()
- }
-}
diff --git a/BasicSamples/ButtonClicker/src/main/AndroidManifest.xml b/BasicSamples/ButtonClicker/src/main/AndroidManifest.xml
deleted file mode 100644
index 7ead39d2..00000000
--- a/BasicSamples/ButtonClicker/src/main/AndroidManifest.xml
+++ /dev/null
@@ -1,48 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/BasicSamples/ButtonClicker/src/main/java/com/google/example/games/bc/MainActivity.java b/BasicSamples/ButtonClicker/src/main/java/com/google/example/games/bc/MainActivity.java
deleted file mode 100644
index d0ae632d..00000000
--- a/BasicSamples/ButtonClicker/src/main/java/com/google/example/games/bc/MainActivity.java
+++ /dev/null
@@ -1,885 +0,0 @@
-/* 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.bc;
-
-import android.app.Activity;
-import android.content.Intent;
-import android.os.Bundle;
-import android.os.Handler;
-import android.util.Log;
-import android.view.KeyEvent;
-import android.view.View;
-import android.view.WindowManager;
-import android.widget.TextView;
-
-import com.google.android.gms.common.ConnectionResult;
-import com.google.android.gms.common.api.GoogleApiClient;
-import com.google.android.gms.games.Games;
-import com.google.android.gms.games.GamesStatusCodes;
-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.OnInvitationReceivedListener;
-import com.google.android.gms.games.multiplayer.Participant;
-import com.google.android.gms.games.multiplayer.realtime.RealTimeMessage;
-import com.google.android.gms.games.multiplayer.realtime.RealTimeMessageReceivedListener;
-import com.google.android.gms.games.multiplayer.realtime.Room;
-import com.google.android.gms.games.multiplayer.realtime.RoomConfig;
-import com.google.android.gms.games.multiplayer.realtime.RoomStatusUpdateListener;
-import com.google.android.gms.games.multiplayer.realtime.RoomUpdateListener;
-import com.google.android.gms.plus.Plus;
-
-import com.google.example.games.basegameutils.BaseGameUtils;
-
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-
-/**
- * Button Clicker 2000. A minimalistic game showing the multiplayer features of
- * the Google Play game services API. The objective of this game is clicking a
- * button. Whoever clicks the button the most times within a 20 second interval
- * wins. It's that simple. This game can be played with 2, 3 or 4 players. The
- * code is organized in sections in order to make understanding as clear as
- * possible. We start with the integration section where we show how the game
- * is integrated with the Google Play game services API, then move on to
- * game-specific UI and logic.
- *
- * INSTRUCTIONS: To run this sample, please set up
- * a project in the Developer Console. Then, place your app ID on
- * res/values/ids.xml. Also, change the package name to the package name you
- * used to create the client ID in Developer Console. Make sure you sign the
- * APK with the certificate whose fingerprint you entered in Developer Console
- * when creating your Client Id.
- *
- * @author Bruno Oliveira (btco), 2013-04-26
- */
-public class MainActivity extends Activity
- implements GoogleApiClient.ConnectionCallbacks, GoogleApiClient.OnConnectionFailedListener,
- View.OnClickListener, RealTimeMessageReceivedListener,
- RoomStatusUpdateListener, RoomUpdateListener, OnInvitationReceivedListener {
-
- /*
- * API INTEGRATION SECTION. This section contains the code that integrates
- * the game with the Google Play game services API.
- */
-
- final static String TAG = "ButtonClicker2000";
-
- // Request codes for the UIs that we show with startActivityForResult:
- final static int RC_SELECT_PLAYERS = 10000;
- final static int RC_INVITATION_INBOX = 10001;
- final static int RC_WAITING_ROOM = 10002;
-
- // Request code used to invoke sign in user interactions.
- private static final int RC_SIGN_IN = 9001;
-
- // Client used to interact with Google APIs.
- private GoogleApiClient mGoogleApiClient;
-
- // Are we currently resolving a connection failure?
- private boolean mResolvingConnectionFailure = false;
-
- // Has the user clicked the sign-in button?
- private boolean mSignInClicked = false;
-
- // Set to true to automatically start the sign in flow when the Activity starts.
- // Set to false to require the user to click the button in order to sign in.
- private boolean mAutoStartSignInFlow = true;
-
- // Room ID where the currently active game is taking place; null if we're
- // not playing.
- String mRoomId = null;
-
- // Are we playing in multiplayer mode?
- boolean mMultiplayer = false;
-
- // The participants in the currently active game
- ArrayList mParticipants = null;
-
- // My participant ID in the currently active game
- String mMyId = null;
-
- // If non-null, this is the id of the invitation we received via the
- // invitation listener
- String mIncomingInvitationId = null;
-
- // Message buffer for sending messages
- byte[] mMsgBuf = new byte[2];
-
- @Override
- public void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.activity_main);
-
- // Create the Google Api Client with access to Plus and Games
- mGoogleApiClient = new GoogleApiClient.Builder(this)
- .addConnectionCallbacks(this)
- .addOnConnectionFailedListener(this)
- .addApi(Plus.API).addScope(Plus.SCOPE_PLUS_LOGIN)
- .addApi(Games.API).addScope(Games.SCOPE_GAMES)
- .build();
-
- // set up a click listener for everything we care about
- for (int id : CLICKABLES) {
- findViewById(id).setOnClickListener(this);
- }
- }
-
- @Override
- public void onClick(View v) {
- Intent intent;
-
- switch (v.getId()) {
- case R.id.button_single_player:
- case R.id.button_single_player_2:
- // play a single-player game
- resetGameVars();
- startGame(false);
- break;
- case R.id.button_sign_in:
- // user wants to sign in
- // Check to see the developer who's running this sample code read the instructions :-)
- // NOTE: this check is here only because this is a sample! Don't include this
- // check in your actual production app.
- if (!BaseGameUtils.verifySampleSetup(this, R.string.app_id)) {
- Log.w(TAG, "*** Warning: setup problems detected. Sign in may not work!");
- }
-
- // start the sign-in flow
- Log.d(TAG, "Sign-in button clicked");
- mSignInClicked = true;
- mGoogleApiClient.connect();
- break;
- case R.id.button_sign_out:
- // user wants to sign out
- // sign out.
- Log.d(TAG, "Sign-out button clicked");
- mSignInClicked = false;
- Games.signOut(mGoogleApiClient);
- mGoogleApiClient.disconnect();
- switchToScreen(R.id.screen_sign_in);
- break;
- case R.id.button_invite_players:
- // show list of invitable players
- intent = Games.RealTimeMultiplayer.getSelectOpponentsIntent(mGoogleApiClient, 1, 3);
- switchToScreen(R.id.screen_wait);
- startActivityForResult(intent, RC_SELECT_PLAYERS);
- break;
- case R.id.button_see_invitations:
- // show list of pending invitations
- intent = Games.Invitations.getInvitationInboxIntent(mGoogleApiClient);
- switchToScreen(R.id.screen_wait);
- startActivityForResult(intent, RC_INVITATION_INBOX);
- break;
- case R.id.button_accept_popup_invitation:
- // user wants to accept the invitation shown on the invitation popup
- // (the one we got through the OnInvitationReceivedListener).
- acceptInviteToRoom(mIncomingInvitationId);
- mIncomingInvitationId = null;
- break;
- case R.id.button_quick_game:
- // user wants to play against a random opponent right now
- startQuickGame();
- break;
- case R.id.button_click_me:
- // (gameplay) user clicked the "click me" button
- scoreOnePoint();
- break;
- }
- }
-
- void startQuickGame() {
- // quick-start a game with 1 randomly selected opponent
- final int MIN_OPPONENTS = 1, MAX_OPPONENTS = 1;
- Bundle autoMatchCriteria = RoomConfig.createAutoMatchCriteria(MIN_OPPONENTS,
- MAX_OPPONENTS, 0);
- RoomConfig.Builder rtmConfigBuilder = RoomConfig.builder(this);
- rtmConfigBuilder.setMessageReceivedListener(this);
- rtmConfigBuilder.setRoomStatusUpdateListener(this);
- rtmConfigBuilder.setAutoMatchCriteria(autoMatchCriteria);
- switchToScreen(R.id.screen_wait);
- keepScreenOn();
- resetGameVars();
- Games.RealTimeMultiplayer.create(mGoogleApiClient, rtmConfigBuilder.build());
- }
-
- @Override
- public void onActivityResult(int requestCode, int responseCode,
- Intent intent) {
- super.onActivityResult(requestCode, responseCode, intent);
-
- switch (requestCode) {
- case RC_SELECT_PLAYERS:
- // we got the result from the "select players" UI -- ready to create the room
- handleSelectPlayersResult(responseCode, intent);
- break;
- case RC_INVITATION_INBOX:
- // we got the result from the "select invitation" UI (invitation inbox). We're
- // ready to accept the selected invitation:
- handleInvitationInboxResult(responseCode, intent);
- break;
- case RC_WAITING_ROOM:
- // we got the result from the "waiting room" UI.
- if (responseCode == Activity.RESULT_OK) {
- // ready to start playing
- Log.d(TAG, "Starting game (waiting room returned OK).");
- startGame(true);
- } else if (responseCode == GamesActivityResultCodes.RESULT_LEFT_ROOM) {
- // player indicated that they want to leave the room
- leaveRoom();
- } else if (responseCode == Activity.RESULT_CANCELED) {
- // Dialog was cancelled (user pressed back key, for instance). In our game,
- // this means leaving the room too. In more elaborate games, this could mean
- // something else (like minimizing the waiting room UI).
- leaveRoom();
- }
- break;
- case RC_SIGN_IN:
- Log.d(TAG, "onActivityResult with requestCode == RC_SIGN_IN, responseCode="
- + responseCode + ", intent=" + intent);
- mSignInClicked = false;
- mResolvingConnectionFailure = false;
- if (responseCode == RESULT_OK) {
- mGoogleApiClient.connect();
- } else {
- BaseGameUtils.showActivityResultError(this,requestCode,responseCode, R.string.signin_other_error);
- }
- break;
- }
- super.onActivityResult(requestCode, responseCode, intent);
- }
-
- // Handle the result of the "Select players UI" we launched when the user clicked the
- // "Invite friends" button. We react by creating a room with those players.
- private void handleSelectPlayersResult(int response, Intent data) {
- if (response != Activity.RESULT_OK) {
- Log.w(TAG, "*** select players UI cancelled, " + response);
- switchToMainScreen();
- return;
- }
-
- Log.d(TAG, "Select players UI succeeded.");
-
- // get the invitee list
- final ArrayList invitees = data.getStringArrayListExtra(Games.EXTRA_PLAYER_IDS);
- Log.d(TAG, "Invitee count: " + invitees.size());
-
- // get the automatch criteria
- Bundle autoMatchCriteria = null;
- int minAutoMatchPlayers = data.getIntExtra(Multiplayer.EXTRA_MIN_AUTOMATCH_PLAYERS, 0);
- int maxAutoMatchPlayers = data.getIntExtra(Multiplayer.EXTRA_MAX_AUTOMATCH_PLAYERS, 0);
- if (minAutoMatchPlayers > 0 || maxAutoMatchPlayers > 0) {
- autoMatchCriteria = RoomConfig.createAutoMatchCriteria(
- minAutoMatchPlayers, maxAutoMatchPlayers, 0);
- Log.d(TAG, "Automatch criteria: " + autoMatchCriteria);
- }
-
- // create the room
- Log.d(TAG, "Creating room...");
- RoomConfig.Builder rtmConfigBuilder = RoomConfig.builder(this);
- rtmConfigBuilder.addPlayersToInvite(invitees);
- rtmConfigBuilder.setMessageReceivedListener(this);
- rtmConfigBuilder.setRoomStatusUpdateListener(this);
- if (autoMatchCriteria != null) {
- rtmConfigBuilder.setAutoMatchCriteria(autoMatchCriteria);
- }
- switchToScreen(R.id.screen_wait);
- keepScreenOn();
- resetGameVars();
- Games.RealTimeMultiplayer.create(mGoogleApiClient, rtmConfigBuilder.build());
- Log.d(TAG, "Room created, waiting for it to be ready...");
- }
-
- // Handle the result of the invitation inbox UI, where the player can pick an invitation
- // to accept. We react by accepting the selected invitation, if any.
- private void handleInvitationInboxResult(int response, Intent data) {
- if (response != Activity.RESULT_OK) {
- Log.w(TAG, "*** invitation inbox UI cancelled, " + response);
- switchToMainScreen();
- return;
- }
-
- Log.d(TAG, "Invitation inbox UI succeeded.");
- Invitation inv = data.getExtras().getParcelable(Multiplayer.EXTRA_INVITATION);
-
- // accept invitation
- acceptInviteToRoom(inv.getInvitationId());
- }
-
- // Accept the given invitation.
- void acceptInviteToRoom(String invId) {
- // accept the invitation
- Log.d(TAG, "Accepting invitation: " + invId);
- RoomConfig.Builder roomConfigBuilder = RoomConfig.builder(this);
- roomConfigBuilder.setInvitationIdToAccept(invId)
- .setMessageReceivedListener(this)
- .setRoomStatusUpdateListener(this);
- switchToScreen(R.id.screen_wait);
- keepScreenOn();
- resetGameVars();
- Games.RealTimeMultiplayer.join(mGoogleApiClient, roomConfigBuilder.build());
- }
-
- // Activity is going to the background. We have to leave the current room.
- @Override
- public void onStop() {
- Log.d(TAG, "**** got onStop");
-
- // if we're in a room, leave it.
- leaveRoom();
-
- // stop trying to keep the screen on
- stopKeepingScreenOn();
-
- if (mGoogleApiClient == null || !mGoogleApiClient.isConnected()){
- switchToScreen(R.id.screen_sign_in);
- }
- else {
- switchToScreen(R.id.screen_wait);
- }
- super.onStop();
- }
-
- // Activity just got to the foreground. We switch to the wait screen because we will now
- // go through the sign-in flow (remember that, yes, every time the Activity comes back to the
- // foreground we go through the sign-in flow -- but if the user is already authenticated,
- // this flow simply succeeds and is imperceptible).
- @Override
- public void onStart() {
- switchToScreen(R.id.screen_wait);
- if (mGoogleApiClient != null && mGoogleApiClient.isConnected()) {
- Log.w(TAG,
- "GameHelper: client was already connected on onStart()");
- } else {
- Log.d(TAG,"Connecting client.");
- mGoogleApiClient.connect();
- }
- super.onStart();
- }
-
- // Handle back key to make sure we cleanly leave a game if we are in the middle of one
- @Override
- public boolean onKeyDown(int keyCode, KeyEvent e) {
- if (keyCode == KeyEvent.KEYCODE_BACK && mCurScreen == R.id.screen_game) {
- leaveRoom();
- return true;
- }
- return super.onKeyDown(keyCode, e);
- }
-
- // Leave the room.
- void leaveRoom() {
- Log.d(TAG, "Leaving room.");
- mSecondsLeft = 0;
- stopKeepingScreenOn();
- if (mRoomId != null) {
- Games.RealTimeMultiplayer.leave(mGoogleApiClient, this, mRoomId);
- mRoomId = null;
- switchToScreen(R.id.screen_wait);
- } else {
- switchToMainScreen();
- }
- }
-
- // Show the waiting room UI to track the progress of other players as they enter the
- // room and get connected.
- void showWaitingRoom(Room room) {
- // minimum number of players required for our game
- // For simplicity, we require everyone to join the game before we start it
- // (this is signaled by Integer.MAX_VALUE).
- final int MIN_PLAYERS = Integer.MAX_VALUE;
- Intent i = Games.RealTimeMultiplayer.getWaitingRoomIntent(mGoogleApiClient, room, MIN_PLAYERS);
-
- // show waiting room UI
- startActivityForResult(i, RC_WAITING_ROOM);
- }
-
- // Called when we get an invitation to play a game. We react by showing that to the user.
- @Override
- public void onInvitationReceived(Invitation invitation) {
- // We got an invitation to play a game! So, store it in
- // mIncomingInvitationId
- // and show the popup on the screen.
- mIncomingInvitationId = invitation.getInvitationId();
- ((TextView) findViewById(R.id.incoming_invitation_text)).setText(
- invitation.getInviter().getDisplayName() + " " +
- getString(R.string.is_inviting_you));
- switchToScreen(mCurScreen); // This will show the invitation popup
- }
-
- @Override
- public void onInvitationRemoved(String invitationId) {
- if (mIncomingInvitationId.equals(invitationId)) {
- mIncomingInvitationId = null;
- switchToScreen(mCurScreen); // This will hide the invitation popup
- }
- }
-
- /*
- * CALLBACKS SECTION. This section shows how we implement the several games
- * API callbacks.
- */
-
- @Override
- public void onConnected(Bundle connectionHint) {
- Log.d(TAG, "onConnected() called. Sign in successful!");
-
- Log.d(TAG, "Sign-in succeeded.");
-
- // register listener so we are notified if we receive an invitation to play
- // while we are in the game
- Games.Invitations.registerInvitationListener(mGoogleApiClient, this);
-
- if (connectionHint != null) {
- Log.d(TAG, "onConnected: connection hint provided. Checking for invite.");
- Invitation inv = connectionHint
- .getParcelable(Multiplayer.EXTRA_INVITATION);
- if (inv != null && inv.getInvitationId() != null) {
- // retrieve and cache the invitation ID
- Log.d(TAG,"onConnected: connection hint has a room invite!");
- acceptInviteToRoom(inv.getInvitationId());
- return;
- }
- }
- switchToMainScreen();
-
- }
-
- @Override
- public void onConnectionSuspended(int i) {
- Log.d(TAG, "onConnectionSuspended() called. Trying to reconnect.");
- mGoogleApiClient.connect();
- }
-
- @Override
- public void onConnectionFailed(ConnectionResult connectionResult) {
- Log.d(TAG, "onConnectionFailed() called, result: " + connectionResult);
-
- if (mResolvingConnectionFailure) {
- Log.d(TAG, "onConnectionFailed() ignoring connection failure; already resolving.");
- return;
- }
-
- if (mSignInClicked || mAutoStartSignInFlow) {
- mAutoStartSignInFlow = false;
- mSignInClicked = false;
- mResolvingConnectionFailure = BaseGameUtils.resolveConnectionFailure(this, mGoogleApiClient,
- connectionResult, RC_SIGN_IN, getString(R.string.signin_other_error));
- }
-
- switchToScreen(R.id.screen_sign_in);
- }
-
- // Called when we are connected to the room. We're not ready to play yet! (maybe not everybody
- // is connected yet).
- @Override
- public void onConnectedToRoom(Room room) {
- Log.d(TAG, "onConnectedToRoom.");
-
- // get room ID, participants and my ID:
- mRoomId = room.getRoomId();
- mParticipants = room.getParticipants();
- mMyId = room.getParticipantId(Games.Players.getCurrentPlayerId(mGoogleApiClient));
-
- // print out the list of participants (for debug purposes)
- Log.d(TAG, "Room ID: " + mRoomId);
- Log.d(TAG, "My ID " + mMyId);
- Log.d(TAG, "<< CONNECTED TO ROOM>>");
- }
-
- // Called when we've successfully left the room (this happens a result of voluntarily leaving
- // via a call to leaveRoom(). If we get disconnected, we get onDisconnectedFromRoom()).
- @Override
- public void onLeftRoom(int statusCode, String roomId) {
- // we have left the room; return to main screen.
- Log.d(TAG, "onLeftRoom, code " + statusCode);
- switchToMainScreen();
- }
-
- // Called when we get disconnected from the room. We return to the main screen.
- @Override
- public void onDisconnectedFromRoom(Room room) {
- mRoomId = null;
- showGameError();
- }
-
- // Show error message about game being cancelled and return to main screen.
- void showGameError() {
- BaseGameUtils.makeSimpleDialog(this, getString(R.string.game_problem));
- switchToMainScreen();
- }
-
- // Called when room has been created
- @Override
- public void onRoomCreated(int statusCode, Room room) {
- Log.d(TAG, "onRoomCreated(" + statusCode + ", " + room + ")");
- if (statusCode != GamesStatusCodes.STATUS_OK) {
- Log.e(TAG, "*** Error: onRoomCreated, status " + statusCode);
- showGameError();
- return;
- }
-
- // show the waiting room UI
- showWaitingRoom(room);
- }
-
- // Called when room is fully connected.
- @Override
- public void onRoomConnected(int statusCode, Room room) {
- Log.d(TAG, "onRoomConnected(" + statusCode + ", " + room + ")");
- if (statusCode != GamesStatusCodes.STATUS_OK) {
- Log.e(TAG, "*** Error: onRoomConnected, status " + statusCode);
- showGameError();
- return;
- }
- updateRoom(room);
- }
-
- @Override
- public void onJoinedRoom(int statusCode, Room room) {
- Log.d(TAG, "onJoinedRoom(" + statusCode + ", " + room + ")");
- if (statusCode != GamesStatusCodes.STATUS_OK) {
- Log.e(TAG, "*** Error: onRoomConnected, status " + statusCode);
- showGameError();
- return;
- }
-
- // show the waiting room UI
- showWaitingRoom(room);
- }
-
- // We treat most of the room update callbacks in the same way: we update our list of
- // participants and update the display. In a real game we would also have to check if that
- // change requires some action like removing the corresponding player avatar from the screen,
- // etc.
- @Override
- public void onPeerDeclined(Room room, List arg1) {
- updateRoom(room);
- }
-
- @Override
- public void onPeerInvitedToRoom(Room room, List arg1) {
- updateRoom(room);
- }
-
- @Override
- public void onP2PDisconnected(String participant) {
- }
-
- @Override
- public void onP2PConnected(String participant) {
- }
-
- @Override
- public void onPeerJoined(Room room, List arg1) {
- updateRoom(room);
- }
-
- @Override
- public void onPeerLeft(Room room, List peersWhoLeft) {
- updateRoom(room);
- }
-
- @Override
- public void onRoomAutoMatching(Room room) {
- updateRoom(room);
- }
-
- @Override
- public void onRoomConnecting(Room room) {
- updateRoom(room);
- }
-
- @Override
- public void onPeersConnected(Room room, List peers) {
- updateRoom(room);
- }
-
- @Override
- public void onPeersDisconnected(Room room, List peers) {
- updateRoom(room);
- }
-
- void updateRoom(Room room) {
- if (room != null) {
- mParticipants = room.getParticipants();
- }
- if (mParticipants != null) {
- updatePeerScoresDisplay();
- }
- }
-
- /*
- * GAME LOGIC SECTION. Methods that implement the game's rules.
- */
-
- // Current state of the game:
- int mSecondsLeft = -1; // how long until the game ends (seconds)
- final static int GAME_DURATION = 20; // game duration, seconds.
- int mScore = 0; // user's current score
-
- // Reset game variables in preparation for a new game.
- void resetGameVars() {
- mSecondsLeft = GAME_DURATION;
- mScore = 0;
- mParticipantScore.clear();
- mFinishedParticipants.clear();
- }
-
- // Start the gameplay phase of the game.
- void startGame(boolean multiplayer) {
- mMultiplayer = multiplayer;
- updateScoreDisplay();
- broadcastScore(false);
- switchToScreen(R.id.screen_game);
-
- findViewById(R.id.button_click_me).setVisibility(View.VISIBLE);
-
- // run the gameTick() method every second to update the game.
- final Handler h = new Handler();
- h.postDelayed(new Runnable() {
- @Override
- public void run() {
- if (mSecondsLeft <= 0)
- return;
- gameTick();
- h.postDelayed(this, 1000);
- }
- }, 1000);
- }
-
- // Game tick -- update countdown, check if game ended.
- void gameTick() {
- if (mSecondsLeft > 0)
- --mSecondsLeft;
-
- // update countdown
- ((TextView) findViewById(R.id.countdown)).setText("0:" +
- (mSecondsLeft < 10 ? "0" : "") + String.valueOf(mSecondsLeft));
-
- if (mSecondsLeft <= 0) {
- // finish game
- findViewById(R.id.button_click_me).setVisibility(View.GONE);
- broadcastScore(true);
- }
- }
-
- // indicates the player scored one point
- void scoreOnePoint() {
- if (mSecondsLeft <= 0)
- return; // too late!
- ++mScore;
- updateScoreDisplay();
- updatePeerScoresDisplay();
-
- // broadcast our new score to our peers
- broadcastScore(false);
- }
-
- /*
- * COMMUNICATIONS SECTION. Methods that implement the game's network
- * protocol.
- */
-
- // Score of other participants. We update this as we receive their scores
- // from the network.
- Map mParticipantScore = new HashMap();
-
- // Participants who sent us their final score.
- Set mFinishedParticipants = new HashSet();
-
- // Called when we receive a real-time message from the network.
- // Messages in our game are made up of 2 bytes: the first one is 'F' or 'U'
- // indicating
- // whether it's a final or interim score. The second byte is the score.
- // There is also the
- // 'S' message, which indicates that the game should start.
- @Override
- public void onRealTimeMessageReceived(RealTimeMessage rtm) {
- byte[] buf = rtm.getMessageData();
- String sender = rtm.getSenderParticipantId();
- Log.d(TAG, "Message received: " + (char) buf[0] + "/" + (int) buf[1]);
-
- if (buf[0] == 'F' || buf[0] == 'U') {
- // score update.
- int existingScore = mParticipantScore.containsKey(sender) ?
- mParticipantScore.get(sender) : 0;
- int thisScore = (int) buf[1];
- if (thisScore > existingScore) {
- // this check is necessary because packets may arrive out of
- // order, so we
- // should only ever consider the highest score we received, as
- // we know in our
- // game there is no way to lose points. If there was a way to
- // lose points,
- // we'd have to add a "serial number" to the packet.
- mParticipantScore.put(sender, thisScore);
- }
-
- // update the scores on the screen
- updatePeerScoresDisplay();
-
- // if it's a final score, mark this participant as having finished
- // the game
- if ((char) buf[0] == 'F') {
- mFinishedParticipants.add(rtm.getSenderParticipantId());
- }
- }
- }
-
- // Broadcast my score to everybody else.
- void broadcastScore(boolean finalScore) {
- if (!mMultiplayer)
- return; // playing single-player mode
-
- // First byte in message indicates whether it's a final score or not
- mMsgBuf[0] = (byte) (finalScore ? 'F' : 'U');
-
- // Second byte is the score.
- mMsgBuf[1] = (byte) mScore;
-
- // Send to every other participant.
- for (Participant p : mParticipants) {
- if (p.getParticipantId().equals(mMyId))
- continue;
- if (p.getStatus() != Participant.STATUS_JOINED)
- continue;
- if (finalScore) {
- // final score notification must be sent via reliable message
- Games.RealTimeMultiplayer.sendReliableMessage(mGoogleApiClient, null, mMsgBuf,
- mRoomId, p.getParticipantId());
- } else {
- // it's an interim score notification, so we can use unreliable
- Games.RealTimeMultiplayer.sendUnreliableMessage(mGoogleApiClient, mMsgBuf, mRoomId,
- p.getParticipantId());
- }
- }
- }
-
- /*
- * UI SECTION. Methods that implement the game's UI.
- */
-
- // This array lists everything that's clickable, so we can install click
- // event handlers.
- final static int[] CLICKABLES = {
- R.id.button_accept_popup_invitation, R.id.button_invite_players,
- R.id.button_quick_game, R.id.button_see_invitations, R.id.button_sign_in,
- R.id.button_sign_out, R.id.button_click_me, R.id.button_single_player,
- R.id.button_single_player_2
- };
-
- // This array lists all the individual screens our game has.
- final static int[] SCREENS = {
- R.id.screen_game, R.id.screen_main, R.id.screen_sign_in,
- R.id.screen_wait
- };
- int mCurScreen = -1;
-
- void switchToScreen(int screenId) {
- // make the requested screen visible; hide all others.
- for (int id : SCREENS) {
- findViewById(id).setVisibility(screenId == id ? View.VISIBLE : View.GONE);
- }
- mCurScreen = screenId;
-
- // should we show the invitation popup?
- boolean showInvPopup;
- if (mIncomingInvitationId == null) {
- // no invitation, so no popup
- showInvPopup = false;
- } else if (mMultiplayer) {
- // if in multiplayer, only show invitation on main screen
- showInvPopup = (mCurScreen == R.id.screen_main);
- } else {
- // single-player: show on main screen and gameplay screen
- showInvPopup = (mCurScreen == R.id.screen_main || mCurScreen == R.id.screen_game);
- }
- findViewById(R.id.invitation_popup).setVisibility(showInvPopup ? View.VISIBLE : View.GONE);
- }
-
- void switchToMainScreen() {
- if (mGoogleApiClient != null && mGoogleApiClient.isConnected()) {
- switchToScreen(R.id.screen_main);
- }
- else {
- switchToScreen(R.id.screen_sign_in);
- }
- }
-
- // updates the label that shows my score
- void updateScoreDisplay() {
- ((TextView) findViewById(R.id.my_score)).setText(formatScore(mScore));
- }
-
- // formats a score as a three-digit number
- String formatScore(int i) {
- if (i < 0)
- i = 0;
- String s = String.valueOf(i);
- return s.length() == 1 ? "00" + s : s.length() == 2 ? "0" + s : s;
- }
-
- // updates the screen with the scores from our peers
- void updatePeerScoresDisplay() {
- ((TextView) findViewById(R.id.score0)).setText(formatScore(mScore) + " - Me");
- int[] arr = {
- R.id.score1, R.id.score2, R.id.score3
- };
- int i = 0;
-
- if (mRoomId != null) {
- for (Participant p : mParticipants) {
- String pid = p.getParticipantId();
- if (pid.equals(mMyId))
- continue;
- if (p.getStatus() != Participant.STATUS_JOINED)
- continue;
- int score = mParticipantScore.containsKey(pid) ? mParticipantScore.get(pid) : 0;
- ((TextView) findViewById(arr[i])).setText(formatScore(score) + " - " +
- p.getDisplayName());
- ++i;
- }
- }
-
- for (; i < arr.length; ++i) {
- ((TextView) findViewById(arr[i])).setText("");
- }
- }
-
- /*
- * MISC SECTION. Miscellaneous methods.
- */
-
-
- // Sets the flag to keep this screen on. It's recommended to do that during
- // the
- // handshake when setting up a game, because if the screen turns off, the
- // game will be
- // cancelled.
- void keepScreenOn() {
- getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
- }
-
- // Clears the flag that keeps the screen on.
- void stopKeepingScreenOn() {
- getWindow().clearFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
- }
-}
diff --git a/BasicSamples/ButtonClicker/src/main/res/drawable-hdpi/ic_action_search.png b/BasicSamples/ButtonClicker/src/main/res/drawable-hdpi/ic_action_search.png
deleted file mode 100644
index 67de12de..00000000
Binary files a/BasicSamples/ButtonClicker/src/main/res/drawable-hdpi/ic_action_search.png and /dev/null differ
diff --git a/BasicSamples/ButtonClicker/src/main/res/drawable-ldpi/ic_launcher.png b/BasicSamples/ButtonClicker/src/main/res/drawable-ldpi/ic_launcher.png
deleted file mode 100644
index 26e8a4da..00000000
Binary files a/BasicSamples/ButtonClicker/src/main/res/drawable-ldpi/ic_launcher.png and /dev/null differ
diff --git a/BasicSamples/ButtonClicker/src/main/res/drawable-mdpi/ic_action_search.png b/BasicSamples/ButtonClicker/src/main/res/drawable-mdpi/ic_action_search.png
deleted file mode 100644
index 134d5490..00000000
Binary files a/BasicSamples/ButtonClicker/src/main/res/drawable-mdpi/ic_action_search.png and /dev/null differ
diff --git a/BasicSamples/ButtonClicker/src/main/res/drawable-xhdpi/ic_action_search.png b/BasicSamples/ButtonClicker/src/main/res/drawable-xhdpi/ic_action_search.png
deleted file mode 100644
index d699c6b3..00000000
Binary files a/BasicSamples/ButtonClicker/src/main/res/drawable-xhdpi/ic_action_search.png and /dev/null differ
diff --git a/BasicSamples/ButtonClicker/src/main/res/layout/activity_main.xml b/BasicSamples/ButtonClicker/src/main/res/layout/activity_main.xml
deleted file mode 100644
index 1553767b..00000000
--- a/BasicSamples/ButtonClicker/src/main/res/layout/activity_main.xml
+++ /dev/null
@@ -1,94 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/BasicSamples/ButtonClicker/src/main/res/values-v11/styles.xml b/BasicSamples/ButtonClicker/src/main/res/values-v11/styles.xml
deleted file mode 100644
index 997965b5..00000000
--- a/BasicSamples/ButtonClicker/src/main/res/values-v11/styles.xml
+++ /dev/null
@@ -1,20 +0,0 @@
-
-
-
-
-
-
diff --git a/BasicSamples/ButtonClicker/src/main/res/values/strings.xml b/BasicSamples/ButtonClicker/src/main/res/values/strings.xml
deleted file mode 100644
index 07a73538..00000000
--- a/BasicSamples/ButtonClicker/src/main/res/values/strings.xml
+++ /dev/null
@@ -1,44 +0,0 @@
-
-
-
-
- Signing in with Google
- Signing out
- Button Clicker
- Button Clicker 2000!
- A sample game that tests your ability to click a button. Can you click faster than your friends? Only one way to find out! To play this game with friends, you must sign in with Google.
- Single Player
- Get some practice!
- Quick game
- Invite friends
- See invitations
- Challenge a random opponent.
- Invite friends to play a game.
- See who is inviting you right now.
- Incoming invitation!
- Accept!
- Sign Out
- Please wait...
- Click the button as fast as you can!
- Dismiss
- Your score:
- Error
- An error occurred while starting the game. Please try again.
- Click me!
- is challenging you to a game!
- There was an issue with sign in. Please try again later.
-
diff --git a/BasicSamples/ButtonClicker/src/main/res/values/styles.xml b/BasicSamples/ButtonClicker/src/main/res/values/styles.xml
deleted file mode 100644
index 3b711af7..00000000
--- a/BasicSamples/ButtonClicker/src/main/res/values/styles.xml
+++ /dev/null
@@ -1,200 +0,0 @@
-
-
-
-
-
- #cc0000
- @color/AccentColor
- #ffffff
- #ffffff
- #a0a0a0
- #e0e0e0
- #404040
-
- 30sp
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/BasicSamples/CollectAllTheStars2/.gitignore b/BasicSamples/CollectAllTheStars2/.gitignore
deleted file mode 100644
index 47036e4a..00000000
--- a/BasicSamples/CollectAllTheStars2/.gitignore
+++ /dev/null
@@ -1,3 +0,0 @@
-/build/
-/bin/
-/gen/
diff --git a/BasicSamples/CollectAllTheStars2/README.md b/BasicSamples/CollectAllTheStars2/README.md
deleted file mode 100644
index c1068165..00000000
--- a/BasicSamples/CollectAllTheStars2/README.md
+++ /dev/null
@@ -1,21 +0,0 @@
-# Collect all the Stars 2 #
-This sample demonstrates how to use the Snapshots feature to save game data.
-It signs the user into Google Play Game Services ("GPGS"), synchronizes his or her data from a named Snapshot,
-and then updates the UI to reflect the game state saved in the Snapshot.
-
-## Setup ##
-Follow these steps to set up the sample:
-1. Update the package name in `AndroidManifest.xml` to be something other
- than `com.google.example.games.catt2`.
-2. Modify your app folder structure to match your package name.
-3. Replace the package name in `MainActivity.java`. Note that the package name must be unique; otherwise, the API console
- cannot link your app correctly.
-4. Create your project in the Google Play Developer Console.
-5. Link your app.
-6. Copy the `APP ID` from the console into `CollectAllTheStars/values/ids.xml`.
-
-## Running ##
-1. Sign in. Upon success, the Play Games toast appears.
-2. Make changes to the game state by selecting stars.
-3. Sign out. The game UI resets.
-4. Sign back in with your account. The game UI reflects the saved game state.
diff --git a/BasicSamples/CollectAllTheStars2/build.gradle b/BasicSamples/CollectAllTheStars2/build.gradle
deleted file mode 100644
index 17f46e23..00000000
--- a/BasicSamples/CollectAllTheStars2/build.gradle
+++ /dev/null
@@ -1,32 +0,0 @@
-apply plugin: 'android'
-
-android {
- compileSdkVersion 20
- buildToolsVersion '20'
-
- defaultConfig {
- minSdkVersion 9
- targetSdkVersion 20
- versionCode 1
- versionName "1.0"
- }
- buildTypes {
- release {
- minifyEnabled false
- proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.txt'
- }
- }
-}
-
-dependencies {
- compile 'com.android.support:appcompat-v7:20.0.+'
- compile 'com.android.support:support-v4:20.0.+'
- compile 'com.google.android.gms:play-services:5+'
- compile project(':libraries:BaseGameUtils')
-}
-
-buildscript {
- repositories {
- mavenCentral()
- }
-}
diff --git a/BasicSamples/CollectAllTheStars2/src/main/java/com/google/example/games/catt2/MainActivity.java b/BasicSamples/CollectAllTheStars2/src/main/java/com/google/example/games/catt2/MainActivity.java
deleted file mode 100644
index 70f0690b..00000000
--- a/BasicSamples/CollectAllTheStars2/src/main/java/com/google/example/games/catt2/MainActivity.java
+++ /dev/null
@@ -1,884 +0,0 @@
-/* Copyright (C) 2014 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.catt2;
-
-import android.app.Activity;
-import android.app.ProgressDialog;
-import android.content.Intent;
-import android.graphics.Bitmap;
-import android.os.AsyncTask;
-import android.os.Bundle;
-import android.util.Log;
-import android.view.Menu;
-import android.view.MenuItem;
-import android.view.View;
-import android.widget.Button;
-import android.widget.RatingBar;
-import android.widget.RatingBar.OnRatingBarChangeListener;
-import android.widget.TextView;
-import android.widget.Toast;
-
-import com.google.android.gms.common.ConnectionResult;
-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.GamesStatusCodes;
-import com.google.android.gms.games.snapshot.Snapshot;
-import com.google.android.gms.games.snapshot.SnapshotMetadata;
-import com.google.android.gms.games.snapshot.SnapshotMetadataChange;
-import com.google.android.gms.games.snapshot.Snapshots;
-import com.google.android.gms.plus.Plus;
-import com.google.example.games.basegameutils.BaseGameUtils;
-
-import java.io.IOException;
-import java.math.BigInteger;
-import java.util.ArrayList;
-import java.util.Calendar;
-import java.util.Random;
-
-/**
- * Collect All the Stars sample. This sample demonstrates how to use the cloud save features
- * of the Google Play game services API. It's a "game" where there are several worlds
- * with several levels each, and on each level the player can get from 0 to 5 stars.
- * The progress of the player is saved to the cloud and kept in sync across all their devices.
- * If they earn 5 stars on level 1 on one device and then earn 4 stars on level 2 on a different
- * device, upon synchronizing the consolidated progress will be 5 stars on level 1 AND
- * 4 stars on level 2. If they clear the same level on two different devices, then the biggest
- * star rating of the two will apply.
- *
- * It's worth noting that this sample also works offline, and even when the player is not
- * signed in. In all cases, the progress is saved locally as well.
- *
- * @author Bruno Oliveira (Google)
- */
-public class MainActivity extends Activity
- implements GoogleApiClient.ConnectionCallbacks, GoogleApiClient.OnConnectionFailedListener,
- View.OnClickListener, OnRatingBarChangeListener {
-
-
- private static final String TAG = "CollectAllTheStars2";
-
- // Request code used to invoke sign in user interactions.
- private static final int RC_SIGN_IN = 9001;
-
- // Request code for listing saved games
- private static final int RC_LIST_SAVED_GAMES = 9002;
-
- // Request code for selecting a snapshot
- private static final int RC_SELECT_SNAPSHOT = 9003;
-
- // Request code for saving the game to a snapshot.
- private static final int RC_SAVE_SNAPSHOT = 9004;
-
- private static final int RC_LOAD_SNAPSHOT = 9005;
-
- // Client used to interact with Google APIs.
- private GoogleApiClient mGoogleApiClient;
-
- // Are we currently resolving a connection failure?
- private boolean mResolvingConnectionFailure = false;
-
- // Has the user clicked the sign-in button?
- private boolean mSignInClicked = false;
-
- // Set to true to automatically start the sign in flow when the Activity starts.
- // Set to false to require the user to click the button in order to sign in.
- private boolean mAutoStartSignInFlow = true;
-
- // current save game - serializable to and from the saved game
- SaveGame mSaveGame = new SaveGame();
-
- private String currentSaveName = "snapshotTemp";
-
- // world we're currently viewing
- int mWorld = 1;
- private static final int WORLD_MIN = 1;
- private static final int WORLD_MAX = 20;
- private static final int LEVELS_PER_WORLD = 12;
-
- // level we're currently "playing"
- int mLevel = 0;
-
- // state of "playing" - used to make the back button work correctly
- boolean mInLevel = false;
-
- // progress dialog we display while we're loading state from the cloud
- ProgressDialog mLoadingDialog = null;
-
- // whether we already loaded the state the first time (so we don't reload
- // every time the activity goes to the background and comes back to the foreground)
- boolean mAlreadyLoadedState = false;
-
- // the level buttons (the ones the user clicks to play a given level)
- final static int[] LEVEL_BUTTON_IDS = {
- R.id.button_level_1, R.id.button_level_2, R.id.button_level_3, R.id.button_level_4,
- R.id.button_level_5, R.id.button_level_6, R.id.button_level_7, R.id.button_level_8,
- R.id.button_level_9, R.id.button_level_10, R.id.button_level_11, R.id.button_level_12
- };
-
- // star strings (we use the Unicode BLACK STAR and WHITE STAR characters -- lazy graphics!)
- final static String[] STAR_STRINGS = {
- "\u2606\u2606\u2606\u2606\u2606", // 0 stars
- "\u2605\u2606\u2606\u2606\u2606", // 1 star
- "\u2605\u2605\u2606\u2606\u2606", // 2 stars
- "\u2605\u2605\u2605\u2606\u2606", // 3 stars
- "\u2605\u2605\u2605\u2605\u2606", // 4 stars
- "\u2605\u2605\u2605\u2605\u2605", // 5 stars
- };
-
- // Members related to the conflict resolution chooser of Snapshots.
- final static int MAX_SNAPSHOT_RESOLVE_RETRIES = 3;
-
- /**
- * You can capture the Snapshot selection intent in the onActivityResult method. The result
- * either indicates a new Snapshot was created (EXTRA_SNAPSHOT_NEW) or was selected.
- */
- @Override
- protected void onActivityResult(int requestCode, int resultCode, Intent intent) {
- if (requestCode == RC_SIGN_IN) {
- Log.d(TAG, "onActivityResult with requestCode == RC_SIGN_IN, responseCode="
- + resultCode + ", intent=" + intent);
- mSignInClicked = false;
- mResolvingConnectionFailure = false;
- if (resultCode == RESULT_OK) {
- mGoogleApiClient.connect();
- } else {
- BaseGameUtils.showActivityResultError(this, requestCode, resultCode, R.string.signin_other_error);
- }
- }
- // the standard snapshot selection intent
- else if (requestCode == RC_LIST_SAVED_GAMES) {
- if (intent != null) {
- if (intent.hasExtra(Snapshots.EXTRA_SNAPSHOT_METADATA)) {
- // Load a snapshot.
- SnapshotMetadata snapshotMetadata =
- intent.getParcelableExtra(Snapshots.EXTRA_SNAPSHOT_METADATA);
- currentSaveName = snapshotMetadata.getUniqueName();
- loadFromSnapshot(snapshotMetadata);
- } else if (intent.hasExtra(Snapshots.EXTRA_SNAPSHOT_NEW)) {
- // Create a new snapshot named with a unique string
- // TODO: check for existing snapshot, for now, add garbage text.
- String unique = new BigInteger(281, new Random()).toString(13);
- currentSaveName = "snapshotTemp-" + unique;
- saveSnapshot(null);
- }
- }
- }
- // the example use of Snapshot.load() which displays a custom list of snapshots.
- else if (requestCode == RC_SELECT_SNAPSHOT) {
- Log.d(TAG, "Selected a snapshot!");
- if (resultCode == RESULT_OK) {
- if (intent != null && intent.hasExtra(SelectSnapshotActivity.SNAPSHOT_METADATA)) {
- // Load a snapshot.
- SnapshotMetadata snapshotMetadata =
- intent.getParcelableExtra(SelectSnapshotActivity.SNAPSHOT_METADATA);
- currentSaveName = snapshotMetadata.getUniqueName();
- Log.d(TAG, "ok - loading " + currentSaveName);
- loadFromSnapshot(snapshotMetadata);
- } else {
- Log.w(TAG, "Expected snapshot metadata but found none.");
- }
- }
- }
- // loading a snapshot into the game.
- else if (requestCode == RC_LOAD_SNAPSHOT) {
- Log.d(TAG,"Loading a snapshot resultCode = " + resultCode);
- if (resultCode == RESULT_OK) {
- if (intent != null && intent.hasExtra(SelectSnapshotActivity.SNAPSHOT_METADATA)) {
- // Load a snapshot.
- String conflictId = intent.getStringExtra(SelectSnapshotActivity.CONFLICT_ID);
- int retryCount = intent.getIntExtra(SelectSnapshotActivity.RETRY_COUNT,
- MAX_SNAPSHOT_RESOLVE_RETRIES);
- SnapshotMetadata snapshotMetadata =
- intent.getParcelableExtra(SelectSnapshotActivity.SNAPSHOT_METADATA);
- if (conflictId == null) {
- loadFromSnapshot(snapshotMetadata);
- } else {
- Log.d(TAG,"resolving " + snapshotMetadata);
- resolveSnapshotConflict(requestCode, conflictId, retryCount,
- snapshotMetadata);
- }
- }
- }
-
- }
- // saving the game into a snapshot.
- else if (requestCode == RC_SAVE_SNAPSHOT) {
- if (resultCode == RESULT_OK) {
- if (intent != null && intent.hasExtra(SelectSnapshotActivity.SNAPSHOT_METADATA)) {
- // Load a snapshot.
- String conflictId = intent.getStringExtra(SelectSnapshotActivity.CONFLICT_ID);
- int retryCount = intent.getIntExtra(SelectSnapshotActivity.RETRY_COUNT,
- MAX_SNAPSHOT_RESOLVE_RETRIES);
- SnapshotMetadata snapshotMetadata =
- intent.getParcelableExtra(SelectSnapshotActivity.SNAPSHOT_METADATA);
- if (conflictId == null) {
- saveSnapshot(snapshotMetadata);
- } else {
- Log.d(TAG,"resolving " + snapshotMetadata);
- resolveSnapshotConflict(requestCode, conflictId, retryCount, snapshotMetadata);
- }
- }
- }
- }
- super.onActivityResult(requestCode, resultCode, intent);
- }
-
-
- @Override
- protected void onCreate(Bundle savedInstanceState) {
-
- log("onCreate.");
- super.onCreate(savedInstanceState);
- setContentView(R.layout.activity_main);
-
- // Create the Google Api Client with access to Plus and Games
- mGoogleApiClient = new GoogleApiClient.Builder(this)
- .addConnectionCallbacks(this)
- .addOnConnectionFailedListener(this)
- .addApi(Plus.API).addScope(Plus.SCOPE_PLUS_LOGIN)
- .addApi(Games.API).addScope(Games.SCOPE_GAMES)
- .addApi(Drive.API).addScope(Drive.SCOPE_APPFOLDER)
- .build();
-
- for (int id : LEVEL_BUTTON_IDS) {
- findViewById(id).setOnClickListener(this);
- }
- findViewById(R.id.button_next_world).setOnClickListener(this);
- findViewById(R.id.button_prev_world).setOnClickListener(this);
- findViewById(R.id.button_sign_in).setOnClickListener(this);
- findViewById(R.id.button_sign_out).setOnClickListener(this);
- ((RatingBar) findViewById(R.id.gameplay_rating)).setOnRatingBarChangeListener(this);
- mSaveGame = new SaveGame();
- updateUi();
- }
-
-
- @Override
- public boolean onOptionsItemSelected(MenuItem item) {
-
- // Player wants to force save or load.
- // NOTE: this button exists in this sample for debug purposes and so that you can
- // see the effects immediately. A game probably shouldn't have a "Load/Save"
- // button (or at least not one that's so prominently displayed in the UI).
- if (item.getItemId() == R.id.menu_sync) {
- loadFromSnapshot(null);
- return true;
- }
- if (item.getItemId() == R.id.menu_save) {
- saveSnapshot(null);
- return true;
- }
- if (item.getItemId() == R.id.menu_select) {
- selectSnapshot();
- }
- return false;
- }
-
-
- @Override
- protected void onStart() {
- updateUi();
- super.onStart();
- }
-
-
- @Override
- protected void onStop() {
- if (mLoadingDialog != null) {
- mLoadingDialog.dismiss();
- mLoadingDialog = null;
- }
- super.onStop();
- }
-
-
- @Override
- public boolean onCreateOptionsMenu(Menu menu) {
- // Inflate the menu; this adds items to the action bar if it is present.
- getMenuInflater().inflate(R.menu.activity_main, menu);
- return true;
- }
-
- @Override
- public void onConnected(Bundle connectionHint) {
-
- // Sign-in worked!
- log("Sign-in successful! Loading game state from cloud.");
- showSignOutBar();
- if (!mAlreadyLoadedState) {
- showSnapshots(getString(R.string.title_load_game), false, false);
- } else {
- updateUi();
- }
- }
-
-
- @Override
- public void onConnectionSuspended(int cause) {
- Log.d(TAG, "onConnectionSuspended() called. Cause: " + cause);
- // onConnected will automatically be called when the client reconnects.
- }
-
- @Override
- public void onConnectionFailed(ConnectionResult connectionResult) {
- Log.d(TAG, "onConnectionFailed() called, result: " + connectionResult);
-
- if (mResolvingConnectionFailure) {
- Log.d(TAG, "onConnectionFailed() ignoring connection failure; already resolving.");
- return;
- }
-
- if (mSignInClicked || mAutoStartSignInFlow) {
- mAutoStartSignInFlow = false;
- mSignInClicked = false;
- mResolvingConnectionFailure = BaseGameUtils
- .resolveConnectionFailure(this, mGoogleApiClient,
- connectionResult, RC_SIGN_IN, getString(R.string.signin_other_error));
- }
- showSignInBar();
- }
-
-
- @Override
- public void onBackPressed() {
- if (mInLevel) {
- updateUi();
- findViewById(R.id.screen_gameplay).setVisibility(View.GONE);
- findViewById(R.id.screen_main).setVisibility(View.VISIBLE);
- mInLevel = false;
- } else {
- super.onBackPressed();
- }
- }
-
- /** Called when the "sign in" or "sign out" button is clicked. */
- @Override
- public void onClick(View view) {
- switch (view.getId()) {
- case R.id.button_sign_in:
- // Check to see the developer who's running this sample code read the instructions :-)
- // NOTE: this check is here only because this is a sample! Don't include this
- // check in your actual production app.
- if (!BaseGameUtils.verifySampleSetup(this, R.string.app_id)) {
- Log.w(TAG, "*** Warning: setup problems detected. Sign in may not work!");
- }
-
- // start the sign-in flow
- Log.d(TAG, "Sign-in button clicked");
- mSignInClicked = true;
- mGoogleApiClient.connect();
- break;
- case R.id.button_sign_out:
- // sign out.
- mSignInClicked = false;
- Games.signOut(mGoogleApiClient);
- mGoogleApiClient.disconnect();
- showSignInBar();
- mSaveGame = new SaveGame();
- mAlreadyLoadedState = false;
- updateUi();
- break;
- case R.id.button_next_world:
- if (isConnected()) {
- BaseGameUtils.makeSimpleDialog(this, getString(R.string.please_sign_in)).show();
- return;
- }
- if (mWorld < WORLD_MAX) {
- mWorld++;
- updateUi();
- }
- break;
- case R.id.button_prev_world:
- if (isConnected()) {
- BaseGameUtils.makeSimpleDialog(this, getString(R.string.please_sign_in)).show();
- return;
- }
- if (mWorld > WORLD_MIN) {
- mWorld--;
- updateUi();
- }
- break;
- default:
- if (isConnected()) {
- BaseGameUtils.makeSimpleDialog(this, getString(R.string.please_sign_in)).show();
- return;
- }
- for (int i = 0; i < LEVEL_BUTTON_IDS.length; ++i) {
- if (view.getId() == LEVEL_BUTTON_IDS[i]) {
- launchLevel(i + 1);
- return;
- }
- }
- }
- }
-
- private boolean isConnected() {
- return mGoogleApiClient == null || !mGoogleApiClient.isConnected();
- }
-
- /**
- * Gets a screenshot to use with snapshots. Note that in practice you probably do not want to
- * use this approach because tablet screen sizes can become pretty large and because the image
- * will contain any UI and layout surrounding the area of interest.
- */
- Bitmap getScreenShot() {
- View root = findViewById(R.id.screen_main);
- Bitmap coverImage;
- try {
- root.setDrawingCacheEnabled(true);
- Bitmap base = root.getDrawingCache();
- coverImage = base.copy(base.getConfig(), false /* isMutable */);
- } catch (Exception ex) {
- Log.i(TAG, "Failed to create screenshot", ex);
- coverImage = null;
- } finally {
- root.setDrawingCacheEnabled(false);
- }
- return coverImage;
- }
-
-
- /** Shows the user's snapshots. */
- void showSnapshots(String title, boolean allowAdd, boolean allowDelete) {
- int maxNumberOfSavedGamesToShow = 5;
- Intent snapshotIntent = Games.Snapshots.getSelectSnapshotIntent(
- mGoogleApiClient, title, allowAdd, allowDelete, maxNumberOfSavedGamesToShow);
- startActivityForResult(snapshotIntent, RC_LIST_SAVED_GAMES);
- }
-
- /**
- * Loads a Snapshot from the user's synchronized storage.
- */
- void loadFromSnapshot(final SnapshotMetadata snapshotMetadata) {
- if (mLoadingDialog == null) {
- mLoadingDialog = new ProgressDialog(this);
- mLoadingDialog.setMessage(getString(R.string.loading_from_cloud));
- }
-
- mLoadingDialog.show();
-
- AsyncTask task = new AsyncTask() {
- @Override
- protected Integer doInBackground(Void... params) {
- Snapshots.OpenSnapshotResult result;
- if (snapshotMetadata != null && snapshotMetadata.getUniqueName() != null) {
- Log.i(TAG, "Opening snapshot by metadata: " + snapshotMetadata);
- result = Games.Snapshots.open(mGoogleApiClient,snapshotMetadata).await();
- } else {
- Log.i(TAG, "Opening snapshot by name: " + currentSaveName);
- result = Games.Snapshots.open(mGoogleApiClient, currentSaveName, true).await();
- }
-
- int status = result.getStatus().getStatusCode();
-
- Snapshot snapshot = null;
- if (status == GamesStatusCodes.STATUS_OK) {
- snapshot = result.getSnapshot();
- } else if (status == GamesStatusCodes.STATUS_SNAPSHOT_CONFLICT) {
-
- // if there is a conflict - then resolve it.
- snapshot = processSnapshotOpenResult(RC_LOAD_SNAPSHOT, result, 0);
-
- // if it resolved OK, change the status to Ok
- if (snapshot != null) {
- status = GamesStatusCodes.STATUS_OK;
- }
- else {
- Log.w(TAG,"Conflict was not resolved automatically");
- }
- } else {
- Log.e(TAG, "Error while loading: " + status);
- }
-
- if (snapshot != null) {
- try {
- readSavedGame(snapshot);
- } catch (IOException e) {
- Log.e(TAG, "Error while reading snapshot contents: " + e.getMessage());
- }
- }
- return status;
- }
-
- @Override
- protected void onPostExecute(Integer status) {
- Log.i(TAG, "Snapshot loaded: " + status);
-
- // Note that showing a toast is done here for debugging. Your application should
- // resolve the error appropriately to your app.
- if (status == GamesStatusCodes.STATUS_SNAPSHOT_NOT_FOUND) {
- Log.i(TAG, "Error: Snapshot not found");
- Toast.makeText(getBaseContext(), "Error: Snapshot not found",
- Toast.LENGTH_SHORT).show();
- } else if (status == GamesStatusCodes.STATUS_SNAPSHOT_CONTENTS_UNAVAILABLE) {
- Log.i(TAG, "Error: Snapshot contents unavailable");
- Toast.makeText(getBaseContext(), "Error: Snapshot contents unavailable",
- Toast.LENGTH_SHORT).show();
- } else if (status == GamesStatusCodes.STATUS_SNAPSHOT_FOLDER_UNAVAILABLE) {
- Log.i(TAG, "Error: Snapshot folder unavailable");
- Toast.makeText(getBaseContext(), "Error: Snapshot folder unavailable.",
- Toast.LENGTH_SHORT).show();
- }
-
- if (mLoadingDialog != null && mLoadingDialog.isShowing()) {
- mLoadingDialog.dismiss();
- mLoadingDialog = null;
- }
- hideAlertBar();
- updateUi();
- }
- };
-
- task.execute();
- }
-
- private void readSavedGame(Snapshot snapshot) throws IOException {
- mSaveGame = new SaveGame(snapshot.getSnapshotContents().readFully());
- mAlreadyLoadedState = true;
- }
-
- /**
- * Conflict resolution for when Snapshots are opened.
- *
- * @param requestCode - the request currently being processed. This is used to forward on the
- * information to another activity, or to send the result intent.
- * @param result The open snapshot result to resolve on open.
- * @param retryCount - the current iteration of the retry. The first retry should be 0.
- * @return The opened Snapshot on success; otherwise, returns null.
- */
- Snapshot processSnapshotOpenResult(int requestCode, Snapshots.OpenSnapshotResult result,
- int retryCount) {
-
- retryCount++;
- int status = result.getStatus().getStatusCode();
-
- Log.i(TAG, "Save Result status: " + status);
-
- 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) {
- final Snapshot snapshot = result.getSnapshot();
- final Snapshot conflictSnapshot = result.getConflictingSnapshot();
-
- ArrayList snapshotList = new ArrayList(2);
- snapshotList.add(snapshot);
- snapshotList.add(conflictSnapshot);
-
- selectSnapshotItem(requestCode, snapshotList, result.getConflictId(), retryCount);
- // display both to the user and allow them to select on
- }
- // Fail, return null.
- return null;
- }
-
- /**
- * Handles resolving the snapshot conflict asynchronously.
- *
- * @param requestCode - the request currently being processed. This is used to forward on the
- * information to another activity, or to send the result intent.
- * @param conflictId - the id of the conflict being resolved.
- * @param retryCount - the current iteration of the retry. The first retry should be 0.
- * @param snapshotMetadata - the metadata of the snapshot that is selected to resolve the conflict.
- */
- private void resolveSnapshotConflict(final int requestCode, final String conflictId,
- final int retryCount,
- final SnapshotMetadata snapshotMetadata) {
-
- Log.i(TAG,"Resolving conflict retry count = " + retryCount + " conflictid = " + conflictId);
- AsyncTask task =
- new AsyncTask() {
- @Override
- protected Snapshots.OpenSnapshotResult doInBackground(Void... voids) {
-
- Snapshots.OpenSnapshotResult result;
- if (snapshotMetadata.getUniqueName() != null) {
- Log.d(TAG,"Opening unique name " + snapshotMetadata.getUniqueName());
- result = Games.Snapshots.open(mGoogleApiClient, snapshotMetadata)
- .await();
- }
- else {
- Log.d(TAG,"Opening current save name " + currentSaveName);
- result = Games.Snapshots.open(mGoogleApiClient, currentSaveName, true)
- .await();
- }
-
- Log.d(TAG,"opening from metadata - result is " + result.getStatus() +
- " snapshot is " + result.getSnapshot());
-
- return Games.Snapshots
- .resolveConflict(mGoogleApiClient, conflictId, result.getSnapshot())
- .await();
- }
-
- @Override
- protected void onPostExecute(Snapshots.OpenSnapshotResult openSnapshotResult) {
- Snapshot snapshot = processSnapshotOpenResult(requestCode,
- openSnapshotResult,
- retryCount);
- Log.d(TAG,"resolved snapshot conflict - snapshot is " + snapshot);
- // if there is a snapshot returned, then pass it along to onActivityResult.
- // otherwise, another activity will be used to resolve the conflict so we
- // don't need to do anything here.
- if (snapshot != null) {
- Intent intent = new Intent("");
- intent.putExtra(SelectSnapshotActivity.SNAPSHOT_METADATA,
- snapshot.getMetadata().freeze());
- onActivityResult(requestCode, RESULT_OK, intent);
- }
- }
- };
-
- task.execute();
- }
-
-
- /**
- * Prepares saving Snapshot to the user's synchronized storage, conditionally resolves errors,
- * and stores the Snapshot.
- */
- void saveSnapshot(final SnapshotMetadata snapshotMetadata) {
- AsyncTask task =
- new AsyncTask() {
- @Override
- protected Snapshots.OpenSnapshotResult doInBackground(Void... params) {
- if (snapshotMetadata == null) {
- Log.i(TAG, "Calling open with " + currentSaveName);
- return Games.Snapshots.open(mGoogleApiClient, currentSaveName, true)
- .await();
- }
- else {
- Log.i(TAG, "Calling open with " + snapshotMetadata);
- return Games.Snapshots.open(mGoogleApiClient, snapshotMetadata)
- .await();
- }
- }
-
- @Override
- protected void onPostExecute(Snapshots.OpenSnapshotResult result) {
- Snapshot toWrite = processSnapshotOpenResult(RC_SAVE_SNAPSHOT, result, 0);
- if (toWrite != null) {
- Log.i(TAG, writeSnapshot(toWrite));
- }
- else {
- Log.e(TAG, "Error opening snapshot: " + result.toString());
- }
- }
- };
-
- task.execute();
- }
-
- /**
- * Generates metadata, takes a screenshot, and performs the write operation for saving a
- * snapshot.
- */
- private String writeSnapshot(Snapshot snapshot) {
- // Set the data payload for the snapshot.
- snapshot.getSnapshotContents().writeBytes(mSaveGame.toBytes());
-
- // Save the snapshot.
- SnapshotMetadataChange metadataChange = new SnapshotMetadataChange.Builder()
- .setCoverImage(getScreenShot())
- .setDescription("Modified data at: " + Calendar.getInstance().getTime())
- .build();
- Games.Snapshots.commitAndClose(mGoogleApiClient, snapshot, metadataChange);
- return snapshot.toString();
- }
-
-
- /** Shows the "sign in" bar (explanation and button). */
- private void showSignInBar() {
- findViewById(R.id.sign_in_bar).setVisibility(View.VISIBLE);
- findViewById(R.id.sign_out_bar).setVisibility(View.GONE);
- }
-
- /** Shows the "sign out" bar (explanation and button). */
- private void showSignOutBar() {
- findViewById(R.id.sign_in_bar).setVisibility(View.GONE);
- findViewById(R.id.sign_out_bar).setVisibility(View.VISIBLE);
- }
-
-
- /** Updates the game UI. */
- private void updateUi() {
- ((TextView) findViewById(R.id.world_display)).setText(getString(R.string.world)
- + " " + mWorld);
- for (int i = 0; i < LEVELS_PER_WORLD; i++) {
- int levelNo = i + 1; // levels are numbered from 1
- Button b = (Button) findViewById(LEVEL_BUTTON_IDS[i]);
- int stars = mSaveGame.getLevelStars(mWorld, levelNo);
- b.setTextColor(getResources().getColor(stars > 0 ? R.color.ClearedLevelColor :
- R.color.UnclearedLevelColor));
- b.setText(String.valueOf(mWorld) + "-" + String.valueOf(levelNo) + "\n" +
- STAR_STRINGS[stars]);
- }
- // disable world changing if we are at the end of the list.
- Button button;
-
- button = (Button) findViewById(R.id.button_next_world);
- button.setEnabled(mWorld < WORLD_MAX);
-
- button = (Button) findViewById(R.id.button_prev_world);
- button.setEnabled(mWorld > WORLD_MIN);
- }
-
-
- /**
- * Loads the specified level state.
- *
- * @param level - level to load.
- */
- private void launchLevel(int level) {
- mLevel = level;
- ((TextView) findViewById(R.id.gameplay_level_display)).setText(
- getString(R.string.level) + " " + mWorld + "-" + mLevel);
- ((RatingBar) findViewById(R.id.gameplay_rating)).setRating(
- mSaveGame.getLevelStars(mWorld, mLevel));
- findViewById(R.id.screen_gameplay).setVisibility(View.VISIBLE);
- findViewById(R.id.screen_main).setVisibility(View.GONE);
- mInLevel = true;
- }
-
-
- @Override
- public void onRatingChanged(RatingBar ratingBar, float rating, boolean fromUser) {
- mSaveGame.setLevelStars(mWorld, mLevel, (int) rating);
- updateUi();
- findViewById(R.id.screen_gameplay).setVisibility(View.GONE);
- findViewById(R.id.screen_main).setVisibility(View.VISIBLE);
-
- mInLevel = false;
- // save new data to cloud
- saveSnapshot(null);
- }
-
- /** Prints a log message (convenience method). */
- void log(String message) {
- Log.d(TAG, message);
- }
-
-
- /** Shows an alert message. */
- private void showAlertBar(int resId) {
- ((TextView) findViewById(R.id.alert_bar)).setText(getString(resId));
- findViewById(R.id.alert_bar).setVisibility(View.VISIBLE);
- }
-
-
- /** Dismisses the previously displayed alert message. */
- private void hideAlertBar() {
- View alertBar = findViewById(R.id.alert_bar);
- if (alertBar != null && alertBar.getVisibility() != View.GONE) {
- alertBar.setVisibility(View.GONE);
- }
- }
-
-
- /**
- * This is an example of how to call Games.Snapshots.load(). It displays another
- * activity to allow the user to select the snapshot. It is recommended to use the
- * standard selection intent, Games.Snapshots.getSelectSnapshotIntent().
- */
- private void selectSnapshot() {
- if (mLoadingDialog == null) {
- mLoadingDialog = new ProgressDialog(this);
- mLoadingDialog.setMessage(getString(R.string.loading_from_cloud));
- }
- mLoadingDialog.show();
-
- //Start an asynchronous task to read this snapshot and load it.
- AsyncTask task =
- new AsyncTask() {
- @Override
- protected Snapshots.LoadSnapshotsResult doInBackground(Void... params) {
-
- Log.i(TAG, "Listing snapshots");
- return Games.Snapshots.load(mGoogleApiClient, false).await();
- }
-
- @Override
- protected void onPostExecute(Snapshots.LoadSnapshotsResult snapshotResults) {
-
- if (mLoadingDialog != null && mLoadingDialog.isShowing()) {
- mLoadingDialog.dismiss();
- mLoadingDialog = null;
- }
- int status = snapshotResults.getStatus().getStatusCode();
-
- // Note that showing a toast is done here for debugging. Your application should
- // resolve the error appropriately to your app.
- if (status == GamesStatusCodes.STATUS_SNAPSHOT_NOT_FOUND) {
- Log.i(TAG, "Error: Snapshot not found");
- Toast.makeText(getBaseContext(), "Error: Snapshot not found",
- Toast.LENGTH_SHORT).show();
- } else if (status
- == GamesStatusCodes.STATUS_SNAPSHOT_CONTENTS_UNAVAILABLE) {
- Log.i(TAG, "Error: Snapshot contents unavailable");
- Toast.makeText(getBaseContext(), "Error: Snapshot contents unavailable",
- Toast.LENGTH_SHORT).show();
- } else if (status == GamesStatusCodes.STATUS_SNAPSHOT_FOLDER_UNAVAILABLE) {
- Log.i(TAG, "Error: Snapshot folder unavailable");
- Toast.makeText(getBaseContext(), "Error: Snapshot folder unavailable.",
- Toast.LENGTH_SHORT).show();
- }
-
- ArrayList items = new ArrayList();
- for (SnapshotMetadata m : snapshotResults.getSnapshots()) {
- items.add(m);
- }
- selectSnapshotItem(RC_SELECT_SNAPSHOT, items);
-
- }
- };
-
- task.execute();
- }
-
- private void selectSnapshotItem(int requestCode, ArrayList items,
- String conflictId, int retryCount) {
-
- ArrayList snapshotList = new ArrayList(items.size());
- for (Snapshot m : items) {
- snapshotList.add(m.getMetadata().freeze());
- }
- Intent intent = new Intent(this, SelectSnapshotActivity.class);
- intent.putParcelableArrayListExtra(SelectSnapshotActivity.SNAPSHOT_METADATA_LIST,
- snapshotList);
-
- intent.putExtra(SelectSnapshotActivity.CONFLICT_ID, conflictId);
- intent.putExtra(SelectSnapshotActivity.RETRY_COUNT, retryCount);
-
- Log.d(TAG, "Starting activity to select snapshot");
- startActivityForResult(intent, requestCode);
- }
-
- private void selectSnapshotItem(int requestCode, ArrayList items) {
-
- ArrayList metadataArrayList =
- new ArrayList(items.size());
- for (SnapshotMetadata m : items) {
- metadataArrayList.add(m.freeze());
- }
- Intent intent = new Intent(this, SelectSnapshotActivity.class);
- intent.putParcelableArrayListExtra(SelectSnapshotActivity.SNAPSHOT_METADATA_LIST,
- metadataArrayList);
-
- startActivityForResult(intent, requestCode);
- }
-}
diff --git a/BasicSamples/CollectAllTheStars2/src/main/java/com/google/example/games/catt2/SaveGame.java b/BasicSamples/CollectAllTheStars2/src/main/java/com/google/example/games/catt2/SaveGame.java
deleted file mode 100644
index 12100a27..00000000
--- a/BasicSamples/CollectAllTheStars2/src/main/java/com/google/example/games/catt2/SaveGame.java
+++ /dev/null
@@ -1,271 +0,0 @@
-/* Copyright (C) 2014 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.catt2;
-
-import java.util.HashMap;
-import java.util.Iterator;
-import java.util.Map;
-import android.util.Log;
-
-import org.json.JSONException;
-import org.json.JSONObject;
-
-import android.content.SharedPreferences;
-import android.os.Parcel;
-
-import com.google.android.gms.drive.Contents;
-import com.google.android.gms.games.snapshot.Snapshot;
-import com.google.android.gms.games.snapshot.SnapshotMetadata;
-
-/**
- * Represents the player's progress in the game. The player's progress is how many stars
- * they got on each level.
- *
- * @author Bruno Oliveira
- */
-public class SaveGame{
-
- private static final String TAG = "CollectAllTheStars";
-
- // serialization format version
- private static final String SERIAL_VERSION = "1.1";
-
- // Maps a level name (like "2-8") to the number of stars the user has in that level.
- // Any key that doesn't exist in this map is considered to be associated to the value 0.
- Map mLevelStars = new HashMap();
-
- // Minimum and maximum stars the player can have on a level
- public static final int MIN_STARS = 0, MAX_STARS = 5;
-
- /** Constructs an empty SaveGame object. No stars on no levels. */
- public SaveGame() {
- }
-
- /** Constructs a SaveGame object from serialized data. */
- public SaveGame(byte[] data) {
- if (data == null) return; // default progress
- loadFromJson(new String(data));
- }
-
- /** Constructs a SaveGame object from a JSON string. */
- public SaveGame(String json) {
- if (json == null) return; // default progress
- loadFromJson(json);
- }
-
- /** Constructs a SaveGame object by reading from a SharedPreferences. */
- public SaveGame(SharedPreferences sp, String key) {
- loadFromJson(sp.getString(key, ""));
- }
-
- /** Replaces this SaveGame's content with the content loaded from the given JSON string. */
- public void loadFromJson(String json) {
- zero();
- if (json == null || json.trim().equals("")) return;
-
- try {
- JSONObject obj = new JSONObject(json);
- String format = obj.getString("version");
- if (!format.equals(SERIAL_VERSION)) {
- throw new RuntimeException("Unexpected loot format " + format);
- }
- JSONObject levels = obj.getJSONObject("levels");
- Iterator> iter = levels.keys();
-
- while (iter.hasNext()) {
- String levelName = (String)iter.next();
- mLevelStars.put(levelName, levels.getInt(levelName));
- }
- }
- catch (JSONException ex) {
- ex.printStackTrace();
- Log.e(TAG, "Save data has a syntax error: " + json, ex);
-
- // Initializing with empty stars if the game file is corrupt.
- // NOTE: In your game, you want to try recovering from the snapshot payload.
- mLevelStars.clear();
- }
- catch (NumberFormatException ex) {
- ex.printStackTrace();
- throw new RuntimeException("Save data has an invalid number in it: " + json, ex);
- }
- }
-
- /** Serializes this SaveGame to an array of bytes. */
- public byte[] toBytes() {
- return toString().getBytes();
- }
-
- /** Serializes this SaveGame to a JSON string. */
- @Override
- public String toString() {
- try {
- JSONObject levels = new JSONObject();
- for (String levelName : mLevelStars.keySet()) {
- levels.put(levelName, mLevelStars.get(levelName));
- }
-
- JSONObject obj = new JSONObject();
- obj.put("version", SERIAL_VERSION);
- obj.put("levels", levels);
- return obj.toString();
- }
- catch (JSONException ex) {
- ex.printStackTrace();
- throw new RuntimeException("Error converting save data to JSON.", ex);
- }
- }
-
- /**
- * Computes the union of this SaveGame with the given SaveGame. The union will have any
- * levels present in either operand. If the same level is present in both operands,
- * then the number of stars will be the greatest of the two.
- *
- * @param other The other operand with which to compute the union.
- * @return The result of the union.
- */
- public SaveGame unionWith(SaveGame other) {
- SaveGame result = clone();
- for (String levelName : other.mLevelStars.keySet()) {
- int existingStars = result.getLevelStars(levelName);
- int newStars = other.getLevelStars(levelName);
-
- // only overwrite if number of stars is greater
- if (newStars > existingStars) {
- result.setLevelStars(levelName, newStars);
- }
-
- // note that this code doesn't preserve mappings from a level to the value 0,
- // but that is not a problem because, in our semantics, the absence of a mapping
- // is equivalent to mapping to 0 stars.
- }
- return result;
- }
-
- /** Returns a clone of this SaveGame object. */
- public SaveGame clone() {
- SaveGame result = new SaveGame();
- for (String levelName : mLevelStars.keySet()) {
- result.setLevelStars(levelName, getLevelStars(levelName));
- }
- return result;
- }
-
- /** Resets this SaveGame object to be empty. Empty means no stars on no levels. */
- public void zero() {
- mLevelStars.clear();
- }
-
- /** Returns whether or not this SaveGame is empty. Empty means no stars on no levels. */
- public boolean isZero() {
- return mLevelStars.keySet().size() == 0;
- }
-
- /** Save this SaveGame object to a SharedPreferences. */
- public void save(SharedPreferences sp, String key) {
- SharedPreferences.Editor spe = sp.edit();
- spe.putString(key, toString());
- spe.commit();
- }
-
- /**
- * Gets how many stars the player has on the given level. If the level does not exist
- * in the save game, will return 0.
- */
- public int getLevelStars(String levelName) {
- Integer r = mLevelStars.get(levelName);
- return r == null ? 0 : r.intValue();
- }
-
- /**
- * Gets how many stars the player has on the given level. If the level does not exist
- * in the save game, will return 0.
- */
- public int getLevelStars(int world, int level) {
- return getLevelStars(String.valueOf(world) + "-" + String.valueOf(level));
- }
-
- /** Sets how many stars the player has on the given level. */
- public void setLevelStars(String levelName, int stars) {
- if (stars < MIN_STARS) stars = MIN_STARS;
- if (stars > MAX_STARS) stars = MAX_STARS;
- if (stars == 0) {
- // zero stars means remove it from the map
- if (mLevelStars.containsKey(levelName)) {
- mLevelStars.remove(levelName);
- }
- } else {
- mLevelStars.put(levelName, stars);
- }
- }
-
- /** Sets how many stars the player has on the given level. */
- public void setLevelStars(int world, int level, int stars) {
- setLevelStars(String.valueOf(world) + "-" + String.valueOf(level), stars);
- }
-
- /** Implementation of Snapshot interface. */
- /*
- @Override
- public byte[] readFully() {
- return new byte[0];
- }
-
- @Override
- public void writeToParcel(Parcel parcel, int i) {
-
- }
-
- @Override
- public boolean writeBytes(byte[] bytes) {
- return false;
- }
-
- @Override
- public void jy() {
-
- }
-
- @Override
- public boolean modifyBytes(int i, byte[] bytes, int i2, int i3) {
- return false;
- }
-
- @Override
- public boolean isDataValid() {
- return false;
- }
-
- @Override
- public int describeContents() {
- return 0;
- }
-
- @Override
- public Snapshot freeze() {
- return null;
- }
-
- @Override
- public SnapshotMetadata getMetadata() {
- return null;
- }
-
- @Override
- public Contents getContents() {
- return null;
- }*/
-}
diff --git a/BasicSamples/CollectAllTheStars2/src/main/java/com/google/example/games/catt2/SelectSnapshotActivity.java b/BasicSamples/CollectAllTheStars2/src/main/java/com/google/example/games/catt2/SelectSnapshotActivity.java
deleted file mode 100644
index 57505596..00000000
--- a/BasicSamples/CollectAllTheStars2/src/main/java/com/google/example/games/catt2/SelectSnapshotActivity.java
+++ /dev/null
@@ -1,193 +0,0 @@
-/* Copyright (C) 2014 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.catt2;
-
-import com.google.android.gms.common.images.ImageManager;
-import com.google.android.gms.games.snapshot.Snapshot;
-import com.google.android.gms.games.snapshot.SnapshotMetadata;
-
-import android.app.Activity;
-import android.content.Context;
-import android.content.Intent;
-import android.os.Bundle;
-import android.util.Log;
-import android.view.LayoutInflater;
-import android.view.View;
-import android.view.ViewGroup;
-import android.widget.AdapterView;
-import android.widget.ArrayAdapter;
-import android.widget.ImageView;
-import android.widget.ListView;
-import android.widget.TextView;
-
-import java.util.ArrayList;
-
-/**
- * Activity to select a snapshot from a list of snapshots or snapshot metadata. The intended
- * use of this activity is to present a choice of two conflicting snapshots to the user so
- * they can select the "best" snapshot.
- *
- * There is also a code path that loads all the saved games and presents this list, which is not
- * expected to be "production" code, but rather demonstrate how the Snapshots.load() method works.
- *
- * @author Clayton Wilkinson (Google)
- */
-public class SelectSnapshotActivity extends Activity implements AdapterView.OnItemClickListener {
-
- private static final String TAG = "CollectAllTheStars2.SelectSnapshotActivity";
- // intent data which is a snapshot metadata
- public static final String SNAPSHOT_METADATA = "snapshotmeta";
-
- // intent data that is a list of snapshot metadatas.
- public static final String SNAPSHOT_METADATA_LIST = "snapshotmetaList";
-
- // intent data that is the conflict id. used when resolving a conflict.
- public static final String CONFLICT_ID = "conflictId";
-
- // intent data that is the retry count for retrying the conflict resolution.
- public static final String RETRY_COUNT = "retrycount";
-
- // keep these variables for the current activity and return them in the result.
- private String mConflictId;
-
- private int mRetryCount;
-
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.activity_select_snapshot);
-
- //expect the intent to include the list of snapshots or snapshot metadatas to display
- Intent intent = getIntent();
- if (intent != null) {
- ArrayList snapshotMetadataList;
- ListView vw = (ListView) findViewById(R.id.snapshot_list);
-
- snapshotMetadataList = intent.getParcelableArrayListExtra(SNAPSHOT_METADATA_LIST);
- // set a custom list adapter that can display the image and other
- // information about a snapshot.
- vw.setAdapter(
- new SnapshotListAdapter(this, snapshotMetadataList));
-
- mConflictId = intent.getStringExtra(CONFLICT_ID);
- mRetryCount = intent.getIntExtra(RETRY_COUNT, 0);
-
- // register this class as the listener for when an item is selected
- vw.setOnItemClickListener(this);
- }
- }
-
-
- @Override
- public void onItemClick(AdapterView> adapterView, View view, int position, long listId) {
-
- SnapshotMetadata selected = (SnapshotMetadata) adapterView.getItemAtPosition(position);
- Intent intent = new Intent(Intent.ACTION_DEFAULT);
-
- intent.putExtra(SNAPSHOT_METADATA, selected.freeze());
-
- if (mConflictId != null) {
- intent.putExtra(CONFLICT_ID, mConflictId);
- intent.putExtra(RETRY_COUNT, mRetryCount);
- }
-
- Log.d(TAG, "Finishing item at position " + position + " clicked");
- setResult(RESULT_OK, intent);
- finish();
- }
-
- /**
- * Custom mSnapshotMetadataArrayList adapter which holds the snapshot metadata. This is used
- * to
- * display the image and information for each snapshot.
- */
- static class SnapshotListAdapter extends ArrayAdapter {
-
-
- public SnapshotListAdapter(Activity activity, ArrayList data) {
- super(activity, R.layout.snapshotlayout, data);
- }
-
- @Override
- public View getView(int position, View convertView, ViewGroup parent) {
-
- // load the view used for each item in the mSnapshotMetadataArrayList
- LayoutInflater inflater = (LayoutInflater) getContext().getSystemService(
- Context.LAYOUT_INFLATER_SERVICE);
- View rowView = inflater.inflate(R.layout.snapshotlayout, parent, false);
-
- // get the elements of the view which display the specific data for the snapshot.
- TextView textView = (TextView) rowView.findViewById(R.id.label);
- TextView ageView = (TextView) rowView.findViewById(R.id.age);
- ImageView imageView = (ImageView) rowView.findViewById(R.id.icon);
-
- SnapshotMetadata snapshotMetadata;
- T item = getItem(position);
- if (item instanceof Snapshot) {
- snapshotMetadata = ((Snapshot) item).getMetadata();
- } else {
- snapshotMetadata = (SnapshotMetadata) item;
- }
- textView.setText(snapshotMetadata.getDescription());
- ageView.setText(getAge(snapshotMetadata.getLastModifiedTimestamp()));
- ImageManager.create(getContext())
- .loadImage(imageView, snapshotMetadata.getCoverImageUri());
-
- return rowView;
-
- }
-
-
- private static final long MILLIS_PER_MINUTE = 60 * 1000;
-
- private static final long MILLIS_PER_HOUR = 60 * MILLIS_PER_MINUTE;
-
- private static final long MILLIS_PER_DAY = 24 * MILLIS_PER_HOUR;
-
- /**
- * Helper function to convert the time difference into a string like "3 days ago"
- *
- * @param timestamp - the time to convert.
- * @return localized string, never null.
- */
- private String getAge(long timestamp) {
- long delta = System.currentTimeMillis() - timestamp;
- int days = (int) (delta / MILLIS_PER_DAY);
-
- delta = delta % MILLIS_PER_DAY;
- int hours = (int) (delta / MILLIS_PER_HOUR);
-
- delta = delta % MILLIS_PER_HOUR;
- int minutes = (int) (delta / MILLIS_PER_MINUTE);
-
- delta = (int) (delta % MILLIS_PER_MINUTE);
- int seconds = (int) delta / 1000;
-
- if (days > 0) {
- return getContext().getString(R.string.format_days_ago, days);
- }
- if (hours > 0) {
- return getContext().getString(R.string.format_hours_ago, hours);
- }
- if (minutes > 0) {
- return getContext().getString(R.string.format_minutes_ago, minutes);
- }
- if (seconds > 0) {
- return getContext().getString(R.string.format_seconds_ago, seconds);
- }
- return getContext().getString(R.string.moments_ago);
- }
- }
-}
diff --git a/BasicSamples/CollectAllTheStars2/src/main/res/drawable-ldpi/ic_launcher.png b/BasicSamples/CollectAllTheStars2/src/main/res/drawable-ldpi/ic_launcher.png
deleted file mode 100644
index 2c4a5b26..00000000
Binary files a/BasicSamples/CollectAllTheStars2/src/main/res/drawable-ldpi/ic_launcher.png and /dev/null differ
diff --git a/BasicSamples/CollectAllTheStars2/src/main/res/values-v11/styles.xml b/BasicSamples/CollectAllTheStars2/src/main/res/values-v11/styles.xml
deleted file mode 100644
index 3d45cb70..00000000
--- a/BasicSamples/CollectAllTheStars2/src/main/res/values-v11/styles.xml
+++ /dev/null
@@ -1,28 +0,0 @@
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/BasicSamples/SavedGames/.gitignore b/BasicSamples/SavedGames/.gitignore
deleted file mode 100644
index 796b96d1..00000000
--- a/BasicSamples/SavedGames/.gitignore
+++ /dev/null
@@ -1 +0,0 @@
-/build
diff --git a/BasicSamples/SavedGames/README.md b/BasicSamples/SavedGames/README.md
deleted file mode 100644
index 6364b83e..00000000
--- a/BasicSamples/SavedGames/README.md
+++ /dev/null
@@ -1,59 +0,0 @@
-# SavedGames
-This sample demonstrates how to migrate data from the Cloud Save (AppState) service to the Saved
-Games (Snapshot) service.
-
-## Background
-All developers should use the Saved Games API in place of the old Cloud Save API. Here is a
-feature comparison of the two services:
-
-* Saved Games can store unlimited Snapshots per user with up to 3MB of raw data and 800KB of
-metadata each, up to the quota of the user's Google Drive storage. Cloud Save can only store 4
-AppState saves per user with a max size of 256KB each.
-* Saved Games separates data from metadata and provides a rich set of standard metadata
-attributes such as description, total play time, and a cover image for each Snapshot.
-Cloud Save stores only raw data.
-* Saved Games has a built-in UI with Material Design that can be launched with an
-`Intent` to allow users to select, create, and delete Snapshots. Cloud Save requires
-the developer to build a custom selection UI for each app.
-
-## Setup
-Follow these steps to set up the sample:
-
-1. Update the package name in `AndroidManifest.xml` to be something other than
-`com.google.example.games.savedgames`. The package name must be unique; otherwise,
-the API console cannot link your app correctly.
-1. Create your project in the Google Play Developer Console.
-1. Enable **Saved Games** on the Game Details page when creating your app in order to enable the
-Snapshots API.
-1. Link your app.
-1. Copy the `APP_ID` from the console into `values/ids.xml`.
-1. If you are using Android Studio, resync gradle and build the SavedGames module.
-
-## Requirements
-If you are migrating an app from Cloud Save to Saved Games, there are a few things you will need to do
-before you can begin using the Snapshots API:
-
-* Snapshots are stored in the user's Google Drive, so you will need to use the Drive API (`Drive.API`)
-along with the App Folder Scope (`Drive.SCOPE_APPFOLDER)` when creating your `GoogleApiClient`.
-* In the Google Play Developers Console, make sure to enable the Saved Games feature on your app
-in the Game Details tab. If you do not enable this feature, your app will crash when attempting to
-access the Snapshots API.
-
-## Running the Sample
-1. Press the **Run** button in Android Studio and select a target device. When the app starts, the
-Play Games UI appears.
-
-## Migrating Data from Cloud Save to Saved Games
-1. Sign in to the app.
-1. Create some AppState data by entering some text into the text field at the top of the screen
-and then pressing the **Update** button under **Cloud Save Actions**. Then click the **Load**
-button under Cloud Save Actions to ensure that the data was correctly saved.
-1. Migrate the data from AppState to Snapshots by pressing the **Migrate** button under **Cloud Save
-Actions**. Then press the **Load** button under **Saved Games Actions** to ensure that the data
-was correctly migrated.
-1. Once the data has been migrated from Cloud Save to Saved Games, explore the actions under
-**Saved Games Actions** to view and edit the saved data.
-
-## Next Steps
-For a complete overview of Saved Games on Android and a comparison to the Cloud Save API, see the
-[Saved Games in Android](https://developers.google.com/games/services/android/savedgames) page.
\ No newline at end of file
diff --git a/BasicSamples/SavedGames/build.gradle b/BasicSamples/SavedGames/build.gradle
deleted file mode 100644
index 474c187d..00000000
--- a/BasicSamples/SavedGames/build.gradle
+++ /dev/null
@@ -1,34 +0,0 @@
-apply plugin: 'android'
-
-android {
- compileSdkVersion 20
- buildToolsVersion "20.0.0"
-
- defaultConfig {
- minSdkVersion 9
- targetSdkVersion 20
- versionCode 1
- versionName "1.0"
- }
- buildTypes {
- release {
- minifyEnabled false
- proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
- }
- }
-}
-
-dependencies {
- compile project(':libraries:BaseGameUtils')
- compile 'com.android.support:appcompat-v7:20.0.+'
- compile 'com.android.support:support-v4:20.0.+'
- compile 'com.google.android.gms:play-services:+'
-}
-
-buildscript {
- repositories {
- mavenCentral()
- }
-}
-
-
diff --git a/BasicSamples/SavedGames/src/main/AndroidManifest.xml b/BasicSamples/SavedGames/src/main/AndroidManifest.xml
deleted file mode 100644
index bf75a69f..00000000
--- a/BasicSamples/SavedGames/src/main/AndroidManifest.xml
+++ /dev/null
@@ -1,50 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/BasicSamples/SavedGames/src/main/ic_launcher-web.png b/BasicSamples/SavedGames/src/main/ic_launcher-web.png
deleted file mode 100644
index 4b14629c..00000000
Binary files a/BasicSamples/SavedGames/src/main/ic_launcher-web.png and /dev/null differ
diff --git a/BasicSamples/SavedGames/src/main/java/com/google/example/games/savedgames/MainActivity.java b/BasicSamples/SavedGames/src/main/java/com/google/example/games/savedgames/MainActivity.java
deleted file mode 100644
index c27e1d06..00000000
--- a/BasicSamples/SavedGames/src/main/java/com/google/example/games/savedgames/MainActivity.java
+++ /dev/null
@@ -1,666 +0,0 @@
-/* Copyright (C) 2014 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.savedgames;
-
-import android.app.Activity;
-import android.app.ProgressDialog;
-import android.content.Intent;
-import android.graphics.Bitmap;
-import android.graphics.BitmapFactory;
-import android.graphics.Color;
-import android.os.AsyncTask;
-import android.os.Bundle;
-import android.util.Log;
-import android.view.View;
-import android.widget.EditText;
-import android.widget.TextView;
-
-import com.google.android.gms.appstate.AppStateManager;
-import com.google.android.gms.common.ConnectionResult;
-import com.google.android.gms.common.api.GoogleApiClient;
-import com.google.android.gms.common.api.PendingResult;
-import com.google.android.gms.common.api.ResultCallback;
-import com.google.android.gms.drive.Drive;
-import com.google.android.gms.games.Games;
-import com.google.android.gms.games.snapshot.Snapshot;
-import com.google.android.gms.games.snapshot.SnapshotMetadata;
-import com.google.android.gms.games.snapshot.SnapshotMetadataChange;
-import com.google.android.gms.games.snapshot.Snapshots;
-import com.google.example.games.basegameutils.BaseGameUtils;
-
-import java.io.IOException;
-
-/**
- * SavedGames. A sample that demonstrates how to migrate from the Cloud Save (AppState) API to the
- * newer Saved Games (Snapshots) API. The app allows load/update to both services as well as an
- * example of migrating data from AppState to Snapshots.
- *
- * @author Sam Stern (samstern@google.com)
- */
-public class MainActivity extends Activity implements View.OnClickListener,
- GoogleApiClient.ConnectionCallbacks, GoogleApiClient.OnConnectionFailedListener {
-
- public static final String TAG = "SavedGames";
-
- // The AppState slot we are editing. For simplicity this sample only manipulates a single
- // Cloud Save slot and a corresponding Snapshot entry, This could be changed to any integer
- // 0-3 without changing functionality (Cloud Save has four slots, numbered 0-3).
- private static final int APP_STATE_KEY = 0;
-
- // Request code used to invoke sign-in UI.
- private static final int RC_SIGN_IN = 9001;
-
- // Request code used to invoke Snapshot selection UI.
- private static final int RC_SELECT_SNAPSHOT = 9002;
-
- /// Client used to interact with Google APIs.
- private GoogleApiClient mGoogleApiClient;
-
- // Progress Dialog used to display loading messages.
- private ProgressDialog mProgressDialog;
-
- // True when the application is attempting to resolve a sign-in error that has a possible
- // resolution,
- private boolean mIsResolving = false;
-
- // True immediately after the user clicks the sign-in button/
- private boolean mSignInClicked = false;
-
- // True if we want to automatically attempt to sign in the user at application start.
- private boolean mAutoStartSignIn = true;
-
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.activity_main);
-
- // Build API client with access to Games, AppState, and SavedGames.
- // It is very important to add Drive or the SavedGames API will not work
- // Make sure to also go to console.developers.google.com and enable the Drive API for your
- // project
- mGoogleApiClient = new GoogleApiClient.Builder(this)
- .addConnectionCallbacks(this)
- .addOnConnectionFailedListener(this)
- .addApi(Games.API).addScope(Games.SCOPE_GAMES) // Games
- .addApi(AppStateManager.API).addScope(AppStateManager.SCOPE_APP_STATE) // AppState
- .addScope(Drive.SCOPE_APPFOLDER) // SavedGames
- .build();
-
- // Set up button listeners
- findViewById(R.id.button_sign_in).setOnClickListener(this);
-
- findViewById(R.id.button_cloud_save_load).setOnClickListener(this);
- findViewById(R.id.button_cloud_save_update).setOnClickListener(this);
- findViewById(R.id.button_cloud_save_migrate).setOnClickListener(this);
-
- findViewById(R.id.button_saved_games_load).setOnClickListener(this);
- findViewById(R.id.button_saved_games_update).setOnClickListener(this);
- findViewById(R.id.button_saved_games_select).setOnClickListener(this);
- }
-
- @Override
- protected void onStart() {
- super.onStart();
- mGoogleApiClient.connect();
- updateUI();
- }
-
- @Override
- protected void onStop() {
- super.onStop();
- if (mGoogleApiClient != null && mGoogleApiClient.isConnected()) {
- mGoogleApiClient.disconnect();
- }
- }
-
- @Override
- protected void onActivityResult(int requestCode, int resultCode, Intent data) {
- super.onActivityResult(requestCode, resultCode, data);
- dismissProgressDialog();
-
- if (requestCode == RC_SIGN_IN) {
- Log.d(TAG, "onActivityResult: RC_SIGN_IN, resultCode = " + resultCode);
- mSignInClicked = false;
- mIsResolving = false;
-
- if (resultCode == RESULT_OK) {
- // Sign-in was successful, connect the API Client
- Log.d(TAG, "onActivityResult: RC_SIGN_IN (OK)");
- mGoogleApiClient.connect();
- } else {
- // There was an error during sign-in, display a Dialog with the appropriate message
- // to the user.
- Log.d(TAG, "onActivityResult: RC_SIGN_IN (Error)");
- BaseGameUtils.showActivityResultError(this, requestCode, resultCode, R.string.signin_other_error);
- }
- } else if (requestCode == RC_SELECT_SNAPSHOT) {
- Log.d(TAG, "onActivityResult: RC_SELECT_SNAPSHOT, resultCode = " + resultCode);
- if (resultCode == RESULT_OK) {
- // Successfully returned from Snapshot selection UI
- if (data != null) {
- Bundle bundle = data.getExtras();
- SnapshotMetadata selected = Games.Snapshots.getSnapshotFromBundle(bundle);
- if (selected == null) {
- // No snapshot in the Intent bundle, display error message
- displayMessage(getString(R.string.saved_games_select_failure), true);
- setData(null);
- displaySnapshotMetadata(null);
- } else {
- // Found Snapshot Metadata in Intent bundle. Load Snapshot by name.
- String snapshotName = selected.getUniqueName();
- savedGamesLoad(snapshotName);
- }
- }
- } else {
- // User canceled the select intent or it failed for some other reason
- displayMessage(getString(R.string.saved_games_select_cancel), true);
- setData(null);
- displaySnapshotMetadata(null);
- }
- }
- }
-
- @Override
- public void onConnected(Bundle connectionHint) {
- Log.d(TAG, "onConnected");
- updateUI();
- }
-
- @Override
- public void onConnectionSuspended(int i) {
- Log.d(TAG, "onConnectionSuspended: " + i);
- mGoogleApiClient.connect();
- updateUI();
- }
-
- @Override
- public void onConnectionFailed(ConnectionResult connectionResult) {
- Log.d(TAG, "onConnectionFailed");
- if (mIsResolving) {
- // The application is attempting to resolve this connection failure already.
- Log.d(TAG, "onConnectionFailed: already resolving");
- return;
- }
-
- if (mSignInClicked || mAutoStartSignIn) {
- mSignInClicked = false;
- mAutoStartSignIn = false;
-
- // Attempt to resolve the connection failure.
- Log.d(TAG, "onConnectionFailed: begin resolution.");
- mIsResolving = BaseGameUtils.resolveConnectionFailure(this, mGoogleApiClient,
- connectionResult, RC_SIGN_IN, getString(R.string.signin_other_error));
- }
-
- updateUI();
- }
-
- @Override
- public void onClick(View v) {
- switch (v.getId()) {
- case R.id.button_sign_in:
- beginUserInitiatedSignIn();
- break;
- case R.id.button_cloud_save_load:
- cloudSaveLoad();
- break;
- case R.id.button_cloud_save_update:
- cloudSaveUpdate();
- break;
- case R.id.button_cloud_save_migrate:
- cloudSaveMigrate();
- break;
- case R.id.button_saved_games_load:
- savedGamesLoad(makeSnapshotName(APP_STATE_KEY));
- break;
- case R.id.button_saved_games_update:
- savedGamesUpdate();
- break;
- case R.id.button_saved_games_select:
- savedGamesSelect();
- break;
- }
- }
-
- /**
- * Start the sign-in process after the user clicks the sign-in button.
- */
- private void beginUserInitiatedSignIn() {
- Log.d(TAG, "beginUserInitiatedSignIn");
- // Check to see the developer who's running this sample code read the instructions :-)
- // NOTE: this check is here only because this is a sample! Don't include this
- // check in your actual production app.
- if (!BaseGameUtils.verifySampleSetup(this, R.string.app_id)) {
- Log.w(TAG, "*** Warning: setup problems detected. Sign in may not work!");
- }
-
- showProgressDialog("Signing in.");
- mSignInClicked = true;
- mGoogleApiClient.connect();
- }
-
- /**
- * Async load AppState from Cloud Save. This will load using stateKey APP_STATE_KEY. After load,
- * the AppState data and metadata will be displayed.
- */
- private void cloudSaveLoad() {
- PendingResult pendingResult = AppStateManager.load(
- mGoogleApiClient, APP_STATE_KEY);
-
- showProgressDialog("Loading Cloud Save");
- ResultCallback callback =
- new ResultCallback() {
- @Override
- public void onResult(AppStateManager.StateResult stateResult) {
- if (stateResult.getStatus().isSuccess()) {
- // Successfully loaded data from App State
- displayMessage(getString(R.string.cloud_save_load_success), false);
- byte[] data = stateResult.getLoadedResult().getLocalData();
- setData(new String(data));
- displayAppStateMetadata(stateResult.getLoadedResult().getStateKey());
- } else {
- // Failed to load data from App State
- displayMessage(getString(R.string.cloud_save_load_failure), true);
- clearDataUI();
- }
-
- dismissProgressDialog();
- }
- };
- pendingResult.setResultCallback(callback);
- }
-
- /**
- * Async update AppState data in Cloud Save. This will use stateKey APP_STATE_KEY. After save,
- * the UI will be cleared and the data will be available to load from Cloud Save.
- */
- private void cloudSaveUpdate() {
- // Use the data from the EditText as AppState data
- byte[] data = getData().getBytes();
-
- // Use updateImmediate to update the AppState data. This is used for diagnostic purposes
- // so that the app can display the result of the update, however it is generally recommended
- // to use AppStateManager.update(...) in order to reduce performance and battery impact.
- PendingResult pendingResult = AppStateManager.updateImmediate(
- mGoogleApiClient, APP_STATE_KEY, data);
-
- showProgressDialog("Updating Cloud Save");
- ResultCallback callback =
- new ResultCallback() {
- @Override
- public void onResult(AppStateManager.StateResult stateResult) {
- if (stateResult.getStatus().isSuccess()) {
- displayMessage(getString(R.string.cloud_save_update_success), false);
- } else {
- displayMessage(getString(R.string.cloud_save_update_failure), true);
- }
-
- dismissProgressDialog();
- clearDataUI();
- }
- };
- pendingResult.setResultCallback(callback);
- }
-
- /**
- * Async migrate the data in Cloud Save (stateKey APP_STATE_KEY) to a Snapshot in the Saved
- * Games service with unique snap 'Snapshot-{APP_STATE_KEY}'. If no such Snapshot exists,
- * create a Snapshot and populate all fields. If the Snapshot already exists, update the
- * appropriate data and metadata. After migrate, the UI will be cleared and the data will be
- * available to load from Snapshots.
- */
- private void cloudSaveMigrate() {
- final boolean createIfMissing = true;
-
- // Note: when migrating your users from Cloud Save to Saved Games, you will need to perform
- // the migration process at most once per device. You should keep track of the migration
- // status locally for each AppState data slot (using SharedPreferences or similar)
- // to avoid repeating network calls or migrating the same AppState data multiple times.
-
- // Compute SnapshotMetadata fields based on the information available from AppState. In
- // this case there is no data available to auto-generate a description, cover image, or
- // playedTime. It is strongly recommended that you generate unique and meaningful
- // values for these fields based on the data in your app.
- final String snapshotName = makeSnapshotName(APP_STATE_KEY);
- final String description = "Saved game #" + APP_STATE_KEY;
- final long playedTimeMillis = 60 * 60 * 1000;
- final Bitmap bitmap = BitmapFactory.decodeResource(getResources(), R.drawable.ic_launcher);
-
- AsyncTask migrateTask = new AsyncTask() {
- @Override
- protected void onPreExecute() {
- showProgressDialog("Migrating");
- }
-
- @Override
- protected Boolean doInBackground(Void... params) {
- // Get AppState Data
- AppStateManager.StateResult load = AppStateManager.load(
- mGoogleApiClient, APP_STATE_KEY).await();
-
- if (!load.getStatus().isSuccess()) {
- Log.w(TAG, "Could not load App State for migration.");
- return false;
- }
-
- // Get Data from AppState
- byte[] data = load.getLoadedResult().getLocalData();
-
- // Open the snapshot, creating if necessary
- Snapshots.OpenSnapshotResult open = Games.Snapshots.open(
- mGoogleApiClient, snapshotName, createIfMissing).await();
-
- if (!open.getStatus().isSuccess()) {
- Log.w(TAG, "Could not open Snapshot for migration.");
- // TODO: Handle Snapshot conflicts
- // Note: one reason for failure to open a Snapshot is conflicting saved games.
- // This is outside the scope of this sample, however you should resolve such
- // conflicts in your own app by following the steps outlined here:
- // https://developers.google.com/games/services/android/savedgames#handling_saved_game_conflicts
- return false;
- }
-
- // Write the new data to the snapshot
- Snapshot snapshot = open.getSnapshot();
- snapshot.getSnapshotContents().writeBytes(data);
-
- // Change metadata
- SnapshotMetadataChange metadataChange = new SnapshotMetadataChange.Builder()
- .fromMetadata(snapshot.getMetadata())
- .setCoverImage(bitmap)
- .setDescription(description)
- .setPlayedTimeMillis(playedTimeMillis)
- .build();
-
- Snapshots.CommitSnapshotResult commit = Games.Snapshots.commitAndClose(
- mGoogleApiClient, snapshot, metadataChange).await();
-
- if (!commit.getStatus().isSuccess()) {
- Log.w(TAG, "Failed to commit Snapshot.");
- return false;
- }
-
- // No failures
- return true;
- }
-
- @Override
- protected void onPostExecute(Boolean result) {
- if (result) {
- displayMessage(getString(R.string.cloud_save_migrate_success), false);
- } else {
- displayMessage(getString(R.string.cloud_save_migrate_failure), true);
- }
-
- dismissProgressDialog();
- clearDataUI();
- }
- };
- migrateTask.execute();
- }
-
- /**
- * Load a Snapshot from the Saved Games service based on its unique name. After load, the UI
- * will update to display the Snapshot data and SnapshotMetadata.
- * @param snapshotName the unique name of the Snapshot.
- */
- private void savedGamesLoad(String snapshotName) {
- PendingResult pendingResult = Games.Snapshots.open(
- mGoogleApiClient, snapshotName, false);
-
- showProgressDialog("Loading Saved Game");
- ResultCallback callback =
- new ResultCallback() {
- @Override
- public void onResult(Snapshots.OpenSnapshotResult openSnapshotResult) {
- if (openSnapshotResult.getStatus().isSuccess()) {
- displayMessage(getString(R.string.saved_games_load_success), false);
- byte[] data = new byte[0];
- try {
- data = openSnapshotResult.getSnapshot().getSnapshotContents().readFully();
- } catch (IOException e) {
- displayMessage("Exception reading snapshot: " + e.getMessage(), true);
- }
- setData(new String(data));
- displaySnapshotMetadata(openSnapshotResult.getSnapshot().getMetadata());
- } else {
- displayMessage(getString(R.string.saved_games_load_failure), true);
- clearDataUI();
- }
-
- dismissProgressDialog();
- }
- };
- pendingResult.setResultCallback(callback);
- }
-
- /**
- * Launch the UI to select a Snapshot from the user's Saved Games. The result of this
- * selection will be returned to onActivityResult.
- */
- private void savedGamesSelect() {
- final boolean allowAddButton = false;
- final boolean allowDelete = false;
- Intent intent = Games.Snapshots.getSelectSnapshotIntent(
- mGoogleApiClient, "Saved Games", allowAddButton, allowDelete,
- Snapshots.DISPLAY_LIMIT_NONE);
-
- showProgressDialog("Loading");
- startActivityForResult(intent, RC_SELECT_SNAPSHOT);
- }
-
- /**
- * Update the Snapshot in the Saved Games service with new data. Metadata is not affected,
- * however for your own application you will likely want to update metadata such as cover image,
- * played time, and description with each Snapshot update. After update, the UI will
- * be cleared.
- */
- private void savedGamesUpdate() {
- final String snapshotName = makeSnapshotName(APP_STATE_KEY);
- final boolean createIfMissing = false;
-
- // Use the data from the EditText as the new Snapshot data.
- final byte[] data = getData().getBytes();
-
- AsyncTask updateTask = new AsyncTask() {
- @Override
- protected void onPreExecute() {
- showProgressDialog("Updating Saved Game");
- }
-
- @Override
- protected Boolean doInBackground(Void... params) {
- Snapshots.OpenSnapshotResult open = Games.Snapshots.open(
- mGoogleApiClient, snapshotName, createIfMissing).await();
-
- if (!open.getStatus().isSuccess()) {
- Log.w(TAG, "Could not open Snapshot for update.");
- return false;
- }
-
- // Change data but leave existing metadata
- Snapshot snapshot = open.getSnapshot();
- snapshot.getSnapshotContents().writeBytes(data);
-
- Snapshots.CommitSnapshotResult commit = Games.Snapshots.commitAndClose(
- mGoogleApiClient, snapshot, SnapshotMetadataChange.EMPTY_CHANGE).await();
-
- if (!commit.getStatus().isSuccess()) {
- Log.w(TAG, "Failed to commit Snapshot.");
- return false;
- }
-
- // No failures
- return true;
- }
-
- @Override
- protected void onPostExecute(Boolean result) {
- if (result) {
- displayMessage(getString(R.string.saved_games_update_success), false);
- } else {
- displayMessage(getString(R.string.saved_games_update_failure), true);
- }
-
- dismissProgressDialog();
- clearDataUI();
- }
- };
- updateTask.execute();
- }
-
- /**
- * Generate a unique Snapshot name from an AppState stateKey.
- * @param appStateKey the stateKey for the Cloud Save data.
- * @return a unique Snapshot name that maps to the stateKey.
- */
- private String makeSnapshotName(int appStateKey) {
- return "Snapshot-" + String.valueOf(appStateKey);
- }
-
- /**
- * Display either the signed-in or signed-out view, depending on the user's state.
- */
- private void updateUI() {
- // Show signed in or signed out view
- if (isSignedIn()) {
- findViewById(R.id.layout_signed_in).setVisibility(View.VISIBLE);
- findViewById(R.id.layout_signed_out).setVisibility(View.GONE);
- displayMessage(getString(R.string.message_signed_in), false);
- } else {
- findViewById(R.id.layout_signed_in).setVisibility(View.GONE);
- findViewById(R.id.layout_signed_out).setVisibility(View.VISIBLE);
- displayMessage(getString(R.string.message_sign_in), false);
- }
- }
-
- /**
- * Replace the data displaying in the EditText.
- * @param data the String to display.
- */
- private void setData(String data) {
- EditText dataEditText = (EditText) findViewById(R.id.edit_game_data);
-
- if (data == null) {
- dataEditText.setText("");
- } else {
- dataEditText.setText(data);
- }
- }
-
- /**
- * Get the data from the EditText.
- * @return the String in the EditText, or "" if empty.
- */
- private String getData() {
- EditText dataEditText = (EditText) findViewById(R.id.edit_game_data);
- return dataEditText.getText().toString();
- }
-
- /**
- * Display a status message for the last operation at the bottom of the screen.
- * @param msg the message to display.
- * @param error true if an error occurred, false otherwise.
- */
- private void displayMessage(String msg, boolean error) {
- // Set text
- TextView messageView = (TextView) findViewById(R.id.text_message);
- messageView.setText(msg);
-
- // Set text color
- if (error) {
- messageView.setTextColor(Color.RED);
- } else {
- messageView.setTextColor(Color.BLACK);
- }
- }
-
- /**
- * Display metadata about AppState save data,
- * @param stateKey the slot stateKey of the AppState.
- */
- private void displayAppStateMetadata(int stateKey) {
- TextView metaDataView = (TextView) findViewById(R.id.text_metadata);
-
- String metadataStr = "Source: Cloud Save" + '\n'
- + "State Key: " + stateKey;
- metaDataView.setText(metadataStr);
- }
-
- /**
- * Display metadata about Snapshot save data.
- * @param metadata the SnapshotMetadata associated with the saved game.
- */
- private void displaySnapshotMetadata(SnapshotMetadata metadata) {
- TextView metaDataView = (TextView) findViewById(R.id.text_metadata);
-
- if (metadata == null) {
- metaDataView.setText("");
- return;
- }
-
- String metadataStr = "Source: Saved Games" + '\n'
- + "Description: " + metadata.getDescription() + '\n'
- + "Name: " + metadata.getUniqueName() + '\n'
- + "Last Modified: " + String.valueOf(metadata.getLastModifiedTimestamp()) + '\n'
- + "Played Time: " + String.valueOf(metadata.getPlayedTime()) + '\n'
- + "Cover Image URL: " + metadata.getCoverImageUrl();
- metaDataView.setText(metadataStr);
- }
-
- /**
- * Clear the data and metadata displays.
- */
- private void clearDataUI() {
- // Clear the Game Data field and the Metadata field
- EditText dataEditText = (EditText) findViewById(R.id.edit_game_data);
- TextView metaDataView = (TextView) findViewById(R.id.text_metadata);
-
- dataEditText.setText("");
- metaDataView.setText("");
- }
-
- /**
- * Determine if the Google API Client is signed in and ready to access Games APIs.
- * @return true if client exits and is signed in, false otherwise.
- */
- private boolean isSignedIn() {
- return (mGoogleApiClient != null && mGoogleApiClient.isConnected());
- }
-
- /**
- * Show a progress dialog for asynchronous operations.
- * @param msg the message to display.
- */
- private void showProgressDialog(String msg) {
- if (mProgressDialog == null) {
- mProgressDialog = new ProgressDialog(this);
- mProgressDialog.setIndeterminate(true);
- }
-
- mProgressDialog.setMessage(msg);
- mProgressDialog.show();
- }
-
- /**
- * Hide the progress dialog, if it was showing.
- */
- private void dismissProgressDialog() {
- if (mProgressDialog != null && mProgressDialog.isShowing()) {
- mProgressDialog.dismiss();
- }
- }
-}
diff --git a/BasicSamples/SavedGames/src/main/res/drawable-hdpi/ic_launcher.png b/BasicSamples/SavedGames/src/main/res/drawable-hdpi/ic_launcher.png
deleted file mode 100644
index c1b44ccc..00000000
Binary files a/BasicSamples/SavedGames/src/main/res/drawable-hdpi/ic_launcher.png and /dev/null differ
diff --git a/BasicSamples/SavedGames/src/main/res/drawable-mdpi/ic_launcher.png b/BasicSamples/SavedGames/src/main/res/drawable-mdpi/ic_launcher.png
deleted file mode 100644
index a1bf709d..00000000
Binary files a/BasicSamples/SavedGames/src/main/res/drawable-mdpi/ic_launcher.png and /dev/null differ
diff --git a/BasicSamples/SavedGames/src/main/res/drawable-xhdpi/ic_launcher.png b/BasicSamples/SavedGames/src/main/res/drawable-xhdpi/ic_launcher.png
deleted file mode 100644
index 3b5ae5b2..00000000
Binary files a/BasicSamples/SavedGames/src/main/res/drawable-xhdpi/ic_launcher.png and /dev/null differ
diff --git a/BasicSamples/SavedGames/src/main/res/drawable-xxhdpi/ic_launcher.png b/BasicSamples/SavedGames/src/main/res/drawable-xxhdpi/ic_launcher.png
deleted file mode 100644
index b7df51b1..00000000
Binary files a/BasicSamples/SavedGames/src/main/res/drawable-xxhdpi/ic_launcher.png and /dev/null differ
diff --git a/BasicSamples/SavedGames/src/main/res/layout/activity_main.xml b/BasicSamples/SavedGames/src/main/res/layout/activity_main.xml
deleted file mode 100644
index 4e934eb6..00000000
--- a/BasicSamples/SavedGames/src/main/res/layout/activity_main.xml
+++ /dev/null
@@ -1,153 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/BasicSamples/SavedGames/src/main/res/values-w820dp/dimens.xml b/BasicSamples/SavedGames/src/main/res/values-w820dp/dimens.xml
deleted file mode 100644
index 9eb52435..00000000
--- a/BasicSamples/SavedGames/src/main/res/values-w820dp/dimens.xml
+++ /dev/null
@@ -1,18 +0,0 @@
-
-
-
- 64dp
-
diff --git a/BasicSamples/SavedGames/src/main/res/values/dimens.xml b/BasicSamples/SavedGames/src/main/res/values/dimens.xml
deleted file mode 100644
index 318d9165..00000000
--- a/BasicSamples/SavedGames/src/main/res/values/dimens.xml
+++ /dev/null
@@ -1,17 +0,0 @@
-
-
-
- 16dp
- 16dp
-
diff --git a/BasicSamples/SavedGames/src/main/res/values/ids.xml b/BasicSamples/SavedGames/src/main/res/values/ids.xml
deleted file mode 100644
index c3dfe9f7..00000000
--- a/BasicSamples/SavedGames/src/main/res/values/ids.xml
+++ /dev/null
@@ -1,4 +0,0 @@
-
-
- APP_ID
-
diff --git a/BasicSamples/SavedGames/src/main/res/values/strings.xml b/BasicSamples/SavedGames/src/main/res/values/strings.xml
deleted file mode 100644
index dfaa1b79..00000000
--- a/BasicSamples/SavedGames/src/main/res/values/strings.xml
+++ /dev/null
@@ -1,42 +0,0 @@
-
-
-
-
- SavedGames
- Update
- Load
- Migrate
- Select
- There was an error during sign in.
- Sign-in to begin.
- Signed in.
- Loaded from Saved Games.
- Failed to load from Saved Games.
- Saved to Saved Games.
- Failed to save to Saved Games
- Failed to select from Saved Games.
- No Saved Game selected.
- Loaded from Cloud Save.
- Failed to load from Cloud Save.
- Saved to Cloud Save.
- Failed to save to Cloud Save.
- Migrated to Saved Games.
- Failed to migrate to Saved Games.
- Game Data:
- Metadata:
- Cloud Save Actions:
- Saved Game Actions:
- save data
-
-
diff --git a/BasicSamples/SavedGames/src/main/res/values/styles.xml b/BasicSamples/SavedGames/src/main/res/values/styles.xml
deleted file mode 100644
index 79f791ed..00000000
--- a/BasicSamples/SavedGames/src/main/res/values/styles.xml
+++ /dev/null
@@ -1,20 +0,0 @@
-
-
-
-
-
-
-
diff --git a/BasicSamples/SkeletonTbmp/.classpath b/BasicSamples/SkeletonTbmp/.classpath
deleted file mode 100644
index 51769745..00000000
--- a/BasicSamples/SkeletonTbmp/.classpath
+++ /dev/null
@@ -1,9 +0,0 @@
-
-
-
-
-
-
-
-
-
diff --git a/BasicSamples/SkeletonTbmp/.gitignore b/BasicSamples/SkeletonTbmp/.gitignore
deleted file mode 100644
index 84c048a7..00000000
--- a/BasicSamples/SkeletonTbmp/.gitignore
+++ /dev/null
@@ -1 +0,0 @@
-/build/
diff --git a/BasicSamples/SkeletonTbmp/.project b/BasicSamples/SkeletonTbmp/.project
deleted file mode 100644
index 905b5424..00000000
--- a/BasicSamples/SkeletonTbmp/.project
+++ /dev/null
@@ -1,33 +0,0 @@
-
-
- TbmpSkeleton
-
-
-
-
-
- com.android.ide.eclipse.adt.ResourceManagerBuilder
-
-
-
-
- com.android.ide.eclipse.adt.PreCompilerBuilder
-
-
-
-
- org.eclipse.jdt.core.javabuilder
-
-
-
-
- com.android.ide.eclipse.adt.ApkBuilder
-
-
-
-
-
- com.android.ide.eclipse.adt.AndroidNature
- org.eclipse.jdt.core.javanature
-
-
diff --git a/BasicSamples/SkeletonTbmp/build.gradle b/BasicSamples/SkeletonTbmp/build.gradle
deleted file mode 100644
index d6a339c7..00000000
--- a/BasicSamples/SkeletonTbmp/build.gradle
+++ /dev/null
@@ -1,34 +0,0 @@
-apply plugin: 'android'
-
-android {
- enforceUniquePackageName=false
-
- compileSdkVersion 20
- buildToolsVersion '20'
-
- defaultConfig {
- minSdkVersion 9
- targetSdkVersion 20
- versionCode 1
- versionName "1.0"
- }
- buildTypes {
- release {
- minifyEnabled false
- proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.txt'
- }
- }
-}
-
-dependencies {
- compile project(':libraries:BaseGameUtils')
- compile 'com.android.support:appcompat-v7:20.0.+'
- compile 'com.android.support:support-v4:20.0.+'
- compile 'com.google.android.gms:play-services:+'
-}
-
-buildscript {
- repositories {
- mavenCentral()
- }
-}
diff --git a/BasicSamples/SkeletonTbmp/src/main/AndroidManifest.xml b/BasicSamples/SkeletonTbmp/src/main/AndroidManifest.xml
deleted file mode 100644
index b74edecd..00000000
--- a/BasicSamples/SkeletonTbmp/src/main/AndroidManifest.xml
+++ /dev/null
@@ -1,29 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/BasicSamples/SkeletonTbmp/src/main/java/com/google/example/tbmpskeleton/SkeletonActivity.java b/BasicSamples/SkeletonTbmp/src/main/java/com/google/example/tbmpskeleton/SkeletonActivity.java
deleted file mode 100644
index 67b2d759..00000000
--- a/BasicSamples/SkeletonTbmp/src/main/java/com/google/example/tbmpskeleton/SkeletonActivity.java
+++ /dev/null
@@ -1,797 +0,0 @@
-/*
- * 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.tbmpskeleton;
-
-import java.util.ArrayList;
-
-import android.app.Activity;
-import android.app.AlertDialog;
-import android.content.DialogInterface;
-import android.content.Intent;
-import android.os.Bundle;
-import android.util.Log;
-import android.view.View;
-import android.widget.TextView;
-import android.widget.Toast;
-
-import com.google.android.gms.common.ConnectionResult;
-import com.google.android.gms.common.api.GoogleApiClient;
-import com.google.android.gms.common.api.ResultCallback;
-import com.google.android.gms.games.Games;
-import com.google.android.gms.games.GamesStatusCodes;
-import com.google.android.gms.games.multiplayer.Invitation;
-import com.google.android.gms.games.multiplayer.OnInvitationReceivedListener;
-import com.google.android.gms.games.multiplayer.realtime.RoomConfig;
-import com.google.android.gms.games.multiplayer.turnbased.OnTurnBasedMatchUpdateReceivedListener;
-import com.google.android.gms.games.multiplayer.turnbased.TurnBasedMatch;
-import com.google.android.gms.games.multiplayer.turnbased.TurnBasedMatchConfig;
-import com.google.android.gms.games.multiplayer.turnbased.TurnBasedMultiplayer;
-import com.google.android.gms.games.multiplayer.Multiplayer;
-import com.google.android.gms.plus.Plus;
-import com.google.example.games.basegameutils.BaseGameUtils;
-
-
-/**
- * TBMPSkeleton: A minimalistic "game" that shows turn-based
- * multiplayer features for Play Games Services. In this game, you
- * can invite a variable number of players and take turns editing a
- * shared state, which consists of single string. You can also select
- * automatch players; all known players play before automatch slots
- * are filled.
- *
- * INSTRUCTIONS: To run this sample, please set up
- * a project in the Developer Console. Then, place your app ID on
- * res/values/ids.xml. Also, change the package name to the package name you
- * used to create the client ID in Developer Console. Make sure you sign the
- * APK with the certificate whose fingerprint you entered in Developer Console
- * when creating your Client Id.
- *
- * @author Wolff (wolff@google.com), 2013
- */
-public class SkeletonActivity extends Activity
- implements GoogleApiClient.ConnectionCallbacks, GoogleApiClient.OnConnectionFailedListener,
- OnInvitationReceivedListener, OnTurnBasedMatchUpdateReceivedListener,
- View.OnClickListener {
-
- public static final String TAG = "SkeletonActivity";
-
- // Client used to interact with Google APIs
- private GoogleApiClient mGoogleApiClient;
-
- // Are we currently resolving a connection failure?
- private boolean mResolvingConnectionFailure = false;
-
- // Has the user clicked the sign-in button?
- private boolean mSignInClicked = false;
-
- // Automatically start the sign-in flow when the Activity starts
- private boolean mAutoStartSignInFlow = true;
-
- // Current turn-based match
- private TurnBasedMatch mTurnBasedMatch;
-
- // Local convenience pointers
- public TextView mDataView;
- public TextView mTurnTextView;
-
- private AlertDialog mAlertDialog;
-
- // For our intents
- private static final int RC_SIGN_IN = 9001;
- final static int RC_SELECT_PLAYERS = 10000;
- final static int RC_LOOK_AT_MATCHES = 10001;
-
- // How long to show toasts.
- final static int TOAST_DELAY = Toast.LENGTH_SHORT;
-
- // Should I be showing the turn API?
- public boolean isDoingTurn = false;
-
- // This is the current match we're in; null if not loaded
- public TurnBasedMatch mMatch;
-
- // This is the current match data after being unpersisted.
- // Do not retain references to match data once you have
- // taken an action on the match, such as takeTurn()
- public SkeletonTurn mTurnData;
-
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.activity_main);
-
- // Create the Google API Client with access to Plus and Games
- mGoogleApiClient = new GoogleApiClient.Builder(this)
- .addConnectionCallbacks(this)
- .addOnConnectionFailedListener(this)
- .addApi(Plus.API).addScope(Plus.SCOPE_PLUS_LOGIN)
- .addApi(Games.API).addScope(Games.SCOPE_GAMES)
- .build();
-
- // Setup signin and signout buttons
- findViewById(R.id.sign_out_button).setOnClickListener(this);
- findViewById(R.id.sign_in_button).setOnClickListener(this);
-
- mDataView = ((TextView) findViewById(R.id.data_view));
- mTurnTextView = ((TextView) findViewById(R.id.turn_counter_view));
- }
-
- @Override
- protected void onStart() {
- super.onStart();
- Log.d(TAG, "onStart(): Connecting to Google APIs");
- mGoogleApiClient.connect();
- }
-
- @Override
- protected void onStop() {
- super.onStop();
- Log.d(TAG, "onStop(): Disconnecting from Google APIs");
- if (mGoogleApiClient.isConnected()) {
- mGoogleApiClient.disconnect();
- }
- }
-
- @Override
- public void onConnected(Bundle connectionHint) {
- Log.d(TAG, "onConnected(): Connection successful");
-
- // Retrieve the TurnBasedMatch from the connectionHint
- if (connectionHint != null) {
- mTurnBasedMatch = connectionHint.getParcelable(Multiplayer.EXTRA_TURN_BASED_MATCH);
-
- if (mTurnBasedMatch != null) {
- if (mGoogleApiClient == null || !mGoogleApiClient.isConnected()) {
- Log.d(TAG, "Warning: accessing TurnBasedMatch when not connected");
- }
-
- updateMatch(mTurnBasedMatch);
- return;
- }
- }
-
- setViewVisibility();
-
- // As a demonstration, we are registering this activity as a handler for
- // invitation and match events.
-
- // This is *NOT* required; if you do not register a handler for
- // invitation events, you will get standard notifications instead.
- // Standard notifications may be preferable behavior in many cases.
- Games.Invitations.registerInvitationListener(mGoogleApiClient, this);
-
- // Likewise, we are registering the optional MatchUpdateListener, which
- // will replace notifications you would get otherwise. You do *NOT* have
- // to register a MatchUpdateListener.
- Games.TurnBasedMultiplayer.registerMatchUpdateListener(mGoogleApiClient, this);
- }
-
- @Override
- public void onConnectionSuspended(int i) {
- Log.d(TAG, "onConnectionSuspended(): Trying to reconnect.");
- mGoogleApiClient.connect();
- setViewVisibility();
- }
-
- @Override
- public void onConnectionFailed(ConnectionResult connectionResult) {
- Log.d(TAG, "onConnectionFailed(): attempting to resolve");
- if (mResolvingConnectionFailure) {
- // Already resolving
- Log.d(TAG, "onConnectionFailed(): ignoring connection failure, already resolving.");
- return;
- }
-
- // Launch the sign-in flow if the button was clicked or if auto sign-in is enabled
- if (mSignInClicked || mAutoStartSignInFlow) {
- mAutoStartSignInFlow = false;
- mSignInClicked = false;
-
- mResolvingConnectionFailure = BaseGameUtils.resolveConnectionFailure(this,
- mGoogleApiClient, connectionResult, RC_SIGN_IN,
- getString(R.string.signin_other_error));
- }
-
- setViewVisibility();
- }
-
- // Displays your inbox. You will get back onActivityResult where
- // you will need to figure out what you clicked on.
- public void onCheckGamesClicked(View view) {
- Intent intent = Games.TurnBasedMultiplayer.getInboxIntent(mGoogleApiClient);
- startActivityForResult(intent, RC_LOOK_AT_MATCHES);
- }
-
- // Open the create-game UI. You will get back an onActivityResult
- // and figure out what to do.
- public void onStartMatchClicked(View view) {
- Intent intent = Games.TurnBasedMultiplayer.getSelectOpponentsIntent(mGoogleApiClient,
- 1, 7, true);
- startActivityForResult(intent, RC_SELECT_PLAYERS);
- }
-
- // Create a one-on-one automatch game.
- public void onQuickMatchClicked(View view) {
-
- Bundle autoMatchCriteria = RoomConfig.createAutoMatchCriteria(
- 1, 1, 0);
-
- TurnBasedMatchConfig tbmc = TurnBasedMatchConfig.builder()
- .setAutoMatchCriteria(autoMatchCriteria).build();
-
- showSpinner();
-
- // Start the match
- ResultCallback cb = new ResultCallback() {
- @Override
- public void onResult(TurnBasedMultiplayer.InitiateMatchResult result) {
- processResult(result);
- }
- };
- Games.TurnBasedMultiplayer.createMatch(mGoogleApiClient, tbmc).setResultCallback(cb);
- }
-
- // In-game controls
-
- // Cancel the game. Should possibly wait until the game is canceled before
- // giving up on the view.
- public void onCancelClicked(View view) {
- showSpinner();
- Games.TurnBasedMultiplayer.cancelMatch(mGoogleApiClient, mMatch.getMatchId())
- .setResultCallback(new ResultCallback() {
- @Override
- public void onResult(TurnBasedMultiplayer.CancelMatchResult result) {
- processResult(result);
- }
- });
- isDoingTurn = false;
- setViewVisibility();
- }
-
- // Leave the game during your turn. Note that there is a separate
- // Games.TurnBasedMultiplayer.leaveMatch() if you want to leave NOT on your turn.
- public void onLeaveClicked(View view) {
- showSpinner();
- String nextParticipantId = getNextParticipantId();
-
- Games.TurnBasedMultiplayer.leaveMatchDuringTurn(mGoogleApiClient, mMatch.getMatchId(),
- nextParticipantId).setResultCallback(
- new ResultCallback() {
- @Override
- public void onResult(TurnBasedMultiplayer.LeaveMatchResult result) {
- processResult(result);
- }
- });
- setViewVisibility();
- }
-
- // Finish the game. Sometimes, this is your only choice.
- public void onFinishClicked(View view) {
- showSpinner();
- Games.TurnBasedMultiplayer.finishMatch(mGoogleApiClient, mMatch.getMatchId())
- .setResultCallback(new ResultCallback() {
- @Override
- public void onResult(TurnBasedMultiplayer.UpdateMatchResult result) {
- processResult(result);
- }
- });
-
- isDoingTurn = false;
- setViewVisibility();
- }
-
-
- // Upload your new gamestate, then take a turn, and pass it on to the next
- // player.
- public void onDoneClicked(View view) {
- showSpinner();
-
- String nextParticipantId = getNextParticipantId();
- // Create the next turn
- mTurnData.turnCounter += 1;
- mTurnData.data = mDataView.getText().toString();
-
- showSpinner();
-
- Games.TurnBasedMultiplayer.takeTurn(mGoogleApiClient, mMatch.getMatchId(),
- mTurnData.persist(), nextParticipantId).setResultCallback(
- new ResultCallback() {
- @Override
- public void onResult(TurnBasedMultiplayer.UpdateMatchResult result) {
- processResult(result);
- }
- });
-
- mTurnData = null;
- }
-
- // Sign-in, Sign out behavior
-
- // Update the visibility based on what state we're in.
- public void setViewVisibility() {
- boolean isSignedIn = (mGoogleApiClient != null) && (mGoogleApiClient.isConnected());
-
- if (!isSignedIn) {
- findViewById(R.id.login_layout).setVisibility(View.VISIBLE);
- findViewById(R.id.sign_in_button).setVisibility(View.VISIBLE);
- findViewById(R.id.matchup_layout).setVisibility(View.GONE);
- findViewById(R.id.gameplay_layout).setVisibility(View.GONE);
-
- if (mAlertDialog != null) {
- mAlertDialog.dismiss();
- }
- return;
- }
-
-
- ((TextView) findViewById(R.id.name_field)).setText(Games.Players.getCurrentPlayer(
- mGoogleApiClient).getDisplayName());
- findViewById(R.id.login_layout).setVisibility(View.GONE);
-
- if (isDoingTurn) {
- findViewById(R.id.matchup_layout).setVisibility(View.GONE);
- findViewById(R.id.gameplay_layout).setVisibility(View.VISIBLE);
- } else {
- findViewById(R.id.matchup_layout).setVisibility(View.VISIBLE);
- findViewById(R.id.gameplay_layout).setVisibility(View.GONE);
- }
- }
-
- // Switch to gameplay view.
- public void setGameplayUI() {
- isDoingTurn = true;
- setViewVisibility();
- mDataView.setText(mTurnData.data);
- mTurnTextView.setText("Turn " + mTurnData.turnCounter);
- }
-
- // Helpful dialogs
-
- public void showSpinner() {
- findViewById(R.id.progressLayout).setVisibility(View.VISIBLE);
- }
-
- public void dismissSpinner() {
- findViewById(R.id.progressLayout).setVisibility(View.GONE);
- }
-
- // Generic warning/info dialog
- public void showWarning(String title, String message) {
- AlertDialog.Builder alertDialogBuilder = new AlertDialog.Builder(this);
-
- // set title
- alertDialogBuilder.setTitle(title).setMessage(message);
-
- // set dialog message
- alertDialogBuilder.setCancelable(false).setPositiveButton("OK",
- new DialogInterface.OnClickListener() {
- @Override
- public void onClick(DialogInterface dialog, int id) {
- // if this button is clicked, close
- // current activity
- }
- });
-
- // create alert dialog
- mAlertDialog = alertDialogBuilder.create();
-
- // show it
- mAlertDialog.show();
- }
-
- // Rematch dialog
- public void askForRematch() {
- AlertDialog.Builder alertDialogBuilder = new AlertDialog.Builder(this);
-
- alertDialogBuilder.setMessage("Do you want a rematch?");
-
- alertDialogBuilder
- .setCancelable(false)
- .setPositiveButton("Sure, rematch!",
- new DialogInterface.OnClickListener() {
- @Override
- public void onClick(DialogInterface dialog, int id) {
- rematch();
- }
- })
- .setNegativeButton("No.",
- new DialogInterface.OnClickListener() {
- @Override
- public void onClick(DialogInterface dialog, int id) {
- }
- });
-
- alertDialogBuilder.show();
- }
-
- // This function is what gets called when you return from either the Play
- // Games built-in inbox, or else the create game built-in interface.
- @Override
- public void onActivityResult(int request, int response, Intent data) {
- super.onActivityResult(request, response, data);
- if (request == RC_SIGN_IN) {
- mSignInClicked = false;
- mResolvingConnectionFailure = false;
- if (response == Activity.RESULT_OK) {
- mGoogleApiClient.connect();
- } else {
- BaseGameUtils.showActivityResultError(this, request, response, R.string.signin_other_error);
- }
- } else if (request == RC_LOOK_AT_MATCHES) {
- // Returning from the 'Select Match' dialog
-
- if (response != Activity.RESULT_OK) {
- // user canceled
- return;
- }
-
- TurnBasedMatch match = data
- .getParcelableExtra(Multiplayer.EXTRA_TURN_BASED_MATCH);
-
- if (match != null) {
- updateMatch(match);
- }
-
- Log.d(TAG, "Match = " + match);
- } else if (request == RC_SELECT_PLAYERS) {
- // Returned from 'Select players to Invite' dialog
-
- if (response != Activity.RESULT_OK) {
- // user canceled
- return;
- }
-
- // get the invitee list
- final ArrayList invitees = data
- .getStringArrayListExtra(Games.EXTRA_PLAYER_IDS);
-
- // get automatch criteria
- Bundle autoMatchCriteria = null;
-
- int minAutoMatchPlayers = data.getIntExtra(
- Multiplayer.EXTRA_MIN_AUTOMATCH_PLAYERS, 0);
- int maxAutoMatchPlayers = data.getIntExtra(
- Multiplayer.EXTRA_MAX_AUTOMATCH_PLAYERS, 0);
-
- if (minAutoMatchPlayers > 0) {
- autoMatchCriteria = RoomConfig.createAutoMatchCriteria(
- minAutoMatchPlayers, maxAutoMatchPlayers, 0);
- } else {
- autoMatchCriteria = null;
- }
-
- TurnBasedMatchConfig tbmc = TurnBasedMatchConfig.builder()
- .addInvitedPlayers(invitees)
- .setAutoMatchCriteria(autoMatchCriteria).build();
-
- // Start the match
- Games.TurnBasedMultiplayer.createMatch(mGoogleApiClient, tbmc).setResultCallback(
- new ResultCallback() {
- @Override
- public void onResult(TurnBasedMultiplayer.InitiateMatchResult result) {
- processResult(result);
- }
- });
- showSpinner();
- }
- }
-
- // startMatch() happens in response to the createTurnBasedMatch()
- // above. This is only called on success, so we should have a
- // valid match object. We're taking this opportunity to setup the
- // game, saving our initial state. Calling takeTurn() will
- // callback to OnTurnBasedMatchUpdated(), which will show the game
- // UI.
- public void startMatch(TurnBasedMatch match) {
- mTurnData = new SkeletonTurn();
- // Some basic turn data
- mTurnData.data = "First turn";
-
- mMatch = match;
-
- String playerId = Games.Players.getCurrentPlayerId(mGoogleApiClient);
- String myParticipantId = mMatch.getParticipantId(playerId);
-
- showSpinner();
-
- Games.TurnBasedMultiplayer.takeTurn(mGoogleApiClient, match.getMatchId(),
- mTurnData.persist(), myParticipantId).setResultCallback(
- new ResultCallback() {
- @Override
- public void onResult(TurnBasedMultiplayer.UpdateMatchResult result) {
- processResult(result);
- }
- });
- }
-
- // If you choose to rematch, then call it and wait for a response.
- public void rematch() {
- showSpinner();
- Games.TurnBasedMultiplayer.rematch(mGoogleApiClient, mMatch.getMatchId()).setResultCallback(
- new ResultCallback() {
- @Override
- public void onResult(TurnBasedMultiplayer.InitiateMatchResult result) {
- processResult(result);
- }
- });
- mMatch = null;
- isDoingTurn = false;
- }
-
- /**
- * Get the next participant. In this function, we assume that we are
- * round-robin, with all known players going before all automatch players.
- * This is not a requirement; players can go in any order. However, you can
- * take turns in any order.
- *
- * @return participantId of next player, or null if automatching
- */
- public String getNextParticipantId() {
-
- String playerId = Games.Players.getCurrentPlayerId(mGoogleApiClient);
- String myParticipantId = mMatch.getParticipantId(playerId);
-
- ArrayList participantIds = mMatch.getParticipantIds();
-
- int desiredIndex = -1;
-
- for (int i = 0; i < participantIds.size(); i++) {
- if (participantIds.get(i).equals(myParticipantId)) {
- desiredIndex = i + 1;
- }
- }
-
- if (desiredIndex < participantIds.size()) {
- return participantIds.get(desiredIndex);
- }
-
- if (mMatch.getAvailableAutoMatchSlots() <= 0) {
- // You've run out of automatch slots, so we start over.
- return participantIds.get(0);
- } else {
- // You have not yet fully automatched, so null will find a new
- // person to play against.
- return null;
- }
- }
-
- // This is the main function that gets called when players choose a match
- // from the inbox, or else create a match and want to start it.
- public void updateMatch(TurnBasedMatch match) {
- mMatch = match;
-
- int status = match.getStatus();
- int turnStatus = match.getTurnStatus();
-
- switch (status) {
- case TurnBasedMatch.MATCH_STATUS_CANCELED:
- showWarning("Canceled!", "This game was canceled!");
- return;
- case TurnBasedMatch.MATCH_STATUS_EXPIRED:
- showWarning("Expired!", "This game is expired. So sad!");
- return;
- case TurnBasedMatch.MATCH_STATUS_AUTO_MATCHING:
- showWarning("Waiting for auto-match...",
- "We're still waiting for an automatch partner.");
- return;
- case TurnBasedMatch.MATCH_STATUS_COMPLETE:
- if (turnStatus == TurnBasedMatch.MATCH_TURN_STATUS_COMPLETE) {
- showWarning(
- "Complete!",
- "This game is over; someone finished it, and so did you! There is nothing to be done.");
- break;
- }
-
- // Note that in this state, you must still call "Finish" yourself,
- // so we allow this to continue.
- showWarning("Complete!",
- "This game is over; someone finished it! You can only finish it now.");
- }
-
- // OK, it's active. Check on turn status.
- switch (turnStatus) {
- case TurnBasedMatch.MATCH_TURN_STATUS_MY_TURN:
- mTurnData = SkeletonTurn.unpersist(mMatch.getData());
- setGameplayUI();
- return;
- case TurnBasedMatch.MATCH_TURN_STATUS_THEIR_TURN:
- // Should return results.
- showWarning("Alas...", "It's not your turn.");
- break;
- case TurnBasedMatch.MATCH_TURN_STATUS_INVITED:
- showWarning("Good inititative!",
- "Still waiting for invitations.\n\nBe patient!");
- }
-
- mTurnData = null;
-
- setViewVisibility();
- }
-
- private void processResult(TurnBasedMultiplayer.CancelMatchResult result) {
- dismissSpinner();
-
- if (!checkStatusCode(null, result.getStatus().getStatusCode())) {
- return;
- }
-
- isDoingTurn = false;
-
- showWarning("Match",
- "This match is canceled. All other players will have their game ended.");
- }
-
- private void processResult(TurnBasedMultiplayer.InitiateMatchResult result) {
- TurnBasedMatch match = result.getMatch();
- dismissSpinner();
-
- if (!checkStatusCode(match, result.getStatus().getStatusCode())) {
- return;
- }
-
- if (match.getData() != null) {
- // This is a game that has already started, so I'll just start
- updateMatch(match);
- return;
- }
-
- startMatch(match);
- }
-
-
- private void processResult(TurnBasedMultiplayer.LeaveMatchResult result) {
- TurnBasedMatch match = result.getMatch();
- dismissSpinner();
- if (!checkStatusCode(match, result.getStatus().getStatusCode())) {
- return;
- }
- isDoingTurn = (match.getTurnStatus() == TurnBasedMatch.MATCH_TURN_STATUS_MY_TURN);
- showWarning("Left", "You've left this match.");
- }
-
-
- public void processResult(TurnBasedMultiplayer.UpdateMatchResult result) {
- TurnBasedMatch match = result.getMatch();
- dismissSpinner();
- if (!checkStatusCode(match, result.getStatus().getStatusCode())) {
- return;
- }
- if (match.canRematch()) {
- askForRematch();
- }
-
- isDoingTurn = (match.getTurnStatus() == TurnBasedMatch.MATCH_TURN_STATUS_MY_TURN);
-
- if (isDoingTurn) {
- updateMatch(match);
- return;
- }
-
- setViewVisibility();
- }
-
- // Handle notification events.
- @Override
- public void onInvitationReceived(Invitation invitation) {
- Toast.makeText(
- this,
- "An invitation has arrived from "
- + invitation.getInviter().getDisplayName(), TOAST_DELAY)
- .show();
- }
-
- @Override
- public void onInvitationRemoved(String invitationId) {
- Toast.makeText(this, "An invitation was removed.", TOAST_DELAY).show();
- }
-
- @Override
- public void onTurnBasedMatchReceived(TurnBasedMatch match) {
- Toast.makeText(this, "A match was updated.", TOAST_DELAY).show();
- }
-
- @Override
- public void onTurnBasedMatchRemoved(String matchId) {
- Toast.makeText(this, "A match was removed.", TOAST_DELAY).show();
-
- }
-
- public void showErrorMessage(TurnBasedMatch match, int statusCode,
- int stringId) {
-
- showWarning("Warning", getResources().getString(stringId));
- }
-
- // Returns false if something went wrong, probably. This should handle
- // more cases, and probably report more accurate results.
- private boolean checkStatusCode(TurnBasedMatch match, int statusCode) {
- switch (statusCode) {
- case GamesStatusCodes.STATUS_OK:
- return true;
- case GamesStatusCodes.STATUS_NETWORK_ERROR_OPERATION_DEFERRED:
- // This is OK; the action is stored by Google Play Services and will
- // be dealt with later.
- Toast.makeText(
- this,
- "Stored action for later. (Please remove this toast before release.)",
- TOAST_DELAY).show();
- // NOTE: This toast is for informative reasons only; please remove
- // it from your final application.
- return true;
- case GamesStatusCodes.STATUS_MULTIPLAYER_ERROR_NOT_TRUSTED_TESTER:
- showErrorMessage(match, statusCode,
- R.string.status_multiplayer_error_not_trusted_tester);
- break;
- case GamesStatusCodes.STATUS_MATCH_ERROR_ALREADY_REMATCHED:
- showErrorMessage(match, statusCode,
- R.string.match_error_already_rematched);
- break;
- case GamesStatusCodes.STATUS_NETWORK_ERROR_OPERATION_FAILED:
- showErrorMessage(match, statusCode,
- R.string.network_error_operation_failed);
- break;
- case GamesStatusCodes.STATUS_CLIENT_RECONNECT_REQUIRED:
- showErrorMessage(match, statusCode,
- R.string.client_reconnect_required);
- break;
- case GamesStatusCodes.STATUS_INTERNAL_ERROR:
- showErrorMessage(match, statusCode, R.string.internal_error);
- break;
- case GamesStatusCodes.STATUS_MATCH_ERROR_INACTIVE_MATCH:
- showErrorMessage(match, statusCode,
- R.string.match_error_inactive_match);
- break;
- case GamesStatusCodes.STATUS_MATCH_ERROR_LOCALLY_MODIFIED:
- showErrorMessage(match, statusCode,
- R.string.match_error_locally_modified);
- break;
- default:
- showErrorMessage(match, statusCode, R.string.unexpected_status);
- Log.d(TAG, "Did not have warning or string to deal with: "
- + statusCode);
- }
-
- return false;
- }
-
- @Override
- public void onClick(View v) {
- switch (v.getId()) {
- case R.id.sign_in_button:
- // Check to see the developer who's running this sample code read the instructions :-)
- // NOTE: this check is here only because this is a sample! Don't include this
- // check in your actual production app.
- if (!BaseGameUtils.verifySampleSetup(this, R.string.app_id)) {
- Log.w(TAG, "*** Warning: setup problems detected. Sign in may not work!");
- }
-
- mSignInClicked = true;
- mTurnBasedMatch = null;
- findViewById(R.id.sign_in_button).setVisibility(View.GONE);
- mGoogleApiClient.connect();
- break;
- case R.id.sign_out_button:
- mSignInClicked = false;
- Games.signOut(mGoogleApiClient);
- if (mGoogleApiClient.isConnected()) {
- mGoogleApiClient.disconnect();
- }
- setViewVisibility();
- break;
- }
- }
-}
diff --git a/BasicSamples/SkeletonTbmp/src/main/java/com/google/example/tbmpskeleton/SkeletonTurn.java b/BasicSamples/SkeletonTbmp/src/main/java/com/google/example/tbmpskeleton/SkeletonTurn.java
deleted file mode 100644
index 7aeda632..00000000
--- a/BasicSamples/SkeletonTbmp/src/main/java/com/google/example/tbmpskeleton/SkeletonTurn.java
+++ /dev/null
@@ -1,100 +0,0 @@
-/*
- * 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.tbmpskeleton;
-
-import java.io.UnsupportedEncodingException;
-import java.nio.charset.Charset;
-
-import org.json.JSONException;
-import org.json.JSONObject;
-
-import android.util.Log;
-
-/**
- * Basic turn data. It's just a blank data string and a turn number counter.
- *
- * @author wolff
- *
- */
-public class SkeletonTurn {
-
- public static final String TAG = "EBTurn";
-
- public String data = "";
- public int turnCounter;
-
- public SkeletonTurn() {
- }
-
- // This is the byte array we will write out to the TBMP API.
- public byte[] persist() {
- JSONObject retVal = new JSONObject();
-
- try {
- retVal.put("data", data);
- retVal.put("turnCounter", turnCounter);
-
- } catch (JSONException e) {
- // TODO Auto-generated catch block
- e.printStackTrace();
- }
-
- String st = retVal.toString();
-
- Log.d(TAG, "==== PERSISTING\n" + st);
-
- return st.getBytes(Charset.forName("UTF-8"));
- }
-
- // Creates a new instance of SkeletonTurn.
- static public SkeletonTurn unpersist(byte[] byteArray) {
-
- if (byteArray == null) {
- Log.d(TAG, "Empty array---possible bug.");
- return new SkeletonTurn();
- }
-
- String st = null;
- try {
- st = new String(byteArray, "UTF-8");
- } catch (UnsupportedEncodingException e1) {
- e1.printStackTrace();
- return null;
- }
-
- Log.d(TAG, "====UNPERSIST \n" + st);
-
- SkeletonTurn retVal = new SkeletonTurn();
-
- try {
- JSONObject obj = new JSONObject(st);
-
- if (obj.has("data")) {
- retVal.data = obj.getString("data");
- }
- if (obj.has("turnCounter")) {
- retVal.turnCounter = obj.getInt("turnCounter");
- }
-
- } catch (JSONException e) {
- // TODO Auto-generated catch block
- e.printStackTrace();
- }
-
- return retVal;
- }
-}
diff --git a/BasicSamples/SkeletonTbmp/src/main/res/drawable-hdpi/ic_launcher.png b/BasicSamples/SkeletonTbmp/src/main/res/drawable-hdpi/ic_launcher.png
deleted file mode 100755
index 0ea6bed7..00000000
Binary files a/BasicSamples/SkeletonTbmp/src/main/res/drawable-hdpi/ic_launcher.png and /dev/null differ
diff --git a/BasicSamples/SkeletonTbmp/src/main/res/drawable-mdpi/grey_background_pattern_tile.png b/BasicSamples/SkeletonTbmp/src/main/res/drawable-mdpi/grey_background_pattern_tile.png
deleted file mode 100644
index 12a6c137..00000000
Binary files a/BasicSamples/SkeletonTbmp/src/main/res/drawable-mdpi/grey_background_pattern_tile.png and /dev/null differ
diff --git a/BasicSamples/SkeletonTbmp/src/main/res/drawable-mdpi/ic_launcher.png b/BasicSamples/SkeletonTbmp/src/main/res/drawable-mdpi/ic_launcher.png
deleted file mode 100755
index 3cb25ae1..00000000
Binary files a/BasicSamples/SkeletonTbmp/src/main/res/drawable-mdpi/ic_launcher.png and /dev/null differ
diff --git a/BasicSamples/SkeletonTbmp/src/main/res/drawable-xhdpi/button_default.9.png b/BasicSamples/SkeletonTbmp/src/main/res/drawable-xhdpi/button_default.9.png
deleted file mode 100644
index d6335b0c..00000000
Binary files a/BasicSamples/SkeletonTbmp/src/main/res/drawable-xhdpi/button_default.9.png and /dev/null differ
diff --git a/BasicSamples/SkeletonTbmp/src/main/res/drawable-xhdpi/button_focused.9.png b/BasicSamples/SkeletonTbmp/src/main/res/drawable-xhdpi/button_focused.9.png
deleted file mode 100644
index 497bd30f..00000000
Binary files a/BasicSamples/SkeletonTbmp/src/main/res/drawable-xhdpi/button_focused.9.png and /dev/null differ
diff --git a/BasicSamples/SkeletonTbmp/src/main/res/drawable-xhdpi/button_pressed.9.png b/BasicSamples/SkeletonTbmp/src/main/res/drawable-xhdpi/button_pressed.9.png
deleted file mode 100644
index 3a3814d4..00000000
Binary files a/BasicSamples/SkeletonTbmp/src/main/res/drawable-xhdpi/button_pressed.9.png and /dev/null differ
diff --git a/BasicSamples/SkeletonTbmp/src/main/res/drawable-xhdpi/grey_background_pattern_tile.png b/BasicSamples/SkeletonTbmp/src/main/res/drawable-xhdpi/grey_background_pattern_tile.png
deleted file mode 100644
index a441d0da..00000000
Binary files a/BasicSamples/SkeletonTbmp/src/main/res/drawable-xhdpi/grey_background_pattern_tile.png and /dev/null differ
diff --git a/BasicSamples/SkeletonTbmp/src/main/res/drawable-xhdpi/ic_launcher.png b/BasicSamples/SkeletonTbmp/src/main/res/drawable-xhdpi/ic_launcher.png
deleted file mode 100755
index 45bdd70d..00000000
Binary files a/BasicSamples/SkeletonTbmp/src/main/res/drawable-xhdpi/ic_launcher.png and /dev/null differ
diff --git a/BasicSamples/SkeletonTbmp/src/main/res/drawable-xxhdpi/ic_launcher.png b/BasicSamples/SkeletonTbmp/src/main/res/drawable-xxhdpi/ic_launcher.png
deleted file mode 100755
index 91e7fe84..00000000
Binary files a/BasicSamples/SkeletonTbmp/src/main/res/drawable-xxhdpi/ic_launcher.png and /dev/null differ
diff --git a/BasicSamples/SkeletonTbmp/src/main/res/drawable/button.xml b/BasicSamples/SkeletonTbmp/src/main/res/drawable/button.xml
deleted file mode 100644
index 55acedeb..00000000
--- a/BasicSamples/SkeletonTbmp/src/main/res/drawable/button.xml
+++ /dev/null
@@ -1,30 +0,0 @@
-
-
-
-
-
-
-
-
diff --git a/BasicSamples/SkeletonTbmp/src/main/res/drawable/grey_background_pattern.xml b/BasicSamples/SkeletonTbmp/src/main/res/drawable/grey_background_pattern.xml
deleted file mode 100644
index a7bbd4b8..00000000
--- a/BasicSamples/SkeletonTbmp/src/main/res/drawable/grey_background_pattern.xml
+++ /dev/null
@@ -1,22 +0,0 @@
-
-
-
-
diff --git a/BasicSamples/SkeletonTbmp/src/main/res/drawable/none.jpg b/BasicSamples/SkeletonTbmp/src/main/res/drawable/none.jpg
deleted file mode 100644
index 6e33487a..00000000
Binary files a/BasicSamples/SkeletonTbmp/src/main/res/drawable/none.jpg and /dev/null differ
diff --git a/BasicSamples/SkeletonTbmp/src/main/res/layout/activity_main.xml b/BasicSamples/SkeletonTbmp/src/main/res/layout/activity_main.xml
deleted file mode 100644
index 6f32a331..00000000
--- a/BasicSamples/SkeletonTbmp/src/main/res/layout/activity_main.xml
+++ /dev/null
@@ -1,201 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/BasicSamples/SkeletonTbmp/src/main/res/values-sw600dp/dimens.xml b/BasicSamples/SkeletonTbmp/src/main/res/values-sw600dp/dimens.xml
deleted file mode 100644
index 44f01db7..00000000
--- a/BasicSamples/SkeletonTbmp/src/main/res/values-sw600dp/dimens.xml
+++ /dev/null
@@ -1,8 +0,0 @@
-
-
-
-
-
diff --git a/BasicSamples/SkeletonTbmp/src/main/res/values-sw720dp-land/dimens.xml b/BasicSamples/SkeletonTbmp/src/main/res/values-sw720dp-land/dimens.xml
deleted file mode 100644
index 61e3fa8f..00000000
--- a/BasicSamples/SkeletonTbmp/src/main/res/values-sw720dp-land/dimens.xml
+++ /dev/null
@@ -1,9 +0,0 @@
-
-
-
- 128dp
-
-
diff --git a/BasicSamples/SkeletonTbmp/src/main/res/values-v11/styles.xml b/BasicSamples/SkeletonTbmp/src/main/res/values-v11/styles.xml
deleted file mode 100644
index 3c02242a..00000000
--- a/BasicSamples/SkeletonTbmp/src/main/res/values-v11/styles.xml
+++ /dev/null
@@ -1,11 +0,0 @@
-
-
-
-
-
-
diff --git a/BasicSamples/SkeletonTbmp/src/main/res/values-v14/styles.xml b/BasicSamples/SkeletonTbmp/src/main/res/values-v14/styles.xml
deleted file mode 100644
index a91fd037..00000000
--- a/BasicSamples/SkeletonTbmp/src/main/res/values-v14/styles.xml
+++ /dev/null
@@ -1,12 +0,0 @@
-
-
-
-
-
-
diff --git a/BasicSamples/SkeletonTbmp/src/main/res/values/dimens.xml b/BasicSamples/SkeletonTbmp/src/main/res/values/dimens.xml
deleted file mode 100644
index 0dd41098..00000000
--- a/BasicSamples/SkeletonTbmp/src/main/res/values/dimens.xml
+++ /dev/null
@@ -1,29 +0,0 @@
-
-
-
-
- 16dp
- 16dp
- 14sp
- 20sp
- 32sp
-
- 8dp
- 16dp
- 32dp
- 64dp
-
diff --git a/BasicSamples/SkeletonTbmp/src/main/res/values/ids.xml b/BasicSamples/SkeletonTbmp/src/main/res/values/ids.xml
deleted file mode 100644
index a235775d..00000000
--- a/BasicSamples/SkeletonTbmp/src/main/res/values/ids.xml
+++ /dev/null
@@ -1,4 +0,0 @@
-
-
- ReplaceMe
-
diff --git a/BasicSamples/SkeletonTbmp/src/main/res/values/strings.xml b/BasicSamples/SkeletonTbmp/src/main/res/values/strings.xml
deleted file mode 100644
index 9958088d..00000000
--- a/BasicSamples/SkeletonTbmp/src/main/res/values/strings.xml
+++ /dev/null
@@ -1,25 +0,0 @@
-
-
-
- Tbmp Skeleton
- Settings
- Hello world!
- Next turn
- Welcome to the Skeleton, the game! This is network-only, so you'll need to log in to play!
- Sign Out
- Type in a new word for the data in this game, then hit done.
- Quick match
- Continue
- This has not been set.
- Clear
- Done
- Leave
- Cancel
- Finish
- Welcome to our skeleton app!
- Check games
- Start Match
- Turn counter
- There was an issue with sign in. Please try again later.
-
-
diff --git a/BasicSamples/SkeletonTbmp/src/main/res/values/styles.xml b/BasicSamples/SkeletonTbmp/src/main/res/values/styles.xml
deleted file mode 100644
index 6f74cd90..00000000
--- a/BasicSamples/SkeletonTbmp/src/main/res/values/styles.xml
+++ /dev/null
@@ -1,78 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/BasicSamples/SkeletonTbmp/src/main/res/values/tbmp_helper_strings.xml b/BasicSamples/SkeletonTbmp/src/main/res/values/tbmp_helper_strings.xml
deleted file mode 100644
index 31544261..00000000
--- a/BasicSamples/SkeletonTbmp/src/main/res/values/tbmp_helper_strings.xml
+++ /dev/null
@@ -1,11 +0,0 @@
-
-
- Anyone you invite must be a trusted tester
- This rematch has already been started!
- Games client reconnect required
- Network error: Operation failed
- Internal error
- Unexpected status
- This match is inactive.
- This match has locally-modified data. This operation cannot be performed until the match is sent to the server.
-
diff --git a/BasicSamples/TrivialQuest/.gitignore b/BasicSamples/TrivialQuest/.gitignore
deleted file mode 100644
index 47036e4a..00000000
--- a/BasicSamples/TrivialQuest/.gitignore
+++ /dev/null
@@ -1,3 +0,0 @@
-/build/
-/bin/
-/gen/
diff --git a/BasicSamples/TrivialQuest/build.gradle b/BasicSamples/TrivialQuest/build.gradle
deleted file mode 100644
index d6a339c7..00000000
--- a/BasicSamples/TrivialQuest/build.gradle
+++ /dev/null
@@ -1,34 +0,0 @@
-apply plugin: 'android'
-
-android {
- enforceUniquePackageName=false
-
- compileSdkVersion 20
- buildToolsVersion '20'
-
- defaultConfig {
- minSdkVersion 9
- targetSdkVersion 20
- versionCode 1
- versionName "1.0"
- }
- buildTypes {
- release {
- minifyEnabled false
- proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.txt'
- }
- }
-}
-
-dependencies {
- compile project(':libraries:BaseGameUtils')
- compile 'com.android.support:appcompat-v7:20.0.+'
- compile 'com.android.support:support-v4:20.0.+'
- compile 'com.google.android.gms:play-services:+'
-}
-
-buildscript {
- repositories {
- mavenCentral()
- }
-}
diff --git a/BasicSamples/TrivialQuest/src/main/AndroidManifest.xml b/BasicSamples/TrivialQuest/src/main/AndroidManifest.xml
deleted file mode 100644
index cad3fbf6..00000000
--- a/BasicSamples/TrivialQuest/src/main/AndroidManifest.xml
+++ /dev/null
@@ -1,62 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/BasicSamples/TrivialQuest/src/main/java/com/google/example/games/tq/MainActivity.java b/BasicSamples/TrivialQuest/src/main/java/com/google/example/games/tq/MainActivity.java
deleted file mode 100644
index 765aaa53..00000000
--- a/BasicSamples/TrivialQuest/src/main/java/com/google/example/games/tq/MainActivity.java
+++ /dev/null
@@ -1,191 +0,0 @@
-/* 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.tq;
-
-import android.app.Activity;
-import android.content.Intent;
-import android.os.Bundle;
-import android.util.Log;
-import android.view.View;
-
-import com.google.android.gms.common.ConnectionResult;
-import com.google.android.gms.common.api.GoogleApiClient;
-import com.google.android.gms.games.Games;
-import com.google.android.gms.plus.Plus;
-import com.google.example.games.basegameutils.BaseGameUtils;
-
-/**
- * Trivial quest. A sample game that sets up the Google Play game services
- * API and allows the user to click a button to win (yes, incredibly epic).
- * Even though winning the game is fun, the purpose of this sample is to
- * illustrate the simplest possible game that uses the API.
- *
- * @author Bruno Oliveira (Google)
- */
-public class MainActivity extends Activity
- implements GoogleApiClient.ConnectionCallbacks, GoogleApiClient.OnConnectionFailedListener,
- View.OnClickListener {
-
- private static final String TAG = "TrivialQuest";
-
- // Request code used to invoke sign in user interactions.
- private static final int RC_SIGN_IN = 9001;
-
- // Client used to interact with Google APIs.
- private GoogleApiClient mGoogleApiClient;
-
- // Are we currently resolving a connection failure?
- private boolean mResolvingConnectionFailure = false;
-
- // Has the user clicked the sign-in button?
- private boolean mSignInClicked = false;
-
- // Set to true to automatically start the sign in flow when the Activity starts.
- // Set to false to require the user to click the button in order to sign in.
- private boolean mAutoStartSignInFlow = true;
-
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- Log.d(TAG, "onCreate()");
-
- super.onCreate(savedInstanceState);
-
- // Create the Google Api Client with access to Plus and Games
- mGoogleApiClient = new GoogleApiClient.Builder(this)
- .addConnectionCallbacks(this)
- .addOnConnectionFailedListener(this)
- .addApi(Plus.API).addScope(Plus.SCOPE_PLUS_LOGIN)
- .addApi(Games.API).addScope(Games.SCOPE_GAMES)
- .build();
-
- setContentView(R.layout.activity_main);
-
- // set this class to listen for the button clicks
- findViewById(R.id.button_sign_in).setOnClickListener(this);
- findViewById(R.id.button_sign_out).setOnClickListener(this);
- findViewById(R.id.button_win).setOnClickListener(this);
- }
-
- protected void onStart() {
- Log.d(TAG, "onStart()");
- super.onStart();
- mGoogleApiClient.connect();
- }
-
- protected void onStop() {
- Log.d(TAG, "onStop()");
- super.onStop();
- if (mGoogleApiClient.isConnected()) {
- mGoogleApiClient.disconnect();
- }
- }
-
- // Shows the "sign in" bar (explanation and button).
- private void showSignInBar() {
- Log.d(TAG, "Showing sign in bar");
- findViewById(R.id.sign_in_bar).setVisibility(View.VISIBLE);
- findViewById(R.id.sign_out_bar).setVisibility(View.GONE);
- }
-
- // Shows the "sign out" bar (explanation and button).
- private void showSignOutBar() {
- Log.d(TAG, "Showing sign out bar");
- findViewById(R.id.sign_in_bar).setVisibility(View.GONE);
- findViewById(R.id.sign_out_bar).setVisibility(View.VISIBLE);
- }
-
- @Override
- public void onClick(View view) {
- switch (view.getId()) {
- case R.id.button_sign_in:
- // Check to see the developer who's running this sample code read the instructions :-)
- // NOTE: this check is here only because this is a sample! Don't include this
- // check in your actual production app.
- if (!BaseGameUtils.verifySampleSetup(this, R.string.app_id,
- R.string.achievement_trivial_victory)) {
- Log.w(TAG, "*** Warning: setup problems detected. Sign in may not work!");
- }
-
- // start the sign-in flow
- Log.d(TAG, "Sign-in button clicked");
- mSignInClicked = true;
- mGoogleApiClient.connect();
- break;
- case R.id.button_sign_out:
- // sign out.
- Log.d(TAG, "Sign-out button clicked");
- mSignInClicked = false;
- Games.signOut(mGoogleApiClient);
- mGoogleApiClient.disconnect();
- showSignInBar();
- break;
- case R.id.button_win:
- // win!
- Log.d(TAG, "Win button clicked");
- BaseGameUtils.showAlert(this, getString(R.string.you_won));
- if (mGoogleApiClient.isConnected()) {
- // unlock the "Trivial Victory" achievement.
- Games.Achievements.unlock(mGoogleApiClient,
- getString(R.string.achievement_trivial_victory));
- }
- break;
- }
- }
-
- @Override
- public void onConnected(Bundle bundle) {
- Log.d(TAG, "onConnected() called. Sign in successful!");
- showSignOutBar();
- }
-
- @Override
- public void onConnectionSuspended(int i) {
- Log.d(TAG, "onConnectionSuspended() called. Trying to reconnect.");
- mGoogleApiClient.connect();
- }
-
- @Override
- public void onConnectionFailed(ConnectionResult connectionResult) {
- Log.d(TAG, "onConnectionFailed() called, result: " + connectionResult);
-
- if (mResolvingConnectionFailure) {
- Log.d(TAG, "onConnectionFailed() ignoring connection failure; already resolving.");
- return;
- }
-
- if (mSignInClicked || mAutoStartSignInFlow) {
- mAutoStartSignInFlow = false;
- mSignInClicked = false;
- mResolvingConnectionFailure = BaseGameUtils.resolveConnectionFailure(this, mGoogleApiClient,
- connectionResult, RC_SIGN_IN, getString(R.string.signin_other_error));
- }
- showSignInBar();
- }
-
- protected void onActivityResult(int requestCode, int responseCode, Intent intent) {
- if (requestCode == RC_SIGN_IN) {
- Log.d(TAG, "onActivityResult with requestCode == RC_SIGN_IN, responseCode="
- + responseCode + ", intent=" + intent);
- mSignInClicked = false;
- mResolvingConnectionFailure = false;
- if (responseCode == RESULT_OK) {
- mGoogleApiClient.connect();
- } else {
- BaseGameUtils.showActivityResultError(this,requestCode,responseCode, R.string.signin_other_error);
- }
- }
- }
-}
diff --git a/BasicSamples/TrivialQuest/src/main/res/drawable-hdpi/ic_launcher.png b/BasicSamples/TrivialQuest/src/main/res/drawable-hdpi/ic_launcher.png
deleted file mode 100644
index bfe60a8a..00000000
Binary files a/BasicSamples/TrivialQuest/src/main/res/drawable-hdpi/ic_launcher.png and /dev/null differ
diff --git a/BasicSamples/TrivialQuest/src/main/res/drawable-ldpi/ic_launcher.png b/BasicSamples/TrivialQuest/src/main/res/drawable-ldpi/ic_launcher.png
deleted file mode 100644
index 2c4a5b26..00000000
Binary files a/BasicSamples/TrivialQuest/src/main/res/drawable-ldpi/ic_launcher.png and /dev/null differ
diff --git a/BasicSamples/TrivialQuest/src/main/res/drawable-mdpi/ic_launcher.png b/BasicSamples/TrivialQuest/src/main/res/drawable-mdpi/ic_launcher.png
deleted file mode 100644
index 13845b21..00000000
Binary files a/BasicSamples/TrivialQuest/src/main/res/drawable-mdpi/ic_launcher.png and /dev/null differ
diff --git a/BasicSamples/TrivialQuest/src/main/res/drawable-xhdpi/ic_launcher.png b/BasicSamples/TrivialQuest/src/main/res/drawable-xhdpi/ic_launcher.png
deleted file mode 100644
index b42fe111..00000000
Binary files a/BasicSamples/TrivialQuest/src/main/res/drawable-xhdpi/ic_launcher.png and /dev/null differ
diff --git a/BasicSamples/TrivialQuest/src/main/res/drawable-xxhdpi/ic_launcher.png b/BasicSamples/TrivialQuest/src/main/res/drawable-xxhdpi/ic_launcher.png
deleted file mode 100644
index 72f6a0c1..00000000
Binary files a/BasicSamples/TrivialQuest/src/main/res/drawable-xxhdpi/ic_launcher.png and /dev/null differ
diff --git a/BasicSamples/TrivialQuest/src/main/res/layout/activity_main.xml b/BasicSamples/TrivialQuest/src/main/res/layout/activity_main.xml
deleted file mode 100644
index 057bdb5d..00000000
--- a/BasicSamples/TrivialQuest/src/main/res/layout/activity_main.xml
+++ /dev/null
@@ -1,48 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/BasicSamples/TrivialQuest/src/main/res/values-v14/styles.xml b/BasicSamples/TrivialQuest/src/main/res/values-v14/styles.xml
deleted file mode 100644
index 9e1013d7..00000000
--- a/BasicSamples/TrivialQuest/src/main/res/values-v14/styles.xml
+++ /dev/null
@@ -1,29 +0,0 @@
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/BasicSamples/TrivialQuest/src/main/res/values/ids.xml b/BasicSamples/TrivialQuest/src/main/res/values/ids.xml
deleted file mode 100644
index d09c8e5d..00000000
--- a/BasicSamples/TrivialQuest/src/main/res/values/ids.xml
+++ /dev/null
@@ -1,24 +0,0 @@
-
-
-
-
-
- ReplaceMe
-
-
- ReplaceMe
-
diff --git a/BasicSamples/TrivialQuest/src/main/res/values/strings.xml b/BasicSamples/TrivialQuest/src/main/res/values/strings.xml
deleted file mode 100644
index cad0ed3f..00000000
--- a/BasicSamples/TrivialQuest/src/main/res/values/strings.xml
+++ /dev/null
@@ -1,29 +0,0 @@
-
-
-
-
- Signing in with Google
- Signing out
- Trivial Quest
- Sign with Google to upload your achievements and share with friends.
- You are signed in with Google.
- Sign Out
- Click me!
- Victory
- OK! You won!
- There was an issue with sign in. Please try again later.
-
\ No newline at end of file
diff --git a/BasicSamples/TrivialQuest/src/main/res/values/styles.xml b/BasicSamples/TrivialQuest/src/main/res/values/styles.xml
deleted file mode 100644
index e4a79ada..00000000
--- a/BasicSamples/TrivialQuest/src/main/res/values/styles.xml
+++ /dev/null
@@ -1,86 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/BasicSamples/TrivialQuest2/.gitignore b/BasicSamples/TrivialQuest2/.gitignore
deleted file mode 100644
index 47036e4a..00000000
--- a/BasicSamples/TrivialQuest2/.gitignore
+++ /dev/null
@@ -1,3 +0,0 @@
-/build/
-/bin/
-/gen/
diff --git a/BasicSamples/TrivialQuest2/README.md b/BasicSamples/TrivialQuest2/README.md
deleted file mode 100644
index 7891c31f..00000000
--- a/BasicSamples/TrivialQuest2/README.md
+++ /dev/null
@@ -1,31 +0,0 @@
-# Trivial Quest 2 #
-This sample demonstrates how to use the Event-and-Quest feature of Google
-Play Game Services. In this sample, the game displays a sign-in button, along with four colored buttons. Clicking each button causes the application to send an event to Google Play Game Services ("GPGS"), enabling GPGS to track the player's progress toward a milestone.
-
-When the player reaches a milestone specified in a Quest, the game receives a callback with an object describing the Quest reward.
-
-## Setup ##
-Follow these steps to set up the sample:
-1. Update the package name in `AndroidManifest.xml` to be something other
- than `com.google.example.games.tq2`.
-2. Modify your app folder structure to match your package name.
-3. Replace the package name in `MainActivity.java`. The package name must be unique; otherwise, the API console
- cannot link your app correctly.
-4. Create your project in the Google Play Developer Console.
-5. Link your app.
-6. Copy the `APP ID` from the console into `TrivialQuest2/values/ids.xml`.
-7. Set up four events in the console. As you create each event,
- copy its identifier into `TrivialQuest2/values/ids.xml`.
-8. If you are using Android Studio, resync gradle, and build the TrivialQuest 2
- module.
-
-## Running the Sample ##
-1. Press the **Run** button in Android Studio, and select a target device. When the app starts, the Play Games UI appears.
-2. Sign in to the app. The application toasts a message with the events and their current counts.
-3. In the application, click the **Quests** button to show current quests.
-
-## Creating and completing Quests ##
-1. Create a Quest in the Google Play Developer Console, setting a date range that includes the current date.
-2. Accept the Quest in the app.
-3. Complete the Quest.
-4. A toast appears showing the Quest reward (as JSON data, for example).
diff --git a/BasicSamples/TrivialQuest2/build.gradle b/BasicSamples/TrivialQuest2/build.gradle
deleted file mode 100644
index af7e3aaa..00000000
--- a/BasicSamples/TrivialQuest2/build.gradle
+++ /dev/null
@@ -1,26 +0,0 @@
-apply plugin: 'android'
-
-android {
- compileSdkVersion 20
- buildToolsVersion '20'
-
- defaultConfig {
- minSdkVersion 9
- targetSdkVersion 20
- versionCode 1
- versionName "1.0"
- }
-}
-
-dependencies {
- compile 'com.android.support:appcompat-v7:20.0.+'
- compile 'com.android.support:support-v4:20.0.+'
- compile 'com.google.android.gms:play-services:5+'
- compile project(':libraries:BaseGameUtils')
-}
-
-buildscript {
- repositories {
- mavenCentral()
- }
-}
diff --git a/BasicSamples/TrivialQuest2/src/main/AndroidManifest.xml b/BasicSamples/TrivialQuest2/src/main/AndroidManifest.xml
deleted file mode 100644
index 3d6f95e1..00000000
--- a/BasicSamples/TrivialQuest2/src/main/AndroidManifest.xml
+++ /dev/null
@@ -1,61 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/BasicSamples/TrivialQuest2/src/main/java/com/google/example/games/tq2/MainActivity.java b/BasicSamples/TrivialQuest2/src/main/java/com/google/example/games/tq2/MainActivity.java
deleted file mode 100644
index 46cc7669..00000000
--- a/BasicSamples/TrivialQuest2/src/main/java/com/google/example/games/tq2/MainActivity.java
+++ /dev/null
@@ -1,414 +0,0 @@
-/* Copyright (C) 2014 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.tq2;
-
-import android.app.Activity;
-import android.content.Intent;
-import android.os.Bundle;
-import android.util.Log;
-import android.view.View;
-import android.widget.Toast;
-
-import com.google.android.gms.common.ConnectionResult;
-import com.google.android.gms.common.api.GoogleApiClient;
-import com.google.android.gms.common.api.ResultCallback;
-import com.google.android.gms.games.Games;
-import com.google.android.gms.games.event.Events;
-import com.google.android.gms.games.quest.Quest;
-import com.google.android.gms.games.quest.QuestBuffer;
-import com.google.android.gms.games.quest.QuestUpdateListener;
-import com.google.android.gms.games.quest.Quests;
-import com.google.android.gms.plus.Plus;
-import com.google.example.games.basegameutils.BaseGameUtils;
-
-import java.io.UnsupportedEncodingException;
-
-/**
- * Trivial Quest 2. A sample game that uses Play Games Services to
- * manage events and quests. The user clicks attack buttons to trigger Events.
- * Using the event data, you can configure quests and milestones to trigger
- * experiences in your games. The most exciting part is that you can instrument
- * in-game bonus rewards and determine the criteria for unlocking them after your
- * game is published by instrumenting in-game events as we're demonstrating here.
- *
- * @author Gus Class (Google)
- *
- */
-public class MainActivity extends Activity implements View.OnClickListener,
- QuestUpdateListener, GoogleApiClient.OnConnectionFailedListener,
- GoogleApiClient.ConnectionCallbacks {
-
- private static final String TAG = "TrivialQuest2";
- private static final int RC_SIGN_IN = 9001;
- private static EventCallback ec;
- private static QuestCallback qc;
- private ResultCallback mClaimMilestoneResultCallback;
-
- // Client used to interact with Google APIs
- private GoogleApiClient mGoogleApiClient;
-
- // Are we currently resolving a connection failure?
- private boolean mResolvingConnectionFailure = false;
-
- // Has the user clicked the sign-in button?
- private boolean mSignInClicked = false;
-
- // Automatically start the sign-in flow when the Activity starts
- private boolean mAutoStartSignInFlow = true;
-
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
-
- // Create the Google API Client with access to Plus and Games
- mGoogleApiClient = new GoogleApiClient.Builder(this)
- .addConnectionCallbacks(this)
- .addOnConnectionFailedListener(this)
- .addApi(Plus.API).addScope(Plus.SCOPE_PLUS_LOGIN)
- .addApi(Games.API).addScope(Games.SCOPE_GAMES)
- .build();
-
- setContentView(R.layout.activity_main);
- findViewById(R.id.button_sign_in).setOnClickListener(this);
- findViewById(R.id.button_sign_out).setOnClickListener(this);
- findViewById(R.id.button_red).setOnClickListener(this);
- findViewById(R.id.button_green).setOnClickListener(this);
- findViewById(R.id.button_blue).setOnClickListener(this);
- findViewById(R.id.button_yellow).setOnClickListener(this);
- findViewById(R.id.button_quests).setOnClickListener(this);
-
- // Initialize the callbacks for API data return.
- ec = new EventCallback(this);
- qc = new QuestCallback(this);
-
- // Set the callback for when milestones are claimed.
- mClaimMilestoneResultCallback = new ResultCallback() {
- @Override
- public void onResult(Quests.ClaimMilestoneResult result) {
- onMilestoneClaimed(result);
- }
- };
-
- // List event stats.
- loadAndPrintEvents();
- }
-
- @Override
- protected void onStart() {
- super.onStart();
- Log.d(TAG, "onStart(): connecting");
- mGoogleApiClient.connect();
- }
-
- @Override
- protected void onStop() {
- super.onStop();
- Log.d(TAG, "onStop(): disconnecting");
- if (mGoogleApiClient.isConnected()) {
- mGoogleApiClient.disconnect();
- }
- }
-
- @Override
- protected void onActivityResult(int requestCode, int resultCode, Intent intent) {
- super.onActivityResult(requestCode, resultCode, intent);
- if (requestCode == RC_SIGN_IN) {
- mSignInClicked = false;
- mResolvingConnectionFailure = false;
- if (resultCode == RESULT_OK) {
- mGoogleApiClient.connect();
- } else {
- BaseGameUtils.showActivityResultError(this, requestCode, resultCode, R.string.signin_other_error);
- }
- }
- }
-
- /**
- * Lists all of the events for this app as well as the event counts.
- */
- public void loadAndPrintEvents() {
- // Load up a list of events
- com.google.android.gms.common.api.PendingResult pr =
- Games.Events.load(mGoogleApiClient, true);
-
- // Set the callback to the EventCallback class.
- pr.setResultCallback(ec);
- }
-
- /**
- * Class implementation for handling Event results.
- */
- class EventCallback implements com.google.android.gms.common.api.ResultCallback {
- /**
- * The activity that creates the callback handler class.
- */
- MainActivity m_parent;
-
- public EventCallback (MainActivity main){
- m_parent = main;
- }
-
- /**
- * Receives event results.
- *
- * @param result The result from the Event.
- */
- public void onResult(com.google.android.gms.common.api.Result result) {
- Events.LoadEventsResult r = (Events.LoadEventsResult)result;
- com.google.android.gms.games.event.EventBuffer eb = r.getEvents();
-
- String message = "Current stats: \n";
-
- Log.i(TAG, "number of events: " + eb.getCount());
-
- String currentEvent = "";
- for(int i=0; i < eb.getCount(); i++) {
- message += "event: " + eb.get(i).getName() + " " + eb.get(i).getEventId() +
- " " + eb.get(i).getValue() + "\n";
- }
- eb.close();
-
- Toast.makeText(m_parent, message, Toast.LENGTH_LONG).show();
- }
- }
-
- /**
- * List all of the quests for this app.
- */
- public void loadAndListQuests() {
- int[] selection = {Quests.SELECT_OPEN, Quests.SELECT_COMPLETED_UNCLAIMED,
- Quests.SELECT_ACCEPTED};
- com.google.android.gms.common.api.PendingResult pr =
- Games.Quests.load(mGoogleApiClient, selection,
- Quests.SORT_ORDER_ENDING_SOON_FIRST, true);
-
- // Set the callback to the Quest callback.
- pr.setResultCallback(qc);
- }
-
- /**
- * Class implementation for handling Quest results.
- */
- class QuestCallback implements com.google.android.gms.common.api.ResultCallback {
- /**
- * The activity that creates the callback handler class.
- */
- MainActivity m_parent;
-
- public QuestCallback (MainActivity main){
- m_parent = main;
- }
-
- /**
- * Receives Quest results.
- *
- * @param result The result from the Quest.
- */
- public void onResult(com.google.android.gms.common.api.Result result) {
- Quests.LoadQuestsResult r = (Quests.LoadQuestsResult)result;
- QuestBuffer qb = r.getQuests();
-
- String message = "Current quest details: \n";
-
- Log.i(TAG, "Number of quests: " + qb.getCount());
-
- String currentEvent = "";
- for(int i=0; i < qb.getCount(); i++) {
- message += "Quest: " + qb.get(i).getName() + " id: " + qb.get(i).getQuestId();
- }
- qb.close();
-
- Toast.makeText(m_parent, message, Toast.LENGTH_LONG).show();
- }
- }
-
- /**
- * Event handler for when Quests are completed.
- *
- * @param quest The quest that has been completed.
- */
- @Override
- public void onQuestCompleted(Quest quest) {
- // create a message string indicating that the quest was successfully completed
- String message = "You successfully completed quest " + quest.getName();
-
- // Print out message for debugging purposes.
- Log.i(TAG, message);
-
- // Create a custom toast to indicate the quest was successfully completed.
- Toast.makeText(this, message, Toast.LENGTH_LONG).show();
-
- // Claim the quest reward.
- Games.Quests.claim(
- mGoogleApiClient,
- quest.getQuestId(),
- quest.getCurrentMilestone().getMilestoneId())
- .setResultCallback(mClaimMilestoneResultCallback);
- }
-
- public void onMilestoneClaimed(Quests.ClaimMilestoneResult result){
- // Process the RewardData binary array to provide a specific reward and present the
- // information to the user.
- try {
- if (result.getStatus().isSuccess()){
- String reward = new String(result.getQuest().getCurrentMilestone().
- getCompletionRewardData(),
- "UTF-8");
- // TOAST to let the player what they were rewarded.
- Toast.makeText(this, "Congratulations, you got a " + reward,
- Toast.LENGTH_LONG).show();
- } else {
- Log.e(TAG, "Reward was not claimed due to error.");
- Toast.makeText(this, "Reward was not claimed due to error.",
- Toast.LENGTH_LONG).show();
- }
- } catch (UnsupportedEncodingException uee) {
- uee.printStackTrace();
- }
- }
-
-
- /**
- * Shows the "sign in" bar (explanation and button).
- */
- private void showSignInBar() {
- findViewById(R.id.sign_in_bar).setVisibility(View.VISIBLE);
- findViewById(R.id.sign_out_bar).setVisibility(View.GONE);
- }
-
- /**
- * Shows the "sign out" bar (explanation and button).
- */
- private void showSignOutBar() {
- findViewById(R.id.sign_in_bar).setVisibility(View.GONE);
- findViewById(R.id.sign_out_bar).setVisibility(View.VISIBLE);
- }
-
- @Override
- public void onConnected(Bundle bundle) {
- Log.d(TAG, "onConnected(): connected to Google APIs");
- showSignOutBar();
-
- // Start the quest listener.
- Games.Quests.registerQuestUpdateListener(mGoogleApiClient, this);
- }
-
- @Override
- public void onConnectionSuspended(int i) {
- Log.d(TAG, "onConnectionSuspended(): attempting to reconnect");
- mGoogleApiClient.connect();
- }
-
- @Override
- public void onConnectionFailed(ConnectionResult connectionResult) {
- Log.d(TAG, "onConnectionFailed(): attempting to resolve");
- if (mResolvingConnectionFailure) {
- Log.d(TAG, "onConnectionFailed(): already resolving, ignoring");
- return;
- }
-
- if (mSignInClicked || mAutoStartSignInFlow) {
- mAutoStartSignInFlow = false;
- mSignInClicked = false;
- mResolvingConnectionFailure = true;
- if (!BaseGameUtils.resolveConnectionFailure(this, mGoogleApiClient, connectionResult,
- RC_SIGN_IN, getString(R.string.signin_other_error))) {
- mResolvingConnectionFailure = false;
- }
- }
- showSignInBar();
- }
-
-
- /**
- * Shows the current list of available quests.
- */
- public void showQuests() {
- int[] selection = {Quests.SELECT_OPEN, Quests.SELECT_COMPLETED_UNCLAIMED,
- Quests.SELECT_ACCEPTED};
- android.content.Intent questsIntent = Games.Quests.getQuestsIntent(mGoogleApiClient,
- selection);
- startActivityForResult(questsIntent, 0);
- }
-
-
- /**
- * Click handler for the activity. This method is used to determine which monster the user
- * has defeated by clicking the according button.
- *
- * @param view Contains event data such as which button was clicked.
- */
- @Override
- public void onClick(View view) {
- switch (view.getId()) {
- case R.id.button_sign_in:
- // Check to see the developer who's running this sample code read the instructions :-)
- // NOTE: this check is here only because this is a sample! Don't include this
- // check in your actual production app.
- if(!BaseGameUtils.verifySampleSetup(this, R.string.app_id, R.string.red_event_id)) {
- Log.w(TAG, "*** Warning: setup problems detected. Sign in may not work!");
- }
-
- // start the sign-in flow
- mSignInClicked = true;
- mGoogleApiClient.connect();
- break;
- case R.id.button_sign_out:
- // sign out.
- mSignInClicked = false;
- Games.signOut(mGoogleApiClient);
- if (mGoogleApiClient.isConnected()) {
- mGoogleApiClient.disconnect();
- }
- showSignInBar();
- break;
- case R.id.button_quests:
- showQuests();
- break;
- case R.id.button_red:
- if (mGoogleApiClient.isConnected()) {
- Games.Events.increment(mGoogleApiClient, getString(R.string.red_event_id), 1);
- }
- BaseGameUtils.makeSimpleDialog(this,
- getString(R.string.victory), getString(R.string.defeat_red_monster)).show();
- break;
- case R.id.button_blue:
- if (mGoogleApiClient.isConnected()) {
- Games.Events.increment(mGoogleApiClient, getString(R.string.blue_event_id), 1);
- }
- BaseGameUtils.makeSimpleDialog(this,
- getString(R.string.victory), getString(R.string.defeat_blue_monster)).show();
- break;
- case R.id.button_green:
- if (mGoogleApiClient.isConnected()) {
- Games.Events.increment(mGoogleApiClient, getString(R.string.green_event_id), 1);
- }
- BaseGameUtils.makeSimpleDialog(this,
- getString(R.string.victory), getString(R.string.defeat_green_monster)).show();
- break;
- case R.id.button_yellow:
- if (mGoogleApiClient.isConnected()) {
- Games.Events.increment(mGoogleApiClient, getString(R.string.yellow_event_id), 1);
- }
- BaseGameUtils.makeSimpleDialog(this,
- getString(R.string.victory), getString(R.string.defeat_yellow_monster)).show();
- break;
- default:
- break;
-
- }
- }
-}
diff --git a/BasicSamples/TrivialQuest2/src/main/res/drawable-hdpi/ic_launcher.png b/BasicSamples/TrivialQuest2/src/main/res/drawable-hdpi/ic_launcher.png
deleted file mode 100644
index bfe60a8a..00000000
Binary files a/BasicSamples/TrivialQuest2/src/main/res/drawable-hdpi/ic_launcher.png and /dev/null differ
diff --git a/BasicSamples/TrivialQuest2/src/main/res/drawable-ldpi/ic_launcher.png b/BasicSamples/TrivialQuest2/src/main/res/drawable-ldpi/ic_launcher.png
deleted file mode 100644
index 2c4a5b26..00000000
Binary files a/BasicSamples/TrivialQuest2/src/main/res/drawable-ldpi/ic_launcher.png and /dev/null differ
diff --git a/BasicSamples/TrivialQuest2/src/main/res/drawable-mdpi/ic_launcher.png b/BasicSamples/TrivialQuest2/src/main/res/drawable-mdpi/ic_launcher.png
deleted file mode 100644
index 13845b21..00000000
Binary files a/BasicSamples/TrivialQuest2/src/main/res/drawable-mdpi/ic_launcher.png and /dev/null differ
diff --git a/BasicSamples/TrivialQuest2/src/main/res/drawable-xhdpi/ic_launcher.png b/BasicSamples/TrivialQuest2/src/main/res/drawable-xhdpi/ic_launcher.png
deleted file mode 100644
index b42fe111..00000000
Binary files a/BasicSamples/TrivialQuest2/src/main/res/drawable-xhdpi/ic_launcher.png and /dev/null differ
diff --git a/BasicSamples/TrivialQuest2/src/main/res/drawable-xxhdpi/ic_launcher.png b/BasicSamples/TrivialQuest2/src/main/res/drawable-xxhdpi/ic_launcher.png
deleted file mode 100644
index 72f6a0c1..00000000
Binary files a/BasicSamples/TrivialQuest2/src/main/res/drawable-xxhdpi/ic_launcher.png and /dev/null differ
diff --git a/BasicSamples/TrivialQuest2/src/main/res/layout/activity_main.xml b/BasicSamples/TrivialQuest2/src/main/res/layout/activity_main.xml
deleted file mode 100644
index 24246d9b..00000000
--- a/BasicSamples/TrivialQuest2/src/main/res/layout/activity_main.xml
+++ /dev/null
@@ -1,83 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/BasicSamples/TrivialQuest2/src/main/res/values-v11/styles.xml b/BasicSamples/TrivialQuest2/src/main/res/values-v11/styles.xml
deleted file mode 100644
index 3d45cb70..00000000
--- a/BasicSamples/TrivialQuest2/src/main/res/values-v11/styles.xml
+++ /dev/null
@@ -1,28 +0,0 @@
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/BasicSamples/TrivialQuest2/src/main/res/values-v14/styles.xml b/BasicSamples/TrivialQuest2/src/main/res/values-v14/styles.xml
deleted file mode 100644
index 9e1013d7..00000000
--- a/BasicSamples/TrivialQuest2/src/main/res/values-v14/styles.xml
+++ /dev/null
@@ -1,29 +0,0 @@
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/BasicSamples/TrivialQuest2/src/main/res/values/ids.xml b/BasicSamples/TrivialQuest2/src/main/res/values/ids.xml
deleted file mode 100644
index b7f7e74d..00000000
--- a/BasicSamples/TrivialQuest2/src/main/res/values/ids.xml
+++ /dev/null
@@ -1,26 +0,0 @@
-
-
-
-
- ReplaceMe
-
-
- ReplaceMe
- ReplaceMe
- ReplaceMe
- ReplaceMe
-
diff --git a/BasicSamples/TrivialQuest2/src/main/res/values/strings.xml b/BasicSamples/TrivialQuest2/src/main/res/values/strings.xml
deleted file mode 100644
index f5bd5301..00000000
--- a/BasicSamples/TrivialQuest2/src/main/res/values/strings.xml
+++ /dev/null
@@ -1,37 +0,0 @@
-
-
-
-
- Signing in with Google
- Signing out
- Trivial Quest 2
- Sign with Google to upload your achievements and share with friends.
- You are signed in with Google.
- Sign Out
- Show me the Quests
- Attack red!
- Attack green!
- Attack blue!
- Attack yellow!
- Victory
- You defeated a blue monster!!
- You defeated a green monster!
- You defeated a red monster!
- You defeated a yellow monster.
- OK! You won!
- There was an issue with sign in. Please try again later.
-
diff --git a/BasicSamples/TrivialQuest2/src/main/res/values/styles.xml b/BasicSamples/TrivialQuest2/src/main/res/values/styles.xml
deleted file mode 100644
index e4a79ada..00000000
--- a/BasicSamples/TrivialQuest2/src/main/res/values/styles.xml
+++ /dev/null
@@ -1,86 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/BasicSamples/TypeANumber/.gitignore b/BasicSamples/TypeANumber/.gitignore
deleted file mode 100644
index 47036e4a..00000000
--- a/BasicSamples/TypeANumber/.gitignore
+++ /dev/null
@@ -1,3 +0,0 @@
-/build/
-/bin/
-/gen/
diff --git a/BasicSamples/TypeANumber/build.gradle b/BasicSamples/TypeANumber/build.gradle
deleted file mode 100644
index d6a339c7..00000000
--- a/BasicSamples/TypeANumber/build.gradle
+++ /dev/null
@@ -1,34 +0,0 @@
-apply plugin: 'android'
-
-android {
- enforceUniquePackageName=false
-
- compileSdkVersion 20
- buildToolsVersion '20'
-
- defaultConfig {
- minSdkVersion 9
- targetSdkVersion 20
- versionCode 1
- versionName "1.0"
- }
- buildTypes {
- release {
- minifyEnabled false
- proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.txt'
- }
- }
-}
-
-dependencies {
- compile project(':libraries:BaseGameUtils')
- compile 'com.android.support:appcompat-v7:20.0.+'
- compile 'com.android.support:support-v4:20.0.+'
- compile 'com.google.android.gms:play-services:+'
-}
-
-buildscript {
- repositories {
- mavenCentral()
- }
-}
diff --git a/BasicSamples/TypeANumber/src/main/java/com/google/example/games/tanc/GameplayFragment.java b/BasicSamples/TypeANumber/src/main/java/com/google/example/games/tanc/GameplayFragment.java
deleted file mode 100644
index 1293ba0f..00000000
--- a/BasicSamples/TypeANumber/src/main/java/com/google/example/games/tanc/GameplayFragment.java
+++ /dev/null
@@ -1,103 +0,0 @@
-/*
- * 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.tanc;
-
-import android.os.Bundle;
-import android.support.v4.app.Fragment;
-import android.view.LayoutInflater;
-import android.view.View;
-import android.view.View.OnClickListener;
-import android.view.ViewGroup;
-import android.widget.Button;
-import android.widget.TextView;
-
-/**
- * Fragment for the gameplay portion of the game. It shows the keypad
- * where the user can request their score.
- *
- * @author Bruno Oliveira (Google)
- *
- */
-public class GameplayFragment extends Fragment implements OnClickListener {
- int mRequestedScore = 5000;
-
- static int[] MY_BUTTONS = {
- R.id.digit_button_0, R.id.digit_button_1, R.id.digit_button_2,
- R.id.digit_button_3, R.id.digit_button_4, R.id.digit_button_5,
- R.id.digit_button_6, R.id.digit_button_7, R.id.digit_button_8,
- R.id.digit_button_9, R.id.digit_button_clear, R.id.ok_score_button
- };
-
- public interface Listener {
- public void onEnteredScore(int score);
- }
-
- Listener mListener = null;
-
- @Override
- public View onCreateView(LayoutInflater inflater, ViewGroup container,
- Bundle savedInstanceState) {
- View v = inflater.inflate(R.layout.fragment_gameplay, container, false);
- for (int i : MY_BUTTONS) {
- ((Button) v.findViewById(i)).setOnClickListener(this);
- }
- return v;
- }
-
- public void setListener(Listener l) {
- mListener = l;
- }
-
- @Override
- public void onStart() {
- super.onStart();
- updateUi();
- }
-
- void updateUi() {
- if (getActivity() == null) return;
- TextView scoreInput = ((TextView) getActivity().findViewById(R.id.score_input));
- if (scoreInput != null) scoreInput.setText(String.format("%04d", mRequestedScore));
- }
-
- @Override
- public void onClick(View view) {
- switch (view.getId()) {
- case R.id.digit_button_clear:
- mRequestedScore = 0;
- updateUi();
- break;
- case R.id.digit_button_0:
- case R.id.digit_button_1:
- case R.id.digit_button_2:
- case R.id.digit_button_3:
- case R.id.digit_button_4:
- case R.id.digit_button_5:
- case R.id.digit_button_6:
- case R.id.digit_button_7:
- case R.id.digit_button_8:
- case R.id.digit_button_9:
- int x = Integer.parseInt(((Button)view).getText().toString().trim());
- mRequestedScore = (mRequestedScore * 10 + x) % 10000;
- updateUi();
- break;
- case R.id.ok_score_button:
- mListener.onEnteredScore(mRequestedScore);
- break;
- }
- }
-}
diff --git a/BasicSamples/TypeANumber/src/main/java/com/google/example/games/tanc/MainActivity.java b/BasicSamples/TypeANumber/src/main/java/com/google/example/games/tanc/MainActivity.java
deleted file mode 100644
index e8e2a6fa..00000000
--- a/BasicSamples/TypeANumber/src/main/java/com/google/example/games/tanc/MainActivity.java
+++ /dev/null
@@ -1,460 +0,0 @@
-/*
- * 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.tanc;
-
-import android.content.Context;
-import android.content.Intent;
-import android.os.Bundle;
-import android.support.v4.app.Fragment;
-import android.support.v4.app.FragmentActivity;
-import android.util.Log;
-import android.widget.Toast;
-
-import com.google.android.gms.common.ConnectionResult;
-import com.google.android.gms.common.api.GoogleApiClient;
-import com.google.android.gms.games.Games;
-import com.google.android.gms.games.Player;
-import com.google.android.gms.plus.Plus;
-import com.google.example.games.basegameutils.BaseGameUtils;
-
-/**
- * Our main activity for the game.
- *
- * IMPORTANT: Before attempting to run this sample, please change
- * the package name to your own package name (not com.android.*) and
- * replace the IDs on res/values/ids.xml by your own IDs (you must
- * create a game in the developer console to get those IDs).
- *
- * This is a very simple game where the user selects "easy mode" or
- * "hard mode" and then the "gameplay" consists of inputting the
- * desired score (0 to 9999). In easy mode, you get the score you
- * request; in hard mode, you get half.
- *
- * @author Bruno Oliveira
- */
-public class MainActivity extends FragmentActivity
- implements MainMenuFragment.Listener,
- GameplayFragment.Listener, WinFragment.Listener,
- GoogleApiClient.ConnectionCallbacks, GoogleApiClient.OnConnectionFailedListener {
-
- // Fragments
- MainMenuFragment mMainMenuFragment;
- GameplayFragment mGameplayFragment;
- WinFragment mWinFragment;
-
- // Client used to interact with Google APIs
- private GoogleApiClient mGoogleApiClient;
-
- // Are we currently resolving a connection failure?
- private boolean mResolvingConnectionFailure = false;
-
- // Has the user clicked the sign-in button?
- private boolean mSignInClicked = false;
-
- // Automatically start the sign-in flow when the Activity starts
- private boolean mAutoStartSignInFlow = true;
-
- // request codes we use when invoking an external activity
- private static final int RC_RESOLVE = 5000;
- private static final int RC_UNUSED = 5001;
- private static final int RC_SIGN_IN = 9001;
-
- // tag for debug logging
- final boolean ENABLE_DEBUG = true;
- final String TAG = "TanC";
-
- // playing on hard mode?
- boolean mHardMode = false;
-
- // achievements and scores we're pending to push to the cloud
- // (waiting for the user to sign in, for instance)
- AccomplishmentsOutbox mOutbox = new AccomplishmentsOutbox();
-
- @Override
- public void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.activity_main);
-
- // Create the Google API Client with access to Plus and Games
- mGoogleApiClient = new GoogleApiClient.Builder(this)
- .addConnectionCallbacks(this)
- .addOnConnectionFailedListener(this)
- .addApi(Plus.API).addScope(Plus.SCOPE_PLUS_LOGIN)
- .addApi(Games.API).addScope(Games.SCOPE_GAMES)
- .build();
-
- // create fragments
- mMainMenuFragment = new MainMenuFragment();
- mGameplayFragment = new GameplayFragment();
- mWinFragment = new WinFragment();
-
- // listen to fragment events
- mMainMenuFragment.setListener(this);
- mGameplayFragment.setListener(this);
- mWinFragment.setListener(this);
-
- // add initial fragment (welcome fragment)
- getSupportFragmentManager().beginTransaction().add(R.id.fragment_container,
- mMainMenuFragment).commit();
-
- // IMPORTANT: if this Activity supported rotation, we'd have to be
- // more careful about adding the fragment, since the fragment would
- // already be there after rotation and trying to add it again would
- // result in overlapping fragments. But since we don't support rotation,
- // we don't deal with that for code simplicity.
-
- // load outbox from file
- mOutbox.loadLocal(this);
- }
-
- // Switch UI to the given fragment
- void switchToFragment(Fragment newFrag) {
- getSupportFragmentManager().beginTransaction().replace(R.id.fragment_container, newFrag)
- .commit();
- }
-
- private boolean isSignedIn() {
- return (mGoogleApiClient != null && mGoogleApiClient.isConnected());
- }
-
- @Override
- protected void onStart() {
- super.onStart();
- Log.d(TAG, "onStart(): connecting");
- mGoogleApiClient.connect();
- }
-
- @Override
- protected void onStop() {
- super.onStop();
- Log.d(TAG, "onStop(): disconnecting");
- if (mGoogleApiClient.isConnected()) {
- mGoogleApiClient.disconnect();
- }
- }
-
- @Override
- public void onStartGameRequested(boolean hardMode) {
- startGame(hardMode);
- }
-
- @Override
- public void onShowAchievementsRequested() {
- if (isSignedIn()) {
- startActivityForResult(Games.Achievements.getAchievementsIntent(mGoogleApiClient),
- RC_UNUSED);
- } else {
- BaseGameUtils.makeSimpleDialog(this, getString(R.string.achievements_not_available)).show();
- }
- }
-
- @Override
- public void onShowLeaderboardsRequested() {
- if (isSignedIn()) {
- startActivityForResult(Games.Leaderboards.getAllLeaderboardsIntent(mGoogleApiClient),
- RC_UNUSED);
- } else {
- BaseGameUtils.makeSimpleDialog(this, getString(R.string.leaderboards_not_available)).show();
- }
- }
-
- /**
- * Start gameplay. This means updating some status variables and switching
- * to the "gameplay" screen (the screen where the user types the score they want).
- *
- * @param hardMode whether to start gameplay in "hard mode".
- */
- void startGame(boolean hardMode) {
- mHardMode = hardMode;
- switchToFragment(mGameplayFragment);
- }
-
- @Override
- public void onEnteredScore(int requestedScore) {
- // Compute final score (in easy mode, it's the requested score; in hard mode, it's half)
- int finalScore = mHardMode ? requestedScore / 2 : requestedScore;
-
- mWinFragment.setFinalScore(finalScore);
- mWinFragment.setExplanation(mHardMode ? getString(R.string.hard_mode_explanation) :
- getString(R.string.easy_mode_explanation));
-
- // check for achievements
- checkForAchievements(requestedScore, finalScore);
-
- // update leaderboards
- updateLeaderboards(finalScore);
-
- // push those accomplishments to the cloud, if signed in
- pushAccomplishments();
-
- // switch to the exciting "you won" screen
- switchToFragment(mWinFragment);
- }
-
- // Checks if n is prime. We don't consider 0 and 1 to be prime.
- // This is not an implementation we are mathematically proud of, but it gets the job done.
- boolean isPrime(int n) {
- int i;
- if (n == 0 || n == 1) return false;
- for (i = 2; i <= n / 2; i++) {
- if (n % i == 0) {
- return false;
- }
- }
- return true;
- }
-
- /**
- * Check for achievements and unlock the appropriate ones.
- *
- * @param requestedScore the score the user requested.
- * @param finalScore the score the user got.
- */
- void checkForAchievements(int requestedScore, int finalScore) {
- // Check if each condition is met; if so, unlock the corresponding
- // achievement.
- if (isPrime(finalScore)) {
- mOutbox.mPrimeAchievement = true;
- achievementToast(getString(R.string.achievement_prime_toast_text));
- }
- if (requestedScore == 9999) {
- mOutbox.mArrogantAchievement = true;
- achievementToast(getString(R.string.achievement_arrogant_toast_text));
- }
- if (requestedScore == 0) {
- mOutbox.mHumbleAchievement = true;
- achievementToast(getString(R.string.achievement_humble_toast_text));
- }
- if (finalScore == 1337) {
- mOutbox.mLeetAchievement = true;
- achievementToast(getString(R.string.achievement_leet_toast_text));
- }
- mOutbox.mBoredSteps++;
- }
-
- void unlockAchievement(int achievementId, String fallbackString) {
- if (isSignedIn()) {
- Games.Achievements.unlock(mGoogleApiClient, getString(achievementId));
- } else {
- Toast.makeText(this, getString(R.string.achievement) + ": " + fallbackString,
- Toast.LENGTH_LONG).show();
- }
- }
-
- void achievementToast(String achievement) {
- // Only show toast if not signed in. If signed in, the standard Google Play
- // toasts will appear, so we don't need to show our own.
- if (!isSignedIn()) {
- Toast.makeText(this, getString(R.string.achievement) + ": " + achievement,
- Toast.LENGTH_LONG).show();
- }
- }
-
- void pushAccomplishments() {
- if (!isSignedIn()) {
- // can't push to the cloud, so save locally
- mOutbox.saveLocal(this);
- return;
- }
- if (mOutbox.mPrimeAchievement) {
- Games.Achievements.unlock(mGoogleApiClient, getString(R.string.achievement_prime));
- mOutbox.mPrimeAchievement = false;
- }
- if (mOutbox.mArrogantAchievement) {
- Games.Achievements.unlock(mGoogleApiClient, getString(R.string.achievement_arrogant));
- mOutbox.mArrogantAchievement = false;
- }
- if (mOutbox.mHumbleAchievement) {
- Games.Achievements.unlock(mGoogleApiClient, getString(R.string.achievement_humble));
- mOutbox.mHumbleAchievement = false;
- }
- if (mOutbox.mLeetAchievement) {
- Games.Achievements.unlock(mGoogleApiClient, getString(R.string.achievement_leet));
- mOutbox.mLeetAchievement = false;
- }
- if (mOutbox.mBoredSteps > 0) {
- Games.Achievements.increment(mGoogleApiClient, getString(R.string.achievement_really_bored),
- mOutbox.mBoredSteps);
- Games.Achievements.increment(mGoogleApiClient, getString(R.string.achievement_bored),
- mOutbox.mBoredSteps);
- }
- if (mOutbox.mEasyModeScore >= 0) {
- Games.Leaderboards.submitScore(mGoogleApiClient, getString(R.string.leaderboard_easy),
- mOutbox.mEasyModeScore);
- mOutbox.mEasyModeScore = -1;
- }
- if (mOutbox.mHardModeScore >= 0) {
- Games.Leaderboards.submitScore(mGoogleApiClient, getString(R.string.leaderboard_hard),
- mOutbox.mHardModeScore);
- mOutbox.mHardModeScore = -1;
- }
- mOutbox.saveLocal(this);
- }
-
- /**
- * Update leaderboards with the user's score.
- *
- * @param finalScore The score the user got.
- */
- void updateLeaderboards(int finalScore) {
- if (mHardMode && mOutbox.mHardModeScore < finalScore) {
- mOutbox.mHardModeScore = finalScore;
- } else if (!mHardMode && mOutbox.mEasyModeScore < finalScore) {
- mOutbox.mEasyModeScore = finalScore;
- }
- }
-
- @Override
- public void onWinScreenDismissed() {
- switchToFragment(mMainMenuFragment);
- }
-
- @Override
- protected void onActivityResult(int requestCode, int resultCode, Intent intent) {
- super.onActivityResult(requestCode, resultCode, intent);
- if (requestCode == RC_SIGN_IN) {
- mSignInClicked = false;
- mResolvingConnectionFailure = false;
- if (resultCode == RESULT_OK) {
- mGoogleApiClient.connect();
- } else {
- BaseGameUtils.showActivityResultError(this, requestCode, resultCode, R.string.signin_other_error);
- }
- }
- }
-
- @Override
- public void onConnected(Bundle bundle) {
- Log.d(TAG, "onConnected(): connected to Google APIs");
- // Show sign-out button on main menu
- mMainMenuFragment.setShowSignInButton(false);
-
- // Show "you are signed in" message on win screen, with no sign in button.
- mWinFragment.setShowSignInButton(false);
-
- // Set the greeting appropriately on main menu
- Player p = Games.Players.getCurrentPlayer(mGoogleApiClient);
- String displayName;
- if (p == null) {
- Log.w(TAG, "mGamesClient.getCurrentPlayer() is NULL!");
- displayName = "???";
- } else {
- displayName = p.getDisplayName();
- }
- mMainMenuFragment.setGreeting("Hello, " + displayName);
-
-
- // if we have accomplishments to push, push them
- if (!mOutbox.isEmpty()) {
- pushAccomplishments();
- Toast.makeText(this, getString(R.string.your_progress_will_be_uploaded),
- Toast.LENGTH_LONG).show();
- }
- }
-
- @Override
- public void onConnectionSuspended(int i) {
- Log.d(TAG, "onConnectionSuspended(): attempting to connect");
- mGoogleApiClient.connect();
- }
-
- @Override
- public void onConnectionFailed(ConnectionResult connectionResult) {
- Log.d(TAG, "onConnectionFailed(): attempting to resolve");
- if (mResolvingConnectionFailure) {
- Log.d(TAG, "onConnectionFailed(): already resolving");
- return;
- }
-
- if (mSignInClicked || mAutoStartSignInFlow) {
- mAutoStartSignInFlow = false;
- mSignInClicked = false;
- mResolvingConnectionFailure = true;
- if (!BaseGameUtils.resolveConnectionFailure(this, mGoogleApiClient, connectionResult,
- RC_SIGN_IN, getString(R.string.signin_other_error))) {
- mResolvingConnectionFailure = false;
- }
- }
-
- // Sign-in failed, so show sign-in button on main menu
- mMainMenuFragment.setGreeting(getString(R.string.signed_out_greeting));
- mMainMenuFragment.setShowSignInButton(true);
- mWinFragment.setShowSignInButton(true);
- }
-
- @Override
- public void onSignInButtonClicked() {
- // Check to see the developer who's running this sample code read the instructions :-)
- // NOTE: this check is here only because this is a sample! Don't include this
- // check in your actual production app.
- if(!BaseGameUtils.verifySampleSetup(this, R.string.app_id,
- R.string.achievement_prime, R.string.leaderboard_easy)) {
- Log.w(TAG, "*** Warning: setup problems detected. Sign in may not work!");
- }
-
- // start the sign-in flow
- mSignInClicked = true;
- mGoogleApiClient.connect();
- }
-
- @Override
- public void onSignOutButtonClicked() {
- mSignInClicked = false;
- Games.signOut(mGoogleApiClient);
- if (mGoogleApiClient.isConnected()) {
- mGoogleApiClient.disconnect();
- }
-
- mMainMenuFragment.setGreeting(getString(R.string.signed_out_greeting));
- mMainMenuFragment.setShowSignInButton(true);
- mWinFragment.setShowSignInButton(true);
- }
-
- class AccomplishmentsOutbox {
- boolean mPrimeAchievement = false;
- boolean mHumbleAchievement = false;
- boolean mLeetAchievement = false;
- boolean mArrogantAchievement = false;
- int mBoredSteps = 0;
- int mEasyModeScore = -1;
- int mHardModeScore = -1;
-
- boolean isEmpty() {
- return !mPrimeAchievement && !mHumbleAchievement && !mLeetAchievement &&
- !mArrogantAchievement && mBoredSteps == 0 && mEasyModeScore < 0 &&
- mHardModeScore < 0;
- }
-
- public void saveLocal(Context ctx) {
- /* TODO: This is left as an exercise. To make it more difficult to cheat,
- * this data should be stored in an encrypted file! And remember not to
- * expose your encryption key (obfuscate it by building it from bits and
- * pieces and/or XORing with another string, for instance). */
- }
-
- public void loadLocal(Context ctx) {
- /* TODO: This is left as an exercise. Write code here that loads data
- * from the file you wrote in saveLocal(). */
- }
- }
-
- @Override
- public void onWinScreenSignInClicked() {
- mSignInClicked = true;
- mGoogleApiClient.connect();
- }
-}
diff --git a/BasicSamples/TypeANumber/src/main/java/com/google/example/games/tanc/MainMenuFragment.java b/BasicSamples/TypeANumber/src/main/java/com/google/example/games/tanc/MainMenuFragment.java
deleted file mode 100644
index 6e046ba9..00000000
--- a/BasicSamples/TypeANumber/src/main/java/com/google/example/games/tanc/MainMenuFragment.java
+++ /dev/null
@@ -1,117 +0,0 @@
-/* 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.tanc;
-
-import android.os.Bundle;
-import android.support.v4.app.Fragment;
-import android.view.LayoutInflater;
-import android.view.View;
-import android.view.View.OnClickListener;
-import android.view.ViewGroup;
-import android.widget.TextView;
-
-/**
- * Fragment with the main menu for the game. The main menu allows the player
- * to choose a gameplay mode (Easy or Hard), and click the buttons to
- * show view achievements/leaderboards.
- *
- * @author Bruno Oliveira (Google)
- *
- */
-public class MainMenuFragment extends Fragment implements OnClickListener {
- String mGreeting = "Hello, anonymous user (not signed in)";
-
- public interface Listener {
- public void onStartGameRequested(boolean hardMode);
- public void onShowAchievementsRequested();
- public void onShowLeaderboardsRequested();
- public void onSignInButtonClicked();
- public void onSignOutButtonClicked();
- }
-
- Listener mListener = null;
- boolean mShowSignIn = true;
-
- @Override
- public View onCreateView(LayoutInflater inflater, ViewGroup container,
- Bundle savedInstanceState) {
- View v = inflater.inflate(R.layout.fragment_mainmenu, container, false);
- final int[] CLICKABLES = new int[] {
- R.id.easy_mode_button, R.id.hard_mode_button,
- R.id.show_achievements_button, R.id.show_leaderboards_button,
- R.id.sign_in_button, R.id.sign_out_button
- };
- for (int i : CLICKABLES) {
- v.findViewById(i).setOnClickListener(this);
- }
- return v;
- }
-
- public void setListener(Listener l) {
- mListener = l;
- }
-
- @Override
- public void onStart() {
- super.onStart();
- updateUi();
- }
-
- public void setGreeting(String greeting) {
- mGreeting = greeting;
- updateUi();
- }
-
- void updateUi() {
- if (getActivity() == null) return;
- TextView tv = (TextView) getActivity().findViewById(R.id.hello);
- if (tv != null) tv.setText(mGreeting);
-
- getActivity().findViewById(R.id.sign_in_bar).setVisibility(mShowSignIn ?
- View.VISIBLE : View.GONE);
- getActivity().findViewById(R.id.sign_out_bar).setVisibility(mShowSignIn ?
- View.GONE : View.VISIBLE);
- }
-
- @Override
- public void onClick(View view) {
- switch (view.getId()) {
- case R.id.easy_mode_button:
- mListener.onStartGameRequested(false);
- break;
- case R.id.hard_mode_button:
- mListener.onStartGameRequested(true);
- break;
- case R.id.show_achievements_button:
- mListener.onShowAchievementsRequested();
- break;
- case R.id.show_leaderboards_button:
- mListener.onShowLeaderboardsRequested();
- break;
- case R.id.sign_in_button:
- mListener.onSignInButtonClicked();
- break;
- case R.id.sign_out_button:
- mListener.onSignOutButtonClicked();
- break;
- }
- }
-
- public void setShowSignInButton(boolean showSignIn) {
- mShowSignIn = showSignIn;
- updateUi();
- }
-}
diff --git a/BasicSamples/TypeANumber/src/main/java/com/google/example/games/tanc/WinFragment.java b/BasicSamples/TypeANumber/src/main/java/com/google/example/games/tanc/WinFragment.java
deleted file mode 100644
index b053aa87..00000000
--- a/BasicSamples/TypeANumber/src/main/java/com/google/example/games/tanc/WinFragment.java
+++ /dev/null
@@ -1,100 +0,0 @@
-/*
- * 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.tanc;
-
-import android.os.Bundle;
-import android.support.v4.app.Fragment;
-import android.view.LayoutInflater;
-import android.view.View;
-import android.view.View.OnClickListener;
-import android.view.ViewGroup;
-import android.widget.TextView;
-
-/**
- * Fragment that shows the 'You won' message. Apart from congratulating the user
- * on their heroic number typing deeds, this screen also allows the player to sign
- * in if they are not signed in yet.
- *
- * @author Bruno Oliveira (Google)
- *
- */
-public class WinFragment extends Fragment implements OnClickListener {
- String mExplanation = "";
- int mScore = 0;
- boolean mShowSignIn = false;
-
- public interface Listener {
- public void onWinScreenDismissed();
- public void onWinScreenSignInClicked();
- }
-
- Listener mListener = null;
-
- @Override
- public View onCreateView(LayoutInflater inflater, ViewGroup container,
- Bundle savedInstanceState) {
- View v = inflater.inflate(R.layout.fragment_win, container, false);
- v.findViewById(R.id.win_ok_button).setOnClickListener(this);
- v.findViewById(R.id.win_screen_sign_in_button).setOnClickListener(this);
- return v;
- }
-
- public void setFinalScore(int i) {
- mScore = i;
- }
-
- public void setExplanation(String s) {
- mExplanation = s;
- }
-
- public void setListener(Listener l) {
- mListener = l;
- }
-
- @Override
- public void onStart() {
- super.onStart();
- updateUi();
- }
-
- void updateUi() {
- if (getActivity() == null) return;
- TextView scoreTv = (TextView) getActivity().findViewById(R.id.score_display);
- TextView explainTv = (TextView) getActivity().findViewById(R.id.scoreblurb);
-
- if (scoreTv != null) scoreTv.setText(String.valueOf(mScore));
- if (explainTv != null) explainTv.setText(mExplanation);
-
- getActivity().findViewById(R.id.win_screen_sign_in_bar).setVisibility(
- mShowSignIn ? View.VISIBLE : View.GONE);
- getActivity().findViewById(R.id.win_screen_signed_in_bar).setVisibility(
- mShowSignIn ? View.GONE : View.VISIBLE);
- }
-
- @Override
- public void onClick(View view) {
- if (view.getId() == R.id.win_screen_sign_in_button) {
- mListener.onWinScreenSignInClicked();
- }
- mListener.onWinScreenDismissed();
- }
-
- public void setShowSignInButton(boolean showSignIn) {
- mShowSignIn = showSignIn;
- updateUi();
- }
-}
diff --git a/BasicSamples/TypeANumber/src/main/res/drawable-hdpi/ic_action_search.png b/BasicSamples/TypeANumber/src/main/res/drawable-hdpi/ic_action_search.png
deleted file mode 100644
index 67de12de..00000000
Binary files a/BasicSamples/TypeANumber/src/main/res/drawable-hdpi/ic_action_search.png and /dev/null differ
diff --git a/BasicSamples/TypeANumber/src/main/res/drawable-hdpi/ic_launcher.png b/BasicSamples/TypeANumber/src/main/res/drawable-hdpi/ic_launcher.png
deleted file mode 100644
index bfe60a8a..00000000
Binary files a/BasicSamples/TypeANumber/src/main/res/drawable-hdpi/ic_launcher.png and /dev/null differ
diff --git a/BasicSamples/TypeANumber/src/main/res/drawable-ldpi/ic_launcher.png b/BasicSamples/TypeANumber/src/main/res/drawable-ldpi/ic_launcher.png
deleted file mode 100644
index c4544c6e..00000000
Binary files a/BasicSamples/TypeANumber/src/main/res/drawable-ldpi/ic_launcher.png and /dev/null differ
diff --git a/BasicSamples/TypeANumber/src/main/res/drawable-mdpi/ic_action_search.png b/BasicSamples/TypeANumber/src/main/res/drawable-mdpi/ic_action_search.png
deleted file mode 100644
index 134d5490..00000000
Binary files a/BasicSamples/TypeANumber/src/main/res/drawable-mdpi/ic_action_search.png and /dev/null differ
diff --git a/BasicSamples/TypeANumber/src/main/res/drawable-mdpi/ic_launcher.png b/BasicSamples/TypeANumber/src/main/res/drawable-mdpi/ic_launcher.png
deleted file mode 100644
index 13845b21..00000000
Binary files a/BasicSamples/TypeANumber/src/main/res/drawable-mdpi/ic_launcher.png and /dev/null differ
diff --git a/BasicSamples/TypeANumber/src/main/res/drawable-xhdpi/ic_action_search.png b/BasicSamples/TypeANumber/src/main/res/drawable-xhdpi/ic_action_search.png
deleted file mode 100644
index d699c6b3..00000000
Binary files a/BasicSamples/TypeANumber/src/main/res/drawable-xhdpi/ic_action_search.png and /dev/null differ
diff --git a/BasicSamples/TypeANumber/src/main/res/drawable-xhdpi/ic_launcher.png b/BasicSamples/TypeANumber/src/main/res/drawable-xhdpi/ic_launcher.png
deleted file mode 100644
index b42fe111..00000000
Binary files a/BasicSamples/TypeANumber/src/main/res/drawable-xhdpi/ic_launcher.png and /dev/null differ
diff --git a/BasicSamples/TypeANumber/src/main/res/drawable-xxhdpi/ic_launcher.png b/BasicSamples/TypeANumber/src/main/res/drawable-xxhdpi/ic_launcher.png
deleted file mode 100644
index 72f6a0c1..00000000
Binary files a/BasicSamples/TypeANumber/src/main/res/drawable-xxhdpi/ic_launcher.png and /dev/null differ
diff --git a/BasicSamples/TypeANumber/src/main/res/values-v11/styles.xml b/BasicSamples/TypeANumber/src/main/res/values-v11/styles.xml
deleted file mode 100644
index 997965b5..00000000
--- a/BasicSamples/TypeANumber/src/main/res/values-v11/styles.xml
+++ /dev/null
@@ -1,20 +0,0 @@
-
-
-
-
-
-
diff --git a/BasicSamples/TypeANumber/src/main/res/values/ids.xml b/BasicSamples/TypeANumber/src/main/res/values/ids.xml
deleted file mode 100644
index 29464b98..00000000
--- a/BasicSamples/TypeANumber/src/main/res/values/ids.xml
+++ /dev/null
@@ -1,31 +0,0 @@
-
-
-
-
- ReplaceMe
-
-
- ReplaceMe
- ReplaceMe
- ReplaceMe
- ReplaceMe
- ReplaceMe
- ReplaceMe
-
- ReplaceMe
- ReplaceMe
-
diff --git a/BasicSamples/build.gradle b/BasicSamples/build.gradle
deleted file mode 100644
index e3bd35e2..00000000
--- a/BasicSamples/build.gradle
+++ /dev/null
@@ -1,16 +0,0 @@
-// intentionally empty - the content is inside the gradle files in the subdirectories
-
-buildscript {
- repositories {
- mavenCentral()
- }
- dependencies {
- classpath 'com.android.tools.build:gradle:1.0.0'
- }
-}
-
-allprojects {
- repositories {
- mavenCentral()
- }
-}
diff --git a/BasicSamples/libraries/BaseGameUtils/.gitignore b/BasicSamples/libraries/BaseGameUtils/.gitignore
deleted file mode 100644
index 4cfe4113..00000000
--- a/BasicSamples/libraries/BaseGameUtils/.gitignore
+++ /dev/null
@@ -1,3 +0,0 @@
-/bin/
-/build/
-/gen/
diff --git a/BasicSamples/libraries/BaseGameUtils/build.gradle b/BasicSamples/libraries/BaseGameUtils/build.gradle
deleted file mode 100644
index 91b65ae2..00000000
--- a/BasicSamples/libraries/BaseGameUtils/build.gradle
+++ /dev/null
@@ -1,27 +0,0 @@
-apply plugin: 'android-library'
-
-repositories {
- mavenCentral()
-}
-
-buildscript {
- repositories {
- mavenCentral()
- }
-
- dependencies {
- classpath 'com.android.tools.build:gradle:1.0.0'
- }
-}
-
-dependencies {
- compile 'com.android.support:appcompat-v7:20.0.+'
- compile 'com.android.support:support-v4:20.0.+'
- compile 'com.google.android.gms:play-services:+'
-}
-
-android {
- compileSdkVersion 20
- buildToolsVersion '20'
-}
-
diff --git a/BasicSamples/libraries/BaseGameUtils/src/main/AndroidManifest.xml b/BasicSamples/libraries/BaseGameUtils/src/main/AndroidManifest.xml
deleted file mode 100644
index 09061bd1..00000000
--- a/BasicSamples/libraries/BaseGameUtils/src/main/AndroidManifest.xml
+++ /dev/null
@@ -1,31 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/BasicSamples/libraries/BaseGameUtils/src/main/java/com/google/example/games/basegameutils/BaseGameActivity.java b/BasicSamples/libraries/BaseGameUtils/src/main/java/com/google/example/games/basegameutils/BaseGameActivity.java
deleted file mode 100644
index 1eab7ad6..00000000
--- a/BasicSamples/libraries/BaseGameUtils/src/main/java/com/google/example/games/basegameutils/BaseGameActivity.java
+++ /dev/null
@@ -1,179 +0,0 @@
-/*
- * 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.support.v4.app.FragmentActivity;
-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 abstract class BaseGameActivity extends FragmentActivity 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.
- protected int mRequestedClients = CLIENT_GAMES;
-
- private final static String TAG = "BaseGameActivity";
- protected boolean mDebugLog = false;
-
- /** Constructs a BaseGameActivity with default client (GamesClient). */
- protected BaseGameActivity() {
- super();
- }
-
- /**
- * Constructs a BaseGameActivity with the requested clients.
- * @param requestedClients The requested clients (a combination of CLIENT_GAMES,
- * CLIENT_PLUS and CLIENT_APPSTATE).
- */
- protected BaseGameActivity(int requestedClients) {
- super();
- setRequestedClients(requestedClients);
- }
-
- /**
- * 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.
- */
- protected void setRequestedClients(int requestedClients) {
- mRequestedClients = requestedClients;
- }
-
- public GameHelper getGameHelper() {
- if (mHelper == null) {
- mHelper = new GameHelper(this, mRequestedClients);
- mHelper.enableDebugLog(mDebugLog);
- }
- return mHelper;
- }
-
- @Override
- protected void onCreate(Bundle b) {
- super.onCreate(b);
- if (mHelper == null) {
- getGameHelper();
- }
- mHelper.setup(this);
- }
-
- @Override
- protected void onStart() {
- super.onStart();
- mHelper.onStart(this);
- }
-
- @Override
- protected void onStop() {
- super.onStop();
- mHelper.onStop();
- }
-
- @Override
- protected void onActivityResult(int request, int response, Intent data) {
- super.onActivityResult(request, response, data);
- mHelper.onActivityResult(request, response, data);
- }
-
- protected GoogleApiClient getApiClient() {
- return mHelper.getApiClient();
- }
-
- protected boolean isSignedIn() {
- return mHelper.isSignedIn();
- }
-
- protected void beginUserInitiatedSignIn() {
- mHelper.beginUserInitiatedSignIn();
- }
-
- protected void signOut() {
- mHelper.signOut();
- }
-
- protected void showAlert(String message) {
- mHelper.makeSimpleDialog(message).show();
- }
-
- protected void showAlert(String title, String message) {
- mHelper.makeSimpleDialog(title, message).show();
- }
-
- protected void enableDebugLog(boolean enabled) {
- mDebugLog = true;
- if (mHelper != null) {
- mHelper.enableDebugLog(enabled);
- }
- }
-
- @Deprecated
- protected void enableDebugLog(boolean enabled, String tag) {
- Log.w(TAG, "BaseGameActivity.enabledDebugLog(bool,String) is " +
- "deprecated. Use enableDebugLog(boolean)");
- enableDebugLog(enabled);
- }
-
- protected String getInvitationId() {
- return mHelper.getInvitationId();
- }
-
- protected void reconnectClient() {
- mHelper.reconnectClient();
- }
-
- protected boolean hasSignInError() {
- return mHelper.hasSignInError();
- }
-
- protected GameHelper.SignInFailureReason getSignInError() {
- return mHelper.getSignInError();
- }
-}
diff --git a/BasicSamples/libraries/BaseGameUtils/src/main/java/com/google/example/games/basegameutils/BaseGameUtils.java b/BasicSamples/libraries/BaseGameUtils/src/main/java/com/google/example/games/basegameutils/BaseGameUtils.java
deleted file mode 100644
index cb13455e..00000000
--- a/BasicSamples/libraries/BaseGameUtils/src/main/java/com/google/example/games/basegameutils/BaseGameUtils.java
+++ /dev/null
@@ -1,178 +0,0 @@
-package com.google.example.games.basegameutils;
-
-import android.app.Activity;
-import android.app.AlertDialog;
-import android.app.Dialog;
-import android.content.IntentSender;
-import android.util.Log;
-
-import com.google.android.gms.common.ConnectionResult;
-import com.google.android.gms.common.GooglePlayServicesUtil;
-import com.google.android.gms.common.api.GoogleApiClient;
-import com.google.android.gms.games.GamesActivityResultCodes;
-
-public class BaseGameUtils {
-
- /**
- * Show an {@link android.app.AlertDialog} with an 'OK' button and a message.
- *
- * @param activity the Activity in which the Dialog should be displayed.
- * @param message the message to display in the Dialog.
- */
- public static void showAlert(Activity activity, String message) {
- (new AlertDialog.Builder(activity)).setMessage(message)
- .setNeutralButton(android.R.string.ok, null).create().show();
- }
-
- /**
- * Resolve a connection failure from
- * {@link com.google.android.gms.common.api.GoogleApiClient.OnConnectionFailedListener#onConnectionFailed(com.google.android.gms.common.ConnectionResult)}
- *
- * @param activity the Activity trying to resolve the connection failure.
- * @param client the GoogleAPIClient instance of the Activity.
- * @param result the ConnectionResult received by the Activity.
- * @param requestCode a request code which the calling Activity can use to identify the result
- * of this resolution in onActivityResult.
- * @param fallbackErrorMessage a generic error message to display if the failure cannot be resolved.
- * @return true if the connection failure is resolved, false otherwise.
- */
- public static boolean resolveConnectionFailure(Activity activity,
- GoogleApiClient client, ConnectionResult result, int requestCode,
- String fallbackErrorMessage) {
-
- if (result.hasResolution()) {
- try {
- result.startResolutionForResult(activity, requestCode);
- return true;
- } catch (IntentSender.SendIntentException e) {
- // The intent was canceled before it was sent. Return to the default
- // state and attempt to connect to get an updated ConnectionResult.
- client.connect();
- return false;
- }
- } else {
- // not resolvable... so show an error message
- int errorCode = result.getErrorCode();
- Dialog dialog = GooglePlayServicesUtil.getErrorDialog(errorCode,
- activity, requestCode);
- if (dialog != null) {
- dialog.show();
- } else {
- // no built-in dialog: show the fallback error message
- showAlert(activity, fallbackErrorMessage);
- }
- return false;
- }
- }
-
- /**
- * For use in sample code only. Checks if the sample was set up correctly,
- * including changing the package name to a non-Google package name and
- * replacing the placeholder IDs. Shows alert dialogs to notify about problems.
- * DO NOT call this method from a production app, it's meant only for samples!
- * @param resIds the resource IDs to check for placeholders
- * @return true if sample is set up correctly; false otherwise.
- */
- public static boolean verifySampleSetup(Activity activity, int... resIds) {
- StringBuilder problems = new StringBuilder();
- boolean problemFound = false;
- problems.append("The following set up problems were found:\n\n");
-
- // Did the developer forget to change the package name?
- if (activity.getPackageName().startsWith("com.google.example.games")) {
- problemFound = true;
- problems.append("- Package name cannot be com.google.*. You need to change the "
- + "sample's package name to your own package.").append("\n");
- }
-
- for (int i : resIds) {
- if (activity.getString(i).toLowerCase().contains("replaceme")) {
- problemFound = true;
- problems.append("- You must replace all " +
- "placeholder IDs in the ids.xml file by your project's IDs.").append("\n");
- break;
- }
- }
-
- if (problemFound) {
- problems.append("\n\nThese problems may prevent the app from working properly.");
- showAlert(activity, problems.toString());
- return false;
- }
-
- return true;
- }
-
- /**
- * Show a {@link android.app.Dialog} with the correct message for a connection error.
- * @param activity the Activity in which the Dialog should be displayed.
- * @param requestCode the request code from onActivityResult.
- * @param actResp the response code from onActivityResult.
- * @param errorDescription the resource id of a String for a generic error message.
- */
- public static void showActivityResultError(Activity activity, int requestCode, int actResp, int errorDescription) {
- if (activity == null) {
- Log.e("BaseGameUtils", "*** No Activity. Can't show failure dialog!");
- return;
- }
- Dialog errorDialog;
-
- switch (actResp) {
- case GamesActivityResultCodes.RESULT_APP_MISCONFIGURED:
- errorDialog = makeSimpleDialog(activity,
- activity.getString(R.string.app_misconfigured));
- break;
- case GamesActivityResultCodes.RESULT_SIGN_IN_FAILED:
- errorDialog = makeSimpleDialog(activity,
- activity.getString(R.string.sign_in_failed));
- break;
- case GamesActivityResultCodes.RESULT_LICENSE_FAILED:
- errorDialog = makeSimpleDialog(activity,
- activity.getString(R.string.license_failed));
- break;
- default:
- // No meaningful Activity response code, so generate default Google
- // Play services dialog
- final int errorCode = GooglePlayServicesUtil.isGooglePlayServicesAvailable(activity);
- errorDialog = GooglePlayServicesUtil.getErrorDialog(errorCode,
- activity, requestCode, null);
- if (errorDialog == null) {
- // get fallback dialog
- Log.e("BaseGamesUtils",
- "No standard error dialog available. Making fallback dialog.");
- errorDialog = makeSimpleDialog(activity, activity.getString(errorDescription));
- }
- }
-
- errorDialog.show();
- }
-
- /**
- * Create a simple {@link Dialog} with an 'OK' button and a message.
- *
- * @param activity the Activity in which the Dialog should be displayed.
- * @param text the message to display on the Dialog.
- * @return an instance of {@link android.app.AlertDialog}
- */
- public static Dialog makeSimpleDialog(Activity activity, String text) {
- return (new AlertDialog.Builder(activity)).setMessage(text)
- .setNeutralButton(android.R.string.ok, null).create();
- }
-
- /**
- * Create a simple {@link Dialog} with an 'OK' button, a title, and a message.
- *
- * @param activity the Activity in which the Dialog should be displayed.
- * @param title the title to display on the dialog.
- * @param text the message to display on the Dialog.
- * @return an instance of {@link android.app.AlertDialog}
- */
- public static Dialog makeSimpleDialog(Activity activity, String title, String text) {
- return (new AlertDialog.Builder(activity))
- .setTitle(title)
- .setMessage(text)
- .setNeutralButton(android.R.string.ok, null)
- .create();
- }
-
-}
diff --git a/BasicSamples/libraries/BaseGameUtils/src/main/java/com/google/example/games/basegameutils/GameHelper.java b/BasicSamples/libraries/BaseGameUtils/src/main/java/com/google/example/games/basegameutils/GameHelper.java
deleted file mode 100644
index c666cfd8..00000000
--- a/BasicSamples/libraries/BaseGameUtils/src/main/java/com/google/example/games/basegameutils/GameHelper.java
+++ /dev/null
@@ -1,1071 +0,0 @@
-/*
- * 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 java.util.ArrayList;
-
-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;
-
-public class GameHelper implements GoogleApiClient.ConnectionCallbacks,
- GoogleApiClient.OnConnectionFailedListener {
-
- static final String TAG = "GameHelper";
-
- /** Listener for sign-in success or failure events. */
- public interface GameHelperListener {
- /**
- * Called when sign-in fails. As a result, a "Sign-In" button can be
- * shown to the user; when that button is clicked, call
- *
- * @link{GamesHelper#beginUserInitiatedSignIn . Note that not all calls
- * to this method mean an
- * error; it may be a result
- * of the fact that automatic
- * sign-in could not proceed
- * because user interaction
- * was required (consent
- * dialogs). So
- * implementations of this
- * method should NOT display
- * an error message unless a
- * call to @link{GamesHelper#
- * hasSignInError} indicates
- * that an error indeed
- * occurred.
- */
- void onSignInFailed();
-
- /** Called when sign-in succeeds. */
- void onSignInSucceeded();
- }
-
- // configuration done?
- private boolean mSetupDone = false;
-
- // are we currently connecting?
- private boolean mConnecting = false;
-
- // 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;
-
- // 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;
-
- // 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;
-
- // Client request flags
- public final static int CLIENT_NONE = 0x00;
- 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;
-
- // What clients were requested? (bit flags)
- int mRequestedClients = CLIENT_NONE;
-
- // 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 mRequests;
-
- // Listener
- GameHelperListener mListener = null;
-
- // 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 = 3;
- int mMaxAutoSignInAttempts = DEFAULT_MAX_SIGN_IN_ATTEMPTS;
-
- /**
- * 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();
- }
-
- /**
- * 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
- *
- * @link{GameHelperListener#onSignInSucceeded method, to check if there's an
- * invitation available. In that
- * case, accept the invitation.
- * @return The id of the invitation, or null if none was received.
- */
- 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
- *
- * @link{GameHelperListener#onSignInSucceeded method, to check if there's an
- * invitation available. In that
- * case, accept the invitation.
- * @return The invitation, or null if none was received.
- */
- 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
- *
- * @link{GameHelperListener#onSignInSucceeded method, to check if there's a
- * match available.
- * @return The match, or null if none was received.
- */
- 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
- *
- * @link{GameHelperListener#onSignInSucceeded method, to check if there are
- * incoming requests that must be
- * handled.
- * @return The requests, or null if none were received.
- */
- public ArrayList 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;
- mSignInFailureReason = null; // cancelling is not a failure!
- mConnecting = false;
- mGoogleApiClient.disconnect();
-
- // increment # of cancellations
- int prevCancellations = getSignInCancellations();
- int newCancellations = incrementSignInCancellations();
- debugLog("onAR: # of cancellations " + prevCancellations + " --> "
- + newCancellations + ", max " + mMaxAutoSignInAttempts);
-
- notifyListener(false);
- } else {
- // Whatever the problem we were trying to solve, it was not
- // solved. So give up and show an error message.
- debugLog("onAR: responseCode="
- + GameHelperUtils
- .activityResponseCodeToString(responseCode)
- + ", so giving up.");
- giveUp(new SignInFailureReason(mConnectionResult.getErrorCode(),
- responseCode));
- }
- }
-
- void notifyListener(boolean success) {
- debugLog("Notifying LISTENER of sign-in "
- + (success ? "SUCCESS"
- : mSignInFailureReason != null ? "FAILURE (error)"
- : "FAILURE (no error)"));
- if (mListener != null) {
- if (success) {
- mListener.onSignInSucceeded();
- } else {
- mListener.onSignInFailed();
- }
- }
- }
-
- /**
- * Starts a user-initiated sign-in flow. This should be called when the user
- * clicks on a "Sign In" button. As a result, authentication/consent dialogs
- * may show up. At the end of the process, the GameHelperListener's
- * onSignInSucceeded() or onSignInFailed() methods will be called.
- */
- public void beginUserInitiatedSignIn() {
- debugLog("beginUserInitiatedSignIn: resetting attempt count.");
- resetSignInCancellations();
- mSignInCancelled = false;
- mConnectOnStart = true;
-
- if (mGoogleApiClient.isConnected()) {
- // nothing to do
- logWarn("beginUserInitiatedSignIn() called when already connected. "
- + "Calling listener directly to notify of success.");
- notifyListener(true);
- return;
- } else if (mConnecting) {
- logWarn("beginUserInitiatedSignIn() called when already connecting. "
- + "Be patient! You can only call this method after you get an "
- + "onSignInSucceeded() or onSignInFailed() callback. Suggestion: disable "
- + "the sign-in button on startup and also when it's clicked, and re-enable "
- + "when you get the callback.");
- // ignore call (listener will get a callback when the connection
- // process finishes)
- return;
- }
-
- debugLog("Starting USER-INITIATED sign-in flow.");
-
- // indicate that user is actively trying to sign in (so we know to
- // resolve
- // connection problems by showing dialogs)
- mUserInitiatedSignIn = true;
-
- if (mConnectionResult != null) {
- // We have a pending connection result from a previous failure, so
- // start with that.
- debugLog("beginUserInitiatedSignIn: continuing pending sign-in flow.");
- mConnecting = true;
- resolveConnectionResult();
- } else {
- // We don't have a pending connection result, so start anew.
- debugLog("beginUserInitiatedSignIn: starting new sign-in flow.");
- mConnecting = true;
- connect();
- }
- }
-
- void connect() {
- if (mGoogleApiClient.isConnected()) {
- debugLog("Already connected.");
- return;
- }
- debugLog("Starting connection.");
- mConnecting = true;
- mInvitation = null;
- mTurnBasedMatch = null;
- mGoogleApiClient.connect();
- }
-
- /**
- * Disconnects the API client, then connects again.
- */
- public void reconnectClient() {
- if (!mGoogleApiClient.isConnected()) {
- Log.w(TAG, "reconnectClient() called when client is not connected.");
- // interpret it as a request to connect
- connect();
- } else {
- debugLog("Reconnecting client.");
- mGoogleApiClient.reconnect();
- }
- }
-
- /** Called when we successfully obtain a connection to a client. */
- @Override
- public void onConnected(Bundle connectionHint) {
- debugLog("onConnected: connected!");
-
- if (connectionHint != null) {
- debugLog("onConnected: connection hint provided. Checking for invite.");
- Invitation inv = connectionHint
- .getParcelable(Multiplayer.EXTRA_INVITATION);
- if (inv != null && inv.getInvitationId() != null) {
- // retrieve and cache the invitation ID
- debugLog("onConnected: connection hint has a room invite!");
- mInvitation = inv;
- debugLog("Invitation ID: " + mInvitation.getInvitationId());
- }
-
- // Do we have any requests pending?
- mRequests = Games.Requests
- .getGameRequestsFromBundle(connectionHint);
- if (!mRequests.isEmpty()) {
- // We have requests in onConnected's connectionHint.
- debugLog("onConnected: connection hint has " + mRequests.size()
- + " request(s)");
- }
-
- debugLog("onConnected: connection hint provided. Checking for TBMP game.");
- mTurnBasedMatch = connectionHint
- .getParcelable(Multiplayer.EXTRA_TURN_BASED_MATCH);
- }
-
- // we're good to go
- succeedSignIn();
- }
-
- void succeedSignIn() {
- debugLog("succeedSignIn");
- mSignInFailureReason = null;
- mConnectOnStart = true;
- mUserInitiatedSignIn = false;
- mConnecting = false;
- notifyListener(true);
- }
-
- private final String GAMEHELPER_SHARED_PREFS = "GAMEHELPER_SHARED_PREFS";
- private final String KEY_SIGN_IN_CANCELLATIONS = "KEY_SIGN_IN_CANCELLATIONS";
-
- // Return the number of times the user has cancelled the sign-in flow in the
- // life of the app
- int getSignInCancellations() {
- SharedPreferences sp = mAppContext.getSharedPreferences(
- GAMEHELPER_SHARED_PREFS, Context.MODE_PRIVATE);
- return sp.getInt(KEY_SIGN_IN_CANCELLATIONS, 0);
- }
-
- // Increments the counter that indicates how many times the user has
- // cancelled the sign in
- // flow in the life of the application
- int incrementSignInCancellations() {
- int cancellations = getSignInCancellations();
- SharedPreferences.Editor editor = mAppContext.getSharedPreferences(
- GAMEHELPER_SHARED_PREFS, Context.MODE_PRIVATE).edit();
- editor.putInt(KEY_SIGN_IN_CANCELLATIONS, cancellations + 1);
- editor.commit();
- return cancellations + 1;
- }
-
- // Reset the counter of how many times the user has cancelled the sign-in
- // flow.
- void resetSignInCancellations() {
- SharedPreferences.Editor editor = mAppContext.getSharedPreferences(
- GAMEHELPER_SHARED_PREFS, Context.MODE_PRIVATE).edit();
- editor.putInt(KEY_SIGN_IN_CANCELLATIONS, 0);
- editor.commit();
- }
-
- /** Handles a connection failure. */
- @Override
- public void onConnectionFailed(ConnectionResult result) {
- // save connection result for later reference
- debugLog("onConnectionFailed");
-
- mConnectionResult = result;
- debugLog("Connection failure:");
- debugLog(" - code: "
- + GameHelperUtils.errorCodeToString(mConnectionResult
- .getErrorCode()));
- debugLog(" - resolvable: " + mConnectionResult.hasResolution());
- debugLog(" - details: " + mConnectionResult.toString());
-
- int cancellations = getSignInCancellations();
- boolean shouldResolve = false;
-
- if (mUserInitiatedSignIn) {
- debugLog("onConnectionFailed: WILL resolve because user initiated sign-in.");
- shouldResolve = true;
- } else if (mSignInCancelled) {
- debugLog("onConnectionFailed WILL NOT resolve (user already cancelled once).");
- shouldResolve = false;
- } else if (cancellations < mMaxAutoSignInAttempts) {
- debugLog("onConnectionFailed: WILL resolve because we have below the max# of "
- + "attempts, "
- + cancellations
- + " < "
- + mMaxAutoSignInAttempts);
- shouldResolve = true;
- } else {
- shouldResolve = false;
- debugLog("onConnectionFailed: Will NOT resolve; not user-initiated and max attempts "
- + "reached: "
- + cancellations
- + " >= "
- + mMaxAutoSignInAttempts);
- }
-
- if (!shouldResolve) {
- // Fail and wait for the user to want to sign in.
- debugLog("onConnectionFailed: since we won't resolve, failing now.");
- mConnectionResult = result;
- mConnecting = false;
- notifyListener(false);
- return;
- }
-
- debugLog("onConnectionFailed: resolving problem...");
-
- // Resolve the connection result. This usually means showing a dialog or
- // starting an Activity that will allow the user to give the appropriate
- // consents so that sign-in can be successful.
- resolveConnectionResult();
- }
-
- /**
- * Attempts to resolve a connection failure. This will usually involve
- * starting a UI flow that lets the user give the appropriate consents
- * necessary for sign-in to work.
- */
- void resolveConnectionResult() {
- // Try to resolve the problem
- if (mExpectingResolution) {
- debugLog("We're already expecting the result of a previous resolution.");
- return;
- }
-
- if (mActivity == null) {
- debugLog("No need to resolve issue, activity does not exist anymore");
- return;
- }
-
- debugLog("resolveConnectionResult: trying to resolve result: "
- + mConnectionResult);
- if (mConnectionResult.hasResolution()) {
- // This problem can be fixed. So let's try to fix it.
- debugLog("Result has resolution. Starting it.");
- try {
- // launch appropriate UI flow (which might, for example, be the
- // sign-in flow)
- mExpectingResolution = true;
- mConnectionResult.startResolutionForResult(mActivity,
- RC_RESOLVE);
- } catch (SendIntentException e) {
- // Try connecting again
- debugLog("SendIntentException, so connecting again.");
- connect();
- }
- } else {
- // It's not a problem what we can solve, so give up and show an
- // error.
- debugLog("resolveConnectionResult: result has no resolution. Giving up.");
- giveUp(new SignInFailureReason(mConnectionResult.getErrorCode()));
- }
- }
-
- public void disconnect() {
- if (mGoogleApiClient.isConnected()) {
- debugLog("Disconnecting client.");
- mGoogleApiClient.disconnect();
- } else {
- Log.w(TAG,
- "disconnect() called when client was already disconnected.");
- }
- }
-
- /**
- * Give up on signing in due to an error. Shows the appropriate error
- * message to the user, using a standard error dialog as appropriate to the
- * cause of the error. That dialog will indicate to the user how the problem
- * can be solved (for example, re-enable Google Play Services, upgrade to a
- * new version, etc).
- */
- void giveUp(SignInFailureReason reason) {
- mConnectOnStart = false;
- disconnect();
- mSignInFailureReason = reason;
-
- if (reason.mActivityResultCode == GamesActivityResultCodes.RESULT_APP_MISCONFIGURED) {
- // print debug info for the developer
- GameHelperUtils.printMisconfiguredDebugInfo(mAppContext);
- }
-
- showFailureDialog();
- mConnecting = false;
- notifyListener(false);
- }
-
- /** Called when we are disconnected from the Google API client. */
- @Override
- public void onConnectionSuspended(int cause) {
- debugLog("onConnectionSuspended, cause=" + cause);
- disconnect();
- mSignInFailureReason = null;
- debugLog("Making extraordinary call to onSignInFailed callback");
- mConnecting = false;
- notifyListener(false);
- }
-
- public void showFailureDialog() {
- if (mSignInFailureReason != null) {
- int errorCode = mSignInFailureReason.getServiceErrorCode();
- int actResp = mSignInFailureReason.getActivityResultCode();
-
- if (mShowErrorDialogs) {
- showFailureDialog(mActivity, actResp, errorCode);
- } else {
- debugLog("Not showing error dialog because mShowErrorDialogs==false. "
- + "" + "Error was: " + mSignInFailureReason);
- }
- }
- }
-
- /** 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();
- }
-
- public Dialog makeSimpleDialog(String text) {
- if (mActivity == null) {
- logError("*** makeSimpleDialog failed: no current Activity!");
- return null;
- }
- return makeSimpleDialog(mActivity, text);
- }
-
- public Dialog makeSimpleDialog(String title, String text) {
- if (mActivity == null) {
- logError("*** makeSimpleDialog failed: no current Activity!");
- return null;
- }
- return makeSimpleDialog(mActivity, title, text);
- }
-
- void debugLog(String message) {
- if (mDebugLog) {
- Log.d(TAG, "GameHelper: " + message);
- }
- }
-
- void logWarn(String message) {
- Log.w(TAG, "!!! GameHelper WARNING: " + message);
- }
-
- void logError(String message) {
- Log.e(TAG, "*** GameHelper ERROR: " + message);
- }
-
- // Represents the reason for a sign-in failure
- public static class SignInFailureReason {
- public static final int NO_ACTIVITY_RESULT_CODE = -100;
- int mServiceErrorCode = 0;
- int mActivityResultCode = NO_ACTIVITY_RESULT_CODE;
-
- public int getServiceErrorCode() {
- return mServiceErrorCode;
- }
-
- public int getActivityResultCode() {
- return mActivityResultCode;
- }
-
- public SignInFailureReason(int serviceErrorCode, int activityResultCode) {
- mServiceErrorCode = serviceErrorCode;
- mActivityResultCode = activityResultCode;
- }
-
- public SignInFailureReason(int serviceErrorCode) {
- this(serviceErrorCode, NO_ACTIVITY_RESULT_CODE);
- }
-
- @Override
- public String toString() {
- return "SignInFailureReason(serviceErrorCode:"
- + GameHelperUtils.errorCodeToString(mServiceErrorCode)
- + ((mActivityResultCode == NO_ACTIVITY_RESULT_CODE) ? ")"
- : (",activityResultCode:"
- + GameHelperUtils
- .activityResponseCodeToString(mActivityResultCode) + ")"));
- }
- }
-
- // Not recommended for general use. This method forces the
- // "connect on start" flag
- // to a given state. This may be useful when using GameHelper in a
- // non-standard
- // sign-in flow.
- public void setConnectOnStart(boolean connectOnStart) {
- debugLog("Forcing mConnectOnStart=" + connectOnStart);
- mConnectOnStart = connectOnStart;
- }
-}
diff --git a/BasicSamples/libraries/BaseGameUtils/src/main/java/com/google/example/games/basegameutils/GameHelperUtils.java b/BasicSamples/libraries/BaseGameUtils/src/main/java/com/google/example/games/basegameutils/GameHelperUtils.java
deleted file mode 100644
index 703569de..00000000
--- a/BasicSamples/libraries/BaseGameUtils/src/main/java/com/google/example/games/basegameutils/GameHelperUtils.java
+++ /dev/null
@@ -1,182 +0,0 @@
-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];
- }
- }
-}
diff --git a/BasicSamples/libraries/BaseGameUtils/src/main/res/values/gamehelper_strings.xml b/BasicSamples/libraries/BaseGameUtils/src/main/res/values/gamehelper_strings.xml
deleted file mode 100644
index cddc764a..00000000
--- a/BasicSamples/libraries/BaseGameUtils/src/main/res/values/gamehelper_strings.xml
+++ /dev/null
@@ -1,7 +0,0 @@
-
-
- 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.
- Unknown error.
-
diff --git a/BasicSamples/libraries/BaseGameUtils/src/main/res/values/strings.xml b/BasicSamples/libraries/BaseGameUtils/src/main/res/values/strings.xml
deleted file mode 100644
index 3aaeb7ca..00000000
--- a/BasicSamples/libraries/BaseGameUtils/src/main/res/values/strings.xml
+++ /dev/null
@@ -1,7 +0,0 @@
-
-
- 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.
- Unknown error.
-
diff --git a/BasicSamples/settings.gradle b/BasicSamples/settings.gradle
deleted file mode 100644
index 79584eb1..00000000
--- a/BasicSamples/settings.gradle
+++ /dev/null
@@ -1,3 +0,0 @@
-include ':libraries:BaseGameUtils', ':BeGenerous', ':ButtonClicker', ':CollectAllTheStars2', ':TrivialQuest', ':TrivialQuest2', ':TypeANumber', ':SkeletonTbmp', ':SavedGames'
-
-
diff --git a/CollectAllTheStars2/README.md b/CollectAllTheStars2/README.md
new file mode 100644
index 00000000..10cde28a
--- /dev/null
+++ b/CollectAllTheStars2/README.md
@@ -0,0 +1,29 @@
+# Collect all the Stars 2 #
+This sample demonstrates how to use the Snapshots feature to save game data.
+It signs the user into Google Play Game Services ("GPGS"), synchronizes his or
+her data from a named Snapshot, and then updates the UI to reflect the game
+state saved in the Snapshot.
+
+## Setup ##
+1. Create your project in the Google Play Developer Console and
+ set **Saved Games** to **ON**.
+2. Link your app to the game configuration.
+3. Set the applicationId in build.gradle to the package name configured in
+ the Google Play Developer Console.
+4. Copy the `APP ID` from the console into `CollectAllTheStars/values/ids.xml`.
+
+## Running ##
+1. Sign in. Upon success, the Play Games toast appears.
+2. Make changes to the game state by selecting stars.
+3. Sign out. The game UI resets.
+4. Sign back in with your account. The game UI reflects the saved game state.
+
+## Troubleshooting ##
+If you are encountering errors such as:
+
+ {statusCode=INTERNAL_ERROR, resolution=null}
+
+You may need to manually enable the Drive API from the
+[Google API Console] (https://console.developers.google.com/) or may need to
+enable the saved games feature from the
+[Play Games Developer Console](https://play.google.com/apps/publish).
diff --git a/CollectAllTheStars2/build.gradle b/CollectAllTheStars2/build.gradle
new file mode 100644
index 00000000..ac588625
--- /dev/null
+++ b/CollectAllTheStars2/build.gradle
@@ -0,0 +1,39 @@
+apply plugin: 'com.android.application'
+
+android {
+
+ compileSdkVersion android_compile_version
+
+ defaultConfig {
+ /*
+ TODO: Replace this value with your application's package name
+ You can find this in Linked Apps section of your Game Service in the Google Play Console
+ */
+ applicationId "com.google.example.games.replace.me"
+
+ minSdkVersion android_min_sdk_version
+ targetSdkVersion android_compile_version
+ versionCode 1
+ versionName "1.0"
+ }
+
+ buildTypes {
+ release {
+ minifyEnabled true
+ proguardFiles getDefaultProguardFile('proguard-android.txt')
+ }
+ }
+}
+
+dependencies {
+ implementation 'androidx.appcompat:appcompat:1.0.0'
+ implementation 'androidx.legacy:legacy-support-v4:1.0.0'
+ implementation "com.google.android.gms:play-services-games:${gms_library_version}"
+ implementation "com.google.android.gms:play-services-auth:${gms_library_version}"
+}
+
+buildscript {
+ repositories {
+ jcenter()
+ }
+}
diff --git a/BasicSamples/CollectAllTheStars2/src/main/AndroidManifest.xml b/CollectAllTheStars2/src/main/AndroidManifest.xml
similarity index 100%
rename from BasicSamples/CollectAllTheStars2/src/main/AndroidManifest.xml
rename to CollectAllTheStars2/src/main/AndroidManifest.xml
diff --git a/CollectAllTheStars2/src/main/java/com/google/example/games/catt2/MainActivity.java b/CollectAllTheStars2/src/main/java/com/google/example/games/catt2/MainActivity.java
new file mode 100644
index 00000000..c9c49d93
--- /dev/null
+++ b/CollectAllTheStars2/src/main/java/com/google/example/games/catt2/MainActivity.java
@@ -0,0 +1,1037 @@
+/* Copyright (C) 2014 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.catt2;
+
+import android.app.ProgressDialog;
+import android.content.Intent;
+import android.graphics.Bitmap;
+import android.os.Bundle;
+import android.util.Log;
+import android.view.Menu;
+import android.view.MenuItem;
+import android.view.View;
+import android.widget.Button;
+import android.widget.RatingBar;
+import android.widget.RatingBar.OnRatingBarChangeListener;
+import android.widget.TextView;
+import android.widget.Toast;
+
+import androidx.annotation.NonNull;
+import androidx.appcompat.app.AlertDialog;
+import androidx.appcompat.app.AppCompatActivity;
+
+import com.google.android.gms.auth.api.signin.GoogleSignIn;
+import com.google.android.gms.auth.api.signin.GoogleSignInAccount;
+import com.google.android.gms.auth.api.signin.GoogleSignInClient;
+import com.google.android.gms.auth.api.signin.GoogleSignInOptions;
+import com.google.android.gms.common.api.ApiException;
+import com.google.android.gms.common.api.Result;
+import com.google.android.gms.drive.Drive;
+import com.google.android.gms.games.AnnotatedData;
+import com.google.android.gms.games.Games;
+import com.google.android.gms.games.GamesClientStatusCodes;
+import com.google.android.gms.games.SnapshotsClient;
+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.tasks.Continuation;
+import com.google.android.gms.tasks.OnCompleteListener;
+import com.google.android.gms.tasks.OnFailureListener;
+import com.google.android.gms.tasks.OnSuccessListener;
+import com.google.android.gms.tasks.Task;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Calendar;
+
+/**
+ * Collect All the Stars sample. This sample demonstrates how to use the cloud save features
+ * of the Google Play game services API. It's a "game" where there are several worlds
+ * with several levels each, and on each level the player can get from 0 to 5 stars.
+ * The progress of the player is saved to the cloud and kept in sync across all their devices.
+ * If they earn 5 stars on level 1 on one device and then earn 4 stars on level 2 on a different
+ * device, upon synchronizing the consolidated progress will be 5 stars on level 1 AND
+ * 4 stars on level 2. If they clear the same level on two different devices, then the biggest
+ * star rating of the two will apply.
+ *
+ * It's worth noting that this sample also works offline, and even when the player is not
+ * signed in. In all cases, the progress is saved locally as well.
+ *
+ * @author Bruno Oliveira (Google)
+ */
+public class MainActivity extends AppCompatActivity implements
+ View.OnClickListener,
+ OnRatingBarChangeListener {
+
+ private static final String TAG = "CollectAllTheStars2";
+
+ // Request code used to invoke sign in user interactions.
+ private static final int RC_SIGN_IN = 9001;
+
+ // Request code for listing saved games
+ private static final int RC_LIST_SAVED_GAMES = 9002;
+
+ // Request code for selecting a snapshot
+ private static final int RC_SELECT_SNAPSHOT = 9003;
+
+ // Request code for saving the game to a snapshot.
+ private static final int RC_SAVE_SNAPSHOT = 9004;
+
+ private static final int RC_LOAD_SNAPSHOT = 9005;
+
+ // Client used to sign in with Google APIs
+ private GoogleSignInClient mGoogleSignInClient;
+
+ // Client used to interact with Google Snapshots.
+ private SnapshotsClient mSnapshotsClient = null;
+
+ // current save game - serializable to and from the saved game
+ SaveGame mSaveGame = new SaveGame();
+
+ private String currentSaveName = "snapshotTemp";
+
+ // world we're currently viewing
+ int mWorld = 1;
+ private static final int WORLD_MIN = 1;
+ private static final int WORLD_MAX = 20;
+ private static final int LEVELS_PER_WORLD = 12;
+
+ // level we're currently "playing"
+ int mLevel = 0;
+
+ // state of "playing" - used to make the back button work correctly
+ boolean mInLevel = false;
+
+ // progress dialog we display while we're loading state from the cloud
+ ProgressDialog mLoadingDialog = null;
+
+ // the level buttons (the ones the user clicks to play a given level)
+ final static int[] LEVEL_BUTTON_IDS = {
+ R.id.button_level_1, R.id.button_level_2, R.id.button_level_3, R.id.button_level_4,
+ R.id.button_level_5, R.id.button_level_6, R.id.button_level_7, R.id.button_level_8,
+ R.id.button_level_9, R.id.button_level_10, R.id.button_level_11, R.id.button_level_12
+ };
+
+ // star strings (we use the Unicode BLACK STAR and WHITE STAR characters -- lazy graphics!)
+ final static String[] STAR_STRINGS = {
+ "\u2606\u2606\u2606\u2606\u2606", // 0 stars
+ "\u2605\u2606\u2606\u2606\u2606", // 1 star
+ "\u2605\u2605\u2606\u2606\u2606", // 2 stars
+ "\u2605\u2605\u2605\u2606\u2606", // 3 stars
+ "\u2605\u2605\u2605\u2605\u2606", // 4 stars
+ "\u2605\u2605\u2605\u2605\u2605", // 5 stars
+ };
+
+ // Members related to the conflict resolution chooser of Snapshots.
+ final static int MAX_SNAPSHOT_RESOLVE_RETRIES = 50;
+
+ /**
+ * Start a sign in activity. To properly handle the result, call tryHandleSignInResult from
+ * your Activity's onActivityResult function
+ */
+ public void startSignInIntent() {
+ startActivityForResult(mGoogleSignInClient.getSignInIntent(), RC_SIGN_IN);
+ }
+
+ /**
+ * Try to sign in without displaying dialogs to the user.
+ *
+ * If the user has already signed in previously, it will not show dialog.
+ */
+ public void signInSilently() {
+ Log.d(TAG, "signInSilently()");
+
+ mGoogleSignInClient.silentSignIn().addOnCompleteListener(this,
+ new OnCompleteListener() {
+ @Override
+ public void onComplete(@NonNull Task task) {
+ if (task.isSuccessful()) {
+ Log.d(TAG, "signInSilently(): success");
+ onConnected(task.getResult());
+ } else {
+ Log.d(TAG, "signInSilently(): failure", task.getException());
+ onDisconnected();
+ }
+ }
+ });
+ }
+
+ public void signOut() {
+ Log.d(TAG, "signOut()");
+
+ mGoogleSignInClient.signOut().addOnCompleteListener(this,
+ new OnCompleteListener() {
+ @Override
+ public void onComplete(@NonNull Task task) {
+
+ if (task.isSuccessful()) {
+ Log.d(TAG, "signOut(): success");
+ } else {
+ handleException(task.getException(), "signOut() failed!");
+ }
+
+ onDisconnected();
+ }
+ });
+ }
+
+
+ /**
+ * You can capture the Snapshot selection intent in the onActivityResult method. The result
+ * either indicates a new Snapshot was created (EXTRA_SNAPSHOT_NEW) or was selected.
+ */
+ @Override
+ protected void onActivityResult(int requestCode, int resultCode, Intent intent) {
+
+ if (requestCode == RC_SIGN_IN) {
+
+ Task task =
+ GoogleSignIn.getSignedInAccountFromIntent(intent);
+
+ try {
+ GoogleSignInAccount account = task.getResult(ApiException.class);
+ onConnected(account);
+ } catch (ApiException apiException) {
+ String message = apiException.getMessage();
+ if (message == null || message.isEmpty()) {
+ message = getString(R.string.signin_other_error);
+ }
+
+ onDisconnected();
+
+ new AlertDialog.Builder(this)
+ .setMessage(message)
+ .setNeutralButton(android.R.string.ok, null)
+ .show();
+ }
+ } else if (requestCode == RC_LIST_SAVED_GAMES) {
+ // the standard snapshot selection intent
+ if (intent != null) {
+ if (intent.hasExtra(SnapshotsClient.EXTRA_SNAPSHOT_METADATA)) {
+ // Load a snapshot.
+ SnapshotMetadata snapshotMetadata =
+ intent.getParcelableExtra(SnapshotsClient.EXTRA_SNAPSHOT_METADATA);
+ currentSaveName = snapshotMetadata.getUniqueName();
+ loadFromSnapshot(snapshotMetadata);
+ } else if (intent.hasExtra(SnapshotsClient.EXTRA_SNAPSHOT_NEW)) {
+ // Create a new snapshot named with a unique string
+ String unique = Long.toString(System.currentTimeMillis());
+ currentSaveName = "snapshotTemp-" + unique;
+ saveSnapshot(null);
+ }
+ }
+ }
+ // the example use of Snapshot.load() which displays a custom list of snapshots.
+ else if (requestCode == RC_SELECT_SNAPSHOT) {
+ Log.d(TAG, "Selected a snapshot!");
+ if (resultCode == RESULT_OK) {
+ if (intent != null && intent.hasExtra(SelectSnapshotActivity.SNAPSHOT_METADATA)) {
+ // Load a snapshot.
+ SnapshotMetadata snapshotMetadata =
+ intent.getParcelableExtra(SelectSnapshotActivity.SNAPSHOT_METADATA);
+ currentSaveName = snapshotMetadata.getUniqueName();
+ Log.d(TAG, "ok - loading " + currentSaveName);
+ loadFromSnapshot(snapshotMetadata);
+ } else {
+ Log.w(TAG, "Expected snapshot metadata but found none.");
+ }
+ }
+ }
+ // loading a snapshot into the game.
+ else if (requestCode == RC_LOAD_SNAPSHOT) {
+ Log.d(TAG, "Loading a snapshot resultCode = " + resultCode);
+ if (resultCode == RESULT_OK) {
+ if (intent != null && intent.hasExtra(SelectSnapshotActivity.SNAPSHOT_METADATA)) {
+ // Load a snapshot.
+ String conflictId = intent.getStringExtra(SelectSnapshotActivity.CONFLICT_ID);
+ int retryCount = intent.getIntExtra(SelectSnapshotActivity.RETRY_COUNT,
+ MAX_SNAPSHOT_RESOLVE_RETRIES);
+ SnapshotMetadata snapshotMetadata =
+ intent.getParcelableExtra(SelectSnapshotActivity.SNAPSHOT_METADATA);
+ if (conflictId == null) {
+ loadFromSnapshot(snapshotMetadata);
+ } else {
+ Log.d(TAG, "resolving " + snapshotMetadata);
+ resolveSnapshotConflict(requestCode, conflictId, retryCount,
+ snapshotMetadata);
+ }
+ }
+ }
+
+ }
+ // saving the game into a snapshot.
+ else if (requestCode == RC_SAVE_SNAPSHOT) {
+ if (resultCode == RESULT_OK) {
+ if (intent != null && intent.hasExtra(SelectSnapshotActivity.SNAPSHOT_METADATA)) {
+ // Load a snapshot.
+ String conflictId = intent.getStringExtra(SelectSnapshotActivity.CONFLICT_ID);
+ int retryCount = intent.getIntExtra(SelectSnapshotActivity.RETRY_COUNT,
+ MAX_SNAPSHOT_RESOLVE_RETRIES);
+ SnapshotMetadata snapshotMetadata =
+ intent.getParcelableExtra(SelectSnapshotActivity.SNAPSHOT_METADATA);
+ if (conflictId == null) {
+ saveSnapshot(snapshotMetadata);
+ } else {
+ Log.d(TAG, "resolving " + snapshotMetadata);
+ resolveSnapshotConflict(requestCode, conflictId, retryCount, snapshotMetadata);
+ }
+ }
+ }
+ }
+ super.onActivityResult(requestCode, resultCode, intent);
+ }
+
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+
+ log("onCreate.");
+ super.onCreate(savedInstanceState);
+ setContentView(R.layout.activity_main);
+
+ // Create the client used to sign in.
+ mGoogleSignInClient = GoogleSignIn.getClient(this,
+ new GoogleSignInOptions.Builder(GoogleSignInOptions.DEFAULT_GAMES_SIGN_IN)
+ // Since we are using SavedGames, we need to add the SCOPE_APPFOLDER to access Google Drive.
+ .requestScopes(Drive.SCOPE_APPFOLDER)
+ .build());
+
+ for (int id : LEVEL_BUTTON_IDS) {
+ findViewById(id).setOnClickListener(this);
+ }
+ findViewById(R.id.button_next_world).setOnClickListener(this);
+ findViewById(R.id.button_prev_world).setOnClickListener(this);
+ findViewById(R.id.button_sign_in).setOnClickListener(this);
+ findViewById(R.id.button_sign_out).setOnClickListener(this);
+ ((RatingBar) findViewById(R.id.gameplay_rating)).setOnRatingBarChangeListener(this);
+ mSaveGame = new SaveGame();
+ updateUi();
+ checkPlaceholderIds();
+ }
+
+ // Check the sample to ensure all placeholder ids are are updated with real-world values.
+ // This is strictly for the purpose of the samples; you don't need this in a production
+ // application.
+ private void checkPlaceholderIds() {
+ StringBuilder problems = new StringBuilder();
+
+ if (getPackageName().startsWith("com.google.")) {
+ problems.append("- Package name start with com.google.*\n");
+ }
+
+ for (Integer id : new Integer[]{R.string.app_id}) {
+
+ String value = getString(id);
+
+ if (value.startsWith("YOUR_")) {
+ // needs replacing
+ problems.append("- Placeholders(YOUR_*) in ids.xml need updating\n");
+ break;
+ }
+ }
+
+ if (problems.length() > 0) {
+ problems.insert(0, "The following problems were found:\n\n");
+
+ problems.append("\nThese problems may prevent the app from working properly.");
+ problems.append("\n\nSee the TODO window in Android Studio for more information");
+ (new AlertDialog.Builder(this)).setMessage(problems.toString())
+ .setNeutralButton(android.R.string.ok, null).create().show();
+ }
+ }
+
+ @Override
+ protected void onResume() {
+ super.onResume();
+ Log.d(TAG, "onResume()");
+
+ // Since the state of the signed in user can change when the activity is not active
+ // it is recommended to try and sign in silently from when the app resumes.
+ signInSilently();
+ }
+
+ @Override
+ public boolean onOptionsItemSelected(MenuItem item) {
+
+ // Player wants to force save or load.
+ // NOTE: this button exists in this sample for debug purposes and so that you can
+ // see the effects immediately. A game probably shouldn't have a "Load/Save"
+ // button (or at least not one that's so prominently displayed in the UI).
+ if (item.getItemId() == R.id.menu_sync) {
+ loadFromSnapshot(null);
+ return true;
+ }
+ if (item.getItemId() == R.id.menu_save) {
+ saveSnapshot(null);
+ return true;
+ }
+ if (item.getItemId() == R.id.menu_select) {
+ selectSnapshot();
+ }
+ return false;
+ }
+
+
+ @Override
+ protected void onStart() {
+ updateUi();
+ super.onStart();
+
+ checkPlaceholderIds();
+ }
+
+ public static boolean verifySampleSetup(AppCompatActivity activity, int... resIds) {
+ StringBuilder problems = new StringBuilder();
+ boolean problemFound = false;
+ problems.append("The following set up problems were found:\n\n");
+
+ // Did the developer forget to change the package name?
+ if (activity.getPackageName().startsWith("com.google.example.games")) {
+ problemFound = true;
+ problems.append("- Package name cannot be com.google.*. You need to change the "
+ + "sample's package name to your own package.").append("\n");
+ }
+
+ for (int i : resIds) {
+ if (activity.getString(i).startsWith("YOUR_")) {
+ problemFound = true;
+ problems.append("- You must replace `YOUR_*`" +
+ "placeholder IDs in the ids.xml file by your project's IDs.").append("\n");
+ break;
+ }
+ }
+
+ if (problemFound) {
+ problems.append("\n\nThese problems may prevent the app from working properly.");
+ (new AlertDialog.Builder(activity)).setMessage(problems.toString())
+ .setNeutralButton(android.R.string.ok, null).create().show();
+ return false;
+ }
+
+ return true;
+ }
+
+ @Override
+ protected void onStop() {
+ if (mLoadingDialog != null) {
+ mLoadingDialog.dismiss();
+ mLoadingDialog = null;
+ }
+ super.onStop();
+ }
+
+
+ @Override
+ public boolean onCreateOptionsMenu(Menu menu) {
+ // Inflate the menu; this adds items to the action bar if it is present.
+ getMenuInflater().inflate(R.menu.activity_main, menu);
+ return true;
+ }
+
+
+ // The currently signed in account, used to check the account has changed outside of this activity when resuming.
+ GoogleSignInAccount mSignedInAccount = null;
+
+ private void onConnected(GoogleSignInAccount googleSignInAccount) {
+ Log.d(TAG, "onConnected(): connected to Google APIs");
+ if (mSignedInAccount != googleSignInAccount) {
+
+ mSignedInAccount = googleSignInAccount;
+
+ onAccountChanged(googleSignInAccount);
+ } else {
+ updateUi();
+ }
+ }
+
+ private void onAccountChanged(GoogleSignInAccount googleSignInAccount) {
+ mSnapshotsClient = Games.getSnapshotsClient(this, googleSignInAccount);
+
+ // Sign-in worked!
+ log("Sign-in successful! Loading game state from cloud.");
+
+ showSignOutBar();
+
+ showSnapshots(getString(R.string.title_load_game), false, false);
+ }
+
+ private void onDisconnected() {
+
+ Log.d(TAG, "onDisconnected()");
+
+ mSnapshotsClient = null;
+ showSignInBar();
+ }
+
+
+ @Override
+ public void onBackPressed() {
+ if (mInLevel) {
+ updateUi();
+ findViewById(R.id.screen_gameplay).setVisibility(View.GONE);
+ findViewById(R.id.screen_main).setVisibility(View.VISIBLE);
+ mInLevel = false;
+ } else {
+ super.onBackPressed();
+ }
+ }
+
+ /**
+ * Called when the "sign in" or "sign out" button is clicked.
+ */
+ @Override
+ public void onClick(View view) {
+ switch (view.getId()) {
+ case R.id.button_sign_in:
+ // start the sign-in flow
+ Log.d(TAG, "Sign-in button clicked");
+ startSignInIntent();
+ return;
+
+ case R.id.button_sign_out:
+ // sign out.
+ signOut();
+ showSignInBar();
+ mSaveGame = new SaveGame();
+ updateUi();
+ return;
+ }
+
+ if (!isSignedIn()) {
+ // All other buttons force the user to sign in.
+ new AlertDialog.Builder(this)
+ .setMessage(getString(R.string.please_sign_in))
+ .setNeutralButton(android.R.string.ok, null)
+ .create()
+ .show();
+
+ return;
+ }
+
+ switch (view.getId()) {
+ case R.id.button_next_world:
+ if (mWorld < WORLD_MAX) {
+ mWorld++;
+ updateUi();
+ }
+ break;
+ case R.id.button_prev_world:
+ if (mWorld > WORLD_MIN) {
+ mWorld--;
+ updateUi();
+ }
+ break;
+ default:
+ for (int i = 0; i < LEVEL_BUTTON_IDS.length; ++i) {
+ if (view.getId() == LEVEL_BUTTON_IDS[i]) {
+ launchLevel(i + 1);
+ return;
+ }
+ }
+ }
+ }
+
+ private boolean isSignedIn() {
+ return mSnapshotsClient != null;
+ }
+
+ /**
+ * Gets a screenshot to use with snapshots. Note that in practice you probably do not want to
+ * use this approach because tablet screen sizes can become pretty large and because the image
+ * will contain any UI and layout surrounding the area of interest.
+ */
+ Bitmap getScreenShot() {
+ View root = findViewById(R.id.screen_main);
+ Bitmap coverImage;
+ try {
+ root.setDrawingCacheEnabled(true);
+ Bitmap base = root.getDrawingCache();
+ coverImage = base.copy(base.getConfig(), false /* isMutable */);
+ } catch (Exception ex) {
+ Log.i(TAG, "Failed to create screenshot", ex);
+ coverImage = null;
+ } finally {
+ root.setDrawingCacheEnabled(false);
+ }
+ return coverImage;
+ }
+
+ /**
+ * Since a lot of the operations use tasks, we can use a common handler for whenever one fails.
+ *
+ * @param exception The exception to evaluate. Will try to display a more descriptive reason for the exception.
+ * @param details Will display alongside the exception if you wish to provide more details for why the exception
+ * happened
+ */
+ private void handleException(Exception exception, String details) {
+ int status = 0;
+
+ if (exception instanceof ApiException) {
+ ApiException apiException = (ApiException) exception;
+ status = apiException.getStatusCode();
+ }
+
+ String message = getString(R.string.status_exception_error, details, status, exception);
+
+ new AlertDialog.Builder(MainActivity.this)
+ .setMessage(message)
+ .setNeutralButton(android.R.string.ok, null)
+ .show();
+
+ // Note that showing a toast is done here for debugging. Your application should
+ // resolve the error appropriately to your app.
+ if (status == GamesClientStatusCodes.SNAPSHOT_NOT_FOUND) {
+ Log.i(TAG, "Error: Snapshot not found");
+ Toast.makeText(getBaseContext(), "Error: Snapshot not found",
+ Toast.LENGTH_SHORT).show();
+ } else if (status == GamesClientStatusCodes.SNAPSHOT_CONTENTS_UNAVAILABLE) {
+ Log.i(TAG, "Error: Snapshot contents unavailable");
+ Toast.makeText(getBaseContext(), "Error: Snapshot contents unavailable",
+ Toast.LENGTH_SHORT).show();
+ } else if (status == GamesClientStatusCodes.SNAPSHOT_FOLDER_UNAVAILABLE) {
+ Log.i(TAG, "Error: Snapshot folder unavailable");
+ Toast.makeText(getBaseContext(), "Error: Snapshot folder unavailable.",
+ Toast.LENGTH_SHORT).show();
+ }
+ }
+
+ /**
+ * Shows the user's snapshots.
+ */
+ void showSnapshots(String title, boolean allowAdd, boolean allowDelete) {
+ int maxNumberOfSavedGamesToShow = 5;
+ SnapshotCoordinator.getInstance().getSelectSnapshotIntent(
+ mSnapshotsClient, title, allowAdd, allowDelete, maxNumberOfSavedGamesToShow)
+ .addOnCompleteListener(new OnCompleteListener() {
+ @Override
+ public void onComplete(@NonNull Task task) {
+ if (task.isSuccessful()) {
+ startActivityForResult(task.getResult(), RC_LIST_SAVED_GAMES);
+ } else {
+ handleException(task.getException(), getString(R.string.show_snapshots_error));
+ }
+ }
+ });
+ }
+
+ private Task> waitForClosedAndOpen(final SnapshotMetadata snapshotMetadata) {
+
+ final boolean useMetadata = snapshotMetadata != null && snapshotMetadata.getUniqueName() != null;
+ if (useMetadata) {
+ Log.i(TAG, "Opening snapshot using metadata: " + snapshotMetadata);
+ } else {
+ Log.i(TAG, "Opening snapshot using currentSaveName: " + currentSaveName);
+ }
+
+ final String filename = useMetadata ? snapshotMetadata.getUniqueName() : currentSaveName;
+
+ return SnapshotCoordinator.getInstance()
+ .waitForClosed(filename)
+ .addOnFailureListener(new OnFailureListener() {
+ @Override
+ public void onFailure(@NonNull Exception e) {
+ handleException(e, "There was a problem waiting for the file to close!");
+ }
+ })
+ .continueWithTask(new Continuation>>() {
+ @Override
+ public Task> then(@NonNull Task task) throws Exception {
+ Task> openTask = useMetadata
+ ? SnapshotCoordinator.getInstance().open(mSnapshotsClient, snapshotMetadata)
+ : SnapshotCoordinator.getInstance().open(mSnapshotsClient, filename, true);
+ return openTask.addOnFailureListener(new OnFailureListener() {
+ @Override
+ public void onFailure(@NonNull Exception e) {
+ handleException(e,
+ useMetadata
+ ? getString(R.string.error_opening_metadata)
+ : getString(R.string.error_opening_filename)
+ );
+ }
+ });
+ }
+ });
+ }
+
+ /**
+ * Loads a Snapshot from the user's synchronized storage.
+ */
+ void loadFromSnapshot(final SnapshotMetadata snapshotMetadata) {
+ if (mLoadingDialog == null) {
+ mLoadingDialog = new ProgressDialog(this);
+ mLoadingDialog.setMessage(getString(R.string.loading_from_cloud));
+ }
+
+ mLoadingDialog.show();
+
+ waitForClosedAndOpen(snapshotMetadata)
+ .addOnSuccessListener(new OnSuccessListener>() {
+ @Override
+ public void onSuccess(SnapshotsClient.DataOrConflict result) {
+
+ // if there is a conflict - then resolve it.
+ Snapshot snapshot = processOpenDataOrConflict(RC_LOAD_SNAPSHOT, result, 0);
+
+ if (snapshot == null) {
+ Log.w(TAG, "Conflict was not resolved automatically, waiting for user to resolve.");
+ } else {
+ try {
+ readSavedGame(snapshot);
+ Log.i(TAG, "Snapshot loaded.");
+ } catch (IOException e) {
+ Log.e(TAG, "Error while reading snapshot contents: " + e.getMessage());
+ }
+ }
+
+ SnapshotCoordinator.getInstance().discardAndClose(mSnapshotsClient, snapshot)
+ .addOnFailureListener(new OnFailureListener() {
+ @Override
+ public void onFailure(@NonNull Exception e) {
+ handleException(e, "There was a problem discarding the snapshot!");
+ }
+ });
+
+ if (mLoadingDialog != null && mLoadingDialog.isShowing()) {
+ mLoadingDialog.dismiss();
+ mLoadingDialog = null;
+ }
+ hideAlertBar();
+ updateUi();
+ }
+ });
+ }
+
+ private void readSavedGame(Snapshot snapshot) throws IOException {
+ mSaveGame = new SaveGame(snapshot.getSnapshotContents().readFully());
+ }
+
+ /**
+ * Conflict resolution for when Snapshots are opened.
+ *
+ * @param requestCode - the request currently being processed. This is used to forward on the
+ * information to another activity, or to send the result intent.
+ * @param result The open snapshot result to resolve on open.
+ * @param retryCount - the current iteration of the retry. The first retry should be 0.
+ * @return The opened Snapshot on success; otherwise, returns null.
+ */
+ Snapshot processOpenDataOrConflict(int requestCode,
+ SnapshotsClient.DataOrConflict result,
+ int retryCount) {
+
+ retryCount++;
+
+ if (!result.isConflict()) {
+ return result.getData();
+ }
+
+ Log.i(TAG, "Open resulted in a conflict!");
+
+ SnapshotsClient.SnapshotConflict conflict = result.getConflict();
+ final Snapshot snapshot = conflict.getSnapshot();
+ final Snapshot conflictSnapshot = conflict.getConflictingSnapshot();
+
+ ArrayList snapshotList = new ArrayList(2);
+ snapshotList.add(snapshot);
+ snapshotList.add(conflictSnapshot);
+
+ // Display both snapshots to the user and allow them to select the one to resolve.
+ selectSnapshotItem(requestCode, snapshotList, conflict.getConflictId(), retryCount);
+
+ // Since we are waiting on the user for input, there is no snapshot available; return null.
+ return null;
+ }
+
+ /**
+ * Handles resolving the snapshot conflict asynchronously.
+ *
+ * @param requestCode - the request currently being processed. This is used to forward on the
+ * information to another activity, or to send the result intent.
+ * @param conflictId - the id of the conflict being resolved.
+ * @param retryCount - the current iteration of the retry. The first retry should be 0.
+ * @param snapshotMetadata - the metadata of the snapshot that is selected to resolve the conflict.
+ */
+ private Task> resolveSnapshotConflict(final int requestCode,
+ final String conflictId,
+ final int retryCount,
+ final SnapshotMetadata snapshotMetadata) {
+
+ Log.i(TAG, "Resolving conflict retry count = " + retryCount + " conflictid = " + conflictId);
+ return waitForClosedAndOpen(snapshotMetadata)
+ .continueWithTask(new Continuation, Task>>() {
+ @Override
+ public Task> then(@NonNull Task> task) throws Exception {
+ return SnapshotCoordinator.getInstance().resolveConflict(
+ mSnapshotsClient,
+ conflictId,
+ task.getResult().getData())
+ .addOnCompleteListener(new OnCompleteListener>() {
+ @Override
+ public void onComplete(@NonNull Task> task) {
+ if (!task.isSuccessful()) {
+ handleException(
+ task.getException(),
+ "There was a problem opening a file for resolving the conflict!");
+ return;
+ }
+
+ Snapshot snapshot = processOpenDataOrConflict(requestCode,
+ task.getResult(),
+ retryCount);
+ Log.d(TAG, "resolved snapshot conflict - snapshot is " + snapshot);
+ // if there is a snapshot returned, then pass it along to onActivityResult.
+ // otherwise, another activity will be used to resolve the conflict so we
+ // don't need to do anything here.
+ if (snapshot != null) {
+ Intent intent = new Intent("");
+ intent.putExtra(SelectSnapshotActivity.SNAPSHOT_METADATA, snapshot.getMetadata().freeze());
+ onActivityResult(requestCode, RESULT_OK, intent);
+ }
+ }
+ });
+ }
+ });
+ }
+
+ /**
+ * Prepares saving Snapshot to the user's synchronized storage, conditionally resolves errors,
+ * and stores the Snapshot.
+ */
+ void saveSnapshot(final SnapshotMetadata snapshotMetadata) {
+ waitForClosedAndOpen(snapshotMetadata)
+ .addOnCompleteListener(new OnCompleteListener>() {
+ @Override
+ public void onComplete(@NonNull Task> task) {
+ SnapshotsClient.DataOrConflict result = task.getResult();
+ Snapshot snapshotToWrite = processOpenDataOrConflict(RC_SAVE_SNAPSHOT, result, 0);
+
+ if (snapshotToWrite == null) {
+ // No snapshot available yet; waiting on the user to choose one.
+ return;
+ }
+
+ Log.d(TAG, "Writing data to snapshot: " + snapshotToWrite.getMetadata().getUniqueName());
+ writeSnapshot(snapshotToWrite)
+ .addOnCompleteListener(new OnCompleteListener() {
+ @Override
+ public void onComplete(@NonNull Task task) {
+ if (task.isSuccessful()) {
+ Log.i(TAG, "Snapshot saved!");
+ } else {
+ handleException(task.getException(), getString(R.string.write_snapshot_error));
+ }
+ }
+ });
+ }
+ });
+ }
+
+ /**
+ * Generates metadata, takes a screenshot, and performs the write operation for saving a
+ * snapshot.
+ */
+ private Task writeSnapshot(Snapshot snapshot) {
+ // Set the data payload for the snapshot.
+ snapshot.getSnapshotContents().writeBytes(mSaveGame.toBytes());
+
+ // Save the snapshot.
+ SnapshotMetadataChange metadataChange = new SnapshotMetadataChange.Builder()
+ .setCoverImage(getScreenShot())
+ .setDescription("Modified data at: " + Calendar.getInstance().getTime())
+ .build();
+ return SnapshotCoordinator.getInstance().commitAndClose(mSnapshotsClient, snapshot, metadataChange);
+ }
+
+
+ /**
+ * Shows the "sign in" bar (explanation and button).
+ */
+ private void showSignInBar() {
+ findViewById(R.id.sign_in_bar).setVisibility(View.VISIBLE);
+ findViewById(R.id.sign_out_bar).setVisibility(View.GONE);
+ }
+
+ /**
+ * Shows the "sign out" bar (explanation and button).
+ */
+ private void showSignOutBar() {
+ findViewById(R.id.sign_in_bar).setVisibility(View.GONE);
+ findViewById(R.id.sign_out_bar).setVisibility(View.VISIBLE);
+ }
+
+
+ /**
+ * Updates the game UI.
+ */
+ private void updateUi() {
+ ((TextView) findViewById(R.id.world_display)).setText(getString(R.string.world)
+ + " " + mWorld);
+ for (int i = 0; i < LEVELS_PER_WORLD; i++) {
+ int levelNo = i + 1; // levels are numbered from 1
+ Button b = (Button) findViewById(LEVEL_BUTTON_IDS[i]);
+ int stars = mSaveGame.getLevelStars(mWorld, levelNo);
+ b.setTextColor(getResources().getColor(stars > 0 ? R.color.ClearedLevelColor :
+ R.color.UnclearedLevelColor));
+ b.setText(String.valueOf(mWorld) + "-" + String.valueOf(levelNo) + "\n" +
+ STAR_STRINGS[stars]);
+ }
+ // disable world changing if we are at the end of the list.
+ Button button;
+
+ button = (Button) findViewById(R.id.button_next_world);
+ button.setEnabled(mWorld < WORLD_MAX);
+
+ button = (Button) findViewById(R.id.button_prev_world);
+ button.setEnabled(mWorld > WORLD_MIN);
+ }
+
+
+ /**
+ * Loads the specified level state.
+ *
+ * @param level - level to load.
+ */
+ private void launchLevel(int level) {
+ mLevel = level;
+ ((TextView) findViewById(R.id.gameplay_level_display)).setText(
+ getString(R.string.level) + " " + mWorld + "-" + mLevel);
+ ((RatingBar) findViewById(R.id.gameplay_rating)).setRating(
+ mSaveGame.getLevelStars(mWorld, mLevel));
+ findViewById(R.id.screen_gameplay).setVisibility(View.VISIBLE);
+ findViewById(R.id.screen_main).setVisibility(View.GONE);
+ mInLevel = true;
+ }
+
+
+ @Override
+ public void onRatingChanged(RatingBar ratingBar, float rating, boolean fromUser) {
+ mSaveGame.setLevelStars(mWorld, mLevel, (int) rating);
+ updateUi();
+ findViewById(R.id.screen_gameplay).setVisibility(View.GONE);
+ findViewById(R.id.screen_main).setVisibility(View.VISIBLE);
+
+ mInLevel = false;
+ // save new data to cloud
+ saveSnapshot(null);
+ }
+
+ /**
+ * Prints a log message (convenience method).
+ */
+ void log(String message) {
+ Log.d(TAG, message);
+ }
+
+
+ /**
+ * Shows an alert message.
+ */
+ private void showAlertBar(int resId) {
+ ((TextView) findViewById(R.id.alert_bar)).setText(getString(resId));
+ findViewById(R.id.alert_bar).setVisibility(View.VISIBLE);
+ }
+
+
+ /**
+ * Dismisses the previously displayed alert message.
+ */
+ private void hideAlertBar() {
+ View alertBar = findViewById(R.id.alert_bar);
+ if (alertBar != null && alertBar.getVisibility() != View.GONE) {
+ alertBar.setVisibility(View.GONE);
+ }
+ }
+
+
+ /**
+ * This is an example of how to call Games.Snapshots.load(). It displays another
+ * activity to allow the user to select the snapshot. It is recommended to use the
+ * standard selection intent, Games.Snapshots.getSelectSnapshotIntent().
+ */
+ private void selectSnapshot() {
+ if (mLoadingDialog == null) {
+ mLoadingDialog = new ProgressDialog(this);
+ mLoadingDialog.setMessage(getString(R.string.loading_from_cloud));
+ }
+ mLoadingDialog.show();
+
+ SnapshotCoordinator.getInstance().load(mSnapshotsClient, false)
+ .addOnCompleteListener(new OnCompleteListener>() {
+ @Override
+ public void onComplete(@NonNull Task> task) {
+
+ if (mLoadingDialog != null && mLoadingDialog.isShowing()) {
+ mLoadingDialog.dismiss();
+ mLoadingDialog = null;
+ }
+
+ if (!task.isSuccessful()) {
+ handleException(task.getException(), "There was a problem selecting a snapshot!");
+ } else {
+ AnnotatedData result = task.getResult();
+
+ if (result.isStale()) {
+ Log.w(TAG, "The selected snapshot result was stale!");
+ }
+
+ ArrayList items = new ArrayList();
+ SnapshotMetadataBuffer snapshotMetadatas = result.get();
+ if (snapshotMetadatas != null) {
+ for (SnapshotMetadata m : snapshotMetadatas) {
+ items.add(m);
+ }
+ }
+ selectSnapshotItem(RC_SELECT_SNAPSHOT, items);
+ }
+
+ }
+ });
+ }
+
+ private void selectSnapshotItem(int requestCode,
+ ArrayList items,
+ String conflictId,
+ int retryCount) {
+
+ ArrayList snapshotList = new ArrayList(items.size());
+ for (Snapshot m : items) {
+ snapshotList.add(m.getMetadata().freeze());
+ }
+ Intent intent = new Intent(this, SelectSnapshotActivity.class);
+ intent.putParcelableArrayListExtra(SelectSnapshotActivity.SNAPSHOT_METADATA_LIST,
+ snapshotList);
+
+ intent.putExtra(SelectSnapshotActivity.CONFLICT_ID, conflictId);
+ intent.putExtra(SelectSnapshotActivity.RETRY_COUNT, retryCount);
+
+ Log.d(TAG, "Starting activity to select snapshot");
+ startActivityForResult(intent, requestCode);
+ }
+
+ private void selectSnapshotItem(int requestCode, ArrayList items) {
+
+ ArrayList metadataArrayList =
+ new ArrayList(items.size());
+ for (SnapshotMetadata m : items) {
+ metadataArrayList.add(m.freeze());
+ }
+ Intent intent = new Intent(this, SelectSnapshotActivity.class);
+ intent.putParcelableArrayListExtra(SelectSnapshotActivity.SNAPSHOT_METADATA_LIST,
+ metadataArrayList);
+
+ startActivityForResult(intent, requestCode);
+ }
+}
diff --git a/CollectAllTheStars2/src/main/java/com/google/example/games/catt2/SaveGame.java b/CollectAllTheStars2/src/main/java/com/google/example/games/catt2/SaveGame.java
new file mode 100644
index 00000000..bd01156c
--- /dev/null
+++ b/CollectAllTheStars2/src/main/java/com/google/example/games/catt2/SaveGame.java
@@ -0,0 +1,237 @@
+/* Copyright (C) 2014 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.catt2;
+
+import android.content.SharedPreferences;
+import android.util.Log;
+
+import org.json.JSONException;
+import org.json.JSONObject;
+
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.Map;
+
+/**
+ * Represents the player's progress in the game. The player's progress is how many stars
+ * they got on each level.
+ *
+ * @author Bruno Oliveira
+ */
+public class SaveGame {
+
+ private static final String TAG = "CollectAllTheStars";
+
+ // serialization format version
+ private static final String SERIAL_VERSION = "1.1";
+
+ // Maps a level name (like "2-8") to the number of stars the user has in that level.
+ // Any key that doesn't exist in this map is considered to be associated to the value 0.
+ Map mLevelStars = new HashMap();
+
+ // Minimum and maximum stars the player can have on a level
+ public static final int MIN_STARS = 0, MAX_STARS = 5;
+
+ /**
+ * Constructs an empty SaveGame object. No stars on no levels.
+ */
+ public SaveGame() {
+ }
+
+ /**
+ * Constructs a SaveGame object from serialized data.
+ */
+ public SaveGame(byte[] data) {
+ if (data == null) return; // default progress
+ loadFromJson(new String(data));
+ }
+
+ /**
+ * Constructs a SaveGame object from a JSON string.
+ */
+ public SaveGame(String json) {
+ if (json == null) return; // default progress
+ loadFromJson(json);
+ }
+
+ /**
+ * Constructs a SaveGame object by reading from a SharedPreferences.
+ */
+ public SaveGame(SharedPreferences sp, String key) {
+ loadFromJson(sp.getString(key, ""));
+ }
+
+ /**
+ * Replaces this SaveGame's content with the content loaded from the given JSON string.
+ */
+ public void loadFromJson(String json) {
+ zero();
+ if (json == null || json.trim().equals("")) return;
+
+ try {
+ JSONObject obj = new JSONObject(json);
+ String format = obj.getString("version");
+ if (!format.equals(SERIAL_VERSION)) {
+ throw new RuntimeException("Unexpected loot format " + format);
+ }
+ JSONObject levels = obj.getJSONObject("levels");
+ Iterator> iter = levels.keys();
+
+ while (iter.hasNext()) {
+ String levelName = (String) iter.next();
+ mLevelStars.put(levelName, levels.getInt(levelName));
+ }
+ } catch (JSONException ex) {
+ ex.printStackTrace();
+ Log.e(TAG, "Save data has a syntax error: " + json, ex);
+
+ // Initializing with empty stars if the game file is corrupt.
+ // NOTE: In your game, you want to try recovering from the snapshot payload.
+ mLevelStars.clear();
+ } catch (NumberFormatException ex) {
+ ex.printStackTrace();
+ throw new RuntimeException("Save data has an invalid number in it: " + json, ex);
+ }
+ }
+
+ /**
+ * Serializes this SaveGame to an array of bytes.
+ */
+ public byte[] toBytes() {
+ return toString().getBytes();
+ }
+
+ /**
+ * Serializes this SaveGame to a JSON string.
+ */
+ @Override
+ public String toString() {
+ try {
+ JSONObject levels = new JSONObject();
+ for (String levelName : mLevelStars.keySet()) {
+ levels.put(levelName, mLevelStars.get(levelName));
+ }
+
+ JSONObject obj = new JSONObject();
+ obj.put("version", SERIAL_VERSION);
+ obj.put("levels", levels);
+ return obj.toString();
+ } catch (JSONException ex) {
+ ex.printStackTrace();
+ throw new RuntimeException("Error converting save data to JSON.", ex);
+ }
+ }
+
+ /**
+ * Computes the union of this SaveGame with the given SaveGame. The union will have any
+ * levels present in either operand. If the same level is present in both operands,
+ * then the number of stars will be the greatest of the two.
+ *
+ * @param other The other operand with which to compute the union.
+ * @return The result of the union.
+ */
+ public SaveGame unionWith(SaveGame other) {
+ SaveGame result = clone();
+ for (String levelName : other.mLevelStars.keySet()) {
+ int existingStars = result.getLevelStars(levelName);
+ int newStars = other.getLevelStars(levelName);
+
+ // only overwrite if number of stars is greater
+ if (newStars > existingStars) {
+ result.setLevelStars(levelName, newStars);
+ }
+
+ // note that this code doesn't preserve mappings from a level to the value 0,
+ // but that is not a problem because, in our semantics, the absence of a mapping
+ // is equivalent to mapping to 0 stars.
+ }
+ return result;
+ }
+
+ /**
+ * Returns a clone of this SaveGame object.
+ */
+ public SaveGame clone() {
+ SaveGame result = new SaveGame();
+ for (String levelName : mLevelStars.keySet()) {
+ result.setLevelStars(levelName, getLevelStars(levelName));
+ }
+ return result;
+ }
+
+ /**
+ * Resets this SaveGame object to be empty. Empty means no stars on no levels.
+ */
+ public void zero() {
+ mLevelStars.clear();
+ }
+
+ /**
+ * Returns whether or not this SaveGame is empty. Empty means no stars on no levels.
+ */
+ public boolean isZero() {
+ return mLevelStars.keySet().size() == 0;
+ }
+
+ /**
+ * Save this SaveGame object to a SharedPreferences.
+ */
+ public void save(SharedPreferences sp, String key) {
+ SharedPreferences.Editor spe = sp.edit();
+ spe.putString(key, toString());
+ spe.apply();
+ }
+
+ /**
+ * Gets how many stars the player has on the given level. If the level does not exist
+ * in the save game, will return 0.
+ */
+ public int getLevelStars(String levelName) {
+ Integer r = mLevelStars.get(levelName);
+ return r == null ? 0 : r;
+ }
+
+ /**
+ * Gets how many stars the player has on the given level. If the level does not exist
+ * in the save game, will return 0.
+ */
+ public int getLevelStars(int world, int level) {
+ return getLevelStars(String.valueOf(world) + "-" + String.valueOf(level));
+ }
+
+ /**
+ * Sets how many stars the player has on the given level.
+ */
+ public void setLevelStars(String levelName, int stars) {
+ if (stars < MIN_STARS) stars = MIN_STARS;
+ if (stars > MAX_STARS) stars = MAX_STARS;
+ if (stars == 0) {
+ // zero stars means remove it from the map
+ if (mLevelStars.containsKey(levelName)) {
+ mLevelStars.remove(levelName);
+ }
+ } else {
+ mLevelStars.put(levelName, stars);
+ }
+ }
+
+ /**
+ * Sets how many stars the player has on the given level.
+ */
+ public void setLevelStars(int world, int level, int stars) {
+ setLevelStars(String.valueOf(world) + "-" + String.valueOf(level), stars);
+ }
+}
diff --git a/CollectAllTheStars2/src/main/java/com/google/example/games/catt2/SelectSnapshotActivity.java b/CollectAllTheStars2/src/main/java/com/google/example/games/catt2/SelectSnapshotActivity.java
new file mode 100644
index 00000000..736621b7
--- /dev/null
+++ b/CollectAllTheStars2/src/main/java/com/google/example/games/catt2/SelectSnapshotActivity.java
@@ -0,0 +1,194 @@
+/* Copyright (C) 2014 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.catt2;
+
+import android.content.Context;
+import android.content.Intent;
+import android.os.Bundle;
+import android.util.Log;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.AdapterView;
+import android.widget.ArrayAdapter;
+import android.widget.ImageView;
+import android.widget.ListView;
+import android.widget.TextView;
+
+import androidx.appcompat.app.AppCompatActivity;
+
+import com.google.android.gms.common.images.ImageManager;
+import com.google.android.gms.games.snapshot.Snapshot;
+import com.google.android.gms.games.snapshot.SnapshotMetadata;
+
+import java.util.ArrayList;
+
+/**
+ * Activity to select a snapshot from a list of snapshots or snapshot metadata. The intended
+ * use of this activity is to present a choice of two conflicting snapshots to the user so
+ * they can select the "best" snapshot.
+ *
+ * There is also a code path that loads all the saved games and presents this list, which is not
+ * expected to be "production" code, but rather demonstrate how the Snapshots.load() method works.
+ *
+ * @author Clayton Wilkinson (Google)
+ */
+public class SelectSnapshotActivity extends AppCompatActivity implements AdapterView.OnItemClickListener {
+
+ private static final String TAG = "SelSnapshotActivity";
+ // intent data which is a snapshot metadata
+ public static final String SNAPSHOT_METADATA = "snapshotmeta";
+
+ // intent data that is a list of snapshot metadatas.
+ public static final String SNAPSHOT_METADATA_LIST = "snapshotmetaList";
+
+ // intent data that is the conflict id. used when resolving a conflict.
+ public static final String CONFLICT_ID = "conflictId";
+
+ // intent data that is the retry count for retrying the conflict resolution.
+ public static final String RETRY_COUNT = "retrycount";
+
+ // keep these variables for the current activity and return them in the result.
+ private String mConflictId;
+
+ private int mRetryCount;
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setContentView(R.layout.activity_select_snapshot);
+
+ //expect the intent to include the list of snapshots or snapshot metadatas to display
+ Intent intent = getIntent();
+ if (intent != null) {
+ ArrayList snapshotMetadataList;
+ ListView vw = (ListView) findViewById(R.id.snapshot_list);
+
+ snapshotMetadataList = intent.getParcelableArrayListExtra(SNAPSHOT_METADATA_LIST);
+ // set a custom list adapter that can display the image and other
+ // information about a snapshot.
+ vw.setAdapter(
+ new SnapshotListAdapter(this, snapshotMetadataList));
+
+ mConflictId = intent.getStringExtra(CONFLICT_ID);
+ mRetryCount = intent.getIntExtra(RETRY_COUNT, 0);
+
+ // register this class as the listener for when an item is selected
+ vw.setOnItemClickListener(this);
+ }
+ }
+
+
+ @Override
+ public void onItemClick(AdapterView> adapterView, View view, int position, long listId) {
+
+ SnapshotMetadata selected = (SnapshotMetadata) adapterView.getItemAtPosition(position);
+ Intent intent = new Intent(Intent.ACTION_DEFAULT);
+
+ intent.putExtra(SNAPSHOT_METADATA, selected.freeze());
+
+ if (mConflictId != null) {
+ intent.putExtra(CONFLICT_ID, mConflictId);
+ intent.putExtra(RETRY_COUNT, mRetryCount);
+ }
+
+ Log.d(TAG, "Finishing item at position " + position + " clicked");
+ setResult(RESULT_OK, intent);
+ finish();
+ }
+
+ /**
+ * Custom mSnapshotMetadataArrayList adapter which holds the snapshot metadata. This is used
+ * to
+ * display the image and information for each snapshot.
+ */
+ static class SnapshotListAdapter extends ArrayAdapter {
+
+
+ public SnapshotListAdapter(AppCompatActivity activity, ArrayList data) {
+ super(activity, R.layout.snapshotlayout, data);
+ }
+
+ @Override
+ public View getView(int position, View convertView, ViewGroup parent) {
+
+ // load the view used for each item in the mSnapshotMetadataArrayList
+ LayoutInflater inflater = (LayoutInflater) getContext().getSystemService(
+ Context.LAYOUT_INFLATER_SERVICE);
+ View rowView = inflater.inflate(R.layout.snapshotlayout, parent, false);
+
+ // get the elements of the view which display the specific data for the snapshot.
+ TextView textView = (TextView) rowView.findViewById(R.id.label);
+ TextView ageView = (TextView) rowView.findViewById(R.id.age);
+ ImageView imageView = (ImageView) rowView.findViewById(R.id.snapshot_icon);
+
+ SnapshotMetadata snapshotMetadata;
+ T item = getItem(position);
+ if (item instanceof Snapshot) {
+ snapshotMetadata = ((Snapshot) item).getMetadata();
+ } else {
+ snapshotMetadata = (SnapshotMetadata) item;
+ }
+ textView.setText(snapshotMetadata.getDescription());
+ ageView.setText(getAge(snapshotMetadata.getLastModifiedTimestamp()));
+ ImageManager.create(getContext())
+ .loadImage(imageView, snapshotMetadata.getCoverImageUri());
+
+ return rowView;
+
+ }
+
+
+ private static final long MILLIS_PER_MINUTE = 60 * 1000;
+
+ private static final long MILLIS_PER_HOUR = 60 * MILLIS_PER_MINUTE;
+
+ private static final long MILLIS_PER_DAY = 24 * MILLIS_PER_HOUR;
+
+ /**
+ * Helper function to convert the time difference into a string like "3 days ago"
+ *
+ * @param timestamp - the time to convert.
+ * @return localized string, never null.
+ */
+ private String getAge(long timestamp) {
+ long delta = System.currentTimeMillis() - timestamp;
+ int days = (int) (delta / MILLIS_PER_DAY);
+
+ delta = delta % MILLIS_PER_DAY;
+ int hours = (int) (delta / MILLIS_PER_HOUR);
+
+ delta = delta % MILLIS_PER_HOUR;
+ int minutes = (int) (delta / MILLIS_PER_MINUTE);
+
+ delta = (int) (delta % MILLIS_PER_MINUTE);
+ int seconds = (int) delta / 1000;
+
+ if (days > 0) {
+ return getContext().getString(R.string.format_days_ago, days);
+ }
+ if (hours > 0) {
+ return getContext().getString(R.string.format_hours_ago, hours);
+ }
+ if (minutes > 0) {
+ return getContext().getString(R.string.format_minutes_ago, minutes);
+ }
+ if (seconds > 0) {
+ return getContext().getString(R.string.format_seconds_ago, seconds);
+ }
+ return getContext().getString(R.string.moments_ago);
+ }
+ }
+}
diff --git a/CollectAllTheStars2/src/main/java/com/google/example/games/catt2/SnapshotCoordinator.java b/CollectAllTheStars2/src/main/java/com/google/example/games/catt2/SnapshotCoordinator.java
new file mode 100644
index 00000000..48ad50b5
--- /dev/null
+++ b/CollectAllTheStars2/src/main/java/com/google/example/games/catt2/SnapshotCoordinator.java
@@ -0,0 +1,456 @@
+// Copyright 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.example.games.catt2;
+
+import android.content.Intent;
+import android.os.AsyncTask;
+import android.os.Bundle;
+import androidx.annotation.NonNull;
+import android.util.Log;
+
+import com.google.android.gms.common.api.CommonStatusCodes;
+import com.google.android.gms.common.api.Result;
+import com.google.android.gms.common.api.Status;
+import com.google.android.gms.games.AnnotatedData;
+import com.google.android.gms.games.SnapshotsClient;
+import com.google.android.gms.games.snapshot.Snapshot;
+import com.google.android.gms.games.snapshot.SnapshotContents;
+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.tasks.Continuation;
+import com.google.android.gms.tasks.OnCompleteListener;
+import com.google.android.gms.tasks.Task;
+import com.google.android.gms.tasks.TaskCompletionSource;
+
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+import java.util.concurrent.CountDownLatch;
+
+/**
+ * The SnapshotCoordinator is used to overcome some dangerous behavior when using Saved Game API
+ * (aka Snapshots). The problem is caused by the not having way to prevent having the same file
+ * opened multiple overlapping times. Also there is no way to stop the incorrect reusing of
+ * the Snapshot contained in the OpenSnapshotResult object. It should be used once to write or be
+ * closed. Multiple commits using the same snapshot will result in unrecoverable conflicts.
+ *
+ * This class is used to encapsulate the access to the Snapshots API and enforce these semantics of
+ * exclusive file access and one-time committing of metadata.
+ *
+ * How to use this class
+ *
+ * This class can be used as a drop-in replacement for SnapshotsClient. If the usage of the API
+ * is inconsistent with enforced rules (any file can be open only once before closing it, and
+ * snapshot data can only be committed once per open), then an IllegalStateException is thrown.
+ *
+ * To make it easier to use Snapshots correctly, you should call SnapshotCoordinator.waitForClosed()
+ * to obtain a Task which will be resolved when the file is ready to be opened again.
+ */
+public class SnapshotCoordinator {
+
+ private static final SnapshotCoordinator theInstance = new SnapshotCoordinator();
+
+ private static final String TAG = "SnapshotCoordinator";
+
+ /**
+ * Singleton for coordinating the Snapshots API. This is important since
+ * we need to coordinate all operations through the same instance in order to
+ * detect usages that would cause data corruption.
+ *
+ * @return the singleton
+ */
+ public static SnapshotCoordinator getInstance() {
+ return theInstance;
+ }
+
+ // Sets to keep track of the files that are opened or in the process of closing.
+ private final Map opened;
+ private final Set closing;
+
+ private SnapshotCoordinator() {
+ opened = new HashMap<>();
+ closing = new HashSet<>();
+ }
+
+ /**
+ * Returns true if the named file is already opened. This is a synchronized
+ * operation since it is highly likely that multiple threads are involved via AsyncTasks.
+ *
+ * @param filename - the filename to check
+ * @return true if opened.
+ */
+ public synchronized boolean isAlreadyOpen(String filename) {
+ return opened.containsKey(filename);
+ }
+
+ /**
+ * Returns true if the named file is in the process of closing. This is a synchronized
+ * operation since it is highly likely that multiple threads are involved via AsyncTasks.
+ *
+ * @param filename - the filename to check
+ * @return true if closing.
+ */
+ public synchronized boolean isAlreadyClosing(String filename) {
+ return closing.contains(filename);
+ }
+
+ /**
+ * Records the fact that the named file is closing (which also includes committing the data).
+ * This is a synchronized operation since it is highly likely that multiple threads
+ * are involved via AsyncTasks.
+ *
+ * @param filename - the filename of interest.
+ */
+ private synchronized void setIsClosing(String filename) {
+ closing.add(filename);
+ }
+
+ /**
+ * Records the fact that the named file is closed.
+ * This is a synchronized operation since it is highly likely that multiple threads
+ * are involved via AsyncTasks.
+ *
+ * @param filename - the filename of interest.
+ */
+ private synchronized void setClosed(String filename) {
+ closing.remove(filename);
+ CountDownLatch l = opened.remove(filename);
+ if (l != null) {
+ l.countDown();
+ }
+ }
+
+ /**
+ * Records the fact that the named file is opening.
+ * This is a synchronized operation since it is highly likely that multiple threads
+ * are involved via AsyncTasks.
+ *
+ * @param filename - the filename of interest.
+ */
+ private synchronized void setIsOpening(String filename) {
+ opened.put(filename, new CountDownLatch(1));
+ }
+
+ /**
+ * Returns a task that will complete when given file is closed. Returns immediately if the
+ * file is not open.
+ *
+ * @param filename - the file name in question.
+ */
+ public Task waitForClosed(String filename) {
+ final TaskCompletionSource taskCompletionSource = new TaskCompletionSource<>();
+
+ final CountDownLatch latch;
+ synchronized (this) {
+ latch = opened.get(filename);
+ }
+
+ if (latch == null) {
+ taskCompletionSource.setResult(null);
+
+ return taskCompletionSource.getTask();
+ }
+
+ new AsyncTask() {
+ @Override
+ protected Void doInBackground(Void... voids) {
+ Result result = new CountDownTask(latch).await();
+ taskCompletionSource.setResult(result);
+
+ return null;
+ }
+ }.execute();
+
+ return taskCompletionSource.getTask();
+ }
+
+ /*
+ Many operations on the Snapshots API do not affect specific files. These methods are
+ passed directly through to the client API.
+ */
+
+ public Task getMaxDataSize(SnapshotsClient snapshotsClient) {
+ return snapshotsClient.getMaxDataSize();
+ }
+
+ public Task getMaxCoverImageSize(SnapshotsClient snapshotsClient) {
+ return snapshotsClient.getMaxCoverImageSize();
+ }
+
+ public Task getSelectSnapshotIntent(SnapshotsClient snapshotsClient,
+ String title,
+ boolean allowAddButton,
+ boolean allowDelete,
+ int maxSnapshots) {
+ return snapshotsClient.getSelectSnapshotIntent(title,
+ allowAddButton, allowDelete, maxSnapshots);
+ }
+
+ public Task> load(SnapshotsClient snapshotsClient,
+ boolean forceReload) {
+ return snapshotsClient.load(forceReload);
+ }
+
+ public SnapshotMetadata getSnapshotFromBundle(Bundle bundle) {
+ return SnapshotsClient.getSnapshotFromBundle(bundle);
+ }
+
+ public Task> resolveConflict(SnapshotsClient snapshotsClient,
+ String conflictId, String snapshotId,
+ SnapshotMetadataChange snapshotMetadataChange,
+ SnapshotContents snapshotContents) {
+ // Since the unique name of the snapshot is unknown, this resolution method cannot be safely
+ // used. Please use another method of resolution.
+ throw new IllegalStateException("resolving conflicts with ids is not supported.");
+ }
+
+ public Task discardAndClose(final SnapshotsClient snapshotsClient, final Snapshot snapshot) {
+
+ final String filename = snapshot.getMetadata().getUniqueName();
+
+ return setIsClosingTask(filename).continueWithTask(new Continuation>() {
+ @Override
+ public Task then(@NonNull Task task) throws Exception {
+ return snapshotsClient.discardAndClose(snapshot)
+ .addOnCompleteListener(new OnCompleteListener() {
+ @Override
+ public void onComplete(@NonNull Task task) {
+ Log.d(TAG, "Closed " + snapshot.getMetadata().getUniqueName());
+ setClosed(snapshot.getMetadata().getUniqueName());
+ }
+ });
+ }
+ });
+ }
+
+ @NonNull
+ private OnCompleteListener> createOpenListener(final String filename) {
+ return new OnCompleteListener>() {
+ @Override
+ public void onComplete(@NonNull Task> task) {
+ // if open failed, set the file to closed, otherwise, keep it open.
+ if (!task.isSuccessful()) {
+ Exception e = task.getException();
+ Log.e(TAG, "Open was not a success for filename " + filename, e);
+ setClosed(filename);
+ } else {
+ SnapshotsClient.DataOrConflict result
+ = task.getResult();
+ if (result.isConflict()) {
+ Log.d(TAG, "Open successful: " + filename + ", but with a conflict");
+ } else {
+ Log.d(TAG, "Open successful: " + filename);
+ }
+ }
+ }
+ };
+ }
+
+ @NonNull
+ private Task setIsOpeningTask(String filename) {
+ TaskCompletionSource source = new TaskCompletionSource<>();
+
+ if (isAlreadyOpen(filename)) {
+ source.setException(new IllegalStateException(filename + " is already open!"));
+ } else if (isAlreadyClosing(filename)) {
+ source.setException(new IllegalStateException(filename + " is current closing!"));
+ } else {
+ setIsOpening(filename);
+ source.setResult(null);
+ }
+ return source.getTask();
+ }
+
+ @NonNull
+ private Task setIsClosingTask(String filename) {
+ TaskCompletionSource source = new TaskCompletionSource<>();
+
+ if (!isAlreadyOpen(filename)) {
+ source.setException(new IllegalStateException(filename + " is already closed!"));
+ } else if (isAlreadyClosing(filename)) {
+ source.setException(new IllegalStateException(filename + " is current closing!"));
+ } else {
+ setIsClosing(filename);
+ source.setResult(null);
+ }
+ return source.getTask();
+ }
+
+ public Task> open(final SnapshotsClient snapshotsClient,
+ final String filename,
+ final boolean createIfNotFound) {
+
+ return setIsOpeningTask(filename).continueWithTask(new Continuation>>() {
+ @Override
+ public Task> then(@NonNull Task task) throws Exception {
+ return snapshotsClient.open(filename, createIfNotFound)
+ .addOnCompleteListener(createOpenListener(filename));
+ }
+ });
+ }
+
+ public Task> open(final SnapshotsClient snapshotsClient,
+ final String filename,
+ final boolean createIfNotFound,
+ final int conflictPolicy) {
+
+ return setIsOpeningTask(filename).continueWithTask(new Continuation>>() {
+ @Override
+ public Task> then(@NonNull Task task) throws Exception {
+ return snapshotsClient.open(filename, createIfNotFound, conflictPolicy)
+ .addOnCompleteListener(createOpenListener(filename));
+ }
+ });
+ }
+
+ public Task> open(final SnapshotsClient snapshotsClient,
+ final SnapshotMetadata snapshotMetadata) {
+ final String filename = snapshotMetadata.getUniqueName();
+
+ return setIsOpeningTask(filename).continueWithTask(new Continuation>>() {
+ @Override
+ public Task> then(@NonNull Task task) throws Exception {
+ return snapshotsClient.open(snapshotMetadata)
+ .addOnCompleteListener(createOpenListener(filename));
+ }
+ });
+ }
+
+ public Task> open(final SnapshotsClient snapshotsClient,
+ final SnapshotMetadata snapshotMetadata,
+ final int conflictPolicy) {
+ final String filename = snapshotMetadata.getUniqueName();
+
+ return setIsOpeningTask(filename).continueWithTask(new Continuation>>() {
+ @Override
+ public Task> then(@NonNull Task task) throws Exception {
+ return snapshotsClient.open(snapshotMetadata, conflictPolicy)
+ .addOnCompleteListener(createOpenListener(filename));
+ }
+ });
+ }
+
+ public Task commitAndClose(final SnapshotsClient snapshotsClient,
+ final Snapshot snapshot,
+ final SnapshotMetadataChange snapshotMetadataChange) {
+
+ final String filename = snapshot.getMetadata().getUniqueName();
+
+ return setIsClosingTask(filename).continueWithTask(new Continuation>() {
+ @Override
+ public Task then(@NonNull Task task) throws Exception {
+ return snapshotsClient.commitAndClose(snapshot, snapshotMetadataChange)
+ .addOnCompleteListener(new OnCompleteListener() {
+ @Override
+ public void onComplete(@NonNull Task task) {
+ // even if commit and close fails, the file is closed.
+ Log.d(TAG, "CommitAndClose complete, closing " +
+ filename);
+ setClosed(filename);
+ }
+ });
+ }
+ });
+ }
+
+ public Task delete(final SnapshotsClient snapshotsClient,
+ final SnapshotMetadata snapshotMetadata) {
+
+ final String filename = snapshotMetadata.getUniqueName();
+ TaskCompletionSource source = new TaskCompletionSource<>();
+
+ if (isAlreadyOpen(filename)) {
+ source.setException(new IllegalStateException(filename + " is still open!"));
+ } else if (isAlreadyClosing(filename)) {
+ source.setException(new IllegalStateException(filename + " is current closing!"));
+ } else {
+ setIsClosing(filename);
+ source.setResult(null);
+ }
+
+ return source.getTask().continueWithTask(new Continuation>() {
+ @Override
+ public Task then(@NonNull Task task) throws Exception {
+ return snapshotsClient.delete(snapshotMetadata)
+ .addOnCompleteListener(new OnCompleteListener() {
+ @Override
+ public void onComplete(@NonNull Task task) {
+ // deleted files are closed.
+ setClosed(filename);
+ }
+ });
+ }
+ });
+ }
+
+ public Task> resolveConflict(final SnapshotsClient snapshotsClient,
+ final String conflictId,
+ final Snapshot snapshot) {
+ final String filename = snapshot.getMetadata().getUniqueName();
+
+ return setIsOpeningTask(filename).continueWithTask(new Continuation>>() {
+ @Override
+ public Task> then(@NonNull Task task) throws Exception {
+ return snapshotsClient.resolveConflict(conflictId, snapshot)
+ .addOnCompleteListener(new OnCompleteListener>() {
+ @Override
+ public void onComplete(@NonNull Task> task) {
+
+ if (!task.isSuccessful()) {
+ setClosed(filename);
+ }
+ }
+ });
+ }
+ });
+ }
+
+ private class CountDownTask {
+ private final CountDownLatch latch;
+ private boolean canceled;
+
+ private final Status Success = new Status(CommonStatusCodes.SUCCESS);
+ private final Status Canceled = new Status(CommonStatusCodes.CANCELED);
+
+ public CountDownTask(CountDownLatch latch) {
+ this.latch = latch;
+ canceled = false;
+ }
+
+ @NonNull
+ public Result await() {
+ if (!canceled && latch != null) {
+ try {
+ latch.await();
+ } catch (InterruptedException e) {
+ return new Result() {
+ @Override
+ public Status getStatus() {
+ return Canceled;
+ }
+ };
+ }
+ }
+ return new Result() {
+ @Override
+ public Status getStatus() {
+ return canceled ? Canceled : Success;
+ }
+ };
+ }
+
+ }
+}
\ No newline at end of file
diff --git a/BasicSamples/ButtonClicker/src/main/res/drawable-hdpi/ic_launcher.png b/CollectAllTheStars2/src/main/res/drawable-hdpi/ic_launcher.png
similarity index 100%
rename from BasicSamples/ButtonClicker/src/main/res/drawable-hdpi/ic_launcher.png
rename to CollectAllTheStars2/src/main/res/drawable-hdpi/ic_launcher.png
diff --git a/CollectAllTheStars2/src/main/res/drawable-ldpi/ic_launcher.png b/CollectAllTheStars2/src/main/res/drawable-ldpi/ic_launcher.png
new file mode 100644
index 00000000..69553bd9
Binary files /dev/null and b/CollectAllTheStars2/src/main/res/drawable-ldpi/ic_launcher.png differ
diff --git a/BasicSamples/ButtonClicker/src/main/res/drawable-mdpi/ic_launcher.png b/CollectAllTheStars2/src/main/res/drawable-mdpi/ic_launcher.png
similarity index 100%
rename from BasicSamples/ButtonClicker/src/main/res/drawable-mdpi/ic_launcher.png
rename to CollectAllTheStars2/src/main/res/drawable-mdpi/ic_launcher.png
diff --git a/BasicSamples/ButtonClicker/src/main/res/drawable-xhdpi/ic_launcher.png b/CollectAllTheStars2/src/main/res/drawable-xhdpi/ic_launcher.png
similarity index 100%
rename from BasicSamples/ButtonClicker/src/main/res/drawable-xhdpi/ic_launcher.png
rename to CollectAllTheStars2/src/main/res/drawable-xhdpi/ic_launcher.png
diff --git a/BasicSamples/ButtonClicker/src/main/res/drawable-xxhdpi/ic_launcher.png b/CollectAllTheStars2/src/main/res/drawable-xxhdpi/ic_launcher.png
similarity index 100%
rename from BasicSamples/ButtonClicker/src/main/res/drawable-xxhdpi/ic_launcher.png
rename to CollectAllTheStars2/src/main/res/drawable-xxhdpi/ic_launcher.png
diff --git a/BasicSamples/CollectAllTheStars2/src/main/res/layout/activity_main.xml b/CollectAllTheStars2/src/main/res/layout/activity_main.xml
similarity index 100%
rename from BasicSamples/CollectAllTheStars2/src/main/res/layout/activity_main.xml
rename to CollectAllTheStars2/src/main/res/layout/activity_main.xml
diff --git a/BasicSamples/CollectAllTheStars2/src/main/res/layout/activity_select_snapshot.xml b/CollectAllTheStars2/src/main/res/layout/activity_select_snapshot.xml
similarity index 100%
rename from BasicSamples/CollectAllTheStars2/src/main/res/layout/activity_select_snapshot.xml
rename to CollectAllTheStars2/src/main/res/layout/activity_select_snapshot.xml
diff --git a/BasicSamples/CollectAllTheStars2/src/main/res/layout/snapshotlayout.xml b/CollectAllTheStars2/src/main/res/layout/snapshotlayout.xml
similarity index 89%
rename from BasicSamples/CollectAllTheStars2/src/main/res/layout/snapshotlayout.xml
rename to CollectAllTheStars2/src/main/res/layout/snapshotlayout.xml
index d17a1a53..5c4f8366 100644
--- a/BasicSamples/CollectAllTheStars2/src/main/res/layout/snapshotlayout.xml
+++ b/CollectAllTheStars2/src/main/res/layout/snapshotlayout.xml
@@ -13,9 +13,10 @@
android:textSize="25sp" >
-