SDK for Android Developer's Guide

Maps

The core feature of SDK for Android is Maps. The key concepts covered in this section include adding a map to an Android application, changing the location displayed by the map and its various properties. The classes covered include AndroidXMapFragment and Map. AndroidXMapFragment and Map are parts of a Model-View-Controller (MVC) pattern where the Model is the Map, and the View is the AndroidXMapFragment. The AndroidXMapFragment is a standard Android Fragment derived component. You can create a controller class to coordinate all interactions using custom logic.

The first step to integrate a map into an application is to insert a AndroidXMapFragment to the view layout of the application. This is accomplished by adding com.here.android.mpa.mapping.AndroidXMapFragment to the Android XML layout file as follows.


<!-- Example fragment. This can be integrated and annotated
    like any other android Fragment or View widget -->
<fragment
  class="com.here.android.mpa.mapping.AndroidXMapFragment"
  android:id="@+id/mapfragment"
  android:layout_width="match_parent"
  android:layout_height="match_parent"/>

The AndroidXMapFragment class handles all user interactions such as panning, tapping or pinching, as well as other standard HERE SDK touch gestures documented in MapGestures.

Map Integration Examples on GitHub

You can find examples that demonstrate map integration in the Map Attributes and Map Rendering projects at https://github.com/heremaps/.

Initializing AndroidXMapFragment

After the AndroidXMapFragment is added to the layout, the fragment must be initialized. The AndroidXMapFragment initialization is processed asynchronously. During initialization the MapEngine is initialized to create an instance of Map that is associated with the AndroidXMapFragment. The AndroidXMapFragment.init(OnEngineInitListener) method takes in an OnEngineInitListener input parameter to signal the caller when initialization is completed and if it was successful. The AndroidXMapFragment also initializes a MapEngine instance and creates a Map object associated with the AndroidXMapFragment. The following code illustrates the basic initialization flow when an Activity is created.


@Override
public void onCreate(Bundle savedInstanceState) {
  super.onCreate(savedInstanceState);
  setContentView(R.layout.activity_main);
  // Search for the Map Fragment
  final AndroidXMapFragment mapFragment = (AndroidXMapFragment)
     getSupportFragmentManager().findFragmentById(R.id.mapfragment);
  // initialize the Map Fragment and
  // retrieve the map that is associated to the fragment
  mapFragment.init(new OnEngineInitListener() {
    @Override
    public void onEngineInitializationCompleted(
        OnEngineInitListener.Error error) {
      if (error == OnEngineInitListener.Error.NONE) {
        // now the map is ready to be used
        Map map = mapFragment.getMap();
        // ...
      } else {
        System.out.println("ERROR: Cannot initialize AndroidXMapFragment");
      }
    }
  });
}
Note: For performance reasons com.here.android.mpa.mapping.AndroidXMapFragment has set Fragment.setRetainInstance(boolean) to true, and therefore onCreate(Bundle) is not called again when Activity is re-created (for example, after a zoom-level change).
Note: The AndroidXMapFragment class provides an asynchronous method, getScreenCapture(OnScreenCaptureListener), for creating map snapshots of the currently visible AndroidXMapFragment area. When a snapshot has been created, an event callback to OnScreenCaptureListener occurs, and the screenshot is provided as an android.graphics.Bitmap object. This method of screen capture only works if the view is in the foreground and it is rendering. If a background or viewless screen capture is required, use MapOffscreenRenderer.

Working with Map

Once the AndroidXMapFragment is initialized, you get the Map associated with the AndroidXMapFragment through AndroidXMapFragment.getMap(). The Map class represents the virtual model of the world in a digital format. Key attributes of the Map include the center GeoCoordinate, zoom level, orientation, and tilt. For example, the following code snippet illustrates how to use Map.setCenter(GeoCoordinate, Map.Animation) to render the Map at Vancouver, Canada.


// map fragment has been successfully initialized
...

// now the map is ready to be used
Map map = mapFragment.getMap();

// Set the map center to Vancouver, Canada.
map.setCenter(new GeoCoordinate(49.196261,
  -123.004773), Map.Animation.NONE);
...

In the preceding code:

  • The GeoCoordinate for the map center is created by a call to the new GeoCoordinate(double, double) constructor.
  • When setting the center of a map, there is an option either to animate the change or to suppress animation by passing the constant Map.Animation.NONE as the relevant parameter.

Map Center, Tilt, Orientation, and Zoom

Here are examples of setting and getting Map attributes:

Map Center

The center of the Map is a GeoCoordinate location that your Map is focused on. You can move a Map by redefining its center GeoCoordinate:

// Move the map to London
map.setCenter(new GeoCoordinate(51.51,-0.11),
  Map.Animation.NONE);

// Get the current center of the Map
GeoCoordinate coordinate = map.getCenter();

Zoom Level

The size of geographical area displayed by Map can be controlled by changing the zoom level. The zoom level ranges from getMinZoomLevel() to getMaxZoomLevel(), with the minimum value displaying the entire world. The following code sets the zoom level to median.

// Get the maximum, minimum zoom level
double maxZoom = map.getMaxZoomLevel();
double minZoom = map.getMinZoomLevel();

// Set the zoom level to the median (10)
map.setZoomLevel((maxZoom + minZoom)/2);

// Get the zoom level back
double zoom = map.getZoomLevel();

Orientation

The map can be oriented in any direction. By default the orientation is in a true North position. The following code changes the orientation to South-up.

// Rotate 180 degrees
map.setOrientation(180);

// Get the orientation, should be 180
float orientation = map.getOrientation();

Tilt

The map can be tilted and rendered in a three-dimensional perspective. By default the tilt is completely flat. You can retrieve the minimum and maximum possible tilt values by calling getMinTilt() and getMaxTilt()

// Set the tilt to 45 degrees
map.setTilt(45);

// Get the tilt
float tilt = map.getTilt();

Animations

The map supports three types of animations when changing attributes:

  • Map.Animation.NONE
  • Map.Animation.LINEAR
  • Map.Animation.BOW

// Move to Vancouver using linear animation
map.setCenter(new GeoCoordinate(49.0,-123.0),
  Map.Animation.LINEAR);
Note: If the map changes size or the app comes to the foreground while Map.Animation.LINEAR or Map.Animation.BOW is being used in a Map attribute setter method, then the animation aborts, and the transition appears to fail. To avoid this behavior, use the Map.Animation.NONE animation type or wait until the map is stable before performing the transition operation.

Setting Multiple Attributes

Map.setCenter(GeoCoordinate point, Animation animation, double level, float orientation, float tilt) is an extended API provided for changing one or more attributes at the same time. The zoom level, tilt and perspective can be preserved and unchanged using Map.MOVE_PRESERVE_ZOOM_LEVEL, Map.MOVE_PRESERVE_ORIENTATION, Map.MOVE_PRESERVE_TILT respectively.

// Move to Vancouver using a bow animation, zoom level 17, 180
//degree orientation and 45 degree tilt
map.setCenter(new GeoCoordinate(49.0,-123.0),
  Map.Animation.BOW, 17.0d, 180, 45);

Map Projection Mode

By default the map is set to a globe projection mode. You can change it to use Mercator projection by calling setProjectionMode(Projection). For example:
map.setProjectionMode(Map.Projection.MERCATOR);
It may be useful to set the projection modes when you need to predictably display certain types of map information, such as custom raster tiles.
Figure 1. Globe Projection
Figure 2. Mercator Projection

MapState and Listening for Map Transform Events

MapState is an object that is a composite of the tilt, orientation, zoom level and center map attributes. Your application can listen for updates to the MapState by using an OnTransformListener.

Map transform events are triggered by any operation that causes the MapState to change. These operations include user interaction (for example, map gestures) as well as programmatic calls to the Map (for example, map.setCenter(GeoCoordinate, MapAnimation)). The onMapTransformStart() method is called before MapState begins to change, while the onMapTransformEnd(MapState) method is called after the MapState returns to a steady value. Because of this there can be a significant amount of time between the two callbacks in cases such as animated map movement events and continuous user interaction.

The following code is an example of registering an OnTransformListener to listen for map transform events:

map.addTransformListener(new OnTransformListener() {
  @Override
  public void onMapTransformStart() {
    // map transform is about to start
  }
  @Override
  public void onMapTransformEnd(MapState mapState) {
    // map transform has come to an end
  }
});
If you need to update UI widgets as the MapState changes between these two callbacks, the recommended approach is to trigger a Runnable when onMapTransformStart() is called, which periodically checks (at no more than 30 frames per second) the current map state via map.getMapState() and updates the UI widgets accordingly. This Runnable can then be canceled upon a call to onMapTransformEnd(MapState). An Android Handler can be used to trigger these Runnable objects.
Note: Do not update UI widgets in MapRenderListener.onPostDraw(boolean, long) as this method is frequently called.

Pedestrian Features

By default icons that indicate pedestrian access features (such as stairs or escalators) are not displayed on the map. To display a pedestrian feature on the map view, call the Map.setPedestrianFeaturesVisible(EnumSet) method with the desired set of PedestrianFeature. To find out whether a feature type is enabled, call the Map.getPedestrianFeaturesVisible() method.

Figure 3. Pedestrian Feature Icons

Safety Spots

Speed cameras and traffic-light cameras are also known as safety spots in HERE SDK. Similar to pedestrian features icons that indicate safety spots are not displayed on the map by default. To display safety spots, set the Map.setSafetySpotsVisible(boolean) to true. To find out whether safety spots are enabled, call the areSafetySpotsVisible() method.

Individual safety spots icons can be selected on the map by using SafetySpotObject, which is a subclass of MapProxyObject. Each SafetySpotObject contains a reference to a corresponding SafetySpotInfo object that contains the location and other properties about the camera. For more information on selecting map proxy objects refer to Objects and Interaction.