javaandroidgoogle-maps-markersgeofencing

how to start some method when you come within 10 meters to the marker?


I need to make android app with map and some markers. When i'm come within 10 meters to the marker, it becomes clickable, and on click plays audiotrack, then changes marker icon and shows another marker. I tried to use geofences, but i can't change icon or call MediaPlayer from BroadcastReciever or from other activity or service.

marker - center of geofence.

The Question:

How can I change marker's icon and start audiotrack, when geofence triggers?

adding geofences in MapsActivity

private void createGeofences(){
        if (Build.VERSION.SDK_INT >= 29) {
            //We need background permission
            if (ContextCompat.checkSelfPermission(this, Manifest.permission.ACCESS_BACKGROUND_LOCATION) == PackageManager.PERMISSION_GRANTED) {
                for (int i=0; i < ARRAY_SIZE; i++){
                    addGeofence(latLngArray[i], GEOFENCE_RADIUS, Integer.toString(i));
                }
            }
            } else {
                if (ActivityCompat.shouldShowRequestPermissionRationale(this, Manifest.permission.ACCESS_BACKGROUND_LOCATION)) {
                    //We show a dialog and ask for permission
                    ActivityCompat.requestPermissions(this, new String[] {Manifest.permission.ACCESS_BACKGROUND_LOCATION}, BACKGROUND_LOCATION_ACCESS_REQUEST_CODE);
                } else {
                    ActivityCompat.requestPermissions(this, new String[] {Manifest.permission.ACCESS_BACKGROUND_LOCATION}, BACKGROUND_LOCATION_ACCESS_REQUEST_CODE);
                }
            }

    }

     private void addGeofence(LatLng latLng, float radius, String id){
        Geofence geofence = GeofenceHelper.getGeofence(id, latLng, radius, Geofence.GEOFENCE_TRANSITION_ENTER);
        GeofencingRequest geofencingRequest = geofenceHelper.getGeofencingRequest(geofence);
        PendingIntent pendingIntent = geofenceHelper.getPendingIntent();
        if (ContextCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED) {
            geofencingClient.addGeofences(geofencingRequest, pendingIntent)
                    .addOnSuccessListener(new OnSuccessListener<Void>() {
                        @Override
                        public void onSuccess(Void aVoid) {
                            Log.d(TAG, "onSuccess: Geofence Added...");
                        }
                    })
            .addOnFailureListener(new OnFailureListener() {
                @Override
                public void onFailure(@NonNull Exception e) {
                    String errorMessage = GeofenceHelper.getErrorString(e);
                    Log.d(TAG, "onFailure: " + errorMessage);
                }
            });
        }
    }

GeofenceHelper.class

public class GeofenceHelper extends ContextWrapper {

    private static final int loiteringDelay = 0;

    private static final String TAG = "GeofenceHelper";
    PendingIntent pendingIntent;


    public GeofenceHelper(Context base) {
        super(base);
    }

    public GeofencingRequest getGeofencingRequest(Geofence geofence){

        return new GeofencingRequest.Builder()
                .addGeofence(geofence)
                .setInitialTrigger(GeofencingRequest.INITIAL_TRIGGER_ENTER)
                .build();
    }

    public static Geofence getGeofence(String ID, LatLng latLng, float radius, int transitionTypes){
        return new Geofence.Builder()
                .setCircularRegion(latLng.latitude, latLng.longitude, radius)
                .setRequestId(ID)
                .setTransitionTypes(transitionTypes)
                .setLoiteringDelay(loiteringDelay)
                .setExpirationDuration(Geofence.NEVER_EXPIRE)
                .build();
    }

    public PendingIntent getPendingIntent(){
        if(pendingIntent != null){
            return pendingIntent;
        }
        Intent intent = new Intent(this, GeofenceBroadcastReceiver.class);
        pendingIntent = PendingIntent.getBroadcast(this, 956, intent, PendingIntent.FLAG_UPDATE_CURRENT);

        return pendingIntent;
    }

    public static String getErrorString(Exception e) {
        if (e instanceof ApiException) {
            ApiException apiException = (ApiException) e;
            switch (apiException.getStatusCode()) {
                case GeofenceStatusCodes
                        .GEOFENCE_NOT_AVAILABLE:
                    return "GEOFENCE_NOT_AVAILABLE";
                case GeofenceStatusCodes
                        .GEOFENCE_TOO_MANY_GEOFENCES:
                    return "GEOFENCE_TOO_MANY_GEOFENCES";
                case GeofenceStatusCodes
                        .GEOFENCE_TOO_MANY_PENDING_INTENTS:
                    return "GEOFENCE_TOO_MANY_PENDING_INTENTS";
            }
        }
        return e.getLocalizedMessage();
    }
}

GeofenceBroadcastReciever.class

public class GeofenceBroadcastReceiver extends BroadcastReceiver {
    private static final String TAG = "GeofenceBroadcastReceiv";

    //MediaPlayer mediaPlayer;

    @Override
    public void onReceive(Context context, Intent intent) {
        // an Intent broadcast.


        GeofencingEvent geofencingEvent = GeofencingEvent.fromIntent(intent);

        if (geofencingEvent.hasError()) {
            Log.d(TAG, "onReceive: Error receiving geofence event...");
            return;
        };


        List<Geofence> geofenceList = geofencingEvent.getTriggeringGeofences();
        String id = geofenceList.get(0).getRequestId();

        switch (id){
            case "0":
                Toast.makeText(context, "Geofence " + id + " triggered.", Toast.LENGTH_SHORT).show();
            case "1":
                Toast.makeText(context, "Geofence " + id + " triggered.", Toast.LENGTH_SHORT).show();
            case "2":
                Toast.makeText(context, "Geofence " + id + " triggered.", Toast.LENGTH_SHORT).show();
            case "3":
                Toast.makeText(context, "Geofence " + id + " triggered.", Toast.LENGTH_SHORT).show();
            case "4":
                Toast.makeText(context, "Geofence " + id + " triggered.", Toast.LENGTH_SHORT).show();
            case "5":
                Toast.makeText(context, "Geofence " + id + " triggered.", Toast.LENGTH_SHORT).show();
        }

    }
}

Solution

  • MediaPlayer need context Well you can pass a context to the broadcast receiver. I assume (because you have not shown it) that you register your broadcast receiver in an Activity or App which are contexts. Multiple solutions:

    1. Your broadcast receiver can be an inner class of your activity or an anonymous class, in both cases the broadcast receiver would have a reference to the wrapping class (MapsActivity.this).
    2. Pass the Context as a constructor parameter to your broadcast receiver. Useful when you want it to be a top-class and reuse it on multiple places.
    3. Pass a callback (some FunctionalInterface, f.e. Consumer<Integer> onCheckpointReached) in the constructor of the broadcast receiver.

    As per accessing the specific track dynamically, you should not use such a switch but get a resource dynamically, the exact solution (with sounds even!) is here: https://stackoverflow.com/a/7182576/9274948


    Side note: your switch (apiException.getStatusCode()) { does not make much sense, just use apiException.getStatusCode().name() or apiException.getStatusCode().toString().