├── .gitignore ├── License.md ├── README.md ├── SCsub ├── android_src ├── AdMob.java ├── Analytics.java ├── AndroidManifestChunk.xml ├── AndroidPermissionsChunk.xml ├── FireBase.java ├── Firestore.java ├── MessagingService.java ├── Notification.java ├── NotifyInTime.java ├── RemoteConfig.java ├── Share.java ├── auth │ ├── AnonymousAuth.java │ ├── Auth.java │ ├── EmailAndPassword.java │ ├── FacebookSignIn.java │ ├── GoogleSignIn.java │ └── TwitterSignIn.java └── storage │ ├── BaseTaskService.java │ ├── DownloadService.java │ ├── Storage.java │ └── UploadService.java ├── colors.py ├── config.fsql ├── config.py ├── config.pyc ├── frogutils └── Utils.java ├── helper.py └── res ├── drawable-hdpi ├── firebase_lockup_400.png ├── ic_check_white_24.png ├── ic_error_white_24dp.png └── ic_file_upload_white_24dp.png ├── drawable-mdpi └── notification_small_icon.png ├── values ├── colors.xml ├── ids.xml └── strings.xml └── xml └── remote_config_defaults.xml /.gitignore: -------------------------------------------------------------------------------- 1 | android/* 2 | *.pyc 3 | -------------------------------------------------------------------------------- /License.md: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "{}" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright {yyyy} {name of copyright owner} 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # GodotFireBase 2 | 3 | GodotFireBase is a Firebase integration module for Godot Android. 4 | 5 | ### Project has been moved to newer repo [GDFirebase](https://github.com/FrogSquare/GDFirebase) 6 | 7 | [![Platform](https://img.shields.io/badge/Platform-Android-green.svg)](https://github.com/FrogSquare/GodotFireBase) 8 | [![GodotEngine](https://img.shields.io/badge/Godot_Engine-2.X%20/%203.X-blue.svg)](https://github.com/godotengine/godot) 9 | [![LICENCE](https://img.shields.io/badge/License-Apache_V2-blue.svg)](https://www.apache.org/licenses/LICENSE-2.0) 10 | [![PATREON](https://img.shields.io/badge/Patreon-support-yellow.svg)](https://www.patreon.com/bePatron?u=5130479) 11 | 12 | # Depends on 13 | 14 | > Godot game engine: `git clone https://github.com/godotengine/godot` 15 | 16 | > GodotSQL: `git clone https://github.com/FrogSquare/GodotSQL` 17 | 18 | # Available Features 19 | 20 | > AdMob 21 | 22 | > Analytics 23 | 24 | > Authentication [W.I.P] Google, Facebook, Twitter 25 | 26 | > Firebase Notification 27 | 28 | > RemoteConfig 29 | 30 | > Storage 31 | 32 | > Firestore (W.I.P) 33 | 34 | # Ready your project 35 | * open `/platform/android/java/gradle.properties` and add the following line 36 | ``` 37 | android.useAndroidX=true 38 | android.enableJetifier=true 39 | ``` 40 | 41 | # Build/Compile module 42 | 43 | * Copy your `google-services.json` file to `[GODOT-ROOT]/platform/android/java/` 44 | * Edit file modules/FireBase/config.py at line 11 45 | 46 | ``` 47 | p_app_id = "com.your.appid" # config.py L:11 48 | ``` 49 | 50 | * Replace `com.your.appid` with you android application id. 51 | 52 | * To build Admob you need to set your AdMob Application ID in the `AndroidManifestChunk.xml` file. To do this, edit the file `android_src/AndroidManifestChunk.xml`. Navigate to the end of the file. Replace the **value** for APPLICATION_ID with your real application ID. 53 | 54 | 55 | *For customizing the module go [here](https://github.com/FrogSquare/GodotFireBase/wiki/Customize-GodotFireBase)* 56 | 57 | # FAQ 58 | 59 | **Should I rename the android_src folder after customization?** 60 | 61 | > No, After customization the folder used by the module will be `android`, And `android_src` folder will be a backup for future customization. 62 | 63 | # Initialize FireBase 64 | 65 | Edit engine.cfg and add 66 | 67 | ``` 68 | [android] 69 | modules="org/godotengine/godot/FireBase,org/godotengine/godot/SQLBridge" 70 | ``` 71 | 72 | RemoteConfigs default parameters `.xml` file is at `[GODOT-ROOT]/modules/FireBase/res/xml/remote_config_defaults.xml` 73 | 74 | # GDScript - getting module singleton and initializing; 75 | 76 | ### On 2.X 77 | 78 | ``` 79 | var firebase = Globals.get_singleton("FireBase"); 80 | ``` 81 | 82 | ### On 3.X (latest from git) 83 | 84 | ``` 85 | var firebase = Engine.get_singleton("FireBase"); 86 | ``` 87 | 88 | For Analytics only `firebase.init("", get_instance_ID())` or to user RemoteConfig or Notifications (subscribing to topic) 89 | 90 | # GodotFireBase: copy `godot-firebase-config.json` to your projects root directord. 91 | GodotFireBase config file, By default every feature is disabled. 92 | 93 | ``` 94 | { 95 | "AdMob" : true, 96 | "Authentication" : true, 97 | "RemoteConfig" : true, 98 | "Notification" : true, 99 | "Storage" : true, 100 | "Firestore" : true, 101 | 102 | "AuthConf" : 103 | { 104 | "Google" : true, 105 | "Twitter" : true, 106 | "Facebook" : true, 107 | "FacebookAppId" : "1234566789875" 108 | }, 109 | 110 | "Ads" : 111 | { 112 | "AppId": "YOUR_APP_ID_HERE", 113 | "BannerAd" : true, 114 | "BannerGravity" : "BOTTOM", 115 | "BannerAdId" : "", 116 | 117 | "InterstitialAd" : true, 118 | "InterstitialAdId" : "", 119 | 120 | "RewardedVideoAd" : true, 121 | "RewardedVideoAdId" : "", 122 | 123 | "TestAds" : false 124 | } 125 | } 126 | ``` 127 | 128 | And initialize firebase with file path, `RewardedVideoAdId` is a string array i.e `"string1,string2"` 129 | 130 | ``` 131 | func _ready(): 132 | if OS.get_name() == "Android": 133 | firebase.initWithFile("res://godot-firebase-config.json", get_instance_ID()) 134 | 135 | func _receive_message(tag, from, key, data): 136 | if tag == "FrogSquare": 137 | print("From: ", from, " Key: ", key, " Data: ", data) 138 | ``` 139 | 140 | # Using FireBase Analytics 141 | 142 | ``` 143 | firebase.send_events("EventName", Dictionary) 144 | firebase.send_custom("TestKey", "SomeValue") 145 | 146 | firebase.setScreenName("Screen_name") 147 | firebase.sendAchievement("someAchievementId") # unlock achievement 148 | firebase.join_group("clan_name") # join clan/group 149 | firebase.level_up("character_name", level) # send character level 150 | firebase.post_score("charcter name", level, score) # post your score 151 | firebase.earn_currency("currency", amount); # when play earn some virtual currency gold/Diamond/any 152 | firebase.spend_currency("item_id", "currency", amount) # when user spend virtual currency 153 | 154 | firebase.tutorial_begin() # tutorial begin 155 | firebase.tutorial_complete() # tutorial end 156 | 157 | Reference: https://support.google.com/firebase/answer/6317494?hl=en 158 | ``` 159 | 160 | # AlertDialog aditional 161 | 162 | ``` 163 | firebase.alert("Message goes here..!") # Show a simple AlertDialog 164 | firebase.set_debug(true) # Enable/Disable `GodotFireBase` debug messages 165 | ``` 166 | 167 | # Authentication 168 | 169 | For Facebook edit `res/values/ids.xml` and replace facebook_app_id with your Facebook App Id 170 | 171 | ``` 172 | firebase.authConfig("'Google':true,'Facebook':true") # Configure Auth service 173 | 174 | firebase.get_id_token() 175 | 176 | firebase.google_sign_in() # Firebase connect to google. 177 | firebase.facebook_sign_in() # Firebase connect to facebook. 178 | firebase.twitter_sign_in() # Firebase connect to twitter. 179 | firebase.anonymous_sign_in() # Firebase connect anonymously. 180 | 181 | firebase.google_sign_out() # Firebase disconnect from google. 182 | firebase.facebook_sign_out() # Firebase disconnect from facebook. 183 | firebase.twitter_sign_out() # Firebase disconnect from twitter. 184 | firebase.anonymous_sign_out() # Firebase disconnect anonymously. 185 | 186 | var gUserDetails = firebase.get_google_user() # returns name, email_id, photo_uri 187 | var fbUserDetails = firebase.get_facebook_user() # returns name, email_id, photo_uri 188 | 189 | firebase.google_revoke_access() 190 | firebase.facebook_revoke_access() 191 | 192 | firebase.is_google_connected() # bool check for google authentication (google) 193 | firebase.is_facebook_connected() # bool check for facebook authentication (facebook) 194 | firebase.is_anonymous_connected() # bool check for facebook authentication (anonymous) 195 | ``` 196 | 197 | More for facebook permissions 198 | 199 | ``` 200 | firebase.facebook_has_permission("publish_actions") # Check for availabe permission 201 | 202 | firebase.revoke_facebook_permission("publish_actions") # revoke permission 203 | 204 | firebase.ask_facebook_publish_permission("publish_actions"); # asking write permission 205 | 206 | firebase.ask_facebook_read_permission("email"); # asking read only permission 207 | 208 | firbase.get_facebook_permissions() # getting available permissions 209 | ``` 210 | 211 | Recive message from java 212 | 213 | ``` 214 | func _receive_message(tag, from, key, data): 215 | if tag == "FrogSquare": 216 | if from == "Auth": 217 | if key == "GoogleLogin" && data == "true": print("User Signed in.") 218 | if key == "FacebookLogin" && data == "true": print("User Signed in.") 219 | ``` 220 | 221 | # Firebase Notification API 222 | 223 | ``` 224 | firebase.subscribeToTopic("topic") # Subscribe to particular topic. 225 | firebase.getToken() # Get current client TokenID 226 | 227 | If recived notifiction has a payload, it will be saved inside SQL Database under key: "firebase_notification_data" 228 | 229 | firebase.notifyInMins("message", 60) # Shedule notification in 60 min 230 | firebase.notifyInSecs("message", 3200) # Shedule notification in 3200 seconds 231 | 232 | var dict = {} 233 | dict["title"] = "Notification title" 234 | dict["message"] = "This is a text message" 235 | dict["image_uri"] = "res://big_image_in_notification_body.png" 236 | dict["type"] = "text" 237 | 238 | firebase.notifyOnComplete(dict, 3200) # Shedule notification in 3200 seconds 239 | ``` 240 | 241 | # RemoteConfig API 242 | 243 | ``` 244 | firebase.getRemoteValue("remote_key") # Return String value 245 | ``` 246 | 247 | # Settings RemoteConfig default values 248 | 249 | ``` 250 | var defs = Dictionary() 251 | defs["some_remoteconfig_key1"] = "remote_config_value1" 252 | defs["some_remoteconfig_key2"] = "remote_config_value2" 253 | 254 | firebase.setRemoteDefaults(defs.to_json()) 255 | ``` 256 | 257 | OR load from json file 258 | 259 | ``` 260 | firebase.setRemoteDefaultsFile("res://path/to/jsonfile.json") 261 | ``` 262 | 263 | # Firebase Storage 264 | 265 | ``` 266 | # Upload Files from sdcard 267 | firebase.upload("images/file", "destFolder") # uploads file from sdcard to firebase 268 | 269 | # Download Files from Firebase 270 | firebase.download("file", "images") # Saves file from firebase to sdcard 271 | ``` 272 | 273 | # Firebase AdMob 274 | 275 | ``` 276 | firebase.is_banner_loaded() # Returns `true` if banner is loaded 277 | firebase.is_interstitial_loaded() # Returns `true` if interstitial is loaded 278 | 279 | firebase.show_banner_ad(true) # Show Banner Ad 280 | firebase.show_banner_ad(false) # Hide Banner Ad 281 | firebase.set_banner_unitid("unit_id") # Change current Ad unit ID 282 | 283 | firebase.show_interstitial_ad() # Show Interstitial Ad 284 | firebase.show_rewarded_video() # Show Rewarded Video Ad 285 | firebase.show_rvideo("unit_id") # Show Rewarded Video Ad 286 | 287 | firebase.request_rewarded_video_status() # Request the rewarded video status 288 | ``` 289 | 290 | AdMob Recive message from java 291 | 292 | ``` 293 | func _receive_message(tag, from, key, data): 294 | if tag == "FrogSquare" and from == "AdMob": 295 | if key == "AdMobReward": 296 | # when rewared video play complete 297 | print("json data with [RewardType & RewardAmount]: ", data); 298 | 299 | elif key == "AdMob_Video": 300 | # when rewarded video loaded 301 | # data will be `loaded` or `load_failed and `loaded` or `not_loaded` with `firebase.request_rewarded_video_status()` 302 | print("AdMob rewarded video status is ", data); 303 | 304 | elif key == "AdMob_Banner": 305 | # when banner loaded 306 | # data will be `loaded` or `load_failed` 307 | print("Banner Status: ", data); 308 | 309 | elif key == "AdMob_Interstitial" and data == "loaded": 310 | # when Interstitial loaded 311 | # data will be `loaded` or `load_failed` 312 | print("Interstitial Status: ", data); 313 | ``` 314 | 315 | # Firebase Firestore 316 | 317 | ``` 318 | firebase.add_document("collection_name", dict) # Auto created new Document under collection_name 319 | firebase.set_document("collection_name", "document_name", data) # Set document data, Data's are merged by default 320 | firebase.load_document("collection_name") # load or retrive from the server, 321 | 322 | # Note: documents will be sent to the `_receive_message` function as json 323 | ``` 324 | 325 | # Sharing 326 | ``` 327 | # Simple text based sharing. Include links if needed. 'Subject' can be null or empty. 328 | firebase.share("Message", "Subject") 329 | ``` 330 | 331 | # Note 332 | 333 | While exporting, don't forget to add `*.json` under Resources tab, 334 | ![alt text](http://preview.ibb.co/fTwC8Q/Screenshot_from_2017_06_17_18_44_25.png) 335 | 336 | # Log Event 337 | 338 | ``` 339 | adb -d logcat godot:V FrogSquare:V DEBUG:V AndroidRuntime:V ValidateServiceOp:V *:S 340 | ``` 341 | -------------------------------------------------------------------------------- /SCsub: -------------------------------------------------------------------------------- 1 | #SCsub 2 | 3 | Import('env') 4 | 5 | module_env = env.Clone() 6 | module_env.add_source_files(env.modules_sources, "*.cpp") 7 | module_env.add_source_files(env.modules_sources, "src/*.cpp") 8 | module_env.Append(CXXFLAGS=['-O2', '-std=c++11']) 9 | module_env.Append(CPPPATH=['#', '.', 'src']) 10 | 11 | -------------------------------------------------------------------------------- /android_src/AdMob.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2017 FrogSquare. All Rights Reserved. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | **/ 16 | 17 | package org.godotengine.godot; 18 | 19 | import android.app.Activity; 20 | import android.content.Context; 21 | import android.content.Intent; 22 | import android.graphics.Color; 23 | import android.net.Uri; 24 | import android.os.Bundle; 25 | import android.util.Log; 26 | import android.view.Gravity; 27 | import android.view.View; 28 | import android.view.ViewGroup.LayoutParams; 29 | import android.widget.FrameLayout; 30 | import androidx.annotation.NonNull; 31 | 32 | import com.google.android.gms.ads.AdListener; 33 | import com.google.android.gms.ads.AdRequest; 34 | import com.google.android.gms.ads.AdView; 35 | import com.google.android.gms.ads.AdSize; 36 | import com.google.android.gms.ads.MobileAds; 37 | import com.google.android.gms.ads.InterstitialAd; 38 | import com.google.android.gms.ads.reward.RewardedVideoAd; 39 | import com.google.android.gms.ads.rewarded.RewardedAdCallback; 40 | import com.google.android.gms.ads.rewarded.RewardedAdLoadCallback; 41 | import com.google.android.gms.ads.rewarded.RewardItem; 42 | import com.google.android.gms.ads.rewarded.RewardedAd; 43 | 44 | import com.google.firebase.FirebaseApp; 45 | 46 | import com.godot.game.BuildConfig; 47 | import com.godot.game.R; 48 | 49 | import org.godotengine.godot.Godot; 50 | import org.godotengine.godot.Utils; 51 | import org.godotengine.godot.Dictionary; 52 | 53 | import org.json.JSONObject; 54 | import org.json.JSONException; 55 | 56 | import java.util.HashMap; 57 | import java.util.Map; 58 | import java.util.ArrayList; 59 | import java.util.List; 60 | import java.util.Arrays; 61 | //import java.util.Dictionary; 62 | 63 | public class AdMob { 64 | 65 | public static AdMob getInstance (Activity p_activity) { 66 | if (mInstance == null) { 67 | mInstance = new AdMob(p_activity); 68 | } 69 | 70 | return mInstance; 71 | } 72 | 73 | public AdMob(Activity p_activity) { 74 | activity = p_activity; 75 | } 76 | 77 | public void init (FirebaseApp firebaseApp) { 78 | mFirebaseApp = firebaseApp; 79 | 80 | AdMobConfig = FireBase.getConfig().optJSONObject("Ads"); 81 | MobileAds.initialize(activity, AdMobConfig.optString("AppId")); 82 | 83 | if (AdMobConfig.optBoolean("BannerAd", false)) { createBanner(); } 84 | if (AdMobConfig.optBoolean("InterstitialAd", false)) { createInterstitial(); } 85 | if (AdMobConfig.optBoolean("RewardedVideoAd", false)) { 86 | String ad_unit_id = AdMobConfig.optString("RewardedVideoAdId", ""); 87 | List ad_units = new ArrayList(); 88 | 89 | if (ad_unit_id.length() <= 0) { 90 | Utils.d("GodotFireBase", "AdMob:RewardedVideo:UnitId:NotProvided:AddingDefault"); 91 | ad_units.add(activity.getString(R.string.rewarded_video_ad_unit_id)); 92 | } 93 | 94 | reward_ads = new HashMap(); 95 | ad_units = Arrays.asList(ad_unit_id.split(",")); 96 | for (String unit_id : ad_units) { 97 | reward_ads.put(unit_id, createRewardedVideo(unit_id)); 98 | } 99 | } 100 | 101 | mAdSize = new Dictionary(); 102 | mAdSize.put("width", 0); 103 | mAdSize.put("height", 0); 104 | 105 | onStart(); 106 | } 107 | 108 | public Dictionary getBannerSize() { 109 | if ((int)mAdSize.get("width") == 0 || (int)mAdSize.get("height") == 0) { 110 | Utils.d("GodotFireBase", "AdView::Not::Loaded::Yet"); 111 | } 112 | 113 | return mAdSize; 114 | } 115 | 116 | public void setBannerUnitId(final String id) { 117 | createBanner(id); 118 | } 119 | 120 | public void createBanner() { 121 | if (AdMobConfig == null) { return; } 122 | 123 | String ad_unit_id = AdMobConfig.optString("BannerAdId", ""); 124 | 125 | if (ad_unit_id.length() <= 0) { 126 | Utils.d("GodotFireBase", "AdMob:Banner:UnitId:NotProvided:AddingDefault"); 127 | ad_unit_id = activity.getString(R.string.banner_ad_unit_id); 128 | } 129 | 130 | createBanner(ad_unit_id); 131 | } 132 | 133 | public void createBanner(final String ad_unit_id) { 134 | mAdViewLoaded = false; 135 | 136 | FrameLayout layout = ((Godot)activity).layout; // Getting Godots framelayout 137 | FrameLayout.LayoutParams AdParams = new FrameLayout.LayoutParams( 138 | FrameLayout.LayoutParams.MATCH_PARENT, 139 | FrameLayout.LayoutParams.WRAP_CONTENT); 140 | 141 | if(mAdView != null) { layout.removeView(mAdView); } 142 | 143 | if (AdMobConfig.optString("BannerGravity", "BOTTOM").equals("BOTTOM")) { 144 | AdParams.gravity = Gravity.BOTTOM; 145 | } else { AdParams.gravity = Gravity.TOP; } 146 | 147 | AdRequest.Builder adRequestB = new AdRequest.Builder(); 148 | adRequestB.tagForChildDirectedTreatment(true); 149 | 150 | if (BuildConfig.DEBUG || AdMobConfig.optBoolean("TestAds", false)) { 151 | adRequestB.addTestDevice(AdRequest.DEVICE_ID_EMULATOR); 152 | adRequestB.addTestDevice(AdMobConfig.optString("TestDevice", Utils.getDeviceId(activity))); 153 | } 154 | 155 | AdRequest adRequest = adRequestB.build(); 156 | 157 | mAdView = new AdView(activity); 158 | mAdView.setBackgroundColor(Color.TRANSPARENT); 159 | mAdView.setAdUnitId(ad_unit_id); 160 | mAdView.setAdSize(AdSize.SMART_BANNER); 161 | 162 | mAdView.setAdListener(new AdListener() { 163 | @Override 164 | public void onAdLoaded() { 165 | Utils.d("GodotFireBase", "AdMob:Banner:OnAdLoaded"); 166 | AdSize adSize = mAdView.getAdSize(); 167 | mAdViewLoaded = true; 168 | 169 | mAdSize.put("width", adSize.getWidthInPixels(activity)); 170 | mAdSize.put("height", adSize.getHeightInPixels(activity)); 171 | 172 | Utils.callScriptFunc("AdMob", "AdMob_Banner", "loaded"); 173 | } 174 | 175 | @Override 176 | public void onAdFailedToLoad(int errorCode) { 177 | Utils.w("GodotFireBase", "AdMob:Banner:onAdFailedToLoad:ErrorCode:" + errorCode); 178 | Utils.callScriptFunc("AdMob", "AdMob_Banner", "load_failed"); 179 | } 180 | }); 181 | 182 | mAdView.setVisibility(View.INVISIBLE); 183 | mAdView.loadAd(adRequest); 184 | 185 | layout.addView(mAdView, AdParams); 186 | } 187 | 188 | public void createInterstitial() { 189 | if (AdMobConfig == null) { return; } 190 | 191 | String ad_unit_id = AdMobConfig.optString("InterstitialAdId", ""); 192 | 193 | if (ad_unit_id.length() <= 0) { 194 | Utils.d("GodotFireBase", "AdMob:Interstitial:UnitId:NotProvided:AddingDefault"); 195 | ad_unit_id = activity.getString(R.string.interstitial_ad_unit_id); 196 | } 197 | 198 | mInterstitialAd = new InterstitialAd(activity); 199 | mInterstitialAd.setAdUnitId(ad_unit_id); 200 | mInterstitialAd.setAdListener(new AdListener() { 201 | @Override 202 | public void onAdLoaded() { 203 | Utils.d("GodotFireBase", "AdMob:Interstitial:OnAdLoaded"); 204 | Utils.callScriptFunc("AdMob", "AdMob_Interstitial", "loaded"); 205 | } 206 | 207 | @Override 208 | public void onAdFailedToLoad(int errorCode) { 209 | Utils.w("GodotFireBase", "AdMob:Interstitial:onAdFailedToLoad:" + errorCode); 210 | Utils.callScriptFunc("AdMob", "AdMob_Interstitial", "load_failed"); 211 | } 212 | 213 | @Override 214 | public void onAdClosed() { 215 | Utils.w("GodotFireBase", "AdMob:Interstitial:onAdClosed"); 216 | Utils.callScriptFunc("AdMob", "AdMob_Interstitial", "closed"); 217 | requestNewInterstitial(); 218 | } 219 | }); 220 | 221 | requestNewInterstitial(); 222 | } 223 | 224 | public void emitRewardedVideoStatus() { 225 | for (String unit_id : reward_ads.keySet()) { 226 | 227 | Utils.callScriptFunc("AdMob", "AdMob_Video", 228 | buildStatus(unit_id, reward_ads.get(unit_id).isLoaded() ? "loaded" : "not_loaded")); 229 | } 230 | } 231 | 232 | public Dictionary buildStatus(String unitid, String status) { 233 | Dictionary dict = new Dictionary(); 234 | dict.put("unit_id", unitid); 235 | dict.put("status", status); 236 | 237 | return dict; 238 | } 239 | 240 | public RewardedAd createRewardedVideo(final String unitid) { 241 | RewardedAd rewardedAd = new RewardedAd(activity, unitid); 242 | requestNewRewardedVideo(rewardedAd, unitid); 243 | return rewardedAd; 244 | } 245 | 246 | public boolean isBannerLoaded() { 247 | return mAdViewLoaded; 248 | } 249 | 250 | public boolean isInterstitialLoaded() { 251 | if (mInterstitialAd != null) { 252 | return mInterstitialAd.isLoaded(); 253 | } 254 | 255 | Utils.d("GodotFireBase", "Interstitial:NotInitialized"); 256 | return false; 257 | } 258 | 259 | public boolean isRewardedAdLoaded(final String unit_id) { 260 | if (!isInitialized() || reward_ads == null) { 261 | return false; 262 | } 263 | 264 | return reward_ads.get(unit_id).isLoaded(); 265 | } 266 | 267 | public void requestRewardedVideoStatus() { 268 | emitRewardedVideoStatus(); 269 | } 270 | 271 | public void show_rewarded_video() { 272 | if (!isInitialized() || reward_ads == null) { 273 | Utils.d("GodotFireBase", "AdMob:RewardedVideo:NotConfigured[ reward_ad instance is null ]"); 274 | return; 275 | } 276 | 277 | show_rewarded_video((String)reward_ads.keySet().toArray()[0]); 278 | } 279 | 280 | public void show_rewarded_video(final String unit_id) { 281 | if (!isInitialized() || reward_ads == null) { 282 | Utils.d("GodotFireBase", "AdMob:RewardedVideo:NotConfigured[ reward_ad instance is null ]"); 283 | return; 284 | } 285 | 286 | RewardedAdCallback adCallback = new RewardedAdCallback() { 287 | @Override 288 | public void onUserEarnedReward(@NonNull RewardItem reward) { 289 | Utils.d("GodotFireBase", "AdMob:Rewarded:Success"); 290 | 291 | Dictionary ret = new Dictionary(); 292 | ret.put("RewardType", reward.getType()); 293 | ret.put("RewardAmount", reward.getAmount()); 294 | ret.put("unit_id", unit_id); 295 | 296 | Utils.callScriptFunc("AdMob", "AdMobReward", ret); 297 | reloadRewardedVideo(unit_id); 298 | } 299 | 300 | @Override 301 | public void onRewardedAdClosed() { 302 | Utils.d("GodotFireBase", "AdMob:VideoAd:Closed"); 303 | Utils.callScriptFunc("AdMob", "AdMob_Video", buildStatus(unit_id, "closed")); 304 | reloadRewardedVideo(unit_id); 305 | } 306 | 307 | @Override 308 | public void onRewardedAdOpened() { 309 | Utils.d("GodotFireBase", "AdMob:VideoAd:Opended"); 310 | } 311 | 312 | @Override 313 | public void onRewardedAdFailedToShow(int errorCode) { 314 | Utils.d("GodotFireBase", "Reward:VideoAd:FailedToShow"); 315 | } 316 | }; 317 | 318 | rewarded_meta_data.put("unit_id", unit_id); 319 | RewardedAd reward_ad = reward_ads.get(unit_id); 320 | if (reward_ad.isLoaded()) { reward_ad.show(activity, adCallback); } 321 | else { Utils.d("GodotFireBase", "AdMob:RewardedVideo:NotLoaded"); } 322 | } 323 | 324 | public void show_banner_ad(final boolean show) { 325 | if (!isInitialized() || mAdView == null) { return; } 326 | 327 | // Show Ad Banner here 328 | 329 | if (show) { 330 | if (mAdView.isEnabled()) { mAdView.setEnabled(true); } 331 | if (mAdView.getVisibility() == View.INVISIBLE) { 332 | Utils.d("GodotFireBase", "AdMob:Visiblity:On"); 333 | mAdView.setVisibility(View.VISIBLE); 334 | } 335 | } else { 336 | if (mAdView.isEnabled()) { mAdView.setEnabled(false); } 337 | if (mAdView.getVisibility() != View.INVISIBLE) { 338 | Utils.d("GodotFireBase", "AdMob:Visiblity:Off"); 339 | mAdView.setVisibility(View.INVISIBLE); 340 | } 341 | } 342 | } 343 | 344 | public void show_interstitial_ad() { 345 | if (!isInitialized() || mInterstitialAd == null) { return; } 346 | 347 | // Show interstitial ad 348 | 349 | if (mInterstitialAd.isLoaded()) { mInterstitialAd.show(); } 350 | else { Utils.d("GodotFireBase", "AdMob:Interstitial:NotLoaded"); } 351 | } 352 | 353 | public void reloadRewardedVideo(final String unitid) { 354 | if (reward_ads == null) { 355 | return; 356 | } 357 | 358 | if (reload_count <= 3) { 359 | Utils.d("GodotFireBase", "AdMob:RewardedVideo:Reloading_RewardedVideo_Request"); 360 | 361 | RewardedAd reward_ad = reward_ads.get(unitid); 362 | requestNewRewardedVideo(reward_ad, unitid); 363 | 364 | reload_count += 1; 365 | } 366 | } 367 | 368 | private void requestNewRewardedVideo(RewardedAd mrv, final String unitid) { 369 | Utils.d("GodotFireBase", "AdMob:Loading:RewardedAd:For: " + unitid); 370 | 371 | mAdRewardLoaded = false; 372 | AdRequest.Builder adRB = new AdRequest.Builder(); 373 | 374 | if (BuildConfig.DEBUG || AdMobConfig.optBoolean("TestAds", false)) { 375 | adRB.addTestDevice(AdRequest.DEVICE_ID_EMULATOR); 376 | adRB.addTestDevice(AdMobConfig.optString("TestDevice", Utils.getDeviceId(activity))); 377 | } 378 | 379 | mrv.loadAd(adRB.build(), new RewardedAdLoadCallback() { 380 | @Override 381 | public void onRewardedAdLoaded() { 382 | Utils.d("GodotFireBase", "AdMob:Video:Loaded"); 383 | 384 | mAdRewardLoaded = true; 385 | Utils.callScriptFunc("AdMob", "AdMob_Video", buildStatus(unitid, "loaded")); 386 | } 387 | 388 | @Override 389 | public void onRewardedAdFailedToLoad(int errorCode) { 390 | Utils.d("GodotFireBase", "AdMob:VideoLoad:Failed"); 391 | Utils.callScriptFunc("AdMob", "AdMob_Video", buildStatus(unitid, "load_failed")); 392 | //reloadRewardedVideo(unitid); 393 | } 394 | }); 395 | } 396 | 397 | private void requestNewInterstitial() { 398 | AdRequest.Builder adRB = new AdRequest.Builder(); 399 | 400 | if (BuildConfig.DEBUG || AdMobConfig.optBoolean("TestAds", false)) { 401 | adRB.addTestDevice(AdRequest.DEVICE_ID_EMULATOR); 402 | adRB.addTestDevice(AdMobConfig.optString("TestDevice", Utils.getDeviceId(activity))); 403 | } 404 | 405 | AdRequest adRequest = adRB.build(); 406 | 407 | mInterstitialAd.loadAd(adRequest); 408 | } 409 | 410 | private boolean isInitialized() { 411 | if (mFirebaseApp == null) { 412 | Utils.d("GodotFireBase", "AdMob:NotInitialized."); 413 | return false; 414 | } else { 415 | return true; 416 | } 417 | } 418 | 419 | public void onStart() { 420 | reload_count = 0; 421 | rewarded_meta_data = new Dictionary(); 422 | } 423 | 424 | public void onPause() { 425 | if (mAdView != null) { mAdView.pause(); } 426 | //if (reward_ad != null) { reward_ad.pause(activity); } 427 | } 428 | 429 | public void onResume() { 430 | if (mAdView != null) { mAdView.resume(); } 431 | //if (reward_ad != null) { reward_ad.resume(activity); } 432 | } 433 | 434 | public void onStop() { 435 | reload_count = 0; 436 | 437 | if (mAdView != null) { mAdView.destroy(); } 438 | //if (reward_ad != null) { reward_ad.destroy(activity); } 439 | } 440 | 441 | private int reload_count = 0; 442 | 443 | private static Activity activity = null; 444 | private static AdMob mInstance = null; 445 | 446 | private boolean mAdRewardLoaded = false; 447 | private boolean mAdViewLoaded = false; 448 | private HashMap reward_ads = null; 449 | 450 | private AdView mAdView = null; 451 | private InterstitialAd mInterstitialAd = null; 452 | private Dictionary mAdSize = null; 453 | 454 | private FirebaseApp mFirebaseApp = null; 455 | 456 | private JSONObject AdMobConfig = null; 457 | 458 | static private Dictionary rewarded_meta_data = null; 459 | } 460 | -------------------------------------------------------------------------------- /android_src/Analytics.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2017 FrogSquare. All Rights Reserved. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | **/ 16 | 17 | package org.godotengine.godot; 18 | 19 | import android.app.Activity; 20 | import android.content.Context; 21 | import android.util.Log; 22 | import android.os.Bundle; 23 | 24 | import com.google.firebase.FirebaseApp; 25 | import com.google.firebase.analytics.FirebaseAnalytics; 26 | 27 | public class Analytics { 28 | 29 | public static Analytics getInstance(Activity p_activity) { 30 | if (mInstance == null) { 31 | synchronized (Analytics.class) { 32 | mInstance = new Analytics(p_activity); 33 | } 34 | } 35 | 36 | return mInstance; 37 | } 38 | 39 | public Analytics (Activity p_activity) { 40 | activity = p_activity; 41 | } 42 | 43 | public void init (FirebaseApp fireBaseApp) { 44 | mFirebaseApp = fireBaseApp; 45 | mFirebaseAnalytics = FirebaseAnalytics.getInstance(activity); 46 | 47 | Utils.d("GodotFireBase", "Firebase Analytics initialized..!"); 48 | } 49 | 50 | public void set_screen_name(final String s_name) { 51 | mFirebaseAnalytics = FirebaseAnalytics.getInstance(activity); 52 | mFirebaseAnalytics.setCurrentScreen(activity, s_name, null); 53 | 54 | Utils.d("GodotFireBase", "Setting current screen to: " + s_name); 55 | } 56 | 57 | public void send_achievement(final String id) { 58 | Bundle bundle = new Bundle(); 59 | bundle.putString(FirebaseAnalytics.Param.ACHIEVEMENT_ID, id); 60 | 61 | mFirebaseAnalytics = FirebaseAnalytics.getInstance(activity); 62 | mFirebaseAnalytics.logEvent(FirebaseAnalytics.Event.UNLOCK_ACHIEVEMENT, bundle); 63 | 64 | Utils.d("GodotFireBase", "Sending:AchievementUnlocked: " + id); 65 | } 66 | 67 | public void send_group(final String groupID) { 68 | Bundle bundle = new Bundle(); 69 | bundle.putString(FirebaseAnalytics.Param.GROUP_ID, groupID); 70 | 71 | mFirebaseAnalytics = FirebaseAnalytics.getInstance(activity); 72 | mFirebaseAnalytics.logEvent(FirebaseAnalytics.Event.JOIN_GROUP, bundle); 73 | 74 | Utils.d("GodotFireBase", "Sending:JoinGroup: " + groupID); 75 | } 76 | 77 | public void send_level_up(final String character, final int level) { 78 | Bundle bundle = new Bundle(); 79 | bundle.putString(FirebaseAnalytics.Param.CHARACTER, character); 80 | bundle.putInt(FirebaseAnalytics.Param.LEVEL, level); 81 | 82 | mFirebaseAnalytics = FirebaseAnalytics.getInstance(activity); 83 | mFirebaseAnalytics.logEvent(FirebaseAnalytics.Event.LEVEL_UP, bundle); 84 | 85 | Utils.d("GodotFireBase", "Sending:Character:LevelUp: {" + character + "|" + level + "}"); 86 | } 87 | 88 | public void send_score(final String character, final int level, final int score) { 89 | Bundle bundle = new Bundle(); 90 | bundle.putString(FirebaseAnalytics.Param.CHARACTER, character); 91 | bundle.putInt(FirebaseAnalytics.Param.LEVEL, level); 92 | bundle.putInt(FirebaseAnalytics.Param.SCORE, score); 93 | 94 | mFirebaseAnalytics = FirebaseAnalytics.getInstance(activity); 95 | mFirebaseAnalytics.logEvent(FirebaseAnalytics.Event.POST_SCORE, bundle); 96 | 97 | Utils.d("GodotFireBase", "Sending:Level:Score: {" + character + "|" + level + "|" + score + "}"); 98 | } 99 | 100 | public void send_content(final String content_type, final String item_id) { 101 | Bundle bundle = new Bundle(); 102 | bundle.putString(FirebaseAnalytics.Param.CONTENT_TYPE, content_type); 103 | bundle.putString(FirebaseAnalytics.Param.ITEM_ID, item_id); 104 | 105 | mFirebaseAnalytics = FirebaseAnalytics.getInstance(activity); 106 | mFirebaseAnalytics.logEvent(FirebaseAnalytics.Event.SELECT_CONTENT, bundle); 107 | 108 | Utils.d("GodotFireBase", "Sending:Content:Item: {" + content_type + "|" + item_id + "}"); 109 | } 110 | 111 | public void send_share() { 112 | // TODO 113 | 114 | //SHARE 115 | 116 | /** 117 | Bundle bundle = new Bundle(); 118 | bundle.putString(FirebaseAnalytics.Param.ACHIEVEMENT_ID, id); 119 | 120 | mFirebaseAnalytics = FirebaseAnalytics.getInstance(activity); 121 | mFirebaseAnalytics.logEvent(FirebaseAnalytics.Event.UNLOCK_ACHIEVEMENT, bundle); 122 | Utils.d("GodotFireBase", "Sending Achievement: " + id); 123 | **/ 124 | } 125 | 126 | public void earn_currency(final String currency_name, final int value) { 127 | Bundle bundle = new Bundle(); 128 | bundle.putString(FirebaseAnalytics.Param.VIRTUAL_CURRENCY_NAME, currency_name); 129 | bundle.putInt(FirebaseAnalytics.Param.VALUE, value); 130 | 131 | mFirebaseAnalytics = FirebaseAnalytics.getInstance(activity); 132 | mFirebaseAnalytics.logEvent(FirebaseAnalytics.Event.EARN_VIRTUAL_CURRENCY, bundle); 133 | 134 | Utils.d("GodotFireBase", "Sending:Currency:Earn: {" + currency_name + "|" + value + "}"); 135 | } 136 | 137 | public void spend_currency(final String item_name, final String currency_name, final int value) { 138 | Bundle bundle = new Bundle(); 139 | bundle.putString(FirebaseAnalytics.Param.ITEM_NAME, item_name); 140 | bundle.putString(FirebaseAnalytics.Param.VIRTUAL_CURRENCY_NAME, currency_name); 141 | bundle.putInt(FirebaseAnalytics.Param.VALUE, value); 142 | 143 | mFirebaseAnalytics = FirebaseAnalytics.getInstance(activity); 144 | mFirebaseAnalytics.logEvent(FirebaseAnalytics.Event.SPEND_VIRTUAL_CURRENCY, bundle); 145 | 146 | Utils.d("GodotFireBase", 147 | "Sending:Currency:Spend: {" + item_name + "|" + currency_name + "|" + value + "}"); 148 | } 149 | 150 | public void send_tutorial_begin() { 151 | Bundle bundle = new Bundle(); 152 | //bundle.putString(FirebaseAnalytics.Param.ACHIEVEMENT_ID, id); 153 | 154 | mFirebaseAnalytics = FirebaseAnalytics.getInstance(activity); 155 | mFirebaseAnalytics.logEvent(FirebaseAnalytics.Event.TUTORIAL_BEGIN, bundle); 156 | 157 | Utils.d("GodotFireBase", "Sending:Tutorial:Begin"); 158 | } 159 | 160 | public void send_tutorial_complete() { 161 | Bundle bundle = new Bundle(); 162 | //bundle.putString(FirebaseAnalytics.Param.ACHIEVEMENT_ID, id); 163 | 164 | mFirebaseAnalytics = FirebaseAnalytics.getInstance(activity); 165 | mFirebaseAnalytics.logEvent(FirebaseAnalytics.Event.TUTORIAL_COMPLETE, bundle); 166 | Utils.d("GodotFireBase", "Sending:Tutorial:Complete"); 167 | } 168 | 169 | public void send_events(String eventName, Dictionary keyValues) { 170 | 171 | // Generate bundle out of keyValues 172 | Bundle bundle = new Bundle(); 173 | Utils.putAllInDict(bundle, keyValues); 174 | 175 | // Dispatch event 176 | mFirebaseAnalytics = FirebaseAnalytics.getInstance(activity); 177 | mFirebaseAnalytics.logEvent(eventName, bundle); 178 | 179 | Utils.d("GodotFireBase", "Sending:App:Event:[" + eventName + "]:" + bundle.toString() + ""); 180 | } 181 | 182 | public void send_custom(final String key, final String value) { 183 | Bundle bundle = new Bundle(); 184 | bundle.putString(key, value); 185 | 186 | mFirebaseAnalytics = FirebaseAnalytics.getInstance(activity); 187 | mFirebaseAnalytics.logEvent("appEvent", bundle); 188 | Utils.d("GodotFireBase", "Sending:App:Event:" + bundle.toString()); 189 | } 190 | 191 | private static Context context; 192 | private static Activity activity = null; 193 | private static Analytics mInstance = null; 194 | 195 | private FirebaseApp mFirebaseApp = null; 196 | private FirebaseAnalytics mFirebaseAnalytics = null; 197 | } 198 | -------------------------------------------------------------------------------- /android_src/AndroidManifestChunk.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 20 | 21 | 23 | 24 | 25 | 26 | 27 | 29 | 30 | 31 | 34 | 35 | 36 | 37 | 40 | 41 | 44 | 45 | 48 | 49 | 52 | 53 | 54 | 55 | 58 | 59 | -------------------------------------------------------------------------------- /android_src/AndroidPermissionsChunk.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /android_src/FireBase.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2017 FrogSquare. All Rights Reserved. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | **/ 16 | 17 | package org.godotengine.godot; 18 | 19 | import android.app.Activity; 20 | import android.app.AlertDialog; 21 | import android.app.ProgressDialog; 22 | import android.content.Context; 23 | import android.view.View; 24 | import android.os.Bundle; 25 | import android.content.Intent; 26 | 27 | import java.util.Arrays; 28 | import java.util.List; 29 | 30 | import org.json.JSONObject; 31 | import org.json.JSONException; 32 | 33 | import com.google.firebase.FirebaseApp; 34 | import com.google.firebase.FirebaseOptions; 35 | 36 | //Auth++ 37 | import org.godotengine.godot.auth.Auth; 38 | //Auth-- 39 | 40 | //Storage++ 41 | import org.godotengine.godot.storage.Storage; 42 | //Storage-- 43 | 44 | import org.godotengine.godot.Dictionary; 45 | 46 | public class FireBase extends Godot.SingletonBase { 47 | 48 | static public Godot.SingletonBase initialize (Activity p_activity) { 49 | return new FireBase(p_activity); 50 | } 51 | 52 | public FireBase(Activity p_activity) { 53 | registerClass ("FireBase", new String[] { 54 | "init", "initWithFile", "alert", "set_debug", 55 | 56 | //Analytics++ 57 | "setScreenName", "sendAchievement", "send_custom", "send_events", "join_group", "level_up", 58 | "post_score", "content_select", "earn_currency", 59 | "spend_currency", "tutorial_begin", "tutorial_complete", 60 | //Analytics-- 61 | 62 | //AdMob++ 63 | "show_banner_ad", "show_interstitial_ad", "show_rewarded_video", 64 | "request_rewarded_video_status", "set_banner_unitid", "show_rvideo", 65 | "get_banner_size", "is_banner_loaded", 66 | "is_interstitial_loaded", "is_rewarded_video_loaded", 67 | //AdMob-- 68 | 69 | //Auth++ 70 | "get_id_token", 71 | //AuthGoogle++ 72 | "google_sign_in", "google_sign_out", 73 | "is_google_connected", "get_google_user", "google_revoke_access", 74 | //AuthGoogle-- 75 | 76 | //AuthFacebook++ 77 | "facebook_sign_out", "facebook_sign_in", "is_facebook_connected", 78 | "get_facebook_permissions", "facebook_has_permission", 79 | "revoke_facebook_permission", "facebook_revoke_access", 80 | "ask_facebook_read_permission", "ask_facebook_publish_permission", 81 | "get_facebook_user", 82 | //AuthFacebook-- 83 | 84 | //AuthTwitter++ 85 | "twitter_sign_in", "twitter_sign_out", "is_twitter_connected", 86 | //AuthTwitter-- 87 | 88 | "anonymous_sign_in", "anonymous_sign_out", "is_anonymous_connected", 89 | "authConfig", 90 | //Auth-- 91 | 92 | //Notification++ 93 | "notifyInMins", "notifyInSecs", "subscribeToTopic", "getToken", 94 | "notifyOnComplete", "repeatNotification", 95 | //Notification-- 96 | 97 | //RemoteConfig++ 98 | "getRemoteValue", "setRemoteDefaults", "setRemoteDefaultsFile", 99 | //RemoteConfig-- 100 | 101 | //Storage++ 102 | "download", "upload", 103 | //Storage-- 104 | 105 | //Firestore++ 106 | "load_document", "load_document_to", "set_document", "add_document", 107 | //Firestore-- 108 | 109 | //Share++ 110 | "share" 111 | //Share-- 112 | }); 113 | 114 | activity = p_activity; 115 | } 116 | 117 | private void initFireBase(final String data) { 118 | Utils.d("GodotFireBase", "Data From File: " + data); 119 | 120 | JSONObject config = null; 121 | mFirebaseApp = FirebaseApp.initializeApp(activity); 122 | 123 | if (data.length() <= 0) { 124 | Utils.d("GodotFireBase", "FireBase initialized."); 125 | return; 126 | } 127 | 128 | try { 129 | config = new JSONObject(data); 130 | firebaseConfig = config; 131 | } catch (JSONException e) { Utils.d("GodotFireBase", "JSON Parse error: " + e.toString()); } 132 | 133 | //Analytics++ 134 | if (config.optBoolean("Analytics", true)) { 135 | Utils.d("GodotFireBase", "Initializing Firebase Analytics."); 136 | Analytics.getInstance(activity).init(mFirebaseApp); 137 | } 138 | //Analytics-- 139 | 140 | //AdMob++ 141 | if (config.optBoolean("AdMob", false)) { 142 | Utils.d("GodotFireBase", "Initializing Firebase AdMob."); 143 | AdMob.getInstance(activity).init(mFirebaseApp); 144 | } 145 | //AdMob-- 146 | 147 | //Auth++ 148 | if (config.optBoolean("Authentication", false)) { 149 | Utils.d("GodotFireBase", "Initializing Firebase Authentication."); 150 | Auth.getInstance(activity).init(mFirebaseApp); 151 | Auth.getInstance(activity).configure(config.optString("AuthConf")); 152 | } 153 | //Auth-- 154 | 155 | //Notification++ 156 | if (config.optBoolean("Notification", false)) { 157 | Utils.d("GodotFireBase", "Initializing Firebase Notification."); 158 | Notification.getInstance(activity).init(mFirebaseApp); 159 | } 160 | //Notification-- 161 | 162 | //RemoteConfig++ 163 | if (config.optBoolean("RemoteConfig", false)) { 164 | Utils.d("GodotFireBase", "Initializing Firebase RemoteConfig."); 165 | RemoteConfig.getInstance(activity).init(mFirebaseApp); 166 | } 167 | //RemoteConfig-- 168 | 169 | //Storage++ 170 | if (config.optBoolean("Storage", false)) { 171 | if (!config.optBoolean("Authentication", false)) { 172 | Utils.d("GodotFireBase", "Firebase Storage needs Authentication."); 173 | } 174 | 175 | Utils.d("GodotFireBase", "Initializing Firebase Storage."); 176 | Storage.getInstance(activity).init(mFirebaseApp); 177 | } 178 | //Storage-- 179 | 180 | //Firestore++ 181 | if (config.optBoolean("Firestore", false)) { 182 | Utils.d("GodotFireBase", "Initializing Firestore."); 183 | Firestore.getInstance(activity).init(mFirebaseApp); 184 | } 185 | //Firestore-- 186 | 187 | Utils.d("GodotFireBase", "FireBase initialized."); 188 | } 189 | 190 | public void set_debug(final boolean p_value) { 191 | Utils.set_debug("GodotFireBase", p_value); 192 | } 193 | 194 | public void alertMsg(String message) { 195 | alertMsg("FireBase", message); 196 | } 197 | 198 | public void alertMsg(String title, String message) { 199 | AlertDialog.Builder bld; 200 | 201 | bld = new AlertDialog.Builder(activity, AlertDialog.THEME_HOLO_LIGHT); 202 | bld.setIcon (com.godot.game.R.drawable.icon); 203 | bld.setTitle(title); 204 | bld.setMessage(message); 205 | bld.setNeutralButton("OK", null); 206 | bld.create().show(); 207 | } 208 | 209 | public void init(final String data, final int script_id) { 210 | activity.runOnUiThread(new Runnable() { 211 | public void run() { 212 | Utils.setScriptInstance(script_id); 213 | initFireBase(data); 214 | } 215 | }); 216 | } 217 | 218 | public void initWithFile(final String fileName, final int script_id) { 219 | activity.runOnUiThread(new Runnable() { 220 | public void run() { 221 | String data = Utils.readFromFile(fileName, activity); 222 | data = data.replaceAll("\\s+", ""); 223 | 224 | Utils.setScriptInstance(script_id); 225 | initFireBase(data); 226 | } 227 | }); 228 | } 229 | 230 | //Analytics++ 231 | public void setScreenName (final String screen_name) { 232 | activity.runOnUiThread(new Runnable() { 233 | public void run() { 234 | if (screen_name.length() <= 0) { 235 | Utils.d("GodotFireBase", "Screen name is empty defaults to main"); 236 | Analytics.getInstance(activity).set_screen_name("Main Screen"); 237 | } else { 238 | Analytics.getInstance(activity).set_screen_name(screen_name); 239 | } 240 | } 241 | }); 242 | } 243 | 244 | public void sendAchievement(final String a_id) { 245 | if (a_id.length() <= 0) { 246 | Utils.d("GodotFireBase", "Achievement id not provided"); 247 | return; 248 | } 249 | 250 | activity.runOnUiThread(new Runnable() { 251 | public void run() { 252 | Analytics.getInstance(activity).send_achievement(a_id); 253 | } 254 | }); 255 | } 256 | 257 | public void join_group(final String id) { 258 | activity.runOnUiThread(new Runnable() { 259 | public void run() { 260 | Analytics.getInstance(activity).send_group(id); 261 | } 262 | }); 263 | } 264 | 265 | public void level_up(final String character, final int level) { 266 | activity.runOnUiThread(new Runnable() { 267 | public void run() { 268 | Analytics.getInstance(activity).send_level_up(character, level); 269 | } 270 | }); 271 | } 272 | 273 | public void post_score(final String character, final int level, final int score) { 274 | activity.runOnUiThread(new Runnable() { 275 | public void run() { 276 | Analytics.getInstance(activity).send_score(character, level, score); 277 | } 278 | }); 279 | } 280 | 281 | public void content_select(final String content, final String item_id) { 282 | activity.runOnUiThread(new Runnable() { 283 | public void run() { 284 | Analytics.getInstance(activity).send_content(content, item_id); 285 | } 286 | }); 287 | } 288 | 289 | public void earn_currency(final String currency_name, final int value) { 290 | activity.runOnUiThread(new Runnable() { 291 | public void run() { 292 | Analytics.getInstance(activity).earn_currency(currency_name, value); 293 | } 294 | }); 295 | } 296 | 297 | public void spend_currency(final String item_name, final String currency, final int value) { 298 | activity.runOnUiThread(new Runnable() { 299 | public void run() { 300 | Analytics.getInstance(activity) 301 | .spend_currency(item_name, currency, value); 302 | } 303 | }); 304 | } 305 | 306 | public void tutorial_begin() { 307 | activity.runOnUiThread(new Runnable() { 308 | public void run() { 309 | Analytics.getInstance(activity).send_tutorial_begin(); 310 | } 311 | }); 312 | } 313 | 314 | public void tutorial_complete() { 315 | activity.runOnUiThread(new Runnable() { 316 | public void run() { 317 | Analytics.getInstance(activity).send_tutorial_complete(); 318 | } 319 | }); 320 | } 321 | 322 | public void send_events(final String key, final Dictionary data) { 323 | if (key.length() <= 0 || data.size() <= 0) { 324 | Utils.d("GodotFireBase", "Key or Data is null."); 325 | return; 326 | } 327 | 328 | activity.runOnUiThread(new Runnable() { 329 | public void run() { 330 | Analytics.getInstance(activity).send_events(key, data); 331 | } 332 | }); 333 | } 334 | 335 | public void send_custom(final String key, final String value) { 336 | if (key.length() <= 0 || value.length() <= 0) { 337 | Utils.d("GodotFireBase", "Key or Value is null."); 338 | return; 339 | } 340 | 341 | activity.runOnUiThread(new Runnable() { 342 | public void run() { 343 | Analytics.getInstance(activity).send_custom(key, value); 344 | } 345 | }); 346 | } 347 | //Analytics-- 348 | 349 | //AdMob++ 350 | public boolean is_banner_loaded() { 351 | return AdMob.getInstance(activity).isBannerLoaded(); 352 | } 353 | 354 | public boolean is_interstitial_loaded () { 355 | return AdMob.getInstance(activity).isInterstitialLoaded(); 356 | 357 | } 358 | 359 | public boolean is_rewarded_video_loaded(final String unit_id) { 360 | return AdMob.getInstance(activity).isRewardedAdLoaded(unit_id); 361 | } 362 | 363 | public void set_banner_unitid(final String unit_id) { 364 | activity.runOnUiThread(new Runnable() { 365 | public void run() { 366 | AdMob.getInstance(activity).setBannerUnitId(unit_id); 367 | } 368 | }); 369 | } 370 | 371 | public void show_banner_ad(final boolean show) { 372 | activity.runOnUiThread(new Runnable() { 373 | public void run() { 374 | AdMob.getInstance(activity).show_banner_ad(show); 375 | } 376 | }); 377 | } 378 | 379 | public Dictionary get_banner_size() { 380 | return AdMob.getInstance(activity).getBannerSize(); 381 | } 382 | 383 | public void show_interstitial_ad() { 384 | activity.runOnUiThread(new Runnable() { 385 | public void run() { 386 | AdMob.getInstance(activity).show_interstitial_ad(); 387 | } 388 | }); 389 | } 390 | 391 | public void reload_rewarded_video(final String unit_id) { 392 | activity.runOnUiThread(new Runnable() { 393 | public void run() { 394 | AdMob.getInstance(activity).reloadRewardedVideo(unit_id); 395 | } 396 | }); 397 | } 398 | 399 | public void show_rvideo(final String unit_id) { 400 | activity.runOnUiThread(new Runnable() { 401 | public void run() { 402 | AdMob.getInstance(activity).show_rewarded_video(unit_id); 403 | } 404 | }); 405 | } 406 | 407 | public void request_rewarded_video_status() { 408 | activity.runOnUiThread(new Runnable() { 409 | public void run() { 410 | AdMob.getInstance(activity).requestRewardedVideoStatus(); 411 | } 412 | }); 413 | } 414 | 415 | public void show_rewarded_video() { 416 | activity.runOnUiThread(new Runnable() { 417 | public void run() { 418 | AdMob.getInstance(activity).show_rewarded_video(); 419 | } 420 | }); 421 | } 422 | //AdMob-- 423 | 424 | //Auth++ 425 | public void authConfig(final String conf) { 426 | activity.runOnUiThread(new Runnable() { 427 | public void run() { 428 | Auth.getInstance(activity).configure(conf); 429 | } 430 | }); 431 | } 432 | 433 | public void get_id_token() { 434 | activity.runOnUiThread(new Runnable() { 435 | public void run() { 436 | Auth.getInstance(activity).getIdToken(); 437 | } 438 | }); 439 | } 440 | 441 | 442 | //AuthGoogle++ 443 | public void google_sign_in () { 444 | activity.runOnUiThread(new Runnable() { 445 | public void run() { 446 | Auth.getInstance(activity).sign_in(Auth.GOOGLE_AUTH); 447 | } 448 | }); 449 | } 450 | 451 | public void google_sign_out() { 452 | activity.runOnUiThread(new Runnable() { 453 | public void run() { 454 | Auth.getInstance(activity).sign_out(Auth.GOOGLE_AUTH); 455 | } 456 | }); 457 | } 458 | 459 | public void revoke_google_access() { 460 | activity.runOnUiThread(new Runnable() { 461 | public void run() { 462 | Auth.getInstance(activity).revoke(Auth.GOOGLE_AUTH); 463 | } 464 | }); 465 | } 466 | 467 | public boolean is_google_connected() { 468 | return Auth.getInstance(activity).isConnected(Auth.GOOGLE_AUTH); 469 | } 470 | 471 | public String get_google_user() { 472 | return Auth.getInstance(activity).getUserDetails(Auth.GOOGLE_AUTH); 473 | } 474 | //AuthGoogle-- 475 | 476 | //AuthTwitter++ 477 | public void twitter_sign_in () { 478 | activity.runOnUiThread(new Runnable() { 479 | public void run() { 480 | Auth.getInstance(activity).sign_in(Auth.TWITTER_AUTH); 481 | } 482 | }); 483 | } 484 | 485 | public void twitter_sign_out() { 486 | activity.runOnUiThread(new Runnable() { 487 | public void run() { 488 | Auth.getInstance(activity).sign_out(Auth.TWITTER_AUTH); 489 | } 490 | }); 491 | } 492 | //AuthTwitter-- 493 | 494 | //AuthFacebook++ 495 | public void facebook_sign_in() { 496 | activity.runOnUiThread(new Runnable() { 497 | public void run() { 498 | Auth.getInstance(activity).sign_in(Auth.FACEBOOK_AUTH); 499 | } 500 | }); 501 | } 502 | 503 | public void facebook_sign_out() { 504 | activity.runOnUiThread(new Runnable() { 505 | public void run() { 506 | Auth.getInstance(activity).sign_out(Auth.FACEBOOK_AUTH); 507 | } 508 | }); 509 | } 510 | 511 | public void revoke_facebook_access() { 512 | activity.runOnUiThread(new Runnable() { 513 | public void run() { 514 | Auth.getInstance(activity).revoke(Auth.FACEBOOK_AUTH); 515 | } 516 | }); 517 | } 518 | 519 | public boolean is_facebook_connected() { 520 | return Auth.getInstance(activity).isConnected(Auth.FACEBOOK_AUTH); 521 | } 522 | 523 | public String get_facebook_user() { 524 | return Auth.getInstance(activity).getUserDetails(Auth.FACEBOOK_AUTH); 525 | } 526 | 527 | public String get_facebook_permissions() { 528 | return Auth.getInstance(activity).getFacebookPermissions(); 529 | } 530 | 531 | public boolean facebook_has_permission(final String permission) { 532 | return Auth.getInstance(activity).isPermissionGiven (permission); 533 | } 534 | 535 | public void revoke_facebook_permission(final String permission) { 536 | activity.runOnUiThread(new Runnable() { 537 | public void run() { 538 | Auth.getInstance(activity).revokeFacebookPermission(permission); 539 | } 540 | }); 541 | } 542 | 543 | public void ask_facebook_read_permission( 544 | final String title, final String message, final String permission) { 545 | 546 | activity.runOnUiThread(new Runnable() { 547 | public void run() { 548 | Auth.getInstance(activity) 549 | .askForPermission(title, message, permission, true); 550 | } 551 | }); 552 | } 553 | 554 | public void ask_facebook_publish_permission( 555 | final String title, final String message, final String permission) { 556 | 557 | activity.runOnUiThread(new Runnable() { 558 | public void run() { 559 | Auth.getInstance(activity) 560 | .askForPermission(title, message, permission, false); 561 | } 562 | }); 563 | } 564 | //AuthFacebook-- 565 | 566 | public void anonymous_sign_in() { 567 | activity.runOnUiThread(new Runnable() { 568 | public void run() { 569 | Auth.getInstance(activity).sign_in(Auth.ANONYMOUS_AUTH); 570 | } 571 | }); 572 | } 573 | 574 | public void anonymous_sign_out() { 575 | activity.runOnUiThread(new Runnable() { 576 | public void run() { 577 | Auth.getInstance(activity).sign_out(Auth.ANONYMOUS_AUTH); 578 | } 579 | }); 580 | } 581 | 582 | public boolean is_anonymous_connected() { 583 | return Auth.getInstance(activity).isConnected(Auth.ANONYMOUS_AUTH); 584 | } 585 | //Auth-- 586 | 587 | /** Extra **/ 588 | public void alert(final String message) { 589 | if (message.length() <= 0) { 590 | Utils.d("GodotFireBase", "Message is empty."); 591 | return; 592 | } 593 | 594 | activity.runOnUiThread(new Runnable() { 595 | public void run() { 596 | alertMsg(message); 597 | } 598 | }); 599 | } 600 | /** Extra **/ 601 | 602 | //Notification++ 603 | public void repeatNotification(final Dictionary data, final int seconds) { 604 | activity.runOnUiThread(new Runnable() { 605 | public void run() { 606 | Notification.getInstance(activity).shedule(data, seconds); 607 | } 608 | }); 609 | } 610 | 611 | public void notifyOnComplete(final Dictionary data, final int seconds) { 612 | activity.runOnUiThread(new Runnable() { 613 | public void run() { 614 | Notification.getInstance(activity).notifyOnComplete(data, seconds); 615 | } 616 | }); 617 | } 618 | 619 | public void notifyInSecs (final String message, final int secs) { 620 | activity.runOnUiThread(new Runnable() { 621 | public void run() { 622 | Notification.getInstance(activity).notifyInSecs(message, secs); 623 | } 624 | }); 625 | } 626 | 627 | public void notifyInMins (final String message, final int mins) { 628 | activity.runOnUiThread(new Runnable() { 629 | public void run() { 630 | Notification.getInstance(activity).notifyInMins(message, mins); 631 | } 632 | }); 633 | } 634 | 635 | public void subscribeToTopic (final String topic) { 636 | if (topic.length() <= 0) { 637 | Utils.d("GodotFireBase", "Topic id not provided."); 638 | return; 639 | } 640 | 641 | activity.runOnUiThread(new Runnable() { 642 | public void run() { 643 | Notification.getInstance(activity).subscribe(topic); 644 | } 645 | }); 646 | } 647 | 648 | public String getToken () { 649 | return Notification.getInstance(activity).getFirebaseMessagingToken(); 650 | } 651 | 652 | public void sendTokenToServer () { 653 | activity.runOnUiThread(new Runnable() { 654 | public void run() { 655 | 656 | } 657 | }); 658 | } 659 | //Notification-- 660 | 661 | //RemoteConfig++ 662 | public String getRemoteValue (final String key) { 663 | if (key.length() <= 0) { 664 | Utils.d("GodotFireBase", "getting remote config: key not provided, returning null"); 665 | return "NULL"; 666 | } 667 | 668 | return RemoteConfig.getInstance(activity).getValue(key); 669 | } 670 | 671 | public void setRemoteDefaultsFile (final String path) { 672 | if (path.length() <= 0) { 673 | Utils.d("GodotFireBase", "File not provided for remote config"); 674 | return; 675 | } 676 | 677 | activity.runOnUiThread(new Runnable() { 678 | public void run() { 679 | RemoteConfig.getInstance(activity).setDefaultsFile(path); 680 | } 681 | }); 682 | } 683 | 684 | public void setRemoteDefaults (final String jsonData) { 685 | if (jsonData.length() <= 0) { 686 | Utils.d("GodotFireBase", "No defaults were provided."); 687 | return; 688 | } 689 | 690 | activity.runOnUiThread(new Runnable() { 691 | public void run() { 692 | RemoteConfig.getInstance(activity).setDefaults(jsonData); 693 | } 694 | }); 695 | } 696 | //RemoteConfig-- 697 | 698 | //Storage++ 699 | public void download(final String file, final String path) { 700 | activity.runOnUiThread(new Runnable() { 701 | public void run() { 702 | Storage.getInstance(activity).download(file, path); 703 | } 704 | }); 705 | } 706 | 707 | public void upload(final String file, final String path) { 708 | activity.runOnUiThread(new Runnable() { 709 | public void run() { 710 | Storage.getInstance(activity).upload(file, path); 711 | } 712 | }); 713 | } 714 | //Storage-- 715 | 716 | //Firestore++ 717 | public void set_document(final String p_col_name, final String p_doc_name, final Dictionary p_dict) { 718 | activity.runOnUiThread(new Runnable() { 719 | public void run() { 720 | Firestore.getInstance(activity).setData(p_col_name, p_doc_name, p_dict); 721 | } 722 | }); 723 | } 724 | 725 | public void add_document(final String p_name, final Dictionary p_data) { 726 | activity.runOnUiThread(new Runnable() { 727 | public void run() { 728 | Firestore.getInstance(activity).addDocument(p_name, p_data); 729 | } 730 | }); 731 | } 732 | 733 | public void load_document(final String p_name) { 734 | activity.runOnUiThread(new Runnable() { 735 | public void run() { 736 | Firestore.getInstance(activity).loadDocuments(p_name, -1); 737 | } 738 | }); 739 | } 740 | 741 | public void load_document_to(final String p_name, final int callback_instance_id) { 742 | activity.runOnUiThread(new Runnable() { 743 | public void run() { 744 | Firestore.getInstance(activity).loadDocuments(p_name, callback_instance_id); 745 | } 746 | }); 747 | } 748 | //Firestore-- 749 | 750 | //Sharing++ 751 | public void share(final String p_text, final String p_subject) { 752 | activity.runOnUiThread(new Runnable() { 753 | public void run() { 754 | Share.getInstance(activity).share(p_text, p_subject); 755 | } 756 | }); 757 | } 758 | //Sharing-- 759 | 760 | /** Main Funcs **/ 761 | public static JSONObject getConfig() { 762 | return firebaseConfig; 763 | } 764 | 765 | protected void onMainActivityResult (int requestCode, int resultCode, Intent data) { 766 | //Utils.d("GodotFireBase", "onActivityResult: reqCode=" + requestCode + ", resCode=" + resultCode); 767 | 768 | //Analytics++ 769 | // Analytics.getInstance(activity).onActivityResult(requestCode, resultCode, data); 770 | //Analytics-- 771 | 772 | //Auth++ 773 | Auth.getInstance(activity).onActivityResult(requestCode, resultCode, data); 774 | //Auth-- 775 | } 776 | 777 | protected void onMainPause () { 778 | //Analytics++ 779 | // Analytics.getInstance(activity).onPause(); 780 | //Analytics-- 781 | 782 | //RemoteConfig++ 783 | // RemoteConfig.getInstance(activity).onPause(); 784 | //RemoteConfig-- 785 | 786 | //Auth++ 787 | Auth.getInstance(activity).onPause(); 788 | //Auth-- 789 | 790 | 791 | //AdMob++ 792 | AdMob.getInstance(activity).onPause(); 793 | //AdMob-- 794 | } 795 | 796 | protected void onMainResume () { 797 | //Analytics++ 798 | // Analytics.getInstance(activity).onResume(); 799 | //Analytics-- 800 | 801 | //RemoteConfig++ 802 | // RemoteConfig.getInstance(activity).onResume(); 803 | //RemoteConfig++ 804 | 805 | //Auth++ 806 | Auth.getInstance(activity).onResume(); 807 | //Auth-- 808 | 809 | 810 | //AdMob++ 811 | AdMob.getInstance(activity).onResume(); 812 | //AdMob-- 813 | } 814 | 815 | protected void onMainDestroy () { 816 | //Analytics++ 817 | // Analytics.getInstance(activity).onStop(); 818 | //Analytics-- 819 | 820 | //RemoteConfig++ 821 | // RemoteConfig.getInstance(activity).onStop(); 822 | //RemoteConfig-- 823 | 824 | //Auth++ 825 | Auth.getInstance(activity).onStop(); 826 | //Auth-- 827 | 828 | //AdMob++ 829 | AdMob.getInstance(activity).onStop(); 830 | //AdMob-- 831 | 832 | //Storage++ 833 | Storage.getInstance(activity).onStop(); 834 | //Storage-- 835 | } 836 | 837 | private static Context context = null; 838 | private static Activity activity = null; 839 | protected static String currentScreen = "None"; 840 | 841 | private static JSONObject firebaseConfig = new JSONObject(); 842 | 843 | private FirebaseApp mFirebaseApp = null; 844 | } 845 | -------------------------------------------------------------------------------- /android_src/Firestore.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2017 FrogSquare. All Rights Reserved. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | **/ 16 | 17 | package org.godotengine.godot; 18 | 19 | import android.app.Activity; 20 | import android.app.AlertDialog; 21 | import android.app.ProgressDialog; 22 | import android.content.Intent; 23 | import android.content.Context; 24 | import android.view.View; 25 | import android.os.Bundle; 26 | import androidx.annotation.NonNull; 27 | 28 | import java.util.Arrays; 29 | import java.util.List; 30 | 31 | import org.json.JSONObject; 32 | import org.json.JSONException; 33 | 34 | import com.google.firebase.FirebaseApp; 35 | import com.google.firebase.firestore.DocumentReference; 36 | import com.google.firebase.firestore.DocumentSnapshot; 37 | import com.google.firebase.firestore.FirebaseFirestore; 38 | import com.google.firebase.firestore.FirebaseFirestoreException; 39 | import com.google.firebase.firestore.SetOptions; 40 | import com.google.firebase.firestore.QuerySnapshot; 41 | 42 | import com.google.android.gms.tasks.*; 43 | 44 | import org.godotengine.godot.Dictionary; 45 | 46 | public class Firestore { 47 | 48 | public static Firestore getInstance (Activity p_activity) { 49 | if (mInstance == null) { 50 | mInstance = new Firestore(p_activity); 51 | } 52 | 53 | return mInstance; 54 | } 55 | 56 | public Firestore(Activity p_activity) { 57 | activity = p_activity; 58 | } 59 | 60 | public void init (FirebaseApp firebaseApp) { 61 | mFirebaseApp = firebaseApp; 62 | 63 | // Enable Firestore logging 64 | FirebaseFirestore.setLoggingEnabled(true); 65 | db = FirebaseFirestore.getInstance(); 66 | 67 | Utils.d("GodotFireBase", "Firestore::Initialized"); 68 | } 69 | 70 | public void loadDocuments (final String p_name, final int callback_id) { 71 | Utils.d("GodotFireBase", "Firestore::LoadData"); 72 | 73 | db.collection(p_name).get() 74 | .addOnCompleteListener(new OnCompleteListener() { 75 | @Override 76 | public void onComplete(@NonNull Task task) { 77 | if (task.isSuccessful()) { 78 | JSONObject jobject = new JSONObject(); 79 | 80 | try { 81 | JSONObject jobject_1 = new JSONObject(); 82 | 83 | for (DocumentSnapshot document : task.getResult()) { 84 | jobject_1.put(document.getId(), new JSONObject(document.getData())); 85 | } 86 | 87 | jobject.put(p_name, jobject_1); 88 | } catch (JSONException e) { 89 | Utils.d("GodotFireBase", "JSON Exception: " + e.toString()); 90 | } 91 | 92 | 93 | Utils.d("GodotFireBase", "Data: " + jobject.toString()); 94 | 95 | if (callback_id == -1) { 96 | Utils.callScriptFunc( 97 | "Firestore", "Documents", jobject.toString()); 98 | } else { 99 | Utils.callScriptFunc( 100 | callback_id, "Firestore", "Documents", jobject.toString()); 101 | } 102 | 103 | } else { 104 | Utils.w("GodotFireBase", "Error getting documents: " + task.getException()); 105 | } 106 | } 107 | }); 108 | } 109 | 110 | public void addDocument (final String p_name, final Dictionary p_dict) { 111 | Utils.d("GodotFireBase", "Firestore::AddData"); 112 | 113 | // Add a new document with a generated ID 114 | db.collection(p_name) 115 | .add(p_dict) // AutoGrenerate ID use .document("name").set(p_dict) 116 | .addOnSuccessListener(new OnSuccessListener() { 117 | @Override 118 | public void onSuccess(DocumentReference documentReference) { 119 | Utils.d("GodotFireBase", "DocumentSnapshot added with ID: " + documentReference.getId()); 120 | Utils.callScriptFunc("Firestore", "DocumentAdded", true); 121 | } 122 | }).addOnFailureListener(new OnFailureListener() { 123 | @Override 124 | public void onFailure(@NonNull Exception e) { 125 | Utils.w("GodotFireBase", "Error adding document: " + e); 126 | Utils.callScriptFunc("Firestore", "DocumentAdded", false); 127 | } 128 | }); 129 | } 130 | 131 | public void setData(final String p_col_name, final String p_doc_name, final Dictionary p_dict) { 132 | db.collection(p_col_name).document(p_doc_name) 133 | .set(p_dict, SetOptions.merge()) 134 | .addOnSuccessListener(new OnSuccessListener() { 135 | @Override 136 | public void onSuccess(Void aVoid) { 137 | Utils.d("GodotFireBase", "DocumentSnapshot successfully written!"); 138 | Utils.callScriptFunc("Firestore", "DocumentAdded", true); 139 | } 140 | }).addOnFailureListener(new OnFailureListener() { 141 | @Override 142 | public void onFailure(@NonNull Exception e) { 143 | Utils.w("GodotFireBase", "Error adding document: " + e); 144 | Utils.callScriptFunc("Firestore", "DocumentAdded", false); 145 | } 146 | }); 147 | 148 | } 149 | 150 | private FirebaseFirestore db = null; 151 | private static Activity activity = null; 152 | private static Firestore mInstance = null; 153 | 154 | private int script_callback_id = -1; 155 | 156 | private FirebaseApp mFirebaseApp = null; 157 | } 158 | -------------------------------------------------------------------------------- /android_src/MessagingService.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2017 FrogSquare. All Rights Reserved. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | **/ 16 | 17 | package org.godotengine.godot; 18 | 19 | import android.app.NotificationChannel; 20 | import android.app.NotificationManager; 21 | import android.app.PendingIntent; 22 | import android.content.Context; 23 | import android.content.Intent; 24 | import android.graphics.Bitmap; 25 | import android.graphics.BitmapFactory; 26 | import android.media.RingtoneManager; 27 | import android.net.Uri; 28 | import android.os.Bundle; 29 | import android.os.Build; 30 | import android.util.Log; 31 | 32 | import androidx.core.app.NotificationCompat; 33 | 34 | import com.google.firebase.messaging.FirebaseMessagingService; 35 | import com.google.firebase.messaging.RemoteMessage; 36 | 37 | import com.godot.game.R; 38 | 39 | import java.util.Map; 40 | 41 | import org.json.JSONObject; 42 | import org.json.JSONException; 43 | 44 | import org.godotengine.godot.KeyValueStorage; 45 | 46 | public class MessagingService extends FirebaseMessagingService { 47 | 48 | private static int NOTIFICATION_REQUEST_ID = 8001; 49 | 50 | @Override 51 | public void onMessageReceived(RemoteMessage remoteMessage) { 52 | Utils.d("GodotFireBase", "Message From: " + remoteMessage.getFrom()); 53 | Utils.d("GodotFireBase", "Message From: " + remoteMessage.toString()); 54 | 55 | // Check if message contains a data payload. 56 | if (remoteMessage.getData().size() > 0) { 57 | Map data = remoteMessage.getData(); 58 | 59 | Utils.d("GodotFireBase", "Message data payload: " + data.toString()); 60 | 61 | KeyValueStorage.set_context(this); 62 | handleData(data); 63 | } 64 | 65 | // Check if message contains a notification payload. 66 | if (remoteMessage.getNotification() != null) { 67 | Utils.d("GodotFireBase", 68 | "Notification Body: " + remoteMessage.getNotification().getBody()); 69 | 70 | sendNotification(remoteMessage.getNotification().getBody(), this); 71 | } 72 | } 73 | 74 | @Override 75 | public void onNewToken(String token) { 76 | Utils.d("GodotFireBase", "Refreshed token: " + token); 77 | sendRegistrationToServer(token); 78 | } 79 | 80 | private void sendRegistrationToServer(String token) { 81 | // TODO: Implement this method to send token to your app server. 82 | Utils.d("GodotFireBase", "Token: " + token); 83 | } 84 | 85 | private void handleData (Map data) { 86 | // TODO: Perform some action now..! 87 | // ... 88 | 89 | JSONObject jobject = new JSONObject(); 90 | 91 | try { 92 | for (Map.Entry entry : data.entrySet()) { 93 | jobject.put(entry.getKey(), entry.getValue()); 94 | } 95 | } catch (JSONException e) { Utils.d("GodotFireBase", "JSONException: parsing, " + e.toString()); } 96 | 97 | if (jobject.length() > 0) { 98 | KeyValueStorage.setValue("firebase_notification_data", jobject.toString()); 99 | } 100 | } 101 | 102 | public static void sendNotification(Bundle bundle, Context context) { 103 | if (bundle.getString("image_uri") == null) { 104 | sendNotification(bundle.getString("message"), context); 105 | } 106 | 107 | Intent intent = new Intent(context, org.godotengine.godot.Godot.class); 108 | intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP); 109 | 110 | PendingIntent pendingIntent = PendingIntent.getActivity( 111 | context, Utils.FIREBASE_NOTIFICATION_REQUEST, intent, PendingIntent.FLAG_ONE_SHOT); 112 | 113 | Uri defaultSoundUri = 114 | RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION); 115 | 116 | Bitmap large_icon; 117 | if (bundle.get("larget_icon") != null) { 118 | large_icon = Utils.getBitmapFromAsset(context, bundle.getString("large_icon")); 119 | } else { 120 | large_icon = BitmapFactory.decodeResource(context.getResources(), R.drawable.icon); 121 | } 122 | 123 | NotificationCompat.Builder nBuilder = new NotificationCompat.Builder(context) 124 | .setLargeIcon(large_icon) 125 | .setSmallIcon(R.drawable.notification_small_icon) 126 | .setContentTitle(bundle.getString("title")) 127 | .setStyle(new NotificationCompat.BigPictureStyle() 128 | .bigPicture(Utils.getBitmapFromAsset(context, bundle.getString("image_uri")))) 129 | .setAutoCancel(true) 130 | .setSound(defaultSoundUri) 131 | .setContentIntent(pendingIntent); 132 | 133 | NotificationManager notificationManager = 134 | (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE); 135 | 136 | notificationManager.notify(7002, nBuilder.build()); 137 | } 138 | 139 | public static void sendNotification(String messageBody, Context context) { 140 | Intent intent = new Intent(context, org.godotengine.godot.Godot.class); 141 | intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP); 142 | 143 | PendingIntent pendingIntent = PendingIntent.getActivity( 144 | context, Utils.FIREBASE_NOTIFICATION_REQUEST, intent, PendingIntent.FLAG_ONE_SHOT); 145 | 146 | Uri defaultSoundUri = 147 | RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION); 148 | 149 | NotificationCompat.Builder nBuilder = new NotificationCompat.Builder(context, String.valueOf(NOTIFICATION_REQUEST_ID)) 150 | .setLargeIcon(BitmapFactory.decodeResource(context.getResources(), R.drawable.icon)) 151 | .setSmallIcon(R.drawable.notification_small_icon) 152 | .setContentTitle(context.getString(R.string.godot_project_name_string)) 153 | .setContentText(messageBody) 154 | .setAutoCancel(true) 155 | .setPriority(NotificationCompat.PRIORITY_DEFAULT) 156 | .setSound(defaultSoundUri) 157 | .setContentIntent(pendingIntent); 158 | 159 | NotificationManager notificationManager = 160 | (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE); 161 | 162 | // To support for Android 8+, notifications must have a unique channel and priority assigned to them. 163 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { 164 | CharSequence name = context.getString(R.string.godot_project_name_string); 165 | String description = context.getString(R.string.godot_project_name_string); 166 | int importance = NotificationManager.IMPORTANCE_DEFAULT; 167 | NotificationChannel channel = new NotificationChannel(String.valueOf(NOTIFICATION_REQUEST_ID), name, importance); 168 | channel.setDescription(description); 169 | // Register the channel with the system; you can't change the importance 170 | // or other notification behaviors after this 171 | notificationManager.createNotificationChannel(channel); 172 | } 173 | 174 | notificationManager.notify(7002, nBuilder.build()); 175 | } 176 | } 177 | -------------------------------------------------------------------------------- /android_src/Notification.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2017 FrogSquare. All Rights Reserved. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | **/ 16 | 17 | package org.godotengine.godot; 18 | 19 | import android.app.Activity; 20 | import android.app.NotificationManager; 21 | import android.app.PendingIntent; 22 | import android.content.Context; 23 | import android.content.Intent; 24 | import android.media.RingtoneManager; 25 | import android.net.Uri; 26 | import android.os.Bundle; 27 | import android.util.Log; 28 | 29 | import androidx.core.app.NotificationCompat; 30 | 31 | import org.json.JSONObject; 32 | import org.json.JSONException; 33 | 34 | import com.google.firebase.FirebaseApp; 35 | import com.google.firebase.iid.FirebaseInstanceId; 36 | import com.google.firebase.messaging.FirebaseMessaging; 37 | import com.google.firebase.messaging.RemoteMessage; 38 | 39 | import com.godot.game.R; 40 | 41 | import com.firebase.jobdispatcher.JobParameters; 42 | import com.firebase.jobdispatcher.JobService; 43 | import com.firebase.jobdispatcher.GooglePlayDriver; 44 | import com.firebase.jobdispatcher.FirebaseJobDispatcher; 45 | import com.firebase.jobdispatcher.Job; 46 | import com.firebase.jobdispatcher.Trigger; 47 | import com.firebase.jobdispatcher.Lifetime; 48 | import com.firebase.jobdispatcher.RetryStrategy; 49 | 50 | import org.apache.commons.codec.digest.DigestUtils; 51 | 52 | import java.util.Map; 53 | import java.util.HashMap; 54 | import java.util.Iterator; 55 | 56 | public class Notification { 57 | 58 | public static Notification getInstance (Activity p_activity) { 59 | if (mInstance == null) { 60 | synchronized (Notification.class) { 61 | mInstance = new Notification(p_activity); 62 | } 63 | } 64 | 65 | return mInstance; 66 | } 67 | 68 | public Notification (Activity p_activity) { 69 | activity = p_activity; 70 | } 71 | 72 | public void init (FirebaseApp firebaseApp) { 73 | mFirebaseApp = firebaseApp; 74 | String token = getFirebaseMessagingToken(); 75 | 76 | dispatcher = 77 | new FirebaseJobDispatcher(new GooglePlayDriver(activity.getApplicationContext())); 78 | dispatcher.cancelAll(); 79 | 80 | /** 81 | cancel_notification(activity.getString(R.string.godot_firebase_default_tag)); 82 | 83 | if (!Utils.get_db_value("shedule_tag").equals("0")) { 84 | cancel_notification(Utils.get_db_value("shedule_tag")); 85 | Utils.set_db_value("shedule_tag", "0"); 86 | } 87 | **/ 88 | 89 | Utils.d("GodotFireBase", "Firebase Cloud messaging token: " + token); 90 | 91 | // Perform task here..! 92 | if (Utils.get_db_value("notification_complete_task") != "0") { 93 | try { 94 | 95 | Dictionary data = new Dictionary(); 96 | if (!Utils.get_db_value("notification_task_data").equals("0")) { 97 | 98 | JSONObject obj = 99 | new JSONObject(Utils.get_db_value("notification_task_data")); 100 | 101 | Iterator iterator = obj.keys(); 102 | while (iterator.hasNext()) { 103 | String key = iterator.next(); 104 | Object value = obj.opt(key); 105 | 106 | if (value != null) { 107 | data.put(key, value); 108 | } 109 | } 110 | } 111 | 112 | Utils.callScriptCallback( 113 | Utils.get_db_value("notification_complete_task"), "Notification", "TaskComplete", data); 114 | 115 | } catch (JSONException e) { 116 | 117 | } 118 | 119 | KeyValueStorage.setValue("notification_complete_task", "0"); 120 | KeyValueStorage.setValue("notification_task_data", "0"); 121 | } 122 | } 123 | 124 | public void cancel_notification(final String tag) { 125 | dispatcher.cancel(tag); 126 | } 127 | 128 | public void subscribe(final String topic) { 129 | if (!isInitialized()) { return; } 130 | 131 | FirebaseMessaging.getInstance().subscribeToTopic(topic); 132 | } 133 | 134 | public Bundle get_bundle(Dictionary data) { 135 | JSONObject dict = new JSONObject(data); 136 | 137 | Bundle bundle = new Bundle(); 138 | bundle.putString("message", (String) data.get("message")); 139 | bundle.putString("image_uri", (String) data.get("image_uri")); 140 | 141 | bundle.putString("type", dict.optString("type", "text")); 142 | bundle.putString("title", 143 | dict.optString("title", activity.getString(R.string.godot_project_name_string))); 144 | bundle.putString("tag", 145 | dict.optString("tag", activity.getString(R.string.godot_firebase_default_tag))); 146 | 147 | return bundle; 148 | } 149 | 150 | public void shedule(Dictionary data, int seconds) { 151 | Bundle bundle = get_bundle(data); 152 | Utils.d("GodotFireBase", 153 | "Setting new Notification: " + bundle.toString() + ", Seconds: " + String.valueOf(seconds)); 154 | 155 | Job myJob = dispatcher.newJobBuilder() 156 | .setService(NotifyInTime.class) // the JobService that will be called 157 | .setTag(bundle.getString("tag")) // uniquely identifies the job 158 | .setRecurring(true) 159 | .setLifetime(Lifetime.FOREVER) 160 | .setTrigger(Trigger.executionWindow(seconds, seconds+60)) 161 | .setReplaceCurrent(true) 162 | .setRetryStrategy(RetryStrategy.DEFAULT_EXPONENTIAL) 163 | .setExtras(bundle) 164 | .build(); 165 | 166 | dispatcher.mustSchedule(myJob); 167 | } 168 | 169 | public void notifyOnComplete(Dictionary data, int seconds) { 170 | if (data.get("image_uri") == null && data.get("type") == "image") { 171 | Utils.d("GodotFireBase", 172 | "Notification: using Image in content need `image_uri` (i.e, \"res://image.png\")"); 173 | 174 | return; 175 | } 176 | 177 | dispatch_single_job(get_bundle(data), seconds); 178 | } 179 | 180 | public void notifyInSecs(final String message, final int seconds) { 181 | Bundle bundle = new Bundle(); 182 | bundle.putString("tag", activity.getString(R.string.godot_firebase_default_tag)); 183 | bundle.putString("title", activity.getString(R.string.godot_project_name_string)); 184 | bundle.putString("message", message); 185 | bundle.putString("type", "text"); 186 | 187 | dispatch_single_job(bundle, seconds); 188 | } 189 | 190 | private void dispatch_single_job(Bundle bundle, int seconds) { 191 | Utils.d("GodotFireBase", 192 | "Setting new Notification: " + bundle.toString() + ", Seconds: " + String.valueOf(seconds)); 193 | 194 | Job myJob = dispatcher.newJobBuilder() 195 | .setService(NotifyInTime.class) // the JobService that will be called 196 | .setTag(bundle.getString("tag")) // uniquely identifies the job 197 | .setLifetime(Lifetime.UNTIL_NEXT_BOOT) 198 | .setTrigger(Trigger.executionWindow(seconds, seconds+60)) 199 | .setReplaceCurrent(true) 200 | .setRetryStrategy(RetryStrategy.DEFAULT_EXPONENTIAL) 201 | .setExtras(bundle) 202 | .build(); 203 | 204 | dispatcher.mustSchedule(myJob); 205 | } 206 | 207 | public void notifyInMins (final String message, final int mins) { 208 | int seconds = mins * 60; 209 | notifyInSecs(message, seconds); 210 | } 211 | 212 | public void sendMessage (final String data) { 213 | FirebaseMessaging fm = FirebaseMessaging.getInstance(); 214 | 215 | String token = FirebaseInstanceId.getInstance().getToken(); 216 | String msgID = DigestUtils.sha1Hex(token + System.currentTimeMillis()); 217 | String SENDER_ID = "someID"; 218 | 219 | RemoteMessage.Builder RMBuilder = 220 | new RemoteMessage.Builder(SENDER_ID + "@gcm.googleapis.com"); 221 | RMBuilder.setMessageId(msgID); 222 | 223 | Map mapData = Utils.jsonToMap(data); 224 | 225 | for (Map.Entry entry : mapData.entrySet()) { 226 | RMBuilder.addData(entry.getKey(), entry.getValue().toString()); 227 | } 228 | 229 | fm.send(RMBuilder.build()); 230 | } 231 | 232 | public String getFirebaseMessagingToken() { 233 | if (!isInitialized()) { return "NULL"; } 234 | 235 | return FirebaseInstanceId.getInstance().getToken(); 236 | } 237 | 238 | private boolean isInitialized() { 239 | if (mFirebaseApp == null) { 240 | Utils.d("GodotFireBase", "Notification is not initialized."); 241 | return false; 242 | } else { 243 | return true; 244 | } 245 | } 246 | 247 | private static Context context; 248 | private static Activity activity; 249 | 250 | private FirebaseApp mFirebaseApp = null; 251 | private FirebaseJobDispatcher dispatcher = null; 252 | 253 | private static Notification mInstance = null; 254 | } 255 | -------------------------------------------------------------------------------- /android_src/NotifyInTime.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2017 FrogSquare. All Rights Reserved. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | **/ 16 | 17 | package org.godotengine.godot; 18 | 19 | import android.app.Activity; 20 | import android.content.Context; 21 | import android.os.Bundle; 22 | import android.os.Environment; 23 | import android.util.Log; 24 | import androidx.annotation.NonNull;; 25 | 26 | import com.firebase.jobdispatcher.JobParameters; 27 | import com.firebase.jobdispatcher.JobService; 28 | 29 | public class NotifyInTime extends JobService { 30 | 31 | @Override 32 | public boolean onStartJob(JobParameters job) { 33 | // Do some work here 34 | Utils.d("GodotFireBase", "Job Started."); 35 | 36 | Bundle bundle = job.getExtras(); 37 | Utils.d("GodotFireBase", "Message: " + bundle.getString("message")); 38 | 39 | if (bundle.getString("type").equals("image")) { 40 | MessagingService.sendNotification(bundle, this); 41 | } else { 42 | MessagingService.sendNotification(bundle.getString("message"), this); 43 | } 44 | 45 | return false; // Answers the question: "Is there still work going on?" 46 | } 47 | 48 | @Override 49 | public boolean onStopJob(JobParameters job) { 50 | Utils.d("GodotFireBase", "Job Stopped."); 51 | 52 | return false; // Answers the question: "Should this job be retried?" 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /android_src/RemoteConfig.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2017 FrogSquare. All Rights Reserved. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | **/ 16 | 17 | package org.godotengine.godot; 18 | 19 | import android.app.Activity; 20 | import android.content.Context; 21 | import android.os.Bundle; 22 | import android.os.Environment; 23 | import androidx.annotation.NonNull;; 24 | import android.util.Log; 25 | 26 | import com.google.android.gms.tasks.OnCompleteListener; 27 | import com.google.android.gms.tasks.Task; 28 | import com.google.firebase.FirebaseApp; 29 | import com.google.firebase.remoteconfig.FirebaseRemoteConfig; 30 | import com.google.firebase.remoteconfig.FirebaseRemoteConfigSettings; 31 | 32 | import com.godot.game.BuildConfig; 33 | import com.godot.game.R; 34 | 35 | import java.util.Map; 36 | 37 | public class RemoteConfig { 38 | 39 | public static RemoteConfig getInstance (Activity p_activity) { 40 | if (mInstance == null) { 41 | mInstance = new RemoteConfig(p_activity); 42 | } 43 | 44 | return mInstance; 45 | } 46 | 47 | public RemoteConfig (Activity p_activity) { 48 | activity = p_activity; 49 | } 50 | 51 | public void init (FirebaseApp firebaseApp) { 52 | mFirebaseApp = firebaseApp; 53 | 54 | mFirebaseRemoteConfig = FirebaseRemoteConfig.getInstance(); 55 | FirebaseRemoteConfigSettings configSettings = new FirebaseRemoteConfigSettings.Builder() 56 | .setDeveloperModeEnabled(BuildConfig.DEBUG) 57 | .build(); 58 | 59 | mFirebaseRemoteConfig.setConfigSettings(configSettings); 60 | mFirebaseRemoteConfig.setDefaults(R.xml.remote_config_defaults); 61 | 62 | fetchRemoteConfigs(); 63 | } 64 | 65 | private void fetchRemoteConfigs () { 66 | Utils.d("GodotFireBase", "Loading Remote Configs"); 67 | 68 | long cacheExpiration = 3600; 69 | 70 | if (mFirebaseRemoteConfig.getInfo().getConfigSettings().isDeveloperModeEnabled()) { 71 | cacheExpiration = 0; 72 | } 73 | 74 | mFirebaseRemoteConfig.fetch(cacheExpiration) 75 | .addOnCompleteListener(activity, new OnCompleteListener() { 76 | 77 | @Override 78 | public void onComplete(@NonNull Task task) { 79 | if (task.isSuccessful()) { 80 | Utils.d("GodotFireBase", "RemoteConfig, Fetch Successed"); 81 | 82 | mFirebaseRemoteConfig.activateFetched(); 83 | } else { 84 | Utils.d("GodotFireBase", "RemoteConfig, Fetch Failed"); 85 | } 86 | 87 | // Utils.d("GodotFireBase", "Fetched Value: " + getValue("firebase_remoteconfig_test")); 88 | } 89 | }); 90 | } 91 | 92 | public void setDefaultsFile (final String filePath) { 93 | if (!isInitialized()) { return; } 94 | 95 | Utils.d("GodotFireBase", "Loading Defaults from file:" + filePath); 96 | 97 | String data = Utils.readFromFile(filePath, activity.getApplicationContext()); 98 | data = data.replaceAll("\\s+", ""); 99 | 100 | setDefaults (data); 101 | } 102 | 103 | public void setDefaults(final String defaults) { 104 | if (!isInitialized()) { return; } 105 | 106 | Map defaultsMap = Utils.jsonToMap(defaults); 107 | Utils.d("GodotFireBase", "RemoteConfig: Setting Default values, " + defaultsMap.toString()); 108 | 109 | mFirebaseRemoteConfig.setDefaults(defaultsMap); 110 | } 111 | 112 | public String getValue (final String key) { 113 | if (!isInitialized()) { return "NULL"; } 114 | 115 | Utils.d("GodotFireBase", "Getting Remote config value for: " + key); 116 | return mFirebaseRemoteConfig.getValue(key).asString(); 117 | } 118 | 119 | public String getValue (final String key, final String namespace) { 120 | if (!isInitialized()) { return "NULL"; } 121 | 122 | Utils.d("GodotFireBase", "Getting Remote config value for { " + key + " : " + namespace + " }"); 123 | return mFirebaseRemoteConfig.getValue(key, namespace).asString(); 124 | } 125 | 126 | private boolean isInitialized() { 127 | if (mFirebaseApp == null) { 128 | Utils.d("GodotFireBase", "RemoteConfig is not initialized."); 129 | return false; 130 | } else { 131 | return true; 132 | } 133 | } 134 | 135 | private static Activity activity = null; 136 | private static Context context = null; 137 | private static RemoteConfig mInstance = null; 138 | 139 | private FirebaseApp mFirebaseApp = null; 140 | private FirebaseRemoteConfig mFirebaseRemoteConfig = null; 141 | } 142 | -------------------------------------------------------------------------------- /android_src/Share.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2019 BunbySoft. All Rights Reserved. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | **/ 16 | 17 | 18 | package org.godotengine.godot; 19 | 20 | import android.app.Activity; 21 | import android.content.Intent; 22 | import com.google.firebase.FirebaseApp; 23 | 24 | public class Share { 25 | public static Share getInstance(Activity p_activity) { 26 | if (mInstance == null) { 27 | mInstance = new Share(p_activity); 28 | } 29 | return mInstance; 30 | } 31 | 32 | public Share (Activity p_activity) { 33 | activity = p_activity; 34 | } 35 | 36 | public void init (FirebaseApp firebaseApp) { 37 | mFirebaseApp = firebaseApp; 38 | } 39 | 40 | public void share(String text, String subject) { 41 | Intent sendIntent = new Intent(); 42 | sendIntent.setAction(Intent.ACTION_SEND); 43 | sendIntent.putExtra(Intent.EXTRA_TEXT, text); 44 | if (subject != null && !subject.isEmpty()) { 45 | sendIntent.putExtra(Intent.EXTRA_SUBJECT, subject); 46 | } 47 | sendIntent.setType("text/plain"); 48 | activity.startActivity(sendIntent); 49 | } 50 | 51 | private static Activity activity = null; 52 | private static Share mInstance = null; 53 | 54 | private FirebaseApp mFirebaseApp = null; 55 | } 56 | -------------------------------------------------------------------------------- /android_src/auth/AnonymousAuth.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2017 FrogSquare. All Rights Reserved. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | **/ 16 | 17 | package org.godotengine.godot.auth; 18 | 19 | import android.app.Activity; 20 | import android.content.Context; 21 | import android.content.Intent; 22 | import android.content.DialogInterface; 23 | import android.os.Bundle; 24 | import android.util.Log; 25 | import androidx.annotation.NonNull; 26 | 27 | import com.google.android.gms.tasks.OnCompleteListener; 28 | import com.google.android.gms.tasks.Task; 29 | import com.google.firebase.auth.AuthCredential; 30 | import com.google.firebase.auth.AuthResult; 31 | import com.google.firebase.auth.FirebaseAuth; 32 | import com.google.firebase.auth.FirebaseUser; 33 | 34 | import org.godotengine.godot.FireBase; 35 | import org.godotengine.godot.KeyValueStorage; 36 | import org.godotengine.godot.Utils; 37 | 38 | import org.json.JSONArray; 39 | import org.json.JSONObject; 40 | import org.json.JSONException; 41 | 42 | import java.util.Arrays; 43 | import java.util.ArrayList; 44 | import java.util.List; 45 | 46 | public class AnonymousAuth { 47 | 48 | public static AnonymousAuth getInstance (Activity p_activity) { 49 | if (mInstance == null) { 50 | mInstance = new AnonymousAuth(p_activity); 51 | } 52 | 53 | return mInstance; 54 | } 55 | 56 | public AnonymousAuth(Activity p_activity) { 57 | activity = p_activity; 58 | } 59 | 60 | public void init() { 61 | // Initialize listener. 62 | // ... 63 | 64 | mAuth = FirebaseAuth.getInstance(); 65 | mAuthListener = new FirebaseAuth.AuthStateListener() { 66 | @Override 67 | public void onAuthStateChanged(@NonNull FirebaseAuth firebaseAuth) { 68 | FirebaseUser user = firebaseAuth.getCurrentUser(); 69 | 70 | if (user != null) { 71 | // User is signed in 72 | Utils.d("GodotFireBase", 73 | "Anonymous:onAuthStateChanged:signed_in:" + user.getUid()); 74 | 75 | successSignIn(user); 76 | } else { 77 | // User is signed out 78 | Utils.d("GodotFireBase", "Anonymous:onAuthStateChanged:signed_out"); 79 | successSignOut(); 80 | } 81 | 82 | // update firebase auth dets. 83 | } 84 | }; 85 | 86 | onStart(); 87 | } 88 | 89 | public void signIn() { 90 | mAuth.signInAnonymously() 91 | .addOnCompleteListener(activity, new OnCompleteListener() { 92 | @Override 93 | public void onComplete(@NonNull Task task) { 94 | if (task.isSuccessful()) { 95 | //Sign in success, update with the signed-in user's information 96 | Utils.d("GodotFireBase", "Anonymous:SignIn:Success"); 97 | } 98 | } 99 | 100 | }); 101 | } 102 | 103 | public void signUp (final int authType) { 104 | /** 105 | AuthCredential credential = GoogleAuthProvider.getCredential(googleIdToken, null); 106 | AuthCredential credential = FacebookAuthProvider.getCredential(token.getToken()); 107 | AuthCredential credential = EmailAuthProvider.getCredential(email, password); 108 | 109 | mAuth.getCurrentUser().linkWithCredential(credential) 110 | .addOnCompleteListener(activity, new OnCompleteListener() { 111 | @Override 112 | public void onComplete(@NonNull Task task) { 113 | if (task.isSuccessful()) { 114 | 115 | } else { 116 | 117 | } 118 | 119 | // ... 120 | } 121 | }); 122 | **/ 123 | } 124 | 125 | public void signOut() { 126 | mAuth.signOut(); 127 | } 128 | 129 | protected void successSignIn (FirebaseUser user) { 130 | isAnonymousConnected = true; 131 | } 132 | 133 | protected void successSignOut () { 134 | isAnonymousConnected =false; 135 | } 136 | 137 | public boolean isConnected () { 138 | return isAnonymousConnected; 139 | } 140 | 141 | public void onActivityResult(int requestCode, int resultCode, Intent data) { 142 | // ... 143 | } 144 | 145 | public void onStart () { 146 | FirebaseUser user = mAuth.getCurrentUser(); 147 | if (user != null) { successSignIn(user); } 148 | 149 | mAuth.addAuthStateListener(mAuthListener); 150 | } 151 | 152 | public void onStop () { 153 | if (mAuthListener != null) { mAuth.removeAuthStateListener(mAuthListener); } 154 | 155 | isAnonymousConnected = false; 156 | activity = null; 157 | } 158 | 159 | private static Activity activity = null; 160 | private static AnonymousAuth mInstance = null; 161 | 162 | private static boolean isAnonymousConnected = false; 163 | 164 | private FirebaseAuth mAuth; 165 | private FirebaseAuth.AuthStateListener mAuthListener; 166 | } 167 | -------------------------------------------------------------------------------- /android_src/auth/Auth.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2017 FrogSquare. All Rights Reserved. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | **/ 16 | 17 | package org.godotengine.godot.auth; 18 | 19 | import android.app.Activity; 20 | import android.content.Intent; 21 | import android.os.Bundle; 22 | import android.util.Log; 23 | import androidx.annotation.NonNull; 24 | import androidx.annotation.Nullable; 25 | 26 | import com.google.firebase.FirebaseApp; 27 | import com.google.firebase.auth.FirebaseAuth; 28 | import com.google.firebase.auth.FirebaseUser; 29 | import com.google.firebase.auth.GetTokenResult; 30 | import com.google.android.gms.tasks.OnCompleteListener; 31 | import com.google.android.gms.tasks.Task; 32 | 33 | import org.json.JSONObject; 34 | import org.json.JSONException; 35 | 36 | import org.godotengine.godot.Utils; 37 | 38 | public class Auth { 39 | 40 | public static final int GOOGLE_AUTH = 0x0003; 41 | public static final int FACEBOOK_AUTH = 0x0004; 42 | public static final int TWITTER_AUTH = 0x0005; 43 | public static final int EMAIL_AUTH = 0x0006; 44 | public static final int ANONYMOUS_AUTH = 0x0007; 45 | 46 | public static Auth getInstance (Activity p_activity) { 47 | if (mInstance == null) { 48 | mInstance = new Auth(p_activity); 49 | } 50 | 51 | return mInstance; 52 | } 53 | 54 | public Auth(Activity p_activity) { 55 | activity = p_activity; 56 | } 57 | 58 | public void init (FirebaseApp firebaseApp) { 59 | mFirebaseApp = firebaseApp; 60 | } 61 | 62 | public void configure (final String configData) { 63 | try { config = new JSONObject(configData); } 64 | catch (JSONException e) { Utils.d("GodotFireBase", "JSONException, parse error: " + e.toString()); } 65 | 66 | //AuthGoogle++ 67 | if (config.optBoolean("Google", false)) { 68 | GoogleSignIn.getInstance(activity).init(); 69 | } 70 | //AuthGoogle-- 71 | 72 | //AuthFacebook++ 73 | if (config.optBoolean("Facebook", false)) { 74 | FacebookSignIn.getInstance(activity).init(); 75 | } 76 | //AuthFacebook-- 77 | 78 | //AuthTwitter++ 79 | if (config.optBoolean("Twitter", false)) { 80 | TwitterSignIn.getInstance(activity).init(); 81 | } 82 | //AuthTwitter-- 83 | } 84 | 85 | public void sign_in (final int type_id) { 86 | if (!isInitialized()) { return; } 87 | 88 | Utils.d("GodotFireBase", "Auth:SignIn:TAG:" + type_id); 89 | 90 | switch (type_id) { 91 | //AuthGoogle++ 92 | case GOOGLE_AUTH: 93 | Utils.d("GodotFireBase", "Auth:Google:SignIn"); 94 | GoogleSignIn.getInstance(activity).signIn(); 95 | break; 96 | //AuthGoogle-- 97 | //AuthFacebook++ 98 | case FACEBOOK_AUTH: 99 | Utils.d("GodotFireBase", "Auth:Facebook:SignIn"); 100 | FacebookSignIn.getInstance(activity).signIn(); 101 | break; 102 | //AuthFacebook-- 103 | //AuthTwitter++ 104 | case TWITTER_AUTH: 105 | Utils.d("GodotFireBase", "Auth twitter sign in"); 106 | TwitterSignIn.getInstance(activity).signIn(); 107 | break; 108 | //AuthTwitter-- 109 | case ANONYMOUS_AUTH: 110 | Utils.d("GodotFireBase", "Auth:Anonymous:SignIn"); 111 | AnonymousAuth.getInstance(activity).signIn(); 112 | break; 113 | default: 114 | Utils.d("GodotFireBase", "Auth:Type:NotAvailable"); 115 | break; 116 | } 117 | } 118 | 119 | public void sign_out (final int type_id) { 120 | if (!isInitialized()) { return; } 121 | 122 | Utils.d("GodotFireBase", "Auth:SignOut:TAG:" + type_id); 123 | 124 | switch (type_id) { 125 | //AuthGoogle++ 126 | case GOOGLE_AUTH: 127 | Utils.d("GodotFireBase", "Auth:Google:SignOut"); 128 | GoogleSignIn.getInstance(activity).signOut(); 129 | break; 130 | //AuthGoogle-- 131 | //AuthFacebook++ 132 | case FACEBOOK_AUTH: 133 | Utils.d("GodotFireBase", "Auth:Facebook:SignOut"); 134 | FacebookSignIn.getInstance(activity).signOut(); 135 | break; 136 | //AuthFacebook-- 137 | //AuthTwitter++ 138 | case TWITTER_AUTH: 139 | Utils.d("GodotFireBase", "Auth twitter sign out"); 140 | TwitterSignIn.getInstance(activity).signOut(); 141 | break; 142 | //AuthTwitter-- 143 | case ANONYMOUS_AUTH: 144 | Utils.d("GodotFireBase", "Auth:Anonymous:SignOut"); 145 | AnonymousAuth.getInstance(activity).signOut(); 146 | break; 147 | default: 148 | Utils.d("GodotFireBase", "Auth:Type:NotAvailable."); 149 | break; 150 | } 151 | } 152 | 153 | public void revoke(final int type_id) { 154 | if (!isInitialized()) { return; } 155 | 156 | Utils.d("GodotFireBase", "FB:Auth:Revoke:" + type_id); 157 | 158 | switch (type_id) { 159 | //AuthGoogle++ 160 | case GOOGLE_AUTH: 161 | Utils.d("GodotFireBase", "FB:Revoke:Google"); 162 | GoogleSignIn.getInstance(activity).revokeAccess(); 163 | break; 164 | //AuthGoogle-- 165 | //AuthFacebook++ 166 | case FACEBOOK_AUTH: 167 | Utils.d("GodotFireBase", "FB:Revoke:Facebook"); 168 | FacebookSignIn.getInstance(activity).revokeAccess(); 169 | break; 170 | //AuthFacebook-- 171 | case ANONYMOUS_AUTH: 172 | Utils.d("GodotFireBase", "FB:Revoke:Anonymous"); 173 | break; 174 | default: 175 | Utils.d("GodotFireBase", "FB:Auth:Type:NotFound"); 176 | } 177 | 178 | } 179 | 180 | public void signUp(final int type_id) { 181 | if (!isInitialized()) { return; } 182 | 183 | Utils.d("GodotFireBase", "Auth:Linking:" + type_id); 184 | /** 185 | TODO: Signup/LinkAccount from Anonymous account. 186 | **/ 187 | } 188 | 189 | 190 | @Nullable 191 | public FirebaseUser getCurrentUser() { 192 | if (!isInitialized()) { return null; } 193 | 194 | FirebaseUser ret = FirebaseAuth.getInstance().getCurrentUser(); 195 | if (ret == null) { Utils.d("GodotFireBase", "Auth:UserNotSignedIn"); } 196 | 197 | return ret; 198 | } 199 | 200 | public String getUserDetails(final int type_id) { 201 | if (!isInitialized()) { return "NULL"; } 202 | 203 | Utils.d("GodotFireBase", "UserDetails:TAG:" + type_id); 204 | 205 | //AuthGoogle++ 206 | if (type_id == GOOGLE_AUTH && GoogleSignIn.getInstance(activity).isConnected()) { 207 | Utils.d("GodotFireBase", "Getting Google user details"); 208 | return GoogleSignIn.getInstance(activity).getUserDetails(); 209 | } 210 | //AuthGoogle-- 211 | 212 | //AuthFacebook++ 213 | if (type_id == FACEBOOK_AUTH && FacebookSignIn.getInstance(activity).isConnected()) { 214 | Utils.d("GodotFireBase", "Getting Facebook user details"); 215 | return FacebookSignIn.getInstance(activity).getUserDetails(); 216 | } 217 | //AuthFacebook-- 218 | 219 | return "NULL"; 220 | } 221 | 222 | public void getIdToken() { 223 | if (!isInitialized()) { return; } 224 | 225 | FirebaseUser user = FirebaseAuth.getInstance().getCurrentUser(); 226 | if (user == null) { return; } 227 | 228 | user.getIdToken(true).addOnCompleteListener(new OnCompleteListener() { 229 | public void onComplete(@NonNull Task task) { 230 | if (task.isSuccessful()) { 231 | String idToken = task.getResult().getToken(); 232 | Utils.callScriptFunc("Auth", "getIdToken", idToken); 233 | } else { 234 | Utils.callScriptFunc("Auth", "getIdToken", null); 235 | } 236 | } 237 | }); 238 | } 239 | 240 | //AuthFacebook++ 241 | public String getFacebookPermissions() { 242 | return FacebookSignIn.getInstance(activity).getUserPermissions(); 243 | } 244 | 245 | public boolean isPermissionGiven(final String permission) { 246 | return FacebookSignIn.getInstance(activity).isPermissionGiven(permission); 247 | } 248 | 249 | public void revokeFacebookPermission(final String permission) { 250 | if (!isInitialized() && !isConnected(FACEBOOK_AUTH)) { return; } 251 | 252 | Utils.d("GodotFireBase", "Auth:Ask:RevokePermission: " + permission); 253 | FacebookSignIn.getInstance(activity).revokePermission(permission); 254 | } 255 | 256 | public void askForPermission( 257 | final String title, final String message, final String permission, final boolean read) { 258 | if (!isInitialized() && !isConnected(FACEBOOK_AUTH)) { return; } 259 | 260 | Utils.d("GodotFireBase", "Auth:Ask:Permission: " + permission); 261 | FacebookSignIn.getInstance(activity) 262 | .askForPermission(title, message, permission, read); 263 | } 264 | //AuthFacebook-- 265 | 266 | public boolean isConnected(final int type_id) { 267 | Utils.d("GodotFireBase", "Auth:Getting:Status"); 268 | 269 | switch (type_id) { 270 | //AuthGoogle++ 271 | case GOOGLE_AUTH: 272 | Utils.d("GodotFireBase", "Auth:Status:Google:True"); 273 | return GoogleSignIn.getInstance(activity).isConnected(); 274 | //AuthGoogle-- 275 | //AuthFacebook++ 276 | case FACEBOOK_AUTH: 277 | Utils.d("GodotFireBase", "Auth:Status:Facebook:True"); 278 | return FacebookSignIn.getInstance(activity).isConnected(); 279 | //AuthFacebook-- 280 | case ANONYMOUS_AUTH: 281 | Utils.d("GodotFireBase", "Auth:Status:Anonymous:True"); 282 | return AnonymousAuth.getInstance(activity).isConnected(); 283 | default: 284 | Utils.d("GodotFireBase", "Auth:Type:NotAvailable"); 285 | break; 286 | } 287 | 288 | Utils.d("GodotFireBase", "Auth:Status:False"); 289 | return false; 290 | } 291 | 292 | private boolean isInitialized() { 293 | if (mFirebaseApp == null) { 294 | Utils.d("GodotFireBase", "FireBase Auth, not initialized"); 295 | return false; 296 | } 297 | 298 | if (config == null) { 299 | Utils.d("GodotFireBase", "FireBase Auth, not Configured"); 300 | return false; 301 | } 302 | 303 | return true; 304 | } 305 | 306 | public void onActivityResult(int requestCode, int resultCode, Intent data) { 307 | if (!isInitialized()) { return; } 308 | 309 | //AuthGoogle++ 310 | if (config.optBoolean("Google", false)) { 311 | GoogleSignIn.getInstance(activity) 312 | .onActivityResult(requestCode, resultCode, data); 313 | } 314 | //AuthGoogle-- 315 | 316 | //AuthFacebook++ 317 | if (config.optBoolean("Facebook", false)) { 318 | FacebookSignIn.getInstance(activity) 319 | .onActivityResult(requestCode, resultCode, data); 320 | } 321 | //AuthFacebook-- 322 | 323 | //AuthTwitter++ 324 | if (config.optBoolean("Twitter", false)) { 325 | TwitterSignIn.getInstance(activity) 326 | .onActivityResult(requestCode, resultCode, data); 327 | } 328 | //AuthTwitter-- 329 | } 330 | 331 | public void onStart() { 332 | if (!isInitialized()) { return; } 333 | 334 | //AuthGoogle++ 335 | if (config.optBoolean("Google", false)) { 336 | GoogleSignIn.getInstance(activity).onStart(); 337 | } 338 | //AuthGoogle-- 339 | 340 | //AuthFacebook++ 341 | if (config.optBoolean("Facebook", false)) { 342 | FacebookSignIn.getInstance(activity).onStart(); 343 | } 344 | //AuthFacebook-- 345 | 346 | //AuthTwitter++ 347 | if (config.optBoolean("Twitter", false)) { 348 | TwitterSignIn.getInstance(activity).onStart(); 349 | } 350 | //AuthTwitter-- 351 | 352 | } 353 | 354 | public void onPause() { 355 | 356 | } 357 | 358 | public void onResume () { 359 | 360 | } 361 | 362 | public void onStop() { 363 | if (!isInitialized()) { return; } 364 | 365 | //AuthGoogle++ 366 | if (config.optBoolean("Google", false)) { 367 | GoogleSignIn.getInstance(activity).onStop(); 368 | } 369 | //AuthGoogle-- 370 | 371 | //AuthFacebook++ 372 | if (config.optBoolean("Facebook", false)) { 373 | FacebookSignIn.getInstance(activity).onStop(); 374 | } 375 | //AuthFacebook-- 376 | 377 | //AuthTwitter++ 378 | if (config.optBoolean("Twitter", false)) { 379 | TwitterSignIn.getInstance(activity).onStop(); 380 | } 381 | //AuthTwitter-- 382 | } 383 | 384 | private static Activity activity = null; 385 | private static Auth mInstance = null; 386 | 387 | private static JSONObject config = null; 388 | 389 | private FirebaseApp mFirebaseApp = null; 390 | } 391 | 392 | 393 | -------------------------------------------------------------------------------- /android_src/auth/EmailAndPassword.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2017 FrogSquare. All Rights Reserved. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | **/ 16 | 17 | package org.godotengine.godot.auth; 18 | 19 | import android.app.Activity; 20 | import android.os.Bundle; 21 | import android.text.TextUtils; 22 | import android.util.Log; 23 | import androidx.annotation.NonNull; 24 | 25 | import com.google.android.gms.tasks.OnCompleteListener; 26 | import com.google.android.gms.tasks.Task; 27 | import com.google.firebase.auth.AuthResult; 28 | import com.google.firebase.auth.FirebaseAuth; 29 | import com.google.firebase.auth.FirebaseUser; 30 | 31 | import com.godot.game.R; 32 | 33 | import org.json.JSONObject; 34 | import org.json.JSONException; 35 | 36 | import org.godotengine.godot.Utils; 37 | 38 | public class EmailAndPassword { 39 | 40 | public static EmailAndPassword getInstance (Activity p_activity) { 41 | if (mInstance == null) { 42 | mInstance = new EmailAndPassword(p_activity); 43 | } 44 | 45 | return mInstance; 46 | } 47 | 48 | public EmailAndPassword(Activity p_activity) { 49 | activity = p_activity; 50 | } 51 | 52 | public void init() { 53 | // Initialize listener. 54 | // ... 55 | 56 | mAuth = FirebaseAuth.getInstance(); 57 | 58 | mAuthListener = new FirebaseAuth.AuthStateListener() { 59 | 60 | @Override 61 | public void onAuthStateChanged(@NonNull FirebaseAuth firebaseAuth) { 62 | FirebaseUser user = firebaseAuth.getCurrentUser(); 63 | if (user != null) { 64 | Utils.d("GodotFireBase", "E&P:onAuthStateChanged:signed_in:" + user.getUid()); 65 | successSignIn(user); 66 | } else { 67 | // User is signed out 68 | Utils.d("GodotFireBase", "E&P:onAuthStateChanged:signed_out"); 69 | successSignOut(); 70 | } 71 | 72 | // update user details; 73 | } 74 | }; 75 | } 76 | 77 | public void createAccount(final String email, final String password) { 78 | Utils.d("GodotFireBase", "E&P:CreateAccount:" + email); 79 | 80 | mAuth.createUserWithEmailAndPassword(email, password) 81 | .addOnCompleteListener(activity, new OnCompleteListener() { 82 | @Override 83 | public void onComplete(@NonNull Task task) { 84 | Utils.d("GodotFireBase", "E&P:CreateUserWithEmail:onComplete:" + task.isSuccessful()); 85 | 86 | // If sign in fails, display a message to the user. If sign in succeeds 87 | // the auth state listener will be notified and logic to handle the 88 | // signed in user can be handled in the listener. 89 | 90 | if (!task.isSuccessful()) { 91 | Utils.d("GodotFireBase", "E&P:CreateAccount:Error"); 92 | } 93 | } 94 | }); 95 | } 96 | 97 | public void signIn(final String email, final String password) { 98 | 99 | } 100 | 101 | public void signOut() { 102 | mAuth.signOut(); 103 | } 104 | 105 | private void successSignIn(FirebaseUser user) { 106 | Utils.d("GodotFireBase", "E&P:SignIn:Success"); 107 | 108 | try { 109 | currentEPUser.put("name", user.getDisplayName()); 110 | currentEPUser.put("email_id", user.getEmail()); 111 | currentEPUser.put("photo_uri", user.getPhotoUrl()); 112 | } catch(JSONException e) { Utils.d("GodotFireBase", "E&P:JSON:Parse:Error"); } 113 | 114 | // Utils.callScriptFunc("Auth", "login", "true"); 115 | } 116 | 117 | private void successSignOut() { 118 | 119 | // Utils.callScriptFunc("Auth", "login", "false"); 120 | } 121 | 122 | private void sendEmailVerification() { 123 | 124 | } 125 | 126 | public void onStart() { 127 | mAuth.addAuthStateListener(mAuthListener); 128 | } 129 | 130 | public void onStop() { 131 | if (mAuthListener != null) { mAuth.removeAuthStateListener(mAuthListener); } 132 | } 133 | 134 | private static Activity activity = null; 135 | private static EmailAndPassword mInstance = null; 136 | 137 | private FirebaseAuth mAuth; 138 | private FirebaseAuth.AuthStateListener mAuthListener; 139 | 140 | private JSONObject currentEPUser = new JSONObject(); 141 | } 142 | -------------------------------------------------------------------------------- /android_src/auth/FacebookSignIn.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2017 FrogSquare. All Rights Reserved. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | **/ 16 | 17 | package org.godotengine.godot.auth; 18 | 19 | import android.app.*; 20 | import android.content.Context; 21 | import android.content.Intent; 22 | import android.content.DialogInterface; 23 | import android.os.Bundle; 24 | import android.util.Log; 25 | import androidx.annotation.NonNull; 26 | 27 | import com.facebook.AccessToken; 28 | import com.facebook.AccessTokenTracker; 29 | import com.facebook.appevents.AppEventsLogger; 30 | import com.facebook.CallbackManager; 31 | import com.facebook.FacebookCallback; 32 | import com.facebook.FacebookException; 33 | import com.facebook.FacebookSdk; 34 | import com.facebook.FacebookRequestError; 35 | import com.facebook.HttpMethod; 36 | import com.facebook.GraphRequest; 37 | import com.facebook.GraphRequestBatch; 38 | import com.facebook.GraphResponse; 39 | import com.facebook.login.LoginManager; 40 | import com.facebook.login.LoginResult; 41 | import com.facebook.Profile; 42 | import com.facebook.ProfileTracker; 43 | import com.facebook.share.model.GameRequestContent; 44 | import com.facebook.share.model.GameRequestContent.ActionType; 45 | import com.facebook.share.widget.GameRequestDialog; 46 | 47 | import com.google.android.gms.tasks.OnCompleteListener; 48 | import com.google.android.gms.tasks.Task; 49 | import com.google.firebase.auth.AuthCredential; 50 | import com.google.firebase.auth.AuthResult; 51 | import com.google.firebase.auth.FacebookAuthProvider; 52 | import com.google.firebase.auth.FirebaseAuth; 53 | import com.google.firebase.auth.FirebaseUser; 54 | import com.google.firebase.auth.UserInfo; 55 | 56 | import com.godot.game.R; 57 | 58 | import java.util.Arrays; 59 | import java.util.ArrayList; 60 | import java.util.List; 61 | import java.util.Collection; 62 | 63 | import org.json.JSONArray; 64 | import org.json.JSONObject; 65 | import org.json.JSONException; 66 | 67 | import org.godotengine.godot.KeyValueStorage; 68 | import org.godotengine.godot.Utils; 69 | 70 | public class FacebookSignIn { 71 | 72 | public static FacebookSignIn getInstance (Activity p_activity) { 73 | if (mInstance == null) { 74 | mInstance = new FacebookSignIn(p_activity); 75 | } 76 | 77 | return mInstance; 78 | } 79 | 80 | public FacebookSignIn(Activity p_activity) { 81 | activity = p_activity; 82 | } 83 | 84 | public void init() { 85 | // Initialize listener. 86 | // ... 87 | 88 | FacebookSdk.sdkInitialize(activity); 89 | // FacebookSdk.setApplicationId(activity.getString(R.string.facebook_app_id)); 90 | 91 | mAuth = FirebaseAuth.getInstance(); 92 | mAuthListener = new FirebaseAuth.AuthStateListener() { 93 | 94 | @Override 95 | public void onAuthStateChanged(@NonNull FirebaseAuth firebaseAuth) { 96 | FirebaseUser user = firebaseAuth.getCurrentUser(); 97 | if (user != null) { 98 | for (UserInfo usr : user.getProviderData()) { 99 | if (usr.getProviderId().equals("facebook.com")) { 100 | Utils.d("GodotFireBase", "FB:AuthStateChanged:signed_in:"+ 101 | user.getUid()); 102 | successSignin(user); 103 | } 104 | } 105 | } else { 106 | // User is signed out 107 | Utils.d("GodotFireBase", "FB:onAuthStateChanged:signed_out"); 108 | successSignOut(); 109 | } 110 | 111 | // update user details; 112 | } 113 | }; 114 | 115 | // AppEventsLogger.activityApp(activity); 116 | 117 | initCallbacks(); 118 | onStart(); 119 | 120 | Utils.d("GodotFireBase", "Facebook auth initialized."); 121 | } 122 | 123 | private void initCallbacks() { 124 | callbackManager = CallbackManager.Factory.create(); 125 | /** 126 | requestDialog = new GameRequestDialog(activity); 127 | requestDialog.registerCallback(callbackManager, 128 | new FacebookCallback() { 129 | @Override 130 | public void onSuccess (GameRequestDialog.Result result) { 131 | Utils.d("GodotFireBase", "Facebook request sent."); 132 | } 133 | }); 134 | **/ 135 | 136 | LoginManager.getInstance().registerCallback(callbackManager, 137 | new FacebookCallback() { 138 | @Override 139 | public void onSuccess(LoginResult result) { 140 | Utils.d("GodotFireBase", "FB:Connected"); 141 | handleAccessToken(result.getAccessToken()); 142 | } 143 | 144 | @Override 145 | public void onCancel() { 146 | Utils.d("GodotFireBase", "FB:Canceled"); 147 | } 148 | 149 | @Override 150 | public void onError(FacebookException exception) { 151 | Utils.d("GodotFireBase", "FB:Error, " + exception.toString()); 152 | } 153 | }); 154 | 155 | mAccessTokenTracker = new AccessTokenTracker() { 156 | @Override 157 | protected void onCurrentAccessTokenChanged( 158 | AccessToken old, AccessToken current) { 159 | 160 | Utils.d("GodotFireBase", "FB:AccessToken:Changed"); 161 | if (current == null) { successSignOut(); } 162 | else { 163 | accessToken = current; 164 | 165 | try { 166 | currentFBUser 167 | .put("token", accessToken.getToken().toString()); 168 | } catch (JSONException e) { 169 | Utils.d("GodotFireBase", "FB:JSON:Error:162:" + e.toString()); 170 | } 171 | } 172 | } 173 | }; 174 | 175 | mProfileTracker = new ProfileTracker() { 176 | @Override 177 | protected void onCurrentProfileChanged(Profile old, Profile current) { 178 | Utils.d("GodotFireBase", "FB:Profile:Changed"); 179 | profile = current; 180 | } 181 | }; 182 | 183 | mAccessTokenTracker.startTracking(); 184 | mProfileTracker.startTracking(); 185 | 186 | accessToken = AccessToken.getCurrentAccessToken(); 187 | profile = Profile.getCurrentProfile(); 188 | } 189 | 190 | public boolean isPermissionGiven (final String permission) { 191 | Utils.d("GodotFireBase", "FB:Checking:Available:Permissions:For: " + permission); 192 | accessToken = AccessToken.getCurrentAccessToken(); 193 | 194 | if (accessToken == null && accessToken.isExpired()) { 195 | Utils.d("GodotFireBase", "FB:Token:NotValid"); 196 | return false; 197 | } 198 | 199 | return (mUserPermissions.contains(permission)); 200 | } 201 | 202 | public void getPermissions() { 203 | String uri = "me/permissions/"; 204 | 205 | new GraphRequest(AccessToken.getCurrentAccessToken(), 206 | uri, null, HttpMethod.GET, 207 | new GraphRequest.Callback() { 208 | public void onCompleted(GraphResponse response) { 209 | /* handle the result */ 210 | JSONArray data = response.getJSONObject().optJSONArray("data"); 211 | mUserPermissions.clear(); 212 | 213 | for (int i = 0; i < data.length(); i++) { 214 | JSONObject dd = data.optJSONObject(i); 215 | 216 | if (dd.optString("status").equals("granted")) { 217 | mUserPermissions 218 | .add(dd.optString("permission")); 219 | } 220 | } 221 | } 222 | } 223 | ).executeAsync(); 224 | } 225 | 226 | public String getUserPermissions() { 227 | if (!isConnected() && mUserPermissions.size() > 0) { 228 | Utils.d("GodotFireBase", "FB:Check:Login"); 229 | return "NULL"; 230 | } 231 | 232 | return mUserPermissions.toString(); 233 | } 234 | 235 | public void revokePermission(final String permission) { 236 | AccessToken token = AccessToken.getCurrentAccessToken(); 237 | 238 | String uri = "me/permissions/" + permission; 239 | 240 | GraphRequest graphRequest = GraphRequest.newDeleteObjectRequest( 241 | token, uri, new GraphRequest.Callback() { 242 | @Override 243 | public void onCompleted(GraphResponse response) { 244 | FacebookRequestError error = response.getError(); 245 | if (error == null) { 246 | Utils.d("GodotFireBase", "FB:Revoke:Response:" + response.toString()); 247 | getPermissions(); 248 | } 249 | } 250 | }); 251 | 252 | graphRequest.executeAsync(); 253 | } 254 | 255 | public void askForPermission ( 256 | final String title, final String message, final String perm, final boolean read) { 257 | 258 | new AlertDialog.Builder(activity, AlertDialog.THEME_HOLO_LIGHT) 259 | .setPositiveButton("Yes", new DialogInterface.OnClickListener() { 260 | @Override 261 | public void onClick(DialogInterface dialog, int id) { 262 | if (!read) { requestPublishPermissions(Arrays.asList(perm)); } 263 | else { requestReadPermissions(Arrays.asList(perm)); } 264 | } 265 | }) 266 | .setNegativeButton("No", new DialogInterface.OnClickListener() { 267 | public void onClick(DialogInterface dialog, int id) { 268 | 269 | } 270 | }) 271 | .setTitle(title) 272 | .setMessage(message) 273 | .show(); 274 | } 275 | 276 | public void requestReadPermissions(Collection permissions) { 277 | LoginManager.getInstance().logInWithReadPermissions( 278 | activity, permissions); 279 | } 280 | 281 | public void requestPublishPermissions(Collection permissions) { 282 | LoginManager.getInstance().logInWithPublishPermissions( 283 | activity, permissions); 284 | } 285 | 286 | public void signIn() { 287 | if (callbackManager == null) { 288 | Utils.d("GodotFireBase", "FB:Initialized"); 289 | return; 290 | } 291 | 292 | requestReadPermissions(Arrays.asList("email", "public_profile")); 293 | // LoginManager.getInstance().logInWithReadPermissions( 294 | // activity, Arrays.asList("email", "public_profile")); 295 | } 296 | 297 | public void signOut() { 298 | if (callbackManager == null) { return; } 299 | 300 | Utils.d("GodotFireBase", "FB:Logout"); 301 | 302 | mAuth.signOut(); 303 | LoginManager.getInstance().logOut(); 304 | } 305 | 306 | /** GraphRequest **/ 307 | 308 | /** 309 | public void newRequest(final String uri, final String data) { 310 | 311 | } 312 | 313 | public void newPostRequest(final String uri, final String data) { 314 | AccessToken token = AccessToken.getCurrentAccessToken(); 315 | 316 | GraphRequest graphRequest = GraphRequest.newDeleteObjectRequest( 317 | token, uri, new GraphRequest.Callback() { 318 | @Override 319 | public void onCompleted(GraphResponse response) { 320 | Utils.d("GodotFireBase", "Revoke Permission: " + permission); 321 | } 322 | }); 323 | 324 | graphRequest.executeAsync(); 325 | } 326 | 327 | public void newDeleteRequest(final String uri, final String data) { 328 | 329 | } 330 | **/ 331 | 332 | /** GraphRequest **/ 333 | 334 | public void revokeAccess() { 335 | mAuth.signOut(); 336 | 337 | AccessToken token = AccessToken.getCurrentAccessToken(); 338 | GraphRequest graphRequest = GraphRequest.newDeleteObjectRequest( 339 | token, "me/permissions", new GraphRequest.Callback() { 340 | @Override 341 | public void onCompleted(GraphResponse response) { 342 | FacebookRequestError error = response.getError(); 343 | if (error == null) { 344 | Utils.d("GodotFireBase", "FB:Delete:Access" + response.toString()); 345 | } 346 | } 347 | }); 348 | 349 | graphRequest.executeAsync(); 350 | } 351 | 352 | public void handleAccessToken(AccessToken token) { 353 | Utils.d("GodotFireBase", "FB:Handle:AccessToken: " + token.getToken()); 354 | // showProgressDialog(); 355 | 356 | AuthCredential credential = FacebookAuthProvider.getCredential(token.getToken()); 357 | 358 | mAuth.signInWithCredential(credential) 359 | .addOnCompleteListener(activity, new OnCompleteListener() { 360 | 361 | @Override 362 | public void onComplete(@NonNull Task task) { 363 | Utils.d("GodotFireBase", "FB:signInWithCredential:onComplete:" + task.isSuccessful()); 364 | 365 | // If sign in fails, display a message to the user. If sign in succeeds 366 | // the auth state listener will be notified and logic to handle the 367 | // signed in user can be handled in the listener. 368 | 369 | if (!task.isSuccessful()) { 370 | Utils.w("GodotFireBase", "FB:signInWithCredential" + 371 | task.getException().toString()); 372 | } 373 | 374 | // hideProgressDialog(); 375 | } 376 | }); 377 | } 378 | 379 | protected void successSignin (FirebaseUser user) { 380 | Utils.d("GodotFireBase", "FB:Login:Success"); 381 | 382 | isFacebookConnected = true; 383 | accessToken = AccessToken.getCurrentAccessToken(); 384 | 385 | try { 386 | currentFBUser.put("uid", user.getUid()); 387 | currentFBUser.put("name", user.getDisplayName()); 388 | currentFBUser.put("email_id", user.getEmail()); 389 | currentFBUser.put("photo_uri", user.getPhotoUrl()); 390 | currentFBUser.put("token", accessToken.getToken().toString()); 391 | 392 | } catch (JSONException e) { Utils.d("GodotFireBase", "FB:JSON:Error:" + e.toString()); } 393 | 394 | getPermissions(); 395 | 396 | // call Script 397 | Utils.callScriptFunc("Auth", "FacebookLogin", "true"); 398 | } 399 | 400 | protected void successSignOut () { 401 | isFacebookConnected = false; 402 | 403 | currentFBUser = null; 404 | currentFBUser = new JSONObject(); 405 | 406 | // call script. 407 | Utils.callScriptFunc("Auth", "FacebookLogin", "false"); 408 | } 409 | 410 | public String getUserDetails() { 411 | return currentFBUser.toString(); 412 | } 413 | 414 | public boolean isConnected() { 415 | return isFacebookConnected; 416 | } 417 | 418 | public void onActivityResult(int requestCode, int resultCode, Intent data) { 419 | // Result returned from launching the Intent from GoogleSignInApi.getSignInIntent(...); 420 | callbackManager.onActivityResult(requestCode, resultCode, data); 421 | } 422 | 423 | public void onStart () { 424 | mAuth.addAuthStateListener(mAuthListener); 425 | } 426 | 427 | public void onStop () { 428 | if (mAuthListener != null) { mAuth.removeAuthStateListener(mAuthListener); } 429 | 430 | isFacebookConnected = false; 431 | activity = null; 432 | 433 | mAccessTokenTracker.stopTracking(); 434 | mProfileTracker.stopTracking(); 435 | } 436 | 437 | private static Activity activity = null; 438 | private static FacebookSignIn mInstance = null; 439 | 440 | // private static GameRequestDialog requestDialog; 441 | private static CallbackManager callbackManager; 442 | 443 | private static AccessTokenTracker mAccessTokenTracker; 444 | private static ProfileTracker mProfileTracker; 445 | 446 | private static AccessToken accessToken; 447 | private static Profile profile; 448 | 449 | private Boolean isFacebookConnected = false; 450 | private JSONObject currentFBUser = new JSONObject(); 451 | 452 | private ArrayList mUserPermissions = new ArrayList(); 453 | 454 | private FirebaseAuth mAuth; 455 | private FirebaseAuth.AuthStateListener mAuthListener; 456 | } 457 | -------------------------------------------------------------------------------- /android_src/auth/GoogleSignIn.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2017 FrogSquare. All Rights Reserved. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | **/ 16 | 17 | package org.godotengine.godot.auth; 18 | 19 | import android.app.Activity; 20 | import android.content.Intent; 21 | import android.content.IntentSender.SendIntentException; 22 | import android.os.Bundle; 23 | import android.util.Log; 24 | import androidx.annotation.NonNull; 25 | 26 | import com.google.android.gms.auth.api.Auth; 27 | import com.google.android.gms.auth.api.signin.GoogleSignInAccount; 28 | import com.google.android.gms.auth.api.signin.GoogleSignInOptions; 29 | import com.google.android.gms.auth.api.signin.GoogleSignInResult; 30 | import com.google.android.gms.common.ConnectionResult; 31 | import com.google.android.gms.common.api.GoogleApiClient; 32 | import com.google.android.gms.common.api.ResultCallback; 33 | import com.google.android.gms.common.api.Status; 34 | import com.google.android.gms.tasks.OnCompleteListener; 35 | import com.google.android.gms.tasks.Task; 36 | import com.google.firebase.auth.AuthCredential; 37 | import com.google.firebase.auth.AuthResult; 38 | import com.google.firebase.auth.FirebaseAuth; 39 | import com.google.firebase.auth.FirebaseUser; 40 | import com.google.firebase.auth.GoogleAuthProvider; 41 | import com.google.firebase.auth.UserInfo; 42 | 43 | import com.godot.game.R; 44 | 45 | import org.json.JSONObject; 46 | import org.json.JSONException; 47 | 48 | import org.godotengine.godot.FireBase; 49 | import org.godotengine.godot.Utils; 50 | 51 | public class GoogleSignIn 52 | implements GoogleApiClient.OnConnectionFailedListener, GoogleApiClient.ConnectionCallbacks { 53 | 54 | public static GoogleSignIn getInstance (Activity p_activity) { 55 | if (mInstance == null) { 56 | mInstance = new GoogleSignIn(p_activity); 57 | } 58 | 59 | return mInstance; 60 | } 61 | 62 | public GoogleSignIn(Activity p_activity) { 63 | activity = p_activity; 64 | } 65 | 66 | public void init() { 67 | // Initialize listener. 68 | // ... 69 | 70 | GoogleSignInOptions gso = new GoogleSignInOptions.Builder(GoogleSignInOptions.DEFAULT_SIGN_IN) 71 | .requestIdToken(activity.getString(R.string.default_web_client_id)) 72 | .requestEmail() 73 | .build(); 74 | 75 | /** 76 | 77 | try { 78 | Class.forName("org.godotengine.godot.PlayService"); 79 | } catch () { } 80 | 81 | **/ 82 | 83 | mGoogleApiClient = new GoogleApiClient.Builder(activity) 84 | .addConnectionCallbacks(this) 85 | .addOnConnectionFailedListener(this) 86 | .addApi(Auth.GOOGLE_SIGN_IN_API, gso) 87 | .build(); 88 | 89 | Utils.d("GodotFireBase", "Google:Initialized"); 90 | 91 | mAuth = FirebaseAuth.getInstance(); 92 | 93 | mAuthListener = new FirebaseAuth.AuthStateListener() { 94 | @Override 95 | public void onAuthStateChanged(@NonNull FirebaseAuth firebaseAuth) { 96 | FirebaseUser user = firebaseAuth.getCurrentUser(); 97 | 98 | if (user != null) { 99 | for (UserInfo usr : user.getProviderData()) { 100 | if (usr.getProviderId().equals("google.com")) { 101 | Utils.d("GodotFireBase", "Google:AuthStateChanged:signed_in:"+ 102 | user.getUid()); 103 | 104 | successSignIn(user); 105 | } 106 | } 107 | } else { 108 | // User is signed out 109 | Utils.d("GodotFireBase", "Google:onAuthStateChanged:signed_out"); 110 | successSignOut(); 111 | } 112 | 113 | // update firebase auth dets. 114 | } 115 | }; 116 | 117 | onStart(); // calling on start form init 118 | } 119 | 120 | public void signIn() { 121 | if (mGoogleApiClient == null) { 122 | Utils.d("GodotFireBase", "Google:NotInitialized"); 123 | return; 124 | } 125 | 126 | if (!mGoogleApiClient.isConnected() && !mGoogleApiClient.isConnecting()) { 127 | Intent signInIntent = Auth.GoogleSignInApi.getSignInIntent(mGoogleApiClient); 128 | activity.startActivityForResult(signInIntent, Utils.FIREBASE_GOOGLE_SIGN_IN); 129 | } else { Utils.d("GodotFireBase", "Google auth connected."); } 130 | } 131 | 132 | public void signOut() { 133 | // Firebase sign out 134 | mAuth.signOut(); 135 | 136 | // Google sign out 137 | if (mGoogleApiClient.isConnected()) { 138 | Auth.GoogleSignInApi.signOut(mGoogleApiClient).setResultCallback( 139 | new ResultCallback() { 140 | 141 | @Override 142 | public void onResult(@NonNull Status status) { 143 | // update user details. 144 | } 145 | }); 146 | } 147 | } 148 | 149 | public void revokeAccess () { 150 | mAuth.signOut(); 151 | 152 | // Google sign out 153 | Auth.GoogleSignInApi.revokeAccess(mGoogleApiClient).setResultCallback( 154 | new ResultCallback() { 155 | 156 | @Override 157 | public void onResult(@NonNull Status status) { 158 | // update user details. 159 | } 160 | }); 161 | } 162 | 163 | public String getUserDetails() { 164 | return currentGoogleUser.toString(); 165 | } 166 | 167 | public boolean isConnected() { 168 | return isGooglePlayConnected; 169 | } 170 | 171 | protected void successSignIn(FirebaseUser user) { 172 | Utils.d("GodotFireBase", "Google:Connection:Success"); 173 | 174 | isResolvingConnectionFailure = false; 175 | isGooglePlayConnected = true; 176 | isRequestingSignIn = false; 177 | 178 | try { 179 | currentGoogleUser.put("uid", user.getUid()); 180 | currentGoogleUser.put("name", user.getDisplayName()); 181 | currentGoogleUser.put("email_id", user.getEmail()); 182 | currentGoogleUser.put("photo_uri", user.getPhotoUrl()); 183 | } catch (JSONException e) { Utils.d("GodotFireBase", "Google:JSON:Error:" + e.toString()); } 184 | 185 | Utils.callScriptFunc("Auth", "GoogleLogin", "true"); 186 | } 187 | 188 | protected void successSignOut() { 189 | Utils.d("GodotFireBase", "Google:Disconnected"); 190 | 191 | isGooglePlayConnected = false; 192 | 193 | currentGoogleUser = null; 194 | currentGoogleUser = new JSONObject(); 195 | 196 | Utils.callScriptFunc("Auth", "GoogleLogin", "false"); 197 | } 198 | 199 | private void firebaseAuthWithGoogle(GoogleSignInAccount acct) { 200 | 201 | Utils.d("GodotFireBase", "Google:FirebaseAuthWithGoogle:" + acct.getId()); 202 | 203 | // FireBase.showProgressDialog(); 204 | 205 | AuthCredential credential = GoogleAuthProvider.getCredential(acct.getIdToken(), null); 206 | mAuth.signInWithCredential(credential) 207 | .addOnCompleteListener(activity, new OnCompleteListener() { 208 | 209 | @Override 210 | public void onComplete(@NonNull Task task) { 211 | Utils.d("GodotFireBase", 212 | "Google:SignInWithCredential:onComplete:" + task.isSuccessful()); 213 | 214 | // If sign in fails, display a message to the user. If sign in succeeds 215 | // the auth state listener will be notified and logic to handle the 216 | // signed in user can be handled in the listener. 217 | if (!task.isSuccessful()) { 218 | Utils.w("GodotFireBase", "Google:SignInWithCredential:" + task.getException()); 219 | } 220 | 221 | // FireBase.hideProgressDialog(); 222 | } 223 | }); 224 | } 225 | 226 | @Override 227 | public void onConnected(Bundle m_bundle) { 228 | Utils.d("GodotFireBase", "Google:onConnected"); 229 | 230 | if (m_bundle != null) { 231 | 232 | } 233 | } 234 | 235 | @Override 236 | public void onConnectionSuspended(int m_cause) { 237 | Utils.d("GodotFireBase", "Google:Connection:Suspended:Check:Internet"); 238 | } 239 | 240 | @Override 241 | public void onConnectionFailed(@NonNull ConnectionResult m_result) { 242 | Utils.d("GodotFireBase", "Google:Connection:Failed"); 243 | 244 | if (isResolvingConnectionFailure) { return; } 245 | if(!isIntentInProgress && m_result.hasResolution()) { 246 | try { 247 | isIntentInProgress = true; 248 | 249 | activity.startIntentSenderForResult( 250 | m_result.getResolution().getIntentSender(), 251 | Utils.FIREBASE_GOOGLE_SIGN_IN, null, 0, 0, 0); 252 | 253 | } catch (SendIntentException ex) { 254 | isIntentInProgress = false; 255 | signIn(); 256 | } 257 | 258 | isResolvingConnectionFailure = true; 259 | Utils.d("GodotFireBase", "Google:Connection:Resolving."); 260 | } 261 | } 262 | 263 | public void onActivityResult(int requestCode, int resultCode, Intent data) { 264 | // Result returned from launching the Intent from GoogleSignInApi.getSignInIntent(...); 265 | 266 | if (requestCode == Utils.FIREBASE_GOOGLE_SIGN_IN) { 267 | GoogleSignInResult result = 268 | Auth.GoogleSignInApi.getSignInResultFromIntent(data); 269 | 270 | isIntentInProgress = false; 271 | 272 | if (!mGoogleApiClient.isConnecting()) { mGoogleApiClient.connect(); } 273 | 274 | if (result.isSuccess()) { 275 | // Google Sign In was successful, authenticate with Firebase 276 | 277 | GoogleSignInAccount account = result.getSignInAccount(); 278 | firebaseAuthWithGoogle(account); 279 | } else { 280 | // Google Sign In failed, update UI appropriately 281 | // updateUI(null); 282 | } 283 | } 284 | } 285 | 286 | public void onStart () { 287 | mAuth.addAuthStateListener(mAuthListener); 288 | } 289 | 290 | public void onStop () { 291 | if (mAuthListener != null) { mAuth.removeAuthStateListener(mAuthListener); } 292 | if (mGoogleApiClient.isConnected()) { mGoogleApiClient.disconnect(); } 293 | 294 | isGooglePlayConnected = false; 295 | activity = null; 296 | } 297 | 298 | private static Activity activity = null; 299 | private static GoogleSignIn mInstance = null; 300 | 301 | private FirebaseAuth mAuth; 302 | private FirebaseAuth.AuthStateListener mAuthListener; 303 | 304 | private JSONObject currentGoogleUser = new JSONObject(); 305 | 306 | private Boolean isRequestingSignIn = false; 307 | private Boolean isIntentInProgress = false; 308 | private Boolean isGooglePlayConnected = false; 309 | private Boolean isResolvingConnectionFailure = false; 310 | 311 | private static GoogleApiClient mGoogleApiClient = null; 312 | } 313 | -------------------------------------------------------------------------------- /android_src/auth/TwitterSignIn.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2017 FrogSquare. All Rights Reserved. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | **/ 16 | 17 | package org.godotengine.godot.auth; 18 | 19 | import android.app.*; 20 | import android.content.Context; 21 | import android.content.Intent; 22 | import android.content.DialogInterface; 23 | import android.os.Bundle; 24 | import android.util.Log; 25 | import androidx.annotation.NonNull; 26 | 27 | import com.google.android.gms.tasks.OnCompleteListener; 28 | import com.google.android.gms.tasks.Task; 29 | import com.google.firebase.auth.AuthCredential; 30 | import com.google.firebase.auth.AuthResult; 31 | import com.google.firebase.auth.FirebaseAuth; 32 | import com.google.firebase.auth.FirebaseUser; 33 | import com.google.firebase.auth.TwitterAuthProvider; 34 | import com.google.firebase.auth.UserInfo; 35 | 36 | import com.twitter.sdk.android.Twitter; 37 | import com.twitter.sdk.android.core.Callback; 38 | import com.twitter.sdk.android.core.Result; 39 | import com.twitter.sdk.android.core.TwitterAuthConfig; 40 | import com.twitter.sdk.android.core.TwitterException; 41 | import com.twitter.sdk.android.core.TwitterSession; 42 | import com.twitter.sdk.android.core.identity.TwitterAuthClient; 43 | 44 | import io.fabric.sdk.android.Fabric; 45 | 46 | import com.godot.game.R; 47 | 48 | import java.util.Arrays; 49 | import java.util.ArrayList; 50 | import java.util.List; 51 | 52 | import org.json.JSONArray; 53 | import org.json.JSONObject; 54 | import org.json.JSONException; 55 | 56 | import org.godotengine.godot.KeyValueStorage; 57 | import org.godotengine.godot.Utils; 58 | 59 | public class TwitterSignIn { 60 | 61 | public static TwitterSignIn getInstance (Activity p_activity) { 62 | if (mInstance == null) { 63 | mInstance = new TwitterSignIn(p_activity); 64 | } 65 | 66 | return mInstance; 67 | } 68 | 69 | public TwitterSignIn(Activity p_activity) { 70 | activity = p_activity; 71 | } 72 | 73 | public void init() { 74 | TwitterAuthConfig authConfig = new TwitterAuthConfig( 75 | activity.getString(R.string.twitter_consumer_key), 76 | activity.getString(R.string.twitter_consumer_secret)); 77 | 78 | Fabric.with(activity, new Twitter(authConfig)); 79 | 80 | mAuth = FirebaseAuth.getInstance(); 81 | 82 | twitterAuthClient = new TwitterAuthClient(); 83 | mAuthListener = new FirebaseAuth.AuthStateListener() { 84 | @Override 85 | public void onAuthStateChanged(@NonNull FirebaseAuth firebaseAuth) { 86 | FirebaseUser user = firebaseAuth.getCurrentUser(); 87 | 88 | if (user != null) { 89 | // User is signed in 90 | for (UserInfo usr : user.getProviderData()) { 91 | if (usr.getProviderId().equals("twitter.com")) { 92 | Utils.d("GodotFireBase", "Twitter:AuthStateChanged:signed_in:"+ 93 | user.getUid()); 94 | 95 | successSignIn(user); 96 | } 97 | } 98 | 99 | } else { 100 | // User is signed out 101 | Utils.d("GodotFireBase", "Twitter:onAuthStateChanged:signed_out"); 102 | successSignOut(); 103 | } 104 | 105 | // update firebase auth dets. 106 | } 107 | }; 108 | 109 | onStart(); 110 | } 111 | 112 | public void signIn() { 113 | twitterAuthClient.authorize(activity, new Callback() { 114 | @Override 115 | public void success(final Result result) { 116 | final TwitterSession sessionData = result.data; 117 | handleTwitterSession(sessionData); 118 | } 119 | 120 | @Override 121 | public void failure(final TwitterException e) { 122 | // Do something on fail 123 | Utils.d("GodotFireBase", "Twitter::Login:Failed"); 124 | } 125 | }); 126 | } 127 | 128 | public void signOut() { 129 | mAuth.signOut(); 130 | } 131 | 132 | protected void successSignIn(FirebaseUser user) { 133 | Utils.d("GodotFireBase", "Twitter:Connection:Success"); 134 | 135 | isTwitterConnected = true; 136 | 137 | try { 138 | currentTwitterUser.put("uid", user.getUid()); 139 | currentTwitterUser.put("name", user.getDisplayName()); 140 | currentTwitterUser.put("email_id", user.getEmail()); 141 | currentTwitterUser.put("photo_uri", user.getPhotoUrl()); 142 | } catch (JSONException e) { Utils.d("GodotFireBase", "Twitter:JSON:Error:" + e.toString()); } 143 | 144 | Utils.callScriptFunc("Auth", "TwitterLogin", "true"); 145 | } 146 | 147 | protected void successSignOut() { 148 | Utils.d("GodotFireBase", "Twitter:Disconnected"); 149 | 150 | isTwitterConnected = false; 151 | 152 | currentTwitterUser = null; 153 | currentTwitterUser = new JSONObject(); 154 | 155 | Utils.callScriptFunc("Auth", "TwitterLogin", "false"); 156 | } 157 | 158 | private void handleTwitterSession(TwitterSession session) { 159 | Utils.d("GodotFireBase", "Twitter:HandleSession:" + session); 160 | 161 | AuthCredential credential = TwitterAuthProvider.getCredential( 162 | session.getAuthToken().token, 163 | session.getAuthToken().secret); 164 | 165 | mAuth.signInWithCredential(credential) 166 | .addOnCompleteListener(activity, new OnCompleteListener() { 167 | @Override 168 | public void onComplete(@NonNull Task task) { 169 | if (task.isSuccessful()) { 170 | // Sign in success, update UI with the signed-in user's information 171 | Utils.d("GodotFireBase", "signInWithCredential:success"); 172 | } else { 173 | // If sign in fails, display a message to the user. 174 | Utils.w("GodotFireBase", "signInWithCredential:failure: " + task.getException()); 175 | } 176 | 177 | // ... 178 | } 179 | }); 180 | } 181 | 182 | public void onStart () { 183 | mAuth.addAuthStateListener(mAuthListener); 184 | } 185 | 186 | public void onStop () { 187 | if (mAuthListener != null) { mAuth.removeAuthStateListener(mAuthListener); } 188 | 189 | isTwitterConnected = false; 190 | activity = null; 191 | } 192 | 193 | public void onActivityResult(int requestCode, int resultCode, Intent data) { 194 | twitterAuthClient.onActivityResult(requestCode, resultCode, data); 195 | } 196 | 197 | private static Activity activity = null; 198 | private static TwitterSignIn mInstance = null; 199 | private static TwitterAuthClient twitterAuthClient = null; 200 | 201 | private JSONObject currentTwitterUser = new JSONObject(); 202 | private Boolean isTwitterConnected = false; 203 | 204 | private FirebaseAuth mAuth; 205 | private FirebaseAuth.AuthStateListener mAuthListener; 206 | } 207 | -------------------------------------------------------------------------------- /android_src/storage/BaseTaskService.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2017 FrogSquare. All Rights Reserved. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | **/ 16 | 17 | package org.godotengine.godot.storage; 18 | 19 | import android.app.NotificationManager; 20 | import android.app.PendingIntent; 21 | import android.app.Service; 22 | import android.content.Context; 23 | import android.content.Intent; 24 | import android.util.Log; 25 | 26 | import androidx.core.app.NotificationCompat; 27 | 28 | import com.godot.game.R; 29 | 30 | import org.godotengine.godot.Utils; 31 | 32 | /** 33 | * Base class for Services that keep track of the number of active jobs and self-stop when the 34 | * count is zero 35 | * 36 | * Repo: https://github.com/firebase/quickstart-android/ 37 | * File: MyBaseTaskService.java 38 | */ 39 | public abstract class BaseTaskService extends Service { 40 | 41 | static final int PROGRESS_NOTIFICATION_ID = 6001; 42 | static final int FINISHED_NOTIFICATION_ID = 6002; 43 | 44 | public void taskStarted() { 45 | changeNumberOfTasks(1); 46 | } 47 | 48 | public void taskCompleted() { 49 | changeNumberOfTasks(-1); 50 | } 51 | 52 | private synchronized void changeNumberOfTasks(int delta) { 53 | Utils.d("GodotFireBase", "Storage:ChangeNumOfTasks: {" + mNumTasks + ":" + delta + "}"); 54 | mNumTasks += delta; 55 | 56 | // If there are no tasks left, stop the service 57 | if (mNumTasks <= 0) { 58 | Utils.d("GodotFireBase", "stopping"); 59 | stopSelf(); 60 | } 61 | } 62 | 63 | /** 64 | * Show notification with a progress bar. 65 | */ 66 | protected void showProgressNotification(String caption, long completedUnits, long totalUnits) { 67 | int percentComplete = 0; 68 | if (totalUnits > 0) { percentComplete = (int) (100 * completedUnits / totalUnits); } 69 | 70 | NotificationCompat.Builder builder = new NotificationCompat.Builder(this) 71 | .setSmallIcon(R.drawable.ic_file_upload_white_24dp) 72 | .setContentTitle(getString(R.string.godot_project_name_string)) 73 | .setContentText(caption) 74 | .setProgress(100, percentComplete, false) 75 | .setOngoing(true) 76 | .setAutoCancel(false); 77 | 78 | NotificationManager manager = 79 | (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE); 80 | 81 | manager.notify(PROGRESS_NOTIFICATION_ID, builder.build()); 82 | } 83 | 84 | /** 85 | * Show notification that the activity finished. 86 | */ 87 | protected void showFinishedNotification(String caption, Intent intent, boolean success) { 88 | // Make PendingIntent for notification 89 | PendingIntent pendingIntent = PendingIntent.getActivity( 90 | this, 6003, intent, PendingIntent.FLAG_UPDATE_CURRENT); 91 | 92 | int icon = success ? R.drawable.ic_check_white_24 : R.drawable.ic_error_white_24dp; 93 | 94 | NotificationCompat.Builder builder = new NotificationCompat.Builder(this) 95 | .setSmallIcon(icon) 96 | .setContentTitle(getString(R.string.godot_project_name_string)) 97 | .setContentText(caption) 98 | .setAutoCancel(true) 99 | .setContentIntent(pendingIntent); 100 | 101 | NotificationManager manager = 102 | (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE); 103 | 104 | manager.notify(FINISHED_NOTIFICATION_ID, builder.build()); 105 | } 106 | 107 | /** 108 | * Dismiss the progress notification. 109 | */ 110 | protected void dismissProgressNotification() { 111 | NotificationManager manager = 112 | (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE); 113 | 114 | manager.cancel(PROGRESS_NOTIFICATION_ID); 115 | } 116 | 117 | private int mNumTasks = 0; 118 | } 119 | -------------------------------------------------------------------------------- /android_src/storage/DownloadService.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2017 FrogSquare. All Rights Reserved. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | **/ 16 | 17 | package org.godotengine.godot.storage; 18 | 19 | import android.content.Intent; 20 | import android.content.IntentFilter; 21 | import android.net.Uri; 22 | import android.os.Environment; 23 | import android.os.IBinder; 24 | import android.util.Log; 25 | 26 | import androidx.annotation.NonNull; 27 | import androidx.annotation.Nullable; 28 | import android.support.v4.content.LocalBroadcastManager; 29 | 30 | import com.google.android.gms.tasks.OnFailureListener; 31 | import com.google.android.gms.tasks.OnSuccessListener; 32 | 33 | import com.google.firebase.storage.FirebaseStorage; 34 | import com.google.firebase.storage.FileDownloadTask; 35 | import com.google.firebase.storage.OnProgressListener; 36 | import com.google.firebase.storage.StorageReference; 37 | import com.google.firebase.storage.StreamDownloadTask; 38 | import com.godot.game.BuildConfig; 39 | import com.godot.game.R; 40 | 41 | import java.io.File; 42 | import java.io.IOException; 43 | import java.io.InputStream; 44 | 45 | import org.godotengine.godot.Utils; 46 | 47 | public class DownloadService extends BaseTaskService { 48 | 49 | /** Actions **/ 50 | public static final String ACTION_DOWNLOAD = "action_download"; 51 | public static final String DOWNLOAD_COMPLETED = "download_completed"; 52 | public static final String DOWNLOAD_ERROR = "download_error"; 53 | 54 | /** Extras **/ 55 | public static final String EXTRA_DOWNLOAD_PATH = "extra_download_path"; 56 | public static final String EXTRA_DOWNLOAD_TO = "extra_download_to"; 57 | public static final String EXTRA_BYTES_DOWNLOADED = "extra_bytes_downloaded"; 58 | 59 | @Override 60 | public void onCreate() { 61 | super.onCreate(); 62 | 63 | Utils.d("GodotFireBase", "SD:DownloadTask:Created"); 64 | 65 | mStorageRef = FirebaseStorage.getInstance().getReference(); 66 | } 67 | 68 | @Nullable 69 | @Override 70 | public IBinder onBind(Intent intent) { 71 | 72 | return null; 73 | } 74 | 75 | @Override 76 | public int onStartCommand(Intent intent, int flags, int startId) { 77 | Utils.d("GodotFireBase", "SD:OnStartCommand: {" + intent + ":" + startId + "}"); 78 | 79 | if (ACTION_DOWNLOAD.equals(intent.getAction())) { 80 | String downloadPath = intent.getStringExtra(EXTRA_DOWNLOAD_PATH); 81 | String downloadTo = intent.getStringExtra(EXTRA_DOWNLOAD_TO); 82 | //downloadFromPath(downloadPath); 83 | downloadToFile(downloadPath, downloadTo); 84 | } 85 | 86 | return START_REDELIVER_INTENT; 87 | } 88 | 89 | private void downloadToFile(final String downloadPath, final String downloadTo) { 90 | if (Utils.isExternalStorageWritable()) { 91 | Utils.d("GodotFireBase", "SD:CanWrite"); 92 | } else { Utils.d("GodotFireBase", "SD:CannotWrite"); } 93 | 94 | File rootPath = new File( 95 | Environment.getExternalStorageDirectory(), downloadTo); 96 | 97 | if (!rootPath.exists()) { rootPath.mkdirs(); } 98 | 99 | Uri fileUri = Uri.parse(downloadPath); 100 | File localFile = new File(rootPath, fileUri.getLastPathSegment()); 101 | 102 | taskStarted(); 103 | showProgressNotification("Progress downloading", 0, 0); 104 | 105 | mStorageRef.child(downloadPath).getFile(localFile) 106 | .addOnProgressListener(new OnProgressListener() { 107 | @Override 108 | public void onProgress(FileDownloadTask.TaskSnapshot taskSnapshot) { 109 | long totalBytes = taskSnapshot.getTotalByteCount(); 110 | long bytesDownloaded = taskSnapshot.getBytesTransferred(); 111 | 112 | onMainProgress(downloadPath, bytesDownloaded, totalBytes); 113 | } 114 | }) 115 | .addOnSuccessListener(new OnSuccessListener() { 116 | @Override 117 | public void onSuccess(FileDownloadTask.TaskSnapshot taskSnapshot) { 118 | onMainSuccess(downloadPath, taskSnapshot.getTotalByteCount()); 119 | } 120 | }) 121 | .addOnFailureListener(new OnFailureListener() { 122 | @Override 123 | public void onFailure(@NonNull Exception exception) { 124 | onMainFailure(downloadPath, exception); 125 | } 126 | }); 127 | } 128 | 129 | private void downloadFromPath(final String downloadPath) { 130 | Utils.d("GodotFireBase", "SD:DownloadFromPath:" + downloadPath); 131 | 132 | taskStarted(); 133 | // showProgressNotification(getString(R.string.progress_downloading), 0, 0); 134 | showProgressNotification("Progress downloading", 0, 0); 135 | 136 | mStorageRef.child(downloadPath).getStream(new StreamDownloadTask.StreamProcessor() { 137 | @Override 138 | public void doInBackground(StreamDownloadTask.TaskSnapshot taskSnapshot, 139 | InputStream inputStream) throws IOException { 140 | 141 | long totalBytes = taskSnapshot.getTotalByteCount(); 142 | long bytesDownloaded = 0; 143 | 144 | byte[] buffer = new byte[1024]; 145 | int size; 146 | 147 | while ((size = inputStream.read(buffer)) != -1) { 148 | bytesDownloaded += size; 149 | onMainProgress(downloadPath, bytesDownloaded, totalBytes); 150 | } 151 | 152 | // Close the stream at the end of the Task 153 | inputStream.close(); 154 | } 155 | }) 156 | .addOnSuccessListener(new OnSuccessListener() { 157 | @Override 158 | public void onSuccess(StreamDownloadTask.TaskSnapshot taskSnapshot) { 159 | onMainSuccess(downloadPath, taskSnapshot.getTotalByteCount()); 160 | } 161 | }) 162 | .addOnFailureListener(new OnFailureListener() { 163 | @Override 164 | public void onFailure(@NonNull Exception exception) { 165 | onMainFailure(downloadPath, exception); 166 | } 167 | }); 168 | } 169 | 170 | private void onMainProgress(String path, long currentByteCount, long totalByteCount) { 171 | showProgressNotification("Progress downloading", currentByteCount, totalByteCount); 172 | } 173 | 174 | private void onMainSuccess(String path, long totalByteCount) { 175 | Utils.d("GodotFireBase", "SD:Download:SUCCESS"); 176 | 177 | // Send success broadcast with number of bytes downloaded 178 | broadcastDownloadFinished(path, totalByteCount); 179 | showDownloadFinishedNotification(path, (int) totalByteCount); 180 | 181 | // Mark task completed 182 | taskCompleted(); 183 | } 184 | 185 | private void onMainFailure(String path, @NonNull Exception exception) { 186 | Utils.w("GodotFireBase", "SD:Download:FAILURE" + exception.toString()); 187 | 188 | // Send failure broadcast 189 | broadcastDownloadFinished(path, -1); 190 | showDownloadFinishedNotification(path, -1); 191 | 192 | // Mark task completed 193 | taskCompleted(); 194 | } 195 | 196 | /** 197 | * Broadcast finished download (success or failure). 198 | * @return true if a running receiver received the broadcast. 199 | */ 200 | private boolean broadcastDownloadFinished(String downloadPath, long bytesDownloaded) { 201 | boolean success = bytesDownloaded != -1; 202 | String action = success ? DOWNLOAD_COMPLETED : DOWNLOAD_ERROR; 203 | 204 | Intent broadcast = new Intent(action) 205 | .putExtra(EXTRA_DOWNLOAD_PATH, downloadPath) 206 | .putExtra(EXTRA_BYTES_DOWNLOADED, bytesDownloaded); 207 | 208 | return 209 | LocalBroadcastManager.getInstance(getApplicationContext()).sendBroadcast(broadcast); 210 | } 211 | 212 | /** 213 | * Show a notification for a finished download. 214 | */ 215 | private void showDownloadFinishedNotification(String downloadPath, int bytesDownloaded) { 216 | // Hide the progress notification 217 | dismissProgressNotification(); 218 | 219 | // Make Intent to MainActivity 220 | Intent intent = new Intent(this, org.godotengine.godot.Godot.class) 221 | .putExtra(EXTRA_DOWNLOAD_PATH, downloadPath) 222 | .putExtra(EXTRA_BYTES_DOWNLOADED, bytesDownloaded) 223 | .addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_SINGLE_TOP); 224 | 225 | boolean success = bytesDownloaded != -1; 226 | String caption = 227 | success ? "Download Success" : "Download failure"; 228 | // success ? getString(R.string.download_success) : getString(R.string.download_failure); 229 | 230 | showFinishedNotification(caption, intent, true); 231 | } 232 | 233 | public static IntentFilter getIntentFilter() { 234 | IntentFilter filter = new IntentFilter(); 235 | filter.addAction(DOWNLOAD_COMPLETED); 236 | filter.addAction(DOWNLOAD_ERROR); 237 | 238 | return filter; 239 | } 240 | 241 | private StorageReference mStorageRef = null; 242 | } 243 | -------------------------------------------------------------------------------- /android_src/storage/Storage.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2017 FrogSquare. All Rights Reserved. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | **/ 16 | 17 | package org.godotengine.godot.storage; 18 | 19 | import android.app.Activity; 20 | import android.app.ProgressDialog; 21 | import android.content.BroadcastReceiver; 22 | import android.content.Context; 23 | import android.content.Intent; 24 | import android.net.Uri; 25 | import android.os.Bundle; 26 | import android.os.Environment; 27 | import android.util.Log; 28 | import android.view.Menu; 29 | import android.view.MenuItem; 30 | import android.view.View; 31 | import android.widget.TextView; 32 | import androidx.annotation.NonNull; 33 | import android.support.v4.content.LocalBroadcastManager; 34 | 35 | import com.google.firebase.FirebaseApp; 36 | 37 | import org.json.JSONObject; 38 | import org.json.JSONException; 39 | 40 | import org.godotengine.godot.auth.Auth; 41 | import org.godotengine.godot.FireBase; 42 | import org.godotengine.godot.Godot; 43 | import org.godotengine.godot.Utils; 44 | 45 | import java.util.Locale; 46 | import java.io.File; 47 | 48 | // SharedPreferences 49 | 50 | public class Storage { 51 | 52 | public static Storage getInstance (Activity p_activity) { 53 | if (mInstance == null) { 54 | mInstance = new Storage(p_activity); 55 | } 56 | 57 | return mInstance; 58 | } 59 | 60 | public Storage(Activity p_activity) { 61 | activity = p_activity; 62 | } 63 | 64 | public void init (FirebaseApp firebaseApp) { 65 | mFirebaseApp = firebaseApp; 66 | 67 | // Local broadcast receiver 68 | mBroadcastReceiver = new BroadcastReceiver() { 69 | @Override 70 | public void onReceive(Context context, Intent intent) { 71 | Utils.d("GodotFireBase", "SD:OnReceive:" + intent.toString()); 72 | 73 | // hideProgressDialog(); // Hiding our progress dialog 74 | 75 | switch (intent.getAction()) { 76 | case DownloadService.DOWNLOAD_COMPLETED: 77 | // Get number of bytes downloaded 78 | long numBytes = intent.getLongExtra( 79 | DownloadService.EXTRA_BYTES_DOWNLOADED,0); 80 | 81 | // Alert success 82 | // activity.getString(R.string.success), 83 | 84 | /** 85 | showMessageDialog("Success", 86 | String.format(Locale.getDefault(), 87 | "%d bytes downloaded from %s", numBytes, 88 | intent.getStringExtra(DownloadService.EXTRA_DOWNLOAD_PATH))); 89 | **/ 90 | break; 91 | case DownloadService.DOWNLOAD_ERROR: 92 | // Alert failure 93 | /** 94 | showMessageDialog("Error", 95 | String.format(Locale.getDefault(), "Failed to download from %s", 96 | intent.getStringExtra(DownloadService.EXTRA_DOWNLOAD_PATH))); 97 | **/ 98 | break; 99 | // case MyUploadService.UPLOAD_COMPLETED: 100 | // case MyUploadService.UPLOAD_ERROR: 101 | // onUploadResultIntent(intent); 102 | // break; 103 | } 104 | } 105 | }; 106 | 107 | onStart(); 108 | 109 | Utils.d("GodotFireBase", "Initilaized Storage"); 110 | } 111 | 112 | public void download(String url, String path) { 113 | if (!isInitialized() || Auth.getInstance(activity).getCurrentUser() == null) { return; } 114 | 115 | Utils.d("GodotFireBase", "SD:Downloading:"+url); 116 | mDownloadUrl = Uri.parse(url); 117 | // String path = mFileUri.getLastPathSegment(); 118 | 119 | // Kick off MyDownloadService to download the file 120 | Intent intent = new Intent(activity, DownloadService.class) 121 | .putExtra(DownloadService.EXTRA_DOWNLOAD_PATH, url) 122 | .putExtra(DownloadService.EXTRA_DOWNLOAD_TO, path) 123 | .setAction(DownloadService.ACTION_DOWNLOAD); 124 | 125 | Utils.d("GodotFireBase", "SD:Starting:Service:Download"); 126 | activity.startService(intent); 127 | } 128 | 129 | public void upload(final String filePath, final String child) { 130 | String path = ""; 131 | if (!isInitialized() || Auth.getInstance(activity).getCurrentUser() == null) { return; } 132 | 133 | if (filePath.startsWith("user://")) { 134 | path = filePath.replaceFirst("user://", ""); 135 | path = Godot.getInstance().io.getDataDir() + "/" + path; 136 | } else { 137 | path = 138 | Environment.getExternalStorageDirectory().getAbsolutePath() + "/" + filePath; 139 | } 140 | 141 | Utils.d("GodotFireBase", "SD:Uploading:"+path); 142 | Uri fileUri = Uri.fromFile(new File(path)); 143 | // String path = mFileUri.getLastPathSegment(); 144 | 145 | // Kick off UploadService to upload the file 146 | Intent intent = new Intent(activity, UploadService.class) 147 | .putExtra(UploadService.EXTRA_FILE_URI, fileUri) 148 | .putExtra(UploadService.EXTRA_FILE_CHILD, child) 149 | .setAction(UploadService.ACTION_UPLOAD); 150 | 151 | Utils.d("GodotFireBase", "SD:Starting:Service:Upload"); 152 | activity.startService(intent); 153 | } 154 | 155 | public void onStart() { 156 | LocalBroadcastManager.getInstance(activity) 157 | .registerReceiver(mBroadcastReceiver, DownloadService.getIntentFilter()); 158 | } 159 | 160 | public void onStop() { 161 | if (!isInitialized()) { return; } 162 | 163 | LocalBroadcastManager.getInstance(activity).unregisterReceiver(mBroadcastReceiver); 164 | } 165 | 166 | private boolean isInitialized() { 167 | if (mFirebaseApp == null) { 168 | Utils.d("GodotFireBase", "FireBase Storage, not initialized"); 169 | return false; 170 | } 171 | 172 | return true; 173 | } 174 | 175 | private static Activity activity = null; 176 | private static Storage mInstance = null; 177 | 178 | private FirebaseApp mFirebaseApp = null; 179 | 180 | private BroadcastReceiver mBroadcastReceiver = null; 181 | private Uri mDownloadUrl = null; 182 | private Uri mFileUrl = null; 183 | 184 | } 185 | -------------------------------------------------------------------------------- /android_src/storage/UploadService.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2017 FrogSquare. All Rights Reserved. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | **/ 16 | 17 | package org.godotengine.godot.storage; 18 | 19 | import android.content.Intent; 20 | import android.content.IntentFilter; 21 | import android.net.Uri; 22 | import android.os.IBinder; 23 | import android.util.Log; 24 | 25 | import androidx.annotation.NonNull; 26 | import androidx.annotation.Nullable; 27 | import android.support.v4.content.LocalBroadcastManager; 28 | 29 | import com.google.android.gms.tasks.OnFailureListener; 30 | import com.google.android.gms.tasks.OnSuccessListener; 31 | 32 | import com.google.firebase.storage.FirebaseStorage; 33 | import com.google.firebase.storage.UploadTask; 34 | import com.google.firebase.storage.OnProgressListener; 35 | import com.google.firebase.storage.StorageReference; 36 | import com.google.firebase.storage.StorageMetadata; 37 | import com.google.firebase.storage.StreamDownloadTask; 38 | import com.godot.game.BuildConfig; 39 | import com.godot.game.R; 40 | 41 | import java.io.File; 42 | import java.io.IOException; 43 | import java.io.InputStream; 44 | 45 | import org.godotengine.godot.Utils; 46 | 47 | public class UploadService extends BaseTaskService { 48 | 49 | /** Intent Actions **/ 50 | public static final String ACTION_UPLOAD = "action_upload"; 51 | public static final String UPLOAD_COMPLETED = "upload_completed"; 52 | public static final String UPLOAD_ERROR = "upload_error"; 53 | 54 | /** Intent Extras **/ 55 | public static final String EXTRA_FILE_URI = "extra_file_uri"; 56 | public static final String EXTRA_FILE_CHILD = "extra_file_child"; 57 | public static final String EXTRA_DOWNLOAD_URL = "extra_download_url"; 58 | 59 | @Override 60 | public void onCreate() { 61 | super.onCreate(); 62 | 63 | mStorageRef = FirebaseStorage.getInstance().getReference(); 64 | } 65 | 66 | @Nullable 67 | @Override 68 | public IBinder onBind(Intent intent) { 69 | return null; 70 | } 71 | 72 | @Override 73 | public int onStartCommand(Intent intent, int flags, int startId) { 74 | Utils.d("GodotFireBase", "SD:OnStartCommand: {" + intent + ":" + startId + "}"); 75 | 76 | if (ACTION_UPLOAD.equals(intent.getAction())) { 77 | Utils.d("GodotFireBase", "Intent here: " + intent.getExtras().toString()); 78 | 79 | Uri fileUri = intent.getParcelableExtra(EXTRA_FILE_URI); 80 | String child = intent.getStringExtra(EXTRA_FILE_CHILD); 81 | uploadFromUri(fileUri, child); 82 | } 83 | 84 | return START_REDELIVER_INTENT; 85 | } 86 | 87 | private void uploadFromUri(final Uri fileUri, final String child) { 88 | uploadFromUri(fileUri, child, ""); 89 | } 90 | 91 | private void uploadFromUri(final Uri fileUri, final String folder, final String meta) { 92 | Utils.d("GodotFireBase", "SD:UploadFromUri:src:" + fileUri.toString()); 93 | 94 | taskStarted(); 95 | showProgressNotification("progress_uploading", 0, 0); 96 | 97 | // Get a reference to store file at photos/.jpg 98 | final StorageReference photoRef; 99 | 100 | if (folder.equals("")) { photoRef = mStorageRef.child(fileUri.getLastPathSegment()); } 101 | else { photoRef = mStorageRef.child(folder).child(fileUri.getLastPathSegment()); } 102 | 103 | // Upload file to Firebase Storage 104 | Utils.d("GodotFireBase", "SD:UploadFromUri:dist:" + photoRef.getPath()); 105 | 106 | UploadTask task; 107 | 108 | if (meta.equals("")) { task = photoRef.putFile(fileUri); } 109 | else { 110 | StorageMetadata metadata = new StorageMetadata.Builder() 111 | .setContentType(meta) 112 | .build(); 113 | 114 | task = photoRef.putFile(fileUri, metadata); 115 | } 116 | 117 | task.addOnProgressListener(new OnProgressListener() { 118 | @Override 119 | public void onProgress(UploadTask.TaskSnapshot taskSnapshot) { 120 | showProgressNotification("progress_uploading", 121 | taskSnapshot.getBytesTransferred(), 122 | taskSnapshot.getTotalByteCount()); 123 | } 124 | }).addOnSuccessListener(new OnSuccessListener() { 125 | @Override 126 | public void onSuccess(UploadTask.TaskSnapshot taskSnapshot) { 127 | // Upload succeeded 128 | Utils.d("GodotFireBase", "SD:UploadFromUri:onSuccess"); 129 | 130 | // Get the public download URL 131 | Uri downloadUri = photoRef.getDownloadUrl(); 132 | 133 | broadcastUploadFinished(downloadUri, fileUri); 134 | showUploadFinishedNotification(downloadUri, fileUri); 135 | taskCompleted(); 136 | } 137 | }).addOnFailureListener(new OnFailureListener() { 138 | @Override 139 | public void onFailure(@NonNull Exception exception) { 140 | // Upload failed 141 | Utils.w("GodotFireBase", "SD:UploadFromUri:onFailure:" + exception.toString()); 142 | 143 | broadcastUploadFinished(null, fileUri); 144 | showUploadFinishedNotification(null, fileUri); 145 | 146 | taskCompleted(); 147 | } 148 | }); 149 | } 150 | 151 | private boolean broadcastUploadFinished(@Nullable Uri downloadUrl, @Nullable Uri fileUri) { 152 | boolean success = downloadUrl != null; 153 | 154 | String action = success ? UPLOAD_COMPLETED : UPLOAD_ERROR; 155 | 156 | Intent broadcast = new Intent(action) 157 | .putExtra(EXTRA_DOWNLOAD_URL, downloadUrl) 158 | .putExtra(EXTRA_FILE_URI, fileUri); 159 | 160 | return 161 | LocalBroadcastManager.getInstance(getApplicationContext()).sendBroadcast(broadcast); 162 | } 163 | 164 | private void showUploadFinishedNotification(@Nullable Uri downloadUrl, @Nullable Uri fileUri) { 165 | // Hide the progress notification 166 | dismissProgressNotification(); 167 | 168 | // Make Intent to MainActivity 169 | Intent intent = new Intent(this, org.godotengine.godot.Godot.class) 170 | .putExtra(EXTRA_DOWNLOAD_URL, downloadUrl) 171 | .putExtra(EXTRA_FILE_URI, fileUri) 172 | .addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_SINGLE_TOP); 173 | 174 | boolean success = downloadUrl != null; 175 | String caption = success ? "upload_success" : "upload_failure"; 176 | 177 | showFinishedNotification(caption, intent, success); 178 | } 179 | 180 | public static IntentFilter getIntentFilter() { 181 | IntentFilter filter = new IntentFilter(); 182 | filter.addAction(UPLOAD_COMPLETED); 183 | filter.addAction(UPLOAD_ERROR); 184 | 185 | return filter; 186 | } 187 | 188 | @Override 189 | public void onDestroy() { 190 | 191 | } 192 | 193 | /** 194 | // Pause the upload 195 | uploadTask.pause(); 196 | 197 | // Resume the upload 198 | uploadTask.resume(); 199 | 200 | // Cancel the upload 201 | uploadTask.cancel(); 202 | **/ 203 | 204 | private StorageReference mStorageRef = null; 205 | } 206 | -------------------------------------------------------------------------------- /colors.py: -------------------------------------------------------------------------------- 1 | RED = "\033[1;31m" 2 | BLUE = "\033[1;34m" 3 | CYAN = "\033[1;36m" 4 | GREEN = "\033[0;32m" 5 | RESET = "\033[0;0m" 6 | BOLD = "\033[;1m" 7 | REVERSE = "\033[;7m" 8 | -------------------------------------------------------------------------------- /config.fsql: -------------------------------------------------------------------------------- 1 | { 2 | "Name": "GodotFireBase", 3 | "Author": "RameshRavone (Ramesh Mani Maran)", 4 | "Email": "frogsquare@gmail.com", 5 | "License": "Apache License 2.0" 6 | } 7 | -------------------------------------------------------------------------------- /config.py: -------------------------------------------------------------------------------- 1 | 2 | import sys 3 | import json 4 | import os 5 | import re 6 | import shutil 7 | 8 | from colors import * 9 | from helper import * 10 | 11 | # Set your Android app ID 12 | p_app_id = "com.your.id" 13 | 14 | # Update this to customize the module 15 | _config = { 16 | "Analytics" : True, 17 | "AdMob" : True, 18 | "RemoteConfig" : False, 19 | "Notification" : True, 20 | "Storage" : False, 21 | "Firestore" : True, 22 | "Share" : True, 23 | 24 | "Authentication" : True, 25 | "AuthGoogle" : True, 26 | "AuthFacebook" : False, 27 | "AuthTwitter" : False 28 | } 29 | 30 | def can_build(env_plat, plat = None): 31 | #return False 32 | if plat == None: 33 | #print("`GodotFireBase`"+RED+" master "+RESET+" branch not compatable with godot 2.X") 34 | #print("Try using `GodotFireBase` "+GREEN+" 2.X "+RESET+" branch for Godot 2.X") 35 | 36 | if isinstance(env_plat, basestring): 37 | plat = env_plat 38 | else: 39 | print("GodotFireBase: "+RED+" Platform not set, Disabling GodotFireBase "+RESET) 40 | print("GodotFireBase: "+RED+" To use `GodotFireBase` in Godot 2.X copy the `build.gradle.template` from Godot 3.X and place it in `platform/android/`"+RESET) 41 | return False 42 | 43 | if plat == "android": 44 | print("GodotFireBase: " + GREEN + "Enabled" + RESET) 45 | return True 46 | else: 47 | print("GodotFireBase: " + RED + "Disabled" + RESET) 48 | return False 49 | pass 50 | 51 | def copytree(src, dst, symlinks=False, ignore=None): 52 | for item in os.listdir(src): 53 | if not os.path.exists(dst): os.makedirs(dst) 54 | 55 | s = os.path.join(src, item) 56 | d = os.path.join(dst, item) 57 | 58 | if os.path.isdir(s): shutil.copytree(s, d, symlinks, ignore) 59 | else: shutil.copyfile(s, d) 60 | pass 61 | 62 | def parse_file_data(file_data, regex_list, file_type = "Java"): 63 | final_data = []; 64 | 65 | for rr in regex_list: 66 | re_start = rr[0] 67 | re_stop = rr[1] 68 | 69 | # print("Using Regex: " + re_start); 70 | 71 | skip_line = False 72 | blank_line = False; 73 | 74 | for line in file_data: 75 | if re_start.search(line) and not skip_line: 76 | skip_line = True 77 | continue 78 | elif re_stop.search(line) and skip_line: 79 | skip_line = False 80 | continue 81 | elif empty_line.match(line): 82 | blank_line = True; 83 | continue 84 | 85 | if blank_line and len(final_data) > 0: 86 | if final_data[-1] != "\n": final_data.append("\n"); 87 | blank_line = False; 88 | 89 | if not skip_line: final_data.append(line); 90 | 91 | file_data = final_data; 92 | final_data = [] 93 | 94 | return file_data; 95 | pass 96 | 97 | def parse_java_file(p_file_src, p_file_dst, p_regex_list): 98 | p_file_data = [] 99 | 100 | try: 101 | with open(p_file_src, 'r') as file_in: 102 | p_file_data = file_in.readlines() 103 | except (OSError, IOError): return res 104 | 105 | out_file = open(p_file_dst, 'w') 106 | p_file_data = parse_file_data(p_file_data, p_regex_list, "JAVA") 107 | out_file.write("".join(p_file_data)) 108 | out_file.close() 109 | pass 110 | 111 | def update_module(env): 112 | src_dir = os.path.dirname(os.path.abspath(__file__)) + "/android_src/" 113 | target_dir = os.path.dirname(os.path.abspath(__file__)) + "/android/" 114 | 115 | if os.path.exists(target_dir): 116 | shutil.rmtree(target_dir) 117 | 118 | if not os.path.exists(target_dir): 119 | os.makedirs(target_dir) 120 | 121 | _config["Auth"] = _config["Authentication"] 122 | 123 | if (_config["Storage"] or _config["Firestore"]) and not _config["Auth"]: 124 | sys.stdout.write(RED) 125 | print("Storage/Firestore needs FireBase Authentication, Skipping `GodotFireBase` module") 126 | sys.stdout.write(RESET) 127 | 128 | return False 129 | 130 | data_to_check = \ 131 | ["Analytics", "AdMob", "Auth", "Notification", "RemoteConfig",\ 132 | "Storage", "Firestore", "Share", "AuthFacebook", "AuthGoogle", "AuthTwitter"] 133 | 134 | regex_list = [] 135 | 136 | for _file in FILES_LIST["Base"]: shutil.copyfile(src_dir+_file, target_dir+_file) 137 | 138 | if not _config["Auth"]: 139 | _config["AuthGoogle"] = False 140 | _config["AuthFacebook"] = False 141 | _config["AuthTwitter"] = False 142 | 143 | dbg_msg = "" 144 | for d in data_to_check: 145 | if d == "AdMob": 146 | if any(elem in env.module_list for elem in ["GodotAds"]): 147 | _config[d] = False 148 | elif d == "AuthGoogle": 149 | if any(elem in env.module_list for elem in ["GodotGoogleService"]): 150 | #_config[d] = False 151 | pass 152 | 153 | if not _config[d]: 154 | regex_list.append(\ 155 | [re.compile(r'([\/]+'+d+'[\+]+)'), re.compile(r'([\/]+'+d+'[\-]+)')]) 156 | else: 157 | dbg_msg += " %s," % d 158 | 159 | if d != "Storage": 160 | if d == "Auth": 161 | if not os.path.exists(target_dir+"auth/"): os.makedirs(target_dir+"auth/") 162 | for files in FILES_LIST[d]: 163 | if d == "Auth" or (d.startswith("Auth")): 164 | shutil.copyfile(src_dir+"auth/"+files, target_dir+"auth/"+files) 165 | else: shutil.copyfile(src_dir+files, target_dir+files) 166 | else: copytree(src_dir+d.lower(), target_dir+d.lower()) 167 | 168 | print("GodotFireBase: [" + dbg_msg[1:-1] + "]") 169 | 170 | # Copy FireBase.java file into memory 171 | parse_java_file(src_dir+"FireBase.java", target_dir+"FireBase.java", regex_list) 172 | 173 | if _config["Auth"] and (not _config["AuthGoogle"] or not _config["AuthFacebook"] or not _config["AuthTwitter"]): 174 | parse_java_file(src_dir+"auth/Auth.java", target_dir+"auth/Auth.java", regex_list) 175 | 176 | # Parsing AndroidManifest 177 | regex_list = [] 178 | 179 | for d in data_to_check: 180 | if not _config[d]: 181 | regex_list.append(\ 182 | [re.compile(r'(<\![\-]+ '+d+' [\-]+>)'), re.compile(r'(<\![\-]+ '+d+' [\-]+>)')]) 183 | 184 | out_file = open(target_dir+"AndroidManifestChunk.xml", 'w') 185 | file_data = [] 186 | 187 | try: 188 | with open(src_dir+"AndroidManifestChunk.xml", 'r') as file_in: 189 | file_data = file_in.readlines() 190 | except (OSError, IOError): return res 191 | 192 | file_data = parse_file_data(file_data, regex_list, "XML") 193 | 194 | out_file.write("".join(file_data)) 195 | out_file.close() 196 | 197 | return True 198 | 199 | def implement(api, support=False): 200 | supportv4 = "{exclude group: 'com.android.support' exclude module: 'appcompat-v7' exclude module: 'support-v4'}" 201 | return "implementation('"+api+"')" + (supportv4 if support else "") 202 | pass 203 | 204 | def configure(env): 205 | global p_app_id 206 | if env["platform"] == "android": 207 | if (not update_module(env)): 208 | print("Error updating module.") 209 | return 210 | 211 | if env.get("application_id", None) != None: 212 | p_app_id = env["application_id"] 213 | 214 | env.android_add_maven_repository("url 'https://maven.fabric.io/public'") 215 | env.android_add_maven_repository("url 'https://maven.google.com'") 216 | env.android_add_maven_repository(\ 217 | "url 'https://oss.sonatype.org/content/repositories/snapshots'") 218 | 219 | env.android_add_gradle_classpath("com.google.gms:google-services:4.3.0") 220 | env.android_add_gradle_plugin("com.google.gms.google-services") 221 | 222 | env.android_add_dependency(implement("com.google.firebase:firebase-core:17.0.1")) 223 | if _config["Auth"]: 224 | env.android_add_dependency(implement("com.google.firebase:firebase-auth:18.1.0")) 225 | if _config["AuthGoogle"]: 226 | env.android_add_dependency(implement("com.google.android.gms:play-services-auth:+")) 227 | pass 228 | 229 | if _config["AuthFacebook"]: 230 | env.android_add_dependency(implement("com.facebook.android:facebook-android-sdk:[4,5]", False)) 231 | 232 | if _config["AuthTwitter"]: 233 | env.android_add_dependency(\ 234 | "implementation('com.twitter.sdk.android:twitter-core:1.6.6@aar') { transitive = true }") 235 | env.android_add_dependency(\ 236 | "implementation('com.twitter.sdk.android:twitter:1.13.1@aar') { transitive = true }") 237 | 238 | if _config["AdMob"]: 239 | if any(elem in env.module_list for elem in ["GodotAds"]): pass 240 | else: 241 | env.android_add_dependency(implement("com.google.firebase:firebase-ads:18.1.1")) 242 | 243 | if _config["RemoteConfig"]: 244 | env.android_add_dependency(implement("com.google.firebase:firebase-config:18.0.0")) 245 | env.android_add_dependency(implement("com.android.support:appcompat-v7:28.0.0")) 246 | 247 | if _config["Notification"]: 248 | env.android_add_dependency(implement("com.google.firebase:firebase-messaging:19.0.1")) 249 | env.android_add_dependency(implement("com.firebase:firebase-jobdispatcher:0.8.5")) 250 | 251 | if _config["Storage"]: 252 | env.android_add_dependency(implement("com.google.firebase:firebase-storage:18.1.0")) 253 | 254 | if _config["Firestore"]: 255 | env.android_add_dependency(implement("com.google.firebase:firebase-firestore:20.1.0")) 256 | 257 | env.android_add_dependency("implementation 'commons-codec:commons-codec:1.12'") 258 | 259 | env.android_add_java_dir("android"); 260 | env.android_add_res_dir("res"); 261 | 262 | if "frogutils" in [os.path.split(path)[1] for path in env.android_java_dirs]: pass 263 | else: env.android_add_java_dir("frogutils"); 264 | 265 | env.android_add_to_manifest("android/AndroidManifestChunk.xml"); 266 | env.android_add_to_permissions("android/AndroidPermissionsChunk.xml"); 267 | env.android_add_default_config("minSdkVersion 18") 268 | env.android_add_default_config("applicationId '"+ p_app_id +"'") 269 | -------------------------------------------------------------------------------- /config.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FrogSquare/GodotFireBase/44c71e2726c3ea4c2da828aa95ae49930d47445b/config.pyc -------------------------------------------------------------------------------- /frogutils/Utils.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2017 FrogSquare. All Rights Reserved. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | **/ 16 | 17 | package org.godotengine.godot; 18 | 19 | import android.app.Activity; 20 | import android.content.Context; 21 | import android.content.res.AssetManager; 22 | import android.graphics.Bitmap; 23 | import android.graphics.BitmapFactory; 24 | import android.os.Bundle; 25 | import android.os.Environment; 26 | import android.provider.Settings; 27 | import android.util.Log; 28 | 29 | import com.godot.game.BuildConfig; 30 | import com.godot.game.R; 31 | 32 | import org.json.JSONObject; 33 | import org.json.JSONException; 34 | 35 | import java.io.InputStream; 36 | import java.io.InputStreamReader; 37 | import java.io.IOException; 38 | import java.io.BufferedReader; 39 | import java.security.MessageDigest; 40 | import java.security.NoSuchAlgorithmException; 41 | import java.util.HashMap; 42 | import java.util.Map; 43 | import java.util.Iterator; 44 | 45 | import org.godotengine.godot.Utils; 46 | 47 | public class Utils { 48 | 49 | public static final String TAG = "FrogSquare"; 50 | 51 | public static final int FIREBASE_INVITE_REQUEST = 8002; 52 | public static final int FIREBASE_NOTIFICATION_REQUEST = 8003; 53 | public static final int FIREBASE_GOOGLE_SIGN_IN = 8004; 54 | public static final int FIREBASE_FACEBOOK_SIGN_IN = 8005; 55 | public static final int FIREBASE_TWITTER_SIGN_IN = 8006; 56 | // public static final int FIREBASE_ = ; 57 | 58 | public static void initDebug(final String from) { 59 | if (DebugCfg == null) { 60 | DebugCfg = new HashMap< String, Boolean>(); 61 | } 62 | 63 | set_debug(from, true); 64 | } 65 | 66 | public static void set_debug(final String from, final boolean value) { 67 | if (DebugCfg == null) { 68 | initDebug(from); 69 | } 70 | 71 | DebugCfg.put(from, value); 72 | } 73 | 74 | public static boolean get_debug(final String from) { 75 | if (DebugCfg == null) { 76 | initDebug(from); 77 | } 78 | 79 | if (DebugCfg.containsKey(from)) { 80 | return DebugCfg.get(from); 81 | } else { 82 | set_debug(from, true); 83 | return DebugCfg.get(from); 84 | } 85 | } 86 | 87 | /** GodotSQL **/ 88 | public static boolean get_db_bool(final String p_key) { 89 | String val = get_db_value(p_key); 90 | 91 | if (val.equals("0") || val.equals("false")) { 92 | return false; 93 | } else { 94 | return true; 95 | } 96 | } 97 | 98 | public static String get_db_value(final String p_key) { 99 | return KeyValueStorage.getValue(p_key); 100 | } 101 | 102 | public static void set_db_value(final String p_key, final String p_value) { 103 | KeyValueStorage.setValue(p_key, p_value); 104 | } 105 | /** GodotSQL **/ 106 | 107 | public static void d(final String from, final String message) { 108 | if (get_debug(from)) { 109 | Log.d(TAG, message); 110 | } 111 | } 112 | 113 | public static void e(final String from, final String message) { 114 | if (get_debug(from)) { 115 | Log.e(TAG, message); 116 | } 117 | } 118 | 119 | public static void i(final String from, final String message) { 120 | if (get_debug(from)) { 121 | Log.i(TAG, message); 122 | } 123 | } 124 | 125 | public static void w(final String from, final String message) { 126 | if (get_debug(from)) { 127 | Log.w(TAG, message); 128 | } 129 | } 130 | 131 | public static Map jsonToMap (String jsonData) { 132 | JSONObject jobject = null; 133 | 134 | try { jobject = new JSONObject(jsonData); } 135 | catch (JSONException e) { Utils.d(TAG, "JSONObject exception: " + e.toString()); } 136 | 137 | Map retMap = new HashMap(); 138 | Iterator keysItr = jobject.keys(); 139 | 140 | while(keysItr.hasNext()) { 141 | try { 142 | String key = keysItr.next(); 143 | Object value = jobject.get(key); 144 | 145 | retMap.put(key, value); 146 | } catch (JSONException e) { 147 | Utils.d(TAG, "JSONObject get key error" + e.toString()); 148 | } 149 | } 150 | 151 | return retMap; 152 | } 153 | 154 | public static Bitmap getBitmapFromAsset(Context context, String filePath) { 155 | if (filePath.startsWith("res://")) { filePath = filePath.replaceFirst("res://", ""); } 156 | 157 | AssetManager assetManager = context.getAssets(); 158 | 159 | InputStream istr; 160 | Bitmap bitmap = null; 161 | 162 | try { 163 | istr = assetManager.open(filePath); 164 | bitmap = BitmapFactory.decodeStream(istr); 165 | } catch (IOException e) { 166 | // handle exception 167 | } 168 | 169 | return bitmap; 170 | } 171 | 172 | public static String readFromFile(String fPath, Context context) { 173 | Utils.d(TAG, "Reading File: " + fPath); 174 | StringBuilder returnString = new StringBuilder(); 175 | 176 | String fileName = fPath; 177 | if (fPath.startsWith("res://")) { fileName = fileName.replaceFirst("res://", ""); } 178 | 179 | InputStream fIn = null; 180 | InputStreamReader isr = null; 181 | BufferedReader input = null; 182 | 183 | try { 184 | fIn = context.getResources().getAssets() 185 | .open(fileName, Context.MODE_WORLD_READABLE); 186 | 187 | isr = new InputStreamReader(fIn); 188 | input = new BufferedReader(isr); 189 | 190 | String line = ""; 191 | 192 | while ((line = input.readLine()) != null) { 193 | returnString.append(line); 194 | } 195 | 196 | } 197 | catch (Exception e) { 198 | Utils.d(TAG, "FileRead Failed: " + e.getMessage()); 199 | } 200 | finally { 201 | try { 202 | if (isr != null) { isr.close(); } 203 | if (fIn != null) { fIn.close(); } 204 | if (input != null) { input.close(); } 205 | 206 | } catch (Exception e2) { e2.getMessage(); } 207 | } 208 | 209 | return returnString.toString(); 210 | } 211 | 212 | public static String askForPath(final String folder) { 213 | return Environment.getExternalStorageDirectory().getAbsolutePath() + folder; 214 | } 215 | 216 | // { Device ID - https://stackoverflow.com/questions/4524752/how-can-i-get-device-id-for-admob 217 | 218 | public static String getDeviceId(Activity activity) { 219 | String android_id = 220 | Settings.Secure.getString(activity.getContentResolver(), Settings.Secure.ANDROID_ID); 221 | 222 | String deviceId = md5(android_id).toUpperCase(); 223 | 224 | return android_id; 225 | } 226 | 227 | public static final String md5(final String s) { 228 | try { 229 | // Create MD5 Hash 230 | MessageDigest digest = java.security.MessageDigest.getInstance("MD5"); 231 | digest.update(s.getBytes()); 232 | 233 | byte messageDigest[] = digest.digest(); 234 | 235 | // Create Hex String 236 | StringBuffer hexString = new StringBuffer(); 237 | 238 | for (int i = 0; i < messageDigest.length; i++) { 239 | String h = Integer.toHexString(0xFF & messageDigest[i]); 240 | 241 | while (h.length() < 2) { 242 | h = "0" + h; 243 | } 244 | 245 | hexString.append(h); 246 | } 247 | 248 | return hexString.toString(); 249 | } catch (NoSuchAlgorithmException e) { Utils.w(TAG, "FB:MD5:Algorithm:" + e.toString()); } 250 | 251 | return ""; 252 | } 253 | 254 | /* Checks if external storage is available for read and write */ 255 | public static boolean isExternalStorageWritable() { 256 | String state = Environment.getExternalStorageState(); 257 | if (Environment.MEDIA_MOUNTED.equals(state)) { 258 | return true; 259 | } 260 | 261 | return false; 262 | } 263 | 264 | /* Checks if external storage is available to at least read */ 265 | public static boolean isExternalStorageReadable() { 266 | String state = Environment.getExternalStorageState(); 267 | if (Environment.MEDIA_MOUNTED.equals(state) || 268 | Environment.MEDIA_MOUNTED_READ_ONLY.equals(state)) { 269 | 270 | return true; 271 | } 272 | 273 | return false; 274 | } 275 | 276 | // Check for class 277 | public static boolean isClass(String className) { 278 | try { 279 | Class.forName(className); 280 | return true; 281 | } catch (ClassNotFoundException e) { return false; } 282 | } 283 | 284 | public static void setScriptInstance(int instanceID) { 285 | script_instanceID = instanceID; 286 | } 287 | 288 | public static void callScriptCallback( 289 | int script_id, String function, String from, Object key, Object value) { 290 | 291 | GodotLib.calldeferred(script_id, function, new Object[] { TAG, from, key, value }); 292 | } 293 | 294 | public static void callScriptCallback(String function, String from, Object key, Object value) { 295 | if (script_instanceID == -1) { 296 | Utils.d(TAG, "Script::Instance::NotSset"); 297 | return; 298 | } 299 | 300 | GodotLib.calldeferred(script_instanceID, function, 301 | new Object[] { TAG, from, key, value }); 302 | } 303 | 304 | public static void callScriptFunc(int script_id, String from, Object key, Object value) { 305 | GodotLib.calldeferred(script_id, "_receive_message", 306 | new Object[] { TAG, from, key, value }); 307 | } 308 | 309 | public static void callScriptFunc(String from, Object key, Object value) { 310 | if (script_instanceID == -1) { 311 | Utils.d(TAG, "Script::Instance::NotSset"); 312 | return; 313 | } 314 | 315 | GodotLib.calldeferred(script_instanceID, "_receive_message", 316 | new Object[] { TAG, from, key, value }); 317 | } 318 | 319 | public static boolean checkGooglePlayService(Activity activity) { 320 | return true; 321 | } 322 | 323 | public static void putAllInDict(Bundle bundle, Dictionary keyValues) { 324 | String[] keys = keyValues.get_keys(); 325 | for(int i=0; i < keys.length; i++) { 326 | String key = keys[i]; 327 | Utils.putGodotValue(bundle, key, keyValues.get(key)); 328 | } 329 | } 330 | 331 | public static void putGodotValue(Bundle bundle, String key, Object value) { 332 | 333 | if (value instanceof Boolean) { 334 | bundle.putBoolean(key, (Boolean) value); 335 | 336 | } else if (value instanceof Integer) { 337 | bundle.putInt(key, (Integer) value); 338 | 339 | } else if (value instanceof Double) { 340 | bundle.putDouble(key, (Double) value); 341 | 342 | } else if (value instanceof String) { 343 | bundle.putString(key, (String) value); 344 | 345 | } else { 346 | 347 | if (value != null) { 348 | bundle.putString(key, value.toString()); 349 | } 350 | 351 | } 352 | } 353 | 354 | private static Map< String, Boolean> DebugCfg = null; 355 | public static int script_instanceID = -1; 356 | } 357 | -------------------------------------------------------------------------------- /helper.py: -------------------------------------------------------------------------------- 1 | 2 | import re 3 | 4 | FILES_LIST = \ 5 | { 6 | "AdMob" : ["AdMob.java"], 7 | "Analytics" : ["Analytics.java"], 8 | "Auth" : ["AnonymousAuth.java", "Auth.java", "EmailAndPassword.java"], 9 | "Base" : ["FireBase.java", "AndroidPermissionsChunk.xml"], 10 | "Notification" : ["MessagingService.java", "Notification.java", \ 11 | "NotifyInTime.java"], 12 | "RemoteConfig" : ["RemoteConfig.java"], 13 | "Storage" : ["storage/"], 14 | "Firestore" : ["Firestore.java"], 15 | "Share" : ["Share.java"], 16 | 17 | "AuthGoogle" : ["GoogleSignIn.java"], 18 | "AuthFacebook" : ["FacebookSignIn.java"], 19 | "AuthTwitter" : ["TwitterSignIn.java"], 20 | } 21 | 22 | directory = "android" 23 | empty_line = re.compile(r'^\s*$') 24 | -------------------------------------------------------------------------------- /res/drawable-hdpi/firebase_lockup_400.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FrogSquare/GodotFireBase/44c71e2726c3ea4c2da828aa95ae49930d47445b/res/drawable-hdpi/firebase_lockup_400.png -------------------------------------------------------------------------------- /res/drawable-hdpi/ic_check_white_24.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FrogSquare/GodotFireBase/44c71e2726c3ea4c2da828aa95ae49930d47445b/res/drawable-hdpi/ic_check_white_24.png -------------------------------------------------------------------------------- /res/drawable-hdpi/ic_error_white_24dp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FrogSquare/GodotFireBase/44c71e2726c3ea4c2da828aa95ae49930d47445b/res/drawable-hdpi/ic_error_white_24dp.png -------------------------------------------------------------------------------- /res/drawable-hdpi/ic_file_upload_white_24dp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FrogSquare/GodotFireBase/44c71e2726c3ea4c2da828aa95ae49930d47445b/res/drawable-hdpi/ic_file_upload_white_24dp.png -------------------------------------------------------------------------------- /res/drawable-mdpi/notification_small_icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FrogSquare/GodotFireBase/44c71e2726c3ea4c2da828aa95ae49930d47445b/res/drawable-mdpi/notification_small_icon.png -------------------------------------------------------------------------------- /res/values/colors.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | #FFA000 5 | 6 | -------------------------------------------------------------------------------- /res/values/ids.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 1234567890987654 5 | ca-app-pub-3940256099942544/6300978111 6 | ca-app-pub-3940256099942544/1033173712 7 | ca-app-pub-3940256099942544/5224354917 8 | Mv71bxjlRumBlPI3HoRdle4I7 9 | 7yShM5dovdoBfLSnTfiIlZmZj6s6efBxQqapWcoZEOzDMHaKYx 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /res/values/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Invite Friends! 5 | gd-firebase-notify-in-time-UID 6 | 7 | -------------------------------------------------------------------------------- /res/xml/remote_config_defaults.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | firebase_remoteconfig_test 6 | This is remote config default Test Value... 7 | 8 | 9 | --------------------------------------------------------------------------------