PlaneRun/Assets/GooglePlayGames/com.google.play.games/Runtime/Scripts/Platforms/Android/AndroidClient.cs

1053 lines
44 KiB
C#

// <copyright file="NativeClient.cs" company="Google Inc.">
// 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.
// </copyright>
#if UNITY_ANDROID
#pragma warning disable 0642 // Possible mistaken empty statement
namespace GooglePlayGames.Android
{
using GooglePlayGames.BasicApi;
using GooglePlayGames.BasicApi.Events;
using GooglePlayGames.BasicApi.SavedGame;
using GooglePlayGames.OurUtils;
using System;
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 static String PlayGamesSdkClassName =
"com.google.android.gms.games.PlayGamesSdk";
private volatile ISavedGameClient mSavedGameClient;
private volatile IEventsClient mEventsClient;
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.PlayGames");
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()
{
PlayGamesHelperObject.CreateObject();
InitializeSdk();
}
private static void InitializeSdk() {
using (var playGamesSdkClass = new AndroidJavaClass(PlayGamesSdkClassName)) {
playGamesSdkClass.CallStatic("initialize", AndroidHelperFragment.GetActivity());
}
}
public void Authenticate(Action<SignInStatus> callback)
{
Authenticate( /* isAutoSignIn= */ true, callback);
}
public void ManuallyAuthenticate(Action<SignInStatus> callback)
{
Authenticate( /* isAutoSignIn= */ false, callback);
}
private void Authenticate(bool isAutoSignIn, Action<SignInStatus> callback)
{
callback = AsOnGameThreadCallback(callback);
lock (AuthStateLock)
{
// If the user is already authenticated, just fire the callback, we don't need
// any additional work.
if (mAuthState == AuthState.Authenticated)
{
OurUtils.Logger.d("Already authenticated.");
InvokeCallbackOnGameThread(callback, SignInStatus.Success);
return;
}
}
string methodName = isAutoSignIn ? "isAuthenticated" : "signIn";
OurUtils.Logger.d("Starting Auth using the method " + methodName);
using (var client = getGamesSignInClient())
using (
var task = client.Call<AndroidJavaObject>(methodName))
{
AndroidTaskUtils.AddOnSuccessListener<AndroidJavaObject>(task, authenticationResult =>
{
bool isAuthenticated = authenticationResult.Call<bool>("isAuthenticated");
SignInOnResult(isAuthenticated, callback);
});
AndroidTaskUtils.AddOnFailureListener(task, exception =>
{
OurUtils.Logger.e("Authentication failed - " + exception.Call<string>("toString"));
callback(SignInStatus.InternalError);
});
}
}
private void SignInOnResult(bool isAuthenticated, Action<SignInStatus> callback)
{
if (isAuthenticated)
{
using (var signInTasks = new AndroidJavaObject("java.util.ArrayList"))
{
AndroidJavaObject taskGetPlayer =
getPlayersClient().Call<AndroidJavaObject>("getCurrentPlayer");
signInTasks.Call<bool>("add", taskGetPlayer);
using (var tasks = new AndroidJavaClass(TasksClassName))
using (var allTask = tasks.CallStatic<AndroidJavaObject>("whenAll", signInTasks))
{
AndroidTaskUtils.AddOnCompleteListener<AndroidJavaObject>(
allTask,
completeTask =>
{
if (completeTask.Call<bool>("isSuccessful"))
{
using (var resultObject = taskGetPlayer.Call<AndroidJavaObject>("getResult"))
{
mUser = AndroidJavaConverter.ToPlayer(resultObject);
}
lock (GameServicesLock)
{
mSavedGameClient = new AndroidSavedGameClient(this);
mEventsClient = new AndroidEventsClient();
}
mAuthState = AuthState.Authenticated;
InvokeCallbackOnGameThread(callback, SignInStatus.Success);
OurUtils.Logger.d("Authentication succeeded");
LoadAchievements(ignore => { });
}
else
{
if (completeTask.Call<bool>("isCanceled"))
{
InvokeCallbackOnGameThread(callback, SignInStatus.Canceled);
return;
}
using (var exception = completeTask.Call<AndroidJavaObject>("getException"))
{
OurUtils.Logger.e(
"Authentication failed - " + exception.Call<string>("toString"));
InvokeCallbackOnGameThread(callback, SignInStatus.InternalError);
}
}
}
);
}
}
}
else
{
lock (AuthStateLock)
{
OurUtils.Logger.e("Returning an error code.");
InvokeCallbackOnGameThread(callback, SignInStatus.Canceled);
}
}
}
public void RequestServerSideAccess(bool forceRefreshToken, Action<string> callback)
{
callback = AsOnGameThreadCallback(callback);
if (!GameInfo.WebClientIdInitialized())
{
throw new InvalidOperationException("Requesting server side access requires web " +
"client id to be configured.");
}
using (var client = getGamesSignInClient())
using (var task = client.Call<AndroidJavaObject>("requestServerSideAccess",
GameInfo.WebClientId, forceRefreshToken))
{
AndroidTaskUtils.AddOnSuccessListener<string>(
task,
authCode => callback(authCode)
);
AndroidTaskUtils.AddOnFailureListener(task, exception =>
{
OurUtils.Logger.e("Requesting server side access task failed - " +
exception.Call<string>("toString"));
callback(null);
});
}
}
public void RequestRecallAccessToken(Action<RecallAccess> callback)
{
callback = AsOnGameThreadCallback(callback);
using (var client = getRecallClient())
using (var task = client.Call<AndroidJavaObject>("requestRecallAccess"))
{
AndroidTaskUtils.AddOnSuccessListener<AndroidJavaObject>(
task,
recallAccess => {
var sessionId = recallAccess.Call<string>("getSessionId");
callback(new RecallAccess(sessionId));
}
);
AndroidTaskUtils.AddOnFailureListener(task, exception =>
{
OurUtils.Logger.e("Requesting Recall access task failed - " +
exception.Call<string>("toString"));
callback(null);
});
}
}
private static Action<T> AsOnGameThreadCallback<T>(Action<T> 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<T>(Action<T> callback, T data)
{
if (callback == null)
{
return;
}
PlayGamesHelperObject.RunOnGameThread(() => { callback(data); });
}
private static Action<T1, T2> AsOnGameThreadCallback<T1, T2>(
Action<T1, T2> toInvokeOnGameThread)
{
return (result1, result2) =>
{
if (toInvokeOnGameThread == null)
{
return;
}
PlayGamesHelperObject.RunOnGameThread(() => toInvokeOnGameThread(result1, result2));
};
}
private static void InvokeCallbackOnGameThread<T1, T2>(Action<T1, T2> callback, T1 t1, T2 t2)
{
if (callback == null)
{
return;
}
PlayGamesHelperObject.RunOnGameThread(() => { callback(t1, t2); });
}
public bool IsAuthenticated()
{
lock (AuthStateLock)
{
return mAuthState == AuthState.Authenticated;
}
}
public void LoadFriends(Action<bool> callback)
{
LoadAllFriends(mFriendsMaxResults, /* forceReload= */ false, /* loadMore= */ false, callback);
}
private void LoadAllFriends(int pageSize, bool forceReload, bool loadMore,
Action<bool> 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<LoadFriendsStatus> callback)
{
LoadFriendsPaginated(pageSize, /* isLoadMore= */ false, /* forceReload= */ forceReload,
callback);
}
public void LoadMoreFriends(int pageSize, Action<LoadFriendsStatus> callback)
{
LoadFriendsPaginated(pageSize, /* isLoadMore= */ true, /* forceReload= */ false,
callback);
}
private void LoadFriendsPaginated(int pageSize, bool isLoadMore, bool forceReload,
Action<LoadFriendsStatus> callback)
{
mFriendsResolutionException = null;
using (var playersClient = getPlayersClient())
using (var task = isLoadMore
? playersClient.Call<AndroidJavaObject>("loadMoreFriends", pageSize)
: playersClient.Call<AndroidJavaObject>("loadFriends", pageSize,
forceReload))
{
AndroidTaskUtils.AddOnSuccessListener<AndroidJavaObject>(
task, annotatedData =>
{
using (var playersBuffer = annotatedData.Call<AndroidJavaObject>("get"))
{
AndroidJavaObject metadata = playersBuffer.Call<AndroidJavaObject>("getMetadata");
var areMoreFriendsToLoad = metadata != null &&
metadata.Call<AndroidJavaObject>("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<AndroidJavaObject>("getResolution");
mLastLoadFriendsStatus = LoadFriendsStatus.ResolutionRequired;
mFriends = new IUserProfile[0];
InvokeCallbackOnGameThread(callback, LoadFriendsStatus.ResolutionRequired);
}
else
{
mFriendsResolutionException = null;
if (IsApiException(exception))
{
var statusCode = exception.Call<int>("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<string>("toString"));
InvokeCallbackOnGameThread(callback, LoadFriendsStatus.InternalError);
}
});
return;
});
}
}
private static bool IsApiException(AndroidJavaObject exception) {
var exceptionClassName = exception.Call<AndroidJavaObject>("getClass")
.Call<String>("getName");
return exceptionClassName == "com.google.android.gms.common.api.ApiException";
}
public LoadFriendsStatus GetLastLoadFriendsStatus()
{
return mLastLoadFriendsStatus;
}
public void AskForLoadFriendsResolution(Action<UIStatus> 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<AndroidJavaObject>("loadFriends", /* pageSize= */ 1,
/* forceReload= */ false))
{
AndroidTaskUtils.AddOnSuccessListener<AndroidJavaObject>(
task, annotatedData => { InvokeCallbackOnGameThread(callback, UIStatus.Valid); });
AndroidTaskUtils.AddOnFailureListener(task, exception =>
{
AndroidHelperFragment.IsResolutionRequired(exception, resolutionRequired =>
{
if (resolutionRequired)
{
mFriendsResolutionException =
exception.Call<AndroidJavaObject>("getResolution");
AndroidHelperFragment.AskForLoadFriendsResolution(
mFriendsResolutionException, AsOnGameThreadCallback(callback));
return;
}
if (IsApiException(exception))
{
var statusCode = exception.Call<int>("getStatusCode");
if (statusCode ==
/* GamesClientStatusCodes.NETWORK_ERROR_NO_DATA */ 26504)
{
InvokeCallbackOnGameThread(callback, UIStatus.NetworkError);
return;
}
}
OurUtils.Logger.e("LoadFriends failed: " +
exception.Call<string>("toString"));
InvokeCallbackOnGameThread(callback, UIStatus.InternalError);
});
});
}
}
else
{
AndroidHelperFragment.AskForLoadFriendsResolution(mFriendsResolutionException,
AsOnGameThreadCallback(callback));
}
}
public void ShowCompareProfileWithAlternativeNameHintsUI(string playerId,
string otherPlayerInGameName,
string currentPlayerInGameName,
Action<UIStatus> callback)
{
AndroidHelperFragment.ShowCompareProfileWithAlternativeNameHintsUI(
playerId, otherPlayerInGameName, currentPlayerInGameName,
AsOnGameThreadCallback(callback));
}
public void GetFriendsListVisibility(bool forceReload,
Action<FriendsListVisibilityStatus> callback)
{
using (var playersClient = getPlayersClient())
using (
var task = playersClient.Call<AndroidJavaObject>("getCurrentPlayer", forceReload))
{
AndroidTaskUtils.AddOnSuccessListener<AndroidJavaObject>(task, annotatedData =>
{
AndroidJavaObject currentPlayerInfo =
annotatedData.Call<AndroidJavaObject>("get").Call<AndroidJavaObject>(
"getCurrentPlayerInfo");
int playerListVisibility =
currentPlayerInfo.Call<int>("getFriendsListVisibilityStatus");
InvokeCallbackOnGameThread(callback,
AndroidJavaConverter.ToFriendsListVisibilityStatus(playerListVisibility));
});
AndroidTaskUtils.AddOnFailureListener(task, exception =>
{
InvokeCallbackOnGameThread(callback, FriendsListVisibilityStatus.NetworkError);
return;
});
}
}
public IUserProfile[] GetFriends()
{
return mFriends;
}
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 GetPlayerStats(Action<CommonStatusCodes, PlayerStats> callback)
{
using (var playerStatsClient = getPlayerStatsClient())
using (var task = playerStatsClient.Call<AndroidJavaObject>("loadPlayerStats", /* forceReload= */ false))
{
AndroidTaskUtils.AddOnSuccessListener<AndroidJavaObject>(
task,
annotatedData =>
{
using (var playerStatsJava = annotatedData.Call<AndroidJavaObject>("get"))
{
int numberOfPurchases = playerStatsJava.Call<int>("getNumberOfPurchases");
float avgSessionLength = playerStatsJava.Call<float>("getAverageSessionLength");
int daysSinceLastPlayed = playerStatsJava.Call<int>("getDaysSinceLastPlayed");
int numberOfSessions = playerStatsJava.Call<int>("getNumberOfSessions");
float sessionPercentile = playerStatsJava.Call<float>("getSessionPercentile");
float spendPercentile = playerStatsJava.Call<float>("getSpendPercentile");
float spendProbability = playerStatsJava.Call<float>("getSpendProbability");
float churnProbability = playerStatsJava.Call<float>("getChurnProbability");
float highSpenderProbability = playerStatsJava.Call<float>("getHighSpenderProbability");
float totalSpendNext28Days = playerStatsJava.Call<float>("getTotalSpendNext28Days");
PlayerStats result = new PlayerStats(
numberOfPurchases,
avgSessionLength,
daysSinceLastPlayed,
numberOfSessions,
sessionPercentile,
spendPercentile,
spendProbability,
churnProbability,
highSpenderProbability,
totalSpendNext28Days);
InvokeCallbackOnGameThread(callback, CommonStatusCodes.Success, result);
}
});
AndroidTaskUtils.AddOnFailureListener(task, exception =>
{
OurUtils.Logger.e("GetPlayerStats failed: " + exception.Call<string>("toString"));
var statusCode = IsAuthenticated()
? CommonStatusCodes.InternalError
: CommonStatusCodes.SignInRequired;
InvokeCallbackOnGameThread(callback, statusCode, new PlayerStats());
});
}
}
public void LoadUsers(string[] userIds, Action<IUserProfile[]> 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<AndroidJavaObject>("loadPlayer", userIds[i]))
{
AndroidTaskUtils.AddOnSuccessListener<AndroidJavaObject>(
task,
annotatedData =>
{
using (var player = annotatedData.Call<AndroidJavaObject>("get"))
{
string playerId = player.Call<string>("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);
}
}
}
});
AndroidTaskUtils.AddOnFailureListener(task, exception =>
{
OurUtils.Logger.e("LoadUsers failed for index " + i +
" with: " + exception.Call<string>("toString"));
lock (countLock)
{
++resultCount;
if (resultCount == count)
{
InvokeCallbackOnGameThread(callback, users);
}
}
});
}
}
}
}
public void LoadAchievements(Action<Achievement[]> callback)
{
using (var achievementsClient = getAchievementsClient())
using (var task = achievementsClient.Call<AndroidJavaObject>("load", /* forceReload= */ false))
{
AndroidTaskUtils.AddOnSuccessListener<AndroidJavaObject>(
task,
annotatedData =>
{
using (var achievementBuffer = annotatedData.Call<AndroidJavaObject>("get"))
{
int count = achievementBuffer.Call<int>("getCount");
Achievement[] result = new Achievement[count];
for (int i = 0; i < count; ++i)
{
Achievement achievement = new Achievement();
using (var javaAchievement = achievementBuffer.Call<AndroidJavaObject>("get", i))
{
achievement.Id = javaAchievement.Call<string>("getAchievementId");
achievement.Description = javaAchievement.Call<string>("getDescription");
achievement.Name = javaAchievement.Call<string>("getName");
achievement.Points = javaAchievement.Call<ulong>("getXpValue");
long timestamp = javaAchievement.Call<long>("getLastUpdatedTimestamp");
achievement.LastModifiedTime = AndroidJavaConverter.ToDateTime(timestamp);
achievement.RevealedImageUrl = javaAchievement.Call<string>("getRevealedImageUrl");
achievement.UnlockedImageUrl = javaAchievement.Call<string>("getUnlockedImageUrl");
achievement.IsIncremental =
javaAchievement.Call<int>("getType") == 1 /* TYPE_INCREMENTAL */;
if (achievement.IsIncremental)
{
achievement.CurrentSteps = javaAchievement.Call<int>("getCurrentSteps");
achievement.TotalSteps = javaAchievement.Call<int>("getTotalSteps");
}
int state = javaAchievement.Call<int>("getState");
achievement.IsUnlocked = state == 0 /* STATE_UNLOCKED */;
achievement.IsRevealed = state == 1 /* STATE_REVEALED */;
}
result[i] = achievement;
}
achievementBuffer.Call("release");
InvokeCallbackOnGameThread(callback, result);
}
});
AndroidTaskUtils.AddOnFailureListener(task, exception =>
{
OurUtils.Logger.e("LoadAchievements failed: " + exception.Call<string>("toString"));
InvokeCallbackOnGameThread(callback, new Achievement[0]);
});
}
}
public void UnlockAchievement(string achId, Action<bool> callback)
{
if (!IsAuthenticated())
{
InvokeCallbackOnGameThread(callback, false);
return;
}
using (var achievementsClient = getAchievementsClient())
{
achievementsClient.Call("unlock", achId);
InvokeCallbackOnGameThread(callback, true);
}
}
public void RevealAchievement(string achId, Action<bool> 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<bool> 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<bool> callback)
{
if (!IsAuthenticated())
{
InvokeCallbackOnGameThread(callback, false);
return;
}
using (var achievementsClient = getAchievementsClient())
{
achievementsClient.Call("setSteps", achId, steps);
InvokeCallbackOnGameThread(callback, true);
}
}
public void ShowAchievementsUI(Action<UIStatus> callback)
{
if (!IsAuthenticated())
{
InvokeCallbackOnGameThread(callback, UIStatus.NotAuthorized);
return;
}
AndroidHelperFragment.ShowAchievementsUI(AsOnGameThreadCallback(callback));
}
public int LeaderboardMaxResults()
{
return mLeaderboardMaxResults;
}
public void ShowLeaderboardUI(string leaderboardId, LeaderboardTimeSpan span, Action<UIStatus> callback)
{
if (!IsAuthenticated())
{
InvokeCallbackOnGameThread(callback, UIStatus.NotAuthorized);
return;
}
if (leaderboardId == null)
{
AndroidHelperFragment.ShowAllLeaderboardsUI(AsOnGameThreadCallback(callback));
}
else
{
AndroidHelperFragment.ShowLeaderboardUI(leaderboardId, span,
AsOnGameThreadCallback(callback));
}
}
public void LoadScores(string leaderboardId, LeaderboardStart start,
int rowCount, LeaderboardCollection collection,
LeaderboardTimeSpan timeSpan,
Action<LeaderboardScoreData> callback)
{
using (var client = getLeaderboardsClient())
{
string loadScoresMethod =
start == LeaderboardStart.TopScores ? "loadTopScores" : "loadPlayerCenteredScores";
using (var task = client.Call<AndroidJavaObject>(
loadScoresMethod,
leaderboardId,
AndroidJavaConverter.ToLeaderboardVariantTimeSpan(timeSpan),
AndroidJavaConverter.ToLeaderboardVariantCollection(collection),
rowCount))
{
AndroidTaskUtils.AddOnSuccessListener<AndroidJavaObject>(
task,
annotatedData =>
{
using (var leaderboardScores = annotatedData.Call<AndroidJavaObject>("get"))
{
InvokeCallbackOnGameThread(callback, CreateLeaderboardScoreData(
leaderboardId,
collection,
timeSpan,
annotatedData.Call<bool>("isStale")
? ResponseStatus.SuccessWithStale
: ResponseStatus.Success,
leaderboardScores));
leaderboardScores.Call("release");
}
});
AndroidTaskUtils.AddOnFailureListener(task, exception =>
{
AndroidHelperFragment.IsResolutionRequired(
exception, resolutionRequired =>
{
if (resolutionRequired)
{
mFriendsResolutionException = exception.Call<AndroidJavaObject>(
"getResolution");
InvokeCallbackOnGameThread(
callback, new LeaderboardScoreData(leaderboardId,
ResponseStatus.ResolutionRequired));
}
else
{
mFriendsResolutionException = null;
}
});
OurUtils.Logger.e("LoadScores failed: " + exception.Call<string>("toString"));
InvokeCallbackOnGameThread(
callback, new LeaderboardScoreData(leaderboardId,
ResponseStatus.InternalError));
});
}
}
}
public void LoadMoreScores(ScorePageToken token, int rowCount,
Action<LeaderboardScoreData> callback)
{
using (var client = getLeaderboardsClient())
using (var task = client.Call<AndroidJavaObject>("loadMoreScores",
token.InternalObject, rowCount, AndroidJavaConverter.ToPageDirection(token.Direction)))
{
AndroidTaskUtils.AddOnSuccessListener<AndroidJavaObject>(
task,
annotatedData =>
{
using (var leaderboardScores = annotatedData.Call<AndroidJavaObject>("get"))
{
InvokeCallbackOnGameThread(callback, CreateLeaderboardScoreData(
token.LeaderboardId,
token.Collection,
token.TimeSpan,
annotatedData.Call<bool>("isStale")
? ResponseStatus.SuccessWithStale
: ResponseStatus.Success,
leaderboardScores));
leaderboardScores.Call("release");
}
});
AndroidTaskUtils.AddOnFailureListener(task, exception =>
{
AndroidHelperFragment.IsResolutionRequired(exception, resolutionRequired =>
{
if (resolutionRequired)
{
mFriendsResolutionException =
exception.Call<AndroidJavaObject>("getResolution");
InvokeCallbackOnGameThread(
callback, new LeaderboardScoreData(token.LeaderboardId,
ResponseStatus.ResolutionRequired));
}
else
{
mFriendsResolutionException = null;
}
});
OurUtils.Logger.e("LoadMoreScores failed: " + exception.Call<string>("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<AndroidJavaObject>("getScores");
int count = scoresBuffer.Call<int>("getCount");
for (int i = 0; i < count; ++i)
{
using (var leaderboardScore = scoresBuffer.Call<AndroidJavaObject>("get", i))
{
long timestamp = leaderboardScore.Call<long>("getTimestampMillis");
System.DateTime date = AndroidJavaConverter.ToDateTime(timestamp);
ulong rank = (ulong) leaderboardScore.Call<long>("getRank");
string scoreHolderId = "";
using (var scoreHolder = leaderboardScore.Call<AndroidJavaObject>("getScoreHolder"))
{
scoreHolderId = scoreHolder.Call<string>("getPlayerId");
}
ulong score = (ulong) leaderboardScore.Call<long>("getRawScore");
string metadata = leaderboardScore.Call<string>("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<AndroidJavaObject>("getLeaderboard"))
using (var variants = leaderboard.Call<AndroidJavaObject>("getVariants"))
using (var variant = variants.Call<AndroidJavaObject>("get", 0))
{
leaderboardScoreData.Title = leaderboard.Call<string>("getDisplayName");
if (variant.Call<bool>("hasPlayerInfo"))
{
System.DateTime date = AndroidJavaConverter.ToDateTime(0);
ulong rank = (ulong) variant.Call<long>("getPlayerRank");
ulong score = (ulong) variant.Call<long>("getRawPlayerScore");
string metadata = variant.Call<string>("getPlayerScoreTag");
leaderboardScoreData.PlayerScore = new PlayGamesScore(date, leaderboardId,
rank, mUser.id, score, metadata);
}
leaderboardScoreData.ApproximateCount = (ulong) variant.Call<long>("getNumScores");
}
return leaderboardScoreData;
}
public void SubmitScore(string leaderboardId, long score, Action<bool> 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<bool> callback)
{
if (!IsAuthenticated())
{
InvokeCallbackOnGameThread(callback, false);
}
using (var client = getLeaderboardsClient())
{
client.Call("submitScore", leaderboardId, score, metadata);
InvokeCallbackOnGameThread(callback, true);
}
}
public ISavedGameClient GetSavedGameClient()
{
lock (GameServicesLock)
{
return mSavedGameClient;
}
}
public IEventsClient GetEventsClient()
{
lock (GameServicesLock)
{
return mEventsClient;
}
}
private AndroidJavaObject getAchievementsClient()
{
return mGamesClass.CallStatic<AndroidJavaObject>("getAchievementsClient",
AndroidHelperFragment.GetActivity());
}
private AndroidJavaObject getPlayersClient()
{
return mGamesClass.CallStatic<AndroidJavaObject>("getPlayersClient", AndroidHelperFragment.GetActivity());
}
private AndroidJavaObject getLeaderboardsClient()
{
return mGamesClass.CallStatic<AndroidJavaObject>("getLeaderboardsClient",
AndroidHelperFragment.GetActivity());
}
private AndroidJavaObject getPlayerStatsClient()
{
return mGamesClass.CallStatic<AndroidJavaObject>("getPlayerStatsClient",
AndroidHelperFragment.GetActivity());
}
private AndroidJavaObject getGamesSignInClient()
{
return mGamesClass.CallStatic<AndroidJavaObject>("getGamesSignInClient",
AndroidHelperFragment.GetActivity());
}
private AndroidJavaObject getRecallClient()
{
return mGamesClass.CallStatic<AndroidJavaObject>("getRecallClient",
AndroidHelperFragment.GetActivity());
}
}
}
#endif