Skip to content

CPIK Set up Guide

After downloading and extracting the CoPilot CPIK .zip file, you should have access to everything needed to get up and running quickly.

CPIK takes a library / plugin approach, therefore certain files and resources need to be included in your Android project. The below are files that should be copied from the com.alk.copilot.generic_enterprise_cpik folder (please note folder name may vary slightly).

Copy all files from Copy all files to
Library and Resources/assets/* <​your app>/app/src/main/assets/
Library and Resources/jars/* <​your app>/app/libs/
Library and Resources/native libs/* <​your app>/app/src/main/jniLibs

Inside Android Studio, look at your module’s build.gradle (not project). If the build.gradle does not contain compile.fileTree(dir: ‘libs’, include: [‘*jar’]) then include it. Alternatively you could compile each jar on separate lines. In your build.gradle you also need to ensure that the application meets CoPilot’s minimum SDK version of 8. You can add minSdkVersion 8 to your build.gradle if needed.

Adding to your AndroidManifest.xml

The next section covers what additional lines and attributes you will require in your AndroidManifest.xml. For easier reference we provide a AndroidManifest_template.xml file for reference inside the Library and Resource folder.

First we need to add some attributes to the main activity in your application that is used on startup.

<activity>
android:name="com.alk.helloworld.MainActivity"
android:multiprocess="false"
android:configChanges="mcc|mnc|locale|keyboard|keyboardHidden|orientation|screenSize|fontScale|uiMode"
android:launchMode="singleTask"
android:label="@string/mainactivity_label"
android:windowSoftInputMode="stateHidden|adjustPan">
<intent-filter>
  <!-- Launcher intent (Your manifest probably has this already) -->
  <action android:name="android.intent.action.MAIN">
    <category android:name="android.intent.category.LAUNCHER">
  </intent-filter>
</activity>

You will also need to add the following services and metadata to your 'application' element inside the Android Manifest.

<service  android:name="com.alk.copilot.CopilotService" android:enabled="true"></service>
    <!-- This should always be "true" -->
    <meta-data android:value="true" android:name="ALK_isCustomFragment">

    <!-- "true" if you want CoPilot to store data (maps, speech, etc) in the default install directory
         "false" if you want CoPilot to store data using the external storage dir (usually on the sdcard) -->
    <meta-data android:value="false" android:name="ALK_useInternalStorage">

    <!-- "true" if you will be starting CoPilot in the background and do not want to show a splash screen. false" otherwise -->
    <meta-data android:value="true" android:name="ALK_doBackgroundStart">
    <meta-data android:name="ALK_useOpenGL" android:value="true" >

Android Permissions

You will need to add some additional permission access inside your 'manifest' element, sibling to the 'application' element in the xml tree.

<uses-permission android:name="android.permission.INTERNET"/>
  <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/>
  <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>
  <uses-permission android:name="android.permission.ACCESS_LOCATION_EXTRA_COMMANDS"/>
  <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
  <uses-permission android:name="android.permission.DISABLE_KEYGUARD"/>
  <uses-permission android:name="android.permission.WAKE_LOCK"/>
  <uses-permission android:name="android.permission.READ_CONTACTS"/>
  <uses-permission android:name="android.permission.READ_PHONE_STATE" android:maxSdkVersion="22"/>
  <uses-permission android:name="android.permission.VIBRATE"/>
  <uses-permission android:name="android.permission.ACCESS_WIFI_STATE"/>
  <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
  <uses-permission android:name="com.android.vending.CHECK_LICENSE"/>
  <uses-permission android:name="com.android.vending.BILLING"/>

These permissions will be added to your MainActivity as we will see later on.

Everything should be set up to continue development inside your application now.

Creating a CoPilot activity

In this example we will be assigning CoPilot to a whole view with in an activity. Create a new activity and include some form of layout in that. The below can be used in the onCreate() method of that activity.

public class CopilotActivity extends AppCompatActivity {

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

       RelativeLayout layout = (RelativeLayout) findViewById(R.id.copilotLayout);
       View copilotView = CopilotMgr.getView();
       layout.addView(copilotView);
   }
}

When the activity is created, CoPilot is called and returns a view. This view is then assigned to your layout; displaying the software.

Launching CoPilot - Binding the CoPilot service

The first part in launching and interacting with CoPilot is binding it as a service to your parent application. By running as a service CoPilot can work in the background or without continuous user interaction. We do this first by implementing a new ServiceConnection as below:

private ServiceConnection mCopilotServiceConnection = new ServiceConnection() {

   public void onServiceConnected(ComponentName className, IBinder service) {

       m_copilotBinder = (CopilotService.CopilotBinder) service;

       // Utilise CoPilot so that the OS does not kill it
       NotificationCompat.Builder builder = new NotificationCompat.Builder(
               MainActivity.this);

       Intent resultIntent = new Intent(MainActivity.this,
               MainActivity.class);
       PendingIntent pendingIntent = PendingIntent.getActivity(
               MainActivity.this, 0, resultIntent,
               PendingIntent.FLAG_UPDATE_CURRENT);

       builder.setContentIntent(pendingIntent);

       m_copilotBinder.startForeground(1, builder.build());
   }

   public void onServiceDisconnected(ComponentName className) {
   }
};
private CopilotService.CopilotBinder m_copilotBinder = null;

Here, we’re taking the impending service and starting it. We use pendingIntent to ensure the application’s permissions are used (defined previously in your manifest) to ensure CoPilot has access to everything it needs seamlessly.

Once implemented we can make use of the ServiceConnection as part of our initialization code. In the example below this has been added to the onCreate method of our main activity.

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

   validatePermissions();

   // start CoPilot in background
   Intent intent = new Intent(this, CopilotService.class);
   bindService(intent, mCopilotServiceConnection, Context.BIND_AUTO_CREATE);
}

We are now binding the CoPilot service using the ServiceConnection we created and instantiated to mCopilotServiceConnection previously. At this point we can also implement our validatePermissions method as shown below:

   private void validatePermissions() {
        if (ContextCompat.checkSelfPermission(this, Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
            ActivityCompat.requestPermissions(this, new String[]{
                    Manifest.permission.INTERNET,
                    Manifest.permission.ACCESS_COARSE_LOCATION,
                    Manifest.permission.ACCESS_FINE_LOCATION,
                    Manifest.permission.ACCESS_LOCATION_EXTRA_COMMANDS,
                    Manifest.permission.ACCESS_NETWORK_STATE,
                    Manifest.permission.DISABLE_KEYGUARD,
                    Manifest.permission.WAKE_LOCK,
                    Manifest.permission.WRITE_SETTINGS,
                    Manifest.permission.READ_CONTACTS,
                    Manifest.permission.READ_PHONE_STATE,
                    Manifest.permission.VIBRATE,
                    Manifest.permission.ACCESS_WIFI_STATE,
                    Manifest.permission.READ_EXTERNAL_STORAGE,
                    Manifest.permission.WRITE_EXTERNAL_STORAGE
            }, 0);
        } else {
            startCopilot();
        }
    }

Launching CoPilot - Checking CoPilot is ready

The CoPilot service should now have started. However during it’s startup and initialization CoPilot cannot be interacted with at an API level. Instead a listener is provided to alert your application when initialization is completed and we’re ready to go. First we need to create a nested StartupListener class. This inherits from CopilotListener and more importantly you will need to implement the onCPStartup method.

private class StartupListener extends CopilotListener {

   @Override
   public void onCPStartup() {
    // CoPilot has started up and is ready for API usage
    // Enable any UI that allows users to access CoPilot or set flags
    // Pass any initial configs etc.
    CopilotListener.unregisterListener(this);
   }
}

This will be used when we register a listener with CoPilot, that way when CoPilot is ready and completed its startup procedures the process to work with CoPilot can continue. We are adding to our onCreate code from earlier to instantiate that StartupListener and register it.

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

   // start CoPilot in background
   Intent intent = new Intent(this, CopilotService.class);
   bindService(intent, mCopilotServiceConnection, Context.BIND_AUTO_CREATE);

   // cannot make any API calls until onCPStartup() is called so listen
   // out for when it happens
   StartupListener listener = new StartupListener();
   CopilotListener.registerListener(listener);
}

This will be used when we register a listener with CoPilot, that way when CoPilot is ready and completed its startup procedures the process to work with CoPilot can continue. We are adding to our onCreate code from earlier to instantiate that StartupListener and register it.

Launching CoPilot - Displaying CoPilot

Once the service has been bound, launched and the startup procedures have been completed, displaying CoPilot is as simple as launching into another activity.

Intent intent = new Intent(this, CopilotActivity.class);
startActivity(intent);

Licensing CoPilot

Now that the link has been formed with CoPilot and we know how to display the activity and view that contains it, it’s time to license it. The generic enterprise build you have contains no functionality until you provide it with a license. The license is passed down via an API and, once activated, enables CoPilot to use specific functionality (truck, traffic etc.) or map regions (North America, Europe etc.)

Similarly to checking onCPStartup, licensing can only be done after the licensing module is ready and thus another listener is provided to assist. First we create a new LicenseListener. The next step depends on whether you are managing your licenses via our traditional product key licensing or the Trimble MAPS Account Manager.

Account Manager Licensing

Implement the LicenseMgtCredentialHook method to return a LicenseMgtInfo object, with the UserName and CompanyID for the license. LicenseMgtCredentialHook is fired on every startup, regardless of login status. You can change the active user by responding to it with a different UserName/CompanyID combination.

Product Key Licensing

Implement the onLicensingReady method. Each time CoPilot is started the onLicensingReady method will be called, therefore it is important to check if we have already activated your keys or not. This can be verified by using LicenseMgr.getLicenseStatus and confirming the key has been activated or not. If it hasn’t then it can be activated using LicenseMgr.activateLicense.

LicenseMgr returns an object called LicenseActivationResponse which will provide a success / failure message.

Provided the activation was a success when you next launch into CoPilot you should see the features associated with the key(s) you have licensed.

Sample Code

private LicenseListener m_LicenseListener = new LicenseListener() {
   @Override
   public void onLicensingReady() {
      String regionKeyString = "XXXX-XXXX-XXXX-XXXX";
      Log.d("License", "gets here");

      try {
        License regionLicense = new License(regionKeyString);
        if (LicenseMgr.getLicenseStatus(regionLicense) != LicenseStatus.ACTIVATED) {
          LicenseMgr.activateLicense(new License(regionKeyString));
        }
      } catch (Exception e) { }
   }
};

Note

In our provided sample application the code makes use of the mapRegionUpgradeKeyHook method inside the listener. This method is only used if you have pre populated map data on your device and do not wish to use the download manager inside CoPilot for map data. This hook will only trigger if CoPilot has not been licensed for a map region and thus once the software has been licensed for a map region it will not be called again.

Now that we have our listener object ready to go, we can register that listener. As previously, in this example it has been added to the onCreate method.

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

  // start CoPilot in background
  Intent intent = new Intent(this, CopilotService.class);
  bindService(intent, mCopilotServiceConnection, Context.BIND_AUTO_CREATE);

  // cannot make any API calls until onCPStartup() is called so listen
  // out for when it happens
  StartupListener listener = new StartupListener();
  CopilotListener.registerListener(listener);

  // Register the licensing listener
  LicenseListener.registerListener(m_LicenseListener);
}

Summary

You should be setup to use CoPilot within your application. All the libraries, assets etc. should be in their correct locations within your setup and your application is able to bind the service in order launch and license CoPilot as well as display it. This covers the basics of getting started but we recommend working from the sample application we provide as a reference. Even as part of the start up procedures it goes into much more depth on the options available such as passing in configurations into CoPilot on startup or using fragments instead of activities to display CoPilot.

Note

In later versions of the Android API list (API level 23+) simply listing certain permissions in the AndroidManifest.xml file is no longer enough. Instead, an application must explicitly request that the user allow these permissions via a popup. See the Android documentation on requesting permissions for more detail on this. Three in particular that must be requested in API level 23+ for CoPilot is ACCESS_COARSE_LOCATION, WRITE_EXTERNAL_STORAGE and ACCESS_FINE_LOCATION.


Last update: May 26, 2020