Standalone integration using Eclipse

Introduction

In the following we will guide you through creating a simple Android application integrating Sygic navigation engine with a standalone integration (Sygic runs on a separate screen in the fullscreen mode).
In this example we will develop a simple application, where you can type in an address string and through a custom button you can start navigation to that address.

Prepare your working environment

For being able to compile your application you need to have Eclipse ADT on your computer. If you don't have it please follow Download Eclipse ADT. As the key point you need to Download and Install SDK library on your computer.
You may want to install the Sygic navigation on your device in advance. Check Installation of navigation. You will definitely need it at later stages when you want to test your application on device.
Not necessarily but we recommend first to test the compilation flow using the IpcDemo3D project within the Sygic SDK package.
Check Run Demo Example.

Create new project

Let's start Eclipse and create the new project through File->New->Android Application Project.
The project is automatically populated with several files, while these are relevant:

  • MainActivity.java, which is the placeholder for application coding (java code)
  • activity_main.xml, which will define graphical look of application (layout form)

The java code should be generated as follows:

package com.example.myapp;
import android.app.Activity;
import android.os.Bundle;

public class MainActivity extends Activity {

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

The layout form should be generated as follows:

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context="${packageName}.${activityClass}" >

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="@string/hello_world" />

</RelativeLayout>

Include Sygic library

Including Sygic SDK library consists of two steps:

  • copy remoteAPI.jar from SDK package to project's Lib folder
    The Sygic Library should automatically appear in project (possibly click on refresh) as shown here:

  • add import references of Sygic packages into java code
    Note that these references might be automatically added when writing java code.

Finally the import section should look as shown here:

import com.sygic.sdk.remoteapi.Api;
import com.sygic.sdk.remoteapi.ApiCallback;
import com.sygic.sdk.remoteapi.ApiNavigation;
import com.sygic.sdk.remoteapi.events.ApiEvents;
import com.sygic.sdk.remoteapi.exception.NavigationException;

Note that all Sygic classes and functions are located in the package com.sygic.sdk.remoteapi.

Define graphical look

As envisioned we add two graphical elements into application, which is the EditText for inputting address and Button for triggering navigation functions.
Thus we need to modify the default generated layout to the following form.

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context="${packageName}.${activityClass}" >

    <Button
        android:id="@+id/btnMap"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="Map" />

    <EditText
        android:id="@+id/editAddress"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentLeft="true"
        android:ems="10" >
        <requestFocus />
    </EditText>

    <Button
        android:id="@+id/btnNavigate"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentLeft="true"
        android:layout_below="@+id/editAddress"
        android:text="Navigate" />

</RelativeLayout>

Code the application

The application will be written solely in the java class MainActivity.

Define application framework using Sygic callback mechanism

The following code is the typical framework to pick when starting to write an application using Sygic API.

public class MainActivity extends Activity {

    private Api mApi;
    private ApiCallback mApiCallback = new ApiCallback() {

        @Override
        public void onServiceDisconnected() {
        }

        @Override
        public void onServiceConnected() {
        }

        @Override
        public void onEvent(int event, String data) {
        }
    };

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        mApi = Api.init(getApplicationContext(), ... , mApiCallback);
    }
}

The activity class needs to contain the instance of Sygic Api (mApi) and the instance of ApiCallback (mApiCallback).
The ApiCallback as the interface defines 3 functions mandatory to fill (onServiceConnected, onServiceDisconnected, onEvent).
With the applicaton start (the application basically starts at OnCreate) we need to call the mApi.init function, which binds API with the defined callback and with Sygic navigation.

Bind API to Sygic Navigation engine

The binding means filling the appropriate application and service identificators into mApi.init function. in this example we use com.sygic.fleet, which corresponds to Sygic Professional Navigation.

mApi = Api.init(getApplicationContext(), "com.sygic.fleet", "com.sygic.fleet.SygicService", mApiCallback);

If the example should work with another version of navigation the identificators will need to change. The available identificators are:

  • com.sygic.fleet for Sygic Professional Navigation
  • com.sygic.truck for Sygic 3D Truck (note it will cease to support SDK in future, use Sygic Professional)
  • com.sygic.drive for Sygic 2D Navigation

Define API opening and closing operations

The opening of API interface is implemented with calling connect at the application start right after init as follows:

protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        mApi = Api.init(getApplicationContext(), ... , mApiCallback);
        mApi.connect();
    }

and registerCallback, which typically resides in onServiceConnected

@Override
        public void onServiceConnected() {
            try {
                mApi.registerCallback();
        } catch (RemoteException e) {
            e.printStackTrace();
        }
    }

Next, we want to close API with an application exit, and the typical choice is to place unregisterCallback and disconnect inside the application's onDestroy method as follows:

@Override
    protected void onDestroy() {
        try {
            mApi.unregisterCallback();
        } catch (RemoteException e) {
            e.printStackTrace();
        }
        mApi.disconnect();
        super.onDestroy();
    }

Invoke navigation function (Navigate button)

We will call the navigation function from the button Navigate through its event function OnClick.
Inside OnClick we will read the user typed address and use it in the API function call NavigateToAddress.
Thus the whole function can be defined within default activity OnCreate method as follows:

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

        btnNavigate = (Button)findViewById(R.id.btnNavigate);
        btnNavigate.setOnClickListener(new View.OnClickListener() {

            @Override
            public void onClick(View v) {
                String address = ((EditText)findViewById(R.id.editAddress)).getText().toString();
                try {
                    mApi.show(false);
                    ApiNavigation.navigateToAddress(address, false, 0, 0);
                } catch (NavigationException e) {
                    e.printStackTrace();
                } catch (RemoteException e) {
                    e.printStackTrace();
                }
            }

        });

        mApi = Api.init(getApplicationContext(), "com.sygic.fleet", "com.sygic.fleet.SygicService", mApiCallback);
        mApi.connect();
    }

Open navigation (Map button)

We will define the Map button, which will serve two purposes. When clicked it will open up Sygic navigation if yet not started, or else if started, it will put it into foreground. This definition belongs to the OnCreate method too.

Button btnMap = (Button)findViewById(R.id.btnMap);
btnMap.setOnClickListener(new View.OnClickListener() {
   public void onClick(View v)
   {
      try {
        mApi.show(false);
      } catch (RemoteException e) {
        e.printStackTrace();
      }
   }
});

Manage Navigate button activation

For better consistency of the demo application we will enable or disable the Navigation button based on the condition whether navigation is started or not. This is to avoid excessive error management with calling navigation API function when Sygic navigation is not started yet.
For this we need to manipulate the button Navigate, which we will do in four places:

  1. We define globally accessible class variable:
    Button btnNavigate = null;
  2. We set it to inactive with application start within the OnCreate button.
    btnNavigate = (Button)findViewById(R.id.btnNavigate);        
    btnNavigate.setEnabled(false);
  3. We activate or deactivate the button when receiving callback from service connection. Here we check the Sygic application is running or not using yhe API function isApplicationRunning.

    @Override
                public void onServiceConnected() {
                   try {
                      mApi.registerCallback();
                   } catch (RemoteException e) {
                      e.printStackTrace();
                   }
    
                   try {
                      boolean isRun = Api.isApplicationRunning(1000);
                      if (isRun)
                      {
                          btnNavigate.setEnabled(true);
                      }
                      else
                      {
                          btnNavigate.setEnabled(false)
                      }
                   } catch (GeneralException e) {
                      e.printStackTrace();
                   }
    
                }
  4. We activate or deactivate the button when receiving callback in the OnEvent method. Here we check the API events EVENT_APP_STARTED and EVENT_APP_EXIT, which signal start or exit of the Sygic navigation.
    Here we use the pattern to handle events within the UI thread as it is prohibited to handle UI functions outside UI threads.
    This pattern is generally safe pattern for performing any operations within the OnEvent method.

        public void onEvent(int event, String data) {
              eventHandler.obtainMessage(event, data).sendToTarget();
        }
    
       Handler eventHandler = new Handler(new Handler.Callback() {
    
            @Override
            public boolean handleMessage(Message msg) {
                int event = msg.what;
                String data = (String)msg.obj;
                if (event == ApiEvents.EVENT_APP_STARTED)
                {
                    btnNavigate.setEnabled(true);
                }
                if (event == ApiEvents.EVENT_APP_EXIT)
                {
                    btnNavigate.setEnabled(false);
                }
    
                return false;
            }
        });

Build and deploy application

Building the application is simple as clicking on Run button in Eclipse.
The result of the build process is generation of MyApp.apk, which just needs to be copied to your Android device.
You also need to copy and install Sygic Navigation to device. Please note in this example it should be Sygic Professional Navigation.
For binding to other versions of navigation please change the application identificator inside the Api.init function.
If you have not done that yet please follow Installation of navigation.

Full sample reference


package com.example.myapp;
import android.app.Activity;
import android.os.Bundle;
import android.os.RemoteException;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.Toast;
import com.sygic.sdk.remoteapi.Api;
import com.sygic.sdk.remoteapi.ApiCallback;
import com.sygic.sdk.remoteapi.ApiNavigation;
import com.sygic.sdk.remoteapi.events.ApiEvents;
import com.sygic.sdk.remoteapi.exception.NavigationException;

public class MainActivity extends Activity {

    private Api mApi;

        Button btnNavigate = null;

        Handler eventHandler = new Handler(new Handler.Callback() {

            @Override
            public boolean handleMessage(Message msg) {
                int event = msg.what;
                String data = (String)msg.obj;
                if (event == ApiEvents.EVENT_APP_STARTED)
                {
                    btnNavigate.setEnabled(true);
                }
                if (event == ApiEvents.EVENT_APP_EXIT)
                {
                    btnNavigate.setEnabled(false);
                }

                return false;
            }
        });

    private ApiCallback mApiCallback = new ApiCallback() {

        @Override
        public void onServiceDisconnected() {
        }

        @Override
        public void onServiceConnected() {
              try {
                  mApi.registerCallback();
          } catch (RemoteException e) {
              e.printStackTrace();
          }

                  try {
                      boolean isRun = Api.isApplicationRunning(1000);
                      if (isRun)
                      {
                          btnNavigate.setEnabled(true);
                      }
                      else
                      {
                          btnNavigate.setEnabled(false);
                      }
                   } catch (GeneralException e) {
                      e.printStackTrace();
                   }
        }

        @Override
        public void onEvent(int event, String data) {
                    eventHandler.obtainMessage(event, data).sendToTarget();
        }
    };

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

        Button btnMap = (Button)findViewById(R.id.btnMap);
        btnMap.setOnClickListener(new View.OnClickListener() {  
             public void onClick(View v) {

                    try {
                        mApi.show(false);
                    } catch (RemoteException e) {
                        e.printStackTrace();
                    }
             }
        });

        btnNavigate = (Button)findViewById(R.id.btnNavigate);
        btnNavigate.setEnabled(false);
        btnNavigate.setOnClickListener(new View.OnClickListener() {

            @Override
            public void onClick(View v) {
                String address = ((EditText)findViewById(R.id.editAddress)).getText().toString();
                try {
                    mApi.show(false);
                    ApiNavigation.navigateToAddress(address, false, 0, 0);
                } catch (NavigationException e) {
                    e.printStackTrace();
                } catch (RemoteException e) {
                    e.printStackTrace();
                }
            }

        });

        mApi = Api.init(getApplicationContext(), "com.sygic.fleet", "com.sygic.fleet.SygicService", mApiCallback);
        mApi.connect();
    }

    @Override
    protected void onDestroy() {
        try {
            mApi.unregisterCallback();
        } catch (RemoteException e) {
            e.printStackTrace();
        }
        mApi.disconnect();
        super.onDestroy();
    }
}
```java