// // Copyright (C) 2015 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. // #if UNITY_ANDROID namespace GooglePlayGames.Android { using System; using System.Linq; using BasicApi; using OurUtils; using UnityEngine; using System.Collections.Generic; internal class AndroidTokenClient : TokenClient { private const string HelperFragmentClass = "com.google.games.bridge.HelperFragment"; // These are the configuration values. private bool requestEmail; private bool requestAuthCode; private bool requestIdToken; private List oauthScopes; private string webClientId; private bool forceRefresh; private bool hidePopups; private string accountName; // These are the results private AndroidJavaObject account; private string email; private string authCode; private string idToken; public void SetRequestAuthCode(bool flag, bool forceRefresh) { requestAuthCode = flag; this.forceRefresh = forceRefresh; } public void SetRequestEmail(bool flag) { requestEmail = flag; } public void SetRequestIdToken(bool flag) { requestIdToken = flag; } public void SetWebClientId(string webClientId) { this.webClientId = webClientId; } public void SetHidePopups(bool flag) { this.hidePopups = flag; } public void SetAccountName(string accountName) { this.accountName = accountName; } public void AddOauthScopes(params string[] scopes) { if (scopes != null) { if (oauthScopes == null) { oauthScopes = new List(); } oauthScopes.AddRange(scopes); } } public void Signout() { account = null; authCode = null; email = null; idToken = null; PlayGamesHelperObject.RunOnGameThread(() => { Debug.Log("Calling Signout in token client"); AndroidJavaClass cls = new AndroidJavaClass(HelperFragmentClass); cls.CallStatic("signOut", AndroidHelperFragment.GetActivity()); }); } /// Gets the email selected by the current player. /// This is not necessarily the email address of the player. It /// is just the account selected by the player from a list of accounts /// present on the device. /// /// A string representing the email. public string GetEmail() { return email; } public string GetAuthCode() { return authCode; } /// Gets the OpenID Connect ID token for authentication with a server backend. /// Server client ID from console.developers.google.com or the Play Games /// services console. /// A callback to be invoked after token is retrieved. Will be passed null value /// on failure. public string GetIdToken() { return idToken; } public void FetchTokens(bool silent, Action callback) { PlayGamesHelperObject.RunOnGameThread(() => DoFetchToken(silent, callback)); } public void RequestPermissions(string[] scopes, Action callback) { using (var bridgeClass = new AndroidJavaClass(HelperFragmentClass)) using (var currentActivity = AndroidHelperFragment.GetActivity()) using (var task = bridgeClass.CallStatic("showRequestPermissionsUi", currentActivity, oauthScopes.Union(scopes).ToArray())) { AndroidTaskUtils.AddOnSuccessListener(task, /* disposeResult= */ false, accountWithNewScopes => { if (accountWithNewScopes == null) { callback(SignInStatus.InternalError); return; } account = accountWithNewScopes; email = account.Call("getEmail"); idToken = account.Call("getIdToken"); authCode = account.Call("getServerAuthCode"); oauthScopes = oauthScopes.Union(scopes).ToList(); callback(SignInStatus.Success); }); AndroidTaskUtils.AddOnFailureListener(task, e => { if (!Misc.IsApiException(e)) { OurUtils.Logger.e("Exception requesting new permissions" + e.Call("toString")); return; } var failCode = SignInHelper.ToSignInStatus(e.Call("getStatusCode")); OurUtils.Logger.e("Exception requesting new permissions: " + failCode); callback(failCode); }); } } /// Returns whether or not user has given permissions for given scopes. /// array of scopes /// true, if given, false otherwise. public bool HasPermissions(string[] scopes) { using (var bridgeClass = new AndroidJavaClass(HelperFragmentClass)) using (var currentActivity = AndroidHelperFragment.GetActivity()) { return bridgeClass.CallStatic("hasPermissions", currentActivity, scopes); } } private void DoFetchToken(bool silent, Action callback) { try { using (var bridgeClass = new AndroidJavaClass(HelperFragmentClass)) using (var currentActivity = AndroidHelperFragment.GetActivity()) using (var pendingResult = bridgeClass.CallStatic( "fetchToken", currentActivity, silent, requestAuthCode, requestEmail, requestIdToken, webClientId, forceRefresh, oauthScopes.ToArray(), hidePopups, accountName)) { pendingResult.Call("setResultCallback", new ResultCallbackProxy( tokenResult => { account = tokenResult.Call("getAccount"); authCode = tokenResult.Call("getAuthCode"); email = tokenResult.Call("getEmail"); idToken = tokenResult.Call("getIdToken"); callback(tokenResult.Call("getStatusCode")); })); } } catch (Exception e) { OurUtils.Logger.e("Exception launching token request: " + e.Message); OurUtils.Logger.e(e.ToString()); } } public AndroidJavaObject GetAccount() { return account; } /// /// Gets another server auth code. /// /// This method should be called after authenticating, and exchanging /// the initial server auth code for a token. This is implemented by signing in /// silently, which if successful returns almost immediately and with a new /// server auth code. /// /// Calls Authenticate if needed when /// retrieving another auth code. /// Callback. public void GetAnotherServerAuthCode(bool reAuthenticateIfNeeded, Action callback) { PlayGamesHelperObject.RunOnGameThread(() => DoGetAnotherServerAuthCode(reAuthenticateIfNeeded, callback)); } private void DoGetAnotherServerAuthCode(bool reAuthenticateIfNeeded, Action callback) { try { using (var bridgeClass = new AndroidJavaClass(HelperFragmentClass)) using (var currentActivity = AndroidHelperFragment.GetActivity()) using (var pendingResult = bridgeClass.CallStatic( "fetchToken", currentActivity, /* silent= */ reAuthenticateIfNeeded, /* requestAuthCode= */ true, /* requestEmail= */ false, /* requestIdToken= */ false, webClientId, /* forceRefresh= */ false, oauthScopes.ToArray(), /* hidePopups= */ true, /* accountName= */ "")) { pendingResult.Call("setResultCallback", new ResultCallbackProxy( tokenResult => { callback(tokenResult.Call("getAuthCode")); })); } } catch (Exception e) { OurUtils.Logger.e("Exception launching token request: " + e.Message); OurUtils.Logger.e(e.ToString()); } } private class ResultCallbackProxy : AndroidJavaProxy { private Action mCallback; public ResultCallbackProxy(Action callback) : base("com/google/android/gms/common/api/ResultCallback") { mCallback = callback; } public void onResult(AndroidJavaObject tokenResult) { mCallback(tokenResult); } } } } #endif