ServiceRouting: How to transfer data for free!

The BlackBerry JDE v4.1 includes a new API in addition to the suite of existing BlackBerry device APIs, called ServiceRouting. This API provides an application with the ability to route traffic through a USB or Bluetooth connection to the desktop using the standard connectivity protocols.

To better understand how the ServiceRouting API works, it is important to first discuss the least-cost routing feature that was added to the BlackBerry JDE v4.0 release, as the ServiceRouting API leverages this feature. With BlackBerry Device Software v4.0, BlackBerry Desktop Manager v4.0 and BlackBerry Enterprise Server v4.0, when a user connects their device to the desktop via the USB cable, the BlackBerry Enterprise Server will automatically route traffic that was destined for the wireless network to the device over the internal network using the USB cable connected to the device. Similarly, any device traffic destined for the wireless network will be automatically sent over the USB cable to the BlackBerry Enterprise Server for processing. The effect? All traffic to and from the device is routed over the wired network, saving the user from utilizing additional bandwidth from their wireless service provider. When least-cost routing is used on the device, it is performed automatically by the low-level protocol layers and does not require any changes to an application for it to leverage this capability.

With BlackBerry Device Software v4.1 and BlackBerry Desktop Manager v4.1, the user has the ability to perform least-cost routing over a Bluetooth connection to their computer rather than relying on USB connectivity.

With the least-cost routing infrastructure in place, it was important to provide an API for third party developers to be able to determine when the user’s device was connected to a computer via Bluetooth or USB. There are several different use cases for leveraging the ServiceRouting API:

  • An optimal environment for determining when to perform synchronization activities with application servers due to fast and simple data transfer capabilities

  • The ability to transfer large amounts of data to and from the device with no additional cost to the user

  • Indication of the connectivity habits of the user, allowing the application to tailor its synchronization activities to particular use cases

The ServiceRouting API provides two main pieces of functionality:

  1. The ability to determine whether a particular service is currently enabled for serial bypass or least-cost routing. This is performed using the isSerialBypassActive() and isSerialBypassActive( String service ) methods.

  2. The ability to add and remove listeners which provide updates on when the device obtains and loses the ability to perform least-cost routing.

All of the routing capabilities on BlackBerry are provided through the concept of Service Books and Service Records. It will come as no surprise that the ServiceRouting API can leverage Service Record information to assist developers in determining exactly which paths are available for least-cost routing.

To fully explain the interaction between the ServiceBook API and the ServiceRouting API, sample code has been provided below which illustrates how to leverage the two main pieces of functionality of the ServiceRouting API as described above in conjunction with the ServiceBook API. The sample code provides a tree-based structure indicating which Service Records are enabled for least-cost routing when a device is connected to a computer. In addition, the sample also provides listener capability to pop up a dialog when least-cost routing capability is obtained and lost by the device.

/*
 * ServiceRoutingDemo.java
 *
 * © Research In Motion Limited, 2003-2003
 * Confidential and proprietary.
 */ 

package internal.com.rim.samples.device.serviceroutingdemo; 

import net.rim.device.api.servicebook.*;
import net.rim.device.api.system.*;
import net.rim.device.api.ui.*;
import net.rim.device.api.ui.component.*;
import net.rim.device.api.ui.container.*; 

/**
 * This application will showcase how third party applications
 * can take advantage of the service routing API to leverage
 * the serial bypass mechanism that was implemented with 4.0 BES
 * and 4.0 handhelds.
 * @since 4.1 JDE
 */
public class ServiceRoutingDemo extends UiApplication implements TreeFieldCallback, ServiceRoutingListener
{

    private static String   CONNECTED       = "Serial Bypass: Connected";
    private static String   DISCONNECTED    = "Serial Bypass: Disconnected";
    private static String   DESKTOP         = "Desktop"; 

    private MainScreen      _screen;        // screen shown to the user
    private RichTextField   _statusField;   // field containing connected or disconnected string
    private TreeField       _treeField;     // tree of service records
    private String          _desktopUID;    // UID representing the Desktop service
record
    private UiApplication   _app;           // Application instance

    public static void main( String[] args )
    {
        ServiceRoutingDemo demo = new ServiceRoutingDemo();
        demo.enterEventDispatcher();
    } 

    public ServiceRoutingDemo()
    {       
        // Save the current application isntance for later use.
        _app = UiApplication.getUiApplication();    

        // Create the MainScreen and add the appropriate UI fields
        _screen = new MainScreen();
        _screen.setTitle( "Service Routing Demo" );

        ServiceRouting sr = ServiceRouting.getInstance();
        sr.addListener( this );
        _statusField = new RichTextField( sr.isSerialBypassActive() ? CONNECTED : DISCONNECTED );

        _screen.add( _statusField );

        _treeField = new TreeField( this, Field.FOCUSABLE );
        _treeField.setEmptyString( "* No Service Books *", 0 );
        _treeField.setDefaultExpanded( false );
        _screen.add( _treeField );      

        pushScreen( _screen );       

        // Fill out the tree based on the current service records
        showServices();
    }

    /**
     * This method will enumerate through all of the services on the
     * handheld and indicate whether that service is enabled for
     * serial bypass.  This will also be updated when serial bypass
     * is connected or disconnected for the handheld using the listener.
     */
    private void showServices()
    {
        // Remove all of the items from the listField.
        _treeField.deleteAll();

        // Get a copy of the ServiceRouting class.
        ServiceRouting serviceRouting = ServiceRouting.getInstance();       

        // Add in our new items by trolling through the ServiceBook API.
        ServiceBook sb = ServiceBook.getSB();
        ServiceRecord[] records = sb.getRecords();
        if( records == null ) {
            return;
        }

        int rootNode = _treeField.addChildNode( 0, "Service Records" );      

        int numRecords = records.length;
        for( int i = 0; i < numRecords; i++ ) {
            String name = records[i].getName();
            String description = records[i].getDescription();
            if( description == null || description.length() == 0 ) {
                description = "No description available.";
            }
            String uid = records[i].getUid();
            boolean serialBypass = serviceRouting.isSerialBypassActive( uid );
 

            int newParentNode = _treeField.addChildNode( rootNode, name );
            _treeField.addChildNode( newParentNode, description );
            _treeField.addChildNode( newParentNode, uid );
            _treeField.addChildNode( newParentNode, serialBypass ? CONNECTED : DISCONNECTED );

            // Perform the check for the Desktop SerialRecord
            if( name != null && name.equals( DESKTOP )) {
                _desktopUID = uid;
            }
        }

        _treeField.setCurrentNode( rootNode ); // Set the root as the starting point.
    } 

    /////////////////////////////////////////////////////////////////
    /// ServiceRoutingListener Interface Implementation   ///
    ///////////////////////////////////////////////////////////////

    /**
     * When a BlackBerry data service routing changes, this method is invoked.
     * <p>
     *  @param      service         The relevant service, a UID of a {@link ServiceRecord}.
     *  @param      serviceState    True if the associated service has undergone a routing change. You can query for the
     *  particular routing method via {@link ServiceRouting#isSerialBypassActive}
     */
    public void serviceRoutingStateChanged( String service, boolean serviceState )
    {
        UpdateThread thread = new UpdateThread( service, serviceState );
        _app.invokeLater( thread );
    }   

    /////////////////////////////////////////////////////////////
    /// TreeFieldCallback Interface Implementation            ///
    /////////////////////////////////////////////////////////////   

    /**
     * Invoked when a particular tree item requires painting.
     *
     * <p> The graphics context passed to this method represents the entire
     * tree, not just the row for repainting.  Accordingly, the y parameter
     * indicates how far down in the field's extent the repaint should occur.
     *
     * @param treeField Tree field that requires repainting.
     * @param graphics Graphics context for the list.
     * @param index Row index to draw.
     * @param y Distance from the top of the tree field for painting.
     * @param width Width of the area remaining to draw the item (accounting for
     * the indent).
     * @param indent Number of pixels that should be reserved due to the nesting
     * depth of the current item.

     * */
    public void drawTreeItem( TreeField treeField, Graphics graphics, int node, int y, int width, int indent )
    {
        if( treeField != _treeField ) {
            return;
        }       

        Object cookie = _treeField.getCookie( node );
        if( cookie instanceof String ) {
            String text = (String)cookie;
            graphics.drawText( text, indent, y, Graphics.ELLIPSIS, width );
        }
    }

    //////////////////////////////////////////////////////////////////
    /// UpdateThread Implementation                              ///
    /////////////////////////////////////////////////////////////////

    private class UpdateThread extends Thread
    {
        private String      _service;
        private boolean     _serviceState;

        public UpdateThread( String service, boolean serviceState )
        {
            _service = service;
            _serviceState = serviceState;
        }

        public void run()
        {
            _statusField.setText( ServiceRouting.getInstance().isSerialBypassActive() ? CONNECTED : DISCONNECTED );
            showServices();

            // Show an indication to the user if the desktop service is available over Serial bypass
            if( _service.equals( _desktopUID )) {
                if( _serviceState ) {
                    Dialog.inform( "Desktop Serial Bypass available" );
                } else {
                    Dialog.inform( "Desktop Serial Bypass unavailable" );
                }
            }
        }
    }
}

** This article and sample code is provided for informational purposes only. It is not to be copied, distributed, disclosed or reproduced, in full or in part in any way without express written consent from RIM. **


© 2005 Research In Motion Limited. All rights reserved. The BlackBerry and RIM families of related marks, images and symbols are the exclusive properties and trademarks of Research In Motion Limited. RIM, Research In Motion, ‘Always On, Always Connected’ and BlackBerry are registered with the U.S. Patent and Trademark Office and may be pending or registered in other countries. All other brands, product names, company names, trademarks and service marks are the properties of their respective owners. The specifications and features contained in this document are subject to change without notice. All other brands, product names, company names, trademarks and service marks are the properties of their respective owners. Prices subject to change without notice. Research In Motion Limited presents information about third party products and services on BlackBerry Developer for your information. However, since Research In Motion Limited relies on information provided by outside sources, it makes no warranty or guarantee concerning the features, reliability or pricing of third party products or services, or their compatibility with any Research In Motion Limited products.

Research In Motion Limited | 295 Phillip Street | Waterloo, Ontario | Canada N2L 3W8