From f453f6c707941fe81d42f421513f7bd12c602eff Mon Sep 17 00:00:00 2001 From: Thaina Yu Date: Mon, 9 Oct 2023 15:39:02 +0700 Subject: [PATCH 01/25] remove native google signin > convert to direct unity call to java add signin in editor and desktop support --- .../Editor/GoogleSignInDependencies.xml | 2 +- .../Editor/GoogleSignInDependencies.xml.meta | 4 +- .../GoogleSignInSupportDependencies.xml.meta | 10 - .../Editor/google-signin-plugin_v1.0.0.txt | 21 - .../google-signin-plugin_v1.0.0.txt.meta | 12 - .../google-signin-plugin_v1.0.1.txt.meta | 12 - ....1.txt => google-signin-plugin_v1.0.4.txt} | 54 +- ...a => google-signin-plugin_v1.0.4.txt.meta} | 5 +- .../google/signin/google-signin-support.meta | 10 - .../maven-metadata.xml.md5.meta | 11 - .../maven-metadata.xml.meta | 11 - .../maven-metadata.xml.sha1.meta | 11 - .../Assets/GoogleSignIn/Future.cs.meta | 4 +- .../Assets/GoogleSignIn/GoogleSignIn.cs | 6 +- .../Assets/GoogleSignIn/GoogleSignIn.cs.meta | 4 +- .../GoogleSignIn/GoogleSignInConfiguration.cs | 5 + .../GoogleSignInConfiguration.cs.meta | 4 +- .../GoogleSignInStatusCode.cs.meta | 4 +- .../GoogleSignIn/GoogleSignInUser.cs.meta | 4 +- .../GoogleSignIn/Impl/BaseObject.cs.meta | 4 +- .../GoogleSignIn/Impl/GoogleSignInImpl.cs | 178 +++++- .../Impl/GoogleSignInImpl.cs.meta | 4 +- .../Impl/GoogleSignInImplEditor.cs | 199 +++++++ .../Impl/GoogleSignInImplEditor.cs.meta | 11 + .../Assets/GoogleSignIn/Impl/NativeFuture.cs | 67 +-- .../GoogleSignIn/Impl/NativeFuture.cs.meta | 4 +- .../Impl/SignInHelperObject.cs.meta | 4 +- .../Assets/Plugins/Android.meta | 5 +- .../Android/src.meta} | 4 +- .../Android/src/main.meta} | 4 +- .../Assets/Plugins/Android/src/main/java.meta | 8 + .../Android/src/main/java}/com.meta | 4 +- .../Android/src/main/java}/com/google.meta | 4 +- .../main/java/com/google/googlesignin.meta | 8 + .../googlesignin/GoogleSignInFragment.java | 114 ++-- .../GoogleSignInFragment.java.meta | 32 + .../googlesignin/GoogleSignInHelper.java | 19 +- .../googlesignin/GoogleSignInHelper.java.meta | 32 + .../com/google/googlesignin/IListener.java | 8 + .../google/googlesignin/IListener.java.meta | 32 + .../googlesignin/TokenPendingResult.java | 4 +- .../googlesignin/TokenPendingResult.java.meta | 32 + .../com/google/googlesignin/TokenRequest.java | 6 +- .../googlesignin/TokenRequest.java.meta | 32 + .../com/google/googlesignin/TokenResult.java | 6 +- .../google/googlesignin/TokenResult.java.meta | 32 + .../iOS/{GoogleSignIn => }/GoogleSignIn.h | 0 .../Assets/Plugins/iOS/GoogleSignIn.h.meta | 35 ++ .../Assets/Plugins/iOS/GoogleSignIn.meta | 9 - .../iOS/{GoogleSignIn => }/GoogleSignIn.mm | 0 .../Assets/Plugins/iOS/GoogleSignIn.mm.meta | 35 ++ .../iOS/GoogleSignIn/GoogleSignIn.h.meta | 35 -- .../iOS/GoogleSignIn/GoogleSignIn.mm.meta | 35 -- .../GoogleSignInAppController.h | 0 .../GoogleSignInAppController.h.meta | 21 +- .../GoogleSignInAppController.mm | 12 +- .../GoogleSignInAppController.mm.meta | 21 +- build.gradle | 377 ------------ build_all.sh | 5 - gradle/wrapper/gradle-wrapper.jar | Bin 53636 -> 0 bytes gradle/wrapper/gradle-wrapper.properties | 6 - gradlew | 160 ----- gradlew.bat | 90 --- native-googlesignin/CMakeLists.txt | 62 -- native-googlesignin/build.gradle | 116 ---- .../src/main/AndroidManifest.xml | 22 - native-googlesignin/src/main/cpp/future.h | 40 -- .../src/main/cpp/google_signin.cc | 392 ------------- .../src/main/cpp/google_signin.h | 169 ------ .../src/main/cpp/google_signin_bridge.cc | 227 -------- .../src/main/cpp/google_signin_bridge.h | 172 ------ .../src/main/cpp/google_signin_user.cc | 206 ------- .../src/main/cpp/google_signin_user.h | 45 -- .../src/main/cpp/google_signin_user_impl.h | 46 -- native-googlesignin/src/main/cpp/jni.cc | 104 ---- native-googlesignin/src/main/cpp/jni_init.h | 27 - settings.gradle | 15 - staging/DIR_README.md | 4 - staging/native/GoogleSignInCpp.podspec | 40 -- staging/native/LICENSE | 215 ------- staging/native/README.md | 55 -- staging/native/build.gradle | 121 ---- .../native/gradle/wrapper/gradle-wrapper.jar | Bin 54208 -> 0 bytes .../gradle/wrapper/gradle-wrapper.properties | 6 - staging/native/gradlew | 172 ------ staging/native/gradlew.bat | 84 --- .../native/src/android/AndroidManifest.xml | 22 - staging/native/src/android/CMakeLists.txt | 51 -- staging/native/src/android/google_signin.cc | 398 ------------- .../native/src/android/google_signin_user.cc | 191 ------ .../src/android/google_signin_user_impl.h | 53 -- .../googlesignin/GoogleSignInFragment.java | 547 ------------------ .../googlesignin/GoogleSignInHelper.java | 148 ----- .../googlesignin/TokenPendingResult.java | 145 ----- .../com/google/googlesignin/TokenRequest.java | 171 ------ .../com/google/googlesignin/TokenResult.java | 66 --- staging/native/src/android/jni.cc | 153 ----- staging/native/src/android/jni_context.h | 71 --- staging/native/src/include/future.h | 41 -- staging/native/src/include/google_signin.h | 179 ------ .../native/src/include/google_signin_user.h | 46 -- staging/native/src/ios/GoogleSignIn.h | 20 - staging/native/src/ios/GoogleSignIn.mm | 314 ---------- .../native/testapp/LaunchScreen.storyboard | 7 - staging/native/testapp/Podfile | 7 - staging/native/testapp/build.gradle | 110 ---- .../testapp/gradle/wrapper/gradle-wrapper.jar | Bin 54208 -> 0 bytes .../gradle/wrapper/gradle-wrapper.properties | 6 - staging/native/testapp/gradlew | 172 ------ staging/native/testapp/gradlew.bat | 84 --- .../testapp/src/android/AndroidManifest.xml | 22 - .../native/testapp/src/android/CMakeLists.txt | 57 -- .../testapp/src/android/android_main.cpp | 254 -------- .../google/signin/testapp/LoggingUtils.java | 55 -- .../google/signin/testapp/TextEntryField.java | 106 ---- .../testapp/src/android/res/layout/main.xml | 17 - .../src/android/res/values/strings.xml | 4 - staging/native/testapp/src/common_main.cpp | 81 --- staging/native/testapp/src/ios/ios_main.mm | 174 ------ staging/native/testapp/src/main.h | 54 -- .../testapp/testapp.xcodeproj/project.pbxproj | 378 ------------ .../xcshareddata/xcschemes/testapp.xcscheme | 93 --- .../AppIcon.appiconset/Contents.json | 98 ---- .../LaunchImage.launchimage/Contents.json | 51 -- staging/native/testapp/testapp/Info.plist | 39 -- 125 files changed, 853 insertions(+), 7864 deletions(-) delete mode 100644 GoogleSignInPlugin/Assets/GoogleSignIn/Editor/GoogleSignInSupportDependencies.xml.meta delete mode 100644 GoogleSignInPlugin/Assets/GoogleSignIn/Editor/google-signin-plugin_v1.0.0.txt delete mode 100644 GoogleSignInPlugin/Assets/GoogleSignIn/Editor/google-signin-plugin_v1.0.0.txt.meta delete mode 100644 GoogleSignInPlugin/Assets/GoogleSignIn/Editor/google-signin-plugin_v1.0.1.txt.meta rename GoogleSignInPlugin/Assets/GoogleSignIn/Editor/{google-signin-plugin_v1.0.1.txt => google-signin-plugin_v1.0.4.txt} (52%) rename GoogleSignInPlugin/Assets/GoogleSignIn/Editor/{google-signin-plugin.txt.meta => google-signin-plugin_v1.0.4.txt.meta} (64%) delete mode 100644 GoogleSignInPlugin/Assets/GoogleSignIn/Editor/m2repository/com/google/signin/google-signin-support.meta delete mode 100644 GoogleSignInPlugin/Assets/GoogleSignIn/Editor/m2repository/com/google/signin/google-signin-support/maven-metadata.xml.md5.meta delete mode 100644 GoogleSignInPlugin/Assets/GoogleSignIn/Editor/m2repository/com/google/signin/google-signin-support/maven-metadata.xml.meta delete mode 100644 GoogleSignInPlugin/Assets/GoogleSignIn/Editor/m2repository/com/google/signin/google-signin-support/maven-metadata.xml.sha1.meta create mode 100644 GoogleSignInPlugin/Assets/GoogleSignIn/Impl/GoogleSignInImplEditor.cs create mode 100644 GoogleSignInPlugin/Assets/GoogleSignIn/Impl/GoogleSignInImplEditor.cs.meta rename GoogleSignInPlugin/Assets/{GoogleSignIn/Editor/m2repository.meta => Plugins/Android/src.meta} (62%) rename GoogleSignInPlugin/Assets/{GoogleSignIn/Editor/m2repository/com/google/signin.meta => Plugins/Android/src/main.meta} (62%) create mode 100644 GoogleSignInPlugin/Assets/Plugins/Android/src/main/java.meta rename GoogleSignInPlugin/Assets/{GoogleSignIn/Editor/m2repository => Plugins/Android/src/main/java}/com.meta (62%) rename GoogleSignInPlugin/Assets/{GoogleSignIn/Editor/m2repository => Plugins/Android/src/main/java}/com/google.meta (62%) create mode 100644 GoogleSignInPlugin/Assets/Plugins/Android/src/main/java/com/google/googlesignin.meta rename {native-googlesignin => GoogleSignInPlugin/Assets/Plugins/Android}/src/main/java/com/google/googlesignin/GoogleSignInFragment.java (85%) create mode 100644 GoogleSignInPlugin/Assets/Plugins/Android/src/main/java/com/google/googlesignin/GoogleSignInFragment.java.meta rename {native-googlesignin => GoogleSignInPlugin/Assets/Plugins/Android}/src/main/java/com/google/googlesignin/GoogleSignInHelper.java (89%) create mode 100644 GoogleSignInPlugin/Assets/Plugins/Android/src/main/java/com/google/googlesignin/GoogleSignInHelper.java.meta create mode 100644 GoogleSignInPlugin/Assets/Plugins/Android/src/main/java/com/google/googlesignin/IListener.java create mode 100644 GoogleSignInPlugin/Assets/Plugins/Android/src/main/java/com/google/googlesignin/IListener.java.meta rename {native-googlesignin => GoogleSignInPlugin/Assets/Plugins/Android}/src/main/java/com/google/googlesignin/TokenPendingResult.java (97%) create mode 100644 GoogleSignInPlugin/Assets/Plugins/Android/src/main/java/com/google/googlesignin/TokenPendingResult.java.meta rename {native-googlesignin => GoogleSignInPlugin/Assets/Plugins/Android}/src/main/java/com/google/googlesignin/TokenRequest.java (98%) create mode 100644 GoogleSignInPlugin/Assets/Plugins/Android/src/main/java/com/google/googlesignin/TokenRequest.java.meta rename {native-googlesignin => GoogleSignInPlugin/Assets/Plugins/Android}/src/main/java/com/google/googlesignin/TokenResult.java (94%) create mode 100644 GoogleSignInPlugin/Assets/Plugins/Android/src/main/java/com/google/googlesignin/TokenResult.java.meta rename GoogleSignInPlugin/Assets/Plugins/iOS/{GoogleSignIn => }/GoogleSignIn.h (100%) create mode 100644 GoogleSignInPlugin/Assets/Plugins/iOS/GoogleSignIn.h.meta delete mode 100644 GoogleSignInPlugin/Assets/Plugins/iOS/GoogleSignIn.meta rename GoogleSignInPlugin/Assets/Plugins/iOS/{GoogleSignIn => }/GoogleSignIn.mm (100%) create mode 100644 GoogleSignInPlugin/Assets/Plugins/iOS/GoogleSignIn.mm.meta delete mode 100644 GoogleSignInPlugin/Assets/Plugins/iOS/GoogleSignIn/GoogleSignIn.h.meta delete mode 100644 GoogleSignInPlugin/Assets/Plugins/iOS/GoogleSignIn/GoogleSignIn.mm.meta rename GoogleSignInPlugin/Assets/Plugins/iOS/{GoogleSignIn => }/GoogleSignInAppController.h (100%) rename GoogleSignInPlugin/Assets/Plugins/iOS/{GoogleSignIn => }/GoogleSignInAppController.h.meta (59%) rename GoogleSignInPlugin/Assets/Plugins/iOS/{GoogleSignIn => }/GoogleSignInAppController.mm (87%) rename GoogleSignInPlugin/Assets/Plugins/iOS/{GoogleSignIn => }/GoogleSignInAppController.mm.meta (59%) delete mode 100644 build.gradle delete mode 100755 build_all.sh delete mode 100644 gradle/wrapper/gradle-wrapper.jar delete mode 100644 gradle/wrapper/gradle-wrapper.properties delete mode 100755 gradlew delete mode 100644 gradlew.bat delete mode 100644 native-googlesignin/CMakeLists.txt delete mode 100644 native-googlesignin/build.gradle delete mode 100644 native-googlesignin/src/main/AndroidManifest.xml delete mode 100644 native-googlesignin/src/main/cpp/future.h delete mode 100644 native-googlesignin/src/main/cpp/google_signin.cc delete mode 100644 native-googlesignin/src/main/cpp/google_signin.h delete mode 100644 native-googlesignin/src/main/cpp/google_signin_bridge.cc delete mode 100644 native-googlesignin/src/main/cpp/google_signin_bridge.h delete mode 100644 native-googlesignin/src/main/cpp/google_signin_user.cc delete mode 100644 native-googlesignin/src/main/cpp/google_signin_user.h delete mode 100644 native-googlesignin/src/main/cpp/google_signin_user_impl.h delete mode 100644 native-googlesignin/src/main/cpp/jni.cc delete mode 100644 native-googlesignin/src/main/cpp/jni_init.h delete mode 100644 settings.gradle delete mode 100644 staging/DIR_README.md delete mode 100644 staging/native/GoogleSignInCpp.podspec delete mode 100644 staging/native/LICENSE delete mode 100644 staging/native/README.md delete mode 100644 staging/native/build.gradle delete mode 100644 staging/native/gradle/wrapper/gradle-wrapper.jar delete mode 100644 staging/native/gradle/wrapper/gradle-wrapper.properties delete mode 100755 staging/native/gradlew delete mode 100644 staging/native/gradlew.bat delete mode 100644 staging/native/src/android/AndroidManifest.xml delete mode 100644 staging/native/src/android/CMakeLists.txt delete mode 100644 staging/native/src/android/google_signin.cc delete mode 100644 staging/native/src/android/google_signin_user.cc delete mode 100644 staging/native/src/android/google_signin_user_impl.h delete mode 100644 staging/native/src/android/java/com/google/googlesignin/GoogleSignInFragment.java delete mode 100644 staging/native/src/android/java/com/google/googlesignin/GoogleSignInHelper.java delete mode 100644 staging/native/src/android/java/com/google/googlesignin/TokenPendingResult.java delete mode 100644 staging/native/src/android/java/com/google/googlesignin/TokenRequest.java delete mode 100644 staging/native/src/android/java/com/google/googlesignin/TokenResult.java delete mode 100644 staging/native/src/android/jni.cc delete mode 100644 staging/native/src/android/jni_context.h delete mode 100644 staging/native/src/include/future.h delete mode 100644 staging/native/src/include/google_signin.h delete mode 100644 staging/native/src/include/google_signin_user.h delete mode 100644 staging/native/src/ios/GoogleSignIn.h delete mode 100644 staging/native/src/ios/GoogleSignIn.mm delete mode 100644 staging/native/testapp/LaunchScreen.storyboard delete mode 100644 staging/native/testapp/Podfile delete mode 100644 staging/native/testapp/build.gradle delete mode 100644 staging/native/testapp/gradle/wrapper/gradle-wrapper.jar delete mode 100644 staging/native/testapp/gradle/wrapper/gradle-wrapper.properties delete mode 100755 staging/native/testapp/gradlew delete mode 100644 staging/native/testapp/gradlew.bat delete mode 100644 staging/native/testapp/src/android/AndroidManifest.xml delete mode 100644 staging/native/testapp/src/android/CMakeLists.txt delete mode 100644 staging/native/testapp/src/android/android_main.cpp delete mode 100644 staging/native/testapp/src/android/java/com/google/signin/testapp/LoggingUtils.java delete mode 100644 staging/native/testapp/src/android/java/com/google/signin/testapp/TextEntryField.java delete mode 100644 staging/native/testapp/src/android/res/layout/main.xml delete mode 100644 staging/native/testapp/src/android/res/values/strings.xml delete mode 100644 staging/native/testapp/src/common_main.cpp delete mode 100644 staging/native/testapp/src/ios/ios_main.mm delete mode 100644 staging/native/testapp/src/main.h delete mode 100644 staging/native/testapp/testapp.xcodeproj/project.pbxproj delete mode 100644 staging/native/testapp/testapp.xcodeproj/xcshareddata/xcschemes/testapp.xcscheme delete mode 100644 staging/native/testapp/testapp/Images.xcassets/AppIcon.appiconset/Contents.json delete mode 100644 staging/native/testapp/testapp/Images.xcassets/LaunchImage.launchimage/Contents.json delete mode 100644 staging/native/testapp/testapp/Info.plist diff --git a/GoogleSignInPlugin/Assets/GoogleSignIn/Editor/GoogleSignInDependencies.xml b/GoogleSignInPlugin/Assets/GoogleSignIn/Editor/GoogleSignInDependencies.xml index 15ad7e70..89c7983e 100644 --- a/GoogleSignInPlugin/Assets/GoogleSignIn/Editor/GoogleSignInDependencies.xml +++ b/GoogleSignInPlugin/Assets/GoogleSignIn/Editor/GoogleSignInDependencies.xml @@ -12,7 +12,7 @@ - diff --git a/GoogleSignInPlugin/Assets/GoogleSignIn/Editor/GoogleSignInDependencies.xml.meta b/GoogleSignInPlugin/Assets/GoogleSignIn/Editor/GoogleSignInDependencies.xml.meta index 298fa3d3..6493d604 100644 --- a/GoogleSignInPlugin/Assets/GoogleSignIn/Editor/GoogleSignInDependencies.xml.meta +++ b/GoogleSignInPlugin/Assets/GoogleSignIn/Editor/GoogleSignInDependencies.xml.meta @@ -2,9 +2,9 @@ fileFormatVersion: 2 guid: 938014c9994164100b26d82840a88fbb labels: - gvh -timeCreated: 1507661087 -licenseType: Pro +- gvh_version-1.0.4 TextScriptImporter: + externalObjects: {} userData: assetBundleName: assetBundleVariant: diff --git a/GoogleSignInPlugin/Assets/GoogleSignIn/Editor/GoogleSignInSupportDependencies.xml.meta b/GoogleSignInPlugin/Assets/GoogleSignIn/Editor/GoogleSignInSupportDependencies.xml.meta deleted file mode 100644 index fd0bf367..00000000 --- a/GoogleSignInPlugin/Assets/GoogleSignIn/Editor/GoogleSignInSupportDependencies.xml.meta +++ /dev/null @@ -1,10 +0,0 @@ -fileFormatVersion: 2 -guid: e8689106c65f445c19cec6044d615c19 -labels: -- gvh -timeCreated: 1507661087 -licenseType: Pro -TextScriptImporter: - userData: - assetBundleName: - assetBundleVariant: diff --git a/GoogleSignInPlugin/Assets/GoogleSignIn/Editor/google-signin-plugin_v1.0.0.txt b/GoogleSignInPlugin/Assets/GoogleSignIn/Editor/google-signin-plugin_v1.0.0.txt deleted file mode 100644 index b1d0d00d..00000000 --- a/GoogleSignInPlugin/Assets/GoogleSignIn/Editor/google-signin-plugin_v1.0.0.txt +++ /dev/null @@ -1,21 +0,0 @@ -Assets/Parse/Plugins/Unity.Tasks.dll -Assets/Parse/Plugins/Unity.Compat.dll -Assets/Parse/LICENSE -Assets/Plugins/iOS/GoogleSignIn/GoogleSignInAppController.h -Assets/Plugins/iOS/GoogleSignIn/GoogleSignInAppController.mm -Assets/Plugins/Android/native-googlesignin-release.aar -Assets/PlayServicesResolver/Editor/Google.IOSResolver_v1.2.54.0.dll -Assets/PlayServicesResolver/Editor/Google.VersionHandler.dll -Assets/PlayServicesResolver/Editor/play-services-resolver_v1.2.54.0.txt -Assets/PlayServicesResolver/Editor/Google.VersionHandlerImpl_v1.2.54.0.dll -Assets/PlayServicesResolver/Editor/Google.JarResolver_v1.2.54.0.dll -Assets/GoogleSignIn/GoogleSignInStatusCode.cs -Assets/GoogleSignIn/Editor/GoogleSignInDependencies.xml -Assets/GoogleSignIn/GoogleSignInUser.cs -Assets/GoogleSignIn/GoogleSignIn.cs -Assets/GoogleSignIn/Future.cs -Assets/GoogleSignIn/Impl/SignInHelperObject.cs -Assets/GoogleSignIn/Impl/BaseObject.cs -Assets/GoogleSignIn/Impl/GoogleSignInImpl.cs -Assets/GoogleSignIn/Impl/NativeFuture.cs -Assets/GoogleSignIn/GoogleSignInConfiguration.cs diff --git a/GoogleSignInPlugin/Assets/GoogleSignIn/Editor/google-signin-plugin_v1.0.0.txt.meta b/GoogleSignInPlugin/Assets/GoogleSignIn/Editor/google-signin-plugin_v1.0.0.txt.meta deleted file mode 100644 index 5477b554..00000000 --- a/GoogleSignInPlugin/Assets/GoogleSignIn/Editor/google-signin-plugin_v1.0.0.txt.meta +++ /dev/null @@ -1,12 +0,0 @@ -fileFormatVersion: 2 -guid: ca932999723384cdc86087c8423332bb -labels: -- gvh -- gvh_manifest -timeCreated: 1508875148 -licenseType: Free -TextScriptImporter: - externalObjects: {} - userData: - assetBundleName: - assetBundleVariant: diff --git a/GoogleSignInPlugin/Assets/GoogleSignIn/Editor/google-signin-plugin_v1.0.1.txt.meta b/GoogleSignInPlugin/Assets/GoogleSignIn/Editor/google-signin-plugin_v1.0.1.txt.meta deleted file mode 100644 index b6e2fd62..00000000 --- a/GoogleSignInPlugin/Assets/GoogleSignIn/Editor/google-signin-plugin_v1.0.1.txt.meta +++ /dev/null @@ -1,12 +0,0 @@ -fileFormatVersion: 2 -guid: 817a6673340324b8ca85e24466f60953 -labels: -- gvh -- gvh_manifest -timeCreated: 1508875148 -licenseType: Free -TextScriptImporter: - externalObjects: {} - userData: - assetBundleName: - assetBundleVariant: diff --git a/GoogleSignInPlugin/Assets/GoogleSignIn/Editor/google-signin-plugin_v1.0.1.txt b/GoogleSignInPlugin/Assets/GoogleSignIn/Editor/google-signin-plugin_v1.0.4.txt similarity index 52% rename from GoogleSignInPlugin/Assets/GoogleSignIn/Editor/google-signin-plugin_v1.0.1.txt rename to GoogleSignInPlugin/Assets/GoogleSignIn/Editor/google-signin-plugin_v1.0.4.txt index f7061862..a0e24547 100644 --- a/GoogleSignInPlugin/Assets/GoogleSignIn/Editor/google-signin-plugin_v1.0.1.txt +++ b/GoogleSignInPlugin/Assets/GoogleSignIn/Editor/google-signin-plugin_v1.0.4.txt @@ -1,27 +1,33 @@ -Assets/GoogleSignIn/Editor/GoogleSignInDependencies.xml -Assets/GoogleSignIn/Editor/m2repository/com/google/signin/google-signin-support/1.0.1/google-signin-support-1.0.1.aar -Assets/GoogleSignIn/Editor/m2repository/com/google/signin/google-signin-support/1.0.1/google-signin-support-1.0.1.aar.md5 -Assets/GoogleSignIn/Editor/m2repository/com/google/signin/google-signin-support/1.0.1/google-signin-support-1.0.1.aar.sha1 -Assets/GoogleSignIn/Editor/m2repository/com/google/signin/google-signin-support/1.0.1/google-signin-support-1.0.1.pom -Assets/GoogleSignIn/Editor/m2repository/com/google/signin/google-signin-support/1.0.1/google-signin-support-1.0.1.pom.md5 -Assets/GoogleSignIn/Editor/m2repository/com/google/signin/google-signin-support/1.0.1/google-signin-support-1.0.1.pom.sha1 -Assets/GoogleSignIn/Future.cs -Assets/GoogleSignIn/GoogleSignIn.cs -Assets/GoogleSignIn/GoogleSignInConfiguration.cs -Assets/GoogleSignIn/GoogleSignInStatusCode.cs -Assets/GoogleSignIn/GoogleSignInUser.cs -Assets/GoogleSignIn/Impl/BaseObject.cs -Assets/GoogleSignIn/Impl/GoogleSignInImpl.cs -Assets/GoogleSignIn/Impl/NativeFuture.cs -Assets/GoogleSignIn/Impl/SignInHelperObject.cs +Assets/PlayServicesResolver/Editor/Google.VersionHandlerImpl_v1.2.89.0.dll +Assets/PlayServicesResolver/Editor/Google.IOSResolver_v1.2.89.0.dll +Assets/PlayServicesResolver/Editor/Google.VersionHandler.dll +Assets/PlayServicesResolver/Editor/Google.JarResolver_v1.2.89.0.dll +Assets/Plugins/iOS/GoogleSignIn/GoogleSignInAppController.mm +Assets/Plugins/iOS/GoogleSignIn/GoogleSignInAppController.h +Assets/Plugins/iOS/GoogleSignIn/GoogleSignIn.h +Assets/Plugins/iOS/GoogleSignIn/GoogleSignIn.mm Assets/Parse/LICENSE Assets/Parse/Plugins/Unity.Compat.dll Assets/Parse/Plugins/Unity.Tasks.dll -Assets/PlayServicesResolver/Editor/Google.IOSResolver_v1.2.54.0.dll -Assets/PlayServicesResolver/Editor/Google.JarResolver_v1.2.54.0.dll -Assets/PlayServicesResolver/Editor/Google.VersionHandler.dll -Assets/PlayServicesResolver/Editor/Google.VersionHandlerImpl_v1.2.54.0.dll -Assets/PlayServicesResolver/Editor/play-services-resolver_v1.2.54.0.txt -Assets/Plugins/Android/native-googlesignin-release.aar -Assets/Plugins/iOS/GoogleSignIn/GoogleSignInAppController.h -Assets/Plugins/iOS/GoogleSignIn/GoogleSignInAppController.mm +Assets/SignInSample/MainScene.unity +Assets/SignInSample/SigninSampleScript.cs +Assets/GoogleSignIn/Impl/GoogleSignInImpl.cs +Assets/GoogleSignIn/Impl/SignInHelperObject.cs +Assets/GoogleSignIn/Impl/NativeFuture.cs +Assets/GoogleSignIn/Impl/BaseObject.cs +Assets/GoogleSignIn/GoogleSignIn.cs +Assets/GoogleSignIn/GoogleSignInConfiguration.cs +Assets/GoogleSignIn/Future.cs +Assets/GoogleSignIn/GoogleSignInUser.cs +Assets/GoogleSignIn/GoogleSignInStatusCode.cs +Assets/GoogleSignIn/Editor/GoogleSignInDependencies.xml +Assets/GoogleSignIn/Editor/GoogleSignInSupportDependencies.xml +Assets/GoogleSignIn/Editor/m2repository/com/google/signin/google-signin-support/maven-metadata.xml +Assets/GoogleSignIn/Editor/m2repository/com/google/signin/google-signin-support/maven-metadata.xml.md5 +Assets/GoogleSignIn/Editor/m2repository/com/google/signin/google-signin-support/maven-metadata.xml.sha1 +Assets/GoogleSignIn/Editor/m2repository/com/google/signin/google-signin-support/1.0.4/google-signin-support-1.0.4.pom.md5 +Assets/GoogleSignIn/Editor/m2repository/com/google/signin/google-signin-support/1.0.4/google-signin-support-1.0.4.srcaar.sha1 +Assets/GoogleSignIn/Editor/m2repository/com/google/signin/google-signin-support/1.0.4/google-signin-support-1.0.4.pom.sha1 +Assets/GoogleSignIn/Editor/m2repository/com/google/signin/google-signin-support/1.0.4/google-signin-support-1.0.4.srcaar +Assets/GoogleSignIn/Editor/m2repository/com/google/signin/google-signin-support/1.0.4/google-signin-support-1.0.4.pom +Assets/GoogleSignIn/Editor/m2repository/com/google/signin/google-signin-support/1.0.4/google-signin-support-1.0.4.srcaar.md5 diff --git a/GoogleSignInPlugin/Assets/GoogleSignIn/Editor/google-signin-plugin.txt.meta b/GoogleSignInPlugin/Assets/GoogleSignIn/Editor/google-signin-plugin_v1.0.4.txt.meta similarity index 64% rename from GoogleSignInPlugin/Assets/GoogleSignIn/Editor/google-signin-plugin.txt.meta rename to GoogleSignInPlugin/Assets/GoogleSignIn/Editor/google-signin-plugin_v1.0.4.txt.meta index 0bbedeb2..eb7a5d66 100644 --- a/GoogleSignInPlugin/Assets/GoogleSignIn/Editor/google-signin-plugin.txt.meta +++ b/GoogleSignInPlugin/Assets/GoogleSignIn/Editor/google-signin-plugin_v1.0.4.txt.meta @@ -1,10 +1,9 @@ fileFormatVersion: 2 -guid: 817a6673340324b8ca85e24466f60953 +guid: a67d5f0cfc09749e6b1ce13e8b8e6e1d labels: - gvh - gvh_manifest -timeCreated: 1508953127 -licenseType: Free +- gvh_version-1.0.4 TextScriptImporter: externalObjects: {} userData: diff --git a/GoogleSignInPlugin/Assets/GoogleSignIn/Editor/m2repository/com/google/signin/google-signin-support.meta b/GoogleSignInPlugin/Assets/GoogleSignIn/Editor/m2repository/com/google/signin/google-signin-support.meta deleted file mode 100644 index 1132fbfe..00000000 --- a/GoogleSignInPlugin/Assets/GoogleSignIn/Editor/m2repository/com/google/signin/google-signin-support.meta +++ /dev/null @@ -1,10 +0,0 @@ -fileFormatVersion: 2 -guid: e3becceb8680148d59e5bb93e5eb5a24 -folderAsset: yes -timeCreated: 1508956004 -licenseType: Free -DefaultImporter: - externalObjects: {} - userData: - assetBundleName: - assetBundleVariant: diff --git a/GoogleSignInPlugin/Assets/GoogleSignIn/Editor/m2repository/com/google/signin/google-signin-support/maven-metadata.xml.md5.meta b/GoogleSignInPlugin/Assets/GoogleSignIn/Editor/m2repository/com/google/signin/google-signin-support/maven-metadata.xml.md5.meta deleted file mode 100644 index 8baf9d33..00000000 --- a/GoogleSignInPlugin/Assets/GoogleSignIn/Editor/m2repository/com/google/signin/google-signin-support/maven-metadata.xml.md5.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: c020582c1a85d47c7934908f00a0bd37 -labels: -- gvh -timeCreated: 1508956004 -licenseType: Free -DefaultImporter: - externalObjects: {} - userData: - assetBundleName: - assetBundleVariant: diff --git a/GoogleSignInPlugin/Assets/GoogleSignIn/Editor/m2repository/com/google/signin/google-signin-support/maven-metadata.xml.meta b/GoogleSignInPlugin/Assets/GoogleSignIn/Editor/m2repository/com/google/signin/google-signin-support/maven-metadata.xml.meta deleted file mode 100644 index 3976f6ef..00000000 --- a/GoogleSignInPlugin/Assets/GoogleSignIn/Editor/m2repository/com/google/signin/google-signin-support/maven-metadata.xml.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: f3911d467587242978192a8723c68395 -labels: -- gvh -timeCreated: 1508956022 -licenseType: Free -TextScriptImporter: - externalObjects: {} - userData: - assetBundleName: - assetBundleVariant: diff --git a/GoogleSignInPlugin/Assets/GoogleSignIn/Editor/m2repository/com/google/signin/google-signin-support/maven-metadata.xml.sha1.meta b/GoogleSignInPlugin/Assets/GoogleSignIn/Editor/m2repository/com/google/signin/google-signin-support/maven-metadata.xml.sha1.meta deleted file mode 100644 index 7f0f11ac..00000000 --- a/GoogleSignInPlugin/Assets/GoogleSignIn/Editor/m2repository/com/google/signin/google-signin-support/maven-metadata.xml.sha1.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: 16b8065a143bb4277af08381a56157dd -labels: -- gvh -timeCreated: 1508956004 -licenseType: Free -DefaultImporter: - externalObjects: {} - userData: - assetBundleName: - assetBundleVariant: diff --git a/GoogleSignInPlugin/Assets/GoogleSignIn/Future.cs.meta b/GoogleSignInPlugin/Assets/GoogleSignIn/Future.cs.meta index 3932f1d0..75a7f224 100644 --- a/GoogleSignInPlugin/Assets/GoogleSignIn/Future.cs.meta +++ b/GoogleSignInPlugin/Assets/GoogleSignIn/Future.cs.meta @@ -2,9 +2,9 @@ fileFormatVersion: 2 guid: ad3b09fb652fb4ff0a68d1966f13160e labels: - gvh -timeCreated: 1495747145 -licenseType: Pro +- gvh_version-1.0.4 MonoImporter: + externalObjects: {} serializedVersion: 2 defaultReferences: [] executionOrder: 0 diff --git a/GoogleSignInPlugin/Assets/GoogleSignIn/GoogleSignIn.cs b/GoogleSignInPlugin/Assets/GoogleSignIn/GoogleSignIn.cs index c59ced72..52dcf863 100644 --- a/GoogleSignInPlugin/Assets/GoogleSignIn/GoogleSignIn.cs +++ b/GoogleSignInPlugin/Assets/GoogleSignIn/GoogleSignIn.cs @@ -87,7 +87,9 @@ public static GoogleSignInConfiguration Configuration { public static GoogleSignIn DefaultInstance { get { if (theInstance == null) { -#if UNITY_ANDROID || UNITY_IOS +#if UNITY_EDITOR || UNITY_STANDALONE + theInstance = new GoogleSignIn(new GoogleSignInImplEditor(Configuration)); +#elif UNITY_ANDROID || UNITY_IOS theInstance = new GoogleSignIn(new GoogleSignInImpl(Configuration)); #else theInstance = new GoogleSignIn(null); @@ -100,7 +102,7 @@ public static GoogleSignIn DefaultInstance { } } - internal GoogleSignIn(GoogleSignInImpl impl) { + internal GoogleSignIn(ISignInImpl impl) { this.impl = impl; } diff --git a/GoogleSignInPlugin/Assets/GoogleSignIn/GoogleSignIn.cs.meta b/GoogleSignInPlugin/Assets/GoogleSignIn/GoogleSignIn.cs.meta index e289fb9f..31609ffd 100644 --- a/GoogleSignInPlugin/Assets/GoogleSignIn/GoogleSignIn.cs.meta +++ b/GoogleSignInPlugin/Assets/GoogleSignIn/GoogleSignIn.cs.meta @@ -2,9 +2,9 @@ fileFormatVersion: 2 guid: 138b984208e394be797ce8905a44fd54 labels: - gvh -timeCreated: 1490814915 -licenseType: Pro +- gvh_version-1.0.4 MonoImporter: + externalObjects: {} serializedVersion: 2 defaultReferences: [] executionOrder: 0 diff --git a/GoogleSignInPlugin/Assets/GoogleSignIn/GoogleSignInConfiguration.cs b/GoogleSignInPlugin/Assets/GoogleSignIn/GoogleSignInConfiguration.cs index d914c68d..8eb14a79 100644 --- a/GoogleSignInPlugin/Assets/GoogleSignIn/GoogleSignInConfiguration.cs +++ b/GoogleSignInPlugin/Assets/GoogleSignIn/GoogleSignInConfiguration.cs @@ -30,6 +30,11 @@ public class GoogleSignInConfiguration { /// See the README for more details. /// public bool UseGameSignIn = false; +#if UNITY_EDITOR || UNITY_STANDALONE + /// Client Secret for used in editor and desktop platform + /// Required for requesting auth code or id token in editor + public string ClientSecret = null; +#endif /// Web client id associated with this app. /// Required for requesting auth code or id token. public string WebClientId = null; diff --git a/GoogleSignInPlugin/Assets/GoogleSignIn/GoogleSignInConfiguration.cs.meta b/GoogleSignInPlugin/Assets/GoogleSignIn/GoogleSignInConfiguration.cs.meta index 0a5774a6..943644cc 100644 --- a/GoogleSignInPlugin/Assets/GoogleSignIn/GoogleSignInConfiguration.cs.meta +++ b/GoogleSignInPlugin/Assets/GoogleSignIn/GoogleSignInConfiguration.cs.meta @@ -2,9 +2,9 @@ fileFormatVersion: 2 guid: 0c3999c0f68f04ae08f04fb3bf2a2050 labels: - gvh -timeCreated: 1495747213 -licenseType: Pro +- gvh_version-1.0.4 MonoImporter: + externalObjects: {} serializedVersion: 2 defaultReferences: [] executionOrder: 0 diff --git a/GoogleSignInPlugin/Assets/GoogleSignIn/GoogleSignInStatusCode.cs.meta b/GoogleSignInPlugin/Assets/GoogleSignIn/GoogleSignInStatusCode.cs.meta index 9a8718dd..238e45f5 100644 --- a/GoogleSignInPlugin/Assets/GoogleSignIn/GoogleSignInStatusCode.cs.meta +++ b/GoogleSignInPlugin/Assets/GoogleSignIn/GoogleSignInStatusCode.cs.meta @@ -2,9 +2,9 @@ fileFormatVersion: 2 guid: 077933fcaedac412d9762bf3e0a3be68 labels: - gvh -timeCreated: 1501271136 -licenseType: Pro +- gvh_version-1.0.4 MonoImporter: + externalObjects: {} serializedVersion: 2 defaultReferences: [] executionOrder: 0 diff --git a/GoogleSignInPlugin/Assets/GoogleSignIn/GoogleSignInUser.cs.meta b/GoogleSignInPlugin/Assets/GoogleSignIn/GoogleSignInUser.cs.meta index 757b4d0d..587c6861 100644 --- a/GoogleSignInPlugin/Assets/GoogleSignIn/GoogleSignInUser.cs.meta +++ b/GoogleSignInPlugin/Assets/GoogleSignIn/GoogleSignInUser.cs.meta @@ -2,9 +2,9 @@ fileFormatVersion: 2 guid: c56b92217d0144af5907627d1235e0a5 labels: - gvh -timeCreated: 1495747250 -licenseType: Pro +- gvh_version-1.0.4 MonoImporter: + externalObjects: {} serializedVersion: 2 defaultReferences: [] executionOrder: 0 diff --git a/GoogleSignInPlugin/Assets/GoogleSignIn/Impl/BaseObject.cs.meta b/GoogleSignInPlugin/Assets/GoogleSignIn/Impl/BaseObject.cs.meta index 286f1c84..0e24225d 100644 --- a/GoogleSignInPlugin/Assets/GoogleSignIn/Impl/BaseObject.cs.meta +++ b/GoogleSignInPlugin/Assets/GoogleSignIn/Impl/BaseObject.cs.meta @@ -2,9 +2,9 @@ fileFormatVersion: 2 guid: fe250cda690a44cb08f8f7d26c9723b4 labels: - gvh -timeCreated: 1495748295 -licenseType: Pro +- gvh_version-1.0.4 MonoImporter: + externalObjects: {} serializedVersion: 2 defaultReferences: [] executionOrder: 0 diff --git a/GoogleSignInPlugin/Assets/GoogleSignIn/Impl/GoogleSignInImpl.cs b/GoogleSignInPlugin/Assets/GoogleSignIn/Impl/GoogleSignInImpl.cs index 78c8081f..aa6335e3 100644 --- a/GoogleSignInPlugin/Assets/GoogleSignIn/Impl/GoogleSignInImpl.cs +++ b/GoogleSignInPlugin/Assets/GoogleSignIn/Impl/GoogleSignInImpl.cs @@ -16,16 +16,13 @@ namespace Google.Impl { using System; + using System.Text; using System.Collections.Generic; using System.Runtime.InteropServices; - internal class GoogleSignInImpl : BaseObject, ISignInImpl { + using UnityEngine; -#if UNITY_ANDROID - private const string DllName = "native-googlesignin"; -#else - private const string DllName = "__Internal"; -#endif + internal class GoogleSignInImpl : BaseObject, ISignInImpl { internal GoogleSignInImpl(GoogleSignInConfiguration configuration) : base(GoogleSignIn_Create(GetPlayerActivity())) { @@ -93,6 +90,94 @@ public void Disconnect() { GoogleSignIn_Disconnect(SelfPtr()); } +#if UNITY_ANDROID + static AndroidJavaClass GoogleSignInHelper = new AndroidJavaClass("com.google.googlesignin.GoogleSignInHelper"); + static AndroidJavaClass GoogleSignInFragment = new AndroidJavaClass("com.google.googlesignin.GoogleSignInFragment"); + + static AndroidJavaObject parentActivity; + static IntPtr GoogleSignIn_Create(IntPtr activity) + { + parentActivity = new AndroidJavaObject(activity); + + return GoogleSignInFragment.CallStatic("getInstance",parentActivity).GetRawObject(); + } + + static bool GoogleSignIn_Configure(HandleRef googleSignInHelper, + bool useGameSignIn, string webClientId, + bool requestAuthCode, bool forceTokenRefresh, bool requestEmail, + bool requestIdToken, bool hidePopups, string[] additionalScopes, + int scopeCount, string accountName) + { + GoogleSignInHelper.CallStatic("configure",parentActivity, + useGameSignIn, + webClientId, + requestAuthCode, + forceTokenRefresh, + requestEmail, + requestIdToken, + hidePopups, + accountName, + additionalScopes, + new SignInListener()); + + return !useGameSignIn; + } + + public class SignInListener : AndroidJavaProxy + { + public SignInListener() : base("com.google.googlesignin.IListener") + { + + } + + public void OnResult(int result, AndroidJavaObject acct) + { + + } + } + + static void GoogleSignIn_EnableDebugLogging(HandleRef self, bool flag) => GoogleSignInHelper.CallStatic("enableDebugLogging",flag); + + static IntPtr GoogleSignIn_SignIn(HandleRef self) + { + return GoogleSignInHelper.CallStatic("signIn",parentActivity).GetRawObject(); + } + + static IntPtr GoogleSignIn_SignInSilently(HandleRef self) + { + return GoogleSignInHelper.CallStatic("signInSilently",parentActivity).GetRawObject(); + } + + static void GoogleSignIn_Signout(HandleRef self) => GoogleSignInHelper.CallStatic("signOut",new AndroidJavaObject(self.Handle)); + + static void GoogleSignIn_Disconnect(HandleRef self) => GoogleSignInHelper.CallStatic("disconnect",new AndroidJavaObject(self.Handle)); + + internal static void GoogleSignIn_DisposeFuture(HandleRef self) => new AndroidJavaObject(self.Handle).Dispose(); + + internal static bool GoogleSignIn_Pending(HandleRef self) => new AndroidJavaObject(self.Handle).Call("isPending"); + + internal static IntPtr GoogleSignIn_Result(HandleRef self) => new AndroidJavaObject(self.Handle).Call("getAccount").GetRawObject(); + + internal static int GoogleSignIn_Status(HandleRef self) => new AndroidJavaObject(self.Handle).Call("getStatus"); + + internal static string GoogleSignIn_GetServerAuthCode(HandleRef self) => new AndroidJavaObject(self.Handle).Call("getServerAuthCode"); + + internal static string GoogleSignIn_GetDisplayName(HandleRef self) => new AndroidJavaObject(self.Handle).Call("getDisplayName"); + + internal static string GoogleSignIn_GetEmail(HandleRef self) => new AndroidJavaObject(self.Handle).Call("getEmail"); + + internal static string GoogleSignIn_GetFamilyName(HandleRef self) => new AndroidJavaObject(self.Handle).Call("getFamilyName"); + + internal static string GoogleSignIn_GetGivenName(HandleRef self) => new AndroidJavaObject(self.Handle).Call("getGivenName"); + + internal static string GoogleSignIn_GetIdToken(HandleRef self) => new AndroidJavaObject(self.Handle).Call("getIdToken"); + + internal static string GoogleSignIn_GetImageUrl(HandleRef self) => new AndroidJavaObject(self.Handle).Call("getPhotoUrl").Call("toString"); + + internal static string GoogleSignIn_GetUserId(HandleRef self) => new AndroidJavaObject(self.Handle).Call("getId"); +#else + private const string DllName = "__Internal"; + /// /// Creates an instance of the native Google Sign-In implementation. /// @@ -144,41 +229,86 @@ internal static extern UIntPtr GoogleSignIn_GetServerAuthCode( HandleRef self, [In, Out] byte[] bytes, UIntPtr len); [DllImport(DllName)] - internal static extern UIntPtr GoogleSignIn_GetDisplayName(HandleRef self, - [In, Out] byte[] bytes, UIntPtr len); + internal static extern UIntPtr GoogleSignIn_GetDisplayName(HandleRef self, [In, Out] byte[] bytes, UIntPtr len); [DllImport(DllName)] - internal static extern UIntPtr GoogleSignIn_GetEmail(HandleRef self, - [In, Out] byte[] bytes, UIntPtr len); + internal static extern UIntPtr GoogleSignIn_GetEmail(HandleRef self, [In, Out] byte[] bytes, UIntPtr len); [DllImport(DllName)] - internal static extern UIntPtr GoogleSignIn_GetFamilyName(HandleRef self, - [In, Out] byte[] bytes, UIntPtr len); + internal static extern UIntPtr GoogleSignIn_GetFamilyName(HandleRef self, [In, Out] byte[] bytes, UIntPtr len); [DllImport(DllName)] - internal static extern UIntPtr GoogleSignIn_GetGivenName(HandleRef self, - [In, Out] byte[] bytes, UIntPtr len); + internal static extern UIntPtr GoogleSignIn_GetGivenName(HandleRef self, [In, Out] byte[] bytes, UIntPtr len); [DllImport(DllName)] - internal static extern UIntPtr GoogleSignIn_GetIdToken(HandleRef self, - [In, Out] byte[] bytes, UIntPtr len); + internal static extern UIntPtr GoogleSignIn_GetIdToken(HandleRef self, [In, Out] byte[] bytes, UIntPtr len); [DllImport(DllName)] - internal static extern UIntPtr GoogleSignIn_GetImageUrl(HandleRef self, - [In, Out] byte[] bytes, UIntPtr len); + internal static extern UIntPtr GoogleSignIn_GetImageUrl(HandleRef self, [In, Out] byte[] bytes, UIntPtr len); [DllImport(DllName)] - internal static extern UIntPtr GoogleSignIn_GetUserId(HandleRef self, - [In, Out] byte[] bytes, UIntPtr len); + internal static extern UIntPtr GoogleSignIn_GetUserId(HandleRef self, [In, Out] byte[] bytes, UIntPtr len); + + internal static string GoogleSignIn_GetServerAuthCode(HandleRef self) => + OutParamsToString((out_string, out_size) => + GoogleSignInImpl.GoogleSignIn_GetServerAuthCode(self, out_string, out_size)); + + internal static string GoogleSignIn_GetDisplayName(HandleRef self) => + OutParamsToString((out_string, out_size) => + GoogleSignInImpl.GoogleSignIn_GetDisplayName(self, out_string, out_size)); + + internal static string GoogleSignIn_GetEmail(HandleRef self) => + OutParamsToString((out_string, out_size) => + GoogleSignInImpl.GoogleSignIn_GetEmail(self, out_string, out_size)); + + internal static string GoogleSignIn_GetFamilyName(HandleRef self) => + OutParamsToString((out_string, out_size) => + GoogleSignInImpl.GoogleSignIn_GetFamilyName(self, out_string, out_size)); + + internal static string GoogleSignIn_GetGivenName(HandleRef self) => + OutParamsToString((out_string, out_size) => + GoogleSignInImpl.GoogleSignIn_GetGivenName(self, out_string, out_size)); + + internal static string GoogleSignIn_GetIdToken(HandleRef self) => + OutParamsToString((out_string, out_size) => + GoogleSignInImpl.GoogleSignIn_GetIdToken(self, out_string, out_size)); + + internal static string GoogleSignIn_GetImageUrl(HandleRef self) => + OutParamsToString((out_string, out_size) => + GoogleSignInImpl.GoogleSignIn_GetImageUrl(self, out_string, out_size)); + + internal static string GoogleSignIn_GetUserId(HandleRef self) => + OutParamsToString((out_string, out_size) => + GoogleSignInImpl.GoogleSignIn_GetUserId(self, out_string, out_size)); + + internal delegate UIntPtr OutStringMethod([In, Out] byte[] out_bytes,UIntPtr out_size); + + internal static String OutParamsToString(OutStringMethod outStringMethod) { + UIntPtr requiredSize = outStringMethod(null, UIntPtr.Zero); + if (requiredSize.Equals(UIntPtr.Zero)) { + return null; + } + + string str = null; + try { + byte[] array = new byte[requiredSize.ToUInt32()]; + outStringMethod(array, requiredSize); + str = Encoding.UTF8.GetString(array, 0, + (int)requiredSize.ToUInt32() - 1); + } catch (Exception e) { + Debug.LogError("Exception creating string from char array: " + e); + str = string.Empty; + } + return str; + } +#endif // Gets the Unity player activity. // For iOS, this returns Zero. private static IntPtr GetPlayerActivity() { #if UNITY_ANDROID - UnityEngine.AndroidJavaClass jc = new UnityEngine.AndroidJavaClass( - "com.unity3d.player.UnityPlayer"); - return jc.GetStatic("currentActivity") - .GetRawObject(); + var jc = new AndroidJavaClass("com.unity3d.player.UnityPlayer"); + return jc.GetStatic("currentActivity").GetRawObject(); #else return IntPtr.Zero; #endif diff --git a/GoogleSignInPlugin/Assets/GoogleSignIn/Impl/GoogleSignInImpl.cs.meta b/GoogleSignInPlugin/Assets/GoogleSignIn/Impl/GoogleSignInImpl.cs.meta index d4e90199..46c1d561 100644 --- a/GoogleSignInPlugin/Assets/GoogleSignIn/Impl/GoogleSignInImpl.cs.meta +++ b/GoogleSignInPlugin/Assets/GoogleSignIn/Impl/GoogleSignInImpl.cs.meta @@ -2,9 +2,9 @@ fileFormatVersion: 2 guid: 9ae1f008f9f994b9c96c1a14067d7b48 labels: - gvh -timeCreated: 1502758941 -licenseType: Pro +- gvh_version-1.0.4 MonoImporter: + externalObjects: {} serializedVersion: 2 defaultReferences: [] executionOrder: 0 diff --git a/GoogleSignInPlugin/Assets/GoogleSignIn/Impl/GoogleSignInImplEditor.cs b/GoogleSignInPlugin/Assets/GoogleSignIn/Impl/GoogleSignInImplEditor.cs new file mode 100644 index 00000000..35fd8920 --- /dev/null +++ b/GoogleSignInPlugin/Assets/GoogleSignIn/Impl/GoogleSignInImplEditor.cs @@ -0,0 +1,199 @@ +#if UNITY_EDITOR || UNITY_STANDALONE +using System; +using System.IO; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +using System.Net; +using System.Net.NetworkInformation; + +using UnityEngine; + +using Newtonsoft.Json.Linq; + +namespace Google.Impl +{ + internal class GoogleSignInImplEditor : ISignInImpl, FutureAPIImpl + { + GoogleSignInConfiguration configuration; + + public bool Pending { get; private set; } + + public GoogleSignInStatusCode Status { get; private set; } + + public GoogleSignInUser Result { get; private set; } + + public GoogleSignInImplEditor(GoogleSignInConfiguration configuration) + { + this.configuration = configuration; + } + + public void Disconnect() + { + throw new NotImplementedException(); + } + + public void EnableDebugLogging(bool flag) + { + throw new NotImplementedException(); + } + + public Future SignIn() + { + SigningIn(); + return new Future(this); + } + + public Future SignInSilently() + { + SigningIn(); + return new Future(this); + } + + public void SignOut() + { + Debug.Log("No need on editor?"); + } + + static HttpListener BindLocalHostFirstAvailablePort() + { + ushort minPort = 49215; +#if UNITY_EDITOR_WIN + var listeners = IPGlobalProperties.GetIPGlobalProperties().GetActiveTcpListeners(); + return Enumerable.Range(minPort, ushort.MaxValue - minPort).Where((i) => !listeners.Any((x) => x.Port == i)).Select((port) => { +#else + return Enumerable.Range(0,10).Select((i) => UnityEngine.Random.Range(minPort,ushort.MaxValue)).Select((port) => { +#endif + try + { + var listener = new HttpListener(); + listener.Prefixes.Add($"http://localhost:{port}/"); + listener.Start(); + return listener; + } + catch(System.Exception e) + { + Debug.LogException(e); + return null; + } + }).FirstOrDefault((listener) => listener != null); + } + + void SigningIn() + { + Debug.Log("SigningIn"); + Pending = true; + var httpListener = BindLocalHostFirstAvailablePort(); + try + { + var openURL = "https://accounts.google.com/o/oauth2/v2/auth?scope=openid email profile&response_type=code&redirect_uri=" + httpListener.Prefixes.FirstOrDefault() + "&client_id=" + configuration.WebClientId; + Debug.Log(openURL); + Application.OpenURL(openURL); + } + catch(Exception e) + { + Debug.LogException(e); + throw; + } + + var taskScheduler = TaskScheduler.FromCurrentSynchronizationContext(); + httpListener.GetContextAsync().ContinueWith(async(task) => { + try + { + var context = task.Result; + var queryString = context.Request.Url.Query; + Debug.Log(queryString); + var queryDictionary = System.Web.HttpUtility.ParseQueryString(queryString); + if(queryDictionary == null || queryDictionary.Get("code") is not string code || string.IsNullOrEmpty(code)) + { + Status = GoogleSignInStatusCode.InvalidAccount; + Debug.Log("no code? : " + context.Request.Url); + + context.Response.StatusCode = 404; + context.Response.OutputStream.Write(Encoding.UTF8.GetBytes("Cannot get code")); + context.Response.Close(); + return; + } + + context.Response.StatusCode = 200; + context.Response.OutputStream.Write(Encoding.UTF8.GetBytes("Can close this page")); + context.Response.Close(); + + var result = await HttpWebRequest.CreateHttp("https://www.googleapis.com/oauth2/v4/token").Post("application/x-www-form-urlencoded","code=" + code + "&client_id=" + configuration.WebClientId + "&client_secret=" + configuration.ClientSecret + "&redirect_uri=" + httpListener.Prefixes.FirstOrDefault() + "&grant_type=authorization_code").ContinueWith((task) => task.Result,taskScheduler); + var jobj = JObject.Parse(result); + Debug.Log(jobj); + + var accessToken = (string)jobj.GetValue("access_token"); + var expiresIn = (int)jobj.GetValue("expires_in"); + var scope = (string)jobj.GetValue("scope"); + var tokenType = (string)jobj.GetValue("token_type"); + + var user = new GoogleSignInUser(); + if(configuration.RequestIdToken) + user.IdToken = (string)jobj.GetValue("id_token"); + + if(configuration.RequestEmail || configuration.RequestProfile) + { + var request = HttpWebRequest.CreateHttp("https://openidconnect.googleapis.com/v1/userinfo"); + request.Method = "GET"; + request.Headers.Add("Authorization", "Bearer " + accessToken); + + var data = await request.GetResponseAsStringAsync().ContinueWith((task) => task.Result,taskScheduler); + // "email_verified": true,"locale": "" + var userInfo = JObject.Parse(data); + user.UserId = (string)userInfo.GetValue("sub"); + user.DisplayName = (string)userInfo.GetValue("name"); + user.GivenName = (string)userInfo.GetValue("given_name"); + user.FamilyName = (string)userInfo.GetValue("family_name"); + user.Email = (string)userInfo.GetValue("email"); + user.ImageUrl = Uri.TryCreate((string)userInfo.GetValue("picture"),UriKind.Absolute,out var url) ? url : null; + } + + Result = user; + + Status = GoogleSignInStatusCode.Success; + } + catch(Exception e) + { + Status = GoogleSignInStatusCode.Error; + Debug.LogException(e); + throw; + } + finally + { + Pending = false; + } + },taskScheduler); + } + } + + public static class EditorExt + { + public static Task Post(this HttpWebRequest request,string contentType,string data,Encoding encoding = null) + { + if(encoding == null) + encoding = Encoding.UTF8; + + request.Method = "POST"; + request.ContentType = contentType; + using(var stream = request.GetRequestStream()) + stream.Write(encoding.GetBytes(data)); + + return request.GetResponseAsStringAsync(encoding); + } + + public static async Task GetResponseAsStringAsync(this HttpWebRequest request,Encoding encoding = null) + { + using(var response = await request.GetResponseAsync()) + { + using(var stream = response.GetResponseStream()) + return stream.ReadToEnd(encoding ?? Encoding.UTF8); + } + } + + public static string ReadToEnd(this Stream stream,Encoding encoding = null) => new StreamReader(stream,encoding ?? Encoding.UTF8).ReadToEnd(); + public static void Write(this Stream stream,byte[] data) => stream.Write(data,0,data.Length); + } +} +#endif \ No newline at end of file diff --git a/GoogleSignInPlugin/Assets/GoogleSignIn/Impl/GoogleSignInImplEditor.cs.meta b/GoogleSignInPlugin/Assets/GoogleSignIn/Impl/GoogleSignInImplEditor.cs.meta new file mode 100644 index 00000000..aabd98e5 --- /dev/null +++ b/GoogleSignInPlugin/Assets/GoogleSignIn/Impl/GoogleSignInImplEditor.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: fbddd2a0a0c14f84aa4aaa7efa06d1d4 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/GoogleSignInPlugin/Assets/GoogleSignIn/Impl/NativeFuture.cs b/GoogleSignInPlugin/Assets/GoogleSignIn/Impl/NativeFuture.cs index 6d460f22..cdb378f5 100644 --- a/GoogleSignInPlugin/Assets/GoogleSignIn/Impl/NativeFuture.cs +++ b/GoogleSignInPlugin/Assets/GoogleSignIn/Impl/NativeFuture.cs @@ -41,48 +41,32 @@ public bool Pending { public GoogleSignInUser Result { get { IntPtr ptr = GoogleSignInImpl.GoogleSignIn_Result(SelfPtr()); - if (ptr != IntPtr.Zero) { - GoogleSignInUser user = new GoogleSignInUser(); - HandleRef userPtr = new HandleRef(user, ptr); - - user.DisplayName = OutParamsToString((out_string, out_size) => - GoogleSignInImpl.GoogleSignIn_GetDisplayName(userPtr, - out_string, - out_size)); - user.Email = OutParamsToString((out_string, out_size) => - GoogleSignInImpl.GoogleSignIn_GetEmail(userPtr, out_string, - out_size)); - - user.FamilyName = OutParamsToString((out_string, out_size) => - GoogleSignInImpl.GoogleSignIn_GetFamilyName(userPtr, out_string, - out_size)); - - user.GivenName = OutParamsToString((out_string, out_size) => - GoogleSignInImpl.GoogleSignIn_GetGivenName(userPtr, out_string, - out_size)); - - user.IdToken = OutParamsToString((out_string, out_size) => - GoogleSignInImpl.GoogleSignIn_GetIdToken(userPtr, out_string, - out_size)); - - user.AuthCode = OutParamsToString((out_string, out_size) => - GoogleSignInImpl.GoogleSignIn_GetServerAuthCode(userPtr, out_string, - out_size)); - - string url = OutParamsToString((out_string, out_size) => - GoogleSignInImpl.GoogleSignIn_GetImageUrl(userPtr, out_string, - out_size)); - if (url.Length > 0) { - user.ImageUrl = new System.Uri(url); - } - - user.UserId = OutParamsToString((out_string, out_size) => - GoogleSignInImpl.GoogleSignIn_GetUserId(userPtr, out_string, - out_size)); - return user; - } else { + if (ptr == IntPtr.Zero) { return null; } + + var user = new GoogleSignInUser(); + var userPtr = new HandleRef(user, ptr); + + user.DisplayName = GoogleSignInImpl.GoogleSignIn_GetDisplayName(userPtr); + + user.Email = GoogleSignInImpl.GoogleSignIn_GetEmail(userPtr); + + user.FamilyName = GoogleSignInImpl.GoogleSignIn_GetFamilyName(userPtr); + + user.GivenName = GoogleSignInImpl.GoogleSignIn_GetGivenName(userPtr); + + user.IdToken = GoogleSignInImpl.GoogleSignIn_GetIdToken(userPtr); + + user.AuthCode = GoogleSignInImpl.GoogleSignIn_GetServerAuthCode(userPtr); + + string url = GoogleSignInImpl.GoogleSignIn_GetImageUrl(userPtr); + if (url.Length > 0) { + user.ImageUrl = new System.Uri(url); + } + + user.UserId = GoogleSignInImpl.GoogleSignIn_GetUserId(userPtr); + return user; } } @@ -94,8 +78,7 @@ public GoogleSignInUser Result { /// The status. public GoogleSignInStatusCode Status { get { - return (GoogleSignInStatusCode)GoogleSignInImpl.GoogleSignIn_Status( - SelfPtr()); + return (GoogleSignInStatusCode)GoogleSignInImpl.GoogleSignIn_Status(SelfPtr()); } } } diff --git a/GoogleSignInPlugin/Assets/GoogleSignIn/Impl/NativeFuture.cs.meta b/GoogleSignInPlugin/Assets/GoogleSignIn/Impl/NativeFuture.cs.meta index 2c44becc..0cb0bd1b 100644 --- a/GoogleSignInPlugin/Assets/GoogleSignIn/Impl/NativeFuture.cs.meta +++ b/GoogleSignInPlugin/Assets/GoogleSignIn/Impl/NativeFuture.cs.meta @@ -2,9 +2,9 @@ fileFormatVersion: 2 guid: 5f1aae79b1ca4432d9d8ec382c54bf46 labels: - gvh -timeCreated: 1502759707 -licenseType: Pro +- gvh_version-1.0.4 MonoImporter: + externalObjects: {} serializedVersion: 2 defaultReferences: [] executionOrder: 0 diff --git a/GoogleSignInPlugin/Assets/GoogleSignIn/Impl/SignInHelperObject.cs.meta b/GoogleSignInPlugin/Assets/GoogleSignIn/Impl/SignInHelperObject.cs.meta index 8f90a6b2..2dd5652c 100644 --- a/GoogleSignInPlugin/Assets/GoogleSignIn/Impl/SignInHelperObject.cs.meta +++ b/GoogleSignInPlugin/Assets/GoogleSignIn/Impl/SignInHelperObject.cs.meta @@ -2,9 +2,9 @@ fileFormatVersion: 2 guid: ad98e5b48888e44eb81dd5884d3a1754 labels: - gvh -timeCreated: 1500486239 -licenseType: Pro +- gvh_version-1.0.4 MonoImporter: + externalObjects: {} serializedVersion: 2 defaultReferences: [] executionOrder: 0 diff --git a/GoogleSignInPlugin/Assets/Plugins/Android.meta b/GoogleSignInPlugin/Assets/Plugins/Android.meta index 8d4c2f5e..5c901c39 100644 --- a/GoogleSignInPlugin/Assets/Plugins/Android.meta +++ b/GoogleSignInPlugin/Assets/Plugins/Android.meta @@ -1,9 +1,8 @@ fileFormatVersion: 2 -guid: 7e4ce092146284b2ab8d322170972a45 +guid: c3c65b0f034270e4caba2316f11faace folderAsset: yes -timeCreated: 1490826122 -licenseType: Pro DefaultImporter: + externalObjects: {} userData: assetBundleName: assetBundleVariant: diff --git a/GoogleSignInPlugin/Assets/GoogleSignIn/Editor/m2repository.meta b/GoogleSignInPlugin/Assets/Plugins/Android/src.meta similarity index 62% rename from GoogleSignInPlugin/Assets/GoogleSignIn/Editor/m2repository.meta rename to GoogleSignInPlugin/Assets/Plugins/Android/src.meta index 26cfc222..641e7dd9 100644 --- a/GoogleSignInPlugin/Assets/GoogleSignIn/Editor/m2repository.meta +++ b/GoogleSignInPlugin/Assets/Plugins/Android/src.meta @@ -1,8 +1,6 @@ fileFormatVersion: 2 -guid: eefc3dc8b56e545998952bd59ab36247 +guid: 48773aabe4b3fb047a3fa9eb0bde5471 folderAsset: yes -timeCreated: 1508956004 -licenseType: Free DefaultImporter: externalObjects: {} userData: diff --git a/GoogleSignInPlugin/Assets/GoogleSignIn/Editor/m2repository/com/google/signin.meta b/GoogleSignInPlugin/Assets/Plugins/Android/src/main.meta similarity index 62% rename from GoogleSignInPlugin/Assets/GoogleSignIn/Editor/m2repository/com/google/signin.meta rename to GoogleSignInPlugin/Assets/Plugins/Android/src/main.meta index 4a56a312..af6edf97 100644 --- a/GoogleSignInPlugin/Assets/GoogleSignIn/Editor/m2repository/com/google/signin.meta +++ b/GoogleSignInPlugin/Assets/Plugins/Android/src/main.meta @@ -1,8 +1,6 @@ fileFormatVersion: 2 -guid: 34b86fc2e934d482ea5f9d1f5354b0f9 +guid: 7d18e7e9da507324389da155a7221c46 folderAsset: yes -timeCreated: 1508956004 -licenseType: Free DefaultImporter: externalObjects: {} userData: diff --git a/GoogleSignInPlugin/Assets/Plugins/Android/src/main/java.meta b/GoogleSignInPlugin/Assets/Plugins/Android/src/main/java.meta new file mode 100644 index 00000000..8b162cb9 --- /dev/null +++ b/GoogleSignInPlugin/Assets/Plugins/Android/src/main/java.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: d3b660da37efb134cb3f07fc6157e014 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/GoogleSignInPlugin/Assets/GoogleSignIn/Editor/m2repository/com.meta b/GoogleSignInPlugin/Assets/Plugins/Android/src/main/java/com.meta similarity index 62% rename from GoogleSignInPlugin/Assets/GoogleSignIn/Editor/m2repository/com.meta rename to GoogleSignInPlugin/Assets/Plugins/Android/src/main/java/com.meta index 9372f2b8..4dc5c3cc 100644 --- a/GoogleSignInPlugin/Assets/GoogleSignIn/Editor/m2repository/com.meta +++ b/GoogleSignInPlugin/Assets/Plugins/Android/src/main/java/com.meta @@ -1,8 +1,6 @@ fileFormatVersion: 2 -guid: ade49ef91c70440a0baeac322ecaa2d7 +guid: 8dbb9fb8f598ac943bcf432238355d51 folderAsset: yes -timeCreated: 1508956004 -licenseType: Free DefaultImporter: externalObjects: {} userData: diff --git a/GoogleSignInPlugin/Assets/GoogleSignIn/Editor/m2repository/com/google.meta b/GoogleSignInPlugin/Assets/Plugins/Android/src/main/java/com/google.meta similarity index 62% rename from GoogleSignInPlugin/Assets/GoogleSignIn/Editor/m2repository/com/google.meta rename to GoogleSignInPlugin/Assets/Plugins/Android/src/main/java/com/google.meta index a1cf31a7..9d0c904d 100644 --- a/GoogleSignInPlugin/Assets/GoogleSignIn/Editor/m2repository/com/google.meta +++ b/GoogleSignInPlugin/Assets/Plugins/Android/src/main/java/com/google.meta @@ -1,8 +1,6 @@ fileFormatVersion: 2 -guid: 707de6ade212a46b1ab4bf4d42325176 +guid: 70bae88dddfd96f40840bbd280386ebe folderAsset: yes -timeCreated: 1508956004 -licenseType: Free DefaultImporter: externalObjects: {} userData: diff --git a/GoogleSignInPlugin/Assets/Plugins/Android/src/main/java/com/google/googlesignin.meta b/GoogleSignInPlugin/Assets/Plugins/Android/src/main/java/com/google/googlesignin.meta new file mode 100644 index 00000000..ffd7079e --- /dev/null +++ b/GoogleSignInPlugin/Assets/Plugins/Android/src/main/java/com/google/googlesignin.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 53682122783400c45bedcd332e89ae2c +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/native-googlesignin/src/main/java/com/google/googlesignin/GoogleSignInFragment.java b/GoogleSignInPlugin/Assets/Plugins/Android/src/main/java/com/google/googlesignin/GoogleSignInFragment.java similarity index 85% rename from native-googlesignin/src/main/java/com/google/googlesignin/GoogleSignInFragment.java rename to GoogleSignInPlugin/Assets/Plugins/Android/src/main/java/com/google/googlesignin/GoogleSignInFragment.java index e844c03c..4c4881f8 100644 --- a/native-googlesignin/src/main/java/com/google/googlesignin/GoogleSignInFragment.java +++ b/GoogleSignInPlugin/Assets/Plugins/Android/src/main/java/com/google/googlesignin/GoogleSignInFragment.java @@ -20,8 +20,8 @@ import android.app.FragmentTransaction; import android.content.Intent; import android.os.Bundle; -import android.support.annotation.NonNull; -import android.support.annotation.Nullable; +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; import android.view.View; import com.google.android.gms.auth.api.Auth; import com.google.android.gms.auth.api.signin.GoogleSignInAccount; @@ -51,6 +51,30 @@ public class GoogleSignInFragment extends Fragment implements public static final String FRAGMENT_TAG = "signin.SignInFragment"; private static final int RC_SIGNIN = 9009; + void DoSignIn(boolean silent) { + if (!silent) { + Intent signInIntent = Auth.GoogleSignInApi.getSignInIntent(mGoogleApiClient); + startActivityForResult(signInIntent, RC_SIGNIN); + return; + } + + Auth.GoogleSignInApi.silentSignIn(mGoogleApiClient).setResultCallback(new ResultCallback() { + @Override + public void onResult(@NonNull GoogleSignInResult googleSignInResult) { + if (!googleSignInResult.isSuccess()) { + GoogleSignInHelper.logError( + "Error with " + "silentSignIn: " + googleSignInResult.getStatus()); + } + + GoogleSignInHelper.nativeOnResult( + request.getHandle(), + googleSignInResult.getStatus().getStatusCode(), + googleSignInResult.getSignInAccount()); + setState(State.READY); + } + }); + } + /** * Handle the Google API Client connection being connected. * @@ -59,34 +83,12 @@ public class GoogleSignInFragment extends Fragment implements @Override public void onConnected(@Nullable Bundle connectionHint) { GoogleSignInHelper.logDebug("onConnected!"); - if (mGoogleApiClient.hasConnectedApi(Auth.GOOGLE_SIGN_IN_API)) { + boolean hasConnectedAuth = mGoogleApiClient.hasConnectedApi(Auth.GOOGLE_SIGN_IN_API); + if (hasConnectedAuth) { GoogleSignInHelper.logDebug("has connected auth!"); - Auth.GoogleSignInApi.silentSignIn(mGoogleApiClient) - .setResultCallback( - new ResultCallback() { - @Override - public void onResult(@NonNull GoogleSignInResult googleSignInResult) { - if (googleSignInResult.isSuccess()) { - GoogleSignInHelper.nativeOnResult( - request.getHandle(), - googleSignInResult.getStatus().getStatusCode(), - googleSignInResult.getSignInAccount()); - setState(State.READY); - } else { - GoogleSignInHelper.logError( - "Error with " + "silentSignIn: " + googleSignInResult.getStatus()); - GoogleSignInHelper.nativeOnResult( - request.getHandle(), - googleSignInResult.getStatus().getStatusCode(), - googleSignInResult.getSignInAccount()); - setState(State.READY); - } - } - }); - } else { - Intent signInIntent = Auth.GoogleSignInApi.getSignInIntent(mGoogleApiClient); - startActivityForResult(signInIntent, RC_SIGNIN); } + + DoSignIn(!hasConnectedAuth); } @Override @@ -103,8 +105,7 @@ public void onConnectionFailed(@NonNull ConnectionResult connectionResult) { // if there is a resolution, just start the sign-in intent, which handles // the resolution logic. if (connectionResult.hasResolution()) { - Intent signInIntent = Auth.GoogleSignInApi.getSignInIntent(mGoogleApiClient); - startActivityForResult(signInIntent, RC_SIGNIN); + DoSignIn(false); } else { GoogleSignInHelper.nativeOnResult( request.getHandle(), @@ -133,6 +134,10 @@ private enum State { } private State state; + + public boolean isPending() { + return state == State.PENDING || state == State.PENDING_SILENT; + } /** * The request to sign-in. This contains the configuration for the API client/Sign-in options and @@ -140,6 +145,22 @@ private enum State { */ private TokenRequest request = null; + public TokenRequest getRequest() { + return request; + } + + public GoogleSignInAccount getAccount() { + return request.getPendingResponse().await().getAccount(); + } + + public int getStatus() { + if(request == null) { + return CommonStatusCodes.DEVELOPER_ERROR; + } + + return request.getPendingResponse().await().getStatus().getStatusCode(); + } + private GoogleApiClient mGoogleApiClient; // TODO: make config async. @@ -255,13 +276,12 @@ private void processWhenReady(boolean silent) { */ private void processRequest(final boolean silent) { try { - if (request != null) { - setState(State.BUSY); - } else { + if (request == null) { GoogleSignInHelper.logInfo("No pending configuration, returning"); return; } + setState(State.BUSY); request .getPendingResponse() .setResultCallback( @@ -290,33 +310,7 @@ public void onResult(@NonNull TokenResult tokenResult) { " Has connected == " + mGoogleApiClient.hasConnectedApi(Auth.GOOGLE_SIGN_IN_API)); if (!mGoogleApiClient.hasConnectedApi(Auth.GOOGLE_SIGN_IN_API)) { - if (!silent) { - Intent signInIntent = Auth.GoogleSignInApi.getSignInIntent(mGoogleApiClient); - startActivityForResult(signInIntent, RC_SIGNIN); - } else { - Auth.GoogleSignInApi.silentSignIn(mGoogleApiClient) - .setResultCallback( - new ResultCallback() { - @Override - public void onResult(@NonNull GoogleSignInResult googleSignInResult) { - if (googleSignInResult.isSuccess()) { - GoogleSignInHelper.nativeOnResult( - request.getHandle(), - googleSignInResult.getStatus().getStatusCode(), - googleSignInResult.getSignInAccount()); - setState(State.READY); - } else { - GoogleSignInHelper.logError( - "Error with " + "silentSignIn: " + googleSignInResult.getStatus()); - GoogleSignInHelper.nativeOnResult( - request.getHandle(), - googleSignInResult.getStatus().getStatusCode(), - googleSignInResult.getSignInAccount()); - setState(State.READY); - } - } - }); - } + DoSignIn(silent); } } catch (Throwable throwable) { GoogleSignInHelper.logError("Exception caught! " + throwable.getMessage()); diff --git a/GoogleSignInPlugin/Assets/Plugins/Android/src/main/java/com/google/googlesignin/GoogleSignInFragment.java.meta b/GoogleSignInPlugin/Assets/Plugins/Android/src/main/java/com/google/googlesignin/GoogleSignInFragment.java.meta new file mode 100644 index 00000000..e957325f --- /dev/null +++ b/GoogleSignInPlugin/Assets/Plugins/Android/src/main/java/com/google/googlesignin/GoogleSignInFragment.java.meta @@ -0,0 +1,32 @@ +fileFormatVersion: 2 +guid: b1fd4b2d68e09924f8b7105c1876d21d +PluginImporter: + externalObjects: {} + serializedVersion: 2 + iconMap: {} + executionOrder: {} + defineConstraints: [] + isPreloaded: 0 + isOverridable: 0 + isExplicitlyReferenced: 0 + validateReferences: 1 + platformData: + - first: + Android: Android + second: + enabled: 1 + settings: {} + - first: + Any: + second: + enabled: 0 + settings: {} + - first: + Editor: Editor + second: + enabled: 0 + settings: + DefaultValueInitialized: true + userData: + assetBundleName: + assetBundleVariant: diff --git a/native-googlesignin/src/main/java/com/google/googlesignin/GoogleSignInHelper.java b/GoogleSignInPlugin/Assets/Plugins/Android/src/main/java/com/google/googlesignin/GoogleSignInHelper.java similarity index 89% rename from native-googlesignin/src/main/java/com/google/googlesignin/GoogleSignInHelper.java rename to GoogleSignInPlugin/Assets/Plugins/Android/src/main/java/com/google/googlesignin/GoogleSignInHelper.java index fd251b30..0dcd5a6a 100644 --- a/native-googlesignin/src/main/java/com/google/googlesignin/GoogleSignInHelper.java +++ b/GoogleSignInPlugin/Assets/Plugins/Android/src/main/java/com/google/googlesignin/GoogleSignInHelper.java @@ -67,7 +67,7 @@ public static void configure( boolean hideUiPopups, String defaultAccountName, String[] additionalScopes, - long requestHandle) { + IListener requestHandle) { logDebug("TokenFragment.configure called"); TokenRequest request = new TokenRequest( @@ -93,22 +93,26 @@ public static void configure( } } - public static void signIn(Activity activity, long requestHandle) { + public static GoogleSignInFragment signIn(Activity activity) { logDebug("AuthHelperFragment.authenticate called!"); GoogleSignInFragment fragment = GoogleSignInFragment.getInstance(activity); if (!fragment.startSignIn()) { - nativeOnResult(requestHandle, CommonStatusCodes.DEVELOPER_ERROR, null); + nativeOnResult(fragment.getRequest().getHandle(), CommonStatusCodes.DEVELOPER_ERROR, null); } + + return fragment; } - public static void signInSilently(Activity activity, long requestHandle) { + public static GoogleSignInFragment signInSilently(Activity activity) { logDebug("AuthHelperFragment.signinSilently called!"); GoogleSignInFragment fragment = GoogleSignInFragment.getInstance(activity); if (!fragment.startSignInSilently()) { - nativeOnResult(requestHandle, CommonStatusCodes.DEVELOPER_ERROR, null); + nativeOnResult(fragment.getRequest().getHandle(), CommonStatusCodes.DEVELOPER_ERROR, null); } + + return fragment; } public static void signOut(Activity activity) { @@ -144,5 +148,8 @@ public static void logDebug(String msg) { * @param result Authentication result. * @param acct The account that is signed in, if successful. */ - public static native void nativeOnResult(long handle, int result, GoogleSignInAccount acct); + public static void nativeOnResult(IListener handle, int result, GoogleSignInAccount acct) + { + handle.OnResult(result,acct); + } } diff --git a/GoogleSignInPlugin/Assets/Plugins/Android/src/main/java/com/google/googlesignin/GoogleSignInHelper.java.meta b/GoogleSignInPlugin/Assets/Plugins/Android/src/main/java/com/google/googlesignin/GoogleSignInHelper.java.meta new file mode 100644 index 00000000..a31fd982 --- /dev/null +++ b/GoogleSignInPlugin/Assets/Plugins/Android/src/main/java/com/google/googlesignin/GoogleSignInHelper.java.meta @@ -0,0 +1,32 @@ +fileFormatVersion: 2 +guid: 7f834712c6088fe4e935636c1b9960ef +PluginImporter: + externalObjects: {} + serializedVersion: 2 + iconMap: {} + executionOrder: {} + defineConstraints: [] + isPreloaded: 0 + isOverridable: 0 + isExplicitlyReferenced: 0 + validateReferences: 1 + platformData: + - first: + Android: Android + second: + enabled: 1 + settings: {} + - first: + Any: + second: + enabled: 0 + settings: {} + - first: + Editor: Editor + second: + enabled: 0 + settings: + DefaultValueInitialized: true + userData: + assetBundleName: + assetBundleVariant: diff --git a/GoogleSignInPlugin/Assets/Plugins/Android/src/main/java/com/google/googlesignin/IListener.java b/GoogleSignInPlugin/Assets/Plugins/Android/src/main/java/com/google/googlesignin/IListener.java new file mode 100644 index 00000000..5ebce7a5 --- /dev/null +++ b/GoogleSignInPlugin/Assets/Plugins/Android/src/main/java/com/google/googlesignin/IListener.java @@ -0,0 +1,8 @@ +package com.google.googlesignin; + +import com.google.android.gms.auth.api.signin.GoogleSignInAccount; + +public interface IListener +{ + void OnResult(int result, GoogleSignInAccount acct); +} \ No newline at end of file diff --git a/GoogleSignInPlugin/Assets/Plugins/Android/src/main/java/com/google/googlesignin/IListener.java.meta b/GoogleSignInPlugin/Assets/Plugins/Android/src/main/java/com/google/googlesignin/IListener.java.meta new file mode 100644 index 00000000..e545d5d3 --- /dev/null +++ b/GoogleSignInPlugin/Assets/Plugins/Android/src/main/java/com/google/googlesignin/IListener.java.meta @@ -0,0 +1,32 @@ +fileFormatVersion: 2 +guid: bf5da076086ff3f42adf1c261c1794ec +PluginImporter: + externalObjects: {} + serializedVersion: 2 + iconMap: {} + executionOrder: {} + defineConstraints: [] + isPreloaded: 0 + isOverridable: 0 + isExplicitlyReferenced: 0 + validateReferences: 1 + platformData: + - first: + Android: Android + second: + enabled: 1 + settings: {} + - first: + Any: + second: + enabled: 0 + settings: {} + - first: + Editor: Editor + second: + enabled: 0 + settings: + DefaultValueInitialized: true + userData: + assetBundleName: + assetBundleVariant: diff --git a/native-googlesignin/src/main/java/com/google/googlesignin/TokenPendingResult.java b/GoogleSignInPlugin/Assets/Plugins/Android/src/main/java/com/google/googlesignin/TokenPendingResult.java similarity index 97% rename from native-googlesignin/src/main/java/com/google/googlesignin/TokenPendingResult.java rename to GoogleSignInPlugin/Assets/Plugins/Android/src/main/java/com/google/googlesignin/TokenPendingResult.java index 7f8389d0..02d2e9b5 100644 --- a/native-googlesignin/src/main/java/com/google/googlesignin/TokenPendingResult.java +++ b/GoogleSignInPlugin/Assets/Plugins/Android/src/main/java/com/google/googlesignin/TokenPendingResult.java @@ -30,13 +30,13 @@ public class TokenPendingResult extends PendingResult { private static final String TAG = "TokenPendingResult"; - private final long requestHandle; + private final IListener requestHandle; private CountDownLatch latch = new CountDownLatch(1); private TokenResult result; private ResultCallback resultCallback; - public TokenPendingResult(long requestHandle) { + public TokenPendingResult(IListener requestHandle) { this.requestHandle = requestHandle; result = new TokenResult(); result.setHandle(requestHandle); diff --git a/GoogleSignInPlugin/Assets/Plugins/Android/src/main/java/com/google/googlesignin/TokenPendingResult.java.meta b/GoogleSignInPlugin/Assets/Plugins/Android/src/main/java/com/google/googlesignin/TokenPendingResult.java.meta new file mode 100644 index 00000000..ceded97a --- /dev/null +++ b/GoogleSignInPlugin/Assets/Plugins/Android/src/main/java/com/google/googlesignin/TokenPendingResult.java.meta @@ -0,0 +1,32 @@ +fileFormatVersion: 2 +guid: 3065444eac9447a45aa62369e8d28a3b +PluginImporter: + externalObjects: {} + serializedVersion: 2 + iconMap: {} + executionOrder: {} + defineConstraints: [] + isPreloaded: 0 + isOverridable: 0 + isExplicitlyReferenced: 0 + validateReferences: 1 + platformData: + - first: + Android: Android + second: + enabled: 1 + settings: {} + - first: + Any: + second: + enabled: 0 + settings: {} + - first: + Editor: Editor + second: + enabled: 0 + settings: + DefaultValueInitialized: true + userData: + assetBundleName: + assetBundleVariant: diff --git a/native-googlesignin/src/main/java/com/google/googlesignin/TokenRequest.java b/GoogleSignInPlugin/Assets/Plugins/Android/src/main/java/com/google/googlesignin/TokenRequest.java similarity index 98% rename from native-googlesignin/src/main/java/com/google/googlesignin/TokenRequest.java rename to GoogleSignInPlugin/Assets/Plugins/Android/src/main/java/com/google/googlesignin/TokenRequest.java index 35335024..4e81154d 100644 --- a/native-googlesignin/src/main/java/com/google/googlesignin/TokenRequest.java +++ b/GoogleSignInPlugin/Assets/Plugins/Android/src/main/java/com/google/googlesignin/TokenRequest.java @@ -31,7 +31,7 @@ public class TokenRequest { private boolean hidePopups; private String accountName; private String[] scopes; - private long handle; + private IListener handle; /** * Constructs a token request. @@ -60,7 +60,7 @@ public TokenRequest( boolean hideUiPopups, String defaultAccountName, String[] additionalScopes, - long requestHandle) { + IListener requestHandle) { pendingResponse = new TokenPendingResult(requestHandle); this.useGamesConfig = useGamesConfig; this.webClientId = webClientId; @@ -137,7 +137,7 @@ public boolean isValid() { return true; } - public long getHandle() { + public IListener getHandle() { return handle; } diff --git a/GoogleSignInPlugin/Assets/Plugins/Android/src/main/java/com/google/googlesignin/TokenRequest.java.meta b/GoogleSignInPlugin/Assets/Plugins/Android/src/main/java/com/google/googlesignin/TokenRequest.java.meta new file mode 100644 index 00000000..b194122b --- /dev/null +++ b/GoogleSignInPlugin/Assets/Plugins/Android/src/main/java/com/google/googlesignin/TokenRequest.java.meta @@ -0,0 +1,32 @@ +fileFormatVersion: 2 +guid: abff1b835e0405d439149d095c18b791 +PluginImporter: + externalObjects: {} + serializedVersion: 2 + iconMap: {} + executionOrder: {} + defineConstraints: [] + isPreloaded: 0 + isOverridable: 0 + isExplicitlyReferenced: 0 + validateReferences: 1 + platformData: + - first: + Android: Android + second: + enabled: 1 + settings: {} + - first: + Any: + second: + enabled: 0 + settings: {} + - first: + Editor: Editor + second: + enabled: 0 + settings: + DefaultValueInitialized: true + userData: + assetBundleName: + assetBundleVariant: diff --git a/native-googlesignin/src/main/java/com/google/googlesignin/TokenResult.java b/GoogleSignInPlugin/Assets/Plugins/Android/src/main/java/com/google/googlesignin/TokenResult.java similarity index 94% rename from native-googlesignin/src/main/java/com/google/googlesignin/TokenResult.java rename to GoogleSignInPlugin/Assets/Plugins/Android/src/main/java/com/google/googlesignin/TokenResult.java index db85d96b..b5f46f77 100644 --- a/native-googlesignin/src/main/java/com/google/googlesignin/TokenResult.java +++ b/GoogleSignInPlugin/Assets/Plugins/Android/src/main/java/com/google/googlesignin/TokenResult.java @@ -25,7 +25,7 @@ public class TokenResult implements Result { private Status status; private GoogleSignInAccount account; - private long handle; + private IListener handle; TokenResult() { status = new Status(CommonStatusCodes.SIGN_IN_REQUIRED); @@ -56,11 +56,11 @@ public void setStatus(int status) { this.status = new Status(status); } - public long getHandle() { + public IListener getHandle() { return handle; } - public void setHandle(long handle) { + public void setHandle(IListener handle) { this.handle = handle; } } diff --git a/GoogleSignInPlugin/Assets/Plugins/Android/src/main/java/com/google/googlesignin/TokenResult.java.meta b/GoogleSignInPlugin/Assets/Plugins/Android/src/main/java/com/google/googlesignin/TokenResult.java.meta new file mode 100644 index 00000000..34333901 --- /dev/null +++ b/GoogleSignInPlugin/Assets/Plugins/Android/src/main/java/com/google/googlesignin/TokenResult.java.meta @@ -0,0 +1,32 @@ +fileFormatVersion: 2 +guid: 255165ffb347b9d4f802441bb7cab85b +PluginImporter: + externalObjects: {} + serializedVersion: 2 + iconMap: {} + executionOrder: {} + defineConstraints: [] + isPreloaded: 0 + isOverridable: 0 + isExplicitlyReferenced: 0 + validateReferences: 1 + platformData: + - first: + Android: Android + second: + enabled: 1 + settings: {} + - first: + Any: + second: + enabled: 0 + settings: {} + - first: + Editor: Editor + second: + enabled: 0 + settings: + DefaultValueInitialized: true + userData: + assetBundleName: + assetBundleVariant: diff --git a/GoogleSignInPlugin/Assets/Plugins/iOS/GoogleSignIn/GoogleSignIn.h b/GoogleSignInPlugin/Assets/Plugins/iOS/GoogleSignIn.h similarity index 100% rename from GoogleSignInPlugin/Assets/Plugins/iOS/GoogleSignIn/GoogleSignIn.h rename to GoogleSignInPlugin/Assets/Plugins/iOS/GoogleSignIn.h diff --git a/GoogleSignInPlugin/Assets/Plugins/iOS/GoogleSignIn.h.meta b/GoogleSignInPlugin/Assets/Plugins/iOS/GoogleSignIn.h.meta new file mode 100644 index 00000000..e115ee31 --- /dev/null +++ b/GoogleSignInPlugin/Assets/Plugins/iOS/GoogleSignIn.h.meta @@ -0,0 +1,35 @@ +fileFormatVersion: 2 +guid: 62c129704e1ec48179ba285e1af154b8 +labels: +- gvh +- gvh_version-1.0.4 +PluginImporter: + externalObjects: {} + serializedVersion: 2 + iconMap: {} + executionOrder: {} + defineConstraints: [] + isPreloaded: 0 + isOverridable: 0 + isExplicitlyReferenced: 0 + validateReferences: 1 + platformData: + - first: + Any: + second: + enabled: 0 + settings: {} + - first: + Editor: Editor + second: + enabled: 0 + settings: + DefaultValueInitialized: true + - first: + iPhone: iOS + second: + enabled: 1 + settings: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/GoogleSignInPlugin/Assets/Plugins/iOS/GoogleSignIn.meta b/GoogleSignInPlugin/Assets/Plugins/iOS/GoogleSignIn.meta deleted file mode 100644 index c4ea38dc..00000000 --- a/GoogleSignInPlugin/Assets/Plugins/iOS/GoogleSignIn.meta +++ /dev/null @@ -1,9 +0,0 @@ -fileFormatVersion: 2 -guid: 07c86a3f84f494e589218ed67d10255a -folderAsset: yes -timeCreated: 1490995894 -licenseType: Pro -DefaultImporter: - userData: - assetBundleName: - assetBundleVariant: diff --git a/GoogleSignInPlugin/Assets/Plugins/iOS/GoogleSignIn/GoogleSignIn.mm b/GoogleSignInPlugin/Assets/Plugins/iOS/GoogleSignIn.mm similarity index 100% rename from GoogleSignInPlugin/Assets/Plugins/iOS/GoogleSignIn/GoogleSignIn.mm rename to GoogleSignInPlugin/Assets/Plugins/iOS/GoogleSignIn.mm diff --git a/GoogleSignInPlugin/Assets/Plugins/iOS/GoogleSignIn.mm.meta b/GoogleSignInPlugin/Assets/Plugins/iOS/GoogleSignIn.mm.meta new file mode 100644 index 00000000..98623911 --- /dev/null +++ b/GoogleSignInPlugin/Assets/Plugins/iOS/GoogleSignIn.mm.meta @@ -0,0 +1,35 @@ +fileFormatVersion: 2 +guid: 521784ee6b2184e0e947a8fd1508afbc +labels: +- gvh +- gvh_version-1.0.4 +PluginImporter: + externalObjects: {} + serializedVersion: 2 + iconMap: {} + executionOrder: {} + defineConstraints: [] + isPreloaded: 0 + isOverridable: 0 + isExplicitlyReferenced: 0 + validateReferences: 1 + platformData: + - first: + Any: + second: + enabled: 0 + settings: {} + - first: + Editor: Editor + second: + enabled: 0 + settings: + DefaultValueInitialized: true + - first: + iPhone: iOS + second: + enabled: 1 + settings: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/GoogleSignInPlugin/Assets/Plugins/iOS/GoogleSignIn/GoogleSignIn.h.meta b/GoogleSignInPlugin/Assets/Plugins/iOS/GoogleSignIn/GoogleSignIn.h.meta deleted file mode 100644 index 25735784..00000000 --- a/GoogleSignInPlugin/Assets/Plugins/iOS/GoogleSignIn/GoogleSignIn.h.meta +++ /dev/null @@ -1,35 +0,0 @@ -fileFormatVersion: 2 -guid: 62c129704e1ec48179ba285e1af154b8 -labels: -- gvh -timeCreated: 1510357716 -licenseType: Pro -PluginImporter: - serializedVersion: 2 - iconMap: {} - executionOrder: {} - isPreloaded: 0 - isOverridable: 0 - platformData: - data: - first: - Any: - second: - enabled: 0 - settings: {} - data: - first: - Editor: Editor - second: - enabled: 0 - settings: - DefaultValueInitialized: true - data: - first: - iPhone: iOS - second: - enabled: 1 - settings: {} - userData: - assetBundleName: - assetBundleVariant: diff --git a/GoogleSignInPlugin/Assets/Plugins/iOS/GoogleSignIn/GoogleSignIn.mm.meta b/GoogleSignInPlugin/Assets/Plugins/iOS/GoogleSignIn/GoogleSignIn.mm.meta deleted file mode 100644 index d33a9650..00000000 --- a/GoogleSignInPlugin/Assets/Plugins/iOS/GoogleSignIn/GoogleSignIn.mm.meta +++ /dev/null @@ -1,35 +0,0 @@ -fileFormatVersion: 2 -guid: 521784ee6b2184e0e947a8fd1508afbc -labels: -- gvh -timeCreated: 1510357716 -licenseType: Pro -PluginImporter: - serializedVersion: 2 - iconMap: {} - executionOrder: {} - isPreloaded: 0 - isOverridable: 0 - platformData: - data: - first: - Any: - second: - enabled: 0 - settings: {} - data: - first: - Editor: Editor - second: - enabled: 0 - settings: - DefaultValueInitialized: true - data: - first: - iPhone: iOS - second: - enabled: 1 - settings: {} - userData: - assetBundleName: - assetBundleVariant: diff --git a/GoogleSignInPlugin/Assets/Plugins/iOS/GoogleSignIn/GoogleSignInAppController.h b/GoogleSignInPlugin/Assets/Plugins/iOS/GoogleSignInAppController.h similarity index 100% rename from GoogleSignInPlugin/Assets/Plugins/iOS/GoogleSignIn/GoogleSignInAppController.h rename to GoogleSignInPlugin/Assets/Plugins/iOS/GoogleSignInAppController.h diff --git a/GoogleSignInPlugin/Assets/Plugins/iOS/GoogleSignIn/GoogleSignInAppController.h.meta b/GoogleSignInPlugin/Assets/Plugins/iOS/GoogleSignInAppController.h.meta similarity index 59% rename from GoogleSignInPlugin/Assets/Plugins/iOS/GoogleSignIn/GoogleSignInAppController.h.meta rename to GoogleSignInPlugin/Assets/Plugins/iOS/GoogleSignInAppController.h.meta index fc4d5558..1005ed81 100644 --- a/GoogleSignInPlugin/Assets/Plugins/iOS/GoogleSignIn/GoogleSignInAppController.h.meta +++ b/GoogleSignInPlugin/Assets/Plugins/iOS/GoogleSignInAppController.h.meta @@ -2,23 +2,32 @@ fileFormatVersion: 2 guid: ce40e3e7b37a54617a4683dfc0479c71 labels: - gvh -timeCreated: 1490998272 -licenseType: Pro +- gvh_version-1.0.4 PluginImporter: - serializedVersion: 1 + externalObjects: {} + serializedVersion: 2 iconMap: {} executionOrder: {} + defineConstraints: [] isPreloaded: 0 isOverridable: 0 + isExplicitlyReferenced: 0 + validateReferences: 1 platformData: - Any: + - first: + Any: + second: enabled: 0 settings: {} - Editor: + - first: + Editor: Editor + second: enabled: 0 settings: DefaultValueInitialized: true - iOS: + - first: + iPhone: iOS + second: enabled: 1 settings: {} userData: diff --git a/GoogleSignInPlugin/Assets/Plugins/iOS/GoogleSignIn/GoogleSignInAppController.mm b/GoogleSignInPlugin/Assets/Plugins/iOS/GoogleSignInAppController.mm similarity index 87% rename from GoogleSignInPlugin/Assets/Plugins/iOS/GoogleSignIn/GoogleSignInAppController.mm rename to GoogleSignInPlugin/Assets/Plugins/iOS/GoogleSignInAppController.mm index fe7601c5..66d92c21 100644 --- a/GoogleSignInPlugin/Assets/Plugins/iOS/GoogleSignIn/GoogleSignInAppController.mm +++ b/GoogleSignInPlugin/Assets/Plugins/iOS/GoogleSignInAppController.mm @@ -59,11 +59,9 @@ + (void)load { method_exchangeImplementations(original, swizzled); } -- (BOOL)GoogleSignInAppController:(UIApplication *)application - didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { - - return [self GoogleSignInAppController:application - didFinishLaunchingWithOptions:launchOptions]; +- (BOOL)GoogleSignInAppController:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { + NSLog(@"GSI application:didFinishLaunchingWithOption:"); + return [self GoogleSignInAppController:application didFinishLaunchingWithOptions:launchOptions]; } /** @@ -77,7 +75,7 @@ - (BOOL)GoogleSignInAppController:(UIApplication *)application openURL:url sourceApplication:sourceApplication annotation:annotation]; - + NSLog(@"GSI application:openURL:sourceApplication:annotation: %s", [url.absoluteString UTF8String]); return [[GIDSignIn sharedInstance] handleURL:url] || handled; } @@ -87,8 +85,8 @@ - (BOOL)GoogleSignInAppController:(UIApplication *)application - (BOOL)GoogleSignInAppController:(UIApplication *)app openURL:(NSURL *)url options:(NSDictionary *)options { - BOOL handled = [self GoogleSignInAppController:app openURL:url options:options]; + NSLog(@"GSI application:openURL:options: %s", [url.absoluteString UTF8String]); return [[GIDSignIn sharedInstance] handleURL:url] || handled; } diff --git a/GoogleSignInPlugin/Assets/Plugins/iOS/GoogleSignIn/GoogleSignInAppController.mm.meta b/GoogleSignInPlugin/Assets/Plugins/iOS/GoogleSignInAppController.mm.meta similarity index 59% rename from GoogleSignInPlugin/Assets/Plugins/iOS/GoogleSignIn/GoogleSignInAppController.mm.meta rename to GoogleSignInPlugin/Assets/Plugins/iOS/GoogleSignInAppController.mm.meta index 8e0a46a3..676c7108 100644 --- a/GoogleSignInPlugin/Assets/Plugins/iOS/GoogleSignIn/GoogleSignInAppController.mm.meta +++ b/GoogleSignInPlugin/Assets/Plugins/iOS/GoogleSignInAppController.mm.meta @@ -2,23 +2,32 @@ fileFormatVersion: 2 guid: 50b2e1c9319e4446e9dbd9b183790472 labels: - gvh -timeCreated: 1490998272 -licenseType: Pro +- gvh_version-1.0.4 PluginImporter: - serializedVersion: 1 + externalObjects: {} + serializedVersion: 2 iconMap: {} executionOrder: {} + defineConstraints: [] isPreloaded: 0 isOverridable: 0 + isExplicitlyReferenced: 0 + validateReferences: 1 platformData: - Any: + - first: + Any: + second: enabled: 0 settings: {} - Editor: + - first: + Editor: Editor + second: enabled: 0 settings: DefaultValueInitialized: true - iOS: + - first: + iPhone: iOS + second: enabled: 1 settings: {} userData: diff --git a/build.gradle b/build.gradle deleted file mode 100644 index 50f8d7ec..00000000 --- a/build.gradle +++ /dev/null @@ -1,377 +0,0 @@ -/* Copyright (C) 2014 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. - */ - -// Top-level build file where you can add configuration options common to all sub-projects/modules. - -import groovy.io.FileType - -buildscript { - repositories { - google() - jcenter() - } - dependencies { - classpath 'com.android.tools.build:gradle:3.1.4' - - // NOTE: Do not place your application dependencies here; they belong - // in the individual module build.gradle files - } -} - -allprojects { - repositories { - google() - jcenter() - } -} - -project.ext { - // Determine the current OS. - os_name = System.getProperty("os.name").toLowerCase(); - os_osx = os_name.contains("mac os x"); - os_windows = os_name.contains("windows"); - os_linux = os_name.contains("linux"); - - unity_exe = System.getProperty("UNITY_EXE") - if (unity_exe == null || unity_exe.isEmpty()) { - unity_exe = System.getenv("UNITY_EXE") - } - if (unity_exe == null || unity_exe.isEmpty()) { - if (os_osx) { - unity_exe = '/Applications/Unity/Unity.app/Contents/MacOS/Unity' - } else if (os_windows) { - unity_exe = 'c:\\program files\\unity\\editor\\unity.exe' - } else { - // Fallback to just unity, and expect it on the path. - unity_exe = 'unity' - } - } - - git_exe = System.getProperty("GIT_EXE") - if (git_exe == null || git_exe.isEmpty()) { - git_exe = System.getenv("GIT_EXE") - } - if (git_exe == null || git_exe.isEmpty()) { - // Fallback to git and expect it to be on the path. - git_exe = 'git' - } - - pluginVersion = "1.0.4" - currentPluginBasename = 'google-signin-plugin' - currentPluginName = (currentPluginBasename + '-' + pluginVersion + - '.unitypackage') - editorDir = "Assets/GoogleSignIn/Editor" - uploadDir = "${buildDir}/GoogleSignInPlugin/${editorDir}/m2repository" - exportPath = file(currentPluginName).absolutePath - samplePath = file('GoogleSignIn-sample.unitypackage').absolutePath - pluginSrcPath = file('GoogleSignInPlugin').absolutePath - pluginProjectPath = file('build/GoogleSignInPlugin').absolutePath - - resolverDir = new File('build/jarresolver').absolutePath - jarresolver_uri = System.getProperty("RESOLVER_PACKAGE_URI") - jarresolver_repos = [ - 'https://github.com/googlesamples/unity-jar-resolver.git' - ] - // Set the tag to a specific value if you want to build pinned to a - // specific version of the jar resolver (This is uncommon). - // null indicates HEAD. - jarresolver_tag = null; -} - -task clean(type: Delete) { - delete rootProject.buildDir -} - -task copy_unity_project() { - dependsOn ':native-googlesignin:uploadArchives' - doFirst { - copy { - from pluginSrcPath - into pluginProjectPath - } - } -} - -task copy_jarresolver() { - description = "Clones the jar resolver project." - doFirst { - if (file(resolverDir).exists()) { - delete resolverDir - } - } - - doLast { - // Copy the package if the direct path is given. - if (jarresolver_uri != null) { - mkdir("${resolverDir}") - def resolver = new File("${resolverDir}/resolver.unitypackage") - new URL("${jarresolver_uri}").withInputStream { - inputStream -> resolver.withOutputStream { it << inputStream } - } - return - } - - // Else, check each one of the repo addresses and stop when successful. - for (repo in jarresolver_repos) { - def result = exec { - executable "${git_exe}" - args "clone", repo, "${resolverDir}" - ignoreExitValue true - } - if (result.exitValue == 0 && jarresolver_tag != null) { - result = exec { - executable "${git_exe}" - args "checkout", "-b", "buildver", "${jarresolver_tag}" - workingDir "${resolverDir}" - } - } - - if (result.exitValue == 0) { - println "Downloaded resolver from " + repo - return - } - } - } -} - -task import_jarresolver() { - description = "Imports the jar resolver into the project" - dependsOn copy_unity_project, copy_jarresolver - - doLast { - def tree = fileTree(resolverDir) { - include "*.unitypackage" - } - def jarresolver_package = tree.getSingleFile() - def argv = [ - "-gvh_disable", - "-g.building", - "-buildTarget", - "android", - // This prevents the VersionHandler to preserve the plugin layout - "-batchmode", - "-projectPath", pluginProjectPath, - "-logFile", "build/import_jarresolver.log", - "-importPackage", jarresolver_package, - "-quit" - ] - - ext.execResult = exec { - executable "${unity_exe}" - args argv - ignoreExitValue true - } - if (ext.execResult.exitValue != 0) { - println "***Error Running Unity:" - def src = file('build/import_jarresolver.log').text - print src - throw new GradleException('error importing jarresolver plugin') - } - } -} - -task generate_dependency_xml() { - description "Generate the JarResolver dependency file for the support library" - dependsOn copy_unity_project - doFirst { - def xmlFile = file("${pluginProjectPath}/${editorDir}/GoogleSignInSupportDependencies.xml") - - xmlFile << '\n' - xmlFile << '\n' - xmlFile << '\n' - xmlFile << ' \n' - xmlFile << ' \n" - xmlFile << ' \n' - xmlFile << ' Assets/GoogleSignIn/Editor/m2repository\n' - xmlFile << ' \n' - xmlFile << ' \n' - xmlFile << ' \n' - xmlFile << '\n' - } -} - -task generate_manifest(dependsOn: [ 'inject_versionIntoMetaFiles']) { - description 'Generate a manifest for the files in the plug-in.' - doLast { - def dir = file("${pluginProjectPath}/Assets") - def list = [] - dir.eachFileRecurse(groovy.io.FileType.FILES) { filename -> - def path = filename.path - if (!(path.toLowerCase().endsWith('.meta') || - path.toLowerCase().endsWith('.txt'))) { - list << filename.path.replace("${pluginProjectPath}/", '') - } - } - def manifest = file("${pluginProjectPath}/${editorDir}/" + - versionedAssetName(currentPluginBasename + '.txt', - "${pluginVersion}")) - manifest.write(list.join('\n') + '\n') - } -} - -task copy_manifestMetadata(dependsOn: generate_manifest, type: Copy) { - def manifestBasename = versionedAssetName(currentPluginBasename + '.txt', - null) + '.meta' - description 'Copy .meta file for the plugin manifest.' - from file("${pluginSrcPath}/${editorDir}/" + manifestBasename) - into file("${pluginProjectPath}/${editorDir}/") - rename { - String fn -> - return fn.replace(manifestBasename, - versionedAssetName(currentPluginBasename + '.txt', - "${pluginVersion}") + '.meta') - } -} - -task package_plugin () { - description = "Creates and exports the Plugin unity package" - dependsOn generate_manifest, copy_manifestMetadata - - doLast { - def tree = fileTree(resolverDir) { - include "*.unitypackage" - } - def jarresolver_package = tree.getSingleFile() - def argv = [ - "-gvh_disable", - "-g.building", - "-buildTarget", - "android", - // This prevents the VersionHandler to preserve the plugin layout - "-batchmode", - "-projectPath", pluginProjectPath, - "-logFile", "build/unity.log", - "-importPackage", jarresolver_package, - "-exportPackage", - "Assets/GoogleSignIn", - "Assets/Parse", - "Assets/PlayServicesResolver", - "Assets/Plugins", - "${exportPath}", - "-quit" - ] - - ext.execResult = exec { - executable "${unity_exe}" - args argv - ignoreExitValue true - } - if (ext.execResult.exitValue != 0) { - println "***Error Running Unity:" - def src = file('build/unity.log').text - print src - throw new GradleException('error exporting plugin') - } - } -} - - -task package_sample () { - description = "Creates and exports the Google Sign-in Sample" - - doLast { - def argv = [ - "-gvh_disable", - "-g.building", - // NOTE: This doesn't target Android since we don't want to have - // dependencies on the Jar Resolver as they require the plugin to - // be enabled during the build process which would break the - // versioning process. Compilation is verified when exporting - // the sample projects. - "-batchmode", - "-projectPath", pluginProjectPath, - "-logFile", "build/unity-sample.log", - "-exportPackage", - "Assets/SignInSample", - "${samplePath}", - "-quit" - ] - - ext.execResult = exec { - executable "${unity_exe}" - args argv - ignoreExitValue true - } - if (ext.execResult.exitValue != 0) { - println "***Error Running Unity:" - def src = file('build/unity-sample.log').text - print src - throw new GradleException('error exporting sample') - } - } -} - -task inject_versionIntoMetaFiles() { - description 'Inject the version number into the plugin\'s meta files.' - dependsOn copy_unity_project, generate_dependency_xml, import_jarresolver - doLast { - for (fileobj in fileTree("${pluginProjectPath}")) { - if (fileobj.path.endsWith('.meta')) { - // Skip the manifest files for any previous versions - if (fileobj.path.contains("Editor/${currentPluginBasename}")) { - continue - } - def lines = fileobj.text.split('\n') - def outputLines = [] - def added = false - for (line in lines) { - outputLines.add(line) - if (line.contains('labels:')) { - outputLines.add("- gvh_v${pluginVersion}") - added = true - } else if (line.contains('folderAsset:') && line.contains('yes')) { - added = true - } - } - if (!added) { - outputLines.add("labels:\n- gvh_v${pluginVersion}") - } - fileobj.write(outputLines.join('\n') + '\n') - } - } - } -} - -// Construct the name of a versioned asset from the source filename and version -// // string. -// // The encoded string takes the form... -// // ${filename}_v${version}_.${extension} -// // where extension is derived from the specified filename. -def versionedAssetName(filename, version) { - def extensionIndex = filename.lastIndexOf('.') - def basename = filename.substring(0, extensionIndex) - def extension = filename.substring(extensionIndex) - // Encode the DLL version and target names into the DLL in the form... - // ${dllname}_t${hypen_separated_target_names}_v${version}.dll - def targetName = basename - if (version != null && !version.isEmpty()) { - targetName += '_v' + version - } - return targetName + extension -} - -/* - * This is a top level task that build the Unity plugin. - * It does the following: - * - copy the java/C++ library to the Plugins directory. - * - Import the latest Play Services Resolver plugin - * - Build the Google Sign-In plugin package (requires Unity). - * - Build the Google Sign-In Sample package (requires Unity). - */ -task build_all() { - dependsOn ':native-googlesignin:uploadArchives', copy_jarresolver, package_plugin, package_sample -} - diff --git a/build_all.sh b/build_all.sh deleted file mode 100755 index b1035eb2..00000000 --- a/build_all.sh +++ /dev/null @@ -1,5 +0,0 @@ -#!/bin/bash -readonly THIS_DIR="$(cd "$(dirname "$0")"; pwd)" -pushd ${THIS_DIR} -./gradlew -PlintAbortOnError="true" build_all -popd \ No newline at end of file diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar deleted file mode 100644 index 13372aef5e24af05341d49695ee84e5f9b594659..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 53636 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ⅅ8zCNKueM5c!$)^mKpZNR!eIlFST57ePGQcqCqedAQ3UaUEzpjM--5V4YO zY22VxQm%$2NDnwfK+jkz=i2>NjAM6&P1DdcO<*Xs1-lzdXWn#LGSxwhPH7N%D8-zCgpFWt@`LgNYI+Fh^~nSiQmwH0^>E>*O$47MqfQza@Ce z1wBw;igLc#V2@y-*~Hp?jA1)+MYYyAt|DV_8RQCrRY@sAviO}wv;3gFdO>TE(=9o? z=S(r=0oT`w24=ihA=~iFV5z$ZG74?rmYn#eanx(!Hkxcr$*^KRFJKYYB&l6$WVsJ^ z-Iz#HYmE)Da@&seqG1fXsTER#adA&OrD2-T(z}Cwby|mQf{0v*v3hq~pzF`U`jenT z=XHXeB|fa?Ws$+9ADO0rco{#~+`VM?IXg7N>M0w1fyW1iiKTA@p$y zSiAJ%-Mg{m>&S4r#Tw@?@7ck}#oFo-iZJCWc`hw_J$=rw?omE{^tc59ftd`xq?jzf zo0bFUI=$>O!45{!c4?0KsJmZ#$vuYpZLo_O^oHTmmLMm0J_a{Nn`q5tG1m=0ecv$T z5H7r0DZGl6be@aJ+;26EGw9JENj0oJ5K0=^f-yBW2I0jqVIU};NBp*gF7_KlQnhB6 z##d$H({^HXj@il`*4^kC42&3)(A|tuhs;LygA-EWFSqpe+%#?6HG6}mE215Z4mjO2 zY2^?5$<8&k`O~#~sSc5Fy`5hg5#e{kG>SAbTxCh{y32fHkNryU_c0_6h&$zbWc63T z7|r?X7_H!9XK!HfZ+r?FvBQ$x{HTGS=1VN<>Ss-7M3z|vQG|N}Frv{h-q623@Jz*@ ziXlZIpAuY^RPlu&=nO)pFhML5=ut~&zWDSsn%>mv)!P1|^M!d5AwmSPIckoY|0u9I zTDAzG*U&5SPf+@c_tE_I!~Npfi$?gX(kn=zZd|tUZ_ez(xP+)xS!8=k(<{9@<+EUx zYQgZhjn(0qA#?~Q+EA9oh_Jx5PMfE3#KIh#*cFIFQGi)-40NHbJO&%ZvL|LAqU=Rw zf?Vr4qkUcKtLr^g-6*N-tfk+v8@#Lpl~SgKyH!+m9?T8B>WDWK22;!i5&_N=%f{__ z-LHb`v-LvKqTJZCx~z|Yg;U_f)VZu~q7trb%C6fOKs#eJosw&b$nmwGwP;Bz`=zK4 z>U3;}T_ptP)w=vJaL8EhW;J#SHA;fr13f=r#{o)`dRMOs-T;lp&Toi@u^oB_^pw=P zp#8Geo2?@!h2EYHY?L;ayT}-Df0?TeUCe8Cto{W0_a>!7Gxmi5G-nIIS;X{flm2De z{SjFG%knZoVa;mtHR_`*6)KEf=dvOT3OgT7C7&-4P#4X^B%VI&_57cBbli()(%zZC?Y0b;?5!f22UleQ=9h4_LkcA!Xsqx@q{ko&tvP_V@7epFs}AIpM{g??PA>U(sk$Gum>2Eu zD{Oy{$OF%~?B6>ixQeK9I}!$O0!T3#Ir8MW)j2V*qyJ z8Bg17L`rg^B_#rkny-=<3fr}Y42+x0@q6POk$H^*p3~Dc@5uYTQ$pfaRnIT}Wxb;- zl!@kkZkS=l)&=y|21veY8yz$t-&7ecA)TR|=51BKh(@n|d$EN>18)9kSQ|GqP?aeM ztXd9C&Md$PPF*FVs*GhoHM2L@D$(Qf%%x zwQBUt!jM~GgwluBcwkgwQ!249uPkNz3u@LSYZgmpHgX|P#8!iKk^vSKZ;?)KE$92d z2U>y}VWJ0&zjrIqddM3dz-nU%>bL&KU%SA|LiiUU7Ka|c=jF|vQ1V)Jz`JZe*j<5U6~RVuBEVJoY~ z&GE+F$f>4lN=X4-|9v*5O*Os>>r87u z!_1NSV?_X&HeFR1fOFb8_P)4lybJ6?1BWK`Tv2;4t|x1<#@17UO|hLGnrB%nu)fDk zfstJ4{X4^Y<8Lj<}g2^kksSefQTMuTo?tJLCh zC~>CR#a0hADw!_Vg*5fJwV{~S(j8)~sn>Oyt(ud2$1YfGck77}xN@3U_#T`q)f9!2 zf>Ia;Gwp2_C>WokU%(z2ec8z94pZyhaK+e>3a9sj^-&*V494;p9-xk+u1Jn#N_&xs z59OI2w=PuTErv|aNcK*>3l^W*p3}fjXJjJAXtBA#%B(-0--s;1U#f8gFYW!JL+iVG zV0SSx5w8eVgE?3Sg@eQv)=x<+-JgpVixZQNaZr}3b8sVyVs$@ndkF5FYKka@b+YAh z#nq_gzlIDKEs_i}H4f)(VQ!FSB}j>5znkVD&W0bOA{UZ7h!(FXrBbtdGA|PE1db>s z$!X)WY)u#7P8>^7Pjjj-kXNBuJX3(pJVetTZRNOnR5|RT5D>xmwxhAn)9KF3J05J; z-Mfb~dc?LUGqozC2p!1VjRqUwwDBnJhOua3vCCB-%ykW_ohSe?$R#dz%@Gym-8-RA zjMa_SJSzIl8{9dV+&63e9$4;{=1}w2=l+_j_Dtt@<(SYMbV-18&%F@Zl7F_5! z@xwJ0wiDdO%{}j9PW1(t+8P7Ud79yjY>x>aZYWJL_NI?bI6Y02`;@?qPz_PRqz(7v``20`- z033Dy|4;y6di|>cz|P-z|6c&3f&g^OAt8aN0Zd&0yZ>dq2aFCsE<~Ucf$v{sL=*++ zBxFSa2lfA+Y%U@B&3D=&CBO&u`#*nNc|PCY7XO<}MnG0VR764XrHtrb5zwC*2F!Lp zE<~Vj0;z!S-|3M4DFxuQ=`ShTf28<9p!81(0hFbGNqF%0gg*orez9!qt8e%o@Yfl@ zhvY}{@3&f??}7<`p>FyU;7?VkKbh8_=csozU=|fH&szgZ{=NDCylQ>EH^x5!K3~-V z)_2Y>0uJ`Z0Pb58y`RL+&n@m9tJ)O<%q#&u#DAIt+-rRt0eSe1MTtMl@W)H$b3D)@ z*A-1bUgZI)>HdcI4&W>P4W5{-j=s5p5`cbQ+{(g0+RDnz!TR^mxSLu_y#SDVKrj8i zA^hi6>jMGM;`$9Vfb-Yf!47b)Ow`2OKtNB=z|Kxa$5O}WPo;(Dc^`q(7X8kkeFyO8 z{XOq^07=u|7*P2`m;>PIFf=i80MKUxsN{d2cX0M+REsE*20+WQ79T9&cqT>=I_U% z{=8~^Isg(Nzo~`4iQfIb_#CVCD>#5h>=-Z#5dH}WxYzn%0)GAm6L2WdUdP=0_h>7f z(jh&7%1i(ZOn+}D8$iGK4Vs{pmHl_w4Qm-46H9>4^{3dz^DZDh+dw)6Xd@CpQNK$j z{CU;-cmpK=egplZ3y3%y=sEnCJ^eYVKXzV8H2_r*fJ*%*B;a1_lOpt6)IT1IAK2eB z{rie|uDJUrbgfUE>~C>@RO|m5ex55F{=~Bb4Cucp{ok7Yf9V}QuZ`#Gc|WaqsQlK- zKaV)iMRR__&Ak2Z=IM9R9g5$WM4u{a^C-7uX*!myEym z#_#p^T!P~#Dx$%^K>Y_nj_3J*E_LwJ60-5Xu=LkJAwcP@|0;a&+|+ZX`Jbj9P5;T% z|KOc}4*#4o{U?09`9Hz`Xo-I!P=9XfIrr*MQ}y=$!qgv?_J38^bNb4kM&_OVg^_=Eu-qG5U(fw0KMgH){C8pazq~51rN97hf#20-7=aK0)N|UM H-+%o-(+5aQ diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties deleted file mode 100644 index 24eb41f2..00000000 --- a/gradle/wrapper/gradle-wrapper.properties +++ /dev/null @@ -1,6 +0,0 @@ -#Wed Mar 29 15:27:07 PDT 2017 -distributionBase=GRADLE_USER_HOME -distributionPath=wrapper/dists -zipStoreBase=GRADLE_USER_HOME -zipStorePath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-4.4-all.zip diff --git a/gradlew b/gradlew deleted file mode 100755 index 9d82f789..00000000 --- a/gradlew +++ /dev/null @@ -1,160 +0,0 @@ -#!/usr/bin/env bash - -############################################################################## -## -## Gradle start up script for UN*X -## -############################################################################## - -# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. -DEFAULT_JVM_OPTS="" - -APP_NAME="Gradle" -APP_BASE_NAME=`basename "$0"` - -# Use the maximum available, or set MAX_FD != -1 to use that value. -MAX_FD="maximum" - -warn ( ) { - echo "$*" -} - -die ( ) { - echo - echo "$*" - echo - exit 1 -} - -# OS specific support (must be 'true' or 'false'). -cygwin=false -msys=false -darwin=false -case "`uname`" in - CYGWIN* ) - cygwin=true - ;; - Darwin* ) - darwin=true - ;; - MINGW* ) - msys=true - ;; -esac - -# Attempt to set APP_HOME -# Resolve links: $0 may be a link -PRG="$0" -# Need this for relative symlinks. -while [ -h "$PRG" ] ; do - ls=`ls -ld "$PRG"` - link=`expr "$ls" : '.*-> \(.*\)$'` - if expr "$link" : '/.*' > /dev/null; then - PRG="$link" - else - PRG=`dirname "$PRG"`"/$link" - fi -done -SAVED="`pwd`" -cd "`dirname \"$PRG\"`/" >/dev/null -APP_HOME="`pwd -P`" -cd "$SAVED" >/dev/null - -CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar - -# Determine the Java command to use to start the JVM. -if [ -n "$JAVA_HOME" ] ; then - if [ -x "$JAVA_HOME/jre/sh/java" ] ; then - # IBM's JDK on AIX uses strange locations for the executables - JAVACMD="$JAVA_HOME/jre/sh/java" - else - JAVACMD="$JAVA_HOME/bin/java" - fi - if [ ! -x "$JAVACMD" ] ; then - die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME - -Please set the JAVA_HOME variable in your environment to match the -location of your Java installation." - fi -else - JAVACMD="java" - which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. - -Please set the JAVA_HOME variable in your environment to match the -location of your Java installation." -fi - -# Increase the maximum file descriptors if we can. -if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then - MAX_FD_LIMIT=`ulimit -H -n` - if [ $? -eq 0 ] ; then - if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then - MAX_FD="$MAX_FD_LIMIT" - fi - ulimit -n $MAX_FD - if [ $? -ne 0 ] ; then - warn "Could not set maximum file descriptor limit: $MAX_FD" - fi - else - warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" - fi -fi - -# For Darwin, add options to specify how the application appears in the dock -if $darwin; then - GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" -fi - -# For Cygwin, switch paths to Windows format before running java -if $cygwin ; then - APP_HOME=`cygpath --path --mixed "$APP_HOME"` - CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` - JAVACMD=`cygpath --unix "$JAVACMD"` - - # We build the pattern for arguments to be converted via cygpath - ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` - SEP="" - for dir in $ROOTDIRSRAW ; do - ROOTDIRS="$ROOTDIRS$SEP$dir" - SEP="|" - done - OURCYGPATTERN="(^($ROOTDIRS))" - # Add a user-defined pattern to the cygpath arguments - if [ "$GRADLE_CYGPATTERN" != "" ] ; then - OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" - fi - # Now convert the arguments - kludge to limit ourselves to /bin/sh - i=0 - for arg in "$@" ; do - CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` - CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option - - if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition - eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` - else - eval `echo args$i`="\"$arg\"" - fi - i=$((i+1)) - done - case $i in - (0) set -- ;; - (1) set -- "$args0" ;; - (2) set -- "$args0" "$args1" ;; - (3) set -- "$args0" "$args1" "$args2" ;; - (4) set -- "$args0" "$args1" "$args2" "$args3" ;; - (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; - (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; - (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; - (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; - (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; - esac -fi - -# Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules -function splitJvmOpts() { - JVM_OPTS=("$@") -} -eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS -JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME" - -exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@" diff --git a/gradlew.bat b/gradlew.bat deleted file mode 100644 index aec99730..00000000 --- a/gradlew.bat +++ /dev/null @@ -1,90 +0,0 @@ -@if "%DEBUG%" == "" @echo off -@rem ########################################################################## -@rem -@rem Gradle startup script for Windows -@rem -@rem ########################################################################## - -@rem Set local scope for the variables with windows NT shell -if "%OS%"=="Windows_NT" setlocal - -@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. -set DEFAULT_JVM_OPTS= - -set DIRNAME=%~dp0 -if "%DIRNAME%" == "" set DIRNAME=. -set APP_BASE_NAME=%~n0 -set APP_HOME=%DIRNAME% - -@rem Find java.exe -if defined JAVA_HOME goto findJavaFromJavaHome - -set JAVA_EXE=java.exe -%JAVA_EXE% -version >NUL 2>&1 -if "%ERRORLEVEL%" == "0" goto init - -echo. -echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. -echo. -echo Please set the JAVA_HOME variable in your environment to match the -echo location of your Java installation. - -goto fail - -:findJavaFromJavaHome -set JAVA_HOME=%JAVA_HOME:"=% -set JAVA_EXE=%JAVA_HOME%/bin/java.exe - -if exist "%JAVA_EXE%" goto init - -echo. -echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% -echo. -echo Please set the JAVA_HOME variable in your environment to match the -echo location of your Java installation. - -goto fail - -:init -@rem Get command-line arguments, handling Windowz variants - -if not "%OS%" == "Windows_NT" goto win9xME_args -if "%@eval[2+2]" == "4" goto 4NT_args - -:win9xME_args -@rem Slurp the command line arguments. -set CMD_LINE_ARGS= -set _SKIP=2 - -:win9xME_args_slurp -if "x%~1" == "x" goto execute - -set CMD_LINE_ARGS=%* -goto execute - -:4NT_args -@rem Get arguments from the 4NT Shell from JP Software -set CMD_LINE_ARGS=%$ - -:execute -@rem Setup the command line - -set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar - -@rem Execute Gradle -"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% - -:end -@rem End local scope for the variables with windows NT shell -if "%ERRORLEVEL%"=="0" goto mainEnd - -:fail -rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of -rem the _cmd.exe /c_ return code! -if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 -exit /b 1 - -:mainEnd -if "%OS%"=="Windows_NT" endlocal - -:omega diff --git a/native-googlesignin/CMakeLists.txt b/native-googlesignin/CMakeLists.txt deleted file mode 100644 index 5d865f88..00000000 --- a/native-googlesignin/CMakeLists.txt +++ /dev/null @@ -1,62 +0,0 @@ -# Copyright (C) 2017 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. -## - -# For more information about using CMake with Android Studio, read the -# documentation: https://d.android.com/studio/projects/add-native-code.html - -# Sets the minimum version of CMake required to build the native library. - -cmake_minimum_required(VERSION 3.4.1) - -# Creates and names a library, sets it as either STATIC -# or SHARED, and provides the relative paths to its source code. -# You can define multiple libraries, and CMake builds them for you. -# Gradle automatically packages shared libraries with your APK. - -add_library( # Sets the name of the library. - native-googlesignin - - # Sets the library as a shared library. - SHARED - - # Provides a relative path to your source file(s). - src/main/cpp/google_signin_bridge.cc - src/main/cpp/google_signin.cc - src/main/cpp/google_signin_user.cc - src/main/cpp/jni.cc) - -# Searches for a specified prebuilt library and stores the path as a -# variable. Because CMake includes system libraries in the search path by -# default, you only need to specify the name of the public NDK library -# you want to add. CMake verifies that the library exists before -# completing its build. - -find_library( # Sets the name of the path variable. - log-lib - - # Specifies the name of the NDK library that - # you want CMake to locate. - log ) - -# Specifies libraries CMake should link to your target library. You -# can link multiple libraries, such as libraries you define in this -# build script, prebuilt third-party libraries, or system libraries. - -target_link_libraries( # Specifies the target library. - native-googlesignin - - # Links the target library to the log library - # included in the NDK. - ${log-lib} ) diff --git a/native-googlesignin/build.gradle b/native-googlesignin/build.gradle deleted file mode 100644 index ba2f0d9b..00000000 --- a/native-googlesignin/build.gradle +++ /dev/null @@ -1,116 +0,0 @@ -/* Copyright (C) 2017 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. - */ -apply plugin: 'com.android.library' -apply plugin: 'maven' - -group "com.google.signin" - -if (project.hasProperty("pluginVersion")) { - project.version = project.pluginVersion -} else { - project.version '0-SNAPSHOT' -} - -if (project.hasProperty("uploadDir")) { - project.ext.uploadDir = project.uploadDir -} else { - project.ext.uploadDir = "${buildDir}/m2repository" -} - -project.ext.baseName = "google-signin-support" - -android { - compileSdkVersion 26 - defaultConfig { - minSdkVersion 14 - targetSdkVersion 26 - versionName project.version - archivesBaseName = project.ext.baseName - externalNativeBuild { - cmake { - cppFlags "-std=c++11", "-Wall" - } - } - ndk { - abiFilters 'x86', 'armeabi-v7a', 'arm64-v8a' - } - } - lintOptions { - abortOnError (project.hasProperty("lintAbortOnError") && - (project.lintAbortOnError == "" || - project.lintAbortOnError.toBoolean())) - } - buildTypes { - release { - minifyEnabled false - proguardFiles getDefaultProguardFile('proguard-android.txt') - } - } - externalNativeBuild { - cmake { - path "CMakeLists.txt" - } - } -} - -// Rename the .aar file to be .srcaar to work around -// having the local repo in a subdirectory in a Unity project. -// The jar resolver plugin handles the changing back from .srcaar -// to .aar -// -// This is done in 2 parts, first declare the .srcaar as an -// artifact, the second is a task to rename the aar -> srcaar. - -artifacts { - archives file("build/${baseName}-${version}.srcaar") -} - -task renameLibrary() { - doFirst { - copy { - from "${buildDir}/outputs/aar/${baseName}-release.aar" - into "${buildDir}" - rename { - String fn -> - return fn.replace("release.aar", "${version}.srcaar") - } - } - } - - doLast { - configurations.archives.with { - artifacts.remove artifacts.find { it.extension == "aar"} - } - } -} - -uploadArchives { - dependsOn renameLibrary - repositories { - mavenDeployer { - repository(url: uri(project.ext.uploadDir)) - - // Remove the dependencies from the pom file to simplify the - // the resolution process. - pom.whenConfigured { - p -> p.dependencies = [] - } - } - } -} - -dependencies { - api "com.google.android.gms:play-services-auth:16.0.0" -} diff --git a/native-googlesignin/src/main/AndroidManifest.xml b/native-googlesignin/src/main/AndroidManifest.xml deleted file mode 100644 index b3147faf..00000000 --- a/native-googlesignin/src/main/AndroidManifest.xml +++ /dev/null @@ -1,22 +0,0 @@ - - - - - - - diff --git a/native-googlesignin/src/main/cpp/future.h b/native-googlesignin/src/main/cpp/future.h deleted file mode 100644 index 59220788..00000000 --- a/native-googlesignin/src/main/cpp/future.h +++ /dev/null @@ -1,40 +0,0 @@ -// Copyright (C) 2017 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. - -#ifndef GOOGLESIGNIN_FUTURE_H // NOLINT -#define GOOGLESIGNIN_FUTURE_H - -namespace googlesignin { - -// Provides a future promise for an asynchronous result of type -template -class Future { - public: - virtual ~Future() {} - // Returns the Status of the operation. This is set once Pending is false. - virtual int Status() const = 0; - - // Returns the Result of the operation if successful. If it is not - // successful, the error code should be retrieved using Status(). The result - // is available once Pending() is false. - virtual T* Result() const = 0; - - // Returns true while the promise has not been fulfilled by the operation. - // Once it is false, the Status and Result fields are populated. - virtual bool Pending() const = 0; -}; - -} // namespace googlesignin - -#endif // GOOGLESIGNIN_FUTURE_H NOLINT diff --git a/native-googlesignin/src/main/cpp/google_signin.cc b/native-googlesignin/src/main/cpp/google_signin.cc deleted file mode 100644 index 59848e4f..00000000 --- a/native-googlesignin/src/main/cpp/google_signin.cc +++ /dev/null @@ -1,392 +0,0 @@ -// Copyright (C) 2017 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. - -#include "google_signin.h" -#include -#include -#include "google_signin_user_impl.h" -#include "jni_init.h" - -#define TAG "native-googlesignin" -#define HELPER_CLASSNAME "com/google/googlesignin/GoogleSignInHelper" - -/* -public static void enableDebugLogging(boolean flag) - */ -#define ENABLE_DEBUG_METHOD_NAME "enableDebugLogging" -#define ENABLE_DEBUG_METHOD_SIG "(Z)V" - -/* -public static void configure(Activity parentActivity, - boolean useGamesConfig, - String webClientId, - boolean requestAuthCode, - boolean forceRefreshToken, - boolean requestEmail, - boolean requestIdToken, - boolean hideUiPopups, - String defaultAccountName, - String[] additionalScopes, - long requestHandle) -*/ -#define CONFIG_METHOD_NAME "configure" -#define CONFIG_METHOD_SIG \ - "(Landroid/app/Activity;" \ - "Z" \ - "Ljava/lang/String;" \ - "ZZZZZ" \ - "Ljava/lang/String;" \ - "[Ljava/lang/String;" \ - "J)V" - -/* -public static void nativeSignIn() - */ -#define DISCONNECT_METHOD_NAME "disconnect" -#define DISCONNECT_METHOD_SIG "(Landroid/app/Activity;)V" - -/* -public static void nativeSignIn() - */ -#define SIGNIN_METHOD_NAME "signIn" -#define SIGNIN_METHOD_SIG "(Landroid/app/Activity;J)V" - -/* -public static void nativeSignIn() - */ -#define SIGNINSILENTLY_METHOD_NAME "signInSilently" -#define SIGNINSILENTLY_METHOD_SIG "(Landroid/app/Activity;J)V" - -/* -public static void nativeSignOut() - */ -#define SIGNOUT_METHOD_NAME "signOut" -#define SIGNOUT_METHOD_SIG "(Landroid/app/Activity;)V" - -/* -public static void nativeOnResult(long requestHandle, int result, - GoogleSignInAccount acct), - */ -#define NATIVEONRESULT_METHOD_NAME "nativeOnResult" -#define NATIVEONRESULT_METHOD_SIG \ - "(J" \ - "I" \ - "Lcom/google/android/gms/auth/api/signin/GoogleSignInAccount;" \ - ")V" - -namespace googlesignin { - -class GoogleSignInFuture; - -// The implementation of GoogleSignIn. This implements the JNI interface to -// call the Java helper class the handles the authentication flow within Java. -// For the public methods see google_signin.h for details. -class GoogleSignIn::GoogleSignInImpl { - public: - jobject activity_; - GoogleSignInFuture *current_result_; - Configuration *current_configuration_; - - // Constructs the implementation providing the Java activity to use when - // making calls. - GoogleSignInImpl(jobject activity); - ~GoogleSignInImpl(); - - void Configure(const Configuration &configuration); - - void EnableDebugLogging(bool flag); - - // Starts the authentication process. - Future &SignIn(); - - Future &SignInSilently(); - - // Get the result of the last sign-in. - const Future *GetLastSignInResult(); - - // Signs out. - void SignOut(); - - void Disconnect(); - - // Native method implementation for the Java class. - static void NativeOnAuthResult(JNIEnv *env, jobject obj, jlong handle, - jint result, jobject user); - - private: - void CallConfigure(); - - static const JNINativeMethod methods[]; - - static jclass helper_clazz_; - static jmethodID enable_debug_method_; - static jmethodID config_method_; - static jmethodID disconnect_method_; - static jmethodID signin_method_; - static jmethodID signinsilently_method_; - static jmethodID signout_method_; -}; - -const JNINativeMethod GoogleSignIn::GoogleSignInImpl::methods[] = { - { - NATIVEONRESULT_METHOD_NAME, - NATIVEONRESULT_METHOD_SIG, - reinterpret_cast( - GoogleSignIn::GoogleSignInImpl::NativeOnAuthResult), - }, -}; - -jclass GoogleSignIn::GoogleSignInImpl::helper_clazz_ = 0; -jmethodID GoogleSignIn::GoogleSignInImpl::enable_debug_method_ = 0; -jmethodID GoogleSignIn::GoogleSignInImpl::config_method_ = 0; -jmethodID GoogleSignIn::GoogleSignInImpl::disconnect_method_ = 0; -jmethodID GoogleSignIn::GoogleSignInImpl::signin_method_ = 0; -jmethodID GoogleSignIn::GoogleSignInImpl::signinsilently_method_ = 0; -jmethodID GoogleSignIn::GoogleSignInImpl::signout_method_ = 0; - -// Implementation of the SignIn future. -class GoogleSignInFuture : public Future { - virtual int Status() const { - return result_ ? result_->StatusCode - : GoogleSignIn::StatusCode::kStatusCodeUninitialized; - } - virtual GoogleSignIn::SignInResult *Result() const { return result_; } - virtual bool Pending() const { - return (!result_) || result_->StatusCode == - GoogleSignIn::StatusCode::kStatusCodeUninitialized; - } - - public: - GoogleSignInFuture() : result_(nullptr) {} - void SetResult(GoogleSignIn::SignInResult *result) { result_ = result; } - - private: - GoogleSignIn::SignInResult *result_; -}; - -// Constructs a new instance. The static members are initialized if need-be. -GoogleSignIn::GoogleSignInImpl::GoogleSignInImpl(jobject activity) - : current_result_(nullptr), current_configuration_(nullptr) { - JNIEnv *env = GetJniEnv(); - - activity_ = env->NewGlobalRef(activity); - - if (!helper_clazz_) { - // Find the java helper class and initialize it. - helper_clazz_ = FindClass(HELPER_CLASSNAME, activity); - - assert(helper_clazz_); - - if (helper_clazz_) { - helper_clazz_ = (jclass)env->NewGlobalRef(helper_clazz_); - env->RegisterNatives(helper_clazz_, methods, - sizeof(methods) / sizeof(methods[0])); - enable_debug_method_ = env->GetStaticMethodID(helper_clazz_, ENABLE_DEBUG_METHOD_NAME, - ENABLE_DEBUG_METHOD_SIG); - config_method_ = env->GetStaticMethodID(helper_clazz_, CONFIG_METHOD_NAME, - CONFIG_METHOD_SIG); - disconnect_method_ = env->GetStaticMethodID( - helper_clazz_, DISCONNECT_METHOD_NAME, DISCONNECT_METHOD_SIG); - signin_method_ = env->GetStaticMethodID(helper_clazz_, SIGNIN_METHOD_NAME, - SIGNIN_METHOD_SIG); - signinsilently_method_ = env->GetStaticMethodID( - helper_clazz_, SIGNINSILENTLY_METHOD_NAME, SIGNINSILENTLY_METHOD_SIG); - signout_method_ = env->GetStaticMethodID( - helper_clazz_, SIGNOUT_METHOD_NAME, SIGNOUT_METHOD_SIG); - } - } -} - -GoogleSignIn::GoogleSignInImpl::~GoogleSignInImpl() { - JNIEnv *env = GetJniEnv(); - - env->DeleteGlobalRef(activity_); - activity_ = nullptr; - delete current_result_; - current_result_ = nullptr; -} - -void GoogleSignIn::GoogleSignInImpl::EnableDebugLogging(bool flag) { - JNIEnv *env = GetJniEnv(); - - env->CallStaticVoidMethod(helper_clazz_, enable_debug_method_, flag); - -} - -void GoogleSignIn::GoogleSignInImpl::Configure( - const Configuration &configuration) { - delete current_configuration_; - current_configuration_ = new Configuration(configuration); - - delete current_result_; - current_result_ = new GoogleSignInFuture(); - - CallConfigure(); -} - -void GoogleSignIn::GoogleSignInImpl::CallConfigure() { - JNIEnv *env = GetJniEnv(); - - if (!current_configuration_) { - __android_log_print(ANDROID_LOG_ERROR, TAG, "configuration is null!?"); - return; - } - jstring j_web_client_id = - current_configuration_->web_client_id.empty() ? nullptr - : env->NewStringUTF(current_configuration_->web_client_id.c_str()); - - jstring j_account_name = - current_configuration_->account_name.empty() ? nullptr - : env->NewStringUTF(current_configuration_->account_name.c_str()); - - jobjectArray j_auth_scopes = nullptr; - - if (current_configuration_->additional_scopes.size() > 0) { - jclass string_clazz = FindClass("java/lang/String", activity_); - j_auth_scopes = env->NewObjectArray( - current_configuration_->additional_scopes.size(), string_clazz, nullptr); - - for (int i = 0; i < current_configuration_->additional_scopes.size(); i++) { - env->SetObjectArrayElement( - j_auth_scopes, i, - env->NewStringUTF(current_configuration_->additional_scopes[i].c_str())); - } - env->DeleteLocalRef(string_clazz); - } - - env->CallStaticVoidMethod( - helper_clazz_, config_method_, activity_, - current_configuration_->use_game_signin, j_web_client_id, - current_configuration_->request_auth_code, - current_configuration_->force_token_refresh, - current_configuration_->request_email, - current_configuration_->request_id_token, - current_configuration_->hide_ui_popups, j_account_name, j_auth_scopes, - reinterpret_cast(current_result_)); - - if (j_web_client_id) { - env->DeleteLocalRef(j_web_client_id); - } - - if (j_account_name) { - env->DeleteLocalRef(j_account_name); - } - - if (j_auth_scopes) { - env->DeleteLocalRef(j_auth_scopes); - } -} - -Future &GoogleSignIn::GoogleSignInImpl::SignIn() { - JNIEnv *env = GetJniEnv(); - - if (current_result_) { - current_result_->SetResult(nullptr); - } - - CallConfigure(); - - env->CallStaticVoidMethod(helper_clazz_, signin_method_, activity_, - (jlong)current_result_); - - return *current_result_; -} - -Future - &GoogleSignIn::GoogleSignInImpl::SignInSilently() { - JNIEnv *env = GetJniEnv(); - - if (current_result_) { - current_result_->SetResult(nullptr); - } - - CallConfigure(); - - env->CallStaticVoidMethod(helper_clazz_, signinsilently_method_, activity_, - (jlong)current_result_); - - return *current_result_; -} - -// Get the result of the last sign-in. -const Future - *GoogleSignIn::GoogleSignInImpl::GetLastSignInResult() { - return current_result_; -} - -// Signs out. -void GoogleSignIn::GoogleSignInImpl::SignOut() { - JNIEnv *env = GetJniEnv(); - - __android_log_print(ANDROID_LOG_INFO, TAG, - "helper: %x method: %x activity: %x", - (uintptr_t)helper_clazz_, (uintptr_t)signin_method_, - (uintptr_t)activity_); - - env->CallStaticVoidMethod(helper_clazz_, signout_method_, activity_); -} - -// Signs out. -void GoogleSignIn::GoogleSignInImpl::Disconnect() { - JNIEnv *env = GetJniEnv(); - - env->CallStaticVoidMethod(helper_clazz_, disconnect_method_, activity_); -} - -void GoogleSignIn::GoogleSignInImpl::NativeOnAuthResult( - JNIEnv *env, jobject obj, jlong handle, jint result, jobject user) { - GoogleSignInFuture *future = reinterpret_cast(handle); - if (future) { - SignInResult *rc = new GoogleSignIn::SignInResult(); - rc->StatusCode = result; - rc->User = GoogleSignInUserImpl::UserFromAccount(user); - - if (rc->User) { - __android_log_print(ANDROID_LOG_INFO, TAG, "User Display Name is %s", - rc->User->GetDisplayName()); - } - future->SetResult(rc); - } -} - -// Public class implementation. These are called by external callers to use the -// Google Sign-in API. -GoogleSignIn::GoogleSignIn(jobject activity) - : impl_(new GoogleSignInImpl(activity)) {} - -void GoogleSignIn::EnableDebugLogging(bool flag) { - impl_->EnableDebugLogging(flag); -} - -void GoogleSignIn::Configure(const Configuration &configuration) { - impl_->Configure(configuration); -} - -Future &GoogleSignIn::SignIn() { - return impl_->SignIn(); -} - -Future &GoogleSignIn::SignInSilently() { - return impl_->SignInSilently(); -} - -const Future *GoogleSignIn::GetLastSignInResult() { - return impl_->GetLastSignInResult(); -} - -void GoogleSignIn::SignOut() { impl_->SignOut(); } - -void GoogleSignIn::Disconnect() { impl_->Disconnect(); } - -} // namespace googlesignin diff --git a/native-googlesignin/src/main/cpp/google_signin.h b/native-googlesignin/src/main/cpp/google_signin.h deleted file mode 100644 index 8086c06b..00000000 --- a/native-googlesignin/src/main/cpp/google_signin.h +++ /dev/null @@ -1,169 +0,0 @@ -// Copyright (C) 2017 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. - -#ifndef GOOGLESIGNIN_GOOGLESIGNIN_H // NOLINT -#define GOOGLESIGNIN_GOOGLESIGNIN_H - -#if !defined(__ANDROID__) -#error "This class is for Android only." -#endif - -#include -#include -#include - -#include "future.h" // NOLINT -#include "google_signin_user.h" // NOLINT - -namespace googlesignin { - -class GoogleSignIn { - public: - /// StatusCode - /// These are based on - /// https://developers.google.com/android/reference/com/google/android/gms/common/api/CommonStatusCodes - /// and consistent with what is returned by the Google Sign-In API on both iOS - /// and Android. - /// - enum StatusCode { - /// The result is uninitialized. - kStatusCodeUninitialized = 100, - - /// The client attempted to call a method from an API that - /// failed to connect. - kStatusCodeApiNotConnected = 17, - - /// The result was canceled either due to client disconnect - /// or cancel(). - kStatusCodeCanceled = 16, - - /// The application is misconfigured. - /// This error is not recoverable. - /// - /// The developer should look at the logs after this to determine - /// more actionable information. - /// - kStatusCodeDeveloperError = 10, - - /// The operation failed with no more detailed - /// information. - kStatusCodeError = 13, - - /// An internal error occurred. Retrying should resolve the - /// problem. - kStatusCodeInternalError = 8, - - /// A blocking call was interrupted while waiting and did not - /// run to completion. - kStatusCodeInterrupted = 14, - - /// The client attempted to connect to the service with an - /// invalid account name specified. - kStatusCodeInvalidAccount = 5, - - /// A network error occurred. Retrying should resolve the problem. - /// - kStatusCodeNetworkError = 7, - - /// The operation was successful. - kStatusCodeSuccess = 0, - - /// The operation was successful, but was used the device's cache. - /// - kStatusCodeSuccessCached = -1, - - /// Timed out while awaiting the result. - kStatusCodeTimeout = 15, - }; - - // Defines the configuration for the sign-in process. - struct Configuration { - /// true to use games signin, false for default signin. - bool use_game_signin; - /// web client id associated with this app. - std::string web_client_id; - /// true for getting an auth code when authenticating. - /// Note: This may trigger re-consent on iOS. Ideally, this - /// is set to true once, and the result sent to the server where the - /// token is managed forever. - bool request_auth_code; - /// true to request to reset the refresh token. Causes re-consent. - bool force_token_refresh; - /// request email address, requires consent. - bool request_email; - /// request id token, requires consent. - bool request_id_token; - /// used with games signin to show or hide the connecting popup UI. - /// and to associate an invisible view for other popups. This is - /// recommended for VR applications. - bool hide_ui_popups; - /// account name to use when authenticating, null indicates use default. - std::string account_name; - /// additional scopes to request, requires consent. - std::vector additional_scopes; - - Configuration() = default; - ~Configuration() = default; - Configuration(Configuration const ©) = default; - Configuration(Configuration &&move) = delete; - Configuration &operator=(Configuration const ©) = delete; - Configuration &operator=(Configuration &&move) = delete; - }; - - // Holds the result of the sign-in process. - struct SignInResult { - GoogleSignInUser *User; - int StatusCode; - SignInResult() = default; - ~SignInResult() = default; - SignInResult(SignInResult const ©) = default; - SignInResult(SignInResult &&move) = delete; - SignInResult &operator=(SignInResult const ©) = delete; - SignInResult &operator=(SignInResult &&move) = delete; - }; - - // Constructs a new instance. The activity parameter is needed to - // add a fragment to the activity which performs the sign-in operation. - GoogleSignIn(jobject activity); - - // Enables verbose logging. - void EnableDebugLogging(bool flag); - - // Sets the configuration for the sign-in. This must be called before - // calling SignIn(). Calling this invalidates the current sign-in result. - void Configure(const Configuration &configuration); - - // Starts the authentication process. - Future &SignIn(); - - // Attempts to sign in silently. - Future &SignInSilently(); - - // Get the result of the last sign-in. - const Future *GetLastSignInResult(); - - // Signs out the local user. Any server side tokens are still valid. - void SignOut(); - - // Disconnects this user from the application. Invalidates all tokens and - // consent. - void Disconnect(); - - private: - class GoogleSignInImpl; - GoogleSignInImpl *impl_; -}; -} // namespace googlesignin - -#endif // GOOGLESIGNIN_GOOGLESIGNIN_H NOLINT diff --git a/native-googlesignin/src/main/cpp/google_signin_bridge.cc b/native-googlesignin/src/main/cpp/google_signin_bridge.cc deleted file mode 100644 index e8a287ef..00000000 --- a/native-googlesignin/src/main/cpp/google_signin_bridge.cc +++ /dev/null @@ -1,227 +0,0 @@ -// -// Copyright 2017 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. -// - -#include "google_signin_bridge.h" - -#include -#include - -#include "google_signin.h" - -// Wrapper for the GoogleSignIn object when returning it via the extern -// "C" interface. -struct GoogleSignInHolder { - std::unique_ptr wrapped_; - - GoogleSignInHolder() : wrapped_(nullptr) {} - - GoogleSignInHolder(googlesignin::GoogleSignIn *ptr) : wrapped_(ptr) {} - - ~GoogleSignInHolder() = default; - - GoogleSignInHolder(GoogleSignInHolder const ©) = default; - - GoogleSignInHolder(GoogleSignInHolder &&move) = delete; - - GoogleSignInHolder &operator=(GoogleSignInHolder const ©) = delete; - - GoogleSignInHolder &operator=(GoogleSignInHolder &&move) = delete; -}; - -// Wrapper for the Future result from calling SignIn(). -struct GoogleSignInFuture { - std::unique_ptr< - googlesignin::Future> - wrapped_; - - GoogleSignInFuture() : wrapped_(nullptr) {} - - GoogleSignInFuture( - googlesignin::Future *ptr) - : wrapped_(ptr) {} - - ~GoogleSignInFuture() = default; - - GoogleSignInFuture(GoogleSignInFuture const ©) = default; - - GoogleSignInFuture(GoogleSignInFuture &&move) = delete; - - GoogleSignInFuture &operator=(GoogleSignInFuture const ©) = delete; - - GoogleSignInFuture &operator=(GoogleSignInFuture &&move) = delete; -}; - -// Wrapper for the signed in user object. -struct GoogleSignInUser { - googlesignin::GoogleSignInUser *wrapped_; - - GoogleSignInUser() : wrapped_() {} - - GoogleSignInUser(googlesignin::GoogleSignInUser *ref) : wrapped_(ref) { - __android_log_print(ANDROID_LOG_INFO, "native-googlesignin", - "In Wrapper display name is %s", - ref->GetDisplayName()); - } - - ~GoogleSignInUser() = default; - - GoogleSignInUser(GoogleSignInUser const ©) = delete; - - GoogleSignInUser(GoogleSignInUser &&move) = delete; - - GoogleSignInUser &operator=(GoogleSignInUser const ©) = delete; - - GoogleSignInUser &operator=(GoogleSignInUser &&move) = delete; -}; - -GoogleSignIn_t GoogleSignIn_Create(jobject activity) { - return new GoogleSignInHolder(new googlesignin::GoogleSignIn(activity)); -} - -void GoogleSignIn_Dispose(GoogleSignIn_t self) { delete self; } - -void GoogleSignIn_EnableDebugLogging(GoogleSignIn_t self, bool flag) { - self->wrapped_->EnableDebugLogging(flag); -} - -void GoogleSignIn_Configure(GoogleSignIn_t self, bool useGameSignIn, - const char *webClientId, bool requestAuthCode, - bool forceTokenRefresh, bool requestEmail, - bool requestIdToken, bool hidePopups, - const char **additional_scopes, int scopes_count, - const char *accountName) { - googlesignin::GoogleSignIn::Configuration configuration; - - configuration.use_game_signin = useGameSignIn; - if (webClientId) { - configuration.web_client_id = webClientId; - } - configuration.request_auth_code = requestAuthCode; - configuration.force_token_refresh = forceTokenRefresh; - configuration.request_email = requestEmail; - configuration.request_id_token = requestIdToken; - configuration.hide_ui_popups = hidePopups; - if (accountName) { - configuration.account_name = accountName; - } - if (scopes_count) { - for(int i=0;iwrapped_->Configure(configuration); -} - -GoogleSignInFuture_t GoogleSignIn_SignIn(GoogleSignIn_t self) { - return new GoogleSignInFuture(&self->wrapped_->SignIn()); -} - -GoogleSignInFuture_t GoogleSignIn_SignInSilently(GoogleSignIn_t self) { - return new GoogleSignInFuture(&self->wrapped_->SignInSilently()); -} - -void GoogleSignIn_Signout(GoogleSignIn_t self) { self->wrapped_->SignOut(); } - -void GoogleSignIn_Disconnect(GoogleSignIn_t self) { - self->wrapped_->Disconnect(); -} - -bool GoogleSignIn_Pending(GoogleSignInFuture_t self) { - return self->wrapped_->Pending(); -} - -int GoogleSignIn_Status(GoogleSignInFuture_t self) { - // Map the Android status code onto the Unity plugin enum. - switch (self->wrapped_->Status()) { - case googlesignin::GoogleSignIn::kStatusCodeApiNotConnected: - return googlesignin::GoogleSignUnityStatusCode::kUnityStatusCodeApiNotConnected; - case googlesignin::GoogleSignIn::kStatusCodeCanceled: - return googlesignin::GoogleSignUnityStatusCode::kUnityStatusCodeCanceled; - case googlesignin::GoogleSignIn::kStatusCodeDeveloperError: - return googlesignin::GoogleSignUnityStatusCode::kUnityStatusCodeDeveloperError; - case googlesignin::GoogleSignIn::kStatusCodeInternalError: - return googlesignin::GoogleSignUnityStatusCode::kUnityStatusCodeInternalError; - case googlesignin::GoogleSignIn::kStatusCodeInterrupted: - return googlesignin::GoogleSignUnityStatusCode::kUnityStatusCodeInterrupted; - case googlesignin::GoogleSignIn::kStatusCodeInvalidAccount: - return googlesignin::GoogleSignUnityStatusCode::kUnityStatusCodeInvalidAccount; - case googlesignin::GoogleSignIn::kStatusCodeNetworkError: - return googlesignin::GoogleSignUnityStatusCode::kUnityStatusCodeNetworkError; - case googlesignin::GoogleSignIn::kStatusCodeTimeout: - return googlesignin::GoogleSignUnityStatusCode::kUnityStatusCodeInternalError; - case googlesignin::GoogleSignIn::kStatusCodeSuccessCached: - return googlesignin::GoogleSignUnityStatusCode::kUnityStatusCodeSuccessCached; - case googlesignin::GoogleSignIn::kStatusCodeSuccess: - return googlesignin::GoogleSignUnityStatusCode::kUnityStatusCodeSuccess; - case googlesignin::GoogleSignIn::kStatusCodeError: - // fall through to default case - default: - return googlesignin::GoogleSignUnityStatusCode ::kUnityStatusCodeError; - } -} - -GoogleSignInUser_t GoogleSignIn_Result(GoogleSignInFuture_t self) { - return (self->wrapped_->Result() && self->wrapped_->Result()->User) - ? new GoogleSignInUser(self->wrapped_->Result()->User) - : nullptr; -} - -static size_t ReturnCopiedString(const char *src, char *dest, size_t len) { - if (dest && src && len) { - strncpy(dest, src, len); - return len; - } - return src ? strlen(src) + 1 : 0; -} - -size_t GoogleSignIn_GetServerAuthCode(GoogleSignInUser_t self, char *buf, - size_t len) { - return ReturnCopiedString(self->wrapped_->GetServerAuthCode(), buf, len); -} - -size_t GoogleSignIn_GetDisplayName(GoogleSignInUser_t self, char *buf, - size_t len) { - return ReturnCopiedString(self->wrapped_->GetDisplayName(), buf, len); -} - -size_t GoogleSignIn_GetEmail(const GoogleSignInUser_t self, char *buf, - size_t len) { - return ReturnCopiedString(self->wrapped_->GetEmail(), buf, len); -} - -size_t GoogleSignIn_GetFamilyName(GoogleSignInUser_t self, char *buf, - size_t len) { - return ReturnCopiedString(self->wrapped_->GetFamilyName(), buf, len); -} - -size_t GoogleSignIn_GetGivenName(GoogleSignInUser_t self, char *buf, - size_t len) { - return ReturnCopiedString(self->wrapped_->GetGivenName(), buf, len); -} - -size_t GoogleSignIn_GetIdToken(GoogleSignInUser_t self, char *buf, size_t len) { - return ReturnCopiedString(self->wrapped_->GetIdToken(), buf, len); -} - -size_t GoogleSignIn_GetImageUrl(GoogleSignInUser_t self, char *buf, - size_t len) { - return ReturnCopiedString(self->wrapped_->GetImageUrl(), buf, len); -} - -size_t GoogleSignIn_GetUserId(GoogleSignInUser_t self, char *buf, size_t len) { - return ReturnCopiedString(self->wrapped_->GetUserId(), buf, len); -} diff --git a/native-googlesignin/src/main/cpp/google_signin_bridge.h b/native-googlesignin/src/main/cpp/google_signin_bridge.h deleted file mode 100644 index 6095ade2..00000000 --- a/native-googlesignin/src/main/cpp/google_signin_bridge.h +++ /dev/null @@ -1,172 +0,0 @@ -// -// Copyright 2017 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. -// -#ifndef GOOGLESIGNIN_GOOGLESIGNINBRIDGE_H -#define GOOGLESIGNIN_GOOGLESIGNINBRIDGE_H - -// Definition of the extern "C" interface. This is used -// primarily by the Unity plugin. - -#include -#include - -struct GoogleSignInHolder; -typedef GoogleSignInHolder* GoogleSignIn_t; - -struct GoogleSignInFuture; -typedef GoogleSignInFuture* GoogleSignInFuture_t; - -struct GoogleSignInUser; -typedef GoogleSignInUser* GoogleSignInUser_t; - -namespace googlesignin { -//Enum of the status codes used in the Unity plugin. The -// Android specific codes are mapped onto this when returning status via -// GoogleSignIn_Status(). -enum GoogleSignUnityStatusCode { - kUnityStatusCodeSuccessCached = -1, - kUnityStatusCodeSuccess = 0, - kUnityStatusCodeApiNotConnected = 1, - kUnityStatusCodeCanceled = 2, - kUnityStatusCodeInterrupted = 3, - kUnityStatusCodeInvalidAccount = 4, - kUnityStatusCodeTimeout = 5, - kUnityStatusCodeDeveloperError = 6, - kUnityStatusCodeInternalError = 7, - kUnityStatusCodeNetworkError = 8, - kUnityStatusCodeError = 9 -}; -} - -extern "C" { - -// Create a new instance of the GoogleSignIn class. -GoogleSignIn_t GoogleSignIn_Create(jobject activity); - -// Dispose the instance created by GoogleSignIn_Create(). -void GoogleSignIn_Dispose(GoogleSignIn_t self); - -// Enable verbose debugging -void GoogleSignIn_EnableDebugLogging(GoogleSignIn_t self, bool flag); - -// Configure the sign-in process. See GoogleSignIn::Configuration for details. -void GoogleSignIn_Configure(GoogleSignIn_t self, bool useGameSignIn, - const char* webClientId, bool requestAuthCode, - bool forceTokenRefresh, bool requestEmail, - bool requestIdToken, bool hidePopups, - const char** additional_scopes, int scopes_count, - const char* accountName); - -// Start the sign-in process. Returns a Future to use to get the result. -GoogleSignInFuture_t GoogleSignIn_SignIn(GoogleSignIn_t self); - -// Attempts to sign in silently. This method should be attempted first when -// when signing in "automatically". -GoogleSignInFuture_t GoogleSignIn_SignInSilently(GoogleSignIn_t self); - -// Signs out. This affects the local state. -void GoogleSignIn_Signout(GoogleSignIn_t self); - -// Disconnect from the app. This revokes all tokens for the user both locally -// and on the server. -void GoogleSignIn_Disconnect(GoogleSignIn_t self); - -// Accesses the Pending() method of the Future. This avoids -// having to marshal classes and structures between C and other languages -// (i.e. C#). -bool GoogleSignIn_Pending(GoogleSignInFuture_t self); - -// Accesses the Status() method of the Future. This avoids -// having to marshal classes and structures between C and other languages -// (i.e. C#). -int GoogleSignIn_Status(GoogleSignInFuture_t self); - -// Accesses the Result() method of the Future. This avoids -// having to marshal classes and structures between C and other languages -// (i.e. C#). -GoogleSignInUser_t GoogleSignIn_Result(GoogleSignInFuture_t self); - -// Accesses the AuthCode() method of the GoogleSignInUser. -// This avoids having to marshal classes and structures between C and other -// languages (i.e. C#). -// -// The value is copied into buf up to len-1 characters. If buf is null, then -// nothing is copied. The return value is the length needed to copy the -// complete value. -size_t GoogleSignIn_GetServerAuthCode(GoogleSignInUser_t self, char* buf, - size_t len); - -// Accesses the DisplayName() method of the GoogleSignInUser. -// This avoids having to marshal classes and structures between C and other -// languages (i.e. C#). -// -// The value is copied into buf up to len-1 characters. If buf is null, then -// nothing is copied. The return value is the length needed to copy the -// complete value. -size_t GoogleSignIn_GetDisplayName(GoogleSignInUser_t self, char* buf, - size_t len); - -// Accesses the Email() method of the GoogleSignInUser. -// This avoids having to marshal classes and structures between C and other -// languages (i.e. C#). -// -// The value is copied into buf up to len-1 characters. If buf is null, then -// nothing is copied. The return value is the length needed to copy the -// complete value. -// -// Depending on the requested scopes and fields, this may return null. -size_t GoogleSignIn_GetEmail(GoogleSignInUser_t self, char* buf, size_t len); - -// Accesses the FamilyName() method of the GoogleSignInUser. -// This avoids having to marshal classes and structures between C and other -// languages (i.e. C#). -// -// The value is copied into buf up to len-1 characters. If buf is null, then -// nothing is copied. The return value is the length needed to copy the -// complete value. -size_t GoogleSignIn_GetFamilyName(GoogleSignInUser_t self, char* buf, - size_t len); - -// Accesses the GiveName() method of the GoogleSignInUser. -// This avoids having to marshal classes and structures between C and other -// languages (i.e. C#). -// -// The value is copied into buf up to len-1 characters. If buf is null, then -// nothing is copied. The return value is the length needed to copy the -// complete value. -size_t GoogleSignIn_GetGivenName(GoogleSignInUser_t self, char* buf, - size_t len); - -// Accesses the IdToken() method of the GoogleSignInUser. -// This avoids having to marshal classes and structures between C and other -// languages (i.e. C#). -// -// The value is copied into buf up to len-1 characters. If buf is null, then -// nothing is copied. The return value is the length needed to copy the -// complete value. -size_t GoogleSignIn_GetIdToken(GoogleSignInUser_t self, char* buf, size_t len); - -// Accesses the ImageUrl() method of the GoogleSignInUser. -// This avoids having to marshal classes and structures between C and other -// languages (i.e. C#). -// -// The value is copied into buf up to len-1 characters. If buf is null, then -// nothing is copied. The return value is the length needed to copy the -// complete value. -size_t GoogleSignIn_GetImageUrl(GoogleSignInUser_t self, char* buf, size_t len); - -size_t GoogleSignIn_GetUserId(GoogleSignInUser_t self, char* buf, size_t len); -} // extern "C" -#endif // GOOGLESIGNIN_GOOGLESIGNINBRIDGE_H diff --git a/native-googlesignin/src/main/cpp/google_signin_user.cc b/native-googlesignin/src/main/cpp/google_signin_user.cc deleted file mode 100644 index 715a2da4..00000000 --- a/native-googlesignin/src/main/cpp/google_signin_user.cc +++ /dev/null @@ -1,206 +0,0 @@ -// -// Copyright 2017 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. -// - -#include "google_signin_user.h" // NOLINT -#include - -#include "google_signin_user_impl.h" // NOLINT -#include "jni_init.h" // NOLINT - -#define GOOGLESIGNINACCOUNT_NAME \ - "com/google/android/gms/auth/api/signin/GoogleSignInAccount" - -// String getDisplayName() -#define GETDISPLAYNAME_METHOD_NAME "getDisplayName" -#define GETDISPLAYNAME_METHOD_SIG "()Ljava/lang/String;" - -// String getEmail() -#define GETEMAIL_METHOD_NAME "getEmail" -#define GETEMAIL_METHOD_SIG "()Ljava/lang/String;" - -// String getFamilyName() -#define GETFAMILYNAME_METHOD_NAME "getFamilyName" -#define GETFAMILYNAME_METHOD_SIG "()Ljava/lang/String;" - -// String getGivenName() -#define GETGIVENNAME_METHOD_NAME "getGivenName" -#define GETGIVENNAME_METHOD_SIG "()Ljava/lang/String;" - -// String getId() -#define GETID_METHOD_NAME "getId" -#define GETID_METHOD_SIG "()Ljava/lang/String;" - -// String getIdToken() -#define GETIDTOKEN_METHOD_NAME "getIdToken" -#define GETIDTOKEN_METHOD_SIG "()Ljava/lang/String;" - -// String getServerAuthCode() -#define GETSERVERAUTHCODE_METHOD_NAME "getServerAuthCode" -#define GETSERVERAUTHCODE_METHOD_SIG "()Ljava/lang/String;" - -// Uri getPhotoUrl() -#define GETPHOTOURL_METHOD_NAME "getPhotoUrl" -#define GETPHOTOURL_METHOD_SIG "()Landroid/net/Uri;" - -#define URI_NAME "android/net/Uri" -#define TOSTRING_METHOD_NAME "toString" -#define TOSTRING_METHOD_SIG "()Ljava/lang/String;" - -namespace googlesignin { - -jmethodID GoogleSignInUserImpl::method_getDisplayName = 0; -jmethodID GoogleSignInUserImpl::method_getEmail = 0; -jmethodID GoogleSignInUserImpl::method_getFamilyName = 0; -jmethodID GoogleSignInUserImpl::method_getGivenName = 0; -jmethodID GoogleSignInUserImpl::method_getId = 0; -jmethodID GoogleSignInUserImpl::method_getIdToken = 0; -jmethodID GoogleSignInUserImpl::method_getPhotoUrl = 0; -jmethodID GoogleSignInUserImpl::method_getServerAuthCode = 0; -jmethodID GoogleSignInUserImpl::method_uri_toString = 0; - -void GoogleSignInUserImpl::Initialize(jobject obj) { - JNIEnv* env = GetJniEnv(); - - if (!method_getDisplayName) { - jclass google_acct_class = FindClass(GOOGLESIGNINACCOUNT_NAME, obj); - - method_getDisplayName = - env->GetMethodID(google_acct_class, GETDISPLAYNAME_METHOD_NAME, - GETDISPLAYNAME_METHOD_SIG); - - method_getEmail = env->GetMethodID(google_acct_class, GETEMAIL_METHOD_NAME, - GETEMAIL_METHOD_SIG); - - method_getFamilyName = env->GetMethodID( - google_acct_class, GETFAMILYNAME_METHOD_NAME, GETFAMILYNAME_METHOD_SIG); - - method_getGivenName = env->GetMethodID( - google_acct_class, GETGIVENNAME_METHOD_NAME, GETGIVENNAME_METHOD_SIG); - - method_getId = env->GetMethodID(google_acct_class, GETID_METHOD_NAME, - GETID_METHOD_SIG); - - method_getIdToken = env->GetMethodID( - google_acct_class, GETIDTOKEN_METHOD_NAME, GETIDTOKEN_METHOD_SIG); - - method_getPhotoUrl = env->GetMethodID( - google_acct_class, GETPHOTOURL_METHOD_NAME, GETPHOTOURL_METHOD_SIG); - - jclass uri_class = FindClass(URI_NAME, obj); - method_uri_toString = env->GetMethodID( - uri_class, TOSTRING_METHOD_NAME, TOSTRING_METHOD_SIG); - - method_getServerAuthCode = - env->GetMethodID(google_acct_class, GETSERVERAUTHCODE_METHOD_NAME, - GETSERVERAUTHCODE_METHOD_SIG); - } -} - -GoogleSignInUser::GoogleSignInUser() : impl_(new GoogleSignInUserImpl()) {} -GoogleSignInUser::~GoogleSignInUser() { delete impl_; } - -const char* GoogleSignInUser::GetDisplayName() const { - return impl_->display_name.c_str(); -} -const char* GoogleSignInUser::GetEmail() const { return impl_->email.c_str(); } -const char* GoogleSignInUser::GetFamilyName() const { - return impl_->family_name.c_str(); -} -const char* GoogleSignInUser::GetGivenName() const { - return impl_->given_name.c_str(); -} -const char* GoogleSignInUser::GetIdToken() const { - return impl_->id_token.c_str(); -} -const char* GoogleSignInUser::GetImageUrl() const { - return impl_->image_url.c_str(); -} -const char* GoogleSignInUser::GetServerAuthCode() const { - return impl_->server_auth_code.c_str(); -} -const char* GoogleSignInUser::GetUserId() const { - return impl_->user_id.c_str(); -} - -void StringFromJava(jstring j_str, std::string* dest) { - if (!j_str) { - dest->clear(); - return; - } - JNIEnv* env = GetJniEnv(); - const char* buf = env->GetStringUTFChars(j_str, nullptr); - - *dest = buf; - - __android_log_print(ANDROID_LOG_INFO, "native-googlesignin", - "StringFromJava %s == %s", dest->c_str(), buf); - - env->ReleaseStringUTFChars(j_str, buf); -} - -GoogleSignInUser* GoogleSignInUserImpl::UserFromAccount(jobject user_account) { - if (!user_account) { - return nullptr; - } - JNIEnv* env = GetJniEnv(); - GoogleSignInUserImpl* user_impl = new GoogleSignInUserImpl(); - - if (!GoogleSignInUserImpl::method_getDisplayName) { - GoogleSignInUserImpl::Initialize(user_account); - } - - jstring val = static_cast(env->CallObjectMethod( - user_account, GoogleSignInUserImpl::method_getDisplayName)); - StringFromJava(val, &user_impl->display_name); - - val = static_cast(env->CallObjectMethod( - user_account, GoogleSignInUserImpl::method_getEmail)); - StringFromJava(val, &user_impl->email); - - val = static_cast(env->CallObjectMethod( - user_account, GoogleSignInUserImpl::method_getFamilyName)); - StringFromJava(val, &user_impl->family_name); - - val = static_cast(env->CallObjectMethod( - user_account, GoogleSignInUserImpl::method_getGivenName)); - StringFromJava(val, &user_impl->given_name); - - val = static_cast( - env->CallObjectMethod(user_account, GoogleSignInUserImpl::method_getId)); - StringFromJava(val, &user_impl->user_id); - - val = static_cast(env->CallObjectMethod( - user_account, GoogleSignInUserImpl::method_getIdToken)); - StringFromJava(val, &user_impl->id_token); - - jobject uri = env->CallObjectMethod(user_account, - GoogleSignInUserImpl::method_getPhotoUrl); - if (uri) { - val = static_cast( - env->CallObjectMethod(uri, GoogleSignInUserImpl::method_uri_toString)); - } else { - val = nullptr; - } - StringFromJava(val, &user_impl->image_url); - - val = static_cast(env->CallObjectMethod( - user_account, GoogleSignInUserImpl::method_getServerAuthCode)); - StringFromJava(val, &user_impl->server_auth_code); - - return new GoogleSignInUser(user_impl); -} - -} // namespace googlesignin diff --git a/native-googlesignin/src/main/cpp/google_signin_user.h b/native-googlesignin/src/main/cpp/google_signin_user.h deleted file mode 100644 index dfddb137..00000000 --- a/native-googlesignin/src/main/cpp/google_signin_user.h +++ /dev/null @@ -1,45 +0,0 @@ -// Copyright (C) 2017 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. - -#ifndef GOOGLESIGNIN_GOOGLE_SIGNIN_USER_H -#define GOOGLESIGNIN_GOOGLE_SIGNIN_USER_H - -namespace googlesignin { - -class GoogleSignInUserImpl; - -// Represents the currently signed in user. -class GoogleSignInUser { - public: - ~GoogleSignInUser(); - - const char* GetDisplayName() const; - const char* GetEmail() const; - const char* GetFamilyName() const; - const char* GetGivenName() const; - const char* GetIdToken() const; - const char* GetImageUrl() const; - const char* GetServerAuthCode() const; - const char* GetUserId() const; - - private: - friend class GoogleSignInUserImpl; - GoogleSignInUser(); - GoogleSignInUser(GoogleSignInUserImpl* impl) : impl_(impl) {} - GoogleSignInUserImpl* impl_; -}; - -} // namespace googlesignin - -#endif // GOOGLESIGNIN_GOOGLE_SIGNIN_USER_H diff --git a/native-googlesignin/src/main/cpp/google_signin_user_impl.h b/native-googlesignin/src/main/cpp/google_signin_user_impl.h deleted file mode 100644 index 5c1047ce..00000000 --- a/native-googlesignin/src/main/cpp/google_signin_user_impl.h +++ /dev/null @@ -1,46 +0,0 @@ -// Copyright (C) 2017 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. - -#ifndef GOOGLESIGNIN_GOOGLE_SIGNIN_USER_IMPL_H -#define GOOGLESIGNIN_GOOGLE_SIGNIN_USER_IMPL_H - -#include -#include - -namespace googlesignin { -class GoogleSignInUserImpl { - public: - std::string display_name; - std::string email; - std::string family_name; - std::string given_name; - std::string id_token; - std::string image_url; - std::string user_id; - std::string server_auth_code; - static jmethodID method_getDisplayName; - static jmethodID method_getEmail; - static jmethodID method_getFamilyName; - static jmethodID method_getGivenName; - static jmethodID method_getId; - static jmethodID method_getIdToken; - static jmethodID method_getPhotoUrl; - static jmethodID method_getServerAuthCode; - static jmethodID method_uri_toString; - - static void Initialize(jobject obj); - static GoogleSignInUser *UserFromAccount(jobject user_account); -}; -} // namespace googlesignin -#endif // GOOGLESIGNIN_GOOGLE_SIGNIN_USER_IMPL_H diff --git a/native-googlesignin/src/main/cpp/jni.cc b/native-googlesignin/src/main/cpp/jni.cc deleted file mode 100644 index 74ea9449..00000000 --- a/native-googlesignin/src/main/cpp/jni.cc +++ /dev/null @@ -1,104 +0,0 @@ -// -// Copyright 2017 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. -// -#include -#include -#include "jni_init.h" - -// static pointer to access the JVM. -static JavaVM *g_vm; - -/// Called when the library is loaded by a Java VM. -extern "C" jint JNI_OnLoad(JavaVM *vm, void *reserved) { - JNIEnv *env; - if (vm->GetEnv(reinterpret_cast(&env), JNI_VERSION_1_6) != JNI_OK) { - return -1; - } - - g_vm = vm; - - return JNI_VERSION_1_6; -} - -namespace googlesignin { - -// Static variables used in tracking thread initialization and cleanup. -pthread_key_t jni_env_key; -pthread_once_t pthread_key_initialized = PTHREAD_ONCE_INIT; - -void DetachJVMThreads(void *stored_java_vm) { - assert(stored_java_vm); - JNIEnv *jni_env; - JavaVM *java_vm = static_cast(stored_java_vm); - // AttachCurrentThread does nothing if we're already attached, but - // calling it ensures that the DetachCurrentThread doesn't fail. - java_vm->AttachCurrentThread(&jni_env, nullptr); - java_vm->DetachCurrentThread(); -} - -// Called the first time GetJNIEnv is invoked. -// Ensures that jni_env_key is created and that the destructor is in place. -void SetupJvmDetachOnThreadDestruction() { - pthread_key_create(&jni_env_key, DetachJVMThreads); -} - -// Helper function used to access the jni environment on the current thread. -JNIEnv *GetJniEnv() { - // Set up the thread key and destructor the first time this is called: - (void)pthread_once(&pthread_key_initialized, - SetupJvmDetachOnThreadDestruction); - pthread_setspecific(jni_env_key, g_vm); - - JNIEnv *env; - jint result = g_vm->AttachCurrentThread(&env, nullptr); - return result == JNI_OK ? env : nullptr; -} - -// Find a class, attempting to load the class if it's not found. -jclass FindClass(const char *class_name, jobject activity) { - JNIEnv *env = GetJniEnv(); - jclass class_object = env->FindClass(class_name); - if (env->ExceptionCheck()) { - env->ExceptionClear(); - // If the class isn't found it's possible NativeActivity is being used by - // the application which means the class path is set to only load system - // classes. The following falls back to loading the class using the - // Activity before retrieving a reference to it. - jclass activity_class = env->FindClass("android/app/Activity"); - jmethodID activity_get_class_loader = env->GetMethodID( - activity_class, "getClassLoader", "()Ljava/lang/ClassLoader;"); - - jobject class_loader_object = - env->CallObjectMethod(activity, activity_get_class_loader); - - jclass class_loader_class = env->FindClass("java/lang/ClassLoader"); - jmethodID class_loader_load_class = - env->GetMethodID(class_loader_class, "loadClass", - "(Ljava/lang/String;)Ljava/lang/Class;"); - jstring class_name_object = env->NewStringUTF(class_name); - - class_object = static_cast(env->CallObjectMethod( - class_loader_object, class_loader_load_class, class_name_object)); - - if (env->ExceptionCheck()) { - env->ExceptionClear(); - class_object = nullptr; - } - env->DeleteLocalRef(class_name_object); - env->DeleteLocalRef(class_loader_object); - } - return class_object; -} -} // namespace googlesignin diff --git a/native-googlesignin/src/main/cpp/jni_init.h b/native-googlesignin/src/main/cpp/jni_init.h deleted file mode 100644 index cffccedd..00000000 --- a/native-googlesignin/src/main/cpp/jni_init.h +++ /dev/null @@ -1,27 +0,0 @@ -// Copyright (C) 2017 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. - -#ifndef GOOGLESIGNIN_JNI_INIT_H -#define GOOGLESIGNIN_JNI_INIT_H - -#include - -namespace googlesignin { - -JNIEnv *GetJniEnv(); -jclass FindClass(const char *class_name, jobject activity); - -} // namespace googlesignin - -#endif // GOOGLESIGNIN_JNI_INIT_H diff --git a/settings.gradle b/settings.gradle deleted file mode 100644 index e47e0e32..00000000 --- a/settings.gradle +++ /dev/null @@ -1,15 +0,0 @@ -/* Copyright (C) 2017 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. - */ -include ':native-googlesignin' diff --git a/staging/DIR_README.md b/staging/DIR_README.md deleted file mode 100644 index e5273932..00000000 --- a/staging/DIR_README.md +++ /dev/null @@ -1,4 +0,0 @@ -This directory is a temporary staging area for reassembling the native C++ API. - -When done, the contents of this folder will be merged into the parent folder, -and replace the existing native wrappers. \ No newline at end of file diff --git a/staging/native/GoogleSignInCpp.podspec b/staging/native/GoogleSignInCpp.podspec deleted file mode 100644 index 5583f0eb..00000000 --- a/staging/native/GoogleSignInCpp.podspec +++ /dev/null @@ -1,40 +0,0 @@ -# -# Be sure to run `pod lib lint GoogleSignInCpp.podspec' to ensure this is a -# valid spec before submitting. -# -# Any lines starting with a # are optional, but their use is encouraged -# To learn more about a Podspec see http://guides.cocoapods.org/syntax/podspec.html -# - -Pod::Spec.new do |s| - s.name = 'GoogleSignInCpp' - s.version = '0.1.0' - s.summary = 'Google Sign In C++ SDK for iOS' - - s.description = <<-DESC -Google Sign-In is a secure authentication system that reduces the burden of login for your users, by enabling them to sign in with their Google account—the same account they already use with Gmail, Play, Google+, and other Google services. -This C++ SDK wraps the iOS SDK, as well as the android SDK, providing a platform agnostic API. - DESC - - s.homepage = 'https://developers.google.com/identity/' - s.license = { :type => 'Apache', :file => 'LICENSE' } - s.authors = 'Google, Inc.' - - s.source = { :git => 'https://github.com/TBD/GoogleSignInCpp.git', :tag => s.version.to_s } - # s.social_media_url = 'https://twitter.com/' - - s.ios.deployment_target = '7.0' - - s.cocoapods_version = '>= 1.4.0.beta.2' - s.static_framework = true - s.prefix_header_file = false - - s.source_files = 'src/ios/*' - s.source_files = 'src/include/*' - s.requires_arc = 'src/ios/*' - s.public_header_files = 'src/include/*.h' - - s.ios.dependency 'GoogleSignIn', '~> 4.1' - - s.library = 'c++' -end \ No newline at end of file diff --git a/staging/native/LICENSE b/staging/native/LICENSE deleted file mode 100644 index 25e29461..00000000 --- a/staging/native/LICENSE +++ /dev/null @@ -1,215 +0,0 @@ -Copyright (C) 2017 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. - - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright [yyyy] [name of copyright owner] - - 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. diff --git a/staging/native/README.md b/staging/native/README.md deleted file mode 100644 index 9fb32a97..00000000 --- a/staging/native/README.md +++ /dev/null @@ -1,55 +0,0 @@ -# Google Sign-In C++ SDK -_Copyright (c) 2018 Google Inc. All rights reserved._ - - -## Overview - -This is the Google Sign-In C++ API, for Android and iOS. The intent is to unify -the iOS (Objective-C) and Android (Java) native interfaces into a single common -C++ interface that abstracts all of the platform specific details, however -currently only the Android implementation is supported. - -This is intended for projects that require OAuth ID tokens for server auth -codes. - -### Getting Started - -See -[Google Sign-In for Android](https://developers.google.com/identity/sign-in/android/start) -for information on getting started. - -### Dependencies - -On Android you'll need to add the dependency -`com.google.android.gms:play-services-auth`, based on the -[setup guide](https://developers.google.com/identity/sign-in/android/start-integrating). - - -## Configuring the application on the API Console - -To authenticate you need to create credentials on the -API console for your application. The steps to do this are available on -[Google Sign-In for Android](https://developers.google.com/identity/sign-in/android/start). -In order to access ID tokens or server auth codes, you also need to configure a -*web* client ID. From the -[Credentials Page on the API Console](https://console.developers.google.com/apis/credentials) -select the "Create credentials" dropdown, and choose OAuth Client ID. On the -next page choose Web Application, name the client whatever you like, and then -click "Create". - - -## How to build the sample - -First be sure to edit the sample source configuration: - -In testapp/src/common_main.cpp, replace "YOUR_WEB_CLIENT_ID_HERE" with your web -client id, from the configuration step above. - -### Building for Android - -The android build is setup using gradle. - -Navigate to the testapp directory, and build using the "build" target: - -cd testapp -./gradlew build diff --git a/staging/native/build.gradle b/staging/native/build.gradle deleted file mode 100644 index 97040265..00000000 --- a/staging/native/build.gradle +++ /dev/null @@ -1,121 +0,0 @@ -/* Copyright (C) 2018 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. - */ -buildscript { - repositories { - jcenter() - mavenCentral() - } - dependencies { - classpath 'com.android.tools.build:gradle:2.3.3' - } -} - -allprojects { - repositories { - jcenter() - maven { - url "https://maven.google.com" - } - } -} - -apply plugin: 'com.android.library' - -group "com.google.signin" - -if (project.hasProperty("pluginVersion")) { - project.version = project.pluginVersion -} else { - project.version '1.0.0' -} - -project.ext.baseName = "google-signin-cpp" - -android { - compileSdkVersion 26 - buildToolsVersion "25.0.3" - defaultConfig { - minSdkVersion 14 - targetSdkVersion 26 - versionName project.version - archivesBaseName = project.ext.baseName - externalNativeBuild { - cmake { - targets 'google-signin-cpp' - cppFlags "-std=c++11", "-Wall" - } - } - ndk { - abiFilters 'x86', 'armeabi-v7a' - } - } - lintOptions { - abortOnError (project.hasProperty("lintAbortOnError") && - (project.lintAbortOnError == "" || - project.lintAbortOnError.toBoolean())) - } - buildTypes { - release { - minifyEnabled false - proguardFiles getDefaultProguardFile('proguard-android.txt') - } - } - externalNativeBuild { - cmake { - path "src/android/CMakeLists.txt" - } - } - sourceSets { - main { - java.srcDirs = ['src/android/java'] - manifest.srcFile 'src/android/AndroidManifest.xml' - } - } -} - -task copy_aar() { - description = "Copies the local java dependency as an aar to the packaging folder." - doLast { - copy { - from('build/outputs/aar') { - include '*.aar' - } - into 'google-signin-cpp/' - } - } -} - -project.afterEvaluate { - assembleRelease.doLast { - copy { - from('build/outputs/aar') { - include '*-release.aar' - } - into 'google-signin-cpp/' - } - } - assembleDebug.doLast { - copy { - from('build/outputs/aar') { - include '*-debug.aar' - } - into 'google-signin-cpp/' - } - } -} - -dependencies { - compile 'com.google.android.gms:play-services-auth:11.8.0' -} diff --git a/staging/native/gradle/wrapper/gradle-wrapper.jar b/staging/native/gradle/wrapper/gradle-wrapper.jar deleted file mode 100644 index e9ac3e271dba5ed33430ee5547586969a6f7645c..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 54208 zcmaI7W3XjgkTrT(b!^+VZQHhOvyN@swr$(CZTqW^?*97Se)qi=aD0)rp{0Dyr3KzI>K0Q|jx{^R!d0{?5$!b<$q;xZz%zyNapa9sZMd*c1;p!C=N zhX0SFG{20vh_Ip(jkL&v^yGw;BsI+(v?Mjf^yEx~0^K6x?$P}u^{Dui^c1By6(GcU zuu<}1p$2&?Dsk~)p}}Z>6UGJlgTtKz;Q!-+U!MPbGmyUzv~@83$4mWhAISgmF?G;4 zvNHbvbw&KAtE+>)ot?46|0`tuI|Oh93;-bUuRqzphp7H%sIZ%{p|g{%1C61TzN2H3 zYM3YD3j9x19F@B|)F@gleHZ|+Ks>!`YdjLB;^w;?HKxVFu)3tBXILe21@bPFxqwIE znf7`kewVDrNTc3dD>!$a^vws)PpnUtdq<^;LEhuT$;)?hVxq?Fxhdi{Y)ru*}G{?0XIuDTgbgDhU{TZBc@$+^ay*JK-Y1#a7SpO zHyWJnsR7T|T~Bv6T*n>U;oojNGn}}GOCkMk$tSQ6w{djY2X8sv z`d;xTvUj&RwNbF9%Uq2O~P)32M5LhEvu)YifH{1z#~{bWNWb@jLMh zVUJV2#fMpMrGIr%9Y7o#C)zVd+KQX8Z)V`&oL^y}Ut?pT;i8{o%0fdIdjtoI5(~Y{ zl$R_`XQt0k0VLP&_!>>&wg55P~iFB}0=c!p}&pO(~&fo}p9!sAW37Mf!kAsUZ4@ zwYFm>c`ib_KqQ|-f1mK47)b3M%)Z2KT)vjM>^`gn=~VsD%Iyl77GI{(9#eGF0Ao6S(TAGLd+S<_FpyMWx={C_7^bT$Bbrg{4Bex-6CxC+|3- zq-eUnX4He-g``+N04TM@rr|3$bFmDJz_Oxtgj-HMLL}x?xt0LJZOW+8cgLnDeSviP z+~H_$+_wl(UWUCKktl{p{0p7l8GOP((+bpm>KqIG{0Nc^gP2jVEgeGC1)41Qmf$GA ztV|uyJTjG?BbIT|YCPeWKDTUGMHyo??xB-yw_N?@6)--PTy6=|ge97~FsHIA6+Zlj z?>&AY_|8}uVjW^javZJ#ZHh9@$;1T%RK%qs3oX3Q{|U=4C0pAP;TvE&B?eaxJ+_g}vtIrE=zaCbk^9am`Fyhw!*X zf(5y2gXmQUWg)$8X>C~+g}k_F8P+fni0nq}RN_pq`P0P^!I*Mp(gK0|RlKIWBA6z+ zZvXp_Hp8KRiwNMwLun?;)l})q>G{HkK^3t@znN?AGnI5!^ogl;>Cq#F|Orith$uD5^dob0h8vyOzOu2MKJUyq{(MIx-^e>y#K0oqJug- znT^aGBM&`u6gvDu6;_!pIhv`i?^JJ3pDprdv}(_9;+=Ub<&Vj_z7nL#{lzISdygW$ zS;Mm_eAx{{ZeO`u(NFR~UdmTUQehNB{7>b+o!b|<@4Vfd*OWj(U=bxEug6FmX;Iuc zldB0@l*UM&GRw8n>=)-VlXN+q$~%nY>?zH2by=_U&1$aGwXNL`A>|})<{n{soC{$f z6i{}Rq~K;U@!0~l0*!C)-VOGv&L>;)DIe{~MOx}*9-Ilor5hAU<|QurOl76NzoN3V zFz=oQ*mRGk@zvH6bG=PAVuhP#vQ)|NqkokQjR$y!VE`vqM(9pk6O3%eF#5L)yu2A+ zs*{Pv!F6}w4%j=vsHRJRBQFSruEA8b+xm116n3s9l*X^2CIqvWhj3h>YKD7;Vodb*~~wfg>xvIfk;u|-e5I|v(RV` zfVcu;xAAxGfjJ}RpiGe>hrN<&TjLbp$?XY{pD8hDB;3DtAmV zOU8|p1xwqShBr-NT}{v1+|S!xNU5h>%WD}IS5wdewOiX8W;fOdo*A_H&U|h?L(e>Y z+pdZ5JuYFFG5hLVA*lzhsL6A!QJrgiynro+pe}MwuJMaD?c>~oZ86oJv^p`~seL|~ z1ArVq0QgvgpqnwMr|XIY4uJWp1|TCsL??Ec(|na|KJjYy28(mJ+-pqtRmNvp*i%Bn>YoSNj+$8+o{rJE{3LOmHi-8jE|VJk_ot%f8pC+4sRyV(3# zW3O2ekaOSg_hUNR7YtwtYU4(m-K}~6*>ToXhNBN4SJ^3&JH}VFGf2J)odBc@>*Gl- zu!@kC8GN(Z%CmDFt?t)BFVTrrZ!TnsPU=#=U$g_cdL4gn$zU5h5vGgRrg@pWEHx`Y z|LMgbYmX`<5rDTUZj18LN6hc9Y_ch?Mvg14mUt;M@RzemPs;Q4n8`|C<7dRgZGJHI zwVvX>w5PjdBjX<^bnISW$31*#3Mt_V3Ao-Pm*S)!i<{%`o-C~T>iy;u%@3-6-z`da z;}xiz)MqEgBfPGcZ39Q~i%t-b3?ye+s zkV{&6m%A-gUR^>9Cg;E*M8+;83~U?~k$A^f&yHwE4pT*`ItMWs>*JDDl0*7UOs3rb z{N%7rt%axd2NKO377KmHN-?%orIejNHen&@RYXd9e{|0?3Z@QR&K_88nhI*wn zl_95|n6VThK4AIQu(kAlGG#LYNFwEsi~vd_%0*~WeMfzssz;mj4JG${`-^wNa@^*u z?1Se|Y4gsSwq$N7$s7O8lxI5YL)Oh?M$6Cl%*79o9n4SU9#^DbV)ckzuSjG(`2aL} zwyJ#Mm9)AVg#`Ve-l&XvA!>fDv5SG+-nff!a0Z3VkR6sLz14*8$!#4O56%GT?HC$Q z5UTKdWBAPI=Ng*Kfg^*L&X6^-Zs>jlJ<+WKk}kp#?ZhoI{iAYRH_Fh8@wW)lPUOBO zy%**V{0Xh--4K$N^hncGQ@CX^6{yB?J(OpDDQEN^8Jn}a zkClUmg|oT7h0oKtm5qh7zC918qdLFWd$5n<43cw2ta>hB1zq{>t``4oEHts?wEyHs=F{&{>VYY$DN|T5^;50-h$n*X8tDV$ zVr~9Nk&!g~n6K}EH8Uk&F@*5|$fEErn^6)H8!_VPoN7$moX&?~o% z!6kGR_z~thhh53cpJ1*`T)(qa+tG*IhNzCAH3wpZPe@O&rOclYvKv_ z$Hytrd^BA-$jHy+Y|Qan157h8Y#;?EzO(dW?&*I);tr@ysC4#JwcOXX^jUhA$=kjE zJfioI8g;!`WvNYLW4-xBl{dVBfX8L;w$#Wu$YH1zDokI{a0e!=41*dG;R1vbHGEHp z88sW%D^$I^8JgM;&}_x0%tdqs#BdypVQMz43>ih(iH+fx)VuUpW=ol9ek9@GA_dT18;t9-Mb&B2VurL628tpA$#ZPxIjlxWVD(7rsfn(hajk_}%sP9xNhl zrJ{)y=?ZENjKlW>@fHaLx`TaX7bSGN=!p~g5#y22p|5_@a+hV=mdqo3 zCuyRIO;)UZ1<=N0Ml8GsSAZ+d8gPqO2u%0N1Y#K13SxsT46W@7M`X^-G#AdceVFsls%T{Z^LV&`j4|WDsRZ{7y557 z5BiXpTcO`?X(K>&nMIwU#I)&g9PjW{o~Ij!#IUhElGfxc)lQ#Q$iOjA+x%=@2{t!X z`&-aD`#Mar42lblnS=)o**}54&DVL5xKCWAi)ww!HKT85aIf`c)Gi*QBZ6)C;(fhE zJRDf-=;x5!szU?NF{J3|Xp*V+W|4&ns|StSqY|=Pmay6SSXTCIe#$ilOgaR2wCa1V z;=4b@*@z+}3wK7y0X2B(?GepcPFzP-97U%GXP$aA!LCHq{9S{hYNR@IM%Stzp4(;u z?@Sj@=pNq5>}tl&r=HbUM%ZUW%l=T6o+l5Jxk}i&A}ZJ&<3In4q%mB*PPhMCE8(C3 z02u$hRtmcrS~)wKyBLd@TN(2k8X7w~O6%L`oBmJX)O5r&Mfc%RpI^Ut!nfI1VXsc$ zBPMN*M-hvYE-e`556f(=GdOQ%(w5Y{j8g3|Xp%6%LxM18Pga!NfJ@yA)}fo6MK33E z3$_Dg)Ec;jY`uhLowVb3>(*YoBfnl`{EoiabKiM++g{rFei`8fWDD0lbHgfv@j^gd zq^sJC;MjMQ8HkJ~lCXH_)aaUxMqT&*6*^pP62#?kg%POWZPqiHB zjK-Gm`fY`sQkQFkg{|Crb(`3w!P&hDj_ZsKh`~|4YXNj#b27M))fy}etvh$C46TcJ zN}WBC)5fMlmfgwbtnbx%o5`npSMNMD&XLTSk_F+lk%b9=I__!1UAw8b?tr0?OITYm zZwZ3v3@8tGTJ0XKXa{_zTZiSGiq)je$wm_^h6<5p?&r2$Ay-#o)^TrDz(M&H&wL?v zG()L5-FUQNvBMGh`+=p(C?cCTCF`LooUlRFyFw+w=lQUyexY`Lp-*=GxT%AC59vYJ&WHijkfN>?*}Xx%{_#wN<6Q3-=x z#yg8RzNweQR4j?ybGpetSoSMyPQk`7KgPFGL0E0 zg|d`R9ScEK^)03o*8-GQ-qY{-RbB`#JXlx*w?%|i?OFj27IiqI6cxuB)g`4fznbzQ z=t66!^#15RjJ#FZ2tt?};n9t1Lvg$-&Fr?zHbGC@Z$lGK+=00=CYmemy!LIt1$6N6 zS=qh(HuL0F;=w2%Vu!KYjDf-8V};oV&rXfQ$Q~@o#|6*Bgs)C4KwHTfHYF2gt%E=~ z1sYV844uKUAgBvGoU}I6YG$3AD{(Z-e_)Ah5bT^9QoJK+x7jaE@7NJ8N%yod&;##c zq~7YbR?2tUslO(C5u(9&5D%{RzJ(3ls*N@$ScyA-r5s*V?|D9^#?tJMPRr~5-f&|| z5hG4_qe_t?&JYXofBA`%*zTKF@&}e~+-eQbzS;U|V4!bYf3kU3qDfy}Xi2#cwA91u zj_?Lz=NH$77i>?Pf1aOj}Wer%O5^pQg2XI&tg@}X|aQ9xmEwfVE_C@_)0A@ zSGbHYe0oR3Gf4i43Hljw_0hu?@Ie-iHVqD)AY?D`Sb*oU*SI=y?DNMJeH**aXfzIW zEEVH=en4^dv`L(oJv;9AMCYDGAdYbBJ63c8>xcQn1DBAQA>FTxCXeW`yB zVT|dk=M&LV6!Mh4MYhG<2jZ*1=nl}&+nl-lSJ*9#SxOy z?b$iv;=He)Bb670FaOG}HWrc_?A`tcSF~bngbktNmslVzr3`Y`*o^@}`<;VXcMii= z=FGm2$Z2w-t{?Y9bN!c3eTM3yvIysmd zI6Il!+WZ&kub?T3$&d6sZL+oGRAJxLysp{k9%^~9zOO0Cj{t(-7=(iBMJ5%GFVnsT zogf|YBhe>!o5$OWtIWk1JYNduwVLMmLF2eO(Szy>&^c7WKB-p)1}iK5IEgjm-T5d_ z@@maI8l#j$w{sevL!hGGS%dKAvsq3leS2@nTzUz|f{}JTh)um77U^p~cO!}I3;%Yv zt%v71C1f$|j;mCD9~0Ph{&*)oH)iz^ySrT9Ohm<`M8ON~DP7hB{tKaBWEo*BZ+86f zAm1_)0mZsz`nkyh#xbcVa2HRysG8Wn$lb`bylI>o!AEm7?(K)TBU{1w;rKe7YebV7 zom96W&t~j`C=+gtr4>M!3k*(=yBEs@_%-#Zj^EAIH|BC!LtJP*jF+{eJ_!**xncaC ziKX%(XYY!$@Wo1Avwzn^ zPfE}$xxI4jvV^r|P&w5rGW2kuo|IImxq`L9 zyCnpoTEiCp0N#LriHe0Nio6-=zo=rPncSuGj1@+m5CtzTfZ9zJI4YTL!-s_C|powj7a%txF*KQ(sgv@^^Fq6{h218-K34C$?^mfUa*|L-w z?9l+DEk8JVrcj#Pj>?DOyTZivZ6|Rr!O?m%`kW(CV35Nos1;(Ij2fs}S#FWLOpe-i z2&lK72Yv1-iGGA`i6|fz7<$NsAX}|3worY-PRsm!L(~& zF%V64k%>!j>#dHjkdkS<=~pPQVH&tG1iZ$Sot>eD&DJj;mzN`v!q<7}_YB8o%^CEV zRJ$5ar>Yh74Ew$1ho)*4iZ%#w#!z+PQCZ;<-UnrZ%{LB*^u@G_RWK6t4k6dm8^vOi zs*+pOUb+hHwACR}wc4+6@b6R7U=4h8DPJ!LwOy8C`H^d3rg%!QFf8|*SdK-48Bz~x z_C4vZpU3(Fr;N2963h1zueM5{oDJIkGr^2JCU@fhCKvZ#p_T666HL+F(aG5QZ+89F zBc05R9mVu*{)(CZMKMLGXew$dBYm@ov*BZncQJ`+7B&THD$t4%H&P%GAp;SE73rMg zXOe^jJMNE(1KK{lYv^K`o(I^%OtVcdrqGQ>dcTO4?Z^-uE{_}4Kd)PQdtNp5G_A;d zzkkH=0(OSldY=vz`jg|H)13`COHroY^$|wdzUAtv$Pg%W%Cpmm z)sYQJ<0?^!yH&zZxRt}qerk7WQqzHlUubrT5*JxYd21*th(^py+7g5K zbrD{*0kGDNd<3{(b%~OONM{9sUm=9xuuYA;gWvVRU`lB}I20DBI`T_i#p*B& zt;lg`Zmz#JGVTE)a?U;@a?XKYIPGnbe~pq?lr6|F*=+?N>ZBAkKI)<&wlT8D8H{m*1(^qX#M5Zs~^uY9_HY(sgHR5yrRiBe_-U6uCrAQc64e zU@d95dqi)+O9UxR6|!e00zhixU>_U_+A~NiuD=MF)g6cr z!)U%>KSa}*le&IsOYJ&Fg#|t$))2q~6`k4T z8N6{9<2Cl)J{A3=Kn+0mhd&w`t)EU_i>f;yLu|K2aIxxYfSENl;6v0c7zejsQ1I&$ zKapAFStLZ%!EAS><+t-DHFD3#7>-9lh};UyoX}%g^D&kNT0V0~bDVc0FZy)e0YDbe zTpVyFid*1?Qai}-mX9lp>G~(T6L0_R++iD*$1t}KY*WrG`{B!>w&@vnFFUHr%Qrik z2Ndetsc3B2Z+mv$cluy^rg=hGTw%^5bvJvMsl&P?sP{2lT=k0+)6hl`_Go!bQfhsK zhH&`RMjpHZSoEjg-}-N$HM^>j$KqNBjXX{W$cHrgk8rMO>w->*YoZ?3o#83B4CG68 z0hFR=#7&LS_K*9fT78yOLAX1PD|C`{@>DW?u1V`nUVyqK&muaW54!){-?A#uUKjt8 z0W7fp-x7h1qm#as6%qY^f~Ks$)B}<#x{vHL!-UBnI1M{ZvpJDfDrm?&IdDG+aBIO7 zK1=}+L+5%3#c_47lN5t(D z72Y$f_o_$49UxP>fnm>nhbChvPEC(QJu?vbQv>ei8-c~VLV#=Y`{ zyiB$E@}}T@gQ+3)3)RM`Mvv2u#x|MAM14TDE$H1Qpb|Hm!}yqZzMj6~6wPO-V8uHE zIekC2?=Ac!EjkC=;2T7&qt?)7Xd**j;!$I{B@_eFvv+L6ChdsF=zW1kb7;khE2icG zt=A^&t4Mdm1^s#e2Ak8qC;CM%C7RzWpgUdg?3DyZNo_--;0t+zCN(=c!i|5V<83q^$>9^jYxY_Y&AT@s7w(?6IR>jTJ}ovoqtf{CONXPfB(nIXG?*K zv_iwOtk!4D0KsU$D4Pqyb(0OI@0fex7C4;p(qcnoo#l_Pt_~43wx0XkV+$o%oBK$WL#QLM z{dERKhszLa4B9snqT%6#Nt(7B<%ivM@`q)HHIsw0DW+*ucY*i}`U@3H|6~92=7tBu z5M;kZgP%)AuC?wk$9glV>NGV<8%mZj~TT znW@zaG*6L;2x8FNNQb6Edo7bcCI54Lov1d>C-or0_@ch;&rYpoBx()nqXl>;zJpHs26q$+#~UgR2JePYBZWD2A;z** zDuXm7FO<7UWwRQ&24Gmb$OW9pADw8A+fMioI;ggQJF$F}E?2IgR5w*xUD18FV+f9N zH5cr$1Jyb7>PL!X*P30qq4A2&FFA}dgC*h09WCJ(;mSO|FgmX~511Bh80rq)KPX*+ zW=60pbL^Wu?bie{wCJW&UYUMo6dFV8;CDPBu8T??ib|&y`!E#B_NK26S*^0dHTvEl zWoD;W)nOc!?3>(hokwq6aFRpSds*SA(cJfsG(oJfXrV12Z6W*$_SeKhijaxnGkK=_ z^S(MY?$OG3*Ax}~Zl8BY#VD-i=^~Naqd{5p!SB2tCLzg zoN?jWFst}W-dL9G&xF!4R|Gi@M)O4ON_Zi~WBDhCI3h6G`bj&5Lpyc2KfQ3@LHbQN zzZXe#BpBS(p!agicj27@Llz&CJ-}mrRi+Ixyt@Oy(#s?!XWY@{?7xz#Gx-M? z!MH0PC~0tqiN31nD_|3)3m&TSUyYEZ;piW>*riHEGYnIB+>~4yGV28245RIl5z9*q zcRa`CjR*w)(v7QSO)ks7xkq@6Udo;9*kgk~?SUN$cmvtS?aUbboeFX5t2{Kr^!h>j z&zgASp^dSPfDuA+VKzL(TuAN5~HWY?N7u* z;U*hv^(l9EA`U{76b7`C?6n7yqi?At*$EDJjEc3k{r*x*u%irpX>Hr^a?hc4^_MfQ zB&5Vg1vwb$j1(jjTZMyTD?m@@ChbLys)B$^Fo^~~l`;RNNrSqQ<}9tf5{4j=rmn23 zOdYjjDKxh|D*g(+)_n30#e; zrlB&+&Yg&THMR9hn%4bm%49}r(thGWQ@z>TvRFPoSDySnJx;RBn6RUd>i48wBf0F< z=uqdel4w(9fstNSPz_@MT7Ui@m?#*Bb*jHnyJkTf$TZW`WNiNOpp1BkA3CudfD+uI zecGD|xs+u6v3eA%gTEoDy0HKO8<7+3b^Cy=;ORU>>{~4CyMoz#`r01UkgN^_!?R1W z^_Y!i`$S*W_-1I{#^1He0|RA|yuxQnqjfOi+tm#^!60}>N>LrCc^ARko2Lgp1o~25 zCHe%tr2lNS7I(E4A0W1nQ6>l4B6&sJoFZR(=#XPJs~B-6A<^Y9O?c24q`C-|yy!KA zcJ&d^G>4ipI-G4v2r+Uw$P_S`T^QToGw`Tj#8AHC@ZQe)AklsEdPb+4veveTem1*% z2kG$1GO6tRj%bJ?)~XaQ)*wapnxEG1D@G6%kNRS{&(GNf%2e^dC zBi=B5tzIw{_&#f(iO_+9o>LLEi0m8^`Xjt?LkxQXgkEe3!Az?dg0O=}O%WnX($gPh zfhp_kK}#a%@?^-A7mmAayl}C^1*4#Dyrx8zF~dL46SDNFX;4=c2EL$sMP;Ur-HQ8v z+)hm+rJzGe-F{J^L135e?h=CZf9v9g_tXA-KOluL4Sa$;P^+&Gh7H7^I?c!K@CXa)ja&8#UC-etu4?M+p4Do7U+ zo1ps5jBU-`Oy^`771U@XfkDpUl%x>U?iWJZk|Vyp6_Ee}4s;^zQ7GGzvSOSVEB$0X z?Me)`U=O^pPUvvlUM0AJvjk8AB51#GL!t(tovE?C|CfAPBlWB&dQU!$}YoI8d9Rx zK5L8CKckM5!?+(4TIzzLgi*@*qYfNAY~b~wNM4)bJ!!EGIEG?UGN!OJkXs_<r2(QEvMBbQX}G>ErdB+ZtJRo;yuUZJpc_U$E!yQ21mXP!KAU^ChICNq zE0XyLwJdHj#vu^s!>8~KPLkq-cb`-V#v)ctC~?nVuu38U&pvbC8J7H;OIpr6YgGVW zuNx{={f(0#C+;)Y%sY6Mp%nz&c)o__PlKafvP?6#9Xu!Ct1`g!+ioIkbWchTRUTzv zw+#LV)&R1^b-@InMgfiC*NGsmo*^M2H7{BmQ;HXw>SBJr{DGye$_G{x}_3CIE#f~E!)cd{c zssrB)IXbxM%zqYPeUI~zerpUsVr-l0F;}CR^?gA9rQ8!oaN`F;oV^BnMepd@y*7JE zZ^eOg`b&;((?~4dDx+u6U%9$-|IP<=8{vi1{?7Y`5_R?(>Q%jC{q>EayAT&2(UTz1 zP2<{Ky@xp;Xgj_q%>LPh)lD2?JF&;<@LJ7ufa~;G;D_%eJM!ZE$u|HCeL1Aa@h#5t zqaObmk@-~taP{ zmP;ehKFgGMkw4aJuYYO~L?bnhOlclwwmd|k-FRxyMAP4{RuIwDu0{&lXkpMr!eT~1 z0079CJ+*G5JABWzfe04UK0Wj%=ZOFfHg&TVY5ae+H_dUafCDm~r7 zI;K6tQatQE@#^i&O5DYfnzrtuC$--3K6a8ig5yAa$E86fc=&K@5}_=>$a31V+0$&8 z#yz!G_PC^^h!j)iWj@==$7V9Qxn{g=I+CesW=t|KGR83R{LtHPxt^ZToj2trtiyUr z-s2Cz+$uD)2D*YeCowg#uweSh#rWr)6?4b2`oeQ-2FhwDNE^1~+}_iC`l^^_s9w!c zk)mW*T>;JOgmt_Pox%|_HW_}nX$ki6T;b7Lht1hcu@ckP>fiGu=b$bVkyof`oA?_! z&Y>s66dWtr({h@wcae|9RiUWnP5bjz(iw4Mjz;l3iJmRdtzXF*;*#ag%1TGIYDAmb z!f5gI1f&-gY)WZpO1}@)r!K{g7?W*dQuJG^yIC!6D)lDHjaD2J-TLg^lkB3{kllbR zH_j#K4z~ldvf_`-h3(}jU@9m@ll=GGhSui~-Ig*!HW#Uah%-Ag>W!OgE2&BBrN-&) zX^*9i=u8P9M}%ZxQ0Zj{O}u$gC&n(5pDhd$$gBGZf$A!hf-#d*RLkL3EDRdRn?p-U zn$!0=?7PTq;5MYV{(MM(lK4y@v4&q!QAD)ORv^q}mrs))D>!ef;))|%JFMn~xhOh? z${^N^*k-s<;+#Acy=g<(N;{z=Wk}18i(R!pef{euv#k7*BBOcCZ`R&NL(G8mF0`?WHAR3J4z*$uD&Vs zF-TS@;A<#rO)I-FjYJ?{6!fW2H5W-N7hCJRu+XkIPi>TZUzMh(8z>ZtIV3R*Dkz*V z>9BV{TQFOZ2C0%78}M9cqE=|hWB-20wryak(i5wHmXGGG*+x)R&fRXTGRBr%mmg^O z8hCC@nz;q7D?1NT6f7}HT_TQqBdw~{nnzlpj<8LUXh2HuFr~QiC>Q1&dVR)z22f5+ z`ZjakxF?~WSLxX)TUFRMO@@!O(p6@xvkwbTHz{rU1}BWyi(Gp-UISFQ-O?%fDBbyF zL5wS(4ks>yh+j{(l+Ln#wy!=146rWobRD$R@-=97Ym5(466kKN_AWwoCHFC2k5Ju) zUdq}jtpu5vDqS!3QKlJHuDOYieoNZ{cWTozDZ4MWIPO-TkQUQxAnz!SVlON`S^=n1 z*PPj6I`PkVM%Tm84;v{0jQWJy_n|m&tB1wE3|p+ER@6H9EIoJ|S|hWJf#`NKw|<*+ z&1yJs*F@n@69=wlW-NIx*qk{!JL0_i!OiFt56x9Ww*_A=N>)6UTA5k;NY-(#$9|l! z#c-E>O3u%*>=&}WrX03ZMx|i1L050%*H(S`b2>qxsL*irL+2u2_qb}X;O&W>y)fZc zUPNVi!1`IqxSuhd?Ru@RcUcv1bH)+7V);oN+x5`>S!i43D)-~CjO{vopQ4oqqu^XEm*20FDU1b#;=dYdK554TnG0xMJ)>N8!>{IY zni*o8P@T>GWJNI5WykKJ^;QUd+m`1InBR4P&eZ726EOT-Z3?%maw|?eb=^3|&l^%AT_0=4K-|c&-N^h`O?jJE(yQk;m zms4(!1sg(y$Wu@&scQ=hH$)K{eMP_(E`Mj)z4hB;pk^%*CiLz0KNs1S%*)K&MprBv zQBAEr)n`w(g_k9BaN8=qQKU=7T^pz2r%@N_5Uby-vN)n3xCLJw`@fh(ZfUSa8qf-c z@x3xVbN04T+g_Bfy%TU!XeRYRpSl5iB7dV-u`X2W>UWwiy8eRQLw0%r5xJ|FOdvVu z71plt$JbVMd5+jKK?k$WB#R&z2a9_P|ko=t69ab}>GjRiRC) zHQ)*xvemft;tPxmy}K!(9b)x~EZk;On$;!vMQeEb5Xhtd17dY&yXgY^zJK9r<27@M!LsJkn7P0(H@pS`nap9Cz7WhG^0OLk3L5nK`knIwlcb60>(; ziXm@jV{}|pcMsf(m9Nv|Bu}?9dXbPqF46VhN}b$)&psq%@9>3--g$!LWi;KrutVCJ z0)O+dUt#G}UvrCz_JI42s{6a&iDr%gJ=&pfhae|<+0q;QpxLU_jo!Q}Y@Jgw46e&C^DaRD``Hf$5s}}NgM^4bG(WOwnL8F zcZ>c87Ib4Vm*k078x>~sCx(weoR%~`PmC^Zkswb<;YN%|Qy>egv3ihr^J_4^)|-0D z1N+c-H!uwk{+D6ms_a8doA))K{EfNjPY!#PsdT##$5K~&o#3wq$%;Q5Pz|3)Me+j4=#tiuF8JDVu zL?OH2o;zUr)B&*8xG`Y)fx}y6Y_URmxmWcuM$pNJyI((~@o+xC)WOhv&)|&YQJd5t zx8m?LgdF|KyL%g#>fzm5CqwVaZ5v?c5_u;D-$XB@;nO^m*a8`n3S`j3XQzlqIueiW z-pp&;+KgpU0WsgnJ%{=7?^mGhTszA@%eQX4wuvVs=H)=0X)R=4dHvQ5=6}DwYX)e# z6^5{dm8-b5-i!F^6y%|aE0)lw=Cj_cwiEr+Y~PVH;IsU-Nq+BgWY3D3zf|P2O+FI} zhN#Sjk}IQzAkCHI`O07}6@&=5J{C2v#z0?oOB3V?yh!MHut^H}E<85@{Hfk8z*7_3 zLODdLO6G-(NM9yhmuj;t+9)I-O9zUHp}JyivE5pbSLS>WT&$eI!ct|qR@ZHFfKl9k zEZL;3AuSZ)yws>s41b|9%~Z{UBdMk_xn3z8KYL_BqD!>BRFomLka1w5DxFdmMCc)1 zQ}*WV&B-+q^foIUjO^|rfO0AZ|{X3%g%o{t- zsDHJnhK0aGTQnqFta8a9omw*rGidmL27rABg3v^bGL44j3#5xjJpnO7yE$!46BqVE z3Nbw@bvr(?`QlgvI$+<=Ed*t)GA-DvgriHP1#o7{?ue>8ObE|AcVLlO(v}VZWkJ0f z!^%F}&a7lEiHUh4bR;>2U50g^*#OaASoE1qaZNnIUqru_HR`$0%a(yq>Hzzmeye<~ zF%MiZyuPH-#S$`w%34|^jYLG~DY%k9sD|J5;nb#hh_vy3lfI%?9ex@*I1S!H&2-76 zd+9XJb`^nb&eKR;U~i_68tqa{L~onQ?<6t0P~jMbJKLr!CJg$Mxi2A$x!|1kDW zQJQthzIRsIwr$(4v~AmVR%WGb+qNog+qP}<#?^q47}~AMXi&C`()sm#Ybsc~_IhTYnNR+VvBI)uvlWik#~q%MF$hQK>jbXkDKys1)#IMY8yRh{!JQ%TNuy2b6()&oc!C-Zr}GhI zLuPX3_nc*2>V|{LT{k*+01BIOi7d1d-9Kd*JD+;)ZDLAV#3y4J4I!prCyWOowwo1R zG=6}xOfO`s7?a5X*A{a5+@&6ktTj@aGO|9nb=sxE9peF+fxx-R`mDh2SJFOBOJ6T^ zr~$Qfw_z^WQHnGXCJrtUE{EYGgqPY)Fve# zPud^{Udiq(xbjmrZ7~mNj#J-8d`^S9p-d)ladBrr(&z?+toB*y&O&A@PoGvYaO_sm z#nq*uK%9ol*xJ~>JaZDKzr56afl<2f=-54RvskyBnctuCBjQ)ptl~FkU}=`G#0kb* zrZD&fA@T9LQO`>PrHC3Za%%2@@}lSrd9(7?`Q1IS`iKY8M}W7pI+Z_$%*65#7 zFRt%~gIygaa*fFSIMg7n@GeG*9JDS>|Tl1F&Q3bHKiEHe$mhgaxLRw3E0y zt3bh(KtVGdaRVK4>?NdJwROnc_XcJn)LDa%6cdB`NJ+qQSe7D}%@`CoXTtE{dtR&A z*w1Od@%B%PdGx;brAFN_n?$_*4}%&YN}up225Y`5c#2JknvmeUY#G2ryj|P!hUiO` z7knSlgR5T3b?anxk>E^6p_|E=bm&Y>Y-HX_ViiP7AQ9~&;l@w7KTVQwjb|RzM&>iP zD>XtLK?~a2i1knoOqg}8EKrfSX-671Q&0~n_S6lpLN!iZ*A6i%iGmu=7T6ZS1!gc9 z5a>h5I6Emd)DY&R!ji^Jdi^HJ8n~y-dowYpb>l{Y=Lg7g3wdhfZL`q1MP)FF#1aN4 z4d`(WazPoF5d&NbjoOtLWKN9g!nR)YW34ST<3@QE6!uCl4t5Jq4p5UCD ze2XC(=!;?Rn(lB)Uf~$UT-s zE&pP^Nu-n||3c1Je*L8M+38#BW>ry09;D$61unVdkejt*Ks%4YW+{Z|%_sNFk(hl1 zbW(z&IIuH*RVT}3NZHj*7p6ofes>EFWn9LcsJp{MPTr4)C|O-p99glb^h>&E;&tCI zvb3EyDbBXA#?ngODiXg5Lz%fCZoJkCtYAZnWqg&{pH20Xzn zk27dh<^b>Z4Dw6t0PhZq@+)AgU#(gZwCo-AOX=Xx3(kB_Rb#Y7*HJdbyJO-OiqpH_ zmZYYKRAkXD-HzdBqMqrXnP~-V?x207`kfNd1+1QMyFsgY!#>dvF&p+plr^L!L8yqelQe-7F zjZd}UNLlM@(OigQZwytWzxABpIQBz3R#kF#uVh+A+uhI))*l8q(>}k)dfLx{*$Cpb zX3=I5aP@oko0N^Er^#247O5$GrgysM(PTomX=viH;zEg-;=LtPYzLO0b(4@2SzC4| zg7+kn7p#YVUn6pjoj7=ye=NVGz9o+Cot?67*bdA&MBu4!3Q-WvpkLJ5@!mVHny>Ko zN91-|S9oeYP&mX(U6LRT9?<84(P9}!M6`Lo8jJOW$}7#D?~7ez6l5M(TgvtmiAyHC zVYY}r<}>=@@hlV8O?{maOkAtG#7VM^&k*S%w5ZO$L9g{i4c!+;Tjv# zYTZT(3$^O`gKMBqa)0zcY3s=YWS%yvaR({T?vk?<&L4nwPbTwsm}@ew#q^=!Aq_c= z4i;dbHtD>nIVxO>>(&5Ads-#lxoGJb2OFqBqnH|($3BHCZooa|EfnnJ&a=eczmj05 zU$o_*6bFnmut~(xF`==>@hlcgC>Jrwj1rH{u{#2aDg0TNv$mLc4<@qIYsmyk+v^a^ zAZHG8H=43P$j$Maep__LCCf-VZ>tU1`?W-sr)S;-A)+&a+yaYV(AwC)+FZ&ea!=04 z1Q3rm_f|1~bPU6UR1Z0RtmXKU$CX*Wyj_Dev_3y?w5HcjGk zRl9huBzrW3JlW3)L|a@+b%!drsz{JSbFV`VcJ&cS)aWhrjxj5q-WAUK#|7GrGYq-g zO@=0~nEQbcvKiHQwiq2uoJY!FqAE6NVf!up%V;_5+_MmCFxIpT5#B0?8b;oT6Q@y% zWPJ&+t?6_mI)$s*Z1VA#@MHRL|6{sXqG4C47ViD8z|Jt-*h6p-u^va`0RU;W@S>c; zcYDm}?uenWYm_If!Y4R*c67J!_5)!9POvC)0PZtw{BU z)6lP=n_lDf0wbw!(cWqt{Ph;O2j@)!kPDPqg`b2z(@*0a%szxT zP_JR{;Z>Z1#S4cZcc5lbPd1})lpuFt$M-Y>KU)uNRxXY{hIHU4fs`1nk`|Z|E&}1( zB1xxJ_zkhN+z=*;E|{ZfgK}M_Q|DnF15UVS&4HX}N#=ioI?ow9QREZ@naQsOWXfG5 zR&;`ijOO2&Lu^Ps#p)(ZraW-A;)w|M>n#A?;}@jxx0&(b_^Lxu2yFF2(wPY#6TGsH zw<2o6eQ(wyiC0)}G@DV@>%Mz2NP1a);haSU*tWwaB_07&dM{?@ki$llB#-Q(I#yZZ zGX%g^swjg7#8M+&i)M@anj?s^$y{V#Zgl|08B+Xukm*Z6FOO1OR&-DgNs&2JEOe_b z9KW9qH4ZR564Adm_l}jVsl=xA?~TsBg93`otRRp8OTz^yC0!j3F_y+nN`a4eE;9sx zT0O}f!2#5cyvB*}sGpVAEy|VFojIyXr4!x>s8Cr+Zqd`TJ1LolTn7^L?P<3N(eVhe z0>XQ#@Sj>CTL9-AbUq0Zw^fb(I6yxMJB&uFxjI6%nmrmh zQ>*0L=lwqyf2`Jlxc@}#4WxN959@QG(z(lA3fBN=tFt;>6J<*7=?%Ye0B=Pj z$b-X=9=>DPM*y=zQ)F0e)Bo_)t9`3ES&znmnxpo*gx_h)FLfo< z&+SXj4!{Z5vl+ep!Jzg^Z(s;+#|??!3AX(KTZ6du2$0bcGKhBkQ|$xOijQt)Y`Zzw zWR}V|4{u${BT>gc+0vZsBSt4U8LxL8Zzg)ib@`WPU(ll{#*~jRUo8(`=w|;_W>b*u zv?gnV<31x*qrJ^Qa`!KdohTxwk^BM}IZwx*`a=MLj+ez+R{~Q#QpYH(+);phQ?tl9 z)|7HYm{RuS1#accS(~+el%h6cie9+B34RmCC@$Ped%4vQ6&dQG(%TIVSUQPJXn?x@ z`-w37u%i#y>ld+VJ@X)ag6ub6gwXehY8?@JZXl$dC=}-`#P7-G1juN)sQ%gzCLNMp zzRPp#u$z?`MN8Iqp{_m^Hr_{?Bej}IC(NFSFPAa&XOLi#5`DT zEeZM&nXv0be-vxY6e#fIj~V$Ha_%Px!hm*ptceCePwE61@W)s0*K}Qgq$)4ue z!JbEQ9Gt#t(*sUuPwv-j1-@p4rp>rm>E~ollRlvF@g%gJcr5bHM6F}5^zOAOeK!Tn zc+ogj1jp)6fQ-iB1Wt&iUx5Zr@B~iaO8P#*HSqGQUYN+eBfMT^Q;C_;)-J&Av6fx9 znpU<98VjB~Ft{#3Dl#Jt=}I8aA!E{g;L31^YrwES!B^&58e#T)0Kv%qZ2I#478?S8efz>410xbZ0KN^Pf-W8+Erzq^+XK`dLIAkFxWNu_B9(sWbk#B2@$}r)R!=P%d{fQ0eX{w~`Qd%_);Sda<^Ie7 zklv4q!e#d-Y{D&6ONTN!nSwn(Ps}g;+5x2cdN1);yTqkV^TuI3Qn6eQ)K^N)4EkO(S`A`C0bjkIee2b4%4+l#0 zULPf|Uv$|sI&al3lAB-;8H$(004sOt?%Z<(UUnjL_TAncWG6mf7dc#ZT(E9jMAq%z zSlo>2`*WFJwYcVG(%8~Rv(V?SzG&OBXVlKhZLVKls)#%QwxT|Hj8a4}T+N{LHX_~v11vu^ z5jA|20abDCXUD7_7pk6$J|I+0*TP721~Kz%S7GlC&<_NA<9w4PqyA7*(cgVGl+t|3 zl*T|)Zk0n(*Aee-bsl- zw)G2NRZh^>&J*URFCXP|d=TFrom5#WRHLSBr1RMx=4V)!`7_sNEH_izf3h?^c$@GzkoQ zmHC4HH#)RdfJWS5)%v1BY8xZ3SDFo074TZ$(xh};=A~S#G>Y)J3&Eey%<{xxEV=Y~ zy|N3!5H_Y5ElE2vRVd^WBnV~XiB6bf16~&Ggrm&zw3Nv5rJ+9wb3!PkmBI(Y)bc_x zYZGMB_c~{{m|kX+Wz=SxV|fxRfKh6tkkG`vy+zH7NRz@*0J&E0g?k$Wi9k0HObG)B z8F&&gi%o?@Cya)b+4?6DIMbN-a>3Kr5qOLPES3r_(oG7@uVM{F`e*wkY9%C~%?%on z(V*AZ+zn@2M(e#AM6|}IA5#dhNcQsripqhN#mGd+3s=hvEDb8vibEgrRJIv!?JT9q z_0iJhEY?GWqeUWP<(TbpKc&M;=7f2w4Ba2e=_0h!Q%N_h;H2OB6PJi1t>uLCNm)Z8 z+oSxf`qG+#|4pm}ij=C1{Uis!QxqnnnpKS^q<$0|HX!DU7Ru|E0Kl8|%F1Ts>8Z4_! z-wWxy>`?TcaAle5c=seZ)*hK9UHO5+CB1mNuql#|4rNmwZU>rn_d?e>s>9EnQYQJLge*V(hP&T@uV`l94)IBn8c z7TIcs)k=y~&h2<%hiP-L1?_>oj5-9-@lHcFPiDkz&E93!CdDeMx^zy+49hrPSfpk_ ztn*058P}bl>W!+qnOD_=4#pjdzx393#E%usL1_9Ijn{194&F52=69hU#c|Oz6n^3( zxE<_q?zshu(!;t>yMZ{=f>nA4p99woX4pNTKp#BlI2~ckdrwX`HB8=VNl;}{bQHhr z^YC4*jH4vyAp;cw$k!I^S zrMzXM>ExeRsb4MA&b2e}OtR18RN(bmSPjAg@B%Xg0AUAJ@7Vm1XvUjdDPPAMUrDz2 zAve{Pfh54A*QzEXhUQQM`U!&s54TDl+=9B+o!I=l{1Bgi2;nmc-w(kcRxKm9S)ms< zyWg*BP@MYwaQ7@#aON5~EZti`7j*P@PW7?;b1)jH#A~qkk48TKS?C4~yHwz0$?M+~ zN-=eHE#zv%=4c?^Fc`pT;big)6~HKh;l*;&2?H3^BRQnQ@r4tgIX-*Deh&2&Ek=FB zv=%D<7JbM`aA1-}HGYpeWmDs#P z+r3(1P*xYprI()mA#k2f*V=2L*u z?8P`xfL7%LVOx!gt>+PgQEc)MYr3LVL`rW-&LP|9C(0G-ES)~HCdR5JGtMa+KLG2R zNyhRP2FhzuCiQ^6tf84fdNH&Ze@nldw>mB_7_HnSUe>imSH*i=mG&M&HyPEi_)9W1 zTU~vSpQZIS?F>R_*+(&^0nuPsb)iX;(AyPW$)BU^EKl==mXlsbI94%MA~nBO(3Hn@ zwyZB0kr)Gf1i&D0`dUCUI>XY3R_$Eyq&(=b2)STo{d|=mov6RT?)|t`K0keB7EkyASRR?*SXdB~cKN<+VOpN+(8n~a?*G2a$ghetO+SD+g?yd7 zXq@tJoA8{9eWPrc?wK92ex$QQiSJ6^@;uia%9^+*d;ac^A5#OcND(Vf3A0R{jJ&r_ z(dqP)x7A<0)bG7Cu9LvRBF~LY+7wtbjS?!pT z(SEHZkc;c-^pv|Greb?zI*#Yf7XFgj&pdA+Cx|qb`bvdXGuOo$+33}#eX^!~x}|`Q zF~=a0(xc~#wi(?~xO6~hw?I4_`1&_8C2*<7hSqnxxcs-E=zkFt{T=BlI~qHP*;*S* z+1gq<+x;EvMk;E`VtxZkL}IlU9~3Ic8=EXNfi+h&E|ll`$I3#L!0{nujRGO6Xxog` zt=?5Th%GE;hj{NrS$O&ssD}O9Mp`CZI~@{ zh-f{B!i&`4@3i>E0Cd26$creLN%u-ZNJ7VJzCOMRQ0lIZRM{5Z&kD#)CArLHI|bRD zF0->RkJXfGOgc)pwT{wnL{fcww}`9>G)Yg7Sbej(TC6O6Pmn$fhuyBgr6(v}=4O-C zqNmtgzASQjVAf1Xl86GS^eZ;Y;PnZtU{o}3cH=%u^eT#X7y50SRG1*)QTuX@1r|!w zCEhlXj!A9n;sadf=C-qWw^4hUG-nI%=2Zk!^hmOInzX1UYmE&0Ta6V9*TVgbBF#gC z-vq1SOcZg-!t?@KyzX`4A^Qjd#O(^T5h$P!CNMvIq^~b)OWgcXP@dpTQjW9UMCKYO z*Nwro=gQr}UFWNl?xD)vqT!(LT(QBNue-!vuTzpcqU0_sc5X2H^b$QWmIyGfA_!2s zyh#u{Y)0JZ@H6dWj+?zDg3KnW=&3hD>v#a{`Lp(d(JzNQ=Le}bUgbS-K0?CG<4^|B z&3ofFM17FIo2&2%QrU&#;*n>>m}Y^X(DZaQW5`GJsMw>xh?VhtDY%JodYN$><7G9B z?wR|%laJ{xKm0rb`D05!I|KZaV>pF+pF!1AmI4Wdp$Sz&T%e=HC-H+?&Uz71$w?nc z=1#k+k|{L36ji}d=yC$UNAA4=iNdz5=lwBVGP4hMmqazagZKf~Z zTJZnHO#hjR3EA41n43B~=>IoICoPjn+XC=nL!yE zMa)a6$}WlMAZlHkVszf-JkwgOKS_{V zW79;8n)6d>mhE!XLzCxxUHg+sInw6EWooANT>XnWF;dU(3#NI@swLLdtd_0Xh^Z`h zFDv&!nSE95qx_9a4^mTtb+0wZMcVduxyljSsW%73T94Y``lLennK{bhJ=&_$^YXOd zvaiQ75z)3dQ{fea(m$ptAAp` zpg_;)=-SX$vz)eRPP`somPfKV!}t#~L1+9T_@ugFL5^9H+btT84Eh1{bCdlcTQ{+a zQ+HS7YNu9fI`SkDDuGbMJ^qpJ7Sb-sY1EC4_bYI!V}e#nCjP{PU9a6d3F);M)YhmS4jVGQJ%*721f#$n z%J;7V5zG!a@GtuJT}_FY0%*p3;Fd~I@lkxog48P@1$g{;iI@uLx*Xt^e9)0m{AlsJ z0yr^wUnvR!1;$}V5;0|%xHy3%@%mY?0%Cp(iI@gx1y#S}Zx|GGolM%2H~%Q05$F8+ z2h{&8HtYpX>*9VF8L+>fzf?(oPn)3m=LiX!f6RZd`=$fa+WmhF7b^16DG6y>iY93~ z38@kB1?kC=eM-s+s*!Q&Mv#9I1U>xQ(2H-1!as&y{Bxj%p_Tdnm{9T8>!LFz=W*XV zE#q51^l$jZzg`!zwYL5S$Vi#n7|ZE9e4h!#vUY#%G{tXrm5u4&$3mjwg$&X+v1ksi zDWOq&G?_fjPkEKbm|~YKWDpaH=m!!s=oid|T9TD(`o_R<{xk4rqA>nUKiG9{gliF% z;2Q9=pcB)z0 zvv#_DKtb$J>Ci2WJfE?eu&(KgCdX?wj;Z?HmcdO&arFjmF3qF#n&&)A=@ixs#1=Y2 z^hQfosufp%Tmrt5uGj@#Zco=&b~|bI$Wy^xFMI{In;nd?PM>xhrdRkN`3?s30Ch}x(x#a zEuqc2^JbT&{XC!ZV^%gt#ehWXVSv8z&;}OBZEfJc*0_l~eS?&?^?3WG-QI98J>*F_ zE*TP~kIw0U9(x!YMGbABQ)=c`VTeHmjkHmieYGYd^vs#1r#u8B#ZVI#b(S)FosjE5 zaSA>7^@_#inTN|bp25fDG4_+gCO;kL1Xl1exQB~t-5CAMv8C|oe$>56VQV1Le9*qXNlU5%lOC{_|ze;cakm*5(& zh(wTof@uRb!3RqG7i-X@l^53zGrnc5{(#Wce54!w3vyl-YNZ36Ij+DJXmmCp8JC_= z*o5ddOq^(MZt6jcVLxo^cA8&$CJ`CaG(FA)e_uq}?|YkE-{#m}>-7_Tk=@o*bJG;* z@>zy)O3nU));RQyOCGJCm~7^Ov9JHK;r=plT{zy^{BIMd0Q-M5aRHNW{q)~saCbQ=VTJ>&GDNF~#w;zQu90>A05N)%gJ+Hy8$rGKX20azZAq%1}-a=?+7R zs+6Ei&A5O1tA2#1eAkV&&ust=rksqRfG zk)Y#L6PQk{@71N=B)qu&FwVGncd145pf}dTND53-CY-?M$XG9Y$QE$usi5`Hy-Cg4 zz1%q70yhFX9D|gAboY$n%pkt2dIjqTn!wsHJ)^e!z?Q?@fll8#c)%WuiU})*f)=xp zgLXVLP$!yDNpmm#eA1e{Ib#kct7nX7zXWYwIL*^m^zGEkX6w~QDe03csH^8f5;h&K z_<%AfeZ_Y-MEuA>4N5{L$O|Qt6t*#hf76a_c@*#Qz>wI80@6dgydIB@l2$WbKlC7Z_dwaqO5QG#0#7IR9Qj z0gtN!dY@!Hj3EJ5h+wQVh9RgPVGp4)=a}3}^tC0|M?}J8`RN3p1_MyidI`1${zsux z6mj7GT{C*_l?aPvoQ2mMvAdJos zbDN>-w5>o=GOnV^M6*eRWu#{q6H+NkJbJ}gzn$L#rHKtT1N#; zD3AmH!!PDrATE^ivsPJDDOOAUaQ3a^1FHSL@}Ll|L9w@B-08Jn$n=%$RcQ5>sEW}_ zon%pb=w#MH)`qQX7tbx8&$qMkO}??l=AtJt?x`SBn zr@3*H99)A~527>_5aErQJT3K$VJ7GxD#&xA9?TiC6D8k@?13*Mv0p@nlN1pj^h7i& z-#<=LPnu@=CE8JbNEv0bU&L&xCODL!!>n9vV2Sv+*o9MS1G7MVScI*~7T!nZE+~It zU@Xp*c>+d)y9!@}$ujSdN}7)8OoU<2C_g>wuIbt%CKj}zs6H*xl%yIsQelxkFA;KP z(pkr!xh%#8-fE_qI9qW^Ey2DHzFHUFl2?feO_R)azh2VVP>>dAzcEj`F>Hf4gRn85 z8IP!N0uaF4D$aP-ipo5J&V0s*GN82>TmX4P zwfqvHm4Q4>_G2@VJ~w4Q4upr$jjZVh&M=FJ*l3zXMRCfLs=uQl5HZdao9zz z=riLcu7$ic$VdGyKiTV2KOn(Z=}^%5JZDkSM%Cw=MFe6laZRF zY|L9v!M3RqggNcg;6ljI;H4#bU-SjP979ekDsUWSNs@_z9=$npa~>OcA*OJ@o{FB7 zfQyrvuevA>6=f1aR7h+BSjU*k{3Lz&_?!Z$vBji{HcXehyEgx=SMoSNW4-)l%luAh z_=&BjyX*|R1E9^(Do1HZ+E*9#UxOrw?lHFn7QaNf2({>pvjj)Eh1S*;8~6l>@0b>O z1R9EB>#0J-n;q;xa1e0~umYR=??OYz=|Z5Z_|5yy^S|kip_{9*dya4hUY7-5$gR`i zxQBJ=YC)j~+=UDp?ZV;EG(oZ3SE(P|sfX#Rb}7#xkfQX!&9gGtB)5hMC{@Z6_I%Z< z6qz~67AhQ<0TY}*E@~}f9K*>I-qv%J$2=p9SiEmmY;EUS1vn^tMmWfH24lMih`mL_2&Y5Nx2;t_6(0Ut{)4CSoN9e~zL<` zA`U^;-rRI+foNa?vPQmGRU%W>jYx+VzfcRPEb+3eusNWKWtuzky62TR%c9!)`7del zUtXQjO0`MiJCXtZ_Ut168QcG7ur8$UX#6b-Ft%|tclze1{~fh|zh4Yie=aNT<5VQ6_CnoCppyOO$BCV**PnGbv_ zS;rj4IKBrxfU9*-r^Sx)M_Gj;y|oWh~rW{N2@sZO&yRr3a+$17c&xF?FjPi z?Xwgcc;X<$2;-st^$DO-$f03XLOV{8u#5|~*EJ1|9Rn}o3ek|t;tL;L#{gRVg~TYpVs z8Bx&2g9U??Nc7?IMFh@Ld@FC?V;EQgSei}_M%dZ0IHEr<+h`sfJ#3Y8UZyx#I5iAj z=&9;8-M*cXx%4T%>@MfaA+|5fer`5|I66r*I1X8Q^#UC{*Xm0||D@F0&59pIH3D}a zu`E#^6MYLtoyt)vLiuBpJUG>XeLS~}E4@9`AB3@vyfoLmG+TsxyqLWhFA(s$sq&(>_O^xDWNe36o0Uz<@OCmRMcv<E&}=w2K4{^TmKHb{{HZ9Vw02cKXYjX?Y|h%JoW1JF4EEsX}hiw6e1Kh z$hyRYX8g#0kg?p)tl~iz!zL;wWF%ktT?Mj%yw5Ut%J@>m1Z*-jLJN%LH{5;0Sk3fBsOE*a|v$U$q1(on5-Yj zr(2p|?G;#djs)oMJdO;jZP;gmZ!oS;SFblJ2(l4o5&Mx3O{fJ6l(^F&3b4g}!&#qN zPFHyITSvKKIs3dS$mb75peI^jc@i)VH}6Z8pGYOUP#z3_YWR1`1?}XmdhKty!`q{P z(&QIHo+(mI2KQ>+>?GmA1D$>T-Wpg1Z|ueUG%kX1Ta-FD18P?M{3;gyABjK zNK$m}VJ|~CrU)zw1@4%=D$^tDXt!Q)hta~kIAbQGkH(AYlS>n}ka+aco+k$yni8t= zw1NZ}F_=91^t_1w_FqXb^8We_hkPUg{QL~w+`vj*&>SL5L95R(kT-!w?PyH>OYk^i zV5MsyoTyifJ5r@KDXFsf9mWD~)cDv+fAS%gj2iwIsj&XzzbLc*GW2i(7Avps#fSP{ ze9r%L%ikoui=X~3U%GsAdjAX8l^G`~+sls}I0XVM?8PV7mv`O`jEUsD zMyt%1o0)IN=p0w6vrfTULAf?!v@eN}p=)winuCh^IVw=>EDJ^-hf?yXc>xD6nZB7fbS9+$yq z*b=6<#|Jjjj@>`g6-=Xci(QG{^pXz~L+)O`Xfi$3Iw4~6g2z8=TnG|Gu^!102dW6Q z_(y&?k{84ngI4s;y~e3MD2=z!obIs%U|QDCvCv}+z_iq#R1hUEu4JVTaR1YJkpYWA zV|=fv>0gC||6J4meF-Dwr6v3L;l1Y;2j{EH$fgLHAw{aCDa7QF0U;qa|D3d1iL=#h zBz&^MeFFF-G)w0K#|xq*WxCg2eWSyUp3bnkc_wk3a54}xh!vr#U~;#himiIy6DW4N z(5qJ14+J1Qab(>M0IMMpIHSh`d@xf>Tl|^)u*7pyMp($!7a-sy)QlRG2+=|9vE3dK zvpn^S0_m933)W>7PP!O)j^gE6(-~MG3Rhd|&u|J@JF7AWgOPu(siGK!DwrL2dy?IQ z+ILxSS7a(A9B}T)GB&=Vk+jTsKxl1MsRfK(Or}={T>3!uPPpv)qrOB?)vqX}^PA~8 zr_l%^(WGCjR2bi|Vq>w?=qjzJNerpL+Nt$h?t>2vc;5aCo9VAT<3_rxr1yOZh50>n zm+L?OUjc)^cy|A9o2F7l(-rd@Y7Gl5#h7~Nm&-z0DGrSS2vgZ)PQxrQH?KGHvozG4 z%EcEV71_kjBt-bj|ElW1Q}+zYT1!$j`vd0_);aq(zEMq~dhf2*%eP%?o@de-hgh*mWT= zToY&wPk_DG02x=iJN_=g)|XiS5}^b1XF-wWBceYW_KE>~Qe@sJecX(bbBD@E`Jp$7 zE~z-aA#%cPl7WTSCL-ixmI;H_6uJq84r8K$dL-JY26y5gD@BUs^dfm>X-&mS<9r4A zdqTE0t79-?r3v6ZHE|vl&h?Vjv|Of$V4_s-1OCutln&&n)uN(gG3VYw579=H$_iAB zB997n5JgLMY-;q^DwVQSU=Cznh$f)bA_I+paHO4TPQ##;rL*{^8HaCm5GmsaplC^0nUPk=!qzhg~-|5Xx%VK4kQ=gM$Qgc_Lhk!L9 z@(qkJTX~|>fJ@!m9@gDT@!Bv&Pt_yL@JdVUmMWAB;V!ED=xMUMVX3BVRaFZR&XH^l&w+vp6YHI3|0&17<=CrvWM=KX=aG z#gv-Jk682uV@4-=_`wA`7WH>y0@dYO>T_>l^rFF0Gj^-&IoFC4j%I0Kk~oRkdl>?4{3X{BHZ{ zsDi;+VA)Pm7$NywT=+iP`rwZB7c#}46qh?s^NP?GUI%G~YS2*3KZ)nf-Xd!}U9$&F zrps=Gq#xbLPn@R6IM6Ri&`gfM1~{&x!3S-58n33QWq3BEpAWPBKLml`NJ}5Mdhv_8 zuPXC>@0tO?0qJ05_~uSc-DNqi^s9^;Bvy4!=|sG{dg}KwZM)Mq5K55hV4fEZV4jx@ zm{G9Mmp_**0RS80ft|uSj}Qo>v3s26G?0EXLC!?SZh|Z4&|jFeyTzbBeUiC9DQ1T| zbiqKg;^XLt=zq*27zJh52>LTY)9tiSNP+*}0Tn^@7TB6X51(~L>;2Ne8(t==YaqiuQgTM|{=A#)H=+-937xGO!M;x;h{ z;Ycr$+97?`i}?|84+c2Czyi1iuy!QpQL zL&!(q!FO^ALkJ5Cm60_9>-3h0759#fg3_cCbgy-_#89Fs(SG@UZ4WN>Mq;tG*0l4a zLLvx~*zX)}Uamc5bb4P-?0;PSxdPa?*A#%>gXE;25h%}~kMG?d=t=N19~ZV~3A2QD zSlP?M9l#cPM{pf$Z6gJQJ_TA^+%OJL9`i`mHyE&w%-FfjD?EZsO4W3cAhAJHmC~%< z6*=9$gC@AdgdRyWeFvFRUuSi&%(7es#TkGKRtwt6ALo^=jmpN41({>*_zBA6ol(mn z;5lHrh|xPH6B~AhN>QFTTXe~Ln4Uzdvya@|IH|38?ytA(X%Qy|Bzu0;bT|8}`5-mw zBRPX6!45GcYs>g}(_2T!AyPv8503&{=1NYDp<>Wk<>}gHT#P4UruiS)FhjiAP4gU^ zwFm~CJtBwE%{nIr12**T>r+1F8h4jX+qwoG3Mriw3jHDs5se>nV~ZJKn$uUQc^{>Q z97wy7lpZr=aok5mF5KOzSke=O8eF$m-J!oI2n#UR7vDl0S$Kh2Ze zB8cUAGuM7JP|eUvb?O>|#Wd9N1T>uE_O3qT?&EOA#1N+YNilsQFunl?dW*2V`SCuY z6dy~KBkBQ|0{D>78huJ=QM^#eONHc_+S4|3O6nMi?<_TX5)$@yzO-9BFmD^PNB01v zLdDcIMGvPFZC^R-wSac=k1F*z?ia>)^Lg2orOA25MudNcr=VZ?n#4Nvqd-_E&#(S8 z!;^QoCCDdKTbAu#scwx!R8~0^qoW1W!YaT&2~S~7!r=p0<4{-t!{bw&C{;%3OXNR7 z7XivN6noxVR z*iB3(?)QjPN-BVSN!~o=gM4|Op0{dgrOHq75c!JAD+B9t?+sq7tBZ$C%{5P3&ovKA z&6BRj)YNe)SklM6y>lMV>W;U-FkPUhO280U*CeLAU&%#Y?7=|h}HCraHxGB4bMd$F7-HznMY zM}FM2`%L>x8heD9u-E8#(F^9>(R0hybHun;drSvUz%NqBVd9+HeevE})I_EureP6M z4>!zaBXizfO@mBMko4jEh>?=cWd@J-sSO9W5W``RFG`U9lsjCCy!FDejW#a0*?o@t zia9r0nW&D9gLh6EqjxMiIrfnXvbaz)iIktF?BOU&)f>5&sc0?E-4XOR);KwuOz+J$-9;; zyh>$M!S|fC@H-xM!+h@nF?A33NLQ9XGd0}v?^$2m>eY@MGXGqoaHh8}3{B)gywBv- z4^;Bn#E-Z{`b+g2Re%RqnrRP53{;@cr6_0K=n=1@M}ziRJI6-JFj))|$w&TSkgj4f zTnw`thaB>|*_NS7524u7$?UY@nroKqTkDI}*7tO1#E4X%8EnS*!wf61J5Zc@rblUq z4$FkH0A|P#(qw9xZ*2kTS!x}rDeuW#WFKJOfXTs!9yx&3)+AUB%d`#%I##hLHb08F z)XZe;yQ*z6KN=IxJv@fq{VUSRk|DF!;$an~9J7geevxjguGQsY^&pv<{zcV>$u&(` z`$n&X(xOqltz0GD-V8-&n3>Xms;z=+#83&-xnl()ZGBKrb2-BGXKmj>YJK>5HUZPR ziZPQ~Gb5sPxkY#y4MBMs2XckPxwSF9)ygQX7GM^L2|4nLGTyp%Bk}k^KUNJ8OV$qE zIC7I(rhNH|Ql~F6IULq%oqsGPO9L-vKfPKugR~$;SyC2SM5?9`D)pr{GBntpWQrC^ z;aSSMb1bSPD^w$9D`%6&Ors#UJQdM|iCHEF%;;5r4%a4b0Hz|ZzHO7Ku$Q<*b$|pR z9iL~+$Q*@a%3-1vw$;F_m3)|wWE#KSuqEy@L=UVLK<1b$o92jbKki|2fqbPeXs4-l#TcsToBj}~h@98k&Jyq(foKD{W6QqgWRWZS)F=SYd9`oUv zh7hGUfkiqg7*iW0`=!(l2CzSz);g+CNbWiu_lrzyJfuuztz7Z32m3I=1#t=L99FCP z?vA(opn$&-W0A{Y;P&?#;shcx0CiL&R0ujWgR#bCtkzAKAzfRARM4db99gZr99~Is zNKmK&G5yv08D}bI!VG&jQi;NYf^|KL^(G4$>S1K=i#>~)>X8s^Oi>WGLX7b5kHs1W z!bszXaZwrpY%51mMq=NY8&yCJ^GYq-7GRc_&4XI;=M4k*bLbnq$~& z_PCrLir?dWY7&D-XeuGL_SPmwu1iZC$`oAvQNhhl+COq4)?{(UN{_Iv7+;$}RcG9d z!a$`w?Dof{u_;V;5C*Y9Y9gdrg#wRp>gh*N_^6SgWTq=|eBb(f@#L`*<*A8dJxaKA zI+r8q+^9SI z&0{%z?MQeYa=cFf@L;TNxfqs1r1ra9$K+71=Iv|SHl4FM!6ytwySY*R0_U-Vn7YQ- zxSLead_>vhsb#_3kJx7#>fVuqZ_u4d)pKrLJ=q6mFrV0402yOZH2${xKq3BNkp6sA zY~RgW6wDo`sOoHc=p`k~ZZEqN2cTQMV9=e3U3%Bn??3%*kGKHLNF)slA;Ja{jX}3Y zzygnH{jUy%0IXT)<`^Y|`_0`$Yr`fIjm5^8*`-y|$MR>y=C}Lu?w5Piv7j5p1eqS4 z;e1B6JzseJuh4|JyIs-W@%fCd`@Dv?>E?JqzlSSYc=c~rga5GtgB@k{$J?tW1tLW1 zBKg&sxwG9UKj!D3Y64U5`+q9?3aG5Mt!=uM?nXMK8>G8LI;Fe2yE~-2yO9RzkZzz( z^TnHpq)ZrezAlLnrC9@)tyIpR&4kwVM-O9up8*P_ZjS*J)Yyc^q7M;)*=P9>G}_># zFUH69#MmZ#Lso1^v@B|>A#aRLrAl9si6omRD=&uihB|_89P}_!8pvbW!7de_3_^VA ztT4Gx*6Y5I#10&&VncdukIpL6Y0Zcckezm5fUyt^krJA+uvTT@rwn&OQ7vDiFT65BKz^Ppi@l}-HpogVwp?onP0FD7E00*j7P){h67|<3xG_fk+rHoe z)oe==omT5hH)-C+mjz!$UO|S)oC(uAI$3e-4Cpl6q&`@6pj*G?C#=z zpnYiBjp!+h;Dd+0v~ID=EFI-2R8Zk@8Kd#^ZQ3%-Li@^Hfr-2y17ozY+Ei(0mBd2? z+SJaAdcVq4o_lVWm-EErU$VnAbJH7{bkIfa7tkgSh}%ui%SC-X19BlxXRQxeYhXru zK>3l)38i7tq8F=l$@(JGw`m+#kw-Y;69?+b4X(kJVq>ew#=wG}Y_NbzGv6|qgI!XV zG8*5627xktzsXaJ6jSQ>@WJ}xqVnvFGEsJ@xFTEp`Wxb%$-2r8ZP=%wgN2hc13msk z43*Z|A)H=Y-kF*}G`M=@=1qcQ;0h}iQ04lOn9c%9t<+jH`~j}R=+LZ!onnw% zRA0Zd#D{v6vlI=DID~K)v`d4+Doiw5rN2p>&yFr1x!{XdOMLz6^gE$7tM1N_jGz%( zHSwr8^R|EG{QDi`Rmk0JU4f!NU!O3XdVDQm1ENgxv9nTTTc$*}gCC#B!fsx(VCKiQ zERXvUgRtHy#a>)ay?}ll6}H=&v6&t6Izb@?viSt9hT1p3J&OrEL1d(P}P>g6SS3wKDoY=ePnB-TE8M6Tc3|ON;o#9 zZyfJ3QsHqF2h(1t%!&>q6p8m-Fc?eh2jXKaf~_n>ryMzI>rgm2EQn&YQPalWl0XST{;q7uR#m~L2L64VbGii{A2>X zp=nx9q0Qje$jN>@tPA;&GNs*m%5VjX5QVqg{E<43P`A|w6{}BO=NOHCML!76M?tY2 zc{W)u&mK1Qt5AT`oJ8--jXUi9G`{3e{Z#j02 zCF8#`DPV}VPIjN(3C+!Pg0OitnM2vRotIIJa zgni%+JE8ZxSKnz5vua9OS@aRf4WP=lX78^z+xW|9Im@OO~`oe0_2+dd2SOp%zvns0l z8291AaYmIr=y;cq&BcI+Mz`-%gCa&0b^~Hctn{9K`S5uO2)keP&#)rgxN5Qkw;+kr z)hW{>J^-zRGexkB%Xd4`Xh@@vqp3 zuqI+m%M-EEXN1oqGka1}o3WCQeGS?a?J2{0hQF)$NVU|9KY73&^N4iEEm~=z*QK;; zdc7V#*oj)*p=@8mL(0sSZ?RXIq@!zzzB~&YU7wmN%94sg+;cKc*W#o z=47UC>r7zU1MrLs(ihVkb{7b4__#C9%5HkG3miuV_;FXT+qIeYFG3c$BJt9jA7$~m zAycl%=!IpuGos5_x?8;-p`Ic({PFe~C33G>Z>pv+dAu*Gr2LEqAVt3#%#e23Gq zrd3|tZr8z&c_2vvZ_a8AsFL!*ZmrF1Ysp#{{JfxWKyixFh|e#M=4>$Q1Uj%-Jka5Q zzBP9HfY*IQ3*ufIRFu^TfsCaV-5%59L+6dBYV&>SP9Kz>9ejqAAPK%M39NZYQ0*0M zsW<*i*C_TX>$oHGJu|emmaC8mu_tngdiyETEt=7yJn!UM23chnbEZ?0X2+ZkZ~665 z9vg9$Eplsd2&yKf7vmB>w}fVz+_*(h55_*z&}VEu<-DrH53!oH9XeAl5< z2_Bj;d)xT92$oUSXhK8eEfMdM)J}$Q`N&N78JmBG zTqBfti`$aR_*pMaIV*CeWK;Y)$-8rKk@me@EQrxmQ#f}mBDN}m=%FEU-3PF-1$C#! zRtgyi=UC2;aZRT^QoptM0y#n_5)cVqQgrBj5ts!2=5L~_(@?O;#@NEihy2On@k{V! z(gf#^;J}x*e&csg2`hwt@A${uB*|0?>Vbk+*4$iDw#OWA)Nk=-$FCa0m)A7T->!)B zd{^4(yXScDlkt&2T7I3a!$zScGz*kSqGwBZNACjL!YukFtxdr44cAJ6F;FuZ{T-*@ z<<(Tk^w!_>Q~?%STY}st>MPzAR3N7DX7iR(ixmNz3JKD z&dqyEI~aVsonVv&sWBy^)ShI}>MC|)`kh9-rn)q;E+3tgiCZ>t%83*&e-UWpe(M65 zeP1IRkD*ZD=d)|i$#dB{`B3t5Iw6O|cyr3&N18AjSVlnL9sQip=tiL!|DDk% z43TO26kj+5qftK33LgjbeYZRx2iDhqh?M0^Y_AIPG9LtC=4FU8AJDFqY>3EK0wr&b zx_6cR6}jG^Iq;+_7%CN{h2q`fYX|i_Nqlis-v9b`A`ShiL)K>GnD`0*VO*OYUVvf$ zqF}15P<0p~oX6MU{5^{D;X8hdSw?w93{L42L-O<5VnT=zKa=nMT<4Fa#O^_*Xkj=) z8Vwb}I_TL;;hbu$^8n+TfGg@ex6zePpW&Eh*?oiWWutu)+JQYrhMxn^{AhM7-kFdQ zPv9j)Eo+nQ4$%Cl?;~j~tFHy_*g3A{A!p=pRP^Wn|5tb(ym@|{Y&S9E3unGuZtUZn5({7mpen7x8>jswuE7Y-8?t6rO0WuP za7Tu~ARPO!I798iVy`ZddmSI=9{Ab1jCm6)c;;P~^{!cu7rl;&#aGe}X4nYF+dDsl zh+2rNLmlhG!nLVdjmNDvaLLw5x>xlQtNiZPr~1NK4cnodF3uxn7${H|%GRedsFD*I zSe&^FkhKEPor1TeiSZayX1-Uz4Bg8}%8s$dQi*K}?Bk1?i(Z|j-_^b`G#^AyC0aCr zH1C~tO;;|;Lz`kcN4r^rl+0ZvA6)(rQU5?QrufASw?x>^F>-52O;dHns>Bg~;WXPrVLbXecIH#W z8z81lgqw1tck0^oZfMu8kRCHvBlmrI*7zfi9!_PC8JZtPorF4sS|}?$2z$yuMF;(0 zxtIgZX)0c2zV}a<1!u{f#*Dz4jjh9blhHkGK;!~iA?hU8p+3SOmLo$PV4U7wBE{K#56T;OjBTnF0ry!Bx}=4>@8VDwD-pvG&W$$d z48zf)-Kh0@3b&3I1t3zE4b9yJJU&?WubQIBzi z#+&HJWSv)}WY@FmDIYm`@)}uIOY$W^Q^T+6Wvr@bO%<6aVugzHh;f*ZS+)^$$|WH0 zl=HvJ>*&0jFk5psKFqv1a`BOaBQDCQn+sTlD}?d{gC!)kK|Gbe%n2ua z9r_$mitMZMyGtGXRX#JvV92V?JiP9@K(3%N+BZKgH{>v}Ng~^LIKo2$D~(@&wbIky zaW2Jr8=mgZWc6BUDD$+Z*SJ&~U*t3r`mJSZPcjl*bmr#*#`?K_JOmj&B$?QYf-03% zz62+<*7Z_HU;DPpp;xyj#&A*QAdptJS{n!|G8-%=ViHbR3bBO-?lsC}bir}9$~;3O zOI9387nE&nTE%DYdu-D=deBh{k-119#5uU~GL5dq(}(&g3|pKiLU~fxzL1#bI(gxU zNu%lS_lr&GtL(UzHD%5!9zWu++^Vu(+?e5KkK1G6UwV!DOXpg8=yQN5p+>Y*FCn|8 z7@Qy~stL7E`xsQ1-eRW|$lC5bc;4uk&}RB(#@Nnr1#*b@-HLWGWmB7Dg-4U(8}R$& z^R>`Cw%MbZtH7}2qSjuWNd=W}Ox-;ZzfXtnv`2vmf>nN_nP1u}TIGpaA394%sM%+I z0zul7;-uW-AG>a@j+Ahm?gaUSc=Un#@sPbGbkQ@_#v!pf8|6w1*`kLp<^d0UjZrh; z$(ORHFZ#^4-EJJ?T4fPJ7P?r32C7P`n)tO&ZBuKBK}G3;mIz8O3^C9 zbp3Ir@_TKVbv}QJF<%%tt3V}fxNxnhACLhBYjp4SNL1MC)-cNb!y+fIkO?2L_c8R{ zp)Cq%DZ7+qRw}%oj5!1P_)ni+tPo;>IFo+*ecc0&gW3POLU@^p{gatO{RqwnfZ|gyZzCl(9l27zTfpo#+!^LMkbx)Ulv#LfyHkRL?SarDB|l@ zNo716eHu<}Z1HSq18xU4OCW#`Co)6HQt=xGF+_RO#E~k;|YeqO7)$qo29eD1nY&0kVW~iuI`$|Z=ep`T4`o+!3R^2lEmr-v zm0%Kz)UU4Pm7NB%LoU92G7top&jb3-j*gyOvcEN)(I_C}eC`C?lM$$qgaI|vdylD%Gyl|+dg zXM0D>3s`1Ci&JjtR=w6orLy(?N=4rWGYxh~Y?a@3UhBp3B`b;6js|>~I-9e|2=M3I zY*m=zcc%NQPhkJ;_9a{gb;S*Eb*k9sI5;I&9o!eGL zXj(#{Acv-xlZjznji2xuG>_Oo>U=6%b-p%BnoaKET2M{ffgMGMkSo>7K80|;QF}% zJWZsSlru4$R8u^?ewU;l*#VT6rv5Qu#RJN0L-i9P9FBm8j;ALlmHe9vSM@Gp`#2PRf@Z$*ja0H`i`RBfx zeDSCEf)ykq2OU0N-y0QNNLK_F{Q*wHu^QH4XsLpKP{=UV?I zE&NZPo7l7#)E2-bO8|&_p#JMb`>&y>_siJ)HKy&SXa&H*=CQ7x=71SLZqV5d;eZmlF)}A{+2Eydov&;MT|N($}7E>hMLq`&Eu%Bf$GcE_v+mB zwh%}dB-bG`YbCz?>cPvzxqZ(^Z-UNG z8yvL2LT1BC&6Fd8T1hD9DRRslG9##*DVU>(VJg z<&OP{fx4exjuOwr2`q*St5eLme4K%MoXOeC4qCNSw~1>>n)%a-V3!<)(dARGbAZ0C zYr_Ob+u55k`uc=Mg0@|?o@X9%-DBHr!iRE$xs5R$(UW`9#V3Bpyb zGqsK1^*O2p(}o813!#VCvMzC5^&VjiPv}PkPJVbycl-c3vb7z=3B-G!%OVZyL?$1T zBKe$*>%Jm>JY?MIg!$<{3cQn&A9gWM>oFIfsMjD1IAb=nZN{Q-dPwO}Rh@(pjg?}F z&qQ{@SM43CwxUSc-?Y8Q$37icVlr^Uv@;aw{XkBIeZCsw16o)GuXnGT(0lVb{99cI zJAT~Li#TRACyT^S0E0vy;%|Lt{xS;wj3`k0=83I@`Y626KOtD9&=;{psxZkGug@Mp zJmypsxlB93PvrY(jLsg6>HVX9vVPy0=+-1TcUa4+mgCdoFsPK zB)HmW@GJ+eBm52wz5y~Q*yuUW)Y;|qrxk_n#c(KpzL;38RmF=QV<=zsU zQDjM9j5);jZF~PGV^qk{cvW&^-!l^TW9#W+BY$XHYguL(xu&c%8|sKKM0SO`+7N@e zL&d!D>rw-`&5qtQAm7(fc{IrqsvVHx#!6-qxb-2^LhH6UpI;k_S3vEwV%M>BM1=1J zSVW5L49!raRx(R)f1D7$9T5$ZOazy58a*~B4&7${0evFH@A5TONy1QG0^QWIre`yi z)Q>+_3YyTp!tavf2uHWh_$1|n!?hh~T+|ZfQdrmd$o@AcQc+GF+MPI{B~rJ&uLj|l zmjnUCc1#nM>gBT5Y`mW5hljznVPN{Y5{5#(>vbwr*Oz7=-y?mJPyjfmhj-={!Djo$ z;@dGOo)C2Ov>2j|p|7oTtGs%L9$)k7<&B`N!UWhhcv z?WevPC{SyecZeLzVk)7w_&VylDRo>O zyMyzz!;|P8Zm}}fF)O0nL-E9)AhUD}AL`%BcZ?p}LPNG%v!(79eP;|uk8YlIQVVW{ zXqVfjt&Tz+TK(jMdheq&N-F2;DD*C8HQ^dHP`JW}LXs*G=;nc0QU6}JgN(jlwf-7c z#Ca)9s{m#C!*EHC(iU@MU|P9M(sH`EWiQ=klzY6A z;qNT;WQ3`x_R$vUvZ-B7j-RXKv6Ax-ze=zk*(lrG4n?U!rj_B+rwVP*IR+C8`lS6B zO|OFxI2;W#e}(y-UPR4_-|8_V#elS^98Q(43 z*X*o>9lo@<-E?f)w&K$ZOIr)(M#@vRpH1(QO7M&)gtd#^l{IQY= znWvyg6dEo(w6D7VF=6?)oyS{(*+7=kpBIG0H}Ap-zjk>sdC}<|w!}1pQ#fL0HL5|a z@cQX|(%FajZci^=<*&025%XaBo>+2wwo*4vgP%@5@&Bieh<& z9T~p6(g)wsg=$n*VbiXAwD`ekl8WVUS*HSj6J65|BMc}Q4;4A4f9y*nS!attu#CAz zcKYOi*V&g=LC6Ojv5v7S8i^>>3H=pj8o!beHyZM*xSN zctD6ar(DL+WUg`)=Jvp( zB!AFO-wBv8>?|U6?Z`D)MqW4HKBAisClQ}{<6}yHD(XJNEhNA4g|Q?XOlO)1P9Mi2 zXdANm&=tlSaq1n=oDfZ-6$E-bM4P!&kLpI6a(uADf6Sex=1+BaLD(PQcI=J0$?uJr1*36(SB()a<6 zMAJd@9yQy~Kf*|WqnTB3TeaZKvuk8wCrRQclx=#E7UmMo%VerADm?n`enviCA`tpxN1CEOmlK z(fSwaD^cwX5_caoKu}lsz=itw=zx|4m|DONEmrk~KWQu{8M!mjR~}k^g;teJr7W0; z$)F*+c5vXF6t&5P?%PID#TD=V7J6N3c=u}b^1Y|I!|g?ESqXj#-cNgIe^^$W$efwGJ9qsku!8*D797R5u>lZ~yfwn<`h#VpT5=h$<&;Q z54}u+HU{)htpvJ3US6a=wDi(U9a=t0@TE!2OL7xvE3_>qz1R-~nxffnPCDUN0~yi_ zXl$`1dgDnC*kwj<(q?P_mF7Fs4;7XEyF#~YP%IP4bO|L=V!WXc#jqefb`LW|&%FIB z2|@Zky7Rf%46B9lgI5X79KM&lP)nMOjT<|!yVSo`m-G}5Q{`(e(uc1nE0kEvQeg96 zJ&;E5##4L^A%wd^>*BA&=e39>tTs>}&)_p|Xj594IVf;j$c%VpjG$twpsNjzOPj~v|q+XjJR)?*F11Z{(A zZrZTD&pH+PunB}q!&#Z#NdSNgdCVe2k(ptT}V&&fwJ7z$U5(G1Nw3F z@JL4;F|>}ds^Qth40GDprK7=QVw8nvjl;ml@_>rJ!`chBF+0J0|KMr1PW~#whmq}v zwUGqKh(L%8CPC7Zw-qj^e-X#0Bl89sytfC~ELH`7ZkT`1DZ4(t4nhl7oy+}n+# z>8_WL7e|(~K)Kc*dsT+gvJEtaF>G-#F_F;psaI8jBpOCef)lB2OQGgoVKOMP&p=d; zSj+W7yo;j`l8Q(TL#Sgr#i_@u?x_qHdKw1@A=?ZqFSszEvHhWC>OqzYGG8b zP*Sdf$xjPdFw)YO%D8lW6k*$1Vo^6RN#XmN+>F(QsXb>hC7x_ALZdK%^fgKUb5ogW zQzC14Oy(eh=J;Vsd|kepee)POvpWMhc0iWOw_?=_Q?QgXV$6fRAZaXeeBS1uNoTYG zzDe@AV*PFWZ%xKlZX{RnxiX5*=Uwcd! zL+x_hkJmHeas_{Xy$GJX1urGn3Sq&HXA(=f5@xN=(wGP*;tdQ3zamcQTqDi7yXDI8 zCb`zg05iLFUpETYpo>y2IS2>muw4?i5jC|d$VaOkOauQ65-qNa0GWQWd9?K$TN%ELe>BiI$)xeb0+_FObhv?k$-^L(}|Uh0lP@ZPJi zYK5>WX5u*x1~cE~Q1-w_{RHLEwg6~JBy;-Y>}Yu4eS!cmT=!4k#dNSfAP}oGIX7^X ziB8#y&^Tl&ezEF8OQWMlpMdG2m)K)8v>OJ~snJLREA|j=+jc%D%Kcg8QQs8`CKmiUmECrm z&5Cw*Z2*VS4|D8{4CLY`WT{Hm z4u7nMBktDg@TA0e3vzf^6(0ppWR^=cDOgwM{T!n#p*gjD?!&_suZY|2Ljs}}Wsg(8 zvYz23@^~{}SBy|2t9)83eMBFXwJ%hl56X1sP)^W}b2iGS!cof)z#G_95N3}CwXt9O ztI}mal*>U#8TsfTD61rS=Tr5Kb_^&kaJOdF=u+s1gpp#}yXUbEy)mqC;dNF6$pt<} zh|KOMR}CMT8*s`Ek$Y1c^$&}!OT_o)mL+{ZMaej4&R|NA1r(8r{BSESuj z%bpW(M~z=2NO*_--`%REREpuJ5~(l1^!SgwK>k>j{a$G$O@8!Wwn&2}eQoos(;ThO zKB`&o^(Y8L#e;H#p{o#);ewa*5Axwu90m^KuPfRIQXpMVK!QnoYdk-l3_FzZo0_oM zEvH}(yjoZoD8)iY`wxT8L!IJ9rp?#`JBiRuaIme+ZPg{5a3O-+pm>E z7@xtTHTKnFNe81yw9jRlt6X&%TlO;rgQ~S@=R1US`8)DL@W2T}(W5l53HwV>8IJI3 zS2rRq#0ES8omp$@3NzT1dZ>C8>(+p8$AU|BL&-E!op`VX<;ksR>6Xro%W>jxE;Ng> zlZ|ehqNy;GXwqF~ZzPtYZ!|bI0;WSk+|e^*H3<>#1!iHP`j#J-OVv$lmAI=-_=-5Q zu}-cAm0Shc;|TL+F%aT^+}-rVH2Ez)0bvGQ>USaX$pu$m&=wE#&Trw9)HnIh<$vgH zTR1nFfi1FNUYfQL!xbm+)&r5LD%bU0bN(2izoyn4VaeVG_q}ME8*kDbp?D()j5NwX zRAYO%(z?sI=|d?ET9*^;XAHc{FVM*t3pQ9C+SdU_SO&Lg9Sq$3zQXHh+$yisp(UEN z=ack|RS`ZmfIUgR?t>}=rRq8wBvkY)bl9-;NIw1-gDWF2W^B4-fj1D;Z{HlXZ-HOZ4!T zZf@`9g3(;7KqZD;I&e7VQ;H%TGqdcPR5e#j>_t4|5`-O0Z;@8SDLvQglbS?Wb39!= zMihL0;GFN=1ff#|OIpA(Q8zDiEb7`TZ4&`~y%?|&`Tywae2&^Sf2xE2GMknu08~L` z5xDCC8XXQ*s97GXkUEG>C@{?Z1u#hT#IKU4m^wV`4^+|Xo3{>UB1KN1?>FG31jC8n zc>%O|)#6nrl7-eYMn;B`Z1Wwr4j=C?9w5D(OUa_TU%ld}J~igg$wrOzXT6zHji zKm|l5FcZ@i=x7Q>6ROyzNF7c|#OpGIC8&>+Gl5ks7-Si!`S+f1pC&ZXb(9(Fo8-!11WI;dqESg4#j zF>vpw6lK2guZ^ft9-|Lpj{O2CIkto6^TEn7sJWveME+tOR70soFP25)w)Mm4o5YDZS ztKqax{tGl`w1e`yd3&-2NoT6V=Pmo4I2wz=$m&9kxwMaiaooG#%&rR4(oMN=3c|** zKNL6`f_2&Sc-yJIPYW-WM)q5OUN8f7m? zIyYRctk4EywjeWayt}|YE(7Fy$2>B|Dd&6c50Ik!5apLuIYnX+bwO-udlNJccA?%D zV6zL%8x6cO1e?U}A4jMVIRh0u1dE&qFZ-+A-uR0ME@F9GQG z^nbf*0PM5v&Gjwpgq(Es|0RL@r+GbkSR9ld#b4%@G3RrgsyWqO=V7e^cPCFIk`lUs;YxM3uiIR@T zcJ^(b0&bt%EKeEyB6L|qmj`)kM2E-#FnY{#SH`7 zI)rJ*eyiOHl;`|HeTZj1L9Pi55k(l-{r)gDiNWW4>{{>?3E2{>z0_hxMnzxL5o!~h z?(*SC#or~}%vjN9s$`2@_pV@4(SQmv&nWKA{rP+HeeQOGM(>q&>%cQ2xZaZJ&wh5;?I0GNna z|F%{Bw21ui(FIsatbP?Xi&OZQYO9CE?6@okhNavwxF8(1rM?#d9Ac^t8aiDP;fXHh zF!iqLghO}68vI)5$97Sj>-|Wg^aU2%O7S%TSHRwneYEkarPj0D;{oD*dqf!1mfrcP z68shkbw5HCxi0h|lBT$FboBZiil&(I#<4xL5HvQDCZnA>M*NyN1F_AGJ4BTp{vMn= zYS)BgN;v4!O(||-E@t5z^YG#`2qX}zTa+~gP zUB820#`Y8p!;aE1gc?#ErsB~Y5?}m63Kh2b>b)G&G9~#MuKngPKfPH`0JU+sW}W(y z&8tziaZcUH9s-oGRqie)^%*vcPgzz+jSUV}nKp0&vUxdZk(RKO8X8wV1Wbj1Pz^O~ zdHdy<`b82gZ48S@%VfKJueW@@e8!^++56+Kl!ipYdp?iDY?sT$(&~D*S++89xu4sk z5FW?pECC(Js~VR_rM?S1_5}m>JwIF*ckm~Si39S|<^s#$rIg*dPwS7VEgwoHv<5zb zHKfvE2Dl@8{Z5W@INZg6@4Y~jB+IZ;t2Q}Up2cNT~97Xk~Z|Jo|u|(nGJk_$d zd_~GVJ1!TUyL}>4LFpWHP=dj6Ug!GT*;iFzMjd#(*Q`g1*MwB1@> z;_>u+gs=*F0}8#rGsle35dn-l8h6F-%#Q1f3yv!k;M8-WuA(2bby@(Yx^!d}FdgvY zBv!j(SZL715n7DZZDB86wNv2^x^Q6h&?{@|*k6~UbI-2P*ioZq22WJ`TlL|UOZ=>? zp8X2vHouLm!Cb@8#pkDtqa9MgIK>im5|$;rH*kH8y-D^KNg9K;L-i=x%7ct^&6k+< z`t0}tqM;->6V-J=KILK)rf;XYsr$nL{w=FM+NPTALmexS^eC-6pW-k}Dg1x1d)JX0 z>(ObtS2=%dYGWO%>a!}@` zzeef8{NuD(XS;d8ko|0&AoQJBBAe(s-fPSd)2ITI)><4)Y)opoMQ-T7zKnJA4%mYaXwF-o2uMW5%coztRNCf z3}-QmHDjp=vnVzI-SJ7II2wgRYGF~;lJ)^B3x(`2Nr)y>=Zuuerf1&?E52#IfsKwt z4@yT7e`DnT!P;+b8S3O{5{62T&l$RO(&J5`JjS*(C52_$a%Fq7jErBloRe4Jr;?Fq zXf_tIZHzvi&d z;xyIFGmH=b|2#;jjm4?}fXhA*;FKKjcVG|{AVBQ^&@gUq#DC%fM$Nwpz{BfBkrI;U zqY;x92B>cS_iZ!x-WNZ$UgQD4pO5-neoBM==Qb%mX)$3TIr+Cz!oMOs06bWJ-tli@ zfPvzdk_@>1sUh=scL2jgXVRuKj;hMPF8HdtceM7yz{Z_z^ur0FI6_YzZg z?l9RJfQbP2hf@4ACJ&%@{{|DV7&NoD1t_Zu8=L9#>FVm++Dd6#XdC`70uus2b_l>r zRQyvW@|ge_^S1>5RcT^LOI>X`0uVF3Ha-8ngJkjYo~2yM*OFM=*!w3xu_-_0ctx9sO`^eGS5W| zFn)i7$8TwA_fvn)>Sv-)z@GM5pz$TNk&m814ghZ&@O$%&3%E*t`&;P$yz2i^*F0ys zCPhHo0RcYjKWEeD;z9dcKuJr(|JmJ^ZdWKU01EKSfX+quj0Cts1ei#F^Wguk-S3AS zggJgPE?`pF2fQ_c|AI3D%#Oc-`?FnskM=U@>N8;1hu@-!{5}Qi%O-i5;_4ZaT!5eI|bb{Om_R z3t$}mQX&C>zckiQecG2dzsw5re0SSlZ~kSG`Cr?yKWw0XZTz3Ldzq8tnIOyHFSYwC z!Cy0UynKR}2@swM;*9@};8)ktmzXc*x1TXhE&mSl&$sfA#JK;$`9ehbnG@6IA8`I= zmihVmU&<9fqk`N11JplW(jSlYi^=b0-CyeBKC^(>|ApoMLnZem&r7Y=XPy~{zwrFh znO8kXM$yf3h z%)h>tzj0i8S^JkRA2()8A434>S5p_?H&oXLz}mzk~mC{Qce@{F3CQ z5$&18{>xuT{yo9}(yRZEIpn2b \(.*\)$'` - if expr "$link" : '/.*' > /dev/null; then - PRG="$link" - else - PRG=`dirname "$PRG"`"/$link" - fi -done -SAVED="`pwd`" -cd "`dirname \"$PRG\"`/" >/dev/null -APP_HOME="`pwd -P`" -cd "$SAVED" >/dev/null - -APP_NAME="Gradle" -APP_BASE_NAME=`basename "$0"` - -# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. -DEFAULT_JVM_OPTS="" - -# Use the maximum available, or set MAX_FD != -1 to use that value. -MAX_FD="maximum" - -warn ( ) { - echo "$*" -} - -die ( ) { - echo - echo "$*" - echo - exit 1 -} - -# OS specific support (must be 'true' or 'false'). -cygwin=false -msys=false -darwin=false -nonstop=false -case "`uname`" in - CYGWIN* ) - cygwin=true - ;; - Darwin* ) - darwin=true - ;; - MINGW* ) - msys=true - ;; - NONSTOP* ) - nonstop=true - ;; -esac - -CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar - -# Determine the Java command to use to start the JVM. -if [ -n "$JAVA_HOME" ] ; then - if [ -x "$JAVA_HOME/jre/sh/java" ] ; then - # IBM's JDK on AIX uses strange locations for the executables - JAVACMD="$JAVA_HOME/jre/sh/java" - else - JAVACMD="$JAVA_HOME/bin/java" - fi - if [ ! -x "$JAVACMD" ] ; then - die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME - -Please set the JAVA_HOME variable in your environment to match the -location of your Java installation." - fi -else - JAVACMD="java" - which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. - -Please set the JAVA_HOME variable in your environment to match the -location of your Java installation." -fi - -# Increase the maximum file descriptors if we can. -if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then - MAX_FD_LIMIT=`ulimit -H -n` - if [ $? -eq 0 ] ; then - if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then - MAX_FD="$MAX_FD_LIMIT" - fi - ulimit -n $MAX_FD - if [ $? -ne 0 ] ; then - warn "Could not set maximum file descriptor limit: $MAX_FD" - fi - else - warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" - fi -fi - -# For Darwin, add options to specify how the application appears in the dock -if $darwin; then - GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" -fi - -# For Cygwin, switch paths to Windows format before running java -if $cygwin ; then - APP_HOME=`cygpath --path --mixed "$APP_HOME"` - CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` - JAVACMD=`cygpath --unix "$JAVACMD"` - - # We build the pattern for arguments to be converted via cygpath - ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` - SEP="" - for dir in $ROOTDIRSRAW ; do - ROOTDIRS="$ROOTDIRS$SEP$dir" - SEP="|" - done - OURCYGPATTERN="(^($ROOTDIRS))" - # Add a user-defined pattern to the cygpath arguments - if [ "$GRADLE_CYGPATTERN" != "" ] ; then - OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" - fi - # Now convert the arguments - kludge to limit ourselves to /bin/sh - i=0 - for arg in "$@" ; do - CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` - CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option - - if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition - eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` - else - eval `echo args$i`="\"$arg\"" - fi - i=$((i+1)) - done - case $i in - (0) set -- ;; - (1) set -- "$args0" ;; - (2) set -- "$args0" "$args1" ;; - (3) set -- "$args0" "$args1" "$args2" ;; - (4) set -- "$args0" "$args1" "$args2" "$args3" ;; - (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; - (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; - (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; - (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; - (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; - esac -fi - -# Escape application args -save ( ) { - for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done - echo " " -} -APP_ARGS=$(save "$@") - -# Collect all arguments for the java command, following the shell quoting and substitution rules -eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS" - -# by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong -if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then - cd "$(dirname "$0")" -fi - -exec "$JAVACMD" "$@" diff --git a/staging/native/gradlew.bat b/staging/native/gradlew.bat deleted file mode 100644 index e95643d6..00000000 --- a/staging/native/gradlew.bat +++ /dev/null @@ -1,84 +0,0 @@ -@if "%DEBUG%" == "" @echo off -@rem ########################################################################## -@rem -@rem Gradle startup script for Windows -@rem -@rem ########################################################################## - -@rem Set local scope for the variables with windows NT shell -if "%OS%"=="Windows_NT" setlocal - -set DIRNAME=%~dp0 -if "%DIRNAME%" == "" set DIRNAME=. -set APP_BASE_NAME=%~n0 -set APP_HOME=%DIRNAME% - -@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. -set DEFAULT_JVM_OPTS= - -@rem Find java.exe -if defined JAVA_HOME goto findJavaFromJavaHome - -set JAVA_EXE=java.exe -%JAVA_EXE% -version >NUL 2>&1 -if "%ERRORLEVEL%" == "0" goto init - -echo. -echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. -echo. -echo Please set the JAVA_HOME variable in your environment to match the -echo location of your Java installation. - -goto fail - -:findJavaFromJavaHome -set JAVA_HOME=%JAVA_HOME:"=% -set JAVA_EXE=%JAVA_HOME%/bin/java.exe - -if exist "%JAVA_EXE%" goto init - -echo. -echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% -echo. -echo Please set the JAVA_HOME variable in your environment to match the -echo location of your Java installation. - -goto fail - -:init -@rem Get command-line arguments, handling Windows variants - -if not "%OS%" == "Windows_NT" goto win9xME_args - -:win9xME_args -@rem Slurp the command line arguments. -set CMD_LINE_ARGS= -set _SKIP=2 - -:win9xME_args_slurp -if "x%~1" == "x" goto execute - -set CMD_LINE_ARGS=%* - -:execute -@rem Setup the command line - -set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar - -@rem Execute Gradle -"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% - -:end -@rem End local scope for the variables with windows NT shell -if "%ERRORLEVEL%"=="0" goto mainEnd - -:fail -rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of -rem the _cmd.exe /c_ return code! -if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 -exit /b 1 - -:mainEnd -if "%OS%"=="Windows_NT" endlocal - -:omega diff --git a/staging/native/src/android/AndroidManifest.xml b/staging/native/src/android/AndroidManifest.xml deleted file mode 100644 index c714f9ee..00000000 --- a/staging/native/src/android/AndroidManifest.xml +++ /dev/null @@ -1,22 +0,0 @@ - - - - - - - diff --git a/staging/native/src/android/CMakeLists.txt b/staging/native/src/android/CMakeLists.txt deleted file mode 100644 index aba96c85..00000000 --- a/staging/native/src/android/CMakeLists.txt +++ /dev/null @@ -1,51 +0,0 @@ -# Copyright 2018 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. - -# For more information about using CMake with Android Studio, read the -# documentation: https://d.android.com/studio/projects/add-native-code.html - -# Sets the minimum version of CMake required to build the native library. - -cmake_minimum_required(VERSION 3.4.1) - -include_directories( ../include ) - -# Creates and names a library, sets it as either STATIC -# or SHARED, and provides the relative paths to its source code. -# You can define multiple libraries, and CMake builds them for you. -# Gradle automatically packages shared libraries with your APK. - -add_library( # Sets the name of the library. - google-signin-cpp - - # Sets the library as a shared library. - STATIC - - # Provides a relative path to your source file(s). - google_signin.cc - google_signin_user.cc - jni.cc) - -set(PACKAGE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/../../google-signin-cpp) -MAKE_DIRECTORY("${PACKAGE_DIR}/include") -set_target_properties(google-signin-cpp - PROPERTIES - ARCHIVE_OUTPUT_DIRECTORY - "${PACKAGE_DIR}/lib/${ANDROID_ABI}") - -add_custom_command(TARGET google-signin-cpp POST_BUILD - COMMAND "${CMAKE_COMMAND}" -E - copy "${CMAKE_CURRENT_SOURCE_DIR}/../include/*.h" - "${PACKAGE_DIR}/include" - COMMENT "Copying public headers to output package") \ No newline at end of file diff --git a/staging/native/src/android/google_signin.cc b/staging/native/src/android/google_signin.cc deleted file mode 100644 index f266d402..00000000 --- a/staging/native/src/android/google_signin.cc +++ /dev/null @@ -1,398 +0,0 @@ -// Copyright 2018 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. - -#include "google_signin.h" -#include -#include -#include "google_signin_user_impl.h" -#include "jni_context.h" - -#define TAG "native-googlesignin" -#define HELPER_CLASSNAME "com/google/googlesignin/GoogleSignInHelper" - -/* -public static void enableDebugLogging(boolean flag) - */ -#define ENABLE_DEBUG_METHOD_NAME "enableDebugLogging" -#define ENABLE_DEBUG_METHOD_SIG "(Z)V" - -/* -public static void configure(Activity parentActivity, - boolean useGamesConfig, - String webClientId, - boolean requestAuthCode, - boolean forceRefreshToken, - boolean requestEmail, - boolean requestIdToken, - boolean hideUiPopups, - String defaultAccountName, - String[] additionalScopes, - long requestHandle) -*/ -#define CONFIG_METHOD_NAME "configure" -#define CONFIG_METHOD_SIG \ - "(Landroid/app/Activity;" \ - "Z" \ - "Ljava/lang/String;" \ - "ZZZZZ" \ - "Ljava/lang/String;" \ - "[Ljava/lang/String;" \ - "J)V" - -/* -public static void nativeSignIn() - */ -#define DISCONNECT_METHOD_NAME "disconnect" -#define DISCONNECT_METHOD_SIG "(Landroid/app/Activity;)V" - -/* -public static void nativeSignIn() - */ -#define SIGNIN_METHOD_NAME "signIn" -#define SIGNIN_METHOD_SIG "(Landroid/app/Activity;J)V" - -/* -public static void nativeSignIn() - */ -#define SIGNINSILENTLY_METHOD_NAME "signInSilently" -#define SIGNINSILENTLY_METHOD_SIG "(Landroid/app/Activity;J)V" - -/* -public static void nativeSignOut() - */ -#define SIGNOUT_METHOD_NAME "signOut" -#define SIGNOUT_METHOD_SIG "(Landroid/app/Activity;)V" - -/* -public static void nativeOnResult(long requestHandle, int result, - GoogleSignInAccount acct), - */ -#define NATIVEONRESULT_METHOD_NAME "nativeOnResult" -#define NATIVEONRESULT_METHOD_SIG \ - "(J" \ - "I" \ - "Lcom/google/android/gms/auth/api/signin/GoogleSignInAccount;" \ - ")V" - -namespace google { -namespace signin { - -class GoogleSignInFuture; - -// The implementation of GoogleSignIn. This implements the JNI interface to -// call the Java helper class the handles the authentication flow within Java. -// For the public methods see google_signin.h for details. -class GoogleSignIn::GoogleSignInImpl { - public: - JNIContext jni_; - GoogleSignInFuture *current_result_; - Configuration *current_configuration_; - - // Constructs the implementation providing the Java activity to use when - // making calls. - GoogleSignInImpl(jobject activity, JavaVM *vm); - ~GoogleSignInImpl(); - - void Configure(const Configuration &configuration); - - void EnableDebugLogging(bool flag); - - // Starts the authentication process. - Future &SignIn(); - - Future &SignInSilently(); - - // Get the result of the last sign-in. - const Future *GetLastSignInResult(); - - // Signs out. - void SignOut(); - - void Disconnect(); - - // Native method implementation for the Java class. - static void NativeOnAuthResult(JNIContext &jni_context, jobject obj, - jlong handle, jint result, jobject user); - - private: - void CallConfigure(); - - static const JNINativeMethod methods[]; - - static jclass helper_clazz_; - static jmethodID enable_debug_method_; - static jmethodID config_method_; - static jmethodID disconnect_method_; - static jmethodID signin_method_; - static jmethodID signinsilently_method_; - static jmethodID signout_method_; -}; - -const JNINativeMethod GoogleSignIn::GoogleSignInImpl::methods[] = { - { - NATIVEONRESULT_METHOD_NAME, - NATIVEONRESULT_METHOD_SIG, - reinterpret_cast( - GoogleSignIn::GoogleSignInImpl::NativeOnAuthResult), - }, -}; - -jclass GoogleSignIn::GoogleSignInImpl::helper_clazz_ = 0; -jmethodID GoogleSignIn::GoogleSignInImpl::enable_debug_method_ = 0; -jmethodID GoogleSignIn::GoogleSignInImpl::config_method_ = 0; -jmethodID GoogleSignIn::GoogleSignInImpl::disconnect_method_ = 0; -jmethodID GoogleSignIn::GoogleSignInImpl::signin_method_ = 0; -jmethodID GoogleSignIn::GoogleSignInImpl::signinsilently_method_ = 0; -jmethodID GoogleSignIn::GoogleSignInImpl::signout_method_ = 0; - -// Implementation of the SignIn future. -class GoogleSignInFuture : public Future { - virtual int Status() const { - return result_ ? result_->StatusCode - : GoogleSignIn::StatusCode::kStatusCodeUninitialized; - } - virtual GoogleSignIn::SignInResult *Result() const { return result_; } - virtual bool Pending() const { - return (!result_) || result_->StatusCode == - GoogleSignIn::StatusCode::kStatusCodeUninitialized; - } - - public: - GoogleSignInFuture() : result_(nullptr) {} - void SetResult(GoogleSignIn::SignInResult *result) { result_ = result; } - - private: - GoogleSignIn::SignInResult *result_; -}; - -// Constructs a new instance. The static members are initialized if need-be. -GoogleSignIn::GoogleSignInImpl::GoogleSignInImpl(jobject activity, JavaVM *vm) - : jni_(activity, vm), current_result_(nullptr), - current_configuration_(nullptr) { - JNIEnv *env = jni_.GetJniEnv(); - - if (!helper_clazz_) { - // Find the java helper class and initialize it. - helper_clazz_ = jni_.FindClass(HELPER_CLASSNAME); - - assert(helper_clazz_); - if (helper_clazz_) { - helper_clazz_ = (jclass)env->NewGlobalRef(helper_clazz_); - env->RegisterNatives(helper_clazz_, methods, - sizeof(methods) / sizeof(methods[0])); - enable_debug_method_ = env->GetStaticMethodID(helper_clazz_, ENABLE_DEBUG_METHOD_NAME, - ENABLE_DEBUG_METHOD_SIG); - config_method_ = env->GetStaticMethodID(helper_clazz_, CONFIG_METHOD_NAME, - CONFIG_METHOD_SIG); - disconnect_method_ = env->GetStaticMethodID( - helper_clazz_, DISCONNECT_METHOD_NAME, DISCONNECT_METHOD_SIG); - signin_method_ = env->GetStaticMethodID(helper_clazz_, SIGNIN_METHOD_NAME, - SIGNIN_METHOD_SIG); - signinsilently_method_ = env->GetStaticMethodID( - helper_clazz_, SIGNINSILENTLY_METHOD_NAME, SIGNINSILENTLY_METHOD_SIG); - signout_method_ = env->GetStaticMethodID( - helper_clazz_, SIGNOUT_METHOD_NAME, SIGNOUT_METHOD_SIG); - } - } -} - -GoogleSignIn::GoogleSignInImpl::~GoogleSignInImpl() { - delete current_result_; - current_result_ = nullptr; -} - -void GoogleSignIn::GoogleSignInImpl::EnableDebugLogging(bool flag) { - JNIEnv *env = jni_.GetJniEnv(); - - env->CallStaticVoidMethod(helper_clazz_, enable_debug_method_, flag); -} - -void GoogleSignIn::GoogleSignInImpl::Configure( - const Configuration &configuration) { - delete current_configuration_; - current_configuration_ = new Configuration(configuration); - - delete current_result_; - current_result_ = new GoogleSignInFuture(); - - CallConfigure(); -} - -void GoogleSignIn::GoogleSignInImpl::CallConfigure() { - JNIEnv *env = jni_.GetJniEnv(); - - if (!current_configuration_) { - __android_log_print(ANDROID_LOG_ERROR, TAG, "configuration is null!?"); - return; - } - jstring j_web_client_id = - current_configuration_->web_client_id.empty() ? nullptr - : env->NewStringUTF(current_configuration_->web_client_id.c_str()); - - jstring j_account_name = - current_configuration_->account_name.empty() ? nullptr - : env->NewStringUTF(current_configuration_->account_name.c_str()); - - jobjectArray j_auth_scopes = nullptr; - - if (current_configuration_->additional_scopes.size() > 0) { - jclass string_clazz = jni_.FindClass("java/lang/String"); - j_auth_scopes = env->NewObjectArray( - current_configuration_->additional_scopes.size(), string_clazz, nullptr); - - for (int i = 0; i < current_configuration_->additional_scopes.size(); i++) { - env->SetObjectArrayElement( - j_auth_scopes, i, - env->NewStringUTF(current_configuration_->additional_scopes[i].c_str())); - } - env->DeleteLocalRef(string_clazz); - } - - jobject j_activity = jni_.GetActivity(); - env->CallStaticVoidMethod( - helper_clazz_, config_method_, j_activity, - current_configuration_->use_game_signin, j_web_client_id, - current_configuration_->request_auth_code, - current_configuration_->force_token_refresh, - current_configuration_->request_email, - current_configuration_->request_id_token, - current_configuration_->hide_ui_popups, j_account_name, j_auth_scopes, - reinterpret_cast(current_result_)); - env->DeleteLocalRef(j_activity); - - if (j_web_client_id) { - env->DeleteLocalRef(j_web_client_id); - } - - if (j_account_name) { - env->DeleteLocalRef(j_account_name); - } - - if (j_auth_scopes) { - env->DeleteLocalRef(j_auth_scopes); - } -} - -Future &GoogleSignIn::GoogleSignInImpl::SignIn() { - JNIEnv *env = jni_.GetJniEnv(); - - if (current_result_) { - current_result_->SetResult(nullptr); - } - - CallConfigure(); - - jobject j_activity = jni_.GetActivity(); - env->CallStaticVoidMethod(helper_clazz_, signin_method_, j_activity, - (jlong)current_result_); - env->DeleteLocalRef(j_activity); - - return *current_result_; -} - -Future - &GoogleSignIn::GoogleSignInImpl::SignInSilently() { - JNIEnv *env = jni_.GetJniEnv(); - - if (current_result_) { - current_result_->SetResult(nullptr); - } - - CallConfigure(); - - jobject j_activity = jni_.GetActivity(); - env->CallStaticVoidMethod(helper_clazz_, signinsilently_method_, j_activity, - (jlong)current_result_); - env->DeleteLocalRef(j_activity); - - return *current_result_; -} - -// Get the result of the last sign-in. -const Future - *GoogleSignIn::GoogleSignInImpl::GetLastSignInResult() { - return current_result_; -} - -// Signs out. -void GoogleSignIn::GoogleSignInImpl::SignOut() { - JNIEnv *env = jni_.GetJniEnv(); - - jobject j_activity = jni_.GetActivity(); - __android_log_print(ANDROID_LOG_INFO, TAG, - "helper: %x method: %x activity: %x", - (uintptr_t)helper_clazz_, (uintptr_t)signin_method_, - (uintptr_t)j_activity); - - env->CallStaticVoidMethod(helper_clazz_, signout_method_, j_activity); - env->DeleteLocalRef(j_activity); -} - -// Signs out. -void GoogleSignIn::GoogleSignInImpl::Disconnect() { - JNIEnv *env = jni_.GetJniEnv(); - - jobject j_activity = jni_.GetActivity(); - env->CallStaticVoidMethod(helper_clazz_, disconnect_method_, j_activity); - env->DeleteLocalRef(j_activity); -} - -void GoogleSignIn::GoogleSignInImpl::NativeOnAuthResult(JNIContext &jni_context, - jobject obj, jlong handle, jint result, jobject user) { - GoogleSignInFuture *future = reinterpret_cast(handle); - if (future) { - SignInResult *rc = new GoogleSignIn::SignInResult(); - rc->StatusCode = result; - rc->User = GoogleSignInUserImpl::UserFromAccount(jni_context, user); - - if (rc->User) { - __android_log_print(ANDROID_LOG_INFO, TAG, "User Display Name is %s", - rc->User->GetDisplayName()); - } - future->SetResult(rc); - } -} - -// Public class implementation. These are called by external callers to use the -// Google Sign-in API. - -GoogleSignIn::GoogleSignIn(jobject activity, JavaVM *vm) - : impl_(new GoogleSignInImpl(activity, vm)) {} - -void GoogleSignIn::EnableDebugLogging(bool flag) { - impl_->EnableDebugLogging(flag); -} - -void GoogleSignIn::Configure(const Configuration &configuration) { - impl_->Configure(configuration); -} - -Future &GoogleSignIn::SignIn() { - return impl_->SignIn(); -} - -Future &GoogleSignIn::SignInSilently() { - return impl_->SignInSilently(); -} - -const Future *GoogleSignIn::GetLastSignInResult() { - return impl_->GetLastSignInResult(); -} - -void GoogleSignIn::SignOut() { impl_->SignOut(); } - -void GoogleSignIn::Disconnect() { impl_->Disconnect(); } - -} // namespace signin -} // namespace google diff --git a/staging/native/src/android/google_signin_user.cc b/staging/native/src/android/google_signin_user.cc deleted file mode 100644 index 198afda9..00000000 --- a/staging/native/src/android/google_signin_user.cc +++ /dev/null @@ -1,191 +0,0 @@ -// Copyright 2018 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. - -#include "google_signin_user.h" // NOLINT -#include - -#include "google_signin_user_impl.h" // NOLINT -#include "jni_context.h" // NOLINT - -#define GOOGLESIGNINACCOUNT_NAME \ - "com/google/android/gms/auth/api/signin/GoogleSignInAccount" - -// String getDisplayName() -#define GETDISPLAYNAME_METHOD_NAME "getDisplayName" -#define GETDISPLAYNAME_METHOD_SIG "()Ljava/lang/String;" - -// String getEmail() -#define GETEMAIL_METHOD_NAME "getEmail" -#define GETEMAIL_METHOD_SIG "()Ljava/lang/String;" - -// String getFamilyName() -#define GETFAMILYNAME_METHOD_NAME "getFamilyName" -#define GETFAMILYNAME_METHOD_SIG "()Ljava/lang/String;" - -// String getGivenName() -#define GETGIVENNAME_METHOD_NAME "getGivenName" -#define GETGIVENNAME_METHOD_SIG "()Ljava/lang/String;" - -// String getId() -#define GETID_METHOD_NAME "getId" -#define GETID_METHOD_SIG "()Ljava/lang/String;" - -// String getIdToken() -#define GETIDTOKEN_METHOD_NAME "getIdToken" -#define GETIDTOKEN_METHOD_SIG "()Ljava/lang/String;" - -// String getServerAuthCode() -#define GETSERVERAUTHCODE_METHOD_NAME "getServerAuthCode" -#define GETSERVERAUTHCODE_METHOD_SIG "()Ljava/lang/String;" - -// Uri getPhotoUrl() -#define GETPHOTOURL_METHOD_NAME "getPhotoUrl" -#define GETPHOTOURL_METHOD_SIG "()Landroid/net/Uri;" - -#define URI_NAME "android/net/Uri" -#define TOSTRING_METHOD_NAME "toString" -#define TOSTRING_METHOD_SIG "()Ljava/lang/String;" - -namespace google { -namespace signin { - -jmethodID GoogleSignInUserImpl::method_getDisplayName = 0; -jmethodID GoogleSignInUserImpl::method_getEmail = 0; -jmethodID GoogleSignInUserImpl::method_getFamilyName = 0; -jmethodID GoogleSignInUserImpl::method_getGivenName = 0; -jmethodID GoogleSignInUserImpl::method_getId = 0; -jmethodID GoogleSignInUserImpl::method_getIdToken = 0; -jmethodID GoogleSignInUserImpl::method_getPhotoUrl = 0; -jmethodID GoogleSignInUserImpl::method_getServerAuthCode = 0; -jmethodID GoogleSignInUserImpl::method_uri_toString = 0; - -void GoogleSignInUserImpl::Initialize(JNIContext &jni_context) { - JNIEnv* env = jni_context.GetJniEnv(); - - if (!method_getDisplayName) { - jclass google_acct_class = jni_context.FindClass(GOOGLESIGNINACCOUNT_NAME); - - method_getDisplayName = - env->GetMethodID(google_acct_class, GETDISPLAYNAME_METHOD_NAME, - GETDISPLAYNAME_METHOD_SIG); - - method_getEmail = env->GetMethodID(google_acct_class, GETEMAIL_METHOD_NAME, - GETEMAIL_METHOD_SIG); - - method_getFamilyName = env->GetMethodID( - google_acct_class, GETFAMILYNAME_METHOD_NAME, GETFAMILYNAME_METHOD_SIG); - - method_getGivenName = env->GetMethodID( - google_acct_class, GETGIVENNAME_METHOD_NAME, GETGIVENNAME_METHOD_SIG); - - method_getId = env->GetMethodID(google_acct_class, GETID_METHOD_NAME, - GETID_METHOD_SIG); - - method_getIdToken = env->GetMethodID( - google_acct_class, GETIDTOKEN_METHOD_NAME, GETIDTOKEN_METHOD_SIG); - - method_getPhotoUrl = env->GetMethodID( - google_acct_class, GETPHOTOURL_METHOD_NAME, GETPHOTOURL_METHOD_SIG); - - jclass uri_class = jni_context.FindClass(URI_NAME); - method_uri_toString = env->GetMethodID( - uri_class, TOSTRING_METHOD_NAME, TOSTRING_METHOD_SIG); - - method_getServerAuthCode = - env->GetMethodID(google_acct_class, GETSERVERAUTHCODE_METHOD_NAME, - GETSERVERAUTHCODE_METHOD_SIG); - } -} - -GoogleSignInUser::GoogleSignInUser() : impl_(new GoogleSignInUserImpl()) {} -GoogleSignInUser::~GoogleSignInUser() { delete impl_; } - -const char* GoogleSignInUser::GetDisplayName() const { - return impl_->display_name.c_str(); -} -const char* GoogleSignInUser::GetEmail() const { return impl_->email.c_str(); } -const char* GoogleSignInUser::GetFamilyName() const { - return impl_->family_name.c_str(); -} -const char* GoogleSignInUser::GetGivenName() const { - return impl_->given_name.c_str(); -} -const char* GoogleSignInUser::GetIdToken() const { - return impl_->id_token.c_str(); -} -const char* GoogleSignInUser::GetImageUrl() const { - return impl_->image_url.c_str(); -} -const char* GoogleSignInUser::GetServerAuthCode() const { - return impl_->server_auth_code.c_str(); -} -const char* GoogleSignInUser::GetUserId() const { - return impl_->user_id.c_str(); -} - -GoogleSignInUser* GoogleSignInUserImpl::UserFromAccount(JNIContext &jni_context, - jobject user_account) { - if (!user_account) { - return nullptr; - } - JNIEnv* env = jni_context.GetJniEnv(); - GoogleSignInUserImpl* user_impl = new GoogleSignInUserImpl(); - - if (!GoogleSignInUserImpl::method_getDisplayName) { - GoogleSignInUserImpl::Initialize(jni_context); - } - - jstring val = static_cast(env->CallObjectMethod( - user_account, GoogleSignInUserImpl::method_getDisplayName)); - user_impl->display_name = jni_context.JStringToString(val); - - val = static_cast(env->CallObjectMethod( - user_account, GoogleSignInUserImpl::method_getEmail)); - user_impl->email = jni_context.JStringToString(val); - - val = static_cast(env->CallObjectMethod( - user_account, GoogleSignInUserImpl::method_getFamilyName)); - user_impl->family_name = jni_context.JStringToString(val); - - val = static_cast(env->CallObjectMethod( - user_account, GoogleSignInUserImpl::method_getGivenName)); - user_impl->given_name = jni_context.JStringToString(val); - - val = static_cast( - env->CallObjectMethod(user_account, GoogleSignInUserImpl::method_getId)); - user_impl->user_id = jni_context.JStringToString(val); - - val = static_cast(env->CallObjectMethod( - user_account, GoogleSignInUserImpl::method_getIdToken)); - user_impl->id_token = jni_context.JStringToString(val); - - jobject uri = env->CallObjectMethod(user_account, - GoogleSignInUserImpl::method_getPhotoUrl); - if (uri) { - val = static_cast( - env->CallObjectMethod(uri, GoogleSignInUserImpl::method_uri_toString)); - } else { - val = nullptr; - } - user_impl->image_url = jni_context.JStringToString(val); - - val = static_cast(env->CallObjectMethod( - user_account, GoogleSignInUserImpl::method_getServerAuthCode)); - user_impl->server_auth_code = jni_context.JStringToString(val); - - return new GoogleSignInUser(user_impl); -} - -} // namespace signin -} // namespace google diff --git a/staging/native/src/android/google_signin_user_impl.h b/staging/native/src/android/google_signin_user_impl.h deleted file mode 100644 index 5eef60a7..00000000 --- a/staging/native/src/android/google_signin_user_impl.h +++ /dev/null @@ -1,53 +0,0 @@ -// Copyright 2018 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. - -#ifndef GOOGLESIGNIN_GOOGLE_SIGNIN_USER_IMPL_H -#define GOOGLESIGNIN_GOOGLE_SIGNIN_USER_IMPL_H - -#include -#include - -namespace google { -namespace signin { - -class JNIContext; - -class GoogleSignInUserImpl { - public: - std::string display_name; - std::string email; - std::string family_name; - std::string given_name; - std::string id_token; - std::string image_url; - std::string user_id; - std::string server_auth_code; - static jmethodID method_getDisplayName; - static jmethodID method_getEmail; - static jmethodID method_getFamilyName; - static jmethodID method_getGivenName; - static jmethodID method_getId; - static jmethodID method_getIdToken; - static jmethodID method_getPhotoUrl; - static jmethodID method_getServerAuthCode; - static jmethodID method_uri_toString; - - static void Initialize(JNIContext &jni_context); - static GoogleSignInUser *UserFromAccount(JNIContext &jni_context, - jobject user_account); -}; - -} // namespace signin -} // namespace google -#endif // GOOGLESIGNIN_GOOGLE_SIGNIN_USER_IMPL_H diff --git a/staging/native/src/android/java/com/google/googlesignin/GoogleSignInFragment.java b/staging/native/src/android/java/com/google/googlesignin/GoogleSignInFragment.java deleted file mode 100644 index 9356426a..00000000 --- a/staging/native/src/android/java/com/google/googlesignin/GoogleSignInFragment.java +++ /dev/null @@ -1,547 +0,0 @@ -/* - * Copyright 2018 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. - */ -package com.google.googlesignin; - -import android.app.Activity; -import android.app.Fragment; -import android.app.FragmentTransaction; -import android.content.Intent; -import android.os.Bundle; -import android.support.annotation.NonNull; -import android.support.annotation.Nullable; -import android.view.View; -import com.google.android.gms.auth.api.Auth; -import com.google.android.gms.auth.api.signin.GoogleSignInAccount; -import com.google.android.gms.auth.api.signin.GoogleSignInOptions; -import com.google.android.gms.auth.api.signin.GoogleSignInOptionsExtension; -import com.google.android.gms.auth.api.signin.GoogleSignInResult; -import com.google.android.gms.common.ConnectionResult; -import com.google.android.gms.common.api.Api; -import com.google.android.gms.common.api.CommonStatusCodes; -import com.google.android.gms.common.api.GoogleApiClient; -import com.google.android.gms.common.api.ResultCallback; -import com.google.android.gms.common.api.Scope; -import java.lang.reflect.Field; -import java.lang.reflect.InvocationTargetException; -import java.lang.reflect.Method; -import java.util.Locale; - -/** - * Activity fragment with no UI added to the parent activity in order to manage the accessing of the - * player's email address and tokens. - */ -public class GoogleSignInFragment extends Fragment implements - GoogleApiClient.ConnectionCallbacks, - GoogleApiClient.OnConnectionFailedListener { - - // Tag uniquely identifying this fragment. - public static final String FRAGMENT_TAG = "signin.SignInFragment"; - private static final int RC_SIGNIN = 9009; - - /** - * Handle the Google API Client connection being connected. - * - * @param connectionHint - is not used. - */ - @Override - public void onConnected(@Nullable Bundle connectionHint) { - GoogleSignInHelper.logDebug("onConnected!"); - if (mGoogleApiClient.hasConnectedApi(Auth.GOOGLE_SIGN_IN_API)) { - GoogleSignInHelper.logDebug("has connected auth!"); - Auth.GoogleSignInApi.silentSignIn(mGoogleApiClient) - .setResultCallback( - new ResultCallback() { - @Override - public void onResult(@NonNull GoogleSignInResult googleSignInResult) { - if (googleSignInResult.isSuccess()) { - GoogleSignInHelper.nativeOnResult( - request.getHandle(), - googleSignInResult.getStatus().getStatusCode(), - googleSignInResult.getSignInAccount()); - setState(State.READY); - } else { - GoogleSignInHelper.logError( - "Error with " + "silentSignIn: " + googleSignInResult.getStatus()); - GoogleSignInHelper.nativeOnResult( - request.getHandle(), - googleSignInResult.getStatus().getStatusCode(), - googleSignInResult.getSignInAccount()); - setState(State.READY); - } - } - }); - } else { - Intent signInIntent = Auth.GoogleSignInApi.getSignInIntent(mGoogleApiClient); - startActivityForResult(signInIntent, RC_SIGNIN); - } - } - - @Override - public void onConnectionSuspended(int cause) { - GoogleSignInHelper.logDebug("onConnectionSuspended() called: " + cause); - } - - - @Override - public void onConnectionFailed(@NonNull ConnectionResult connectionResult) { - // Handle errors during connection, such as Play Store not installed. - GoogleSignInHelper.logError("Connection failed: " + - connectionResult.getErrorCode()); - // if there is a resolution, just start the sign-in intent, which handles - // the resolution logic. - if (connectionResult.hasResolution()) { - Intent signInIntent = Auth.GoogleSignInApi.getSignInIntent(mGoogleApiClient); - startActivityForResult(signInIntent, RC_SIGNIN); - } else { - GoogleSignInHelper.nativeOnResult( - request.getHandle(), - connectionResult.getErrorCode(), - null); - } - } - - public void disconnect() { - - if (mGoogleApiClient != null) { - mGoogleApiClient.disconnect(); - } - } - - /** - * The state of the fragment. It can only handle one sign-in request at a time, so we use these - * values to keep track of the request lifecycle. - */ - private enum State { - NEW, - READY, - PENDING, - PENDING_SILENT, - BUSY - } - - private State state; - - /** - * The request to sign-in. This contains the configuration for the API client/Sign-in options and - * the callback information used to communicate the result. - */ - private TokenRequest request = null; - - private GoogleApiClient mGoogleApiClient; - - // TODO: make config async. - private static GoogleSignInFragment theFragment; - - /** - * Gets the instance of the fragment. - * - * @param parentActivity - the activity to attach the fragment to. - * @return the instance. - */ - public static GoogleSignInFragment getInstance(Activity parentActivity) { - GoogleSignInFragment fragment = - (GoogleSignInFragment) parentActivity.getFragmentManager().findFragmentByTag(FRAGMENT_TAG); - - fragment = (fragment != null) ? fragment : theFragment; - if (fragment == null) { - GoogleSignInHelper.logDebug("Creating fragment"); - fragment = new GoogleSignInFragment(); - FragmentTransaction trans = parentActivity.getFragmentManager().beginTransaction(); - trans.add(fragment, FRAGMENT_TAG); - trans.commitAllowingStateLoss(); - theFragment = fragment; - } - return fragment; - } - - public synchronized boolean submitRequest(TokenRequest request) { - if (this.request == null || this.state == State.READY) { - this.request = request; - return true; - } - GoogleSignInHelper.logError(String.format(Locale.getDefault(), - "Existing request: %s ignoring %s. State = %s", this.request, request, this.state)); - return false; - } - - private synchronized State getState() { - return state; - } - - private synchronized void setState(State state) { - this.state = state; - } - - /** - * Signs out and disconnects the client. NOTE: if you are using the Games API, you **MUST** call - * Games.signout() before this method. Failure to do so will result in not being able to access - * Games API until the application is restarted. - */ - public void signOut() { - clearRequest(true); - if (mGoogleApiClient != null) { - Auth.GoogleSignInApi.signOut(mGoogleApiClient); - } - } - - /** - * Starts the sign-in process using the Sign-in UI, if any UI is needed. This is in contrast to - * startSignInSilently, which does not use any UI. - * - * @return true if the sign-in flow was started. - */ - public boolean startSignIn() { - if (request == null) { - GoogleSignInHelper.logError("Request not configured! Failing authenticate"); - return false; - } - if (getState() == State.BUSY) { - GoogleSignInHelper.logError("There is already a pending callback" + " configured."); - } else if (getState() == State.READY) { - processRequest(false); - } else { - processWhenReady(false); - } - return true; - } - - /** - * Starts the sign-in silently flow. - * - * @return true if the flow was started successfully. - */ - public boolean startSignInSilently() { - if (request == null) { - GoogleSignInHelper.logError("Request not configured! Failing authenticate"); - return false; - } - if (getState() == State.BUSY) { - GoogleSignInHelper.logError("There is already a pending callback" + " configured."); - } else if (getState() == State.READY) { - processRequest(true); - } else { - processWhenReady(true); - } - return true; - } - - /** - * Indicates that the token request has been set and it is ready to be processed. The processing - * can start once the fragment is attached to the activity and initialized. - * - * @param silent - true if the sign-in should be silent. - */ - private void processWhenReady(boolean silent) { - GoogleSignInHelper.logInfo("Fragment not initialized yet, " + "waiting to authenticate"); - setState(silent ? State.PENDING_SILENT : State.PENDING); - } - - /** - * Processes the token requests that are queued up. First checking that the google api client is - * connected. - */ - private void processRequest(final boolean silent) { - try { - if (request != null) { - setState(State.BUSY); - } else { - GoogleSignInHelper.logInfo("No pending configuration, returning"); - return; - } - - request - .getPendingResponse() - .setResultCallback( - new ResultCallback() { - @Override - public void onResult(@NonNull TokenResult tokenResult) { - GoogleSignInHelper.logDebug( - String.format( - Locale.getDefault(), - "Calling nativeOnResult: handle: %s, status: %d acct: %s", - tokenResult.getHandle(), - tokenResult.getStatus().getStatusCode(), - tokenResult.getAccount())); - GoogleSignInHelper.nativeOnResult( - tokenResult.getHandle(), - tokenResult.getStatus().getStatusCode(), - tokenResult.getAccount()); - clearRequest(false); - } - }); - - // Build the GoogleAPIClient - buildClient(request); - - GoogleSignInHelper.logDebug( - " Has connected == " + mGoogleApiClient.hasConnectedApi(Auth.GOOGLE_SIGN_IN_API)); - if (!mGoogleApiClient.hasConnectedApi(Auth.GOOGLE_SIGN_IN_API)) { - - if (!silent) { - Intent signInIntent = Auth.GoogleSignInApi.getSignInIntent(mGoogleApiClient); - startActivityForResult(signInIntent, RC_SIGNIN); - } else { - Auth.GoogleSignInApi.silentSignIn(mGoogleApiClient) - .setResultCallback( - new ResultCallback() { - @Override - public void onResult(@NonNull GoogleSignInResult googleSignInResult) { - if (googleSignInResult.isSuccess()) { - GoogleSignInHelper.nativeOnResult( - request.getHandle(), - googleSignInResult.getStatus().getStatusCode(), - googleSignInResult.getSignInAccount()); - setState(State.READY); - } else { - GoogleSignInHelper.logError( - "Error with " + "silentSignIn: " + googleSignInResult.getStatus()); - GoogleSignInHelper.nativeOnResult( - request.getHandle(), - googleSignInResult.getStatus().getStatusCode(), - googleSignInResult.getSignInAccount()); - setState(State.READY); - } - } - }); - } - } - } catch (Throwable throwable) { - GoogleSignInHelper.logError("Exception caught! " + throwable.getMessage()); - request.setResult(CommonStatusCodes.INTERNAL_ERROR, null); - return; - } - - GoogleSignInHelper.logDebug("Done with processRequest!"); - } - - /** - * Builds the Google API Client based on the configuration in the request. - * - * @param request - the request for a token. - */ - private void buildClient(TokenRequest request) { - GoogleSignInOptions.Builder builder; - - if (request.getUseGamesConfig()) { - GoogleSignInHelper.logDebug("Using DEFAULT_GAMES_SIGN_IN"); - builder = new GoogleSignInOptions.Builder(GoogleSignInOptions.DEFAULT_GAMES_SIGN_IN); - } else { - GoogleSignInHelper.logDebug("Using DEFAULT_SIGN_IN"); - builder = new GoogleSignInOptions.Builder(GoogleSignInOptions.DEFAULT_SIGN_IN); - } - - if (request.getDoAuthCode()) { - if (!request.getWebClientId().isEmpty()) { - GoogleSignInHelper.logDebug( - "Requesting AuthCode force = " - + request.getForceRefresh() - + "client: " - + request.getWebClientId()); - builder.requestServerAuthCode(request.getWebClientId(), request.getForceRefresh()); - } else { - GoogleSignInHelper.logError("Web client ID is needed for Auth Code"); - request.setResult(CommonStatusCodes.DEVELOPER_ERROR, null); - throw new IllegalStateException("Web client ID is needed for Auth Code"); - } - } - - if (request.getDoEmail()) { - GoogleSignInHelper.logDebug("Requesting email"); - builder.requestEmail(); - } - - if (request.getDoIdToken()) { - if (!request.getWebClientId().isEmpty()) { - GoogleSignInHelper.logDebug("Requesting IDToken client: " + request.getWebClientId()); - - builder.requestIdToken(request.getWebClientId()); - } else { - GoogleSignInHelper.logError("Web client ID is needed for ID Token"); - request.setResult(CommonStatusCodes.DEVELOPER_ERROR, null); - throw new IllegalStateException("Web client ID is needed for Auth Code"); - } - } - if (request.getScopes() != null) { - for (String s : request.getScopes()) { - GoogleSignInHelper.logDebug("Adding scope: " + s); - - builder.requestScopes(new Scope(s)); - } - } - - if (request.getHidePopups() && request.getUseGamesConfig()) { - GoogleSignInHelper.logDebug("hiding popup views for games API"); - // Use reflection to build the extension, so we don't force - // a dependency on Games. - - builder.addExtension(getGamesExtension()); - } - - if (request.getAccountName() != null) { - GoogleSignInHelper.logDebug("Setting accountName: " + request.getAccountName()); - - builder.setAccountName(request.getAccountName()); - } - - GoogleSignInOptions options = builder.build(); - - GoogleApiClient.Builder clientBuilder = - new GoogleApiClient.Builder(getActivity()).addApi(Auth.GOOGLE_SIGN_IN_API, options); - if (request.getUseGamesConfig()) { - GoogleSignInHelper.logDebug("Adding games API"); - - try { - clientBuilder.addApi(getGamesAPI()); - } catch (Exception e) { - GoogleSignInHelper.logError("Exception getting Games API: " + e.getMessage()); - request.setResult(CommonStatusCodes.DEVELOPER_ERROR, null); - return; - } - } - if (request.getHidePopups()) { - View invisible = new View(getContext()); - invisible.setVisibility(View.INVISIBLE); - invisible.setClickable(false); - clientBuilder.setViewForPopups(invisible); - } - mGoogleApiClient = clientBuilder.build(); - mGoogleApiClient.connect(GoogleApiClient.SIGN_IN_MODE_OPTIONAL); - } - - private Api getGamesAPI() { - try { - Class gamesClass = Class.forName("com" + ".google.android.gms.games.Games"); - Field apiField = gamesClass.getField("API"); - return (Api) apiField.get(null); - } catch (ClassNotFoundException e) { - throw new IllegalArgumentException("Games API requested, but " + "can't load Games class", e); - } catch (NoSuchFieldException e) { - throw new IllegalArgumentException( - "Games API requested, but " + "can't load Games API field", e); - } catch (IllegalAccessException e) { - throw new IllegalArgumentException( - "Games API requested, but " + "can't load Games API field", e); - } - } - - /** - * Builds the games extension to hide popups using Reflection. This avoids the hard dependency on - * Games. - * - * @return the extension, or throws InvalidArgumentException if games is requested, but not found. - */ - private GoogleSignInOptionsExtension getGamesExtension() { - try { - Class gamesClass = Class.forName("com" + ".google.android.gms.games.Games$GamesOptions"); - - Method builderMethod = gamesClass.getMethod("builder()"); - - Object builder = builderMethod.invoke(null); - - Method setter = builder.getClass().getMethod("setShowConnectingPopup", boolean.class); - - setter.invoke(builder, false); - - Method buildMethod = builder.getClass().getMethod("build"); - return (GoogleSignInOptionsExtension) builderMethod.invoke(builder); - - } catch (ClassNotFoundException e) { - throw new IllegalArgumentException( - "Games API requested, but" + "can't load Games$GamesOptions class", e); - } catch (NoSuchMethodException e) { - throw new IllegalArgumentException( - "Games API requested, but" + "can't find builder() static method.", e); - } catch (InvocationTargetException e) { - throw new IllegalArgumentException( - "Games API requested, but" + "can't invoke builder() static method.", e); - } catch (IllegalAccessException e) { - throw new IllegalArgumentException( - "Games API requested, but" + "can't invoke builder() static method.", e); - } - } - - @Override - public void onStart() { - super.onStart(); - - // This just connects the client. If there is no user signed in, you - // still need to call Auth.GoogleSignInApi.getSignInIntent() to start - // the sign-in process. - if (mGoogleApiClient != null) { - mGoogleApiClient.connect(GoogleApiClient.SIGN_IN_MODE_OPTIONAL); - } - } - - /** - * Called when the fragment is visible to the user and actively running. This is generally tied to - * {@link Activity#onResume() Activity.onResume} of the containing Activity's lifecycle. - */ - @Override - public void onResume() { - GoogleSignInHelper.logDebug("onResume called"); - if (theFragment != this) { - theFragment = this; - } - super.onResume(); - if (getState() == State.PENDING) { - GoogleSignInHelper.logDebug("State is pending, calling processRequest(false)"); - processRequest(false); - } else if (getState() == State.PENDING_SILENT) { - GoogleSignInHelper.logDebug("State is pending_silent, calling processRequest(true)"); - processRequest(true); - } else { - GoogleSignInHelper.logDebug("State is now ready"); - setState(State.READY); - } - } - - /** - * Receive the result from a previous call to {@link #startActivityForResult(Intent, int)}. This - * follows the related Activity API as described there in {@link Activity#onActivityResult(int, - * int, Intent)}. - * - * @param requestCode The integer request code originally supplied to startActivityForResult(), - * allowing you to identify who this result came from. - * @param resultCode The integer result code returned by the child activity through its - * setResult(). - * @param data An Intent, which can return result data to the caller - */ - @Override - public void onActivityResult(int requestCode, int resultCode, Intent data) { - GoogleSignInHelper.logDebug("onActivityResult: " + requestCode + " " + resultCode); - if (requestCode == RC_SIGNIN) { - GoogleSignInResult result = Auth.GoogleSignInApi.getSignInResultFromIntent(data); - TokenRequest request = this.request; - if (request != null) { - GoogleSignInAccount acct = result.getSignInAccount(); - request.setResult(result.getStatus().getStatusCode(), acct); - } else { - GoogleSignInHelper.logError("Pending request is null, can't " + "return result!"); - } - return; - } - super.onActivityResult(requestCode, resultCode, data); - } - - private synchronized void clearRequest(boolean cancel) { - if (cancel && request != null) { - // Cancel request. - request.cancel(); - } - request = null; - setState(getActivity() != null ? State.READY : State.NEW); - } -} diff --git a/staging/native/src/android/java/com/google/googlesignin/GoogleSignInHelper.java b/staging/native/src/android/java/com/google/googlesignin/GoogleSignInHelper.java deleted file mode 100644 index a1cdafab..00000000 --- a/staging/native/src/android/java/com/google/googlesignin/GoogleSignInHelper.java +++ /dev/null @@ -1,148 +0,0 @@ -/* - * Copyright 2018 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. - */ -package com.google.googlesignin; - -import android.app.Activity; -import android.util.Log; -import com.google.android.gms.auth.api.signin.GoogleSignInAccount; -import com.google.android.gms.common.api.CommonStatusCodes; - -/** - * Helper class used by the native C++ code to interact with Google Sign-in API. The general flow is - * Call configure, then one of signIn or signInSilently. - */ -public class GoogleSignInHelper { - - // Set to true to get more debug logging. - public static boolean loggingEnabled = false; - private static final String TAG = "SignInFragment"; - - /** - * Enables verbose logging - */ - public static void enableDebugLogging(boolean flag) { - loggingEnabled = flag; - } - - /** - * Sets the configuration of the sign-in api that should be used. - * - * @param parentActivity - the parent activity. This API creates a fragment that is attached to - * this activity. - * @param useGamesConfig - true if the GAMES_CONFIG should be used when signing-in. - * @param webClientId - the web client id of the backend server associated with this application. - * @param requestAuthCode - true if a server auth code is needed. This also requires the web - * client id to be set. - * @param forceRefreshToken - true to force a refresh token when using the server auth code. - * @param requestEmail - true if email address of the user is requested. - * @param requestIdToken - true if an id token for the user is requested. - * @param hideUiPopups - true if the popups during sign-in from the Games API should be hidden. - * This only has affect if useGamesConfig is true. - * @param defaultAccountName - the account name to attempt to default to when signing in. - * @param additionalScopes - additional API scopes to request when authenticating. - * @param requestHandle - the handle to this request, created by the native C++ code, this is used - * to correlate the response with the request. - */ - public static void configure( - Activity parentActivity, - boolean useGamesConfig, - String webClientId, - boolean requestAuthCode, - boolean forceRefreshToken, - boolean requestEmail, - boolean requestIdToken, - boolean hideUiPopups, - String defaultAccountName, - String[] additionalScopes, - long requestHandle) { - logDebug("TokenFragment.configure called"); - TokenRequest request = - new TokenRequest( - useGamesConfig, - webClientId, - requestAuthCode, - forceRefreshToken, - requestEmail, - requestIdToken, - hideUiPopups, - defaultAccountName, - additionalScopes, - requestHandle); - - GoogleSignInFragment fragment = GoogleSignInFragment.getInstance(parentActivity); - - if (request.isValid()) { - if (!fragment.submitRequest(request)) { - logError("There is already a pending" + " authentication token request!"); - } - } else { - nativeOnResult(requestHandle, CommonStatusCodes.DEVELOPER_ERROR, null); - } - } - - public static void signIn(Activity activity, long requestHandle) { - logDebug("AuthHelperFragment.authenticate called!"); - GoogleSignInFragment fragment = GoogleSignInFragment.getInstance(activity); - - if (!fragment.startSignIn()) { - nativeOnResult(requestHandle, CommonStatusCodes.DEVELOPER_ERROR, null); - } - } - - public static void signInSilently(Activity activity, long requestHandle) { - logDebug("AuthHelperFragment.signinSilently called!"); - GoogleSignInFragment fragment = GoogleSignInFragment.getInstance(activity); - - if (!fragment.startSignInSilently()) { - nativeOnResult(requestHandle, CommonStatusCodes.DEVELOPER_ERROR, null); - } - } - - public static void signOut(Activity activity) { - GoogleSignInFragment fragment = GoogleSignInFragment.getInstance(activity); - fragment.signOut(); - } - - public static void disconnect(Activity activity) { - GoogleSignInFragment fragment = GoogleSignInFragment.getInstance(activity); - fragment.disconnect(); - } - - public static void logInfo(String msg) { - if (loggingEnabled) { - Log.i(TAG, msg); - } - } - - public static void logError(String msg) { - Log.e(TAG, msg); - } - - public static void logDebug(String msg) { - if (loggingEnabled) { - Log.d(TAG, msg); - } - } - - /** - * Native callback for the authentication result. - * - * @param handle Identifies the request. - * @param result Authentication result. - * @param acct The account that is signed in, if successful. - */ - public static native void nativeOnResult(long handle, int result, GoogleSignInAccount acct); -} diff --git a/staging/native/src/android/java/com/google/googlesignin/TokenPendingResult.java b/staging/native/src/android/java/com/google/googlesignin/TokenPendingResult.java deleted file mode 100644 index 5d305aba..00000000 --- a/staging/native/src/android/java/com/google/googlesignin/TokenPendingResult.java +++ /dev/null @@ -1,145 +0,0 @@ -/* - * Copyright 2018 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. - */ -package com.google.googlesignin; - -import android.util.Log; -import com.google.android.gms.auth.api.signin.GoogleSignInAccount; -import com.google.android.gms.common.api.CommonStatusCodes; -import com.google.android.gms.common.api.PendingResult; -import com.google.android.gms.common.api.ResultCallback; -import java.util.concurrent.CountDownLatch; -import java.util.concurrent.TimeUnit; - -/** - * Pending result class for TokenResult. This allows the pending result to be returned to the - * caller, and then updated when available, simplifying the handling of callbacks. - */ -public class TokenPendingResult extends PendingResult { - - private static final String TAG = "TokenPendingResult"; - private final long requestHandle; - - private CountDownLatch latch = new CountDownLatch(1); - private TokenResult result; - private ResultCallback resultCallback; - - public TokenPendingResult(long requestHandle) { - this.requestHandle = requestHandle; - result = new TokenResult(); - result.setHandle(requestHandle); - } - - @Override - public TokenResult await() { - - try { - latch.await(); - } catch (InterruptedException e) { - setResult(null, CommonStatusCodes.INTERRUPTED); - } - - return getResult(); - } - - @Override - public TokenResult await(long l, TimeUnit timeUnit) { - try { - if (!latch.await(l, timeUnit)) { - setResult(null, CommonStatusCodes.TIMEOUT); - } - } catch (InterruptedException e) { - setResult(null, CommonStatusCodes.INTERRUPTED); - } - return getResult(); - } - - @Override - public void cancel() { - setResult(null, CommonStatusCodes.CANCELED); - latch.countDown(); - } - - @Override - public boolean isCanceled() { - return getResult() != null && getResult().getStatus().isCanceled(); - } - - @Override - public void setResultCallback(ResultCallback resultCallback) { - - // Handle adding the callback when the latch has already counted down. This - // can happen if there is an error right away. - if (latch.getCount() == 0) { - resultCallback.onResult(getResult()); - } else { - setCallback(resultCallback); - } - } - - @Override - public void setResultCallback( - ResultCallback resultCallback, long l, TimeUnit timeUnit) { - try { - if (!latch.await(l, timeUnit)) { - setResult(null, CommonStatusCodes.TIMEOUT); - } - } catch (InterruptedException e) { - setResult(null, CommonStatusCodes.INTERRUPTED); - } - - resultCallback.onResult(getResult()); - } - - private synchronized void setCallback(ResultCallback callback) { - this.resultCallback = callback; - } - - private synchronized ResultCallback getCallback() { - return this.resultCallback; - } - - /** - * Set the result. If any of the values are null, and a previous non-null value was set, the - * non-null value is retained. - * - * @param account - the signin account, if any. - * @param resultCode - the result code. - */ - public synchronized void setResult(GoogleSignInAccount account, int resultCode) { - result = new TokenResult(account, resultCode); - result.setHandle(requestHandle); - } - - private synchronized TokenResult getResult() { - return result; - } - - /** - * Sets the result status and releases the latch and/or calls the callback. - * - * @param status - the result status. - */ - public void setStatus(int status) { - result.setStatus(status); - latch.countDown(); - ResultCallback cb = getCallback(); - TokenResult res = getResult(); - if (cb != null) { - Log.d(TAG, " Calling onResult for callback. result: " + res); - getCallback().onResult(res); - } - } -} diff --git a/staging/native/src/android/java/com/google/googlesignin/TokenRequest.java b/staging/native/src/android/java/com/google/googlesignin/TokenRequest.java deleted file mode 100644 index e987d8ec..00000000 --- a/staging/native/src/android/java/com/google/googlesignin/TokenRequest.java +++ /dev/null @@ -1,171 +0,0 @@ -/* - * Copyright 2018 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. - */ -package com.google.googlesignin; - -import com.google.android.gms.auth.api.signin.GoogleSignInAccount; -import com.google.android.gms.common.api.PendingResult; -import java.util.Locale; - -/** Helper class containing the request for information. */ -public class TokenRequest { - private TokenPendingResult pendingResponse; - private boolean useGamesConfig; - private boolean doAuthCode; - private boolean doEmail; - private boolean doIdToken; - private String webClientId; - private boolean forceRefresh; - private boolean hidePopups; - private String accountName; - private String[] scopes; - private long handle; - - /** - * Constructs a token request. - * - * @param useGamesConfig - true if the GAMES_CONFIG should be used when signing-in. - * @param webClientId - the web client id of the backend server associated with this application. - * @param requestAuthCode - true if a server auth code is needed. This also requires the web - * client id to be set. - * @param forceRefreshToken - true to force a refresh token when using the server auth code. - * @param requestEmail - true if email address of the user is requested. - * @param requestIdToken - true if an id token for the user is requested. - * @param hideUiPopups - true if the popups during sign-in from the Games API should be hidden. - * This only has affect if useGamesConfig is true. - * @param defaultAccountName - the account name to attempt to default to when signing in. - * @param additionalScopes - additional API scopes to request when authenticating. - * @param requestHandle - the handle to this request, created by the native C++ code, this is used - * to correlate the response with the request. - */ - public TokenRequest( - boolean useGamesConfig, - String webClientId, - boolean requestAuthCode, - boolean forceRefreshToken, - boolean requestEmail, - boolean requestIdToken, - boolean hideUiPopups, - String defaultAccountName, - String[] additionalScopes, - long requestHandle) { - pendingResponse = new TokenPendingResult(requestHandle); - this.useGamesConfig = useGamesConfig; - this.webClientId = webClientId; - this.doAuthCode = requestAuthCode; - this.forceRefresh = forceRefreshToken; - this.doEmail = requestEmail; - this.doIdToken = requestIdToken; - this.hidePopups = hideUiPopups; - this.accountName = defaultAccountName; - this.handle = requestHandle; - if (additionalScopes != null && additionalScopes.length > 0) { - scopes = new String[additionalScopes.length]; - System.arraycopy(additionalScopes, 0, scopes, 0, additionalScopes.length); - } else { - scopes = null; - } - } - - /** - * Returns the pending response object for this request. - * - * @return the pending response. - */ - public PendingResult getPendingResponse() { - return pendingResponse; - } - - /** - * Sets the result of the reuquest. - * - * @param code - the status code of the request. - * @param account - the GoogleSignInAccount if successful. - */ - public void setResult(int code, GoogleSignInAccount account) { - pendingResponse.setResult(account, code); - pendingResponse.setStatus(code); - } - - /** Cancels the request and notifies the pending response. */ - public void cancel() { - pendingResponse.cancel(); - } - - @Override - public String toString() { - return String.format( - Locale.getDefault(), - "%s(a:%b:e:%b:i:%b)", - Integer.toHexString(hashCode()), - doAuthCode, - doEmail, - doIdToken); - } - - public String getWebClientId() { - return webClientId == null ? "" : webClientId; - } - - public boolean getForceRefresh() { - return forceRefresh; - } - - public boolean isValid() { - if (webClientId == null || webClientId.isEmpty()) { - if (doAuthCode) { - GoogleSignInHelper.logError( - "Invalid configuration, auth code" + " requires web " + "client id"); - return false; - } else if (doIdToken) { - GoogleSignInHelper.logError("Invalid configuration, id token requires web " + "client id"); - return false; - } - } - return true; - } - - public long getHandle() { - return handle; - } - - public boolean getUseGamesConfig() { - return useGamesConfig; - } - - public boolean getDoAuthCode() { - return doAuthCode; - } - - public boolean getDoEmail() { - return doEmail; - } - - public boolean getDoIdToken() { - return doIdToken; - } - - public String[] getScopes() { - return scopes; - } - - public String getAccountName() { - return accountName; - } - - public boolean getHidePopups() { - return hidePopups; - } -} diff --git a/staging/native/src/android/java/com/google/googlesignin/TokenResult.java b/staging/native/src/android/java/com/google/googlesignin/TokenResult.java deleted file mode 100644 index 80e36c5a..00000000 --- a/staging/native/src/android/java/com/google/googlesignin/TokenResult.java +++ /dev/null @@ -1,66 +0,0 @@ -/* - * Copyright 2018 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. - */ -package com.google.googlesignin; - -import com.google.android.gms.auth.api.signin.GoogleSignInAccount; -import com.google.android.gms.common.api.CommonStatusCodes; -import com.google.android.gms.common.api.Result; -import com.google.android.gms.common.api.Status; -import java.util.Locale; - -/** Class for returning the tokens to a native caller. */ -public class TokenResult implements Result { - private Status status; - private GoogleSignInAccount account; - private long handle; - - TokenResult() { - status = new Status(CommonStatusCodes.SIGN_IN_REQUIRED); - account = null; - } - - TokenResult(GoogleSignInAccount account, int resultCode) { - status = new Status(resultCode); - this.account = account; - } - - @Override - public String toString() { - return String.format( - Locale.getDefault(), "Status: %s %s", status, (account == null) ? "" : account); - } - - @Override - public Status getStatus() { - return status; - } - - public GoogleSignInAccount getAccount() { - return account; - } - - public void setStatus(int status) { - this.status = new Status(status); - } - - public long getHandle() { - return handle; - } - - public void setHandle(long handle) { - this.handle = handle; - } -} diff --git a/staging/native/src/android/jni.cc b/staging/native/src/android/jni.cc deleted file mode 100644 index 37334671..00000000 --- a/staging/native/src/android/jni.cc +++ /dev/null @@ -1,153 +0,0 @@ -// Copyright 2018 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. -// - -// This file isolates some of the JNI boilerplate for managing the JNI -// environment, dealing with class loaders and keeping track of threads that -// have been bound to the JavaVM. - -#include -#include -#include -#include "jni_context.h" - -namespace google { -namespace signin { - -JavaVM* JNIContext::vm_ = nullptr; -static pthread_key_t jni_env_key; -static pthread_once_t pthread_key_initialized = PTHREAD_ONCE_INIT; - -// This will be called by any thread that's attached to the JVM when it exits. -extern "C" { -static void DetachJVMThreads(void* stored_java_vm) { - assert(stored_java_vm); - JavaVM* java_vm = static_cast(stored_java_vm); - - // AttachCurrentThread does nothing if we're already attached, but - // calling it ensures that the DetachCurrentThread doesn't fail. - JNIEnv* jni_env; - java_vm->AttachCurrentThread(&jni_env, nullptr); - java_vm->DetachCurrentThread(); -} - -// Called the first time GetJNIEnv is invoked. -// Ensures that jni_env_key is created and that the destructor is in place. -static void SetupJvmThreadStorage() { - // Set up the thread destructor when the JavaVM is first known. - // This creates a key for a thread local value. The destructor is then - // called for any thread (when it exits), which has assigned a value - // to this key, using setspecific. - pthread_key_create(&jni_env_key, DetachJVMThreads); -} -} - -JNIContext::JNIContext(jobject activity, JavaVM *vm) { - vm_ = vm; - (void)pthread_once(&pthread_key_initialized, - SetupJvmThreadStorage); - - JNIEnv* env = GetJniEnv(); - activity_ = env->NewGlobalRef(activity); -} - -JNIContext::~JNIContext() { - JNIEnv* env = GetJniEnv(); - env->DeleteGlobalRef(activity_); - activity_ = nullptr; - - // we don't clear the vm_ in case there are multiple contexts. -} - -// This could be static, but it should never be called before at least one -// instance is constructed. -JNIEnv* JNIContext::GetJniEnv() { - assert(vm_); - // This call allows us to set a thread-local value. Even though there will - // only ever be one JavaVM, and every thread will store the same value, - // this ensures any thread attaching to the JVM will call the thread - // destructor to detach before exiting. - pthread_setspecific(jni_env_key, vm_); - JNIEnv* env; - jint result = vm_->AttachCurrentThread(&env, nullptr); - return result == JNI_OK ? env : nullptr; -} - -// Returns a local reference to the activity used to construct this class. -// The user is expected to call DeleteLocalRef to avoid leaking. -jobject JNIContext::GetActivity() { - assert(activity_); - JNIEnv* env = GetJniEnv(); - return env->NewLocalRef(activity_); -} - -// Find a class, attempting to load the class if it's not found. -jclass JNIContext::FindClass(const char *class_name) { - JNIEnv *env = GetJniEnv(); - jclass class_object = env->FindClass(class_name); - if (env->ExceptionCheck()) { - env->ExceptionClear(); - // If the class isn't found it's possible NativeActivity is being used by - // the application which means the class path is set to only load system - // classes. The following falls back to loading the class using the - // Activity before retrieving a reference to it. - - jclass activity_class = env->FindClass("android/app/Activity"); - jmethodID activity_get_class_loader = env->GetMethodID( - activity_class, "getClassLoader", "()Ljava/lang/ClassLoader;"); - - jobject activity_instance = GetActivity(); - jobject class_loader_object = - env->CallObjectMethod(activity_instance, activity_get_class_loader); - - jclass class_loader_class = env->FindClass("java/lang/ClassLoader"); - jmethodID class_loader_load_class = - env->GetMethodID(class_loader_class, "loadClass", - "(Ljava/lang/String;)Ljava/lang/Class;"); - jstring class_name_object = env->NewStringUTF(class_name); - - class_object = static_cast(env->CallObjectMethod( - class_loader_object, class_loader_load_class, class_name_object)); - - if (env->ExceptionCheck()) { - env->ExceptionClear(); - class_object = nullptr; - } - env->DeleteLocalRef(activity_instance); - env->DeleteLocalRef(class_name_object); - env->DeleteLocalRef(class_loader_object); - } - return class_object; -} - -std::string JNIContext::JStringAsString(jstring j_str) { - if (!j_str) { - return ""; - } - JNIEnv* env = GetJniEnv(); - const char* buf = env->GetStringUTFChars(j_str, nullptr); - std::string return_string(buf); - env->ReleaseStringUTFChars(j_str, buf); - return return_string; -} - -std::string JNIContext::JStringToString(jstring j_str) { - JNIEnv* env = GetJniEnv(); - std::string return_string = JStringAsString(j_str); - env->DeleteLocalRef(j_str); - return return_string; -} - -} // namespace signin -} // namespace google diff --git a/staging/native/src/android/jni_context.h b/staging/native/src/android/jni_context.h deleted file mode 100644 index 8ce6d6c6..00000000 --- a/staging/native/src/android/jni_context.h +++ /dev/null @@ -1,71 +0,0 @@ -// Copyright 2018 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. - -#ifndef GOOGLESIGNIN_JNI_INIT_H -#define GOOGLESIGNIN_JNI_INIT_H - -// All methods in this header are meant for Android only. - -#include -#include -#include - -namespace google { -namespace signin { - -// This stores the JavaVM, assuming there's only ever one, and a global -// reference to an Activity. You can instantiate this for each activity, though -// any activity will work for all cases as it's just used to get access to -// non-system class loaders when using the FindClass method. -// Any thread that calls GetJniEnv is bound to the JavaVM and will -// automatically be detached when that thread exits. -class JNIContext { -public: - JNIContext(jobject activity, JavaVM *vm); - ~JNIContext(); - - // This could be static, but it should never be called before at least one - // instance is constructed. - JNIEnv* GetJniEnv(); - - // Returns a local reference to the activity used to construct this class. - // The user is expected to call DeleteLocalRef to avoid leaking. - jobject GetActivity(); - - // Find a class, attempting to load the class if it's not found. - jclass FindClass(const char *class_name); - - // Copies a Java String to an std::string. This does not delete the local - // reference to the jstring. - std::string JStringAsString(jstring j_str); - - // Like JStringAsString, but will also delete the local reference to the - // java string. - std::string JStringToString(jstring j_str); - -private: - // The docs say this has to be a c function. - // not sure if that means we cannot have it as a static. - // But, if there's a problem move this outside the class and use: - // extern "C" void DetachJVMThreads(void* thread_set_jvm); - static void DetachJVMThreads(void* stored_java_vm); - - static JavaVM *vm_; - jobject activity_; -}; - -} // namespace signin -} // namespace google - -#endif // GOOGLESIGNIN_JNI_INIT_H \ No newline at end of file diff --git a/staging/native/src/include/future.h b/staging/native/src/include/future.h deleted file mode 100644 index fd8e8799..00000000 --- a/staging/native/src/include/future.h +++ /dev/null @@ -1,41 +0,0 @@ -// Copyright 2018 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. - -#ifndef GOOGLESIGNIN_FUTURE_H // NOLINT -#define GOOGLESIGNIN_FUTURE_H - -namespace google { -namespace signin { - -// Provides a future promise for an asynchronous result of type -template -class Future { - public: - virtual ~Future() {} - // Returns the Status of the operation. This is set once Pending is false. - virtual int Status() const = 0; - - // Returns the Result of the operation if successful. If it is not - // successful, the error code should be retrieved using Status(). The result - // is available once Pending() is false. - virtual T* Result() const = 0; - - // Returns true while the promise has not been fulfilled by the operation. - // Once it is false, the Status and Result fields are populated. - virtual bool Pending() const = 0; -}; - -} // namespace signin -} // namespace google -#endif // GOOGLESIGNIN_FUTURE_H NOLINT diff --git a/staging/native/src/include/google_signin.h b/staging/native/src/include/google_signin.h deleted file mode 100644 index abd45072..00000000 --- a/staging/native/src/include/google_signin.h +++ /dev/null @@ -1,179 +0,0 @@ -// Copyright 2018 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. - -#ifndef GOOGLE_SIGNIN_GOOGLESIGNIN_H // NOLINT -#define GOOGLE_SIGNIN_GOOGLESIGNIN_H - -#include -#include - -#include "future.h" // NOLINT -#include "google_signin_user.h" // NOLINT - -#if defined(__ANDROID__) -#include -#endif - -namespace google { -namespace signin { - -class GoogleSignIn { - public: - /// StatusCode - /// These are based on - /// https://developers.google.com/android/reference/com/google/android/gms/common/api/CommonStatusCodes - /// and consistent with what is returned by the Google Sign-In API on both iOS - /// and Android. - /// - enum StatusCode { - /// The operation was successful, but used the device's cache. - /// - kStatusCodeSuccessCached = -1, - - /// The operation was successful. - kStatusCodeSuccess = 0, - - /// The result is uninitialized. - kStatusCodeUninitialized = 100, - - - /// The client attempted to connect to the service with an - /// invalid account name specified. - kStatusCodeInvalidAccount = 5, - - /// A network error occurred. Retrying should resolve the problem. - /// - kStatusCodeNetworkError = 7, - - /// An internal error occurred. Retrying should resolve the - /// problem. - kStatusCodeInternalError = 8, - - /// The application is misconfigured. - /// This error is not recoverable. - /// - /// The developer should look at the logs after this to determine - /// more actionable information. - /// - kStatusCodeDeveloperError = 10, - - /// The operation failed with no more detailed - /// information. - kStatusCodeError = 13, - - /// A blocking call was interrupted while waiting and did not - /// run to completion. - kStatusCodeInterrupted = 14, - - /// Timed out while awaiting the result. - kStatusCodeTimeout = 15, - - /// The result was canceled either due to client disconnect - /// or cancel(). - kStatusCodeCanceled = 16, - - /// The client attempted to call a method from an API that - /// failed to connect. - kStatusCodeApiNotConnected = 17, - }; - - // Defines the configuration for the sign-in process. - struct Configuration { - /// true to use games signin, false for default signin. - /// games signing only works on Android. - bool use_game_signin; - /// Web client id associated with this app. - std::string web_client_id; - /// true for getting an auth code when authenticating. - /// Note: This may trigger re-consent on iOS. Ideally, this - /// is set to true once, and the result sent to the server where the - /// token is managed forever. - bool request_auth_code; - /// true to request to reset the refresh token. Causes re-consent. - bool force_token_refresh; - /// request email address, requires consent. - bool request_email; - /// request id token, requires consent. - bool request_id_token; - /// used with games signin to show or hide the connecting popup UI. - /// and to associate an invisible view for other popups. This is - /// recommended for VR applications. - bool hide_ui_popups; - /// account name to use when authenticating, null indicates use default. - std::string account_name; - /// additional scopes to request, requires consent. - std::vector additional_scopes; - int additional_scope_count; - - Configuration(Configuration const ©) = default; - Configuration(Configuration &&move) = delete; - ~Configuration() = default; - - Configuration &operator=(Configuration const ©) = delete; - Configuration &operator=(Configuration &&move) = delete; - }; - - // Holds the result of the sign-in process. - struct SignInResult { - GoogleSignInUser *User; - int StatusCode; - - SignInResult() = default; - SignInResult(SignInResult const ©) = default; - SignInResult(SignInResult &&move) = delete; - ~SignInResult() = default; - - SignInResult &operator=(SignInResult const ©) = delete; - SignInResult &operator=(SignInResult &&move) = delete; - }; - - // Constructs a new instance. -#if defined(__ANDROID__) - GoogleSignIn(jobject activity, JavaVM *vm); -#else - GoogleSignIn(); -#endif - - // Enables verbose logging. - void EnableDebugLogging(bool flag); - - // Sets the configuration for the sign-in. This must be called before - // calling SignIn(). Calling this invalidates the current sign-in result. - void Configure(const Configuration &configuration); - - // Starts the authentication process. - Future &SignIn(); - - // Attempts to sign in silently. - Future &SignInSilently(); - - // Get the result of the last sign-in. - const Future *GetLastSignInResult(); - - // Signs out the local user. Any server side tokens are still valid. - void SignOut(); - - // Disconnects this user from the application. Invalidates all tokens and - // consent. - void Disconnect(); - - private: - class GoogleSignInImpl; - GoogleSignInImpl *impl_; -}; - -} // namespace signin -} // namespace google - -#endif // GOOGLESIGNIN_GOOGLESIGNIN_H NOLINT diff --git a/staging/native/src/include/google_signin_user.h b/staging/native/src/include/google_signin_user.h deleted file mode 100644 index c2f81ead..00000000 --- a/staging/native/src/include/google_signin_user.h +++ /dev/null @@ -1,46 +0,0 @@ -// Copyright 2018 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. - -#ifndef GOOGLESIGNIN_GOOGLE_SIGNIN_USER_H -#define GOOGLESIGNIN_GOOGLE_SIGNIN_USER_H - -namespace google { -namespace signin { - -class GoogleSignInUserImpl; - -// Represents the currently signed in user. -class GoogleSignInUser { - public: - ~GoogleSignInUser(); - - const char* GetDisplayName() const; - const char* GetEmail() const; - const char* GetFamilyName() const; - const char* GetGivenName() const; - const char* GetIdToken() const; - const char* GetImageUrl() const; - const char* GetServerAuthCode() const; - const char* GetUserId() const; - - private: - friend class GoogleSignInUserImpl; - GoogleSignInUser(); - GoogleSignInUser(GoogleSignInUserImpl* impl) : impl_(impl) {} - GoogleSignInUserImpl* impl_; -}; - -} // namespace signin -} // namespace google -#endif // GOOGLESIGNIN_GOOGLE_SIGNIN_USER_H diff --git a/staging/native/src/ios/GoogleSignIn.h b/staging/native/src/ios/GoogleSignIn.h deleted file mode 100644 index 5e77bc10..00000000 --- a/staging/native/src/ios/GoogleSignIn.h +++ /dev/null @@ -1,20 +0,0 @@ -/** - * Copyright 2017 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. - */ -#import -@interface GoogleSignInHandler - : NSObject - -@end diff --git a/staging/native/src/ios/GoogleSignIn.mm b/staging/native/src/ios/GoogleSignIn.mm deleted file mode 100644 index b6c30357..00000000 --- a/staging/native/src/ios/GoogleSignIn.mm +++ /dev/null @@ -1,314 +0,0 @@ -/** - * Copyright 2017 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. - */ -#import "GoogleSignIn.h" -#import -#import -#import -#import - -#import - -// These values are in the Unity plugin code. The iOS specific -// codes are mapped to these. -static const int kStatusCodeSuccessCached = -1; -static const int kStatusCodeSuccess = 0; -static const int kStatusCodeApiNotConnected = 1; -static const int kStatusCodeCanceled = 2; -static const int kStatusCodeInterrupted = 3; -static const int kStatusCodeInvalidAccount = 4; -static const int kStatusCodeTimeout = 5; -static const int kStatusCodeDeveloperError = 6; -static const int kStatusCodeInternalError = 7; -static const int kStatusCodeNetworkError = 8; -static const int kStatusCodeError = 9; - - -// result for pending operation. Access to this should be protected using the -// resultLock. -struct SignInResult { - int result_code; - bool finished; -}; - -std::unique_ptr currentResult_; - -NSRecursiveLock *resultLock = [NSRecursiveLock alloc]; - -@implementation GoogleSignInHandler - -/** - * The sign-in flow has finished and was successful if |error| is |nil|. - * Map the errors from the iOS SDK back to the Android values for consistency's - * sake in the Unity layer. - */ -- (void)signIn:(GIDSignIn *)signIn - didSignInForUser:(GIDGoogleUser *)user - withError:(NSError *)_error { - if (_error == nil) { - if (currentResult_) { - currentResult_->result_code = kStatusCodeSuccess; - currentResult_->finished = true; - } else { - NSLog(@"No currentResult to set status on!"); - } - NSLog(@"didSignInForUser: SUCCESS"); - } else { - NSLog(@"didSignInForUser: %@", _error.localizedDescription); - if (currentResult_) { - switch (_error.code) { - case kGIDSignInErrorCodeUnknown: - currentResult_->result_code = kStatusCodeError; - break; - case kGIDSignInErrorCodeKeychain: - currentResult_->result_code = kStatusCodeInternalError; - break; - case kGIDSignInErrorCodeNoSignInHandlersInstalled: - currentResult_->result_code = kStatusCodeDeveloperError; - break; - case kGIDSignInErrorCodeHasNoAuthInKeychain: - currentResult_->result_code = kStatusCodeError; - break; - case kGIDSignInErrorCodeCanceled: - currentResult_->result_code = kStatusCodeCanceled; - break; - default: - NSLog(@"Unmapped error code: %ld, returning Error", - static_cast(_error.code)); - currentResult_->result_code = kStatusCodeError; - } - - currentResult_->finished = true; - } else { - NSLog(@"No currentResult to set status on!"); - } - } -} - -// Finished disconnecting |user| from the app successfully if |error| is |nil|. -- (void)signIn:(GIDSignIn *)signIn - didDisconnectWithUser:(GIDGoogleUser *)user - withError:(NSError *)_error { - if (_error == nil) { - NSLog(@"didDisconnectWithUser: SUCCESS"); - } else { - NSLog(@"didDisconnectWithUser: %@", _error); - } -} - -@end - -/** - * These are the external "C" methods that are imported by the Unity C# code. - * The parameters are intended to be primative, easy to marshall. - */ -extern "C" { -/** - * This method does nothing in the iOS implementation. It is here - * to make the API uniform between Android and iOS. - */ -void *GoogleSignIn_Create(void *data) { return NULL; } - -void GoogleSignIn_EnableDebugLogging(void *unused, bool flag) { - if (flag) { - NSLog(@"GoogleSignIn: No optional logging available on iOS"); - } -} - -/** - * Configures the GIDSignIn instance. The first parameter is unused in iOS. - * It is here to make the API between Android and iOS uniform. - */ -bool GoogleSignIn_Configure(void *unused, bool useGameSignIn, - const char *webClientId, bool requestAuthCode, - bool forceTokenRefresh, bool requestEmail, - bool requestIdToken, bool hidePopups, - const char **additionalScopes, int scopeCount, - const char *accountName) { - if (webClientId) { - [GIDSignIn sharedInstance].serverClientID = - [NSString stringWithUTF8String:webClientId]; - } - - [GIDSignIn sharedInstance].shouldFetchBasicProfile = true; - - int scopeSize = scopeCount; - - if (scopeSize) { - NSMutableArray *tmpary = - [[NSMutableArray alloc] initWithCapacity:scopeSize]; - for (int i = 0; i < scopeCount; i++) { - [tmpary addObject:[NSString stringWithUTF8String:additionalScopes[i]]]; - } - - [GIDSignIn sharedInstance].scopes = tmpary; - } - - if (accountName) { - [GIDSignIn sharedInstance].loginHint = - [NSString stringWithUTF8String:accountName]; - } - - return !useGameSignIn; -} - -/** - Starts the sign-in process. Returns and error result if error, null otherwise. - */ -static SignInResult *startSignIn() { - bool busy = false; - [resultLock lock]; - if (!currentResult_ || currentResult_->finished) { - currentResult_.reset(new SignInResult()); - currentResult_->result_code = 0; - currentResult_->finished = false; - } else { - busy = true; - } - [resultLock unlock]; - - if (busy) { - NSLog(@"ERROR: There is already a pending sign-in operation."); - // Returned to the caller, should be deleted by calling - // GoogleSignIn_DisposeFuture(). - return new SignInResult{.result_code = kStatusCodeDeveloperError, - .finished = true}; - } - return nullptr; -} - -/** - * Sign-In. The return value is a pointer to the currentResult object. - */ -void *GoogleSignIn_SignIn() { - SignInResult *result = startSignIn(); - if (!result) { - [[GIDSignIn sharedInstance] signIn]; - result = currentResult_.get(); - } - return result; -} - -/** - * Attempt a silent sign-in. Return value is the pointer to the currentResult - * object. - */ -void *GoogleSignIn_SignInSilently() { - SignInResult *result = startSignIn(); - if (!result) { - [[GIDSignIn sharedInstance] signInSilently]; - result = currentResult_.get(); - } - return result; -} - -void GoogleSignIn_Signout() { - GIDSignIn *signIn = [GIDSignIn sharedInstance]; - [signIn signOut]; -} - -void GoogleSignIn_Disconnect() { - GIDSignIn *signIn = [GIDSignIn sharedInstance]; - [signIn disconnect]; -} - -bool GoogleSignIn_Pending(SignInResult *result) { - volatile bool ret; - [resultLock lock]; - ret = !result->finished; - [resultLock unlock]; - return ret; -} - -GIDGoogleUser *GoogleSignIn_Result(SignInResult *result) { - if (result && result->finished) { - GIDGoogleUser *guser = [GIDSignIn sharedInstance].currentUser; - return guser; - } - return nullptr; -} - -int GoogleSignIn_Status(SignInResult *result) { - if (result) { - return result->result_code; - } - return kStatusCodeDeveloperError; -} - -void GoogleSignIn_DisposeFuture(SignInResult *result) { - if (result == currentResult_.get()) { - currentResult_.reset(nullptr); - } else { - delete result; - } -} - -/** - * Private helper function to copy NSString to char*. If the destination is - * non-null, the contents of src are copied up to len bytes (using strncpy). The - * then len is returned. Otherwise returns length of the string to copy + 1. - */ -static size_t CopyNSString(NSString *src, char *dest, size_t len) { - if (dest && src && len) { - const char *string = [src UTF8String]; - strncpy(dest, string, len); - return len; - } - return src ? src.length + 1 : 0; -} - -size_t GoogleSignIn_GetServerAuthCode(GIDGoogleUser *guser, char *buf, - size_t len) { - NSString *val = [guser serverAuthCode]; - return CopyNSString(val, buf, len); -} - -size_t GoogleSignIn_GetDisplayName(GIDGoogleUser *guser, char *buf, - size_t len) { - NSString *val = [guser.profile name]; - return CopyNSString(val, buf, len); -} - -size_t GoogleSignIn_GetEmail(GIDGoogleUser *guser, char *buf, size_t len) { - NSString *val = [guser.profile email]; - return CopyNSString(val, buf, len); -} - -size_t GoogleSignIn_GetFamilyName(GIDGoogleUser *guser, char *buf, size_t len) { - NSString *val = [guser.profile familyName]; - return CopyNSString(val, buf, len); -} - -size_t GoogleSignIn_GetGivenName(GIDGoogleUser *guser, char *buf, size_t len) { - NSString *val = [guser.profile givenName]; - return CopyNSString(val, buf, len); -} - -size_t GoogleSignIn_GetIdToken(GIDGoogleUser *guser, char *buf, size_t len) { - NSString *val = [guser.authentication idToken]; - return CopyNSString(val, buf, len); -} - -size_t GoogleSignIn_GetImageUrl(GIDGoogleUser *guser, char *buf, size_t len) { - NSURL *url = [guser.profile imageURLWithDimension:128]; - NSString *val = url ? [url absoluteString] : nullptr; - return CopyNSString(val, buf, len); -} - -size_t GoogleSignIn_GetUserId(GIDGoogleUser *guser, char *buf, size_t len) { - NSString *val = [guser userID]; - return CopyNSString(val, buf, len); -} -} // extern "C" diff --git a/staging/native/testapp/LaunchScreen.storyboard b/staging/native/testapp/LaunchScreen.storyboard deleted file mode 100644 index 673e0f7e..00000000 --- a/staging/native/testapp/LaunchScreen.storyboard +++ /dev/null @@ -1,7 +0,0 @@ - - - - - - - diff --git a/staging/native/testapp/Podfile b/staging/native/testapp/Podfile deleted file mode 100644 index b115e020..00000000 --- a/staging/native/testapp/Podfile +++ /dev/null @@ -1,7 +0,0 @@ -use_frameworks! -platform :ios, '8.0' - -target 'testapp' do - pod 'GoogleSignInCpp', :path => '../' - -end diff --git a/staging/native/testapp/build.gradle b/staging/native/testapp/build.gradle deleted file mode 100644 index 40da1bd8..00000000 --- a/staging/native/testapp/build.gradle +++ /dev/null @@ -1,110 +0,0 @@ -/* Copyright (C) 2018 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. - */ -buildscript { - repositories { - jcenter() - } - dependencies { - classpath 'com.android.tools.build:gradle:2.3.3' - } -} - -allprojects { - repositories { - jcenter() - maven { - url "https://maven.google.com" - } - flatDir { - // Add the path to the google sign in library so the local AAR - // can be found. 'Compile' referencing a relative file doesn't work - // with AAR files, so we need to use this method instead. - dirs '../google-signin-cpp' - } - } -} - -apply plugin: 'com.android.application' - -project.ext { - ndk_dir = project.android.ndkDirectory - if (ndk_dir == null || !ndk_dir.exists()) { - ndk_dir = System.getenv('ANDROID_NDK_HOME') - if (ndk_dir == null || ndk_dir.isEmpty()) { - throw new StopActionException( - 'Android NDK directory should be specified using the ndk.dir ' + - 'property or ANDROID_NDK_HOME environment variable.') - } - } - - if (project.hasProperty("pluginVersion")) { - version = project.pluginVersion - } else { - version '1.0.0' - } - - baseName = "signin-testapp" -} - -android { - compileSdkVersion 26 - buildToolsVersion '26.0.3' - - sourceSets { - main { - manifest.srcFile 'src/android/AndroidManifest.xml' - java.srcDirs = ['src/android/java'] - jniLibs.srcDirs = ['../plugin/libs'] - res.srcDirs = ['src/android/res'] - } - } - lintOptions { - abortOnError false - } - defaultConfig { - applicationId 'com.google.signin.testapp' - minSdkVersion 14 - targetSdkVersion 26 - versionName project.version - archivesBaseName = project.ext.baseName - externalNativeBuild { - cmake { - cppFlags "-std=c++11", "-Wall" - } - } - ndk { - abiFilters 'x86', 'armeabi-v7a' - } - } - buildTypes { - release { - minifyEnabled false - proguardFiles getDefaultProguardFile('proguard-android.txt') - } - } - externalNativeBuild { - cmake { - path "src/android/CMakeLists.txt" - } - } -} - -dependencies { - compile 'com.google.android.gms:play-services-auth:11.8.0' - // Depend on the AAR built with the google sign in library in order to add - // the java helper classes which are used by the c++ library. - compile(name:'google-signin-cpp-release', ext:'aar') -} - diff --git a/staging/native/testapp/gradle/wrapper/gradle-wrapper.jar b/staging/native/testapp/gradle/wrapper/gradle-wrapper.jar deleted file mode 100644 index 463732c909dfb41bb8b8c0d1672e7a4aa895b406..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 54208 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 \(.*\)$'` - if expr "$link" : '/.*' > /dev/null; then - PRG="$link" - else - PRG=`dirname "$PRG"`"/$link" - fi -done -SAVED="`pwd`" -cd "`dirname \"$PRG\"`/" >/dev/null -APP_HOME="`pwd -P`" -cd "$SAVED" >/dev/null - -APP_NAME="Gradle" -APP_BASE_NAME=`basename "$0"` - -# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. -DEFAULT_JVM_OPTS="" - -# Use the maximum available, or set MAX_FD != -1 to use that value. -MAX_FD="maximum" - -warn ( ) { - echo "$*" -} - -die ( ) { - echo - echo "$*" - echo - exit 1 -} - -# OS specific support (must be 'true' or 'false'). -cygwin=false -msys=false -darwin=false -nonstop=false -case "`uname`" in - CYGWIN* ) - cygwin=true - ;; - Darwin* ) - darwin=true - ;; - MINGW* ) - msys=true - ;; - NONSTOP* ) - nonstop=true - ;; -esac - -CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar - -# Determine the Java command to use to start the JVM. -if [ -n "$JAVA_HOME" ] ; then - if [ -x "$JAVA_HOME/jre/sh/java" ] ; then - # IBM's JDK on AIX uses strange locations for the executables - JAVACMD="$JAVA_HOME/jre/sh/java" - else - JAVACMD="$JAVA_HOME/bin/java" - fi - if [ ! -x "$JAVACMD" ] ; then - die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME - -Please set the JAVA_HOME variable in your environment to match the -location of your Java installation." - fi -else - JAVACMD="java" - which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. - -Please set the JAVA_HOME variable in your environment to match the -location of your Java installation." -fi - -# Increase the maximum file descriptors if we can. -if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then - MAX_FD_LIMIT=`ulimit -H -n` - if [ $? -eq 0 ] ; then - if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then - MAX_FD="$MAX_FD_LIMIT" - fi - ulimit -n $MAX_FD - if [ $? -ne 0 ] ; then - warn "Could not set maximum file descriptor limit: $MAX_FD" - fi - else - warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" - fi -fi - -# For Darwin, add options to specify how the application appears in the dock -if $darwin; then - GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" -fi - -# For Cygwin, switch paths to Windows format before running java -if $cygwin ; then - APP_HOME=`cygpath --path --mixed "$APP_HOME"` - CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` - JAVACMD=`cygpath --unix "$JAVACMD"` - - # We build the pattern for arguments to be converted via cygpath - ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` - SEP="" - for dir in $ROOTDIRSRAW ; do - ROOTDIRS="$ROOTDIRS$SEP$dir" - SEP="|" - done - OURCYGPATTERN="(^($ROOTDIRS))" - # Add a user-defined pattern to the cygpath arguments - if [ "$GRADLE_CYGPATTERN" != "" ] ; then - OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" - fi - # Now convert the arguments - kludge to limit ourselves to /bin/sh - i=0 - for arg in "$@" ; do - CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` - CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option - - if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition - eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` - else - eval `echo args$i`="\"$arg\"" - fi - i=$((i+1)) - done - case $i in - (0) set -- ;; - (1) set -- "$args0" ;; - (2) set -- "$args0" "$args1" ;; - (3) set -- "$args0" "$args1" "$args2" ;; - (4) set -- "$args0" "$args1" "$args2" "$args3" ;; - (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; - (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; - (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; - (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; - (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; - esac -fi - -# Escape application args -save ( ) { - for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done - echo " " -} -APP_ARGS=$(save "$@") - -# Collect all arguments for the java command, following the shell quoting and substitution rules -eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS" - -# by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong -if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then - cd "$(dirname "$0")" -fi - -exec "$JAVACMD" "$@" diff --git a/staging/native/testapp/gradlew.bat b/staging/native/testapp/gradlew.bat deleted file mode 100644 index e95643d6..00000000 --- a/staging/native/testapp/gradlew.bat +++ /dev/null @@ -1,84 +0,0 @@ -@if "%DEBUG%" == "" @echo off -@rem ########################################################################## -@rem -@rem Gradle startup script for Windows -@rem -@rem ########################################################################## - -@rem Set local scope for the variables with windows NT shell -if "%OS%"=="Windows_NT" setlocal - -set DIRNAME=%~dp0 -if "%DIRNAME%" == "" set DIRNAME=. -set APP_BASE_NAME=%~n0 -set APP_HOME=%DIRNAME% - -@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. -set DEFAULT_JVM_OPTS= - -@rem Find java.exe -if defined JAVA_HOME goto findJavaFromJavaHome - -set JAVA_EXE=java.exe -%JAVA_EXE% -version >NUL 2>&1 -if "%ERRORLEVEL%" == "0" goto init - -echo. -echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. -echo. -echo Please set the JAVA_HOME variable in your environment to match the -echo location of your Java installation. - -goto fail - -:findJavaFromJavaHome -set JAVA_HOME=%JAVA_HOME:"=% -set JAVA_EXE=%JAVA_HOME%/bin/java.exe - -if exist "%JAVA_EXE%" goto init - -echo. -echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% -echo. -echo Please set the JAVA_HOME variable in your environment to match the -echo location of your Java installation. - -goto fail - -:init -@rem Get command-line arguments, handling Windows variants - -if not "%OS%" == "Windows_NT" goto win9xME_args - -:win9xME_args -@rem Slurp the command line arguments. -set CMD_LINE_ARGS= -set _SKIP=2 - -:win9xME_args_slurp -if "x%~1" == "x" goto execute - -set CMD_LINE_ARGS=%* - -:execute -@rem Setup the command line - -set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar - -@rem Execute Gradle -"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% - -:end -@rem End local scope for the variables with windows NT shell -if "%ERRORLEVEL%"=="0" goto mainEnd - -:fail -rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of -rem the _cmd.exe /c_ return code! -if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 -exit /b 1 - -:mainEnd -if "%OS%"=="Windows_NT" endlocal - -:omega diff --git a/staging/native/testapp/src/android/AndroidManifest.xml b/staging/native/testapp/src/android/AndroidManifest.xml deleted file mode 100644 index 7ed7551d..00000000 --- a/staging/native/testapp/src/android/AndroidManifest.xml +++ /dev/null @@ -1,22 +0,0 @@ - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/staging/native/testapp/src/android/CMakeLists.txt b/staging/native/testapp/src/android/CMakeLists.txt deleted file mode 100644 index 48ca1d81..00000000 --- a/staging/native/testapp/src/android/CMakeLists.txt +++ /dev/null @@ -1,57 +0,0 @@ -# Copyright 2018 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. -# - -# For more information about using CMake with Android Studio, read the -# documentation: https://d.android.com/studio/projects/add-native-code.html - -# Sets the minimum version of CMake required to build the native library. -cmake_minimum_required(VERSION 3.4.1) - -add_library(native-app-glue - STATIC - ${ANDROID_NDK}/sources/android/native_app_glue/android_native_app_glue.c) - -# now build app's shared lib -set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=gnu++11 -Wall -Werror") - -set(GSI_PACKAGE_DIR "${CMAKE_SOURCE_DIR}/../../../google-signin-cpp") -add_library(lib-google-signin-cpp STATIC IMPORTED) -set_target_properties(lib-google-signin-cpp PROPERTIES IMPORTED_LOCATION - ${GSI_PACKAGE_DIR}/lib/${ANDROID_ABI}/libgoogle-signin-cpp.a ) - -# Our testapp is an SO the native app loads. -add_library(signin-testapp - SHARED - ../common_main.cpp - android_main.cpp) - -# Export ANativeActivity_onCreate(), -# Refer to: https://github.com/android-ndk/ndk/issues/381. -set(CMAKE_SHARED_LINKER_FLAGS - "${CMAKE_SHARED_LINKER_FLAGS} -u ANativeActivity_onCreate") - -# Add lib inlcudes -target_include_directories(signin-testapp - PRIVATE - ${ANDROID_NDK}/sources/android/native_app_glue - ${GSI_PACKAGE_DIR}/include - ..) - -# add lib dependencies -target_link_libraries(signin-testapp - android - lib-google-signin-cpp - native-app-glue - log) diff --git a/staging/native/testapp/src/android/android_main.cpp b/staging/native/testapp/src/android/android_main.cpp deleted file mode 100644 index 242e6f0f..00000000 --- a/staging/native/testapp/src/android/android_main.cpp +++ /dev/null @@ -1,254 +0,0 @@ -// Copyright 2018 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. - -#include -#include - -#include -#include -#include -#include - -#include "main.h" // NOLINT - -// This implementation is derived from http://github.com/google/fplutil - -extern "C" int common_main(int argc, const char* argv[]); - -static struct android_app* g_app_state = nullptr; -static bool g_destroy_requested = false; -static bool g_started = false; -static bool g_restarted = false; -static pthread_mutex_t g_started_mutex; - -// Handle state changes from via native app glue. -static void OnAppCmd(struct android_app* app, int32_t cmd) { - g_destroy_requested |= cmd == APP_CMD_DESTROY; -} - -// Process events pending on the main thread. -// Returns true when the app receives an event requesting exit. -bool ProcessEvents(int msec) { - struct android_poll_source* source = nullptr; - int events; - int looperId = ALooper_pollAll(msec, nullptr, &events, - reinterpret_cast(&source)); - if (looperId >= 0 && source) { - source->process(g_app_state, source); - } - return g_destroy_requested | g_restarted; -} - -JNIEnv* GetJniEnv() { - JavaVM* vm = g_app_state->activity->vm; - JNIEnv* env; - jint result = vm->AttachCurrentThread(&env, nullptr); - return result == JNI_OK ? env : nullptr; -} - -jobject GetActivity() { return g_app_state->activity->clazz; } -JavaVM* GetJavaVM() { return g_app_state->activity->vm; } - -// Get the window context. For Android, it's a jobject pointing to the Activity. -jobject GetWindowContext() { return g_app_state->activity->clazz; } - -// Find a class, attempting to load the class if it's not found. -jclass FindClass(JNIEnv* env, jobject activity_object, const char* class_name) { - jclass class_object = env->FindClass(class_name); - if (env->ExceptionCheck()) { - env->ExceptionClear(); - // If the class isn't found it's possible NativeActivity is being used by - // the application which means the class path is set to only load system - // classes. The following falls back to loading the class using the - // Activity before retrieving a reference to it. - jclass activity_class = env->FindClass("android/app/Activity"); - jmethodID activity_get_class_loader = env->GetMethodID( - activity_class, "getClassLoader", "()Ljava/lang/ClassLoader;"); - - jobject class_loader_object = - env->CallObjectMethod(activity_object, activity_get_class_loader); - - jclass class_loader_class = env->FindClass("java/lang/ClassLoader"); - jmethodID class_loader_load_class = - env->GetMethodID(class_loader_class, "loadClass", - "(Ljava/lang/String;)Ljava/lang/Class;"); - jstring class_name_object = env->NewStringUTF(class_name); - - class_object = static_cast(env->CallObjectMethod( - class_loader_object, class_loader_load_class, class_name_object)); - - if (env->ExceptionCheck()) { - env->ExceptionClear(); - class_object = nullptr; - } - env->DeleteLocalRef(class_name_object); - env->DeleteLocalRef(class_loader_object); - } - return class_object; -} - -// Vars that we need available for appending text to the log window: -class LoggingUtilsData { - public: - LoggingUtilsData() - : logging_utils_class_(nullptr), - logging_utils_add_log_text_(0), - logging_utils_init_log_window_(0) {} - - ~LoggingUtilsData() { - JNIEnv* env = GetJniEnv(); - assert(env); - if (logging_utils_class_) { - env->DeleteGlobalRef(logging_utils_class_); - } - } - - void Init() { - JNIEnv* env = GetJniEnv(); - assert(env); - - jclass logging_utils_class = FindClass( - env, GetActivity(), "com/google/signin/testapp/LoggingUtils"); - assert(logging_utils_class != 0); - - // Need to store as global references so it don't get moved during garbage - // collection. - logging_utils_class_ = - static_cast(env->NewGlobalRef(logging_utils_class)); - env->DeleteLocalRef(logging_utils_class); - - logging_utils_init_log_window_ = env->GetStaticMethodID( - logging_utils_class_, "initLogWindow", "(Landroid/app/Activity;)V"); - logging_utils_add_log_text_ = env->GetStaticMethodID( - logging_utils_class_, "addLogText", "(Ljava/lang/String;)V"); - - env->CallStaticVoidMethod(logging_utils_class_, - logging_utils_init_log_window_, GetActivity()); - } - - void AppendText(const char* text) { - if (logging_utils_class_ == 0) return; // haven't been initted yet - JNIEnv* env = GetJniEnv(); - assert(env); - jstring text_string = env->NewStringUTF(text); - env->CallStaticVoidMethod(logging_utils_class_, logging_utils_add_log_text_, - text_string); - env->DeleteLocalRef(text_string); - } - - private: - jclass logging_utils_class_; - jmethodID logging_utils_add_log_text_; - jmethodID logging_utils_init_log_window_; -}; - -LoggingUtilsData* g_logging_utils_data; - -// Checks if a JNI exception has happened, and if so, logs it to the console. -void CheckJNIException() { - JNIEnv* env = GetJniEnv(); - if (env->ExceptionCheck()) { - // Get the exception text. - jthrowable exception = env->ExceptionOccurred(); - env->ExceptionClear(); - - // Convert the exception to a string. - jclass object_class = env->FindClass("java/lang/Object"); - jmethodID toString = - env->GetMethodID(object_class, "toString", "()Ljava/lang/String;"); - jstring s = (jstring)env->CallObjectMethod(exception, toString); - const char* exception_text = env->GetStringUTFChars(s, nullptr); - - // Log the exception text. - __android_log_print(ANDROID_LOG_INFO, APP_NAME, - "-------------------JNI exception:"); - __android_log_print(ANDROID_LOG_INFO, APP_NAME, "%s", - exception_text); - __android_log_print(ANDROID_LOG_INFO, APP_NAME, - "-------------------"); - - // Also, assert fail. - assert(false); - - // In the event we didn't assert fail, clean up. - env->ReleaseStringUTFChars(s, exception_text); - env->DeleteLocalRef(s); - env->DeleteLocalRef(exception); - } -} - -// Log a message that can be viewed in "adb logcat". -void LogMessage(const char* format, ...) { - static const int kLineBufferSize = 100; - char buffer[kLineBufferSize + 2]; - - va_list list; - va_start(list, format); - int string_len = vsnprintf(buffer, kLineBufferSize, format, list); - string_len = string_len < kLineBufferSize ? string_len : kLineBufferSize; - // append a linebreak to the buffer: - buffer[string_len] = '\n'; - buffer[string_len + 1] = '\0'; - - __android_log_vprint(ANDROID_LOG_INFO, APP_NAME, format, list); - g_logging_utils_data->AppendText(buffer); - CheckJNIException(); - va_end(list); -} - -// Execute common_main(), flush pending events and finish the activity. -extern "C" void android_main(struct android_app* state) { - // native_app_glue spawns a new thread, calling android_main() when the - // activity onStart() or onRestart() methods are called. This code handles - // the case where we're re-entering this method on a different thread by - // signalling the existing thread to exit, waiting for it to complete before - // reinitializing the application. - if (g_started) { - g_restarted = true; - // Wait for the existing thread to exit. - pthread_mutex_lock(&g_started_mutex); - pthread_mutex_unlock(&g_started_mutex); - } else { - g_started_mutex = PTHREAD_MUTEX_INITIALIZER; - } - pthread_mutex_lock(&g_started_mutex); - g_started = true; - - // Save native app glue state and setup a callback to track the state. - g_destroy_requested = false; - g_app_state = state; - g_app_state->onAppCmd = OnAppCmd; - - // Create the logging display. - g_logging_utils_data = new LoggingUtilsData(); - g_logging_utils_data->Init(); - - // Execute cross platform entry point. - static const char* argv[] = {APP_NAME}; - int return_value = common_main(1, argv); - (void)return_value; // Ignore the return value. - ProcessEvents(10); - - // Clean up logging display. - delete g_logging_utils_data; - g_logging_utils_data = nullptr; - - // Finish the activity. - if (!g_restarted) ANativeActivity_finish(state->activity); - - g_app_state->activity->vm->DetachCurrentThread(); - g_started = false; - g_restarted = false; - pthread_mutex_unlock(&g_started_mutex); -} \ No newline at end of file diff --git a/staging/native/testapp/src/android/java/com/google/signin/testapp/LoggingUtils.java b/staging/native/testapp/src/android/java/com/google/signin/testapp/LoggingUtils.java deleted file mode 100644 index dc1f4c06..00000000 --- a/staging/native/testapp/src/android/java/com/google/signin/testapp/LoggingUtils.java +++ /dev/null @@ -1,55 +0,0 @@ -// Copyright 2018 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. - -package com.google.signin.testapp; - -import android.app.Activity; -import android.os.Handler; -import android.os.Looper; -import android.view.Window; -import android.widget.LinearLayout; -import android.widget.ScrollView; -import android.widget.TextView; - -/** - * A utility class, encapsulating the data and methods required to log arbitrary - * text to the screen, via a non-editable TextView. - */ -public class LoggingUtils { - public static TextView sTextView = null; - - public static void initLogWindow(Activity activity) { - LinearLayout linearLayout = new LinearLayout(activity); - ScrollView scrollView = new ScrollView(activity); - TextView textView = new TextView(activity); - textView.setTag("Logger"); - linearLayout.addView(scrollView); - scrollView.addView(textView); - Window window = activity.getWindow(); - window.takeSurface(null); - window.setContentView(linearLayout); - sTextView = textView; - } - - public static void addLogText(final String text) { - new Handler(Looper.getMainLooper()).post(new Runnable() { - @Override - public void run() { - if (sTextView != null) { - sTextView.append(text); - } - } - }); - } -} diff --git a/staging/native/testapp/src/android/java/com/google/signin/testapp/TextEntryField.java b/staging/native/testapp/src/android/java/com/google/signin/testapp/TextEntryField.java deleted file mode 100644 index e6ea7542..00000000 --- a/staging/native/testapp/src/android/java/com/google/signin/testapp/TextEntryField.java +++ /dev/null @@ -1,106 +0,0 @@ -// Copyright 2018 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. - -package com.google.signin.testapp; - -import android.app.Activity; -import android.app.AlertDialog; -import android.content.DialogInterface; -import android.widget.EditText; - -/** - * A utility class, with a method to prompt the user to enter a line of text, and a native method to - * sleep for a given number of milliseconds. - */ -public class TextEntryField { - private static Object lock = new Object(); - private static String resultText = null; - - /** - * Prompt the user with a text field, blocking until the user fills it out, then returns the text - * they entered. If the user cancels, returns an empty string. - */ - public static String readText( - final Activity activity, final String title, final String message, final String placeholder) { - resultText = null; - // Show the alert dialog on the main thread. - activity.runOnUiThread( - new Runnable() { - @Override - public void run() { - AlertDialog.Builder alertBuilder = new AlertDialog.Builder(activity); - alertBuilder.setTitle(title); - alertBuilder.setMessage(message); - - // Set up and add the text field. - final EditText textField = new EditText(activity); - textField.setHint(placeholder); - alertBuilder.setView(textField); - - alertBuilder.setPositiveButton( - "OK", - new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialog, int whichButton) { - synchronized (lock) { - resultText = textField.getText().toString(); - } - } - }); - - alertBuilder.setNegativeButton( - "Cancel", - new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialog, int whichButton) { - synchronized (lock) { - resultText = ""; - } - } - }); - - alertBuilder.setOnCancelListener( - new DialogInterface.OnCancelListener() { - @Override - public void onCancel(DialogInterface dialog) { - synchronized (lock) { - resultText = ""; - } - } - }); - alertBuilder.show(); - } - }); - - // In our original thread, wait for the dialog to finish, then return its result. - while (true) { - // Pause a second, waiting for the user to enter text. - if (nativeSleep(1000)) { - // If this returns true, an exit was requested. - return ""; - } - synchronized (lock) { - if (resultText != null) { - // resultText will be set to non-null when a dialog button is clicked, or the dialog - // is canceled. - String result = resultText; - resultText = null; // Consume the result. - return result; - } - } - } - } - - private static native boolean nativeSleep(int milliseconds); -} diff --git a/staging/native/testapp/src/android/res/layout/main.xml b/staging/native/testapp/src/android/res/layout/main.xml deleted file mode 100644 index d0ffcb82..00000000 --- a/staging/native/testapp/src/android/res/layout/main.xml +++ /dev/null @@ -1,17 +0,0 @@ - - - - - diff --git a/staging/native/testapp/src/android/res/values/strings.xml b/staging/native/testapp/src/android/res/values/strings.xml deleted file mode 100644 index 8c8e1ed3..00000000 --- a/staging/native/testapp/src/android/res/values/strings.xml +++ /dev/null @@ -1,4 +0,0 @@ - - - Google Signin Testapp - diff --git a/staging/native/testapp/src/common_main.cpp b/staging/native/testapp/src/common_main.cpp deleted file mode 100644 index 74ffa9dc..00000000 --- a/staging/native/testapp/src/common_main.cpp +++ /dev/null @@ -1,81 +0,0 @@ -// Copyright 2018 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. - - -// This is platform agnostic test code of the C++ GSI API. -// The platform specific bootstraps are in android/ and ios/ respectively, -// and those call into this to do the API calls. - -#include "main.h" - -#include "google_signin.h" -#include "future.h" - -using namespace google::signin; - -// Don't return until `future` is complete. -// Print a message for whether the result mathes our expectations. -// Returns true if the application should exit. -template -bool WaitForFuture(Future &future, const char* fn, - GoogleSignIn::StatusCode expected_error, - bool log_error = true) { - // Wait for future to complete. - LogMessage(" Calling %s...", fn); - while (future.Pending()) { - if (ProcessEvents(100)) return true; - } - - // Log error result. - if (log_error) { - const GoogleSignIn::StatusCode error = - static_cast(future.Status()); - if (error == expected_error) { - LogMessage("%s completed as expected", fn); - } else { - LogMessage("ERROR: %s completed with error: %d", fn, error); - } - } - return false; -} - -extern "C" int common_main(int argc, const char* argv[]) { - - LogMessage("GSI Testapp Initialized!"); - - GoogleSignIn::Configuration config = {}; - config.web_client_id = "64192632067-d37vn8fg59u8pvdgc7lc8jeve9mbbd7o.apps.googleusercontent.com"; // "YOUR_WEB_CLIENT_ID_HERE"; - config.request_id_token = true; - config.use_game_signin = false; - config.request_auth_code = false; - - LogMessage("Constructing..."); -#if defined(__ANDROID__) - GoogleSignIn gsi = GoogleSignIn(GetActivity(), GetJavaVM()); -#else - GoogleSignIn gsi = GoogleSignIn(); -#endif // defined(__ANDROID__) - - LogMessage("Calling Configure..."); - gsi.Configure(config); - - LogMessage("Calling SignIn..."); - Future &future = gsi.SignIn(); - WaitForFuture(future, "GoogleSignIn::SignIn()", GoogleSignIn::kStatusCodeSuccess); - - while (!ProcessEvents(1000)) { - } - - return 0; -} diff --git a/staging/native/testapp/src/ios/ios_main.mm b/staging/native/testapp/src/ios/ios_main.mm deleted file mode 100644 index 57fc138e..00000000 --- a/staging/native/testapp/src/ios/ios_main.mm +++ /dev/null @@ -1,174 +0,0 @@ -// Copyright 2016 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. - -#import - -#include -#include - -#include "main.h" - -extern "C" int common_main(int argc, const char* argv[]); - -@interface AppDelegate : UIResponder - -@property(nonatomic, strong) UIWindow *window; - -@end - -@interface FTAViewController : UIViewController - -@property(atomic, strong) NSString *textEntryResult; - -@end - -static int g_exit_status = 0; -static bool g_shutdown = false; -static NSCondition *g_shutdown_complete; -static NSCondition *g_shutdown_signal; -static UITextView *g_text_view; -static UIView *g_parent_view; -static FTAViewController *g_view_controller; - -@implementation FTAViewController - -- (void)viewDidLoad { - [super viewDidLoad]; - g_parent_view = self.view; - dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ - const char *argv[] = {"FIREBASE_TESTAPP_NAME"}; - [g_shutdown_signal lock]; - g_exit_status = common_main(1, argv); - [g_shutdown_complete signal]; - }); -} - -@end - -bool ProcessEvents(int msec) { - [g_shutdown_signal - waitUntilDate:[NSDate dateWithTimeIntervalSinceNow:static_cast(msec) / 1000.0f]]; - return g_shutdown; -} - -WindowContext GetWindowContext() { - return g_parent_view; -} - -// Log a message that can be viewed in the console. -void LogMessage(const char* format, ...) { - va_list args; - NSString *formatString = @(format); - - va_start(args, format); - NSString *message = [[NSString alloc] initWithFormat:formatString arguments:args]; - va_end(args); - - NSLog(@"%@", message); - message = [message stringByAppendingString:@"\n"]; - - dispatch_async(dispatch_get_main_queue(), ^{ - g_text_view.text = [g_text_view.text stringByAppendingString:message]; - }); -} - -int main(int argc, char* argv[]) { - @autoreleasepool { - UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class])); - } - return g_exit_status; -} - -// Create an alert dialog via UIAlertController, and prompt the user to enter a line of text. -// This function spins until the text has been entered (or the alert dialog was canceled). -// If the user cancels, returns an empty string. -std::string ReadTextInput(const char *title, const char *message, const char *placeholder) { - assert(g_view_controller); - // This should only be called from a background thread, as it blocks, which will mess up the main - // thread. - assert(![NSThread isMainThread]); - - g_view_controller.textEntryResult = nil; - - dispatch_async(dispatch_get_main_queue(), ^{ - UIAlertController *alertController = - [UIAlertController alertControllerWithTitle:@(title) - message:@(message) - preferredStyle:UIAlertControllerStyleAlert]; - [alertController addTextFieldWithConfigurationHandler:^(UITextField *_Nonnull textField) { - textField.placeholder = @(placeholder); - }]; - UIAlertAction *confirmAction = [UIAlertAction - actionWithTitle:@"OK" - style:UIAlertActionStyleDefault - handler:^(UIAlertAction *_Nonnull action) { - g_view_controller.textEntryResult = alertController.textFields.firstObject.text; - }]; - [alertController addAction:confirmAction]; - UIAlertAction *cancelAction = [UIAlertAction actionWithTitle:@"Cancel" - style:UIAlertActionStyleCancel - handler:^(UIAlertAction *_Nonnull action) { - g_view_controller.textEntryResult = @""; - }]; - [alertController addAction:cancelAction]; - [g_view_controller presentViewController:alertController animated:YES completion:nil]; - }); - - while (true) { - // Pause a second, waiting for the user to enter text. - if (ProcessEvents(1000)) { - // If this returns true, an exit was requested. - return ""; - } - if (g_view_controller.textEntryResult != nil) { - // textEntryResult will be set to non-nil when a dialog button is clicked. - std::string result = g_view_controller.textEntryResult.UTF8String; - g_view_controller.textEntryResult = nil; // Consume the result. - return result; - } - } -} - -@implementation AppDelegate - -- (BOOL)application:(UIApplication*)application - didFinishLaunchingWithOptions:(NSDictionary*)launchOptions { - g_shutdown_complete = [[NSCondition alloc] init]; - g_shutdown_signal = [[NSCondition alloc] init]; - [g_shutdown_complete lock]; - - self.window = [[UIWindow alloc] initWithFrame:[UIScreen mainScreen].bounds]; - g_view_controller = [[FTAViewController alloc] init]; - self.window.rootViewController = g_view_controller; - [self.window makeKeyAndVisible]; - - g_text_view = [[UITextView alloc] initWithFrame:g_view_controller.view.bounds]; - - g_text_view.editable = NO; - g_text_view.scrollEnabled = YES; - g_text_view.userInteractionEnabled = YES; - - [g_view_controller.view addSubview:g_text_view]; - - return YES; -} - -- (void)applicationWillTerminate:(UIApplication *)application { - g_view_controller = nil; - g_shutdown = true; - [g_shutdown_signal signal]; - [g_shutdown_complete wait]; -} - -@end diff --git a/staging/native/testapp/src/main.h b/staging/native/testapp/src/main.h deleted file mode 100644 index a3b98f17..00000000 --- a/staging/native/testapp/src/main.h +++ /dev/null @@ -1,54 +0,0 @@ -// Copyright 2018 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. - -#ifndef TESTAPP_MAIN_H -#define TESTAPP_MAIN_H - -#if defined(__ANDROID__) -#include -#include -jobject GetActivity(); -JavaVM* GetJavaVM(); -#elif defined(__APPLE__) -extern "C" { -#include -} // extern "C" -#endif // __ANDROID__ - -// Fallback, if not defined using -DAPP_NAME=some_app_name when compiling -// this file. -#ifndef APP_NAME -#define APP_NAME "gsi_testapp" -#endif // APP_NAME - -// WindowContext represents the handle to the parent window. It's type -// (and usage) vary based on the OS. -#if defined(__ANDROID__) -typedef jobject WindowContext; // A jobject to the Java Activity. -#elif defined(__APPLE__) -typedef id WindowContext; // A pointer to an iOS UIView. -#else -typedef void* WindowContext; // A void* for any other environments. -#endif - -// Cross platform logging method. -// Implemented by android/android_main.cc or ios/ios_main.mm. -extern "C" void LogMessage(const char* format, ...); - -// Cross platform method to flush pending events for the main thread. -// Implemented by android/android_main.cc or ios/ios_main.mm. -// Returns true when an event requesting program-exit is received. -bool ProcessEvents(int msec); - -#endif // TESTAPP_MAIN_H \ No newline at end of file diff --git a/staging/native/testapp/testapp.xcodeproj/project.pbxproj b/staging/native/testapp/testapp.xcodeproj/project.pbxproj deleted file mode 100644 index 36c938a1..00000000 --- a/staging/native/testapp/testapp.xcodeproj/project.pbxproj +++ /dev/null @@ -1,378 +0,0 @@ -// !$*UTF8*$! -{ - archiveVersion = 1; - classes = { - }; - objectVersion = 46; - objects = { - -/* Begin PBXBuildFile section */ - 4C3C7DCC2033BACC0077B58E /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 4C3C7DCB2033BACC0077B58E /* LaunchScreen.storyboard */; }; - 4C3C7DCF2033BAF60077B58E /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 4C3C7DCD2033BAF60077B58E /* Images.xcassets */; }; - 4CE59BEA2033B47E00A73A92 /* common_main.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4CE59BE72033B47E00A73A92 /* common_main.cpp */; }; - 4CE59BEF2033B69300A73A92 /* ios_main.mm in Sources */ = {isa = PBXBuildFile; fileRef = 4CE59BEE2033B69300A73A92 /* ios_main.mm */; }; - 6003F58E195388D20070C39A /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 6003F58D195388D20070C39A /* Foundation.framework */; }; - 6003F590195388D20070C39A /* CoreGraphics.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 6003F58F195388D20070C39A /* CoreGraphics.framework */; }; - 6003F592195388D20070C39A /* UIKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 6003F591195388D20070C39A /* UIKit.framework */; }; -/* End PBXBuildFile section */ - -/* Begin PBXFileReference section */ - 0167588598B78EAA2D036D67 /* GoogleSignInCpp.podspec */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text; name = GoogleSignInCpp.podspec; path = ../GoogleSignInCpp.podspec; sourceTree = ""; xcLanguageSpecificationIdentifier = xcode.lang.ruby; }; - 4C3C7DCB2033BACC0077B58E /* LaunchScreen.storyboard */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.storyboard; path = LaunchScreen.storyboard; sourceTree = ""; }; - 4C3C7DCD2033BAF60077B58E /* Images.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; name = Images.xcassets; path = testapp/Images.xcassets; sourceTree = ""; }; - 4C3C7DCE2033BAF60077B58E /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = Info.plist; path = testapp/Info.plist; sourceTree = ""; }; - 4CE59BE72033B47E00A73A92 /* common_main.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = common_main.cpp; sourceTree = ""; }; - 4CE59BE82033B47E00A73A92 /* main.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = main.h; sourceTree = ""; }; - 4CE59BEB2033B65100A73A92 /* Podfile */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = Podfile; sourceTree = ""; xcLanguageSpecificationIdentifier = xcode.lang.ruby; }; - 4CE59BEE2033B69300A73A92 /* ios_main.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; name = ios_main.mm; path = src/ios/ios_main.mm; sourceTree = SOURCE_ROOT; }; - 6003F58A195388D20070C39A /* testapp.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = testapp.app; sourceTree = BUILT_PRODUCTS_DIR; }; - 6003F58D195388D20070C39A /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = System/Library/Frameworks/Foundation.framework; sourceTree = SDKROOT; }; - 6003F58F195388D20070C39A /* CoreGraphics.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreGraphics.framework; path = System/Library/Frameworks/CoreGraphics.framework; sourceTree = SDKROOT; }; - 6003F591195388D20070C39A /* UIKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = UIKit.framework; path = System/Library/Frameworks/UIKit.framework; sourceTree = SDKROOT; }; - 7A126461E42F7806F61A588A /* README.md */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = net.daringfireball.markdown; name = README.md; path = ../README.md; sourceTree = ""; }; - BF63353FEBAEFDC384526617 /* LICENSE */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text; name = LICENSE; path = ../LICENSE; sourceTree = ""; }; -/* End PBXFileReference section */ - -/* Begin PBXFrameworksBuildPhase section */ - 6003F587195388D20070C39A /* Frameworks */ = { - isa = PBXFrameworksBuildPhase; - buildActionMask = 2147483647; - files = ( - 6003F590195388D20070C39A /* CoreGraphics.framework in Frameworks */, - 6003F592195388D20070C39A /* UIKit.framework in Frameworks */, - 6003F58E195388D20070C39A /* Foundation.framework in Frameworks */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXFrameworksBuildPhase section */ - -/* Begin PBXGroup section */ - 4CE59BED2033B66E00A73A92 /* ios */ = { - isa = PBXGroup; - children = ( - 4CE59BEE2033B69300A73A92 /* ios_main.mm */, - ); - path = ios; - sourceTree = ""; - }; - 6003F581195388D10070C39A = { - isa = PBXGroup; - children = ( - 4C3C7DCD2033BAF60077B58E /* Images.xcassets */, - 4C3C7DCE2033BAF60077B58E /* Info.plist */, - 4C3C7DCB2033BACC0077B58E /* LaunchScreen.storyboard */, - 60FF7A9C1954A5C5007DD14C /* Podspec Metadata */, - 6003F593195388D20070C39A /* src */, - 6003F58C195388D20070C39A /* Frameworks */, - 6003F58B195388D20070C39A /* Products */, - ); - sourceTree = ""; - }; - 6003F58B195388D20070C39A /* Products */ = { - isa = PBXGroup; - children = ( - 6003F58A195388D20070C39A /* testapp.app */, - ); - name = Products; - sourceTree = ""; - }; - 6003F58C195388D20070C39A /* Frameworks */ = { - isa = PBXGroup; - children = ( - 6003F58D195388D20070C39A /* Foundation.framework */, - 6003F58F195388D20070C39A /* CoreGraphics.framework */, - 6003F591195388D20070C39A /* UIKit.framework */, - ); - name = Frameworks; - sourceTree = ""; - }; - 6003F593195388D20070C39A /* src */ = { - isa = PBXGroup; - children = ( - 4CE59BE72033B47E00A73A92 /* common_main.cpp */, - 4CE59BE82033B47E00A73A92 /* main.h */, - 4CE59BED2033B66E00A73A92 /* ios */, - ); - path = src; - sourceTree = ""; - }; - 60FF7A9C1954A5C5007DD14C /* Podspec Metadata */ = { - isa = PBXGroup; - children = ( - 4CE59BEB2033B65100A73A92 /* Podfile */, - 0167588598B78EAA2D036D67 /* GoogleSignInCpp.podspec */, - 7A126461E42F7806F61A588A /* README.md */, - BF63353FEBAEFDC384526617 /* LICENSE */, - ); - name = "Podspec Metadata"; - sourceTree = ""; - }; -/* End PBXGroup section */ - -/* Begin PBXNativeTarget section */ - 6003F589195388D20070C39A /* testapp */ = { - isa = PBXNativeTarget; - buildConfigurationList = 6003F5BF195388D20070C39A /* Build configuration list for PBXNativeTarget "testapp" */; - buildPhases = ( - 3CFAC7B749210A2C53CA2CA6 /* [CP] Check Pods Manifest.lock */, - 6003F586195388D20070C39A /* Sources */, - 6003F587195388D20070C39A /* Frameworks */, - 6003F588195388D20070C39A /* Resources */, - AEAE3DFAF96D6BF95BB0395C /* [CP] Embed Pods Frameworks */, - FAD69C6CC584AB1F1E027745 /* [CP] Copy Pods Resources */, - ); - buildRules = ( - ); - dependencies = ( - ); - name = testapp; - productName = GoogleSignInCpp; - productReference = 6003F58A195388D20070C39A /* testapp.app */; - productType = "com.apple.product-type.application"; - }; -/* End PBXNativeTarget section */ - -/* Begin PBXProject section */ - 6003F582195388D10070C39A /* Project object */ = { - isa = PBXProject; - attributes = { - CLASSPREFIX = ""; - LastUpgradeCheck = 0720; - ORGANIZATIONNAME = Google; - }; - buildConfigurationList = 6003F585195388D10070C39A /* Build configuration list for PBXProject "testapp" */; - compatibilityVersion = "Xcode 3.2"; - developmentRegion = English; - hasScannedForEncodings = 0; - knownRegions = ( - en, - Base, - ); - mainGroup = 6003F581195388D10070C39A; - productRefGroup = 6003F58B195388D20070C39A /* Products */; - projectDirPath = ""; - projectRoot = ""; - targets = ( - 6003F589195388D20070C39A /* testapp */, - ); - }; -/* End PBXProject section */ - -/* Begin PBXResourcesBuildPhase section */ - 6003F588195388D20070C39A /* Resources */ = { - isa = PBXResourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - 4C3C7DCF2033BAF60077B58E /* Images.xcassets in Resources */, - 4C3C7DCC2033BACC0077B58E /* LaunchScreen.storyboard in Resources */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXResourcesBuildPhase section */ - -/* Begin PBXShellScriptBuildPhase section */ - 3CFAC7B749210A2C53CA2CA6 /* [CP] Check Pods Manifest.lock */ = { - isa = PBXShellScriptBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - inputPaths = ( - "${PODS_PODFILE_DIR_PATH}/Podfile.lock", - "${PODS_ROOT}/Manifest.lock", - ); - name = "[CP] Check Pods Manifest.lock"; - outputPaths = ( - "$(DERIVED_FILE_DIR)/Pods-testapp-checkManifestLockResult.txt", - ); - runOnlyForDeploymentPostprocessing = 0; - shellPath = /bin/sh; - shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; - showEnvVarsInLog = 0; - }; - AEAE3DFAF96D6BF95BB0395C /* [CP] Embed Pods Frameworks */ = { - isa = PBXShellScriptBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - inputPaths = ( - "${SRCROOT}/Pods/Target Support Files/Pods-testapp/Pods-testapp-frameworks.sh", - "${BUILT_PRODUCTS_DIR}/GTMOAuth2/GTMOAuth2.framework", - "${BUILT_PRODUCTS_DIR}/GTMSessionFetcher/GTMSessionFetcher.framework", - "${BUILT_PRODUCTS_DIR}/GoogleToolboxForMac/GoogleToolboxForMac.framework", - ); - name = "[CP] Embed Pods Frameworks"; - outputPaths = ( - "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/GTMOAuth2.framework", - "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/GTMSessionFetcher.framework", - "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/GoogleToolboxForMac.framework", - ); - runOnlyForDeploymentPostprocessing = 0; - shellPath = /bin/sh; - shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-testapp/Pods-testapp-frameworks.sh\"\n"; - showEnvVarsInLog = 0; - }; - FAD69C6CC584AB1F1E027745 /* [CP] Copy Pods Resources */ = { - isa = PBXShellScriptBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - inputPaths = ( - "${SRCROOT}/Pods/Target Support Files/Pods-testapp/Pods-testapp-resources.sh", - "${PODS_ROOT}/GoogleSignIn/Resources/GoogleSignIn.bundle", - ); - name = "[CP] Copy Pods Resources"; - outputPaths = ( - "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/GoogleSignIn.bundle", - ); - runOnlyForDeploymentPostprocessing = 0; - shellPath = /bin/sh; - shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-testapp/Pods-testapp-resources.sh\"\n"; - showEnvVarsInLog = 0; - }; -/* End PBXShellScriptBuildPhase section */ - -/* Begin PBXSourcesBuildPhase section */ - 6003F586195388D20070C39A /* Sources */ = { - isa = PBXSourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - 4CE59BEF2033B69300A73A92 /* ios_main.mm in Sources */, - 4CE59BEA2033B47E00A73A92 /* common_main.cpp in Sources */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXSourcesBuildPhase section */ - -/* Begin XCBuildConfiguration section */ - 6003F5BD195388D20070C39A /* Debug */ = { - isa = XCBuildConfiguration; - buildSettings = { - ALWAYS_SEARCH_USER_PATHS = NO; - CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; - CLANG_CXX_LIBRARY = "libc++"; - CLANG_ENABLE_MODULES = YES; - CLANG_ENABLE_OBJC_ARC = YES; - CLANG_WARN_BOOL_CONVERSION = YES; - CLANG_WARN_CONSTANT_CONVERSION = YES; - CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; - CLANG_WARN_EMPTY_BODY = YES; - CLANG_WARN_ENUM_CONVERSION = YES; - CLANG_WARN_INT_CONVERSION = YES; - CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; - CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; - "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; - COPY_PHASE_STRIP = NO; - ENABLE_STRICT_OBJC_MSGSEND = YES; - GCC_C_LANGUAGE_STANDARD = gnu99; - GCC_DYNAMIC_NO_PIC = NO; - GCC_NO_COMMON_BLOCKS = YES; - GCC_OPTIMIZATION_LEVEL = 0; - GCC_PREPROCESSOR_DEFINITIONS = ( - "DEBUG=1", - "$(inherited)", - ); - GCC_SYMBOLS_PRIVATE_EXTERN = NO; - GCC_WARN_64_TO_32_BIT_CONVERSION = YES; - GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; - GCC_WARN_UNDECLARED_SELECTOR = YES; - GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; - GCC_WARN_UNUSED_FUNCTION = YES; - GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 8.4; - MTL_ENABLE_DEBUG_INFO = YES; - ONLY_ACTIVE_ARCH = YES; - SDKROOT = iphoneos; - TARGETED_DEVICE_FAMILY = "1,2"; - }; - name = Debug; - }; - 6003F5BE195388D20070C39A /* Release */ = { - isa = XCBuildConfiguration; - buildSettings = { - ALWAYS_SEARCH_USER_PATHS = NO; - CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; - CLANG_CXX_LIBRARY = "libc++"; - CLANG_ENABLE_MODULES = YES; - CLANG_ENABLE_OBJC_ARC = YES; - CLANG_WARN_BOOL_CONVERSION = YES; - CLANG_WARN_CONSTANT_CONVERSION = YES; - CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; - CLANG_WARN_EMPTY_BODY = YES; - CLANG_WARN_ENUM_CONVERSION = YES; - CLANG_WARN_INT_CONVERSION = YES; - CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; - CLANG_WARN_UNREACHABLE_CODE = YES; - CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; - "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; - COPY_PHASE_STRIP = NO; - ENABLE_NS_ASSERTIONS = NO; - ENABLE_STRICT_OBJC_MSGSEND = YES; - GCC_C_LANGUAGE_STANDARD = gnu99; - GCC_NO_COMMON_BLOCKS = YES; - GCC_WARN_64_TO_32_BIT_CONVERSION = YES; - GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; - GCC_WARN_UNDECLARED_SELECTOR = YES; - GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; - GCC_WARN_UNUSED_FUNCTION = YES; - GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 8.4; - MTL_ENABLE_DEBUG_INFO = NO; - SDKROOT = iphoneos; - TARGETED_DEVICE_FAMILY = "1,2"; - VALIDATE_PRODUCT = YES; - }; - name = Release; - }; - 6003F5C0195388D20070C39A /* Debug */ = { - isa = XCBuildConfiguration; - buildSettings = { - ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; - ASSETCATALOG_COMPILER_LAUNCHIMAGE_NAME = LaunchImage; - GCC_PRECOMPILE_PREFIX_HEADER = NO; - GCC_PREFIX_HEADER = ""; - INFOPLIST_FILE = "$(SRCROOT)/testapp/Info.plist"; - MODULE_NAME = testapp; - PRODUCT_NAME = "$(TARGET_NAME)"; - WRAPPER_EXTENSION = app; - }; - name = Debug; - }; - 6003F5C1195388D20070C39A /* Release */ = { - isa = XCBuildConfiguration; - buildSettings = { - ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; - ASSETCATALOG_COMPILER_LAUNCHIMAGE_NAME = LaunchImage; - GCC_PRECOMPILE_PREFIX_HEADER = NO; - GCC_PREFIX_HEADER = ""; - INFOPLIST_FILE = "$(SRCROOT)/testapp/Info.plist"; - MODULE_NAME = testapp; - PRODUCT_NAME = "$(TARGET_NAME)"; - WRAPPER_EXTENSION = app; - }; - name = Release; - }; -/* End XCBuildConfiguration section */ - -/* Begin XCConfigurationList section */ - 6003F585195388D10070C39A /* Build configuration list for PBXProject "testapp" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - 6003F5BD195388D20070C39A /* Debug */, - 6003F5BE195388D20070C39A /* Release */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; - 6003F5BF195388D20070C39A /* Build configuration list for PBXNativeTarget "testapp" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - 6003F5C0195388D20070C39A /* Debug */, - 6003F5C1195388D20070C39A /* Release */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; -/* End XCConfigurationList section */ - }; - rootObject = 6003F582195388D10070C39A /* Project object */; -} diff --git a/staging/native/testapp/testapp.xcodeproj/xcshareddata/xcschemes/testapp.xcscheme b/staging/native/testapp/testapp.xcodeproj/xcshareddata/xcschemes/testapp.xcscheme deleted file mode 100644 index 42407bae..00000000 --- a/staging/native/testapp/testapp.xcodeproj/xcshareddata/xcschemes/testapp.xcscheme +++ /dev/null @@ -1,93 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/staging/native/testapp/testapp/Images.xcassets/AppIcon.appiconset/Contents.json b/staging/native/testapp/testapp/Images.xcassets/AppIcon.appiconset/Contents.json deleted file mode 100644 index d8db8d65..00000000 --- a/staging/native/testapp/testapp/Images.xcassets/AppIcon.appiconset/Contents.json +++ /dev/null @@ -1,98 +0,0 @@ -{ - "images" : [ - { - "idiom" : "iphone", - "size" : "20x20", - "scale" : "2x" - }, - { - "idiom" : "iphone", - "size" : "20x20", - "scale" : "3x" - }, - { - "idiom" : "iphone", - "size" : "29x29", - "scale" : "2x" - }, - { - "idiom" : "iphone", - "size" : "29x29", - "scale" : "3x" - }, - { - "idiom" : "iphone", - "size" : "40x40", - "scale" : "2x" - }, - { - "idiom" : "iphone", - "size" : "40x40", - "scale" : "3x" - }, - { - "idiom" : "iphone", - "size" : "60x60", - "scale" : "2x" - }, - { - "idiom" : "iphone", - "size" : "60x60", - "scale" : "3x" - }, - { - "idiom" : "ipad", - "size" : "20x20", - "scale" : "1x" - }, - { - "idiom" : "ipad", - "size" : "20x20", - "scale" : "2x" - }, - { - "idiom" : "ipad", - "size" : "29x29", - "scale" : "1x" - }, - { - "idiom" : "ipad", - "size" : "29x29", - "scale" : "2x" - }, - { - "idiom" : "ipad", - "size" : "40x40", - "scale" : "1x" - }, - { - "idiom" : "ipad", - "size" : "40x40", - "scale" : "2x" - }, - { - "idiom" : "ipad", - "size" : "76x76", - "scale" : "1x" - }, - { - "idiom" : "ipad", - "size" : "76x76", - "scale" : "2x" - }, - { - "idiom" : "ipad", - "size" : "83.5x83.5", - "scale" : "2x" - }, - { - "idiom" : "ios-marketing", - "size" : "1024x1024", - "scale" : "1x" - } - ], - "info" : { - "version" : 1, - "author" : "xcode" - } -} \ No newline at end of file diff --git a/staging/native/testapp/testapp/Images.xcassets/LaunchImage.launchimage/Contents.json b/staging/native/testapp/testapp/Images.xcassets/LaunchImage.launchimage/Contents.json deleted file mode 100644 index 6f870a46..00000000 --- a/staging/native/testapp/testapp/Images.xcassets/LaunchImage.launchimage/Contents.json +++ /dev/null @@ -1,51 +0,0 @@ -{ - "images" : [ - { - "orientation" : "portrait", - "idiom" : "iphone", - "extent" : "full-screen", - "minimum-system-version" : "7.0", - "scale" : "2x" - }, - { - "orientation" : "portrait", - "idiom" : "iphone", - "subtype" : "retina4", - "extent" : "full-screen", - "minimum-system-version" : "7.0", - "scale" : "2x" - }, - { - "orientation" : "portrait", - "idiom" : "ipad", - "extent" : "full-screen", - "minimum-system-version" : "7.0", - "scale" : "1x" - }, - { - "orientation" : "landscape", - "idiom" : "ipad", - "extent" : "full-screen", - "minimum-system-version" : "7.0", - "scale" : "1x" - }, - { - "orientation" : "portrait", - "idiom" : "ipad", - "extent" : "full-screen", - "minimum-system-version" : "7.0", - "scale" : "2x" - }, - { - "orientation" : "landscape", - "idiom" : "ipad", - "extent" : "full-screen", - "minimum-system-version" : "7.0", - "scale" : "2x" - } - ], - "info" : { - "version" : 1, - "author" : "xcode" - } -} \ No newline at end of file diff --git a/staging/native/testapp/testapp/Info.plist b/staging/native/testapp/testapp/Info.plist deleted file mode 100644 index 7d1be075..00000000 --- a/staging/native/testapp/testapp/Info.plist +++ /dev/null @@ -1,39 +0,0 @@ - - - - - CFBundleDevelopmentRegion - en - CFBundleExecutable - $(EXECUTABLE_NAME) - CFBundleIdentifier - com.google.ios.signin.testapp - CFBundleInfoDictionaryVersion - 6.0 - CFBundleName - $(PRODUCT_NAME) - CFBundlePackageType - APPL - CFBundleShortVersionString - 1.0 - CFBundleURLTypes - - - CFBundleTypeRole - Editor - CFBundleURLName - com.google.ios.signin.testapp - CFBundleURLSchemes - - com.google.ios.signin.testapp - - - - CFBundleVersion - 1 - LSRequiresIPhoneOS - - UILaunchStoryboardName - LaunchScreen - - From 57a9a9a25319020e3a1f1f8f465df29c065281c0 Mon Sep 17 00:00:00 2001 From: Thaina Yu Date: Tue, 10 Oct 2023 16:06:00 +0700 Subject: [PATCH 02/25] UPM package + Update pod version --- CONTRIBUTING.md.meta | 7 ++ GoogleSignIn.asmdef | 3 + GoogleSignIn.asmdef.meta | 7 ++ .../GoogleSignIn.meta => GoogleSignIn.meta | 0 .../GoogleSignIn => GoogleSignIn}/Editor.meta | 0 .../Editor/GoogleSignInDependencies.xml | 3 +- .../Editor/GoogleSignInDependencies.xml.meta | 0 .../Editor/google-signin-plugin_v1.0.4.txt | 0 .../google-signin-plugin_v1.0.4.txt.meta | 0 .../GoogleSignIn => GoogleSignIn}/Future.cs | 6 +- .../Future.cs.meta | 0 .../GoogleSignIn.cs | 2 +- .../GoogleSignIn.cs.meta | 0 .../GoogleSignInConfiguration.cs | 2 +- .../GoogleSignInConfiguration.cs.meta | 0 GoogleSignIn/GoogleSignInStatusCode.cs | 53 +++++++++++++ .../GoogleSignInStatusCode.cs.meta | 0 .../GoogleSignInUser.cs | 0 .../GoogleSignInUser.cs.meta | 0 .../GoogleSignIn => GoogleSignIn}/Impl.meta | 0 .../Impl/BaseObject.cs | 0 .../Impl/BaseObject.cs.meta | 0 .../Impl/GoogleSignInImpl.cs | 3 +- .../Impl/GoogleSignInImpl.cs.meta | 0 .../Impl/GoogleSignInImplEditor.cs | 13 +--- .../Impl/GoogleSignInImplEditor.cs.meta | 0 .../Impl/NativeFuture.cs | 8 +- .../Impl/NativeFuture.cs.meta | 0 .../Impl/SignInHelperObject.cs | 0 .../Impl/SignInHelperObject.cs.meta | 0 .../GoogleSignIn/GoogleSignInStatusCode.cs | 72 ------------------ GoogleSignInPlugin/Assets/Parse.meta | 9 --- GoogleSignInPlugin/Assets/Parse/LICENSE | 30 -------- GoogleSignInPlugin/Assets/Parse/Plugins.meta | 9 --- .../Assets/Parse/Plugins/Unity.Compat.dll | Bin 22016 -> 0 bytes .../Parse/Plugins/Unity.Compat.dll.meta | 36 --------- .../Assets/Parse/Plugins/Unity.Tasks.dll | Bin 26624 -> 0 bytes .../Assets/Parse/Plugins/Unity.Tasks.dll.meta | 36 --------- .../Assets/Parse/LICENSE.meta => LICENSE.meta | 7 +- .../Assets/Plugins.meta => Plugins.meta | 2 +- .../Assets/Plugins => Plugins}/Android.meta | 0 .../Plugins => Plugins}/Android/src.meta | 0 .../Plugins => Plugins}/Android/src/main.meta | 0 .../Android/src/main/java.meta | 0 .../Android/src/main/java/com.meta | 0 .../Android/src/main/java/com/google.meta | 0 .../main/java/com/google/googlesignin.meta | 0 .../googlesignin/GoogleSignInFragment.java | 13 +++- .../GoogleSignInFragment.java.meta | 0 .../googlesignin/GoogleSignInHelper.java | 0 .../googlesignin/GoogleSignInHelper.java.meta | 0 .../com/google/googlesignin/IListener.java | 0 .../google/googlesignin/IListener.java.meta | 0 .../googlesignin/TokenPendingResult.java | 0 .../googlesignin/TokenPendingResult.java.meta | 0 .../com/google/googlesignin/TokenRequest.java | 0 .../googlesignin/TokenRequest.java.meta | 0 .../com/google/googlesignin/TokenResult.java | 0 .../google/googlesignin/TokenResult.java.meta | 0 .../Assets/Plugins => Plugins}/iOS.meta | 0 .../Plugins => Plugins}/iOS/GoogleSignIn.h | 0 .../iOS/GoogleSignIn.h.meta | 0 .../Plugins => Plugins}/iOS/GoogleSignIn.mm | 0 .../iOS/GoogleSignIn.mm.meta | 0 .../iOS/GoogleSignInAppController.h | 0 .../iOS/GoogleSignInAppController.h.meta | 0 .../iOS/GoogleSignInAppController.mm | 0 .../iOS/GoogleSignInAppController.mm.meta | 0 README.md.meta | 7 ++ .../Assets => Samples~}/SignInSample.meta | 0 .../SignInSample/MainScene.unity | Bin .../SignInSample/MainScene.unity.meta | 0 .../SignInSample/SigninSampleScript.cs | 16 ++-- .../SignInSample/SigninSampleScript.cs.meta | 0 package.json | 22 ++++++ package.json.meta | 7 ++ 76 files changed, 145 insertions(+), 228 deletions(-) create mode 100644 CONTRIBUTING.md.meta create mode 100644 GoogleSignIn.asmdef create mode 100644 GoogleSignIn.asmdef.meta rename GoogleSignInPlugin/Assets/GoogleSignIn.meta => GoogleSignIn.meta (100%) rename {GoogleSignInPlugin/Assets/GoogleSignIn => GoogleSignIn}/Editor.meta (100%) rename {GoogleSignInPlugin/Assets/GoogleSignIn => GoogleSignIn}/Editor/GoogleSignInDependencies.xml (84%) rename {GoogleSignInPlugin/Assets/GoogleSignIn => GoogleSignIn}/Editor/GoogleSignInDependencies.xml.meta (100%) rename {GoogleSignInPlugin/Assets/GoogleSignIn => GoogleSignIn}/Editor/google-signin-plugin_v1.0.4.txt (100%) rename {GoogleSignInPlugin/Assets/GoogleSignIn => GoogleSignIn}/Editor/google-signin-plugin_v1.0.4.txt.meta (100%) rename {GoogleSignInPlugin/Assets/GoogleSignIn => GoogleSignIn}/Future.cs (93%) rename {GoogleSignInPlugin/Assets/GoogleSignIn => GoogleSignIn}/Future.cs.meta (100%) rename {GoogleSignInPlugin/Assets/GoogleSignIn => GoogleSignIn}/GoogleSignIn.cs (98%) rename {GoogleSignInPlugin/Assets/GoogleSignIn => GoogleSignIn}/GoogleSignIn.cs.meta (100%) rename {GoogleSignInPlugin/Assets/GoogleSignIn => GoogleSignIn}/GoogleSignInConfiguration.cs (98%) rename {GoogleSignInPlugin/Assets/GoogleSignIn => GoogleSignIn}/GoogleSignInConfiguration.cs.meta (100%) create mode 100644 GoogleSignIn/GoogleSignInStatusCode.cs rename {GoogleSignInPlugin/Assets/GoogleSignIn => GoogleSignIn}/GoogleSignInStatusCode.cs.meta (100%) rename {GoogleSignInPlugin/Assets/GoogleSignIn => GoogleSignIn}/GoogleSignInUser.cs (100%) rename {GoogleSignInPlugin/Assets/GoogleSignIn => GoogleSignIn}/GoogleSignInUser.cs.meta (100%) rename {GoogleSignInPlugin/Assets/GoogleSignIn => GoogleSignIn}/Impl.meta (100%) rename {GoogleSignInPlugin/Assets/GoogleSignIn => GoogleSignIn}/Impl/BaseObject.cs (100%) rename {GoogleSignInPlugin/Assets/GoogleSignIn => GoogleSignIn}/Impl/BaseObject.cs.meta (100%) rename {GoogleSignInPlugin/Assets/GoogleSignIn => GoogleSignIn}/Impl/GoogleSignInImpl.cs (98%) rename {GoogleSignInPlugin/Assets/GoogleSignIn => GoogleSignIn}/Impl/GoogleSignInImpl.cs.meta (100%) rename {GoogleSignInPlugin/Assets/GoogleSignIn => GoogleSignIn}/Impl/GoogleSignInImplEditor.cs (92%) rename {GoogleSignInPlugin/Assets/GoogleSignIn => GoogleSignIn}/Impl/GoogleSignInImplEditor.cs.meta (100%) rename {GoogleSignInPlugin/Assets/GoogleSignIn => GoogleSignIn}/Impl/NativeFuture.cs (93%) rename {GoogleSignInPlugin/Assets/GoogleSignIn => GoogleSignIn}/Impl/NativeFuture.cs.meta (100%) rename {GoogleSignInPlugin/Assets/GoogleSignIn => GoogleSignIn}/Impl/SignInHelperObject.cs (100%) rename {GoogleSignInPlugin/Assets/GoogleSignIn => GoogleSignIn}/Impl/SignInHelperObject.cs.meta (100%) delete mode 100644 GoogleSignInPlugin/Assets/GoogleSignIn/GoogleSignInStatusCode.cs delete mode 100644 GoogleSignInPlugin/Assets/Parse.meta delete mode 100755 GoogleSignInPlugin/Assets/Parse/LICENSE delete mode 100644 GoogleSignInPlugin/Assets/Parse/Plugins.meta delete mode 100644 GoogleSignInPlugin/Assets/Parse/Plugins/Unity.Compat.dll delete mode 100644 GoogleSignInPlugin/Assets/Parse/Plugins/Unity.Compat.dll.meta delete mode 100644 GoogleSignInPlugin/Assets/Parse/Plugins/Unity.Tasks.dll delete mode 100644 GoogleSignInPlugin/Assets/Parse/Plugins/Unity.Tasks.dll.meta rename GoogleSignInPlugin/Assets/Parse/LICENSE.meta => LICENSE.meta (50%) rename GoogleSignInPlugin/Assets/Plugins.meta => Plugins.meta (79%) rename {GoogleSignInPlugin/Assets/Plugins => Plugins}/Android.meta (100%) rename {GoogleSignInPlugin/Assets/Plugins => Plugins}/Android/src.meta (100%) rename {GoogleSignInPlugin/Assets/Plugins => Plugins}/Android/src/main.meta (100%) rename {GoogleSignInPlugin/Assets/Plugins => Plugins}/Android/src/main/java.meta (100%) rename {GoogleSignInPlugin/Assets/Plugins => Plugins}/Android/src/main/java/com.meta (100%) rename {GoogleSignInPlugin/Assets/Plugins => Plugins}/Android/src/main/java/com/google.meta (100%) rename {GoogleSignInPlugin/Assets/Plugins => Plugins}/Android/src/main/java/com/google/googlesignin.meta (100%) rename {GoogleSignInPlugin/Assets/Plugins => Plugins}/Android/src/main/java/com/google/googlesignin/GoogleSignInFragment.java (97%) rename {GoogleSignInPlugin/Assets/Plugins => Plugins}/Android/src/main/java/com/google/googlesignin/GoogleSignInFragment.java.meta (100%) rename {GoogleSignInPlugin/Assets/Plugins => Plugins}/Android/src/main/java/com/google/googlesignin/GoogleSignInHelper.java (100%) rename {GoogleSignInPlugin/Assets/Plugins => Plugins}/Android/src/main/java/com/google/googlesignin/GoogleSignInHelper.java.meta (100%) rename {GoogleSignInPlugin/Assets/Plugins => Plugins}/Android/src/main/java/com/google/googlesignin/IListener.java (100%) rename {GoogleSignInPlugin/Assets/Plugins => Plugins}/Android/src/main/java/com/google/googlesignin/IListener.java.meta (100%) rename {GoogleSignInPlugin/Assets/Plugins => Plugins}/Android/src/main/java/com/google/googlesignin/TokenPendingResult.java (100%) rename {GoogleSignInPlugin/Assets/Plugins => Plugins}/Android/src/main/java/com/google/googlesignin/TokenPendingResult.java.meta (100%) rename {GoogleSignInPlugin/Assets/Plugins => Plugins}/Android/src/main/java/com/google/googlesignin/TokenRequest.java (100%) rename {GoogleSignInPlugin/Assets/Plugins => Plugins}/Android/src/main/java/com/google/googlesignin/TokenRequest.java.meta (100%) rename {GoogleSignInPlugin/Assets/Plugins => Plugins}/Android/src/main/java/com/google/googlesignin/TokenResult.java (100%) rename {GoogleSignInPlugin/Assets/Plugins => Plugins}/Android/src/main/java/com/google/googlesignin/TokenResult.java.meta (100%) rename {GoogleSignInPlugin/Assets/Plugins => Plugins}/iOS.meta (100%) rename {GoogleSignInPlugin/Assets/Plugins => Plugins}/iOS/GoogleSignIn.h (100%) rename {GoogleSignInPlugin/Assets/Plugins => Plugins}/iOS/GoogleSignIn.h.meta (100%) rename {GoogleSignInPlugin/Assets/Plugins => Plugins}/iOS/GoogleSignIn.mm (100%) rename {GoogleSignInPlugin/Assets/Plugins => Plugins}/iOS/GoogleSignIn.mm.meta (100%) rename {GoogleSignInPlugin/Assets/Plugins => Plugins}/iOS/GoogleSignInAppController.h (100%) rename {GoogleSignInPlugin/Assets/Plugins => Plugins}/iOS/GoogleSignInAppController.h.meta (100%) rename {GoogleSignInPlugin/Assets/Plugins => Plugins}/iOS/GoogleSignInAppController.mm (100%) rename {GoogleSignInPlugin/Assets/Plugins => Plugins}/iOS/GoogleSignInAppController.mm.meta (100%) create mode 100644 README.md.meta rename {GoogleSignInPlugin/Assets => Samples~}/SignInSample.meta (100%) rename {GoogleSignInPlugin/Assets => Samples~}/SignInSample/MainScene.unity (100%) rename {GoogleSignInPlugin/Assets => Samples~}/SignInSample/MainScene.unity.meta (100%) rename {GoogleSignInPlugin/Assets => Samples~}/SignInSample/SigninSampleScript.cs (85%) rename {GoogleSignInPlugin/Assets => Samples~}/SignInSample/SigninSampleScript.cs.meta (100%) create mode 100644 package.json create mode 100644 package.json.meta diff --git a/CONTRIBUTING.md.meta b/CONTRIBUTING.md.meta new file mode 100644 index 00000000..83782ca2 --- /dev/null +++ b/CONTRIBUTING.md.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: bf5b818b5e6f1fb4b920c2d651dd2f82 +TextScriptImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/GoogleSignIn.asmdef b/GoogleSignIn.asmdef new file mode 100644 index 00000000..87028124 --- /dev/null +++ b/GoogleSignIn.asmdef @@ -0,0 +1,3 @@ +{ + "name": "GoogleSignin" +} diff --git a/GoogleSignIn.asmdef.meta b/GoogleSignIn.asmdef.meta new file mode 100644 index 00000000..af758047 --- /dev/null +++ b/GoogleSignIn.asmdef.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 2a0340569ab0e1245a38e0d6c7b2529b +AssemblyDefinitionImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/GoogleSignInPlugin/Assets/GoogleSignIn.meta b/GoogleSignIn.meta similarity index 100% rename from GoogleSignInPlugin/Assets/GoogleSignIn.meta rename to GoogleSignIn.meta diff --git a/GoogleSignInPlugin/Assets/GoogleSignIn/Editor.meta b/GoogleSignIn/Editor.meta similarity index 100% rename from GoogleSignInPlugin/Assets/GoogleSignIn/Editor.meta rename to GoogleSignIn/Editor.meta diff --git a/GoogleSignInPlugin/Assets/GoogleSignIn/Editor/GoogleSignInDependencies.xml b/GoogleSignIn/Editor/GoogleSignInDependencies.xml similarity index 84% rename from GoogleSignInPlugin/Assets/GoogleSignIn/Editor/GoogleSignInDependencies.xml rename to GoogleSignIn/Editor/GoogleSignInDependencies.xml index 89c7983e..4d72e027 100644 --- a/GoogleSignInPlugin/Assets/GoogleSignIn/Editor/GoogleSignInDependencies.xml +++ b/GoogleSignIn/Editor/GoogleSignInDependencies.xml @@ -12,8 +12,7 @@ - + diff --git a/GoogleSignInPlugin/Assets/GoogleSignIn/Editor/GoogleSignInDependencies.xml.meta b/GoogleSignIn/Editor/GoogleSignInDependencies.xml.meta similarity index 100% rename from GoogleSignInPlugin/Assets/GoogleSignIn/Editor/GoogleSignInDependencies.xml.meta rename to GoogleSignIn/Editor/GoogleSignInDependencies.xml.meta diff --git a/GoogleSignInPlugin/Assets/GoogleSignIn/Editor/google-signin-plugin_v1.0.4.txt b/GoogleSignIn/Editor/google-signin-plugin_v1.0.4.txt similarity index 100% rename from GoogleSignInPlugin/Assets/GoogleSignIn/Editor/google-signin-plugin_v1.0.4.txt rename to GoogleSignIn/Editor/google-signin-plugin_v1.0.4.txt diff --git a/GoogleSignInPlugin/Assets/GoogleSignIn/Editor/google-signin-plugin_v1.0.4.txt.meta b/GoogleSignIn/Editor/google-signin-plugin_v1.0.4.txt.meta similarity index 100% rename from GoogleSignInPlugin/Assets/GoogleSignIn/Editor/google-signin-plugin_v1.0.4.txt.meta rename to GoogleSignIn/Editor/google-signin-plugin_v1.0.4.txt.meta diff --git a/GoogleSignInPlugin/Assets/GoogleSignIn/Future.cs b/GoogleSignIn/Future.cs similarity index 93% rename from GoogleSignInPlugin/Assets/GoogleSignIn/Future.cs rename to GoogleSignIn/Future.cs index df469423..1af950c5 100644 --- a/GoogleSignInPlugin/Assets/GoogleSignIn/Future.cs +++ b/GoogleSignIn/Future.cs @@ -71,10 +71,10 @@ internal Future(FutureAPIImpl impl) { /// Tcs. internal IEnumerator WaitForResult(TaskCompletionSource tcs) { yield return new WaitUntil(() => !Pending); - if (Status == GoogleSignInStatusCode.Canceled) { + if (Status == GoogleSignInStatusCode.CANCELED) { tcs.SetCanceled(); - } else if (Status == GoogleSignInStatusCode.Success || - Status == GoogleSignInStatusCode.SuccessCached) { + } else if (Status == GoogleSignInStatusCode.SUCCESS || + Status == GoogleSignInStatusCode.SUCCESS_CACHE) { tcs.SetResult(Result); } else { tcs.SetException(new GoogleSignIn.SignInException(Status)); diff --git a/GoogleSignInPlugin/Assets/GoogleSignIn/Future.cs.meta b/GoogleSignIn/Future.cs.meta similarity index 100% rename from GoogleSignInPlugin/Assets/GoogleSignIn/Future.cs.meta rename to GoogleSignIn/Future.cs.meta diff --git a/GoogleSignInPlugin/Assets/GoogleSignIn/GoogleSignIn.cs b/GoogleSignIn/GoogleSignIn.cs similarity index 98% rename from GoogleSignInPlugin/Assets/GoogleSignIn/GoogleSignIn.cs rename to GoogleSignIn/GoogleSignIn.cs index 52dcf863..afd36d62 100644 --- a/GoogleSignInPlugin/Assets/GoogleSignIn/GoogleSignIn.cs +++ b/GoogleSignIn/GoogleSignIn.cs @@ -69,7 +69,7 @@ public static GoogleSignInConfiguration Configuration { if (theInstance == null || theConfiguration == value || theConfiguration == null) { theConfiguration = value; } else { - throw new SignInException(GoogleSignInStatusCode.DeveloperError, + throw new SignInException(GoogleSignInStatusCode.DEVELOPER_ERROR, "DefaultInstance already created. " + " Cannot change configuration after creation."); } diff --git a/GoogleSignInPlugin/Assets/GoogleSignIn/GoogleSignIn.cs.meta b/GoogleSignIn/GoogleSignIn.cs.meta similarity index 100% rename from GoogleSignInPlugin/Assets/GoogleSignIn/GoogleSignIn.cs.meta rename to GoogleSignIn/GoogleSignIn.cs.meta diff --git a/GoogleSignInPlugin/Assets/GoogleSignIn/GoogleSignInConfiguration.cs b/GoogleSignIn/GoogleSignInConfiguration.cs similarity index 98% rename from GoogleSignInPlugin/Assets/GoogleSignIn/GoogleSignInConfiguration.cs rename to GoogleSignIn/GoogleSignInConfiguration.cs index 8eb14a79..e8ebce7a 100644 --- a/GoogleSignInPlugin/Assets/GoogleSignIn/GoogleSignInConfiguration.cs +++ b/GoogleSignIn/GoogleSignInConfiguration.cs @@ -50,7 +50,7 @@ public class GoogleSignInConfiguration { /// Request id token, requires consent. public bool RequestIdToken = false; /// Request profile information, requires consent. - public bool RequestProfile = false; + public bool RequestProfile = true; /// Hides popup UIs from games services. /// Used with games signin to show or hide the connecting popup UI /// and to associate an invisible view for other popups. This is diff --git a/GoogleSignInPlugin/Assets/GoogleSignIn/GoogleSignInConfiguration.cs.meta b/GoogleSignIn/GoogleSignInConfiguration.cs.meta similarity index 100% rename from GoogleSignInPlugin/Assets/GoogleSignIn/GoogleSignInConfiguration.cs.meta rename to GoogleSignIn/GoogleSignInConfiguration.cs.meta diff --git a/GoogleSignIn/GoogleSignInStatusCode.cs b/GoogleSignIn/GoogleSignInStatusCode.cs new file mode 100644 index 00000000..bc41fd81 --- /dev/null +++ b/GoogleSignIn/GoogleSignInStatusCode.cs @@ -0,0 +1,53 @@ +// +// Copyright (C) 2017 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. +// + +namespace Google { + + /// + /// Status code for the SignIn operations. + /// + /// All successful status codes are less than or equal to 0. + /// + public enum GoogleSignInStatusCode { + SUCCESS_CACHE = -1, + SUCCESS = 0, + [System.Obsolete] + SERVICE_MISSING = 1, + [System.Obsolete] + SERVICE_VERSION_UPDATE_REQUIRED = 2, + [System.Obsolete] + SERVICE_DISABLED = 3, + SIGN_IN_REQUIRED = 4, + INVALID_ACCOUNT = 5, + RESOLUTION_REQUIRED = 6, + NETWORK_ERROR = 7, + INTERNAL_ERROR = 8, + SERVICE_INVALID = 9, + DEVELOPER_ERROR = 10, + LICENSE_CHECK_FAILED = 11, + ERROR = 13, + INTERRUPTED = 14, + TIMEOUT = 15, + CANCELED = 16, + API_NOT_CONNECTED = 17, + DEAD_CLIENT = 18, + REMOTE_EXCEPTION = 19, + CONNECTION_SUSPENDED_DURING_CALL = 20, + RECONNECTION_TIMED_OUT_DURING_UPDATE = 21, + RECONNECTION_TIMED_OUT = 22 + } +} // namespace GoogleSignIn + diff --git a/GoogleSignInPlugin/Assets/GoogleSignIn/GoogleSignInStatusCode.cs.meta b/GoogleSignIn/GoogleSignInStatusCode.cs.meta similarity index 100% rename from GoogleSignInPlugin/Assets/GoogleSignIn/GoogleSignInStatusCode.cs.meta rename to GoogleSignIn/GoogleSignInStatusCode.cs.meta diff --git a/GoogleSignInPlugin/Assets/GoogleSignIn/GoogleSignInUser.cs b/GoogleSignIn/GoogleSignInUser.cs similarity index 100% rename from GoogleSignInPlugin/Assets/GoogleSignIn/GoogleSignInUser.cs rename to GoogleSignIn/GoogleSignInUser.cs diff --git a/GoogleSignInPlugin/Assets/GoogleSignIn/GoogleSignInUser.cs.meta b/GoogleSignIn/GoogleSignInUser.cs.meta similarity index 100% rename from GoogleSignInPlugin/Assets/GoogleSignIn/GoogleSignInUser.cs.meta rename to GoogleSignIn/GoogleSignInUser.cs.meta diff --git a/GoogleSignInPlugin/Assets/GoogleSignIn/Impl.meta b/GoogleSignIn/Impl.meta similarity index 100% rename from GoogleSignInPlugin/Assets/GoogleSignIn/Impl.meta rename to GoogleSignIn/Impl.meta diff --git a/GoogleSignInPlugin/Assets/GoogleSignIn/Impl/BaseObject.cs b/GoogleSignIn/Impl/BaseObject.cs similarity index 100% rename from GoogleSignInPlugin/Assets/GoogleSignIn/Impl/BaseObject.cs rename to GoogleSignIn/Impl/BaseObject.cs diff --git a/GoogleSignInPlugin/Assets/GoogleSignIn/Impl/BaseObject.cs.meta b/GoogleSignIn/Impl/BaseObject.cs.meta similarity index 100% rename from GoogleSignInPlugin/Assets/GoogleSignIn/Impl/BaseObject.cs.meta rename to GoogleSignIn/Impl/BaseObject.cs.meta diff --git a/GoogleSignInPlugin/Assets/GoogleSignIn/Impl/GoogleSignInImpl.cs b/GoogleSignIn/Impl/GoogleSignInImpl.cs similarity index 98% rename from GoogleSignInPlugin/Assets/GoogleSignIn/Impl/GoogleSignInImpl.cs rename to GoogleSignIn/Impl/GoogleSignInImpl.cs index aa6335e3..33747709 100644 --- a/GoogleSignInPlugin/Assets/GoogleSignIn/Impl/GoogleSignInImpl.cs +++ b/GoogleSignIn/Impl/GoogleSignInImpl.cs @@ -132,7 +132,8 @@ public SignInListener() : base("com.google.googlesignin.IListener") public void OnResult(int result, AndroidJavaObject acct) { - + Debug.Log("googlesignin.IListener : " + acct.Call("toString")); + Debug.Log("ID : " + acct.Call("getId")); } } diff --git a/GoogleSignInPlugin/Assets/GoogleSignIn/Impl/GoogleSignInImpl.cs.meta b/GoogleSignIn/Impl/GoogleSignInImpl.cs.meta similarity index 100% rename from GoogleSignInPlugin/Assets/GoogleSignIn/Impl/GoogleSignInImpl.cs.meta rename to GoogleSignIn/Impl/GoogleSignInImpl.cs.meta diff --git a/GoogleSignInPlugin/Assets/GoogleSignIn/Impl/GoogleSignInImplEditor.cs b/GoogleSignIn/Impl/GoogleSignInImplEditor.cs similarity index 92% rename from GoogleSignInPlugin/Assets/GoogleSignIn/Impl/GoogleSignInImplEditor.cs rename to GoogleSignIn/Impl/GoogleSignInImplEditor.cs index 35fd8920..b59fd3ce 100644 --- a/GoogleSignInPlugin/Assets/GoogleSignIn/Impl/GoogleSignInImplEditor.cs +++ b/GoogleSignIn/Impl/GoogleSignInImplEditor.cs @@ -82,13 +82,11 @@ static HttpListener BindLocalHostFirstAvailablePort() void SigningIn() { - Debug.Log("SigningIn"); Pending = true; var httpListener = BindLocalHostFirstAvailablePort(); try { - var openURL = "https://accounts.google.com/o/oauth2/v2/auth?scope=openid email profile&response_type=code&redirect_uri=" + httpListener.Prefixes.FirstOrDefault() + "&client_id=" + configuration.WebClientId; - Debug.Log(openURL); + var openURL = "https://accounts.google.com/o/oauth2/v2/auth?" + Uri.EscapeUriString("scope=openid email profile&response_type=code&redirect_uri=" + httpListener.Prefixes.FirstOrDefault() + "&client_id=" + configuration.WebClientId); Application.OpenURL(openURL); } catch(Exception e) @@ -103,12 +101,10 @@ void SigningIn() { var context = task.Result; var queryString = context.Request.Url.Query; - Debug.Log(queryString); var queryDictionary = System.Web.HttpUtility.ParseQueryString(queryString); if(queryDictionary == null || queryDictionary.Get("code") is not string code || string.IsNullOrEmpty(code)) { - Status = GoogleSignInStatusCode.InvalidAccount; - Debug.Log("no code? : " + context.Request.Url); + Status = GoogleSignInStatusCode.INVALID_ACCOUNT; context.Response.StatusCode = 404; context.Response.OutputStream.Write(Encoding.UTF8.GetBytes("Cannot get code")); @@ -122,7 +118,6 @@ void SigningIn() var result = await HttpWebRequest.CreateHttp("https://www.googleapis.com/oauth2/v4/token").Post("application/x-www-form-urlencoded","code=" + code + "&client_id=" + configuration.WebClientId + "&client_secret=" + configuration.ClientSecret + "&redirect_uri=" + httpListener.Prefixes.FirstOrDefault() + "&grant_type=authorization_code").ContinueWith((task) => task.Result,taskScheduler); var jobj = JObject.Parse(result); - Debug.Log(jobj); var accessToken = (string)jobj.GetValue("access_token"); var expiresIn = (int)jobj.GetValue("expires_in"); @@ -152,11 +147,11 @@ void SigningIn() Result = user; - Status = GoogleSignInStatusCode.Success; + Status = GoogleSignInStatusCode.SUCCESS; } catch(Exception e) { - Status = GoogleSignInStatusCode.Error; + Status = GoogleSignInStatusCode.ERROR; Debug.LogException(e); throw; } diff --git a/GoogleSignInPlugin/Assets/GoogleSignIn/Impl/GoogleSignInImplEditor.cs.meta b/GoogleSignIn/Impl/GoogleSignInImplEditor.cs.meta similarity index 100% rename from GoogleSignInPlugin/Assets/GoogleSignIn/Impl/GoogleSignInImplEditor.cs.meta rename to GoogleSignIn/Impl/GoogleSignInImplEditor.cs.meta diff --git a/GoogleSignInPlugin/Assets/GoogleSignIn/Impl/NativeFuture.cs b/GoogleSignIn/Impl/NativeFuture.cs similarity index 93% rename from GoogleSignInPlugin/Assets/GoogleSignIn/Impl/NativeFuture.cs rename to GoogleSignIn/Impl/NativeFuture.cs index cdb378f5..71103cf5 100644 --- a/GoogleSignInPlugin/Assets/GoogleSignIn/Impl/NativeFuture.cs +++ b/GoogleSignIn/Impl/NativeFuture.cs @@ -48,10 +48,12 @@ public GoogleSignInUser Result { var user = new GoogleSignInUser(); var userPtr = new HandleRef(user, ptr); - user.DisplayName = GoogleSignInImpl.GoogleSignIn_GetDisplayName(userPtr); + user.UserId = GoogleSignInImpl.GoogleSignIn_GetUserId(userPtr); user.Email = GoogleSignInImpl.GoogleSignIn_GetEmail(userPtr); + user.DisplayName = GoogleSignInImpl.GoogleSignIn_GetDisplayName(userPtr); + user.FamilyName = GoogleSignInImpl.GoogleSignIn_GetFamilyName(userPtr); user.GivenName = GoogleSignInImpl.GoogleSignIn_GetGivenName(userPtr); @@ -65,7 +67,9 @@ public GoogleSignInUser Result { user.ImageUrl = new System.Uri(url); } - user.UserId = GoogleSignInImpl.GoogleSignIn_GetUserId(userPtr); + /** Require for no reason (tree shaking ?) */ + var obj = (user.UserId,user.Email,user.DisplayName,user.FamilyName,user.GivenName,user.IdToken,user.AuthCode,user.ImageUrl); + return user; } } diff --git a/GoogleSignInPlugin/Assets/GoogleSignIn/Impl/NativeFuture.cs.meta b/GoogleSignIn/Impl/NativeFuture.cs.meta similarity index 100% rename from GoogleSignInPlugin/Assets/GoogleSignIn/Impl/NativeFuture.cs.meta rename to GoogleSignIn/Impl/NativeFuture.cs.meta diff --git a/GoogleSignInPlugin/Assets/GoogleSignIn/Impl/SignInHelperObject.cs b/GoogleSignIn/Impl/SignInHelperObject.cs similarity index 100% rename from GoogleSignInPlugin/Assets/GoogleSignIn/Impl/SignInHelperObject.cs rename to GoogleSignIn/Impl/SignInHelperObject.cs diff --git a/GoogleSignInPlugin/Assets/GoogleSignIn/Impl/SignInHelperObject.cs.meta b/GoogleSignIn/Impl/SignInHelperObject.cs.meta similarity index 100% rename from GoogleSignInPlugin/Assets/GoogleSignIn/Impl/SignInHelperObject.cs.meta rename to GoogleSignIn/Impl/SignInHelperObject.cs.meta diff --git a/GoogleSignInPlugin/Assets/GoogleSignIn/GoogleSignInStatusCode.cs b/GoogleSignInPlugin/Assets/GoogleSignIn/GoogleSignInStatusCode.cs deleted file mode 100644 index 0719f2c2..00000000 --- a/GoogleSignInPlugin/Assets/GoogleSignIn/GoogleSignInStatusCode.cs +++ /dev/null @@ -1,72 +0,0 @@ -// -// Copyright (C) 2017 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. -// - -namespace Google { - - /// - /// Status code for the SignIn operations. - /// - /// All successful status codes are less than or equal to 0. - /// - public enum GoogleSignInStatusCode { - /// The operation was successful, but used the device's cache. - /// - SuccessCached = -1, - - /// The operation was successful. - Success = 0, - - /// The client attempted to call a method from an API that - /// failed to connect. - ApiNotConnected = 1, - - /// The result was canceled either due to client disconnect - /// or cancel(). - Canceled = 2, - - /// A blocking call was interrupted while waiting and did not - /// run to completion. - Interrupted = 3, - - /// The client attempted to connect to the service with an - /// invalid account name specified. - InvalidAccount = 4, - - /// Timed out while awaiting the result. - Timeout = 5, - - /// The application is misconfigured. - /// This error is not recoverable. - /// - /// The developer should look at the logs after this to determine - /// more actionable information. - /// - DeveloperError = 6, - - /// An internal error occurred. Retrying should resolve the - /// problem. - InternalError = 7, - - /// A network error occurred. Retrying should resolve the problem. - /// - NetworkError = 8, - - /// The operation failed with no more detailed information. - /// - Error = 9, - } -} // namespace GoogleSignIn - diff --git a/GoogleSignInPlugin/Assets/Parse.meta b/GoogleSignInPlugin/Assets/Parse.meta deleted file mode 100644 index 351c7ed2..00000000 --- a/GoogleSignInPlugin/Assets/Parse.meta +++ /dev/null @@ -1,9 +0,0 @@ -fileFormatVersion: 2 -guid: d1a8f2ea2fc954f4db9d55a59d097a7d -folderAsset: yes -timeCreated: 1500403331 -licenseType: Pro -DefaultImporter: - userData: - assetBundleName: - assetBundleVariant: diff --git a/GoogleSignInPlugin/Assets/Parse/LICENSE b/GoogleSignInPlugin/Assets/Parse/LICENSE deleted file mode 100755 index 4abeb6e9..00000000 --- a/GoogleSignInPlugin/Assets/Parse/LICENSE +++ /dev/null @@ -1,30 +0,0 @@ -BSD License - -For Parse .NET SDK software - -Copyright (c) 2015-present, Parse, LLC. All rights reserved. - -Redistribution and use in source and binary forms, with or without modification, -are permitted provided that the following conditions are met: - - * Redistributions of source code must retain the above copyright notice, this - list of conditions and the following disclaimer. - - * Redistributions in binary form must reproduce the above copyright notice, - this list of conditions and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - * Neither the name Parse nor the names of its contributors may be used to - endorse or promote products derived from this software without specific - prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND -ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR -ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON -ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/GoogleSignInPlugin/Assets/Parse/Plugins.meta b/GoogleSignInPlugin/Assets/Parse/Plugins.meta deleted file mode 100644 index 2b04519c..00000000 --- a/GoogleSignInPlugin/Assets/Parse/Plugins.meta +++ /dev/null @@ -1,9 +0,0 @@ -fileFormatVersion: 2 -guid: aecfff8cf5706409e93b95c9c1081553 -folderAsset: yes -timeCreated: 1500403331 -licenseType: Pro -DefaultImporter: - userData: - assetBundleName: - assetBundleVariant: diff --git a/GoogleSignInPlugin/Assets/Parse/Plugins/Unity.Compat.dll b/GoogleSignInPlugin/Assets/Parse/Plugins/Unity.Compat.dll deleted file mode 100644 index 4b8c275e689246aef94d629fc2923f0c995713d5..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 22016 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 bhPKO&Q_8LC?;9P tokenPendingResult = null; + public GoogleSignInAccount getAccount() { - return request.getPendingResponse().await().getAccount(); + return tokenPendingResult.await().getAccount(); } public int getStatus() { - if(request == null) { + if(tokenPendingResult == null) { return CommonStatusCodes.DEVELOPER_ERROR; } - return request.getPendingResponse().await().getStatus().getStatusCode(); + return tokenPendingResult.await().getStatus().getStatusCode(); } private GoogleApiClient mGoogleApiClient; @@ -191,6 +194,7 @@ public static GoogleSignInFragment getInstance(Activity parentActivity) { public synchronized boolean submitRequest(TokenRequest request) { if (this.request == null || this.state == State.READY) { this.request = request; + this.tokenPendingResult = request.getPendingResponse(); return true; } GoogleSignInHelper.logError(String.format(Locale.getDefault(), @@ -213,6 +217,7 @@ private synchronized void setState(State state) { */ public void signOut() { clearRequest(true); + this.tokenPendingResult = null; if (mGoogleApiClient != null) { Auth.GoogleSignInApi.signOut(mGoogleApiClient); } diff --git a/GoogleSignInPlugin/Assets/Plugins/Android/src/main/java/com/google/googlesignin/GoogleSignInFragment.java.meta b/Plugins/Android/src/main/java/com/google/googlesignin/GoogleSignInFragment.java.meta similarity index 100% rename from GoogleSignInPlugin/Assets/Plugins/Android/src/main/java/com/google/googlesignin/GoogleSignInFragment.java.meta rename to Plugins/Android/src/main/java/com/google/googlesignin/GoogleSignInFragment.java.meta diff --git a/GoogleSignInPlugin/Assets/Plugins/Android/src/main/java/com/google/googlesignin/GoogleSignInHelper.java b/Plugins/Android/src/main/java/com/google/googlesignin/GoogleSignInHelper.java similarity index 100% rename from GoogleSignInPlugin/Assets/Plugins/Android/src/main/java/com/google/googlesignin/GoogleSignInHelper.java rename to Plugins/Android/src/main/java/com/google/googlesignin/GoogleSignInHelper.java diff --git a/GoogleSignInPlugin/Assets/Plugins/Android/src/main/java/com/google/googlesignin/GoogleSignInHelper.java.meta b/Plugins/Android/src/main/java/com/google/googlesignin/GoogleSignInHelper.java.meta similarity index 100% rename from GoogleSignInPlugin/Assets/Plugins/Android/src/main/java/com/google/googlesignin/GoogleSignInHelper.java.meta rename to Plugins/Android/src/main/java/com/google/googlesignin/GoogleSignInHelper.java.meta diff --git a/GoogleSignInPlugin/Assets/Plugins/Android/src/main/java/com/google/googlesignin/IListener.java b/Plugins/Android/src/main/java/com/google/googlesignin/IListener.java similarity index 100% rename from GoogleSignInPlugin/Assets/Plugins/Android/src/main/java/com/google/googlesignin/IListener.java rename to Plugins/Android/src/main/java/com/google/googlesignin/IListener.java diff --git a/GoogleSignInPlugin/Assets/Plugins/Android/src/main/java/com/google/googlesignin/IListener.java.meta b/Plugins/Android/src/main/java/com/google/googlesignin/IListener.java.meta similarity index 100% rename from GoogleSignInPlugin/Assets/Plugins/Android/src/main/java/com/google/googlesignin/IListener.java.meta rename to Plugins/Android/src/main/java/com/google/googlesignin/IListener.java.meta diff --git a/GoogleSignInPlugin/Assets/Plugins/Android/src/main/java/com/google/googlesignin/TokenPendingResult.java b/Plugins/Android/src/main/java/com/google/googlesignin/TokenPendingResult.java similarity index 100% rename from GoogleSignInPlugin/Assets/Plugins/Android/src/main/java/com/google/googlesignin/TokenPendingResult.java rename to Plugins/Android/src/main/java/com/google/googlesignin/TokenPendingResult.java diff --git a/GoogleSignInPlugin/Assets/Plugins/Android/src/main/java/com/google/googlesignin/TokenPendingResult.java.meta b/Plugins/Android/src/main/java/com/google/googlesignin/TokenPendingResult.java.meta similarity index 100% rename from GoogleSignInPlugin/Assets/Plugins/Android/src/main/java/com/google/googlesignin/TokenPendingResult.java.meta rename to Plugins/Android/src/main/java/com/google/googlesignin/TokenPendingResult.java.meta diff --git a/GoogleSignInPlugin/Assets/Plugins/Android/src/main/java/com/google/googlesignin/TokenRequest.java b/Plugins/Android/src/main/java/com/google/googlesignin/TokenRequest.java similarity index 100% rename from GoogleSignInPlugin/Assets/Plugins/Android/src/main/java/com/google/googlesignin/TokenRequest.java rename to Plugins/Android/src/main/java/com/google/googlesignin/TokenRequest.java diff --git a/GoogleSignInPlugin/Assets/Plugins/Android/src/main/java/com/google/googlesignin/TokenRequest.java.meta b/Plugins/Android/src/main/java/com/google/googlesignin/TokenRequest.java.meta similarity index 100% rename from GoogleSignInPlugin/Assets/Plugins/Android/src/main/java/com/google/googlesignin/TokenRequest.java.meta rename to Plugins/Android/src/main/java/com/google/googlesignin/TokenRequest.java.meta diff --git a/GoogleSignInPlugin/Assets/Plugins/Android/src/main/java/com/google/googlesignin/TokenResult.java b/Plugins/Android/src/main/java/com/google/googlesignin/TokenResult.java similarity index 100% rename from GoogleSignInPlugin/Assets/Plugins/Android/src/main/java/com/google/googlesignin/TokenResult.java rename to Plugins/Android/src/main/java/com/google/googlesignin/TokenResult.java diff --git a/GoogleSignInPlugin/Assets/Plugins/Android/src/main/java/com/google/googlesignin/TokenResult.java.meta b/Plugins/Android/src/main/java/com/google/googlesignin/TokenResult.java.meta similarity index 100% rename from GoogleSignInPlugin/Assets/Plugins/Android/src/main/java/com/google/googlesignin/TokenResult.java.meta rename to Plugins/Android/src/main/java/com/google/googlesignin/TokenResult.java.meta diff --git a/GoogleSignInPlugin/Assets/Plugins/iOS.meta b/Plugins/iOS.meta similarity index 100% rename from GoogleSignInPlugin/Assets/Plugins/iOS.meta rename to Plugins/iOS.meta diff --git a/GoogleSignInPlugin/Assets/Plugins/iOS/GoogleSignIn.h b/Plugins/iOS/GoogleSignIn.h similarity index 100% rename from GoogleSignInPlugin/Assets/Plugins/iOS/GoogleSignIn.h rename to Plugins/iOS/GoogleSignIn.h diff --git a/GoogleSignInPlugin/Assets/Plugins/iOS/GoogleSignIn.h.meta b/Plugins/iOS/GoogleSignIn.h.meta similarity index 100% rename from GoogleSignInPlugin/Assets/Plugins/iOS/GoogleSignIn.h.meta rename to Plugins/iOS/GoogleSignIn.h.meta diff --git a/GoogleSignInPlugin/Assets/Plugins/iOS/GoogleSignIn.mm b/Plugins/iOS/GoogleSignIn.mm similarity index 100% rename from GoogleSignInPlugin/Assets/Plugins/iOS/GoogleSignIn.mm rename to Plugins/iOS/GoogleSignIn.mm diff --git a/GoogleSignInPlugin/Assets/Plugins/iOS/GoogleSignIn.mm.meta b/Plugins/iOS/GoogleSignIn.mm.meta similarity index 100% rename from GoogleSignInPlugin/Assets/Plugins/iOS/GoogleSignIn.mm.meta rename to Plugins/iOS/GoogleSignIn.mm.meta diff --git a/GoogleSignInPlugin/Assets/Plugins/iOS/GoogleSignInAppController.h b/Plugins/iOS/GoogleSignInAppController.h similarity index 100% rename from GoogleSignInPlugin/Assets/Plugins/iOS/GoogleSignInAppController.h rename to Plugins/iOS/GoogleSignInAppController.h diff --git a/GoogleSignInPlugin/Assets/Plugins/iOS/GoogleSignInAppController.h.meta b/Plugins/iOS/GoogleSignInAppController.h.meta similarity index 100% rename from GoogleSignInPlugin/Assets/Plugins/iOS/GoogleSignInAppController.h.meta rename to Plugins/iOS/GoogleSignInAppController.h.meta diff --git a/GoogleSignInPlugin/Assets/Plugins/iOS/GoogleSignInAppController.mm b/Plugins/iOS/GoogleSignInAppController.mm similarity index 100% rename from GoogleSignInPlugin/Assets/Plugins/iOS/GoogleSignInAppController.mm rename to Plugins/iOS/GoogleSignInAppController.mm diff --git a/GoogleSignInPlugin/Assets/Plugins/iOS/GoogleSignInAppController.mm.meta b/Plugins/iOS/GoogleSignInAppController.mm.meta similarity index 100% rename from GoogleSignInPlugin/Assets/Plugins/iOS/GoogleSignInAppController.mm.meta rename to Plugins/iOS/GoogleSignInAppController.mm.meta diff --git a/README.md.meta b/README.md.meta new file mode 100644 index 00000000..775de2a5 --- /dev/null +++ b/README.md.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 31a22f492fc25314d877e5a10dc0a854 +TextScriptImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/GoogleSignInPlugin/Assets/SignInSample.meta b/Samples~/SignInSample.meta similarity index 100% rename from GoogleSignInPlugin/Assets/SignInSample.meta rename to Samples~/SignInSample.meta diff --git a/GoogleSignInPlugin/Assets/SignInSample/MainScene.unity b/Samples~/SignInSample/MainScene.unity similarity index 100% rename from GoogleSignInPlugin/Assets/SignInSample/MainScene.unity rename to Samples~/SignInSample/MainScene.unity diff --git a/GoogleSignInPlugin/Assets/SignInSample/MainScene.unity.meta b/Samples~/SignInSample/MainScene.unity.meta similarity index 100% rename from GoogleSignInPlugin/Assets/SignInSample/MainScene.unity.meta rename to Samples~/SignInSample/MainScene.unity.meta diff --git a/GoogleSignInPlugin/Assets/SignInSample/SigninSampleScript.cs b/Samples~/SignInSample/SigninSampleScript.cs similarity index 85% rename from GoogleSignInPlugin/Assets/SignInSample/SigninSampleScript.cs rename to Samples~/SignInSample/SigninSampleScript.cs index ce38441b..d34af937 100644 --- a/GoogleSignInPlugin/Assets/SignInSample/SigninSampleScript.cs +++ b/Samples~/SignInSample/SigninSampleScript.cs @@ -26,6 +26,9 @@ public class SigninSampleScript : MonoBehaviour { public Text statusText; public string webClientId = ""; +#if UNITY_EDITOR || UNITY_STANDALONE + public string Secret; +#endif private GoogleSignInConfiguration configuration; @@ -33,6 +36,9 @@ public class SigninSampleScript : MonoBehaviour { // Can be set via the property inspector in the Editor. void Awake() { configuration = new GoogleSignInConfiguration { +#if UNITY_EDITOR || UNITY_STANDALONE + ClientSecret = Secret, +#endif WebClientId = webClientId, RequestIdToken = true }; @@ -41,11 +47,9 @@ void Awake() { public void OnSignIn() { GoogleSignIn.Configuration = configuration; GoogleSignIn.Configuration.UseGameSignIn = false; - GoogleSignIn.Configuration.RequestIdToken = true; AddStatusText("Calling SignIn"); - GoogleSignIn.DefaultInstance.SignIn().ContinueWith( - OnAuthenticationFinished); + GoogleSignIn.DefaultInstance.SignIn().ContinueWith(OnAuthenticationFinished,TaskScheduler.FromCurrentSynchronizationContext()); } public void OnSignOut() { @@ -83,8 +87,7 @@ public void OnSignInSilently() { GoogleSignIn.Configuration.RequestIdToken = true; AddStatusText("Calling SignIn Silently"); - GoogleSignIn.DefaultInstance.SignInSilently() - .ContinueWith(OnAuthenticationFinished); + GoogleSignIn.DefaultInstance.SignInSilently().ContinueWith(OnAuthenticationFinished,TaskScheduler.FromCurrentSynchronizationContext()); } @@ -95,8 +98,7 @@ public void OnGamesSignIn() { AddStatusText("Calling Games SignIn"); - GoogleSignIn.DefaultInstance.SignIn().ContinueWith( - OnAuthenticationFinished); + GoogleSignIn.DefaultInstance.SignIn().ContinueWith(OnAuthenticationFinished,TaskScheduler.FromCurrentSynchronizationContext()); } private List messages = new List(); diff --git a/GoogleSignInPlugin/Assets/SignInSample/SigninSampleScript.cs.meta b/Samples~/SignInSample/SigninSampleScript.cs.meta similarity index 100% rename from GoogleSignInPlugin/Assets/SignInSample/SigninSampleScript.cs.meta rename to Samples~/SignInSample/SigninSampleScript.cs.meta diff --git a/package.json b/package.json new file mode 100644 index 00000000..2300d6f2 --- /dev/null +++ b/package.json @@ -0,0 +1,22 @@ +{ + "name": "com.google.signin", + "displayName": "Google Signin", + "version": "0.8.0", + "unity": "2021.3", + "description": "Google Signin for android, ios ,desktop", + "keywords": [ + "google", + "signin" + ], + "dependencies": { + "com.google.external-dependency-manager": "1.2.177", + "com.unity.nuget.newtonsoft-json": "3.2.1" + }, + "samples": [ + { + "displayName": "SignIn Sample", + "description": "Simple SignIn Sample", + "path": "Samples~/SignInSample" + } + ] +} \ No newline at end of file diff --git a/package.json.meta b/package.json.meta new file mode 100644 index 00000000..5171498e --- /dev/null +++ b/package.json.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: d0144d8f7992f134a87074b63d2c169e +PackageManifestImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: From 2640b94aa95801e8d021fdd80afe4e46ff442ab9 Mon Sep 17 00:00:00 2001 From: Thaina Yu Date: Thu, 19 Oct 2023 15:43:15 +0700 Subject: [PATCH 03/25] add reflection path for older version of unity --- GoogleSignIn/Impl/GoogleSignInImpl.cs | 68 ++++++++++++++++++--------- GoogleSignIn/link.xml | 5 ++ GoogleSignIn/link.xml.meta | 7 +++ 3 files changed, 59 insertions(+), 21 deletions(-) create mode 100644 GoogleSignIn/link.xml create mode 100644 GoogleSignIn/link.xml.meta diff --git a/GoogleSignIn/Impl/GoogleSignInImpl.cs b/GoogleSignIn/Impl/GoogleSignInImpl.cs index 33747709..03ba351d 100644 --- a/GoogleSignIn/Impl/GoogleSignInImpl.cs +++ b/GoogleSignIn/Impl/GoogleSignInImpl.cs @@ -15,14 +15,18 @@ // namespace Google.Impl { - using System; - using System.Text; - using System.Collections.Generic; - using System.Runtime.InteropServices; + using System; + using System.Text; + using System.Collections.Generic; + using System.Runtime.InteropServices; - using UnityEngine; + using UnityEngine; +#if UNITY_2022_2_OR_NEWER +#else + using System.Reflection; +#endif - internal class GoogleSignInImpl : BaseObject, ISignInImpl { + internal class GoogleSignInImpl : BaseObject, ISignInImpl { internal GoogleSignInImpl(GoogleSignInConfiguration configuration) : base(GoogleSignIn_Create(GetPlayerActivity())) { @@ -97,7 +101,7 @@ public void Disconnect() { static AndroidJavaObject parentActivity; static IntPtr GoogleSignIn_Create(IntPtr activity) { - parentActivity = new AndroidJavaObject(activity); + parentActivity = activity.ToAndroidJavaObject(); return GoogleSignInFragment.CallStatic("getInstance",parentActivity).GetRawObject(); } @@ -149,33 +153,33 @@ static IntPtr GoogleSignIn_SignInSilently(HandleRef self) return GoogleSignInHelper.CallStatic("signInSilently",parentActivity).GetRawObject(); } - static void GoogleSignIn_Signout(HandleRef self) => GoogleSignInHelper.CallStatic("signOut",new AndroidJavaObject(self.Handle)); + static void GoogleSignIn_Signout(HandleRef self) => GoogleSignInHelper.CallStatic("signOut",self.ToAndroidJavaObject()); - static void GoogleSignIn_Disconnect(HandleRef self) => GoogleSignInHelper.CallStatic("disconnect",new AndroidJavaObject(self.Handle)); + static void GoogleSignIn_Disconnect(HandleRef self) => GoogleSignInHelper.CallStatic("disconnect",self.ToAndroidJavaObject()); - internal static void GoogleSignIn_DisposeFuture(HandleRef self) => new AndroidJavaObject(self.Handle).Dispose(); + internal static void GoogleSignIn_DisposeFuture(HandleRef self) => self.ToAndroidJavaObject().Dispose(); - internal static bool GoogleSignIn_Pending(HandleRef self) => new AndroidJavaObject(self.Handle).Call("isPending"); + internal static bool GoogleSignIn_Pending(HandleRef self) => self.ToAndroidJavaObject().Call("isPending"); - internal static IntPtr GoogleSignIn_Result(HandleRef self) => new AndroidJavaObject(self.Handle).Call("getAccount").GetRawObject(); + internal static IntPtr GoogleSignIn_Result(HandleRef self) => self.ToAndroidJavaObject().Call("getAccount").GetRawObject(); - internal static int GoogleSignIn_Status(HandleRef self) => new AndroidJavaObject(self.Handle).Call("getStatus"); + internal static int GoogleSignIn_Status(HandleRef self) => self.ToAndroidJavaObject().Call("getStatus"); - internal static string GoogleSignIn_GetServerAuthCode(HandleRef self) => new AndroidJavaObject(self.Handle).Call("getServerAuthCode"); + internal static string GoogleSignIn_GetServerAuthCode(HandleRef self) => self.ToAndroidJavaObject().Call("getServerAuthCode"); - internal static string GoogleSignIn_GetDisplayName(HandleRef self) => new AndroidJavaObject(self.Handle).Call("getDisplayName"); + internal static string GoogleSignIn_GetDisplayName(HandleRef self) => self.ToAndroidJavaObject().Call("getDisplayName"); - internal static string GoogleSignIn_GetEmail(HandleRef self) => new AndroidJavaObject(self.Handle).Call("getEmail"); + internal static string GoogleSignIn_GetEmail(HandleRef self) => self.ToAndroidJavaObject().Call("getEmail"); - internal static string GoogleSignIn_GetFamilyName(HandleRef self) => new AndroidJavaObject(self.Handle).Call("getFamilyName"); + internal static string GoogleSignIn_GetFamilyName(HandleRef self) => self.ToAndroidJavaObject().Call("getFamilyName"); - internal static string GoogleSignIn_GetGivenName(HandleRef self) => new AndroidJavaObject(self.Handle).Call("getGivenName"); + internal static string GoogleSignIn_GetGivenName(HandleRef self) => self.ToAndroidJavaObject().Call("getGivenName"); - internal static string GoogleSignIn_GetIdToken(HandleRef self) => new AndroidJavaObject(self.Handle).Call("getIdToken"); + internal static string GoogleSignIn_GetIdToken(HandleRef self) => self.ToAndroidJavaObject().Call("getIdToken"); - internal static string GoogleSignIn_GetImageUrl(HandleRef self) => new AndroidJavaObject(self.Handle).Call("getPhotoUrl").Call("toString"); + internal static string GoogleSignIn_GetImageUrl(HandleRef self) => self.ToAndroidJavaObject().Call("getPhotoUrl").Call("toString"); - internal static string GoogleSignIn_GetUserId(HandleRef self) => new AndroidJavaObject(self.Handle).Call("getId"); + internal static string GoogleSignIn_GetUserId(HandleRef self) => self.ToAndroidJavaObject().Call("getId"); #else private const string DllName = "__Internal"; @@ -312,6 +316,28 @@ private static IntPtr GetPlayerActivity() { return jc.GetStatic("currentActivity").GetRawObject(); #else return IntPtr.Zero; +#endif + } + } + + public static class Ext + { +#if UNITY_2022_2_OR_NEWER +#else + static ConstructorInfo constructorInfo; +#endif + + public static AndroidJavaObject ToAndroidJavaObject(in this HandleRef self) => self.Handle.ToAndroidJavaObject(); + public static AndroidJavaObject ToAndroidJavaObject(in this IntPtr intPtr) + { +#if UNITY_2022_2_OR_NEWER + return new AndroidJavaObject(intPtr); +#else + if(constructorInfo == null) + constructorInfo = typeof(AndroidJavaObject).GetConstructor(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic,null,new[] { typeof(IntPtr) },null); + + Debug.Log(constructorInfo); + return constructorInfo.Invoke(new object[] { intPtr }) as AndroidJavaObject; #endif } } diff --git a/GoogleSignIn/link.xml b/GoogleSignIn/link.xml new file mode 100644 index 00000000..af59fefc --- /dev/null +++ b/GoogleSignIn/link.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/GoogleSignIn/link.xml.meta b/GoogleSignIn/link.xml.meta new file mode 100644 index 00000000..6c1ca62e --- /dev/null +++ b/GoogleSignIn/link.xml.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 8d4fb89b8eb5f4d49bfdcdc4f53884e1 +TextScriptImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: From 62ac175412209109f4ffd1b760090b80bae9e786 Mon Sep 17 00:00:00 2001 From: Thaina Yu Date: Thu, 9 Nov 2023 21:18:09 +0700 Subject: [PATCH 04/25] Update GoogleSignInImpl.cs Fix signOut and disconnect --- GoogleSignIn/Impl/GoogleSignInImpl.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/GoogleSignIn/Impl/GoogleSignInImpl.cs b/GoogleSignIn/Impl/GoogleSignInImpl.cs index 03ba351d..d4a45efd 100644 --- a/GoogleSignIn/Impl/GoogleSignInImpl.cs +++ b/GoogleSignIn/Impl/GoogleSignInImpl.cs @@ -153,9 +153,9 @@ static IntPtr GoogleSignIn_SignInSilently(HandleRef self) return GoogleSignInHelper.CallStatic("signInSilently",parentActivity).GetRawObject(); } - static void GoogleSignIn_Signout(HandleRef self) => GoogleSignInHelper.CallStatic("signOut",self.ToAndroidJavaObject()); + static void GoogleSignIn_Signout(HandleRef self) => GoogleSignInHelper.CallStatic("signOut",parentActivity); - static void GoogleSignIn_Disconnect(HandleRef self) => GoogleSignInHelper.CallStatic("disconnect",self.ToAndroidJavaObject()); + static void GoogleSignIn_Disconnect(HandleRef self) => GoogleSignInHelper.CallStatic("disconnect",parentActivity); internal static void GoogleSignIn_DisposeFuture(HandleRef self) => self.ToAndroidJavaObject().Dispose(); From 9aa40ab8b281352b830332b3a8fc22541ab929f4 Mon Sep 17 00:00:00 2001 From: Thaina Yu Date: Sat, 25 Nov 2023 19:59:18 +0700 Subject: [PATCH 05/25] Update GoogleSignInImpl.cs --- GoogleSignIn/Impl/GoogleSignInImpl.cs | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/GoogleSignIn/Impl/GoogleSignInImpl.cs b/GoogleSignIn/Impl/GoogleSignInImpl.cs index d4a45efd..f9297fc2 100644 --- a/GoogleSignIn/Impl/GoogleSignInImpl.cs +++ b/GoogleSignIn/Impl/GoogleSignInImpl.cs @@ -136,8 +136,12 @@ public SignInListener() : base("com.google.googlesignin.IListener") public void OnResult(int result, AndroidJavaObject acct) { - Debug.Log("googlesignin.IListener : " + acct.Call("toString")); - Debug.Log("ID : " + acct.Call("getId")); + if(acct != null) + { + Debug.Log("googlesignin.IListener : " + acct.Call("toString")); + Debug.Log("ID : " + acct.Call("getId")); + } + else Debug.LogError("Should not get null account"); } } From bff1079cb74648057bf85f260675e71bdbabfffb Mon Sep 17 00:00:00 2001 From: Thaina Yu Date: Wed, 13 Dec 2023 16:26:29 +0700 Subject: [PATCH 06/25] add timeout to await for silentSignIn --- GoogleSignIn/Impl/GoogleSignInImpl.cs | 27 +++---- .../googlesignin/GoogleSignInFragment.java | 72 ++++++++++--------- 2 files changed, 55 insertions(+), 44 deletions(-) diff --git a/GoogleSignIn/Impl/GoogleSignInImpl.cs b/GoogleSignIn/Impl/GoogleSignInImpl.cs index f9297fc2..b3edb6f8 100644 --- a/GoogleSignIn/Impl/GoogleSignInImpl.cs +++ b/GoogleSignIn/Impl/GoogleSignInImpl.cs @@ -161,29 +161,29 @@ static IntPtr GoogleSignIn_SignInSilently(HandleRef self) static void GoogleSignIn_Disconnect(HandleRef self) => GoogleSignInHelper.CallStatic("disconnect",parentActivity); - internal static void GoogleSignIn_DisposeFuture(HandleRef self) => self.ToAndroidJavaObject().Dispose(); + internal static void GoogleSignIn_DisposeFuture(HandleRef self) => self.ToAndroidJavaObject()?.Dispose(); - internal static bool GoogleSignIn_Pending(HandleRef self) => self.ToAndroidJavaObject().Call("isPending"); + internal static bool GoogleSignIn_Pending(HandleRef self) => self.ToAndroidJavaObject()?.Call("isPending") ?? false; - internal static IntPtr GoogleSignIn_Result(HandleRef self) => self.ToAndroidJavaObject().Call("getAccount").GetRawObject(); + internal static IntPtr GoogleSignIn_Result(HandleRef self) => self.ToAndroidJavaObject()?.Call("getAccount")?.GetRawObject() ?? IntPtr.Zero; - internal static int GoogleSignIn_Status(HandleRef self) => self.ToAndroidJavaObject().Call("getStatus"); + internal static int GoogleSignIn_Status(HandleRef self) => self.ToAndroidJavaObject()?.Call("getStatus") ?? -1; - internal static string GoogleSignIn_GetServerAuthCode(HandleRef self) => self.ToAndroidJavaObject().Call("getServerAuthCode"); + internal static string GoogleSignIn_GetServerAuthCode(HandleRef self) => self.ToAndroidJavaObject()?.Call("getServerAuthCode"); - internal static string GoogleSignIn_GetDisplayName(HandleRef self) => self.ToAndroidJavaObject().Call("getDisplayName"); + internal static string GoogleSignIn_GetDisplayName(HandleRef self) => self.ToAndroidJavaObject()?.Call("getDisplayName"); - internal static string GoogleSignIn_GetEmail(HandleRef self) => self.ToAndroidJavaObject().Call("getEmail"); + internal static string GoogleSignIn_GetEmail(HandleRef self) => self.ToAndroidJavaObject()?.Call("getEmail"); - internal static string GoogleSignIn_GetFamilyName(HandleRef self) => self.ToAndroidJavaObject().Call("getFamilyName"); + internal static string GoogleSignIn_GetFamilyName(HandleRef self) => self.ToAndroidJavaObject()?.Call("getFamilyName"); - internal static string GoogleSignIn_GetGivenName(HandleRef self) => self.ToAndroidJavaObject().Call("getGivenName"); + internal static string GoogleSignIn_GetGivenName(HandleRef self) => self.ToAndroidJavaObject()?.Call("getGivenName"); - internal static string GoogleSignIn_GetIdToken(HandleRef self) => self.ToAndroidJavaObject().Call("getIdToken"); + internal static string GoogleSignIn_GetIdToken(HandleRef self) => self.ToAndroidJavaObject()?.Call("getIdToken"); - internal static string GoogleSignIn_GetImageUrl(HandleRef self) => self.ToAndroidJavaObject().Call("getPhotoUrl").Call("toString"); + internal static string GoogleSignIn_GetImageUrl(HandleRef self) => self.ToAndroidJavaObject()?.Call("getPhotoUrl")?.Call("toString"); - internal static string GoogleSignIn_GetUserId(HandleRef self) => self.ToAndroidJavaObject().Call("getId"); + internal static string GoogleSignIn_GetUserId(HandleRef self) => self.ToAndroidJavaObject()?.Call("getId"); #else private const string DllName = "__Internal"; @@ -334,6 +334,9 @@ public static class Ext public static AndroidJavaObject ToAndroidJavaObject(in this HandleRef self) => self.Handle.ToAndroidJavaObject(); public static AndroidJavaObject ToAndroidJavaObject(in this IntPtr intPtr) { + if(intPtr == IntPtr.Zero) + return null; + #if UNITY_2022_2_OR_NEWER return new AndroidJavaObject(intPtr); #else diff --git a/Plugins/Android/src/main/java/com/google/googlesignin/GoogleSignInFragment.java b/Plugins/Android/src/main/java/com/google/googlesignin/GoogleSignInFragment.java index 3a56f866..f49dea27 100644 --- a/Plugins/Android/src/main/java/com/google/googlesignin/GoogleSignInFragment.java +++ b/Plugins/Android/src/main/java/com/google/googlesignin/GoogleSignInFragment.java @@ -35,10 +35,12 @@ import com.google.android.gms.common.api.PendingResult; import com.google.android.gms.common.api.ResultCallback; import com.google.android.gms.common.api.Scope; +import com.google.android.gms.common.api.Status; import java.lang.reflect.Field; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.util.Locale; +import java.util.concurrent.TimeUnit; /** * Activity fragment with no UI added to the parent activity in order to manage the accessing of the @@ -62,15 +64,19 @@ void DoSignIn(boolean silent) { Auth.GoogleSignInApi.silentSignIn(mGoogleApiClient).setResultCallback(new ResultCallback() { @Override public void onResult(@NonNull GoogleSignInResult googleSignInResult) { - if (!googleSignInResult.isSuccess()) { - GoogleSignInHelper.logError( - "Error with " + "silentSignIn: " + googleSignInResult.getStatus()); + if(googleSignInResult == null) { + GoogleSignInHelper.logError("Error with silentSignIn: googleSignInResult is null"); + GoogleSignInHelper.nativeOnResult(request.getHandle(),CommonStatusCodes.INTERNAL_ERROR,null); + return; } - GoogleSignInHelper.nativeOnResult( - request.getHandle(), - googleSignInResult.getStatus().getStatusCode(), - googleSignInResult.getSignInAccount()); + Status status = googleSignInResult.getStatus(); + GoogleSignInAccount acct = googleSignInResult.isSuccess() ? googleSignInResult.getSignInAccount() : null; + if (acct == null) { + GoogleSignInHelper.logError("Error with silentSignIn: " + status); + } + + GoogleSignInHelper.nativeOnResult(request.getHandle(),status != null ? status.getStatusCode() : CommonStatusCodes.INTERNAL_ERROR,acct); setState(State.READY); } }); @@ -153,7 +159,10 @@ public TokenRequest getRequest() { private PendingResult tokenPendingResult = null; public GoogleSignInAccount getAccount() { - return tokenPendingResult.await().getAccount(); + if(tokenPendingResult == null || tokenPendingResult.isCanceled()) + return null; + + return tokenPendingResult.await(3,TimeUnit.SECONDS).getAccount(); } public int getStatus() { @@ -161,7 +170,11 @@ public int getStatus() { return CommonStatusCodes.DEVELOPER_ERROR; } - return tokenPendingResult.await().getStatus().getStatusCode(); + if(tokenPendingResult.isCanceled()) { + return CommonStatusCodes.CANCELED; + } + + return tokenPendingResult.await(3,TimeUnit.SECONDS).getStatus().getStatusCode(); } private GoogleApiClient mGoogleApiClient; @@ -287,34 +300,29 @@ private void processRequest(final boolean silent) { } setState(State.BUSY); - request - .getPendingResponse() - .setResultCallback( - new ResultCallback() { - @Override - public void onResult(@NonNull TokenResult tokenResult) { - GoogleSignInHelper.logDebug( - String.format( - Locale.getDefault(), - "Calling nativeOnResult: handle: %s, status: %d acct: %s", - tokenResult.getHandle(), - tokenResult.getStatus().getStatusCode(), - tokenResult.getAccount())); - GoogleSignInHelper.nativeOnResult( - tokenResult.getHandle(), - tokenResult.getStatus().getStatusCode(), - tokenResult.getAccount()); - clearRequest(false); - } - }); + request.getPendingResponse().setResultCallback(new ResultCallback() { + @Override + public void onResult(@NonNull TokenResult tokenResult) { + GoogleSignInHelper.logDebug( + String.format( + Locale.getDefault(), + "Calling nativeOnResult: handle: %s, status: %d acct: %s", + tokenResult.getHandle(), + tokenResult.getStatus().getStatusCode(), + tokenResult.getAccount())); + GoogleSignInHelper.nativeOnResult( + tokenResult.getHandle(), + tokenResult.getStatus().getStatusCode(), + tokenResult.getAccount()); + clearRequest(false); + } + }); // Build the GoogleAPIClient buildClient(request); - GoogleSignInHelper.logDebug( - " Has connected == " + mGoogleApiClient.hasConnectedApi(Auth.GOOGLE_SIGN_IN_API)); + GoogleSignInHelper.logDebug(" Has connected == " + mGoogleApiClient.hasConnectedApi(Auth.GOOGLE_SIGN_IN_API)); if (!mGoogleApiClient.hasConnectedApi(Auth.GOOGLE_SIGN_IN_API)) { - DoSignIn(silent); } } catch (Throwable throwable) { From aea1435dbf430f81aec6fa12d3422a0806a10e0b Mon Sep 17 00:00:00 2001 From: Thaina Yu Date: Wed, 13 Dec 2023 19:45:26 +0700 Subject: [PATCH 07/25] change return status value --- GoogleSignIn/Impl/GoogleSignInImpl.cs | 21 +++++++++++++++------ 1 file changed, 15 insertions(+), 6 deletions(-) diff --git a/GoogleSignIn/Impl/GoogleSignInImpl.cs b/GoogleSignIn/Impl/GoogleSignInImpl.cs index b3edb6f8..017e674d 100644 --- a/GoogleSignIn/Impl/GoogleSignInImpl.cs +++ b/GoogleSignIn/Impl/GoogleSignInImpl.cs @@ -167,7 +167,7 @@ static IntPtr GoogleSignIn_SignInSilently(HandleRef self) internal static IntPtr GoogleSignIn_Result(HandleRef self) => self.ToAndroidJavaObject()?.Call("getAccount")?.GetRawObject() ?? IntPtr.Zero; - internal static int GoogleSignIn_Status(HandleRef self) => self.ToAndroidJavaObject()?.Call("getStatus") ?? -1; + internal static int GoogleSignIn_Status(HandleRef self) => self.ToAndroidJavaObject()?.Call("getStatus") ?? 6; internal static string GoogleSignIn_GetServerAuthCode(HandleRef self) => self.ToAndroidJavaObject()?.Call("getServerAuthCode"); @@ -337,15 +337,24 @@ public static AndroidJavaObject ToAndroidJavaObject(in this IntPtr intPtr) if(intPtr == IntPtr.Zero) return null; + try + { #if UNITY_2022_2_OR_NEWER - return new AndroidJavaObject(intPtr); + return new AndroidJavaObject(intPtr); #else - if(constructorInfo == null) - constructorInfo = typeof(AndroidJavaObject).GetConstructor(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic,null,new[] { typeof(IntPtr) },null); + if(constructorInfo == null) + constructorInfo = typeof(AndroidJavaObject).GetConstructor(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic,null,new[] { typeof(IntPtr) },null); - Debug.Log(constructorInfo); - return constructorInfo.Invoke(new object[] { intPtr }) as AndroidJavaObject; + Debug.LogFormat("constructorInfo : {0}",constructorInfo); + return constructorInfo.Invoke(new object[] { intPtr }) as AndroidJavaObject; #endif + } + catch(Exception e) + { + Debug.LogException(e); + } + + return null; } } } From 113f889c32606d56c7bbb2347dceda429b4ba3ab Mon Sep 17 00:00:00 2001 From: CalummaRobert Date: Tue, 12 Mar 2024 11:46:15 +0100 Subject: [PATCH 08/25] Clean Up + Fixes --- GoogleSignIn/Future.cs | 19 +++++++++++++++++-- GoogleSignIn/GoogleSignIn.cs | 16 ++++++++++++++++ GoogleSignIn/Impl/GoogleSignInImpl.cs | 4 +++- GoogleSignIn/Impl/GoogleSignInImplEditor.cs | 2 ++ GoogleSignIn/Impl/NativeFuture.cs | 4 +++- .../googlesignin/TokenPendingResult.java | 7 +++++++ package.json | 5 +++-- 7 files changed, 51 insertions(+), 6 deletions(-) diff --git a/GoogleSignIn/Future.cs b/GoogleSignIn/Future.cs index 1af950c5..bc502cb7 100644 --- a/GoogleSignIn/Future.cs +++ b/GoogleSignIn/Future.cs @@ -55,14 +55,14 @@ internal Future(FutureAPIImpl impl) { /// Gets the status. /// /// The status is set when Pending == false. - GoogleSignInStatusCode Status { get { return apiImpl.Status; } } + public GoogleSignInStatusCode Status { get { return apiImpl.Status; } } /// /// Gets the result. /// /// The result is set when Pending == false and there is no error. /// - T Result { get { return apiImpl.Result; } } + public T Result { get { return apiImpl.Result; } } /// /// Waits for result then completes the TaskCompleationSource. @@ -71,6 +71,21 @@ internal Future(FutureAPIImpl impl) { /// Tcs. internal IEnumerator WaitForResult(TaskCompletionSource tcs) { yield return new WaitUntil(() => !Pending); + yield return null; + if (Status == GoogleSignInStatusCode.CANCELED) { + tcs.SetCanceled(); + } else if (Status == GoogleSignInStatusCode.SUCCESS || + Status == GoogleSignInStatusCode.SUCCESS_CACHE) { + tcs.SetResult(Result); + } else { + tcs.SetException(new GoogleSignIn.SignInException(Status)); + } + } + + internal async Task WaitForResultAsync(TaskCompletionSource tcs) + { + while (Pending) await Task.Yield(); + await Task.Yield(); if (Status == GoogleSignInStatusCode.CANCELED) { tcs.SetCanceled(); } else if (Status == GoogleSignInStatusCode.SUCCESS || diff --git a/GoogleSignIn/GoogleSignIn.cs b/GoogleSignIn/GoogleSignIn.cs index afd36d62..87c275b9 100644 --- a/GoogleSignIn/GoogleSignIn.cs +++ b/GoogleSignIn/GoogleSignIn.cs @@ -123,6 +123,14 @@ public Task SignIn() { return tcs.Task; } + public Task SignInAsync() { + var tcs = new TaskCompletionSource(); + impl.SignIn().WaitForResultAsync(tcs); + return tcs.Task; + } + + public Future SignInFuture() => impl.SignIn(); + /// Starts the silent authentication process. /// /// The authenication process is started and will attempt to sign in without @@ -136,6 +144,14 @@ public Task SignInSilently() { return tcs.Task; } + public Task SignInSilentlyAsync() { + var tcs = new TaskCompletionSource(); + impl.SignInSilently().WaitForResultAsync(tcs); + return tcs.Task; + } + + public Future SignInSilentlyFuture() => impl.SignInSilently(); + /// /// Signs out the User. /// diff --git a/GoogleSignIn/Impl/GoogleSignInImpl.cs b/GoogleSignIn/Impl/GoogleSignInImpl.cs index 017e674d..23d7ce1a 100644 --- a/GoogleSignIn/Impl/GoogleSignInImpl.cs +++ b/GoogleSignIn/Impl/GoogleSignInImpl.cs @@ -1,4 +1,5 @@ -// +#if UNITY_EDITOR || UNITY_ANDROID || UNITY_IOS +// // Copyright (C) 2017 Google Inc. All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); @@ -358,3 +359,4 @@ public static AndroidJavaObject ToAndroidJavaObject(in this IntPtr intPtr) } } } +#endif diff --git a/GoogleSignIn/Impl/GoogleSignInImplEditor.cs b/GoogleSignIn/Impl/GoogleSignInImplEditor.cs index b59fd3ce..670ac518 100644 --- a/GoogleSignIn/Impl/GoogleSignInImplEditor.cs +++ b/GoogleSignIn/Impl/GoogleSignInImplEditor.cs @@ -62,6 +62,8 @@ static HttpListener BindLocalHostFirstAvailablePort() #if UNITY_EDITOR_WIN var listeners = IPGlobalProperties.GetIPGlobalProperties().GetActiveTcpListeners(); return Enumerable.Range(minPort, ushort.MaxValue - minPort).Where((i) => !listeners.Any((x) => x.Port == i)).Select((port) => { +#elif UNITY_EDITOR_OSX + return Enumerable.Range(minPort, ushort.MaxValue - minPort).Select((port) => { #else return Enumerable.Range(0,10).Select((i) => UnityEngine.Random.Range(minPort,ushort.MaxValue)).Select((port) => { #endif diff --git a/GoogleSignIn/Impl/NativeFuture.cs b/GoogleSignIn/Impl/NativeFuture.cs index 71103cf5..1c09d978 100644 --- a/GoogleSignIn/Impl/NativeFuture.cs +++ b/GoogleSignIn/Impl/NativeFuture.cs @@ -1,4 +1,5 @@ -// +#if UNITY_EDITOR || UNITY_ANDROID || UNITY_IOS +// // Copyright (C) 2017 Google Inc. All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); @@ -87,3 +88,4 @@ public GoogleSignInStatusCode Status { } } } +#endif diff --git a/Plugins/Android/src/main/java/com/google/googlesignin/TokenPendingResult.java b/Plugins/Android/src/main/java/com/google/googlesignin/TokenPendingResult.java index 02d2e9b5..636792d1 100644 --- a/Plugins/Android/src/main/java/com/google/googlesignin/TokenPendingResult.java +++ b/Plugins/Android/src/main/java/com/google/googlesignin/TokenPendingResult.java @@ -22,6 +22,7 @@ import com.google.android.gms.common.api.ResultCallback; import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeUnit; +import java.util.Locale; /** * Pending result class for TokenResult. This allows the pending result to be returned to the @@ -41,6 +42,12 @@ public TokenPendingResult(IListener requestHandle) { result = new TokenResult(); result.setHandle(requestHandle); } + + @Override + public String toString() { + return String.format( + Locale.getDefault(), "Pending Result: %s", (result == null) ? "" : result); + } @Override public TokenResult await() { diff --git a/package.json b/package.json index 2300d6f2..9d121d8b 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,8 @@ { "name": "com.google.signin", "displayName": "Google Signin", - "version": "0.8.0", + "author": "Robert Lehmann", + "version": "0.8.1", "unity": "2021.3", "description": "Google Signin for android, ios ,desktop", "keywords": [ @@ -19,4 +20,4 @@ "path": "Samples~/SignInSample" } ] -} \ No newline at end of file +} From 8bc535a24246c3eb3520db6cd6ba1cb2ef25022c Mon Sep 17 00:00:00 2001 From: CalummaRobert Date: Tue, 12 Mar 2024 15:47:12 +0100 Subject: [PATCH 09/25] Fixes --- GoogleSignIn/Impl/GoogleSignInImpl.cs | 16 ++++++---------- 1 file changed, 6 insertions(+), 10 deletions(-) diff --git a/GoogleSignIn/Impl/GoogleSignInImpl.cs b/GoogleSignIn/Impl/GoogleSignInImpl.cs index 23d7ce1a..5fe8d1e3 100644 --- a/GoogleSignIn/Impl/GoogleSignInImpl.cs +++ b/GoogleSignIn/Impl/GoogleSignInImpl.cs @@ -142,7 +142,7 @@ public void OnResult(int result, AndroidJavaObject acct) Debug.Log("googlesignin.IListener : " + acct.Call("toString")); Debug.Log("ID : " + acct.Call("getId")); } - else Debug.LogError("Should not get null account"); + else Debug.LogWarning("Should not get null account"); } } @@ -335,11 +335,10 @@ public static class Ext public static AndroidJavaObject ToAndroidJavaObject(in this HandleRef self) => self.Handle.ToAndroidJavaObject(); public static AndroidJavaObject ToAndroidJavaObject(in this IntPtr intPtr) { - if(intPtr == IntPtr.Zero) + if (intPtr == IntPtr.Zero) return null; - try - { + try { #if UNITY_2022_2_OR_NEWER return new AndroidJavaObject(intPtr); #else @@ -349,13 +348,10 @@ public static AndroidJavaObject ToAndroidJavaObject(in this IntPtr intPtr) Debug.LogFormat("constructorInfo : {0}",constructorInfo); return constructorInfo.Invoke(new object[] { intPtr }) as AndroidJavaObject; #endif + } catch (Exception e) { + Debug.LogError("Exception creating AndroidJavaObject: " + e); + return null; } - catch(Exception e) - { - Debug.LogException(e); - } - - return null; } } } From a402de9bf9a142fa64107a3ba6ecf7d6ff164b5a Mon Sep 17 00:00:00 2001 From: calumma-robert <134316825+calumma-robert@users.noreply.github.com> Date: Tue, 12 Mar 2024 16:44:51 +0100 Subject: [PATCH 10/25] Version bump --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 9d121d8b..25b04f7c 100644 --- a/package.json +++ b/package.json @@ -2,7 +2,7 @@ "name": "com.google.signin", "displayName": "Google Signin", "author": "Robert Lehmann", - "version": "0.8.1", + "version": "0.8.2", "unity": "2021.3", "description": "Google Signin for android, ios ,desktop", "keywords": [ From b6a161ad3c3ec247434c48c9e5fcb8766e5e6c7f Mon Sep 17 00:00:00 2001 From: CalummaRobert Date: Tue, 12 Mar 2024 17:40:30 +0100 Subject: [PATCH 11/25] Fixes --- .../googlesignin/GoogleSignInFragment.java | 17 ++++++++++++++++- package.json | 2 +- 2 files changed, 17 insertions(+), 2 deletions(-) diff --git a/Plugins/Android/src/main/java/com/google/googlesignin/GoogleSignInFragment.java b/Plugins/Android/src/main/java/com/google/googlesignin/GoogleSignInFragment.java index f49dea27..9e42c86a 100644 --- a/Plugins/Android/src/main/java/com/google/googlesignin/GoogleSignInFragment.java +++ b/Plugins/Android/src/main/java/com/google/googlesignin/GoogleSignInFragment.java @@ -70,6 +70,8 @@ public void onResult(@NonNull GoogleSignInResult googleSignInResult) { return; } + GoogleSignInFragment.this.tokenResult = new TokenResult(googleSignInResult.getSignInAccount(), googleSignInResult.getStatus().getStatusCode()); + Status status = googleSignInResult.getStatus(); GoogleSignInAccount acct = googleSignInResult.isSuccess() ? googleSignInResult.getSignInAccount() : null; if (acct == null) { @@ -77,6 +79,7 @@ public void onResult(@NonNull GoogleSignInResult googleSignInResult) { } GoogleSignInHelper.nativeOnResult(request.getHandle(),status != null ? status.getStatusCode() : CommonStatusCodes.INTERNAL_ERROR,acct); + request.cancel(); setState(State.READY); } }); @@ -122,6 +125,7 @@ public void onConnectionFailed(@NonNull ConnectionResult connectionResult) { } public void disconnect() { + this.tokenResult = null; this.tokenPendingResult = null; if (mGoogleApiClient != null) { mGoogleApiClient.disconnect(); @@ -156,9 +160,13 @@ public TokenRequest getRequest() { return request; } + private TokenResult tokenResult = null; private PendingResult tokenPendingResult = null; public GoogleSignInAccount getAccount() { + if (tokenResult != null) + return tokenResult.getAccount(); + if(tokenPendingResult == null || tokenPendingResult.isCanceled()) return null; @@ -166,6 +174,9 @@ public GoogleSignInAccount getAccount() { } public int getStatus() { + if (tokenResult != null) + return tokenResult.getStatus().getStatusCode(); + if(tokenPendingResult == null) { return CommonStatusCodes.DEVELOPER_ERROR; } @@ -207,6 +218,7 @@ public static GoogleSignInFragment getInstance(Activity parentActivity) { public synchronized boolean submitRequest(TokenRequest request) { if (this.request == null || this.state == State.READY) { this.request = request; + this.tokenResult = null; this.tokenPendingResult = request.getPendingResponse(); return true; } @@ -230,6 +242,7 @@ private synchronized void setState(State state) { */ public void signOut() { clearRequest(true); + this.tokenResult = null; this.tokenPendingResult = null; if (mGoogleApiClient != null) { Auth.GoogleSignInApi.signOut(mGoogleApiClient); @@ -303,6 +316,7 @@ private void processRequest(final boolean silent) { request.getPendingResponse().setResultCallback(new ResultCallback() { @Override public void onResult(@NonNull TokenResult tokenResult) { + GoogleSignInFragment.this.tokenResult = tokenResult; GoogleSignInHelper.logDebug( String.format( Locale.getDefault(), @@ -314,7 +328,8 @@ public void onResult(@NonNull TokenResult tokenResult) { tokenResult.getHandle(), tokenResult.getStatus().getStatusCode(), tokenResult.getAccount()); - clearRequest(false); + request.cancel(); + setState(State.READY); } }); diff --git a/package.json b/package.json index 25b04f7c..55419c13 100644 --- a/package.json +++ b/package.json @@ -2,7 +2,7 @@ "name": "com.google.signin", "displayName": "Google Signin", "author": "Robert Lehmann", - "version": "0.8.2", + "version": "0.8.3", "unity": "2021.3", "description": "Google Signin for android, ios ,desktop", "keywords": [ From 9d4350de2195ee8daafc88039a502c54ae4e93f5 Mon Sep 17 00:00:00 2001 From: CalummaRobert Date: Tue, 12 Mar 2024 21:21:43 +0100 Subject: [PATCH 12/25] No additional wait --- GoogleSignIn/Future.cs | 2 -- 1 file changed, 2 deletions(-) diff --git a/GoogleSignIn/Future.cs b/GoogleSignIn/Future.cs index bc502cb7..42b8f6fe 100644 --- a/GoogleSignIn/Future.cs +++ b/GoogleSignIn/Future.cs @@ -71,7 +71,6 @@ internal Future(FutureAPIImpl impl) { /// Tcs. internal IEnumerator WaitForResult(TaskCompletionSource tcs) { yield return new WaitUntil(() => !Pending); - yield return null; if (Status == GoogleSignInStatusCode.CANCELED) { tcs.SetCanceled(); } else if (Status == GoogleSignInStatusCode.SUCCESS || @@ -85,7 +84,6 @@ internal IEnumerator WaitForResult(TaskCompletionSource tcs) { internal async Task WaitForResultAsync(TaskCompletionSource tcs) { while (Pending) await Task.Yield(); - await Task.Yield(); if (Status == GoogleSignInStatusCode.CANCELED) { tcs.SetCanceled(); } else if (Status == GoogleSignInStatusCode.SUCCESS || From f5404e4f9c22ed9799c4f9b4fc06298d6b9fc530 Mon Sep 17 00:00:00 2001 From: calumma-robert <134316825+calumma-robert@users.noreply.github.com> Date: Wed, 13 Mar 2024 01:57:14 +0100 Subject: [PATCH 13/25] Update Future.cs seems it was needed... --- GoogleSignIn/Future.cs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/GoogleSignIn/Future.cs b/GoogleSignIn/Future.cs index 42b8f6fe..1784b3ea 100644 --- a/GoogleSignIn/Future.cs +++ b/GoogleSignIn/Future.cs @@ -71,6 +71,7 @@ internal Future(FutureAPIImpl impl) { /// Tcs. internal IEnumerator WaitForResult(TaskCompletionSource tcs) { yield return new WaitUntil(() => !Pending); + yield return null; if (Status == GoogleSignInStatusCode.CANCELED) { tcs.SetCanceled(); } else if (Status == GoogleSignInStatusCode.SUCCESS || @@ -84,6 +85,7 @@ internal IEnumerator WaitForResult(TaskCompletionSource tcs) { internal async Task WaitForResultAsync(TaskCompletionSource tcs) { while (Pending) await Task.Yield(); + await Task.Yield(); if (Status == GoogleSignInStatusCode.CANCELED) { tcs.SetCanceled(); } else if (Status == GoogleSignInStatusCode.SUCCESS || @@ -94,4 +96,4 @@ internal async Task WaitForResultAsync(TaskCompletionSource tcs) } } } -} \ No newline at end of file +} From f7c807e95e60dd54129565e9f40b9e9f4c51bf3c Mon Sep 17 00:00:00 2001 From: Thaina Yu Date: Wed, 13 Mar 2024 17:24:23 +0700 Subject: [PATCH 14/25] Update package.json --- package.json | 1 - 1 file changed, 1 deletion(-) diff --git a/package.json b/package.json index 55419c13..f5c2341f 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,6 @@ { "name": "com.google.signin", "displayName": "Google Signin", - "author": "Robert Lehmann", "version": "0.8.3", "unity": "2021.3", "description": "Google Signin for android, ios ,desktop", From 1c4a52e9183b6de4d0926b3ecf6fa035135ee300 Mon Sep 17 00:00:00 2001 From: Thaina Yu Date: Tue, 4 Jun 2024 20:01:51 +0700 Subject: [PATCH 15/25] Update GoogleSignIn.cs --- GoogleSignIn/GoogleSignIn.cs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/GoogleSignIn/GoogleSignIn.cs b/GoogleSignIn/GoogleSignIn.cs index 87c275b9..8f9ae3f4 100644 --- a/GoogleSignIn/GoogleSignIn.cs +++ b/GoogleSignIn/GoogleSignIn.cs @@ -93,9 +93,7 @@ public static GoogleSignIn DefaultInstance { theInstance = new GoogleSignIn(new GoogleSignInImpl(Configuration)); #else theInstance = new GoogleSignIn(null); - throw new SignInException( - GoogleSignInStatusCode.DeveloperError, - "This platform is not supported by GoogleSignIn"); + throw new SignInException(GoogleSignInStatusCode.DEVELOPER_ERROR,"This platform is not supported by GoogleSignIn"); #endif } return theInstance; From 64f17b33e2eb91d3d9a2d9a636810b4f1da7024a Mon Sep 17 00:00:00 2001 From: Thaina Yu Date: Mon, 10 Jun 2024 18:43:03 +0700 Subject: [PATCH 16/25] Migrate android to CredentialManager Migrate ios to 7.1.0 --- .../Editor/GoogleSignInDependencies.xml | 12 +- GoogleSignIn/GoogleSignIn.cs | 16 +- GoogleSignIn/Impl/BaseObject.cs | 9 +- GoogleSignIn/Impl/GoogleSignInImpl.cs | 628 +++++++++--------- GoogleSignIn/Impl/GoogleSignInImplEditor.cs | 29 +- GoogleSignIn/Impl/NativeFuture.cs | 18 +- .../googlesignin/GoogleSignInFragment.java | 576 ---------------- .../GoogleSignInFragment.java.meta | 32 - .../googlesignin/GoogleSignInHelper.java | 306 ++++++--- .../com/google/googlesignin/IListener.java | 11 +- .../googlesignin/TokenPendingResult.java | 152 ----- .../googlesignin/TokenPendingResult.java.meta | 32 - .../com/google/googlesignin/TokenRequest.java | 171 ----- .../googlesignin/TokenRequest.java.meta | 32 - .../com/google/googlesignin/TokenResult.java | 66 -- .../google/googlesignin/TokenResult.java.meta | 32 - Plugins/iOS/GoogleSignIn.mm | 25 +- README.md | 27 + package.json | 6 +- 19 files changed, 628 insertions(+), 1552 deletions(-) delete mode 100644 Plugins/Android/src/main/java/com/google/googlesignin/GoogleSignInFragment.java delete mode 100644 Plugins/Android/src/main/java/com/google/googlesignin/GoogleSignInFragment.java.meta delete mode 100644 Plugins/Android/src/main/java/com/google/googlesignin/TokenPendingResult.java delete mode 100644 Plugins/Android/src/main/java/com/google/googlesignin/TokenPendingResult.java.meta delete mode 100644 Plugins/Android/src/main/java/com/google/googlesignin/TokenRequest.java delete mode 100644 Plugins/Android/src/main/java/com/google/googlesignin/TokenRequest.java.meta delete mode 100644 Plugins/Android/src/main/java/com/google/googlesignin/TokenResult.java delete mode 100644 Plugins/Android/src/main/java/com/google/googlesignin/TokenResult.java.meta diff --git a/GoogleSignIn/Editor/GoogleSignInDependencies.xml b/GoogleSignIn/Editor/GoogleSignInDependencies.xml index 4d72e027..49412fe3 100644 --- a/GoogleSignIn/Editor/GoogleSignInDependencies.xml +++ b/GoogleSignIn/Editor/GoogleSignInDependencies.xml @@ -3,16 +3,14 @@ - - - extra-google-m2repository - - + + + + - - + diff --git a/GoogleSignIn/GoogleSignIn.cs b/GoogleSignIn/GoogleSignIn.cs index 8f9ae3f4..dd3e18b1 100644 --- a/GoogleSignIn/GoogleSignIn.cs +++ b/GoogleSignIn/GoogleSignIn.cs @@ -69,9 +69,7 @@ public static GoogleSignInConfiguration Configuration { if (theInstance == null || theConfiguration == value || theConfiguration == null) { theConfiguration = value; } else { - throw new SignInException(GoogleSignInStatusCode.DEVELOPER_ERROR, - "DefaultInstance already created. " + - " Cannot change configuration after creation."); + throw new SignInException(GoogleSignInStatusCode.DEVELOPER_ERROR,"DefaultInstance already created. Cannot change configuration after creation."); } } @@ -105,7 +103,7 @@ internal GoogleSignIn(ISignInImpl impl) { } public void EnableDebugLogging(bool flag) { - impl.EnableDebugLogging(flag); + impl.EnableDebugLogging(flag); } /// Starts the authentication process. @@ -116,14 +114,13 @@ public void EnableDebugLogging(bool flag) { /// public Task SignIn() { var tcs = new TaskCompletionSource(); - SignInHelperObject.Instance.StartCoroutine( - impl.SignIn().WaitForResult(tcs)); + SignInHelperObject.Instance.StartCoroutine(impl.SignIn().WaitForResult(tcs)); return tcs.Task; } public Task SignInAsync() { var tcs = new TaskCompletionSource(); - impl.SignIn().WaitForResultAsync(tcs); + impl.SignIn().WaitForResultAsync(tcs).ContinueWith((task) => {}); return tcs.Task; } @@ -137,14 +134,13 @@ public Task SignInAsync() { /// public Task SignInSilently() { var tcs = new TaskCompletionSource(); - SignInHelperObject.Instance.StartCoroutine( - impl.SignInSilently().WaitForResult(tcs)); + SignInHelperObject.Instance.StartCoroutine(impl.SignInSilently().WaitForResult(tcs)); return tcs.Task; } public Task SignInSilentlyAsync() { var tcs = new TaskCompletionSource(); - impl.SignInSilently().WaitForResultAsync(tcs); + impl.SignIn().WaitForResultAsync(tcs).ContinueWith((task) => {}); return tcs.Task; } diff --git a/GoogleSignIn/Impl/BaseObject.cs b/GoogleSignIn/Impl/BaseObject.cs index 44d65013..cacb127e 100644 --- a/GoogleSignIn/Impl/BaseObject.cs +++ b/GoogleSignIn/Impl/BaseObject.cs @@ -35,8 +35,7 @@ public BaseObject(IntPtr intPtr) { protected HandleRef SelfPtr() { if (selfHandleRef.Equals(nullSelf)) { - throw new InvalidOperationException( - "Attempted to use object after it was cleaned up"); + throw new InvalidOperationException("Attempted to use object after it was cleaned up"); } return selfHandleRef; } @@ -45,8 +44,7 @@ public virtual void Dispose() { selfHandleRef = nullSelf; } - internal delegate UIntPtr OutStringMethod([In, Out] byte[] out_bytes, - UIntPtr out_size); + internal delegate UIntPtr OutStringMethod([In, Out] byte[] out_bytes,UIntPtr out_size); internal static String OutParamsToString(OutStringMethod outStringMethod) { UIntPtr requiredSize = outStringMethod(null, UIntPtr.Zero); @@ -58,8 +56,7 @@ internal static String OutParamsToString(OutStringMethod outStringMethod) { try { byte[] array = new byte[requiredSize.ToUInt32()]; outStringMethod(array, requiredSize); - str = Encoding.UTF8.GetString(array, 0, - (int)requiredSize.ToUInt32() - 1); + str = Encoding.UTF8.GetString(array, 0, (int)requiredSize.ToUInt32() - 1); } catch (Exception e) { Debug.LogError("Exception creating string from char array: " + e); str = string.Empty; diff --git a/GoogleSignIn/Impl/GoogleSignInImpl.cs b/GoogleSignIn/Impl/GoogleSignInImpl.cs index 5fe8d1e3..84c972c8 100644 --- a/GoogleSignIn/Impl/GoogleSignInImpl.cs +++ b/GoogleSignIn/Impl/GoogleSignInImpl.cs @@ -16,343 +16,349 @@ // namespace Google.Impl { - using System; - using System.Text; - using System.Collections.Generic; - using System.Runtime.InteropServices; + using System; + using System.Text; + using System.Linq; + using System.Collections.Generic; + using System.Runtime.InteropServices; - using UnityEngine; + using UnityEngine; #if UNITY_2022_2_OR_NEWER #else - using System.Reflection; + using System.Reflection; #endif internal class GoogleSignInImpl : BaseObject, ISignInImpl { - internal GoogleSignInImpl(GoogleSignInConfiguration configuration) - : base(GoogleSignIn_Create(GetPlayerActivity())) { - - if (configuration != null) { - List scopes = new List(); - if (configuration.AdditionalScopes != null) { - scopes.AddRange(configuration.AdditionalScopes); - } - GoogleSignIn_Configure(SelfPtr(), configuration.UseGameSignIn, - configuration.WebClientId, - configuration.RequestAuthCode, - configuration.ForceTokenRefresh, - configuration.RequestEmail, - configuration.RequestIdToken, - configuration.HidePopups, - scopes.ToArray(), - scopes.Count, - configuration.AccountName); - } - } - - /// Enables/Disables verbose logging to help troubleshooting - public void EnableDebugLogging(bool flag) { - GoogleSignIn_EnableDebugLogging(SelfPtr(), flag); - } - - /// - /// Starts the authentication process. - /// - /// - /// The authenication process is started and may display account picker - /// popups and consent prompts based on the state of authentication and - /// the requested elements. - /// - public Future SignIn() { - IntPtr nativeFuture = GoogleSignIn_SignIn(SelfPtr()); - return new Future(new NativeFuture(nativeFuture)); - } - - /// - /// Starts the authentication process. - /// - /// - /// The authenication process is started and may display account picker - /// popups and consent prompts based on the state of authentication and - /// the requested elements. - /// - public Future SignInSilently() { - IntPtr nativeFuture = GoogleSignIn_SignInSilently(SelfPtr()); - return new Future(new NativeFuture(nativeFuture)); - } - - /// - /// Signs out the User. - /// - public void SignOut() { - GoogleSignIn_Signout(SelfPtr()); - } - - /// - /// Disconnects the user from the application and revokes all consent. - /// - public void Disconnect() { - GoogleSignIn_Disconnect(SelfPtr()); - } + internal GoogleSignInImpl(GoogleSignInConfiguration configuration) : base(GoogleSignIn_Create(GetPlayerActivity())) { + + if (configuration != null) { + List scopes = new List(); + if (configuration.AdditionalScopes != null) { + scopes.AddRange(configuration.AdditionalScopes); + } + GoogleSignIn_Configure(SelfPtr(), configuration.UseGameSignIn, + configuration.WebClientId, + configuration.RequestAuthCode, + configuration.ForceTokenRefresh, + configuration.RequestEmail, + configuration.RequestIdToken, + configuration.HidePopups, + scopes.ToArray(), + scopes.Count, + configuration.AccountName); + } + } + + /// Enables/Disables verbose logging to help troubleshooting + public void EnableDebugLogging(bool flag) { + GoogleSignIn_EnableDebugLogging(SelfPtr(), flag); + } + + /// + /// Starts the authentication process. + /// + /// + /// The authenication process is started and may display account picker + /// popups and consent prompts based on the state of authentication and + /// the requested elements. + /// + public Future SignIn() { + IntPtr nativeFuture = GoogleSignIn_SignIn(SelfPtr()); + return new Future(new NativeFuture(nativeFuture)); + } + + /// + /// Starts the authentication process. + /// + /// + /// The authenication process is started and may display account picker + /// popups and consent prompts based on the state of authentication and + /// the requested elements. + /// + public Future SignInSilently() { + IntPtr nativeFuture = GoogleSignIn_SignInSilently(SelfPtr()); + return new Future(new NativeFuture(nativeFuture)); + } + + /// + /// Signs out the User. + /// + public void SignOut() { + GoogleSignIn_Signout(SelfPtr()); + } + + /// + /// Disconnects the user from the application and revokes all consent. + /// + public void Disconnect() { + GoogleSignIn_Disconnect(SelfPtr()); + } #if UNITY_ANDROID - static AndroidJavaClass GoogleSignInHelper = new AndroidJavaClass("com.google.googlesignin.GoogleSignInHelper"); - static AndroidJavaClass GoogleSignInFragment = new AndroidJavaClass("com.google.googlesignin.GoogleSignInFragment"); - - static AndroidJavaObject parentActivity; - static IntPtr GoogleSignIn_Create(IntPtr activity) - { - parentActivity = activity.ToAndroidJavaObject(); - - return GoogleSignInFragment.CallStatic("getInstance",parentActivity).GetRawObject(); - } - - static bool GoogleSignIn_Configure(HandleRef googleSignInHelper, - bool useGameSignIn, string webClientId, - bool requestAuthCode, bool forceTokenRefresh, bool requestEmail, - bool requestIdToken, bool hidePopups, string[] additionalScopes, - int scopeCount, string accountName) - { - GoogleSignInHelper.CallStatic("configure",parentActivity, - useGameSignIn, - webClientId, - requestAuthCode, - forceTokenRefresh, - requestEmail, - requestIdToken, - hidePopups, - accountName, - additionalScopes, - new SignInListener()); - - return !useGameSignIn; - } - - public class SignInListener : AndroidJavaProxy - { - public SignInListener() : base("com.google.googlesignin.IListener") - { - - } - - public void OnResult(int result, AndroidJavaObject acct) - { - if(acct != null) - { - Debug.Log("googlesignin.IListener : " + acct.Call("toString")); - Debug.Log("ID : " + acct.Call("getId")); - } - else Debug.LogWarning("Should not get null account"); - } - } - - static void GoogleSignIn_EnableDebugLogging(HandleRef self, bool flag) => GoogleSignInHelper.CallStatic("enableDebugLogging",flag); - - static IntPtr GoogleSignIn_SignIn(HandleRef self) - { - return GoogleSignInHelper.CallStatic("signIn",parentActivity).GetRawObject(); - } - - static IntPtr GoogleSignIn_SignInSilently(HandleRef self) - { - return GoogleSignInHelper.CallStatic("signInSilently",parentActivity).GetRawObject(); - } - - static void GoogleSignIn_Signout(HandleRef self) => GoogleSignInHelper.CallStatic("signOut",parentActivity); - - static void GoogleSignIn_Disconnect(HandleRef self) => GoogleSignInHelper.CallStatic("disconnect",parentActivity); - - internal static void GoogleSignIn_DisposeFuture(HandleRef self) => self.ToAndroidJavaObject()?.Dispose(); - - internal static bool GoogleSignIn_Pending(HandleRef self) => self.ToAndroidJavaObject()?.Call("isPending") ?? false; - - internal static IntPtr GoogleSignIn_Result(HandleRef self) => self.ToAndroidJavaObject()?.Call("getAccount")?.GetRawObject() ?? IntPtr.Zero; - - internal static int GoogleSignIn_Status(HandleRef self) => self.ToAndroidJavaObject()?.Call("getStatus") ?? 6; - - internal static string GoogleSignIn_GetServerAuthCode(HandleRef self) => self.ToAndroidJavaObject()?.Call("getServerAuthCode"); - - internal static string GoogleSignIn_GetDisplayName(HandleRef self) => self.ToAndroidJavaObject()?.Call("getDisplayName"); - - internal static string GoogleSignIn_GetEmail(HandleRef self) => self.ToAndroidJavaObject()?.Call("getEmail"); - - internal static string GoogleSignIn_GetFamilyName(HandleRef self) => self.ToAndroidJavaObject()?.Call("getFamilyName"); - - internal static string GoogleSignIn_GetGivenName(HandleRef self) => self.ToAndroidJavaObject()?.Call("getGivenName"); - - internal static string GoogleSignIn_GetIdToken(HandleRef self) => self.ToAndroidJavaObject()?.Call("getIdToken"); - - internal static string GoogleSignIn_GetImageUrl(HandleRef self) => self.ToAndroidJavaObject()?.Call("getPhotoUrl")?.Call("toString"); - - internal static string GoogleSignIn_GetUserId(HandleRef self) => self.ToAndroidJavaObject()?.Call("getId"); + static AndroidJavaClass GoogleSignInHelper = new AndroidJavaClass("com.google.googlesignin.GoogleSignInHelper"); + + static IntPtr GoogleSignIn_Create(IntPtr activity) + { + return new AndroidJavaObject("com.google.googlesignin.GoogleSignInHelper").GetRawObject(); + } + + static bool GoogleSignIn_Configure(HandleRef googleSignInHelper, + bool useGameSignIn, string webClientId, + bool requestAuthCode, bool forceTokenRefresh, bool requestEmail, + bool requestIdToken, bool hidePopups, string[] additionalScopes, + int scopeCount, string accountName) + { + googleSignInHelper.ToAndroidJavaObject().Call("configure", + useGameSignIn, + webClientId, + requestAuthCode, + forceTokenRefresh, + requestEmail, + requestIdToken, + hidePopups, + accountName, + additionalScopes, + new SignInListener()); + + return !useGameSignIn; + } + + static AndroidJavaObject googleIdTokenCredential; + static AndroidJavaObject authorizationResult; + + public class SignInListener : AndroidJavaProxy + { + public SignInListener() : base("com.google.googlesignin.IListener") { } + + public void onAuthenticated(AndroidJavaObject _googleIdTokenCredential) + { + googleIdTokenCredential?.Dispose(); + googleIdTokenCredential = _googleIdTokenCredential; + } + + public void onAuthorized(AndroidJavaObject _authorizationResult) + { + authorizationResult?.Dispose(); + authorizationResult = _authorizationResult; + } + + public void onFailure(AndroidJavaObject exception) + { + Debug.LogErrorFormat("onFailure {0} : {1}",exception?.Call("getClass").Call("toString"),exception?.Call("getMessage")); + exception.Dispose(); + } + + public void onCanceled() { + googleIdTokenCredential?.Dispose(); + authorizationResult?.Dispose(); + } + } + + static void GoogleSignIn_EnableDebugLogging(HandleRef self, bool flag) => GoogleSignInHelper.CallStatic("enableDebugLogging",flag); + + static IntPtr GoogleSignIn_SignIn(HandleRef self) + { + return self.ToAndroidJavaObject().Call("signIn").GetRawObject(); + } + + static IntPtr GoogleSignIn_SignInSilently(HandleRef self) + { + return self.ToAndroidJavaObject().Call("signInSilently").GetRawObject(); + } + + static void GoogleSignIn_Signout(HandleRef self) + { + googleIdTokenCredential?.Dispose(); + googleIdTokenCredential = null; + + authorizationResult?.Dispose(); + authorizationResult = null; + + self.ToAndroidJavaObject().Call("signOut"); + } + + static void GoogleSignIn_Disconnect(HandleRef self) => throw new NotImplementedException(); + + internal static void GoogleSignIn_DisposeFuture(HandleRef self) => self.ToAndroidJavaObject()?.Call("cancel"); + + internal static bool GoogleSignIn_Pending(HandleRef self) => self.ToAndroidJavaObject()?.Call("isPending") ?? false; + + internal static IntPtr GoogleSignIn_Result(HandleRef self) => self.Handle; + + internal static int GoogleSignIn_Status(HandleRef self) => self.ToAndroidJavaObject()?.Call("getStatus") ?? 6; + + internal static string GoogleSignIn_GetServerAuthCode(HandleRef self) => authorizationResult?.Call("getServerAuthCode"); + + internal static string GoogleSignIn_GetUserId(HandleRef self) + { + try + { + var idTokenPart = googleIdTokenCredential?.Call("getIdToken")?.Split('.')?.ElementAtOrDefault(1); + if(!(idTokenPart?.Length is int length && length > 1)) + return null; + + string fill = new string('=',(4 - (idTokenPart.Length % 4)) % 4); + var jobj = Newtonsoft.Json.Linq.JObject.Parse(Encoding.UTF8.GetString(Convert.FromBase64String(idTokenPart + fill))); + return jobj?["sub"]?.ToString(); + } + catch(Exception e) + { + Debug.LogException(e); + return null; + } + } + + internal static string GoogleSignIn_GetEmail(HandleRef self) => googleIdTokenCredential?.Call("getId"); + + internal static string GoogleSignIn_GetDisplayName(HandleRef self) => googleIdTokenCredential?.Call("getDisplayName"); + + internal static string GoogleSignIn_GetFamilyName(HandleRef self) => googleIdTokenCredential?.Call("getFamilyName"); + + internal static string GoogleSignIn_GetGivenName(HandleRef self) => googleIdTokenCredential?.Call("getGivenName"); + + internal static string GoogleSignIn_GetIdToken(HandleRef self) => googleIdTokenCredential?.Call("getIdToken"); + + internal static string GoogleSignIn_GetImageUrl(HandleRef self) => googleIdTokenCredential?.Call("getProfilePictureUri")?.Call("toString"); #else - private const string DllName = "__Internal"; + private const string DllName = "__Internal"; + + /// + /// Creates an instance of the native Google Sign-In implementation. + /// + /// + /// For Android this must be the JNI raw object for the parentActivity. + /// For iOS it is ignored. + /// + /// The pointer to the instance. + /// Data used in creating the instance. + [DllImport(DllName)] + static extern IntPtr GoogleSignIn_Create(IntPtr data); + + [DllImport(DllName)] + static extern void GoogleSignIn_EnableDebugLogging(HandleRef self, bool flag); + + [DllImport(DllName)] + static extern bool GoogleSignIn_Configure(HandleRef self, + bool useGameSignIn, string webClientId, + bool requestAuthCode, bool forceTokenRefresh, bool requestEmail, + bool requestIdToken, bool hidePopups, string[] additionalScopes, + int scopeCount, string accountName); + + [DllImport(DllName)] + static extern IntPtr GoogleSignIn_SignIn(HandleRef self); + + [DllImport(DllName)] + static extern IntPtr GoogleSignIn_SignInSilently(HandleRef self); + + [DllImport(DllName)] + static extern void GoogleSignIn_Signout(HandleRef self); + + [DllImport(DllName)] + static extern void GoogleSignIn_Disconnect(HandleRef self); + + [DllImport(DllName)] + internal static extern void GoogleSignIn_DisposeFuture(HandleRef self); + + [DllImport(DllName)] + internal static extern bool GoogleSignIn_Pending(HandleRef self); + + [DllImport(DllName)] + internal static extern IntPtr GoogleSignIn_Result(HandleRef self); + + [DllImport(DllName)] + internal static extern int GoogleSignIn_Status(HandleRef self); + + [DllImport(DllName)] + internal static extern UIntPtr GoogleSignIn_GetServerAuthCode( + HandleRef self, [In, Out] byte[] bytes, UIntPtr len); + + [DllImport(DllName)] + internal static extern UIntPtr GoogleSignIn_GetDisplayName(HandleRef self, [In, Out] byte[] bytes, UIntPtr len); + + [DllImport(DllName)] + internal static extern UIntPtr GoogleSignIn_GetEmail(HandleRef self, [In, Out] byte[] bytes, UIntPtr len); + + [DllImport(DllName)] + internal static extern UIntPtr GoogleSignIn_GetFamilyName(HandleRef self, [In, Out] byte[] bytes, UIntPtr len); + + [DllImport(DllName)] + internal static extern UIntPtr GoogleSignIn_GetGivenName(HandleRef self, [In, Out] byte[] bytes, UIntPtr len); + + [DllImport(DllName)] + internal static extern UIntPtr GoogleSignIn_GetIdToken(HandleRef self, [In, Out] byte[] bytes, UIntPtr len); + + [DllImport(DllName)] + internal static extern UIntPtr GoogleSignIn_GetImageUrl(HandleRef self, [In, Out] byte[] bytes, UIntPtr len); + + [DllImport(DllName)] + internal static extern UIntPtr GoogleSignIn_GetUserId(HandleRef self, [In, Out] byte[] bytes, UIntPtr len); + + internal static string GoogleSignIn_GetServerAuthCode(HandleRef self) => + OutParamsToString((out_string, out_size) => GoogleSignIn_GetServerAuthCode(self, out_string, out_size)); + + internal static string GoogleSignIn_GetDisplayName(HandleRef self) => + OutParamsToString((out_string, out_size) => GoogleSignIn_GetDisplayName(self, out_string, out_size)); + + internal static string GoogleSignIn_GetEmail(HandleRef self) => + OutParamsToString((out_string, out_size) => GoogleSignIn_GetEmail(self, out_string, out_size)); + + internal static string GoogleSignIn_GetFamilyName(HandleRef self) => + OutParamsToString((out_string, out_size) => GoogleSignIn_GetFamilyName(self, out_string, out_size)); + + internal static string GoogleSignIn_GetGivenName(HandleRef self) => + OutParamsToString((out_string, out_size) => GoogleSignIn_GetGivenName(self, out_string, out_size)); + + internal static string GoogleSignIn_GetIdToken(HandleRef self) => + OutParamsToString((out_string, out_size) => GoogleSignIn_GetIdToken(self, out_string, out_size)); - /// - /// Creates an instance of the native Google Sign-In implementation. - /// - /// - /// For Android this must be the JNI raw object for the parentActivity. - /// For iOS it is ignored. - /// - /// The pointer to the instance. - /// Data used in creating the instance. - [DllImport(DllName)] - static extern IntPtr GoogleSignIn_Create(IntPtr data); + internal static string GoogleSignIn_GetImageUrl(HandleRef self) => + OutParamsToString((out_string, out_size) => GoogleSignIn_GetImageUrl(self, out_string, out_size)); - [DllImport(DllName)] - static extern void GoogleSignIn_EnableDebugLogging(HandleRef self, bool flag); - - [DllImport(DllName)] - static extern bool GoogleSignIn_Configure(HandleRef self, - bool useGameSignIn, string webClientId, - bool requestAuthCode, bool forceTokenRefresh, bool requestEmail, - bool requestIdToken, bool hidePopups, string[] additionalScopes, - int scopeCount, string accountName); - - [DllImport(DllName)] - static extern IntPtr GoogleSignIn_SignIn(HandleRef self); - - [DllImport(DllName)] - static extern IntPtr GoogleSignIn_SignInSilently(HandleRef self); - - [DllImport(DllName)] - static extern void GoogleSignIn_Signout(HandleRef self); - - [DllImport(DllName)] - static extern void GoogleSignIn_Disconnect(HandleRef self); - - [DllImport(DllName)] - internal static extern void GoogleSignIn_DisposeFuture(HandleRef self); - - [DllImport(DllName)] - internal static extern bool GoogleSignIn_Pending(HandleRef self); - - [DllImport(DllName)] - internal static extern IntPtr GoogleSignIn_Result(HandleRef self); - - [DllImport(DllName)] - internal static extern int GoogleSignIn_Status(HandleRef self); - - [DllImport(DllName)] - internal static extern UIntPtr GoogleSignIn_GetServerAuthCode( - HandleRef self, [In, Out] byte[] bytes, UIntPtr len); - - [DllImport(DllName)] - internal static extern UIntPtr GoogleSignIn_GetDisplayName(HandleRef self, [In, Out] byte[] bytes, UIntPtr len); - - [DllImport(DllName)] - internal static extern UIntPtr GoogleSignIn_GetEmail(HandleRef self, [In, Out] byte[] bytes, UIntPtr len); - - [DllImport(DllName)] - internal static extern UIntPtr GoogleSignIn_GetFamilyName(HandleRef self, [In, Out] byte[] bytes, UIntPtr len); - - [DllImport(DllName)] - internal static extern UIntPtr GoogleSignIn_GetGivenName(HandleRef self, [In, Out] byte[] bytes, UIntPtr len); - - [DllImport(DllName)] - internal static extern UIntPtr GoogleSignIn_GetIdToken(HandleRef self, [In, Out] byte[] bytes, UIntPtr len); - - [DllImport(DllName)] - internal static extern UIntPtr GoogleSignIn_GetImageUrl(HandleRef self, [In, Out] byte[] bytes, UIntPtr len); - - [DllImport(DllName)] - internal static extern UIntPtr GoogleSignIn_GetUserId(HandleRef self, [In, Out] byte[] bytes, UIntPtr len); - - internal static string GoogleSignIn_GetServerAuthCode(HandleRef self) => - OutParamsToString((out_string, out_size) => - GoogleSignInImpl.GoogleSignIn_GetServerAuthCode(self, out_string, out_size)); - - internal static string GoogleSignIn_GetDisplayName(HandleRef self) => - OutParamsToString((out_string, out_size) => - GoogleSignInImpl.GoogleSignIn_GetDisplayName(self, out_string, out_size)); - - internal static string GoogleSignIn_GetEmail(HandleRef self) => - OutParamsToString((out_string, out_size) => - GoogleSignInImpl.GoogleSignIn_GetEmail(self, out_string, out_size)); - - internal static string GoogleSignIn_GetFamilyName(HandleRef self) => - OutParamsToString((out_string, out_size) => - GoogleSignInImpl.GoogleSignIn_GetFamilyName(self, out_string, out_size)); - - internal static string GoogleSignIn_GetGivenName(HandleRef self) => - OutParamsToString((out_string, out_size) => - GoogleSignInImpl.GoogleSignIn_GetGivenName(self, out_string, out_size)); - - internal static string GoogleSignIn_GetIdToken(HandleRef self) => - OutParamsToString((out_string, out_size) => - GoogleSignInImpl.GoogleSignIn_GetIdToken(self, out_string, out_size)); - - internal static string GoogleSignIn_GetImageUrl(HandleRef self) => - OutParamsToString((out_string, out_size) => - GoogleSignInImpl.GoogleSignIn_GetImageUrl(self, out_string, out_size)); - - internal static string GoogleSignIn_GetUserId(HandleRef self) => - OutParamsToString((out_string, out_size) => - GoogleSignInImpl.GoogleSignIn_GetUserId(self, out_string, out_size)); - - internal delegate UIntPtr OutStringMethod([In, Out] byte[] out_bytes,UIntPtr out_size); - - internal static String OutParamsToString(OutStringMethod outStringMethod) { - UIntPtr requiredSize = outStringMethod(null, UIntPtr.Zero); - if (requiredSize.Equals(UIntPtr.Zero)) { - return null; - } - - string str = null; - try { - byte[] array = new byte[requiredSize.ToUInt32()]; - outStringMethod(array, requiredSize); - str = Encoding.UTF8.GetString(array, 0, - (int)requiredSize.ToUInt32() - 1); - } catch (Exception e) { - Debug.LogError("Exception creating string from char array: " + e); - str = string.Empty; - } - return str; - } + internal static string GoogleSignIn_GetUserId(HandleRef self) => + OutParamsToString((out_string, out_size) => GoogleSignIn_GetUserId(self, out_string, out_size)); #endif - // Gets the Unity player activity. - // For iOS, this returns Zero. - private static IntPtr GetPlayerActivity() { + // Gets the Unity player activity. + // For iOS, this returns Zero. + private static IntPtr GetPlayerActivity() { #if UNITY_ANDROID - var jc = new AndroidJavaClass("com.unity3d.player.UnityPlayer"); - return jc.GetStatic("currentActivity").GetRawObject(); + var jc = new AndroidJavaClass("com.unity3d.player.UnityPlayer"); + return jc.GetStatic("currentActivity").GetRawObject(); #else - return IntPtr.Zero; + return IntPtr.Zero; #endif - } - } + } + } - public static class Ext - { + public static class Ext + { #if UNITY_2022_2_OR_NEWER #else - static ConstructorInfo constructorInfo; + static ConstructorInfo constructorInfo; #endif - public static AndroidJavaObject ToAndroidJavaObject(in this HandleRef self) => self.Handle.ToAndroidJavaObject(); - public static AndroidJavaObject ToAndroidJavaObject(in this IntPtr intPtr) - { - if (intPtr == IntPtr.Zero) - return null; + public static AndroidJavaObject ToAndroidJavaObject(in this HandleRef self) => self.Handle.ToAndroidJavaObject(); + public static AndroidJavaObject ToAndroidJavaObject(in this IntPtr intPtr) + { + if (intPtr == IntPtr.Zero) + return null; - try { + try { #if UNITY_2022_2_OR_NEWER - return new AndroidJavaObject(intPtr); + return new AndroidJavaObject(intPtr); #else - if(constructorInfo == null) - constructorInfo = typeof(AndroidJavaObject).GetConstructor(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic,null,new[] { typeof(IntPtr) },null); + if(constructorInfo == null) + constructorInfo = typeof(AndroidJavaObject).GetConstructor(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic,null,new[] { typeof(IntPtr) },null); - Debug.LogFormat("constructorInfo : {0}",constructorInfo); - return constructorInfo.Invoke(new object[] { intPtr }) as AndroidJavaObject; + Debug.LogFormat("constructorInfo : {0}",constructorInfo); + return constructorInfo.Invoke(new object[] { intPtr }) as AndroidJavaObject; #endif - } catch (Exception e) { - Debug.LogError("Exception creating AndroidJavaObject: " + e); - return null; - } - } - } + } catch (Exception e) { + Debug.LogError("Exception creating AndroidJavaObject: " + e); + return null; + } + } + } } #endif diff --git a/GoogleSignIn/Impl/GoogleSignInImplEditor.cs b/GoogleSignIn/Impl/GoogleSignInImplEditor.cs index 670ac518..e6cd8583 100644 --- a/GoogleSignIn/Impl/GoogleSignInImplEditor.cs +++ b/GoogleSignIn/Impl/GoogleSignInImplEditor.cs @@ -89,6 +89,7 @@ void SigningIn() try { var openURL = "https://accounts.google.com/o/oauth2/v2/auth?" + Uri.EscapeUriString("scope=openid email profile&response_type=code&redirect_uri=" + httpListener.Prefixes.FirstOrDefault() + "&client_id=" + configuration.WebClientId); + Debug.Log(openURL); Application.OpenURL(openURL); } catch(Exception e) @@ -101,6 +102,7 @@ void SigningIn() httpListener.GetContextAsync().ContinueWith(async(task) => { try { + Debug.Log(task); var context = task.Result; var queryString = context.Request.Url.Query; var queryDictionary = System.Web.HttpUtility.ParseQueryString(queryString); @@ -127,23 +129,28 @@ void SigningIn() var tokenType = (string)jobj.GetValue("token_type"); var user = new GoogleSignInUser(); + if(configuration.RequestAuthCode) + user.AuthCode = code; + if(configuration.RequestIdToken) user.IdToken = (string)jobj.GetValue("id_token"); - if(configuration.RequestEmail || configuration.RequestProfile) + var request = HttpWebRequest.CreateHttp("https://openidconnect.googleapis.com/v1/userinfo"); + request.Method = "GET"; + request.Headers.Add("Authorization", "Bearer " + accessToken); + + var data = await request.GetResponseAsStringAsync().ContinueWith((task) => task.Result,taskScheduler); + var userInfo = JObject.Parse(data); + user.UserId = (string)userInfo.GetValue("sub"); + user.DisplayName = (string)userInfo.GetValue("name"); + + if(configuration.RequestEmail) + user.Email = (string)userInfo.GetValue("email"); + + if(configuration.RequestProfile) { - var request = HttpWebRequest.CreateHttp("https://openidconnect.googleapis.com/v1/userinfo"); - request.Method = "GET"; - request.Headers.Add("Authorization", "Bearer " + accessToken); - - var data = await request.GetResponseAsStringAsync().ContinueWith((task) => task.Result,taskScheduler); - // "email_verified": true,"locale": "" - var userInfo = JObject.Parse(data); - user.UserId = (string)userInfo.GetValue("sub"); - user.DisplayName = (string)userInfo.GetValue("name"); user.GivenName = (string)userInfo.GetValue("given_name"); user.FamilyName = (string)userInfo.GetValue("family_name"); - user.Email = (string)userInfo.GetValue("email"); user.ImageUrl = Uri.TryCreate((string)userInfo.GetValue("picture"),UriKind.Absolute,out var url) ? url : null; } diff --git a/GoogleSignIn/Impl/NativeFuture.cs b/GoogleSignIn/Impl/NativeFuture.cs index 1c09d978..0cb905ab 100644 --- a/GoogleSignIn/Impl/NativeFuture.cs +++ b/GoogleSignIn/Impl/NativeFuture.cs @@ -17,7 +17,7 @@ namespace Google.Impl { using System; - using System.Runtime.InteropServices; + using System.Runtime.InteropServices; /// /// Native future is an interal class that implements the FutureAPIImpl @@ -28,16 +28,9 @@ internal class NativeFuture : BaseObject, FutureAPIImpl { internal NativeFuture(IntPtr ptr) : base(ptr) { } - public override void Dispose() { - GoogleSignInImpl.GoogleSignIn_DisposeFuture(SelfPtr()); - base.Dispose(); - } + public override void Dispose() => GoogleSignInImpl.GoogleSignIn_DisposeFuture(SelfPtr()); - public bool Pending { - get { - return GoogleSignInImpl.GoogleSignIn_Pending(SelfPtr()); - } - } + public bool Pending => GoogleSignInImpl.GoogleSignIn_Pending(SelfPtr()); public GoogleSignInUser Result { get { @@ -64,12 +57,13 @@ public GoogleSignInUser Result { user.AuthCode = GoogleSignInImpl.GoogleSignIn_GetServerAuthCode(userPtr); string url = GoogleSignInImpl.GoogleSignIn_GetImageUrl(userPtr); - if (url.Length > 0) { + if (url?.Length > 0) { user.ImageUrl = new System.Uri(url); } - /** Require for no reason (tree shaking ?) */ +#pragma warning disable CS0219 // Require for no reason (tree shaking ?) var obj = (user.UserId,user.Email,user.DisplayName,user.FamilyName,user.GivenName,user.IdToken,user.AuthCode,user.ImageUrl); +#pragma warning restore CS0219 return user; } diff --git a/Plugins/Android/src/main/java/com/google/googlesignin/GoogleSignInFragment.java b/Plugins/Android/src/main/java/com/google/googlesignin/GoogleSignInFragment.java deleted file mode 100644 index 9e42c86a..00000000 --- a/Plugins/Android/src/main/java/com/google/googlesignin/GoogleSignInFragment.java +++ /dev/null @@ -1,576 +0,0 @@ -/* - * Copyright 2017 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. - */ -package com.google.googlesignin; - -import android.app.Activity; -import android.app.Fragment; -import android.app.FragmentTransaction; -import android.content.Intent; -import android.os.Bundle; -import androidx.annotation.NonNull; -import androidx.annotation.Nullable; -import android.view.View; -import com.google.android.gms.auth.api.Auth; -import com.google.android.gms.auth.api.signin.GoogleSignInAccount; -import com.google.android.gms.auth.api.signin.GoogleSignInOptions; -import com.google.android.gms.auth.api.signin.GoogleSignInOptionsExtension; -import com.google.android.gms.auth.api.signin.GoogleSignInResult; -import com.google.android.gms.common.ConnectionResult; -import com.google.android.gms.common.api.Api; -import com.google.android.gms.common.api.CommonStatusCodes; -import com.google.android.gms.common.api.GoogleApiClient; -import com.google.android.gms.common.api.PendingResult; -import com.google.android.gms.common.api.ResultCallback; -import com.google.android.gms.common.api.Scope; -import com.google.android.gms.common.api.Status; -import java.lang.reflect.Field; -import java.lang.reflect.InvocationTargetException; -import java.lang.reflect.Method; -import java.util.Locale; -import java.util.concurrent.TimeUnit; - -/** - * Activity fragment with no UI added to the parent activity in order to manage the accessing of the - * player's email address and tokens. - */ -public class GoogleSignInFragment extends Fragment implements - GoogleApiClient.ConnectionCallbacks, - GoogleApiClient.OnConnectionFailedListener { - - // Tag uniquely identifying this fragment. - public static final String FRAGMENT_TAG = "signin.SignInFragment"; - private static final int RC_SIGNIN = 9009; - - void DoSignIn(boolean silent) { - if (!silent) { - Intent signInIntent = Auth.GoogleSignInApi.getSignInIntent(mGoogleApiClient); - startActivityForResult(signInIntent, RC_SIGNIN); - return; - } - - Auth.GoogleSignInApi.silentSignIn(mGoogleApiClient).setResultCallback(new ResultCallback() { - @Override - public void onResult(@NonNull GoogleSignInResult googleSignInResult) { - if(googleSignInResult == null) { - GoogleSignInHelper.logError("Error with silentSignIn: googleSignInResult is null"); - GoogleSignInHelper.nativeOnResult(request.getHandle(),CommonStatusCodes.INTERNAL_ERROR,null); - return; - } - - GoogleSignInFragment.this.tokenResult = new TokenResult(googleSignInResult.getSignInAccount(), googleSignInResult.getStatus().getStatusCode()); - - Status status = googleSignInResult.getStatus(); - GoogleSignInAccount acct = googleSignInResult.isSuccess() ? googleSignInResult.getSignInAccount() : null; - if (acct == null) { - GoogleSignInHelper.logError("Error with silentSignIn: " + status); - } - - GoogleSignInHelper.nativeOnResult(request.getHandle(),status != null ? status.getStatusCode() : CommonStatusCodes.INTERNAL_ERROR,acct); - request.cancel(); - setState(State.READY); - } - }); - } - - /** - * Handle the Google API Client connection being connected. - * - * @param connectionHint - is not used. - */ - @Override - public void onConnected(@Nullable Bundle connectionHint) { - GoogleSignInHelper.logDebug("onConnected!"); - boolean hasConnectedAuth = mGoogleApiClient.hasConnectedApi(Auth.GOOGLE_SIGN_IN_API); - if (hasConnectedAuth) { - GoogleSignInHelper.logDebug("has connected auth!"); - } - - DoSignIn(!hasConnectedAuth); - } - - @Override - public void onConnectionSuspended(int cause) { - GoogleSignInHelper.logDebug("onConnectionSuspended() called: " + cause); - } - - - @Override - public void onConnectionFailed(@NonNull ConnectionResult connectionResult) { - // Handle errors during connection, such as Play Store not installed. - GoogleSignInHelper.logError("Connection failed: " + - connectionResult.getErrorCode()); - // if there is a resolution, just start the sign-in intent, which handles - // the resolution logic. - if (connectionResult.hasResolution()) { - DoSignIn(false); - } else { - GoogleSignInHelper.nativeOnResult( - request.getHandle(), - connectionResult.getErrorCode(), - null); - } - } - - public void disconnect() { - this.tokenResult = null; - this.tokenPendingResult = null; - if (mGoogleApiClient != null) { - mGoogleApiClient.disconnect(); - } - } - - /** - * The state of the fragment. It can only handle one sign-in request at a time, so we use these - * values to keep track of the request lifecycle. - */ - private enum State { - NEW, - READY, - PENDING, - PENDING_SILENT, - BUSY - } - - private State state; - - public boolean isPending() { - return state == State.PENDING || state == State.PENDING_SILENT; - } - - /** - * The request to sign-in. This contains the configuration for the API client/Sign-in options and - * the callback information used to communicate the result. - */ - private TokenRequest request = null; - - public TokenRequest getRequest() { - return request; - } - - private TokenResult tokenResult = null; - private PendingResult tokenPendingResult = null; - - public GoogleSignInAccount getAccount() { - if (tokenResult != null) - return tokenResult.getAccount(); - - if(tokenPendingResult == null || tokenPendingResult.isCanceled()) - return null; - - return tokenPendingResult.await(3,TimeUnit.SECONDS).getAccount(); - } - - public int getStatus() { - if (tokenResult != null) - return tokenResult.getStatus().getStatusCode(); - - if(tokenPendingResult == null) { - return CommonStatusCodes.DEVELOPER_ERROR; - } - - if(tokenPendingResult.isCanceled()) { - return CommonStatusCodes.CANCELED; - } - - return tokenPendingResult.await(3,TimeUnit.SECONDS).getStatus().getStatusCode(); - } - - private GoogleApiClient mGoogleApiClient; - - // TODO: make config async. - private static GoogleSignInFragment theFragment; - - /** - * Gets the instance of the fragment. - * - * @param parentActivity - the activity to attach the fragment to. - * @return the instance. - */ - public static GoogleSignInFragment getInstance(Activity parentActivity) { - GoogleSignInFragment fragment = - (GoogleSignInFragment) parentActivity.getFragmentManager().findFragmentByTag(FRAGMENT_TAG); - - fragment = (fragment != null) ? fragment : theFragment; - if (fragment == null) { - GoogleSignInHelper.logDebug("Creating fragment"); - fragment = new GoogleSignInFragment(); - FragmentTransaction trans = parentActivity.getFragmentManager().beginTransaction(); - trans.add(fragment, FRAGMENT_TAG); - trans.commitAllowingStateLoss(); - theFragment = fragment; - } - return fragment; - } - - public synchronized boolean submitRequest(TokenRequest request) { - if (this.request == null || this.state == State.READY) { - this.request = request; - this.tokenResult = null; - this.tokenPendingResult = request.getPendingResponse(); - return true; - } - GoogleSignInHelper.logError(String.format(Locale.getDefault(), - "Existing request: %s ignoring %s. State = %s", this.request, request, this.state)); - return false; - } - - private synchronized State getState() { - return state; - } - - private synchronized void setState(State state) { - this.state = state; - } - - /** - * Signs out and disconnects the client. NOTE: if you are using the Games API, you **MUST** call - * Games.signout() before this method. Failure to do so will result in not being able to access - * Games API until the application is restarted. - */ - public void signOut() { - clearRequest(true); - this.tokenResult = null; - this.tokenPendingResult = null; - if (mGoogleApiClient != null) { - Auth.GoogleSignInApi.signOut(mGoogleApiClient); - } - } - - /** - * Starts the sign-in process using the Sign-in UI, if any UI is needed. This is in contrast to - * startSignInSilently, which does not use any UI. - * - * @return true if the sign-in flow was started. - */ - public boolean startSignIn() { - if (request == null) { - GoogleSignInHelper.logError("Request not configured! Failing authenticate"); - return false; - } - if (getState() == State.BUSY) { - GoogleSignInHelper.logError("There is already a pending callback" + " configured."); - } else if (getState() == State.READY) { - processRequest(false); - } else { - processWhenReady(false); - } - return true; - } - - /** - * Starts the sign-in silently flow. - * - * @return true if the flow was started successfully. - */ - public boolean startSignInSilently() { - if (request == null) { - GoogleSignInHelper.logError("Request not configured! Failing authenticate"); - return false; - } - if (getState() == State.BUSY) { - GoogleSignInHelper.logError("There is already a pending callback" + " configured."); - } else if (getState() == State.READY) { - processRequest(true); - } else { - processWhenReady(true); - } - return true; - } - - /** - * Indicates that the token request has been set and it is ready to be processed. The processing - * can start once the fragment is attached to the activity and initialized. - * - * @param silent - true if the sign-in should be silent. - */ - private void processWhenReady(boolean silent) { - GoogleSignInHelper.logInfo("Fragment not initialized yet, " + "waiting to authenticate"); - setState(silent ? State.PENDING_SILENT : State.PENDING); - } - - /** - * Processes the token requests that are queued up. First checking that the google api client is - * connected. - */ - private void processRequest(final boolean silent) { - try { - if (request == null) { - GoogleSignInHelper.logInfo("No pending configuration, returning"); - return; - } - - setState(State.BUSY); - request.getPendingResponse().setResultCallback(new ResultCallback() { - @Override - public void onResult(@NonNull TokenResult tokenResult) { - GoogleSignInFragment.this.tokenResult = tokenResult; - GoogleSignInHelper.logDebug( - String.format( - Locale.getDefault(), - "Calling nativeOnResult: handle: %s, status: %d acct: %s", - tokenResult.getHandle(), - tokenResult.getStatus().getStatusCode(), - tokenResult.getAccount())); - GoogleSignInHelper.nativeOnResult( - tokenResult.getHandle(), - tokenResult.getStatus().getStatusCode(), - tokenResult.getAccount()); - request.cancel(); - setState(State.READY); - } - }); - - // Build the GoogleAPIClient - buildClient(request); - - GoogleSignInHelper.logDebug(" Has connected == " + mGoogleApiClient.hasConnectedApi(Auth.GOOGLE_SIGN_IN_API)); - if (!mGoogleApiClient.hasConnectedApi(Auth.GOOGLE_SIGN_IN_API)) { - DoSignIn(silent); - } - } catch (Throwable throwable) { - GoogleSignInHelper.logError("Exception caught! " + throwable.getMessage()); - request.setResult(CommonStatusCodes.INTERNAL_ERROR, null); - return; - } - - GoogleSignInHelper.logDebug("Done with processRequest!"); - } - - /** - * Builds the Google API Client based on the configuration in the request. - * - * @param request - the request for a token. - */ - private void buildClient(TokenRequest request) { - GoogleSignInOptions.Builder builder; - - if (request.getUseGamesConfig()) { - GoogleSignInHelper.logDebug("Using DEFAULT_GAMES_SIGN_IN"); - builder = new GoogleSignInOptions.Builder(GoogleSignInOptions.DEFAULT_GAMES_SIGN_IN); - } else { - GoogleSignInHelper.logDebug("Using DEFAULT_SIGN_IN"); - builder = new GoogleSignInOptions.Builder(GoogleSignInOptions.DEFAULT_SIGN_IN); - } - - if (request.getDoAuthCode()) { - if (!request.getWebClientId().isEmpty()) { - GoogleSignInHelper.logDebug( - "Requesting AuthCode force = " - + request.getForceRefresh() - + "client: " - + request.getWebClientId()); - builder.requestServerAuthCode(request.getWebClientId(), request.getForceRefresh()); - } else { - GoogleSignInHelper.logError("Web client ID is needed for Auth Code"); - request.setResult(CommonStatusCodes.DEVELOPER_ERROR, null); - throw new IllegalStateException("Web client ID is needed for Auth Code"); - } - } - - if (request.getDoEmail()) { - GoogleSignInHelper.logDebug("Requesting email"); - builder.requestEmail(); - } - - if (request.getDoIdToken()) { - if (!request.getWebClientId().isEmpty()) { - GoogleSignInHelper.logDebug("Requesting IDToken client: " + request.getWebClientId()); - - builder.requestIdToken(request.getWebClientId()); - } else { - GoogleSignInHelper.logError("Web client ID is needed for ID Token"); - request.setResult(CommonStatusCodes.DEVELOPER_ERROR, null); - throw new IllegalStateException("Web client ID is needed for Auth Code"); - } - } - if (request.getScopes() != null) { - for (String s : request.getScopes()) { - GoogleSignInHelper.logDebug("Adding scope: " + s); - - builder.requestScopes(new Scope(s)); - } - } - - if (request.getHidePopups() && request.getUseGamesConfig()) { - GoogleSignInHelper.logDebug("hiding popup views for games API"); - // Use reflection to build the extension, so we don't force - // a dependency on Games. - - builder.addExtension(getGamesExtension()); - } - - if (request.getAccountName() != null) { - GoogleSignInHelper.logDebug("Setting accountName: " + request.getAccountName()); - - builder.setAccountName(request.getAccountName()); - } - - GoogleSignInOptions options = builder.build(); - - GoogleApiClient.Builder clientBuilder = - new GoogleApiClient.Builder(getActivity()).addApi(Auth.GOOGLE_SIGN_IN_API, options); - if (request.getUseGamesConfig()) { - GoogleSignInHelper.logDebug("Adding games API"); - - try { - clientBuilder.addApi(getGamesAPI()); - } catch (Exception e) { - GoogleSignInHelper.logError("Exception getting Games API: " + e.getMessage()); - request.setResult(CommonStatusCodes.DEVELOPER_ERROR, null); - return; - } - } - if (request.getHidePopups()) { - View invisible = new View(getActivity()); - invisible.setVisibility(View.INVISIBLE); - invisible.setClickable(false); - clientBuilder.setViewForPopups(invisible); - } - mGoogleApiClient = clientBuilder.build(); - mGoogleApiClient.connect(GoogleApiClient.SIGN_IN_MODE_OPTIONAL); - } - - private Api getGamesAPI() { - try { - Class gamesClass = Class.forName("com" + ".google.android.gms.games.Games"); - Field apiField = gamesClass.getField("API"); - return (Api) apiField.get(null); - } catch (ClassNotFoundException e) { - throw new IllegalArgumentException("Games API requested, but " + "can't load Games class", e); - } catch (NoSuchFieldException e) { - throw new IllegalArgumentException( - "Games API requested, but " + "can't load Games API field", e); - } catch (IllegalAccessException e) { - throw new IllegalArgumentException( - "Games API requested, but " + "can't load Games API field", e); - } - } - - /** - * Builds the games extension to hide popups using Reflection. This avoids the hard dependency on - * Games. - * - * @return the extension, or throws InvalidArgumentException if games is requested, but not found. - */ - private GoogleSignInOptionsExtension getGamesExtension() { - try { - Class gamesClass = Class.forName("com" + ".google.android.gms.games.Games$GamesOptions"); - - Method builderMethod = gamesClass.getMethod("builder()"); - - Object builder = builderMethod.invoke(null); - - Method setter = builder.getClass().getMethod("setShowConnectingPopup", boolean.class); - - setter.invoke(builder, false); - - Method buildMethod = builder.getClass().getMethod("build"); - return (GoogleSignInOptionsExtension) buildMethod.invoke(builder); - - } catch (ClassNotFoundException e) { - throw new IllegalArgumentException( - "Games API requested, but" + "can't load Games$GamesOptions class", e); - } catch (NoSuchMethodException e) { - throw new IllegalArgumentException( - "Games API requested, but" + "can't find builder() static method.", e); - } catch (InvocationTargetException e) { - throw new IllegalArgumentException( - "Games API requested, but" + "can't invoke builder() static method.", e); - } catch (IllegalAccessException e) { - throw new IllegalArgumentException( - "Games API requested, but" + "can't invoke builder() static method.", e); - } - } - - @Override - public void onStart() { - super.onStart(); - - // This just connects the client. If there is no user signed in, you - // still need to call Auth.GoogleSignInApi.getSignInIntent() to start - // the sign-in process. - if (mGoogleApiClient != null) { - mGoogleApiClient.connect(GoogleApiClient.SIGN_IN_MODE_OPTIONAL); - } - } - - /** - * Called when the fragment is visible to the user and actively running. This is generally tied to - * {@link Activity#onResume() Activity.onResume} of the containing Activity's lifecycle. - */ - @Override - public void onResume() { - GoogleSignInHelper.logDebug("onResume called"); - if (theFragment != this) { - theFragment = this; - } - super.onResume(); - if (getState() == State.PENDING) { - GoogleSignInHelper.logDebug("State is pending, calling processRequest(false)"); - processRequest(false); - } else if (getState() == State.PENDING_SILENT) { - GoogleSignInHelper.logDebug("State is pending_silent, calling processRequest(true)"); - processRequest(true); - } else { - GoogleSignInHelper.logDebug("State is now ready"); - setState(State.READY); - } - } - - /** - * Receive the result from a previous call to {@link #startActivityForResult(Intent, int)}. This - * follows the related Activity API as described there in {@link Activity#onActivityResult(int, - * int, Intent)}. - * - * @param requestCode The integer request code originally supplied to startActivityForResult(), - * allowing you to identify who this result came from. - * @param resultCode The integer result code returned by the child activity through its - * setResult(). - * @param data An Intent, which can return result data to the caller - */ - @Override - public void onActivityResult(int requestCode, int resultCode, Intent data) { - GoogleSignInHelper.logDebug("onActivityResult: " + requestCode + " " + resultCode); - if (requestCode == RC_SIGNIN) { - GoogleSignInResult result = Auth.GoogleSignInApi.getSignInResultFromIntent(data); - TokenRequest request = this.request; - if (request != null) { - if (result == null) { - // This usually indicates a problem with Google Play Services not working correctly. - int returnCode = resultCode >= 0 ? CommonStatusCodes.ERROR : resultCode; - request.setResult( returnCode, null); - GoogleSignInHelper.logError("GoogleSignIn result is null, returning error."); - } else { - GoogleSignInAccount acct = result.getSignInAccount(); - request.setResult(result.getStatus().getStatusCode(), acct); - } - } else { - GoogleSignInHelper.logError("Pending request is null, can't " + "return result!"); - } - return; - } - super.onActivityResult(requestCode, resultCode, data); - } - - private synchronized void clearRequest(boolean cancel) { - if (cancel && request != null) { - // Cancel request. - request.cancel(); - } - request = null; - setState(getActivity() != null ? State.READY : State.NEW); - } -} diff --git a/Plugins/Android/src/main/java/com/google/googlesignin/GoogleSignInFragment.java.meta b/Plugins/Android/src/main/java/com/google/googlesignin/GoogleSignInFragment.java.meta deleted file mode 100644 index e957325f..00000000 --- a/Plugins/Android/src/main/java/com/google/googlesignin/GoogleSignInFragment.java.meta +++ /dev/null @@ -1,32 +0,0 @@ -fileFormatVersion: 2 -guid: b1fd4b2d68e09924f8b7105c1876d21d -PluginImporter: - externalObjects: {} - serializedVersion: 2 - iconMap: {} - executionOrder: {} - defineConstraints: [] - isPreloaded: 0 - isOverridable: 0 - isExplicitlyReferenced: 0 - validateReferences: 1 - platformData: - - first: - Android: Android - second: - enabled: 1 - settings: {} - - first: - Any: - second: - enabled: 0 - settings: {} - - first: - Editor: Editor - second: - enabled: 0 - settings: - DefaultValueInitialized: true - userData: - assetBundleName: - assetBundleVariant: diff --git a/Plugins/Android/src/main/java/com/google/googlesignin/GoogleSignInHelper.java b/Plugins/Android/src/main/java/com/google/googlesignin/GoogleSignInHelper.java index 0dcd5a6a..5f232cf3 100644 --- a/Plugins/Android/src/main/java/com/google/googlesignin/GoogleSignInHelper.java +++ b/Plugins/Android/src/main/java/com/google/googlesignin/GoogleSignInHelper.java @@ -16,19 +16,54 @@ package com.google.googlesignin; import android.app.Activity; +import android.os.Bundle; +import android.os.CancellationSignal; import android.util.Log; -import com.google.android.gms.auth.api.signin.GoogleSignInAccount; + +import androidx.annotation.NonNull; +import androidx.credentials.ClearCredentialStateRequest; +import androidx.credentials.Credential; +import androidx.credentials.CredentialManager; +import androidx.credentials.CredentialManagerCallback; +import androidx.credentials.GetCredentialRequest; +import androidx.credentials.GetCredentialResponse; +import androidx.credentials.exceptions.ClearCredentialException; +import androidx.credentials.exceptions.GetCredentialException; + +import com.google.android.gms.auth.api.identity.AuthorizationRequest; +import com.google.android.gms.auth.api.identity.AuthorizationResult; +import com.google.android.gms.auth.api.identity.Identity; +import com.google.android.gms.common.Scopes; import com.google.android.gms.common.api.CommonStatusCodes; +import com.google.android.gms.common.api.Scope; +import com.google.android.gms.common.util.Strings; +import com.google.android.gms.tasks.CancellationToken; +import com.google.android.gms.tasks.OnCompleteListener; +import com.google.android.gms.tasks.OnSuccessListener; +import com.google.android.gms.tasks.OnTokenCanceledListener; +import com.google.android.gms.tasks.SuccessContinuation; +import com.google.android.gms.tasks.Task; +import com.google.android.gms.tasks.TaskCompletionSource; +import com.google.android.gms.tasks.TaskExecutors; +import com.google.android.libraries.identity.googleid.GetGoogleIdOption; +import com.google.android.libraries.identity.googleid.GoogleIdTokenCredential; +import com.unity3d.player.UnityPlayer; + +import org.jetbrains.annotations.NotNull; + +import java.util.ArrayList; +import java.util.List; +import java.util.function.Function; /** - * Helper class used by the native C++ code to interact with Google Sign-in API. The general flow is + * Helper class used by the native C++ code to interact with Google Sign-in API. + * The general flow is * Call configure, then one of signIn or signInSilently. */ public class GoogleSignInHelper { // Set to true to get more debug logging. public static boolean loggingEnabled = false; - private static final String TAG = "SignInFragment"; /** * Enables verbose logging @@ -37,94 +72,207 @@ public static void enableDebugLogging(boolean flag) { loggingEnabled = flag; } + private CancellationSignal cancellationSignal; + private Task task; + private Function> continuation; + public boolean isPending() { + return task != null && !task.isComplete() && !task.isCanceled(); + } + + public int getStatus() { + if(continuation == null) + return CommonStatusCodes.DEVELOPER_ERROR; + + if(task == null) + return CommonStatusCodes.SIGN_IN_REQUIRED; + + if(task.isCanceled()) + return CommonStatusCodes.CANCELED; + + if(task.isSuccessful()) + return CommonStatusCodes.SUCCESS; + + Exception e = task.getException(); + if(e != null) + return CommonStatusCodes.INTERNAL_ERROR; + + return CommonStatusCodes.ERROR; + } + /** * Sets the configuration of the sign-in api that should be used. * - * @param parentActivity - the parent activity. This API creates a fragment that is attached to - * this activity. - * @param useGamesConfig - true if the GAMES_CONFIG should be used when signing-in. - * @param webClientId - the web client id of the backend server associated with this application. - * @param requestAuthCode - true if a server auth code is needed. This also requires the web - * client id to be set. - * @param forceRefreshToken - true to force a refresh token when using the server auth code. - * @param requestEmail - true if email address of the user is requested. - * @param requestIdToken - true if an id token for the user is requested. - * @param hideUiPopups - true if the popups during sign-in from the Games API should be hidden. - * This only has affect if useGamesConfig is true. - * @param defaultAccountName - the account name to attempt to default to when signing in. - * @param additionalScopes - additional API scopes to request when authenticating. - * @param requestHandle - the handle to this request, created by the native C++ code, this is used - * to correlate the response with the request. + * @param useGamesConfig - true if the GAMES_CONFIG should be used when + * signing-in. + * @param webClientId - the web client id of the backend server + * associated with this application. + * @param requestAuthCode - true if a server auth code is needed. This also + * requires the web + * client id to be set. + * @param forceRefreshToken - true to force a refresh token when using the + * server auth code. + * @param requestEmail - true if email address of the user is requested. + * @param requestIdToken - true if an id token for the user is requested. + * @param hideUiPopups - true if the popups during sign-in from the Games + * API should be hidden. + * This only has affect if useGamesConfig is true. + * @param defaultAccountName - the account name to attempt to default to when + * signing in. + * @param additionalScopes - additional API scopes to request when + * authenticating. + * @param requestHandle - the handle to this request, created by the native + * C++ code, this is used + * to correlate the response with the request. */ - public static void configure( - Activity parentActivity, - boolean useGamesConfig, - String webClientId, - boolean requestAuthCode, - boolean forceRefreshToken, - boolean requestEmail, - boolean requestIdToken, - boolean hideUiPopups, - String defaultAccountName, - String[] additionalScopes, - IListener requestHandle) { + public void configure( + boolean useGamesConfig, + String webClientId, + boolean requestAuthCode, + boolean forceRefreshToken, + boolean requestEmail, + boolean requestIdToken, + boolean hideUiPopups, + String defaultAccountName, + String[] additionalScopes, + IListener requestHandle) { logDebug("TokenFragment.configure called"); - TokenRequest request = - new TokenRequest( - useGamesConfig, - webClientId, - requestAuthCode, - forceRefreshToken, - requestEmail, - requestIdToken, - hideUiPopups, - defaultAccountName, - additionalScopes, - requestHandle); - - GoogleSignInFragment fragment = GoogleSignInFragment.getInstance(parentActivity); - - if (request.isValid()) { - if (!fragment.submitRequest(request)) { - logError("There is already a pending" + " authentication token request!"); - } - } else { - nativeOnResult(requestHandle, CommonStatusCodes.DEVELOPER_ERROR, null); - } - } - public static GoogleSignInFragment signIn(Activity activity) { - logDebug("AuthHelperFragment.authenticate called!"); - GoogleSignInFragment fragment = GoogleSignInFragment.getInstance(activity); + continuation = new Function>() { + @Override + public Task apply(@NonNull Boolean silent) { + if(isPending()) { + TaskCompletionSource source = new TaskCompletionSource<>(); + source.trySetException(new Exception("Last task still pending")); + return source.getTask(); + } - if (!fragment.startSignIn()) { - nativeOnResult(fragment.getRequest().getHandle(), CommonStatusCodes.DEVELOPER_ERROR, null); - } + cancellationSignal = new CancellationSignal(); + + CancellationSignal signal = cancellationSignal; + + GetGoogleIdOption.Builder getGoogleIdOptionBuilder = new GetGoogleIdOption.Builder() + .setFilterByAuthorizedAccounts(silent) + .setAutoSelectEnabled(hideUiPopups); + + if(defaultAccountName != null) + getGoogleIdOptionBuilder.setNonce(defaultAccountName); + + if(requestIdToken && !Strings.isEmptyOrWhitespace(webClientId)) + getGoogleIdOptionBuilder.setServerClientId(webClientId); - return fragment; + GetCredentialRequest.Builder getCredentialRequestBuilder = new GetCredentialRequest.Builder() + .addCredentialOption(getGoogleIdOptionBuilder.build()) + .setPreferImmediatelyAvailableCredentials(hideUiPopups); + + TaskCompletionSource source = new TaskCompletionSource<>(); + + CredentialManager.create(UnityPlayer.currentActivity).getCredentialAsync(UnityPlayer.currentActivity, + getCredentialRequestBuilder.build(), + cancellationSignal, + TaskExecutors.MAIN_THREAD, + new CredentialManagerCallback() { + @Override + public void onResult(GetCredentialResponse getCredentialResponse) { + source.trySetResult(getCredentialResponse); + } + + @Override + public void onError(@NotNull GetCredentialException e) { + source.trySetException(e); + } + }); + + return source.getTask().onSuccessTask(new SuccessContinuation() { + @NonNull + @Override + public Task then(GetCredentialResponse getCredentialResponse) throws Exception { + try { + Credential credential = getCredentialResponse.getCredential(); + Log.i(TAG, "credential.getType() : " + credential.getType()); + + GoogleIdTokenCredential googleIdTokenCredential = GoogleIdTokenCredential.createFrom(credential.getData()); + requestHandle.onAuthenticated(googleIdTokenCredential); + } + catch (Exception e) { + throw e; + } + + AuthorizationRequest.Builder authorizationRequestBuilder = new AuthorizationRequest.Builder(); + if (requestAuthCode && !Strings.isEmptyOrWhitespace(webClientId)) + authorizationRequestBuilder.requestOfflineAccess(webClientId, forceRefreshToken); + + int additionalCount = additionalScopes != null ? additionalScopes.length : 0; + List scopes = new ArrayList<>(3 + additionalCount); + scopes.add(new Scope("openid")); + scopes.add(new Scope(Scopes.PROFILE)); + if (requestEmail) + scopes.add(new Scope(Scopes.EMAIL)); + if (additionalCount > 0) { + for (String scope : additionalScopes) { + scopes.add(new Scope(scope)); + } + } + + if (!scopes.isEmpty()) + authorizationRequestBuilder.setRequestedScopes(scopes); + + return Identity.getAuthorizationClient(UnityPlayer.currentActivity).authorize(authorizationRequestBuilder.build()); + } + }).addOnFailureListener(requestHandle).addOnCanceledListener(requestHandle).addOnSuccessListener(new OnSuccessListener() { + @Override + public void onSuccess(AuthorizationResult authorizationResult) { + requestHandle.onAuthorized(authorizationResult); + } + }).addOnCompleteListener(new OnCompleteListener() { + @Override + public void onComplete(@NonNull Task _unused) { + cancellationSignal = null; + } + }); + } + }; } - public static GoogleSignInFragment signInSilently(Activity activity) { - logDebug("AuthHelperFragment.signinSilently called!"); - GoogleSignInFragment fragment = GoogleSignInFragment.getInstance(activity); + public GoogleSignInHelper signIn() { + task = continuation.apply(false); + return this; + } - if (!fragment.startSignInSilently()) { - nativeOnResult(fragment.getRequest().getHandle(), CommonStatusCodes.DEVELOPER_ERROR, null); + public GoogleSignInHelper signInSilently() { + task = continuation.apply(true); + return this; + } + + public void cancel() { + if(isPending() && cancellationSignal != null){ + cancellationSignal.cancel(); + cancellationSignal = null; } - return fragment; + task = null; } - public static void signOut(Activity activity) { - GoogleSignInFragment fragment = GoogleSignInFragment.getInstance(activity); - fragment.signOut(); - } + public void signOut() { + cancel(); - public static void disconnect(Activity activity) { - GoogleSignInFragment fragment = GoogleSignInFragment.getInstance(activity); - fragment.disconnect(); + CredentialManager.create(UnityPlayer.currentActivity).clearCredentialStateAsync(new ClearCredentialStateRequest(), + new CancellationSignal(), + TaskExecutors.MAIN_THREAD, + new CredentialManagerCallback() { + @Override + public void onResult(Void unused) { + logInfo("signOut"); + } + + @Override + public void onError(@NonNull ClearCredentialException e) { + logError(e.getMessage()); + } + }); } + static final String TAG = GoogleSignInHelper.class.getSimpleName(); + public static void logInfo(String msg) { if (loggingEnabled) { Log.i(TAG, msg); @@ -140,16 +288,4 @@ public static void logDebug(String msg) { Log.d(TAG, msg); } } - - /** - * Native callback for the authentication result. - * - * @param handle Identifies the request. - * @param result Authentication result. - * @param acct The account that is signed in, if successful. - */ - public static void nativeOnResult(IListener handle, int result, GoogleSignInAccount acct) - { - handle.OnResult(result,acct); - } } diff --git a/Plugins/Android/src/main/java/com/google/googlesignin/IListener.java b/Plugins/Android/src/main/java/com/google/googlesignin/IListener.java index 5ebce7a5..3ff29731 100644 --- a/Plugins/Android/src/main/java/com/google/googlesignin/IListener.java +++ b/Plugins/Android/src/main/java/com/google/googlesignin/IListener.java @@ -1,8 +1,13 @@ package com.google.googlesignin; -import com.google.android.gms.auth.api.signin.GoogleSignInAccount; +import com.google.android.gms.auth.api.identity.AuthorizationResult; +import com.google.android.gms.tasks.OnCanceledListener; +import com.google.android.gms.tasks.OnFailureListener; -public interface IListener +import com.google.android.libraries.identity.googleid.GoogleIdTokenCredential; + +public interface IListener extends OnCanceledListener, OnFailureListener { - void OnResult(int result, GoogleSignInAccount acct); + void onAuthenticated(GoogleIdTokenCredential acct); + void onAuthorized(AuthorizationResult acct); } \ No newline at end of file diff --git a/Plugins/Android/src/main/java/com/google/googlesignin/TokenPendingResult.java b/Plugins/Android/src/main/java/com/google/googlesignin/TokenPendingResult.java deleted file mode 100644 index 636792d1..00000000 --- a/Plugins/Android/src/main/java/com/google/googlesignin/TokenPendingResult.java +++ /dev/null @@ -1,152 +0,0 @@ -/* - * Copyright 2017 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. - */ -package com.google.googlesignin; - -import android.util.Log; -import com.google.android.gms.auth.api.signin.GoogleSignInAccount; -import com.google.android.gms.common.api.CommonStatusCodes; -import com.google.android.gms.common.api.PendingResult; -import com.google.android.gms.common.api.ResultCallback; -import java.util.concurrent.CountDownLatch; -import java.util.concurrent.TimeUnit; -import java.util.Locale; - -/** - * Pending result class for TokenResult. This allows the pending result to be returned to the - * caller, and then updated when available, simplifying the handling of callbacks. - */ -public class TokenPendingResult extends PendingResult { - - private static final String TAG = "TokenPendingResult"; - private final IListener requestHandle; - - private CountDownLatch latch = new CountDownLatch(1); - private TokenResult result; - private ResultCallback resultCallback; - - public TokenPendingResult(IListener requestHandle) { - this.requestHandle = requestHandle; - result = new TokenResult(); - result.setHandle(requestHandle); - } - - @Override - public String toString() { - return String.format( - Locale.getDefault(), "Pending Result: %s", (result == null) ? "" : result); - } - - @Override - public TokenResult await() { - - try { - latch.await(); - } catch (InterruptedException e) { - setResult(null, CommonStatusCodes.INTERRUPTED); - } - - return getResult(); - } - - @Override - public TokenResult await(long l, TimeUnit timeUnit) { - try { - if (!latch.await(l, timeUnit)) { - setResult(null, CommonStatusCodes.TIMEOUT); - } - } catch (InterruptedException e) { - setResult(null, CommonStatusCodes.INTERRUPTED); - } - return getResult(); - } - - @Override - public void cancel() { - setResult(null, CommonStatusCodes.CANCELED); - latch.countDown(); - } - - @Override - public boolean isCanceled() { - return getResult() != null && getResult().getStatus().isCanceled(); - } - - @Override - public void setResultCallback(ResultCallback resultCallback) { - - // Handle adding the callback when the latch has already counted down. This - // can happen if there is an error right away. - if (latch.getCount() == 0) { - resultCallback.onResult(getResult()); - } else { - setCallback(resultCallback); - } - } - - @Override - public void setResultCallback( - ResultCallback resultCallback, long l, TimeUnit timeUnit) { - try { - if (!latch.await(l, timeUnit)) { - setResult(null, CommonStatusCodes.TIMEOUT); - } - } catch (InterruptedException e) { - setResult(null, CommonStatusCodes.INTERRUPTED); - } - - resultCallback.onResult(getResult()); - } - - private synchronized void setCallback(ResultCallback callback) { - this.resultCallback = callback; - } - - private synchronized ResultCallback getCallback() { - return this.resultCallback; - } - - /** - * Set the result. If any of the values are null, and a previous non-null value was set, the - * non-null value is retained. - * - * @param account - the signin account, if any. - * @param resultCode - the result code. - */ - public synchronized void setResult(GoogleSignInAccount account, int resultCode) { - result = new TokenResult(account, resultCode); - result.setHandle(requestHandle); - } - - private synchronized TokenResult getResult() { - return result; - } - - /** - * Sets the result status and releases the latch and/or calls the callback. - * - * @param status - the result status. - */ - public void setStatus(int status) { - result.setStatus(status); - latch.countDown(); - ResultCallback cb = getCallback(); - TokenResult res = getResult(); - if (cb != null) { - Log.d(TAG, " Calling onResult for callback. result: " + res); - getCallback().onResult(res); - } - } -} diff --git a/Plugins/Android/src/main/java/com/google/googlesignin/TokenPendingResult.java.meta b/Plugins/Android/src/main/java/com/google/googlesignin/TokenPendingResult.java.meta deleted file mode 100644 index ceded97a..00000000 --- a/Plugins/Android/src/main/java/com/google/googlesignin/TokenPendingResult.java.meta +++ /dev/null @@ -1,32 +0,0 @@ -fileFormatVersion: 2 -guid: 3065444eac9447a45aa62369e8d28a3b -PluginImporter: - externalObjects: {} - serializedVersion: 2 - iconMap: {} - executionOrder: {} - defineConstraints: [] - isPreloaded: 0 - isOverridable: 0 - isExplicitlyReferenced: 0 - validateReferences: 1 - platformData: - - first: - Android: Android - second: - enabled: 1 - settings: {} - - first: - Any: - second: - enabled: 0 - settings: {} - - first: - Editor: Editor - second: - enabled: 0 - settings: - DefaultValueInitialized: true - userData: - assetBundleName: - assetBundleVariant: diff --git a/Plugins/Android/src/main/java/com/google/googlesignin/TokenRequest.java b/Plugins/Android/src/main/java/com/google/googlesignin/TokenRequest.java deleted file mode 100644 index 4e81154d..00000000 --- a/Plugins/Android/src/main/java/com/google/googlesignin/TokenRequest.java +++ /dev/null @@ -1,171 +0,0 @@ -/* - * Copyright 2017 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. - */ -package com.google.googlesignin; - -import com.google.android.gms.auth.api.signin.GoogleSignInAccount; -import com.google.android.gms.common.api.PendingResult; -import java.util.Locale; - -/** Helper class containing the request for information. */ -public class TokenRequest { - private TokenPendingResult pendingResponse; - private boolean useGamesConfig; - private boolean doAuthCode; - private boolean doEmail; - private boolean doIdToken; - private String webClientId; - private boolean forceRefresh; - private boolean hidePopups; - private String accountName; - private String[] scopes; - private IListener handle; - - /** - * Constructs a token request. - * - * @param useGamesConfig - true if the GAMES_CONFIG should be used when signing-in. - * @param webClientId - the web client id of the backend server associated with this application. - * @param requestAuthCode - true if a server auth code is needed. This also requires the web - * client id to be set. - * @param forceRefreshToken - true to force a refresh token when using the server auth code. - * @param requestEmail - true if email address of the user is requested. - * @param requestIdToken - true if an id token for the user is requested. - * @param hideUiPopups - true if the popups during sign-in from the Games API should be hidden. - * This only has affect if useGamesConfig is true. - * @param defaultAccountName - the account name to attempt to default to when signing in. - * @param additionalScopes - additional API scopes to request when authenticating. - * @param requestHandle - the handle to this request, created by the native C++ code, this is used - * to correlate the response with the request. - */ - public TokenRequest( - boolean useGamesConfig, - String webClientId, - boolean requestAuthCode, - boolean forceRefreshToken, - boolean requestEmail, - boolean requestIdToken, - boolean hideUiPopups, - String defaultAccountName, - String[] additionalScopes, - IListener requestHandle) { - pendingResponse = new TokenPendingResult(requestHandle); - this.useGamesConfig = useGamesConfig; - this.webClientId = webClientId; - this.doAuthCode = requestAuthCode; - this.forceRefresh = forceRefreshToken; - this.doEmail = requestEmail; - this.doIdToken = requestIdToken; - this.hidePopups = hideUiPopups; - this.accountName = defaultAccountName; - this.handle = requestHandle; - if (additionalScopes != null && additionalScopes.length > 0) { - scopes = new String[additionalScopes.length]; - System.arraycopy(additionalScopes, 0, scopes, 0, additionalScopes.length); - } else { - scopes = null; - } - } - - /** - * Returns the pending response object for this request. - * - * @return the pending response. - */ - public PendingResult getPendingResponse() { - return pendingResponse; - } - - /** - * Sets the result of the reuquest. - * - * @param code - the status code of the request. - * @param account - the GoogleSignInAccount if successful. - */ - public void setResult(int code, GoogleSignInAccount account) { - pendingResponse.setResult(account, code); - pendingResponse.setStatus(code); - } - - /** Cancels the request and notifies the pending response. */ - public void cancel() { - pendingResponse.cancel(); - } - - @Override - public String toString() { - return String.format( - Locale.getDefault(), - "%s(a:%b:e:%b:i:%b)", - Integer.toHexString(hashCode()), - doAuthCode, - doEmail, - doIdToken); - } - - public String getWebClientId() { - return webClientId == null ? "" : webClientId; - } - - public boolean getForceRefresh() { - return forceRefresh; - } - - public boolean isValid() { - if (webClientId == null || webClientId.isEmpty()) { - if (doAuthCode) { - GoogleSignInHelper.logError( - "Invalid configuration, auth code" + " requires web " + "client id"); - return false; - } else if (doIdToken) { - GoogleSignInHelper.logError("Invalid configuration, id token requires web " + "client id"); - return false; - } - } - return true; - } - - public IListener getHandle() { - return handle; - } - - public boolean getUseGamesConfig() { - return useGamesConfig; - } - - public boolean getDoAuthCode() { - return doAuthCode; - } - - public boolean getDoEmail() { - return doEmail; - } - - public boolean getDoIdToken() { - return doIdToken; - } - - public String[] getScopes() { - return scopes; - } - - public String getAccountName() { - return accountName; - } - - public boolean getHidePopups() { - return hidePopups; - } -} diff --git a/Plugins/Android/src/main/java/com/google/googlesignin/TokenRequest.java.meta b/Plugins/Android/src/main/java/com/google/googlesignin/TokenRequest.java.meta deleted file mode 100644 index b194122b..00000000 --- a/Plugins/Android/src/main/java/com/google/googlesignin/TokenRequest.java.meta +++ /dev/null @@ -1,32 +0,0 @@ -fileFormatVersion: 2 -guid: abff1b835e0405d439149d095c18b791 -PluginImporter: - externalObjects: {} - serializedVersion: 2 - iconMap: {} - executionOrder: {} - defineConstraints: [] - isPreloaded: 0 - isOverridable: 0 - isExplicitlyReferenced: 0 - validateReferences: 1 - platformData: - - first: - Android: Android - second: - enabled: 1 - settings: {} - - first: - Any: - second: - enabled: 0 - settings: {} - - first: - Editor: Editor - second: - enabled: 0 - settings: - DefaultValueInitialized: true - userData: - assetBundleName: - assetBundleVariant: diff --git a/Plugins/Android/src/main/java/com/google/googlesignin/TokenResult.java b/Plugins/Android/src/main/java/com/google/googlesignin/TokenResult.java deleted file mode 100644 index b5f46f77..00000000 --- a/Plugins/Android/src/main/java/com/google/googlesignin/TokenResult.java +++ /dev/null @@ -1,66 +0,0 @@ -/* - * Copyright 2017 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. - */ -package com.google.googlesignin; - -import com.google.android.gms.auth.api.signin.GoogleSignInAccount; -import com.google.android.gms.common.api.CommonStatusCodes; -import com.google.android.gms.common.api.Result; -import com.google.android.gms.common.api.Status; -import java.util.Locale; - -/** Class for returning the tokens to a native caller. */ -public class TokenResult implements Result { - private Status status; - private GoogleSignInAccount account; - private IListener handle; - - TokenResult() { - status = new Status(CommonStatusCodes.SIGN_IN_REQUIRED); - account = null; - } - - TokenResult(GoogleSignInAccount account, int resultCode) { - status = new Status(resultCode); - this.account = account; - } - - @Override - public String toString() { - return String.format( - Locale.getDefault(), "Status: %s %s", status, (account == null) ? "" : account); - } - - @Override - public Status getStatus() { - return status; - } - - public GoogleSignInAccount getAccount() { - return account; - } - - public void setStatus(int status) { - this.status = new Status(status); - } - - public IListener getHandle() { - return handle; - } - - public void setHandle(IListener handle) { - this.handle = handle; - } -} diff --git a/Plugins/Android/src/main/java/com/google/googlesignin/TokenResult.java.meta b/Plugins/Android/src/main/java/com/google/googlesignin/TokenResult.java.meta deleted file mode 100644 index 34333901..00000000 --- a/Plugins/Android/src/main/java/com/google/googlesignin/TokenResult.java.meta +++ /dev/null @@ -1,32 +0,0 @@ -fileFormatVersion: 2 -guid: 255165ffb347b9d4f802441bb7cab85b -PluginImporter: - externalObjects: {} - serializedVersion: 2 - iconMap: {} - executionOrder: {} - defineConstraints: [] - isPreloaded: 0 - isOverridable: 0 - isExplicitlyReferenced: 0 - validateReferences: 1 - platformData: - - first: - Android: Android - second: - enabled: 1 - settings: {} - - first: - Any: - second: - enabled: 0 - settings: {} - - first: - Editor: Editor - second: - enabled: 0 - settings: - DefaultValueInitialized: true - userData: - assetBundleName: - assetBundleVariant: diff --git a/Plugins/iOS/GoogleSignIn.mm b/Plugins/iOS/GoogleSignIn.mm index 15822032..b1b91616 100644 --- a/Plugins/iOS/GoogleSignIn.mm +++ b/Plugins/iOS/GoogleSignIn.mm @@ -14,10 +14,11 @@ * limitations under the License. */ #import "GoogleSignIn.h" -#import +#import #import #import #import +#import #import #import "UnityInterface.h" @@ -238,10 +239,10 @@ bool GoogleSignIn_Configure(void *unused, bool useGameSignIn, void *GoogleSignIn_SignIn() { SignInResult *result = startSignIn(); if (!result) { - [[GIDSignIn sharedInstance] signInWithConfiguration:[GoogleSignInHandler sharedInstance]->signInConfiguration - presentingViewController:UnityGetGLViewController() - hint:[GoogleSignInHandler sharedInstance]->loginHint - callback:^(GIDGoogleUser *user, NSError *error) { + [[GIDSignIn sharedInstance] signInWithPresentingViewController:UnityGetGLViewController() + hint:[GoogleSignInHandler sharedInstance]->loginHint + completion:^(GIDSignInResult *result, NSError *error) { + GIDGoogleUser *user = result.user; [[GoogleSignInHandler sharedInstance] signIn:[GIDSignIn sharedInstance] didSignInForUser:user withError:error]; }]; result = currentResult_.get(); @@ -256,7 +257,7 @@ bool GoogleSignIn_Configure(void *unused, bool useGameSignIn, void *GoogleSignIn_SignInSilently() { SignInResult *result = startSignIn(); if (!result) { - [[GIDSignIn sharedInstance] restorePreviousSignInWithCallback:^(GIDGoogleUser *user, NSError *error) { + [[GIDSignIn sharedInstance] restorePreviousSignInWithCompletion:^(GIDGoogleUser *user, NSError *error) { [[GoogleSignInHandler sharedInstance] signIn:[GIDSignIn sharedInstance] didSignInForUser:user withError:error]; }]; result = currentResult_.get(); @@ -271,7 +272,7 @@ void GoogleSignIn_Signout() { void GoogleSignIn_Disconnect() { GIDSignIn *signIn = [GIDSignIn sharedInstance]; - [signIn disconnectWithCallback:^(NSError *error) { + [signIn disconnectWithCompletion:^(NSError *error) { [[GoogleSignInHandler sharedInstance] signIn:[GIDSignIn sharedInstance] didDisconnectWithUser:nil withError:error]; }]; } @@ -323,8 +324,8 @@ static size_t CopyNSString(NSString *src, char *dest, size_t len) { size_t GoogleSignIn_GetServerAuthCode(GIDGoogleUser *guser, char *buf, size_t len) { - NSString *val = [guser serverAuthCode]; - return CopyNSString(val, buf, len); + NSString *val = [guser.configuration serverClientID]; +return CopyNSString(val, buf, len); } size_t GoogleSignIn_GetDisplayName(GIDGoogleUser *guser, char *buf, @@ -349,7 +350,9 @@ size_t GoogleSignIn_GetGivenName(GIDGoogleUser *guser, char *buf, size_t len) { } size_t GoogleSignIn_GetIdToken(GIDGoogleUser *guser, char *buf, size_t len) { - NSString *val = [guser.authentication idToken]; + GIDToken *token = [guser idToken]; + NSString *val = token.tokenString; + return CopyNSString(val, buf, len); } @@ -363,4 +366,4 @@ size_t GoogleSignIn_GetUserId(GIDGoogleUser *guser, char *buf, size_t len) { NSString *val = [guser userID]; return CopyNSString(val, buf, len); } -} // extern "C" +} // extern "C" \ No newline at end of file diff --git a/README.md b/README.md index f8dcabc6..89216d0c 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,30 @@ +# Forked to upgrade base library to newer version + +https://developer.android.com/identity/sign-in/legacy-gsi-migration +https://developers.google.com/identity/sign-in/ios/quick-migration-guide + +Thank for ios fix which was cherrypicked from this fork : https://github.com/pillsgood/google-signin-unity + +Android was migrated to use `CredentialManager` and `AuthorizationClient` since [GoogleSignInAccount was deprecated](https://developers.google.com/android/reference/com/google/android/gms/auth/api/signin/GoogleSignInAccount) + +However, `GoogleIdTokenCredential` actually not provide numeric unique ID anymore and set email as userId instead, so I have to extract jwt `sub` value from idToken (which seem like the same id as userId from GoogleSignIn of other platform) + +Also, this new system seem like it did not support email hint + +Tested in unity 2021.3.21 and unity 6000.0.4 + +Add UPM dependency with branch tag `https://github.com/Thaina/google-signin-unity.git#newmigration` + +```json +{ + "dependencies": { + "com.google.external-dependency-manager": "https://github.com/googlesamples/unity-jar-resolver.git?path=upm", + "com.google.signin": "https://github.com/Thaina/google-signin-unity.git#newmigration", + ... + } +} +``` + # Google Sign-In Unity Plugin _Copyright (c) 2017 Google Inc. All rights reserved._ diff --git a/package.json b/package.json index f5c2341f..0c987933 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "com.google.signin", "displayName": "Google Signin", - "version": "0.8.3", + "version": "0.9.0", "unity": "2021.3", "description": "Google Signin for android, ios ,desktop", "keywords": [ @@ -9,8 +9,8 @@ "signin" ], "dependencies": { - "com.google.external-dependency-manager": "1.2.177", - "com.unity.nuget.newtonsoft-json": "3.2.1" + "com.unity.nuget.newtonsoft-json": "3.2.1", + "com.google.external-dependency-manager": "1.2.175" }, "samples": [ { From d7915e14a7461b2b20f85c8a344cb54be5d15c99 Mon Sep 17 00:00:00 2001 From: Thaina Date: Wed, 12 Jun 2024 23:41:59 +0700 Subject: [PATCH 17/25] always set webclientId update readme --- .../googlesignin/GoogleSignInHelper.java | 2 +- README.md | 18 ++++++++++++++++-- 2 files changed, 17 insertions(+), 3 deletions(-) diff --git a/Plugins/Android/src/main/java/com/google/googlesignin/GoogleSignInHelper.java b/Plugins/Android/src/main/java/com/google/googlesignin/GoogleSignInHelper.java index 5f232cf3..8c6bcc7a 100644 --- a/Plugins/Android/src/main/java/com/google/googlesignin/GoogleSignInHelper.java +++ b/Plugins/Android/src/main/java/com/google/googlesignin/GoogleSignInHelper.java @@ -157,7 +157,7 @@ public Task apply(@NonNull Boolean silent) { if(defaultAccountName != null) getGoogleIdOptionBuilder.setNonce(defaultAccountName); - if(requestIdToken && !Strings.isEmptyOrWhitespace(webClientId)) + if(!Strings.isEmptyOrWhitespace(webClientId)) getGoogleIdOptionBuilder.setServerClientId(webClientId); GetCredentialRequest.Builder getCredentialRequestBuilder = new GetCredentialRequest.Builder() diff --git a/README.md b/README.md index 89216d0c..d1a7b675 100644 --- a/README.md +++ b/README.md @@ -9,9 +9,23 @@ Android was migrated to use `CredentialManager` and `AuthorizationClient` since However, `GoogleIdTokenCredential` actually not provide numeric unique ID anymore and set email as userId instead, so I have to extract jwt `sub` value from idToken (which seem like the same id as userId from GoogleSignIn of other platform) -Also, this new system seem like it did not support email hint +Also, this new system seem like it did not support email hint. And now require WebClientId in addition to Android Client ID. Which need to provided at configuration initialization + +```C# + GoogleSignIn.Configuration = new GoogleSignInConfiguration() { + RequestEmail = true, + RequestProfile = true, + RequestIdToken = true, + RequestAuthCode = true, + // must be web client ID, not android client ID + WebClientId = "XXXXXXXXX-xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx.apps.googleusercontent.com", +#if UNITY_EDITOR || UNITY_STANDALONE + ClientSecret = "XXXXXX-xxxXXXxxxXXXxxx-xxxxXXXXX" // optional for windows/macos and test in editor +#endif + }; +``` -Tested in unity 2021.3.21 and unity 6000.0.4 +Tested in unity 2021.3.21 and unity 6000.0.5 Add UPM dependency with branch tag `https://github.com/Thaina/google-signin-unity.git#newmigration` From 76d29852b1f86cdcaf0f481584025b60ac22dda8 Mon Sep 17 00:00:00 2001 From: ThainaYu Date: Thu, 13 Jun 2024 19:49:17 +0700 Subject: [PATCH 18/25] fix serverAuthCode in ios --- .gitignore | 3 +- .vscode/settings.json | 55 +++++++++++++++++++++++++ Editor.meta | 8 ++++ Editor/iOS.meta | 8 ++++ Editor/iOS/PListImporter.cs | 21 ++++++++++ Editor/iOS/PListImporter.cs.meta | 11 +++++ Editor/iOS/PListProcessor.cs | 67 +++++++++++++++++++++++++++++++ Editor/iOS/PListProcessor.cs.meta | 11 +++++ GoogleSignIn/Impl/NativeFuture.cs | 5 ++- Plugins/iOS/GoogleSignIn.mm | 8 ++-- README.md | 31 ++++++++++++++ 11 files changed, 222 insertions(+), 6 deletions(-) create mode 100644 .vscode/settings.json create mode 100644 Editor.meta create mode 100644 Editor/iOS.meta create mode 100644 Editor/iOS/PListImporter.cs create mode 100644 Editor/iOS/PListImporter.cs.meta create mode 100644 Editor/iOS/PListProcessor.cs create mode 100644 Editor/iOS/PListProcessor.cs.meta diff --git a/.gitignore b/.gitignore index 20168e73..2235a2e2 100644 --- a/.gitignore +++ b/.gitignore @@ -1,6 +1,7 @@ +**/.DS_Store + .gradle/ .idea/ -.vscode/ bin/ build/ *.iml diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 00000000..9c2f3c6f --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,55 @@ +{ + "files.exclude": { + "**/.DS_Store": true, + "**/.git": true, + "**/.gitmodules": true, + "**/*.booproj": true, + "**/*.pidb": true, + "**/*.suo": true, + "**/*.user": true, + "**/*.userprefs": true, + "**/*.unityproj": true, + "**/*.dll": true, + "**/*.exe": true, + "**/*.pdf": true, + "**/*.mid": true, + "**/*.midi": true, + "**/*.wav": true, + "**/*.gif": true, + "**/*.ico": true, + "**/*.jpg": true, + "**/*.jpeg": true, + "**/*.png": true, + "**/*.psd": true, + "**/*.tga": true, + "**/*.tif": true, + "**/*.tiff": true, + "**/*.3ds": true, + "**/*.3DS": true, + "**/*.fbx": true, + "**/*.FBX": true, + "**/*.lxo": true, + "**/*.LXO": true, + "**/*.ma": true, + "**/*.MA": true, + "**/*.obj": true, + "**/*.OBJ": true, + "**/*.asset": true, + "**/*.cubemap": true, + "**/*.flare": true, + "**/*.mat": true, + "**/*.meta": true, + "**/*.prefab": true, + "**/*.unity": true, + "build/": true, + "Build/": true, + "Library/": true, + "library/": true, + "obj/": true, + "Obj/": true, + "ProjectSettings/": true, + "temp/": true, + "Temp/": true + }, + "dotnet.defaultSolution": "TestGoogleSignIn.sln" +} \ No newline at end of file diff --git a/Editor.meta b/Editor.meta new file mode 100644 index 00000000..1a11891a --- /dev/null +++ b/Editor.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: b15db503f08f84da789165e1557fdd7b +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Editor/iOS.meta b/Editor/iOS.meta new file mode 100644 index 00000000..22b933e3 --- /dev/null +++ b/Editor/iOS.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 71aabb773a37445bb8dcac856c8c672e +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Editor/iOS/PListImporter.cs b/Editor/iOS/PListImporter.cs new file mode 100644 index 00000000..569dbb44 --- /dev/null +++ b/Editor/iOS/PListImporter.cs @@ -0,0 +1,21 @@ +#if UNITY_EDITOR +using System.IO; + +using UnityEngine; + +using UnityEditor.AssetImporters; + +[ScriptedImporter(1, "plist")] +public class PListImporter : ScriptedImporter +{ + public override void OnImportAsset(AssetImportContext ctx) + { + if(ctx.mainObject is TextAsset) + return; + + var subAsset = new TextAsset(File.ReadAllText(ctx.assetPath)); + ctx.AddObjectToAsset("text", subAsset); + ctx.SetMainObject(subAsset); + } +} +#endif \ No newline at end of file diff --git a/Editor/iOS/PListImporter.cs.meta b/Editor/iOS/PListImporter.cs.meta new file mode 100644 index 00000000..1c45a1eb --- /dev/null +++ b/Editor/iOS/PListImporter.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 57db1ee44933e4015a8e5b4f29a487e8 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Editor/iOS/PListProcessor.cs b/Editor/iOS/PListProcessor.cs new file mode 100644 index 00000000..ded87cda --- /dev/null +++ b/Editor/iOS/PListProcessor.cs @@ -0,0 +1,67 @@ +#if UNITY_EDITOR +using UnityEngine; + +using UnityEditor; +using UnityEditor.iOS.Xcode; + +using UnityEditor.Build; +using UnityEditor.Build.Reporting; + +using System; +using System.IO; +using System.Linq; +using System.Collections.Generic; + +public class PListProcessor : IPostprocessBuildWithReport +{ + public int callbackOrder => 99999; + + public void OnPostprocessBuild(BuildReport report) + { +#if UNITY_IOS + string projectBundleId = PlayerSettings.GetApplicationIdentifier(BuildTargetGroup.iOS); + var plistFiles = AssetDatabase.FindAssets("glob:\"**/*.plist\"").Select((guid) => { + var doc = new PlistDocument(); + doc.ReadFromFile(AssetDatabase.GUIDToAssetPath(guid)); + return doc; + }).Where((doc) => { + return doc.root.values.TryGetValue("BUNDLE_ID",out var element) && element.AsString() == projectBundleId; + }).ToArray(); + + if(!(plistFiles?.Length > 0)) + return; + + var google = plistFiles.FirstOrDefault(); + + if(!(google.root.values.TryGetValue("CLIENT_ID",out var CLIENT_ID) && CLIENT_ID?.AsString() is string clientID && clientID.EndsWith("googleusercontent.com"))) + throw new KeyNotFoundException("CLIENT_ID"); + if(!(google.root.values.TryGetValue("REVERSED_CLIENT_ID",out var REVERSED_CLIENT_ID) && REVERSED_CLIENT_ID?.AsString() is string reversedClientID && reversedClientID.StartsWith("com.googleusercontent"))) + throw new KeyNotFoundException("REVERSED_CLIENT_ID"); + + string plistPath = Path.Combine( report.summary.outputPath, "Info.plist" ); + + var info = new PlistDocument(); + info.ReadFromFile(plistPath); + + info.root.SetString("GIDClientID",clientID); + var CFBundleURLTypes = (info.root.values.TryGetValue("CFBundleURLTypes",out var element) ? element.AsArray() : null) ?? info.root.CreateArray("CFBundleURLTypes"); + if(!(CFBundleURLTypes?.values?.Count > 0 && CFBundleURLTypes.values.OfType().Select((dict) => dict.values.TryGetValue("CFBundleURLSchemes",out var value) ? value?.AsArray() : null).OfType().SelectMany((array) => array.values).Any((item) => item?.AsString() == reversedClientID))) + { + var dict = CFBundleURLTypes.AddDict(); + dict.SetString("CFBundleTypeRole","Editor"); + dict.CreateArray("CFBundleURLSchemes").AddString(reversedClientID); + } + + if(google.root.values.TryGetValue("WEB_CLIENT_ID",out var WEB_CLIENT_ID) && WEB_CLIENT_ID?.AsString() is string webClientID && !string.IsNullOrWhiteSpace(webClientID)) + { + if(webClientID.EndsWith("googleusercontent.com")) + info.root.SetString("GIDServerClientID",webClientID); + else throw new ArgumentException("WebClientID"); + } + + info.WriteToFile(plistPath); +#endif + } +} + +#endif \ No newline at end of file diff --git a/Editor/iOS/PListProcessor.cs.meta b/Editor/iOS/PListProcessor.cs.meta new file mode 100644 index 00000000..e450597e --- /dev/null +++ b/Editor/iOS/PListProcessor.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 97598a1b92cb146879db81f44bfeb14d +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/GoogleSignIn/Impl/NativeFuture.cs b/GoogleSignIn/Impl/NativeFuture.cs index 0cb905ab..3bbd2833 100644 --- a/GoogleSignIn/Impl/NativeFuture.cs +++ b/GoogleSignIn/Impl/NativeFuture.cs @@ -34,7 +34,8 @@ internal NativeFuture(IntPtr ptr) : base(ptr) { public GoogleSignInUser Result { get { - IntPtr ptr = GoogleSignInImpl.GoogleSignIn_Result(SelfPtr()); + HandleRef self = SelfPtr(); + IntPtr ptr = GoogleSignInImpl.GoogleSignIn_Result(self); if (ptr == IntPtr.Zero) { return null; } @@ -54,7 +55,7 @@ public GoogleSignInUser Result { user.IdToken = GoogleSignInImpl.GoogleSignIn_GetIdToken(userPtr); - user.AuthCode = GoogleSignInImpl.GoogleSignIn_GetServerAuthCode(userPtr); + user.AuthCode = GoogleSignInImpl.GoogleSignIn_GetServerAuthCode(self); string url = GoogleSignInImpl.GoogleSignIn_GetImageUrl(userPtr); if (url?.Length > 0) { diff --git a/Plugins/iOS/GoogleSignIn.mm b/Plugins/iOS/GoogleSignIn.mm index b1b91616..827972ca 100644 --- a/Plugins/iOS/GoogleSignIn.mm +++ b/Plugins/iOS/GoogleSignIn.mm @@ -55,6 +55,7 @@ void UnpauseUnityPlayer() { struct SignInResult { int result_code; bool finished; + NSString* serverAuthCode; }; std::unique_ptr currentResult_; @@ -243,6 +244,7 @@ bool GoogleSignIn_Configure(void *unused, bool useGameSignIn, hint:[GoogleSignInHandler sharedInstance]->loginHint completion:^(GIDSignInResult *result, NSError *error) { GIDGoogleUser *user = result.user; + currentResult_.get()->serverAuthCode = result.serverAuthCode; [[GoogleSignInHandler sharedInstance] signIn:[GIDSignIn sharedInstance] didSignInForUser:user withError:error]; }]; result = currentResult_.get(); @@ -322,10 +324,10 @@ static size_t CopyNSString(NSString *src, char *dest, size_t len) { return src ? src.length + 1 : 0; } -size_t GoogleSignIn_GetServerAuthCode(GIDGoogleUser *guser, char *buf, +size_t GoogleSignIn_GetServerAuthCode(SignInResult *result, char *buf, size_t len) { - NSString *val = [guser.configuration serverClientID]; -return CopyNSString(val, buf, len); + NSString *val = result->serverAuthCode; + return CopyNSString(val, buf, len); } size_t GoogleSignIn_GetDisplayName(GIDGoogleUser *guser, char *buf, diff --git a/README.md b/README.md index d1a7b675..b330c687 100644 --- a/README.md +++ b/README.md @@ -39,6 +39,37 @@ Add UPM dependency with branch tag `https://github.com/Thaina/google-signin-unit } ``` +Also, [New version of iOS recommend](https://developers.google.com/identity/sign-in/ios/quick-migration-guide#google_sign-in_sdk_v700) that we should set `GIDClientID` and `GIDServerClientID` into Info.plist + +So I have add an editor tool `PListProcessor` that look for plist files in the project, extract `CLIENT_ID` and `WEB_CLIENT_ID` property of the plist which contain the `BUNDLE_ID` with the same name as bundle identifier of the project + +The plist file in the project should be downloaded from Google Cloud Console credential page + +Select iOS credential and download at ⬇ button + +```xml + + + + + + CLIENT_ID + {YourCloudProjectID}-yyyyyYYYYyyyyYYYYYYYYYYYYYYyyyyyy.apps.googleusercontent.com + REVERSED_CLIENT_ID + com.googleusercontent.apps.{YourCloudProjectID}-yyyyyYYYYyyyyYYYYYYYYYYYYYYyyyyyy + PLIST_VERSION + 1 + BUNDLE_ID + com.{YourCompany}.{YourProductName} + + WEB_CLIENT_ID + {YourCloudProjectID}-zzzZZZZZZZZZZZZZZzzzzzzzzzzZZZzzz.apps.googleusercontent.com + + +``` + +### Document below is original README, some information might be outdated + # Google Sign-In Unity Plugin _Copyright (c) 2017 Google Inc. All rights reserved._ From f5e644cb233af2117b6b349aedeb7904d5549f91 Mon Sep 17 00:00:00 2001 From: Thaina Yu Date: Wed, 26 Jun 2024 17:32:04 +0700 Subject: [PATCH 19/25] Update README.md, credit the source of the fix --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index b330c687..cfc0b8d2 100644 --- a/README.md +++ b/README.md @@ -3,7 +3,7 @@ https://developer.android.com/identity/sign-in/legacy-gsi-migration https://developers.google.com/identity/sign-in/ios/quick-migration-guide -Thank for ios fix which was cherrypicked from this fork : https://github.com/pillsgood/google-signin-unity +Thank for ios fix which was cherrypicked from this fork : https://github.com/pillsgood/google-signin-unity which came from @DulgiKim https://github.com/googlesamples/google-signin-unity/pull/205#issuecomment-1724733615 Android was migrated to use `CredentialManager` and `AuthorizationClient` since [GoogleSignInAccount was deprecated](https://developers.google.com/android/reference/com/google/android/gms/auth/api/signin/GoogleSignInAccount) From c1e737f2c9dcac3915e44745e0b6fcf0b030b7e2 Mon Sep 17 00:00:00 2001 From: Thaina Date: Sun, 30 Jun 2024 00:18:15 +0700 Subject: [PATCH 20/25] Add GetSignInWithGoogleOption for sign in manually flow --- .../googlesignin/GoogleSignInHelper.java | 39 +++++++++++-------- 1 file changed, 22 insertions(+), 17 deletions(-) diff --git a/Plugins/Android/src/main/java/com/google/googlesignin/GoogleSignInHelper.java b/Plugins/Android/src/main/java/com/google/googlesignin/GoogleSignInHelper.java index 8c6bcc7a..c00ead54 100644 --- a/Plugins/Android/src/main/java/com/google/googlesignin/GoogleSignInHelper.java +++ b/Plugins/Android/src/main/java/com/google/googlesignin/GoogleSignInHelper.java @@ -46,6 +46,7 @@ import com.google.android.gms.tasks.TaskCompletionSource; import com.google.android.gms.tasks.TaskExecutors; import com.google.android.libraries.identity.googleid.GetGoogleIdOption; +import com.google.android.libraries.identity.googleid.GetSignInWithGoogleOption; import com.google.android.libraries.identity.googleid.GoogleIdTokenCredential; import com.unity3d.player.UnityPlayer; @@ -74,13 +75,13 @@ public static void enableDebugLogging(boolean flag) { private CancellationSignal cancellationSignal; private Task task; - private Function> continuation; + private Function> signInFunction; public boolean isPending() { return task != null && !task.isComplete() && !task.isCanceled(); } public int getStatus() { - if(continuation == null) + if(signInFunction == null) return CommonStatusCodes.DEVELOPER_ERROR; if(task == null) @@ -137,7 +138,7 @@ public void configure( IListener requestHandle) { logDebug("TokenFragment.configure called"); - continuation = new Function>() { + signInFunction = new Function>() { @Override public Task apply(@NonNull Boolean silent) { if(isPending()) { @@ -148,21 +149,26 @@ public Task apply(@NonNull Boolean silent) { cancellationSignal = new CancellationSignal(); - CancellationSignal signal = cancellationSignal; + GetCredentialRequest.Builder getCredentialRequestBuilder = new GetCredentialRequest.Builder() + .setPreferImmediatelyAvailableCredentials(hideUiPopups); - GetGoogleIdOption.Builder getGoogleIdOptionBuilder = new GetGoogleIdOption.Builder() - .setFilterByAuthorizedAccounts(silent) - .setAutoSelectEnabled(hideUiPopups); + if(silent) { + GetGoogleIdOption.Builder getGoogleIdOptionBuilder = new GetGoogleIdOption.Builder() + .setFilterByAuthorizedAccounts(false) + .setAutoSelectEnabled(hideUiPopups); - if(defaultAccountName != null) - getGoogleIdOptionBuilder.setNonce(defaultAccountName); + if(defaultAccountName != null) + getGoogleIdOptionBuilder.setNonce(defaultAccountName); - if(!Strings.isEmptyOrWhitespace(webClientId)) - getGoogleIdOptionBuilder.setServerClientId(webClientId); + if(!Strings.isEmptyOrWhitespace(webClientId)) + getGoogleIdOptionBuilder.setServerClientId(webClientId); - GetCredentialRequest.Builder getCredentialRequestBuilder = new GetCredentialRequest.Builder() - .addCredentialOption(getGoogleIdOptionBuilder.build()) - .setPreferImmediatelyAvailableCredentials(hideUiPopups); + getCredentialRequestBuilder.addCredentialOption(getGoogleIdOptionBuilder.build()); + } + else { + GetSignInWithGoogleOption.Builder getSignInWithGoogleOptionBuilder = new GetSignInWithGoogleOption.Builder(webClientId); + getCredentialRequestBuilder.addCredentialOption(getSignInWithGoogleOptionBuilder.build()); + } TaskCompletionSource source = new TaskCompletionSource<>(); @@ -203,7 +209,6 @@ public Task then(GetCredentialResponse getCredentialRespons int additionalCount = additionalScopes != null ? additionalScopes.length : 0; List scopes = new ArrayList<>(3 + additionalCount); - scopes.add(new Scope("openid")); scopes.add(new Scope(Scopes.PROFILE)); if (requestEmail) scopes.add(new Scope(Scopes.EMAIL)); @@ -234,12 +239,12 @@ public void onComplete(@NonNull Task _unused) { } public GoogleSignInHelper signIn() { - task = continuation.apply(false); + task = signInFunction.apply(false); return this; } public GoogleSignInHelper signInSilently() { - task = continuation.apply(true); + task = signInFunction.apply(true); return this; } From 17b3fb45b5cdc8eb793f7bda34dbc3c754f3c9e8 Mon Sep 17 00:00:00 2001 From: Thaina Date: Sun, 30 Jun 2024 02:28:04 +0700 Subject: [PATCH 21/25] Convert java API to be static, as instance API will not let us signIn repeatedly --- GoogleSignIn/Impl/GoogleSignInImpl.cs | 16 +++++----- .../googlesignin/GoogleSignInHelper.java | 30 ++++++++----------- 2 files changed, 21 insertions(+), 25 deletions(-) diff --git a/GoogleSignIn/Impl/GoogleSignInImpl.cs b/GoogleSignIn/Impl/GoogleSignInImpl.cs index 84c972c8..b135b972 100644 --- a/GoogleSignIn/Impl/GoogleSignInImpl.cs +++ b/GoogleSignIn/Impl/GoogleSignInImpl.cs @@ -109,7 +109,7 @@ static bool GoogleSignIn_Configure(HandleRef googleSignInHelper, bool requestIdToken, bool hidePopups, string[] additionalScopes, int scopeCount, string accountName) { - googleSignInHelper.ToAndroidJavaObject().Call("configure", + GoogleSignInHelper.CallStatic("configure", useGameSignIn, webClientId, requestAuthCode, @@ -159,12 +159,12 @@ public void onCanceled() { static IntPtr GoogleSignIn_SignIn(HandleRef self) { - return self.ToAndroidJavaObject().Call("signIn").GetRawObject(); + return GoogleSignInHelper.CallStatic("signIn").GetRawObject(); } static IntPtr GoogleSignIn_SignInSilently(HandleRef self) { - return self.ToAndroidJavaObject().Call("signInSilently").GetRawObject(); + return GoogleSignInHelper.CallStatic("signInSilently").GetRawObject(); } static void GoogleSignIn_Signout(HandleRef self) @@ -175,18 +175,18 @@ static void GoogleSignIn_Signout(HandleRef self) authorizationResult?.Dispose(); authorizationResult = null; - self.ToAndroidJavaObject().Call("signOut"); + GoogleSignInHelper.CallStatic("signOut"); } static void GoogleSignIn_Disconnect(HandleRef self) => throw new NotImplementedException(); - internal static void GoogleSignIn_DisposeFuture(HandleRef self) => self.ToAndroidJavaObject()?.Call("cancel"); + internal static void GoogleSignIn_DisposeFuture(HandleRef self) => GoogleSignInHelper.CallStatic("cancel"); - internal static bool GoogleSignIn_Pending(HandleRef self) => self.ToAndroidJavaObject()?.Call("isPending") ?? false; + internal static bool GoogleSignIn_Pending(HandleRef self) => GoogleSignInHelper.CallStatic("isPending"); - internal static IntPtr GoogleSignIn_Result(HandleRef self) => self.Handle; + internal static IntPtr GoogleSignIn_Result(HandleRef self) => googleIdTokenCredential.GetRawObject(); - internal static int GoogleSignIn_Status(HandleRef self) => self.ToAndroidJavaObject()?.Call("getStatus") ?? 6; + internal static int GoogleSignIn_Status(HandleRef self) => GoogleSignInHelper.CallStatic("getStatus"); internal static string GoogleSignIn_GetServerAuthCode(HandleRef self) => authorizationResult?.Call("getServerAuthCode"); diff --git a/Plugins/Android/src/main/java/com/google/googlesignin/GoogleSignInHelper.java b/Plugins/Android/src/main/java/com/google/googlesignin/GoogleSignInHelper.java index c00ead54..e93075f0 100644 --- a/Plugins/Android/src/main/java/com/google/googlesignin/GoogleSignInHelper.java +++ b/Plugins/Android/src/main/java/com/google/googlesignin/GoogleSignInHelper.java @@ -15,8 +15,6 @@ */ package com.google.googlesignin; -import android.app.Activity; -import android.os.Bundle; import android.os.CancellationSignal; import android.util.Log; @@ -37,10 +35,8 @@ import com.google.android.gms.common.api.CommonStatusCodes; import com.google.android.gms.common.api.Scope; import com.google.android.gms.common.util.Strings; -import com.google.android.gms.tasks.CancellationToken; import com.google.android.gms.tasks.OnCompleteListener; import com.google.android.gms.tasks.OnSuccessListener; -import com.google.android.gms.tasks.OnTokenCanceledListener; import com.google.android.gms.tasks.SuccessContinuation; import com.google.android.gms.tasks.Task; import com.google.android.gms.tasks.TaskCompletionSource; @@ -73,14 +69,14 @@ public static void enableDebugLogging(boolean flag) { loggingEnabled = flag; } - private CancellationSignal cancellationSignal; - private Task task; - private Function> signInFunction; - public boolean isPending() { + private static CancellationSignal cancellationSignal; + private static Task task; + private static Function> signInFunction; + public static boolean isPending() { return task != null && !task.isComplete() && !task.isCanceled(); } - public int getStatus() { + public static int getStatus() { if(signInFunction == null) return CommonStatusCodes.DEVELOPER_ERROR; @@ -125,7 +121,7 @@ public int getStatus() { * C++ code, this is used * to correlate the response with the request. */ - public void configure( + public static void configure( boolean useGamesConfig, String webClientId, boolean requestAuthCode, @@ -208,7 +204,7 @@ public Task then(GetCredentialResponse getCredentialRespons authorizationRequestBuilder.requestOfflineAccess(webClientId, forceRefreshToken); int additionalCount = additionalScopes != null ? additionalScopes.length : 0; - List scopes = new ArrayList<>(3 + additionalCount); + List scopes = new ArrayList<>(2 + additionalCount); scopes.add(new Scope(Scopes.PROFILE)); if (requestEmail) scopes.add(new Scope(Scopes.EMAIL)); @@ -238,17 +234,17 @@ public void onComplete(@NonNull Task _unused) { }; } - public GoogleSignInHelper signIn() { + public static Task signIn() { task = signInFunction.apply(false); - return this; + return task; } - public GoogleSignInHelper signInSilently() { + public static Task signInSilently() { task = signInFunction.apply(true); - return this; + return task; } - public void cancel() { + public static void cancel() { if(isPending() && cancellationSignal != null){ cancellationSignal.cancel(); cancellationSignal = null; @@ -257,7 +253,7 @@ public void cancel() { task = null; } - public void signOut() { + public static void signOut() { cancel(); CredentialManager.create(UnityPlayer.currentActivity).clearCredentialStateAsync(new ClearCredentialStateRequest(), From d4752b8c6ed1e71f20334704f1c77b8bc20a6a8d Mon Sep 17 00:00:00 2001 From: Thaina Date: Sat, 13 Jul 2024 23:15:51 +0700 Subject: [PATCH 22/25] Fix auto signin --- GoogleSignIn/Impl/GoogleSignInImplEditor.cs | 5 +++-- .../java/com/google/googlesignin/GoogleSignInHelper.java | 2 +- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/GoogleSignIn/Impl/GoogleSignInImplEditor.cs b/GoogleSignIn/Impl/GoogleSignInImplEditor.cs index e6cd8583..34ae913d 100644 --- a/GoogleSignIn/Impl/GoogleSignInImplEditor.cs +++ b/GoogleSignIn/Impl/GoogleSignInImplEditor.cs @@ -120,8 +120,9 @@ void SigningIn() context.Response.OutputStream.Write(Encoding.UTF8.GetBytes("Can close this page")); context.Response.Close(); - var result = await HttpWebRequest.CreateHttp("https://www.googleapis.com/oauth2/v4/token").Post("application/x-www-form-urlencoded","code=" + code + "&client_id=" + configuration.WebClientId + "&client_secret=" + configuration.ClientSecret + "&redirect_uri=" + httpListener.Prefixes.FirstOrDefault() + "&grant_type=authorization_code").ContinueWith((task) => task.Result,taskScheduler); - var jobj = JObject.Parse(result); + var jobj = await HttpWebRequest.CreateHttp("https://www.googleapis.com/oauth2/v4/token").Post("application/x-www-form-urlencoded","code=" + code + "&client_id=" + configuration.WebClientId + "&client_secret=" + configuration.ClientSecret + "&redirect_uri=" + httpListener.Prefixes.FirstOrDefault() + "&grant_type=authorization_code").ContinueWith((task) => { + return JObject.Parse(task.Result); + },taskScheduler); var accessToken = (string)jobj.GetValue("access_token"); var expiresIn = (int)jobj.GetValue("expires_in"); diff --git a/Plugins/Android/src/main/java/com/google/googlesignin/GoogleSignInHelper.java b/Plugins/Android/src/main/java/com/google/googlesignin/GoogleSignInHelper.java index e93075f0..35acfca8 100644 --- a/Plugins/Android/src/main/java/com/google/googlesignin/GoogleSignInHelper.java +++ b/Plugins/Android/src/main/java/com/google/googlesignin/GoogleSignInHelper.java @@ -150,7 +150,7 @@ public Task apply(@NonNull Boolean silent) { if(silent) { GetGoogleIdOption.Builder getGoogleIdOptionBuilder = new GetGoogleIdOption.Builder() - .setFilterByAuthorizedAccounts(false) + .setFilterByAuthorizedAccounts(hideUiPopups) .setAutoSelectEnabled(hideUiPopups); if(defaultAccountName != null) From f7eab29add46b9661af0553903bc4334f6e032db Mon Sep 17 00:00:00 2001 From: Thaina Date: Thu, 15 Aug 2024 09:16:31 +0700 Subject: [PATCH 23/25] Fix SignInSilentlyAsync --- GoogleSignIn/GoogleSignIn.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/GoogleSignIn/GoogleSignIn.cs b/GoogleSignIn/GoogleSignIn.cs index dd3e18b1..ed0a98cf 100644 --- a/GoogleSignIn/GoogleSignIn.cs +++ b/GoogleSignIn/GoogleSignIn.cs @@ -140,7 +140,7 @@ public Task SignInSilently() { public Task SignInSilentlyAsync() { var tcs = new TaskCompletionSource(); - impl.SignIn().WaitForResultAsync(tcs).ContinueWith((task) => {}); + impl.SignInSilently().WaitForResultAsync(tcs).ContinueWith((task) => {}); return tcs.Task; } From cdb93a3e74fcc39603269c1d84cc4c208c022248 Mon Sep 17 00:00:00 2001 From: Thaina Date: Thu, 15 Aug 2024 23:39:43 +0700 Subject: [PATCH 24/25] add log with INTERNAL_ERROR --- .../main/java/com/google/googlesignin/GoogleSignInHelper.java | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Plugins/Android/src/main/java/com/google/googlesignin/GoogleSignInHelper.java b/Plugins/Android/src/main/java/com/google/googlesignin/GoogleSignInHelper.java index 35acfca8..1f12d2ea 100644 --- a/Plugins/Android/src/main/java/com/google/googlesignin/GoogleSignInHelper.java +++ b/Plugins/Android/src/main/java/com/google/googlesignin/GoogleSignInHelper.java @@ -91,7 +91,10 @@ public static int getStatus() { Exception e = task.getException(); if(e != null) + { + logError("onFailure with INTERNAL_ERROR : " + e.getClass().toString() + " " + e.getMessage()); return CommonStatusCodes.INTERNAL_ERROR; + } return CommonStatusCodes.ERROR; } From b2eeeea13087a4993d12d7114f47c75631935234 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Harun=20Ayy=C4=B1ld=C4=B1z?= Date: Fri, 27 Sep 2024 15:42:39 +0300 Subject: [PATCH 25/25] Replace URL-safe characters and fix padding --- GoogleSignIn/Impl/GoogleSignInImpl.cs | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/GoogleSignIn/Impl/GoogleSignInImpl.cs b/GoogleSignIn/Impl/GoogleSignInImpl.cs index b135b972..3f21136c 100644 --- a/GoogleSignIn/Impl/GoogleSignInImpl.cs +++ b/GoogleSignIn/Impl/GoogleSignInImpl.cs @@ -192,18 +192,25 @@ static void GoogleSignIn_Signout(HandleRef self) internal static string GoogleSignIn_GetUserId(HandleRef self) { + string idTokenFull = null; try { - var idTokenPart = googleIdTokenCredential?.Call("getIdToken")?.Split('.')?.ElementAtOrDefault(1); + idTokenFull = googleIdTokenCredential?.Call("getIdToken"); + var idTokenPart = idTokenFull?.Split('.')?.ElementAtOrDefault(1); if(!(idTokenPart?.Length is int length && length > 1)) return null; + // Replace URL-safe characters and fix padding + idTokenPart = idTokenPart.Replace('-', '+').Replace('_', '/'); string fill = new string('=',(4 - (idTokenPart.Length % 4)) % 4); - var jobj = Newtonsoft.Json.Linq.JObject.Parse(Encoding.UTF8.GetString(Convert.FromBase64String(idTokenPart + fill))); + var idTokenFromBase64 = Convert.FromBase64String(idTokenPart + fill); + var idToken = Encoding.UTF8.GetString(idTokenFromBase64); + var jobj = Newtonsoft.Json.Linq.JObject.Parse(idToken); return jobj?["sub"]?.ToString(); } catch(Exception e) { + // Debug.LogException(new Exception($"GoogleSignIn_GetUserId.idTokenFull {idTokenFull}")); Debug.LogException(e); return null; }