/
GameHelper.java
758 lines (661 loc) · 27.5 KB
/
GameHelper.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
/*
* 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 org.brandroid.iconcycle.game;
import android.app.Activity;
import android.app.AlertDialog;
import android.app.Dialog;
import android.app.ProgressDialog;
import android.content.Context;
import android.content.Intent;
import android.content.IntentSender.SendIntentException;
import android.os.Bundle;
import android.util.Log;
import android.view.Gravity;
import com.google.android.gms.appstate.AppStateClient;
import com.google.android.gms.common.ConnectionResult;
import com.google.android.gms.common.GooglePlayServicesClient;
import com.google.android.gms.common.GooglePlayServicesUtil;
import com.google.android.gms.common.Scopes;
import com.google.android.gms.games.GamesClient;
import com.google.android.gms.games.OnSignOutCompleteListener;
import com.google.android.gms.games.multiplayer.Invitation;
import com.google.android.gms.plus.PlusClient;
import java.util.Vector;
public class GameHelper implements GooglePlayServicesClient.ConnectionCallbacks,
GooglePlayServicesClient.OnConnectionFailedListener, OnSignOutCompleteListener {
/** 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();
}
/**
* 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;
// OAuth scopes required for the clients. Initialized in setup().
String mScopes[];
// 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;
// Client objects we manage. If a given client is not enabled, it is null.
GamesClient mGamesClient = null;
PlusClient mPlusClient = null;
AppStateClient mAppStateClient = null;
// What clients we manage (OR-able values, can be combined as 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_ALL = CLIENT_GAMES | CLIENT_PLUS | CLIENT_APPSTATE;
// What clients were requested? (bit flags)
int mRequestedClients = CLIENT_NONE;
// What clients are currently connected? (bit flags)
int mConnectedClients = CLIENT_NONE;
// What client are we currently connecting?
int mClientCurrentlyConnecting = CLIENT_NONE;
// A progress dialog we show when we are trying to sign the user is
ProgressDialog mProgressDialog = null;
// Whether to automatically try to sign in on onStart().
boolean mAutoSignIn = 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;
// Whether our sign-in attempt resulted in an error. In this case,
// mConnectionResult
// indicates what was the error we failed to resolve.
boolean mSignInError = false;
// Whether we launched the sign-in dialog flow and therefore are expecting
// an
// onActivityResult with the result of that.
boolean mExpectingActivityResult = false;
// Are we signed in?
boolean mSignedIn = false;
// Print debug logs?
boolean mDebugLog = false;
String mDebugTag = "BaseGameActivity";
// Messages (can be set by the developer).
String mSigningInMessage = "";
String mSigningOutMessage = "";
String mUnknownErrorMessage = "Unknown error";
// If we got an invitation id when we connected to the games client, it's
// here.
// Otherwise, it's null.
String mInvitationId;
// Listener
GameHelperListener mListener = null;
/**
* Construct a GameHelper object, initially tied to the given Activity.
* After constructing this object, call @link{setup} from the onCreate()
* method of your Activity.
*/
public GameHelper(Activity activity) {
mActivity = activity;
}
/** Sets the message that appears onscreen while signing in. */
public void setSigningInMessage(String message) {
mSigningInMessage = message;
}
/** Sets the message that appears onscreen while signing out. */
public void setSigningOutMessage(String message) {
mSigningOutMessage = message;
}
/**
* Sets the message that appears onscreen when there is an unknown error
* (rare!)
*/
public void setUnknownErrorMessage(String message) {
mUnknownErrorMessage = message;
}
/**
* Same as calling @link{setup(GameHelperListener, int)} requesting only the
* CLIENT_GAMES client.
*/
public void setup(GameHelperListener listener) {
setup(listener, CLIENT_GAMES);
}
/**
* 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.
* @param clientsToUse The clients to use. Use a combination of
* CLIENT_GAMES, CLIENT_PLUS and CLIENT_APPSTATE, or CLIENT_ALL
* to request all clients.
*/
public void setup(GameHelperListener listener, int clientsToUse) {
mListener = listener;
mRequestedClients = clientsToUse;
Vector<String> scopesVector = new Vector<String>();
if (0 != (clientsToUse & CLIENT_GAMES)) {
scopesVector.add(Scopes.GAMES);
}
if (0 != (clientsToUse & CLIENT_PLUS)) {
scopesVector.add(Scopes.PLUS_LOGIN);
}
if (0 != (clientsToUse & CLIENT_APPSTATE)) {
scopesVector.add(Scopes.APP_STATE);
}
mScopes = new String[scopesVector.size()];
scopesVector.copyInto(mScopes);
if (0 != (clientsToUse & CLIENT_GAMES)) {
debugLog("onCreate: creating GamesClient");
mGamesClient = new GamesClient.Builder(getContext(), this, this)
.setGravityForPopups(Gravity.TOP | Gravity.CENTER_HORIZONTAL)
.setScopes(mScopes)
.create();
}
if (0 != (clientsToUse & CLIENT_PLUS)) {
debugLog("onCreate: creating GamesPlusClient");
mPlusClient = new PlusClient.Builder(getContext(), this, this)
.setScopes(mScopes)
.build();
}
if (0 != (clientsToUse & CLIENT_APPSTATE)) {
debugLog("onCreate: creating AppStateClient");
mAppStateClient = new AppStateClient.Builder(getContext(), this, this)
.setScopes(mScopes)
.create();
}
}
/**
* Returns the GamesClient object. In order to call this method, you must have
* called @link{setup} with a set of clients that includes CLIENT_GAMES.
*/
public GamesClient getGamesClient() {
if (mGamesClient == null) {
throw new IllegalStateException("No GamesClient. Did you request it at setup?");
}
return mGamesClient;
}
/**
* Returns the AppStateClient object. In order to call this method, you must have
* called @link{#setup} with a set of clients that includes CLIENT_APPSTATE.
*/
public AppStateClient getAppStateClient() {
if (mAppStateClient == null) {
throw new IllegalStateException("No AppStateClient. Did you request it at setup?");
}
return mAppStateClient;
}
/**
* Returns the PlusClient object. In order to call this method, you must have
* called @link{#setup} with a set of clients that includes CLIENT_PLUS.
*/
public PlusClient getPlusClient() {
if (mPlusClient == null) {
throw new IllegalStateException("No PlusClient. Did you request it at setup?");
}
return mPlusClient;
}
/** Returns whether or not the user is signed in. */
public boolean isSignedIn() {
return mSignedIn;
}
/**
* Returns whether or not there was a (non-recoverable) error during the
* sign-in process.
*/
public boolean hasSignInError() {
return mSignInError;
}
/**
* Returns the error that happened during the sign-in process, null if no
* error occurred.
*/
public ConnectionResult getSignInError() {
return mSignInError ? mConnectionResult : null;
}
/** Call this method from your Activity's onStart(). */
public void onStart(Activity act) {
mActivity = act;
debugLog("onStart.");
if (mExpectingActivityResult) {
// this Activity is starting because the UI flow we launched to
// resolve a connection problem has just returned. In this case,
// we should NOT automatically reconnect the client, since
// onActivityResult will handle that.
debugLog("onStart: won't connect because we're expecting activity result.");
} else if (!mAutoSignIn) {
// The user specifically signed out, so don't attempt to sign in
// automatically. If the user wants to sign in, they will click
// the sign-in button, at which point we will try to sign in.
debugLog("onStart: not signing in because user specifically signed out.");
} else {
// Attempt to connect the clients.
debugLog("onStart: connecting clients.");
startConnections();
}
}
/** Call this method from your Activity's onStop(). */
public void onStop() {
debugLog("onStop: disconnecting clients.");
// disconnect the clients -- this is very important (prevents resource
// leaks!)
killConnections(CLIENT_ALL);
// no longer signed in
mSignedIn = false;
mSignInError = false;
// destroy progress dialog -- we create it again when needed
dismissDialog();
mProgressDialog = null;
// let go of the Activity reference
mActivity = null;
}
/** Convenience method to show an alert dialog. */
public void showAlert(String title, String message) {
(new AlertDialog.Builder(getContext())).setTitle(title).setMessage(message)
.setNeutralButton(android.R.string.ok, null).create().show();
}
/** Convenience method to show an alert dialog. */
public void showAlert(String message) {
(new AlertDialog.Builder(getContext())).setMessage(message)
.setNeutralButton(android.R.string.ok, null).create().show();
}
/**
* 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() {
return mInvitationId;
}
/** Enables debug logging, with the given logcat tag. */
public void enableDebugLog(boolean enabled, String tag) {
mDebugLog = enabled;
mDebugTag = tag;
}
/**
* Returns the current requested scopes. This is not valid until setup() has
* been called.
*
* @return the requested scopes, including the oauth2: prefix
*/
public String getScopes() {
StringBuilder scopeStringBuilder = new StringBuilder();
int clientsToUse = mRequestedClients;
// GAMES implies PLUS_LOGIN
if (0 != (clientsToUse & CLIENT_GAMES)) {
addToScope(scopeStringBuilder, Scopes.GAMES);
}
if (0 != (clientsToUse & CLIENT_PLUS)) {
addToScope(scopeStringBuilder, Scopes.PLUS_LOGIN);
}
if (0 != (clientsToUse & CLIENT_APPSTATE)) {
addToScope(scopeStringBuilder, Scopes.APP_STATE);
}
return scopeStringBuilder.toString();
}
/** Sign out and disconnect from the APIs. */
public void signOut() {
mConnectionResult = null;
mAutoSignIn = false;
mSignedIn = false;
mSignInError = false;
if (mPlusClient != null && mPlusClient.isConnected()) {
mPlusClient.clearDefaultAccount();
}
if (mGamesClient != null && mGamesClient.isConnected()) {
showProgressDialog(false);
mGamesClient.signOut(this);
}
// kill connects to all clients but games, which must remain
// connected til we get onSignOutComplete()
killConnections(CLIENT_ALL & ~CLIENT_GAMES);
}
/**
* 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) {
if (requestCode == RC_RESOLVE) {
// We're coming back from an activity that was launched to resolve a
// connection
// problem. For example, the sign-in UI.
mExpectingActivityResult = false;
debugLog("onActivityResult, req " + requestCode + " response " + responseCode);
if (responseCode == Activity.RESULT_OK) {
// Ready to try to connect again.
debugLog("responseCode == RESULT_OK. So connecting.");
connectCurrentClient();
} else {
// Whatever the problem we were trying to solve, it was not
// solved.
// So give up and show an error message.
debugLog("responseCode != RESULT_OK, so not reconnecting.");
giveUp();
}
}
}
/**
* 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() {
if (mSignedIn)
return; // nothing to do
// reset the flag to sign in automatically on onStart() -- now a
// wanted behavior
mAutoSignIn = true;
// Is Google Play services available?
int result = GooglePlayServicesUtil.isGooglePlayServicesAvailable(getContext());
debugLog("isGooglePlayServicesAvailable returned " + result);
if (result != ConnectionResult.SUCCESS) {
// Nope.
debugLog("Google Play services not available. Show error dialog.");
Dialog errorDialog = getErrorDialog(result);
errorDialog.show();
if (mListener != null)
mListener.onSignInFailed();
return;
}
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.");
showProgressDialog(true);
resolveConnectionResult();
} else {
// We don't have a pending connection result, so start anew.
debugLog("beginUserInitiatedSignIn: starting new sign-in flow.");
startConnections();
}
}
Context getContext() {
return mActivity;
}
void addToScope(StringBuilder scopeStringBuilder, String scope) {
if (scopeStringBuilder.length() == 0) {
scopeStringBuilder.append("oauth2:");
} else {
scopeStringBuilder.append(" ");
}
scopeStringBuilder.append(scope);
}
void startConnections() {
mConnectedClients = CLIENT_NONE;
mInvitationId = null;
connectNextClient();
}
void showProgressDialog(boolean signIn) {
String message = signIn ? mSigningInMessage : mSigningOutMessage;
if (mProgressDialog == null) {
if (getContext() == null)
return;
mProgressDialog = new ProgressDialog(getContext());
}
mProgressDialog.setMessage(message == null ? "" : message);
mProgressDialog.setIndeterminate(true);
mProgressDialog.show();
}
void dismissDialog() {
if (mProgressDialog != null)
mProgressDialog.dismiss();
mProgressDialog = null;
}
void connectNextClient() {
// do we already have all the clients we need?
int pendingClients = mRequestedClients & ~mConnectedClients;
if (pendingClients == 0) {
debugLog("All clients now connected. Sign-in successful.");
succeedSignIn();
return;
}
showProgressDialog(true);
// which client should be the next one to connect?
if (mGamesClient != null && (0 != (pendingClients & CLIENT_GAMES))) {
debugLog("Connecting GamesClient.");
mClientCurrentlyConnecting = CLIENT_GAMES;
} else if (mPlusClient != null && (0 != (pendingClients & CLIENT_PLUS))) {
debugLog("Connecting PlusClient.");
mClientCurrentlyConnecting = CLIENT_PLUS;
} else if (mAppStateClient != null && (0 != (pendingClients & CLIENT_APPSTATE))) {
debugLog("Connecting AppStateClient.");
mClientCurrentlyConnecting = CLIENT_APPSTATE;
} else {
throw new AssertionError("Not all clients connected, yet no one is next. R="
+ mRequestedClients + ", C=" + mConnectedClients);
}
connectCurrentClient();
}
void connectCurrentClient() {
switch (mClientCurrentlyConnecting) {
case CLIENT_GAMES:
mGamesClient.connect();
break;
case CLIENT_APPSTATE:
mAppStateClient.connect();
break;
case CLIENT_PLUS:
mPlusClient.connect();
break;
}
}
void killConnections(int whatClients) {
if ((whatClients & CLIENT_GAMES) != 0 && mGamesClient != null
&& mGamesClient.isConnected()) {
mConnectedClients &= ~CLIENT_GAMES;
mGamesClient.disconnect();
}
if ((whatClients & CLIENT_PLUS) != 0 && mPlusClient != null
&& mPlusClient.isConnected()) {
mConnectedClients &= ~CLIENT_PLUS;
mPlusClient.disconnect();
}
if ((whatClients & CLIENT_APPSTATE) != 0 && mAppStateClient != null
&& mAppStateClient.isConnected()) {
mConnectedClients &= ~CLIENT_APPSTATE;
mAppStateClient.disconnect();
}
}
public void reconnectClients(int whatClients) {
showProgressDialog(true);
if ((whatClients & CLIENT_GAMES) != 0 && mGamesClient != null
&& mGamesClient.isConnected()) {
mConnectedClients &= ~CLIENT_GAMES;
mGamesClient.reconnect();
}
if ((whatClients & CLIENT_APPSTATE) != 0 && mAppStateClient != null
&& mAppStateClient.isConnected()) {
mConnectedClients &= ~CLIENT_APPSTATE;
mAppStateClient.reconnect();
}
if ((whatClients & CLIENT_PLUS) != 0 && mPlusClient != null
&& mPlusClient.isConnected()) {
mConnectedClients &= ~CLIENT_PLUS;
mPlusClient.disconnect();
mPlusClient.connect();
}
}
/** Called when we successfully obtain a connection to a client. */
@Override
public void onConnected(Bundle connectionHint) {
debugLog("onConnected: connected! client=" + mClientCurrentlyConnecting);
// Mark the current client as connected
mConnectedClients |= mClientCurrentlyConnecting;
// If this was the games client and it came with an invite, store it for
// later retrieval.
if (mClientCurrentlyConnecting == CLIENT_GAMES && connectionHint != null) {
debugLog("onConnected: connection hint provided. Checking for invite.");
Invitation inv = connectionHint.getParcelable(GamesClient.EXTRA_INVITATION);
if (inv != null && inv.getInvitationId() != null) {
// accept invitation
debugLog("onConnected: connection hint has a room invite!");
mInvitationId = inv.getInvitationId();
debugLog("Invitation ID: " + mInvitationId);
}
}
// connect the next client in line, if any.
connectNextClient();
}
void succeedSignIn() {
debugLog("All requested clients connected. Sign-in succeeded!");
mSignedIn = true;
mSignInError = false;
mAutoSignIn = true;
mUserInitiatedSignIn = false;
dismissDialog();
if (mListener != null) {
mListener.onSignInSucceeded();
}
}
/** Handles a connection failure reported by a client. */
@Override
public void onConnectionFailed(ConnectionResult result) {
// save connection result for later reference
mConnectionResult = result;
debugLog("onConnectionFailed: result " + result.getErrorCode());
dismissDialog();
if (!mUserInitiatedSignIn) {
// If the user didn't initiate the sign-in, we don't try to resolve
// the connection problem automatically -- instead, we fail and wait
// for the user to want to sign in. That way, they won't get an
// authentication (or other) popup unless they are actively trying
// to
// sign in.
debugLog("onConnectionFailed: since user didn't initiate sign-in, failing now.");
mConnectionResult = result;
if (mListener != null) {
mListener.onSignInFailed();
}
return;
}
debugLog("onConnectionFailed: since user initiated sign-in, trying to resolve 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
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)
mExpectingActivityResult = true;
mConnectionResult.startResolutionForResult(mActivity, RC_RESOLVE);
} catch (SendIntentException e) {
// Try connecting again
debugLog("SendIntentException.");
connectCurrentClient();
}
} 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();
}
}
/**
* 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() {
mSignInError = true;
mAutoSignIn = false;
dismissDialog();
debugLog("giveUp: giving up on connection. " +
((mConnectionResult == null) ? "(no connection result)" :
("Status code: " + mConnectionResult.getErrorCode())));
Dialog errorDialog = null;
if (mConnectionResult != null) {
// get error dialog for that specific problem
errorDialog = getErrorDialog(mConnectionResult.getErrorCode());
errorDialog.show();
if (mListener != null) {
mListener.onSignInFailed();
}
} else {
// this is a bug
Log.e("GameHelper", "giveUp() called with no mConnectionResult");
}
}
/** Called when we are disconnected from a client. */
@Override
public void onDisconnected() {
debugLog("onDisconnected.");
mConnectionResult = null;
mAutoSignIn = false;
mSignedIn = false;
mSignInError = false;
mInvitationId = null;
mConnectedClients = CLIENT_NONE;
if (mListener != null) {
mListener.onSignInFailed();
}
}
/** Returns an error dialog that's appropriate for the given error code. */
Dialog getErrorDialog(int errorCode) {
debugLog("Making error dialog for error: " + errorCode);
Dialog errorDialog = GooglePlayServicesUtil.getErrorDialog(errorCode, mActivity,
RC_UNUSED, null);
if (errorDialog != null)
return errorDialog;
// as a last-resort, make a sad "unknown error" dialog.
return (new AlertDialog.Builder(getContext())).setMessage(mUnknownErrorMessage)
.setNeutralButton(android.R.string.ok, null).create();
}
void debugLog(String message) {
if (mDebugLog)
Log.d(mDebugTag, message);
}
@Override
public void onSignOutComplete() {
dismissDialog();
if (mGamesClient.isConnected())
mGamesClient.disconnect();
}
}