Search code examples
javaandroidlocationmanager

Android 11 - LocationManager.addProximityAlert does not trigger alerts


The addProximityAlert call stopped triggering alerts on Android 11 devices.

I call the addProximityAlert for the special locations (calculated for the user location) from the Application.onCreate method or whenever the ACCESS_FINE_LOCATION permission is granted using the following code:

    mLocationManager = (LocationManager) mApplicationContext.getSystemService(Context.LOCATION_SERVICE);
    if (mLocationManager != null) {
        final Criteria criteria = new Criteria();
        //criteria.setAccuracy(Criteria.ACCURACY_COARSE);
        criteria.setAccuracy(Criteria.ACCURACY_FINE);
        String provider = mLocationManager.getBestProvider(criteria, true);
        if (!TextUtils.isEmpty(provider)) {
            mLocationUpdatelistener = new LocationListener() {
                @Override
                public void onLocationChanged(Location location) {
                    subscribeForProximityAlert(location);
                }

                @Override
                public void onStatusChanged(String provider, int status, Bundle extras) {
                }

                @Override
                public void onProviderEnabled(String provider) {
                }

                @Override
                public void onProviderDisabled(String provider) {
                }
            };
            final Location lastKnownLocation = mLocationManager.getLastKnownLocation(provider);
            if (lastKnownLocation == null) {
                try {
                    mLocationManager.requestSingleUpdate(criteria, mLocationUpdatelistener, Looper.getMainLooper());
                } catch (Throwable e) {
                    e.printStackTrace();
                }
            } else {
                subscribeForProximityAlert(lastKnownLocation);
            }
        }
    }

The subscribeForProximityAlert function is as follows (it is called actually after the successful single location update - I've checked that):

                void subscribeForProximityAlert(Location location) {
                    String id;
                    double lat;
                    double lng;
                    long radius;
                    // ... compute the params above using the location

                    final Intent intent = new Intent(ACTION_FILTER);
                    intent.putExtra("_id", id);
                    intent.putExtra("_lat", lat);
                    intent.putExtra("_lng", lng);
                    intent.putExtra("_rad", radius);

                    final PendingIntent pendingIntent = PendingIntent.getBroadcast(mApplicationContext, i, intent, 0);
                    mPendingIntents.add(pendingIntent);

                    mLocationManager.addProximityAlert(
                            lat,
                            lng,
                            (float) radius,
                            24 * 60 * 60 * 1000,
                            pendingIntent
                    );
                }

The ACTION_FILTER is the com.example.appname.ProximityAlert exactly the value I use in manifest to subscribe for the Proximity Alert broadcasts (com.example.appname is the package name of the app):

<application>

    <receiver android:name="com.example.appname.ProximityAlertBroadcastReceiver">
        <intent-filter>
            <action android:name="com.example.appname.ProximityAlert" />
        </intent-filter>
    </receiver>

</application>

The ProximityAlertBroadcastReceiver can be as simple as:

public class ProximityAlertBroadcastReceiver extends BroadcastReceiver {

    public ProximityAlertBroadcastReceiver() {
    }

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

its onReceive method is never called on Android 11 devices (checked with Lod.d and Toast.makeText...show() calls). Not when the app is running, not when it's in background. Not when I'm already in the radius of specified point, not when I'm entering/exiting.

Tried to add the android.permission.ACCESS_BACKGROUND_LOCATION permission to the manifest (nothing about it in the LocationManager.addProximityAlerts docs anyway) and grant the permission in system settings for the app, but it didn't help.

Also tried to reduce the targetSdkVersion from 30 to 28, but it didn't help.


Solution

  • The problem happened because of the implicit intent for the broadcast receiver, which is prohibited for the app targeting Android 8+ (SDK version 26): https://developer.android.com/about/versions/oreo/background#broadcasts

    After changing the

    final Intent intent = new Intent(ACTION_FILTER);
    

    to

    final Intent intent = new Intent(mApplicationContext, ProximityAlertBroadcastReceiver.class);
    

    I started to receive the broadcasts.

    UPDATE: There's a bug in recent Android versions (11, 12, maybe others) which makes Geofences unresponsive on some devices and completely non-working on other devices if no app is actively requesting location at the moment: https://issuetracker.google.com/issues/218335535

    addProximityAlert creates a geofence under the hood, so it's affected too.