Google Play game services - Android samples

Overview

Google Play game services - Android Samples

Copyright (C) 2014 Google Inc.

Contents

These are the Android samples for Google Play game services.

  • CollectAllTheStars2. Demonstrates how to use the Snapshots feature to save game data. The sample signs the user in, synchronizes their data from a named Snapshot, then updates the UI to reflect the game state saved in the Snapshot.

  • TypeANumber. Demonstrates how to use leaderboards, achievements, events, and friends. In this exciting game, you type the score you think you deserve. But wait! There is a twist. If you are playing in easy mode, you get the score you requested. However, if you are playing in hard mode, you only get half! (tough game, we know). You can also check how your friends perform in this game by checking out social leaderboards.

How to run a sample

  1. Set up the project in the Developer Console by following these instructions. Note your package name and the application ID of the project!

  2. For the Type a Number sample, you need to create leaderboards/achievements. (You can see the ones that the sample needs in its res/values/ids.xml file.) You can create them two ways:

    1. Add them via the Developer console.
    2. Use this utility, which will automatically create them for you.

Building using Android Studio...

  1. Open Android Studio and launch the Android SDK manager from it (Tools | Android | SDK Manager)
  2. Ensure the following components are installed and updated to the latest version.
    1. Android SDK Platform-Tools
    2. Android Support Repository
    3. Google Repository
  3. Return to Android Studio and select Open an existing Android Studio project
  4. Select the android-basic-samples directory.

Modify IDs, compile and run

To set up a sample:

  1. Change the applicationId in the build.gradle file to your own package name (ie - com.example.package.name) (the same one you registered in Developer Console!). You will have to update the build.gradle file for each sample you want to run. There is no need to edit the AndroidManifest.xml file.
  2. In the Developer console, select a resource type (Achievements, Events, Leaderboards) and click "Get Resources". Copy the contents from the console and replace the contents of res/values/ids.xml.
    1. If you are running Android Studio, check the TODO window to see if there are any remaining tasks.
  3. Compile and run.

IMPORTANT: make sure to sign your apk with the same certificate as the one whose fingerprint you configured on Developer Console, otherwise you will see errors.

IMPORTANT: if you are testing an unpublished game, make sure that the account you intend to sign in with (the account on the test device) is listed as a tester in the project on your Developer Console setup (check the list in the "Testing" section), otherwise the server will act as though your project did not exist and return errors like 'Failed to sign in. Please check your network connection and try again.'

Building

To build the samples after you have applied the changes above, you can use the build/run option in Android Studio, or build directly from the command line if you prefer.

IMPORTANT Ensure you have set the ANDROID_HOME environment variable.

cd /path/to/android-basic-samples
export ANDROID_HOME = /path/to/android/sdk
./gradlew build

Support

First of all, take a look at our troubleshooting guide. Most setup issues can be solved by following this guide.

If your question is not answered by the troubleshooting guide, we encourage you to post your question to stackoverflow.com. Our team answers questions there regularly.

Samples written by Bruno Oliveira with contributions from Wolff.* Feel free to add us to your circles on Google Plus and pester us to fix stuff that's broken or answer a question on stackoverflow :-)

Special Thanks

  • To ligi for contributing the initial Gradle build files
  • To bechhansen for fixing a bug in GameHelper where the turn-based match was being lost when a non-Games client connected.
Comments
  • BadParcelableException for Google Login API

    BadParcelableException for Google Login API

    Google play services: 9.0.2 Support libs: 24.0.0 Android studio 2.2 Preview 4 Gradle 2.2-alpha-4

    Fatal Exception: java.lang.RuntimeException: Unable to start activity ComponentInfo{com.my.app/com.google.android.gms.auth.api.signin.internal.SignInHubActivity}: android.os.BadParcelableException: ClassNotFoundException when unmarshalling: 佅￿l￿https://www.googleapis.com/auth/plus.login,佅￿$￿profile(佅￿ ￿email,佅￿$￿ at android.app.ActivityThread.performLaunchActivity(ActivityThread.java) at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java) at android.app.ActivityThread.access$900(ActivityThread.java) at android.app.ActivityThread$H.handleMessage(ActivityThread.java) at android.os.Handler.dispatchMessage(Handler.java) at android.os.Looper.loop(Looper.java) at android.app.ActivityThread.main(ActivityThread.java) at java.lang.reflect.Method.invoke(Method.java) at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java) at com.android.internal.os.ZygoteInit.main(ZygoteInit.java) Caused by android.os.BadParcelableException: ClassNotFoundException when unmarshalling: 佅￿l￿https://www.googleapis.com/auth/plus.login,佅￿$￿profile(佅￿ ￿email,佅￿$￿ at android.os.Parcel.readException(Parcel.java) at android.os.Parcel.readException(Parcel.java) at android.app.ActivityManagerProxy.startActivity(ActivityManagerNative.java) at android.app.Instrumentation.execStartActivity(Instrumentation.java) at android.app.Activity.startActivityForResult(Activity.java) at android.support.v4.app.BaseFragmentActivityJB.startActivityForResult(BaseFragmentActivityJB.java:48) at android.support.v4.app.FragmentActivity.startActivityForResult(FragmentActivity.java:75) at android.app.Activity.startActivityForResult(Activity.java) at android.support.v4.app.FragmentActivity.startActivityForResult(FragmentActivity.java:871) at com.google.android.gms.auth.api.signin.internal.SignInHubActivity.zzj(Unknown Source) at com.google.android.gms.auth.api.signin.internal.SignInHubActivity.onCreate(Unknown Source) at android.app.Activity.performCreate(Activity.java) at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java) at android.app.ActivityThread.performLaunchActivity(ActivityThread.java) at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java) at android.app.ActivityThread.access$900(ActivityThread.java) at android.app.ActivityThread$H.handleMessage(ActivityThread.java) at android.os.Handler.dispatchMessage(Handler.java) at android.os.Looper.loop(Looper.java) at android.app.ActivityThread.main(ActivityThread.java) at java.lang.reflect.Method.invoke(Method.java) at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java) at com.android.internal.os.ZygoteInit.main(ZygoteInit.java)

    opened by StilianosTzouvaras 25
  • TurnBasedMultiplayer.LoadMatchesResult empty after deploying new APK

    TurnBasedMultiplayer.LoadMatchesResult empty after deploying new APK

    Hi,

    I have a topic at stackoverflow (https://stackoverflow.com/questions/29805131/turnbased-matches-disappear-after-loading-for-the-first-time). The issue is that if I create a match the match is returned by TurnBasedMultiplayer.LoadMatchesResult (status code OK).

    Now I deploy a new version of the app (either through Android Studio or an update of my alpha app from the Play Store). Result: No matches are returned in the LoadMatchesResult (status code still OK). If I delete the cache from Play Services on the device and reopen the app all matches are returned again. If the matches are not returned in the LoadMatchesResult they are also not shown in the default UI (getInboxIntent()).

    I release the LoadMatchesResult once I'm done with the data by calling release(). This happens both on a Nexus 5 and emulators.

    opened by mkalksma 21
  • savedgames misses conflicts (and can thus lose states)

    savedgames misses conflicts (and can thus lose states)

    I've created a little test-setup to play around with the savegames-api. In this setup, I run the same app (which has been configured for use with the savedgames-api in the developer console) on two different devices, and connect to the games-api using the same user-account. I can then (roughly) simultaneously start a sequence of actions (saving/loading the game state using the savedgames-api), and print the state as seen by the two devices. For details, please refer to the code at the end of this post.

    In this setup I use a manual conflict resolution that always returns the largest value. I now simultaneously write "1" from one device, and "2" from the other, and then, a few seconds later, load the current state on both devices. I would expect the final state on both devices to always be "2" (i.e. the larger of the two values, according to the conflict resolution strategy). Sometimes, everything works as expected (i.e. I see state "2" on both devices), quite regularly I also get "1" on one, and "2" on the other device (which is wrong, but at mostly resolves at the next load on the device that saw "1"), and sometimes, I also get "1" as the loaded state on both devices (in that situation, the state "2" seems to be lost forever).

    Note that this last situation (state is lost forever), might result in quite angry users if they buy something using in-app-payments (which is reflected in the state), and then at some point that state just gets lost due to buggy syncing.

    The corresponding logcat output looks as follows:

    Different results at first load (fixes at second load):
    =======================================================
    Device1:
    04-27 10:58:05.149: V/SyncTestActivity(32369): Own entries.size: 4
    04-27 10:58:06.149: V/SyncTestActivity(32369): (1001) performAction: LOAD [device=1, tMs=1000, data=null, delay=0]
    04-27 10:58:08.089: V/SyncTestActivity(32369): (2941) loaded: ''
    04-27 10:58:21.149: V/SyncTestActivity(32369): (16000) performAction: SAVE [device=1, tMs=16000, data=1, delay=0]
    04-27 10:58:22.159: D/BlockingSyncer(32369): loaded before saving: 
    04-27 10:58:22.159: D/SyncTestActivity(32369): merging  and 1
    04-27 10:58:22.159: D/BlockingSyncer(32369): merged with local data before saving: 1.0
    04-27 10:58:22.619: V/SyncTestActivity(32369): (17474) saved: '1.0'
    04-27 10:58:41.149: V/SyncTestActivity(32369): (36000) performAction: LOAD [device=1, tMs=36000, data=null, delay=0]
    04-27 10:58:42.129: V/SyncTestActivity(32369): (36982) loaded: '1.0'
    04-27 10:59:01.149: V/SyncTestActivity(32369): (56001) performAction: LOAD [device=1, tMs=56000, data=null, delay=0]
    04-27 10:59:03.569: V/SyncTestActivity(32369): (58425) loaded: '2.0'
    04-27 10:59:03.579: V/SyncTestActivity(32369): (58430) done
    
    Device2:
    04-27 10:58:05.128: V/SyncTestActivity(15276): Own entries.size: 4
    04-27 10:58:06.132: V/SyncTestActivity(15276): (1002) performAction: LOAD [device=2, tMs=1000, data=null, delay=0]
    04-27 10:58:07.253: V/SyncTestActivity(15276): (2124) loaded: ''
    04-27 10:58:21.132: V/SyncTestActivity(15276): (16000) performAction: SAVE [device=2, tMs=16000, data=2, delay=0]
    04-27 10:58:22.347: D/BlockingSyncer(15276): loaded before saving: 
    04-27 10:58:22.351: D/SyncTestActivity(15276): merging  and 2
    04-27 10:58:22.355: D/BlockingSyncer(15276): merged with local data before saving: 2.0
    04-27 10:58:23.015: V/SyncTestActivity(15276): (17884) saved: '2.0'
    04-27 10:58:41.128: V/SyncTestActivity(15276): (36000) performAction: LOAD [device=2, tMs=36000, data=null, delay=0]
    04-27 10:58:45.390: D/BlockingSyncer(15276): conflict detected
    04-27 10:58:45.429: D/SyncTestActivity(15276): merging 1.0 and 2.0
    04-27 10:58:49.203: V/SyncTestActivity(15276): (44067) loaded: '2.0'
    04-27 10:59:01.128: V/SyncTestActivity(15276): (56000) performAction: LOAD [device=2, tMs=56000, data=null, delay=0]
    04-27 10:59:02.417: V/SyncTestActivity(15276): (57288) loaded: '2.0'
    04-27 10:59:02.460: V/SyncTestActivity(15276): (57328) done
    
    Different results at first load (does not fix at second load):
    ==============================================================
    Device1:
    04-27 11:44:18.199: V/SyncTestActivity(2714): Own entries.size: 4
    04-27 11:44:19.199: V/SyncTestActivity(2714): (999) performAction: LOAD [device=1, tMs=1000, data=null, delay=0]
    04-27 11:44:21.399: V/SyncTestActivity(2714): (3200) loaded: ''
    04-27 11:44:34.199: V/SyncTestActivity(2714): (16000) performAction: SAVE [device=1, tMs=16000, data=1, delay=0]
    04-27 11:44:35.049: D/BlockingSyncer(2714): loaded before saving: 
    04-27 11:44:35.049: D/SyncTestActivity(2714): merging  and 1
    04-27 11:44:35.049: D/BlockingSyncer(2714): merged with local data before saving: 1.0
    04-27 11:44:35.509: V/SyncTestActivity(2714): (17312) saved: '1.0'
    04-27 11:44:46.199: V/SyncTestActivity(2714): (27999) performAction: LOAD [device=1, tMs=28000, data=null, delay=0]
    04-27 11:44:47.099: V/SyncTestActivity(2714): (28896) loaded: '1.0'
    04-27 11:44:58.199: V/SyncTestActivity(2714): (40000) performAction: LOAD [device=1, tMs=40000, data=null, delay=0]
    04-27 11:44:59.329: V/SyncTestActivity(2714): (41127) loaded: '1.0'
    04-27 11:44:59.329: V/SyncTestActivity(2714): (41129) done
    
    Device2:
    04-27 11:44:18.148: V/SyncTestActivity(18064): Own entries.size: 4
    04-27 11:44:19.148: V/SyncTestActivity(18064): (1000) performAction: LOAD [device=2, tMs=1000, data=null, delay=0]
    04-27 11:44:25.445: V/SyncTestActivity(18064): (7295) loaded: ''
    04-27 11:44:34.152: V/SyncTestActivity(18064): (16001) performAction: SAVE [device=2, tMs=16000, data=2, delay=0]
    04-27 11:44:36.144: D/BlockingSyncer(18064): loaded before saving: 
    04-27 11:44:36.156: D/SyncTestActivity(18064): merging  and 2
    04-27 11:44:36.171: D/BlockingSyncer(18064): merged with local data before saving: 2.0
    04-27 11:44:37.214: V/SyncTestActivity(18064): (19066) saved: '2.0'
    04-27 11:44:46.167: V/SyncTestActivity(18064): (28020) performAction: LOAD [device=2, tMs=28000, data=null, delay=0]
    04-27 11:44:52.429: D/BlockingSyncer(18064): conflict detected
    04-27 11:44:52.457: D/SyncTestActivity(18064): merging 1.0 and 2.0
    04-27 11:44:56.949: V/SyncTestActivity(18064): (38798) loaded: '2.0'
    04-27 11:44:58.152: V/SyncTestActivity(18064): (40001) performAction: LOAD [device=2, tMs=40000, data=null, delay=0]
    04-27 11:44:59.371: V/SyncTestActivity(18064): (41220) loaded: '2.0'
    04-27 11:44:59.414: V/SyncTestActivity(18064): (41266) done
    
    
    Both wrong
    ==========
    Device1:
    04-27 12:10:36.689: V/SyncTestActivity(2714): Own entries.size: 4
    04-27 12:10:37.689: V/SyncTestActivity(2714): (1000) performAction: LOAD [device=1, tMs=1000, data=null, delay=0]
    04-27 12:10:38.379: V/SyncTestActivity(2714): (1695) loaded: ''
    04-27 12:10:52.689: V/SyncTestActivity(2714): (15999) performAction: SAVE [device=1, tMs=16000, data=1, delay=0]
    04-27 12:10:53.479: D/BlockingSyncer(2714): loaded before saving: 
    04-27 12:10:53.479: D/SyncTestActivity(2714): merging  and 1
    04-27 12:10:53.479: D/BlockingSyncer(2714): merged with local data before saving: 1.0
    04-27 12:10:54.009: V/SyncTestActivity(2714): (17326) saved: '1.0'
    04-27 12:11:04.689: V/SyncTestActivity(2714): (27999) performAction: LOAD [device=1, tMs=28000, data=null, delay=0]
    04-27 12:11:05.759: V/SyncTestActivity(2714): (29070) loaded: '1.0'
    04-27 12:11:16.689: V/SyncTestActivity(2714): (40000) performAction: LOAD [device=1, tMs=40000, data=null, delay=0]
    04-27 12:11:17.629: V/SyncTestActivity(2714): (40939) loaded: '1.0'
    04-27 12:11:17.629: V/SyncTestActivity(2714): (40940) done
    
    Device2:
    04-27 12:10:36.824: V/SyncTestActivity(1561): Own entries.size: 4
    04-27 12:10:37.824: V/SyncTestActivity(1561): (1000) performAction: LOAD [device=2, tMs=1000, data=null, delay=0]
    04-27 12:10:41.664: V/SyncTestActivity(1561): (4820) loaded: ''
    04-27 12:10:52.824: V/SyncTestActivity(1561): (16000) performAction: SAVE [device=2, tMs=16000, data=2, delay=0]
    04-27 12:10:55.507: D/BlockingSyncer(1561): loaded before saving: 
    04-27 12:10:55.507: D/SyncTestActivity(1561): merging  and 2
    04-27 12:10:55.507: D/BlockingSyncer(1561): merged with local data before saving: 2.0
    04-27 12:10:55.933: V/SyncTestActivity(1561): (19109) saved: '2.0'
    04-27 12:11:04.824: V/SyncTestActivity(1561): (28000) performAction: LOAD [device=2, tMs=28000, data=null, delay=0]
    04-27 12:11:08.753: V/SyncTestActivity(1561): (31929) loaded: '1.0'
    04-27 12:11:16.824: V/SyncTestActivity(1561): (40001) performAction: LOAD [device=2, tMs=40000, data=null, delay=0]
    04-27 12:11:19.167: V/SyncTestActivity(1561): (42343) loaded: '1.0'
    04-27 12:11:19.167: V/SyncTestActivity(1561): (42344) done
    

    The code for my tests can be found in the following two files: Activity:

    public class SyncTestActivity extends Activity {
        private static final String TAG = SyncTestActivity.class.getSimpleName();
    
        private enum Action {
            SAVE, LOAD
        }
    
        private static class Entry {
            public final int deviceId;
            public final int timeMs;
            public final Action action;
            public final String data;
            public final int readToWriteDelay;
    
            private Entry(int deviceId, int timeMs, Action action, String data, int readToWriteDelay) {
                this.deviceId = deviceId;
                this.timeMs = timeMs;
                this.action = action;
                this.data = data;
                this.readToWriteDelay = readToWriteDelay;
            }
    
            public static Entry load(int deviceId, int timeS) {
                return new Entry(deviceId, timeS, Action.LOAD, null, 0);
            }
    
            public static Entry save(int deviceId, int timeS, String data, int readToWriteDelay) {
                return new Entry(deviceId, timeS, Action.SAVE, data, readToWriteDelay);
            }
    
            @Override
            public String toString() {
                return action + " [device=" + deviceId + ", tMs=" + timeMs + ", data=" + data
                    + ", delay=" + readToWriteDelay + "]";
            }
    
        }
    
        public interface Callback<T> {
            void done(T result);
        }
    
        public interface ConflictResolver {
            byte[] resolveConflict(byte[] bytes1, byte[] bytes2);
        }
    
        public interface IsSyncer {
            void load(Callback<byte[]> callback);
            void save(byte[] data, int readToWriteDelay, Callback<byte[]> callback);
        }
    
        private final static ConflictResolver CONFLICT_RESOLVER = new ConflictResolver() {
    
            @Override
            public byte[] resolveConflict(byte[] bytes1, byte[] bytes2) {
                try {
                    String s1 = new String(bytes1, "UTF-8");
                    String s2 = new String(bytes2, "UTF-8");
    
                    Log.d(TAG, "merging " + s1 + " and " + s2);
    
                    double d1 = toDouble(s1);
                    double d2 = toDouble(s2);
    
                    return Double.toString(Math.max(d1, d2)).getBytes("UTF-8");
                } catch (UnsupportedEncodingException e) {
                    throw new RuntimeException(e);
                }
            }
    
            private double toDouble(String s) {
                return s.isEmpty() ? 0 : Double.parseDouble(s);
            }
    
        };
    
        @SuppressLint("SimpleDateFormat")
        private final static SimpleDateFormat df = new SimpleDateFormat("HH:mm:ss.SSS");
    
        private EditText editDeviceId;
        private Button start;
        private Button stop;
        private Button reset;
        private TextView output;
    
        private List<Entry> entries;
        private StringBuilder sb = new StringBuilder();
        private GameHelper gameHelper;
    
        private IsSyncer syncer;
        private IsSyncer resetter;
    
        private AsyncTask<Void, Void, Void> asyncTask;
        private Long startTimeMs;
    
    
        public SyncTestActivity() {
            entries = createEntries();
        }
    
        private List<Entry> createEntries() {
            List<Entry> entries = new ArrayList<Entry>();
    
            int t = 1000;
            entries.add(Entry.load(1, t));
            entries.add(Entry.load(2, t));
    
            t += 15 * 1000;
            entries.add(Entry.save(1, t, "1", 0));
            entries.add(Entry.save(2, t, "2", 0));
    
            t += 12 * 1000;
            entries.add(Entry.load(1, t));
            entries.add(Entry.load(2, t));
    
            t += 12 * 1000;
            entries.add(Entry.load(1, t));
            entries.add(Entry.load(2, t));
    
            return entries;
        }
    
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_synctest);
    
            editDeviceId = (EditText) findViewById(R.id.device_id);
            start = (Button) findViewById(R.id.start);
            stop = (Button) findViewById(R.id.stop);
            reset = (Button) findViewById(R.id.reset);
            output = (TextView) findViewById(R.id.output);
    
            start.setOnClickListener(new OnClickListener() {
                @Override
                public void onClick(View v) {
                    start();
                }
            });
    
            stop.setOnClickListener(new OnClickListener() {
                @Override
                public void onClick(View v) {
                    stop();
                }
            });
    
            reset.setOnClickListener(new OnClickListener() {
                @Override
                public void onClick(View v) {
                    reset();
                }
            });
    
            initSocial();
        }
    
        private void initSocial() {
            GameHelperListener signInListener = new GameHelperListener() {
    
                @Override
                public void onSignInSucceeded() {
                    Log.v(TAG, "signed in");
                }
    
                @Override
                public void onSignInFailed() {
                    Log.v(TAG, "signin failed");
                }
            };
    
            gameHelper = new GameHelper(this, GameHelper.CLIENT_GAMES | GameHelper.CLIENT_APPSTATE
                | GameHelper.CLIENT_SNAPSHOT);
            gameHelper.enableDebugLog(true);
            gameHelper.setup(signInListener);
            gameHelper.onStart(this);
    
            GoogleApiClient apiClient = gameHelper.getApiClient();
    
            syncer = new BlockingSyncer(apiClient, CONFLICT_RESOLVER);
            resetter = new BlockingSyncer(apiClient, null);
        }
    
        private void start() {
            logState();
            if (!gameHelper.getApiClient().isConnected()) {
                Toast.makeText(this, "Not connected", Toast.LENGTH_LONG).show();
                return;
            }
            int deviceId;
            try {
                deviceId = Integer.parseInt(editDeviceId.getText().toString());
            } catch (NumberFormatException e) {
                Toast.makeText(this, "Please enter a valid device-id", Toast.LENGTH_LONG).show();
                return;
            }
            final List<Entry> ownEntries = getOwnEntries(deviceId);
            Log.v(TAG, "Own entries.size: " + ownEntries.size());
            if (ownEntries.isEmpty()) {
                Toast.makeText(this, "No entries", Toast.LENGTH_LONG).show();
                return;
            }
            start(ownEntries);
        }
    
        private void start(final List<Entry> ownEntries) {
            final long startTime = System.nanoTime();
            startTimeMs = startTime / (long)1e6;
            asyncTask = new AsyncTask<Void, Void, Void>() {
                @Override
                protected Void doInBackground(Void... params) {
                    processEntries(ownEntries, startTime);
                    return null;
                }
            };
            asyncTask.execute();
        }
    
        private void processEntries(final List<Entry> ownEntries, final long startTime) {
            for (int i = 0; i < ownEntries.size(); i++) {
                if (isAborted()) {
                    break;
                }
                Entry entry = ownEntries.get(i);
                long entryTime = entry.timeMs * (long)1e6 + startTime;
                long now = System.nanoTime();
                long sleepMs = (entryTime - now) / (long)1e6;
                try {
                    Thread.sleep(sleepMs);
                } catch (InterruptedException e) {
                    Log.w(TAG, e);
                    break;
                } catch (IllegalArgumentException e) {
                    Log.v(TAG, "sleepMs: " + sleepMs);
                    throw e;
                }
                performAction(entry);
            }
            append("done");
            startTimeMs = null;
        }
    
        private boolean isAborted() {
            if (asyncTask != null) {
                return asyncTask.isCancelled();
            }
            return false;
        }
    
    
        private void logState() {
            Log.v(TAG, "isSignedIn: "+ gameHelper.isSignedIn());
            Log.v(TAG, "isConnected: "+ gameHelper.getApiClient().isConnected());
            Log.v(TAG, "isConnecting: "+ gameHelper.isConnecting());
            Log.v(TAG, "isConnecting: "+ gameHelper.getApiClient().isConnecting());
        }
    
        private void performAction(final Entry entry) {
            append("performAction: " + entry);
            if (entry.action == Action.LOAD) {
                performLoad();
            } else if (entry.action == Action.SAVE) {
                performSave(entry);
            }
        }
    
        private void performSave(Entry entry) {
            syncer.save(convertToBytes(entry.data), entry.readToWriteDelay, new Callback<byte[]>() {
                    @Override
                    public void done(byte[] data) {
                        append("saved: '" + convertToString(data) + "'");
                    }
                });
        }
    
        private void performLoad() {
            syncer.load(new Callback<byte[]>() {
                @Override
                public void done(byte[] data) {
                    append("loaded: '" + convertToString(data) + "'");
                }
            });
        }
    
        private void append(String string) {
            string = timeOffsetString() + string;
            Log.v(TAG, string);
            sb.append(df.format(new Date()) + ": " + string + "\n");
            update();
        }
    
        private String timeOffsetString() {
            if (startTimeMs == null) {
                return "";
            }
            long nowMs = System.nanoTime() / (long)1e6;
            return "(" + (nowMs - startTimeMs) + ") ";
        }
    
        private void update() {
            runOnUiThread(new Runnable() {
                @Override
                public void run() {
                    output.setText(sb.toString());
                }
            });
        }
    
        private List<Entry> getOwnEntries(int deviceId) {
            List<Entry> result = new ArrayList<Entry>();
            for (Entry entry: entries) {
                if (entry.deviceId == deviceId) {
                    result.add(entry);
                }
            }
            return result;
        }
    
        private void stop() {
            logState();
            if (!gameHelper.getApiClient().isConnected()) {
                Toast.makeText(this, "Not connected", Toast.LENGTH_LONG).show();
                return;
            }
    
            if (asyncTask != null) {
                asyncTask.cancel(true);
            }
        }
    
        private void reset() {
            sb.setLength(0);
            append("deleting (writing default-instance)...");
            // it seems delete is buggy (loads can later fail for a while)
            new AsyncTask<Void, Void, Void>() {
                @Override
                protected Void doInBackground(Void... params) {
                    resetter.save(convertToBytes(""), 0,
                        new Callback<byte[]>() {
                            @Override
                            public void done(byte[] data) {
                                append("deletion done. saved: '" + convertToString(data) + "'");
                            }
                        });
                    return null;
                }
            }.execute();
    
            append("user: " + Games.Players.getCurrentPlayer(gameHelper.getApiClient()).getDisplayName());
        }
    
        @Override
        protected void onActivityResult(int request, int response, Intent data) {
            super.onActivityResult(request, response, data);
            gameHelper.onActivityResult(request, response, data);
        }
    
        private static String convertToString(byte[] data) {
            try {
                return new String(data, "UTF-8");
            } catch (UnsupportedEncodingException e) {
                throw new RuntimeException(e);
            }
        }
    
        private static byte[] convertToBytes(String data) {
            try {
                return data.getBytes("UTF-8");
            } catch (UnsupportedEncodingException e) {
                throw new RuntimeException(e);
            }
        }
    
    }
    
    

    Cloud-save logic:

    public class BlockingSyncer implements IsSyncer {
        private final static String TAG = BlockingSyncer.class.getSimpleName();
    
        private final static int MAX_RETRIES = 5;
        private final static String NAME = "savegame";
    
        private final GoogleApiClient client;
        private final ConflictResolver conflictResolver;
        private final int resolutionPolicy;
    
        public BlockingSyncer(GoogleApiClient client, ConflictResolver conflictResolver) {
            this.client = client;
            this.conflictResolver = conflictResolver;
            this.resolutionPolicy = conflictResolver == null ? Snapshots.RESOLUTION_POLICY_MOST_RECENTLY_MODIFIED
                : Snapshots.RESOLUTION_POLICY_MANUAL;
        }
    
        @Override
        public void load(Callback<byte[]> callback) {
            OpenSnapshotResult openResult = getResolvedOpenResult();
            try {
                byte[] data = openResult.getSnapshot().getSnapshotContents().readFully();
                callback.done(data);
            } catch (IOException e) {
                throw new RuntimeException(e);
            }
        }
    
        private OpenSnapshotResult getResolvedOpenResult() {
            OpenSnapshotResult result = Games.Snapshots.open(client, NAME, true, resolutionPolicy).await();
            int retryCount = 0;
            while (!result.getStatus().isSuccess() && retryCount++ < MAX_RETRIES) {
                if (result.getStatus().getStatusCode() != GamesStatusCodes.STATUS_SNAPSHOT_CONFLICT) {
                    throw new IllegalStateException("Unexpected status code: "
                        + result.getStatus().getStatusCode());
                }
                if (conflictResolver == null) {
                    throw new IllegalStateException("Conflict despite automatic conflict resolution");
                }
    
                Log.d(TAG, "conflict detected");
    
                result.getResolutionSnapshotContents().writeBytes(mergeData(result));
    
                String snapshotId = result.getSnapshot().getMetadata().getSnapshotId();
                checkState(result.getConflictingSnapshot().getMetadata().getSnapshotId().equals(snapshotId));
    
                result = Games.Snapshots.resolveConflict(client, result.getConflictId(), snapshotId,
                    SnapshotMetadataChange.EMPTY_CHANGE, result.getResolutionSnapshotContents()).await();
            }
    
            if (!result.getStatus().isSuccess()) {
                throw new IllegalStateException("Couldn't resolve conflicts");
            }
            return result;
        }
    
        private byte[] mergeData(OpenSnapshotResult result) {
            checkState(conflictResolver != null);
            try{
                byte[] d1 = result.getSnapshot().getSnapshotContents().readFully();
                byte[] d2 = result.getConflictingSnapshot().getSnapshotContents().readFully();
                return conflictResolver.resolveConflict(d1, d2);
            } catch (IOException e) {
                throw new RuntimeException(e);
            }
        }
    
        @Override
        public void save(byte[] data, int readToWriteDelay, Callback<byte[]> callback) {
            OpenSnapshotResult result = getResolvedOpenResult();
            try {
                byte[] loaded = result.getSnapshot().getSnapshotContents().readFully();
                Log.d(TAG, "loaded before saving: " + new String(loaded));
                if (conflictResolver != null) {
                    data = conflictResolver.resolveConflict(loaded, data);
                }
                Log.d(TAG, "merged with local data before saving: " + new String(data));
    
                // just for testing
                try {
                    Thread.sleep(readToWriteDelay);
                } catch (InterruptedException e) {
                    Log.w(TAG, e);
                    return;
                }
    
                result.getSnapshot().getSnapshotContents().writeBytes(data);
                CommitSnapshotResult commitResult = Games.Snapshots.commitAndClose(client, result.getSnapshot(), SnapshotMetadataChange.EMPTY_CHANGE).await();
                if (!commitResult.getStatus().isSuccess()) {
                    throw new IllegalStateException("failed to commit: " + commitResult.getStatus());
                }
                callback.done(data);
            } catch (IOException e) {
                throw new RuntimeException(e);
            }
        }
    
        private void checkState(boolean state) {
            if (!state) {
                throw new IllegalStateException();
            }
        }
    
    }
    
    opened by kuhnmi 17
  • IllegalStateException  @ GamesClientImpl.zzb

    IllegalStateException @ GamesClientImpl.zzb

    I'm using android game services 11.8.0 and my users get the following crash without message. The stack trace is reported in google play developer console and I have no idea how to reproduce it:

    java.lang.IllegalStateException: at com.google.android.gms.common.internal.zzbq.zza (Unknown Source) at com.google.android.gms.games.internal.GamesClientImpl.zzb (Unknown Source) at com.google.android.gms.common.internal.zzab. (Unknown Source) at com.google.android.gms.common.internal.zzab. (Unknown Source) at com.google.android.gms.games.internal.GamesClientImpl. (Unknown Source) at com.google.android.gms.games.Games$zzb.zza (Unknown Source) at com.google.android.gms.common.api.GoogleApi.zza (Unknown Source) at com.google.android.gms.common.api.internal.zzbo. (Unknown Source) at com.google.android.gms.common.api.internal.zzbm.zzb (Unknown Source) at com.google.android.gms.common.api.internal.zzbm.handleMessage (Unknown Source) at android.os.Handler.dispatchMessage (Handler.java:98) at android.os.Looper.loop (Looper.java:148) at android.os.HandlerThread.run (HandlerThread.java:61)

    opened by trimax-items 15
  • new gamehelper bug detected in sign in

    new gamehelper bug detected in sign in

    onstart the intent to choose the account appears over and over y don't connect never.

    the same goes in the method beginUserInitiatedSignIn.

    with the previous version did not have this problem.

    02-19 02:01:14.591: D/GameHelper(9425): GameHelper: Setup: requested clients: 1 02-19 02:01:14.621: D/GameHelper(9425): GameHelper: onStart 02-19 02:01:14.621: D/GameHelper(9425): GameHelper: Connecting client. 02-19 02:01:15.442: D/GameHelper(9425): GameHelper: onConnectionFailed 02-19 02:01:15.442: D/GameHelper(9425): GameHelper: Connection failure: 02-19 02:01:15.442: D/GameHelper(9425): GameHelper: - code: SIGN_IN_REQUIRED(4) 02-19 02:01:15.442: D/GameHelper(9425): GameHelper: - resolvable: true 02-19 02:01:15.442: D/GameHelper(9425): GameHelper: - details: ConnectionResult{statusCode=SIGN_IN_REQUIRED, resolution=PendingIntent{40515c60: android.os.BinderProxy@40551f90}} 02-19 02:01:15.442: D/GameHelper(9425): GameHelper: onConnectionFailed: WILL resolve because we have below the max# of attempts, 0 < 3 02-19 02:01:15.442: D/GameHelper(9425): GameHelper: onConnectionFailed: resolving problem... 02-19 02:01:15.442: D/GameHelper(9425): GameHelper: resolveConnectionResult: trying to resolve result: ConnectionResult{statusCode=SIGN_IN_REQUIRED, resolution=PendingIntent{40515c60: android.os.BinderProxy@40551f90}} 02-19 02:01:15.442: D/GameHelper(9425): GameHelper: Result has resolution. Starting it. 02-19 02:01:21.108: D/GameHelper(9425): GameHelper: onStop 02-19 02:01:21.108: D/GameHelper(9425): GameHelper: Client already disconnected when we got onStop. 02-19 02:01:46.973: D/GameHelper(9425): GameHelper: onStart

    opened by ironiko 14
  • Repeated exception causing high battery drain by Google Play Services

    Repeated exception causing high battery drain by Google Play Services

    PID 3250, com.google.android.gms.persistent logs this almost once per second. Uninstalling/reinstalling updates of Google Play Services seems to have fixed it for the time being.

    E/SQLiteLog( 3250): (2067) abort at 35 in [INSERT INTO context(context_name,end_time,context_family,module_id,version,sync_state_mod_time_millis,start_time,sync_state,context_id,time_type,proto_blob) VALUES (?,?,?,?,?,?,?,?,?,?,?)]: UNI I/Babel ( 5969): RTCS will handle all server updates. E/SQLiteDatabase( 3250): Error inserting context_name=6 end_time=1443720116002 context_family=1 module_id=com.google.android.contextmanager.module.DetectedActivityProducer version=1 sync_state_mod_time_millis=1443720116026 start_time=1443720109438 sync_state=0 context_id=12459098-4795-453e-b26b-e89b270f2fd6 time_type=3 proto_blob=[B@3a0a1697 E/SQLiteDatabase( 3250): android.database.sqlite.SQLiteConstraintException: UNIQUE constraint failed: context.context_id (code 2067) E/SQLiteDatabase( 3250): at android.database.sqlite.SQLiteConnection.nativeExecuteForLastInsertedRowId(Native Method) E/SQLiteDatabase( 3250): at android.database.sqlite.SQLiteConnection.executeForLastInsertedRowId(SQLiteConnection.java:782) E/SQLiteDatabase( 3250): at android.database.sqlite.SQLiteSession.executeForLastInsertedRowId(SQLiteSession.java:788) E/SQLiteDatabase( 3250): at android.database.sqlite.SQLiteStatement.executeInsert(SQLiteStatement.java:86) E/SQLiteDatabase( 3250): at android.database.sqlite.SQLiteDatabase.insertWithOnConflict(SQLiteDatabase.java:1471) E/SQLiteDatabase( 3250): at android.database.sqlite.SQLiteDatabase.insert(SQLiteDatabase.java:1341) E/SQLiteDatabase( 3250): at com.google.android.contextmanager.q.al.a(SourceFile:408) E/SQLiteDatabase( 3250): at com.google.android.contextmanager.q.al.b(SourceFile:383) E/SQLiteDatabase( 3250): at com.google.android.contextmanager.q.al.a(SourceFile:349) E/SQLiteDatabase( 3250): at com.google.android.contextmanager.q.al.b(SourceFile:376) E/SQLiteDatabase( 3250): at com.google.android.contextmanager.g.a.j.a(SourceFile:58) E/SQLiteDatabase( 3250): at com.google.android.contextmanager.g.a.a.run(SourceFile:52) E/SQLiteDatabase( 3250): at com.google.android.contextmanager.g.i.handleMessage(SourceFile:215) E/SQLiteDatabase( 3250): at android.os.Handler.dispatchMessage(Handler.java:102) E/SQLiteDatabase( 3250): at android.os.Looper.loop(Looper.java:135) E/SQLiteDatabase( 3250): at android.os.HandlerThread.run(HandlerThread.java:61)

    opened by scoof 11
  • No way of retrieving the url of a video recorded

    No way of retrieving the url of a video recorded

    Hello, Currently the play services recording api has no means to retrieve the url of the shared video. We plan to incentivize users to record their play but it is mandatory that we can : 1-Get confirmation of the share. 2-Get the actual url of the share so that we can create a sort of leaderboard with the recording of the best players.

    Please add such feature to the service.

    Thanks Regards Chris

    opened by 00christian00 10
  • IllegalStateException when recreating Google Play Activities

    IllegalStateException when recreating Google Play Activities

    When the user is on a Play Activity (eg the achievements activity), closes the game and restarts the app the following exception occurs:

    08-03 13:07:58.084: E/AndroidRuntime(32096): java.lang.IllegalStateException: GameHelper: operation attempted at incorrect state. Operation: connectCurrentClient. State: DISCONNECTED. Expected state: CONNECTING.
    08-03 13:07:58.084: E/AndroidRuntime(32096):    at com.google.example.games.basegameutils.GameHelper.assertState(GameHelper.java:187)
    08-03 13:07:58.084: E/AndroidRuntime(32096):    at com.google.example.games.basegameutils.GameHelper.connectCurrentClient(GameHelper.java:696)
    08-03 13:07:58.084: E/AndroidRuntime(32096):    at com.google.example.games.basegameutils.GameHelper.connectNextClient(GameHelper.java:692)
    08-03 13:07:58.084: E/AndroidRuntime(32096):    at com.google.example.games.basegameutils.GameHelper.onConnected(GameHelper.java:771)
    08-03 13:07:58.084: E/AndroidRuntime(32096):    at com.google.android.gms.internal.p.k(Unknown Source)
    

    (the line numbers in the stack trace don't match exactly)

    In addition to starting the Google Play Activity, the app also initiates the regular background sign in for the user.

    Maybe the Helper can not deal with this "double sign in"?

    I am running the very latest GameHelper class from master.

    bug 
    opened by mpost 10
  • GameHelper incorrect signin state after signout from within Google Default UI

    GameHelper incorrect signin state after signout from within Google Default UI

    If signout is made from within Google Default UI (eg. click achievements, then settings, then signout) then the outer layers of the code thinks it is signed in, but the inner layers throws exception on pretty much any action except reconnectClient, because the inner layer knows that it is signed out.

    So after signing out from within default ui:

    • mGoogleApiClient.isConnected() returns true (and therefore BaseGameActivity+GameHelper.isSignedIn() returns true)
    • GameHelper.signOut crashes (I think) with already signed out
    • GameHelper.beginUserInitiatedSignIn does nothing because it thinks its already signed in
    • Starting Intent to show Achievements or leaderboards throws SecurityException.

    It seems the problem might be that mGoogleApiClient is left in a bad state, so I tried setting it to null, and running setup again creating a new object. That worked and I could do new login and show achievements and leaderboards, but once I exit the activity and start it again, a new signin is made to Google Apis, and then it crashes with bad channel or something. I guess this just shows that we (non-Googlers) shouldn't try to modify the GameHelper flow, because we don't know the secret rules of the underlying layer, but I guess that's fine.

    What did work is catching the SecurityException from showAchievements and then do reconnect client, and from Listener.onSignInSucceeded do showAchievements again. It would be nice with some (Java)Doc telling me this was a usecase for reconnectClient. I'm not sure I have circumvented all problems by this approach, but I have not yet discovered any new crashes.

    Best Alex

    opened by arberg 9
  • Some multi-player sessions see zero received messages (reliable/unreliable)

    Some multi-player sessions see zero received messages (reliable/unreliable)

    When I test a 1 vs 1 real time game, pretty much half of the sessions, there is no data received after the room is connected and kicks off.

    I captured a device log of a session where the communication was not successful, despite a successful ShowRoomUI.

    ~~It looks like the earliest sign of problems is in 'UDP bind failed with error 22'~~ ~~Any idea what could be the cause of this, and what is the meaning of error 22?~~

    It looks like the earliest sign of trouble is that RoomServiceStateMachine attempts a reconnection.

    I/RoomServiceStateMachine( 7398): Attempting to reconnect to: p_CJiO4I6oysDA5wEQAQ
    

    thanks,

    bram

    I/libjingle( 7398): Attempting to create a session, with data only.
    I/libjingle( 7398): CompleteInitiateCall_w:[email protected]/games_andr3812DFE4
    I/libjingle( 7398): void gtalk::LibjingleClient::OnCallCreate(cricket::Call*): Connecting to OnAddSession
    E/libjingle( 7398): Error(mediasession.cc:529): cricket::SessionDescription* cricket::MediaSessionDescriptionFactory::CreateOffer(const cricket::MediaSessionOptions&, const cricket::SessionDescription*): Creating Data offer.
    I/libjingle( 7398): AddSession() called. has_data = 1
    I/libjingle( 7398): Creating data channel.
    I/libjingle( 7398): Is worker current:0
    I/libjingle( 7398): Current thread:0x7a5f22d8
    I/libjingle( 7398): worker_thread:0x7a6795a0 initialized=1
    I/libjingle( 7398): Created channel for data
    I/libjingle( 7398): DataChannel::Init() called
    I/libjingle( 7398): result = 1
    D/dalvikvm(13146): DexOpt: unable to opt direct call 0x0083 at 0x86 in Lcom/google/android/gms/games/ui/client/ClientFragmentActivity;.instantiateGoogleApiClient
    I/libjingle( 7398): void gtalk::LibjingleClient::OnAddSession(cricket::Call*, cricket::Session*): OnAddSession called.
    I/swaag   (13059): Participant Status Changed. Valid=1
    I/swaag   (13059): Participant id p_CJiO4I6oysDA5wEQAQ, name Player 7806
    I/libjingle( 7398): Setting local data description
    I/libjingle( 7398): Added data send stream '' with ssrc=542955133
    I/libjingle( 7398): Add send ssrc: 542955133
    I/libjingle( 7398): Changing data state, recv=0 send=0
    I/libjingle( 7398): Channel enabled
    I/libjingle( 7398): Changing data state, recv=1 send=0
    I/libjingle( 7398): Network Information: All networks
    I/libjingle( 7398): Name, Description, Prefix, Prefix Length, IP, ignored
    I/libjingle( 7398): ipv4-default default IPV4 network 0.0.0.0 32 10.0.1.27 0
    I/libjingle( 7398): wlan0 wlan0 10.0.1.0 24 10.0.1.27 0
    I/libjingle( 7398): p2p0 p2p0 fe80:: 64 fe80::485a:3fff:fe5d:dd44 0
    I/libjingle( 7398): wlan0 wlan0 fe80:: 64 fe80::4a5a:3fff:fe5d:dd44 0
    I/libjingle( 7398): 
    I/swaag   (13059): Room Status Changed to 2.
    I/libjingle( 7398): HttpRequest start: relay.google.com/create_session?username=F5YYr1CDXdEsjPSn&password=Ks4ng024KHDGjFHer%2fWN%2bhML&sn=3
    I/libjingle( 7398): SSL Cleanup
    E/libjingle( 7398): Error(basicpacketsocketfactory.cc:67): UDP bind failed with error 22
    E/libjingle( 7398): Error(basicpacketsocketfactory.cc:67): UDP bind failed with error 22
    E/libjingle( 7398): Error(basicpacketsocketfactory.cc:67): UDP bind failed with error 22
    E/libjingle( 7398): Error(basicpacketsocketfactory.cc:67): UDP bind failed with error 22
    I/libjingle( 7398): OpenSSLAdapter::OnConnectEvent
    I/libjingle( 7398): BeginSSL: relay.google.com
    I/libjingle( 7398): Parsing Jingle data content
    I/libjingle( 7398): Setting remote data description
    I/libjingle( 7398): Added data recv stream '' with ssrc=2192033831
    I/libjingle( 7398): Add remote ssrc: 2192033831
    I/libjingle( 7398): SRTP reset to init state
    I/libjingle( 7398): DataMediaChannel::SetSendBandwidth to 10485000bps.
    I/libjingle( 7398): Changing data state, recv=1 send=0
    D/dalvikvm(13146): Note: class Lcom/google/android/gms/games/internal/IGamesService$Stub; has 202 unimplemented (abstract) methods
    I/WaitingRoom(13146): Room status after registering listener: 2
    I/libjingle( 7398): HttpRequest completed successfully
    I/libjingle( 7398): SSL Cleanup
    I/libjingle( 7398): Channel socket writable (data_rtp) for the first time
    I/libjingle( 7398): Changing data state, recv=1 send=1
    I/swaag   (13059): P2P Connected.
    I/swaag   (13059): Connected Set Changed. Currently connected: 2
    I/swaag   (13059): Connected Set Changed. Currently connected: 2
    I/WaitingRoom(13146): CALLBACK: onRoomConnected()...
    I/WaitingRoom(13146): onRoomConnected: statusCode = 0 for room ID: ChoKCQj1jOXnmhsQAhABGAAg____________ARCeuIisweyEgU0
    I/swaag   (13059): CMD_GAINED_FOCUS handled
    D/BuggyActivity(13059): onActivityResult(4673607,-1,Intent { (has extras) }
    V/GamesNativeSDK(13059): Received OnActivityResult with result_code: -1
    V/GamesNativeSDK(13059): Received Activity Resume Event.
    I/swaag   (13059): Succesfully showed room (created by Bram Stolk): (null)
    I/swaag   (13059): Participant 0: Player 7806 (p_CJiO4I6oysDA5wEQAQ)
    I/swaag   (13059): Participant 1: Bram Stolk (p_CJ64iKzB7ISBTRAB)
    E/GamesNativeSDK(13059): Sending reliable message
    E/GamesNativeSDK(13059): Sending reliable message SUCCEEDED
    I/swaag   (13059): Starting round 0 with map 0
    I/swaag   (13059): geomdb cleared of 0 entries (0 evicted from cache).
    I/swaag   (13059): world created for level -1
    I/swaag   (13059): objectOfInterest at 0x7c375dc8 named 'player'
    I/swaag   (13059): CMD_RESUME handled
    D/ChimeraCfgMgr( 1856): Loading module com.google.android.gms.games from APK com.google.android.play.games
    D/ChimeraModuleLdr( 1856): Module APK com.google.android.play.games already loaded
    I/libjingle( 7398): worker_thread:0x7a6795a0 initialized=1
    I/RoomServiceStateMachine( 7398): Attempting to reconnect to: p_CJiO4I6oysDA5wEQAQ
    I/libjingle( 7398): Channel disabled
    I/libjingle( 7398): Changing data state, recv=0 send=0
    I/libjingle( 7398): Destroyed channel
    I/libjingle( 7398): Attempting to create a session, with data only.
    I/libjingle( 7398): CompleteInitiateCall_w:[email protected]/games_andr3812DFE4
    I/libjingle( 7398): void gtalk::LibjingleClient::OnCallCreate(cricket::Call*): Connecting to OnAddSession
    E/libjingle( 7398): Error(mediasession.cc:529): cricket::SessionDescription* cricket::MediaSessionDescriptionFactory::CreateOffer(const cricket::MediaSessionOptions&, const cricket::SessionDescription*): Creating Data offer.
    I/libjingle( 7398): AddSession() called. has_data = 1
    I/libjingle( 7398): Creating data channel.
    I/libjingle( 7398): Is worker current:0
    I/libjingle( 7398): Current thread:0x7a5f22d8
    I/libjingle( 7398): worker_thread:0x7a6795a0 initialized=1
    I/libjingle( 7398): Created channel for data
    I/libjingle( 7398): DataChannel::Init() called
    I/libjingle( 7398): result = 1
    I/libjingle( 7398): void gtalk::LibjingleClient::OnAddSession(cricket::Call*, cricket::Session*): OnAddSession called.
    I/libjingle( 7398): Setting local data description
    I/libjingle( 7398): Added data send stream '' with ssrc=1513025174
    I/libjingle( 7398): Add send ssrc: 1513025174
    I/libjingle( 7398): Changing data state, recv=0 send=0
    E/libjingle( 7398): Error(latencyprober.cpp:83): Peer already added for reliable latency metrics.
    I/libjingle( 7398): Channel enabled
    I/libjingle( 7398): Changing data state, recv=1 send=0
    I/libjingle( 7398): Network Information: All networks
    I/libjingle( 7398): Name, Description, Prefix, Prefix Length, IP, ignored
    I/libjingle( 7398): ipv4-default default IPV4 network 0.0.0.0 32 10.0.1.27 0
    I/libjingle( 7398): wlan0 wlan0 10.0.1.0 24 10.0.1.27 0
    I/libjingle( 7398): p2p0 p2p0 fe80:: 64 fe80::485a:3fff:fe5d:dd44 0
    I/libjingle( 7398): wlan0 wlan0 fe80:: 64 fe80::4a5a:3fff:fe5d:dd44 0
    I/libjingle( 7398): 
    I/libjingle( 7398): HttpRequest start: relay.google.com/create_session?username=2SnHIommK1POhvUN&password=ZfKDjnxO4ER1auGWLUuMb%2fy%2b&sn=3
    I/libjingle( 7398): SSL Cleanup
    E/libjingle( 7398): Error(basicpacketsocketfactory.cc:67): UDP bind failed with error 22
    E/libjingle( 7398): Error(basicpacketsocketfactory.cc:67): UDP bind failed with error 22
    E/libjingle( 7398): Error(basicpacketsocketfactory.cc:67): UDP bind failed with error 22
    E/libjingle( 7398): Error(basicpacketsocketfactory.cc:67): UDP bind failed with error 22
    I/libjingle( 7398): OpenSSLAdapter::OnConnectEvent
    I/libjingle( 7398): BeginSSL: relay.google.com
    I/libjingle( 7398): IbbDataTask::ProcessStart() called:
    I/libjingle( 7398): Got Xmpp data back: <ibb:data ibb:seq="0" ibb:sid="1" xmlns:ibb="http://jabber.org/protocol/ibb"/>
    I/libjingle( 7398): static void gtalk::LibjingleJniHelper::DispatchIbbSendResult(jobject, const string&, const string&, bool): Dispatch ID:1
    I/libjingle( 7398): IbbDataTask::ProcessStart() called:
    I/libjingle( 7398): Parsing Jingle data content
    I/libjingle( 7398): Setting remote data description
    I/libjingle( 7398): Added data recv stream '' with ssrc=1992942837
    I/libjingle( 7398): Add remote ssrc: 1992942837
    I/libjingle( 7398): SRTP reset to init state
    I/libjingle( 7398): DataMediaChannel::SetSendBandwidth to 10485000bps.
    I/libjingle( 7398): Changing data state, recv=1 send=0
    I/swaag   (13059): Connected Set Changed. Currently connected: 0
    I/swaag   (13059): Participant Status Changed. Valid=1
    I/swaag   (13059): Participant id p_CJiO4I6oysDA5wEQAQ, name Player 7806
    I/swaag   (13059): Connected Set Changed. Currently connected: 0
    E/RoomServiceStateMachine( 7398): Attempting to send an unreliable message to participants when not in connected set.
    E/RoomServiceStateMachine( 7398): Attempting to send an unreliable message to participants when not in connected set.
    I/libjingle( 7398): HttpRequest completed successfully
    I/libjingle( 7398): SSL Cleanup
    E/RoomServiceStateMachine( 7398): Attempting to send an unreliable message to participants when not in connected set.
    E/RoomServiceStateMachine( 7398): Attempting to send an unreliable message to participants when not in connected set.
    E/RoomServiceStateMachine( 7398): Attempting to send an unreliable message to participants when not in connected set.
    E/RoomServiceStateMachine( 7398): Attempting to send an unreliable message to participants when not in connected set.
    E/RoomServiceStateMachine( 7398): Attempting to send an unreliable message to participants when not in connected set.
    E/RoomServiceStateMachine( 7398): Attempting to send an unreliable message to participants when not in connected set.
    E/RoomServiceStateMachine( 7398): Attempting to send an unreliable message to participants when not in connected set.
    E/RoomServiceStateMachine( 7398): Attempting to send an unreliable message to participants when not in connected set.
    E/libjingle( 7398): Error(basicpacketsocketfactory.cc:67): UDP bind failed with error 22
    E/libjingle( 7398): Error(basicpacketsocketfactory.cc:67): UDP bind failed with error 22
    E/RoomServiceStateMachine( 7398): Attempting to send an unreliable message to participants when not in connected set.
    E/RoomServiceStateMachine( 7398): Attempting to send an unreliable message to participants when not in connected set.
    E/RoomServiceStateMachine( 7398): Attempting to send an unreliable message to participants when not in connected set.
    E/RoomServiceStateMachine( 7398): Attempting to send an unreliable message to participants when not in connected set.
    E/libjingle( 7398): Error(basicpacketsocketfactory.cc:85): TCP bind failed with error 22
    E/libjingle( 7398): Error(basicpacketsocketfactory.cc:85): TCP bind failed with error 22
    E/RoomServiceStateMachine( 7398): Attempting to send an unreliable message to participants when not in connected set.
    E/RoomServiceStateMachine( 7398): Attempting to send an unreliable message to participants when not in connected set.
    E/RoomServiceStateMachine( 7398): Attempting to send an unreliable message to participants when not in connected set.
    E/RoomServiceStateMachine( 7398): Attempting to send an unreliable message to participants when not in connected set.
    E/RoomServiceStateMachine( 7398): Attempting to send an unreliable message to participants when not in connected set.
    E/RoomServiceStateMachine( 7398): Attempting to send an unreliable message to participants when not in connected set.
    E/RoomServiceStateMachine( 7398): Attempting to send an unreliable message to participants when not in connected set.
    E/RoomServiceStateMachine( 7398): Attempting to send an unreliable message to participants when not in connected set.
    
    
    bug 
    opened by stolk 8
  • Linking Android app to game services stopped working.

    Linking Android app to game services stopped working.

    Using google play developer console, it is no longer possible to link an app by providing key's SHA1 fingerprint.

    This worked two days ago, but yesterday and today, it will only respond with an error message: An unexpected error occurred. Please try again later. (4800001)

    error

    opened by stolk 8
  • Snapshot API - High error rate in Google Cloud Platform console

    Snapshot API - High error rate in Google Cloud Platform console

    Hi, we've noticed high error rate in Google Cloud Platform console in one of our applications which uses cloud save functionality recently. Another project which uses cloud saves looks fine at the moment. since we use the very same SDK versions and integration code we assume that the error rate (90% peak, 82% average) might be due to high DAU and that we might hit some quotas. Testing locally sometimes we see tatusCode:403 Reason:[rateLimitExceeded] message which confirms our idea. However, checking Google Cloud quotas for the project show that we aren't hitting any limit such as queries per 100s or queries per day. Moreover, Snapshot API documentation doesn't say there are any quotas.

    Could you, please, let us know the way to figure out what is the reason of high error rate and if there are any quotas?

    opened by imixerpro 0
  • GPS v21.0.0 = cannot find symbol method `getSnapshotFromBundle(Bundle)`

    GPS v21.0.0 = cannot find symbol method `getSnapshotFromBundle(Bundle)`

    When trying to build with the latest Google's Play Games Services (21.0.0) I'm getting: cannot find symbol method getSnapshotFromBundle(Bundle)

    https://github.com/playgameservices/android-basic-samples/blob/f6a39dfcac2f37c2586626057fb79bec7b610211/CollectAllTheStars2/src/main/java/com/google/example/games/catt2/SnapshotCoordinator.java#L207-L209

    I wonder if Google will be so nice and will update its samples before updates will be necessary.

    opened by Oldes 0
  • Issues with the Saved Games API

    Issues with the Saved Games API

    Earlier this year we've bumped into the following issues: the built signed with the upload certificate started experiencing really long delays up to a few minutes before being logged in and getting save data from the Google cloud.

    A few days ago we've bumped into the similar issues with the built downloaded from google play. Please, note that we got strange errors in the system log just before we get NOT AUTHORIZED error from GPG SDK: we see the error accessing google cloud URI which claimed something similar to "API call limit is reached".

    Please, note that we are using c++ sdk which forces us to use older java SDK: c++ SDK doesn't wokr with the latest ones and support keeps silence.

    Any chance you could help us to figure out what's going on and how to fix this?

    opened by imixerpro 11
Owner
Google Play Game Services
Google Play Game Services
Android samples for Google Workspace APIs

Google Workspace Android Samples A collection of samples that demonstrate how to call Google Workspace APIs from Android. Products Drive Deprecation A

Google Workspace 615 Dec 16, 2022
android-delicious Delicious Android is an Android app which helps you access and save bookmarks via Delicious. It's available over at Google Play.

Delicious Android Delicious Android is an Android app which helps you access and save bookmarks via Delicious. It's available over at Google Play. Fea

Alexander Blom 137 Nov 20, 2022
Ivy Wallet is an Open Source money manager app for android that you can either build or download from Google Play.

Ivy Wallet is an Open Source money manager app for android that you can either build or download from Google Play.

null 727 Dec 26, 2022
Google Play Market's clone application

PlayMarketClone Google Play Market's clone application Features of the application: Images are retrieved from the API The application has a single act

Lazy Coder 3 Dec 3, 2022
A productivity tracker app published on Google Play

producktivity-tracker A productivity tracker app published on Google Play. Includes Google AdMob and in-app-purchases to disable ads. This project was

null 1 Mar 9, 2022
Android samples built using Jetpack Window Manager for foldable and dual-screen devices like Microsoft Surface Duo.

Jetpack Window Manager samples for dual-screen and foldable devices like Microsoft Surface Duo Android app samples that use Jetpack Window Manager to

Microsoft 45 Dec 19, 2022
Samples showing best practices for MIDI on Android.

MIDI Samples This repository contains a set of individual Android Studio projects to help you write apps using MIDI APIs. Android MIDI 2.0 API samples

Android 23 Dec 19, 2022
Samples in Material Animation (Deprecated)

Material-Animation-Samples (Deprecated) or watch it on youtube #Samples: Samples in material animation will be added through the next two monthes. Lay

Ahmed Tarek 228 Dec 7, 2021
Samples demonstrating the features and use of Koala Plot, a Compose Multiplatform based charting and plotting library written in Kotlin.

Koala Plot Samples This repository houses samples demonstrating the use and features of Koala Plot libraries. How to run Build koalaplot-core with the

Koala Plot 6 Oct 18, 2022
akka-samples-peristence-java by Lightbend, but using Kotlin.

This example illustrates event sourcing with Akka Persistence. it is based (okay, stolen from) the generated sample project akka-samples-peristence-ja

Jurjen Vorhauer 1 Oct 11, 2022
Android app for monitoring web services. Notifies you of any HTTP or Onion destination not being available.

Webmon Monitor web services and get notified, if a service becomes unavailable. EARLY BIRD DOWNLOAD App Features Simple UI. No login required. Get not

null 36 Dec 29, 2022
An educational android app that provides services like notes, online videos and visualization calculator to learn and understand deep concepts of DSA.

Aldo ALDO is a free education app for the young programmers who are desiring to master the concepts of Data Structure and Algorithms. ALDO offers prac

Siddharth Singh 2 Aug 8, 2022
SimpleCloud-haste-module - SimpleCloud module for uploading the logs of your services to hastebin

SimpleCloud Haste Module A SimpleCloud Module for uploading the current logs of

NeverStopGaming.net 5 Mar 6, 2022
The application uses Firebase Authentication and Realtime Database services

This is a Chik-Chika. Chick-Chicka is android app, which is based on popular social network - Twitter. The application uses Firebase Authentication and Realtime Database services.

Natro 9 Nov 6, 2022
Google one tap sign in - Flutter Google One Tap Sign In (Android)

Google One Tap Sign In Google One Tap Sign In (Android) A Flutter Plugin for Google One Tap Sign In Getting Started To access Google Sign-In, you'll n

null 6 Nov 23, 2022
xCloud player for Google Chromecast with Google TV

XCTV Player An awesome Microsoft xCloud player for Google Chromecast with Google

Keith Baker 41 Dec 27, 2022
Xctvplayer - xCloud player for Google Chromecast with Google TV

XCTV Player An awesome Microsoft xCloud player for Google Chromecast with Google

Keith Baker 41 Dec 27, 2022
Play Android App

Play Android App Stream music and control the queue of a play server from your Android device. Dependencies ActionBarSherlock http-request android-pus

Play 164 Nov 21, 2022
Tidy up your Android status bar before taking screenshots for the Play Store

DEPRECATED This project no longer works on recent versions of Android. Use Android's build-in Demo mode instead. For the curious, more information abo

Emma Vanbrabant 891 Nov 10, 2022