3

The "Google Maps" app in Jellybean has an indicator which adjusts based on the way you're facing. I am interested in implementing a similar indicator but for multiple indicators.

Does anyone have an idea on how they implemented their heading indicator (note it maintains its heading even when the map is rotated). I attempted my own approach using markers, then I realized that markers will not rotate with the map (kind of an oh duh moment after a few hours of labor...)

To summarize: How do I implement an icon in google maps that rotates based on heading, and not the map.

So as of right now I see two solutions:

  • Capture map rotation and transfer it to the marker
  • Draw over the map using OpenGL

Could anyone offer any advice before I start down another rabbit hole? Thanks!

Constantin
  • 16,812
  • 9
  • 34
  • 52

3 Answers3

2

There are a couple things you can do if you want to show orientation on a map.

Here are all of the imports that are used:

import com.google.android.gms.maps.model.CameraPosition;
import com.google.android.gms.maps.CameraUpdateFactory;
import com.google.android.gms.maps.GoogleMap;

1.Move the map so that the bearing is on top.

private final GoogleMap mMap;

//Get the current position from the map
CameraPosition camPosition = mMap.getCameraPosition();

//Update only the orientation/bearing, get all of the other values from the existing position.
CameraPosition newPos = new CameraPosition(
   camPosition.target,
   camPosition.zoom,        
   camPosition.tilt,
   azimuthInDegress);

//Set the position so that the map will update. The desired heading should not be on top
mMap.moveCamera(CameraUpdateFactory.newCameraPosition(newPos));

The problem with this idea is that if you don't stabilize your orientation updates, the map will move all over the place.

2.Implement a LocationSource

Google maps give you the ability to override it's location provider. First you'll want to implement a new Location source:

import android.app.Activity;
import android.content.Context;
import android.location.Location;
import android.location.LocationListener;
import android.location.LocationManager;
import android.os.Bundle;
import com.google.android.gms.maps.GoogleMap;
import com.google.android.gms.maps.LocationSource;
import com.google.android.gms.maps.MapFragment;


public class LocationSourceImplActivity extends Activity {


@Override
protected void onCreate(Bundle savedInstanceState) {

    super.onCreate(savedInstanceState);

    //Assume using the example from Google
    GoogleMap map = ((MapFragment) getFragmentManager()
            .findFragmentById(R.id.map)).getMap();

    map.setMyLocationEnabled(true);

    LocationManager locManager = (LocationManager) getSystemService(Context.LOCATION_SERVICE);

    map.setLocationSource(new LocationSourceImpl(locManager));
}

    /**
    *The Goal of this class is to listen for both location and heading updates 
    *and combine these into a single update, which will be passed to Google Maps.
    */ 
private class LocationSourceImpl implements LocationSource, LocationListener {

    private OnLocationChangedListener mListener = null;
    private Location mLastLoc = null;
    //Use your desired location provider. You can also update this class to better
    //determine when and how to register
    private static final String PREF_LOC_SRC ="";
    private final LocationManager mLocationManager;
    private float mLastHeading = Float.MAX_VALUE;


    public LocationSourceImpl(LocationManager pLocManager) {
        mLocationManager = pLocManager;

        //Get all updates, modify as desired. 
        mLocationManager.requestLocationUpdates(PREF_LOC_SRC, 0, 0, this);
    }

    @Override
    public void onLocationChanged(Location location) {
        mLastLoc = location;
        notifyListener();
    }

    private void notifyListener() {

        if(mListener != null && mLastLoc!=null) {

            if(mLastHeading != Float.MAX_VALUE) {
                mLastLoc.setBearing(mLastHeading);
            }

            //The listener will be the maps: 
            mListener.onLocationChanged(mLastLoc);

        }

    }

    @Override
    public void activate(OnLocationChangedListener pListener) {
                    //When the setLocationSource is called on the map, the map
                    //will be passed in as an OnLocationChangedListener (may not be the
                    //map, but may be a delegator created by the map. 
        mListener = pListener;
    }

    @Override
    public void deactivate() {
        mListener = null;

    }

    /**
     * This method can/should be replaced with a heading calculation
     * @param pDegrees
     *  Heading in degrees
     */
    public void updateHeadingInDegrees(float pDegrees) {
        mLastHeading = pDegrees;
        notifyListener();

    }

    @Override
    public void onProviderDisabled(String paramString) {

    }

    @Override
    public void onProviderEnabled(String paramString) {

    }

    @Override
    public void onStatusChanged(String paramString, int paramInt,
            Bundle paramBundle) {

    }

}

}

lordoku
  • 908
  • 8
  • 22
  • Here's where I found this information: https://developers.google.com/maps/documentation/android/reference/com/google/android/gms/maps/LocationSource – lordoku Nov 24 '13 at 10:04
0

this is done using the compass to get the direction you are facing based on the magnetic field. see here about the different sensors

http://developer.android.com/guide/topics/sensors/sensors_overview.html

tyczj
  • 71,600
  • 54
  • 194
  • 296
  • Hey ty thanks for your answer, I'm aware of the sensor, I was more interested in the implementation of the display though. – Constantin Sep 17 '13 at 19:59
  • ahh sorry i thought you wanted to know how they got the direction. WHat I would do for the drawing would be to create a framelayour over the map itself the same dimensions as the map and draw the point on there using the position from the map projection to pixels and just rotate the image based on the direction of the sensor. I have not really looked into doing that much so I dont know if there is an easier way – tyczj Sep 17 '13 at 20:09
  • ty I was thinking about that approach, but I am worried about efficiency. I expect to be drawing many of these icons. – Constantin Sep 17 '13 at 20:11
0

http://developer.android.com/reference/android/hardware/SensorManager.html#getOrientation(float[], float[])

Use this. This is implemented using the device's own sensor.

And as you want to know about view too, I think here is an example which would be helpful to you http://android-er.blogspot.in/2010/08/simple-compass-sensormanager-and.html

adarsh
  • 6,738
  • 4
  • 30
  • 52
  • Thank you adarsh, but I am interested in implementing this using google maps... however are you suggesting I overlay a fragment on the google maps ui? – Constantin Sep 17 '13 at 20:03
  • yes you could do that or even one more solution would be to overlay a png and rotate it, something like this? http://stackoverflow.com/questions/8543809/how-to-rotate-a-wheel-image-png-in-android or http://stackoverflow.com/questions/8981845/androidrotate-image-in-imageview-by-an-angle – adarsh Sep 17 '13 at 20:07
  • Interesting, but this is for a view, I am specifically interested for a Google Maps v2 API approach as I will have multiple icons. – Constantin Sep 17 '13 at 20:10
  • https://developers.google.com/maps/documentation/android/interactivity#compass does this look like what you're looking for? – adarsh Sep 17 '13 at 20:12