So I\'ve spent the past few weeks working on my Android App and looking into the best way of implementing what I need to do, but still can\'t quite get it right.. Any/all he
LocationListeners's onProvideEnabled() method will work instantly. When you call this remember if you are doing LocationManager.removeUpdates() in between onProviderEnabled() won't work.
And this is pretty much simple when you are reading locations from Location API's of Android. You don't need the broadcast receivers listening and communication further
But when you are using FusedLocationProviderClient from google API and if you use LocationListener's onProviderEnabled and onProviderDisabled methods you will be having two services running in parallel, checking for the provider changes. So using BroadcastReceiver is better
Here is a solution using dynamic registration:
In your fragment or activity's onResume() method, listen to changes in LocationManager.PROVIDERS_CHANGED_ACTION
IntentFilter filter = new IntentFilter(LocationManager.PROVIDERS_CHANGED_ACTION);
filter.addAction(Intent.ACTION_PROVIDER_CHANGED);
mActivity.registerReceiver(gpsSwitchStateReceiver, filter);
Here is a code sample for the gpsSwitchStateReceiver object:
private BroadcastReceiver gpsSwitchStateReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
if (LocationManager.PROVIDERS_CHANGED_ACTION.equals(intent.getAction())) {
// Make an action or refresh an already managed state.
LocationManager locationManager = (LocationManager) context.getSystemService(Context.LOCATION_SERVICE);
boolean isGpsEnabled = locationManager.isProviderEnabled(LocationManager.GPS_PROVIDER);
boolean isNetworkEnabled = locationManager.isProviderEnabled(LocationManager.NETWORK_PROVIDER);
if (isGpsEnabled || isNetworkEnabled) {
Log.i(this.getClass().getName(), "gpsSwitchStateReceiver.onReceive() location is enabled : isGpsEnabled = " + isGpsEnabled + " isNetworkEnabled = " + isNetworkEnabled);
} else {
Log.w(this.getClass().getName(), "gpsSwitchStateReceiver.onReceive() location disabled ");
}
}
}
};
In your onPause() method, unregister the receiver
mActivity.unregisterReceiver(gpsSwitchStateReceiver);
Since you don't need to actually get a Location, the best implementation for your needs would be a BroadcastReceiver.
This is the best option because you wouldn't need to have a Service running at all times (resulting in extra batter drain), and you would be able to start your Activity from the BroadcastReceiver.
With the intent filter and BroadcastReceiver, your app will be started by the OS whenever the Location setting has changed (enabled or disabled), and in the case that it is enabled, you can start your Activity from the BroadcastReceiver.
First add the intent filter, which will be captured when the OS sends out the implicit Intent that the setting has changed.
<receiver
android:name=".LocationProviderChangedReceiver"
android:exported="false" >
<intent-filter>
<action android:name="android.location.PROVIDERS_CHANGED" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</receiver>
Note that for this to work on Android Oreo and above, you'll need to register the broadcast receiver at runtime, see here: https://developer.android.com/guide/components/broadcasts#context-registered-receivers
Then, in LocationProviderChangedReceiver.java, your implementation would be something like this:
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.location.LocationManager;
import android.util.Log;
import android.widget.Toast;
public class LocationProviderChangedReceiver extends BroadcastReceiver {
private final static String TAG = "LocationProviderChanged";
boolean isGpsEnabled;
boolean isNetworkEnabled;
@Override
public void onReceive(Context context, Intent intent) {
if (intent.getAction().matches("android.location.PROVIDERS_CHANGED"))
{
Log.i(TAG, "Location Providers changed");
LocationManager locationManager = (LocationManager) context.getSystemService(Context.LOCATION_SERVICE);
isGpsEnabled = locationManager.isProviderEnabled(LocationManager.GPS_PROVIDER);
isNetworkEnabled = locationManager.isProviderEnabled(LocationManager.NETWORK_PROVIDER);
//Start your Activity if location was enabled:
if (isGpsEnabled || isNetworkEnabled) {
Intent i = new Intent(context, YourActivity.class);
context.startActivity(i);
}
}
}
}
Edit
Updated solution with Kotlin and registering receiver at runtime for Android 9.
The BroadcastReceiver class in Kotlin:
class LocationProviderChangedReceiver : BroadcastReceiver() {
internal var isGpsEnabled: Boolean = false
internal var isNetworkEnabled: Boolean = false
override fun onReceive(context: Context, intent: Intent) {
intent.action?.let { act ->
if (act.matches("android.location.PROVIDERS_CHANGED".toRegex())) {
val locationManager = context.getSystemService(Context.LOCATION_SERVICE) as LocationManager
isGpsEnabled = locationManager.isProviderEnabled(LocationManager.GPS_PROVIDER)
isNetworkEnabled = locationManager.isProviderEnabled(LocationManager.NETWORK_PROVIDER)
Log.i(TAG, "Location Providers changed, is GPS Enabled: " + isGpsEnabled)
//Start your Activity if location was enabled:
if (isGpsEnabled || isNetworkEnabled) {
val i = Intent(context, YourActivity::class.java)
context.startActivity(i)
}
}
}
}
companion object {
private val TAG = "LocationProviderChanged"
}
}
Register at runtime, for example in onCreate() of your app's MainActivity:
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
val br: BroadcastReceiver = LocationProviderChangedReceiver()
val filter = IntentFilter(LocationManager.PROVIDERS_CHANGED_ACTION)
registerReceiver(br, filter)
}