3

I have an Android application that has SupportMapFragment added on xml file. In fragment I set my location as follows: mMap.setMyLocationEnabled(true); to display my current location

The main issue is that the walking mode is enabled[blue dot] by default, I want free driving mode activated [blue arrow]

How can I achieve free driving mode? To have blue arrow as my position instead of blue dot

enter image description here

Machavity
  • 30,841
  • 27
  • 92
  • 100
Duna
  • 1,564
  • 1
  • 16
  • 36

1 Answers1

2

There is no Driving Mode for SupportMapFragment and no possibilities to change default My Location Marker, but you can:

1) launch Google Maps application in Driving mode via intent as in this answer of Jason Maderski:

Intent intent = getPackageManager().getLaunchIntentForPackage("com.google.android.apps.maps");
intent.setAction(Intent.ACTION_VIEW);
intent.setData(Uri.parse("google.navigation:/?free=1&mode=d&entry=fnls"));
startActivity(intent);

or

2) change custom current location indicator via custom marker on GoogleMap object like in that answer of antonio.

Because of unpredictability of LocationListener update I think better use NMEA data (RMC sentence) from GPS via GpsStatus.NmeaListener (OnNmeaMessageListener for API >= 24) for updating current location. In that case source code can be something like that:

CustomNmeaListener.java:

public class CustomNmeaListener implements GpsStatus.NmeaListener{

    private GoogleMap mGoogleMap;
    private Marker mMarkerPosition = null;
    private BitmapDescriptor mMarkerMoveDescriptor;
    private BitmapDescriptor mMarkerStopDescriptor;

    public CustomNmeaListener(GoogleMap googleMap, int markerMoveResource, int markerStopResource){
        this.mGoogleMap = googleMap;

        mMarkerMoveDescriptor = BitmapDescriptorFactory.fromResource(markerMoveResource);
        mMarkerStopDescriptor = BitmapDescriptorFactory.fromResource(markerStopResource);
    }

    @Override
    public void onNmeaReceived(long timestamp, String nmea) {
        double latitude;
        double longitude;
        float speed;
        float angle;

        // parse NMEA RMC sentence
        // Example $GPRMC,123519,A,4807.038,N,01131.000,E,022.4,084.4,230394,003.1,W*6A
        //   nmea    [0]   [1]  [2]  [3]   [4]   [5]   [6] [7]   [8]   [9]   [10]  [11]
        if (nmea.startsWith("$GPRMC")) {

            String[] nmeaParts = nmea.split(",");

            // if RMC data valid ("active")
            if (nmeaParts[2].equals("A")) {
                latitude = parseLatitude(nmeaParts[3], nmeaParts[4]);
                longitude = parseLongitude(nmeaParts[5], nmeaParts[6]);
                speed = parseSpeed(nmeaParts[7]);
                angle = parseAngle(nmeaParts[8]);

                // remove marker on "old" position
                if (mMarkerPosition != null) {
                    mMarkerPosition.remove();
                }

                MarkerOptions positionMarkerOptions;

                if (speed > 0) {
                    positionMarkerOptions = new MarkerOptions()
                            .position(new LatLng(latitude, longitude))
                            .icon(mMarkerMoveDescriptor)
                            .anchor(0.5f, 0.5f)
                            .rotation(angle);
                } else {
                    positionMarkerOptions = new MarkerOptions()
                            .position(new LatLng(latitude, longitude))
                            .icon(mMarkerStopDescriptor)
                            .anchor(0.5f, 0.5f)
                            .rotation(0);
                }
                mMarkerPosition = mGoogleMap.addMarker(positionMarkerOptions);
            }
        }

    }

    static float parseLatitude(String lat, String sign) {
        float latitude = Float.parseFloat(lat.substring(2)) / 60.0f;
        latitude +=  Float.parseFloat(lat.substring(0, 2));
        if(sign.startsWith("S")) {
            latitude = -latitude;
        }
        return latitude;
    }

    static float parseLongitude(String lon, String sign) {
        float longitude = Float.parseFloat(lon.substring(3)) / 60.0f;
        longitude +=  Float.parseFloat(lon.substring(0, 3));
        if(sign.startsWith("W")) {
            longitude = -longitude;
        }
        return longitude;
    }

    static float parseSpeed(String knots) {
        float speed;
        try {
            speed = Float.parseFloat(knots);
        } catch (Exception e) {
            speed = 0;
        }
        return speed;
    }

    static float parseAngle(String ang) {
        float angle;
        try {
            angle = Float.parseFloat(ang);
        } catch (Exception e) {
            angle = 0;
        }
        return angle;
    }
}

MainActivity.java:

public class MainActivity extends AppCompatActivity implements OnMapReadyCallback, LocationListener {

    private static final String TAG = MainActivity.class.getSimpleName();
    private static final int LOCATION_PERMISSION_REQUEST_CODE = 101;

    private static final int LOCATION_INTERVAL = 1000;
    private static final float LOCATION_DISTANCE = 10f;

    private GoogleMap mGoogleMap;
    private MapFragment mMapFragment;

    private LocationManager mLocationManager = null;
    private CustomNmeaListener mNmeaListener = null;


    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        mMapFragment = (MapFragment) getFragmentManager()
                .findFragmentById(R.id.map_fragment);
        mMapFragment.getMapAsync(this);

    }


    @Override
    public void onMapReady(GoogleMap googleMap) {
        mGoogleMap = googleMap;

        if (android.os.Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
            int locationPermission = ContextCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION);
            if (locationPermission != PackageManager.PERMISSION_GRANTED) {
                makeLocationPermissionRequest();
            } else {
                setCustomLocationListener();
            }
        } else {
            setCustomLocationListener();
        }
    }

    @Override
    public void onLocationChanged(Location location) {

    }

    @Override
    public void onStatusChanged(String s, int i, Bundle bundle) {

    }

    @Override
    public void onProviderEnabled(String s) {

    }

    @Override
    public void onProviderDisabled(String s) {

    }

    @Override
    public void onRequestPermissionsResult(int requestCode, String permissions[], int[] grantResults) {
        switch (requestCode) {
            case LOCATION_PERMISSION_REQUEST_CODE: {
                // If request is cancelled, the result arrays are empty.
                if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
                    setCustomLocationListener();
                } else {
                }
                return;
            }
        }
    }

    private void makeLocationPermissionRequest() {
        ActivityCompat.requestPermissions(this,
                new String[]{android.Manifest.permission.ACCESS_FINE_LOCATION}, LOCATION_PERMISSION_REQUEST_CODE);
    }

    private void setCustomLocationListener() {
        // disable "standard" location marker
        mGoogleMap.setMyLocationEnabled(false);

        initializeLocationManager();
        mNmeaListener = new CustomNmeaListener(mGoogleMap, R.drawable.ic_marker_move, R.drawable.ic_marker_stop);
        mLocationManager.addNmeaListener(mNmeaListener);

        try {
            mLocationManager.requestLocationUpdates(
                    LocationManager.GPS_PROVIDER,
                    LOCATION_INTERVAL,
                    LOCATION_DISTANCE,
                    this
            );
        } catch (java.lang.SecurityException ex) {
            Log.d(TAG, "fail to request location update, ignore", ex);
        }
    }

    private void initializeLocationManager() {
        Log.d(TAG, "initializeLocationManager - LOCATION_INTERVAL: "+ LOCATION_INTERVAL + " LOCATION_DISTANCE: " + LOCATION_DISTANCE);
        if (mLocationManager == null) {
            mLocationManager = (LocationManager) getApplicationContext().getSystemService(Context.LOCATION_SERVICE);
        }
    }

}

and R.drawable.ic_marker_move & R.drawable.ic_marker_stop - drawable resources like:

Marker for movement (speed > 0)

(North orientation is important)

and

Marker for movement (speed = 0)

respectively.

NB! This is a quick and dirty example without NMEA checksum test, GPS data filtering, saving and restoring marker position on Activity visible/hide, etc.

Jeffrey Chung
  • 19,319
  • 8
  • 34
  • 54
Andrii Omelchenko
  • 13,183
  • 12
  • 43
  • 79