From 58ef93549d4f08667ec2fdbe858d0f82f0a076a3 Mon Sep 17 00:00:00 2001 From: Mehmet Date: Tue, 19 Nov 2019 17:16:46 +0000 Subject: [PATCH 1/3] Add HasPermissions method. --- .../GooglePlayGames/BasicApi/DummyClient.cs | 10 ++++++++ .../BasicApi/IPlayGamesClient.cs | 8 +++++++ .../ISocialPlatform/PlayGamesPlatform.cs | 23 +++++++++++++++++++ .../Platforms/Android/AndroidClient.cs | 7 ++++++ .../Platforms/Android/AndroidTokenClient.cs | 12 ++++++++++ .../GooglePlayGames/Platforms/TokenClient.cs | 2 ++ .../google/games/bridge/HelperFragment.java | 9 ++++++++ 7 files changed, 71 insertions(+) diff --git a/source/PluginDev/Assets/GooglePlayGames/BasicApi/DummyClient.cs b/source/PluginDev/Assets/GooglePlayGames/BasicApi/DummyClient.cs index c946e229e..8859099c9 100644 --- a/source/PluginDev/Assets/GooglePlayGames/BasicApi/DummyClient.cs +++ b/source/PluginDev/Assets/GooglePlayGames/BasicApi/DummyClient.cs @@ -372,6 +372,16 @@ public void SubmitScore( callback.Invoke(false); } } + + /// Returns whether or not user has given permissions for given scopes. + /// + /// array of scopes + /// true, if given, false otherwise. + public bool HasPermissions(string[] scopes) + { + LogUsage(); + return false; + } /// /// Returns a real-time multiplayer client. diff --git a/source/PluginDev/Assets/GooglePlayGames/BasicApi/IPlayGamesClient.cs b/source/PluginDev/Assets/GooglePlayGames/BasicApi/IPlayGamesClient.cs index f0e3a0918..5f938716b 100644 --- a/source/PluginDev/Assets/GooglePlayGames/BasicApi/IPlayGamesClient.cs +++ b/source/PluginDev/Assets/GooglePlayGames/BasicApi/IPlayGamesClient.cs @@ -304,6 +304,14 @@ void SubmitScore(string leaderboardId, long score, void SubmitScore(string leaderboardId, long score, string metadata, Action successOrFailureCalllback); + /// + /// Returns whether or not user has given permissions for given scopes + /// + /// + /// list of scopes + /// true, if given, false otherwise. + bool HasPermissions(string[] scopes); + /// /// Returns a real-time multiplayer client. /// diff --git a/source/PluginDev/Assets/GooglePlayGames/ISocialPlatform/PlayGamesPlatform.cs b/source/PluginDev/Assets/GooglePlayGames/ISocialPlatform/PlayGamesPlatform.cs index 8a15bd5cb..6b2bf97b4 100644 --- a/source/PluginDev/Assets/GooglePlayGames/ISocialPlatform/PlayGamesPlatform.cs +++ b/source/PluginDev/Assets/GooglePlayGames/ISocialPlatform/PlayGamesPlatform.cs @@ -1280,6 +1280,29 @@ public void LoadScores(ILeaderboard board, Action callback) (PlayGamesLeaderboard) board, scoreData, callback)); } + /// Returns whether or not user has given permissions for given scopes. + /// scope + /// true, if given, false otherwise. + public bool HasPermission(string scope) + { + return HasPermissions(new string[] {scope}); + } + + /// Returns whether or not user has given permissions for given scopes. + /// array of scopes + /// true, if given, false otherwise. + public bool HasPermissions(string[] scopes) + { + if (!IsAuthenticated()) + { + GooglePlayGames.OurUtils.Logger.e( + "HasPermissions can only be called after authentication."); + return false; + } + + return mClient.HasPermissions(scopes); + } + /// /// Check if the leaderboard is currently loading. /// diff --git a/source/PluginDev/Assets/GooglePlayGames/Platforms/Android/AndroidClient.cs b/source/PluginDev/Assets/GooglePlayGames/Platforms/Android/AndroidClient.cs index b066093fd..c67d7e19b 100644 --- a/source/PluginDev/Assets/GooglePlayGames/Platforms/Android/AndroidClient.cs +++ b/source/PluginDev/Assets/GooglePlayGames/Platforms/Android/AndroidClient.cs @@ -1019,6 +1019,13 @@ public void SubmitScore(string leaderboardId, long score, string metadata, } } + /// Returns whether or not user has given permissions for given scopes. + /// + public bool HasPermissions(string[] scopes) + { + return mTokenClient.HasPermissions(scopes); + } + /// /// public IRealTimeMultiplayerClient GetRtmpClient() diff --git a/source/PluginDev/Assets/GooglePlayGames/Platforms/Android/AndroidTokenClient.cs b/source/PluginDev/Assets/GooglePlayGames/Platforms/Android/AndroidTokenClient.cs index f26812429..44fd96e32 100644 --- a/source/PluginDev/Assets/GooglePlayGames/Platforms/Android/AndroidTokenClient.cs +++ b/source/PluginDev/Assets/GooglePlayGames/Platforms/Android/AndroidTokenClient.cs @@ -132,6 +132,18 @@ public void FetchTokens(bool silent, Action callback) PlayGamesHelperObject.RunOnGameThread(() => DoFetchToken(silent, callback)); } + /// 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 diff --git a/source/PluginDev/Assets/GooglePlayGames/Platforms/TokenClient.cs b/source/PluginDev/Assets/GooglePlayGames/Platforms/TokenClient.cs index adf2e9ce7..e8e1e525b 100644 --- a/source/PluginDev/Assets/GooglePlayGames/Platforms/TokenClient.cs +++ b/source/PluginDev/Assets/GooglePlayGames/Platforms/TokenClient.cs @@ -67,6 +67,8 @@ void GetAnotherServerAuthCode(bool reAuthenticateIfNeeded, void SetHidePopups(bool flag); void FetchTokens(bool silent, Action callback); + + bool HasPermissions(string[] scopes); } } #endif \ No newline at end of file diff --git a/source/SupportLib/PlayGamesPluginSupport/src/main/java/com/google/games/bridge/HelperFragment.java b/source/SupportLib/PlayGamesPluginSupport/src/main/java/com/google/games/bridge/HelperFragment.java index 81ed3f1da..c9b1a7927 100644 --- a/source/SupportLib/PlayGamesPluginSupport/src/main/java/com/google/games/bridge/HelperFragment.java +++ b/source/SupportLib/PlayGamesPluginSupport/src/main/java/com/google/games/bridge/HelperFragment.java @@ -214,6 +214,15 @@ public static Task showInboxUi(Activity parentActivity){ return request.getTask(); } + public static boolean hasPermissions(Activity parentActivity, String[] scopeUris) { + Scope[] scopes = new Scope[scopeUris.length]; + for (int i = 0; i < scopeUris.length; i++) { + scopes[i] = new Scope(scopeUris[i]); + } + + return GoogleSignIn.hasPermissions(getAccount(parentActivity), scopes); + } + public static void signOut(Activity activity) { GoogleSignInClient signInClient = GoogleSignIn.getClient(activity, GoogleSignInOptions.DEFAULT_GAMES_SIGN_IN); signInClient.signOut(); From 584d360b528ed86c3480347f9fb2f48b6fe9b06f Mon Sep 17 00:00:00 2001 From: Mehmet Date: Wed, 20 Nov 2019 13:14:40 +0000 Subject: [PATCH 2/3] Add buttons to Smoketest to test HasPermissions API. --- .../Source/Assets/SmokeTest/MainGui.cs | 44 ++++++++++++++++++- 1 file changed, 42 insertions(+), 2 deletions(-) diff --git a/samples/SmokeTest/Source/Assets/SmokeTest/MainGui.cs b/samples/SmokeTest/Source/Assets/SmokeTest/MainGui.cs index 0436f20d9..3af91a688 100644 --- a/samples/SmokeTest/Source/Assets/SmokeTest/MainGui.cs +++ b/samples/SmokeTest/Source/Assets/SmokeTest/MainGui.cs @@ -92,7 +92,8 @@ public enum Ui Leaderboards, Video, UserInfo, - PopupGravity + PopupGravity, + Permissions } public void Start() @@ -351,7 +352,11 @@ internal void ShowRegularUi() { SetUI(Ui.PopupGravity); } - else if (GUI.Button(this.CalcGrid(1, 5), "Sign Out")) + else if (GUI.Button(this.CalcGrid(1, 5), "Permissions")) + { + SetUI(Ui.Permissions); + } + else if (GUI.Button(this.CalcGrid(0, 6), "Sign Out")) { this.DoSignOut(); } @@ -936,6 +941,38 @@ private void ShowPopupGravityUi() } } + private void ShowPermissionsUi() + { + DrawStatus(); + DrawTitle("PopupGravity Ui"); + + if (GUI.Button(CalcGrid(0, 1), "Has Drive - AppData")) + { + Status = "Drive - AppData Permission " + PlayGamesPlatform.Instance.HasPermission( + /* scope= */ "https://www.googleapis.com/auth/drive.appdata"); + } + else if (GUI.Button(CalcGrid(1, 1), "Has Games Lite")) + { + Status = "Games Lite Permission " + PlayGamesPlatform.Instance.HasPermission( + /* scope= */ "https://www.googleapis.com/auth/games_lite"); + } + else if (GUI.Button(CalcGrid(0, 2), "Has User Info - Profile")) + { + Status = "User Info - Profile Permission " + PlayGamesPlatform.Instance.HasPermission( + /* scope= */ "https://www.googleapis.com/auth/userinfo.profile"); + } + else if (GUI.Button(CalcGrid(1, 2), "Has Play Games Activity")) + { + Status = "Play Games Activity Permission " + PlayGamesPlatform.Instance.HasPermission( + /* scope= */ "https://www.googleapis.com/auth/games "); + } + else if (GUI.Button(CalcGrid(1, 4), "Back")) + { + SetUI(Ui.Main); + ShowEffect(true); + } + } + internal void ShowUserInfoUi() { GUI.Label( @@ -1117,6 +1154,9 @@ internal void OnGUI() case Ui.PopupGravity: ShowPopupGravityUi(); break; + case Ui.Permissions: + ShowPermissionsUi(); + break; default: // check for a status of interest, and if there // is one, then don't touch it. Otherwise From ad1c7c009086cff68d86832fafe1899eabfacc93 Mon Sep 17 00:00:00 2001 From: Mehmet Date: Wed, 18 Dec 2019 16:07:42 +0000 Subject: [PATCH 3/3] Implement RequestPermissions API --- .../Source/Assets/SmokeTest/MainGui.cs | 27 ++--- .../GooglePlayGames/BasicApi/DummyClient.cs | 14 ++- .../BasicApi/IPlayGamesClient.cs | 7 ++ .../GooglePlayGames/BasicApi/SignInStatus.cs | 42 +++++++ .../BasicApi/SignInStatus.cs.meta | 3 + .../ISocialPlatform/PlayGamesPlatform.cs | 28 ++++- .../Platforms/Android/AndroidClient.cs | 24 ++++ .../Platforms/Android/AndroidTokenClient.cs | 74 +++++++++++++ .../GooglePlayGames/Platforms/TokenClient.cs | 3 + .../google/games/bridge/HelperFragment.java | 22 +++- .../bridge/RequestPermissionsRequest.java | 104 ++++++++++++++++++ 11 files changed, 323 insertions(+), 25 deletions(-) create mode 100644 source/PluginDev/Assets/GooglePlayGames/BasicApi/SignInStatus.cs create mode 100644 source/PluginDev/Assets/GooglePlayGames/BasicApi/SignInStatus.cs.meta create mode 100644 source/SupportLib/PlayGamesPluginSupport/src/main/java/com/google/games/bridge/RequestPermissionsRequest.java diff --git a/samples/SmokeTest/Source/Assets/SmokeTest/MainGui.cs b/samples/SmokeTest/Source/Assets/SmokeTest/MainGui.cs index 3af91a688..5a47872fb 100644 --- a/samples/SmokeTest/Source/Assets/SmokeTest/MainGui.cs +++ b/samples/SmokeTest/Source/Assets/SmokeTest/MainGui.cs @@ -944,29 +944,20 @@ private void ShowPopupGravityUi() private void ShowPermissionsUi() { DrawStatus(); - DrawTitle("PopupGravity Ui"); + DrawTitle("Permissions Ui"); - if (GUI.Button(CalcGrid(0, 1), "Has Drive - AppData")) - { - Status = "Drive - AppData Permission " + PlayGamesPlatform.Instance.HasPermission( - /* scope= */ "https://www.googleapis.com/auth/drive.appdata"); - } - else if (GUI.Button(CalcGrid(1, 1), "Has Games Lite")) + if (GUI.Button(CalcGrid(0, 1), "Has Permission - Email")) { - Status = "Games Lite Permission " + PlayGamesPlatform.Instance.HasPermission( - /* scope= */ "https://www.googleapis.com/auth/games_lite"); + Status = "Email Permission " + PlayGamesPlatform.Instance.HasPermission("email"); } - else if (GUI.Button(CalcGrid(0, 2), "Has User Info - Profile")) + else if (GUI.Button(CalcGrid(1, 1), "Request Permission- Email")) { - Status = "User Info - Profile Permission " + PlayGamesPlatform.Instance.HasPermission( - /* scope= */ "https://www.googleapis.com/auth/userinfo.profile"); + Status = "Asking permission for email"; + PlayGamesPlatform.Instance.RequestPermission( + code => { Status = "Result code " + code; }, + "email"); } - else if (GUI.Button(CalcGrid(1, 2), "Has Play Games Activity")) - { - Status = "Play Games Activity Permission " + PlayGamesPlatform.Instance.HasPermission( - /* scope= */ "https://www.googleapis.com/auth/games "); - } - else if (GUI.Button(CalcGrid(1, 4), "Back")) + else if (GUI.Button(CalcGrid(1, 6), "Back")) { SetUI(Ui.Main); ShowEffect(true); diff --git a/source/PluginDev/Assets/GooglePlayGames/BasicApi/DummyClient.cs b/source/PluginDev/Assets/GooglePlayGames/BasicApi/DummyClient.cs index 8859099c9..6a79a0abb 100644 --- a/source/PluginDev/Assets/GooglePlayGames/BasicApi/DummyClient.cs +++ b/source/PluginDev/Assets/GooglePlayGames/BasicApi/DummyClient.cs @@ -372,7 +372,19 @@ public void SubmitScore( callback.Invoke(false); } } - + + /// Asks user to give permissions for the given scopes. + /// Callback used to indicate the outcome of the operation. + /// Scope to ask permission for + public void RequestPermissions(Action callback, string[] scopes) + { + LogUsage(); + if (callback != null) + { + callback.Invoke(SignInStatus.Failed); + } + } + /// Returns whether or not user has given permissions for given scopes. /// /// array of scopes diff --git a/source/PluginDev/Assets/GooglePlayGames/BasicApi/IPlayGamesClient.cs b/source/PluginDev/Assets/GooglePlayGames/BasicApi/IPlayGamesClient.cs index 5f938716b..09f038063 100644 --- a/source/PluginDev/Assets/GooglePlayGames/BasicApi/IPlayGamesClient.cs +++ b/source/PluginDev/Assets/GooglePlayGames/BasicApi/IPlayGamesClient.cs @@ -304,6 +304,13 @@ void SubmitScore(string leaderboardId, long score, void SubmitScore(string leaderboardId, long score, string metadata, Action successOrFailureCalllback); + /// + /// Asks user to give permissions for the given scopes. + /// + /// Callback used to indicate the outcome of the operation. + /// list of scopes to ask permission for + void RequestPermissions(Action callback, string[] scopes); + /// /// Returns whether or not user has given permissions for given scopes /// diff --git a/source/PluginDev/Assets/GooglePlayGames/BasicApi/SignInStatus.cs b/source/PluginDev/Assets/GooglePlayGames/BasicApi/SignInStatus.cs new file mode 100644 index 000000000..22a3535ca --- /dev/null +++ b/source/PluginDev/Assets/GooglePlayGames/BasicApi/SignInStatus.cs @@ -0,0 +1,42 @@ +namespace GooglePlayGames.BasicApi +{ + public enum SignInStatus + { + /// The operation was successful. + Success, + + /// + /// The client attempted to connect to the service but the user is not signed in. The client may + /// choose to continue without using the API. Alternately, if {@link Status#hasResolution} returns + /// {@literal true} the client may call {@link Status#startResolutionForResult(Activity, int)} to + /// prompt the user to sign in. After the sign in activity returns with {@link Activity#RESULT_OK} + /// further attempts should succeed. + /// + UiSignInRequired, + + /// A network error occurred. Retrying should resolve the problem. + NetworkError, + + /// An internal error occurred. + InternalError, + + /// The sign in was canceled. + Canceled, + + /// + /// A sign in process is currently in progress and the current one cannot continue. e.g. the user + /// clicks the SignInButton multiple times and more than one sign in intent was launched. + /// + AlreadyInProgress, + + /// + /// Failure reason is unknown. Check adb log to see details if any. + /// + Failed, + + /// + /// Currently not authenticated. Silent or interactive sign in is required. + /// + NotAuthenticated, + } +} diff --git a/source/PluginDev/Assets/GooglePlayGames/BasicApi/SignInStatus.cs.meta b/source/PluginDev/Assets/GooglePlayGames/BasicApi/SignInStatus.cs.meta new file mode 100644 index 000000000..39f52979a --- /dev/null +++ b/source/PluginDev/Assets/GooglePlayGames/BasicApi/SignInStatus.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 0992bc2597d741e59dc3f8c963a3ca25 +timeCreated: 1574256557 \ No newline at end of file diff --git a/source/PluginDev/Assets/GooglePlayGames/ISocialPlatform/PlayGamesPlatform.cs b/source/PluginDev/Assets/GooglePlayGames/ISocialPlatform/PlayGamesPlatform.cs index 6b2bf97b4..089ff67e4 100644 --- a/source/PluginDev/Assets/GooglePlayGames/ISocialPlatform/PlayGamesPlatform.cs +++ b/source/PluginDev/Assets/GooglePlayGames/ISocialPlatform/PlayGamesPlatform.cs @@ -1280,6 +1280,30 @@ public void LoadScores(ILeaderboard board, Action callback) (PlayGamesLeaderboard) board, scoreData, callback)); } + /// Asks user to give permissions for the given scopes. + /// Callback used to indicate the outcome of the operation. + /// Scope to ask permission for + public void RequestPermission(Action callback, string scope) + { + RequestPermissions(callback, new string[] {scope}); + } + + /// Asks user to give permissions for the given scopes. + /// Callback used to indicate the outcome of the operation. + /// List of scopes to ask permission for + public void RequestPermissions(Action callback, string[] scopes) + { + if (!IsAuthenticated()) + { + GooglePlayGames.OurUtils.Logger.e( + "HasPermissions can only be called after authentication."); + callback(SignInStatus.NotAuthenticated); + return; + } + + mClient.RequestPermissions(callback, scopes); + } + /// Returns whether or not user has given permissions for given scopes. /// scope /// true, if given, false otherwise. @@ -1287,7 +1311,7 @@ public bool HasPermission(string scope) { return HasPermissions(new string[] {scope}); } - + /// Returns whether or not user has given permissions for given scopes. /// array of scopes /// true, if given, false otherwise. @@ -1299,7 +1323,7 @@ public bool HasPermissions(string[] scopes) "HasPermissions can only be called after authentication."); return false; } - + return mClient.HasPermissions(scopes); } diff --git a/source/PluginDev/Assets/GooglePlayGames/Platforms/Android/AndroidClient.cs b/source/PluginDev/Assets/GooglePlayGames/Platforms/Android/AndroidClient.cs index c67d7e19b..b199e90af 100644 --- a/source/PluginDev/Assets/GooglePlayGames/Platforms/Android/AndroidClient.cs +++ b/source/PluginDev/Assets/GooglePlayGames/Platforms/Android/AndroidClient.cs @@ -1019,6 +1019,30 @@ public void SubmitScore(string leaderboardId, long score, string metadata, } } + public void RequestPermissions(Action callback, string[] scopes) + { + callback = AsOnGameThreadCallback(callback); + mTokenClient.RequestPermissions((code => + { + UpdateClients(); + callback(code); + }), scopes); + } + + private void UpdateClients() + { + lock (GameServicesLock) + { + var account = mTokenClient.GetAccount(); + mSavedGameClient = new AndroidSavedGameClient(account); + mEventsClient = new AndroidEventsClient(account); + mVideoClient = new AndroidVideoClient(mVideoClient.IsCaptureSupported(), account); + mRealTimeClient = new AndroidRealTimeMultiplayerClient(this, account); + mTurnBasedClient = new AndroidTurnBasedMultiplayerClient(this, account); + mTurnBasedClient.RegisterMatchDelegate(mConfiguration.MatchDelegate); + } + } + /// Returns whether or not user has given permissions for given scopes. /// public bool HasPermissions(string[] scopes) diff --git a/source/PluginDev/Assets/GooglePlayGames/Platforms/Android/AndroidTokenClient.cs b/source/PluginDev/Assets/GooglePlayGames/Platforms/Android/AndroidTokenClient.cs index 44fd96e32..066d0c76a 100644 --- a/source/PluginDev/Assets/GooglePlayGames/Platforms/Android/AndroidTokenClient.cs +++ b/source/PluginDev/Assets/GooglePlayGames/Platforms/Android/AndroidTokenClient.cs @@ -18,6 +18,7 @@ namespace GooglePlayGames.Android { using System; + using System.Linq; using BasicApi; using OurUtils; using UnityEngine; @@ -132,6 +133,79 @@ public void FetchTokens(bool silent, Action callback) PlayGamesHelperObject.RunOnGameThread(() => DoFetchToken(silent, callback)); } + public void RequestPermissions(Action callback, string[] scopes) + { + 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 => + { + var failCode = ToSignInStatus(e.Call("getStatusCode")); + OurUtils.Logger.e("Exception requesting new permissions: " + failCode); + callback(failCode); + }); + } + } + + private static SignInStatus ToSignInStatus(int code) + { + Dictionary dictionary = new Dictionary() + { + { + /* CommonUIStatus.UI_BUSY */ -12, SignInStatus.AlreadyInProgress + }, + { + /* CommonStatusCodes.SUCCESS */ 0, SignInStatus.Success + }, + { + /* CommonStatusCodes.SIGN_IN_REQUIRED */ 4, SignInStatus.UiSignInRequired + }, + { + /* CommonStatusCodes.NETWORK_ERROR */ 7, SignInStatus.NetworkError + }, + { + /* CommonStatusCodes.INTERNAL_ERROR */ 8, SignInStatus.InternalError + }, + { + /* CommonStatusCodes.CANCELED */ 16, SignInStatus.Canceled + }, + { + /* CommonStatusCodes.API_NOT_CONNECTED */ 17, SignInStatus.Failed + }, + { + /* GoogleSignInStatusCodes.SIGN_IN_FAILED */ 12500, SignInStatus.Failed + }, + { + /* GoogleSignInStatusCodes.SIGN_IN_CANCELLED */ 12501, SignInStatus.Canceled + }, + { + /* GoogleSignInStatusCodes.SIGN_IN_CURRENTLY_IN_PROGRESS */ 12502, SignInStatus.AlreadyInProgress + }, + }; + + return dictionary.ContainsKey(code) ? dictionary[code] : SignInStatus.Failed; + } + /// Returns whether or not user has given permissions for given scopes. /// array of scopes /// true, if given, false otherwise. diff --git a/source/PluginDev/Assets/GooglePlayGames/Platforms/TokenClient.cs b/source/PluginDev/Assets/GooglePlayGames/Platforms/TokenClient.cs index e8e1e525b..bb70aa0a6 100644 --- a/source/PluginDev/Assets/GooglePlayGames/Platforms/TokenClient.cs +++ b/source/PluginDev/Assets/GooglePlayGames/Platforms/TokenClient.cs @@ -17,6 +17,7 @@ #if UNITY_ANDROID namespace GooglePlayGames { + using GooglePlayGames.BasicApi; using System; internal interface TokenClient @@ -68,6 +69,8 @@ void GetAnotherServerAuthCode(bool reAuthenticateIfNeeded, void FetchTokens(bool silent, Action callback); + void RequestPermissions(Action callback, string[] scopes); + bool HasPermissions(string[] scopes); } } diff --git a/source/SupportLib/PlayGamesPluginSupport/src/main/java/com/google/games/bridge/HelperFragment.java b/source/SupportLib/PlayGamesPluginSupport/src/main/java/com/google/games/bridge/HelperFragment.java index c9b1a7927..de15351ac 100644 --- a/source/SupportLib/PlayGamesPluginSupport/src/main/java/com/google/games/bridge/HelperFragment.java +++ b/source/SupportLib/PlayGamesPluginSupport/src/main/java/com/google/games/bridge/HelperFragment.java @@ -56,6 +56,7 @@ public class HelperFragment extends Fragment static final int RC_INBOX_UI = 9007; static final int RC_SHOW_WAITING_ROOM_UI = 9008; static final int RC_SHOW_INVITATION_INBOX_UI = 9009; + static final int RC_SHOW_REQUEST_PERMISSIONS_UI = 9010; // Pending token request. There can be only one outstanding request at a // time. @@ -204,7 +205,7 @@ public static Task showInvitationInboxUI(Ac return request.getTask(); } - public static Task showInboxUi(Activity parentActivity){ + public static Task showInboxUi(Activity parentActivity) { InboxUiRequest request = new InboxUiRequest(); if(!HelperFragment.startRequest(parentActivity, request)) { @@ -214,13 +215,26 @@ public static Task showInboxUi(Activity parentActivity){ return request.getTask(); } - public static boolean hasPermissions(Activity parentActivity, String[] scopeUris) { + public static Task showRequestPermissionsUi(Activity parentActivity, String[] scopes) { + RequestPermissionsRequest request = new RequestPermissionsRequest(toScopeList(scopes)); + + if(!HelperFragment.startRequest(parentActivity, request)) { + request.setFailure(CommonUIStatus.UI_BUSY); + } + + return request.getTask(); + } + + public static boolean hasPermissions(Activity parentActivity, String[] scopes) { + return GoogleSignIn.hasPermissions(getAccount(parentActivity), toScopeList(scopes)); + } + + private static Scope[] toScopeList(String[] scopeUris) { Scope[] scopes = new Scope[scopeUris.length]; for (int i = 0; i < scopeUris.length; i++) { scopes[i] = new Scope(scopeUris[i]); } - - return GoogleSignIn.hasPermissions(getAccount(parentActivity), scopes); + return scopes; } public static void signOut(Activity activity) { diff --git a/source/SupportLib/PlayGamesPluginSupport/src/main/java/com/google/games/bridge/RequestPermissionsRequest.java b/source/SupportLib/PlayGamesPluginSupport/src/main/java/com/google/games/bridge/RequestPermissionsRequest.java new file mode 100644 index 000000000..33a8935fa --- /dev/null +++ b/source/SupportLib/PlayGamesPluginSupport/src/main/java/com/google/games/bridge/RequestPermissionsRequest.java @@ -0,0 +1,104 @@ +package com.google.games.bridge; + +import android.app.Activity; +import android.content.Intent; +import android.util.Log; + +import com.google.android.gms.auth.api.Auth; +import com.google.android.gms.auth.api.signin.GoogleSignIn; +import com.google.android.gms.auth.api.signin.GoogleSignInAccount; +import com.google.android.gms.auth.api.signin.GoogleSignInClient; +import com.google.android.gms.auth.api.signin.GoogleSignInStatusCodes; +import com.google.android.gms.auth.api.signin.GoogleSignInResult; +import com.google.android.gms.auth.api.signin.GoogleSignInOptions; +import com.google.android.gms.common.api.ApiException; +import com.google.android.gms.common.api.CommonStatusCodes; +import com.google.android.gms.common.api.Status; +import com.google.android.gms.common.api.Scope; +import com.google.android.gms.tasks.Task; +import com.google.android.gms.tasks.TaskCompletionSource; +import java.util.ArrayList; + +class RequestPermissionsRequest implements HelperFragment.Request { + private static final String TAG = "RequestPermissions"; + + private final TaskCompletionSource resultTaskSource = new TaskCompletionSource<>(); + private Scope[] scopes; + private HelperFragment helperFragment; + + public RequestPermissionsRequest(Scope[] scopes) { + this.scopes = scopes; + } + + Task getTask() { + return resultTaskSource.getTask(); + } + + public void process(HelperFragment helperFragment) { + this.helperFragment = helperFragment; + final Activity activity = helperFragment.getActivity(); + GoogleSignInAccount account = HelperFragment.getAccount(activity); + Scope[] unauthorizedScopes = getUnauthorizedScopes(account, scopes); + if (unauthorizedScopes.length == 0) { + setSuccess(GoogleSignIn.getAccountForScopes(activity, scopes[0], scopes)); + } else { + Intent intent = getSignInIntentForAccountAndScopes(activity, account, unauthorizedScopes); + helperFragment.startActivityForResult(intent, HelperFragment.RC_SHOW_REQUEST_PERMISSIONS_UI); + } + } + + private Scope[] getUnauthorizedScopes(GoogleSignInAccount account, Scope[] scopes) { + ArrayList unauthorizedScopes = new ArrayList(); + for (Scope scope : scopes) { + if (!GoogleSignIn.hasPermissions(account, scope)) { + unauthorizedScopes.add(scope); + } + } + return unauthorizedScopes.toArray(new Scope[unauthorizedScopes.size()]); + } + + private static Intent getSignInIntentForAccountAndScopes( + /* @NonNull */ Activity activity, /* @Nullable */ GoogleSignInAccount account, /* @NonNull */ Scope... scopes) { + GoogleSignInOptions.Builder optionsBuilder = new GoogleSignInOptions.Builder(); + + if (scopes.length > 0) { + optionsBuilder.requestScopes(scopes[0], scopes); + } + + if (account != null && account.getEmail() != null) { + optionsBuilder.setAccountName(account.getEmail()); + } + + return GoogleSignIn.getClient(activity, optionsBuilder.build()).getSignInIntent(); + } + + public void onActivityResult(int requestCode, int resultCode, Intent data) { + if (requestCode == HelperFragment.RC_SHOW_REQUEST_PERMISSIONS_UI) { + GoogleSignInResult result = Auth.GoogleSignInApi.getSignInResultFromIntent(data); + if (result != null && result.isSuccess()) { + GoogleSignInAccount account = GoogleSignIn.getAccountForScopes(helperFragment.getActivity(), scopes[0], scopes); + setSuccess(account); + } else if (resultCode == Activity.RESULT_CANCELED) { + if (result != null) { + setFailure(result.getStatus().getStatusCode()); + } else { + setFailure(CommonStatusCodes.CANCELED); + } + } else if (result != null) { + setFailure(result.getStatus().getStatusCode()); + } else { + setFailure(CommonStatusCodes.ERROR); + } + } + } + + void setFailure(int code) { + resultTaskSource.setException(new ApiException(new Status(code))); + HelperFragment.finishRequest(this); + } + + private void setSuccess(GoogleSignInAccount account) { + resultTaskSource.setResult(account); + HelperFragment.finishRequest(this); + } +}