From 0f64c45e670da2004e7edad576325cef629f1c0a Mon Sep 17 00:00:00 2001 From: Zohaib Kambrani <> Date: Thu, 17 Dec 2020 09:05:38 +0300 Subject: [PATCH] no message --- .../geofence/GeoZoneModel.kt | 2 +- .../GeofenceTransitionsJobIntentService.kt | 28 +++--- .../GeofencingRebootBroadcastReceiver.kt | 21 +++++ .../geofence/HMG_Geofence.kt | 32 ++++--- .../diplomaticquarterapp/utils/HMGUtils.kt | 86 ++++++++++++++----- .../utils/PlatformBridge.kt | 18 ++-- ios/Podfile.lock | 10 +-- ios/Runner.xcodeproj/project.pbxproj | 6 +- 8 files changed, 143 insertions(+), 60 deletions(-) create mode 100644 android/app/src/main/kotlin/com/cloud/diplomaticquarterapp/geofence/GeofencingRebootBroadcastReceiver.kt 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 8cf31a76..7eba1ead 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 @@ -44,7 +44,7 @@ class GeoZoneModel { long, rad ) - .setTransitionTypes(Geofence.GEOFENCE_TRANSITION_ENTER or Geofence.GEOFENCE_TRANSITION_EXIT) + .setTransitionTypes(GeofenceTransition.ENTER_EXIT.value) // .setNotificationResponsiveness(0) .setExpirationDuration(Geofence.NEVER_EXPIRE) .build() 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 0da35b6b..f28e1720 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 @@ -37,7 +37,10 @@ import android.location.Location import android.util.Log import androidx.core.app.JobIntentService import com.cloud.diplomaticquarterapp.utils.API +import com.cloud.diplomaticquarterapp.utils.httpPost +import com.cloud.diplomaticquarterapp.utils.sendNotification import com.github.kittinunf.fuel.core.extensions.jsonBody +import com.github.kittinunf.fuel.core.isSuccessful import com.github.kittinunf.fuel.httpPost import com.google.android.gms.location.Geofence import com.google.android.gms.location.GeofencingEvent @@ -73,34 +76,31 @@ class GeofenceTransitionsJobIntentService : JobIntentService() { private fun handleEvent(triggerGeofences: List, location:Location, transition:GeofenceTransition) { val hmg = HMG_Geofence.shared(this) - if (hmg.getPatientID() != null){ + 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() } + val pointID = activeGeofences.firstOrNull {it == geofence.requestId}?.split('_')?.first() if(!pointID.isNullOrEmpty() && pointID.toIntOrNull() != null){ - val jsonBody = Gson().toJson( - mapOf("PointsID" to pointID.toIntOrNull(), - "GeoType" to transition.value, - "PatientID" to "") + val body = mapOf( + "PointsID" to pointID.toIntOrNull(), + "GeoType" to transition.value, + "PatientID" to patientId ) - API.LOG_GEOFENCE - .httpPost() - .jsonBody(jsonBody,Charsets.UTF_8) - .timeout(10000) - .response { request, response, result -> - - } + 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) - } } } \ 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 new file mode 100644 index 00000000..641e1522 --- /dev/null +++ b/android/app/src/main/kotlin/com/cloud/diplomaticquarterapp/geofence/GeofencingRebootBroadcastReceiver.kt @@ -0,0 +1,21 @@ +// Copyright 2019 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +package io.flutter.plugins.geofencing + +import android.content.BroadcastReceiver +import android.content.Context +import android.content.Intent +import android.util.Log +import com.cloud.diplomaticquarterapp.geofence.HMG_Geofence + +class GeofencingRebootBroadcastReceiver : BroadcastReceiver() { + override fun onReceive(context: Context, intent: Intent) { + if (intent.action.equals("android.intent.action.BOOT_COMPLETED")) { + HMG_Geofence.shared(context).unRegisterAll { status, exception -> + HMG_Geofence.shared(context).re + } + } + } +} \ No newline at end of file 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 11af61a5..fbef8749 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 @@ -16,11 +16,21 @@ import com.google.gson.reflect.TypeToken enum class GeofenceTransition(val value: Int) { ENTER(1), - EXIT(2); + EXIT(2), + ENTER_EXIT((ENTER.value or EXIT.value)), + DWELL(4); companion object { fun fromInt(value: Int) = GeofenceTransition.values().first { it.value == value } } + + fun named():String{ + if (value == 1)return "Enter" + if (value == 2)return "Exit" + if (value == (ENTER.value or EXIT.value))return "Enter or Exit" + if (value == 4)return "dWell" + return "unknown" + } } const val PREFS_STORAGE = "FlutterSharedPreferences" @@ -28,9 +38,11 @@ const val PREF_KEY_SUCCESS = "HMG_GEOFENCE_SUCCESS" const val PREF_KEY_FAILED = "HMG_GEOFENCE_FAILED" class HMG_Geofence { + // https://developer.android.com/training/location/geofencing#java private lateinit var context: Context private lateinit var preferences:SharedPreferences + private val gson = Gson() private lateinit var geofencingClient:GeofencingClient private val geofencePendingIntent: PendingIntent by lazy { @@ -86,10 +98,10 @@ class HMG_Geofence { print(it.localizedMessage) } } - },null); + },null) } - fun unRegisterAll(completion: (status: Boolean, message: String?) -> Unit){ + fun unRegisterAll(completion: (status: Boolean, exception:Exception?) -> Unit){ getActiveGeofences({ success -> geofencingClient .removeGeofences(success) @@ -97,7 +109,7 @@ class HMG_Geofence { completion(true, null) } .addOnFailureListener { - completion(false, it.localizedMessage) + completion(false, it) } }, { failed -> // Nothing to do with failed geofences. @@ -105,7 +117,6 @@ class HMG_Geofence { } fun saveGeofenceResults(success: List, failed: List){ - val gson = Gson() val jsonSuccess = gson.toJson(success) val jsonFailure = gson.toJson(failed) preferences.edit().putString(PREF_KEY_SUCCESS, jsonSuccess).apply() @@ -114,7 +125,6 @@ class HMG_Geofence { } fun getActiveGeofences(success: (success: List) -> Unit, failure: ((failed: List) -> Unit)?){ - val gson = Gson() val type = object : TypeToken?>() {}.type val jsonSuccess = preferences.getString(PREF_KEY_SUCCESS, "[]") @@ -130,14 +140,16 @@ class HMG_Geofence { } private fun checkPermission() : Boolean{ - return ContextCompat.checkSelfPermission(context, Manifest.permission.ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED + return ContextCompat.checkSelfPermission(context, Manifest.permission.ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED } fun getPatientID():Int?{ val profileJson = preferences.getString("flutter.user-profile", "{}") val type = object : TypeToken?>() {}.type - return Gson() - .fromJson?>(profileJson,type) - ?.get("PatientID") as? Int + return gson.fromJson?>(profileJson,type) + ?.get("PatientID") + .toString() + .toDoubleOrNull() + ?.toInt() } } \ 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 37c0ffb6..5b0201f2 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 @@ -3,21 +3,28 @@ package com.cloud.diplomaticquarterapp.utils import android.app.NotificationChannel import android.app.NotificationManager import android.app.PendingIntent -import android.content.ClipData.newIntent import android.content.Context import android.content.Intent import android.os.Build -import android.view.View import android.widget.Toast +import androidx.annotation.Nullable import androidx.core.app.NotificationCompat import androidx.core.app.TaskStackBuilder import com.cloud.diplomaticquarterapp.BuildConfig import com.cloud.diplomaticquarterapp.MainActivity import com.cloud.diplomaticquarterapp.R +import com.github.kittinunf.fuel.core.extensions.jsonBody +import com.github.kittinunf.fuel.httpPost +import com.google.gson.Gson +import com.google.gson.reflect.TypeToken import io.flutter.plugin.common.MethodChannel +import org.json.JSONArray +import org.json.JSONException +import org.json.JSONObject import java.util.* import kotlin.concurrent.timerTask + class HMGUtils { companion object{ @@ -25,34 +32,34 @@ class HMGUtils { fun getPlatformChannel():MethodChannel{ return platformChannel } - fun setPlatformChannel(channel:MethodChannel){ + fun setPlatformChannel(channel: MethodChannel){ platformChannel = channel } - fun timer(delay:Long, repeat:Boolean, tick:(Timer)->Unit) : Timer{ + fun timer(delay: Long, repeat: Boolean, tick: (Timer) -> Unit) : Timer{ val timer = Timer() if(repeat) timer.schedule(timerTask { tick(timer) - },delay,delay) + }, delay, delay) else timer.schedule(timerTask { tick(timer) - },delay) + }, delay) return timer } - fun popMessage(context:MainActivity, message:String){ + fun popMessage(context: MainActivity, message: String){ context.runOnUiThread { - Toast.makeText(context,message,Toast.LENGTH_LONG).show() + Toast.makeText(context, message, Toast.LENGTH_LONG).show() } } - fun popFlutterText(context:MainActivity, key:String){ + fun popFlutterText(context: MainActivity, key: String){ context.runOnUiThread { FlutterText.with(key){ - Toast.makeText(context,it,Toast.LENGTH_LONG).show() + Toast.makeText(context, it, Toast.LENGTH_LONG).show() } } } @@ -66,9 +73,8 @@ private fun Timer.schedule(timerTask: TimerTask) { } private const val NOTIFICATION_CHANNEL_ID = BuildConfig.APPLICATION_ID + ".channel" -fun sendNotification(context: Context, message: String) { - val notificationManager = context - .getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager +fun sendNotification(context: Context, title:String, @Nullable subtitle:String?, message:String?) { + val notificationManager = context.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O && notificationManager.getNotificationChannel(NOTIFICATION_CHANNEL_ID) == null) { @@ -80,23 +86,63 @@ fun sendNotification(context: Context, message: String) { notificationManager.createNotificationChannel(channel) } - val intent = Intent(context,MainActivity::class.java) + val intent = Intent(context, MainActivity::class.java) val stackBuilder = TaskStackBuilder.create(context) .addParentStack(MainActivity::class.java) .addNextIntent(intent) - val notificationPendingIntent = stackBuilder - .getPendingIntent(getUniqueId(), PendingIntent.FLAG_UPDATE_CURRENT) + val notificationPendingIntent = stackBuilder.getPendingIntent(getUniqueId(), PendingIntent.FLAG_UPDATE_CURRENT) val notification = NotificationCompat.Builder(context, NOTIFICATION_CHANNEL_ID) .setSmallIcon(R.mipmap.ic_launcher) - .setContentTitle(message) .setContentIntent(notificationPendingIntent) .setAutoCancel(true) - .build() + .setContentTitle(title) + + subtitle.let { notification.setContentText(it) } + message.let { notification.setSubText(it) } + + notificationManager.notify(getUniqueId(), notification.build()) +} + - notificationManager.notify(getUniqueId(), notification) +private fun getUniqueId() = ((System.currentTimeMillis() % 10000).toInt()) + +fun isJSONValid(jsonString: String?): Boolean { + try { JSONObject(jsonString) } catch (ex: JSONException) { + try { JSONArray(jsonString) } catch (ex1: JSONException) { + return false + } + } + return true } +class HTTPResponse(data: T){ + final var data:T = data +} +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) + url.httpPost() + .jsonBody(jsonBody, Charsets.UTF_8) + .timeout(10000) + .header("Content-Type","application/json") + .header("Allow","*/*") + .response { request, response, result -> + result.fold({ data -> + val dataString = String(data) + if(isJSONValid(dataString)){ + val responseData = gson.fromJson(dataString,type) + onSuccess(HTTPResponse(responseData)) + }else{ + onError(Exception("Invalid response from server (Not a valid JSON)")) + } + }, { + onError(it) + it.localizedMessage + }) -private fun getUniqueId() = ((System.currentTimeMillis() % 10000).toInt()) \ No newline at end of file + } +} \ No newline at end of file diff --git a/android/app/src/main/kotlin/com/cloud/diplomaticquarterapp/utils/PlatformBridge.kt b/android/app/src/main/kotlin/com/cloud/diplomaticquarterapp/utils/PlatformBridge.kt index cf3b2828..ed1a62c8 100644 --- a/android/app/src/main/kotlin/com/cloud/diplomaticquarterapp/utils/PlatformBridge.kt +++ b/android/app/src/main/kotlin/com/cloud/diplomaticquarterapp/utils/PlatformBridge.kt @@ -94,9 +94,8 @@ class PlatformBridge(binaryMessenger: BinaryMessenger, flutterMainActivity: Main if (!wm.isWifiEnabled) wm.isWifiEnabled = true result.success(true) - }else{ + }else result.error("101","Error while opening wifi, Please try to open wifi yourself and try again","'WifiManager' service failed"); - } } @@ -104,10 +103,10 @@ class PlatformBridge(binaryMessenger: BinaryMessenger, flutterMainActivity: Main channel.invokeMethod("getGeoZones",null, object : MethodChannel.Result{ override fun success(result: Any?) { - if(result is String) - HMG_Geofence.shared(mainActivity).unRegisterAll { status, message -> - HMG_Geofence.shared(mainActivity).register(GeoZoneModel().listFrom(result)) - } + if(result is String) { + val geoZones = GeoZoneModel().listFrom(result) + HMG_Geofence.shared(mainActivity).register(geoZones) + } } override fun error(errorCode: String?, errorMessage: String?, errorDetails: Any?) { print(result) } @@ -117,7 +116,12 @@ class PlatformBridge(binaryMessenger: BinaryMessenger, flutterMainActivity: Main } private fun unRegisterHmgGeofences(methodCall: MethodCall, result: MethodChannel.Result) { - + HMG_Geofence.shared(mainActivity).unRegisterAll { status, exception -> + if(status) + result.success(true) + else + result.error("101", exception?.localizedMessage, exception); + } } } diff --git a/ios/Podfile.lock b/ios/Podfile.lock index 668711ce..d65de659 100644 --- a/ios/Podfile.lock +++ b/ios/Podfile.lock @@ -20,7 +20,7 @@ PODS: - Firebase/Messaging (6.33.0): - Firebase/CoreOnly - FirebaseMessaging (~> 4.7.0) - - firebase_core (0.5.2): + - firebase_core (0.5.3): - Firebase/CoreOnly (~> 6.33.0) - Flutter - firebase_core_web (0.1.0): @@ -70,7 +70,7 @@ PODS: - Flutter - flutter_tts (0.0.1): - Flutter - - "geolocator (6.0.0+4)": + - geolocator (6.1.9): - Flutter - google_maps_flutter (0.0.1): - Flutter @@ -375,7 +375,7 @@ SPEC CHECKSUMS: device_calendar: 23b28a5f1ab3bf77e34542fb1167e1b8b29a98f5 device_info: d7d233b645a32c40dfdc212de5cf646ca482f175 Firebase: 8db6f2d1b2c5e2984efba4949a145875a8f65fe5 - firebase_core: 350ba329d1641211bc6183a3236893cafdacfea7 + firebase_core: 5d6a02f3d85acd5f8321c2d6d62877626a670659 firebase_core_web: d501d8b946b60c8af265428ce483b0fff5ad52d1 firebase_messaging: 0aea2cd5885b65e19ede58ee3507f485c992cc75 FirebaseCore: d889d9e12535b7f36ac8bfbf1713a0836a3012cd @@ -390,7 +390,7 @@ SPEC CHECKSUMS: flutter_local_notifications: 9e4738ce2471c5af910d961a6b7eadcf57c50186 flutter_plugin_android_lifecycle: dc0b544e129eebb77a6bfb1239d4d1c673a60a35 flutter_tts: 0f492aab6accf87059b72354fcb4ba934304771d - geolocator: 1ae40084cc6c1586ce5ad12cfc3fd38c64d05f2f + geolocator: 057a0c63a43e9c5296d8ad845a3ac8e6df23d899 google_maps_flutter: c7f9c73576de1fbe152a227bfd6e6c4ae8088619 GoogleDataTransport: f56af7caa4ed338dc8e138a5d7c5973e66440833 GoogleMaps: 4b5346bddfe6911bb89155d43c903020170523ac @@ -440,4 +440,4 @@ SPEC CHECKSUMS: PODFILE CHECKSUM: 5a17be3f8af73a757fa4439c77cf6ab2db29a6e7 -COCOAPODS: 1.10.0 +COCOAPODS: 1.8.4 diff --git a/ios/Runner.xcodeproj/project.pbxproj b/ios/Runner.xcodeproj/project.pbxproj index 8c39e92b..009006ed 100644 --- a/ios/Runner.xcodeproj/project.pbxproj +++ b/ios/Runner.xcodeproj/project.pbxproj @@ -472,7 +472,7 @@ CLANG_ENABLE_MODULES = YES; CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements; CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; - DEVELOPMENT_TEAM = 3A359E86ZF; + DEVELOPMENT_TEAM = ""; ENABLE_BITCODE = NO; FRAMEWORK_SEARCH_PATHS = ( "$(inherited)", @@ -611,7 +611,7 @@ CLANG_ENABLE_MODULES = YES; CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements; CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; - DEVELOPMENT_TEAM = 3A359E86ZF; + DEVELOPMENT_TEAM = ""; ENABLE_BITCODE = NO; FRAMEWORK_SEARCH_PATHS = ( "$(inherited)", @@ -644,7 +644,7 @@ CLANG_ENABLE_MODULES = YES; CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements; CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; - DEVELOPMENT_TEAM = 3A359E86ZF; + DEVELOPMENT_TEAM = ""; ENABLE_BITCODE = NO; FRAMEWORK_SEARCH_PATHS = ( "$(inherited)",