The core feature of the Sygic Android SDK 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 MapFragment and MapView. The MapFragment is a standard Android Fragment derived component. MapView is a class for controlling the displayed map. To obtain an instance of MapView you call asynchronous MapFragment.getMapAsync():

mapFragment.getMapAsync(new OnMapInitListener() {
    @Override
    public void onMapReady(final MapView mapView) {
        // now you can use returned MapView
    }

    @Override
    public void onMapError(final @MapError int errorCode, final String message) {}
});

Once the map is ready, you get the MapView also synchronously with MapFragment.getMapView(). For example, the following code snippet illustrates how to render the Map at London, UK:

// get MapView
MapView map = mapFragment.getMapView();

// Set the map center to London, UK.
map.getCamera().setPosition(new GeoCoordinates(51.509865, -0.118092));

To enable online maps, call OnlineManager.getInstance().enableOnlineMapStreaming(true). To display map offline, see Offline Maps

In the preceding code the GeoCoordinates for the map center is created by a call to the new GeoCoordinates(double, double) constructor.

Map Handling

Once the MapView is initialized, it can be manipulated and interacted in a variety of ways. Some key attributes of the MapView are its orientation, tilt, geographical center (geoCenter), and zoom level (zoom). You can use these to customize the displayed map via the Camera class.

Zoom Level

The size of the geographical area displayed by Map can be controlled by changing the zoom level.

// Set the zoom to for example 18.5.
map.getCamera().setZoomLevel(18.5f);

// Get the zoom level, should be 18.5.
float zoom = map.getCamera().getZoomLevel();

Rotation

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

// Rotate 180 degrees.
map.getCamera().setRotation(180);

// Get the rotation, should be 180.
float rotation = map.getCamera().getRotation();

Tilt

The map can be tilted and rendered in a three-dimensional perspective. By default, the tilt is completely flat.

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

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

Camera modes

You can set Camera to change position or rotation automatically with setting appropriate mode:

map.getCamera().setCameraMovementMode(Camera.MovementMode.FollowGpsPosition);
map.getCamera().setCameraRotationMode(Camera.RotationMode.Attitude);
Tilt used to display 3D or 2D mode

Camera listeners

If you want to be notifies about certain events, you can simply add camera listeners this way:

map.getCamera().addModeChangedListener(new Camera.ModeChangedListener() {
    @Override
    public void onMovementModeChanged(@Camera.MovementMode int mode) {
        switch (mode) {
            case Camera.MovementMode.Free:
            case Camera.MovementMode.FollowGpsPosition:
            case Camera.MovementMode.FollowGpsPositionWithAutozoom:
                //do stuff
        }
    }

    @Override
    public void onRotationModeChanged(@Camera.RotationMode int mode) {
        switch (mode) {
            case Camera.RotationMode.Free:
            case Camera.RotationMode.NorthUp:
            case Camera.RotationMode.Attitude:
            case Camera.RotationMode.Vehicle:
                //do stuff
        }
    }
});

or

map.getCamera().addPositionChangedListener(new Camera.PositionChangedListener() {
    @Override
    public void onPositionChanged(final GeoCoordinates geoCenter, final float zoom, final float rotation, final float tilt) {
        //do you stuff here
    }

    @Override
    public void onPositionChangeCompleted() {

    }
});

If you no longer need listeners (eg OnDestroy), don't forget to unregister the listeners as well:

map.getCamera().removeModeChangedListener(this);
map.getCamera().removePositionChangedListener(this);

Default map click handling

Touches on map are handled internally by MapFragment. If you want to perform an action on click (like displaying context menu, bubble over map, etc...) you have to register MapGestureListener. We also provide the MapGestureAdapter class, that provides default implementations, so you can override only those methods you need.

MapView map = mapFragment.getMapView();
map.addMapGestureListener(new MapGestureAdapter() {

    @Override
    public boolean onMapClicked(final MotionEvent e, final boolean isTwoFingers) {
        // do something...
        return true;
    }
});

This will override only onMapClicked() method. Calling true as return value will prevent delegating onMapClick to SDK. Then you can get the tapped map GeoCoordinates,

final MapView map = mapFragment.getMapView();
GeoCoordinates get = map.geoCoordinatesFromPoint(x, y);

where {x, y} are screen coordinates of point inside of the MapFragment (obtained for example from MotionEvent.getX() and getY()).

Initial map state

By default, the map will show whole globe after initialization. If you wish to change this, it can be done via xml styleable attributes of SygicSdkMapFragment.

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <fragment
        android:id="@+id/mapFragment"
        class="com.sygic.sdk.map.MapFragment"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        app:sygic_sdk_initial_latitude="40.730655"
        app:sygic_sdk_initial_longitude="-73.997437"
        app:sygic_sdk_initial_zoom="0.15"/>
</LinearLayout>

If you are adding fragment dynamically in code, you can use factory method MapFragment.newInstance() and pass it your wanted initial CameraState.

final CameraState.Builder cameraState = new CameraState.Builder();
cameraState.setPosition(new GeoCoordinates(40.730655, -73.997437));
cameraState.setZoomLevel(18.5f);
MapFragment.newInstance(cameraState.build());

Map Schemes

There are some map schemes available to offer your application users a choice among different kinds of map appearance. The list of available schemes can be obtained by:

final List<String> availableSkins = map.getAvailableSkins();

Some of the options are "default", "day", "night", "car", "pedestrian". Schemes can be combined, as they are only incremental. More info on scheme configuration and possibility to create own schemes is coming soon.

map.setActiveSkin(Arrays.asList("day", "pedestrian", "default"));
Day skin Night Skin

Sygic SDK does not automatically switch map schemes during navigation mode. Before starting car or pedestrian navigation, be sure to save the current map scheme and switch to the appropriate navigation map scheme.

Gestures

The MapView class responds to a number of predefined touch gestures. The default behavior of the map for each gesture type may be used as-is, supplemented, or replaced entirely. The following table is a summary of the available gestures and their default behavior.

Gesture Description Following gestures
Rotate Rotate: Two-finger press, simultaneously orbit both fingers around the center point, lift Pinch, Spread, Move
Zoom out Pinch: Two-finger press, move inwards, lift Spread, Rotate, Move
Zoom in Spread: Two-finger press, move outwards, lift
Move Swipe: One-finger press, move, lift/don't lift
Tilt Tilt: Two fingers press, move up (increase the tilt angle) or move down (decrease the tilt angle)
Short touch Short touch: One-finger press, lift

Map input like map dragging, map rotation, map tilt, map zoom is handled internally by MapFragment. However you can override default behavior by setting your own listener:

MapView map = mapFragment.getMapView();
map.addMapGestureListener(new MapGestureAdapter() {
    @Override
    public boolean onMapMove(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) {
        // do something...
        return true;
    }
});

Set return value true if the listener has consumed the event, false otherwise. If false is returned, default gesture action will be executed.

Objects and Interaction

The Sygic Mobile SDK allows the addition of a variety of objects, each with a specific purpose, to a map view. The types of available object include map markers, routes, polylines, circles. To see all the objects check the MapObject.MapObjectType. Some objects are described in more detail below.

In order to display the map object on the map, the object needs to be added to an MapView by calling addMapObject().

MapCircle

Enables you to draw a circle on the map at a fixed geographical location. You can customize you circle's color, radius, lineColor - see the MapCircle API reference for more information.

MapCircle circle = new MapCircle(new GeoCoordinates(51.509865, -0.118092), 200);
map.addMapObject(circle);

// removing
map.removeMapObject(circle);
Circle

MapPolyline

Enables you can draw one or more connected line segments on the map. The segment vertices are specified by a series of GeoCoordinates. The visual appearance of the polyline can be also customized. See the MapPolyline API reference for more information.

MapPolyline polyline = new MapPolyline(Arrays.asList(
        new GeoCoordinates(51.509, -0.118),
        new GeoCoordinates(51.524, -0.137),
        new GeoCoordinates(51.572, -0.092)));
map.addMapObject(polyline);

// removing
map.removeMapObject(polyline);
Polyline

MapMarker

With Sygic Mobile SDK you can display a icon at a fixed geographical position on the map.

MapMarker marker = new MapMarker(new GeoCoordinates(51.509865, -0.118092));
map.addMapObject(marker);

// removing
map.removeMapObject(marker);
Marker

You can also provide your own image by using BitmapFactory class. Sdk provides two factories for creating markers from Bitmap or Drawable.

MapMarker marker1 = new MapMarker(new GeoCoordinates(51.509865, -0.118092), new DrawableFactory(R.drawable.ic_marker));

Bitmap bitmap = getBitmap();
MapMarker marker2 = new MapMarker(new GeoCoordinates(51.515436, -0.122045), new SimpleBitmapFactory(bitmap));

Requesting objects from map

To query what objects are displayed on map, you can call method MapView.requestObjectsAtPoint(). You can for example use point returned from onMapClicked().

mapView.addMapGestureListener(new MapGestureAdapter() {
    @Override
    public boolean onMapClicked(final MotionEvent e, final boolean isTwoFingers) {
        mapView.requestObjectsAtPoint(e.getX(), e.getY(), new RequestObjectCallback() {
            @Override
            public void onRequestResult(@NonNull final List<ViewObject> objects, final float x, final float y) {

            }
        });

        return true;
    }
});

In the objects parameter there will be a list of objects, as multiple objects can be displayed in the same area. They can have following types:

ScreenObject

This is the very basic object that will be returned from every call to requestObjectsAtPoint(). Has only GeoCoordinates, that can be retrieved with getPosition() call.

MapObjects

This can be any object mentioned previously in Objects and Interaction that was added to map.

ProxyObjects

These are objects rendered by map, such as Points Of Interests (ProxyPoi) or cities (ProxyCity). Additional information about POIs can be loaded via Places.loadPoiObject():

new Places().loadPoiObject(proxyPoi, new Places.PoiObjectListener() {
    @Override
    public void onPoiObjectLoaded(final PoiObject poiObject) {
        PoiInfo poiInfo = poiObject.getPoiInfo();
        @PoiInfo.PoiCategory int category = poiInfo.getCategory();
        String name = poiInfo.getName();

        Map<Integer, List<String>> locationData = poiObject.getLocationInfo().getLocationData();
        List<String> urls = locationData.get(LocationInfo.LocationType.Url);
        List<String> openingHours = locationData.get(LocationInfo.LocationType.OpenHours);
    }
});

Offline Maps

Applications developed with the Sygic Android SDK have the ability to pre-load map data, allowing the use of maps, search, routing, and other features without an active data connection. To download any map, a MapEntry object must be obtained, via listing of continents and maps for continent.

First you have to add MapListListener to MapDownload object:

mMapListListener = new MapListListener() {
    @Override
    public void onContinentList(@NonNull final List<ContinentEntry> list, @NonNull final OperationStatus operationStatus) {

    }

    @Override
    public void onMapList(@NonNull final List<MapEntry> list, @NonNull final OperationStatus operationStatus) {

    }
};

mMapDownload = new MapDownload();
mMapDownload.addMapDownloadListener(mMapListListener);

Then you can query for continents

mMapDownload.loadContinentList();

ContinentEntry objects returned in onContinentList() method can be used for getting list of maps

mMapDownload.loadMapList(continentEntry);

Map installation

Installing or uninstalling maps is done using MapEntry obtained from list of map returned via MapListListener.

mMapDownload.installMap(mapEntry);

If you want information about installation progress and result, you can register MapInstallListener.

mMapInstallListener = new MapInstallListener() {
    @Override
    public void onMapInstallProgress(@NonNull final MapEntry mapEntry, final long downloadedBytes, final long totalBytes) {

    }

    @Override
    public void onMapInstallFinished(@NonNull final MapEntry mapEntry, @NonNull final OperationStatus status) {

    }

    @Override
    public void onMapUninstallFinished(@NonNull final MapEntry mapEntry, @NonNull final OperationStatus status) {

    }

    @Override
    public void onMapUpdateCheckFinished(@NonNull final List<MapEntry> list, @NonNull final OperationStatus status) {

    }

    @Override
    public void onMapUpdateResult(@NonNull final OperationStatus status) {

    }
};

mMapDownload.addMapInstallationListener(mMapInstallListener);

If you want to remove map listener, you can do it like this:

mMapDownload.removeMapDownloadListener(mMapListListener);
mMapDownload.removeMapInstallationListener(mMapInstallListener);