HERE Android SDK Developer's Guide

Street-Level Imagery

The HERE Android SDK allows application developers to offer users panoramic street-level imagery for many cities.

Street-level imagery is a collection of interconnected 360-degree panoramas. You can navigate from one panorama to another by tapping on links that appear on-screen as arrows pointing in various navigable directions.

Figure 1. Street-level imagery at San Francisco

The key concepts covered in this section include:

  • how to display the street-level coverage on a map
  • how to display the street-level imagery in an Android application
  • how to select the displayed street-level location
  • how to add, remove and interact with components of the street-level scene

The street-level imagery APIs follow a similar design as the mapping classes: StreetLevelFragment acts as a View, and StreetLevelModel act as a Model in a Model-View-Controller (MVC) pattern. You can create a controller class to coordinate interactions using custom logic.

Coverage

Street-level imagery is available in more than ninety cities. To display the street-level imagery coverage area on a map, the Map.setStreetLevelCoverageVisible(boolean) method from the com.here.android.mpa.mapping.Map class can be used as described in the code snippet below. The area where the imagery is available is highlighted on the map.

//Assume that map is instantiated
map.setStreetLevelCoverageVisible(true);
Figure 2. Map of San Francisco

Using Street-level Imagery

This section describes how to enhance an application by displaying the appropriate street-level imagery when a user taps on a location on a map. Map data for a specified location must be already downloaded and available before the imagery is requested for that location. This is achieved by displaying the map for that location first, or by pre-downloading the map data for that region.

The first step to integrate street-level imagery into an application is to insert a StreetLevelFragment into a view layout. This is accomplished by adding com.here.android.mpa.streetlevel.StreetLevelFragment to the Android XML layout file as per the following example. StreetLevelFragment is a standard Android Fragment-derived component that enables the display and gesture interactions with street-level scenes.


<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
  android:id="@+id/streetlevel_layout"
  android:layout_width="match_parent"
  android:layout_height="match_parent"
  android:orientation="vertical">

  <fragment
    class="com.here.android.mpa.streetlevel.StreetLevelFragment"
    android:id="@+id/streetlevelfragment"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:layout_weight="1"/>
  ...
</LinearLayout>

After adding a StreetLevelFragment to the layout, the fragment must be initialized by calling the function StreetLevelFragment.init(OnEngineInitListener). During initialization, a default StreetLevelModel is created and associated to the street-level fragment. Street-level imagery can be enhanced by displaying an arrow to show the possible navigation directions. This is achieved by adding an image (for example: an arrow) to the street-level model and making it visible, as shown below:


...
streetLevelFragment = (StreetLevelFragment) getFragmentManager()
    .findFragmentById(R.id.streetlevelfragment);
streetLevelFragment.init(new OnEngineInitListener() {
  @Override
  public void onEngineInitializationCompleted(OnEngineInitListener.Error error) {
    if (error == OnEngineInitListener.Error.NONE) {
      com.here.android.mpa.common.Image arrow = new com.here.android.mpa.common.Image();
      try {
        arrow.setImageResource(R.drawable.panoarrow);
      } catch (IOException e) {
        //handle error
        e.printStackTrace();
      }
      streetLevelFragment.getStreetLevelModel().setNavigationArrow(arrow);
      streetLevelFragment.getStreetLevelModel()
          .setNavigationArrowVisible(true);
      streetLevelFragment.getStreetLevelModel().setOverlayTransparency(
          0.5f);
    }
  }
});
...

The logic required to launch street-level imagery for a particular user-selected map location is illustrated in the following MapGesture.OnGestureListener.onTapEvent(PointF p) method. First, the street-level scene for the specified location is retrieved by calling the StreetLevelModel.getStreetLevel(GeoCoordinate center,int searchRadius) method. This method searches for the street level that is closest to the specified coordinate. The search area around the coordinate is defined by the searchRadius which is expressed in meters. The street-level imagery for the specified location is then rendered by calling StreetLevelModel.moveTo(StreetLevel streetLevel, boolean animation, float heading, float pitch, float zoom).


// Map event listener
 private MapGesture.OnGestureListener mapGestureListener =
   new MapGesture.OnGestureListener() {
    ...
    @Override
    public boolean onTapEvent(PointF p) {
        final StreetLevelFragment streetLevelFragment =
          (StreetLevelFragment) getFragmentManager()
            .findFragmentById(R.id.streetlevelfragment);
        if (streetLevelFragment.getStreetLevelModel() != null) {
          GeoCoordinate coordinate = map.pixelToGeo(p);
          // Get street level meta data
          StreetLevel level =
            streetLevelFragment.getStreetLevelModel()
              .getStreetLevel(coordinate, 100);
          if (level != null) {
            // Render street level imagery
            streetLevelFragment.getStreetLevelModel().moveTo(
              level, false, map.getOrientation(), 0, 1.0f);
          }
        }
        return false;
    }
    ...
};

Using Gestures in a Street-level Scene

Street-level imagery supports the following default gestures:
  • Rotate: Pan the Street-level view to rotate or change the pitch
  • Pinch/Spread to Zoom: Zoom out or zoom in by respectively, pinching or spreading two fingers being held on the screen
  • Single Tap: Select and highlight the object tapped
  • Double Tap: Move to a new location with the center in the vicinity of where the screen was tapped.
The StreetLevelGesture class allows an app to enable, disable, and handle gestures in a street-level scene. StreetLevelGesture is used in a similar manner as the MapGesture class. To use it, call StreetLevelFragment.getStreetLevelGesture() to retrieve the associated object instance, then use setter methods (such as setPinchEnabled(false)) to disable any unwanted gestures.
Note: By default, rotation, pinch, single-tap and double-tap are enabled in StreetLevelGesture.
As with MapGesture.OnGestureListener, you can add custom logic to handle street-level gestures by implementing StreetLevelGesture.OnGestureListener. The OnGestureListener class contains methods such as onPinchZoom that are called when a user performs the particular gesture. As with MapGesture.OnGestureListener, you can allow or prevent the default gesture behavior to be performed after your implemented callback by returning a boolean value.

private StreetLevelGesture.OnGestureListener myStreetLevelGestureListener =
    new StreetLevelGesture.OnGestureListener() {
  ...
  @Override
  public boolean onObjectsSelected(List<StreetLevelSelectedObject> selectedObjects) {
    boolean consumed = false;

    for (StreetLevelSelectedObject o : selectedObjects) {
      if (o != null) {
        ViewObject vo = (ViewObject) o.getObject();
        if (vo instanceof StreetLevelBuilding) {
          StreetLevelBuilding b = (StreetLevelBuilding) vo;
          b.setHighlight(0.5f);

          consumed = true;
          break;
        }
      }
    }
    return consumed;
  }
  ...
  // implement the other gesture callbacks
}
To add the listener to your street-level view, include a call to addOnGestureListener(StreetLevelGesture.OnGestureListener) after the street-level fragment has been successfully initialized as follows:

...
streetLevelFragment.init(new OnEngineInitListener() {
  @Override
  public void onEngineInitializationCompleted(OnEngineInitListener.Error error) {
    if (error == OnEngineInitListener.Error.NONE) {
      // fragment has been successfully initialized
      if (streetLevelFragment.getStreetLevelGesture() != null) {
        streetLevelFragment.getStreetLevelGesture().addOnGestureListener(
            myStreetLevelGestureListener);
      }
    }
  }
});
...
Note: Remember to call removeOnGestureListener(OnGestureListener) when you no longer need to listen for street-level gesture events to free up application resources.

OnEventListener Interface

The StreetLevelModel.OnEventListener interface represents a listener to provide notification upon completion of a StreetLevel event such as user interaction with a street-level object. Relevant StreetLevelModel methods that control adding and removing this kind of listener include:

  • StreetLevelModel.addStreetLevelModelListener(OnEventListener);
  • StreetLevelModel.removeStreetLevelModelListener(OnEventListener)

Registration of the OnEventListener should be performed after the StreetLevelFragment is initialized as described in the code snippet below.


...
streetLevelFragment = (StreetLevelFragment) getFragmentManager().findFragmentById(
    R.id.streetlevelfragment);
streetLevelFragment.init(new FragmentInitListener() {
  @Override
  public void onFragmentInitializationCompleted(InitError error) {
    if (error == InitError.NONE) {
      StreetLevelModel model =
        streetLevelFragment.getStreetLevelModel();
      if (model != null) {
        model.addStreetLevelModelListener(onEventListener);
      }
    ...
    }
  }
});
...

Removing the street-level listener can be performed as described in the code snippet below.


...
StreetLevelFragment streetLevelFragment =
      (StreetLevelFragment) getFragmentManager()
        .findFragmentById(R.id.streetlevelfragment);
streetLevelFragment.getStreetLevelModel()
  .removeStreetLevelModelListener(onEventListener);
...

Compass Map

By default, a circular map view called a Compass Map is presented with street-level imagery. Users can view it by panning a street-level view downward towards the ground. Compass Map provides users with their direction and location context while they are viewing the street-level scene. Users cannot directly manipulate a Compass Map, but changes from panning or navigating the street-level imagery are immediately reflected in it.

To disable the Compass Map, use the setCompassMapVisible(boolean) method in StreetLevelModel.

You cannot use this account to purchase a commercial plan on Developer Portal, as it is already associated to plans with different payment methods.

To purchase a commercial plan on Developer Portal, please register for or sign in with a different HERE Account.

Something took longer than expected.

The project should be available soon under your projects page.

Sorry, our services are not available in this region.

Something seems to have gone wrong. Please try again later.

We've detected that your account is set to Australian Dollars (AUD).
Unfortunately, we do not offer checkouts in AUD anymore.
You can continue using your current plan as normal, but to subscribe to one of our new plans,
please register for a new HERE account or contact us for billing questions on selfservesupport@here.com.