diff --git a/app/src/full/java/io/homeassistant/companion/android/sensors/LocationSensorManager.kt b/app/src/full/java/io/homeassistant/companion/android/sensors/LocationSensorManager.kt index e764760be..d0e1efa4a 100644 --- a/app/src/full/java/io/homeassistant/companion/android/sensors/LocationSensorManager.kt +++ b/app/src/full/java/io/homeassistant/companion/android/sensors/LocationSensorManager.kt @@ -9,6 +9,7 @@ import android.location.Location import android.os.Build import android.os.PowerManager import android.util.Log +import android.widget.Toast import androidx.core.content.ContextCompat.getSystemService import com.google.android.gms.location.Geofence import com.google.android.gms.location.GeofencingEvent @@ -72,6 +73,8 @@ class LocationSensorManager : BroadcastReceiver(), SensorManager { private var lastLocationSend = 0L private var lastUpdateLocation = "" + + private var geofenceRegistered = false } @Inject @@ -122,6 +125,11 @@ class LocationSensorManager : BroadcastReceiver(), SensorManager { isBackgroundLocationSetup = false isZoneLocationSetup = false } + if (backgroundEnabled && !zoneEnabled && isZoneLocationSetup) { + removeGeofenceUpdateRequests() + isZoneLocationSetup = false + Log.d(TAG, "Removing geofence update requests") + } if (backgroundEnabled && !isBackgroundLocationSetup) { isBackgroundLocationSetup = true requestLocationUpdates() @@ -143,9 +151,14 @@ class LocationSensorManager : BroadcastReceiver(), SensorManager { fusedLocationProviderClient.removeLocationUpdates(backgroundIntent) + removeGeofenceUpdateRequests() + } + + private fun removeGeofenceUpdateRequests() { val geofencingClient = LocationServices.getGeofencingClient(latestContext) val zoneIntent = getLocationUpdateIntent(true) geofencingClient.removeGeofences(zoneIntent) + geofenceRegistered = false } private fun requestLocationUpdates() { @@ -170,6 +183,11 @@ class LocationSensorManager : BroadcastReceiver(), SensorManager { return } + if (geofenceRegistered) { + Log.w(TAG, "Not registering for zones as we already have") + return + } + Log.d(TAG, "Registering for zone based location updates") try { @@ -204,12 +222,48 @@ class LocationSensorManager : BroadcastReceiver(), SensorManager { private fun handleGeoUpdate(intent: Intent) { Log.d(TAG, "Received geofence update.") + if (!isEnabled(latestContext, zoneLocation.id)) { + isZoneLocationSetup = false + Log.w(TAG, "Unregistering geofences as zone tracking is disabled and intent was received") + removeGeofenceUpdateRequests() + return + } val geofencingEvent = GeofencingEvent.fromIntent(intent) if (geofencingEvent.hasError()) { Log.e(TAG, "Error getting geofence broadcast status code: ${geofencingEvent.errorCode}") return } + val validGeofencingEvents = listOf(Geofence.GEOFENCE_TRANSITION_ENTER, Geofence.GEOFENCE_TRANSITION_EXIT) + if (geofencingEvent.geofenceTransition in validGeofencingEvents) { + val zoneStatusEvent = when (geofencingEvent.geofenceTransition) { + Geofence.GEOFENCE_TRANSITION_ENTER -> "android.zone_entered" + Geofence.GEOFENCE_TRANSITION_EXIT -> "android.zone_exited" + else -> "" + } + val zoneAttr = mapOf( + "accuracy" to geofencingEvent.triggeringLocation.accuracy, + "altitude" to geofencingEvent.triggeringLocation.altitude, + "bearing" to geofencingEvent.triggeringLocation.bearing, + "latitude" to geofencingEvent.triggeringLocation.latitude, + "longitude" to geofencingEvent.triggeringLocation.longitude, + "provider" to geofencingEvent.triggeringLocation.provider, + "time" to geofencingEvent.triggeringLocation.time, + "vertical_accuracy" to if (Build.VERSION.SDK_INT >= 26) geofencingEvent.triggeringLocation.verticalAccuracyMeters.toInt() else 0, + "zone" to geofencingEvent.triggeringGeofences[0].requestId + ) + runBlocking { + try { + integrationUseCase.fireEvent(zoneStatusEvent, zoneAttr as Map) + Log.d(TAG, "Event sent to Home Assistant") + } catch (e: Exception) { + Log.e(TAG, "Unable to send event to Home Assistant", e) + Toast.makeText(latestContext, R.string.zone_event_failure, Toast.LENGTH_LONG) + .show() + } + } + } + val sensorDao = AppDatabase.getInstance(latestContext).sensorDao() val sensorSettings = sensorDao.getSettings(zoneLocation.id) val minAccuracy = sensorSettings @@ -224,11 +278,11 @@ class LocationSensorManager : BroadcastReceiver(), SensorManager { ) requestSingleAccurateLocation() } else { - sendLocationUpdate(geofencingEvent.triggeringLocation) + sendLocationUpdate(geofencingEvent.triggeringLocation, "", true) } } - private fun sendLocationUpdate(location: Location, name: String = "") { + private fun sendLocationUpdate(location: Location, name: String = "", geofenceUpdate: Boolean = false) { Log.d( TAG, "Last Location: " + "\nCoords:(${location.latitude}, ${location.longitude})" + @@ -256,6 +310,11 @@ class LocationSensorManager : BroadcastReceiver(), SensorManager { Log.d(TAG, "Duplicate location received, not sending to HA") return } + } else { + if (now < lastLocationSend + 5000 && !geofenceUpdate) { + Log.d(TAG, "New location update not possible within 5 seconds, not sending to HA") + return + } } lastLocationSend = now lastUpdateLocation = updateLocation.gps.contentToString() @@ -304,6 +363,7 @@ class LocationSensorManager : BroadcastReceiver(), SensorManager { .build() ) } + geofenceRegistered = true return geofencingRequestBuilder.build() } diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index b15e23c24..8a090180c 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -77,6 +77,7 @@ to your home internet. Connected to Home Assistant Create Template Unable to send migration failure event to Home Assistant + Unable to send zone event to Home Assistant Database migration failed, all sensor and widget data has been reset. Please re-enable your sensors and recreate your widgets. Developer Tools Device Class