From 508bc191bea7ec1d6749fe9748fcb24bbc0e48b8 Mon Sep 17 00:00:00 2001 From: Zohaib Kambrani <> Date: Sun, 20 Dec 2020 13:44:29 +0300 Subject: [PATCH] geofencing login check fix --- android/app/src/main/AndroidManifest.xml | 2 +- .../geofence/GeoZoneModel.kt | 2 + .../geofence/GeofenceBroadcastReceiver.kt | 17 +++++++- .../GeofenceBroadcastReceiverWithService.kt | 13 ++++++ .../GeofenceTransitionsJobIntentService.kt | 37 +++-------------- .../GeofencingRebootBroadcastReceiver.kt | 3 +- .../geofence/HMG_Geofence.kt | 41 ++++++++++++++++++- .../diplomaticquarterapp/utils/HMGUtils.kt | 35 ++++++++++++++-- ios/Runner/AppDelegate.swift | 22 ---------- ios/Runner/Helper/Extensions.swift | 10 +++++ ios/Runner/Helper/GlobalHelper.swift | 30 +++++++++++++- ios/Runner/Helper/HMG_Geofence.swift | 14 ++++--- lib/pages/landing/landing_page.dart | 30 ++++++-------- 13 files changed, 169 insertions(+), 87 deletions(-) create mode 100644 android/app/src/main/kotlin/com/cloud/diplomaticquarterapp/geofence/GeofenceBroadcastReceiverWithService.kt diff --git a/android/app/src/main/AndroidManifest.xml b/android/app/src/main/AndroidManifest.xml index 1032b29b..c114b44d 100644 --- a/android/app/src/main/AndroidManifest.xml +++ b/android/app/src/main/AndroidManifest.xml @@ -80,7 +80,7 @@ - + diff --git a/android/app/src/main/kotlin/com/cloud/diplomaticquarterapp/geofence/GeoZoneModel.kt b/android/app/src/main/kotlin/com/cloud/diplomaticquarterapp/geofence/GeoZoneModel.kt index 7eba1ead..328014e6 100644 --- a/android/app/src/main/kotlin/com/cloud/diplomaticquarterapp/geofence/GeoZoneModel.kt +++ b/android/app/src/main/kotlin/com/cloud/diplomaticquarterapp/geofence/GeoZoneModel.kt @@ -37,6 +37,7 @@ class GeoZoneModel { val rad = Radius.toFloat() if(lat != null && long != null){ + val loiteringDelayMinutes:Int = 5 // in Minutes return Geofence.Builder() .setRequestId(identifier()) .setCircularRegion( @@ -46,6 +47,7 @@ class GeoZoneModel { ) .setTransitionTypes(GeofenceTransition.ENTER_EXIT.value) // .setNotificationResponsiveness(0) +// .setLoiteringDelay(loiteringDelayMinutes * 60 * 1000) .setExpirationDuration(Geofence.NEVER_EXPIRE) .build() } diff --git a/android/app/src/main/kotlin/com/cloud/diplomaticquarterapp/geofence/GeofenceBroadcastReceiver.kt b/android/app/src/main/kotlin/com/cloud/diplomaticquarterapp/geofence/GeofenceBroadcastReceiver.kt index 8fc1faae..f8a861bb 100644 --- a/android/app/src/main/kotlin/com/cloud/diplomaticquarterapp/geofence/GeofenceBroadcastReceiver.kt +++ b/android/app/src/main/kotlin/com/cloud/diplomaticquarterapp/geofence/GeofenceBroadcastReceiver.kt @@ -5,9 +5,24 @@ package com.cloud.diplomaticquarterapp.geofence import android.content.BroadcastReceiver import android.content.Context import android.content.Intent +import android.util.Log +import com.cloud.diplomaticquarterapp.utils.saveLog +import com.google.android.gms.location.GeofencingEvent class GeofenceBroadcastReceiver : BroadcastReceiver() { + private val LOG_TAG = "GeofenceBroadcastReceiver" override fun onReceive(context: Context, intent: Intent) { - GeofenceTransitionsJobIntentService.enqueueWork(context, intent) + + val geofencingEvent = GeofencingEvent.fromIntent(intent) + if (geofencingEvent.hasError()) { + val errorMessage = GeofenceErrorMessages.getErrorString(context, geofencingEvent.errorCode) + Log.e(LOG_TAG, errorMessage) + saveLog(context,LOG_TAG,errorMessage) + return + } + + HMG_Geofence.shared(context).handleEvent(geofencingEvent.triggeringGeofences,geofencingEvent.triggeringLocation, GeofenceTransition.fromInt(geofencingEvent.geofenceTransition)); + } + } \ No newline at end of file diff --git a/android/app/src/main/kotlin/com/cloud/diplomaticquarterapp/geofence/GeofenceBroadcastReceiverWithService.kt b/android/app/src/main/kotlin/com/cloud/diplomaticquarterapp/geofence/GeofenceBroadcastReceiverWithService.kt new file mode 100644 index 00000000..0332f745 --- /dev/null +++ b/android/app/src/main/kotlin/com/cloud/diplomaticquarterapp/geofence/GeofenceBroadcastReceiverWithService.kt @@ -0,0 +1,13 @@ + + +package com.cloud.diplomaticquarterapp.geofence + +import android.content.BroadcastReceiver +import android.content.Context +import android.content.Intent + +class GeofenceBroadcastReceiverWithService : BroadcastReceiver() { + override fun onReceive(context: Context, intent: Intent) { + GeofenceTransitionsJobIntentService.enqueueWork(context, intent) + } +} \ No newline at end of file diff --git a/android/app/src/main/kotlin/com/cloud/diplomaticquarterapp/geofence/GeofenceTransitionsJobIntentService.kt b/android/app/src/main/kotlin/com/cloud/diplomaticquarterapp/geofence/GeofenceTransitionsJobIntentService.kt index f28e1720..18ee92d9 100755 --- a/android/app/src/main/kotlin/com/cloud/diplomaticquarterapp/geofence/GeofenceTransitionsJobIntentService.kt +++ b/android/app/src/main/kotlin/com/cloud/diplomaticquarterapp/geofence/GeofenceTransitionsJobIntentService.kt @@ -52,8 +52,9 @@ class GeofenceTransitionsJobIntentService : JobIntentService() { private const val LOG_TAG = "GeoTrIntentService" private const val JOB_ID = 573 - + var context_: Context? = null fun enqueueWork(context: Context, intent: Intent) { + context_ = context enqueueWork( context, GeofenceTransitionsJobIntentService::class.java, JOB_ID, @@ -70,37 +71,9 @@ class GeofenceTransitionsJobIntentService : JobIntentService() { } if (geofencingEvent.geofenceTransition == Geofence.GEOFENCE_TRANSITION_ENTER || geofencingEvent.geofenceTransition == Geofence.GEOFENCE_TRANSITION_EXIT) { - handleEvent(geofencingEvent.triggeringGeofences,geofencingEvent.triggeringLocation, GeofenceTransition.fromInt(geofencingEvent.geofenceTransition)); - } - } - - private fun handleEvent(triggerGeofences: List, location:Location, transition:GeofenceTransition) { - val hmg = HMG_Geofence.shared(this) - hmg.getPatientID()?.let { patientId -> - - hmg.getActiveGeofences({ activeGeofences -> - - triggerGeofences.forEach { geofence -> - // Extract PointID from 'geofence.requestId' and find from active geofences - val pointID = activeGeofences.firstOrNull {it == geofence.requestId}?.split('_')?.first() - if(!pointID.isNullOrEmpty() && pointID.toIntOrNull() != null){ - - val body = mapOf( - "PointsID" to pointID.toIntOrNull(), - "GeoType" to transition.value, - "PatientID" to patientId - ) - - httpPost>(API.LOG_GEOFENCE, body, { response -> - sendNotification(this, transition.named(), geofence.requestId, "Notified to server.😎") - },{ exception -> - sendNotification(this, transition.named(), geofence.requestId, "Failed to notify server.😔") - }) - - } - } - - },null) + context_?.let { + HMG_Geofence.shared(it).handleEvent(geofencingEvent.triggeringGeofences,geofencingEvent.triggeringLocation, GeofenceTransition.fromInt(geofencingEvent.geofenceTransition)); + } } } } \ No newline at end of file diff --git a/android/app/src/main/kotlin/com/cloud/diplomaticquarterapp/geofence/GeofencingRebootBroadcastReceiver.kt b/android/app/src/main/kotlin/com/cloud/diplomaticquarterapp/geofence/GeofencingRebootBroadcastReceiver.kt index 08a0c93f..4534b08f 100644 --- a/android/app/src/main/kotlin/com/cloud/diplomaticquarterapp/geofence/GeofencingRebootBroadcastReceiver.kt +++ b/android/app/src/main/kotlin/com/cloud/diplomaticquarterapp/geofence/GeofencingRebootBroadcastReceiver.kt @@ -13,7 +13,8 @@ import com.cloud.diplomaticquarterapp.utils.HMGUtils class GeofencingRebootBroadcastReceiver : BroadcastReceiver(){ override fun onReceive(context: Context, intent: Intent) { - if (Intent.ACTION_BOOT_COMPLETED.equals(intent.action)) { +// if (Intent.ACTION_BOOT_COMPLETED.equals(intent.action)) { + if (intent.action.equals("android.intent.action.BOOT_COMPLETE")) { val pref = context.getSharedPreferences(PREFS_STORAGE, Context.MODE_PRIVATE) pref.edit().putString("REBOOT_DETECTED","YES").apply() diff --git a/android/app/src/main/kotlin/com/cloud/diplomaticquarterapp/geofence/HMG_Geofence.kt b/android/app/src/main/kotlin/com/cloud/diplomaticquarterapp/geofence/HMG_Geofence.kt index 4d2c48b3..24639c6c 100644 --- a/android/app/src/main/kotlin/com/cloud/diplomaticquarterapp/geofence/HMG_Geofence.kt +++ b/android/app/src/main/kotlin/com/cloud/diplomaticquarterapp/geofence/HMG_Geofence.kt @@ -6,7 +6,9 @@ import android.content.Context import android.content.Intent import android.content.SharedPreferences import android.content.pm.PackageManager +import android.location.Location import androidx.core.content.ContextCompat +import com.cloud.diplomaticquarterapp.utils.* import com.google.android.gms.location.Geofence import com.google.android.gms.location.GeofencingClient import com.google.android.gms.location.GeofencingRequest @@ -37,6 +39,7 @@ const val PREFS_STORAGE = "FlutterSharedPreferences" const val PREF_KEY_SUCCESS = "HMG_GEOFENCE_SUCCESS" const val PREF_KEY_FAILED = "HMG_GEOFENCE_FAILED" const val PREF_KEY_HMG_ZONES = "flutter.hmg-geo-fences" +const val PREF_KEY_LANGUAGE = "flutter.language" class HMG_Geofence { // https://developer.android.com/training/location/geofencing#java @@ -99,6 +102,7 @@ class HMG_Geofence { } .addOnFailureListener { print(it.localizedMessage) + saveLog(context,"error:ADD_GEOFENCES", it.localizedMessage) } } },null) @@ -107,7 +111,6 @@ class HMG_Geofence { fun unRegisterAll(completion: (status: Boolean, exception:Exception?) -> Unit){ getActiveGeofences({ success -> val mList = success.toMutableList() - mList.add("12345") geofencingClient .removeGeofences(success) .addOnSuccessListener { @@ -115,6 +118,7 @@ class HMG_Geofence { } .addOnFailureListener { completion(false, it) + saveLog(context,"error:REMOVE_GEOFENCES", it.localizedMessage) } removeActiveGeofences() }, { failed -> @@ -154,7 +158,10 @@ class HMG_Geofence { } fun getPatientID():Int?{ - val profileJson = preferences.getString("flutter.imei-user-data", "{}") + var profileJson = preferences.getString("flutter.imei-user-data", null) + if (profileJson == null) + profileJson = preferences.getString("flutter.user-profile", null) + val type = object : TypeToken?>() {}.type return gson.fromJson?>(profileJson,type) ?.get("PatientID") @@ -162,4 +169,34 @@ class HMG_Geofence { .toDoubleOrNull() ?.toInt() } + + + fun handleEvent(triggerGeofences: List, location: Location, transition:GeofenceTransition) { + getPatientID()?.let { patientId -> + getActiveGeofences({ activeGeofences -> + + triggerGeofences.forEach { geofence -> + // Extract PointID from 'geofence.requestId' and find from active geofences + val pointID = activeGeofences.firstOrNull {it == geofence.requestId}?.split('_')?.first() + if(!pointID.isNullOrEmpty() && pointID.toIntOrNull() != null){ + + val body = mutableMapOf( + "PointsID" to pointID.toIntOrNull(), + "GeoType" to transition.value, + "PatientID" to patientId + ) + body.putAll(HMGUtils.defaultHTTPParams(context)) + + httpPost>(API.LOG_GEOFENCE, body, { response -> + sendNotification(context, transition.named(), geofence.requestId, "Notified to server.😎") + },{ exception -> + sendNotification(context, transition.named(), geofence.requestId, "Failed to notify server.😔") + }) + + } + } + + },null) + } + } } \ No newline at end of file diff --git a/android/app/src/main/kotlin/com/cloud/diplomaticquarterapp/utils/HMGUtils.kt b/android/app/src/main/kotlin/com/cloud/diplomaticquarterapp/utils/HMGUtils.kt index bebd0101..413e8c09 100644 --- a/android/app/src/main/kotlin/com/cloud/diplomaticquarterapp/utils/HMGUtils.kt +++ b/android/app/src/main/kotlin/com/cloud/diplomaticquarterapp/utils/HMGUtils.kt @@ -16,6 +16,7 @@ import com.cloud.diplomaticquarterapp.R import com.cloud.diplomaticquarterapp.geofence.GeoZoneModel import com.cloud.diplomaticquarterapp.geofence.PREFS_STORAGE import com.cloud.diplomaticquarterapp.geofence.PREF_KEY_HMG_ZONES +import com.cloud.diplomaticquarterapp.geofence.PREF_KEY_LANGUAGE import com.github.kittinunf.fuel.core.extensions.jsonBody import com.github.kittinunf.fuel.httpPost import com.google.android.gms.location.Geofence @@ -76,6 +77,26 @@ class HMGUtils { return geoZones } + fun getLanguageCode(context: Context) : Int{ + val pref = context.getSharedPreferences(PREFS_STORAGE, Context.MODE_PRIVATE) + val lang = pref.getString(PREF_KEY_LANGUAGE,"ar") + return if(lang == "ar") 2 else 1 + } + + fun defaultHTTPParams(context: Context) : Map{ + return mapOf( + "ZipCode" to "966", + "VersionID" to 5.6, + "Channel" to 3, + "LanguageID" to getLanguageCode(context), + "IPAdress" to "10.20.10.20", + "generalid" to "Cs2020@2016$2958", + "PatientOutSA" to 0, + "SessionID" to null, + "isDentalAllowedBackend" to false, + "DeviceTypeID" to 2) + } + } } @@ -117,7 +138,9 @@ fun sendNotification(context: Context, title:String, @Nullable subtitle:String?, notificationManager.notify(getUniqueId(), notification.build()) } - +//------------------------- +// Open Helper Methods +//------------------------- private fun getUniqueId() = ((System.currentTimeMillis() % 10000).toInt()) fun isJSONValid(jsonString: String?): Boolean { @@ -129,11 +152,18 @@ fun isJSONValid(jsonString: String?): Boolean { return true } +fun saveLog(context:Context, tag:String, message:String){ + val pref = context.getSharedPreferences(PREFS_STORAGE, Context.MODE_PRIVATE) + var logs = pref.getString("GEO_LOGS","") + logs += "$tag -> $message \n" + pref.edit().putString("PLATFORM_LOGS", logs).apply(); +} + class HTTPResponse(data: T){ final var data:T = data } -fun httpPost(url: String, body: Map, onSuccess: (response: HTTPResponse) -> Unit, onError: (error: Exception) -> Unit){ +fun httpPost(url: String, body: Map, onSuccess: (response: HTTPResponse) -> Unit, onError: (error: Exception) -> Unit){ val gson = Gson() val type = object : TypeToken() {}.type val jsonBody = gson.toJson(body) @@ -153,7 +183,6 @@ fun httpPost(url: String, body: Map, onSuccess: (response: HTTP } }, { onError(it) - it.localizedMessage }) } diff --git a/ios/Runner/AppDelegate.swift b/ios/Runner/AppDelegate.swift index e686619c..a9252ee5 100644 --- a/ios/Runner/AppDelegate.swift +++ b/ios/Runner/AppDelegate.swift @@ -8,7 +8,6 @@ import GoogleMaps let locationManager = CLLocationManager() override func application( _ application: UIApplication,didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool { -// initLocationManager() GMSServices.provideAPIKey("AIzaSyCiiJiHkocPbcziHt9O8rGWavDrxHRQys8") GeneratedPluginRegistrant.register(with: self) @@ -24,24 +23,3 @@ import GoogleMaps return super.application(application, didFinishLaunchingWithOptions: launchOptions) } } - -extension AppDelegate: CLLocationManagerDelegate { - - func initLocationManager(){ - locationManager.allowsBackgroundLocationUpdates = true - locationManager.desiredAccuracy = kCLLocationAccuracyNearestTenMeters - locationManager.activityType = .other - locationManager.delegate = self - locationManager.requestAlwaysAuthorization() - } - - func locationManager(_ manager: CLLocationManager, didEnterRegion region: CLRegion) { - if region is CLCircularRegion { - } - } - - func locationManager(_ manager: CLLocationManager, didExitRegion region: CLRegion) { - if region is CLCircularRegion { - } - } -} diff --git a/ios/Runner/Helper/Extensions.swift b/ios/Runner/Helper/Extensions.swift index a8793617..5c1de7c3 100644 --- a/ios/Runner/Helper/Extensions.swift +++ b/ios/Runner/Helper/Extensions.swift @@ -18,6 +18,16 @@ extension String{ } } +extension Dictionary{ + func merge(dict:[String:Any?]) -> [String:Any?]{ + var self_ = self as! [String:Any?] + dict.forEach { (kv) in + self_.updateValue(kv.value, forKey: kv.key) + } + return self_ + } +} + extension Bundle { func certificate(named name: String) -> SecCertificate { diff --git a/ios/Runner/Helper/GlobalHelper.swift b/ios/Runner/Helper/GlobalHelper.swift index c5eb7295..35f89991 100644 --- a/ios/Runner/Helper/GlobalHelper.swift +++ b/ios/Runner/Helper/GlobalHelper.swift @@ -49,9 +49,35 @@ func showNotification(identifier:String? = nil, title:String?, subtitle:String?, } } +func appLanguageCode() -> Int{ + let lang = UserDefaults.standard.string(forKey: "language") ?? "ar" + return lang == "ar" ? 2 : 1 +} + +func userProfile() -> [String:Any?]?{ + var userProf = UserDefaults.standard.string(forKey: "flutter.imei-user-data") + if(userProf == nil){ + userProf = UserDefaults.standard.string(forKey: "flutter.user-profile") + } + return dictionary(from: userProf ?? "{}") +} + +fileprivate let defaultHTTPParams:[String : Any?] = [ + "ZipCode" : "966", + "VersionID" : 5.6, + "Channel" : 3, + "LanguageID" : appLanguageCode(), + "IPAdress" : "10.20.10.20", + "generalid" : "Cs2020@2016$2958", + "PatientOutSA" : 0, + "SessionID" : nil, + "isDentalAllowedBackend" : false, + "DeviceTypeID" : 2 +] -func httpPostRequest(urlString:String, jsonBody:[String:Any], completion:((Bool,[String:Any]?)->Void)?){ - let json: [String: Any] = jsonBody +func httpPostRequest(urlString:String, jsonBody:[String:Any?], completion:((Bool,[String:Any]?)->Void)?){ + var json: [String: Any?] = jsonBody + json = json.merge(dict: defaultHTTPParams) let jsonData = try? JSONSerialization.data(withJSONObject: json) // create post request diff --git a/ios/Runner/Helper/HMG_Geofence.swift b/ios/Runner/Helper/HMG_Geofence.swift index 0c39fe5a..3299fa1a 100644 --- a/ios/Runner/Helper/HMG_Geofence.swift +++ b/ios/Runner/Helper/HMG_Geofence.swift @@ -156,8 +156,13 @@ extension HMG_Geofence{ func notifyServer(forRegion:CLRegion, transition:Transition, location:CLLocation?){ df.dateFormat = "MMM/dd/yyyy hh:mm:ss" - if let userProfileJson = UserDefaults.standard.string(forKey: "flutter.imei-user-data"), - let userProfile = dictionary(from: userProfileJson), let patientId = userProfile["PatientID"] as? Int{ + var userInfo = UserDefaults.standard.string(forKey: "flutter.imei-user-data") + if(userInfo == nil){ + userInfo = UserDefaults.standard.string(forKey: "flutter.user-profile") + } + + if let userProfile = userProfile(), + let patientId = userProfile["PatientID"] as? Int{ if let idString = forRegion.identifier.split(separator: "_").first, let idInt = Int(idString){ let body:[String:Any] = [ @@ -172,15 +177,14 @@ extension HMG_Geofence{ showNotification(title: transition.name(), subtitle: forRegion.identifier, message: status_) - var logs = UserDefaults.init(suiteName: "GeoFenceLog")?.dictionary(forKey: "LOGS") ?? [:] + var logs = UserDefaults.init(suiteName: "GeoFenceLog")?.dictionary(forKey: "GEOFENCE_LOGS") ?? [:] if var geo = logs[forRegion.identifier] as? [String]{ geo.append("\(status_) at \(df.string(from: Date()))") }else{ logs.updateValue(["\(status_) at \(df.string(from: Date()))"], forKey: forRegion.identifier) } - UserDefaults.init(suiteName: "GeoFenceLog")?.set(logs, forKey: "LOGS") - + UserDefaults.init(suiteName: "GeoFenceLog")?.set(logs, forKey: "GEOFENCE_LOGS") } } } diff --git a/lib/pages/landing/landing_page.dart b/lib/pages/landing/landing_page.dart index a45f24eb..7625bcf6 100644 --- a/lib/pages/landing/landing_page.dart +++ b/lib/pages/landing/landing_page.dart @@ -142,11 +142,14 @@ class _LandingPageState extends State with WidgetsBindingObserver { PlatformBridge().connectHMGGuestWifi().then((value) => {GifLoaderDialogUtils.hideDialog(context)}); }).checkAndConnectIfNoInternet(); + if (Platform.isIOS) { _firebaseMessaging.requestNotificationPermissions(); } requestPermissions().then((results) { + registerGeofences(); + if (results[Permission.notification].isGranted) _firebaseMessaging.getToken().then((String token) { sharedPref.setString(PUSH_TOKEN, token); @@ -156,7 +159,7 @@ class _LandingPageState extends State with WidgetsBindingObserver { } }); - if (results[Permission.location].isGranted) ; + if (results[Permission.locationAlways].isGranted) ; if (results[Permission.storage].isGranted) ; if (results[Permission.camera].isGranted) ; if (results[Permission.photos].isGranted) ; @@ -436,7 +439,6 @@ class _LandingPageState extends State with WidgetsBindingObserver { void checkUserStatus(token) async { var result = await authService.selectDeviceImei(token); await setUserValues(result); - registerGeofences(); if (await sharedPref.getObject(USER_PROFILE) != null) { var data = AuthenticatedUser.fromJson(await sharedPref.getObject(USER_PROFILE)); @@ -483,22 +485,14 @@ class _LandingPageState extends State with WidgetsBindingObserver { registerGeofences() async { await locator().getAllGeoZones(GeoZonesRequestModel()); - var userInfo = await getUserInformation(); - - void doIt() { - projectViewModel.platformBridge().registerHmgGeofences(); - } - - if (userInfo != null) { - if (await Permission.location.isGranted) { - doIt(); - } else { - [Permission.location].request().then((value) async { - if (await Permission.location.isGranted) { - doIt(); - } - }); - } + if (await Permission.location.isGranted) { + PlatformBridge().registerHmgGeofences(); + } else { + [Permission.location].request().then((results) async { + if (results[Permission.locationAlways].isGranted){ + PlatformBridge().registerHmgGeofences(); + } + }); } } }