8

In Android OS, in "Settings" --> "Location services", there is a toggle button named "Access to my location" which can be used to disable & enable location info access from apps.

Currently, I am developing a location service application. I am wondering, how can I listen to this setting in my Android project? Is there any broadcast receiver I can use to know right away when user disable or enable "Access to my location" ?

If there isn't any broadcast receiver for it, how can I listen to this change in my Android project?

Mellon
  • 37,586
  • 78
  • 186
  • 264
  • 1
    @ GrlsHu, no, I don't want to do that. The key point of my question is how to listen to this location access setting. – Mellon Nov 28 '13 at 12:37
  • http://stackoverflow.com/a/20673766/1994950 and http://stackoverflow.com/a/23756293/1994950 will help – Kushal Mar 11 '15 at 07:18

4 Answers4

6

This works for me:

Add receiver to the Manifest file:

<receiver
        android:name="com.eegeo.location.LocationProviderChangedReceiver">
        <intent-filter>
            <action android:name="android.location.PROVIDERS_CHANGED" />
        </intent-filter>
    </receiver>

Check both location providers in receiver:

public class LocationProviderChangedReceiver  extends BroadcastReceiver{

    @Override
    public void onReceive(Context context, Intent intent) {

        boolean anyLocationProv = false;
        LocationManager locationManager = (LocationManager) MyMainActivity.context.getSystemService(Context.LOCATION_SERVICE);

        anyLocationProv |= locationManager.isProviderEnabled(LocationManager.GPS_PROVIDER);
        anyLocationProv |=  locationManager.isProviderEnabled(LocationManager.NETWORK_PROVIDER);

        Log.i("", "Location service status" + anyLocationProv);


    }

}

Though this receiver is called more than once due to obvious reasons, but this will tell you the status.

M. Usman Khan
  • 3,689
  • 1
  • 59
  • 69
  • 1
    The manifest broadcast receiver should be used only if the app needs location in the background. It should use a runtime broadcast receiver otherwise – Louis CAD Nov 28 '16 at 09:55
  • 2
    This won't work if your app targets Android 8.0 (API level 26) or above: [Registering broadcast receivers for implicit broadcasts in the manifest has been disabled](https://developer.android.com/about/versions/oreo/background#broadcasts) – minipif May 31 '18 at 07:10
1

You can do it much simpler this way. In your BroadcastReceiver's onReceive() method:

    ContentResolver contentResolver = getContext().getContentResolver();
    // Find out what the settings say about which providers are enabled
    int mode = Settings.Secure.getInt(
            contentResolver, Settings.Secure.LOCATION_MODE, Settings.Secure.LOCATION_MODE_OFF);

    if (mode == Settings.Secure.LOCATION_MODE_OFF) {
        // Location is turned OFF!
    } else {
        // Location is turned ON!
    }

~Thanks to this code: LocationManagerTest.java

IgorGanapolsky
  • 26,189
  • 23
  • 116
  • 147
0

You can use the below code to check whether Location Service Enable or not

 LocationManager lm = null;
 boolean gps_enabled,network_enabled;
    if(lm==null)
        lm = (LocationManager) context.getSystemService(Context.LOCATION_SERVICE);
    try{
    gps_enabled = lm.isProviderEnabled(LocationManager.GPS_PROVIDER);
    }catch(Exception ex){}
    try{
    network_enabled = lm.isProviderEnabled(LocationManager.NETWORK_PROVIDER);
    }catch(Exception ex){}

   if(!gps_enabled && !network_enabled){
        dialog = new AlertDialog.Builder(context);
        dialog.setMessage(context.getResources().getString(R.string.gps_network_not_enabled));
        dialog.setPositiveButton(context.getResources().getString(R.string.open_location_settings), new DialogInterface.OnClickListener() {

            @Override
            public void onClick(DialogInterface paramDialogInterface, int paramInt) {
                // TODO Auto-generated method stub
                Intent myIntent = new Intent( Settings.ACTION_SECURITY_SETTINGS );
                context.startActivity(myIntent);
                //get gps
            }
        });
        dialog.setNegativeButton(context.getString(R.string.Cancel), new DialogInterface.OnClickListener() {

            @Override
            public void onClick(DialogInterface paramDialogInterface, int paramInt) {
                // TODO Auto-generated method stub

            }
        });
        dialog.show();

    }
Karthi
  • 756
  • 4
  • 16
  • 3
    Hi, my question is not about how to check the value, but about how to listen to the change, meaning that how to get a notification in code that user has changed this location access in settings & then get the changed value. – Mellon Nov 28 '13 at 12:19
  • @GrIsHu That is incorrect. Have you tried usman's solution below? – IgorGanapolsky Mar 20 '15 at 15:15
0

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.

VonSchnauzer
  • 912
  • 11
  • 17