@ -30,12 +30,12 @@ enum class GeofenceTransition(val value: Int) {
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 == 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 "
fun named ( ) : String {
if ( value == 1 ) return " Enter "
if ( value == 2 ) return " 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 "
}
}
@ -44,63 +44,65 @@ class HMG_Geofence {
// https://developer.android.com/training/location/geofencing#java
private lateinit var context : Context
private lateinit var preferences : SharedPreferences
private lateinit var preferences : SharedPreferences
private val gson = Gson ( )
private lateinit var geofencingClient : GeofencingClient
private lateinit var geofencingClient : GeofencingClient
private val geofencePendingIntent : PendingIntent by lazy {
val intent = Intent ( context , GeofenceBroadcastReceiver :: class . java )
PendingIntent . getBroadcast (
context ,
0 ,
intent ,
PendingIntent . FLAG _UPDATE _CURRENT )
context ,
0 ,
intent ,
PendingIntent . FLAG _IMMUTABLE
)
}
companion object {
companion object {
var instance : HMG _Geofence ? = null
fun shared ( context : Context ) : HMG _Geofence {
if ( instance == null ) {
fun shared ( context : Context ) : HMG _Geofence {
if ( instance == null ) {
instance = HMG _Geofence ( )
instance ?. context = context
instance ?. geofencingClient = LocationServices . getGeofencingClient ( context )
instance ?. preferences = context . getSharedPreferences ( PREFS _STORAGE , Context . MODE _PRIVATE )
instance ?. preferences =
context . getSharedPreferences ( PREFS _STORAGE , Context . MODE _PRIVATE )
}
return instance !!
return instance !!
}
}
fun limitize ( zones : List < GeoZoneModel > ) : List < GeoZoneModel > {
private fun limitize ( zones : List < GeoZoneModel > ) : List < GeoZoneModel > {
var geoZones _ = zones
if ( zones . size > 100 )
if ( zones . size > 100 )
geoZones _ = zones . subList ( 0 , 99 )
return geoZones _
}
fun register ( completion : ( ( Boolean , java . lang . Exception ? ) -> Unit ) ) {
fun register ( completion : ( ( Boolean , java . lang . Exception ? ) -> Unit ) ) {
unRegisterAll { status , exception ->
val geoZones = getGeoZonesFromPreference ( context )
doRegister ( geoZones ) { status _ , error ->
doRegister ( geoZones ) { status _ , error ->
completion . let { it ( status _ , error ) }
}
}
}
fun unRegisterAll ( completion : ( status : Boolean , exception : Exception ? ) -> Unit ) {
fun unRegisterAll ( completion : ( status : Boolean , exception : Exception ? ) -> Unit ) {
getActiveGeofences ( { success ->
removeActiveGeofences ( )
if ( success . isNotEmpty ( ) )
if ( success . isNotEmpty ( ) )
geofencingClient
. removeGeofences ( success )
. addOnSuccessListener {
completion ( true , null )
}
. addOnFailureListener {
completion ( false , it )
saveLog ( context , " error:REMOVE_GEOFENCES " , it . localizedMessage )
}
. removeGeofences ( success )
. addOnSuccessListener {
completion ( true , null )
}
. addOnFailureListener {
completion ( false , it )
saveLog ( context , " error:REMOVE_GEOFENCES " , it . localizedMessage )
}
else
completion ( true , null )
@ -109,7 +111,10 @@ class HMG_Geofence {
} )
}
private fun doRegister ( geoZones : List < GeoZoneModel > , completion : ( ( Boolean , java . lang . Exception ? ) -> Unit ) ? = null ) {
private fun doRegister (
geoZones : List < GeoZoneModel > ,
completion : ( ( Boolean , java . lang . Exception ? ) -> Unit ) ? = null
) {
if ( geoZones . isEmpty ( ) )
return
@ -117,9 +122,9 @@ class HMG_Geofence {
fun buildGeofencingRequest ( geofences : List < Geofence > ) : GeofencingRequest {
return GeofencingRequest . Builder ( )
. setInitialTrigger ( GeofencingRequest . INITIAL _TRIGGER _DWELL )
. addGeofences ( geofences )
. build ( )
. setInitialTrigger ( GeofencingRequest . INITIAL _TRIGGER _DWELL )
. addGeofences ( geofences )
. build ( )
}
getActiveGeofences ( { active ->
@ -135,26 +140,41 @@ class HMG_Geofence {
if ( checkPermission ( ) && geofences . isNotEmpty ( ) ) {
geofencingClient
. addGeofences ( buildGeofencingRequest ( geofences ) , geofencePendingIntent )
. addOnSuccessListener {
Logs . RegisterGeofence . save ( context , " SUCCESS " , " Successfuly registered the geofences " , Logs . STATUS . SUCCESS )
saveActiveGeofence ( geofences . map { it . requestId } , listOf ( ) )
completion ?. let { it ( true , null ) }
}
. addOnFailureListener { exc ->
Logs . RegisterGeofence . save ( context , " FAILED_TO_REGISTER " , " Failed to register geofence " , Logs . STATUS . ERROR )
completion ?. let { it ( false , exc ) }
}
. addGeofences ( buildGeofencingRequest ( geofences ) , geofencePendingIntent )
. addOnSuccessListener {
Logs . RegisterGeofence . save (
context ,
" SUCCESS " ,
" Successfuly registered the geofences " ,
Logs . STATUS . SUCCESS
)
saveActiveGeofence ( geofences . map { it . requestId } , listOf ( ) )
completion ?. let { it ( true , null ) }
}
. addOnFailureListener { exc ->
Logs . RegisterGeofence . save (
context ,
" FAILED_TO_REGISTER " ,
" Failed to register geofence " ,
Logs . STATUS . ERROR
)
completion ?. let { it ( false , exc ) }
}
// 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 . TriggerIntervalDuration )
HMGUtils . scheduleJob (
context ,
ReregisterGeofenceJobService :: class . java ,
ReregisterGeofenceJobService . JobID ,
ReregisterGeofenceJobService . TriggerIntervalDuration
)
}
} , null )
}
fun getGeoZonesFromPreference ( context : Context ) : List < GeoZoneModel > {
fun getGeoZonesFromPreference ( context : Context ) : List < GeoZoneModel > {
val pref = context . getSharedPreferences ( PREFS _STORAGE , Context . MODE _PRIVATE )
val json = pref . getString ( PREF _KEY _HMG _ZONES , " [] " )
@ -162,26 +182,29 @@ class HMG_Geofence {
return geoZones
}
fun saveActiveGeofence ( success : List < String > , failed : List < String > ) {
fun saveActiveGeofence ( success : List < String > , failed : List < String > ) {
val jsonSuccess = gson . toJson ( success )
val jsonFailure = gson . toJson ( failed )
preferences . edit ( ) . putString ( PREF _KEY _SUCCESS , jsonSuccess ) . apply ( )
preferences . edit ( ) . putString ( PREF _KEY _FAILED , jsonFailure ) . apply ( )
}
fun removeActiveGeofences ( ) {
fun removeActiveGeofences ( ) {
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 ) ? ) {
val type = object : TypeToken < List < String ? > ? > ( ) { } . type
fun getActiveGeofences (
success : ( success : List < String > ) -> Unit ,
failure : ( ( failed : List < String > ) -> Unit ) ?
) {
val type = object : TypeToken < List < String ? > ? > ( ) { } . type
val jsonSuccess = preferences . getString ( PREF _KEY _SUCCESS , " [] " )
val success = gson . fromJson < List < String > > ( jsonSuccess , type )
success ( success )
if ( failure != null ) {
if ( failure != null ) {
val jsonFailure = preferences . getString ( PREF _KEY _FAILED , " [] " )
val failed = gson . fromJson < List < String > > ( jsonFailure , type )
failure ( failed )
@ -189,47 +212,74 @@ class HMG_Geofence {
}
private fun checkPermission ( ) : Boolean {
return ContextCompat . checkSelfPermission ( context , Manifest . permission . ACCESS _FINE _LOCATION ) == PackageManager . PERMISSION _GRANTED
private fun checkPermission ( ) : Boolean {
return ContextCompat . checkSelfPermission (
context ,
Manifest . permission . ACCESS _FINE _LOCATION
) == PackageManager . PERMISSION _GRANTED
}
fun getPatientID ( ) : Int ? {
fun getPatientID ( ) : Int ? {
var profileJson = preferences . getString ( " flutter.imei-user-data " , null )
if ( profileJson == null )
profileJson = preferences . getString ( " flutter.user-profile " , null )
val type = object : TypeToken < Map < String ? , Any ? > ? > ( ) { } . type
return gson . fromJson < Map < String ? , Any ? > ? > ( profileJson , type )
?. get ( " PatientID " )
. toString ( )
. toDoubleOrNull ( )
?. toInt ( )
?. get ( " PatientID " )
. toString ( )
. toDoubleOrNull ( )
?. toInt ( )
}
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 ( )
val pointID =
activeGeofences . firstOrNull { it == geofence . requestId } ?. split ( '_' )
?. first ( )
if ( ! pointID . isNullOrEmpty ( ) && pointID . toIntOrNull ( ) != null ) {
val body = mutableMapOf < String , Any ? > (
" PointsID " to pointID . toIntOrNull ( ) ,
" GeoType " to transition . value ,
" PatientID " to patientId
" 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 ->
saveLog ( context , " HMG_GEOFENCE_NOTIFY " , " Success: Notified to server \uD83D \uDE0E . " )
sendNotification ( context , transition . named ( ) , geofence . requestId , " Notified to server.😎 " )
saveLog (
context ,
" HMG_GEOFENCE_NOTIFY " ,
" Success: Notified to server \uD83D \uDE0E . "
)
sendNotification (
context ,
transition . named ( ) ,
geofence . requestId ,
" Notified to 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} " )
saveLog (
context ,
" HMG_GEOFENCE_NOTIFY " ,
" failed: $errorMessage | error: ${exception.localizedMessage} "
)
sendNotification (
context ,
transition . named ( ) ,
geofence . requestId ,
" Failed to notify server😔 -> ${exception.localizedMessage} "
)
} )
}