Permalink
Browse files

Console updates

  • Loading branch information...
richturner committed Aug 31, 2018
1 parent 723a7e7 commit a8a505d8b0870bbd9a6edaa5f9eee679d58d4f3b
@@ -19,6 +19,7 @@ import java.net.URL
import java.util.*
import java.util.logging.Level
import java.util.logging.Logger
import kotlin.concurrent.schedule
class GeofenceProvider(val context: Context) : ActivityCompat.OnRequestPermissionsResultCallback {
@@ -300,7 +301,17 @@ class GeofenceProvider(val context: Context) : ActivityCompat.OnRequestPermissio
LOG.info("Enabling geofence provider")
Thread {
if (ContextCompat.checkSelfPermission(context, ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED) {
val hasPermission = ContextCompat.checkSelfPermission(context, ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED
callback?.accept(hashMapOf(
"action" to "PROVIDER_ENABLE",
"provider" to "geofence",
"hasPermission" to hasPermission,
"success" to true
))
if (hasPermission) {
LOG.info("Has permission so fetching geofences")
// if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
@@ -309,15 +320,15 @@ class GeofenceProvider(val context: Context) : ActivityCompat.OnRequestPermissio
// context.startService(Intent(context, LocationService::class.java))
// }
refreshGeofences()
if (getGeofences(context).isEmpty()) {
// Could be first time getting geofences so wait a few seconds for backend to catch up
Timer().schedule(10000) {
refreshGeofences()
}
} else {
refreshGeofences()
}
}
callback?.accept(hashMapOf(
"action" to "PROVIDER_ENABLE",
"provider" to "geofence",
"hasPermission" to (ContextCompat.checkSelfPermission(context, ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED),
"success" to true
))
}.start()
}
@@ -3,17 +3,23 @@ package org.openremote.android.service
import android.content.BroadcastReceiver
import android.content.Context
import android.content.Intent
import android.util.Pair
import com.fasterxml.jackson.databind.ObjectMapper
import com.google.android.gms.location.Geofence
import com.google.android.gms.location.GeofencingEvent
import java.net.HttpURLConnection
import java.net.URL
import java.util.*
import java.util.logging.Level
import java.util.logging.Logger
import kotlin.concurrent.schedule
class GeofenceTransitionsIntentService : BroadcastReceiver() {
private val LOG = Logger.getLogger(GeofenceTransitionsIntentService::class.java.name)
private var queuedLocations : MutableList<Pair<GeofenceProvider.GeofenceDefinition, String?>> = mutableListOf()
private var locationTimer : Timer = Timer()
private var nullLocation : GeofenceProvider.GeofenceDefinition? = null
override fun onReceive(context: Context?, intent: Intent?) {
@@ -36,54 +42,109 @@ class GeofenceTransitionsIntentService : BroadcastReceiver() {
val baseUrl = intent!!.getStringExtra(GeofenceProvider.baseUrlKey)
val geofenceTransition = geofencingEvent.geofenceTransition
geofencingEvent.triggeringGeofences.forEach {
geofence ->
val geofenceDefinition = geofenceDefinitions.firstOrNull { it.id == geofence.requestId }
if (geofenceDefinition != null) {
LOG.info("Triggered geofence: id=${geofenceDefinition.id}")
val url = URL("$baseUrl${geofenceDefinition.url}")
val connection = url.openConnection() as HttpURLConnection
connection.setRequestProperty("Content-Type", "application/json")
connection.requestMethod = geofenceDefinition.httpMethod
connection.connectTimeout = 10000
connection.doInput = false
val postJson = when (geofenceTransition) {
Geofence.GEOFENCE_TRANSITION_ENTER -> {
LOG.info("Sending location 'lat=${geofenceDefinition.lat}/lng=${geofenceDefinition.lng}' to server: HTTP ${geofenceDefinition.httpMethod} $url")
hashMapOf(
"type" to "Point",
"coordinates" to arrayOf(geofenceDefinition.lng, geofenceDefinition.lat)
)
}
else -> {
LOG.info("Sending location 'null' to server: HTTP ${geofenceDefinition.httpMethod} $url")
null
}
geofencingEvent.triggeringGeofences.forEach { geofence ->
val geofenceDefinition = geofenceDefinitions.firstOrNull { it.id == geofence.requestId }
if (geofenceDefinition != null) {
LOG.info("Triggered geofence: id=${geofenceDefinition.id}")
geofenceDefinition.url = baseUrl + geofenceDefinition.url
val locationJson = when (geofenceTransition) {
Geofence.GEOFENCE_TRANSITION_ENTER -> {
val location = hashMapOf(
"type" to "Point",
"coordinates" to arrayOf(geofenceDefinition.lng, geofenceDefinition.lat)
)
ObjectMapper().writeValueAsString(location)
}
else -> {
null
}
}
// Android often triggers an exit on one fence at the same time as triggering an enter
// on another so we queue the sends to allow the server time to process the events
queueSendLocation(geofenceDefinition, locationJson)
}
}
}
Thread {
try {
connection.doOutput = true
connection.setChunkedStreamingMode(0)
connection.outputStream
ObjectMapper().writeValue(connection.outputStream, postJson)
connection.outputStream.flush()
val responseCode = connection.responseCode
LOG.info("Send location success: response=$responseCode")
} catch (exception: Exception) {
LOG.log(Level.SEVERE, "Send location failed", exception)
print(exception)
} finally {
connection.disconnect()
}
}.start()
@Synchronized
fun queueSendLocation(geofenceDefinition : GeofenceProvider.GeofenceDefinition, locationJson : String?) {
var scheduleSend = false
if (locationJson == null) {
if (nullLocation == null) {
nullLocation = geofenceDefinition
scheduleSend = true
}
} else {
scheduleSend = queuedLocations.isEmpty()
queuedLocations.add(Pair(geofenceDefinition, locationJson))
}
if (scheduleSend) {
LOG.info("Schedule send location")
locationTimer.schedule(2000) {
doSendLocation()
}
}
}
@Synchronized
fun doSendLocation() {
LOG.info("Do send location")
if (nullLocation != null) {
sendLocation(nullLocation!!, null)
nullLocation = null
} else {
val geofenceAndLocation = queuedLocations.removeAt(0)
sendLocation(geofenceAndLocation.first, geofenceAndLocation.second)
}
if (queuedLocations.isNotEmpty()) {
// Schedule another send
locationTimer.schedule(3000) {
doSendLocation()
}
}
}
@Synchronized
fun sendLocation(geofenceDefinition : GeofenceProvider.GeofenceDefinition, locationJson : String?) {
Thread {
val url = URL(geofenceDefinition.url)
val connection = url.openConnection() as HttpURLConnection
try {
connection.setRequestProperty("Content-Type", "application/json")
connection.requestMethod = geofenceDefinition.httpMethod
connection.connectTimeout = 10000
connection.doInput = false
connection.doOutput = true
connection.setChunkedStreamingMode(0)
if (locationJson == null) {
LOG.info("Sending location 'null' to server: HTTP ${geofenceDefinition.httpMethod} $url")
connection.outputStream.write("null".toByteArray(Charsets.UTF_8))
} else {
LOG.info("Sending location 'lat=${geofenceDefinition.lat}/lng=${geofenceDefinition.lng}' to server: HTTP ${geofenceDefinition.httpMethod} $url")
connection.outputStream.write(locationJson.toByteArray(Charsets.UTF_8))
}
connection.outputStream.flush()
val responseCode = connection.responseCode
LOG.info("Send location success: response=$responseCode")
} catch (exception: Exception) {
LOG.log(Level.SEVERE, "Send location failed", exception)
print(exception)
} finally {
connection.disconnect()
}
}.start()
}
}
@@ -296,11 +296,23 @@ class ConsoleTest extends Specification implements ManagerContainerTrait {
and: "the console should not have been linked to any users"
assert userAssets.isEmpty()
and: "each created consoles should have been sent notifications to refresh their geofences"
conditions.eventually {
assert notificationIds.size() == 3
assert messages.count { ((PushNotificationMessage)it).data.get("GEOFENCE_REFRESH") != null } == 3
}
////////////////////////////////////////////////////
// LOCATION PREDICATE AND ALERT NOTIFICATION TESTS
////////////////////////////////////////////////////
when: "an authenticated user updates the location of a linked console"
when: "notifications are cleared"
notificationIds.clear()
targetIds.clear()
targetTypes.clear()
messages.clear()
and: "an authenticated user updates the location of a linked console"
authenticatedAssetResource.writeAttributeValue(null, testUser3Console1.id, LOCATION.name, new GeoJSONPoint(0d, 0d, 0d).toValue().toJson())
then: "the consoles location should have been updated"

0 comments on commit a8a505d

Please sign in to comment.