Skip to content

08 Traffic information

Overview

In this tutorial, you will learn how to retrieve traffic information from the PTV NavigationSDK.

Base

Use Tutorial07 as a starting point for this project.

Obtaining a key

For using the traffic information functionality of the NavigationSDK, you will need an API key. Please contact the PTV Navigator product management to obtain the key (if you haven't already got one) and set the key with NavigationSDK.setTrafficSearchWebConfiguration in the onCreate method of the Application class.

public class Application extends android.app.Application {

    ...

    @Override
    public void onCreate() {
        ...

        // Uncomment the following line and replace <TOKEN> with your PTV Traffic Token if you want to use traffic
        // NavigationSDK.setTrafficSearchWebConfiguration("http://ti.ptvgroup.com/wfs", "<TOKEN>");
    }

    ...
}

Retrieving traffic informations

To retrieve traffic informations, we have to call NavigationSDK.searchTrafficInformation with our current GPS position. This will trigger an asynchronous call to a traffic REST service. For getting notified when the traffic request is finished, we implement an Observer and pass it to NavigationSDK.searchTrafficInformation. Since we'd like to request updates repeatedly, we call it in the navigation loop every X times the loop is running.

public class NavigationLoop implements Runnable {

    ...

    Observer trafficObserver = new Observer() {
        @Override
        public void onFinished(final int error, int index) {
            super.onFinished(error, index);

            handler.post(new Runnable() {
                @Override
                public void run() {
                    Log.v("Traffic", "onFinished");
                }
            });
        }
    };

    long loop = 0;
    @Override
    public void run() {
        try
        {

            ...

            if ((loop % 10) == 0) {
                NavigationSDK.searchTrafficInformation(
                    gps.getGPSPosition(), 
                    trafficObserver
                );
            }

            ...

            loop++;
        }
        ...
    }

Traffic observer

The above mentioned Observer class is used for getting information as soon as the previously triggered search has finished. This observer has one major function that we override: onFinished. (It also has a method onProgress, but we do not need this method in this chapter). In the code above, we only did a string output to the logcat showing that the function was called. Now, we additionally output the traffic results to the logcat. For this, we retrieve the search results by calling NavigationSDK.getTrafficSearchResults(). We then iterate over the returned results and output the description of the current result to the logcat:

    Observer trafficObserver = new Observer() {
        @Override
        public void onFinished(final int error, int index) {
            super.onFinished(error, index);

            handler.post(new Runnable() {
                @Override
                public void run() {
                    Log.v("Traffic", "onFinished");
                    if (error == SDKErrorCode.Ok.getId()) {
                        Result<TrafficResults> results = 
                            NavigationSDK.getTrafficSearchResults();

                        for (TrafficSearchResult r : results.getResult()) {
                            Log.v("Traffic", r.getDescription());
                        }
                    }
                }
            });
        }
    };

Traffic activity

After starting the traffic search and getting informed when it has finished, it is time to show the results in a separate activity. Let's start with adding a new activity to our project. Create a new activity called "TrafficActivity" and fill it with the code below:

package com.ptvag.navigation.tutorial;

import android.os.Bundle;
import android.widget.ListView;

import com.ptvag.navigation.helper.DrawerActivity;
import com.ptvag.navigation.sdk.NavigationSDK;
import com.ptvag.navigation.sdk.Result;
import com.ptvag.navigation.sdk.TrafficResults;

public class TrafficActivity extends DrawerActivity {

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

        ListView listView = (ListView) findViewById(R.id.listView);


        Result<TrafficResults> results = NavigationSDK.getTrafficSearchResults();

        TrafficAdapter adapter = new TrafficAdapter(this, R.layout.row_traffic_result, results.getResult());
        listView.setAdapter(adapter);
    }
}
The activity should show a listview, so we add a listview to the activity_traffic.xml:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/activity_traffic"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:paddingBottom="16dp"
    android:paddingLeft="16dp"
    android:paddingRight="16dp"
    android:paddingTop="16dp"
    tools:context="com.ptvag.navigation.tutorial.TrafficActivity">

    <ListView
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout_alignParentLeft="true"
        android:layout_alignParentStart="true"
        android:id="@+id/listView"/>

</RelativeLayout>

The above listview should show the results in rows, so we need an xml called row_traffic_result.xml to define the look of one row (this is the same pattern as in the search activity listview). The row view is named "trafficResultItem".

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="wrap_content"
    android:gravity="center_vertical"
    android:orientation="vertical" >

    <TextView
        android:id="@+id/trafficResultItem"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:gravity="center_vertical"
        android:padding="15dp"
        android:textAppearance="@style/Base.TextAppearance.AppCompat.Medium"
        android:maxLines="1"/>

</LinearLayout>

To fill the listview with the traffic search results, we need again an adapter class:

package com.ptvag.navigation.tutorial;

import android.app.Activity;
import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ArrayAdapter;
import android.widget.TextView;

import com.ptvag.navigation.sdk.NativeArray;
import com.ptvag.navigation.sdk.Result;
import com.ptvag.navigation.sdk.SearchKind;
import com.ptvag.navigation.sdk.SearchResult;
import com.ptvag.navigation.sdk.TrafficResults;
import com.ptvag.navigation.sdk.TrafficSearchResult;

public class TrafficAdapter extends ArrayAdapter<TrafficSearchResult>
{
    protected final Activity context;
    protected TrafficResults results;

    public TrafficAdapter(Context context, int textViewResourceId, TrafficResults results)
    {
        super(context, textViewResourceId);
        this.context = (Activity) context;
        this.results = results;
    }

    @Override
    public int getCount()
    {
        return results.size();
    } 

    @Override
    public TrafficSearchResult getItem(int position)
    {
        return results.get(position);
    }

    @Override
    public long getItemId(int arg0)
    {
        if(getCount() > 0)
            return arg0;
        else 
            return 0;
    }

    @Override
    public View getView(int position, View convertView, ViewGroup viewGroup)
    {
        if(getCount() < 1)
            return null;

        View v = convertView;
        if (v == null) { 
            LayoutInflater layoutInflater = (LayoutInflater)context.getLayoutInflater();
            v = layoutInflater.inflate(R.layout.row_traffic_result, null, true);
        }

        TrafficSearchResult result;
        result = getItem(position);

        String description = result.getDescription();

        TextView text = (TextView) v.findViewById(R.id.trafficResultItem);
        text.setText(description);

        return v;
    }

}

We have to override some functions to retrieve the current data for each listview row. We set the traffic search result in the constructor of the adapter. In the getView method, we pick out the desired result and set the text of the trafficResultItem view to the description of this result.

Finally we show the traffic activity. This is done by extending our drawer menu with another item. We add the following line to the drawer_menu.xml:

<item android:id="@+id/menu_traffic" android:title="traffic"></item>

Next, go to the main activity and add the following case statement to the onNavigationItemSelected() method:

 @Override
    public boolean onNavigationItemSelected(@NonNull MenuItem item) {

        switch (item.getItemId()) {
            ...
            case R.id.menu_traffic:
                Intent intent = new Intent(this, TrafficActivity.class);
                startActivity(intent);
                break;
        }
        ...
}

Now we have added a new menu entry in our drawer. A click on it will bring up the traffic information activity.