//
// Copyright (C) 2014 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.
//
#if UNITY_ANDROID
#pragma warning disable 0642 // Possible mistaken empty statement
namespace GooglePlayGames.Android
{
using GooglePlayGames.BasicApi;
using GooglePlayGames.BasicApi.SavedGame;
using GooglePlayGames.OurUtils;
using System;
using System.Collections.Generic;
using GooglePlayGames.BasicApi.Events;
using GooglePlayGames.BasicApi.Video;
using UnityEngine;
using UnityEngine.SocialPlatforms;
public class AndroidClient : IPlayGamesClient
{
private enum AuthState
{
Unauthenticated,
Authenticated
}
private readonly object GameServicesLock = new object();
private readonly object AuthStateLock = new object();
private readonly PlayGamesClientConfiguration mConfiguration;
private volatile ISavedGameClient mSavedGameClient;
private volatile IEventsClient mEventsClient;
private volatile IVideoClient mVideoClient;
private volatile AndroidTokenClient mTokenClient;
private volatile Player mUser = null;
private volatile AuthState mAuthState = AuthState.Unauthenticated;
private IUserProfile[] mFriends = new IUserProfile[0];
private LoadFriendsStatus mLastLoadFriendsStatus = LoadFriendsStatus.Unknown;
AndroidJavaClass mGamesClass = new AndroidJavaClass("com.google.android.gms.games.Games");
private static string TasksClassName = "com.google.android.gms.tasks.Tasks";
private AndroidJavaObject mFriendsResolutionException = null;
private readonly int mLeaderboardMaxResults = 25; // can be from 1 to 25
private readonly int mFriendsMaxResults = 200; // the maximum load friends page size
internal AndroidClient(PlayGamesClientConfiguration configuration)
{
PlayGamesHelperObject.CreateObject();
this.mConfiguration = Misc.CheckNotNull(configuration);
}
///
///
public void Authenticate(bool silent, Action callback)
{
lock (AuthStateLock)
{
// If the user is already authenticated, just fire the callback, we don't need
// any additional work.
if (mAuthState == AuthState.Authenticated)
{
Debug.Log("Already authenticated.");
InvokeCallbackOnGameThread(callback, SignInStatus.Success);
return;
}
}
InitializeTokenClient();
Debug.Log("Starting Auth with token client.");
mTokenClient.FetchTokens(silent, (int result) =>
{
bool succeed = result == 0 /* CommonStatusCodes.SUCCEED */;
InitializeGameServices();
if (succeed)
{
using (var signInTasks = new AndroidJavaObject("java.util.ArrayList"))
{
AndroidJavaObject taskGetPlayer =
getPlayersClient().Call("getCurrentPlayer");
AndroidJavaObject taskGetActivationHint =
getGamesClient().Call("getActivationHint");
AndroidJavaObject taskIsCaptureSupported =
getVideosClient().Call("isCaptureSupported");
if (!mConfiguration.IsHidingPopups)
{
AndroidJavaObject taskSetViewForPopups;
using (var popupView = AndroidHelperFragment.GetDefaultPopupView())
{
taskSetViewForPopups =
getGamesClient().Call("setViewForPopups", popupView);
}
signInTasks.Call("add", taskSetViewForPopups);
}
signInTasks.Call("add", taskGetPlayer);
signInTasks.Call("add", taskGetActivationHint);
signInTasks.Call("add", taskIsCaptureSupported);
using (var tasks = new AndroidJavaClass(TasksClassName))
using (var allTask = tasks.CallStatic("whenAll", signInTasks))
{
AndroidTaskUtils.AddOnCompleteListener(
allTask,
completeTask =>
{
if (completeTask.Call("isSuccessful"))
{
using (var resultObject = taskGetPlayer.Call("getResult"))
{
mUser = AndroidJavaConverter.ToPlayer(resultObject);
}
var account = mTokenClient.GetAccount();
lock (GameServicesLock)
{
mSavedGameClient = new AndroidSavedGameClient(this, account);
mEventsClient = new AndroidEventsClient(account);
bool isCaptureSupported;
using (var resultObject =
taskIsCaptureSupported.Call("getResult"))
{
isCaptureSupported = resultObject.Call("booleanValue");
}
mVideoClient = new AndroidVideoClient(isCaptureSupported, account);
}
mAuthState = AuthState.Authenticated;
InvokeCallbackOnGameThread(callback, SignInStatus.Success);
GooglePlayGames.OurUtils.Logger.d("Authentication succeeded");
LoadAchievements(ignore => { });
}
else
{
SignOut();
if (completeTask.Call("isCanceled"))
{
InvokeCallbackOnGameThread(callback, SignInStatus.Canceled);
return;
}
using (var exception = completeTask.Call("getException"))
{
GooglePlayGames.OurUtils.Logger.e(
"Authentication failed - " + exception.Call("toString"));
InvokeCallbackOnGameThread(callback, SignInStatus.InternalError);
}
}
}
);
}
}
}
else
{
lock (AuthStateLock)
{
Debug.Log("Returning an error code.");
InvokeCallbackOnGameThread(callback, SignInHelper.ToSignInStatus(result));
}
}
});
}
private static Action AsOnGameThreadCallback(Action callback)
{
if (callback == null)
{
return delegate { };
}
return result => InvokeCallbackOnGameThread(callback, result);
}
private static void InvokeCallbackOnGameThread(Action callback)
{
if (callback == null)
{
return;
}
PlayGamesHelperObject.RunOnGameThread(() => { callback(); });
}
private static void InvokeCallbackOnGameThread(Action callback, T data)
{
if (callback == null)
{
return;
}
PlayGamesHelperObject.RunOnGameThread(() => { callback(data); });
}
private static Action AsOnGameThreadCallback(
Action toInvokeOnGameThread)
{
return (result1, result2) =>
{
if (toInvokeOnGameThread == null)
{
return;
}
PlayGamesHelperObject.RunOnGameThread(() => toInvokeOnGameThread(result1, result2));
};
}
private static void InvokeCallbackOnGameThread(Action callback, T1 t1, T2 t2)
{
if (callback == null)
{
return;
}
PlayGamesHelperObject.RunOnGameThread(() => { callback(t1, t2); });
}
private void InitializeGameServices()
{
if (mTokenClient != null)
{
return;
}
InitializeTokenClient();
}
private void InitializeTokenClient()
{
if (mTokenClient != null)
{
return;
}
mTokenClient = new AndroidTokenClient();
if (!GameInfo.WebClientIdInitialized() &&
(mConfiguration.IsRequestingIdToken || mConfiguration.IsRequestingAuthCode))
{
OurUtils.Logger.e("Server Auth Code and ID Token require web clientId to configured.");
}
string[] scopes = mConfiguration.Scopes;
// Set the auth flags in the token client.
mTokenClient.SetWebClientId(GameInfo.WebClientId);
mTokenClient.SetRequestAuthCode(mConfiguration.IsRequestingAuthCode, mConfiguration.IsForcingRefresh);
mTokenClient.SetRequestEmail(mConfiguration.IsRequestingEmail);
mTokenClient.SetRequestIdToken(mConfiguration.IsRequestingIdToken);
mTokenClient.SetHidePopups(mConfiguration.IsHidingPopups);
mTokenClient.AddOauthScopes("https://www.googleapis.com/auth/games_lite");
if (mConfiguration.EnableSavedGames)
{
mTokenClient.AddOauthScopes("https://www.googleapis.com/auth/drive.appdata");
}
mTokenClient.AddOauthScopes(scopes);
mTokenClient.SetAccountName(mConfiguration.AccountName);
}
///
/// Gets the user's email.
///
/// The email address returned is selected by the user from the accounts present
/// on the device. There is no guarantee this uniquely identifies the player.
/// For unique identification use the id property of the local player.
/// The user can also choose to not select any email address, meaning it is not
/// available.
/// The user email or null if not authenticated or the permission is
/// not available.
public string GetUserEmail()
{
if (!this.IsAuthenticated())
{
Debug.Log("Cannot get API client - not authenticated");
return null;
}
return mTokenClient.GetEmail();
}
///
/// Returns an id token, which can be verified server side, if they are logged in.
///
/// A callback to be invoked after token is retrieved. Will be passed null value
/// on failure.
/// The identifier token.
public string GetIdToken()
{
if (!this.IsAuthenticated())
{
Debug.Log("Cannot get API client - not authenticated");
return null;
}
return mTokenClient.GetIdToken();
}
///
/// Asynchronously retrieves the server auth code for this client.
///
/// Note: This function is currently only implemented for Android.
/// The Client ID.
/// Callback for response.
public string GetServerAuthCode()
{
if (!this.IsAuthenticated())
{
Debug.Log("Cannot get API client - not authenticated");
return null;
}
return mTokenClient.GetAuthCode();
}
public void GetAnotherServerAuthCode(bool reAuthenticateIfNeeded,
Action callback)
{
mTokenClient.GetAnotherServerAuthCode(reAuthenticateIfNeeded, AsOnGameThreadCallback(callback));
}
///
///
public bool IsAuthenticated()
{
lock (AuthStateLock)
{
return mAuthState == AuthState.Authenticated;
}
}
public void LoadFriends(Action callback)
{
LoadAllFriends(mFriendsMaxResults, /* forceReload= */ false, /* loadMore= */ false, callback);
}
private void LoadAllFriends(int pageSize, bool forceReload, bool loadMore,
Action callback)
{
LoadFriendsPaginated(pageSize, loadMore, forceReload, result =>
{
mLastLoadFriendsStatus = result;
switch (result)
{
case LoadFriendsStatus.Completed:
InvokeCallbackOnGameThread(callback, true);
break;
case LoadFriendsStatus.LoadMore:
// There are more friends to load.
LoadAllFriends(pageSize, /* forceReload= */ false, /* loadMore= */ true, callback);
break;
case LoadFriendsStatus.ResolutionRequired:
case LoadFriendsStatus.InternalError:
case LoadFriendsStatus.NotAuthorized:
InvokeCallbackOnGameThread(callback, false);
break;
default:
GooglePlayGames.OurUtils.Logger.d("There was an error when loading friends." + result);
InvokeCallbackOnGameThread(callback, false);
break;
}
});
}
public void LoadFriends(int pageSize, bool forceReload,
Action callback)
{
LoadFriendsPaginated(pageSize, /* isLoadMore= */ false, /* forceReload= */ forceReload,
callback);
}
public void LoadMoreFriends(int pageSize, Action callback)
{
LoadFriendsPaginated(pageSize, /* isLoadMore= */ true, /* forceReload= */ false,
callback);
}
private void LoadFriendsPaginated(int pageSize, bool isLoadMore, bool forceReload,
Action callback)
{
mFriendsResolutionException = null;
using (var playersClient = getPlayersClient())
using (var task = isLoadMore
? playersClient.Call("loadMoreFriends", pageSize)
: playersClient.Call("loadFriends", pageSize,
forceReload))
{
AndroidTaskUtils.AddOnSuccessListener(
task, annotatedData =>
{
using (var playersBuffer = annotatedData.Call("get"))
{
AndroidJavaObject metadata = playersBuffer.Call("getMetadata");
var areMoreFriendsToLoad = metadata != null &&
metadata.Call("getString",
"next_page_token") != null;
mFriends = AndroidJavaConverter.playersBufferToArray(playersBuffer);
mLastLoadFriendsStatus = areMoreFriendsToLoad
? LoadFriendsStatus.LoadMore
: LoadFriendsStatus.Completed;
InvokeCallbackOnGameThread(callback, mLastLoadFriendsStatus);
}
});
AndroidTaskUtils.AddOnFailureListener(task, exception =>
{
AndroidHelperFragment.IsResolutionRequired(exception, resolutionRequired =>
{
if (resolutionRequired)
{
mFriendsResolutionException =
exception.Call("getResolution");
mLastLoadFriendsStatus = LoadFriendsStatus.ResolutionRequired;
mFriends = new IUserProfile[0];
InvokeCallbackOnGameThread(callback, LoadFriendsStatus.ResolutionRequired);
}
else
{
mFriendsResolutionException = null;
if (Misc.IsApiException(exception))
{
var statusCode = exception.Call("getStatusCode");
if (statusCode == /* GamesClientStatusCodes.NETWORK_ERROR_NO_DATA */ 26504)
{
mLastLoadFriendsStatus = LoadFriendsStatus.NetworkError;
InvokeCallbackOnGameThread(callback, LoadFriendsStatus.NetworkError);
return;
}
}
mLastLoadFriendsStatus = LoadFriendsStatus.InternalError;
OurUtils.Logger.e("LoadFriends failed: " +
exception.Call("toString"));
InvokeCallbackOnGameThread(callback, LoadFriendsStatus.InternalError);
}
});
return;
});
}
}
public LoadFriendsStatus GetLastLoadFriendsStatus()
{
return mLastLoadFriendsStatus;
}
public void AskForLoadFriendsResolution(Action callback)
{
if (mFriendsResolutionException == null)
{
GooglePlayGames.OurUtils.Logger.d("The developer asked for access to the friends " +
"list but there is no intent to trigger the UI. This may be because the user " +
"has granted access already or the game has not called loadFriends() before.");
using (var playersClient = getPlayersClient())
using (
var task = playersClient.Call("loadFriends", /* pageSize= */ 1,
/* forceReload= */ false))
{
AndroidTaskUtils.AddOnSuccessListener(
task, annotatedData => { InvokeCallbackOnGameThread(callback, UIStatus.Valid); });
AndroidTaskUtils.AddOnFailureListener(task, exception =>
{
AndroidHelperFragment.IsResolutionRequired(exception, resolutionRequired =>
{
if (resolutionRequired)
{
mFriendsResolutionException =
exception.Call("getResolution");
AndroidHelperFragment.AskForLoadFriendsResolution(
mFriendsResolutionException, AsOnGameThreadCallback(callback));
}
else
{
var statusCode = exception.Call("getStatusCode");
if (statusCode == /* GamesClientStatusCodes.NETWORK_ERROR_NO_DATA */ 26504)
{
InvokeCallbackOnGameThread(callback, UIStatus.NetworkError);
return;
}
Debug.Log("LoadFriends failed with status code: " + statusCode);
InvokeCallbackOnGameThread(callback, UIStatus.InternalError);
}
});
return;
});
}
}
else
{
AndroidHelperFragment.AskForLoadFriendsResolution(mFriendsResolutionException,
AsOnGameThreadCallback(callback));
}
}
public void ShowCompareProfileWithAlternativeNameHintsUI(string playerId,
string otherPlayerInGameName,
string currentPlayerInGameName,
Action callback)
{
AndroidHelperFragment.ShowCompareProfileWithAlternativeNameHintsUI(
playerId, otherPlayerInGameName, currentPlayerInGameName,
GetUiSignOutCallbackOnGameThread(callback));
}
public void GetFriendsListVisibility(bool forceReload,
Action callback)
{
using (var playersClient = getPlayersClient())
using (
var task = playersClient.Call("getCurrentPlayer", forceReload))
{
AndroidTaskUtils.AddOnSuccessListener(task, annotatedData =>
{
AndroidJavaObject currentPlayerInfo =
annotatedData.Call("get").Call(
"getCurrentPlayerInfo");
int playerListVisibility =
currentPlayerInfo.Call("getFriendsListVisibilityStatus");
InvokeCallbackOnGameThread(callback,
AndroidJavaConverter.ToFriendsListVisibilityStatus(playerListVisibility));
});
AndroidTaskUtils.AddOnFailureListener(task, exception =>
{
InvokeCallbackOnGameThread(callback, FriendsListVisibilityStatus.NetworkError);
return;
});
}
}
public IUserProfile[] GetFriends()
{
return mFriends;
}
///
///
public void SignOut()
{
SignOut( /* uiCallback= */ null);
}
public void SignOut(Action uiCallback)
{
if (mTokenClient == null)
{
InvokeCallbackOnGameThread(uiCallback);
return;
}
mTokenClient.Signout();
mAuthState = AuthState.Unauthenticated;
if (uiCallback != null)
{
InvokeCallbackOnGameThread(uiCallback);
}
PlayGamesHelperObject.RunOnGameThread(() => SignInHelper.SetPromptUiSignIn(true));
}
///
///
public string GetUserId()
{
if (mUser == null)
{
return null;
}
return mUser.id;
}
///
///
public string GetUserDisplayName()
{
if (mUser == null)
{
return null;
}
return mUser.userName;
}
///
///
public string GetUserImageUrl()
{
if (mUser == null)
{
return null;
}
return mUser.AvatarURL;
}
public void SetGravityForPopups(Gravity gravity)
{
if (!IsAuthenticated())
{
GooglePlayGames.OurUtils.Logger.d("Cannot call SetGravityForPopups when not authenticated");
}
using (var gamesClient = getGamesClient())
using (gamesClient.Call("setGravityForPopups",
(int) gravity | (int) Gravity.CENTER_HORIZONTAL))
;
}
///
///
public void GetPlayerStats(Action callback)
{
using (var playerStatsClient = getPlayerStatsClient())
using (var task = playerStatsClient.Call("loadPlayerStats", /* forceReload= */ false))
{
AndroidTaskUtils.AddOnSuccessListener(
task,
annotatedData =>
{
using (var playerStatsJava = annotatedData.Call("get"))
{
int numberOfPurchases = playerStatsJava.Call("getNumberOfPurchases");
float avgSessionLength = playerStatsJava.Call("getAverageSessionLength");
int daysSinceLastPlayed = playerStatsJava.Call("getDaysSinceLastPlayed");
int numberOfSessions = playerStatsJava.Call("getNumberOfSessions");
float sessionPercentile = playerStatsJava.Call("getSessionPercentile");
float spendPercentile = playerStatsJava.Call("getSpendPercentile");
float spendProbability = playerStatsJava.Call("getSpendProbability");
float churnProbability = playerStatsJava.Call("getChurnProbability");
float highSpenderProbability = playerStatsJava.Call("getHighSpenderProbability");
float totalSpendNext28Days = playerStatsJava.Call("getTotalSpendNext28Days");
PlayerStats result = new PlayerStats(
numberOfPurchases,
avgSessionLength,
daysSinceLastPlayed,
numberOfSessions,
sessionPercentile,
spendPercentile,
spendProbability,
churnProbability,
highSpenderProbability,
totalSpendNext28Days);
InvokeCallbackOnGameThread(callback, CommonStatusCodes.Success, result);
}
});
AddOnFailureListenerWithSignOut(
task,
e =>
{
Debug.Log("GetPlayerStats failed: " + e.Call("toString"));
var statusCode = IsAuthenticated()
? CommonStatusCodes.InternalError
: CommonStatusCodes.SignInRequired;
InvokeCallbackOnGameThread(callback, statusCode, new PlayerStats());
});
}
}
///
///
public void LoadUsers(string[] userIds, Action callback)
{
if (!IsAuthenticated())
{
InvokeCallbackOnGameThread(callback, new IUserProfile[0]);
return;
}
using (var playersClient = getPlayersClient())
{
object countLock = new object();
int count = userIds.Length;
int resultCount = 0;
IUserProfile[] users = new IUserProfile[count];
for (int i = 0; i < count; ++i)
{
using (var task = playersClient.Call("loadPlayer", userIds[i]))
{
AndroidTaskUtils.AddOnSuccessListener(
task,
annotatedData =>
{
using (var player = annotatedData.Call("get"))
{
string playerId = player.Call("getPlayerId");
for (int j = 0; j < count; ++j)
{
if (playerId == userIds[j])
{
users[j] = AndroidJavaConverter.ToPlayer(player);
break;
}
}
lock (countLock)
{
++resultCount;
if (resultCount == count)
{
InvokeCallbackOnGameThread(callback, users);
}
}
}
});
AddOnFailureListenerWithSignOut(task, exception =>
{
Debug.Log("LoadUsers failed for index " + i +
" with: " + exception.Call("toString"));
lock (countLock)
{
++resultCount;
if (resultCount == count)
{
InvokeCallbackOnGameThread(callback, users);
}
}
});
}
}
}
}
///
///
public void LoadAchievements(Action callback)
{
using (var achievementsClient = getAchievementsClient())
using (var task = achievementsClient.Call("load", /* forceReload= */ false))
{
AndroidTaskUtils.AddOnSuccessListener(
task,
annotatedData =>
{
using (var achievementBuffer = annotatedData.Call("get"))
{
int count = achievementBuffer.Call("getCount");
Achievement[] result = new Achievement[count];
for (int i = 0; i < count; ++i)
{
Achievement achievement = new Achievement();
using (var javaAchievement = achievementBuffer.Call("get", i))
{
achievement.Id = javaAchievement.Call("getAchievementId");
achievement.Description = javaAchievement.Call("getDescription");
achievement.Name = javaAchievement.Call("getName");
achievement.Points = javaAchievement.Call("getXpValue");
long timestamp = javaAchievement.Call("getLastUpdatedTimestamp");
achievement.LastModifiedTime = AndroidJavaConverter.ToDateTime(timestamp);
achievement.RevealedImageUrl = javaAchievement.Call("getRevealedImageUrl");
achievement.UnlockedImageUrl = javaAchievement.Call("getUnlockedImageUrl");
achievement.IsIncremental =
javaAchievement.Call("getType") == 1 /* TYPE_INCREMENTAL */;
if (achievement.IsIncremental)
{
achievement.CurrentSteps = javaAchievement.Call("getCurrentSteps");
achievement.TotalSteps = javaAchievement.Call("getTotalSteps");
}
int state = javaAchievement.Call("getState");
achievement.IsUnlocked = state == 0 /* STATE_UNLOCKED */;
achievement.IsRevealed = state == 1 /* STATE_REVEALED */;
}
result[i] = achievement;
}
achievementBuffer.Call("release");
InvokeCallbackOnGameThread(callback, result);
}
});
AddOnFailureListenerWithSignOut(
task,
exception =>
{
Debug.Log("LoadAchievements failed: " + exception.Call("toString"));
InvokeCallbackOnGameThread(callback, new Achievement[0]);
});
}
}
///
///
public void UnlockAchievement(string achId, Action callback)
{
if (!IsAuthenticated())
{
InvokeCallbackOnGameThread(callback, false);
return;
}
using (var achievementsClient = getAchievementsClient())
{
achievementsClient.Call("unlock", achId);
InvokeCallbackOnGameThread(callback, true);
}
}
///
///
public void RevealAchievement(string achId, Action callback)
{
if (!IsAuthenticated())
{
InvokeCallbackOnGameThread(callback, false);
return;
}
using (var achievementsClient = getAchievementsClient())
{
achievementsClient.Call("reveal", achId);
InvokeCallbackOnGameThread(callback, true);
}
}
///
///
public void IncrementAchievement(string achId, int steps, Action callback)
{
if (!IsAuthenticated())
{
InvokeCallbackOnGameThread(callback, false);
return;
}
using (var achievementsClient = getAchievementsClient())
{
achievementsClient.Call("increment", achId, steps);
InvokeCallbackOnGameThread(callback, true);
}
}
///
///
public void SetStepsAtLeast(string achId, int steps, Action callback)
{
if (!IsAuthenticated())
{
InvokeCallbackOnGameThread(callback, false);
return;
}
using (var achievementsClient = getAchievementsClient())
{
achievementsClient.Call("setSteps", achId, steps);
InvokeCallbackOnGameThread(callback, true);
}
}
///
///
public void ShowAchievementsUI(Action callback)
{
if (!IsAuthenticated())
{
InvokeCallbackOnGameThread(callback, UIStatus.NotAuthorized);
return;
}
AndroidHelperFragment.ShowAchievementsUI(GetUiSignOutCallbackOnGameThread(callback));
}
///
///
public int LeaderboardMaxResults()
{
return mLeaderboardMaxResults;
}
///
///
public void ShowLeaderboardUI(string leaderboardId, LeaderboardTimeSpan span, Action callback)
{
if (!IsAuthenticated())
{
InvokeCallbackOnGameThread(callback, UIStatus.NotAuthorized);
return;
}
if (leaderboardId == null)
{
AndroidHelperFragment.ShowAllLeaderboardsUI(GetUiSignOutCallbackOnGameThread(callback));
}
else
{
AndroidHelperFragment.ShowLeaderboardUI(leaderboardId, span,
GetUiSignOutCallbackOnGameThread(callback));
}
}
private void AddOnFailureListenerWithSignOut(AndroidJavaObject task, Action callback)
{
AndroidTaskUtils.AddOnFailureListener(
task,
exception =>
{
var statusCode = exception.Call("getStatusCode");
if (statusCode == /* CommonStatusCodes.SignInRequired */ 4 ||
statusCode == /* GamesClientStatusCodes.CLIENT_RECONNECT_REQUIRED */ 26502)
{
SignOut();
}
callback(exception);
});
}
private Action GetUiSignOutCallbackOnGameThread(Action callback)
{
Action uiCallback = (status) =>
{
if (status == UIStatus.NotAuthorized)
{
SignOut(() =>
{
if (callback != null)
{
callback(status);
}
});
}
else
{
if (callback != null)
{
callback(status);
}
}
};
return AsOnGameThreadCallback(uiCallback);
}
///
///
public void LoadScores(string leaderboardId, LeaderboardStart start,
int rowCount, LeaderboardCollection collection,
LeaderboardTimeSpan timeSpan,
Action callback)
{
using (var client = getLeaderboardsClient())
{
string loadScoresMethod =
start == LeaderboardStart.TopScores ? "loadTopScores" : "loadPlayerCenteredScores";
using (var task = client.Call(
loadScoresMethod,
leaderboardId,
AndroidJavaConverter.ToLeaderboardVariantTimeSpan(timeSpan),
AndroidJavaConverter.ToLeaderboardVariantCollection(collection),
rowCount))
{
AndroidTaskUtils.AddOnSuccessListener(
task,
annotatedData =>
{
using (var leaderboardScores = annotatedData.Call("get"))
{
InvokeCallbackOnGameThread(callback, CreateLeaderboardScoreData(
leaderboardId,
collection,
timeSpan,
annotatedData.Call("isStale")
? ResponseStatus.SuccessWithStale
: ResponseStatus.Success,
leaderboardScores));
leaderboardScores.Call("release");
}
});
AddOnFailureListenerWithSignOut(task, exception =>
{
AndroidHelperFragment.IsResolutionRequired(
exception, resolutionRequired =>
{
if (resolutionRequired)
{
mFriendsResolutionException = exception.Call(
"getResolution");
InvokeCallbackOnGameThread(
callback, new LeaderboardScoreData(leaderboardId,
ResponseStatus.ResolutionRequired));
}
else
{
mFriendsResolutionException = null;
}
});
Debug.Log("LoadScores failed: " + exception.Call("toString"));
InvokeCallbackOnGameThread(
callback, new LeaderboardScoreData(leaderboardId,
ResponseStatus.InternalError));
});
}
}
}
///
///
public void LoadMoreScores(ScorePageToken token, int rowCount,
Action callback)
{
using (var client = getLeaderboardsClient())
using (var task = client.Call("loadMoreScores",
token.InternalObject, rowCount, AndroidJavaConverter.ToPageDirection(token.Direction)))
{
AndroidTaskUtils.AddOnSuccessListener(
task,
annotatedData =>
{
using (var leaderboardScores = annotatedData.Call("get"))
{
InvokeCallbackOnGameThread(callback, CreateLeaderboardScoreData(
token.LeaderboardId,
token.Collection,
token.TimeSpan,
annotatedData.Call("isStale")
? ResponseStatus.SuccessWithStale
: ResponseStatus.Success,
leaderboardScores));
leaderboardScores.Call("release");
}
});
AddOnFailureListenerWithSignOut(task, exception =>
{
AndroidHelperFragment.IsResolutionRequired(exception, resolutionRequired =>
{
if (resolutionRequired)
{
mFriendsResolutionException =
exception.Call("getResolution");
InvokeCallbackOnGameThread(
callback, new LeaderboardScoreData(token.LeaderboardId,
ResponseStatus.ResolutionRequired));
}
else
{
mFriendsResolutionException = null;
}
});
Debug.Log("LoadMoreScores failed: " + exception.Call("toString"));
InvokeCallbackOnGameThread(
callback, new LeaderboardScoreData(token.LeaderboardId,
ResponseStatus.InternalError));
});
}
}
private LeaderboardScoreData CreateLeaderboardScoreData(
string leaderboardId,
LeaderboardCollection collection,
LeaderboardTimeSpan timespan,
ResponseStatus status,
AndroidJavaObject leaderboardScoresJava)
{
LeaderboardScoreData leaderboardScoreData = new LeaderboardScoreData(leaderboardId, status);
var scoresBuffer = leaderboardScoresJava.Call("getScores");
int count = scoresBuffer.Call("getCount");
for (int i = 0; i < count; ++i)
{
using (var leaderboardScore = scoresBuffer.Call("get", i))
{
long timestamp = leaderboardScore.Call("getTimestampMillis");
System.DateTime date = AndroidJavaConverter.ToDateTime(timestamp);
ulong rank = (ulong) leaderboardScore.Call("getRank");
string scoreHolderId = "";
using (var scoreHolder = leaderboardScore.Call("getScoreHolder"))
{
scoreHolderId = scoreHolder.Call("getPlayerId");
}
ulong score = (ulong) leaderboardScore.Call("getRawScore");
string metadata = leaderboardScore.Call("getScoreTag");
leaderboardScoreData.AddScore(new PlayGamesScore(date, leaderboardId,
rank, scoreHolderId, score, metadata));
}
}
leaderboardScoreData.NextPageToken = new ScorePageToken(scoresBuffer, leaderboardId, collection,
timespan, ScorePageDirection.Forward);
leaderboardScoreData.PrevPageToken = new ScorePageToken(scoresBuffer, leaderboardId, collection,
timespan, ScorePageDirection.Backward);
using (var leaderboard = leaderboardScoresJava.Call("getLeaderboard"))
using (var variants = leaderboard.Call("getVariants"))
using (var variant = variants.Call("get", 0))
{
leaderboardScoreData.Title = leaderboard.Call("getDisplayName");
if (variant.Call("hasPlayerInfo"))
{
System.DateTime date = AndroidJavaConverter.ToDateTime(0);
ulong rank = (ulong) variant.Call("getPlayerRank");
ulong score = (ulong) variant.Call("getRawPlayerScore");
string metadata = variant.Call("getPlayerScoreTag");
leaderboardScoreData.PlayerScore = new PlayGamesScore(date, leaderboardId,
rank, mUser.id, score, metadata);
}
leaderboardScoreData.ApproximateCount = (ulong) variant.Call("getNumScores");
}
return leaderboardScoreData;
}
///
///
public void SubmitScore(string leaderboardId, long score, Action callback)
{
if (!IsAuthenticated())
{
InvokeCallbackOnGameThread(callback, false);
}
using (var client = getLeaderboardsClient())
{
client.Call("submitScore", leaderboardId, score);
InvokeCallbackOnGameThread(callback, true);
}
}
///
///
public void SubmitScore(string leaderboardId, long score, string metadata,
Action callback)
{
if (!IsAuthenticated())
{
InvokeCallbackOnGameThread(callback, false);
}
using (var client = getLeaderboardsClient())
{
client.Call("submitScore", leaderboardId, score, metadata);
InvokeCallbackOnGameThread(callback, true);
}
}
public void RequestPermissions(string[] scopes, Action callback)
{
callback = AsOnGameThreadCallback(callback);
mTokenClient.RequestPermissions(scopes, code =>
{
UpdateClients();
callback(code);
});
}
private void UpdateClients()
{
lock (GameServicesLock)
{
var account = mTokenClient.GetAccount();
mSavedGameClient = new AndroidSavedGameClient(this, account);
mEventsClient = new AndroidEventsClient(account);
mVideoClient = new AndroidVideoClient(mVideoClient.IsCaptureSupported(), account);
}
}
/// Returns whether or not user has given permissions for given scopes.
///
public bool HasPermissions(string[] scopes)
{
return mTokenClient.HasPermissions(scopes);
}
///
///
public ISavedGameClient GetSavedGameClient()
{
lock (GameServicesLock)
{
return mSavedGameClient;
}
}
///
///
public IEventsClient GetEventsClient()
{
lock (GameServicesLock)
{
return mEventsClient;
}
}
///
///
public IVideoClient GetVideoClient()
{
lock (GameServicesLock)
{
return mVideoClient;
}
}
private AndroidJavaObject getAchievementsClient()
{
return mGamesClass.CallStatic("getAchievementsClient",
AndroidHelperFragment.GetActivity(), mTokenClient.GetAccount());
}
private AndroidJavaObject getGamesClient()
{
return mGamesClass.CallStatic("getGamesClient", AndroidHelperFragment.GetActivity(),
mTokenClient.GetAccount());
}
private AndroidJavaObject getPlayersClient()
{
return mGamesClass.CallStatic("getPlayersClient", AndroidHelperFragment.GetActivity(),
mTokenClient.GetAccount());
}
private AndroidJavaObject getLeaderboardsClient()
{
return mGamesClass.CallStatic("getLeaderboardsClient",
AndroidHelperFragment.GetActivity(), mTokenClient.GetAccount());
}
private AndroidJavaObject getPlayerStatsClient()
{
return mGamesClass.CallStatic("getPlayerStatsClient",
AndroidHelperFragment.GetActivity(), mTokenClient.GetAccount());
}
private AndroidJavaObject getVideosClient()
{
return mGamesClass.CallStatic("getVideosClient", AndroidHelperFragment.GetActivity(),
mTokenClient.GetAccount());
}
}
}
#endif