This package include a set of widgets that are bound to a Vrpn server buttons, analogs and trackers.

Create a simple application that uses the widgets

The following chapters describe how to create a simple application with a {@link eu.ensam.ii.vrpn.VrpnToggleButton VrpnToggleButton} and a {@link eu.ensam.ii.vrpn.VrpnSeekBar VrpnSeekBar}. An example application project that contains these widgets and more can be found in the example_app directory.

Create and configure the project

Refer to any Android documentation for instructions about how to set-up the Android SDK and the Eclipse plugin. Do not forget to setup the Android SDK in any new workspace (Window > Preferences, then go to the Android tab and configure the SDK location).

Import the Vrpn_library project into your Eclipse workspace. Open the Android section of the project property page and verify that Is library checked. If the build complains about "Android requires .class compatibility set to 5.0", you need first to select the project, right-click > Properties > Android tools > Fix project properties, then open the project properties, go to the Java compiler section, then deselect enable project specific settings. You may need to clean and rebuild (Project > Clean) several times before the project shows no errors.

Create a new Android project : File > New > Other ... , Android > Android Project. On the first page of the wizard, check Create activity and enter any name you like for the main activity (for instance MainActivity).

Add the library to your project : open the properties of the project, go to the Android page. In the Library pane, click Add then select vrpn_library, apply the changes and close the window. At this point, the Eclipse Package Explorer view of your project should contain a vrpn_library_src folder and the gen folder should contain a package entry named eu.ensam.ii.vrpn.

Open the AndroidManifest.xml file. On the Application tab, check Define an <Application> tag in the AndroidManifest.xml. Then click on the Browse button that is on the right of Name and select VrpnApplication.

Modify the main activity

Edit the main activity to define the binding to the Vrpn server when the activity is created. The method {@link android.app.Activity#onCreate onCreate} is called when the Activity is created. The default version of this method contain only the first and last lines :

  super.onCreate(savedInstanceState);
  ....    	
  setContentView(R.layout.main);

We need to define the binding with the Vrpn server. The method becomes :

@Override
public void onCreate(Bundle savedInstanceState) {
  super.onCreate(savedInstanceState);  
  InetAddress vrpnServerAddress = null;
  try {
    // Replace the IP address
    vrpnServerAddress = InetAddress.getByName("192.168.173.1");
  } catch (UnknownHostException e) {
  }
  final int vrpnServerPort = 7777;
  VrpnClient.getInstance().setupVrpnServer(vrpnServerAddress, vrpnServerPort);
  
  setContentView(R.layout.main);
}

Create a Vrpn Ids list

Before laying out your Vrpn widgets in your application, you should create an XML configuration file that contains the IDs of the Vrpn buttons and analog that you will be using. This allows you to keep a unique list of Vrpn IDs, making it easier to avoid duplicate values and reference this list from your application. Create this file with File > New > Other, then Android > Android XML File. In XML file dialog, type any file name you like, for instance vrpn.xml, then select Values as the type of resource to create.

Edit the resulting file, found at res/values/vrpn.xml to add the numbers of the Vrpn Buttons and Analogs that you will be using.

<resources>
  <item type="id" format="integer" name="VrpnAnalogLightIntensity">0</item>
  <item type="id" format="integer" name="VrpnButtonLightsOn">0</item>
</resources>

Note that type must be id and format must be integer, but name can be anything you like.

Add your widgets to the main layout

Say we want an Android application to control the lighting in our VR application : turn the light on or off and also control the light intensity. We will create an application with a {@link eu.ensam.ii.vrpn.VrpnToggleButton VrpnToggleButton} as the light switch and a {@link eu.ensam.ii.vrpn.VrpnSeekBar VrpnSeekBar} as a light intensity controller.

By default, the layout of the main Activity is described in res/layout/main.xml and just displays Hello. Edit this file. The XML code looks is something like :

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

The root element, LinearLayout , is a container for the other widgets, currently contains a TextView .

The basics about XML layouts are presented in Declaring layout SDK page.

Before the end tag </LinearLayout> , include a {@link eu.ensam.ii.vrpn.VrpnToggleButton VrpnToggleButton} to turn the lights on or off :

<eu.ensam.ii.vrpn.VrpnToggleButton
  android:layout_width="fill_parent" 
  android:layout_height="wrap_content" 
  app:vrpnButton="@id/VrpnButtonLightsOn"
/>
The Vrpn widgets use so-called custom XML properties , such as app:vrpnButton . This custom property allows you to specify the id of the target Vrpn button in the XML layout file rather than in Java code. However, the use of this custom property requires the addition of an XML namespace tag so that the build system can find then. After the xmlns:android line, add the following line :
  xmlns:app="http://schemas.android.com/apk/res/your.application.package.name.here"
Different attributes exist for each widgets and the whole list is shown when you unfold gen/eu/ensam.ii.vrpn/R.java/R/attr in the Eclipse Package View. Your layout is now ready for your to include the Vrpn widgets. Now save the file to build your project. If there are build errors, check the following :

In most cases, the Preview tab of the XML layout is not displayed properly as soon as you include one of the Vrpn widgets. This is a known problem for which not solution has currently been found. It prevents you from previewing the layout it wil be displayed correctly in the application, either on a device or in the emulator.

Now add a {@link eu.ensam.ii.vrpn.VrpnSeekBar VrpnSeekBar} to control the light intensity :

<eu.ensam.ii.vrpn.VrpnSeekBar
  android:layout_width="fill_parent" 
  android:layout_height="wrap_content"
  app:minValue="0"
  app:maxValue="255"
  app:defaultValue="128"
  app:vrpnAnalog="@id/VrpnAnalogLightIntensity"
/>
Your Android application is now ready to run. Upload on a device and run. There is not much to seen for the time being. However, if you run a network sniffer on a machine connected to the same network as the Android device, you should see UDP packets flowing out of the device. If you are using the emulator instead of an actual device, see the Emulator networking SDK page for the correct network setup.

Test your application

In order to test your application, you need a VRPN server built with VRPN_USE_JSONNET. See the README.jsoncpp file for instructions to build this server. When you get this server running, the easiest way to test the Android application is to use the vrpn_print_devices application provided with Vrpn. Type the command :
vrpn_print_devices Jsonnet@localhost
The command should then report the values of the Button and SeekBar as they are changed.

Beyond the basics

Application with multiple tabs

If you want to create an application with more widgets that can be placed on a single screen, using a {@link android.app.TabActivity TabActivity} instead of a regular Activity may be the way to go. A {@link android.app.TabActivity TabActivity} can display several activities of view, each inside a tab. The Android SDK documentation explains how to create a tabbed application with activities. However, using activities require careful state management since the activities may be terminated when the use switches from one tab to another. It is therefore easier to manage a {@link android.app.TabActivity TabActivity} that display views intead of activities.

First of all, your main activity must extend {@link android.app.TabActivity TabActivity} intead of {@link android.app.Activity Activity}.

Then, create a layout for each tab in res/layout with File > New > Other... , then Android > New XML file. In the New Android XML file dialog, name the file tab_one.xml, select Layout as the type of resource, then select LinearLayout as the root element. Repeat the process with a second tab layout named tab_two.xml. Update each tab layout as described in Add your widgets to the main layout above, paying attention not to forget the xmlns:app line.

The next step is to create a new layout names res/layout/tab_group.xmlfor the whole activity. This layout looks like :

<?xml version="1.0" encoding="utf-8"?>
<TabHost
  xmlns:android="http://schemas.android.com/apk/res/android"
  android:id="@android:id/tabhost"
  android:layout_width="fill_parent"
  android:layout_height="fill_parent">
  <TabWidget
    android:id="@android:id/tabs"
    android:layout_width="fill_parent"
    android:layout_height="wrap_content"
  />
  <FrameLayout
    android:id="@android:id/tabcontent"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:padding="5dp">
  </FrameLayout>
  <include layout="@layout/tab_one"></include>
  <include layout="@layout/tab_two"></include>
</TabHost>

Then edit the onCreate method of your activity. After the line super.onCreate() add the VrpnClient.getInstance().setUri(....) line, then add :

  LayoutInflater inflater = (LayoutInflater)getSystemService(Context.LAYOUT_INFLATER_SERVICE);
  inflater.inflate(R.layout.tab_group, getTabHost().getTabContentView(), true);
  TabHost.TabSpec spec;
  spec = getTabHost().newTabSpec("1").setContent(R.id.tab_one);
  getTabHost().addTab(spec)
  spec = getTabHost().newTabSpec("2").setContent(R.id.tab_two);
  getTabHost().addTab(spec);        
  getTabHost().setCurrentTab(0);

See in the SDK documentation how to use the {@link android.widget.TabHost.TabSpec#setIndicator setIndicator} method in order to display an icon in the tab headers.

Updating the widget library

Create a new Widget

To create a new Widget type you should look at the source code of VrpnSeekBar, which is the more elaborate. The main steps are as follows :

Note that using the full path of the parent class such as in :

public class VrpnRadioButton extends android.widget.RadioButton
allows Javadoc to generate a link to the parent class.

Generate the documentation

Select the vrpn_library/src folder, then select the menu item Project > Generate Javadoc.

On the first page of the wizard, select the path of the javadoc tool. Check that vrpn_library/src is selected, but not vrpn_library/gen, then select an appropriate destination for the documentation.

On the second page of the wizard select android.jar in the Referenced archives list and take note of the android.jar doc path (like file:/E:/android/docs/reference ).

On the third page of the wizard add the following line to the Extra javadoc options text box :

-linkoffline http://d.android.com/reference file:/E:/android/docs/reference
but replace the file:/ URL by your local Android SDK URL noted from the page two of the wizard. This allows Javadoc to include full references to the on-line Android documentation.