/*
* ServiceRoutingDemo.java
*
* Copyright � 1998-2011 Research In Motion Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* Note: For the sake of simplicity, this sample application may not leverage
* resource bundles and resource strings. However, it is STRONGLY recommended
* that application developers make use of the localization features available
* within the BlackBerry development platform to ensure a seamless application
* experience across a variety of languages and geographies. For more information
* on localizing your application, please refer to the BlackBerry Java Development
* Environment Development Guide associated with this release.
*/
package com.rim.samples.device.serviceroutingdemo;
import net.rim.device.api.servicebook.ServiceBook;
import net.rim.device.api.servicebook.ServiceRecord;
import net.rim.device.api.servicebook.ServiceRouting;
import net.rim.device.api.servicebook.ServiceRoutingListener;
import net.rim.device.api.ui.DrawStyle;
import net.rim.device.api.ui.Field;
import net.rim.device.api.ui.Graphics;
import net.rim.device.api.ui.UiApplication;
import net.rim.device.api.ui.component.Dialog;
import net.rim.device.api.ui.component.RichTextField;
import net.rim.device.api.ui.component.TreeField;
import net.rim.device.api.ui.component.TreeFieldCallback;
import net.rim.device.api.ui.container.MainScreen;
/**
* This application showcases 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.
*/
public class ServiceRoutingDemo extends UiApplication implements
TreeFieldCallback, ServiceRoutingListener {
private final MainScreen _screen; // Screen shown to the user.
private final RichTextField _statusField; // Field containing connected or
// disconnected string.
private final TreeField _treeField; // Tree of service records.
private String _desktopUID; // UID representing the Desktop service record.
private final UiApplication _app; // Application instance.
/**
* Entry point for application.
*
* @param args
* Command line arguments (not used)
*/
public static void main(final String[] args) {
// Create a new instance of the application and make the currently
// running thread the application's event dispatch thread.
final ServiceRoutingDemo demo = new ServiceRoutingDemo();
demo.enterEventDispatcher();
}
/**
* Default constructor.
*/
public ServiceRoutingDemo() {
// Save the current application instance for later use.
_app = UiApplication.getUiApplication();
// Create the MainScreen and add the appropriate UI fields.
_screen = new MainScreen();
_screen.setTitle("Service Routing Demo");
final ServiceRouting sr = ServiceRouting.getInstance();
sr.addListener(this);
_statusField =
new RichTextField(
sr.isSerialBypassActive() ? "Serial Bypass: Connected"
: "Serial Bypass: Disconnected");
_screen.add(_statusField);
_treeField = new TreeField(this, Field.FOCUSABLE);
_treeField.setEmptyString("* No Service Records *", 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.
final ServiceRouting serviceRouting = ServiceRouting.getInstance();
// Add in our new items by trolling through the ServiceBook API.
final ServiceBook sb = ServiceBook.getSB();
final ServiceRecord[] records = sb.getRecords();
if (records == null) {
return;
}
final int rootNode = _treeField.addChildNode(0, "Service Records");
final int numRecords = records.length;
for (int i = 0; i < numRecords; i++) {
final String name = records[i].getName();
String description = records[i].getDescription();
if (description == null || description.length() == 0) {
description = "No description available";
}
final String uid = records[i].getUid();
final boolean serialBypass =
serviceRouting.isSerialBypassActive(uid);
final int newParentNode = _treeField.addChildNode(rootNode, name);
_treeField.addChildNode(newParentNode, description);
_treeField.addChildNode(newParentNode, uid);
_treeField.addChildNode(newParentNode,
serialBypass ? "Serial Bypass: Connected"
: "Serial Bypass: 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(final String service,
final boolean serviceState) {
// Passing the UpdateRunnable to invokeLater() ensures
// that it gets executed on this application's event thread.
final UpdateRunnable runnable =
new UpdateRunnable(service, serviceState);
_app.invokeLater(runnable);
}
// ///////////////////////////////////////////////////////////
// / 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 node
* Node 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(final TreeField treeField,
final Graphics graphics, final int node, final int y,
final int width, final int indent) {
if (treeField != _treeField) {
return;
}
final Object cookie = _treeField.getCookie(node);
if (cookie instanceof String) {
final String text = (String) cookie;
graphics.drawText(text, indent, y, DrawStyle.ELLIPSIS, width);
}
}
// ////////////////////////////////////////////////////////////////
// / UpdateRunnable Implementation ///
// ////////////////////////////////////////////////////////////////
/**
* This class is responsible for displaying the result of a service change.
*/
private class UpdateRunnable implements Runnable {
private final String _service;
private final boolean _serviceState;
/**
* Associates the service changed and its new state with this object.
*
* @param service
* The service that was changed
* @param serviceState
* The new service state
*/
private UpdateRunnable(final String service, final boolean serviceState) {
_service = service;
_serviceState = serviceState;
}
/**
* This displays whether or not serial bypass is still active and
* whether the desktop serial bypass is still available if the desktop
* service had changed state.
*
* @see java.lang.Runnable#run()
*/
public void run() {
_statusField.setText(ServiceRouting.getInstance()
.isSerialBypassActive() ? "Serial Bypass: Connected"
: "Serial Bypass: 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");
}
}
}
}
}