Geofence fixes by JobScheduler

merge-requests/236/head
Zohaib Kambrani 5 years ago
parent 3392a2431b
commit 57925e3b02

@ -81,6 +81,7 @@
<receiver android:name=".geofence.intent_receivers.GeofencingRebootBroadcastReceiver" android:enabled="true">
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED"/>
<action android:name="android.intent.action.MY_PACKAGE_REPLACED"/>
</intent-filter>
</receiver>
<receiver android:name=".geofence.intent_receivers.LocationProviderChangeReceiver">
@ -88,6 +89,8 @@
<action android:name="android.location.PROVIDERS_CHANGED"/>
</intent-filter>
</receiver>
<service android:name=".geofence.intent_receivers.ReregisterGeofenceJobService" android:permission="android.permission.BIND_JOB_SERVICE" />
<!-- Geofencing -->
<meta-data android:name="com.google.android.geo.API_KEY"
android:value="AIzaSyCmevVlr2Bh-c8W1VUzo8gt8JRY7n5PANw"/>

@ -2,8 +2,7 @@ package com.cloud.diplomaticquarterapp
import android.os.Bundle
import android.util.Log
import androidx.annotation.NonNull;
import com.cloud.diplomaticquarterapp.utils.FlutterText
import com.cloud.diplomaticquarterapp.utils.PlatformBridge
import com.cloud.diplomaticquarterapp.utils.*
import io.flutter.embedding.android.FlutterFragmentActivity
import io.flutter.embedding.engine.FlutterEngine
import io.flutter.plugin.common.MethodChannel
@ -15,6 +14,16 @@ class MainActivity: FlutterFragmentActivity() {
// Create Flutter Platform Bridge
PlatformBridge(flutterEngine.dartExecutor.binaryMessenger, this).create()
val time = timeToMillis("04:00:00", "HH:mm:ss")
print(time)
// val d1 = Logs.list(this)
// val d2 = Logs.raw(this)
// val d3 = Logs.RegisterGeofence.list(this)
// val d4 = Logs.RegisterGeofence.raw(this)
// val d5 = Logs.GeofenceEvent.list(this)
// val d6 = Logs.GeofenceEvent.raw(this)
print("")
}
override fun onResume() {

@ -37,7 +37,7 @@ class GeoZoneModel {
val rad = Radius.toFloat()
if(lat != null && long != null){
val loiteringDelayMinutes:Int = 5 // in Minutes
val loiteringDelayMinutes:Int = 2 // in Minutes
return Geofence.Builder()
.setRequestId(identifier())
.setCircularRegion(
@ -46,8 +46,8 @@ class GeoZoneModel {
rad
)
.setTransitionTypes(GeofenceTransition.ENTER_EXIT.value)
// .setNotificationResponsiveness(0)
// .setLoiteringDelay(loiteringDelayMinutes * 60 * 1000)
.setNotificationResponsiveness(0)
.setLoiteringDelay(loiteringDelayMinutes * 60 * 1000)
.setExpirationDuration(Geofence.NEVER_EXPIRE)
.build()
}

@ -9,6 +9,7 @@ import android.content.pm.PackageManager
import android.location.Location
import androidx.core.content.ContextCompat
import com.cloud.diplomaticquarterapp.geofence.intent_receivers.GeofenceBroadcastReceiver
import com.cloud.diplomaticquarterapp.geofence.intent_receivers.ReregisterGeofenceJobService
import com.cloud.diplomaticquarterapp.utils.*
import com.google.android.gms.location.Geofence
import com.google.android.gms.location.GeofencingClient
@ -20,8 +21,10 @@ import com.google.gson.reflect.TypeToken
enum class GeofenceTransition(val value: Int) {
ENTER(1),
EXIT(2),
DWELL(4),
ENTER_EXIT((ENTER.value or EXIT.value)),
DWELL(4);
DWELL_EXIT((DWELL.value or EXIT.value));
companion object {
fun fromInt(value: Int) = GeofenceTransition.values().first { it.value == value }
@ -30,8 +33,9 @@ enum class GeofenceTransition(val value: Int) {
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"
if (value == (ENTER.value or EXIT.value))return "Enter or Exit"
if (value == (DWELL.value or EXIT.value))return "DWell or Exit"
return "unknown"
}
}
@ -73,13 +77,22 @@ class HMG_Geofence {
}
}
fun limitize(zones: List<GeoZoneModel>):List<GeoZoneModel>{
var geoZones_ = zones
if(zones.size > 100)
geoZones_ = zones.subList(0, 99)
return geoZones_
}
fun register(geoZones: List<GeoZoneModel>){
if (geoZones.isEmpty())
return
var geoZones_ = limitize(geoZones)
fun buildGeofencingRequest(geofences: List<Geofence>): GeofencingRequest {
return GeofencingRequest.Builder()
.setInitialTrigger(0)
.setInitialTrigger(GeofencingRequest.INITIAL_TRIGGER_DWELL)
.addGeofences(geofences)
.build()
}
@ -87,9 +100,9 @@ class HMG_Geofence {
getActiveGeofences({ active ->
val geofences = mutableListOf<Geofence>()
geoZones.forEach {
it.toGeofence()?.let { geof ->
if(!active.contains(geof.requestId)){ // if not already registered then register
geoZones_.forEach {
it.toGeofence()?.let { geof ->
if (!active.contains(geof.requestId)) { // if not already registered then register
geofences.add(geof)
}
}
@ -99,19 +112,25 @@ class HMG_Geofence {
geofencingClient
.addGeofences(buildGeofencingRequest(geofences), geofencePendingIntent)
.addOnSuccessListener {
Logs.RegisterGeofence.save(context,"SUCCESS", "Successfuly registered the geofences", Logs.STATUS.SUCCESS)
saveActiveGeofence(geofences.map { it.requestId }, listOf())
}
.addOnFailureListener {
print(it.localizedMessage)
saveLog(context,"error:ADD_GEOFENCES", it.localizedMessage)
Logs.RegisterGeofence.save(context,"FAILED_TO_REGISTER", "Failed to register geofence",Logs.STATUS.ERROR)
}
// Schedule the job to register after specified duration (due to: events not calling after long period.. days or days [Needs to register fences again])
HMGUtils.scheduleJob(context, ReregisterGeofenceJobService::class.java,ReregisterGeofenceJobService.JobID, ReregisterGeofenceJobService.TriggerIntervalMillis)
}
},null)
}, null)
}
fun unRegisterAll(completion: (status: Boolean, exception:Exception?) -> Unit){
fun unRegisterAll(completion: (status: Boolean, exception: Exception?) -> Unit){
getActiveGeofences({ success ->
val mList = success.toMutableList()
removeActiveGeofences()
geofencingClient
.removeGeofences(success)
.addOnSuccessListener {
@ -119,14 +138,20 @@ class HMG_Geofence {
}
.addOnFailureListener {
completion(false, it)
saveLog(context,"error:REMOVE_GEOFENCES", it.localizedMessage)
saveLog(context, "error:REMOVE_GEOFENCES", it.localizedMessage)
}
removeActiveGeofences()
}, { failed ->
// Nothing to do with failed geofences.
})
}
fun reRegister(){
unRegisterAll { status, exception ->
val geoZones = HMGUtils.getGeoZonesFromPreference(context)
register(geoZones)
}
}
fun saveActiveGeofence(success: List<String>, failed: List<String>){
val jsonSuccess = gson.toJson(success)
val jsonFailure = gson.toJson(failed)
@ -135,8 +160,8 @@ class HMG_Geofence {
}
fun removeActiveGeofences(){
preferences.edit().putString(PREF_KEY_SUCCESS,"[]").apply()
preferences.edit().putString(PREF_KEY_FAILED,"[]").apply()
preferences.edit().putString(PREF_KEY_SUCCESS, "[]").apply()
preferences.edit().putString(PREF_KEY_FAILED, "[]").apply()
}
fun getActiveGeofences(success: (success: List<String>) -> Unit, failure: ((failed: List<String>) -> Unit)?){
@ -164,7 +189,7 @@ class HMG_Geofence {
profileJson = preferences.getString("flutter.user-profile", null)
val type = object : TypeToken<Map<String?, Any?>?>() {}.type
return gson.fromJson<Map<String?, Any?>?>(profileJson,type)
return gson.fromJson<Map<String?, Any?>?>(profileJson, type)
?.get("PatientID")
.toString()
.toDoubleOrNull()
@ -172,32 +197,35 @@ class HMG_Geofence {
}
fun handleEvent(triggerGeofences: List<Geofence>, location: Location, transition:GeofenceTransition) {
fun handleEvent(triggerGeofences: List<Geofence>, 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 pointID = activeGeofences.firstOrNull { it == geofence.requestId }?.split('_')?.first()
if (!pointID.isNullOrEmpty() && pointID.toIntOrNull() != null) {
val body = mutableMapOf<String,Any?>(
val body = mutableMapOf<String, Any?>(
"PointsID" to pointID.toIntOrNull(),
"GeoType" to transition.value,
"PatientID" to patientId
)
body.putAll(HMGUtils.defaultHTTPParams(context))
httpPost<Map<String,Any>>(API.LOG_GEOFENCE, body, { response ->
httpPost<Map<String, Any>>(API.LOG_GEOFENCE, body, { response ->
saveLog(context, "HMG_GEOFENCE_NOTIFY", "Success: Notified to server\uD83D\uDE0E.")
sendNotification(context, transition.named(), geofence.requestId, "Notified to server.😎")
},{ exception ->
sendNotification(context, transition.named(), geofence.requestId, "Failed to notify server.😔")
}, { exception ->
val errorMessage = "${transition.named()}, ${geofence.requestId}"
saveLog(context, "HMG_GEOFENCE_NOTIFY", "failed: $errorMessage | error: ${exception.localizedMessage}")
sendNotification(context, transition.named(), geofence.requestId, "Failed to notify server😔 -> ${exception.localizedMessage}")
})
}
}
},null)
}, null)
}
}
}

@ -8,7 +8,9 @@ import android.content.Intent
import android.util.Log
import com.cloud.diplomaticquarterapp.geofence.GeofenceTransition
import com.cloud.diplomaticquarterapp.geofence.HMG_Geofence
import com.cloud.diplomaticquarterapp.utils.Logs
import com.cloud.diplomaticquarterapp.utils.saveLog
import com.google.android.gms.location.GeofenceStatusCodes
import com.google.android.gms.location.GeofencingEvent
class GeofenceBroadcastReceiver : BroadcastReceiver() {
@ -19,12 +21,28 @@ class GeofenceBroadcastReceiver : BroadcastReceiver() {
if (geofencingEvent.hasError()) {
val errorMessage = GeofenceErrorMessages.getErrorString(context, geofencingEvent.errorCode)
Log.e(LOG_TAG, errorMessage)
saveLog(context,LOG_TAG,errorMessage)
Logs.GeofenceEvent.save(context,LOG_TAG,"Error while triggering geofence event",Logs.STATUS.ERROR)
doReRegisterIfRequired(context,geofencingEvent.errorCode)
return
}
Logs.GeofenceEvent.save(context,LOG_TAG,"Geofence event triggered: ${GeofenceTransition.fromInt(geofencingEvent.geofenceTransition).value} for ${geofencingEvent.triggeringGeofences.map {it.requestId}}",Logs.STATUS.SUCCESS)
HMG_Geofence.shared(context).handleEvent(geofencingEvent.triggeringGeofences,geofencingEvent.triggeringLocation, GeofenceTransition.fromInt(geofencingEvent.geofenceTransition));
}
fun doReRegisterIfRequired(context: Context, errorCode: Int){
val errorRequiredReregister = listOf(
GeofenceStatusCodes.GEOFENCE_NOT_AVAILABLE,
GeofenceStatusCodes.GEOFENCE_TOO_MANY_GEOFENCES,
GeofenceStatusCodes.GEOFENCE_TOO_MANY_PENDING_INTENTS,
GeofenceStatusCodes.GEOFENCE_REQUEST_TOO_FREQUENT
)
if(errorRequiredReregister.contains(errorCode))
HMG_Geofence.shared(context).reRegister()
}
}

@ -5,9 +5,12 @@ package com.cloud.diplomaticquarterapp.geofence.intent_receivers
import android.content.BroadcastReceiver
import android.content.Context
import android.content.Intent
import com.cloud.diplomaticquarterapp.geofence.HMG_Geofence
import com.google.android.gms.location.GeofenceStatusCodes
class GeofenceBroadcastReceiverWithJobService : BroadcastReceiver() {
override fun onReceive(context: Context, intent: Intent) {
GeofenceTransitionsJobIntentService.enqueueWork(context, intent)
}
}

@ -4,7 +4,7 @@ package com.cloud.diplomaticquarterapp.geofence.intent_receivers
import android.content.Context
import com.cloud.diplomaticquarterapp.R
import com.cloud.diplomaticquarterapp.utils.saveLog
import com.cloud.diplomaticquarterapp.geofence.HMG_Geofence
import com.google.android.gms.common.api.ApiException
import com.google.android.gms.location.GeofenceStatusCodes
@ -38,8 +38,6 @@ object GeofenceErrorMessages {
else -> resources.getString(R.string.geofence_unknown_error)
}
saveLog(context,"GeofenceErrorMessages","$errorCode | $errorMessage")
return errorMessage
}
}

@ -1,29 +0,0 @@
package com.cloud.diplomaticquarterapp.geofence.intent_receivers
import android.content.Intent
import android.util.Log
import androidx.core.app.JobIntentService
import com.cloud.diplomaticquarterapp.geofence.GeofenceTransition
import com.cloud.diplomaticquarterapp.geofence.HMG_Geofence
import com.cloud.diplomaticquarterapp.utils.saveLog
import com.google.android.gms.location.GeofencingEvent
class GeofenceJobIntentService : JobIntentService(){
private val LOG_TAG = "GeofenceBroadcastReceiver"
override fun onHandleWork(intent: Intent) {
val geofencingEvent = GeofencingEvent.fromIntent(intent)
if (geofencingEvent.hasError()) {
val errorMessage = GeofenceErrorMessages.getErrorString(this, geofencingEvent.errorCode)
Log.e(LOG_TAG, errorMessage)
saveLog(this, LOG_TAG,errorMessage)
return
}
HMG_Geofence.shared(this).handleEvent(geofencingEvent.triggeringGeofences,geofencingEvent.triggeringLocation, GeofenceTransition.fromInt(geofencingEvent.geofenceTransition))
}
}

@ -37,7 +37,9 @@ import android.util.Log
import androidx.core.app.JobIntentService
import com.cloud.diplomaticquarterapp.geofence.GeofenceTransition
import com.cloud.diplomaticquarterapp.geofence.HMG_Geofence
import com.cloud.diplomaticquarterapp.utils.saveLog
import com.google.android.gms.location.Geofence
import com.google.android.gms.location.GeofenceStatusCodes
import com.google.android.gms.location.GeofencingEvent
class GeofenceTransitionsJobIntentService : JobIntentService() {
@ -45,7 +47,7 @@ class GeofenceTransitionsJobIntentService : JobIntentService() {
companion object {
private const val LOG_TAG = "GeoTrIntentService"
private const val JOB_ID = 573
private const val JOB_ID = 95902
var context_: Context? = null
fun enqueueWork(context: Context, intent: Intent) {
context_ = context
@ -59,15 +61,31 @@ class GeofenceTransitionsJobIntentService : JobIntentService() {
override fun onHandleWork(intent: Intent) {
val geofencingEvent = GeofencingEvent.fromIntent(intent)
if (geofencingEvent.hasError()) {
val errorMessage = GeofenceErrorMessages.getErrorString(this, geofencingEvent.errorCode)
val errorMessage = GeofenceErrorMessages.getErrorString(context_!!, geofencingEvent.errorCode)
Log.e(LOG_TAG, errorMessage)
saveLog(context_!!,LOG_TAG,errorMessage)
doReRegisterIfRequired(context_!!, geofencingEvent.errorCode)
return
}
if (geofencingEvent.geofenceTransition == Geofence.GEOFENCE_TRANSITION_ENTER || geofencingEvent.geofenceTransition == Geofence.GEOFENCE_TRANSITION_EXIT) {
context_?.let {
HMG_Geofence.shared(it).handleEvent(geofencingEvent.triggeringGeofences,geofencingEvent.triggeringLocation, GeofenceTransition.fromInt(geofencingEvent.geofenceTransition));
}
}
HMG_Geofence.shared(context_!!).handleEvent(geofencingEvent.triggeringGeofences,geofencingEvent.triggeringLocation, GeofenceTransition.fromInt(geofencingEvent.geofenceTransition));
}
fun doReRegisterIfRequired(context: Context, errorCode: Int){
val errorRequiredReregister = listOf(
GeofenceStatusCodes.GEOFENCE_NOT_AVAILABLE,
GeofenceStatusCodes.GEOFENCE_TOO_MANY_GEOFENCES,
GeofenceStatusCodes.GEOFENCE_TOO_MANY_PENDING_INTENTS,
GeofenceStatusCodes.GEOFENCE_REQUEST_TOO_FREQUENT
)
if(errorRequiredReregister.contains(errorCode))
HMG_Geofence.shared(context).reRegister()
}
}

@ -7,7 +7,6 @@ import android.content.Context
import android.content.Intent
import com.cloud.diplomaticquarterapp.geofence.HMG_Geofence
import com.cloud.diplomaticquarterapp.geofence.PREFS_STORAGE
import com.cloud.diplomaticquarterapp.utils.HMGUtils
class GeofencingRebootBroadcastReceiver : BroadcastReceiver(){
override fun onReceive(context: Context, intent: Intent) {
@ -17,10 +16,7 @@ class GeofencingRebootBroadcastReceiver : BroadcastReceiver(){
val pref = context.getSharedPreferences(PREFS_STORAGE, Context.MODE_PRIVATE)
pref.edit().putString("REBOOT_DETECTED","YES").apply()
HMG_Geofence.shared(context).unRegisterAll { status, exception ->
val geoZones = HMGUtils.getGeoZonesFromPreference(context)
HMG_Geofence.shared(context).register(geoZones)
}
HMG_Geofence.shared(context).reRegister()
}
}

@ -0,0 +1,23 @@
package com.cloud.diplomaticquarterapp.geofence.intent_receivers
import android.app.job.JobParameters
import android.app.job.JobService
import com.cloud.diplomaticquarterapp.geofence.HMG_Geofence
import com.cloud.diplomaticquarterapp.utils.Logs
import com.cloud.diplomaticquarterapp.utils.timeToMillis
class ReregisterGeofenceJobService : JobService(){
companion object{
val TriggerIntervalMillis:String = "24:00:00"
val JobID = 918273
}
override fun onStartJob(params: JobParameters?): Boolean {
HMG_Geofence.shared(applicationContext).reRegister()
Logs.save(applicationContext,"ReregisterGeofenceJobService.onStartJob", "triggered to re-register the geofences after $TriggerIntervalMillis >> [HH:mm:ss]")
return true
}
override fun onStopJob(params: JobParameters?): Boolean {
return true
}
}

@ -3,11 +3,15 @@ package com.cloud.diplomaticquarterapp.utils
import android.app.NotificationChannel
import android.app.NotificationManager
import android.app.PendingIntent
import android.app.job.JobInfo
import android.app.job.JobScheduler
import android.content.ComponentName
import android.content.Context
import android.content.Intent
import android.os.Build
import android.widget.Toast
import androidx.annotation.Nullable
import androidx.annotation.RequiresApi
import androidx.core.app.NotificationCompat
import androidx.core.app.TaskStackBuilder
import com.cloud.diplomaticquarterapp.BuildConfig
@ -17,15 +21,17 @@ 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.cloud.diplomaticquarterapp.geofence.intent_receivers.ReregisterGeofenceJobService
import com.github.kittinunf.fuel.core.extensions.jsonBody
import com.github.kittinunf.fuel.httpPost
import com.google.android.gms.location.Geofence
import com.google.gson.Gson
import com.google.gson.reflect.TypeToken
import io.flutter.plugin.common.MethodChannel
import org.jetbrains.anko.doAsyncResult
import org.json.JSONArray
import org.json.JSONException
import org.json.JSONObject
import java.text.SimpleDateFormat
import java.util.*
import kotlin.concurrent.timerTask
@ -71,7 +77,7 @@ class HMGUtils {
fun getGeoZonesFromPreference(context: Context):List<GeoZoneModel>{
val pref = context.getSharedPreferences(PREFS_STORAGE, Context.MODE_PRIVATE)
val json = pref.getString(PREF_KEY_HMG_ZONES,"[]")
val json = pref.getString(PREF_KEY_HMG_ZONES, "[]")
val geoZones = GeoZoneModel().listFrom(json)
return geoZones
@ -79,14 +85,14 @@ class HMGUtils {
fun getLanguageCode(context: Context) : Int{
val pref = context.getSharedPreferences(PREFS_STORAGE, Context.MODE_PRIVATE)
val lang = pref.getString(PREF_KEY_LANGUAGE,"ar")
val lang = pref.getString(PREF_KEY_LANGUAGE, "ar")
return if(lang == "ar") 2 else 1
}
fun defaultHTTPParams(context: Context) : Map<String,Any?>{
fun defaultHTTPParams(context: Context) : Map<String, Any?>{
return mapOf(
"ZipCode" to "966",
"VersionID" to 5.6,
"VersionID" to 5.8,
"Channel" to 3,
"LanguageID" to getLanguageCode(context),
"IPAdress" to "10.20.10.20",
@ -97,16 +103,44 @@ class HMGUtils {
"DeviceTypeID" to 2)
}
fun <T>scheduleJob(context: Context, pendingIntentClassType:Class<T>, jobId:Int, intervalDuration:String, deadlineMillis:Long = (30 * 1000)) { // default deadline: 30 Seconds
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.M) {
val jobScheduler: JobScheduler = context.getSystemService(JobScheduler::class.java)
val serviceComponent = ComponentName(context, pendingIntentClassType)
val builder = JobInfo.Builder(jobId, serviceComponent)
builder.setPersisted(true)
val intervalMillis = timeToMillis(intervalDuration,"HH:mm:ss")
builder.setMinimumLatency(intervalMillis) // wait at least
builder.setOverrideDeadline((intervalMillis + deadlineMillis)) // maximum delay
if (jobScheduler.schedule(builder.build()) == JobScheduler.RESULT_SUCCESS){
Logs.save(context,"ScheduleJob", "${pendingIntentClassType.simpleName}: Job scheduled to trigger after duration $intervalDuration >> HH:mm:ss --('MinimumLatency:$intervalMillis Deadline:${(intervalMillis + deadlineMillis)}')--",Logs.STATUS.SUCCESS)
}else{
Logs.save(context,"ScheduleJob", "${pendingIntentClassType.simpleName}: Failed to scheduled Job",Logs.STATUS.ERROR)
}
} else {
Logs.save(context,"ScheduleJob", "${pendingIntentClassType.simpleName}: Failed to scheduled Job on VERSION.SDK_INT < ${android.os.Build.VERSION_CODES.M}",Logs.STATUS.ERROR)
}
}
}
}
private fun Timer.schedule(timerTask: TimerTask) {
}
private const val NOTIFICATION_CHANNEL_ID = BuildConfig.APPLICATION_ID + ".channel"
fun sendNotification(context: Context, title:String, @Nullable subtitle:String?, message:String?) {
fun timeToMillis(time:String, format:String):Long{
val sdf = SimpleDateFormat(format, Locale.US)
val millis = sdf.parse(time).time + TimeZone.getDefault().rawOffset
return millis
}
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
@ -126,7 +160,7 @@ fun sendNotification(context: Context, title:String, @Nullable subtitle:String?,
.addNextIntent(intent)
val notificationPendingIntent = stackBuilder.getPendingIntent(getUniqueId(), PendingIntent.FLAG_UPDATE_CURRENT)
val notification = NotificationCompat.Builder(context, NOTIFICATION_CHANNEL_ID + ".geofence")
val notification = NotificationCompat.Builder(context, NOTIFICATION_CHANNEL_ID)
.setSmallIcon(R.mipmap.ic_launcher)
.setContentIntent(notificationPendingIntent)
.setAutoCancel(true)
@ -141,7 +175,15 @@ fun sendNotification(context: Context, title:String, @Nullable subtitle:String?,
//-------------------------
// Open Helper Methods
//-------------------------
private fun getUniqueId() = ((System.currentTimeMillis() % 10000).toInt())
fun getUniqueId() = ((System.currentTimeMillis() % 10000).toInt())
object DateUtils {
@JvmStatic
fun dateTimeNow() : String {
val format = SimpleDateFormat("dd-MMM-yyy hh:mm:ss")
return format.format(Date())
}
}
fun isJSONValid(jsonString: String?): Boolean {
try { JSONObject(jsonString) } catch (ex: JSONException) {
@ -152,11 +194,16 @@ fun isJSONValid(jsonString: String?): Boolean {
return true
}
fun saveLog(context:Context, tag:String, message:String){
fun saveLog(context: Context, tag: String, message: String){
val pref = context.getSharedPreferences(PREFS_STORAGE, Context.MODE_PRIVATE)
var logs = pref.getString("GEOFENCE_LOGS","")
var logs = pref.getString("LOGS", "")
logs += "$tag -> $message \n"
pref.edit().putString("GEOFENCE_LOGS", logs).apply();
pref.edit().putString("LOGS", logs).apply();
}
fun getLogs(context: Context) : String?{
val pref = context.getSharedPreferences(PREFS_STORAGE, Context.MODE_PRIVATE)
return pref.getString("LOGS", "")
}
class HTTPResponse<T>(data: T){
@ -170,15 +217,16 @@ fun <T>httpPost(url: String, body: Map<String, Any?>, onSuccess: (response: HTTP
url.httpPost()
.jsonBody(jsonBody, Charsets.UTF_8)
.timeout(10000)
.header("Content-Type","application/json")
.header("Allow","*/*")
.header("Content-Type", "application/json")
.header("Allow", "*/*")
.response { request, response, result ->
result.doAsyncResult { }
result.fold({ data ->
val dataString = String(data)
if(isJSONValid(dataString)){
val responseData = gson.fromJson<T>(dataString,type)
if (isJSONValid(dataString)) {
val responseData = gson.fromJson<T>(dataString, type)
onSuccess(HTTPResponse(responseData))
}else{
} else {
onError(Exception("Invalid response from server (Not a valid JSON)"))
}
}, {

@ -0,0 +1,146 @@
package com.cloud.diplomaticquarterapp.utils
import android.content.Context
import android.content.SharedPreferences
import android.os.Build
import com.cloud.diplomaticquarterapp.BuildConfig
import com.cloud.diplomaticquarterapp.geofence.PREFS_STORAGE
import com.google.gson.Gson
class Logs {
enum class STATUS{
SUCCESS,
ERROR;
}
class GeofenceEvent{
companion object{
fun save(context: Context, tag:String, message:String, status:Logs.STATUS = STATUS.SUCCESS){
Logs.Common.save(context,"GeofenceEvent", tag, message, status)
}
fun list(context: Context, tag:String? = null, status:Logs.STATUS? = null):List<LogModel>{
return Logs.Common.list(context,"GeofenceEvent", tag, status)
}
fun raw(context: Context):String{
return Logs.Common.raw(context,"GeofenceEvent")
}
}
}
class RegisterGeofence{
companion object{
fun save(context: Context, tag:String, message:String, status:Logs.STATUS = STATUS.SUCCESS){
Logs.Common.save(context,"RegisterGeofence", tag, message, status)
}
fun list(context: Context, tag:String? = null, status:Logs.STATUS? = null):List<LogModel>{
return Logs.Common.list(context,"RegisterGeofence", tag, status)
}
fun raw(context: Context):String{
return Logs.Common.raw(context,"RegisterGeofence");
}
}
}
companion object{
private var pref:SharedPreferences? = null
fun save(context: Context, tag:String, message:String, status:Logs.STATUS = STATUS.SUCCESS){
Logs.Common.save(context,"Logs", tag, message, status)
}
fun list(context: Context, tag:String? = null, status:Logs.STATUS? = null):List<LogModel>{
return Logs.Common.list(context,"Logs", tag, status)
}
fun raw(context: Context):String{
return Logs.Common.raw(context,"Logs");
}
private fun storage(context: Context):SharedPreferences{
if(pref == null) {
pref = context.getSharedPreferences(PREFS_STORAGE, Context.MODE_PRIVATE)
}
return pref!!
}
}
private class Common{
companion object{
private val gson = Gson()
fun save(context: Context, key:String, tag:String, message:String, status:Logs.STATUS = STATUS.SUCCESS){
if(!BuildConfig.DEBUG)
return
val pref = Logs.storage(context)
val string = pref.getString(key,"{}")
val json = gson.fromJson<LogsContainerModel>(string,LogsContainerModel::class.java)
json.add(
LogModel().apply {
this.TAG = tag
this.MESSAGE = message
this.STATUS = status.name
this.DATE = DateUtils.dateTimeNow()
}
)
pref.edit().putString(key,gson.toJson(json)).apply()
}
fun list(context: Context, key:String, tag:String? = null, status:Logs.STATUS? = null):List<LogModel>{
val pref = Logs.storage(context)
val string = pref.getString(key,"{}")
val json = gson.fromJson<LogsContainerModel>(string,LogsContainerModel::class.java)
if(tag == null && status == null) {
return json.LOGS
}else if(tag != null && status != null){
return json.LOGS.filter { (it.TAG == tag && it.STATUS == status.name) }
}else if(tag != null){
return json.LOGS.filter { (it.TAG == tag) }
}else if(status != null){
return json.LOGS.filter { (it.STATUS == status.name) }
}
return listOf()
}
fun raw(context: Context, key:String):String{
val pref = Logs.storage(context)
val string = pref.getString(key,"{}")
return string!!
}
}
}
class LogModel{
lateinit var TAG:String
lateinit var MESSAGE:String
lateinit var STATUS:String
lateinit var DATE:String
companion object{
fun with(tag:String, message:String, status:String):LogModel{
return LogModel().apply {
this.TAG = tag
this.MESSAGE = message
this.STATUS = status
this.DATE = DateUtils.dateTimeNow()
}
}
}
}
class LogsContainerModel{
var LOGS = mutableListOf<LogModel>()
fun add(log:LogModel){
LOGS.add(log)
}
}
}

@ -1 +1 @@
d9d141e787a8aa802f90b776d75f04fc
e7c24319209ad9049a87d4c83aeeb7de

@ -31,6 +31,7 @@
E9A35329258B8E8F00CBA688 /* GoogleService-Info.plist in Resources */ = {isa = PBXBuildFile; fileRef = E9A35328258B8E8F00CBA688 /* GoogleService-Info.plist */; };
E9C8C136256BACDA00EFFB62 /* HMG_Guest.swift in Sources */ = {isa = PBXBuildFile; fileRef = E9C8C135256BACDA00EFFB62 /* HMG_Guest.swift */; };
E9E27168256E3A4000F49B69 /* LocalizedFromFlutter.swift in Sources */ = {isa = PBXBuildFile; fileRef = E9E27167256E3A4000F49B69 /* LocalizedFromFlutter.swift */; };
E9F7623B25922BCE00FB5CCF /* FlutterConstants.swift in Sources */ = {isa = PBXBuildFile; fileRef = E9F7623A25922BCE00FB5CCF /* FlutterConstants.swift */; };
/* End PBXBuildFile section */
/* Begin PBXCopyFilesBuildPhase section */
@ -82,6 +83,7 @@
E9A35328258B8E8F00CBA688 /* GoogleService-Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = "GoogleService-Info.plist"; sourceTree = "<group>"; };
E9C8C135256BACDA00EFFB62 /* HMG_Guest.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = HMG_Guest.swift; sourceTree = "<group>"; };
E9E27167256E3A4000F49B69 /* LocalizedFromFlutter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LocalizedFromFlutter.swift; sourceTree = "<group>"; };
E9F7623A25922BCE00FB5CCF /* FlutterConstants.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FlutterConstants.swift; sourceTree = "<group>"; };
/* End PBXFileReference section */
/* Begin PBXFrameworksBuildPhase section */
@ -180,6 +182,7 @@
E923EFD125863FDF00E3E751 /* GeoZoneModel.swift */,
E923EFD3258645C100E3E751 /* HMG_Geofence.swift */,
E923EFD52587443800E3E751 /* HMGPlatformBridge.swift */,
E9F7623A25922BCE00FB5CCF /* FlutterConstants.swift */,
);
path = Helper;
sourceTree = "<group>";
@ -378,6 +381,7 @@
E91B5396256AAA6500E96549 /* GlobalHelper.swift in Sources */,
E923EFD4258645C100E3E751 /* HMG_Geofence.swift in Sources */,
E923EFD62587443800E3E751 /* HMGPlatformBridge.swift in Sources */,
E9F7623B25922BCE00FB5CCF /* FlutterConstants.swift in Sources */,
74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */,
E9E27168256E3A4000F49B69 /* LocalizedFromFlutter.swift in Sources */,
1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */,

@ -7,25 +7,39 @@ var userNotificationCenterDelegate:UNUserNotificationCenterDelegate? = nil
@UIApplicationMain
@objc class AppDelegate: FlutterAppDelegate {
let locationManager = CLLocationManager()
var flutterViewController:MainFlutterVC!
override func application( _ application: UIApplication,didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
GMSServices.provideAPIKey("AIzaSyCiiJiHkocPbcziHt9O8rGWavDrxHRQys8")
GeneratedPluginRegistrant.register(with: self)
if let mainViewController = window.rootViewController as? MainFlutterVC{
HMGPlatformBridge.initialize(flutterViewController: mainViewController)
}
initializePlatformChannel()
if let _ = launchOptions?[.location] {
HMG_Geofence.initGeofencing()
}
UNUserNotificationCenter.current().delegate = self
return super.application(application, didFinishLaunchingWithOptions: launchOptions)
}
func initializePlatformChannel(){
if let mainViewController = window.rootViewController as? MainFlutterVC{ // platform initialization suppose to be in foreground
flutterViewController = mainViewController
HMGPlatformBridge.initialize(flutterViewController: flutterViewController)
}else if let mainViewController = initialViewController(){ // platform initialization suppose to be in background
flutterViewController = mainViewController
HMGPlatformBridge.initialize(flutterViewController: flutterViewController)
}
}
func initialViewController() -> MainFlutterVC?{
return nil //UIStoryboard(name: "Main", bundle: .main).instantiateInitialViewController() as? MainFlutterVC
}
}
extension AppDelegate{
@ -37,3 +51,18 @@ extension AppDelegate{
}
}
}
/*
let dart = FlutterDartProject(precompiledDartBundle: .main)
let engine = FlutterEngine(name: "com.hmg.cs", project: dart, allowHeadlessExecution: true)
if engine.run(){
flutterMethodChannel = FlutterMethodChannel(name: "HMG-Platform-Bridge", binaryMessenger: engine.binaryMessenger)
Timer.scheduledTimer(withTimeInterval: 0.5, repeats: false) { (timer) in
FlutterText.with(key: "alreadyConnectedHmgNetwork"){ localized in
print(localized)
}
}
}
*/

@ -13,5 +13,10 @@ fileprivate let BASE_URL = "\(DOMAIN)/\(SERVICE)"
struct API {
static let WIFI_CREDENTIALS = "\(BASE_URL)/Hmg_SMS_Get_By_ProjectID_And_PatientID"
}
//struct API {
// static let WIFI_CREDENTIALS = FlutterConstants.WIFI_CREDENTIALS_URL
// static let LOG_GEOFENCE = FlutterConstants.LOG_GEOFENCE_URL
//}

@ -0,0 +1,36 @@
//
// FlutterConstants.swift
// Runner
//
// Created by ZiKambrani on 22/12/2020.
//
import UIKit
class FlutterConstants{
static var LOG_GEOFENCE_URL:String?
static var WIFI_CREDENTIALS_URL:String?
static var DEFAULT_HTTP_PARAMS:[String:Any?]?
class func set(){
// (FiX) Take a start with FlutterMethodChannel (kikstart)
/* First call to flutter method is not returning the correct value (Always returning 'NSObject') then after it wroking fine and returning correct value*/
FlutterText.with(key: "test") { (test) in
flutterMethodChannel?.invokeMethod("getDefaultHttpParameters", arguments: nil){ (response) in
if let defaultHTTPParams = response as? [String:Any?]{
DEFAULT_HTTP_PARAMS = defaultHTTPParams
}
}
flutterMethodChannel?.invokeMethod("getLogGeofenceFullUrl", arguments:nil){ (response) in
if let url = response as? String{
LOG_GEOFENCE_URL = url
}
}
}
}
}

@ -70,7 +70,7 @@ func userProfile() -> [String:Any?]?{
fileprivate let defaultHTTPParams:[String : Any?] = [
"ZipCode" : "966",
"VersionID" : 5.6,
"VersionID" : 5.8,
"Channel" : 3,
"LanguageID" : appLanguageCode(),
"IPAdress" : "10.20.10.20",

@ -49,6 +49,9 @@ class HMGPlatformBridge{
print("")
}
Timer.scheduledTimer(withTimeInterval: 0.1, repeats: false) { (timer) in
FlutterConstants.set()
}
}

@ -22,6 +22,9 @@ const GET_PROJECT = 'Services/Lists.svc/REST/GetProject';
const GET_GEO_ZONES = 'Services/Patients.svc/REST/GeoF_GetAllPoints';
const LOG_GEO_ZONES = 'Services/Patients.svc/REST/GeoF_InsertPatientFileInfo';
// Wifi Credentials
const WIFI_CREDENTIALS = "Services/Patients.svc/Hmg_SMS_Get_By_ProjectID_And_PatientID";
///Doctor
const GET_MY_DOCTOR = 'Services/Doctors.svc/REST/GetPatientDoctorAppointmentResult';
const GET_DOCTOR_PROFILE = 'Services/Doctors.svc/REST/GetDocProfiles';
@ -199,7 +202,7 @@ const UPDATE_HEALTH_TERMS = '/services/Patients.svc/REST/UpdatePateintHealthSumm
const CHANNEL = 3;
const GENERAL_ID = 'Cs2020@2016\$2958';
const IP_ADDRESS = '10.20.10.20';
const VERSION_ID = 5.6;
const VERSION_ID = 5.8;
const SETUP_ID = '91877';
const LANGUAGE = 2;
const PATIENT_OUT_SA = 0;
@ -306,7 +309,6 @@ class AppGlobal {
Request getPublicRequest() {
Request request = new Request();
request.VersionID = 5.6; //3.6;
request.Channel = 3;
request.IPAdress = "10.20.10.20";
request.generalid = 'Cs2020@2016\$2958';

Loading…
Cancel
Save