HERE Android SDK Developer's Guide

Offline Maps (MapLoader)

Applications developed with the HERE iOS SDK have the ability to download map data, allowing the use of maps, search, routing, and other features without an active data connection. The two ways to get map data for offline use are headless API fetches and the Map Loader.

Headless Fetch

MapDataPrefetcher and MapDataPrefetcher.Listener Interfaces

Map data can be fetched into a persistent 256 MB cache to enable offline map capabilities by specifying an area defined by a bounding box or radius around a route. This can be done through the MapDataPrefetcher and associated classes. The MapDataPrefetcher provides a set of methods to initiate fetches, cancel fetches, and clear the map data cache:

  • cancelRequest(int requestId) - Cancel a specified fetch in progress
  • cancelAllRequests() – Cancel all fetches in progress
  • clearMapDataCache() – Clear any unused cached map data
  • fetchMapData(GeoBoundingBox area) - To initiate a fetch for map data in the specified bounding box.
  • fetchMapData(Route route, int radius) - To initiate a fetch for map data around a route in a specified radius.
  • addListener(Listener listener) - Add a listener to keep track of the progress for fetches and removal of map data.
  • removeListener(Listener listener) - Remove a listener to keep track of the progress for fetches and removal of map data.
Note: This is a beta feature and not recommended for deployment in applications to end users due to missing capability to check in advance the size of the data (e.g. in kBs) to be downloaded. This limitation will be addressed in a subsequent release.
Note: The MapDataPrefetcher will fetch a default set of map data types which depend on the capabilities of the SDK allowed by the license key.

MapDataPrefetcher is a singleton which can be obtained using the MapDataPrefetcher.getInstance() method. Note that com.here.android.mpa.mapping.MapEngine must be successfully initialized before this method can be used. The following code example shows basic MapDataPrefetcher use:

Start MapDataPrefetcher fetch:

GeoBoundingBox bbox = ...
MapDataPrefetcher.Request.Error error = MapDataPrefetcher .Request.Error.None;
MapDataPrefetcher.Request request = MapDataPrefetcher.getInstance( ).fetchMapData(bbox);
...

Cancel MapDataPrefetcher fetch:

MapDataPrefetcher.Request request = ...
MapDataPrefetcher.getInstance( ).cancelRequest(request.requestId);
...

MapDataPrefetcher operations are performed asynchronously. When available, the results of these operations are passed on to MapDataPrefetcher’s listeners. Listeners must implement the MapDataPrefetcher.Listener interface to receive notifications while fetches are progressing. Below is a code snippet on adding a listener to the MapDataPrefetcher:

MapDataPrefetcher.Listener mapDataPrefetcherListener = new MapDataPrefetcher.Listener( ) {
public void onProgress(final int requestId, final float progress) {
}
public void onStatus(final int requestId, final PrefetchStatus status) {
}
public void onCachePurged(final boolean success) {
}
};
MapDataPrefetcher.getInstance( ).addListener(mapDataPrefetcherListener);
Note: MapDataPrefetcher.Adapter is provided so implementations do not need to be provided for every single method for MapDataPrefetcher.Listener.

The MapDataPrefetcher.Listener.PrefetchStatus Enum

MapDataPrefetcher.Listener.PrefetchStatus is an enum data type, representing the status for MapDataPrefetcher fetch operations. The status is returned through the MapDataPrefetcher.Listener interface.

  • PREFETCH_IN_PROGRESS - MapDataPrefetcher fetch operation is still in progress.
  • PREFETCH_SUCCESS - MapDataPrefetcher fetch completed successfully.
  • PREFETCH_FAILURE - MapDataPrefetcher fetch operation had failed to complete.
  • PREFETCH_CANCELLED - MapDataPrefetcher fetch operation was cancelled.

The MapDataPrefetcher.Request.Error Enum

MapDataPrefetcher.Request.Error is an enum data type, representing any errors encountered when initiating a MapDataPrefetcher fetch operation.

  • NONE – No errors dispatching the request.
  • UNKNOWN – An unknown error has occurred submitting the request.
  • BUSY – The number of requests is at max capacity
  • INVALID_PARAMETERS – The request was invalid due to invalid parameters
  • OPERATION_NOT_ALLOWED – ODML permission is missing from the license.

It is recommended to check the network connectivity at the application level to ensure MapDataPrefetcher operations are only performed when the device has a connection.

The MapDataPrefetcher.Request

MapDataPrefetcher.Request is an object that is returned when a map data fetch is dispatched. It holds the ID of the request and a MapDataPrefetcher.Request.Error to indicate any errors that occurred.

Incremental Updates

For map data retrieved through the headless fetch APIs above, the map data will be updated as normal if there is an incremental update available. For the case that there is no incremental update available, the map data in the cache will be cleared. Map updates are managed by the Map Loader.

MapLoader

The second method of getting offline maps capabilities are enabled through the use of MapLoader and its associated objects. The MapLoader class provides a set of APIs that allow manipulation of the map data stored on the device. Operations include:

  • getMapPackages() - To retrieve the state of the map data on the device
  • installMapPackages(List<Integer> packageIdList) - To download and install new country or region data
  • uninstallMapPackages(List<Integer> packageIdList) - To uninstall and delete country or region data that is no longer desired
  • checkForMapDataUpdate() - To check whether a new map data version is available
  • performMapDataUpdate() - To perform a map data version update, if available
  • cancelCurrentOperation() - To cancel the running MapLoader operation

To use MapLoader, you must call MapLoader.getInstance() to retrieve a MapLoader object instance. Note that com.here.android.mpa.mapping.MapEngine must be successfully initialized before this method can be used.

MapLoader operations are performed asynchronously. Results of the various operations are returned by way of a MapLoader.Listener implementation that must be set to listen for notifications from the MapLoader as in the code snippet below:


MapLoader.Listener mapLoaderListener = new MapLoader.Listener() {
  public void onUninstallMapPackagesComplete(MapPackage rootMapPackage,
     MapLoader.ResultCode mapLoaderResultCode) {
  }
  public void onProgress(int progressPercentage) {
  }
  public void onPerformMapDataUpdateComplete(MapPackage rootMapPackage,
     MapLoader.ResultCode mapLoaderResultCode) {
  }
  public void onInstallationSize(long diskSize, long networkSize) {
  }
  public void onInstallMapPackagesComplete(MapPackage rootMapPackage,
      MapLoader.ResultCode mapLoaderResultCode) {
  }
  public void onGetMapPackagesComplete(MapPackage rootMapPackage,
      MapLoader.ResultCode mapLoaderResultCode) {
  }
  public void onCheckForUpdateComplete(boolean updateAvailable,
    String currentMapVersion,String newestMapVersion,
          MapLoader.ResultCode mapLoaderResultCode) {
  }
};

MapLoader mapLoader = MapLoader.getInstance();
mapLoader.addListener(mapLoaderListener);

Also, all operations of the MapLoader are mutually exclusive. For example, if method XYZ is called before the callback method ABC has returned a result, method XYZ returns false to indicate that the MapLoader is busy with another operation.

The MapPackage Class

The map data packages available for download are represented as a tree structure with the root map package representing the world map. The MapPackage class represents the model through which this tree structure is accessed. As shown in the preceding code snippet, many of the MapLoader.Listener callbacks returns the root MapPackage. The other MapPackage instances are accessed by recursing through the tree structure from the root.

The MapPackage state of a particular instance is not updated dynamically to reflect changes to map data on disk. Therefore if you retrieve MapPackage instance A, and then perform an installation operation (which returns MapPackage instance B through onInstallMapPackagesComplete()), MapPackage instance A does not reflect the updated map data state, but MapPackage instance B does. Therefore, always use the new MapPackage object returned by a given operation and update the representation in your application accordingly.

Note: The getSize() method returns the maximum install size of the map package, in kilobytes. If this is the first MapPackage to be installed, then the package takes up the same amount of memory storage as returned by this method. However, if other packages have already been installed, then the required disk space for this map package is considerably less than the value returned by getSize(), because common data between map packages does not need to be installed again. To get an accurate representation of the disk space that is used for a given installation operation, use the MapLoader.Listener.onInstallationSize(long, long) callback method.
Note: Map data packages may need to be reinstalled if the application crashes or is forced closed during MapLoader installation or uninstallation.

Incremental Map Data Updates

MapLoader exposes the ability to update the map data version to provide the user with the freshest map data available. The map data version applies not only to map data pre-installed using the MapLoader, but also to data that is retrieved dynamically by browing new areas.

Map data version is consistent for all map data across the entire system, whether the map data is downloaded or not. It is not possible to have some data from one map version and other data from another map version concurrent in the disk cache. Therefore, it is important to keep the map version of the system up to date. However, map version updating does not require re-downloading everything. Instead, only incremental changes need to be downloaded, making typical updates small and quick. Map version updating is exposed through the checkForMapDataUpdate() and performMapDataUpdate() methods.

Data Groups

Map packages are made up of several groups, each of which contains a different type of map data. Some of these groups may be selected or deselected before map packages are downloaded for offline use, depending on the needs of the application. The optional data groups are given in the SelectableDataGroup enum. To select or deselect a data group for download, pass the appropriate enum value to the NMAMapLoader.selectDataGroup(SelectableDataGroup) or deselectDataGroup(SelectableDataGroup) method.

Note: This feature can only be used with an isolated disk cache. For more information, see Embedding the Map Service.

The selected data groups of the map loader are used for all future installation operations. However, changes to the data group selection do not affect previously installed packages. To update these packages, call performMapDataUpdate() after changing the data group selection.

The default data group selection may not be optimal for some applications. To minimize disk space usage, it's recommended that any applications which allow offline map downloads ensure they are only downloading the required data groups.