Native Sample Application Template

This article will help you understand the Sample Application Template so that you can use it in your own native iOS and Android apps.

Template interfaces

This template is composed of the following three main interfaces. These interfaces are explained in more detail below.
  • SampleApplicationSession 
  • SampleApplicationControl
  • SampleAppMenuCommandProtocol

SampleApplicationSession

This class abstracts the key lifetime functionality of a Vuforia application and is passed in as a parameter to each individual sample. This class contains the following key methods:

  • initAR()
  • startAR()
  • pauseAR()
  • resumeAR()
  • stopAR()
  • stopCamera()

This class also contains the ProjectionMatrix. The projection Matrix is used when displaying augmentations and it ensures that the perspective projection of the 3D view is consistent with the device camera view.

SampleApplicationControl

This class is a protocol in iOS and is a standard class in Android. This class mandates any Vuforia functionality that each individual application must provide for it to function correctly. This class contains the following key methods:
  • doInitARDone()
  • doInitTrackers()
  • doLoadTrackersData()
  • doStartTrackers()
  • doStopTrackers()
  • doUnloadTrackersData()
  • doDeinitTrackers()
The following two callback functions are invoked asynchronously, depending on a change in state within Vuforia:
  • onInitARDone()
  • onVuforiaUpdate()

SampleApplicationCommandProtocol

This class is a protocol in iOS and is a standard class in Android. This class mandates Menu functionality that each individual application must provide for it to function correctly.

How the template is used in iOS

The SampleAppAppDelegate (is this correct?) class follows standard iOS initialization and sets up the SampleAppSelectorViewController. The SampleAppSelectorViewController allows the individual samples to be selected from within a Table View. The initWithNibName() method sets up each ViewController by specifying its class name and About page name in an array that is used by the Table View.

When an individual sample is selected, its ViewController creates a SampleApplicationSession object to manage its lifetime and when required, it calls its methods (for example, initAR, and so forth). This abstraction ensures that most of the ViewController code is specific to each individual sample, which should make it easier to understand.

Each sample must conform to the SampleApplicationControl protocol, so each sample must provide the code for these methods. An example is how onInitARDone()initializes Vuforia, trackers, datasets, and so forth.

ImageTargetsViewController protocol methods

Initialize the Image Tracker

The following code initializes the image tracker so that it is able to detect image targets:

- (bool) doInitTrackers {
// Initialize the image or marker tracker
Vuforia::TrackerManager& trackerManager = Vuforia::TrackerManager::getInstance();

// Image Tracker...
Vuforia::Tracker* trackerBase trackerManager.initTracker(Vuforia::ObjectTracker::getClassType());
if (trackerBase == NULL)
{
NSLog(@"Failed to initialize ObjectTracker.");
return false;
}
NSLog(@"Successfully initialized ObjectTracker.");
return true;
}
 

De-initialize the Image Tracker

The following code de-initializes the tracker.

- (bool) doDeinitTrackers {
Vuforia::TrackerManager& trackerManager = Vuforia::TrackerManager::getInstance();
trackerManager.deinitTracker(Vuforia::ObjectTracker::getClassType());
return YES;
}

Initialize the datasets

The following code initializes the Tarmac and StonesAndChips datasets that will be used by the tracker:

- (bool) doLoadTrackersData {

dataSetStonesAndChips = [self loadObjectTrackerDataSet:@"StonesAndChips.xml"];
dataSetTarmac = [self loadObjectTrackerDataSet:@"Tarmac.xml"];
if ((dataSetStonesAndChips == NULL) || (dataSetTarmac == NULL)) {
NSLog(@"Failed to load datasets");
return NO;
}
if (! [self activateDataSet:dataSetStonesAndChips]) {
NSLog(@"Failed to activate dataset");
return NO;
 

Deactivate the dataset

The following code deactivates the current dataset.

- (bool) doUnloadTrackersData {
[self deactivateDataSet: dataSetCurrent];
dataSetCurrent = nil;
return YES;
}
 

Start the Tracker

This code starts the actual Tracker.

- (bool) doStartTrackers {

Vuforia::TrackerManager& trackerManager = Vuforia::TrackerManager::getInstance();
Vuforia::Tracker* tracker =
trackerManager.getTracker(Vuforia::ObjectTracker::getClassType());
if(tracker == 0) {
return NO;
}
 

Stop the Tracker

The following code stops the Tracker.

- (bool) doStopTrackers {

Vuforia::TrackerManager& trackerManager = Vuforia::TrackerManager::getInstance();
Vuforia::Tracker* tracker =
trackerManager.getTracker(Vuforia::ObjectTracker::getClassType());

if (NULL != tracker) {
tracker->stop();
NSLog(@"INFO: successfully stopped tracker");
return YES;
}
 

ImageTargetsViewController other key methods

In summary, this class contains the following key methods:

Key methodDescription
onVuforiaUpdateHandles the switching of datasets
loadImageTrackerDataSetLoads the dataset file from its .dat and .xml file
activateDataSetActivates a dataset
deactivateDataSetDe-activates a dataset
setExtendedTrackingForDataSetStarts or stops Extended Tracking

For more details on these methods, see the ImageTargetsViewController.mm file.

How the template is used in Android

The ActivityLauncher is located in com.vuforia.samples.VuforiaSamples.ui. ActivityList. The ActivityLauncher contains a list of all the activities that correspond to the individual sample features, such as Image Targets, Multi-targets, and so forth.

The ActivityLauncher UI presents a list to the user, and based on the item the user selects, it creates and starts an Android Intent to launch the corresponding sample feature activity. See the following code: 

@Override
public void onListItemClick(ListView l, View v, int position, long id)
{

Intent intent = new Intent(this, AboutScreen.class);
intent.putExtra("ABOUT_TEXT_TITLE", mActivities[position]);

switch (position)
{
case 0:
intent.putExtra("ACTIVITY_TO_LAUNCH",
"app.ImageTargets.ImageTargets");
intent.putExtra("ABOUT_TEXT", "ImageTargets/IT_about.html");
break;
case 1:
intent.putExtra("ACTIVITY_TO_LAUNCH",
"app.CylinderTargets.CylinderTargets");
intent.putExtra("ABOUT_TEXT", "CylinderTargets/CY_about.html");
break;
...
...
}
startActivity(intent);
}


Each sample feature activity (for example, ImageTargets.java) also implements the following two template interfaces:
  • SampleApplicationControl
  • SampleAppMenuInterface

SampleApplicationControl methods

The SampleApplicationControl interface requires the sample feature activity to implement its methods, for example, doInitTrackers(), doLoadTrackersdata(), onInitARDone(), onVuforiaUpdate(), and so forth.

Similarly, the SampleAppMenu interface requires the sample class to implement the menuProcess() interface method. This method handles the different menu commands, such as front and back camera selection, enables flash torch, focus mode selection, and enables extended tracking.

The ImageTargets activity also has a reference to the SampleApplicationSession, which has methods to handle the key steps of the application lifecycle, such as pauseAR(), resumeAR(), startAR(), stopAR(), initAR().

The SampleApplicationSession is initialized in the Activity onCreate() method, and stored in a member variable vuforiaAppSession:  

@Override
protected void onCreate(Bundle savedInstanceState)
{
Log.d(LOGTAG, "onCreate");
super.onCreate(savedInstanceState);

vuforiaAppSession = new SampleApplicationSession(this);
...
}
 

The SampleApplicationSession constructor takes as an argument a reference to the SampleApplicationControl of the calling sample class (passed as this, since the sample activity implements such interface). It holds that argument in its internal member variable m_sessionControl, passed as this, since the sample activity implements such interface.  

public SampleApplicationSession(SampleApplicationControl sessionControl)
{
m_sessionControl = sessionControl;
}

The m_sessionControl variable allows the SampleApplicationSession to interact with the SampleApplicationControl, in particular with the following:
  • Calling m_sessionControl.onInitARDone() upon completing the initAR() method execution
  • Calling m_sessionControl.doInitTrackers() when the InitVuforiaTask is completed
  • Calling m_sessionControl.doStartTrackers() during the startAR() execution
  • Calling m_sessionControl.doLoadTrackersData() as part of the execution step of the LoadTrackerTask
  • Calling m_sessionControl.doDeinitTrackers() and doUnloadTrackersData() from the stopAR() method

The SampleApplicationSession class also implements the Vuforia.UpdateCallbackInterface, which exposes the following method:

    public void Vuforia_onUpdate(State state);

The SampleApplicationSession class is registered with Vuforia using the following code:

    Vuforia.registerCallback(SampleApplicationSession.this);

The specific implementation then calls the onVuforiaUpdate() method of the sample application control:  

@Override
public void Vuforia_onUpdate(State s)
{
m_sessionControl.onVuforiaUpdate(s);
}
 

ImageTargets application control methods

The SampleApplicationControl interface requires the sample feature activity (for example, ImageTargets) to implement its methods, such as doInitTrackers(), doLoadTrackersdata(), onInitARDone(), onVuforiaUpdate(), and so forth).

Initialize the Tracker

The following code initializes the Tracker.   

@Override
public boolean doInitTrackers()
{
// Indicate if the trackers were initialized correctly
boolean result = true;

TrackerManager tManager = TrackerManager.getInstance();
Tracker tracker;

// Trying to initialize the image tracker
tracker = tManager.initTracker(ObjectTracker.getClassType());
if (tracker == null)
{
Log.e(LOGTAG, "Tracker already initialized or camera already started");
result = false;
} else
{
Log.i(LOGTAG, "Tracker successfully initialized");
}
return result;
}
 

De-initialize the Tracker

The following code de-initializes the Tracker. 

@Override
public boolean doDeinitTrackers()
{
// Indicate if the trackers were deinitialized correctly
boolean result = true;

TrackerManager tManager = TrackerManager.getInstance();
tManager.deinitTracker(ObjectTracker.getClassType());

return result;
}
 

Initialize the datasets

The following code initializes the Tarmac and StonesAndChips datasets that will be used by the tracker. 

@Override
public boolean doLoadTrackersData()
{
...

if (!mCurrentDataset.load(
mDatasetStrings.get(mCurrentDatasetSelectionIndex),
DataSet.STORAGE_TYPE.STORAGE_APPRESOURCE))
return false;

if (!objectTracker.activateDataSet(mCurrentDataset))
return false;

...

return true;
}
 

Start the Tracker

The following code starts the actual Tracker.

@Override
public boolean doStartTrackers()
{
// Indicate if the trackers were started correctly
boolean result = true;

Tracker objectTracker = TrackerManager.getInstance().getTracker(
ObjectTracker.getClassType());
if (objectTracker != null)
objectTracker.start();

return result;
}
 

Stop the Tracker

The following code stops the Tracker.  

@Override
public boolean doStopTrackers()
{
// Indicate if the trackers were stopped correctly
boolean result = true;

Tracker objectTracker = TrackerManager.getInstance().getTracker(
ObjectTracker.getClassType());
if (objectTracker != null)
objectTracker.stop();

return result;
}


For more details on these and other methods, see the ImageTargets.java file.

See:
Native Image Target Sample