2023: This solution listens to, and reacts, when user toggles the location in curtain menu. The hard part was figuring out which "intent" filter flag to use (LocationManager.PROVIDERS_CHANGED_ACTION
).
In my example I use @Inject constructor
(Hilt). If you don't, then just send the context
as parameter to register()
and unregister()
: register(context: Context)
etc.
An extension on Context:
fun Context.isLocationEnabled(): Boolean {
val locationManager = this.getSystemService(Context.LOCATION_SERVICE) as LocationManager
return LocationManagerCompat.isLocationEnabled(locationManager)
}
Create a BroadcastReceiver:
class LocationBroadcastReceiver @Inject constructor(private val context: Context) : BroadcastReceiver() {
private val locationStateChange: BehaviorRelay<Boolean> = BehaviorRelay.createDefault(context.isLocationEnabled())
override fun onReceive(context: Context, intent: Intent) {
val action = intent.action
if (action == LocationManager.PROVIDERS_CHANGED_ACTION) {
val state = context.isLocationEnabled()
locationStateChange.accept(state)
}
}
fun subscribeState(): Flowable<Boolean> {
return locationStateChange.toFlowable(BackpressureStrategy.LATEST)
}
/**
* Listen to subscribeState() to receive updates
*/
fun register() {
val filter = IntentFilter(LocationManager.PROVIDERS_CHANGED_ACTION)
val receiverFlags = ContextCompat.RECEIVER_NOT_EXPORTED
ContextCompat.registerReceiver(context, this, filter, receiverFlags)
}
fun unregister() {
context.unregisterReceiver(this)
}
}
Now you can subscribe to
subscribeState()
from your viewModel or compose class and do what you must.