Skip to content

01 First project

Overview

This tutorial will teach you the basics to create a project with the NavigationSDK in Android Studio. You will learn how to add the NavigationSDK as a project dependency, how to initialize the SDK correctly and which additional data you need to use the SDK.

  • docs (SDK documentation files)
    • javadoc (SDK Java wrapper API documentation)
  • maps (prepackaged map data)
  • sdcard (necessary data to run the tutorials)
  • sdk (NavigationSDK library)
  • tutorial (tutorial sources)
  • license.key (license key for the SDK)

Attention

You get a test license.key file with your copy of the NavigationSDK. This license file enables you to test the SDK until a specified date. Please contact PTV if your test license.key has expired.

Create your first NavigationSDK project

Please use com.ptvag.navigation.tutorial as the package name to be in sync with the data directory, we later will introduce. To create our first NavigationSDK project, you have to create a new Android Project with an empty Activity (Hint: Creating an Android Project).
Set the Target-SDK version to 22 to avoid problems in later tutorials with permission requests (Background: Android target versions > 22 will not grant permissions to any resources like GPS or network when the user not explicitly allows the permission. If you want to use a newer target version, please implement the user request in the corresponding tutorial for yourself).

To add the NavigationSDK to your project click on File > New > Import Module... in the Android Studio an select the navigationSDK folder from the sdk folder.

Now add the NavigationSDK module as a dependency to your app Module-level Build File. Add an implementation dependency to the dependencies section.

dependencies {
    implementation project(':navigationSDK')
}

Prepare the map data

Before we can use the SDK, your app needs some app data on the device. To get the directories where android allows us to put the map data, we edit the MainActivity.java:

public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        File dir = getExternalFilesDir(null);
        Log.v("Installation Folder", dir.getAbsolutePath());
    }
}

Run your application and have a look at the logcat output to get our data installation folder. It should look something like this:

/<device dependent part>/Android/data/<yourpackage>/files

Usually your Android system has already created this path during the first start of your application. Create three directories in this path on the device and copy your data there.

  • maps (copy your map data here)
    The maps directory is mandatory. All used maps must be copied to this folder. Copy only the files of the map folders, the maps directory does not accept subfolders. Deleting single files of a map will cause the SDK to not initialize, so be sure to always have complete maps consisting of many files with the same prefix.
  • addr (copy your POI data here)
    The addr directory contains the POI data and can be left empty if POIs are not used.
  • data (copy the rendering data and your license.key here)
    This directory contains the subfolders bmp, renderer and profiles for this tutorials.

    Generally, all files besides the license.key in the data directory are optional. The SDK will still work without the rendering data, but the map will look incomplete.

    In the top level, the *.cmp files are used for all text renderings on the map. If you delete them, no street or town names will be rendered anymore. All other files in the top level directory of data can be removed, they are only used for the tutorials.

    In the data\bmp directory you can find all icons that are directly rendered onto the map - like POI or restriction icons. If you don't need any of these icons, you can delete them. Please have in mind that a blue dot will be rendered for each POI as a fallback incase of POI data is present but icons are missing.

    In the data\renderer directory reside the map design files. You can remove this directory if you don't want to change the map design.

    The date\profiles directory contains files with predefined route options for various vehicles (see tutorial 5 for loading such files).

Shortcut

Your SDK delivery contains a sample sdcard folder which holds all necessary data for all tutorials. Just replace the files inside the maps folder with your favored maps and copy the Android folder to your sdcard. You need about 4GB of free space on your sdcard. Copying can be done for example with the adb call: adb push Android /mnt/sdcard/.

Attention

Please check the presence of the license.key key file as mentioned above.

Initialize the NavigationSDK

To initialize the NavigationSDK, we edit the MainActivity again and add a NavigationSDK.initialize() call. Initialization needs three paths and a map name. The three paths are the maps, addr and data directories that you just have created. The map name is the file name without the file extension (e.g. deu).

public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        File dir = getExternalFilesDir(null);

        try {
            NavigationSDK.initialize(
                new File(dir, "maps"),
                "deu",
                new File(dir, "addr"),
                new File(dir, "data")
            );
        } catch (NavigationException e) {
            e.printStackTrace();
        }
    }
}

That's it. You can now use the NavigationSDK.

Attention

If initialization throws an NavigationException with code: -53 you either forgot to copy the license.key file to your data directory or your test license.key has expired.

Improvements

To avoid reinitializing the NavigationSDK every time the MainActivity is created, you should move the initialization code to a new class maintaining the global application state. Create a new class called Application extending android.app.Application:

public class Application extends android.app.Application {
    @Override
    public void onCreate() {
        super.onCreate();

        File dir = getExternalFilesDir(null);

        try {
            NavigationSDK.initialize(
                new File(dir, "maps"),
                "deu",
                new File(dir, "addr"),
                new File(dir, "data")
            );
        } catch (NavigationException e) {
            e.printStackTrace();
        }
    }
}
Connect the new Application class in AndroidManifest.xml through setting the android:name attribute (Hint: Application class documentation).

    ...
    <application
        android:name=".Application"
        ...
    />
    ...

Now the SDK will be initialized only once the application is created.

As a helper for further tutorials we also save the paths to static members to easily access these directories later.

public class Application extends android.app.Application {

    private static File basePath;
    private static File mapsPath;
    private static File addrPath;
    private static File dataPath;

    @Override
    public void onCreate() {
        super.onCreate();

        basePath = getExternalFilesDir(null);
        mapsPath = new File(basePath, "maps");
        addrPath = new File(basePath, "addr");
        dataPath = new File(basePath, "data");

        try {
            NavigationSDK.initialize(
                    mapsPath,
                    "deu",
                    addrPath,
                    dataPath
            );
        } catch (NavigationException e) {
            e.printStackTrace();
        }
    }

    public static File getBasePath() {
        return basePath;
    }

    public static File getMapsPath() {
        return mapsPath;
    }

    public static File getAddrPath() {
        return addrPath;
    }

    public static File getDataPath() {
        return dataPath;
    }

Error Handling

For the sake of this tutorial we implement a minimal error handling for the initialization of the SDK, so the user gets a failure message if he is missing some of the necessary SDK files. Because the initialization happens in Application::onCreate() where we have no GUI yet, we save possible errors in a static member so we can evaluate it later in the MainActivity.

public class Application extends android.app.Application {

    ...

    private static Throwable startupException;

    public static boolean hadStartupException() {
        return startupException != null;
    }

    public static Throwable getStartupException() {
        return startupException;
    }

    @Override
    public void onCreate() {
        super.onCreate();

        ...

        try {
            NavigationSDK.initialize(
                mapsPath,
                "DEU",
                addrPath,
                dataPath
            );
        } catch (NavigationException e) {
            startupException = e;
            return;
        }
    }
    ...
}

Our approach is to show the startup error by replacing the MainActivity layout with an error layout called activity_startup_error.xml.

<?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"
    xmlns:tools="http://schemas.android.com/tools"
    android:orientation="vertical"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="@color/colorPrimaryDark">

    <ImageView
        android:id="@+id/imageView2"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_gravity="center"
        android:src="@drawable/error" />

    <TextView
        android:id="@+id/errorMessageTextView"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_gravity="center"
        android:inputType="textMultiLine"
        android:maxLines="10"
        android:singleLine="false"
        android:textAppearance="@style/Base.TextAppearance.AppCompat.Medium"
        tools:text="ErrorMessage" />

</LinearLayout>

We replace the layout in the activities onCreate() an use the exceptions message as an error text for the user. We also return early from all livecycle methods to prevent any logic from executing when an startup error occured.

public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        if (Application.hadStartupException()) {
            showStartupError();
            return;
        }

        setContentView(R.layout.activity_main);
    }

    private void showStartupError() {
        setContentView(R.layout.activity_startup_error);
        TextView errorMessage = findViewById(R.id.errorMessageTextView);
        Throwable e = Application.getStartupException();

        errorMessage.setText(e.getMessage());
    }
    @Override
    protected void onResume() {
        super.onResume();
        if (Application.hadStartupException())
            return;
    }

    @Override
    protected void onPause() {
        super.onPause();
        if (Application.hadStartupException())
            return;
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        if (Application.hadStartupException())
            return;
    }
}