blackBerry_j2me-jde41_development_guide

blackBerry_j2me-jde41_development_guide
BlackBerry Java Development
Environment
Version 4.1.0
BlackBerry Application Developer Guide Volume 1:
Fundamentals
BlackBerry Java Development Environment Version 4.1.0 BlackBerry Application Developer Guide Volume 1: Fundamentals Volume 1:
Fundamentals
Last modified: 13 October 2005
Part number: SWD_X_JDE(EN)-001.002
At the time of publication, this documentation complies with the BlackBerry Java Development Environment Version 4.1.0.
©2005 Research In Motion Limited. All Rights Reserved. The BlackBerry and RIM families of related marks, images, and symbols are the
exclusive properties of Research In Motion Limited. RIM, Research In Motion, “Always On, Always Connected”, the “envelope in motion”
symbol, and BlackBerry are registered with the U.S. Patent and Trademark Office and might be pending or registered in other countries.
The Bluetooth word mark and logos are owned by the Bluetooth SIG, Inc. and any use of such marks by Research In Motion Limited is under
license. IBM, Lotus, Domino, and Lotus Notes are either registered trademarks or trademarks of International Business Machines Corporation in
the United States, other countries, or both. JavaScript, Java, and Javadoc is a trademark of Sun Microsystems, Inc. in the United States and
other countries. Microsoft, Outlook, PowerPoint, and Windows are either registered trademarks or trademarks of Microsoft Corporation in the
United States and/or other countries. Novell and GroupWise are either registered trademarks or trademarks of Novell, Inc. in the United States
and other countries. All other brands, product names, company names, trademarks, and service marks are the properties of their respective
owners. The Casira general-purpose development system is a trademark of CSR.
The BlackBerry device and/or associated software are protected by copyright, international treaties and various patents, including one or more
of the following U.S. patents: 6,278,442; 6,271,605; 6,219,694; 6,075,470; 6,073,318; D445,428; D433,460; D416,256. Other patents
are registered or pending in various countries around the world. Visit www.rim.com/patents.shtml for a current listing of applicable patents.
This document is provided “as is” and Research In Motion Limited and its affiliated companies (“RIM”) assume no responsibility for any
typographical, technical or other inaccuracies in this document. RIM reserves the right to periodically change information that is contained in
this document; however, RIM makes no commitment to provide any such changes, updates, enhancements or other additions to this document
to you in a timely manner or at all. RIM MAKES NO REPRESENTATIONS, WARRANTIES, CONDITIONS OR COVENANTS, EITHER EXPRESS OR
IMPLIED (INCLUDING WITHOUT LIMITATION, ANY EXPRESS OR IMPLIED WARRANTIES OR CONDITIONS OF FITNESS FOR A PARTICULAR
PURPOSE, NON-INFRINGEMENT, MERCHANTABILITY, DURABILITY, TITLE, OR RELATED TO THE PERFORMANCE OR NON-PERFORMANCE OF
ANY SOFTWARE REFERENCED HEREIN OR PERFORMANCE OF ANY SERVICES REFERENCED HEREIN). IN CONNECTION WITH YOUR USE OF
THIS DOCUMENTATION, NEITHER RIM NOR ITS RESPECTIVE DIRECTORS, OFFICERS, EMPLOYEES OR CONSULTANTS SHALL BE LIABLE TO
YOU FOR ANY DAMAGES WHATSOEVER BE THEY DIRECT, ECONOMIC, COMMERCIAL, SPECIAL, CONSEQUENTIAL, INCIDENTAL,
EXEMPLARY OR INDIRECT DAMAGES, EVEN IF RIM HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES, INCLUDING WITHOUT
LIMITATION, LOSS OF BUSINESS REVENUE OR EARNINGS, LOST DATA, DAMAGES CAUSED BY DELAYS, LOST PROFITS, OR A FAILURE TO
REALIZE EXPECTED SAVINGS.
This document might contain references to third party sources of information, hardware or software, products or services and/or third party
web sites (collectively the “Third-Party Information”). RIM does not control, and is not responsible for, any Third-Party Information, including,
without limitation the content, accuracy, copyright compliance, compatibility, performance, trustworthiness, legality, decency, links, or any
other aspect of Third-Party Information. The inclusion of Third-Party Information in this document does not imply endorsement by RIM of the
Third Party Information or the third party in any way. Installation and use of Third Party Information with RIM's products and services may
require one or more patent, trademark or copyright licenses in order to avoid infringement of the intellectual property rights of others. Any
dealings with Third Party Information, including, without limitation, compliance with applicable licenses and terms and conditions, are solely
between you and the third party. You are solely responsible for determining whether such third party licenses are required and are responsible
for acquiring any such licenses relating to Third Party Information. To the extent that such intellectual property licenses may be required, RIM
expressly recommends that you do not install or use Third Party Information until all such applicable licenses have been acquired by you or on
your behalf. Your use of Third Party Information shall be governed by and subject to you agreeing to the terms of the Third Party Information
licenses. Any Third Party Information that is provided with RIM's products and services is provided "as is". RIM makes no representation,
warranty or guarantee whatsoever in relation to the Third Party Information and RIM assumes no liability whatsoever in relation to the Third
Party Information even if RIM has been advised of the possibility of such damages or can anticipate such damages.
.
Research In Motion Limited
295 Phillip Street
Waterloo, ON N2L 3W8
Canada
Published in Canada
Research In Motion UK Limited
Centrum House, 36 Station Road
Egham, Surrey TW20 9LF
United Kingdom
Contents
1
BlackBerry APIs......................................................................................................................................................... 8
Using BlackBerry APIs..................................................................................................................................................... 8
Using Java on BlackBerry devices .............................................................................................................................11
Application control ........................................................................................................................................................16
2
Writing BlackBerry Java applications ...............................................................................................................18
Application management ............................................................................................................................................18
Writing a sample application .....................................................................................................................................18
Reusing common code .................................................................................................................................................20
Using the BlackBerry IDE.............................................................................................................................................22
Using the command line..............................................................................................................................................26
Using the Bluetooth development environment .................................................................................................26
Using the Eclipse development environment .......................................................................................................27
Programming guidelines..............................................................................................................................................30
3
Creating user interfaces .......................................................................................................................................39
User interface APIs.........................................................................................................................................................39
Displaying user interface components ....................................................................................................................39
Managing use interface components ......................................................................................................................49
Creating custom user interface components.........................................................................................................53
Working with images ....................................................................................................................................................69
Drawing using graphics objects ................................................................................................................................73
Listening for changes to user interface objects....................................................................................................78
4
Using audio .............................................................................................................................................................80
Playing a tune from a supported audio format....................................................................................................80
Voicenotes API ................................................................................................................................................................80
5
Supporting media content ...................................................................................................................................81
PME content.....................................................................................................................................................................81
Playing media content..................................................................................................................................................83
Listening for media engine events............................................................................................................................85
Creating custom connections.....................................................................................................................................91
6
Connecting to networks .......................................................................................................................................95
HTTP and socket connections ....................................................................................................................................95
Using HTTP connections ..............................................................................................................................................95
Using HTTPS connections.........................................................................................................................................100
Using socket connections .........................................................................................................................................101
Using port connections .............................................................................................................................................102
Using Bluetooth serial port connections .............................................................................................................103
7
Using datagram connections........................................................................................................................... 111
Datagram connections...............................................................................................................................................111
Using UDP connections ............................................................................................................................................111
Using Mobitex networks ...........................................................................................................................................113
Sending and receiving SMS messages..................................................................................................................121
8
Localizing applications ...................................................................................................................................... 125
Resource files ................................................................................................................................................................125
Adding localization support to applications ......................................................................................................126
Retrieving strings from a resource file..................................................................................................................130
Managing resource files for application suites..................................................................................................133
9
Using IT policies .................................................................................................................................................. 135
IT policies .......................................................................................................................................................................135
Retrieve custom policies............................................................................................................................................135
Listening for policy changes ....................................................................................................................................135
10
Creating client/server push applications..................................................................................................... 137
Push applications ........................................................................................................................................................137
Client/server push requests.....................................................................................................................................137
Writing a client-side push application..................................................................................................................143
Writing a server-side push application.................................................................................................................146
Troubleshooting push applications .......................................................................................................................149
11
Using location information .............................................................................................................................. 151
Location API ..................................................................................................................................................................151
12
Packaging and deployment.............................................................................................................................. 166
Deploying applications using the BlackBerry Desktop Software ................................................................166
Deploying applications wirelessly..........................................................................................................................166
13
Testing and debugging...................................................................................................................................... 171
Test applications..........................................................................................................................................................171
Using the debug tools ...............................................................................................................................................179
A
Appendix: Format of .alx files ......................................................................................................................... 183
.alx files ...........................................................................................................................................................................183
B
Appendix: MDS services reference.................................................................................................................. 188
HTTP requests...............................................................................................................................................................188
HTTP responses ............................................................................................................................................................188
HTTPS support..............................................................................................................................................................189
Transcoders....................................................................................................................................................................190
Creating transcoders...................................................................................................................................................196
Compile and install transcoders .............................................................................................................................199
Glossary ................................................................................................................................................................. 201
Index....................................................................................................................................................................... 204
1
BlackBerry APIs
Using BlackBerry APIs
Using Java on BlackBerry devices
Application control
Using BlackBerry APIs
The BlackBerry® Java Development Environment (JDE) is designed to provide a complete set of APIs and tools for
you to develop Java™ applications that run on BlackBerry devices.
BlackBerry devices include a Java Platform Micro Edition (Java ME) runtime environment that is based on the
CLDC 1.1 and MIDP 2.0 specifications. BlackBerry API extensions provide additional capabilities and tighter
integration with BlackBerry devices.
You can use both CLDC/MIDP APIs and BlackBerry APIs in your application. To enable applications to run on any
Java Technology for the Wireless Industry (JTWI)-enabled device, write standard MIDP applications using only the
CLDC and MIDP APIs.
BlackBerry handheld software components
To view the API reference, on the taskbar, click Start > Programs > Research In Motion > BlackBerry JDE 4.1.0
> API JavaDoc Reference.
1: BlackBerry APIs
BlackBerry APIs
The BlackBerry APIs provide access to BlackBerry features for user interfaces, localization, networking, and other
capabilities.
Note: Access to additional APIs for features, such as advanced cryptography, synchronization, and messaging, is restricted. To use
these APIs, you must receive express written permission from an authorized signatory of Research In Motion®. See the BlackBerry
Application Developer Guide Volume 1: Fundamentals Volume 2: Advanced Topics for more information.
BlackBerry API package
Description
net.rim.blackberry.api.browser
This package enables applications to invoke the BlackBerry Browser. See the
BlackBerry Application Developer Guide Volume 2: Advanced Topics for more
information.
net.rim.blackberry.api.invoke
This package enables applications to invoke BlackBerry applications, such as tasks,
messages, memos, and phone. See the BlackBerry Application Developer Guide
Volume 2: Advanced Topics for more information.
net.rim.blackberry.api.mail
This package defines the functionality necessary to convert the components of internal
RIM messaging system objects into portable objects that are compatible with the mail
API. It also provides functionality for sending, receiving, and accessing messages. See
the BlackBerry Application Developer Guide Volume 2: Advanced Topics for more
information.
net.rim.blackberry.api.mail.event
This package defines messaging events and listener interfaces to manage mail events.
See the BlackBerry Application Developer Guide Volume 2: Advanced Topics for more
information.
net.rim.blackberry.api.menuitem
This package enables applications to add custom menu items to BlackBerry
applications, such as the address book, calendar, and messages. See the BlackBerry
Application Developer Guide Volume 2: Advanced Topics for more information.
net.rim.blackberry.api.options
This package enables applications to add items to the BlackBerry device options. See
the BlackBerry Application Developer Guide Volume 2: Advanced Topics for more
information.
net.rim.blackberry.api.pdap
This package enables applications to interact with BlackBerry personal information
management (PIM) applications, including address book, tasks, and calendar. The
MIDP package javax.microedition.pim provides similar functionality. See the
BlackBerry Application Developer Guide Volume 2: Advanced Topics for more
information.
net.rim.blackberry.api.phone
This package provides access to advanced features of the phone application. See the
BlackBerry Application Developer Guide Volume 2: Advanced Topics for more
information.
net.rim.blackberry.api.phone.phonelogs
This package provides access to the phone call history. See the BlackBerry Application
Developer Guide Volume 2: Advanced Topics for more information.
net.rim.device.api.bluetooth
This package enables BlackBerry applications to communicate with Bluetooth®
wireless technology enabled devices on a Bluetooth serial port connection. See “Using
Bluetooth serial port connections” on page 103 for more information.
net.rim.device.api.browser.field
This package enables applications to display browser fields in the user interfaces. See
the BlackBerry Application Developer Guide Volume 2: Advanced Topics for more
information.
net.rim.device.api.browser.plugin
This package enables applications to add support for additional MIME types to the
BlackBerry Browser. See the BlackBerry Application Developer Guide Volume 2:
Advanced Topics for more information.
9
BlackBerry Application Developer Guide Volume 1: Fundamentals
BlackBerry API package
Description
net.rim.device.api.collection
net.rim.device.api.collection.util
This package defines interfaces and utility classes for managing data collections. See
"Collections" on page 13 for more information.
net.rim.device.api.compress
This package provides utilities for compressing data, in both the GZip and Zlib formats.
See “Compression” on page 13 for more information.
net.rim.device.api.i18n
This package provides classes to support the localization of applications on BlackBerry
devices. See “Localizing applications” on page 125 for more information
net.rim.device.api.io
This package provides a library of custom BlackBerry classes for managing data input
and output.
net.rim.device.api.mime
This package provides classes for working with streams of MIME-encoded data.
net.rim.device.api.notification
This package provides methods to trigger event notifications and respond to systemwide and application-specific events. See the BlackBerry Application Developer Guide
Volume 2: Advanced Topics for more information.
net.rim.device.api.servicebook
This package enables applications to add, delete, and access service book entries. See
the BlackBerry Application Developer Guide Volume 2: Advanced Topics for more
information.
net.rim.device.api.system
This package provides access to system-level functionality, including event listeners for
the keyboard and trackwheel, image creation and support, and application control.
net.rim.device.api.ui
This package provides enhanced functionality to control the BlackBerry user interface,
including screen and field layout managers, field type support, and focus, scroll, and
change listeners. See "User interface APIs" on page 39 for more information.
net.rim.device.api.ui.component
This package provides a library of interface components for creating UI applications.
See "Displaying user interface components" on page 39 for more information.
net.rim.device.api.ui.container
This package provides a library of interface manager components for creating UI
applications. See "Managing use interface components" on page 49 for more
information.
net.rim.device.api.ui.text
This package provides classes to filter text strings containing various types of data,
such as phone numbers or URLs.
net.rim.device.api.util
This package provides utility methods and interfaces, including classes for arrays, hash
tables, and string matching.
10
1: BlackBerry APIs
CLDC APIs
CLDC API package
Description
java.io
This package provides for system input and output through data streams.
java.lang
This package provides classes that are fundamental to the design of the Java
programming language.
java.lang.ref
This package provides reference-object classes, which support a limited degree of
interaction with the garbage collector.
java.util
This package contains the collection classes, date and time facilities, and miscellaneous
utility classes.
javax.microedition.io
This package contains classes for generic connections.
MIDP APIs
MIDP API package
Description
javax.microedition.lcdui
This package contains the MIDP UI API, which provides a set of features for
implementation of user interfaces for MIDP applications.
javax.microedition.lcdui.game
This package contains classes that enable the development of rich gaming content for
BlackBerry devices.
javax.microedition.midlet
This package defines Mobile Information Device Profile applications and the interactions
between the application and the environment in which the application runs.
Note: The BlackBerry IDE enables arguments to be passed to a BlackBerry CLDC
Application on startup. This functionality does not exist for MIDlets created in the
BlackBerry IDE for use on a BlackBerry.
javax.microedition.pki
This package defines certificates that are used to authenticate information for secure
connections.
javax.microedition.rms
This package provides a mechanism for MIDlets to store and retrieve persistent data.
PDAP APIs
MIDP API package
Description
javax.microedition.pim
This package provides a standard mechanism for accessing PIM information.
Using Java on BlackBerry devices
Source code is compiled and packaged into .cod files. The .cod files are loaded onto BlackBerry devices and run by
their virtual machines (VM).
Note: The .cod file name is limited to 128 bytes.
11
BlackBerry Application Developer Guide Volume 1: Fundamentals
The BlackBerry JDE uses a split VM architecture, as described in the CLDC specification. To reduce the amount of
memory and processing power that a BlackBerry device requires, part of the class loading process, called
preverification, occurs before the Java code is loaded onto the BlackBerry device. The BlackBerry IDE preverifies
source files automatically before packaging them into .cod files. The VM performs the remainder of verification
during class loading onto BlackBerry devices.
Restrictions
The BlackBerry VM has the following restrictions, as specified by CLDC 1.1:
• no object finalization
• no user class loading
• no reflection, therefore no support for Remote Method Invocation (RMI) or Jini™ network technology
• no native methods
• no Runtime.exec() for running external processes
Multithreading
The BlackBerry Java environment provides a true multithreading environment for running applications. This
environment enables multiple applications to run simultaneously, events to broadcast to multiple applications,
and long operations or listener threads to run in the background.
Persistent storage
Data stored in flash memory persists between BlackBerry device resets. Store data on the BlackBerry device in one
of two ways:
• using MIDP record stores
• using the BlackBerry persistence model
See the BlackBerry Application Developer Guide Volume 1: Fundamentals Volume 2: Advanced Topics for more
information on storing persistent data using the BlackBerry APIs.
Network communication
The BlackBerry JDE implements network communication according to the MIDP 2.0 specification. It provides a
variety of connectivity options, including the ability to securely connect behind corporate firewalls using proxied
HTTP connections.
The BlackBerry JDE provides the following connection types:
• stream connections (StreamConnection interface), including:
• HTTP connections (HttpConnection interface)
• HTTPS connections (HttpsConnection interface)
• socket connections (SocketConnection interface)
12
1: BlackBerry APIs
• secure socket connections (SecureConnection interface)
• serial connections to a communication port on the BlackBerry device (CommConnection interface)
• datagram connections (DatagramConnection interface), including:
• UDP datagram connections (UDPDatagramConnection interface)
The javax.microedition.io.PushRegistry class maintains a list of inbound connections to the BlackBerry
device.
See “Connecting to networks” on page 95 for more information. See “Connector” in the API Reference for detailed
information on opening each of the connection types.
Streams
The BlackBerry JDE provides the standard interfaces and classes for streams that are included in the CLDC
java.io package.
MIME encoding
The BlackBerry JDE provides MIMEInputStream and MIMEOutputStream classes for reading and writing a MIMEencoded data stream.
Class
Description
MIMEInputStream
This class implements a stream that reads a MIME message and then formats and parses the message into
its parts according to the MIME standard.
MIMEOutputStream
This class implements an output stream that can format output into parts according to the MIME standard.
This class does not perform the actual data encoding, so you must encode data before writing it to this
stream.
Compression
The BlackBerry JDE provides classes, in the net.rim.device.api.compress package, for reading data streams
compressed using either the Zlib or GZip formats. These classes behave much like the corresponding classes in the
java.util.zip package in Java SE.
By default, compression is enabled and BlackBerry devices can write valid GZip and Zlib files with the content of
such files compressed. Decompression support is also available.
Collections
The BlackBerry JDE provides a set of interfaces and utility classes for managing collections on the BlackBerry
device.
The net.rim.device.api.collection package includes interfaces that define various types of collections, such
as lists, sets, and maps, for specific types of data. These interfaces define capabilities similar to the List, Set, and
Map interfaces in the Java SE Collections Framework.
Implement these interfaces in your own classes, or use the utility classes that are provided in the
net.rim.device.api.collection.util package.
13
BlackBerry Application Developer Guide Volume 1: Fundamentals
Vectors
The standard java.util.Vector class implements a resizeable array of objects. The BlackBerry JDE also provides
convenience classes, such as net.rim.device.api.util.IntVector and
net.rim.device.api.util.ByteVector for working with arrays of primitive types.
For large arrays of data (more than 10 or 15 KB), the BlackBerry JDE provides the BigVector, BigLongVector,
and BigIntVector classes in net.rim.device.api.collection.util. These classes are like normal vectors,
except that they are optimized for inserting items at any location. In contrast, if you make random changes using
standard large vectors, large amounts of data move between flash memory and RAM.
Lists
The BlackBerry JDE provides classes in the net.rim.device.api.collection.util package to manage lists of
elements.
Class
Description
SortedReadableList and
UnsortedReadableList
Use these classes to maintain sorted or unsorted lists of elements. The SortedReadableList class
requires you to use a comparator object to sort the items in the list; each item that you add to the list
must be recognized as valid by this comparator.
IntSortedReadableList and
LongSortedReadableList
Use these classes to automatically sort lists of integers or elements that are associated with long integer
keys.
BigSortedReadableList and
BigUnsortedReadableList
Use these classes to store large collections of data (more than 10 or 15 KB). These classes do not store
data in an array, so you can make random changes to large data collections more efficiently.
ReadableListCombiner
Use this class to combine two or more ReadableList objects and present them as a single
ReadableList.
ReadableListUtil
Use this class, which provides utility methods such as getAt() and getIndex(), to retrieve data
from readable lists.
Hash tables
In addition to the standard java.util.Hashtable class that the CLDC provides, the BlackBerry JDE includes a
specialized net.rim.device.api.collection.util.LongHashtableCollection class, which provides a hash
table collection that uses long integers as keys. With a LongHashtableCollection object, write operations occur
as a map (using a key-element pair) and read operations occur as a map or as a set (retrieving the elements in the
collection as an array).
Event listeners
Event listener interfaces are divided by event type. Each application registers to receive specific types of events.
The application event queue then dispatches events to the appropriate listeners.
Applications can implement the appropriate listener interfaces or override the listener methods on the various
Screen objects. Most applications implement the KeyListener and TrackwheelListener interfaces and
register the listeners to receive keyboard and trackwheel events. The keyboard and trackwheel are the primary
means by which users interact with applications.
14
1: BlackBerry APIs
The following event listeners are located in the net.rim.device.api.system package:
Listener interface
Type of event
AlertListener
Implement this interface to listen for alert events.
BluetoothSerialPortListener
Implement this interface to listen for Bluetooth serial port events, such as the opening of a Bluetooth
serial port connection either as a server or client.
GlobalEventListener
Implement this interface to listen for global events that are broadcast to all applications.
HolsterListener
Implement this interface to listen for holster events, such as the insertion or removal of the BlackBerry
device from the holster.
IOPortListener
Implement this interface to listen for I/O port events.
KeyListener
Implement this interface to listen for keyboard events, such as the user pressing or releasing a key.
RealTimeClockListener
Implement this interface to listen for real-time clock events, such as the clock being updated.
SerialPortListener
Implement this interface to listen for serial port events, such as a change in the status of data being
sent to the serial port connection, for BlackBerry devices that are connected to the computer serial
port.
SystemListener
Implement this interface to listen for system events, such as changes to battery status and power.
TrackwheelListener
Implement this interface to listen for trackwheel events, such as the clicking of the trackwheel.
USBPortListener
Implement this interface to listen for USB port events, such as the status of data being sent to the
USB port connection, for BlackBerry devices that are connected to the computer USB port.
System capabilities
The classes in the net.rim.device.api.system package provide access to the Java VM and system-wide
resources on the BlackBerry device.
Retrieve radio information
The RadioInfo class provides access to information on the status of the radio.
Retrieve device information
The DeviceInfo class provides access to the following information on BlackBerry devices:
• battery power and status
• BlackBerry device ID
• idle time
• platform version
Notify users of system events
The Alert class enables applications application to notify users when an event, such as the arrival of a new
message, occurs.
Monitor memory usage
Use the static methods provided by the Memory class to retrieve statistics on VM memory usage.
15
BlackBerry Application Developer Guide Volume 1: Fundamentals
Some of the utility methods in the Memory class return a MemoryStats object. Use the utility methods the
MemoryStats class provides to retrieve detailed information on the memory and storage that is available on the
BlackBerry device.
Log events
The EventLogger class enables applications to store event logs in the persistent store. The BlackBerry device
maintains an event queue so that, when the log is full, the oldest events are deleted as new events are added.
Users can view the system event log on the BlackBerry device by holding the Alt key and typing lglg.
Utilities
The BlackBerry JDE provides a set of utilities in the net.rim.device.api.util package. Many of these classes
provide similar capabilities to utilities in Java SE.
• The Comparator interface defines methods that impose order on a collection of objects.
• The Arrays class provides methods for working with arrays, such as sorting and searching, and viewing arrays
as lists.
• The BitSet class maintains a collection of bits.
The net.rim.device.api.util package includes several classes for managing specific types of data collections,
including vectors, hash tables, maps, and stacks.
Application control
Application control enables system administrators to perform the following actions:
• limit internal connections (connections behind a corporate firewall)
• limit external connections
• limit local connections (serial and USB connections)
• limit access to the key store
• limit access to particular APIs
• prevent third-party applications from existing on BlackBerry devices
See the BlackBerry Enterprise Server Handheld Management Guide for more information on application control.
APIs, classes, and methods with limited access
Applications that use the following restricted APIs, classes, and methods can load on BlackBerry devices, but
throw a ControlledAccessException or NoClassDefFoundError at runtime if they access an API not
permitted under application control.
Class, method or API
Default value
Application menu item API (net.rim.blackberry.api.menuitem)
allowed
16
1: BlackBerry APIs
Class, method or API
Default value
Bluetooth API (net.rim.device.api.bluetooth)
allowed
Connector.open() (javax.microedition.io)
prompt
Note: Internal and external connections are
governed by different application control
policies
DeviceKeyStore class (net.rim.device.api.crypto.keystore)
allowed
EventInjector class (net.rim.device.api.system)
not allowed
HTTP Filter API (net.rim.device.api.io.http)
not allowed
Notification API (net.rim.device.api.notification)
allowed
Phone API and invocation API (used to invoke the phone application)
allowed (user prompted by default)
(net.rim.blackberry.api.phone and net.rim.blackberry.api.invoke)
Phone logs API (net.rim.blackberry.api.phone.phonelogs)
allowed (user prompted by default)
PIM API (net.rim.blackberry.api.pdap)
allowed
RuntimeStore class (net.rim.device.api.system)
allowed
SerialPort class (net.rim.device.api.system)
allowed
Session class (net.rim.blackberry.api.mail)
allowed
StringPatternRepository class (net.rim.device.api.util)
allowed
USBPort class (net.rim.device.api.system)
allowed
17
2
Writing BlackBerry Java applications
Application management
Writing a sample application
Reusing common code
Using the BlackBerry IDE
Using the command line
Using the Bluetooth development environment
Using the Eclipse development environment
Programming guidelines
Application management
When the BlackBerry device starts, the VM loads an application manager, which manages all Java applications on
the BlackBerry device. The application manager functions as the central dispatcher of operating system events for
other Java applications.
Applications that provide a user interface extend the net.rim.device.api.ui.UiApplication class. This class
provides methods for applications to register event listeners, manage threads, and manage UI components.
Applications that do not provide a user interface extend the net.rim.device.api.system.Application class.
BlackBerry applications start at main(). When an application starts, its main() thread calls
enterEventDispatcher() to start handling events. This thread runs all drawing and event-handling code and
waits for events on the application queue.
When the application manager receives an event, it copies the event to the appropriate queues, which enables the
application manager to direct messages to certain programs. For example, only the foreground application
receives user input messages.
Writing a sample application
Extend the UiApplication base class
Each application that provides a user interface extends the UiApplication base class. The UiApplication class
defines methods for applications to establish an event thread, and display and maintain Screen objects.
Define main()
In main(), create a new object for the application. Invoke enterEventDispatcher() to cause the application to
enter the event thread and start processing messages.
2: Writing BlackBerry Java applications
public static void main(String[] args) {
HelloWorld theApp = new HelloWorld();
theApp.enterEventDispatcher();
}
Define a constructor
Define the default constructor for your application. The default constructor invokes
UiApplication.pushScreen() to display the screen that appears when the application starts. In this example,
the screen is a new instance of HelloWorldScreen, which you define in the following section:
public HelloWorld() {
pushScreen(new HelloWorldScreen());
}
Define the main screen
To define the main screen of the application UI, extend the MainScreen class. The MainScreen class is a subclass
of Screen, which implements the TrackwheelListener and KeyboardListener interfaces. These interfaces
receive and respond to user interaction. If you extend the Screen class or one of its subclasses, you do not have to
implement the TrackwheelListener and KeyboardListener interfaces.
Your class should override at least two of the MainScreen methods, the default constructor and onClose().
In this example, the constructor invokes the MainScreen constructor. By default, MainScreen provides the
following features:
• A default menu with a Close menu item.
• Default close action when the user clicks Close or presses Escape. To provide custom behavior, such as
displaying a dialog box alert, when the user clicks the Close menu item or presses the Escape button,
override onClose().
• An instance of RichTextField, a read-only rich text field that can receive focus. See "Provide screen
navigation" on page 40 for more information on adding UI components to a screen.
• A context menu with a Select menu item. See "Create custom context menus" on page 60 for more
information.
Code example
The following example creates a screen that contains a rich text field. When the rich text field receives focus, the
menu includes a Close item and a Select context menu item.
Example: HelloWorld.java
/**
* HelloWorld.java
* Copyright (C) 2001-2005 Research In Motion Limited. All rights reserved.
*/
package com.rim.samples.docs.helloworld;
19
BlackBerry Application Developer Guide Volume 1: Fundamentals
import
import
import
import
import
net.rim.device.api.ui.*;
net.rim.device.api.ui.component.*;
net.rim.device.api.ui.container.*;
net.rim.device.api.system.*;
com.rim.samples.docs.resource.*;
public class HelloWorld extends UiApplication {
public static void main(String[] args) {
HelloWorld theApp = new HelloWorld();
theApp.enterEventDispatcher();
}
public HelloWorld() {
pushScreen(new HelloWorldScreen());
}
}
final class HelloWorldScreen extends MainScreen {
public HelloWorldScreen() {
super();
LabelField title = new LabelField(“HelloWorld Sample”, LabelField.ELLIPSIS
| LabelField.USE_ALL_WIDTH);
setTitle(title);
add(new RichTextField(“Hello World!”));
}
public boolean onClose() {
Dialog.alert(“Goodbye!”);
System.exit(0);
return true;
}
}
Reusing common code
Abstract base classes enable you to implement and reuse common functionality across multiple classes. Each
application can extend a single base class.
In the BlackBerry Integrated Development Environment (BlackBerry IDE), add the base class to a library project.
Create separate projects for each application and define a dependency on the library project.
Code example
The sample applications in this guide extend the BaseApp class, which implements the following functionality:
• extends the UiApplication class
• implements the KeyListener and TrackwheelListener interfaces
• defines variables, such as common menu items
• defines a method to create an application menu
• defines a method for menu selection
20
2: Writing BlackBerry Java applications
• defines an abstract method to exit the application
Example: BaseApp.java
/*
* BaseApp.java
* Copyright (C) 2001-2005 Research In Motion Limited. All rights reserved.
*/
package com.rim.samples.docs.baseapp;
import
import
import
import
import
import
net.rim.device.api.i18n.*;
net.rim.device.api.system.*;
net.rim.device.api.ui.container.*;
net.rim.device.api.ui.*;
net.rim.device.api.ui.component.*;
com.rim.samples.docs.resource.*;
public abstract class BaseApp extends UiApplication implements BaseAppResource,
KeyListener, TrackwheelListener {
private MenuItem _closeItem;
private static ResourceBundle _resources =
ResourceBundle.getBundle(BUNDLE_ID, BUNDLE_NAME);
/* Constructor for the abstract base class. */
public BaseApp() {
_closeItem = new MenuItem(_resources, MENUITEM_CLOSE, 200000, 10) {
public void run() {
onExit();
System.exit(0);
}
};
}
/* Override this method to add custom menu items. */
protected void makeMenu( Menu menu, int instance) {
Field focus = UiApplication.getUiApplication().
getActiveScreen().getLeafFieldWithFocus();
if(focus != null) {
ContextMenu contextMenu = focus.getContextMenu();
if( !contextMenu.isEmpty()) {
menu.add(contextMenu);
menu.addSeparator();
}
}
menu.add(_closeItem);
}
/* Invoked when the trackwheel is clicked. */
public boolean trackwheelClick( int status, int time ) {
Menu menu = new Menu();
makeMenu( menu, 0);
menu.show();
return true;
}
/* Invoked when the trackwheel is released. */
public boolean trackwheelUnclick( int status, int time ) {
return false;
}
/* Invoked when the trackwheel is rolled. */
21
BlackBerry Application Developer Guide Volume 1: Fundamentals
public boolean trackwheelRoll(int amount, int status, int time) {
return false;
}
public boolean keyChar(char key, int status, int time) {
/* Intercept the ESC key and exit the application. */
boolean retval = false;
switch (key) {
case Characters.ESCAPE:
onExit();
System.exit(0);
retval = true;
break;
}
return retval;
}
/* Implementation of KeyListener.keyDown(). */
public boolean keyDown(int keycode, int time) {
return false;
}
/* Implementation of KeyListener.keyRepeat(). */
public boolean keyRepeat(int keycode, int time) {
return false;
}
/* Implementation of KeyListener.keyStatus(). */
public boolean keyStatus(int keycode, int time) {
return false;
}
/* Implementation of KeyListener.keyUp(). */
public boolean keyUp(int keycode, int time) {
return false;
}
protected abstract void onExit();
}
Using the BlackBerry IDE
To write, debug, and compile applications, use the BlackBerry IDE that is part of the BlackBerry JDE.
Note: The BlackBerry IDE version 4.1 uses the Sun®Java Development Kit version 5.0
Create a workspace
1. In the BlackBerry IDE, on the File menu, click New Workspace.
2. In the Workspace name field, type a name without a file name extension.
3. In the Create in this directory field, type a folder.
4. Click OK.
22
2: Writing BlackBerry Java applications
Create a project
Note: Create project files in the subdirectories of the folder that contains the workspace file.
1. In the BlackBerry IDE, on the Project menu, click Create New Project.
2. In the Project name field, type a project name without a file name extension.
3. In the Create project in this directory field, type the folder in which to create the project file.
4. Click OK.
5. In the workspace Files pane, double-click the project name to set the project properties.
See the BlackBerry Integrated Development Environment Online Help for information on project properties.
Create source files
Note: Save source files in the same folder as the project file. As with all Java programs, create a folder structure for your source code
that matches the package hierarchy that you use for your classes.
1. In the Blackberry IDE, on the File menu, click New.
2. In the Source file name field, type a file name with the .java file name extension.
3. In the Create source file in this directory field, type a folder name.
4. Click OK.
5. In the editor pane, right-click the file, and then click Insert into project.
6. Select a project.
7. Click OK.
Integrate source file management tools with the BlackBerry IDE
You can use the BlackBerry IDE with different source control programs. The BlackBerry IDE enables you to set the
“check out”, “add new file” and “revert” options for source control programs. After you configure the options for a
particular source control program, the BlackBerry IDE can automatically check out files, run preset commands,
revert changes, and add newly created files to the source control program.
1. In the BlackBerry IDE, on the File menu, click Edit > Preferences.
2. Click the Source Control tab.
3. Click the Check out tab.
4. In the Check out field, type the command to open a file for edit. For example type:
p4 edit %1
Note: The %1 parameter represents the name and absolute path of a file. For example: for a file called foo.java located in
c:\mypath, when the BlackBerry IDE runs the command checkout %1, the BlackBerry IDE actually runs the command
checkout c:\mypath\foo.java.
5. Click the Add file tab.
23
BlackBerry Application Developer Guide Volume 1: Fundamentals
6. In the Add new file field, type the command to add a new file to your source control program. For example
type:
p4 add %1
7. Click the Revert file tab.
8. In the Revert changes field, type the command to revert a file in your source control program. For example
type:
p4 revert %1
9. Click OK.
Build projects
When you build a project, the BlackBerry IDE compiles your source files into Java bytecode, performs
preverification, and then packages the classes into a .cod file.
Note: In Java ME, bytecode verification is divided into two stages. The compiled code is preverified before it is loaded onto the
BlackBerry device, so the BlackBerry device only has to perform basic verification as classes are loaded. The BlackBerry IDE performs
preverification automatically when it builds projects.
When you build a project, the BlackBerry IDE also builds any libraries on which the project depends, if necessary.
Action
Procedure
Build all projects
>
Build all active projects >
Build a single project
Additional information
On the Build menu, click Build All.
To exclude a project, set the project properties.
On the Build menu, click Build.
In the workspace, active project names appear in bold. To change
which projects are active, on the Project menu, click Set Active
Projects.
1. Select a project.
—
2. On the Build menu, click Build
Selected.
Create a workspace
makefile
>
On the Build menu, click Generate
Makefile and Resources.
—
By default, the compiled .cod file uses the project name. To change this name, double-click the project file, click
the Build tab, and type the output file name.
Obfuscate applications
Unlike traditional compilers, the compiler for the BlackBerry platform is optimized for a constrained wireless
environment where the goal is to minimize the size of the application. The resulting .cod file provides a significant
amount of obfuscation-like services similar to other true obfuscation packages in an effort to reduce the size of the
.cod file itself. For example, the following information is removed from a .cod file:
• all debug information
• local variable names
• source Line Numbers
24
2: Writing BlackBerry Java applications
• private method and member names
As such, RIM does not believe it is necessary to provide obfuscation for applications in addition to the existing
obfuscation provided by default for all applications compiled for the BlackBerry platform. In fact, RIM does not
perform any additional obfuscation of its own products.
Support for obfuscation via third party tools is not integrated into the BlackBerry Java Development Environment
(BlackBerry JDE). As such, a command-line procedure is required to obfuscate .cod files for use on BlackBerry
devices.
Obfuscate a .cod file
1. In the BlackBerry IDE, create your application.
Tip: Place the project file in a separate directory during this process.
2. Create a temporary directory.
3. Copy the .jar file created by the BlackBerry IDE to the temporary directory.
4. Extract the contents of the .jar file into the temporary directory. For example, from a command prompt type
the following command:
*jar xvf SampleApplication.jar
5. Delete the .cod file that was extracted as part of the .jar file.
6. Delete the .jar file.
7. Obfuscate the class files that are contained in the temporary directory.
8. Run the preverify tool on the contents of the temporary directory using the following command:
*preverify.exe -verbose -d . -classpath ..\lib\net_rim_api.jar;
9. Run rapc on the obfuscated (and preverified) class files to create a .cod file. Use the following command:
*rapc.exe -verbose import=..\lib\net_rim_api.jar listing=SampleApplication.lst codename=SampleApplication
SampleApplication.rapc C:\yourTempDir\SampleApplication.class
Generate API documentation
Use a BlackBerry IDE macro to add comments to code.
Once enabled, if you type /** on any line preceding a function declaration, the BlackBerry IDE generates the
following comment:
/**
* <description>.
* @param menu <description>.
* @param instance <description>.
* @return <description>.
*/
If you type /** on any other line, the BlackBerry IDE generates the following comment:
/**
* <description>.
*/
25
BlackBerry Application Developer Guide Volume 1: Fundamentals
The BlackBerry IDE also preloads "<description>" as your search string, searches for the first instance, and
selects that instance. This feature enables you to type a description, and then press F3 to move to subsequent
parameters.
Because the javadocs macro relies on parsing the browsing information, add javadocs only after you perform a
successful build. If your file contains a syntax error above where you are trying to insert comments, the macro does
not retrieve the function declaration.
Add a new editor macro
1. On the Edit menu, click Preferences.
2. Click the Editor tab.
3. Click the Macros button.
4. From the When I type drop-down list, select /**.
5. In the Replace it with text box, type @javadoc.
6. Type /** on the same line or the line immediately preceding each function declaration. For example, in the
following code fragment, position the insertion point at the beginning of the word “protected” and type /**.
/** protected int makeMenu(Menu menu, int instance) { ... }
Using the command line
The BlackBerry JDE includes RAPC, a command line compiler. RAPC compiles .java and .jar files into .cod files that
you can run in the BlackBerry device simulator or load onto BlackBerry devices.
The rapc.exe file is located in the bin subdirectory of your BlackBerry JDE installation.
RAPC accepts the following command line options:
Option
Description
import
specify the RIM APIs and other dependent libraries
codename
specify the application name (this is typically the name of the .jar file)
midlet
specify if the application is a MIDlet
jad
specify the JAD file name
\filename_1.java [<additional .java files as required>] specify the .java file name if compiling from java files
\JAR_filename.jar
specify the .jar file name if compiling from a .jar file
Using the Bluetooth development environment
To use the BlackBerry device simulator with a Bluetooth development environment, you will require the Casira
general-purpose development system from CSR (see http://www.btdesigner.com/devcasira.htm).
26
2: Writing BlackBerry Java applications
Use the Bluetooth development environment with a Blackberry device
simulator
1. Open the Blackberry IDE.
2. From the main menu, select Edit > Preferences.
3. Select the Simulator tab.
4. Select the Ports tab.
5. In the Communication port type field, select the appropriate port type (see the Casira Endpoint
documentation)
6. In the Serial port field, type the port information.
7. Click OK.
Using the Eclipse development environment
The Java Debug Wire Protocol (JDWP) program provides an interface to the BlackBerry simulators. When you start
the JDWP, you can use third-party integrated development environments.
Start the JDWP
>
Click Start > Programs > Research In Motion > BlackBerry JDE 4.1.0 > JDWP.
Note: Before you can start the JDWP, you must start the BlackBerry device simulator from the BlackBerry IDE at least once. You need
to start JDWP once only. To start a device simulator, in the Eclipse development environment, click Run > Debug.
Connect to the Eclipse development environment
Note: Before completing the tasks in this section, install and configure the Eclipse development environment.
Perform the following steps:
1. Extend the Sun JRE
2. Add API documentation
3. Set the builder
4. Set project variables
Extend the Sun JRE
1. Set up your workspace and project.
2. Start the Eclipse workbench
3. On the Eclipse taskbar, click Window > Preferences.
4. Expand the Java item.
27
BlackBerry Application Developer Guide Volume 1: Fundamentals
5. Select Installed JREs.
6. Click Add.
7. In the Add JRE window, in the JRE type field, select Standard VM.
8. In the JRE name field, type a name for the JRE.
9. In the JRE home directory field, type the location of the Sun JRE. For example:
C:\Java\jdk1.5.0_02\jre.
10. Make sure the Use default system libraries field is unselected.
11. Click Add External JARs.
12. Browse to the lib directory of your installation of the BlackBerry JDE. For example:
C:\Program Files\Research In Motion\BlackBerry JDE 4.1.0\lib
13. Select net_rim_api.jar.
14. Click Open.
Add the API documentation
1. Add a RIM .jar file to your project.
2. In the Add JRE window, expand the net_rim_api.jar file.
3. Select Javadoc location.
4. Click Edit.
5. Click Browse.
6. Navigate to the docs\api directory of your BlackBerry JDE installation. For example:
C:\Program Files\Research In Motion\BlackBerry JDE 4.1.0\docs\api
7. Click OK.
8. Click OK.
9. In the Installed JREs window, select the newly created JRE. The default is RIM JVM.
10. In the Add JRE window, click OK.
Set builder settings
1. On the Eclipse taskbar, click Project > Properties.
2. Select Builders.
3. Click New.
4. In the Choose configuration type window, select Program.
5. Click OK.
6. In the Properties for New_Builder window, in the Name field, type a name for the builder.
7. In the Location field, click Browse File System.
28
2: Writing BlackBerry Java applications
8. Navigate to the bin directory of your BlackBerry JDE installation. For example:
C:\Program Files\Research In Motion\BlackBerry JDE 4.1.0\bin
9. Select the rapc.exe file.
10. Click Open.
Set project variables
1. In the Working Directory field, click Variables.
2. In the Select Variable window, select build project.
3. Click OK.
4. In the Arguments field, type:
-quiet [desired space separated java, class, jar, or jad files] import=”C\Program Files\Research In Motion\BlackBerry
JDE 4.1.0\lib\net_rim_api.jar” codename=C:\Development\ProjectName
For example:
-quiet C:\Development\TestProject\*.java import=”C:\Program Files\Research In Motion\BlackBerry JDE
4.1.0\lib\net_rim_api.jar” codename=C:\Development\TestProject.
5. Click OK.
6. In the Properties for New_Builder window, click the Build Options tab.
7. In the Run the builder section, verify that the following items are selected:
•
After a “Clean”
•
During manual builds
•
During auto builds
8. Click OK.
9. In the Properties for window, click OK.
Note: RAPC does not support wildcard characters. If an input path error occurs, use a space separated list of files. For example replace
C:\Development\TestProject\*.java with C:\Development\A.java C:\Development\B.java.
Set the connection time
To prevent connection timeouts when debugging in the Eclipse development environment, set the timeout values
for the debug program.
1. On the Eclipse taskbar, click Windows > Preferences.
2. Expand the Java item.
3. Select Debug.
4. In the Communication section, in the Debugger timeout field, type a value.
5. In the Launch timeout field, type a value.
Note: The values you set in the Debugger timeout and Launch timeout fields depend on the processing speed of your computer.
If connection problems continue after setting these fields, increase the timeout values.
29
BlackBerry Application Developer Guide Volume 1: Fundamentals
Debug using the Eclipse development environment
1. From Eclipse, click Run > Debug.
2. Select Remote Java Application.
3. Click New.
4. Click the Source tab.
5. Verify that your application is listed.
6. Click Close.
7. Open the JDWP application. See “Start the JDWP” on page 27 for more information.
8. On the Eclipse taskbar, click Run > Debug.
9. Under the Remote Java Application item, select an application.
10. Click Debug.
Note: If the following error message appears: “Failed to connect to remote VM. Connection timed out”, increase the debugger timeout
values. See “Set the connection time” on page 29 for more information.
Programming guidelines
Write efficient code
Use local variables
Use local variables whenever possible. Access to local variables is more efficient than access to class members.
Use shorthand for evaluating Boolean conditions
Instead of unnecessarily evaluating a Boolean condition as shown in the first example, use shorthand as shown in
the second. The resulting compiled code is shorter.
// Avoid this
if( boolean_expression == true ) {
return true;
} else {
return false;
}
// Do this
return( boolean_expression );
Make classes final
When you create code libraries, mark classes as final if you know that they will never be extended. The presence
of the final keyword enables the compiler to generate more efficient code.
Note: By default, the BlackBerry JDE compiler marks any classes that you do not extend in an application .cod file as final.
30
2: Writing BlackBerry Java applications
Use int instead of long
In Java, a long is a 64-bit integer. Because BlackBerry devices use a 32-bit processor, operations run two to four
times faster if you use an int instead of a long.
Avoid garbage collection
Avoid calling System.gc() to perform garbage collection. This operation takes too much time, especially on
BlackBerry devices with limited available memory. Let the VM collect garbage.
Using static variables for Strings
When defining static fields (also called class fields) of type String, you can increase program speed by using
static variables (not final) instead of constants (final). The opposite is true for primitive data types, such as int.
For example, you might create a String object as follows:
private static final String x = "example";
For this static constant (denoted by the final keyword), a temporary String instance is created each time that
you use the constant. The compiler eliminates "x" and replaces it with the string “example” in the bytecode, so
that the VM performs a hash table lookup each that time you reference "x".
In contrast, for a static variable (no final keyword), the string is created once. The VM performs the hash table
lookup only when it initializes “x”, so access is faster.
Note: You can use public constants (that is, final fields), but mark variables as private.
Avoid the String(String) constructor
Avoid using the java.lang.String(String) constructor because it creates an unnecessary String object that
is a copy of the string that is provided as a parameter. Because String objects cannot be modified after they are
created, copies are not typically necessary.
Note: The compiler generates a warning when you use the string constructor.
String str = new String("abc"); // Avoid.
String str = new String("found " + n + " items"); // Avoid.
In Java programs, each quoted string is implemented as an instance of the java.lang.String class. In other
words, you create a String by writing code as in the following example:
String str = "abc"; // Prefer.
String str = "found " + n + " items"; // Prefer.
Write efficient loops
Factor loop-invariant code out of a loop.
// Avoid.
31
BlackBerry Application Developer Guide Volume 1: Fundamentals
for( int i = 0; i < vector.size(); i++ ) {
...
}
In this implementation, vector.size() is invoked for each iteration, which is inefficient. If your container is likely
to have more than one element, assign the size to a local variable. The following example removes loop-invariant
code:
// Prefer.
int size = vector.size();
for( int i = 0; i < size; ++i ) {
...
}
Alternatively, if the order in which you iterate through items is not important, you can iterate backward to avoid
the extra local on the stack and to make the comparison faster.
for( int i = vector.size() - 1; i >= 0; --i ) {
...
}
Optimize subexpressions
If you use the same expression twice, do not rely on the compiler to optimize it for you. Use a local variable, as in
the following example:
one( i+1 ); two( i+1 ); // Avoid.
int tmp = i+1; one( tmp ); two( tmp ); // Prefer.
Optimize division operations
Division operations can be slow on the BlackBerry devices because the processor does not have a hardware divide
instruction.
When your code divides a positive number by two, use shift right by one ( >> 1 ) instead. Use the “shift right" (>>)
only when you know that you are dealing with a positive value.
midpoint = width / 2; // Avoid.
int = width >> 1; // Prefer.
Avoid java.util.Enumeration
Avoid using java.util.Enumeration objects unless you want to hide data (in other words, to return an
enumeration of data instead of the data itself).
// Avoid.
for (Enumeration e = v.elements(); e.hasMoreElements();) {
o = e.nextElement();
...
}
Asking a vector or hash table for an Enumeration object is slow and creates unnecessary garbage. Instead, iterate
the elements yourself, as in the following example:
// Prefer.
32
2: Writing BlackBerry Java applications
for( int i = v.size() - 1; i >=0; --i ) {
o = v.elementAt( i );
...
}
If the vector might be modified by another thread, synchronize the iteration as in the following example:
synchronized( v ) {
for( int i = v.size() - 1; i >=0; --i ) {
o = v.elementAt( i );
...
}
}
Note: Java SE uses an Iterator object for similar operations, but iterators are not available in Java ME.
Perform casts using instanceof
Use instanceof to evaluate whether a cast succeeds instead of catching a ClassCastException.
// Avoid.
try {
(String)x.whatever();
} catch( ClassCastException e ) {
...
}
// Prefer.
if( x instanceof String ) {
(String)x.whatever();
} else {
...
}
Using instanceof is faster than using a try/catch block. Use the try/catch block only when a cast failure is
an exceptional circumstance.
The BlackBerry JDE compiler and VM are optimized to perform only one class check in the first block of code
following a branch determined by an instanceof check. Perform the cast immediately following the branch that
is determined by an instanceof check to take advantage of this optimization.
For example, the compiler can optimize the first example, but not the second:
// Prefer.
if ( a instanceof <type> ) {
<type> instance = (<type>)a;
x.method(instance);
instance.method(x, y, z);
}
// Avoid.
if( a instanceof <type> ) {
x.method( (<type>)a );
}
33
BlackBerry Application Developer Guide Volume 1: Fundamentals
Evaluate conditions using instanceof
To produce smaller and faster code, if you evaluate a condition using instanceof, do not evaluate explicitly
whether the variable is null. The expression e instanceof <type> evaluates to false if “e” is null.
// Avoid.
if( e != null && e instanceof ExampleClass ) { ... }
if( e == null || ! ( e instanceof ExampleClass) ) { ... }
// Prefer.
if( e instanceof ExampleClass ) { ... }
if( ! ( e instanceof ExampleClass ) ) { ... }
Avoid using StringBuffer.append(StringBuffer)
CLDC does not include a StringBuffer.append( StringBuffer) method. Appending a string buffer to
another in this way creates an intermediate String object. Instead, applications should use
net.rim.device.api.util.StringUtilities.append( StringBuffer dst, StringBuffer src[, int
offset, int length ] ).
// Avoid.
public synchronized StringBuffer append(Object obj) {
return append(String.valueOf(obj));
}
// Prefer.
public synchronized StringBuffer append(Object obj) {
if (obj instanceof StringBuffer) {
StringBuffer sb = (StringBuffer)obj;
net.rim.device.api.util.StringUtilities.append( this, sb, 0, sb )
return this;
}
return append(String.valueOf(obj));
}
Reduce code size
Follow these guidelines when you write applications to reduce the size of the compiled code.
Set appropriate access
When you create code libraries, using the appropriate access modifiers for fields and methods significantly reduces
the size of your compiled code. In particular, perform the following actions:
• Declare fields as private whenever possible. In addition to being good coding practice, this enables the
compiler to optimize the .cod file.
• When possible, use the default (package) access instead of public access (that is, omit the public and
protected keywords).
Avoid creating interfaces
When you create API libraries, avoid creating interfaces unless you foresee multiple implementations of the API.
Interfaces produce larger, slower code.
34
2: Writing BlackBerry Java applications
Use static inner classes
When you use an inner class to hide one class inside another, but the inner class does not reference the outer class
object, declare the inner class as static. This action suppresses the creation of a reference to the outer class.
For example, the following code requires a reference to the outer class object:
// Avoid.
class outer {
int i;
class inner {
inner() {}
int example() { return i; }
}
}
In contrast, the following code only defines the scope of the inner class name:
// Prefer.
class outer {
static class inner {
...
}
}
The previous example is a shorter version of the following code:
class outer {
...
}
class outer$inner {
...
}
Only use a non-static inner class when you need access to data in the outer class from within methods of the inner
class. If you use an inner class for name scoping, make it static.
Avoid unnecessary initialization
Avoid unnecessarily initializing fields in classes, where fields have default values. If you do not initialize a field in
a class, it is initialized automatically using the following default values:
• object references are initialized to null
• int, byte, or long is initialized to 0
• boolean is initialized to false
For example, there is no difference between the following code fragments:
// Avoid.
class BadExample {
private int fieldsCount = 0; // Avoid.
private Field _fieldWithFocus = null; // Avoid.
private boolean _validLayout = false; // Avoid.
}
// Prefer.
class BetterExample {
35
BlackBerry Application Developer Guide Volume 1: Fundamentals
private int fieldsCount; // Prefer.
private Field _fieldWithFocus; // Prefer.
private boolean _validLayout; // Prefer.
}
Note: You must explicitly initialize local variables in a method.
Import individual classes
Applications that use only a small number of classes from a package should import the individual classes rather
than the entire library.
// Avoid.
import net.rim.blackberry.api.browser.*;
// Prefer.
import net.rim.blackberry.api.browser.Browser;
Use time on BlackBerry devices
In time-sensitive applications, do not depend on time zones for anything other than displaying the local time to
the user.
BlackBerry device clock
The BlackBerry device operating system calculates absolute time as milliseconds since midnight, January 1, 1970
Universal Time Coordinate (UTC). Time is typically measured in either CPU ticks or milliseconds.
System time zone changes
If you are caching a time-sensitive object for performance reasons, remember that the system time zone can
change on the BlackBerry device.
When the time zone changes, the system sends out a global event message to the applications. Your
implementation of the GlobalEventListener interface, including eventOccurred(), receives this event.
Register your implementation by invoking Application.addGlobalEventListener().
public void eventOccurred( long guid, int data0, int data1, Object object0,
Object object1 ) {
if( guid == DateTimeUtilities.GUID_TIMEZONE_CHANGED ) {
_cal.setTimeZone( TimeZone.getDefault() );
}
}
Determine the Network Time on the Handheld
Invoke RadioInfo.GetNetworkTime(long deviceTime) to obtain the time in milliseconds corresponding to the
network reported time, normalized to the local time zone. The deviceTime parameter represents the current time in
milliseconds.
36
2: Writing BlackBerry Java applications
Recommended practices
Use multithreading
Make effective use of the multithreading capabilities of the BlackBerry operating system. In particular, always
create a new thread for network connections or other lengthy operations (more than one-tenth of a second). Use
background threads for listeners or other processes that run in the background when the application starts.
Minimize memory use
To minimize runtime memory, use the following guidelines:
• Use primitive types (such as int or boolean) instead of objects (such as String or Integer).
• Do not depend entirely on the garbage collector. Avoid creating many objects quickly. Set object references to
null when you have finished using them. Reuse objects as much as possible.
• Move heavy processing to the server. For example, perform data filtering or sorting before sending data to the
BlackBerry device.
Avoid returning null
If you are writing a public method that returns an object, it should return null only under the following
conditions:
• A null is expected during normal program operation.
• The Javadoc @return parameter states that null is a possible return value.
If a null return value is not normally expected, then the method should throw an appropriate exception, which
forces the caller to deal explicitly with the problem. The caller is not expected to check for a null return value,
unless the documentation says otherwise.
Avoid passing null into methods
Do not pass null parameters into an API method unless the API Reference states explicitly that the method
supports them.
Use caution when passing null into a constructor
To avoid ambiguity when passing null into a constructor, cast null to the appropriate object.
new someObject ( (someObject)null );
If a class has two or more constructors, passing in a null parameter might not uniquely identify which constructor
to use. As a result, the compiler reports an error. Not all supported constructors appear in the API Reference
because some constructors are for internal use only.
By casting null to the appropriate object, you indicate precisely which constructor the compiler should use. This
practice also provides forward compatibility if later releases of the API add new constructors.
37
BlackBerry Application Developer Guide Volume 1: Fundamentals
Use longs for unique identifiers
Use a long identifier instead of a String identifier for unique constants, such as GUIDs, hash table keys, and
state or context identifiers.
For identifiers to remain unique across third-party applications, use keys that are generated based on a hash of a
String. In the input string, include enough information to provide uniqueness. For example, use a fully qualified
package name such as com.rim.samples.docs.helloworld.
Convert a String to a long
1. In the BlackBerry IDE text editor, type a string.
2. Select the string.
3. Right-click the string.
4. Click Convert “string” to Long.
Exit applications correctly
Before you invoke System.exit(int status), your application should perform any necessary cleanup, such as
removing objects from the runtime store that are no longer required by any applications.
Print the stack trace
The VM is optimized to eliminate the stack trace if it finds code that catches the exception using catch
It does not eliminate the stack trace if Throwable is caught.
(Exception e).
For example, the following code does not print a stack trace:
catch (IOException e) {
e.printStackTrace()
}
To print a stack trace, write code such as the following:
catch (Throwable t) {
t.printStackTrace();
}
When you debug, to view the stack trace, catch a Throwable instance.
38
3
Creating user interfaces
User interface APIs
Displaying user interface components
Managing use interface components
Creating custom user interface components
Working with images
Drawing using graphics objects
Listening for changes to user interface objects
User interface APIs
When you write applications for BlackBerry devices, use one of the following two API sets for user interfaces:
• MIDP UI APIs (javax.microedition.lcdui package)
• BlackBerry UI APIs (net.rim.device.api.ui packages)
If you are writing an application to run on any MIDP-compliant device, use the MIDP UI APIs. If you are writing an
application specifically for BlackBerry devices, use the BlackBerry UI APIs. BlackBerry APIs provide access to
specific features of the BlackBerry device and enable more sophisticated user interface layout and interaction.
Note: Do not use MIDP UI APIs and BlackBerry UI APIs in the same application, or exceptions will be thrown. The UI framework
supports one type of UI object in an application.
Displaying user interface components
Display screens
The main structure for a user interface is the Screen. An application displays one Screen at a time.
Note: Do not use Screen objects for text input. The Screen class does not implement disambiguation, which is required for complex
input methods, such as international keyboards and the 7100 series of devices. For seamless integration of the different input
methods, extend Field or one of its subclasses. See "Create custom fields" on page 53 for more information.
BlackBerry Application Developer Guide Volume 1: Fundamentals
Display stack
Screen objects are maintained in a display stack, an ordered set of Screen objects. The screen at the top of the
stack is the active screen that appears to the user. When an application displays a screen, it pushes the screen to
the top of the stack. When an application closes a screen, it pops the screen off the stack and displays the next
screen on the stack, redrawing it as necessary.
Note: Each screen can appear only once in the display stack. The VM throws a runtime exception if the same screen is pushed onto
the stack more than once. Applications must pop screens off of the display stack when the user finishes interacting with them so that
memory is not used unnecessarily. Do not use more than a few modal screens at one time, because each screen uses a separate thread.
Types of screens
In most cases, the most efficient way to create a screen is to create a new class that extends Screen or one of its
subclasses, FullScreen or MainScreen.
Class
Description
Screen
Use the Screen class to define a manager to lay out UI components on the screen and to define a specific type of screen
using the styles that are defined by constants on the Field superclass.
FullScreen
By default, a FullScreen contains a single vertical field manager. Use a FullScreen to provide an empty screen that
you can add UI components to in a standard vertical layout. If you need another type of layout, such as horizontal or
diagonal, use a Screen class and add a Manager to it.
MainScreen
The MainScreen class provides features that are common to standard BlackBerry applications. Use a MainScreen object
for the first screen of your application to maintain consistency with other BlackBerry applications. The MainScreen class
provides the following UI components:
•
•
•
•
default position of a screen title, with a SeparatorField after the title
a main scrollable section contained in a VerticalFieldManager
default menu with a Close menu item
default close action when the user clicks the Close menu item or presses the Escape key
Respond to user interaction
The BlackBerry APIs provide an event listener framework that is similar to Java SE. In particular, two listener
interfaces enable applications to receive and respond to user interaction: TrackwheelListener and
KeyboardListener. The Screen class and its subclasses implement these interfaces.
Provide screen navigation
BlackBerry applications provide a menu for users to perform actions. Avoid using buttons or other UI elements
that take up space on the screen.
Note: Users click the trackwheel to access the menu.
When you create a FullScreen or Screen, specify the DEFAULT_MENU and DEFAULT_CLOSE parameters in the
constructor to provide default navigation.
FullScreen fullScreen = new FullScreen(DEFAULT_MENU | DEFAULT_CLOSE);
40
3: Creating user interfaces
Parameter
Description
DEFAULT_MENU
This parameter adds a default menu, which includes different menu items, depending on the user context. For example,
if an EditField has focus, Cut, Copy, and Paste menu items appear. All selectable fields provide Select and Cancel
Selection items.
DEFAULT_CLOSE
This parameter adds a Close item to the menu, with default behavior. When users click the Close menu item or press
the Escape button, a confirmation dialog box appears if anything on the screen has changed. If this screen is the only
one on the stack, the application closes.
Default navigation is provided by default when you create a MainScreen.
Add menu items
Create MenuItem objects.
private MenuItem viewItem = new MenuItem("View Message", 100, 10) {
public void run() {
Dialog.inform("This is today’s message");
}
};
The MenuItem constructor accepts the following three parameters:
Parameter
Description
text
name of the menu item
ordinal
order of menu items; a higher value indicates that the item appears closer to the bottom of the menu
priority
priority of the menu item for receiving the default focus
Your implementation of run() defines the action that occurs when the user clicks the menu item. If you are not
using localization resources, override toString() to specify the name of the menu item.
To add context menus to fields in an application, invoke getLeafFieldWithFocus() and invoke
getContextMenu() on the return value to determine which fields receive custom menu items in makeMenu(). See
"Create custom context menus" on page 60 for more information.
When you add your own menu items, define a Close menu item explicitly:
private MenuItem closeItem = new MenuItem("Close", 200000, 10) {
public void run() {
onClose();
}
};
To add the menu items to the screen, override Screen.makeMenu().
protected void makeMenu(Menu menu, int instance) {
menu.add(viewItem);
menu.add(closeItem);
}
If you extend Screen or one of its subclasses, the default implementation of TrackwheelListener invokes
makeMenu() when the user clicks the trackwheel.
41
BlackBerry Application Developer Guide Volume 1: Fundamentals
If you do not extend Screen, implement TrackwheelListener. In particular, your implementation of
trackwheelClick() creates a new Menu, adds menu items, and displays the menu on screen.
public boolean trackwheelClick(int status, int time) {
Menu appMenu = new Menu();
makeMenu(appMenu, 0); // Add menu items.
appMenu.show(); // Display the menu on screen.
return true;
}
Note: To create custom menu items that provide additional functionality, extend the MenuItem class. See "Create custom context
menus" on page 60 for more information.
Display dialog boxes
The PopupScreen class provides features for building dialog boxes and status screens using its subclasses,
Dialog and Status. Popup screens are not pushed onto the display stack. To display a popup screen, invoke
Dialog.ask(int) or Status.show().
To control the layout of a dialog box, use a DialogFieldManager object. See "Specify the layout for a
PopupScreen" on page 50 for more information.
To display a dialog box, invoke Dialog.ask() with one of the following parameters:
Parameter
Description
D_OK
displays a string and prompts the user to click OK
D_SAVE
displays a string and prompts the user to click Save, Discard, or Cancel; pressing Escape returns
cancel
D_DELETE
displays a string and prompts the user to click Delete or Cancel; pressing Escape returns cancel
D_YES_NO
displays a string and prompts the user to click Yes or No
int response = Dialog.ask(Dialog.D_SAVE);
if (Dialog.SAVE == response || Dialog.CANCEL == response)
return false;
if ( Dialog.DISCARD == response )
_item.deleteItem(_itemIndex);
To specify a default response for a dialog box, use a version of Dialog.ask() that accepts defaultChoice as a
parameter.
int response = Dialog.ask(Dialog.D_YES_NO, "Are you sure?", Dialog.NO);
Display status messages
Invoke Status.show() to display a status message. By default, the status screen remains on the screen for two
seconds.
Status.show("Status screen message");
42
3: Creating user interfaces
See the API Reference for information on versions of Status.show() that enable you to specify additional
parameters, such as a different icon or the amount of time that the status dialog remains visible. You can create
status dialog boxes that are modal (require the user to dismiss them) or timed (dismiss automatically after a
specified time).
Display fields
All UI components are represented by fields—rectangular regions that are contained in a manager. The size of the
field is determined by its layout requirements. Managers provide scrolling for the fields that they contain.
The BlackBerry JDE provides a library of prebuilt interface controls and components in the
net.rim.device.api.ui.component package. In most cases, you can use these objects to construct UI
applications.
To create a specialized field component (such as a text field that contains multiple elements), create your own
custom types by extending the Field class or one of its subclasses. See "Create custom fields" on page 53 for
more information.
Note: See the API Reference for more information on valid/supported styles for specific field classes. An
IllegalArgumentException is thrown if you instantiate a Field using an unsupported style.
Bitmap fields
A BitmapField contains bitmaps. Use a BitmapField when you draw with the Graphics object. To modify the
contents of a field, invoke drawing methods on a BitmapField. See "Drawing using graphics objects" on page
73 for more information.
Bitmap myBitmap = Bitmap.getPredefinedBitmap(Bitmap.INFORMATION);
BitmapField myBitmapField = new BitmapField(myBitmap.getPredefinedBitmap(myBitmap));
...
mainScreen.add(myBitmapField);
There are four predefined bitmaps:
•
Bitmap.INFORMATION
•
Bitmap.QUESTION
•
Bitmap.EXCLAMATION
•
Bitmap.HOURGLASS
To use an original .gif or .png image as a bitmap, invoke getBitmapResource().
Note: The size of a binary resource, such as a .png file, must not exceed 63,000 bytes.
private static final Bitmap myBitmap = Bitmap.getBitmapResource("customBitmap.gif");
...
BitmapField bitmapField = new BitmapField(myBitmap);
mainScreen.add(bitmapField);
43
BlackBerry Application Developer Guide Volume 1: Fundamentals
Button fields
A ButtonField contains buttons that users select to perform actions. Use ButtonField to create interfaces that
have an extended interactivity beyond that of the menu.
ButtonField mySubmitButton = new ButtonField("Submit");
ButtonField myResetButton = new ButtonField("Reset");
mainScreen.add(mySubmitButton);
mainScreen.add(myResetButton);
To add functionality to the button, extend ButtonField and override trackwheelClick() so that it performs an
action instead of invoking the menu. To receive notification when the user clicks the button, use a
FieldChangeListener object. See "Listening for changes to user interface objects" on page 78 for more
information.
Choice fields
Choice fields are similar to drop-down lists. There are two types of choice fields: those that contain integers and
those that contain objects that can be converted to strings.
You can also display a set of options as check boxes or radio buttons. See "Option fields" on page 45 for more
information.
To select a value from the ChoiceField, users perform one of the following actions:
• click the field and press the Space key
• hold the Alt key and roll the trackwheel
• open the menu and click Change Option
Class
Description
NumericChoiceField
A NumericChoiceField is a ChoiceField that contains a range of numeric values. NumericChoiceField
instances are typically used for a small range of numbers (up to 20).
NumericChoiceField myNumericChoice = new NumericChoiceField( "Select a number: ",
1, 20, 10);
mainScreen.add(myNumericChoice);
Note: For a large range of numbers, use a GaugeField. See "Gauge fields" on page 47 for more information.
ObjectChoiceField
An ObjectChoiceField is a ChoiceField that contains objects. All objects in the field should implement
Object.toString() to provide string representations of themselves.
Provide an object array as a parameter when you create an ObjectChoiceField.
String choiceItems[] = {"Option one", "Option two", "Option three"};
mainScreen.add(new ObjectChoiceField("Select an option:", choiceItems));
A Change Option menu item is provided by default for an ObjectChoiceField. Users click Change Option
and select an option.
44
3: Creating user interfaces
Option fields
Option fields enable users to select entries from lists. Use CheckboxField for option lists that enable users to
select multiple entries. Use a RadioButtonField for lists that enable users to select only one entry.
Class
Description
CheckboxField
Each CheckboxField object is an individual object that is not associated with the other check boxes.
CheckboxField myCheckbox = new CheckboxField("First checkbox", true);
CheckboxField myCheckbox2 = new CheckboxField("Second checkbox", false);
...
mainScreen.add(myCheckbox);
mainScreen.add(myCheckbox2);
RadioButtonField
Multiple RadioButtonField objects are combined into a RadioButtonGroup so that the user can select only
one option at a time.
RadioButtonGroup rbGroup = new RadioButtonGroup();
RadioButtonField rbField = new RadioButtonField("First field");
RadioButtonField rbField2 = new RadioButtonField("Second field");
...
rbGroup.add(rbField);
rbGroup.add(rbField2);
...
mainScreen.add(rbField);
mainScreen.add(rbField2);
Date fields
A DateField displays the current date and time in your application.
Type
Description
DATE
displays the year, month, and day
DATE_TIME
displays the year, month, day, hour, minutes, and seconds
TIME
displays the hour, minutes and seconds
When you create a DateField, invoke System.currentTimeMillis() to retrieve the current time.
DateField dateField = new DateField("Date: ", System.currentTimeMillis(),
DateField.DATE_TIME);
mainScreen.add(dateField);
Date fields are editable by default. To create a DateField that cannot be edited by users, specify the
Field.READONLY parameter in the DateField constructor.
A Change Option menu item is provided by default for an editable DateField.
45
BlackBerry Application Developer Guide Volume 1: Fundamentals
Edit fields
An EditField enables users to type text in fields. AutoTextEditField, EditField, and PasswordEditField
extend BasicEditField.
Note: The net.rim.device.api.ui.component.TextField class, which extends the Field class, is abstract. Instantiate one
of its subclasses, such as RichTextField or EditField, to create a UI field that displays text or enables a user to type text.
You can apply the following filters to edit fields:
Filter
Description
DEFAULT_MAXCHARS
This filter limits the number of characters in the field. The default maximum number of characters for edit fields
is 15.
FILTER_DEFAULT
This is the default text input filter. Use this filter when the constructor requires a filter but you do not want to
apply any special filtering.
FILTER_EMAIL
This filter permits only valid internet messaging address characters (for example, users can only type one @
sign). It automatically formats text into internet messaging address format (for example, when the user presses
the space key for the first time, an @ symbol appears, followed by .’s each additional time the user presses the
space key).
FILTER_HEXADECIMAL
This filter permits only numbers and the letters A through F.
FILTER_INTEGER
This filter permits only numbers and the minus sign (–).
FILTER_LOWERCASE
This filter converts letters to lowercase.
FILTER_NUMERIC
This filter permits only numbers.
FILTER_PHONE
This filter permits only valid phone number characters, numeric characters, hyphen, plus and minus signs, right
and left parentheses, and "x".
FILTER_PIN_ADDRESS
This filter accepts only characters valid in a PIN address for input.
FILTER_UPPERCASE
This filter converts letters to uppercase.
FILTER_URL
This filter permits only valid URL characters. It also automatically formats fields (for example, it inserts a period
when the user presses the space key).
JUMP_FOCUS_AT_END
This filter changes field behavior, so that when the field is in focus, and the user attempts to scroll down, the
focus moves to the end of the field (instead of moving to the next field).
NO_NEWLINE
This filter ignores line feeds and carriage returns in text, such as text that a user copies and pastes from another
source.
Class
Description
RichTextField
RichTextField creates a read-only field that can be formatted with different fonts and styles. Rich text fields,
although not editable, can receive focus.
mainScreen.add(new RichTextField("RichTextField"));
BasicEditField
BasicEditField is the base class for EditField and PasswordEditField.
BasicEditField is an editable text field that contains no default formatting, but accepts filters.
BasicEditField bf = new BasicEditField("BasicEditField: ", "", 10,
EditField.FILTER_UPPERCASE);
mainScreen.add(bf);
46
3: Creating user interfaces
Class
Description
EditField
EditField is an editable text field that extends BasicEditField. EditField enables users to access special
characters. For example, users hold the A key and roll the trackwheel to select from a variety of accented A
characters, and the Æ ligature. EditField accepts styles, but some styles negate the functionality of EditField
(such as EditField.FILTER_PHONE).
mainScreen.add(new EditField("EditField: ", "", 10, EditField.FILTER_DEFAULT));
PasswordEditField
PasswordEditField extends BasicEditField to provide the following functionality:
• Masks user input with asterisk characters (*).
• AutoText (and other automatic formatting) is not applied.
• Cut or copy operations are not supported.
The following example uses a constructor that enables you to provide a default initial value for the
PasswordEditField.
mainScreen.add(new PasswordEditField("PasswordEditField: ", ""));
AutoTextEditField
AutoTextEditField applies formatting that is specified by the AutoText engine. Any text that is typed in this
field is formatted according to the specifications of the AutoText database on the BlackBerry device.
Some filters render some AutoText entries ineffective. For example, FILTER_LOWERCASE renders an AutoText
entry that contains capitalization ineffective.
mainScreen.add(new AutoTextEditField("AutoTextEditField: ", ""));
Gauge fields
Gauges enable you to create visual representations of numeric values. GaugeField displays a progress bar or
enables users to select numbers. You can prefix the gauge with a label and display the current value within the
gauge. For example, combine a GaugeField and a NumericChoiceField to create a graphical representation of
a numeric selection made by the user.
To create an interactive GaugeField, instantiate the field with Field.FOCUSABLE and Field.EDITABLE styles.
GaugeField staticGauge = new GaugeField("1: ", 1, 100, 20, GaugeField.NO_TEXT);
GaugeField percentGauge = new GaugeField("Percent: ", 1, 100, 29, GaugeField.PERCENT)
GaugeField interactiveGauge = new GaugeField("Gauge: ", 1, 100, 60, Field.FOCUSABLE |
Field.EDITABLE);
...
mainScreen.add(staticGauge);
mainScreen.add(percentGauge);
mainScreen.add(interactiveGauge);
Label and separator fields
A LabelField enables you to add text labels to screens. A LabelField is read-only. By default, it cannot receive
focus. Most applications use a LabelField to display a static title on their first screens.
A SeparatorField is a static horizontal line that spans the width of the screen. Use a SeparatorField to group
related content on screens and menus.
The MainScreen displays a separator after the title by default.
LabelField title = new LabelField("UI Component Sample", LabelField.ELLIPSIS));
mainScreen.setTitle(title);
47
BlackBerry Application Developer Guide Volume 1: Fundamentals
List fields
Lists enable you to create directories of items through which users can scroll and select individual or multiple
entries. The BlackBerry address book is an example of a List object.
You cannot directly populate the field entries with content. Your implementation of ListFieldCallback for a
ListField or TreeFieldCallback for a TreeField draws the field.
Class
Description
ListField
ListField contains rows of selectable items. To display content in a ListField, set a ListFieldCallback
for the list. See "Create a callback object" on page 66 for more information.
String fieldOne = new String("Mark Guo");
String fieldTwo = new String("Amy Krul");
...
ListField myList = new ListField();
ListCallback myCallback = new ListCallback();
myList.setCallback(myCallback);
myCallback.add(myList, fieldOne);
myCallback.add(myList, fieldTwo);
...
mainScreen.add(myList);
Note: To enable the user to select a range of items in the list, specify a ListField as MULTI_SELECT.
ListFieldCallback.add() adds the list element to the vector and calls List.insert() to determine the
appropriate position.
ObjectListField
An ObjectListField is a list field that contains objects as entries. All objects that are contained in the list must
implement Object.toString() to provide string representations of themselves. An ObjectListField is
rendered in the interface in the same way as a standard ListField.
TreeField
contains parent and child nodes and presents a folder or tree relationship between items (such as
documents or message folders). By default, all the entries are visible. To specify whether a folder is collapsible,
invoke setExpanded() on the TreeField object.
TreeField
Icons appear beside each node that has child nodes to specify whether the node is expanded or collapsed.
String fieldOne = new String("Main folder");
...
TreeCallback myCallback = new TreeCallback();
TreeField myTree = new TreeField(myCallback, Field.FOCUSABLE);
int node1 = myTree.addChildNode(0, fieldOne);
int node2 = myTree.addChildNode(0, fieldTwo);
int node3 = myTree.addChildNode(node2, fieldThree);
int node4 = myTree.addChildNode(node3, fieldFour);
...
int node10 = myTree.addChildNode(node1, fieldTen);
myTree.setExpanded(node4, false);
...
mainScreen.add(myTree);
Your implementation of TreeFieldCallback adds fields to the tree. See "Create a callback object" on page 66
for more information on callbacks.
48
3: Creating user interfaces
private class TreeCallback implements TreeFieldCallback {
public void drawTreeItem(TreeField _tree, Graphics g, int node, int y, int width, int
indent) {
String text = (String)_tree.getCookie(node);
g.drawText(text, indent, y);
}
}
Managing use interface components
Manage layout
Use BlackBerry API layout managers to arrange components on a screen.
The following four classes extend the Manager class to provide predefined layout managers:
•
VerticalFieldManager
•
HorizontalFieldManager
•
FlowFieldManager
•
DialogFieldManager
Both MainScreen and FullScreen use a VerticalFieldManager by default; define a layout manager for
instances of these classes only to provide a different layout.
Note: To create a custom layout manager, extend Manager. See "Create custom layout managers" on page 63 for more information.
To define the layout manager for a particular instance of Screen, complete the following actions:
• instantiate the appropriate Manager subclass
• add UI components to the layout manager
• add the layout manager to the screen
VerticalFieldManager vfm = new VerticalFieldManager(Manager.VERTICAL_SCROLL);
vfm.add(bitmapField);
vfm.add(bitmapField2);
...
mainScreen.add(vfm)
The Manager class defines several constants that provide system styles, which define behavior such as scrolling
and alignment. Use these styles as parameters when you create the layout manager. See
net.rim.device.api.ui.Manager in the API reference for more information.
Organize fields vertically
organizes fields vertically. All fields start on a new line. To enable vertical scrolling,
provide the Manager.VERTICAL_SCROLL parameter.
VerticalFieldManager
VerticalFieldManager vfm = new VerticalFieldManager(Manager.VERTICAL_SCROLL);
vfManager.add(bitmapField);
vfManager.add(bitmapField2);
...
49
BlackBerry Application Developer Guide Volume 1: Fundamentals
mainScreen.add(vfManager);
By default, BitmapField objects are all left-aligned in the VerticalFieldManager.
Organize fields horizontally
organizes fields horizontally. To enable horizontal scrolling, provide the
style. If you do not include the HORIZONTAL_SCROLL parameter, the fields
arrange themselves horizontally and can exceed the width of the screen, but users cannot scroll to content that is
beyond the right side of the screen.
HorizontalFieldManager
Manager.HORIZONTAL_SCROLL
BlackBerry devices do not display horizontal scrolling indicators or scroll bars.
HorizontalFieldManager hfm = new HorizontalFieldManager(Manager.HORIZONTAL_SCROLL);
Organize fields horizontally and vertically
FlowFieldManager organizes fields horizontally and then vertically. Fields are arranged horizontally until there is
insufficient space to place another field, and then the manager arranges them horizontally on the next line. The
Home screen is an example of a FlowFieldManager.
FlowFieldManager flManager = new FlowFieldManager(Manager.FIELD_HCENTER);
Specify the layout for a PopupScreen
specifies the layout for PopupScreen objects. It manages layout for an icon, a message,
and a list of custom fields. The icon and message appear beside each other at the top of the layout, and the
custom fields appear below the message. This layout is standard for dialog PopupScreen objects. To create
custom dialog boxes, extend DialogFieldManager.
DialogFieldManager
BitmapField bitmapField = new BitmapField(Bitmap.getBitmapResource("x.gif"));
RichTextField message = new RichTextField("Dialog manager message", Field.NON_FOCUSABLE);
LabelField dialogChoice = new LabelField("Choice one", Field.FOCUSABLE);
...
DialogFieldManager dialogManager = new DialogFieldManager();
dialogManager.setMessage(message);
dialogManager.setIcon(bitmapField);
dialogManager.addCustomField(dialogChoice);
Manage user interface interactions
Only one thread at a time (usually the event-dispatching thread) can gain access to the UI. Background threads
can access the UI from outside the main event-handling or UI drawing code in one of the following ways:
• acquire and hold the event lock
• use invokeLater() or invokeAndWait() to run on the event dispatch thread
Acquire and hold the event lock
The event dispatcher sets an event lock on the event thread while it processes a message. Background threads
(that is, non-event dispatch threads) can access the UI by acquiring this lock for a short time, without interfering
with event dispatcher processing.
50
3: Creating user interfaces
To retrieve the event lock, invoke Application.getEventLock(). Synchronize with this object to serialize access
to the UI. Hold this lock for only short periods of time because the lock pauses the event dispatcher. An
application should never invoke notify() or wait() on the EventLock object.
class MyTimerTask extends TimerTask {
public void run() {
synchronized(Application.getEventLock()) {
_label.setText("new text " + System.currentTimeMillis());
}
}
}
Run on the event dispatch thread
If holding the event lock is not appropriate, create a class that implements the Runnable interface. Invoke its
run() method on the event dispatch thread by invoking one of the following three methods:
• Invoke invokeAndWait(Runnable) to have run() called on the event dispatch thread immediately. The call
blocks until run() completes.
• Invoke invokeLater(Runnable) to have run() called on the event dispatch thread after all pending events
are processed.
• Invoke invokeLater(Runnable, long, boolean) to have run() called on the event dispatch thread after
a specified amount of time, where time specifies the number of milliseconds to wait before adding Runnable
to the event queue. If repeat is true, the Runnable is added to the event queue every time milliseconds.
Manage foreground events
The system calls Application.activate() when it brings an application to the foreground.
Most applications do not need to override activate(). Applications should perform any initialization, including
any required UiApplication.pushScreen() calls, in the application constructor. Because activate() can be
called multiple times for the same application, applications should not perform a one-time initialization in this
method.
An application can override activate() to perform additional processing when it is brought to the foreground. If
you override activate(), invoke super.activate() from within the method definition so that the application
repaints correctly.
Manage drawing areas
Using XYRect objects
The Graphics object represents the entire drawing surface that is available to the application. To limit this area,
divide it into XYRect objects. An XYRect creates rectangular clipping regions on top of the graphics context.
An XYRect object consists of two XYPoint objects. The first XYPoint object represents the top left coordinate of
the XYRect, and the second XYPoint represents the bottom right coordinate. Each XYPoint represents a point on
the screen, which is composed of an X coordinate and a Y coordinate.
51
BlackBerry Application Developer Guide Volume 1: Fundamentals
XYPoint topLeft = new XYPoint(10, 10);
XYPoint bottomRight = new XYPoint(50, 50);
XYRect rectangle = new XYRect(topLeft, bottomRight);
The rectangle object limits the drawing area of the context for this XYRect object to the area between (10,
10) and (50, 50).
To initiate drawing calls to the XYRect object, invoke pushContext() or pushRegion().
When you make drawing calls with pushContext(), specify that the region origin should not adjust the drawing
offset.
graphics.pushContext(rectangle, 0, 0);
graphics.fillRect(10, 10, 30, 30);
graphics.drawRect(15, 15, 30, 30);
graphics.popContext();
When you invoke drawing methods by first calling pushRegion(), you specify that the drawing offset is to be
adjusted by the region origin. The top left XYPoint object represents the region origin. All drawing is offset by this
amount.
In the following example, pushRegion() places the XYRect object 10 pixels to the right of, and 10 pixels down,
from (10, 10). The region origin adjusts the drawing offset (XYPoint topLeft = new XYPoint(10, 10)).
graphics.pushRegion(rectangle);
graphics.fillRect(10, 10, 30, 30);
graphics.drawRect(15, 15, 30, 30);
graphics.popRegion();
Invert an area
Inverting an area on the Graphics object reverses the pixels by inverting the bits in each pixel value (that is, 0s
become 1s, 1s become 0s). Most fields use inversion to signify focus; however, you can create your own focus
behavior for custom fields.
To invert an arbitrary portion of the Graphics object, provide coordinates, or invert a specified XYRect object.
Specify the portion of the Graphics object to push onto the stack. After you invoke pushContext() (or
pushRegion()), provide the portion of the Graphics object to invert.
graphics.pushContext(rectangle);
graphics.invert(rectangle); // invert
graphics.popContext();
the entire XYRect object
Translate an area
To move an area to another location in the graphics context, invoke translate().
XYRect rectangle = new XYRect(1, 1, 100, 100);
XYPoint newLocation = new XYPoint(20, 20);
rectangle.translate(newLocation);
The XYRect is translated from its origin of (1, 1) to an origin of (20, 20). After translation, the bottom portion
of the XYRect object extends past the bounds of the graphics context and is clipped.
52
3: Creating user interfaces
Creating custom user interface components
You can only add custom context menu items and custom layouts to a custom field.
Create custom fields
To override default field behaviour, create a custom field.
Note: Do not use Screen objects for text input. Screen does not implement disambiguation, which is required for complex input
methods such as international keyboards and the 7100 series of wireless handhelds. For seamless integration of the different input
methods, extend Field or one of its subclasses.
Your implementation of the DrawStyle interface enables drawing styles on custom fields. See "Create an
interface that is consistent with standard BlackBerry user interfaces" on page 73 for more information.
Your custom field should implement all relevant system styles. For example, USE_ALL_WIDTH and
USE_ALL_HEIGHT are appropriate for many fields.
Extend the Field class
Extend the Field class, or one of its subclasses, to specify the characteristics of the custom field.
public class CustomButtonField extends Field implements DrawStyle {
public static final int RECTANGLE = 1;
public static final int TRIANGLE = 2;
public static final int OCTAGON = 3;
private String _label;
private int _shape;
private Font _font;
private int _labelHeight;
private int _labelWidth;
}
Define the label, shape, and style of the button
Your constructor implementations define the label, shape, and style of the button.
public CustomButtonField(String label)
this(label, RECTANGLE, 0);
}
public CustomButtonField(String label,
this(label, shape, 0);
}
public CustomButtonField(String label,
this(label, RECTANGLE, style);
}
public CustomButtonField(String label,
super(style);
_label = label;
_shape = shape;
_font = getFont();
_labelHeight = _font.getHeight();
_labelWidth = font.getWidth();
}
{
int shape) {
long style) {
int shape, long style) {
53
BlackBerry Application Developer Guide Volume 1: Fundamentals
Specify the arrangement of objects in the field
Any class that extends Field must implement layout(). The field manager invokes layout() to determine how
the field should arrange its contents, according to the available space.
protected void layout(int width, int height) {
_font = getFont();
_labelHeight = _font.getHeight();
_labelWidth = _font.getAdvance(_label);
width = Math.min( width, getPreferredWidth() );
height = Math.min( height, getPreferredHeight() );
setExtent( width, height );
}
The width and height parameters specify the available horizontal and vertical space, respectively. To calculate
the available width and height, invoke Math.min() to return the smaller of the specified width and height and
the preferred width and height of the field. See "Define the preferred width" on page 54 for more information.
To set the required dimensions for the field, invoke setExtent(int, int). If you do not invoke setExtent(),
the field is not painted and an exception is not thrown.
Note: Arrange field data so that you perform the most complex calculations in layout(), instead of in paint(). Your
implementation of paint() should be as efficient as possible.
Recalculate pixel layout, cached fonts, and locale strings in layout(). The framework invokes this method whenever system
preferences change. For example, when the system default font changes, all fields in the system update automatically if their layout
method is implemented correctly. The same is true for locale changes and date format changes.
Define the preferred width
Note: In most cases, override getPreferredWidth() to make sure that the proper layout appears in custom layout managers.
Your implementation of getPreferredWidth() calculates the preferred width of the custom field based on the
relative dimensions of the field label. Using the relative dimensions makes sure that the label does not exceed the
field dimensions.
public int getPreferredWidth() {
switch(_shape) {
case TRIANGLE:
if (_labelWidth < _labelHeight) {
return _labelHeight << 2;
} else {
return _labelWidth << 1;
}
case OCTAGON:
if (_labelWidth < _labelHeight) {
return _labelHeight + 4;
} else {
return _labelWidth + 8;
}
case RECTANGLE: default:
return _labelWidth + 8;
}
}
54
3: Creating user interfaces
Define the preferred height
Note: In most cases, override getPreferredHeight() to make sure that the proper layout appears in custom layout managers.
Your implementation of getPreferredHeight() determines the preferred height of the custom field based on
the relative dimensions of the field label. This makes sure that the label does not exceed the field dimensions.
public int getPreferredHeight() {
switch(_shape) {
case TRIANGLE:
if (_labelWidth < _labelHeight) {
return _labelHeight << 1;
} else {
return _labelWidth;
}
case RECTANGLE:
return _labelHeight + 4;
case OCTAGON:
return getPreferredWidth();
}
return 0;
}
Define the appearance of the custom field
Your implementation of paint() defines the appearance of the custom field on BlackBerry device screens. The
field manager invokes paint() to redraw the field whenever an area of the field is marked as invalid.
Tip: Verify that paint() is efficient because the UI framework calls paint() whenever an area of the field changes.
For large fields, use Graphics.getClippingRect() to save drawing time by painting only within the visible region.
Avoid allocating in paint(); arrange field data so that complex calculations are performed in layout() instead of in paint().
protected void paint(Graphics graphics) {
int textX, textY, textWidth;
int w = getWidth();
switch(_shape) {
case TRIANGLE:
int h = (w>>1);
int m = (w>>1)-1;
graphics.drawLine(0, h-1, m, 0);
graphics.drawLine(m, 0, w-1, h-1);
graphics.drawLine(0, h-1, w-1, h-1);
textWidth = Math.min(_labelWidth,h);
textX = (w - textWidth) >> 1;
textY = h >> 1;
break;
case OCTAGON:
int x = 5*w/17;
int x2 = w-x-1;
int x3 = w-1;
graphics.drawLine(0, x, 0, x2);
graphics.drawLine(x3, x, x3, x2);
graphics.drawLine(x, 0, x2, 0);
graphics.drawLine(x, x3, x2, x3);
graphics.drawLine(0, x, x, 0);
55
BlackBerry Application Developer Guide Volume 1: Fundamentals
graphics.drawLine(0, x2, x, x3);
graphics.drawLine(x2, 0, x3, x);
graphics.drawLine(x2, x3, x3, x2);
textWidth = Math.min(_labelWidth, w - 6);
textX = (w-textWidth) >> 1;
textY = (w-_labelHeight) >> 1;
break;
case RECTANGLE: default:
graphics.drawRect(0, 0, w, getHeight());
textX = 4;
textY = 2;
textWidth = w - 6;
break;
}
graphics.drawText(_label, textX, textY, (int)( getStyle() & DrawStyle.ELLIPSIS |
DrawStyle.HALIGN_MASK ), textWidth );
}
Handle focus events
To support focus events, use the Field.FOCUSABLE style and implement Field.moveFocus(). If you want your
field to receive focus, override Field.isFocusable() to return true.
The UI framework invokes onFocus() when the field gains focus and onUnfocus() when the field loses focus.
Override these methods if your field requires specific behavior for these events. The framework invokes
moveFocus() to handle focus movements in a field. This corresponds to the trackwheelRoll event. Override
moveFocus() for special behavior.
To change the appearance of the default focus indicator (inverting the contents of the entire field), override
drawFocus().
Implement set and get methods
Your implementations of the get and set methods of Field add capabilities to your field.
Note: All get and set methods should work before and after the field is added to a Screen. For example, setLabel() should update
the display with the new value if the field is currently on screen by invoking invalidate() or updateLayout() as appropriate.
public String getLabel() {
return _label;
}
public int getShape() {
return _shape;
}
public void setLabel(String label) {
_label = label;
_labelWidth = _font.getAdvance(_label);
updateLayout();
}
public void setShape(int shape) {
_shape = shape;
updateLayout();
}
56
3: Creating user interfaces
Code example
The CustomButtonField.java sample creates button fields of various shapes.
Example: CustomButtonField.java
/**
* CustomButtonField.java
* Copyright (C) 2001-2005 Research In Motion Limited. All rights reserved.
*/
package com.rim.samples.docs.custombuttons;
import net.rim.device.api.ui.*;
import net.rim.device.api.system.*;
/**
* CustomButtonField is a class that creates button fields of various
* shapes. This sample demonstrates how to create custom UI fields.
*/
public class CustomButtonField extends Field implements DrawStyle {
public static final int RECTANGLE = 1;
public static final int TRIANGLE = 2;
public static final int OCTAGON = 3;
private
private
private
private
private
String _label;
int _shape;
Font _font;
int _labelHeight;
int _labelWidth;
/* Constructs a button with specified label, and the default style and shape. */
public CustomButtonField(String label) {
this(label, RECTANGLE, 0);
}
/* Constructs a button with specified label and shape, and the default style. */
public CustomButtonField(String label, int shape) {
this(label, shape, 0);
}
/* Constructs a button with specified label and style, and the default shape. */
public CustomButtonField(String label, long style) {
this(label, RECTANGLE, style);
}
/* Constructs a button with specified label, shape, and style */
public CustomButtonField(String label, int shape, long style) {
super(style);
_label = label;
_shape = shape;
_font = getFont();
_labelHeight = _font.getHeight();
_labelWidth = _font.getAdvance(_label);
}
/* Method that draws the focus indicator for this button and
57
BlackBerry Application Developer Guide Volume 1: Fundamentals
* inverts the inside region of the shape.
*/
protected void drawFocus(Graphics graphics, boolean on) {
switch(_shape) {
case TRIANGLE:
int w = getWidth();
int h = w >> 1;
for (int i=h-1; i>=2; --i) {
graphics.invert(i, h - i, w - (i << 1), 1);
}
break;
case RECTANGLE:
graphics.invert(1, 1, getWidth() - 2, getHeight() - 2);
break;
case OCTAGON:
int x3 = getWidth();
int x = 5 * x3 / 17;
int x2 = x3 - x;
x3 = x3 - 1;
x2 = x2 - 1;
graphics.invert(1, x, getWidth() - 2, x2 - x + 1);
for (int i=1; i<x; ++i) {
graphics.invert(1+i, x-i,
getWidth() - ((i+1)<<1), 1);
graphics.invert(1+i, x2+i,
getWidth() - ((i+1)<<1), 1);
}
break;
}
}
/* Returns the label. */
public String getLabel() {
return _label;
}
/* Returns the shape. */
public int getShape() {
return _shape;
}
/* Sets the label. */
public void setLabel(String label) {
_label = label;
_labelWidth = _font.getAdvance(_label);
updateLayout();
}
/* Sets the shape. */
public void setShape(int shape) {
_shape = shape;
updateLayout();
}
/* Retrieves the preferred width of the button. */
public int getPreferredWidth() {
switch(_shape) {
case TRIANGLE:
58
3: Creating user interfaces
if (_labelWidth < _labelHeight) {
return _labelHeight << 2;
} else {
return _labelWidth << 1;
}
case OCTAGON:
if (_labelWidth < _labelHeight) {
return _labelHeight + 4;
} else {
return _labelWidth + 8;
}
case RECTANGLE: default:
return _labelWidth + 8;
}
}
/* Retrieves the preferred height of the button. */
public int getPreferredHeight() {
switch(_shape) {
case TRIANGLE:
if (_labelWidth < _labelHeight) {
return _labelHeight << 1;
} else {
return _labelWidth;
}
case RECTANGLE:
return _labelHeight + 4;
case OCTAGON:
return getPreferredWidth();
}
return 0;
}
/* Lays out this button’s contents.
* This field’s manager invokes this method during the layout
* process to instruct this field to arrange its contents, given an
* amount of available space.
**/
protected void layout(int width, int height) {
// Update the cached font in case it has been changed.
_font = getFont();
_labelHeight = _font.getHeight();
_labelWidth = _font.getAdvance(_label);
// Calculate width.
width = Math.min( width, getPreferredWidth() );
// Calculate height.
height = Math.min( height, getPreferredHeight() );
// Set dimensions.
setExtent( width, height );
}
/*
* Redraws this button. The field’s manager invokes this method during the
* repainting process to instruct this field to repaint itself.
*/
protected void paint(Graphics graphics) {
int textX, textY, textWidth;
int w = getWidth();
59
BlackBerry Application Developer Guide Volume 1: Fundamentals
switch(_shape) {
case TRIANGLE:
int h = (w>>1);
int m = (w>>1)-1;
graphics.drawLine(0, h-1, m, 0);
graphics.drawLine(m, 0, w-1, h-1);
graphics.drawLine(0, h-1, w-1, h-1);
textWidth = Math.min(_labelWidth,h);
textX = (w - textWidth) >> 1;
textY = h >> 1;
break;
case OCTAGON:
int x = 5*w/17;
int x2 = w-x-1;
int x3 = w-1;
graphics.drawLine(0, x, 0, x2);
graphics.drawLine(x3, x, x3, x2);
graphics.drawLine(x, 0, x2, 0);
graphics.drawLine(x, x3, x2, x3);
graphics.drawLine(0, x, x, 0);
graphics.drawLine(0, x2, x, x3);
graphics.drawLine(x2, 0, x3, x);
graphics.drawLine(x2, x3, x3, x2);
textWidth = Math.min(_labelWidth, w - 6);
textX = (w-textWidth) >> 1;
textY = (w-_labelHeight) >> 1;
break;
case RECTANGLE: default:
graphics.drawRect(0, 0, w, getHeight());
textX = 4;
textY = 2;
textWidth = w - 6;
break;
}
graphics.drawText(_label, textX, textY, (int)( getStyle() &
DrawStyle.ELLIPSIS | DrawStyle.HALIGN_MASK ),
textWidth );
}
}
Create custom context menus
The system invokes getContextMenu() when context menu events occur. It invokes makeContextMenu() to
reset the context menu with the menu items that are appropriate for that field. The context menu contents remain
set until the next time getContextMenu() is invoked.
To add custom context menu items to specific fields, create custom context menu items and then override
makeContextMenu() and makeMenu() to provide and display a context menu.
Custom context menus can only be added to custom fields. See "Create custom fields" on page 53 for more
information.
60
3: Creating user interfaces
Create custom context menu items
In your field class, create the custom context menu items. See "Display screens" on page 39 for more information
on implementing menus.
private MenuItem myContextMenuItemA = new MenuItem( _resources, MENUITEM_ONE, 200000, 10) {
public void run() {
onMyMenuItemA();
}
};
private MenuItem myContextMenuItemB = new MenuItem( _resources, MENUITEM_ONE, 200000, 10) {
public void run() {
onMyMenuItemB();
}
};
Provide a context menu
In your main application class, override makeContextMenu() to provide a context menu.
protected void makeContextMenu(ContextMenu contextMenu) {
contextMenu.addItem(myContextMenuItemA);
contextMenu.addItem(myContextMenuItemB);
}
Create the application menu
In your main application class, override makeMenu() to create the application menu and update the context menu
whenever a particular field has the focus.
protected void makeMenu(Menu menu) {
Field focus =
UiApplication.getUiApplication().getActiveScreen().getLeafFieldWithFocus();
if (focus != null) {
ContextMenu contextMenu = focus.getContextMenu();
if (!contextMenu.isEmpty()) {
menu.add(contextMenu);
menu.addSeparator();
}
}
}
Code example
Example: ContextMenuSample.java
/**
* ContextMenuSample.java
* Copyright (C) 2001-2005 Research In Motion Limited. All rights reserved.
*/
package com.rim.samples.docs.contextmenus;
import net.rim.device.api.i18n.*;
import net.rim.device.api.ui.*;
import net.rim.device.api.ui.component.*;
61
BlackBerry Application Developer Guide Volume 1: Fundamentals
import net.rim.device.api.ui.container.*;
import net.rim.device.api.system.*;
import com.rim.samples.docs.baseapp.*;
public class ContextMenuSample extends BaseApp implements ContextMenuSampleResource {
private MyContextField myContextField;
private static ResourceBundle _resources = ResourceBundle.getBundle(
ContextMenuSampleResource.BUNDLE_ID,
ContextMenuSampleResource.BUNDLE_NAME);
public static void main(String[] args) {
ContextMenuSample app = new ContextMenuSample();
app.enterEventDispatcher();
}
// Inner class to define a new field.
private class MyContextField extends RichTextField {
private MenuItem myContextMenuItemA = new MenuItem(
_resources, MENUITEM_ONE, 200000, 10) {
public void run() {
onMyMenuItemA();
}
};
private MenuItem myContextMenuItemB = new MenuItem(
_resources, MENUITEM_TWO, 200000, 10) {
public void run() {
onMyMenuItemB();
}
};
private void onMyMenuItemA() {
// Perform an action when user selects menu item.
}
private void onMyMenuItemB() {
// Perform an action when user selects menu item.
}
protected void makeContextMenu(ContextMenu contextMenu) {
contextMenu.addItem(myContextMenuItemA);
contextMenu.addItem(myContextMenuItemB);
}
MyContextField(String text) {
super(text);
}
}
protected void makeMenu(Menu menu) {
super.makeMenu(menu, 0); // Implemented by BaseApp.
}
public ContextMenuSample() {
MainScreen mainScreen = new MainScreen();
MyContextField myContextField = new MyContextField(“Field label: “);
mainScreen.add(myContextField);
62
3: Creating user interfaces
mainScreen.addKeyListener(this);
mainScreen.addTrackwheelListener(this);
pushScreen(mainScreen);
}
public void onExit() {
// Perform action when application closes.
}
}
Create custom layout managers
Manager
objects control the position of UI components and determine how fields are organized on the screen.
Create a custom layout manager
Extend the Manager class or one of its subclasses.
class DiagonalManager extends Manager {
public DiagonalManager(long style){
super(style);
}
...
}
Return a preferred field width
Override getPreferredWidth() so that it returns the preferred field width for the manager.
Your implementation of getPreferredWidth() might return a different value depending on the purpose of the
layout manager. For example, if a manager extends HoriztonalFieldManager, getPreferredWidth() returns
the sum of the widths of each field. If a manager extends VerticalFieldManager, getPreferredWidth()
returns the width of the widest field.
public
int
int
for
int getPreferredWidth() {
width = 0;
numberOfFields = getFieldCount();
(int i=0; i<numberOfFields; ++i) {
width += getField(i).getPreferredWidth();
}
return width;
}
Note: TextFields and Managers use the entire width that is assigned to them. To organize two or more of these objects
horizontally, override their respective getPreferredWidth() methods accordingly. To organize multiple TextFields horizontally,
override layout().
Return a preferred field height
Override getPreferredHeight() so that it returns the preferred field height for the manager.
63
BlackBerry Application Developer Guide Volume 1: Fundamentals
public
int
int
for
int getPreferredHeight() {
height = 0;
numberOfFields = getFieldCount();
(int i=0; i<numberOfFields; ++i) {
height += getField(i).getPreferredHeight();
}
return height;
}
Specify how child fields are arranged
The sublayout() method specifies how the manager organizes fields on the screen. It retrieves the total number
of fields in the manager and sets the appropriate positioning and layout for the child fields.
The layout() method invokes sublayout(). The sublayout() method controls how each child field is added to
the screen by calling setPositionChild() and layoutChild() for each field that the manager contains.
protected void sublayout(int width, int height) {
int x = 0;
int y = 0;
Field field;
int numberOfFields = getFieldCount();
for (int i=0; i<numberOfFields; ++i) {
field = getField(i);
layoutChild(field, width, height);
setPositionChild(field, x, y);
field.setPosition(x,y);
x += field.getPreferredWidth();
y += field.getPreferredHeight();
}
setExtent(width,height);
}
Note: To set the required size for the fields, invoke setExtent() in sublayout(). If you do not invoke setExtent(), the field
is not painted and an exception is not thrown.
Handle focus
To specify how fields should be given focus when the user rolls the trackwheel, override nextFocus(). The
direction parameter indicates the direction in which the focus moves (generally, down and to the right when
the trackwheel is rolled down, and up and to the left when the trackwheel is rolled up).
protected int nextFocus(int direction, boolean alt) {
int index = this.getFieldWithFocusIndex();
if(alt) {
if(direction > 0) {
// action to perform if trackwheel is rolled up
} else {
// action to perform if trackwheel is rolled down
}
}
if (index == this.getFieldWithFocusIndex())
return super.nextFocus(direction, alt);
else
return index;
}
64
3: Creating user interfaces
To shift the focus to a field that is not the next field in the layout order of the manager, override nextFocus().
For example, nextFocus() is useful if you want to implement page-up and page-down functionality for the
manager.
Repaint fields when the visible region changes
By default, the custom manager invokes paint() to repaint all the fields without regard to the clipping region. If
this results in unnecessary repainting, your implementation of subpaint() repaints fields only when the visible
region changes.
Code example
Example: DiagonalManager.java
/**
* DiagonalManager.java
* Copyright (C) 2001-2005 Research In Motion Limited. All rights reserved.
*/
package com.rim.samples.docs.custommenu;
import
import
import
import
net.rim.device.api.system.*;
net.rim.device.api.ui.container.*;
net.rim.device.api.ui.*;
net.rim.device.api.ui.component.*;
class DiagonalManager extends Manager {
public DiagonalManager(long style) {
super(style);
}
public int getPreferredWidth() {
int width = 0;
int numberOfFields = getFieldCount();
for (int i=0; i<numberOfFields; ++i) {
width += getField(i).getPreferredWidth();
}
return width;
}
public int getPreferredHeight() {
int height = 0;
int numberOfFields = getFieldCount();
for (int i=0; i<numberOfFields; ++i) {
height += getField(i).getPreferredHeight();
}
return height;
}
protected void sublayout(int width, int height) {
int x = 0;
int y = 0;
Field field;
int numberOfFields = getFieldCount();
65
BlackBerry Application Developer Guide Volume 1: Fundamentals
for (int i=0; i<numberOfFields; ++i) {
field = getField(i);
layoutChild( field, width, height );
setPositionChild(field, x, y);
x += field.getPreferredWidth();
y += field.getPreferredHeight();
}
setExtent(width,height);
}
protected int nextFocus(int direction, boolean alt) {
int index = this.getFieldWithFocusIndex();
if(alt) {
if(direction > 0) {
// Action to perform if trackwheel is rolled up.
}
else {
// Action to perform if trackwheel is rolled down.
}
}
if (index == this.getFieldWithFocusIndex())
return super.nextFocus(direction, alt);
else
return index;
}
}
Create lists
A ListField contains rows of selectable items. To enable users to select multiple items in the list, declare lists as
MULTI_SELECT.
Create a callback object
A ListFieldCallback object controls all repainting tasks for the list. Each time the field is required to display an
entry in the list, the necessary methods are invoked on the callback object.
Your implementation of the ListFieldCallback interface creates a callback object. The system calls methods in
this interface to paint a particular list row, get a particular list element, or determine the list width.
private class ListCallback implements ListFieldCallback {
// The listElements vector contain the entries in the list.
private Vector listElements = new Vector();
...
}
Enable the field to repaint a row
Your implementation of drawListRow() enables the field to repaint a row. The graphics context that is passed
into drawListRow() represents the entire list; accordingly, your invocation of drawText() must specify which
row to paint.
public void drawListRow(ListField list, Graphics g, int index, int y, int w) {
66
3: Creating user interfaces
String text = (String)listElements.elementAt(index);
g.drawText(text, 0, y, 0, w);
}
Enable the field to retrieve an entry from the list
Your implementation of get() enables the field to retrieve an entry from the list. This method returns the object
contained in the row specified by index.
public Object get(ListField list, int index) {
return listElements.elementAt(index);
}
Return a preferred width for the List
Your implementation of getPreferredWidth() returns a preferred width for the List. In the following
implementation, getPreferredWidth() returns the total drawing width of the screen.
Your implementation of getPreferredWidth() returns a different value depending on the type of field manager.
For example, if the field manager organizes fields horizontally, getPreferredWidth() should return the sum of
the widths of each field. If the manager organizes fields vertically, getPreferredWidth() should return the
width of the widest field.
public int getPreferredWidth(ListField list) {
return Graphics.getScreenWidth();
}
Assign the callback and adding entries to the list
Create the list objects and assign the callback to the list.
Create the list objects
Create the ListField and ListCallback objects for this list.
Note: ListCallback is the custom ListFieldCallback class created in “Create a callback object” on page 66.
ListField myList = new ListField();
ListCallback myCallback = new ListCallback();
Set the callback
Invoke setCallback() to associate the ListFieldCallback with the ListField. This association enables the
callback to add items to the list.
myList.setCallback(myCallback);
Add the list entries
To add entries to the list, create entries, specify an index at which to insert each entry on the ListField object,
and then insert each ListField object into the ListFieldCallback.
String fieldOne = new String("Field one label");
67
BlackBerry Application Developer Guide Volume 1: Fundamentals
String fieldTwo = new String("Field two label");
String fieldThree = new String("Field three label");
myList.insert(0);
myList.insert(1);
myList.insert(2);
myCallback.insert(fieldOne, 0);
myCallback.insert(fieldTwo, 1);
myCallback.insert(fieldThree, 2);
mainScreen.add(myList);
Code example
Example: SampleListFieldCallback.java
/**
* SampleListFieldCallback.java
* Copyright (C) 2001-2005 Research In Motion Limited. All rights reserved.
*/
package com.rim.samples.docs.listfields;
import
import
import
import
import
java.util.*;
net.rim.device.api.system.*;
net.rim.device.api.ui.*;
net.rim.device.api.ui.component.*;
net.rim.device.api.ui.container.*;
public class SampleListFieldCallback extends UiApplication {
private ListField myList;
public static void main(String[] args) {
SampleListFieldCallback app = new SampleListFieldCallback();
app.enterEventDispatcher();
}
private static class ListCallback implements ListFieldCallback {
private Vector listElements = new Vector();
public void drawListRow(
ListField list, Graphics g, int index, int y, int w) {
String text = (String)listElements.elementAt(index);
g.drawText(text, 0, y, 0, w);
}
public Object get(ListField list, int index) {
return listElements.elementAt(index);
}
public int indexOfList(ListField list, String p, int s) {
return listElements.indexOf(p, s);
}
public int getPreferredWidth(ListField list) {
return Graphics.getScreenWidth();
}
public void insert(String toInsert, int index) {
listElements.addElement(toInsert);
}
public void erase() {
listElements.removeAllElements();
}
}
public SampleListFieldCallback() {
68
3: Creating user interfaces
MainScreen mainScreen = new MainScreen();
myList = new ListField();
ListCallback myCallback = new ListCallback();
myList.setCallback(myCallback);
String fieldOne = “ListField one”;
String fieldTwo = “ListField two”;
String fieldThree = “ListField three”;
myList.insert(0);
myCallback.insert(fieldOne, 0);
myList.insert(1);
myCallback.insert(fieldTwo, 1);
myList.insert(2);
myCallback.insert(fieldThree, 2);
mainScreen.add(myList);
pushScreen(mainScreen);
}
}
Working with images
Use raw image data
To retrieve raw image data from a specified region of a bitmap and store the data in an integer array, invoke
Bitmap.getARGB(). Applications can then manipulate the raw image data directly.
void getARGB(int[] argbData, int offset, int scanLength, int x, int y, int width, int
height);
Note: The getARGB() method is only available on BlackBerry devices with color screens.
Parameter
Description
argbData
integer array that stores the ARGB data; each pixel is stored in 0xAARRGGBB format
offset
offset into the data from which to start retrieving
scanLength
width of a scan line within the data array
x
left edge of the rectangle from which to retrieve image data
y
top edge of the rectangle from which to retrieve image data
width
width of the rectangle from which to retrieve image data
height
height of the rectangle from which to retrieve image data
The device simulator displays image data as one integer for each pixel, with 8 bits each for alpha (opacity), red,
green, and blue values. The color components are packed into the int as 0xAARRGGBB.
Retrieve image data
Initialize an integer array, and then invoke Bitmap.getARGB() to store the raw image data of the new or
predefined bitmap in the integer array.
69
BlackBerry Application Developer Guide Volume 1: Fundamentals
Bitmap original = Bitmap.getPredefinedBitmap(Bitmap.INFORMATION);
int[] argb = new int[original.getWidth() * original.getHeight()];
original.getARGB(argb, 0, original.getWidth(), 0, 0, original.getWidth(),
original.getHeight());
Compare two images
Invoke Bitmap.equals() to determine if the two bitmaps are identical.
if(restored.equals(original)) {
System.out.println("Success! Bitmap renders correctly with RGB data.");
} else if(!restored.equals(original)) {
System.out.println("Bitmap rendered incorrectly with RGB data.");
}
Use encoded images
The net.rim.device.api.system.EncodedImage class encapsulates encoded images of various formats. The
BlackBerry device supports the following image formats: .gif, .png, .wbmp, and .jpeg. Only BlackBerry devices with
color screens support .jpeg images.
Note: The JPEGEncodedImage class requires a signature that is not available.
Use EncodedImage subclasses, PNGEncodedImage and WBMPEncodedImage, to access specific properties of .png
and .wbmp images, respectively. For example, PNGEncodedImage provides methods to retrieve the bit depth of
the image, the bit depth of the alpha channel, and the color type.
An application can directly access images that are added to its project or to a library project on which it depends
in the BlackBerry Integrated Development Environment (BlackBerry IDE).
Access an image
Save an image to the project folder or subfolder, and then add the image to the project in the BlackBerry IDE.
Invoke Class.getResourceAsStream() to retrieve the image as an input stream of bytes.
private InputStream input;
...
try {
input = Class.forName("com.rim.samples.docs.imagedemo.ImageDemo").
getResourceAsStream("/images/example.png");
} catch (ClassNotFoundException e) {
System.out.println("Class not found");
}
Decode an image
To encode an image, invoke EncodedImage.createEncodedImage(). This method creates an instance of
EncodedImage using the raw image data in the byte array. It throws an IllegalArgumentException if the byte
array that is provided as a parameter does not contain a recognized image format.
private byte[] data = new byte[2430]; // Store the contents of the image file.
try {
input.read(data); // Read the image data into the byte array.
70
3: Creating user interfaces
} catch (IOException e) {
// Handle exception.
}
try {
EncodedImage image = EncodedImage.createEncodedImage(data, 0, data.length);
} catch (IllegalArgumentException iae) {
System.out.println("Image format not recognized.");
}
Note: By default, the BlackBerry device software detects the MIME type of an image based on the image format. If the correct MIME
type is not detected automatically, use the following form of EncodedImage.createEncodedImage() to specify a particular
MIME type:
createEncodedImage(byte[] data, createEncodedImage(byte[] data, int offset, int length, String
mimeType)
This method throws an IllegalArgumentException if the image format does not match the specified MIME type. Supported
MIME types include: image/gif, image/png, image/vnd.wap.wbmp, and image/jpeg.
Display an encoded image
Invoke BitmapField.setImage() to assign the encoded image to a BitmapField, and then invoke add() to
add the BitmapField to the screen.
BitmapField field = new BitmapField();
field.setImage(image);
add(field);
Set the decoding mode
Invoke EncodedImage.setDecodeMode() to set the decoding mode of the image. Provide one of the following
modes as a parameter to the method:
Decoding mode
Description
DECODE_ALPHA
decodes an alpha channel, if one exists (this is the default mode)
DECODE_NATIVE
forces the bitmap to be decoded to the native bitmap type of the handheld software
DECODE_READONLY
marks the decoded bitmap as read-only
Set the scaling factor
To set the integer factor that is used to downscale an image when decoding, invoke EncodedImage.setScale().
The image is scaled by the inverse of the integer specified by the scale parameter. For example, if you set the
scaling factor to 2, the image is decoded at 50% of its original size.
Code example
The ImageDemo.java sample retrieves raw data from an image that is included in its project, and then uses that
raw data to recreate an EncodedImage.
Example: ImageDemo.java
/**
* ImageDemo.java
71
BlackBerry Application Developer Guide Volume 1: Fundamentals
* Copyright (C) 2001-2005 Research In Motion Limited. All rights reserved.
*/
package com.rim.samples.docs.imagedemo;
import
import
import
import
import
net.rim.device.api.ui.*;
net.rim.device.api.ui.component.*;
net.rim.device.api.ui.container.*;
net.rim.device.api.system.*;
java.io.*;
/* The ImageDemo.java sample retrieves raw data from an image that
is included in its project, and then uses that raw data to
recreate an EncodedImage. */
public class ImageDemo extends UiApplication {
public static void main(String[] args) {
ImageDemo app = new ImageDemo();
app.enterEventDispatcher();
}
public ImageDemo() {
pushScreen(new ImageDemoScreen());
}
}
final class
private
private
private
ImageDemoScreen extends MainScreen {
static final int IMAGE_SIZE = 2430;
InputStream input;
byte[] data = new byte[IMAGE_SIZE];
public ImageDemoScreen() {
super();
setTitle(new LabelField(“Image Demo Sample”));
try {
input =
Class.forName(“com.rim.samples.docs.imagedemo.ImageDemo”).getResourceAsStream(“/images/
hellokitty.png”);
} catch (ClassNotFoundException e) {
System.out.println(“Class not found”);
}
if(input == null) {
System.out.println(“Error: input stream is not initialized.”);
} else if (input != null) {
System.out.println(“OK: input stream is initialized.”);
try {
int code = input.read(data);
System.out.println(“Total number of bytes read into buffer: “ + code + “
.”);
} catch (IOException e) {
// Handle exception.
}
try {
EncodedImage image = EncodedImage.createEncodedImage(data, 0, data.length);
add(new BitmapField(image.getBitmap()));
} catch (IllegalArgumentException iae) {
System.out.println(“Image format not recognized.”);
}
72
3: Creating user interfaces
}
}
}
Drawing using graphics objects
objects enable applications to perform drawing functions and rendering operations. Use the Graphics
class to draw over the entire screen or on a BitmapField. If your application does not contain any fields, invoke
Screen.getGraphics() to obtain the graphics context for the entire screen.
Graphics
To draw over a specific BitmapField, an application obtains a graphics context for a particular field by passing
the field into the Graphics constructor. When drawing over a BitmapField, the field manager passes the
graphics context to the fields when the fields repaint. To perform custom drawing over a field, override the
Graphics.paint() method when you extend the Field class.
The Graphics class enables you to draw shapes, such as arcs, lines, rectangles, and circles.
Use the graphics context
To draw with the Graphics class, obtain a graphics context for an individual field or the entire screen.
To obtain a graphics context for an individual field, invoke the Graphics() constructor.
Bitmap surface = new Bitmap(100, 100);
BitmapField surfaceField = new BitmapField(surface);
Graphics graphics = new Graphics(surface);
To obtain a graphics context for the entire screen, invoke Screen.getGraphics().
Graphics graphics = Screen.getGraphics();
To draw using any graphics context, make sure your methods perform their drawing functions within the
boundaries of the field or screen.
graphics.fillRect(10, 10, 30, 30);
graphics.drawRect(15, 15, 30, 30);
If your graphics context does not apply to the entire screen, add the BitmapField to the screen.
mainScreen.add(surfaceField);
Create an interface that is consistent with standard BlackBerry user
interfaces
The DrawStyle interface provides styles that are used by Graphics and Field objects. Implementing DrawStyle
enables you to create an interface that is consistent with standard BlackBerry user interfaces. If you are extending
the Field class to create a custom field, your code should accept the appropriate styles so that it acts similarly to
standard BlackBerry applications.
DrawStyle
is applied to fields as style parameters, as in the following example:
73
BlackBerry Application Developer Guide Volume 1: Fundamentals
ButtonField buttonField = new ButtonField(DrawStyle.ELLIPSIS);
You can use DrawStyle elements in the following objects:
•
BitmapField
•
ButtonField
•
DateField
•
Graphics
•
LabelField
•
ObjectListField
Draw in color
Drawing in color is only applicable to BlackBerry devices with color screens. To determine whether BlackBerry
devices provide color display, invoke Graphics.isColor(). To determine the number of colors that BlackBerry
devices support, invoke Graphics.numColors().
Set alpha values
The global alpha value determines the transparency of pixels in the drawing area, where 0 (0x0000) is completely
transparent (invisible) and 255 (0x00FF) is fully opaque. To set or get the global alpha value, invoke
Graphics.setGlobalApha() or Graphics.getGlobalAlpha().
Note: The BlackBerry device uses the alpha value for certain raster operations. Text and drawing operations do not use the alpha value.
Determine raster operation support
To determine if a Graphics object supports a particular raster operation, invoke
Graphics.isRopSupported(int), providing one of the following constants as parameter.
Constant
Raster operation
ROP_CONST_GLOBALALPHA
blends the constant foreground color using a constant global alpha value with destination pixels
ROP_SRC_GLOBALALPHA
blends a source bitmap using a constant global alpha value with destination pixels
Draw a path
To draw a set of shaded, filled paths, invoke Graphics.drawShadedFilledPath():
public void drawShadedFilledPath(int[] xPts, int[] yPts, byte[] pointTypes, int[] colors,
int[] offsets);
Parameter
Description
xPts
This ordered list defines x values for each vertex in the paths.
yPts
This ordered list defines y values for each vertex in the paths.
pointTypes Specify one of the following constants for each (x,y) point defined. If pointTypes is null, all points default to
Graphics.CURVEDPATH_END_POINT.
•
•
•
74
Graphics.CURVEDPATH_END_POINT
Graphics.CURVEDPATH_QUADRATIC_BEZIER_CONTROL_POINT
Graphics.CURVEDPATH_CUBIC_BEZIER_CONTROL_POINT
3: Creating user interfaces
Parameter
Description
colors
This ordered list defines color values for each vertex, in 0x00RRGGBB format. If null, a solid filled path is drawn in the current
foreground color.
offsets
This list defines the start of each path in the xPts and yPts data arrays. null indicates a single path, a path that begins at
point (xPts[offsets[i]],yPts[offsets[i]]) and ends at point (xPts[offsets[i+1]]1,yPts[offsets[i+1]]-1).
The following example draws a path that blends from blue to red.
Bitmap surface = new Bitmap(240, 160);
BitmapField surfaceField = new BitmapField(surface);
add(surfaceField);
Graphics graphics = new Graphics(surface);
int[] X_PTS = { 0, 0, 240, 240 };
int[] Y_PTS = { 20, 50, 50, 20 };
int[] drawColors = { 0x0000CC, 0x0000CC, 0xCC0000, 0xCC0000 };
try {
graphics.drawShadedFilledPath(X_PTS, Y_PTS, null, drawColors, null);
} catch (IllegalArgumentException iae) {
System.out.println("Bad arguments.");
}
Use drawing styles
To turn a drawing style on or off, invoke Graphics.setDrawingStyle(int drawStyle, boolean on), where
on specifies whether to turn the style on (true) or off (false). To determine if a drawing style is set, invoke
Graphics.isDrawingStyleSet(int drawStyle).
Constant
Description
DRAWSTYLE_AALINES
style for anti-aliased rendering of lines; used by setDrawingStyle() and isDrawingStyleSet()
DRAWSTYLE_AAPOLYGO style for anti-aliased rendering of polygons; used by setDrawingStyle() and isDrawingStyleSet()
NS
DRAWSTYLE_FOCUS
style set by the framework when painting is being done for focus drawing
DRAWSTYLE_SELECT
style set by the framework when painting is being done for selection drawing
Use monochrome bitmap fields like a stamp
The STAMP_MONOCHROME option enables applications to use monochrome bitmaps like a stamp by rendering the
nontransparent region in color. This option applies to bitmaps that are 1 bit and have alpha defined.
BitmapField field = new BitmapField(original, BitmapField.STAMP_MONOCHROME);
Draw an image from raw data
1. Create an empty bitmap. In this example, the type and size are copied from an existing bitmap.
2. Create a Graphics object using the newly created bitmap as the drawing surface.
3. Invoke Graphics.rawRGB() to draw a new image using raw data retrieved from the original.
Bitmap restored = new Bitmap(original.getType(), original.getWidth(),
original.getHeight());
Graphics graphics = new Graphics(restored);
try {
75
BlackBerry Application Developer Guide Volume 1: Fundamentals
graphics.drawRGB(argb, 0, restored.getWidth(), 0, 0, restored.getWidth(),
restored.getHeight());
} catch(Exception e) {
System.out.println("Error occurred during drawing: " + e);
}
Use bitmap types
Note: The following details on bitmap types are provided for information only. Applications should not rely on the actual bit format
of bitmaps as formats are subject to change in future releases of the handheld software.
To determine the Bitmap type, invoke Bitmap.getType(). This method returns one of the following constants:
Bitmap Type
Description
COLUMNWISE_MONOCHROME
Data is stored in columns, with 1 bit for each pixel: 0 is white and 1 is black. Uppermost pixels are in the less
significant bits in a byte, and lower numbered bytes contain the uppermost pixels within a column.
ROWWISE_MONOCHROME
Data is stored in rows, with 1 bit for each pixel: 0 is black and 1 is white. Each row is a multiple of 4 bytes in
width. Leftmost pixels are in the less significant bits in a byte, and lower numbered bytes contain the leftmost
pixels within a row.
ROWWISE_16BIT_COLOR
Data is stored in rows, with 2 bytes for each pixel: 0 is black and a 0xffff (65535) is white. Each row is a
multiple of 4 bytes in width.
• On BlackBerry devices with monochrome screens, data is ordered in columns, so Bitmap.getType() returns
COLUMNWISE_MONOCHROME. The first 2 bytes represent the first 16 pixels in the first column of the bitmap.
• On BlackBerry devices with color screens, data is ordered in rows, so Bitmap.getType() returns
ROWWISE_MONOCHROME for monochrome images or ROWWISE_16BIT_COLOR for color images. In a
monochrome image, the first 2 bytes represent the first 16 pixels in the first row of the bitmap, going from left
to right. In a color image, the first 2 bytes represent the first pixel.
The following two forms of the Bitmap constructor enable you to specify a type parameter:
•
Bitmap(int type, int width, int height)
•
Bitmap(int type, int width, int height, byte[] data)
To retrieve the default bitmap type for the BlackBerry device, invoke the static method
Bitmap.getDefaultType().
Code example
The DrawDemo.java sample retrieves raw data from a predefined bitmap image, and then draws a new bitmap
using the data. It then displays the original and restored images.
Example: DrawDemo.java
/*
* DrawDemo.java
* Copyright (C) 2002-2005 Research In Motion Limited.
*/
package com.rim.samples.docs.drawing;
76
3: Creating user interfaces
import
import
import
import
net.rim.device.api.system.*;
net.rim.device.api.ui.*;
net.rim.device.api.ui.component.*;
net.rim.device.api.ui.container.*;
/* The DrawDemo.java sample retrieves raw data from a predefined bitmap
image, and then draws a new bitmap using the data. It then displays
the original and restored images. */
public class DrawDemo extends UiApplication {
public static void main(String[] args) {
DrawDemo app = new DrawDemo();
app.enterEventDispatcher();
}
public DrawDemo() {
pushScreen(new DrawDemoScreen());
}
}
final class DrawDemoScreen extends MainScreen {
public DrawDemoScreen() {
super();
LabelField title = new LabelField(“UI Demo”, LabelField.USE_ALL_WIDTH);
setTitle(title);
Bitmap original = Bitmap.getPredefinedBitmap(Bitmap.INFORMATION);
Bitmap restored = new Bitmap(original.getType(), original.getWidth(),
original.getHeight());
Graphics graphics = new Graphics(restored);
// Retrieve raw data from original image.
int[] argb = new int[original.getWidth() * original.getHeight()];
original.getARGB(argb, 0, original.getWidth(), 0, 0, original.getWidth(),
original.getHeight());
// Draw new image using raw data retrieved from original image.
try {
graphics.drawRGB(argb, 0, restored.getWidth(), 0, 0, restored.getWidth(),
restored.getHeight());
} catch(Exception e) {
System.out.println(“Error occurred during drawing: “ + e);
}
if(restored.equals(original)) {
System.out.println(“Success! Bitmap renders correctly with RGB data.”);
} else if(!restored.equals(original)) {
System.out.println(“Bitmap rendered incorrectly with RGB data.”);
}
BitmapField field1 = new BitmapField(original, BitmapField.STAMP_MONOCHROME);
BitmapField field2 = new BitmapField(restored);
add(new LabelField(“Original bitmap: “));
add(field1);
add(new LabelField(“Restored bitmap: “));
77
BlackBerry Application Developer Guide Volume 1: Fundamentals
add(field2);
}
}
Listening for changes to user interface objects
User interface EventListeners enable applications to respond to a change to a user interface object. There are
three types of user interface event listeners:
Listener
Description
FieldChangeListener
notifies when a field property changes
FocusChangeListener
notifies when a field gains or loses focus
ScrollChangeListener
notifies when the horizontal or vertical scrolling value of a manager changes
Listen for field property changes
To monitor changes to fields, implement the FieldChangeListener interface. Assign your implementation to a
field by invoking setChangeListener().
private class FieldListener implements FieldChangeListener {
public void fieldChanged(Field field, int context) {
if (context != FieldChangeListener.PROGRAMMATIC) {
// Perform action if user changed field.
} else {
// Perform action if application changed field.
}
}
}
// ...
FieldListener myFieldChangeListener = new FieldListener()
myField.setChangeListener(myFieldChangeListener);
Listen for focus changes
To monitor changes in focus between fields, assign them a FocusChangeListener. Implement
FocusChangeListener, and then assign your implementation to a Field by invoking setChangeListener(). A
FocusChangeListener considers the gain, loss, or change of focus in relation to a particular field.
Your implementation of FocusChangeListener should specify what action to take when the field gains, loses, or
changes the focus by implementing focusChanged().
private class FocusListener implements FocusChangeListener {
public void focusChanged(Field field, int eventType) {
if (eventType == FOCUS_GAINED) {
// Perform action when this field gains the focus.
}
if (eventType == FOCUS_CHANGED) {
// Perform action when the focus changes for this field.
}
78
3: Creating user interfaces
if (eventType == FOCUS_LOST) {
// Perform action when this field loses focus.
}
}
}
FocusListener myFocusChangeListener = new FocusListener();
myField.setChangeListener(myFocusChangeListener);
Listen for scroll events
Your implementation of the ScrollChangeListener interface enables your field manager to manage scroll
events. Invoke setScrollListener() to assign your implementation to a Manager. When the horizontal or
vertical (or both) scrolling values change, the scrollChanged() method passes in the new values.
Note: Typically, listening for scrolling changes is unnecessary because your application can listen for focus changes to fields; however,
ScrollChangeListener can be useful in a game implementation.
To assign a listener to a field, invoke setScrollListener() on the field manager.
private class ScrollListener implements ScrollChangeListener {
scrollChanged(Manager manager, int newHoriztonalScroll, int newVerticalScroll){
// Perform action.
}
}
ScrollListener myScrollChangeListener = new ScrollListener();
myManager.setScrollListener(myScrollChangeListener);
79
4
Using audio
Playing a tune from a supported audio format
Voicenotes API
Playing a tune from a supported audio format
On BlackBerry devices that support standard audio formats, you can play back an audio file in one of the following
supported formats:
• audio/MPEG-1 Layer 3
• audio/midi
• audio/x-midi
• audio/mid
BlackBerry devices use the Mobile Media API (javax.microedition.media) package to support standard audio
formats.
To determine the supported audio formats at runtime, invoke Manager.getSupportedContentTypes().
See the javax.microedition.media package in the API Reference for information.
Voicenotes API
The Voicenotes API consists of the following three methods in the net.rim.device.api.system package:
•
Audio.playFile(int audioCodec, int fs, String fileName)
•
Audio.recordFile(int audioCodec, int fs, String fileName)
•
Audio.stopFile(int audioCodec, int fs, String fileName)
Each method accepts a codec, a file system, and a file name. The Voicenotes codec is represented by
Audio.AUDIO_CODEC_VOICENOTE. The iDEN™ file system is represented by
net.rim.device.api.io.FILESYSTEM_PATRIOT. This file system is flat; therefore, the file name parameter
consists of a file name with no path.
Applications should register an audio listener to receive notification when the record, play, or stop operation fails
or completes. To register an audio listener, implement net.rim.device.api.system.AudioFileListener.
Register your implementation by invoking Audio.addListener(Application, AudioListener).
Note: The size of the file system, which is currently approximately 250 kB, limits the duration of the recording. This amounts to
approximately 8 minutes 9 seconds of voicenote recording. If a recording exceeds the file system size, the recording stops and the file
is saved.
See the net.rim.device.api.system audio class in the API Reference for more information.
5
Supporting media content
PME content
Playing media content
Listening for media engine events
Creating custom connections
PME content
BlackBerry devices support rich media content in PME format.
Content developers can create PME content using Plazmic Content Developer’s Kit for BlackBerry®. This tool, and
accompanying documentation, is available from the Plazmic web site at www.plazmic.com.
The Media Engine APIs (in the net.rim.plazmic.mediaengine and net.rim.plazmic.mediaengine.io
packages) enable applications to retrieve and play PME content that is stored on the BlackBerry device or on the
network.
Note: The Media Engine APIs support the media type application/x-vnd.rim.pme. Web servers must set the MIME type for
.pme files to application/x-vnd.rim.pme.
Overview of PME APIs
The following three main classes (in the net.rim.plazmic.mediaengine package) provide the ability to load
and play PME media content:
Class
Description
MediaManager
provides methods for loading content from local storage or the network
MediaPlayer
provides methods for playing PME media
MediaException
provides exception codes for errors specific to retrieving or playing media
Media loading
The Media Engine API enables applications to load media content using one of the following four protocols:.
Protocol
Description
http://
The http protocol downloads content from a web server on the network using an HTTP connection. This
protocol requires a BlackBerry Enterprise Server™ with BlackBerry® MDS services enabled.
https://
The https protocol downloads content from a web server on the network using a secure HTTP (HTTPS)
connection. This protocol requires a BlackBerry Enterprise Server with MDS services enabled.
BlackBerry Application Developer Guide Volume 1: Fundamentals
Protocol
Description
jar:///<pme_file>
The jar protocol loads content from a .jar file that is stored locally on the BlackBerry device.
jar:///sample.pme
Note that the leading slash is required.
In the BlackBerry Integrated Development Environment (BlackBerry IDE), the .jar file must be added to the
same project as the calling application or to a library project on which the application depends.
cod://
<module><pme_file>
The cod protocol loads content from a .cod file (module) that is stored locally on the BlackBerry device.
cod://mediasample/sample.pme
To use another protocol, implement a custom Connector. See "Creating custom connections" on page 91 for
more information.
Playback states
To retrieve the current state of the MediaPlayer, invoke MediaPlayer.getState().
State
Description
UNREALIZED
The MediaPlayer is not ready to play media. To move to the REALIZED state, invoke
MediaPlayer.setMedia().
REALIZED
The MediaPlayer is ready to play media. To start playback and move to the STARTED state, invoke
MediaPlayer.start().
STARTED
The MediaPlayer is playing media. To stop playback and return to the REALIZED state, invoke
MediaPlayer.stop().
Exceptions
Methods on MediaEngine and MediaManager classes throw a MediaException that includes a standard HTTP
response code or one of the following exception codes. To retrieve the error code associated with an exception,
invoke MediaException.getCode().
Exception code
Description
INVALID_HEADER
The media format is invalid.
REQUEST_TIMED_OUT
The request has timed out.
INTERRUPTED_DOWNLOAD
The download was cancelled by the application invoking MediaManager.cancel().
UNSUPPORTED_TYPE
The media format (MIME type) is unsupported.
UPGRADE_PLAYER
The current version of the media engine is not compatible with the requested content.
UPGRADE_MEDIA
The current version of the media engine no longer supports the requested content.
CHECKSUM_MISMATCH
The checksum verification failed, so the media cannot be read.
OUT_OF_BOUNDS
An array index is out of bounds, or the application tried to read from an input stream after the end of the file.
Events
The MediaListener interface enables applications to receive and respond to the following events:
Event
Description
MEDIA_REQUESTED
Media has been requested for loading; occurs when an animation automatically requests new content or
when the user clicks a hyperlink for media content.
82
5: Supporting media content
Event
Description
MEDIA_REALIZED
Media has been created for playback; occurs when MediaManager.createMediaLater() is invoked.
MEDIA_COMPLETE
Media has been loaded and played successfully.
MEDIA_IO
Media is being loaded.
See "Listening for media engine events" on page 85 for more information.
Playing media content
To retrieve PME content on BlackBerry devices or networks, use methods on the MediaManager. To play PME
content that has been downloaded to BlackBerry devices, use methods on the MediaPlayer class.
Download content
To download PME content, create a MediaManager object, and then invoke MediaManager.createMedia().
MediaManager manager = new MediaManager();
try {
Object media = manager.createMedia("http://webserver/sample.pme");
} catch (IOException ioe) {
System.out.println("Error: requested content was not downloaded.");
} catch (MediaException me) {
System.out.println("Error: “ + me.getCode());
}
Note: The following default protocols are supported: http://, https://, jar://, and cod://. See "Media loading" on page 81 for
more information.
The first time that you invoke MediaManager.createMedia(), the URL must be absolute, unless you first invoke
MediaManager.setProperty(“URI_BASE”, <base_url>) to set a base URL. When you invoke createMedia()
subsequently, the previous URL is used as the base.
Play PME content
Set the PME object for playback
Invoke MediaPlayer.setMedia().
MediaPlayer player = new MediaPlayer();
try {
player.setMedia(media);
} catch (MediaException me) {
System.out.println("Error: requested content type is not supported.”);
}
Retrieve a UI object that displays PME content
Invoke MediaPlayer.getUI(). Cast the object that getUI() returns as a Field and add it to a Screen for
display.
add((Field)player.getUI());
83
BlackBerry Application Developer Guide Volume 1: Fundamentals
Start playing the downloaded PME content
Invoke MediaPlayer.start().
if(player.getState() == MediaPlayer.REALIZED) {
try {
player.start();
} catch(MediaException me) {
System.out.println("Error occurred during media playback: " +
me.getCode() + me.getMessage());
}
}
Note: Check the current state of the MediaPlayer before you invoke MediaPlayer.start(). The start() method throws an
exception if the media player is not in the REALIZED state.
Code example
The MediaSample.java sample retrieves a PME file from a web server and displays it.
Example: MediaSample.java
/**
* MediaSample.java
* Copyright (C) 2001-2005 Research In Motion Limited. All rights reserved.
*/
package com.rim.samples.docs.mediasample;
import
import
import
import
import
java.io.*;
net.rim.device.api.ui.*;
net.rim.device.api.ui.component.*;
net.rim.device.api.ui.container.*;
net.rim.device.api.system.*;
import net.rim.plazmic.mediaengine.*;
public class MediaSample extends UiApplication {
public static void main(String[] args) {
MediaSample app = new MediaSample();
app.enterEventDispatcher();
}
public MediaSample() {
pushScreen(new MediaSampleScreen());
}
final static class MediaSampleScreen extends MainScreen {
public MediaSampleScreen() {
super();
LabelField title = new LabelField(“Media Sample”, LabelField.ELLIPSIS
| LabelField.USE_ALL_WIDTH);
setTitle(title);
MediaPlayer player = new MediaPlayer();
MediaManager manager = new MediaManager();
84
5: Supporting media content
try {
Object media = manager.createMedia(“http://webserver/SVGFILE.pme”);
player.setMedia(media);
} catch (IOException ioe) {
} catch (MediaException me) {
System.out.println(“Error during media loading: “);
System.out.println(me.getCode());
System.out.println(me.getMessage());
}
add((Field)player.getUI());
try {
player.start();
} catch(MediaException me) {
System.out.println(“Error occured during media playback: “);
System.out.println(me.getCode());
System.out.println(me.getMessage());
}
}
}
}
Listening for media engine events
The MediaListener interface enables applications to register to receive media engine events. Applications can
register listeners on both MediaPlayer and MediaEngine objects.
When an application implements the listener, it can perform the following actions:
• provide information on the status of content downloads
• download content in the background and play it when it arrives
• download content that is requested automatically by an animation
The MediaListener interface includes one method, the listen method.
public void mediaEvent(Object sender, int event, int eventParam, Object data);
Parameter
Description
sender
This parameter refers to the object that sent the event, such as a MediaPlayer or MediaManager object.
event
This parameter is one of the following events:
•
•
•
•
eventParam
MEDIA_REQUESTED: Sent when new content is requested.
MEDIA_COMPLETE: Sent when all scheduled media actions have been completed.
MEDIA_REALIZED: Sent by a MediaManager to return downloaded media.
MEDIA_IO: Sent by the MediaLoader to provide information on download progress or status.
Do not use this parameter as it might receive an arbitrary value. It exists in order to provide a consistent interface for
additional events.
85
BlackBerry Application Developer Guide Volume 1: Fundamentals
Parameter
Description
data
When the data parameter is MEDIA_REQUESTED, data refers to the requested URL as a String object.
When the data parameter is MEDIA_REALIZED, data refers to the media object that was created.
When the data parameter is MEDIA_IO, data refers to a net.rim.plazmic.mediaengine.io.LoadingStatus
object.
Listen for media engine events
Your implementation of the MediaListener interface enables your application to listen for media engine events.
Your implementation of mediaEvent() should handle all possible media events. The following example uses a
switch statement to handle possible media events.
public final class MediaListenerImpl implements MediaListener {
public void mediaEvent(Object sender, int event, int eventParam, Object data) {
switch(event) {
case MEDIA_REQUESTED:
// Perform action.
break;
case MEDIA_COMPLETE:
// Perform action.
break;
case MEDIA_REALIZED:
// Perform action.
break;
case MEDIA_IO:
// Perform action.
break;
}
}
}
Register the listener
To register your listener, invoke addMediaListener() on the MediaPlayer and MediaManager objects.
private MediaListenerImpl _listener = new MediaListenerImpl();
private MediaPlayer player = new MediaPlayer();
private MediaManager manager = new MediaManager();
player.addMediaListener(_listener);
manager.addMediaListener(_listener);
Load content in the background
When you implement MediaListener, you can download PME content in the background (asynchronously), and
then play the content when the download is complete.
Invoke MediaManager.createMediaLater() to download content for future playback.
Note: Unlike createMedia(), createMediaLater() does not return an Object with the media content.
86
5: Supporting media content
In MediaListener.mediaEvent(), add code to handle the MEDIA_REALIZED event that occurs when the
requested content has been loaded successfully. To register the content that is specified in the data parameter,
invoke MediaPlayer.setMedia(data). To start playback, invoke MediaPlayer.start().
manager.createMediaLater("http://webserver/sample.pme");
public void mediaEvent(Object sender, int event, int eventParam, Object data) {
switch(event) {
...
case MEDIA_REALIZED:
try {
player.setMedia(data);
player.start();
} catch(MediaException me) {
System.out.println("Error playing media” + me.getCode() +
me.getMessage());
}
break;
}
}
Track download progress
To obtain information about download progress, use the net.rim.plazmic.mediaengine.io.LoadingStatus
class. This class includes methods that enable you to retrieve the media content type, the total number of bytes,
the number of bytes read, and the source URL of the content.
Status
Description
LOADING_STARTED
Loading has started.
LOADING_READING
The data stream is being parsed.
LOADING_FINISHED
The media has been loaded successfully.
LOADING_FAILED
The media has not been loaded successfully.
• To obtain detailed error codes, invoke getCode(). See "Exceptions" on page 82 for more information.
• To obtain the exception message, invoke getMessage().
In your implementation of mediaEvent(), when the MEDIA_IO event occurs, cast the Object in the data
parameter to a LoadingStatus object.
Invoke LoadingStatus.getStatus() to retrieve the download status, and then handle each status.
For each normal status, print a message to the console.
For the LOADING_FAILED status, perform the following actions:
• Invoke LoadingStatus.getCode() to retrieve the error code.
• Invoke LoadingStatus.getMessage() to retrieve the detailed message.
• Invoke LoadingStatus.getSource() to retrieve the URL string of the content.
public void mediaEvent(Object sender, int event, int eventParam, Object data) {
switch(event) {
...
case MEDIA_IO: {
87
BlackBerry Application Developer Guide Volume 1: Fundamentals
LoadingStatus s = (LoadingStatus)data;
}
...
break;
}
break;
...
switch(s.getStatus()) {
case LoadingStatus.LOADING_STARTED:
System.out.println("Loading in progress");
break;
case LoadingStatus.LOADING_READING:
System.out.println("Parsing in progress");
break;
case LoadingStatus.LOADING_FINISHED:
System.out.println("Loading completed");
break;
case LoadingStatus.LOADING_FAILED:
String errorName = null;
int code = s.getCode();
switch (code) {
case MediaException.INVALID_HEADER:
errorName = "Invalid header" + "\n" + s.getSource();
break;
case MediaException.REQUEST_TIMED_OUT:
errorName = "Request timed out" + "\n" +
s.getSource();
break;
case MediaException.INTERRUPTED_DOWNLOAD:
break;
case MediaException.UNSUPPORTED_TYPE:
errorName = "Unsupported type" + s.getMessage() + "\n" + s.getSource();
break;
default: {
if (code > 200) {
// A code > 200 indicates an HTTP error
errorName = "URL not found";
} else {
// default unidentified error
errorName = "Loading Failed";
}
errorName += "\n" + s.getSource() + "\n" + s.getCode()
+ ": " + s.getMessage();
break;
}
}
System.out.println(errorName);
break;
} // End switch s.getStatus().
break;
}
Code example
The MediaSample2.java sample implements a listener to download media content in the background and display
the download status to the console.
88
5: Supporting media content
Example: MediaSample2.java
/**
* MediaSample2.java
* Copyright (C) 2001-2005 Research In Motion Limited. All rights reserved.
*/
package com.rim.samples.docs.mediasample;
import
import
import
import
import
java.io.*;
net.rim.device.api.ui.*;
net.rim.device.api.ui.component.*;
net.rim.device.api.ui.container.*;
net.rim.device.api.system.*;
import net.rim.plazmic.mediaengine.*;
import net.rim.plazmic.mediaengine.io.*;
public class MediaSample2 extends UiApplication {
private MediaPlayer player = new MediaPlayer();
private MediaManager manager = new MediaManager();
private MediaListenerImpl _listener = new MediaListenerImpl();
private MediaSample2Screen _screen;
public static void main(String[] args) {
MediaSample2 app = new MediaSample2();
app.enterEventDispatcher();
}
public MediaSample2() {
_screen = new MediaSample2Screen();
pushScreen(_screen);
}
public final class MediaListenerImpl implements MediaListener {
public void mediaEvent(Object sender, int event, int eventParam, Object data) {
switch(event) {
case MEDIA_REQUESTED:
System.out.println(“Media requested”);
break;
case MEDIA_COMPLETE:
System.out.println(“Media completed”);
break;
case MEDIA_REALIZED:
try {
player.setMedia(data);
player.start();
}
catch(MediaException me) {
System.out.println(“Error during media loading: “ + me.getCode() +
me.getMessage());
}
break;
case MEDIA_IO: {
LoadingStatus s = (LoadingStatus)data;
switch(s.getStatus()) {
89
BlackBerry Application Developer Guide Volume 1: Fundamentals
case LoadingStatus.LOADING_STARTED:
System.out.println(“Loading in progress”);
break;
case LoadingStatus.LOADING_READING:
System.out.println(“Parsing in progress”);
break;
case LoadingStatus.LOADING_FINISHED:
System.out.println(“Loading completed”);
break;
case LoadingStatus.LOADING_FAILED:
String errorName = null;
int code = s.getCode();
switch (code) {
case MediaException.INVALID_HEADER:
errorName = “Invalid header” + “\n” +
break;
case MediaException.REQUEST_TIMED_OUT:
errorName = “Request timed out” + “\n” +
break;
s.getSource();
s.getSource();
case MediaException.INTERRUPTED_DOWNLOAD:
break;
case MediaException.UNSUPPORTED_TYPE:
errorName = “Unsupported type” + s.getMessage() + “\n”
+ s.getSource();
break;
default: {
if (code > 200) {
// A code > 200 indicates an HTTP error.
errorName = “URL not found”;
}
else {
// Default unidentified error.
errorName = “Loading Failed”;
}
errorName += “\n” + s.getSource() + “\n”
+ s.getCode() + “: “ + s.getMessage();
break;
}
}
System.out.println(errorName);
break;
} // End switch s.getStatus().
break;
}
}
}
}
final class MediaSample2Screen extends MainScreen {
public MediaSample2Screen() {
super();
LabelField title = new LabelField(“Media Sample”, LabelField.ELLIPSIS
| LabelField.USE_ALL_WIDTH);
setTitle(title);
90
5: Supporting media content
player.addMediaListener(_listener);
manager.addMediaListener(_listener);
// Change this to the location of a test .pme file.
manager.createMediaLater(“http://test.rim.com/SVGBS0001.pme”);
add((Field)player.getUI());
}
}
}
Creating custom connections
MediaManager uses a Connector object to load media and open an input stream. The default Connector
supports the following protocols: http://, https://, jar://, and cod://. To add support for a custom protocol or
to override default behavior, create a custom Connector by implementing the
net.rim.plazmic.mediaengine.io.Connector interface.
Method signature
Implementation
InputStream getInputStream(String,
ConnectionInfo)
Implement this method to return an input stream to read content from the specific
URI.
void releaseConnection(ConnectionInfo)
Implement this method to release the connection. MediaManager invokes this
method to inform a Connector that it can release the connection.
void setProperty(String, String)
Implement this method to set connector-specific properties.
Implement a custom connector
To perform processing for a custom protocol, implement the Connector interface, including getInputStream().
To handle a standard protocol, invoke the default Connector.
Your implementation of setProperty(String name, String value) sets specific properties. In this example,
the connector does not have to set any specific properties, so the implementation of setProperty() invokes
setProperty() on the default Connector.
public class SampleConnector implements Connector {
Connector delegate; // The default Connector.
SampleConnector(Connector delegate) {
this.delegate = delegate;
}
public InputStream getInputStream(String uri, ConnectionInfo info)
throws IOException, MediaException {
InputStream input = null;
if (uri.startsWith("myprotocol://")) {
// Perform special tasks.
info.setConnection(new MyProtocolConnection());
info.setContentType("application/x-vnd.rim.pme");
// openMyInputStream() is a custom method that opens
//stream for "myprotocol://".
input = openMyInputStream(uri);
91
BlackBerry Application Developer Guide Volume 1: Fundamentals
} else {
input = delegate.getInputStream(uri, info);
}
return input;
}
public void releaseConnection(ConnectionInfo info)
throws IOException, MediaException {
Object o = info.getConnection();
if (o instanceof MyProtocolConnection) {
((MyProtocolConnection)o).close(); // Perform cleanup.
} else {
delegate.releaseConnection(info);
}
}
public void setProperty(String property, String value) {
delegate.setProperty(property, value);
}
}
Register a custom connector
In your main method, invoke MediaManager.setConnector() to register your custom connector.
MediaManager manager = new MediaManager();
manager.setConnector(new CustomPMEConnector(manager.getDefaultConnector()));
Code example
The CustomPMEConnector.java sample provides a framework for implementing a custom connector.
Example: CustomPMEConnector.java
/*
* CustomPMEConnector.java
* Copyright (C) 2003-2005 Research In Motion Limited. All rights reserved.
*/
package com.rim.samples.docs.mediasample;
import java.io.*;
import net.rim.plazmic.mediaengine.*;
import net.rim.plazmic.mediaengine.io.*;
public class CustomPMEConnector implements Connector {
private Connector delegate;
private InputStream input;
CustomPMEConnector(Connector delegate) {
this.delegate = delegate;
}
public InputStream getInputStream(String uri, ConnectionInfo info)
throws IOException, MediaException {
if (uri.startsWith(“myprotocol://”)) {
92
5: Supporting media content
// Perform special tasks.
info.setConnection(new MyProtocolConnection());
info.setContentType(“application/x-vnd.rim.pme”);
// OpenMyInputStream() is a custom method that opens
//stream for “myprotocol://”
input = openMyInputStream(uri);
} else {
input = delegate.getInputStream(uri, info);
}
return input;
}
private InputStream openMyInputStream(String uri) {
InputStream input = null;
// @todo: open stream here
return input;
}
public void releaseConnection(ConnectionInfo info)
throws IOException, MediaException {
Object o = info.getConnection();
if (o instanceof MyProtocolConnection) {
((MyProtocolConnection)o).close(); // Perform cleanup.
} else {
delegate.releaseConnection(info);
}
}
public void setProperty(String property, String value) {
delegate.setProperty(property, value);
}
// Inner class that defines the connection class.
public static class MyProtocolConnection {
public MyProtocolConnection() {
// ...
}
public void close() {
// ...
}
}
}
93
BlackBerry Application Developer Guide Volume 1: Fundamentals
94
6
Connecting to networks
HTTP and socket connections
Using HTTP connections
Using HTTPS connections
Using socket connections
Using port connections
Using Bluetooth serial port connections
HTTP and socket connections
Although you can implement HTTP over a socket connection, it is preferable to use an HTTP connection because
socket connections do not support BlackBerry® MDS services features, such as push. It is also preferable to use
HTTP connections because applications that use socket connections typically require significantly more bandwidth
than those that use HTTP connections.
Note: If you use socket connections, design the application to accommodate intermittent connections to the wireless network. For
example, the application should re-open the connection if an error occurs.
Using HTTP connections
Note: With the BlackBerry Internet Service™ Browser Java applications cannot initiate HTTP, HTTPS, or TCP connections.
Open an HTTP connection
To open an HTTP connection, invoke Connector.open(), specifying http as the protocol. Cast the returned
object as an HTTPConnection or a StreamConnection object. An HttpConnection is a StreamConnection
that provides access to specific HTTP functionality, including headers and other HTTP resources.
HttpConnection conn = null;
String URL = "http://www.myServer.com/myContent";
conn = (HttpConnection)Connector.open(URL);
Set the HTTP request method
To set the HTTP request method (GET or POST), invoke HttpConnection.setRequestMethod().
conn.setRequestMethod(HttpConnection.POST);
BlackBerry Application Developer Guide Volume 1: Fundamentals
Set or retrieve header fields
To set or retrieve header fields for HTTP request or HTTP response messages, invoke getRequestProperty() or
setRequestProperty() on the HttpConnection.
conn.setRequestProperty("User-Agent", "BlackBerry/3.2.1");
String lang = conn.getRequestProperty("Content-Language");
Send and receive data over HTTP
To send and receive data, acquire input and output streams by invoking openInputStream() and
openOutputStream() on the HTTPConnection.
InputStream in = conn.openInputStream();
OutputStream out = conn.openOutputStream();
Code example
The HttpFetch.java example uses an HTTP connection to retrieve data. It performs the following steps:
1. Creates a connection thread.
2. Defines a method to retrieve data.
3. Defines a method to display data to the user.
4. Defines a method to exit the application.
5. Defines the application constructor.
Note: The HTTPFetch.java example requires you to create resource files in the application project and define the required resource
keys. See "Localizing applications" on page 125 for more information.
Example: HTTPFetch.java
/**
* HTTPFetch.java
* Copyright (C) 2001-2005 Research In Motion Limited. All rights reserved.
*/
package com.rim.samples.docs.httpfetch;
import
import
import
import
import
import
import
import
import
net.rim.device.api.ui.*;
net.rim.device.api.ui.component.*;
net.rim.device.api.ui.container.*;
net.rim.device.api.i18n.*;
net.rim.device.api.system.*;
javax.microedition.io.*;
java.io.*;
com.rim.samples.docs.baseapp.*;
com.rim.samples.docs.resource.*;
public class HTTPFetch extends BaseApp implements HTTPFetchResource {
// Constants.
private static final String SAMPLE_PAGE = “http://localhost/testpage/sample.txt”;
private static final String[] HTTP_PROTOCOL = {“http://”, “http:\\”};
96
6: Connecting to networks
// Members.
private MainScreen _mainScreen;
private RichTextField _content;
/**
* Send and receive data over the network on a
* separate thread from the main thread of your application.
*/
ConnectionThread _connectionThread = new ConnectionThread();
//statics
private static ResourceBundle _resources = ResourceBundle.getBundle(
HTTPFetchResource.BUNDLE_ID, HTTPFetchResource.BUNDLE_NAME);
public static void main(String[] args) {
HTTPFetch theApp = new HTTPFetch();
theApp.enterEventDispatcher();
}
/**
* The ConnectionThread class manages the HTTP connection.
* Fetch operations are not queued, but if a second fetch request
* is made while a previous request is still active,
* the second request stalls until the previous request completes.
*/
private class ConnectionThread extends Thread {
private static final int TIMEOUT = 500; //ms
private String _theUrl;
/* The volatile keyword indicates that because the data is shared,
* the value of each variable must always be read and written from memory,
* instead of cached by the VM. This technique is equivalent to wrapping
* the shared data in a synchronized block, but produces less overhead.
*/
private volatile boolean _start = false;
private volatile boolean _stop = false;
/**
* Retrieve the URL. The synchronized keyword makes sure that only one
* thread at a time can call this method on a ConnectionThread object.
*/
public synchronized String getUrl() {
return _theUrl;
}
/**
* Fetch a page. This method is invoked on the connection thread by
* fetchPage(), which is invoked in the application constructor when
* the user selects the Fetch menu item.
*/
public void fetch(String url) {
_start = true;
_theUrl = url;
}
/**
* Close the thread. Invoked when the application exits.
97
BlackBerry Application Developer Guide Volume 1: Fundamentals
*/
public void stop() {
_stop = true;
}
/**
* Open an input stream and extract data. Invoked when the thread
* is started.
*/
public void run() {
for(;;) {
// Thread control.
while( !_start && !_stop) {
// No connections are open for fetch requests,
// but the thread has not been stopped.
try {
sleep(TIMEOUT);
} catch (InterruptedException e) {
System.err.println(e.toString());
}
}
// Exit condition.
if ( _stop ) {
return;
}
/* Ensure that fetch requests are not missed
* while received data is processed.
*/
synchronized(this) {
// Open the connection and extract the data.
StreamConnection s = null;
try {
s = (StreamConnection)Connector.open(getUrl());
InputStream input = s.openInputStream();
// Extract data in 256 byte chunks.
byte[] data = new byte[256];
int len = 0;
StringBuffer raw = new StringBuffer();
while ( -1 != (len = input.read(data)) ) {
raw.append(new String(data, 0, len));
}
String text = raw.toString();
updateContent(text);
input.close();
s.close();
} catch (IOException e) {
System.err.println(e.toString());
// Display the text on the screen.
updateContent(e.toString());
}
// Reset the start state.
_start = false;
}
}
}
}
98
6: Connecting to networks
// Constructor.
public HTTPFetch() {
_mainScreen = new MainScreen();
_mainScreen.setTitle(new LabelField(
_resources.getString(APPLICATION_TITLE), LabelField.ELLIPSIS
| LabelField.USE_ALL_WIDTH));
_mainScreen.add(new SeparatorField());
_content = new RichTextField(
_resources.getString(HTTPDEMO_CONTENT_DEFAULT));
_mainScreen.add(_content);
_mainScreen.addKeyListener(this);
_mainScreen.addTrackwheelListener(this);
// Start the helper thread.
_connectionThread.start();
pushScreen(_mainScreen);
fetchPage(SAMPLE_PAGE);
}
// Retrieve web content.
private void fetchPage(String url) {
// Perform basic validation (set characters to lowercase and add http:// or https:/
/).
String lcase = url.toLowerCase();
boolean validHeader = false;
int i = 0;
for (i = HTTP_PROTOCOL.length - 1; i >= 0; --i) {
if ( -1 != lcase.indexOf(HTTP_PROTOCOL[i]) ) {
validHeader = true;
break;
}
}
if ( !validHeader ) {
// Prepend the protocol specifier if it is missing.
url = HTTP_PROTOCOL[0] + url;
}
// Create a new thread for connection operations.
_connectionThread.fetch(url);
}
// Display the content.
private void updateContent(final String text) {
/* This technique creates several short-lived objects but avoids
* the threading issues involved in creating a static Runnable and
* setting the text.
*/
UiApplication.getUiApplication().invokeLater(new Runnable() {
public void run() {
_content.setText(text);
}
});
}
// Close the connection thread when the user closes the application.
protected void onExit() {
_connectionThread.stop();
}
}
99
BlackBerry Application Developer Guide Volume 1: Fundamentals
Using HTTPS connections
Note: The BlackBerry Internet Service Browser does not permit Java applications to initiate HTTP, HTTPS, or TCP connections.
Open an HTTPS connection
To open an HTTPS connection, invoke Connector.open(), specifying https as the protocol. Cast the returned
object as an HttpsConnection.
HttpsConnection stream = (HttpsConnection)Connector.open("https://host:443/");
Specify proxy or end-to-end mode
By default, the connection uses HTTPS in proxy mode. Users can also set a BlackBerry device option to use end-toend mode by default. See "HTTPS support" on page 189 for more information.
To open an HTTPS connection in end-to-end mode, add one of the following parameters to the connection string
passed to Connector.open():
Parameter
Description
EndToEndRequired
This parameter specifies that an end-to-end HTTPS connection must be used from the BlackBerry device to the
target server. If an end-to-end HTTPS connection cannot be set up, the connection is closed.
EndToEndDesired
This parameter specifies that an end-to-end HTTPS connection should be used from the BlackBerry device to the
target server if the BlackBerry device supports it. If the BlackBerry device does not support end-to-end TLS, and
the user permits proxy TLS connections, then a proxy connection is used.
HttpsConnection stream = (HttpsConnection)Connector.open("https://host:443/
;EndToEndDesired");
Note: The modules for end-to-end HTTPS are not installed on BlackBerry devices by default; however, they are included with the
BlackBerry Desktop Software version 3.6.0 or later. To load the required modules when the application is loaded onto the BlackBerry
device, add the following tags to the .alx file for your application:
<requires id="net.rim.blackberry.crypto1"/>
<requires id="net.rim.blackberry.crypto2"/>
See ".alx files" on page 183 for more information.
100
6: Connecting to networks
Using socket connections
Note: With the BlackBerry Internet Service Browser Java applications cannot initiate HTTP, HTTPS, or TCP connections.
Specify TCP settings
Applications can set up a Transmission Control Protocol (TCP) socket connection or an HTTP connection over TCP,
in one of two modes:
Mode
Description
Proxy mode
The MDS services feature of the BlackBerry Enterprise Server sets up the TCP connection to the web server on behalf of the
BlackBerry device.
Direct mode
The BlackBerry device sets up a direct TCP connection to the web server.
Note: Using direct TCP mode requires that you work closely with service providers. Contact your service provider to verify that direct
TCP socket connections are supported.
To specify TCP settings programmatically, add the optional deviceside parameter to the connection string
passed to Connector.open().
To specify TCP settings in BlackBerry devices on GSM networks, users click TCP on the BlackBerry device options.
Note: TCP only appears under the BlackBerry device options if the IT policy settings permit TCP connections.
If TCP settings are not specified, the following defaults are used.
Network
Default TCP setting
Alternate TCP setting
GSM
proxy mode
direct mode
iDEN
direct mode
proxy mode
See Connector in the API Reference for more information.
Open a socket connection
To open a socket connection, invoke Connector.open(), specifying socket as the protocol.
Note: Applications must input their local machine IP explicitly because localhost is not supported.
private static String URL = "socket://<local machine IP>:4444";
StreamConnection conn = null;
conn = (StreamConnection)Connector.open(URL);
Send and receive data on a socket connection
Acquire input and output streams using openInputStream() and openOutputStream().
101
BlackBerry Application Developer Guide Volume 1: Fundamentals
OutputStreamWriter _out = new OutputStreamWriter(conn.openOutputStream());
String data = "This is a test";
int length = data.length();
_out.write(data, 0, length);
InputStreamReader _in = new InputStreamReader(conn.openInputStream());
char[] input = new char[length];
for ( int i = 0; i < length; ++i ) {
input[i] = (char)_in.read();
}
Close the connection
Invoke close() on the input and output streams and the socket connection.
Note: Each of the close() methods throws an IOException. Applications must implement exception handling.
_in.close();
_out.close();
conn.close();
Using port connections
Note: Check for a NoClassDefFoundError when your application first accesses the net.rim.device.api.system.SerialPort class or the
net.rim.device.api.system.USBPort class. This error is thrown if the system administrator restricts access to the serial and USB ports
using application control. See "Application control" on page 16 for more information.
Using a serial or USB connection, applications can communicate with desktop applications when they are
connected to a computer using a serial or USB port. This type of connection can also be used to communicate with
a peripheral device that plugs into the serial or USB port.
Note: If you are using the port connection to communicate with a desktop application, you must not have any other applications
running that are using the serial or USB port, such as the BlackBerry Desktop Manager.
Open a USB or serial port connection
Invoke Connector.open(), specifying comm as the protocol and COM1 or USB as the port.
private StreamConnection _conn = (StreamConnection)Connector.open(
"comm:COM1;baudrate=9600;bitsperchar=8;parity=none;stopbits=1");
Send data on a port connection
Acquire an output stream by invoking openDataOutputStream() or openOutputStream().
DataOutputStream _dout = _conn.openDataOutputStream();
Use the write methods on the output stream to write data.
private String data = "This is a test";
_dout.writeChars(test);
102
6: Connecting to networks
Receive data on a port connection
Acquire an input stream by invoking openInputStream() or openDataInputStream().
DataInputStream _din = _conn.openInputStream();
Use the read methods on the input stream to read data.
String contents = _din.readUTF();
Note: You cannot read from the input stream on the main event thread, because this operation blocks until data is received. Create a
separate thread on which to receive data.
Close a port connection
Invoke close() on the input and output streams, and the port connection.
Note: Each of the close() methods can throw an IOException. Applications must implement exception handling.
_din.close();
_dout.close();
conn.close();
Using Bluetooth serial port connections
The Bluetooth API (net.rim.device.api.bluetooth) enables applications to access the Bluetooth Serial Port
Profile and initiate a server or client Bluetooth serial port connection to a computer or other Bluetooth wireless
technology enabled device.
Note: Check for a NoClassDefFoundError when your application first accesses the Bluetooth API. This error is thrown if the system
administrator restricts access to the Bluetooth API using application control. See "Application control" on page 16 for more
information.
The BlackBerry device simulator does not support Bluetooth.
Open a Bluetooth serial port connection
To open a Bluetooth serial port connection, invoke Connector.open(), providing the serial port information
returned by BluetoothSerialPort.getSerialPortInfo() as a parameter. The connection string returned by
this method specifies btspp:// as the protocol and one of the following items:
• If you are opening the connection as a client, the connection string returned by
getSerialPortInfo().toString() contains the device ID and port number on which the server device is
listening.
• If you are opening the connection as a server, the connection string returned by
getSerialPortInfo().toString() contains the port on which your BlackBerry device is listening.
BluetoothSerialPortInfo[] info = BluetoothSerialPort.getSerialPortInfo();
StreamConnection _conn = (StreamConnection)Connector.open( info.toString(),
Connector.READ_WRITE );
103
BlackBerry Application Developer Guide Volume 1: Fundamentals
Send data on a Bluetooth serial port connection
Acquire an output stream by invoking openDataOutputStream() or openOutputStream().
Note: This call blocks until the connection is made.
DataOutputStream _dout = _conn.openDataOutputStream();
Use the write methods on the output stream to write data.
private String data = "This is a test";
_dout.writeChars(test);
Receive data on a Bluetooth serial port connection
Acquire an input stream by invoking openInputStream() or openDataInputStream().
DataInputStream _din = _conn.openInputStream();
Use the read methods on the input stream to read data.
String contents = _din.readUTF();
Note: You cannot read from the input stream on the main event thread, because this operation blocks until data is received. Create a
separate thread on which to receive data.
Close a port connection
Invoke close() on the input and output streams, and the Bluetooth serial port connection.
if (_bluetoothConnection != null) {
try {
_bluetoothConnection.close();
} catch(IOException ioe) {
}
}
if (_din != null) {
try {
_din.close();
} catch(IOException ioe) {
}
}
if (_dout != null) {
try {
_dout.close();
} catch(IOException ioe) {
}
}
_bluetoothConnection = null;
_din = null;
_dout = null;
Code example
The BluetoothSerialPortDemo.java sample is the client side of a simple Bluetooth serial port application. This
application listens for data on the serial port and renders the data when it arrives.
104
6: Connecting to networks
Example: BluetoothSerialPortDemo.java
/**
* BluetoothSerialPortDemo.java
* Copyright (C) 2004-2005 Research In Motion Limited.
*/
/* The client side of a simple serial port demonstration application.
* This application listens for text on the serial port and
* renders the data when it arrives.
*/
package com.rim.samples.docs.bluetoothserialportdemo;
import java.io.*;
import javax.microedition.io.*;
import net.rim.device.api.bluetooth.*;
import net.rim.device.api.ui.*;
import net.rim.device.api.ui.component.*;
import net.rim.device.api.ui.container.*;
import net.rim.device.api.i18n.*;
import net.rim.device.api.system.*;
import net.rim.device.api.util.*;
import com.rim.samples.docs.baseapp.*;
import com.rim.samples.docs.resource.*;
public class BluetoothSerialPortDemo extends BaseApp implements
BluetoothSerialPortDemoResResource {
//statics -----------------------------------------------------------------private static ResourceBundle _resources;
private static final int INSERT = 1;
private static final int REMOVE = 2;
private static final int CHANGE = 3;
private static final int JUST_OPEN = 4;
private static final int CONTENTS = 5;
private static final int NO_CONTENTS = 6;
static {
_resources = ResourceBundle.getBundle(BluetoothSerialPortDemoResResource.BUNDLE_ID,
BluetoothSerialPortDemoResResource.BUNDLE_NAME);
}
105
BlackBerry Application Developer Guide Volume 1: Fundamentals
private EditField _infoField;
private StreamConnection _bluetoothConnection;
private DataInputStream _din;
private DataOutputStream _dout;
public static void main(String[] args)
{
BluetoothSerialPortDemo theApp = new BluetoothSerialPortDemo();
theApp.enterEventDispatcher();
}
//constructor -------------------------------------------------------------public BluetoothSerialPortDemo()
{
MainScreen mainScreen = new MainScreen();
mainScreen.setTitle(new LabelField(_resources.getString(TITLE),
LabelField.USE_ALL_WIDTH));
_infoField = new EditField(Field.READONLY);
mainScreen.add(_infoField);
mainScreen.addKeyListener(this);
mainScreen.addTrackwheelListener(this);
pushScreen(mainScreen);
invokeLater(new Runnable() {
public void run() {
openPort();
}
});
}
protected void onExit() {
closePort();
}
// Close the serial port.
private void closePort() {
if (_bluetoothConnection != null) {
try {
_bluetoothConnection.close();
} catch(IOException ioe) {
}
106
6: Connecting to networks
}
if (_din != null) {
try {
_din.close();
} catch(IOException ioe) {
}
}
if (_dout != null) {
try {
_dout.close();
} catch(IOException ioe) {
}
}
_bluetoothConnection = null;
_din = null;
_dout = null;
}
// Open the serial port.
private void openPort() {
if (_bluetoothConnection != null) {
closePort();
}
new InputThread().start();
}
private class InputThread extends Thread {
public void run() {
try {
BluetoothSerialPortInfo[] info = BluetoothSerialPort.getSerialPortInfo();
if( info == null || info.length == 0 ) {
invokeAndWait( new Runnable() {
public void run() {
Dialog.alert( “No bluetooth serial ports available for
connection.” );
onExit();
System.exit(1);
}
});
}
_bluetoothConnection = (StreamConnection)Connector.open(
info[0].toString(), Connector.READ_WRITE );
107
BlackBerry Application Developer Guide Volume 1: Fundamentals
_din = _bluetoothConnection.openDataInputStream();
_dout = _bluetoothConnection.openDataOutputStream();
} catch(IOException e) {
invokeAndWait( new Runnable() {
public void run() {
Dialog.alert(“Unable to open serial port”);
onExit();
System.exit(1);
}
});
} catch( UnsupportedOperationException e ) {
invokeAndWait( new Runnable() {
public void run() {
Dialog.alert(“This handheld or simulator does not support
bluetooth.”);
onExit();
System.exit(1);
}
});
}
try {
int type, offset, count;
String value;
_dout.writeInt(JUST_OPEN);
_dout.flush();
for (;;) {
type = _din.readInt();
if (type == INSERT) {
offset = _din.readInt();
value = _din.readUTF();
insert(value, offset);
} else if (type == REMOVE) {
offset = _din.readInt();
count = _din.readInt();
remove(offset, count);
} else if (type == JUST_OPEN) {
// Send contents to desktop.
value = _infoField.getText();
if (value == null || value.equals(““)) {
_dout.writeInt(NO_CONTENTS);
_dout.flush();
} else {
_dout.writeInt(CONTENTS);
108
6: Connecting to networks
_dout.writeUTF(_infoField.getText());
_dout.flush();
}
} else if (type == CONTENTS) {
String contents = _din.readUTF();
synchronized(Application.getEventLock()) {
_infoField.setText(contents);
}
} else if (type == NO_CONTENTS) {
} else {
throw new RuntimeException();
}
}
} catch(IOException ioe) {
invokeLater(new Runnable() {
public void run() {
Dialog.alert(“Problems reading from or writing to serial port.”);
onExit();
System.exit(1);
}
});
}
}
}
private void insert(final String msg, final int offset) {
invokeLater(new Runnable() {
public void run() {
_infoField.setCursorPosition(offset);
_infoField.insert(msg);
}
});
}
private void remove(final int offset, final int count) {
invokeLater(new Runnable() {
public void run() {
_infoField.setCursorPosition(offset+count);
_infoField.backspace(count);
}
});
}
109
BlackBerry Application Developer Guide Volume 1: Fundamentals
/**
* Override makeMenu to add custom menu items.
*/
protected void makeMenu(Menu menu, int instance)
{
if (_infoField.getTextLength() > 0) {
menu.add(new MenuItem(_resources, MENUITEM_COPY, 100000, 10) {
public void run() {
Clipboard.getClipboard().put(_infoField.getText());
}
});
}
super.makeMenu(menu, instance);
}
}
110
7
Using datagram connections
Datagram connections
Using UDP connections
Using Mobitex networks
Sending and receiving SMS messages
Datagram connections
BlackBerry devices support datagram connections using the User Datagram Protocol (UDP). Applications use UDP
to communicate with standard network services.
Datagrams are independent packets of data that applications send over networks. A Datagram object is a wrapper
for the array of bytes that is the payload of the datagram. To retrieve a reference to this byte array, invoke
getData().
Unlike HTTP connections, datagram connections are stateless: packets arrive in any order, and delivery is not
guaranteed. Applications are responsible for making sure that the data payload of request datagrams is formatted
according to the standards of the network service over which the datagram is transmitted. Applications must also
be able to parse the datagrams that are sent back from the server.
Use datagram connections to send SMS messages. See "Sending and receiving SMS messages" on page 121 for
more information.
Using UDP connections
To use a UDP connection, you must have your own infrastructure to connect to the wireless network, including an
access point name (APN) for General Packet Radio Service (GPRS) networks.
Note: Datagram connections do not use the BlackBerry Infrastructure, so communication is not encrypted. The APN of the simulator
is net.rim.gprs.
The javax.microedition.io.DatagramConnection interface, which extends the Connection class, defines
connections that send and receive datagrams. The Datagram interface defines the packets that are sent and
received over a datagram connection.
Note: Using UDP connections requires that you work closely with service providers. Contact your service provider to verify that UDP
connections are supported.
You might not be able to set up a UDP connection if your service provider does not support multiple PDP contexts. One PDP context
is reserved for the blackberry.net APN, which is used for messaging. You might, however, be able to use blackberry.net as the APN for
UDP. Contact your service provider for more information.
BlackBerry Application Developer Guide Volume 1: Fundamentals
Retrieve a datagram connection
Invoke Connector.open() using the following format. Specify udp as the protocol. Cast the returned object as a
DatagramConnection.
(DatagramConnection)Connector.open("udp://host:dest_port[;src_port]/apn");
Parameter
Description
host
This parameter specifies the host address in dotted ASCII-decimal format.
dest_port
This parameter specifies the destination port at the host address (optional for receiving messages).
src_port
This parameter specifies the local source port (optional).
apn
This parameter specifies the network APN in string format.
Note: You can send and receive UDP datagrams on the same port.
To send data on a UDP connection, specify a destination port in the connection string. To receive data on a UDP
connection, specify a source port in the connection string. To receive datagrams from all ports at the specified
host, omit the destination port.
Note: To open a connection on a non-GPRS network, do not specify an APN. Include the slash mark after the source port. For example,
the address for a CDMA network connection would be udp://121.0.0.0:2332;6343/.
Create a datagram
Invoke DatagramConnection.newDatagram().
Datagram outDatagram = conn.newDatagram(buf, buf.length);
Add data to a datagram
Invoke Datagram.setData(). The format of the data is determined by the service that receives it.
byte[] buf = new byte[256];
outDatagram.setData(buf, buf.length);
Send data on a UDP connection
Invoke send() on the datagram connection.
conn.send(outDatagram);
Note: If an application attempts to send a datagram on a UDP connection and the recipient is not listening on the specified source
port, an IOException is thrown.
Receive data on a UDP connection
Invoke receive() on the datagram connection.
byte[] buf = new byte[256];
Datagram inDatagram = conn.newDatagram(buf, buf.length);
conn.receive(inDatagram);
112
7: Using datagram connections
Note: The receive() method blocks other operations until it receives a packet. If the packet is lost, the application waits indefinitely.
Set a timer to retransmit the request or close the connection if a reply does not arrive.
Extract data from a datagram
Invoke getData() on the datagram connection. If you know the type of data that you are receiving, convert the
data to the appropriate format.
String received = new String(inDatagram.getData());
Close the UDP connection
As with all connections in the MIDP framework, invoke close() on the input and output streams, and on the
datagram connection.
Using Mobitex networks
The DatagramConnectionBase class provides methods that handle BlackBerry datagram connection and
transmission operations over Mobitex networks.
Open a Mobitex datagram connection
Invoke Connector.open(), and then cast the returned object as a DatagramConnectionBase. The
DatagramConnectionBase class implements DatagramConnection but provides additional methods that are
necessary to register a datagram status listener.
Provide as parameter to Connector.open() a connection string using the following format:
mobitex:<type>:<MAN>
Parameter
Description
<type>
accepts the following values: “TEXT”, “DATA”, “STATUS” or “HPDATA{HPID}” (in which case HPID is in ASCIIdecimal format)
<MAN>
Mobitex Access Number; accepts ASCII-decimal format
Note: If you open a server connection (a listener), leave the MAN blank.
// The datagram connection <type> is DATA and the MAN is left blank for an incoming
// connection.
DatagramConnection dc = (DatagramConnection)Connector.open("mobitex:DATA:");
DatagramConnectionBase dcb = (DatagramConnectionBase)dc;
Listen for datagram status events
If you want to register a datagram status listener, use a DatagramBase rather than a Datagram to hold data.
DatagramBase implements the Datagram interface, but provides additional methods that are necessary to
register a datagram status listener.
113
BlackBerry Application Developer Guide Volume 1: Fundamentals
// dc is a DatagramConnection.
Datagram d = dc.newDatagram(dc.getMaximumLength());
d.setAddress(address);
d.setData(raw, 0, raw.length);
DatagramBase db = (DatagramBase)d; // An error if this fails.
Register a datagram status listener
Your implementation of the DatagramStatusListener interface listens for events, such as the receipt of a
datagram. See DatagramStatusListener in the API Reference for a complete list of datagram status events.
To allocate a datagram ID and assign it to the DatagramStatusListener implicitly, invoke
DatagramConnectionBase.allocateDatagramId().
int id = dcb.allocateDatagramId(d);
Preallocating the datagram ID in this way makes sure that your listener code is aware of the datagram that is
associated with the ID.
Obtain datagram information
The MobitexAddress class encapsulates Mobitex addressing information, such as the Mobitex Access Number
(MAN), the type of message, and the message status.
The MobitexPacketHeader class provides low-level access to the radio header field. To use the
MobitexPacketHeader for all addressing operations and ignore the other MobitexAddress fields, invoke
MobitexAddress.setPacketHeader().
Obtain radio and network information
The MobitexInfo class provides objects to store general information about the state of the radio. The
MobitexInfo.MobitexCellInfo class provides objects to store Mobitex cell information.
Code example
The MobitexDemo.java code example demonstrates the use of the Mobitex radio layer APIs.
Example: MobitexDemo.java
/*
* MobitexDemo.java
*
* Copyright (C) 2003-2005 Research In Motion Limited
*/
package com.rim.docs.samples.mobitexdemo;
import javax.microedition.io.*;
import net.rim.device.api.ui.*;
114
7: Using datagram connections
import net.rim.device.api.ui.component.*;
import net.rim.device.api.ui.container.*;
import net.rim.device.api.i18n.*;
import java.util.*;
import net.rim.device.api.io.*;
import net.rim.device.api.system.*;
import java.io.*;
import com.rim.docs.samples.baseapp.*;
/**
* A simple mobitex layer sample.
*/
public final class MobitexDemo extends BaseApp implements MobitexDemoResource {
private MainScreen _mainScreen;
private EditField _pin;
private EditField _data;
private RichTextField _messages;
private SenderThread _sendThread;
private ReceiverThread _receiverThread;
// statics -----------------------------------------------------------------private static ResourceBundle _resources =
ResourceBundle.getBundle(MobitexDemoResource.BUNDLE_ID, MobitexDemoResource.BUNDLE_NAME);
static public void main(String[] args)
{
new MobitexDemo().enterEventDispatcher();
}
// menu items ---------------------------------------------------------------// Cache the send menu item for reuse.
private MenuItem _sendMenuItem = new MenuItem(_resources, MOBITEXDEMO_MENUITEM_SEND,
100, 10) {
public void run()
{
// Don’t execute on a blank address.
String pin = _pin.getText();
String data = _data.getText();
if ( pin.length() > 0
) {
send(pin, data);
}
}
};
115
BlackBerry Application Developer Guide Volume 1: Fundamentals
// Cache the clear messages menu item for reuse.
private MenuItem _clearMessages = new MenuItem(_resources,
MOBITEXDEMO_MENUITEM_CLEARMESSAGES, 105, 10) {
public void run() {
_messages.setText("");
}
};
public MobitexDemo()
{
_mainScreen = new MainScreen();
_mainScreen.setTitle( new LabelField(_resources.getString(MOBITEXDEMO_TITLE),
LabelField.ELLIPSIS | LabelField.USE_ALL_WIDTH));
_pin = new EditField(_resources.getString(MOBITEXDEMO_LABEL_PIN), null,
Integer.MAX_VALUE, EditField.FILTER_PIN_ADDRESS);
_mainScreen.add(_pin);
_data = new EditField(_resources.getString(MOBITEXDEMO_LABEL_DATA), null);
_mainScreen.add(_data);
_mainScreen.add(new SeparatorField());
_messages = new RichTextField(_resources.getString(MOBITEXDEMO_CONTENT_DEFAULT));
_mainScreen.add(_messages);
_mainScreen.addKeyListener(this); //implemented by the super
_mainScreen.addTrackwheelListener(this); //implemented by the super
//start the helper threads
_sendThread = new SenderThread();
_sendThread.start();
_receiverThread = new ReceiverThread();
_receiverThread.start();
//push the main screen - a method from the UiApplication class
pushScreen(_mainScreen);
}
// methods -----------------------------------------------------------------/*public boolean keyChar(char key, int status, int time)
{
116
7: Using datagram connections
if ( UiApplication.getUiApplication().getActiveScreen().getLeafFieldWithFocus() ==
_pin && key == Characters.ENTER )
{
_sendMenuItem.run();
return true; // I’ve absorbed this event, so return true.
}
else
{
return super.keyChar(key, status, time);
}
}*/
protected void makeMenu(Menu menu, int instance)
{
menu.add(_sendMenuItem);
menu.add(_clearMessages);
menu.addSeparator();
super.makeMenu(menu, instance);
}
private void send(String pin, String data)
{
_sendThread.send(pin, data);
}
private void message(String msg)
{
System.out.println(msg);
_messages.setText(_messages.getText() + msg + "\n");
}
// inner classes ------------------------------------------------------------private class ReceiverThread extends Thread
{
private DatagramConnection _dc;
// Shut down the thread.
public void stop()
{
try {
_dc.close();
} catch(IOException e) {
117
BlackBerry Application Developer Guide Volume 1: Fundamentals
MobitexDemo.this.message(e.toString());
}
}
public void run()
{
try {
// Incoming data connection - leave the MAN blank.
_dc = (DatagramConnection)Connector.open("mobitex:DATA:");
for(;;) {
Datagram d = _dc.newDatagram(_dc.getMaximumLength());
_dc.receive(d);
DatagramBase db = (DatagramBase)d;
MobitexAddress ma = (MobitexAddress)db.getAddressBase();
MobitexPacketHeader mph = ma.getPacketHeader();
StringBuffer sb = new StringBuffer();
sb.append("Recieved packet");
sb.append("\nFROM:");
sb.append(mph.getSourceAddress());
sb.append("\nTO:");
sb.append(mph.getDestinationAddress());
sb.append("\nFLAGS:");
sb.append(Integer.toHexString(mph.getPacketFlags()));
sb.append("\nDATA:");
sb.append(new String(db.getData()));
MobitexDemo.this.message(sb.toString());
}
} catch (IOException e) {
MobitexDemo.this.message(e.toString());
}
}
}
/**
* The ConnectionThread class manages the datagram connection
*/
private class SenderThread extends Thread implements DatagramStatusListener {
private static final int TIMEOUT = 500; //ms
private Vector _sendQueue = new Vector(5);
118
7: Using datagram connections
private volatile boolean _start = false;
private volatile boolean _stop = false;
// Queue something for sending
public void send(String pin, String data) {
synchronized(_sendQueue) {
_sendQueue.addElement(new String[] { pin, data });
_start = true;
}
}
// Shut down the thread.
public void stop() {
_stop = true;
}
public void run()
{
for(;;) {
String pin = null;
String data = null;
// Thread control.
synchronized(_sendQueue) {
while( !_start && !_stop)
{
// Sleep for a bit so we don’t spin.
try {
_sendQueue.wait(TIMEOUT);
} catch (InterruptedException e) {
System.err.println(e.toString());
}
}
if (_start) {
String[] a = (String[])_sendQueue.firstElement();
if ( a != null ) {
pin = a[0];
data = a[1];
}
_start = false;
} else if ( _stop ) { // Exit condition
return;
}
119
BlackBerry Application Developer Guide Volume 1: Fundamentals
}
// Open the connection and extract the data.
DatagramConnection dc = null;
try {
String address = "DATA:" + pin;
dc = (DatagramConnection)Connector.open("mobitex:" + address);
//an error if this fails
DatagramConnectionBase dcb = (DatagramConnectionBase)dc;
Datagram d = dc.newDatagram(dc.getMaximumLength());
byte[] raw = data.getBytes();
d.setAddress(address);
d.setData(raw, 0, raw.length);
// An error if this fails.
DatagramBase db = (DatagramBase)d;
// Allocate a datagram ID - if you want to know about status.
// For this particular datagram, then we can allocate the id
// here and log it for later follow up
dcb.allocateDatagramId(d);
// Set up a status listener.
db.setDatagramStatusListener(this);
dcb.send(d);
dc.close();
} catch (IOException e) {
MobitexDemo.this.message(e.toString());
}
// We’re done one connection so reset the start state.
_start = false;
}
}
public void updateDatagramStatus(int dgId, int code, Object context) {
String msg = "Datagram: " + Integer.toHexString(dgId) +
"\nStatus: " + DatagramStatusListenerUtil.getStatusMessage(code);
MobitexDemo.this.message(msg);
}
}
protected void onExit() {
120
7: Using datagram connections
_sendThread.stop();
_receiverThread.stop();
}
}
Sending and receiving SMS messages
Send and receive SMS messages in datagram packets using UDP. SMS datagram packets, which include the
BlackBerry header information, have a fixed size of 160 bytes.
Note: SMS messaging is not fully supported on all networks. Check with your service provider to verify that the relevant networks have
full or partial support for SMS messaging. In most cases, SMS is supported on GPRS and CDMA network-enabled BlackBerry devices.
If the service provider supports SMS, system administrators can also use an IT policy to control the use of SMS messaging by corporate
users. Administrators can set the ENABLE_SMS item to TRUE or FALSE. The default is TRUE (SMS messaging is enabled).
Send SMS messages
Open a datagram connection for sending SMS messages
Invoke Connector.open(). Provide a connection string using the following format, where <peer_address> is
the phone number—Mobile Station ISDN Number (MSISDN)—of the recipient.
DatagramConnection _dc = Connector.open("sms://<peer_address>");
You can also omit the peer_address and invoke Datagram.setAddress() instead to set the destination
address of the message.
Create an SMS message
Invoke DatagramConnection.newDatagram().
Datagram smsMessage = conn.newDatagram(buf, buf.length);
Set SMS message contents
Invoke setData().
private String _msg = "This is a test message";
byte[] data = _msg.getBytes();
smsMessage.setData(data, 0, data.length);
121
BlackBerry Application Developer Guide Volume 1: Fundamentals
Send an SMS message
Note: Open network connections on a separate thread from the main application thread so the UI does not stall.
If you did not specify peer_address in the connection string, invoke Datagram.setAddress() to set the SMS
address. To send the SMS message, invoke DatagramConnection.send().
smsMessage.setAddress("sms://+15555551234");
_dc.send(datagram);
Code example
The SendSms.java code example demonstrates how to send an SMS message on a separate thread.
The SmsDemo.java sample application in the samples workspace requires a server-side application to interact with
the BlackBerry device simulator, to simulate sending and receiving SMS messages. You cannot send an actual SMS
message from the BlackBerry device simulator.
A server-side component of the sample application (SMSServer.java) is included with the BlackBerry JDE. To run
the server side component, run run.bat, located in the samples subdirectory of your BlackBerry Java Development
Environment (BlackBerry JDE) installation. For Example:
\samples\com\rim\samples\server\smsdemo\.
Example: SendSms.java
/**
* SendSms.java
* Copyright (C) 2002-2005 Research In Motion Limited. All rights reserved.
*/
package com.rim.samples.docs.smsdemo;
import
import
import
import
import
net.rim.device.api.io.*;
net.rim.device.api.system.*;
javax.microedition.io.*;
java.util.*;
java.io.*;
public class SendSms extends Application {
private static final int MAX_PHONE_NUMBER_LENGTH = 32;
// Members.
private String addr = “15195551234”;
private String msg = “This is a test message.”;
private DatagramConnection _dc = null;
private static String _openString = “sms://”;
public static void main(String[] args) {
new SendSms().enterEventDispatcher();
}
public SendSms() {
try {
_dc = (DatagramConnection)Connector.open(_openString);
byte[] data = msg.getBytes();
Datagram d = _dc.newDatagram(_dc.getMaximumLength());
d.setAddress(“//” + addr);
122
7: Using datagram connections
_dc.send(d);
} catch ( IOException e) {
}
System.exit(0);
}
}
Receive an SMS message
Create a separate listener thread
Listen for messages on a separate thread from the main application thread so that the UI does not stall.
Open a datagram connection
Invoke Connector.open(). Provide a connection string using the following format:
_dc =
(DatagramConnection)Connector.open("sms://<peer_address><port>");
where:
• <peer_address> is the phone number—Mobile Station ISDN Number (MSISDN)—of the receiver
• <port> is the port number for which the application receives SMS messages
Retrieve a datagram
Create a Datagram object to store the datagram. To retrieve the SMS message datagram, invoke receive() on
the datagram connection. This operation blocks until data is received.
Datagram d = _dc.newDatagram(160); // SMS messages have a fixed size of 160 bytes
_dc.receive(d);
Extract data from a datagram
To extract the address from the SMS message, invoke Datagram.getAddress(). To extract the data from the SMS
message, invoke Datagram.getData().
String address = d.getAddress();
String msg = new String(d.getData());
Code example
The ReceiveSms.java code example demonstrates how to receive an SMS message on a separate thread.
Example: ReceiveSms.java
/**
* ReceiveSms.java
* Copyright (C) 2002-2005 Research In Motion Limited. All rights reserved.
*/
package com.rim.samples.docs.smsdemo;
123
BlackBerry Application Developer Guide Volume 1: Fundamentals
import
import
import
import
import
net.rim.device.api.io.*;
net.rim.device.api.system.*;
javax.microedition.io.*;
java.util.*;
java.io.*;
public class ReceiveSms extends Application {
private ListeningThread _listener;
// Additional code required for complete sample.
public static void main(String[] args) {
new ReceiveSms().enterEventDispatcher();
}
ReceiveSms() {
_listener = new ListeningThread();
_listener.start();
}
private static class ListeningThread extends Thread {
private boolean _stop = false;
private DatagramConnection _dc;
public synchronized void stop() {
_stop = true;
try {
_dc.close(); // Close the connection so the thread returns.
} catch (IOException e) {
System.err.println(e.toString());
}
}
public void run() {
try {
_dc = (DatagramConnection)Connector.open(“sms://”);
for(;;) {
if ( _stop ) {
return;
}
Datagram d = _dc.newDatagram(_dc.getMaximumLength());
_dc.receive(d);
String address = new String(d.getAddress());
String msg = new String(d.getData());
System.out.println(“Message received: “ + msg);
System.out.println(“From: “ + address);
System.exit(0);
}
} catch (IOException e) {
System.err.println(e.toString());
}
}
}
}
124
8
Localizing applications
Resource files
Adding localization support to applications
Retrieving strings from a resource file
Managing resource files for application suites
Resource files
Design applications so that they can be localized (adapted to specific languages and regions) without coding
changes. Instead of including textual elements in your source code, store text strings in separate resource files. In
your source code, use unique identifiers to map to the appropriate resource.
Storing text strings in separate resource files has two benefits:
• Text translation is more efficient because all of the text strings for a given locale are stored in a single file,
outside your source code.
• Applications can dynamically retrieve the appropriate text to display to the user, based on the user locale.
The BlackBerry JDE includes a built-in resource mechanism for creating string resources. The Localization API is
included in the net.rim.device.api.i18n package.
Note: MIDP applications do not support localization.
The resources for a given locale are stored in a ResourceBundle object. A ResourceBundleFamily object
contains a collection of ResourceBundles, which groups the resources for an application. The application can
switch languages, depending on the user locale, without requiring new resource bundles.
The BlackBerry Integrated Development Environment (BlackBerry IDE) compiles each resource bundle into a
separate compiled .cod file. You can load the appropriate .cod files onto BlackBerry devices with the other .cod
files for the application.
File required for
localization
Description
Example
Resource header file
This file defines descriptive keys for each localized string.
AppName.rrh
When the BlackBerry IDE builds a project, it creates a resource interface with
Resource appended to the .rrh file name as its name. For example, if you create
AppName.rrh, the interface is AppNameResource.
Resource content file (root This file maps resource keys to string values for the root (global) locale. It has the
locale)
same name as the resource header file.
AppName.rrc
BlackBerry Application Developer Guide Volume 1: Fundamentals
File required for
localization
Description
Resource content file
(specific locales)
This file maps resource keys to string values for specific locales (language and
AppName_en.rrc
country). Files have the same name as the resource header file, followed by an
AppName_en_GB.rrc
underscore (_) and the language code, and then, optionally, an underscore (_) and
AppName_fr.rrc
country code.
Example
Two-letter language and country codes are specified in ISO-639 and ISO-3166,
respectively.
Initialization file
This file initializes the resource bundle mechanism. This file is required only when
resources are compiled as a separate project.
init.java
Resource inheritance
Resources are organized in a hierarchy based on inheritance. If a string is not defined in a locale, a string from the
next closest locale is used.
Adding localization support to applications
Add resource header files
1. In the BlackBerry IDE, on the File menu, click New.
2. In the Source file name field, type a file name.
3. Click Browse.
4. Select the folder that contains the file.
5. Click OK.
6. In the field, type the package name, for example, com.rim.samples.docs.countryinfo.
7. Click OK.
8. Click Yes.
9. Leave the file that appears in the text editor empty except for the package statement.
10. Add the file to your project by right-clicking the file in the right pane, and then clicking Insert into project.
Add resource content files
Create three resource content files in the same folder where CountryInfo.java is located: CountryInfo.rrc
(root locale), CountryInfo_en.rrc (English), and CountryInfo_fr.rrc (French).
1. On the File menu, click New.
2. Type a file name and location.
3. Click OK.
4. Click Yes.
126
8: Localizing applications
5. Leave the file empty.
6. To add the .rrc file to the application project, right-click the file in the right pane.
7. Click Insert into project.
Add resources
1. In the BlackBerry IDE, double-click a resource header file.
2. On the Root tab, type resource keys and values for each string or string array in your application.
Each row defines a single resource. The Keys column displays a descriptive name for the resource. This is the
name that you use in your code to retrieve the localized text. The Values column displays the text for this
resource in a particular locale.
Note: To add an array of values for a single resource key, in the resource editor, right-click a resource and click Convert to
Multiple Values. Add one or more values to the array.
3. To specify a different text string in other locales, select the tab for a locale, such as fr for the French language.
4. In the Value cell for the resource, type the text string for the locale. If you do not define a value for a resource
in a particular locale, the value for the root locale is used.
Note: Type unicode characters directly into the Value cell. Visit http://www.unicode.org for more information.
5. Set an application title
You can provide a localized application title to display on the Home screen. If you do not provide a resource for
the application title, the value typed into the Title field on the Application tab of the project properties window
is used.
1. In the resource editor, add a resource for the application title, such as APPLICATION_TITLE.
2. Type a value for this resource in each locale that you support.
Note: To create a shortcut key for an application, add the unicode underscore character (\u0332) after the letter that you want
to use as a shortcut key. A shortcut key is a key that a user can press on the Home screen to start the application.
3. In the BlackBerry IDE, right-click the application project, and then click Properties.
4. Click the Resources tab.
5. Select the Title Resource Available option.
6. From the Resource Bundle drop-down list, select the resource header file name to use for this application.
7. From the Title Id drop-down list, select the resource to use for the application title, such as
APPLICATION_TITLE.
8. From the Description Id drop-down list, select a description ID.
127
BlackBerry Application Developer Guide Volume 1: Fundamentals
Code example
The CountryInfo.java sample demonstrates how to store text strings in separate resource files for specific locales
rather than providing text strings directly in the code. In your source code, you retrieve the string from the
resource to display the appropriate text for the user locale.
Example: CountryInfo.java
/**
* CountryInfo.java
* Copyright (C) 2001-2005 Research In Motion Limited. All rights reserved.
*/
package com.rim.samples.docs.countryinfo;
import
import
import
import
import
import
net.rim.device.api.ui.*;
net.rim.device.api.ui.component.*;
net.rim.device.api.ui.container.*;
net.rim.device.api.system.*;
net.rim.device.api.i18n.*;
com.rim.samples.docs.resource.*;
/* This sample demonstrates how to store text strings in separate resource
files for specific locales rather than providing text strings directly
in the code. In your source code, you retrieve the string from the resource
to display the appropriate text for the user locale. */
public class CountryInfo extends UiApplication {
public static void main(String[] args) {
CountryInfo theApp = new CountryInfo();
theApp.enterEventDispatcher();
}
public CountryInfo() {
pushScreen(new HelloWorldScreen());
}
}
final class HelloWorldScreen extends MainScreen implements CountryInfoResource {
private InfoScreen _infoScreen;
private ObjectChoiceField choiceField;
private int select;
private static ResourceBundle _resources = ResourceBundle.getBundle(
CountryInfoResource.BUNDLE_ID, CountryInfoResource.BUNDLE_NAME);
public HelloWorldScreen() {
super();
LabelField title = new LabelField(_resources.getString(APPLICATION_TITLE),
LabelField.ELLIPSIS | LabelField.USE_ALL_WIDTH);
setTitle(title);
add(new RichTextField(_resources.getString(FIELD_TITLE)));
String choices[] = _resources.getStringArray(FIELD_COUNTRIES);
choiceField = new ObjectChoiceField(
_resources.getString(FIELD_CHOICE), choices);
add(choiceField);
}
128
8: Localizing applications
public boolean onClose() {
Dialog.alert(_resources.getString(CLOSE));
System.exit(0);
return true;
}
private MenuItem _viewItem = new MenuItem(_resources, MENUITEM_VIEW, 110, 10) {
public void run() {
select = choiceField.getSelectedIndex();
_infoScreen = new InfoScreen();
UiApplication.getUiApplication().pushScreen(_infoScreen);
}
};
private MenuItem _closeItem = new MenuItem(_resources, MENUITEM_CLOSE,
200000, 10) {
public void run() {
onClose();
}
};
protected void makeMenu( Menu menu, int instance ) {
menu.add(_viewItem);
menu.add(_closeItem);
}
private class InfoScreen extends MainScreen {
public InfoScreen() {
super();
LabelField lf = new LabelField();
BasicEditField popField = new BasicEditField(
_resources.getString(FIELD_POP), null, 20, Field.READONLY);
BasicEditField langField = new BasicEditField(
_resources.getString(FIELD_LANG), null, 20, Field.READONLY);
BasicEditField citiesField = new BasicEditField(
_resources.getString(FIELD_CITIES), null, 50, Field.READONLY);
add(lf);
add(new SeparatorField());
add(popField);
add(langField);
add(citiesField);
if (select == 0) {
lf.setText(_resources.getString(FIELD_US));
popField.setText(_resources.getString(FIELD_US_POP));
langField.setText(_resources.getString(FIELD_US_LANG));
citiesField.setText(_resources.getString(FIELD_US_CITIES));
} else if (select == 1) {
lf.setText(_resources.getString(FIELD_CHINA));
popField.setText(_resources.getString(FIELD_CHINA_POP));
langField.setText(_resources.getString(FIELD_CHINA_LANG));
citiesField.setText(_resources.getString(FIELD_CHINA_CITIES));
} else if (select == 2) {
lf.setText(_resources.getString(FIELD_GERMANY));
popField.setText(_resources.getString(FIELD_GERMANY_POP));
langField.setText(_resources.getString(FIELD_GERMANY_LANG));
citiesField.setText(
_resources.getString(FIELD_GERMANY_CITIES));
}
129
BlackBerry Application Developer Guide Volume 1: Fundamentals
}
}
}
Retrieving strings from a resource file
Implement the resource interface
To support internationalization, implement the appropriate resource interface. The BlackBerry IDE compiles this
interface from the resource header (.rrh) automatically. The name of the interface is the name of the .rrh file with
Resource appended to it.
public class HelloWorldScreen extends MainScreen implements CountryInfoResource
{ ... }
Retrieve the resource bundle
Declare a class variable to hold the resource bundle for this application. A ResourceBundle object contains all
localized resources, such as strings, for an application. An application can select the appropriate bundles at
runtime based on its locale.
private static ResourceBundle _resources = ResourceBundle.getBundle(BUNDLE_ID,
BUNDLE_NAME);
To retrieve the appropriate bundle family, invoke getBundle(). The BlackBerry IDE creates the BUNDLE_ID and
BUNDLE_NAME constants when it creates the resource interface as part of building the project.
Create menu items using resources
To create MenuItem objects using resources, use the MenuItem constructor that accepts a resource bundle and a
resource instead of a String for the name of the menu item. Do not implement toString(), because the text of
the menu item is provided by the resource.
private MenuItem _viewItem = new MenuItem(_resources, MENUITEM_VIEW, 110, 10) {
public void run() {
select = choiceField.getSelectedIndex();
_infoScreen = new InfoScreen();
UiApplication.getUiApplication().pushScreen(_infoScreen);
}
};
Replace text strings with the appropriate resources
For each field that appears on the main screen, replace the text string with the appropriate resource. Invoke
getString() or getStringArray() to retrieve the string for the appropriate language.
130
8: Localizing applications
LabelField title = new LabelField(_resources.getString(APPLICATION_TITLE),
LabelField.ELLIPSIS | LabelField.USE_ALL_WIDTH);
add(new RichTextField(_resources.getString(FIELD_TITLE)));
String choices[] = _resources.getStringArray(FIELD_COUNTRIES);
choiceField = new ObjectChoiceField(_resources.getString(FIELD_CHOICE), choices);
Code example
The following example modifies the CountryInfo.java sample to retrieve strings from a resource file.
Example: CountryInfo.java (with localization support)
/**
* CountryInfo.java
* Copyright (C) 2001-2005 Research In Motion Limited. All rights reserved.
*/
package com.rim.samples.docs.localization;
import net.rim.device.api.ui.*;
import net.rim.device.api.ui.component.*;
import net.rim.device.api.ui.container.*;
import net.rim.device.api.system.*;
import net.rim.device.api.i18n.*;
import com.rim.samples.docs.resource.*;
public class CountryInfo extends UiApplication {
public static void main(String[] args) {
CountryInfo theApp = new CountryInfo();
theApp.enterEventDispatcher();
}
public CountryInfo() {
pushScreen(new HelloWorldScreen());
}
}
final class HelloWorldScreen extends MainScreen implements CountryInfoResource {
private InfoScreen _infoScreen;
private ObjectChoiceField choiceField;
private int select;
private static ResourceBundle _resources = ResourceBundle.getBundle( BUNDLE_ID,
BUNDLE_NAME );
public HelloWorldScreen() {
super();
LabelField title = new LabelField(_resources.getString(APPLICATION_TITLE),
LabelField.ELLIPSIS | LabelField.USE_ALL_WIDTH);
setTitle(title);
add(new RichTextField(_resources.getString(FIELD_TITLE)));
String choices[] = _resources.getStringArray(FIELD_COUNTRIES);
choiceField = new ObjectChoiceField(
_resources.getString(FIELD_CHOICE), choices);
add(choiceField);
}
public boolean onClose() {
Dialog.alert(_resources.getString(CLOSE));
System.exit(0);
return true;
}
131
BlackBerry Application Developer Guide Volume 1: Fundamentals
private MenuItem _viewItem = new MenuItem(_resources, MENUITEM_VIEW, 110, 10) {
public void run() {
select = choiceField.getSelectedIndex();
_infoScreen = new InfoScreen();
UiApplication.getUiApplication().pushScreen(_infoScreen);
}
};
private MenuItem _closeItem = new MenuItem(_resources, MENUITEM_CLOSE, 200000, 10) {
public void run() {
onClose();
}
};
protected void makeMenu( Menu menu, int instance ) {
menu.add(_viewItem);
menu.add(_closeItem);
}
private class InfoScreen extends MainScreen {
public InfoScreen() {
super();
LabelField lf = new LabelField();
BasicEditField popField = new BasicEditField(
_resources.getString(FIELD_POP), null, 20, Field.READONLY);
BasicEditField langField = new BasicEditField(
_resources.getString(FIELD_LANG), null, 20, Field.READONLY);
BasicEditField citiesField = new BasicEditField(
_resources.getString(FIELD_CITIES), null, 50, Field.READONLY);
add(lf);
add(new SeparatorField());
add(popField);
add(langField);
add(citiesField);
if (select == 0) {
lf.setText(_resources.getString(FIELD_US));
popField.setText(_resources.getString(FIELD_US_POP));
langField.setText(_resources.getString(FIELD_US_LANG));
citiesField.setText(_resources.getString(FIELD_US_CITIES));
} else if (select == 1) {
lf.setText(_resources.getString(FIELD_CHINA));
popField.setText(_resources.getString(FIELD_CHINA_POP));
langField.setText(_resources.getString(FIELD_CHINA_LANG));
citiesField.setText(_resources.getString(FIELD_CHINA_CITIES));
} else if (select == 2) {
lf.setText(_resources.getString(FIELD_GERMANY));
popField.setText(_resources.getString(FIELD_GERMANY_POP));
langField.setText(_resources.getString(FIELD_GERMANY_LANG));
citiesField.setText(
_resources.getString(FIELD_GERMANY_CITIES));
}
}
}
}
132
8: Localizing applications
Managing resource files for application suites
You can add resources to your application project, or, if you are creating a suite of applications, organize resources
into separate projects for each locale.
Create resource projects
Create a project for each resource bundle (locale), including the root locale.
Give the projects for each locale the same name as the project for the root locale, followed by a double underscore
(__), the language code, and, optionally, an underscore (_) followed by the country code. For example, if the root
locale project is named com_company_app, the projects for each locale would be named com_company_app__en,
com_company_app__en_GB, com_company_app__fr.
Specify output file names
1. Right-click the project, and then click Properties.
2. Click the Build tab.
3. In the Output file name field, type a name for the compiled file, without a file name extension.
Note: The output file names for all resource locale projects must be the same as for the root locale, followed by a double underscore
and the appropriate language and country codes. For example, if the output file name for the root locale project is
com_company_app, the output file name for the French-language locale must be com_company_app__fr.
Create an initialization file
When you compile resources in a separate project, create an initialization file (for example, init.java). The
BlackBerry IDE provides a built-in initialization mechanism, so that you only need to create an empty initialization
class with an empty main().
package com.rim.samples.device.resource;
import net.rim.device.api.i18n.*;
public class init {
public static void main (String[] args) { }
}
Add files to appropriate resource projects
Create one resource header file for each application and one resource content file for each application, for each
supported locale. Organize the resource files into projects.
1. Add the resource header (.rrh) files to the project for each application and to each resource project. This is
necessary to define the dependency between the application project and its resource projects.
2. In each resource project, right-click each .rrh file, and then click Properties.
3. Select Dependency only. Do not build.
133
BlackBerry Application Developer Guide Volume 1: Fundamentals
4. Add the resource content (.rrc) files to the projects for the appropriate locales.
Note: If you support a large number of locales, create a single library project for all resource header (.rrh) files and set the project type
to Library. For each resource locale in this project, define a dependency between the projects.
134
9
Using IT policies
IT policies
Retrieve custom policies
Listening for policy changes
IT policies
The BlackBerry IT policy API (net.rim.device.api.itpolicy) enables applications to access the IT policy
database on BlackBerry devices. Applications can retrieve custom IT policy settings to change their behavior or
functionality accordingly.
Note: System administrators use application control to limit the presence and functioning of third party applications on BlackBerry
devices. See the BlackBerry Enterprise Server Handheld Management Guide for more information on application control.
Each IT policy item consists of a descriptive key and a value. The value can be a string, integer, or Boolean value.
For example, the AllowPhone policy can have a value of true or false.
With the BlackBerry Enterprise Server version 3.5 or later for Microsoft® Exchange and handheld software version
3.5 or later, handheld policy settings are synchronized and updated wirelessly. With earlier versions of handheld
software, handheld policy settings are updated when the user synchronizes the BlackBerry device with the
desktop.
See the BlackBerry Enterprise Server for Microsoft Exchange Handheld Management Guide for more information.
Retrieve custom policies
Note: The IT policy API enables applications to retrieve values for custom (third-party) IT policy items only. Applications cannot retrieve
values for standard IT policy items.
To retrieve the value of a custom third-party IT policy item by name, use the form of each method that accepts a
String parameter.
public static String getString( String name );
public static boolean getBoolean( String name, boolean defaultValue );
public static int getInteger( String name, int defaultValue );
The defaultValue parameter specifies the return value if the parameter has not been set.
Listening for policy changes
A global event is generated when the IT policy database is updated on the BlackBerry device.
BlackBerry Application Developer Guide Volume 1: Fundamentals
To use IT policies, applications implement the GlobalEventListener interface. Register your implementation to
receive global events. GlobalEventListener.eventOccurred() is invoked when a global event, such as a
change in IT policies, occurs. In your implementation of eventOccurred(), retrieve values for IT policy items to
determine whether values have changed.
Code example
The ITPolicyDemo.java sample implements IT policy controls.
Example: ITPolicyDemo.java
/**
* ITPolicyDemo.java
* Copyright (C) 2002-2005 Research In Motion Limited.
*/
package com.rim.samples.docs.itpolicy;
import net.rim.device.api.system.*;
import net.rim.device.api.itpolicy.*;
public class ITPolicyDemo extends Application implements GlobalEventListener {
public static void main(String[] args) {
ITPolicyDemo app = new ITPolicyDemo();
app.enterEventDispatcher();
}
ITPolicyDemo() {
this.addGlobalEventListener(this);
boolean appEnabled = ITPolicy.getBoolean(“DemoAppEnabled”, true);
System.out.println(“App Enabled: “ + appEnabled);
System.exit(0);
}
public void eventOccurred(long guid, int data0, int data1, Object obj0, Object obj1) {
if (guid == ITPolicy.GUID_IT_POLICY_CHANGED ) {
String security = ITPolicy.getString(“DemoSecurityLevel”);
boolean appEnabled = ITPolicy.getBoolean(“DemoAppEnabled”, true);
int retries = ITPolicy.getInteger(“DemoAppRetries”, 10);
}
}
}
136
10
Creating client/server push applications
Push applications
Client/server push requests
Writing a client-side push application
Writing a server-side push application
Troubleshooting push applications
Push applications
Note: Push applications require BlackBerry Enterprise Server version 3.5 or later for Microsoft Exchange, or BlackBerry Enterprise Server
version 2.2 or later for IBM Lotus Domino, with BlackBerry® MDS services enabled.
Push applications send new web content and alerts to specific users. Users do not have to request or download
the data because the push application delivers the information as it becomes available.
There are two types of push applications:
• Browser push applications: Web content is sent to the browser on the BlackBerry device. The BlackBerry
Browser configuration supports MDS services push applications. The WAP Browser configuration supports
WAP push applications. The Internet Browser configuration does not support push applications. See the
BlackBerry Browser Developer Guide for information on writing a browser push application.
• Client/server push applications: Data is pushed to a custom Java application on the BlackBerry device.
Client/server push applications consist of a custom client application for the BlackBerry device and a serverside application that pushes content to it. This approach provides more control over the type of content that
you can send out and how this data is processed and displayed on the BlackBerry device compared to browser
push applications.
Client/server push requests
Applications can push content to BlackBerry devices using one of two methods:
• Push Access Protocol (PAP), which is part of the WAP 2.0 specification
• RIM push
Note: MDS services only queues 1000 push requests, including both RIM and PAP push requests. MDS services responds to the server
with an error if it receives more than 1000 requests.
Both push service implementations support the following tasks:
• sending a server-side push submission
• specifying a reliability mode for the push submission
BlackBerry Application Developer Guide Volume 1: Fundamentals
• specifying a deliver-before time-stamp for the push submission
• requesting a result notification of the push submission
The PAP implementation supports the following additional tasks:
• specifying a deliver-after timestamp for the push submission
• cancelling a push request submission
• querying the status of a push request submission
Store pushes
PAP pushes are stored in a database, whereas RIM pushes are stored in RAM. Undelivered RIM pushes might be
lost if the server reboots.
Transcoding
If applicable, the BlackBerry® MDS Data Optimization Service applies a transcoder to push requests according to
its transcoder rules.
Push requests can override these rules to request a specific transcoder by using the transfer-encoding header.
For example, if the HTTP header transfer-encoding: vnd.wap.wml is set, the MDS data optimization service
runs the wml transcoder before it pushes the data to the BlackBerry device. See “Transcoders” on page 190 for
more information
138
10: Creating client/server push applications
Reliability modes
Reliability mode
Description
Transport-level reliability mode When the push arrives at a BlackBerry device, the BlackBerry® MDS Connection Service initiates a
connection to the URL specified in the push request to inform the server of the delivery. Transport-level
acknowledgement is available in the handheld software version 3.6 or later.
Application-level reliability
mode
When the push arrives at a BlackBerry device, the application acknowledges the content. The MDS
Connection Service initiates a connection to the URL specified during the push request to inform the server
of the delivery. If an error is encountered, the MDS Connection Service sends an error message to the server.
Application-level acknowledgement is available in handheld software version 4.0 and later.
RIM push provides an application-preferred option, which uses application-level acknowledgement in
handheld software version 4.0 or later and transport-level acknowledgement otherwise.
Note: MDS Services version 3.8 or earlier cannot query the BlackBerry Enterprise Server for BlackBerry device
characteristics. To obtain BlackBerry device characteristics, The MDS Connection Service must receive an
HTTP request before it receives a push request.
To provide the necessary request, browse to a web page using the BlackBerry Browser and an MDS Services
browser configuration.
Send a RIM push request
To push data to BlackBerry devices using RIM push, send an HTTP POST request using the following format, where
<destination> is the destination PIN or internet messaging address, <port> is the destination port, <uri> is the URI
sent to the BlackBerry device, and <content> is a byte stream:
/push?DESTINATION=<destination>&PORT=<port>&REQUESTURI=<uri><headers><content>
The following headers are valid for RIM push requests:
HTTP header
Description
X-RIM-Push-ID
This header specifies a unique message ID, which can be used to cancel or check the status of a
message. Typically, specify a URL in combination with a value, such as such as [email protected]
If this header is omitted, MDS services generates a unique message ID.
Note: Push identifiers must not end in @ppg.rim.com.
X-RIM-Push-NotifyURL
This header specifies a URL to send a result notification. The result notification contains the X-RIMPush-ID header, which specifies the message ID, and the X-RIM-Push-Status header, which
X-RIM-Push-Reliability-Mode
This header specifies the delivery reliability mode of the content—transport-level (TRANSPORT),
application-level (APPLICATION) or application preferred (APPLICATION-PREFERRED).
X-RIM-Push-Deliver-Before
This header specifies the date and time by which to deliver the content to the BlackBerry device.
Content that has not been delivered before this date is not delivered.
X-RIM-Push-Priority
This header specifies the priority of channel push messages. Permitted strings include none (default),
low, medium, and high. If the priority is low, medium or high, users receive notification of channel
updates. If the priority is high, a status dialog accompanies the notification.
specifies an HTTP response code.
Send a PAP push request
To push data to BlackBerry devices using PAP, send an HTTP POST request using the following format:
139
BlackBerry Application Developer Guide Volume 1: Fundamentals
/pap
The request is a MIME multipart message, which consists of the following items:
• an XML document specifying the control entity
• the push content
For example, the control entity might contain information for the BlackBerry device address, message ID, and
delivery timestamps.
Use the PAP Document Type Definition (DTD) to specify the following attributes:
XML control entity attributes
Description
X-Wap-Application-Id
This entity attribute specifies the equivalent of the “/”
REQUEST URI HTTP parameter for RIM push.
Example
push-id
Specifies a unique message ID. Additionally, this [email protected]
control entity attribute can be used to cancel or
check the status of a message. It is recommended
that you use a URL in combination with a value.
For example, [email protected]
ppg-notify-requested-to
Specifies the URL that result notification is sent to. http://wapforum:8080/
ReceivePAPNotification
deliver-before-timestamp
Specifies the date and time by which to deliver the 2004-01-20T22:35:00z
content to the BlackBerry device. Content that has
not been sent by this date and time is not
delivered.
Represent the date and time in Coordinate
Universal Time (UTC) format:
YYYY-MM-DDThh:mm:ssZ
where
•
•
•
•
YYYY is a 4 digit year
MM is a 2 digit month
DD is a 2 digit day
hh is a 2 digit hour based on 24-hour
timekeeping system
• mm is a 2 digit minute
• ss is a 2 digit second
• Z indicates that the time is in UTC
deliver-after-timestamp
Specifies the date and time after which content is 2004-01-20T21:35:00z
delivered to the BlackBerry device. Content is not
delivered before this date.
Represent the date and time in UTC format.
address-value
Specifies the address of the BlackBerry device that WAPPUSH=destination%3AportI/
the push content is sent to. The destination is the [email protected]
destination internet messaging address or PIN.
delivery-method
Specifies the delivery reliability mode of the
content, transport-level or application-level.
140
confirmed; unconfirmed
10: Creating client/server push applications
See the Push Access Protocol (WAP-247-PAP-20010429-a) specification for more information on writing serverside push applications using PAP. See the PAP 2.0 DTD for information on the WAP Push DTDs.
Example: PAP push request
Content-Type: multipart/related; type="application/xml"; boundary=asdlfkjiurwghasf
X-Wap-Application-Id: /
--asdlfkjiurwghasf
Content-Type: application/xml
<?xml version="1.0"?>
<!DOCTYPE pap PUBLIC "-//WAPFORUM//DTD PAP 2.0//EN" "http://www.wapforum.org/DTD/
pap_2.0.dtd">
<pap>
<push-message push-id="a_push_id" ppg-notify-requested-to="http://foo.rim.net/
ReceiveNotify">
<address address-value="WAPPUSH=aisha.wahl%40blackberry.com%3A7874/
[email protected]"/>
<quality-of-service delivery-method="unconfirmed"/>
</push-message>
</pap>
--asdlfkjiurwghasf
Content-Type: text/html
<html><body>Hello, PAP world!</body></html>
--asdlfkjiurwghasf--
Send a PAP push cancellation request
Use the following headers to cancel a push submission that has already been sent to MDS Services.
Header
Description
Example
cancel-message push-id
Cancels the push message that was previously
submitted.
<cancel-message pushid="[email protected]">
address address-value
Specifies the address to which the push message was <address addressvalue="WAPPUSH=aisha.wahl%40blackbe
submitted. This tag is required.
rry.com%3A7874/[email protected]" /
>
Example: PAP push cancellation request
Content-Type: application/xml
<?xml version="1.0"?>
<!DOCTYPE pap PUBLIC "-//WAPFORUM//DTD PAP 2.0//EN"
"http://www.wapforum.org/DTD/pap_2.0.dtd">
<pap>
<cancel-message push-id=“a_push_id">
<address address-value=
“WAPPUSH=aisha.wahl%40blackberry.com%3A7874/[email protected]”/>
141
BlackBerry Application Developer Guide Volume 1: Fundamentals
</cancel-message>
</pap>
Send a PAP push query request
To query the status of a push submission that has already been sent to MDS Services, use the following headers.:
XML control entity attributes
Description
Example
statusquery-message push-id
Specifies the push message for which status is
desired. A response is returned with one of the
following message states: delivered, pending,
undeliverable, expired, rejected, timeout,
cancelled, aborted or unknown.
<statusquery-message pushid="[email protected]">
You must include the address attribute in this
request.
address address-value
Specifies the address to which the push message
was submitted. This tag is required.
<address addressvalue="WAPPUSH=aisha.wahl%40blackbe
rry.com%3A7874/[email protected]" /
>
Example: PAP push status query request
Content-Type: application/xml
<?xml version="1.0"?>
<!DOCTYPE pap PUBLIC "-//WAPFORUM//DTD PAP 2.0//EN"
"http://www.wapforum.org/DTD/pap_2.0.dtd">
<pap>
<statusquery-message push-id=“a_push_id">
<address address-value=
“WAPPUSH=aisha.wahl%40blackberry.com%3A7874/[email protected]”/>
</statusquery-message>
</pap>
Determine whether a BlackBerry device is in push coverage
To receive network coverage information for a particular BlackBerry device, from MDS services, specify the
following headers:
XML control entity attributes
Description
Example
x-rim-push-use-coverage
Specify true to receive network coverage
information.the push message for which status is
desired.
<rim-push-use-coverage="true">
Note: This header is typically used to determine
network coverage prior to sending a push request.
142
10: Creating client/server push applications
XML control entity attributes
Description
Example
address address-value
Specifies the address of the BlackBerry device to
determine network coverage for.
<address addressvalue="WAPPUSH=aisha.wahl%40blackbe
rry.com%3A7874/[email protected]" /
>
Example: RIM network status query request
Content-Type: application/xml
<?xml version="1.0"?>
<!DOCTYPE pap PUBLIC "-//WAPFORUM//DTD PAP 2.0//EN"
"http://www.wapforum.org/DTD/pap_2.0.dtd">
<pap>
<rim-push-use-coverage="true" push-id="a_push_id" \>
</pap>
Example: RIM network status query response
Content-Type: application/xml
<?xml version="1.0"?>
<!DOCTYPE pap PUBLIC "-//WAPFORUM//DTD PAP 2.0//EN"
"http://www.wapforum.org/DTD/pap_2.0.dtd">
<pap>
<x-rim-device-state="true">
<!-- a response of true means the device is in network coverage -->
<address address-value="WAPPUSH=aisha.wahl%40blackberry.com%3A7874/
[email protected] />
</rim-push-use-coverage>
</pap>
Writing a client-side push application
Create a listening thread
Send and receive data on a separate thread so that you do not block the main event thread.
Open an input stream
Invoke Connector.open(String), specifying http:// as the protocol and choosing a high port number. Cast the
returned object as a StreamConnectionNotifier.
Open the connection once and keep the connection open. Re-open the connection only if an IOException occurs.
Do not close and re-open the connection every time pushed data is received, because pushed data can be lost if it
arrives before Connector.open() is invoked again after a previous push.
143
BlackBerry Application Developer Guide Volume 1: Fundamentals
To avoid conflicts with other applications, choose a high port number. Port numbers must be from 1 to 65535.
Port 7874 is reserved for the BlackBerry Browser.
StreamConnectionNotifier _notify = (StreamConnectionNotifier)Connector.open("http://
:6234");
// open a server-side socket connection
StreamConnection stream = _notify.acceptAndOpen();
// open an input stream for the connection
InputStream input = stream.openInputStream();
Close the stream connection notifier
Invoke close() on the stream connection notifier.
_notify.close();
Code example
The HTTPPushDemo.java sample demonstrates how to write an application that listens for inbound data from a
web server. You create a listening thread to listen for image data on a specific port and then display it when it
arrives.
Example: HTTPPushDemo.java
/**
* HTTPPushDemo.java
* Copyright (C) 2001-2005 Research In Motion Limited. All rights reserved.
*/
package com.rim.samples.docs.httppush;
import
import
import
import
import
import
import
import
import
java.io.*;
javax.microedition.io.*;
net.rim.device.api.ui.*;
net.rim.device.api.ui.component.*;
net.rim.device.api.ui.container.*;
net.rim.device.api.i18n.*;
net.rim.device.api.system.*;
net.rim.device.api.util.*;
com.rim.samples.docs.baseapp.*;
public class HTTPPushDemo extends BaseApp {
// Constants.
private static final String URL = “http://:6234”;
private static final int CHUNK_SIZE = 256;
// Fields.
private ListeningThread _listeningThread;
private MainScreen _mainScreen;
private RichTextField _infoField;
private BitmapField _imageField;
public static void main(String[] args) {
HTTPPushDemo theApp = new HTTPPushDemo();
144
10: Creating client/server push applications
theApp.enterEventDispatcher();
}
/**
* Create a separate listening thread so that you do not
* block the application’s main event thread.
*/
private class ListeningThread extends Thread {
private boolean _stop = false;
private StreamConnectionNotifier _notify;
public synchronized void stop() {
_stop = true;
try {
_notify.close(); // Close the connection so thread returns.
} catch (IOException e) {
System.err.println(e.toString());
} catch (NullPointerException e) {
// The notify object likely failed to open, due to an IOException.
}
}
public void run() {
StreamConnection stream = null;
InputStream input = null;
try {
synchronized(this) {
// Open the connection once or re-open after an IOException.
_notify = (StreamConnectionNotifier)Connector.open(URL);
}
while (!_stop) {
// NOTE: This method blocks until data is received.
stream = _notify.acceptAndOpen();
input = stream.openInputStream();
// Extract the data from the input stream.
DataBuffer db = new DataBuffer();
byte[] data = new byte[CHUNK_SIZE];
int chunk = 0;
while ( -1 != (chunk = input.read(data)) ) {
db.write(data, 0, chunk);
}
input.close();
data = db.getArray();
updateBitmap(data);
}
} catch (IOException e) {
System.err.println(e.toString()); // It is likely the stream was closed.
}
}
}
// Constructor.
public HTTPPushDemo() {
_mainScreen = new MainScreen();
_mainScreen.setTitle(new LabelField(“Latest Logos”, LabelField.USE_ALL_WIDTH));
_infoField = new RichTextField();
_mainScreen.add(_infoField);
_mainScreen.add(new SeparatorField());
_imageField = new BitmapField(null, BitmapField.HCENTER|BitmapField.TOP);
145
BlackBerry Application Developer Guide Volume 1: Fundamentals
_mainScreen.add(_imageField);
_mainScreen.addKeyListener(this);
_mainScreen.addTrackwheelListener(this);
_listeningThread = new ListeningThread();
_listeningThread.start();
_infoField.setText(“Application is listening...”);
pushScreen(_mainScreen);
}
private void updateBitmap(final byte[] data) {
Application.getApplication().invokeLater(new Runnable() {
public void run() {
// Query the user to load the received image.
String[] choices = {“OK”, “CANCEL”};
if ( 0 != Dialog.ask(“Do you want to display latest logo?”,
choices, 0) ) {
return;
}
_infoField.setText(“Image received. Size: “+ data.length);
_imageField.setBitmap(Bitmap.createBitmapFromPNG(data, 0,data.length));
}
});
}
protected void onExit() {
// Stop the listening thread.
_listeningThread.stop();
try {
_listeningThread.join();
} catch (InterruptedException e) {
System.err.println(e.toString());
}
}
}
Writing a server-side push application
Any programming language that can establish an HTTP connection can be used to create a push application. The
following sections use standard Java to demonstrate a server-side push application.
Construct the push URL
Format RIM push requests as follows:
/push?DESTINATION=<destination>&PORT=<port>&REQUESTURI=<uri><headers><content>
See "Send a RIM push request" on page 139 for more information on constructing a URL for a RIM push request.
Format PAP push requests as follows:
/pap
146
10: Creating client/server push applications
See "Send a PAP push request" on page 139 for more information on constructing a ULR for a PAP push request.
Connect to the BlackBerry Enterprise Server
Invoke openConnection() on the push URL, and then cast the returned object as an HttpURLConnection. An
HttpURLConnection represents a connection to a remote object.
HttpURLConnection conn =(HttpURLConnection)url.openConnection();
Set properties for the HTTP POST request
Server-side push applications use a request method of POST.
conn.setRequestMethod("POST"); // Post to the BlackBerry Enterprise Server.
To receive confirmation, set doInput(Boolean) to true to indicate that the application intends to read data
from the URL connection.
conn.setDoInput(true);
To send data, set doOutput(Boolean) to true to indicate that the application intends to send data to the URL
connection.
conn.setDoOutput(true);
Write data to the server connection
Invoke getOutputStream() to access an output stream. Write to the output stream, and then close it.
OutputStream out = conn.getOutputStream();
out.write(data);
out.close();
Read the server response
Invoke getInputStream() to access an input stream. Determine the size of the content and, if it is nonzero, open
a data input stream, and then read in the content.
InputStream ins = conn.getInputStream();
int contentLength = conn.getContentLength();
if (contentLength > 0) {
byte[] someArray = new byte [contentLength];
DataInputStream dins = new DataInputStream(ins);
dins.readFully(someArray);
System.out.println(new String(someArray));
}
ins.close();
Disconnect the connection
Invoke disconnect() to indicate that the application plans to make no further requests to the server.
147
BlackBerry Application Developer Guide Volume 1: Fundamentals
conn.disconnect();
Code example
The HTTPPush.java sample application, which is written using standard Java, sends a single .png image to a
listening client application on the BlackBerry device. The application pushes data based on an internet messaging
address. To test push applications with the simulator, define a mapping between the internet messaging address
and the simulator PIN (2100000A).
The following code compiles using J2SE 1.4.2.
Example: HTTPPushServer.java
/*
* HttpPushServer.java
* Copyright (C) 2001-2004 Research In Motion Limited. All rights reserved.
*/
package com.rim.docs.samples.httppush;
import java.io.*;
import java.net.*;
import java.util.*;
public class HTTPPushServer {
//constants
private static
private static
private static
private static
private static
final
final
final
final
final
String HANDHELD_EMAIL = “[email protected]”;
String HANDHELD_PORT = “6234”;
String BES_HOST = “localhost”;
int BES_PORT = 8080;
String CONTENT = “com/rim/docs/samples/httppush/logo.png”;
//constructor
public HTTPPushServer() {
}
private static URL getPushURL(String HandheldEmail) {
URL _pushURL = null;
try {
if ((HandheldEmail == null) || (HandheldEmail.length() == 0)) {
HandheldEmail = HANDHELD_EMAIL;
}
_pushURL = new URL(“http”, BES_HOST, BES_PORT,
“/push?DESTINATION=”+ HandheldEmail
+”&PORT=”+HANDHELD_PORT+”&REQUESTURI=/”);
} catch (MalformedURLException e) {
System.err.println(e.toString());
}
return _pushURL;
}
public static void postData(byte[] data) {
try {
URL url = getPushURL(HANDHELD_EMAIL);
System.out.println(“Sending to” + url.toString());
148
10: Creating client/server push applications
HttpURLConnection conn = (HttpURLConnection)url.openConnection();
conn.setDoInput(true); //for receiving the confirmation
conn.setDoOutput(true); //for sending the data
conn.setRequestMethod(“POST”); //post the data to the BES
OutputStream out = conn.getOutputStream();
out.write(data); //write the data
out.close();
InputStream ins = conn.getInputStream();
int contentLength = conn.getContentLength();
System.out.println(“Content length: “+ contentLength);
if (contentLength > 0) {
byte[] someArray = new byte [contentLength];
DataInputStream dins = new DataInputStream(ins);
dins.readFully(someArray);
System.out.println(new String(someArray));
}
ins.close();
conn.disconnect();
} catch (IOException e) {
System.err.println(e);
}
}
public static void main (String args[]) {
try {
File f = new File(CONTENT);
if ( f == null ) {
throw new RuntimeException(“Unable to Open File”);
}
FileInputStream fi = new FileInputStream(f);
if ( null == fi ) {
throw new RuntimeException(“Unable to open file”);
}
int size = fi.available();
byte[] imageData = new byte[size];
int bytesRead = fi.read(imageData);
fi.close();
postData(imageData);
} catch (IOException e) {
System.err.println(e.toString());
}
}
}
Troubleshooting push applications
Note: The following information applies only to BlackBerry Enterprise Server for Microsoft Exchange.
Push applications identify BlackBerry devices based on their internet messaging address. If users stop receiving
data from a push application after they switch to a different BlackBerry device, it might indicate that the mapping
between users’ internet messaging addresses and BlackBerry device PINs is out-of-date. Verify that the BlackBerry
Enterprise Server is operating correctly.
149
BlackBerry Application Developer Guide Volume 1: Fundamentals
The MDS services feature of the BlackBerry Enterprise Server for Microsoft Exchange uses a Database
Consistency tool, dbconsistency.exe, to maintain the mapping between internet messaging addresses and
BlackBerry device PINs. Administrators can configure the frequency at which this tool runs, and can also run this
tool manually. See the BlackBerry Enterprise Server for Microsoft Exchange Maintenance Guide for more
information.
150
11
Using location information
Location API
Code example
Location API
The Location API (javax.microedition.location) enables applications to obtain the Global Positioning
System (GPS) location of the BlackBerry device. The GPS location is the geographical coordinates, latitude and
longitude, of the BlackBerry device. Depending on the location method used, applications might also retrieve the
speed, orientation, and course of the BlackBerry device.
Methods for obtaining the GPS location
Method
Constant
Description
Cellsite
GPS_AID_MODE_CELLSITE
This method uses the GPS location of the active cellsite tower to provide first order
GPS information. It provides the least accurate location information; however, it is
the fastest location mode.
Note: Orientation, course, and speed are not available using this location mode.
This location method requires network connectivity and carrier support.
Assisted
GPS_AID_MODE_ASSIST
Autonomous
GPS_AID_MODE_AUTONOMOUS
This method uses the network to provide ephemeris satellite data to the device
chip. It provides the GPS location faster than the autonomous mode and more
accurately than the cellsite mode.
Note: This location method requires network connectivity and carrier support.
This method uses the GPS chip on the BlackBerry device without assistance from
the network. The autonomous mode provides the first GPS location the slowest.
Specify criteria for selecting a GPS location method
Specify the desired criteria by creating an instance of the javax.microedition.location.Criteria class,
invoking the appropriate set methods, and then passing the instance to LocationProvider.getInstance().
Note: To create a LocationProvider instance with default criteria, invoke LocationProvider.getInstance(null).
Criteria criteria = new Criteria();
// Allow cost.
criteria.setCostAllowed(true);
// Require a horizontal accuracy of 50 metres.
criteria.setHorizontalAccuracy(50);
// Require a vertical accuracy of 50 metres.
criteria.setVerticalAccuracy(50);
BlackBerry Application Developer Guide Volume 1: Fundamentals
LocationProvider provider = LocationProvider.getInstance(criteria);
Criteria for selecting a GPS location method
Recommended GPS location method
Horizontal accuracy
Vertical accuracy
Cost
Power consumption
autonomous
required
required
not allowed
not applicable
autonomous
required
required
allowed
low, medium or no
requirement
first fix: assisted
subsequent fixes: autonomous
required
required
allowed
high
autonomous
not required
not required
not allowed
medium, high or no
requirement
assisted
not required
not required
allowed
medium or no requirement
first fix: assisted
not required
not required
allowed
high
not required
not required
allowed
low
subsequent fixes: autonomous
cellsite
Note: GPS might be unavailable if the BlackBerry wireless device has an obstructed view of satellites. This can occur when the device
is indoors or surrounded by buildings, trees, or dense clouds.
Retrieve the location of the BlackBerry device
The time it takes to retrieve the location of the BlackBerry device for the first time depends on several factors, such
as the selected GPS mode and the GPS signal strength. In autonomous mode, typical times are less than 2
minutes. In assisted mode, typical times are less than 30 seconds.
The average response time for subsequent requests is 1 to 2 seconds, depending on site conditions, if a GPS fix
has occurred within 10 seconds of the request.
Note: If you use a location method that might cost the user money, do not query the BlackBerry device location too often.
To specify a desired response time, invoke Criteria.setPreferredResponseTime(), providing the desired
response time in milliseconds.
Retrieve the location of the BlackBerry device
Invoke LocationProvider.getLocation(int), providing a timeout in seconds.
Note: If LocationProvider.getLocation(int) is invoked on the event thread, a LocationException is thrown.
try {
// Specify -1 to have the implementation use its default timeout value
// for this provider.
Location location = provider.getLocation(-1);
} catch (Exception e) {
// handle LocationException, InterruptedException, SecurityException
// and IllegalArgumentException
}
152
11: Using location information
Retrieve location information
The Location class provides methods to retrieve location information, such as the GPS coordinates, speed, and
course.
Note: The RIM implementation does not support providing textual address information. As a result, the getAddressInfo() method
returns null.
QualifiedCoordinates coordinates = location.getQualifiedCoordinates;
float speed = location.getSpeed();
float course = location.getCourse();
Register a location listener
Implement the LocationListener interface. Register your implementation by invoking
LocationProvider.setLocationListener().
Note: Only one location listener can be associated with a particular location provider. Applications typically listen for updates on a
separate thread.
Example:
import javax.microedition.LocationProvider.*;
public class SampleLocationApp {
public static void main (string[] Args) {
// ...
provider.setLocationListener(new SampleLocationListener(), 0, 60, 60);
}
}
class SampleLocationListener implements LocationListener {
void locationUpdated(LocationProvider provider, Location location) {
// Respond to the updated location.
// If the application registered the location listener with an interval of
// 0, the location provider does not provide location updates.
}
void providerStateChanged(LocationProvider provider, int newState) {
switch (newState) {
case LocationProvider.AVAILABLE :
// The location provider is available.
break;
case LocationProvider.OUT_OF_SERVICE :
// The location provider is permanently unavailable.
// Consider cancelling the location listener by calling
// provider.setLocationListener() with null as the listener.
break;
case LocationProvider.TEMPORARILY_UNAVAILABLE :
// The location provider is temporarily unavailable.
break;
}
}
}
153
BlackBerry Application Developer Guide Volume 1: Fundamentals
Code example
Example: GPSDemo.java
/**
* A GPS sample application using the JSR 179 APIs.
*
* Copyright (C) 2005 Research In Motion Limited.
*/
package com.rim.samples.docs.gpsdemo;
import net.rim.device.api.ui.*;
import net.rim.device.api.ui.component.*;
import net.rim.device.api.ui.container.*;
import com.rim.samples.docs.baseapp.*;
import net.rim.device.api.io.*;
import net.rim.device.api.system.*;
import net.rim.device.api.i18n.*;
import javax.microedition.io.*;
import java.util.*;
import java.io.*;
import javax.microedition.location.*;
import net.rim.device.api.util.*;
import com.rim.samples.docs.resource.*;
/* This application acts as a simple travel computer, recording route coordinates,
* speed, and altitude.
* Recording begins as soon as the application is invoked.
*/
public class GPSDemo extends BaseApp implements GPSDemoResResource {
// Constants. ---------------------------------------------------------------// The number of updates in seconds over which the altitude is calculated.
private static final int GRADE_INTERVAL=5;
// com.rim.samples.docs.gpsdemo.GPSDemo.ID
private static final long ID = 0x4e94d9bc9c54fed3L;
private static final int CAPTURE_INTERVAL=10;
// Statics. -----------------------------------------------------------------private static ResourceBundle _resources =
ResourceBundle.getBundle(GPSDemoResResource.BUNDLE_ID, GPSDemoResResource.BUNDLE_NAME);
// The period of the position query in seconds.
private static int _interval = 1;
154
11: Using location information
private static Vector _previousPoints;
private static float[] _altitudes;
private static float[] _horizontalDistances;
private static PersistentObject _store;
// Initialize or reload the persistent store.
static {
_store = PersistentStore.getPersistentObject(ID);
if(_store.getContents()==null) {
_previousPoints= new Vector();
_store.setContents(_previousPoints);
}
_previousPoints=(Vector)_store.getContents();
}
private long _startTime;
private float _wayHorizontalDistance;
private float _horizontalDistance;
private float _verticalDistance;
private ListField _listField;
private EditField _status;
private StringBuffer _messageString;
private String _oldmessageString;
private LocationProvider _locationProvider;
/* Instantiate the new application object and enter the event loop.
* @param args unsupported. no args are supported for this application
*/
public static void main(String[] args) {
new GPSDemo().enterEventDispatcher();
}
// Constructors. ------------------------------------------------------------public GPSDemo() {
// Used by waypoints; represents the time since the last waypoint.
_startTime = System.currentTimeMillis();
_altitudes=new float[GRADE_INTERVAL];
_horizontalDistances=new float[GRADE_INTERVAL];
_messageString= new StringBuffer();
MainScreen screen = new MainScreen();
screen.setTitle(new LabelField(_resources.getString(GPSDEMO_TITLE),
LabelField.USE_ALL_WIDTH));
155
BlackBerry Application Developer Guide Volume 1: Fundamentals
_status = new EditField();
screen.add(_status);
screen.addKeyListener(this);
screen.addTrackwheelListener(this);
// Start the GPS thread that listens for updates.
startLocationUpdate();
// Render our screen.
pushScreen(screen);
}
/* Update the GUI with the data just received.
*/
private void updateLocationScreen(final String msg) {
invokeLater(new Runnable() {
public void run() {
_status.setText(msg);
}
});
}
// Menu items. --------------------------------------------------------------// Cache the markwaypoint menu item for reuse.
private MenuItem _markWayPoint = new MenuItem(_resources,
GPSDEMO_MENUITEM_MARKWAYPOINT, 110, 10) {
public void run() {
GPSDemo.this.markPoint();
}
};
// Cache the view waypoints menu item for reuse.
private MenuItem _viewWayPoints = new MenuItem(_resources,
GPSDEMO_MENUITEM_VIEWWAYPOINTS, 110, 10) {
public void run() {
GPSDemo.this.viewPreviousPoints();
}
};
// Cache the close menu item for reuse.
private MenuItem _close = new MenuItem(_resources, GPSDEMO_MENUITEM_CLOSE, 110, 10) {
public void run() {
System.exit(0);
156
11: Using location information
}
};
protected void makeMenu(Menu menu, int instance) {
menu.add( _markWayPoint );
menu.add( _viewWayPoints );
menu.add( _close );
menu.addSeparator();
super.makeMenu(menu, instance);
}
/* Invokes the Location API with the default criteria.
*/
private void startLocationUpdate() {
try {
_locationProvider = LocationProvider.getInstance(null);
if ( _locationProvider == null ) {
Dialog.alert("GPS is not supported on this platform, exiting...");
System.exit(0);
}
// A single listener can be associated with a provider,
// and unsetting it involves the same call but with null,
// so there is no need to cache the listener instance.
// Request an update every second.
_locationProvider.setLocationListener(new LocationListenerImpl(), _interval, 1,
1);
} catch (LocationException le) {
System.err.println("Failed to add a location listener. Exiting...");
System.err.println(le);
System.exit(0);
}
}
/* Marks a point in the persistent store. Calculations are based on
* all data collected since the previous way point, or from the start
* of the application if no previous waypoints exist.
*/
private void markPoint() {
long current = System.currentTimeMillis();
157
BlackBerry Application Developer Guide Volume 1: Fundamentals
WayPoint p= new WayPoint(_startTime, current, _wayHorizontalDistance,
_verticalDistance);
addWayPoint(p);
// Reset the waypoint variables.
_startTime = current;
_wayHorizontalDistance = 0;
_verticalDistance = 0;
}
// View the saved waypoints.
private void viewPreviousPoints() {
PointScreen pointScreen = new PointScreen(_previousPoints, _resources);
pushScreen(pointScreen);
}
// Called by the framework when this application is losing focus.
protected void onExit() {
if ( _locationProvider != null ) {
_locationProvider.reset();
_locationProvider.setLocationListener(null, -1, -1, -1);
}
}
/* Adds a new WayPoint and commits the set of saved waypoints
* to flash memory.
* @param p The point to add.
*/
/*package*/ synchronized static void addWayPoint(WayPoint p) {
_previousPoints.addElement(p);
commit();
}
/* Removes a waypoint from the set of saved points and
* commits the modifed set to flash memory.
* @param p the point to remove
*/
/*package*/ synchronized static void removeWayPoint(WayPoint p) {
_previousPoints.removeElement(p);
commit();
}
158
11: Using location information
// Commit the waypoint set to flash memory.
private static void commit() {
_store.setContents(_previousPoints);
_store.commit();
}
/* Implementation of the LocationListener interface.
*/
private class LocationListenerImpl implements LocationListener {
// Members. -------------------------------------------------------------private int captureCount;
// Methods. -------------------------------------------------------------public void locationUpdated(LocationProvider provider, Location location) {
if(location.isValid()) {
float heading = location.getCourse();
double longitude = location.getQualifiedCoordinates().getLongitude();
double latitude = location.getQualifiedCoordinates().getLatitude();
float altitude = location.getQualifiedCoordinates().getAltitude();
float speed = location.getSpeed();
// Horizontal distance.
float horizontalDistance = speed * _interval;
_horizontalDistance += horizontalDistance;
// Horizontal distance for this waypoint.
_wayHorizontalDistance += horizontalDistance;
// Distance over the current interval.
float totalDist = 0;
// Moving average grade.
for(int i = 0; i < GRADE_INTERVAL - 1; ++i) {
_altitudes[i] = _altitudes[i+1];
_horizontalDistances[i] = _horizontalDistances[i+1];
totalDist = totalDist + _horizontalDistances[i];
}
_altitudes[GRADE_INTERVAL-1] = altitude;
_horizontalDistances[GRADE_INTERVAL-1] = speed*_interval;
totalDist= totalDist + _horizontalDistances[GRADE_INTERVAL-1];
float grade = (_altitudes[4] - _altitudes[0]) * 100/totalDist;
// Running total of the vertical distance gain.
float altGain = _altitudes[GRADE_INTERVAL-1] - _altitudes[GRADE_INTERVAL-2];
if (altGain > 0) _verticalDistance = _verticalDistance + altGain;
159
BlackBerry Application Developer Guide Volume 1: Fundamentals
captureCount += _interval;
// If we’re mod zero then it’s time to record this data.
captureCount %= CAPTURE_INTERVAL;
// Information to display on the device.
StringBuffer sb = new StringBuffer();
sb.append("Longitude: ");
sb.append(longitude);
sb.append("\n");
sb.append("Latitude: ");
sb.append(latitude);
sb.append("\n");
sb.append("Altitude: ");
sb.append(altitude);
sb.append(" m");
sb.append("\n");
sb.append("Heading relative to true north: ");
sb.append(heading);
sb.append("\n");
sb.append("Speed : ");
sb.append(speed);
sb.append(" m/s");
sb.append("\n");
sb.append("Grade : ");
if(Float.isNaN(grade))sb.append(" Not available");
else sb.append(grade+" %");
GPSDemo.this.updateLocationScreen(sb.toString());
}
}
public void providerStateChanged(LocationProvider provider, int newState) {
// No operation defined.
}
}
/* WayPoint describes a way point, a marker on a journey or point of interest.
* WayPoints are persistable.
* package
*/
static class WayPoint implements Persistable {
public long _startTime;
public long _endTime;
public float _distance;
160
11: Using location information
public float _verticalDistance;
public WayPoint(long startTime,long endTime,float distance,float verticalDistance){
_startTime=startTime;
_endTime=endTime;
_distance=distance;
_verticalDistance=verticalDistance;
}
}
}
/*
* PointScreen.java
*
* Copyright (C) 2005 Research In Motion Limited.
*/
package com.rim.samples.docs.gpsdemo;
import net.rim.device.api.ui.*;
import net.rim.device.api.ui.component.*;
import net.rim.device.api.ui.container.*;
import com.rim.samples.docs.baseapp.*;
import net.rim.device.api.io.*;
import net.rim.device.api.system.*;
import com.rim.samples.docs.resource.*;
import net.rim.device.api.i18n.*;
import javax.microedition.io.*;
import java.util.*;
import java.io.*;
import javax.microedition.location.*;
import com.rim.samples.docs.gpsdemo.GPSDemo.WayPoint;
import com.rim.samples.docs.resource.*;
/*
* PointScreen is a screen derivative that renders the saved WayPoints.
*/
public class PointScreen extends MainScreen implements ListFieldCallback,
GPSDemoResResource {
private Vector _points;
private ListField _listField;
private ResourceBundle _resources;
161
BlackBerry Application Developer Guide Volume 1: Fundamentals
public PointScreen(Vector points, ResourceBundle resources) {
_resources = resources;
LabelField title = new LabelField(resources.getString(GPSDEMO_POINTSCREEN_TITLE),
LabelField.ELLIPSIS | LabelField.USE_ALL_WIDTH);
setTitle(title);
_points = points;
_listField = new ListField();
_listField.setCallback(this);
add(_listField);
reloadWayPointList();
}
private void reloadWayPointList() {
// Refreshes wayPoint list on screen.
_listField.setSize(_points.size());
}
// ListFieldCallback methods -----------------------------------------------public void drawListRow(ListField listField, Graphics graphics, int index,
int y, int width) {
if ( listField == _listField && index < _points.size()) {
String name = _resources.getString(GSPDEMO_POINTSCREEN_LISTFIELD_ROWPREFIX) +
index;
graphics.drawText(name, 0, y, 0, width);
}
}
public Object get(ListField listField, int index) {
if ( listField == _listField ) {
// If index is out of bounds an exception is thrown,
// but that’s the desired behavior in this case.
return _points.elementAt(index);
}
return null;
}
public int getPreferredWidth(ListField listField) {
// Use the width of the current LCD.
return Graphics.getScreenWidth();
}
public int indexOfList(ListField listField, String prefix, int start) {
162
11: Using location information
return -1; // Not implemented.
}
// Menu items. --------------------------------------------------------------private class ViewPointAction extends MenuItem {
private int _index;
public ViewPointAction( int index ) {
super(PointScreen.this._resources.getString(GPSDEMO_POINTSCREEN_MENUITEM_VIEW),
100000, 10);
_index = index;
}
public void run() {
ViewScreen screen = new ViewScreen( (WayPoint)_points.elementAt(_index),
_index, _resources );
UiApplication.getUiApplication().pushModalScreen( screen );
}
}
private class DeletePointAction extends MenuItem {
private int _index;
public DeletePointAction( int index ) {
super(PointScreen.this._resources.getString(GPSDEMO_POINTSCREEN_MENUITEM_DELETE), 100000,
10);
_index = index;
}
public void run() {
GPSDemo.removeWayPoint((WayPoint)_points.elementAt(_index));
}
}
protected void makeMenu(Menu menu, int instance) {
if( _points.size() > 0 ) {
ViewPointAction viewPointAction = new ViewPointAction(
_listField.getSelectedIndex() );
menu.add( viewPointAction );
menu.addSeparator();
DeletePointAction deletePointAction = new DeletePointAction(
_listField.getSelectedIndex() );
menu.add( deletePointAction );
}
163
BlackBerry Application Developer Guide Volume 1: Fundamentals
super.makeMenu(menu, instance);
}
/**
* Renders a particular Waypoint.
*/
private static class ViewScreen extends MainScreen {
private ResourceBundle _resources;
private MenuItem _cancel;
public ViewScreen(WayPoint point, int count, ResourceBundle resources) {
super();
_resources = resources;
LabelField title = new LabelField(resources.getString(GPSDEMO_VIEWSCREEN_TITLE)
+ count,
LabelField.ELLIPSIS | LabelField.USE_ALL_WIDTH);
setTitle(title);
Date date = new Date(point._startTime);
String startTime = date.toString();
date = new Date(point._endTime);
String endTime = date.toString();
float avgSpeed = point._distance/(point._endTime - point._startTime);
add(new BasicEditField(resources.getString(GPSDEMO_VIEWSCREEN_STARTFIELD),
startTime, 30, Field.READONLY));
add(new BasicEditField(resources.getString(GPSDEMO_VIEWSCREEN_ENDFIELD),
endTime, 30, Field.READONLY));
add(new
BasicEditField(resources.getString(GPSDEMO_VIEWSCREEN_HORIZONTALDISTANCEFIELD),
Float.toString(point._distance), 30, Field.READONLY));
add(new
BasicEditField(resources.getString(GPSDEMO_VIEWSCREEN_VERTICALDISTANCEFIELD),
Float.toString(point._verticalDistance), 30, Field.READONLY));
add(new BasicEditField(resources.getString(GPSDEMO_VIEWSCREEN_AVESPEEDFIELD),
Float.toString(avgSpeed), 30, Field.READONLY));
}
private class CancelMenuItem extends MenuItem {
public CancelMenuItem() {
// Reuse an identical resource below.
super(ViewScreen.this._resources, GPSDEMO_OPTIONSSCREEN_MENUITEM_CANCEL,
300000, 10);
164
11: Using location information
}
public void run() {
UiApplication uiapp = UiApplication.getUiApplication();
uiapp.popScreen(ViewScreen.this);
}
};
protected void makeMenu( Menu menu, int instance ) {
if ( _cancel == null ) _cancel = new CancelMenuItem(); // Create on demand.
menu.add(_cancel);
super.makeMenu(menu, instance);
}
}
}
165
12
Packaging and deployment
Deploying applications using the BlackBerry Desktop Software
Deploying applications wirelessly
Deploying applications using the BlackBerry Desktop
Software
The Application Loader tool, which is part of the BlackBerry Desktop Software, uses an application loader (.alx) file
to load new applications onto the BlackBerry device.
Create an application loader (.alx) file for each application, and then distribute the .alx and .cod files to users. See
the Application Loader Online Help for more information.
Create an application loader file
1. In the BlackBerry Integrated Development Environment (BlackBerry IDE), select a project.
2. On the Project menu, click Generate .alx File.
Distribute this .alx file with the .cod files for the application to users. When users connect their BlackBerry devices
to their computers, they can use the BlackBerry Desktop Software to load the application onto their BlackBerry
devices.
Note: By default, the .cod files for the application must exist in the same folder as the .alx file. If you change the location of .cod files
relative to the .alx file, edit the .alx file and add the <directory> element to specify the file location. See "Appendix: Format of .alx
files" on page 183 for more information.
Deploying applications wirelessly
The handheld software enables users to download applications wirelessly using the BlackBerry Browser. Users can
download both standard MIDlets and BlackBerry applications. For users to download the application wirelessly,
you must provide an application descriptor (.jad) with the appropriate parameters, and the .cod or .jar files for the
application. In the BlackBerry Browser, the user selects the .jad file to download the application.
System administrators can set application control policies to control the use of third-party applications. See
“Application control” on page 16 for more information.
Make BlackBerry or MIDlet applications available for users to download wirelessly in one of the following ways:
• Use BlackBerry® MDS Services which converts .jar files to .cod files.
• Use the BlackBerry JDE, which generates .cod files, to build your projects.
12: Packaging and deployment
Deploy .jar files
The BlackBerry® MDS Data Optimization Service feature of the BlackBerry Enterprise Server provides a built-in
transcoder to convert .jar files to .cod files, which enables users to download standard MIDlets. For example,
corporate administrators can maintain a list of approved MIDlets on an Intranet site. Users can browse to the web
page and select .jad files for applications to download. The BlackBerry Enterprise Server converts .jar files to .cod
files before sending them to the BlackBerry device.
Note: The web server must set the MIME type for both .cod files and .jad files. For .cod files, the MIME type is application/
vnd.rim.cod. For .jad files, the MIME type is text/vnd.sun.j2me.app-descriptor. For .jar files, the MIME type is
application/java-archive.
The following versions of the BlackBerry Enterprise Server provide the transcoder to convert .jar files to .cod files:
• BlackBerry Enterprise Server version 3.6 or later for Microsoft Exchange
• BlackBerry Enterprise Server version 2.2 or later for IBM Lotus Domino
Note: Users can only download .jar files if they access the network using the BlackBerry Enterprise Server with MDS Services enabled.
MDS Services converts .jar files to the .cod file format that the BlackBerry device requires. If users access the network using a WAP
gateway, users can only download .cod files.
MIDlet application descriptor properties
Application descriptor files have an extension of .jad. A standard MIDlet .jad file contains the following predefined
attributes, and might contain additional attributes defined by the application.
Required MIDlet attribute
Description
MIDlet-Jar-Size
number of bytes in the .jar file
MIDlet-Jar-URL
URL from which the .jar file can be loaded
MIDlet-Name
name of the MIDlet suite
MIDlet-Vendor
organization that provides the MIDlet suite
MIDlet-Version
version of the MIDlet suite, formatted as <major>.<minor>.<micro>
Optional MIDlet attribute
Description
MIDlet-Data-Size
minimum number of bytes of persistent data required by the MIDlet suite; the default is zero
MIDlet-Delete-Confirm
text message that appears when prompting the user to confirm deletion of the MIDlet suite
MIDlet-Description
description of the MIDlet suite
MIDlet-Icon
name of the .png image file within the .jar file used to represent the MIDlet suite
MIDlet-Info-URL
URL for further information describing the MIDlet suite
MIDlet-Install-Notify
URL to which a POST request is sent to confirm successful installation of the MIDlet suite
Deploy .cod files
When you build the project, the BlackBerry JDE creates the required BlackBerry application descriptor (.jad) file.
You can also use the BlackBerry JDE to convert MIDlet .jar files to the .cod file format.
167
BlackBerry Application Developer Guide Volume 1: Fundamentals
Make the .cod and .jad files available on a web server for users to download. By making .cod files available, you
can deploy applications to users who do not access the network using a BlackBerry Enterprise Server.
Note: The web server must set the MIME type for both .cod files and .jad files. For .cod files, the MIME type is
application/vnd.rim.cod. For .jad files, the MIME type is text/vnd.sun.j2me.app-descriptor. For .jar files, the MIME
type is application/java-archive.
BlackBerry application descriptor properties
In addition to the MIDlet application properties, the following attributes apply to BlackBerry application .jad files.
Required RIM attribute
Description
RIM-COD-Creation-Time
creation time of the .cod file
RIM-COD-Module-Dependencies
list of modules that the .cod file requires
RIM-COD-Module-Name
name of the module contained in the .cod file
RIM-COD-SHA1
SHA1 hash of the .cod file
RIM-COD-Size
size (in bytes) of the .cod file
RIM-COD-URL
URL from which the .cod file can be loaded
Optional RIM attribute
Description
RIM-Library-Flags
reserved for use by RIM
RIM-MIDlet-Flags
reserved for use by RIM
RIM-MIDlet-NameResourceBundle
name of the resource bundle that the application depends on
RIM-MIDlet-Position
suggested position of the application icon on the Home screen
Note: This position might not be the actual position of the application icon on the Home screen.
The BlackBerry JDE enables you to create a dual-purpose .jad file to support the downloading of MIDlets onto
BlackBerry devices and other wireless devices. To do this, create a .jad file that contains both the RIM-COD-URL
and RIM-COD-Size attributes and the MIDlet-Jar-URL and MIDlet-Jar-Size attributes. On BlackBerry devices,
you download the .cod files; on other devices, you download the .jar files.
Set .cod file dependencies
The application descriptor (.jad) contains a RIM-COD-Module-Dependencies attribute that specifies modules
required for the application, but not provided with it. If any of the required modules are not present, the
BlackBerry Browser will prevent the wireless installation of the application and will list the missing modules for
the user. RIM-COD-Module-Dependencies attribute enables a user to avoid downloading an application that will
not run.
The RIM-COD-Module-Dependencies attribute takes a comma-separated module name list as a parameter. For
example, an application requiring the RIM XML library might use the following in the application descriptor:
RIM-COD-Module-Dependencies: net_rim_cldc, net_rim_xml
168
12: Packaging and deployment
Deploy sibling .cod files
The BlackBerry Java Development Environment (BlackBerry JDE) creates a single .cod file and .jad file for an
application. If an application contains more than 64 kilobytes of byte code or resource data, the BlackBerry IDE
creates a .cod file that contains sibling .cod files. Only the BlackBerry Browser supports wireless installation of a
.cod file that contains sibling .cod files.
Note: If the .cod file requires signing, update the .jad file to reflect the size of the signed .cod file. See the BlackBerry
Integrated Development Environment Help for more information on code signing.
Determine if a .cod file contains sibling .cod files
1. Extract the contents of the .cod file.
Any .cod files within the original .cod file are the sibling files.
Using MDS Services
To use the BlackBerry Browser to deploy an application onto a device that is connected to version 3.6.4 or greater
of a BlackBerry Enterprise Server with BlackBerry MDS Services, you need to place the .cod file and .jad file onto a
web server. To deploy an application to a BlackBerry device, both the .jad file and .cod file must be placed on the
webserver. The MDS services will work with the browser to download each sibling .cod file one at a time.
The BlackBerry browser first loads the .jad file. The MDS Provisioning Service of MDS Services downloads the .cod
file, extracts a sibling .cod file, and sends it to the BlackBerry device. The MDS Provisioning Service repeats the
process for each sibling .cod file in the original .cod file.
Using the BlackBerry Internet Services or the WAP browser
To use the BlackBerry Browser to deploy an application onto a device that is not using a BlackBerry Enterprise
Server, modify the .jad file to list all each sibling file separately. You must extract each sibling .cod file from the
original .cod file and place each sibling .cod file onto a web server. The Blackberry browser will download each
sibling .cod file one at a time in the order you listed them in the .jad file.
Note: To avoid overriding the original .cod file, extract the sibling .cod files into a different directory than the directory that
the original file is in.
To extract sibling .cod files, perform the following actions:
1. Unzip the original .cod file and extract the sibling .cod files.
2. Place each sibling .cod file on a web server.
3. In the .jad file, list the sibling .cod files separately. For each sibling file, create RIM-COD-URL-<#>, and RIMCOD-Size-<#> parameters.
• RIM-COD-URL-<#>: Create a RIM-COD-URL-<#> parameter for each sibling .cod file, and place the name
of the sibling file to the right of this parameter. # is a number that starts at 1and increases by 1 for each
sibling file. Give each sibling .cod files the same name as the original .cod file, followed by -<#>.
169
BlackBerry Application Developer Guide Volume 1: Fundamentals
• RIM-COD-Size-<#>: Create a RIM-COD-Size-<#> parameter for each sibling .cod file, and place the size
of the sibling file to the right of this parameter. # is the same number that is appended to the sibling file’s
name. Place the RIM-COD-Size-<#> parameter immediately below the RIM-COD=URL-<#> parameter.
In the following example, there are two sibling files. The developer names the sibling files myApp-1.cod and
myApp-2.cod, after the original .cod file myAPP. The developer appends the ‘.cod’ file extension to each
sibling file name. The developer creates a RIM-COD-Size-<#> parameter for each sibling file.
Manifest-Version: 1.0
MIDlet-Version: 1.0.0
MIDlet-1: ,,
RIM-COD-Module-Dependencies: net_rim_cldc
MicroEdition-Configuration: CLDC-1.0
RIM-COD-Module-Name: MyApp
MIDlet-Name: My Application
RIM-COD-URL: myApp.cod
RIM-COD-Size: 55000
RIM-COD-URL-1: myApp-1.cod
RIM-COD-Size-1: 50000
RIM-COD-URL-2: myApp-2.cod
RIM-COD-Size-2: 25000
MicroEdition-Profile: MIDP-1.0
Note: Use the following naming convention for sibling .cod files: <name of original .cod file>-<sequential
number>. You must assign a number to each sibling .cod file. The number starts at one and increases sequentially by one.
4. On the device you want to deploy the application on, from the BlackBerry Browser, download each individual
sibling file.
170
13
Testing and debugging
Test applications
Using the debug tools
Test applications
Test applications by running them in the BlackBerry device simulator or on a connected BlackBerry device.
1. In the BlackBerry Integrated Development Environment (BlackBerry IDE), on the Debug menu, click Go.
2. Deploy the application to the device. See “Deploying applications using the BlackBerry Desktop Software” on
page 166 for more information
3. Use the application in the simulator or on a BlackBerry device.
4. In the BlackBerry IDE, on the Debug menu, click Break Now.
To retrieve detailed information, use the debug tools on the View menu. See "Using the debug tools" on
page 179 for more information.
5. Perform any of the following actions:
Action
Procedure
Resume running applications
On the Debug menu, click Continue.
Finish Debugging
On the Debug menu, click Stop Debugging.
Test applications using the device simulator
In the BlackBerry IDE, the device simulator starts automatically when you run applications.
With access to a BlackBerry Enterprise Server, the simulator is designed to will imitate every aspect of running an
application on a BlackBerry device, including email traffic, browser traffic, HTTP/TCP connections, and push
functionality.
Without access to a BlackBerry Enterprise Server, you need the BlackBerry MDS simulator (simulator) to simulate
browser traffic, http/tcp connections to third party applications, and push functionality. See “Test HTTP network
connections” on page 176 for more information. You need a BlackBerry email server simulator (email simulator)
for sending and receiving messages between a BlackBerry device simulator and a computer email program. See
“Use the email server simulator” on page 173 for more information.
Action
Mouse Procedure
Keyboard Procedure
Roll the trackwheel
Roll the mouse wheel.
Press the UP ARROW and DOWN ARROW keys on your keyboard.
Click the trackwheel
Click the mouse wheel button.
Press ENTER.
BlackBerry Application Developer Guide Volume 1: Fundamentals
Action
Mouse Procedure
Keyboard Procedure
Run an application
Select the appropriate icon and click the
mouse wheel button.
Press ENTER.
Press keys
_
Press the keys on your keyboard.
Assign the Escape button 1. In the device simulator, on the Edit menu,
to the trackwheel.
click Map Cursor Key To Escape.
2. Perform one of the following actions:
• To assign Left to the trackwheel,
select either Right.
• To assign Right to the trackwheel,
select either Left.
Test the BlackBerry Enterpise Server API and IT Policies
Note: The device simulator requires version 4.0 or higher of the BlackBerry Enterprise Server.
The device simulator can connect to an account on the BlackBerry Enterprise Server. If you have access to a
BlackBerry Enterprise Server, you can simulate connecting a BlackBerry device to a BlackBerry Enterprise Server.
Use this option to simulate the BlackBerry Enterprise Server Extension API and applied IT policies. This option
requires knowledge of BlackBerry Enterprise Server administration, and introduces network dependency to testing.
You do not require a BlackBerry MDS Simulator or an email server simulator. You will then be able to simulate use
of the BES Extension API, applied IT policies, email and browser messaging, HTTP/TCP connections, and push
functionality.
1. Start the device simulator.
2. On the Home screen, click “Turn Wireless Off”.
3. From the Microsoft Windows taskbar, click Start > Programs > BlackBerry > Desktop Manager.
4. On the simulator menu, perform one of the following actions:
Action
Procedure
Simulate a USB connection
Click Simulate > USB Connected.
Simulate a Serial connection
Click Simulate > Serial Connected.
5. Click YES.
6. Complete the instructions to generate a new encryption key.
7. In the Initial Plug-in: Verifying Applications dialog box, click cancel.
When the initial synchronization with the computer is complete, the enterprise activation starts.
172
13: Testing and debugging
Use the email server simulator
The email server simulator enables you to send and receive messages between the device simulator and either a a
computer email program, such as Microsoft® Outlook® Express, or a mail server such as POP3 and SMTP. Use the
email server simulator instead of connecting a device simulator to a BlackBerry Enterprise Server to test
applications locally on a single computer.
1. On the taskbar, click Start > Programs > Research In Motion > BlackBerry JDE 4.1.0 > ESS.
2. Perform one of the following actions:
• Standalone mode: Stores messages on the local file system and communicate directly with a computer
email program. You do not require a POP3 or SMTP server.
• Open the computer email program
• Set the POP3 server to localhost on port 110
• Set the SMTP server to localhost on port 25.
• Connected mode: The email simulator polls the user POP3 mail server for incoming messages, and uses
the user SMTP server to send messages. The email simulator requires valid POP3 and SMTP servers.
3. To remove email simulator messages from the local file system, click Clean FS
• In the Outgoing field, type the host name of the SMTP server that your account uses.
• In the Incoming field, type the host name of the POP3 server that your account uses.
• In the User name field, type the user name to use to connect to your account.
• In the Password field, type the password to use to connect to your messaging account.
• In the Poll inbox field, specify, in seconds, how often the email simulator checks your Inbox for new
messages.
• In the Name field, type a Name to display in outgoing messages from the device simulator.
• In the Email field, type the message account address to display in outgoing messages from the
BlackBerry device simulator.
• In the PIN field, type the personal identification number (PIN) that device simulator uses (the default PIN
is 0x2100000A).
4. Click Launch.
If you change parameter values in the ESS window, a dialog box prompts you to save your changes.
5. Check the command prompt window for startup information, including any log in errors.
When the email simulator starts, use the message list in the device simulator to send and receive messages
with a message account.
Note: If you start the device simulator from a command prompt, specify the /rport=0x4d4e parameter to communicate with the
email server simulator.
Test an application that uses synchronization in the simulator
1. Exit the BlackBerry Desktop Software.
173
BlackBerry Application Developer Guide Volume 1: Fundamentals
2. Connect a null modem cable between COM port 1 and COM port 2 on your computer.
3. In the BlackBerry IDE, on the Edit menu, click Preferences.
4. In the Preferences window, click the Basic tab.
5. Select the Set serial port for device(s) option. Type 1.
6. Click OK.
7. Build and run the application in the BlackBerry IDE.
8. After the device simulator starts, start the BlackBerry Desktop Software.
9. In the BlackBerry Desktop Manager window, on the Options menu, click Connection Settings.
10. Click Detect to detect the simulator.
Note: If the BlackBerry Desktop Software does not detect the simulator, restart your computer. Repeat steps 7 through 10.
Test applications using a connected BlackBerry device
When you connect a BlackBerry device to a computer, run applications on the BlackBerry device and use the
BlackBerry Integrated Development Environment (BlackBerry IDE) debug tools to perform testing and
optimization.
Note: To attach the BlackBerry IDE to a BlackBerry device with a serial port connection, install the Java Communications API version
2.0. which is available at http://java.sun.com/products/javacomm/. This API is not required if the BlackBerry device is
connected to a USB port.
Install .debug files
To debug applications using a BlackBerry device, the .debug files in the BlackBerry JDE must match the software
version number of the BlackBerry device.
1. Download the .debug files for your BlackBerry device software version number from the BlackBerry Developer
Zone at
http://blackberry.com/developers
2. In the BlackBerry IDE, on the Edit menu, click Preferences.
3. Click the Debug tab.
4. Click the Other tab.
5. In the Handheld debug file location field, type the location of the downloaded .debug files.
174
13: Testing and debugging
Load an application for testing
Note: Before loading an application for testing, back up your BlackBerry device application information.
The JavaLoader.exe tool enables you to add or update applications on a BlackBerry device using a command
prompt. Use this tool for development and testing purposes only. For production applications, use the BlackBerry
Desktop Software.
Note: You must load applications with dependencies in the correct order. If project A is dependent on project B, load the project B
.cod file before loading project A.
1. Exit the BlackBerry Desktop Software.
2. Connect the BlackBerry device to the computer.
3. At the command prompt, navigate to the bin folder in the BlackBerry Java Development Environment
(BlackBerry JDE) installation folder.
4. Type the following command:
JavaLoader [-usb] [-p<port>] [-b<bps>] [-w<password>] load <files>
Option
Description
port
COM port that the BlackBerry device connects to (default is 1), or the BlackBerry device PIN if the BlackBerry device uses
a USB port connection (the -usb option must also be specified)
bps
bit rate speed to the serial port (default is 115200)
password
password for your BlackBerry device, if you have set one
files
one or more .cod file names, separated by a space, to load onto the BlackBerry device
Remove applications from the BlackBerry device
>
At the command prompt, type the following command, where the -f option removes the application even if it
is in use:
JavaLoader [-usb] [-p<port>] [-b<bps>] [-w<password>] erase [-f] <files>
Connect the BlackBerry IDE debugger to a BlackBerry device
1. To connect the BlackBerry IDE debugger to a BlackBerry device that uses a USB port connection, start
BBDevMgr.exe. The installation of the BlackBerry Desktop Software version 3.5.1 or later will install the
BBDevMgr.exe tool.
C:\Program Files\Common Files\Research In Motion\USB Drivers.
2. Perform one of the following actions:
Action
Procedure
Connect the BlackBerry IDE debugger to a BlackBerry
device that uses a serial port connection.
Click Attach to > Handheld > COM n, where n is the serial port that your
BlackBerry device connects to.
Connect the BlackBerry IDE debugger to a BlackBerry
device that uses a USB port connection.
Click Attach to > Handheld > USB(PIN), where PIN is the PIN of a
connected BlackBerry device.
175
BlackBerry Application Developer Guide Volume 1: Fundamentals
• For a BlackBerry device that is connected to a serial port, click Attach to > Handheld > COM n, where n
is the serial port to which your BlackBerry device is connected.
• For a BlackBerry device that is connected to a USB port, click Attach to > Handheld > USB (PIN), where
PIN is the PIN of a connected BlackBerry device.
Test HTTP network connections
To test applications that require an HTTP network connection, use the BlackBerry MDS simulator, which is a
component of the BlackBerry JDE.
>
On the taskbar, click Start > Programs > Research In Motion > BlackBerry JDE 4.1.0 > MDS.
Note: To start MDS services simulator when the device simulator starts, in the BlackBerry IDE, on the Edit menu, click Preferences.
Click the Simulator tab. Select the Launch Mobile Data Service (MDS) with simulator option.
Use a WAP gateway
You can configure an HTTP connection using a WAP gateway that your service provider hosts. BlackBerry devices
support WAP version 1.1 features.
Note: WAP service is available on selected wireless networks only. Before you start development, contact the service provider for
information on how to connect to the WAP gateway.
>
To set up an HTTP connection using WAP, include the WAPGatewayIP and WapGatewayAPN parameters in
at the end of the URL.
Connector.open()
Connector.open("http://host;WAPGatewayIP=127.0.0.1; WAPGatewayAPN=rim.net.gprs");
Separate WAP parameters by a semicolon (;). Verify that WAP parameters do not have spaces.
Parameter
Description
Default
WapGatewayIP
IP address of the gateway
—
WapGatewayAPN
access point name (for GPRS networks only); for testing purposes, use
rim.net.gprs
—
WapGatewayPort
a gateway port value: If you specify port 9203, use WTLS (unless
WapEnableWTLSis set to false).
9201
IP address of the source
127.0.0.1
source port value
8205
TunnelAuthUsername
user name for APN session for PAP or CHAP authentication
none
TunnelAuthPassword
password for APN session for PAP or CHAP authentication
none
WapEnableWTLS
turns on or off WTLS (if you do not specify this parameter, connections to
port 9203 will use WTLS); the BlackBerry device supports WTLS Class 1
(encryption only, no authentication) and Class 2 (encryption and server
authentication)
none
WAP_GATEWAY_PORT_DEFAULT
WapSourceIP
WAP_SOURCE_IP_DEFAULT
WapSourcePort
WAP_SOURCE_PORT_DEFAULT
176
13: Testing and debugging
Note: In the BlackBerry device simulator, when you test applications that require a WAP connection, add the command line option
/rport=<wap_source_port>, typically /rport=8205. The APN of the simulator is rim.net.gprs.
Add a simulator command-line option
In the BlackBerry IDE, on the Edit menu, click Preferences.
Click the Simulator tab.
Click the Advanced tab.
In the Simulator Command Line field, add the command-line option.
Configure the BlackBerry MDS simulator
1. In a text editor, open the rimpublic.property file (located in the MDS\config folder).
2. Edit the parameters to configure the following features:
• See "Logging level parameters" on page 178 for more information.
• See "HTTP support parameters" on page 178 for more information.
• See "HTTPS support parameters" on page 178 for more information.
• See "Push support parameters" on page 179 for more information.
• See "Internet messaging address-to-PIN mapping" on page 179 for more information.
3. Restart the BlackBerry MDS simulator.
Note: In a production environment, the BlackBerry Enterprise Server system administrator configures the MDS services parameters
using the BlackBerry Manager. Contact your system administrator for more information.
177
BlackBerry Application Developer Guide Volume 1: Fundamentals
Logging level parameters
Parameter
Logging.level
Description
Default
This parameter specifies the type of information that is written to the logs, if logging is 4
enabled.
•
•
•
•
Logging.console.log.level
1: writes only information on events, such as MDS services start or stop
2: writes events and errors
3: writes events, errors, and warnings
4: writes events, errors, warnings, and debugging information
This parameter specifies the type of information that appears in the console, if logging 4
is enabled. See the description for the Logging.level parameter.
HTTP support parameters
Parameter
Description
Default
application.handler.http.logging
This parameter turns on (TRUE) or turns off (FALSE) HTTP
standard logging (HTTP headers only).
TRUE
application.handler.http.logging.verbose
This parameter turns on (TRUE) or turns off (FALSE) HTTP debug FALSE
logging (HTTP data and headers). This parameter should be set to
TRUE only when necessary to debug a specific problem.
application.handler.http.CookieSupport
TRUE
This parameter turns on (TRUE) or turns off (FALSE) cookie
storage. If you select TRUE, BlackBerry® MDS Services manages
cookie storage instead of the BlackBerry device. This reduces the
load on the BlackBerry device significantly.
application.handler.http.
AuthenticationSupport
This parameter turns on (TRUE) or turns off (FALSE) storage of
user authentication information.
application.handler.http.
AuthenticationTimeout
If HTTP authentication is set to TRUE, this parameter determines 3600000
the length of time (in milliseconds) before the authentication
information becomes invalid. This timer resets whenever the user
issues a request that invokes the authentication information for a
particular domain.
application.handler.http.device.connection.
timeout
This parameter sets the length of time (in milliseconds) before a
connection attempt to the BlackBerry device expires if the
BlackBerry device is unreachable.
application.handler.http.server.
connection.timeout
This parameter sets the length of time (in milliseconds) before a 150000
connection attempt to a server expires if the server is unreachable.
TRUE
140000
HTTPS support parameters
Parameter
Description
Default
application.handler.https.logging
This parameter turns on (TRUE) or turns off (FALSE) HTTPS logging for
testing purposes.
TRUE
application.handler.https.
allowUntrustedServer
This parameter enables MDS Services to connect to untrusted servers
(TRUE), or restricts access to trusted servers only (FALSE). A server is
trusted if its certificate is installed on MDS Services host machine. See
"Install a certificate using the keytool" on page 190 for more
information.
FALSE
178
13: Testing and debugging
Push support parameters
Do not change these parameters.
Parameter
Description
Default
WebServer.listen.host
This parameter defines the computer on which the MDS services listens for
HTTP POST requests from push applications.
localhost
WebServer.listen.port
This parameter defines the port on which the MDS services listens for HTTP
POST requests from push applications.
8080
Internet messaging address-to-PIN mapping
In a production environment, the BlackBerry Enterprise Server automatically maps user internet messaging
addresses to the personal identification number (PIN) of their BlackBerry devices. In the BlackBerry JDE, you can
simulate the mapping between internet messaging addresses and PINs.
Note: You only need to configure internet messaging address to PIN mappings if you are testing a push application. See "Creating
client/server push applications" on page 137 for more information.
In the rimpublic.property file, located in the MDS/config subdirectory of your BlackBerry JDE installation, add
or change entries in the [Simulator] section. Entries use the following format:
Simulator.<PIN>=<host>:<port>, <messaging_address>
For example:
Simulator.2100000a=<local machine IP>:81, [email protected]
Change the internet messaging address so that you can test push applications that use actual internet messaging
addresses. Pushed data is sent to the specified BlackBerry device simulator.
The default PIN for the simulator is 2100000a. To change the simulator PIN, set the /rsim option. In the
BlackBerry IDE, on the Edit menu, click Preferences. Click the Simulator tab, and then click the Advanced tab.
In the Simulator Command Line field, change /rsim=0x2100000A .
The port must match the value set in the IPPP.push.listen.tcp.port parameter. The default is 81.
Using the debug tools
Note: This section provides an overview of some of the debug tools that are available in the BlackBerry IDE. See the BlackBerry
Integrated Development Environment Online Help for detailed information on using the BlackBerry IDE.
Analyze code coverage
To display a summary of code that has been run, use the coverage tools. A summary is useful when you design
and run test cases because you can see exactly what has been tested.
1. Set two or more breakpoints in your code.
2. In the BlackBerry IDE, on the View menu, click Coverage.
3. To reset information to 0, in the coverage pane, click Clear.
179
BlackBerry Application Developer Guide Volume 1: Fundamentals
4. Run your application to the next breakpoint.
5. To display the percentage of code that has been run since you clicked Clear, in the coverage pane, click
Refresh.
Use the profiler
Use the BlackBerry IDE profiler tool to optimize your code. The profiler tool displays the percentage of time that is
spent in each code area, up to the current point of execution.
Note: To improve the reliability of results when you run the profiler, exit other Microsoft Windows applications.
Run the profiler
1. At the start of a section of code, press F9 to set a breakpoint.
2. At the end of a section of code, press F9 to set a breakpoint.
3. On the Debug menu, click Go.
4. Use the application in the simulator to run the appropriate code until it reaches the breakpoint.
5. On the View menu, click Profile.
6. In the profile pane, click Options.
7. Select the type of method attribution, a sorting method, and the type of information to profile. See "Set
profile options" on page 181 for more information.
8. Click OK.
9. To remove the profiler data and reset the running time, in the profile pane, click Clear.
10. On the Debug menu, click Go.
11. Use the application in the simulator to run the appropriate code until it reaches the breakpoint.
12. If the profile pane is not visible, on the View menu, click Profile.
13. To retrieve all accumulated profile data, on the profile pane, click Refresh.
14. Click Save to save the contents of the profile pane to a comma separated values (.csv) file.
Profile View
Description
Summary
The Summary view displays general statistics about the system and the garbage collector. It displays the percentage of time
that the Java VM has spent idle, running code, and performing quick and full garbage collection. The Percent column displays
the percentage of total VM running time, including idle and collection time.
Methods
The Methods view displays a list of modules, sorted either by the information that you are profiling or by the number of times
that each item was run.
Source
The Source view displays the source lines of a single method. This enables you to navigate through the methods that call, and
are called by, that method. Click the Back and Forward buttons to follow the history of methods that you have visited in the
Source view.
In this view, the Percent column displays the percentage of total VM running time, not including idle and garbage collection
time.
180
13: Testing and debugging
Set profile options
1. Click the Options tab.
2. From the Method attribution drop-down list, select one of the following options:
• To calculate the amount of time that is spent running bytecode in a method and methods that are
invoked by that method, select Cumulative.
• To calculate the amount of time spent executing bytecode in that method only, select In method only.
The timer stops when a call is made to another method.
3. From the Sort method by drop-down list, select Count to sort methods in the Profile views by the number of
times that the item was run, or select the other option to sort methods according to the data that is being
profiled.
4. From the What to profile drop-down list, select the type of data to profile.
Find memory leaks
Use the memory statistics and objects BlackBerry IDE tools to find and correct memory leaks.
Use the Memory Statistics tool
The Memory Statistics tool displays statistics on the number of objects and bytes that are used for object handles,
RAM, and flash memory.
1. On the View menu, click Memory statistics.
2. Set two or more breakpoints in your code.
3. Run your application to the first breakpoint.
4. Click Refresh to refresh the memory statistics.
5. Click Snapshot to take a snapshot.
6. Run the application to the next breakpoint.
7. Click Refresh.
8. Click Compare to Snapshot.
9. To save the contents of the memory statistics pane to a comma separated values (.csv) file, click Save.
Use the Objects tool
The Objects tool displays all of the objects in memory to help you locate object leaks. Object leaks can cause the
VM to run out of flash memory, which resets the BlackBerry device.
1. In the BlackBerry IDE, on the Debug menu, click Go.
2. On the Debug menu, click Break Now.
3. On the View menu, click Objects.
4. Click GC.
5. Click Snapshot.
181
BlackBerry Application Developer Guide Volume 1: Fundamentals
6. On the Debug menu, click Continue.
7. Complete tasks in the application that should not increase the number of reachable objects; for example,
create a new contact, and then delete it.
8. On the Debug menu, click Break Now.
9. In the objects pane, click GC.
Click Compare to Snapshot. The objects pane displays the number of objects that were deleted and added
since the previous snapshot. If the number of objects that are added is not the same as the number of objects
that are deleted, you might have an object leak. Use the Type and Process filters to view specific objects.
10. To save the contents of the objects pane to a comma separated values (.csv) file, click Save.
182
A
Appendix: Format of .alx files
.alx files
.alx files
The Application Loader tool, which is part of the BlackBerry Desktop Software, uses an application loader (.alx) file
to load new applications onto the BlackBerry device. Use the BlackBerry Integrated Development Environment
(BlackBerry IDE) to generate .alx files for your projects.
The following information is provided only as a supplementary reference. In most cases, you do not need to edit
the .alx files generated in the BlackBerry IDE.
In a text editor, you can edit .alx files that the BlackBerry IDE generates. The .alx file uses an XML format.
Example: Sample .alx file
<loader version="1.0">
<application id="com.rim.samples.device.httpdemo">
<name>Sample Network Application</name>
<description>Retrieves a sample page over HTTP connection.
</description>
<version>1.0</version>
<vendor>Research In Motion</vendor>
<copyright>Copyright 1998-2003 Research In Motion</copyright>
<language langid="0x000c">
<name>Application D'Échantillon</name>
<description>Obtenir une page du réseau
</description>
</language>
<fileset Java="1.0">
<directory>samples/httpdemo</directory>
<files>
net_rim_httpdemo.cod
net_rim_resource.cod
net_rim_resource__en.cod
net_rim_resource__fr.cod
</files>
</fileset>
</application>
</loader>
BlackBerry Application Developer Guide Volume 1: Fundamentals
Nest modules
Create a nested structure in an .alx file to provide optional components for an application. Typically, nested
modules provide optional features that are not applicable to all users. Users can choose whether to install
optional modules.
Nesting creates an implicit dependency for nested modules on the base application. To define an explicit
dependency on another application or library, use the <requires> tag. See "Elements in .alx files" on page 185
for more information.
Example: Sample .alx file for an application with a nested module
<loader version="1.0">
<application id="net.rim.sample.contacts">
<name>Sample Contacts Application</name>
<description>Provides the ability to store a list of contacts.
</description>
<version>1.0</version>
<vendor>Research In Motion</vendor>
<copyright>Copyright 1998-2001 Research In Motion</copyright>
<fileset Java="1.0">
<directory>samples/contacts</directory>
<files>
net_rim_contacts.cod
net_rim_resource.cod
net_rim_resource__en.cod
net_rim_resource__fr.cod
</files>
</fileset>
<application id="net.rim.sample.contacts.mail">
<name>Sample Module for Contacts E-Mail Integration</name>
<description>Provides the ability to access the messaging
application</description>
<version>1.0</version>
<vendor>Research In Motion</vendor>
<copyright>Copyright 1998-2001 Research In Motion</copyright>
<fileset Java="1.0">
<directory>samples/contacts</directory>
<files>
net_rim_contacts_mail.cod
</files>
</fileset>
</application>
</application>
</loader>
Specify a BlackBerry device version
Applications that use APIs only available on particular versions of the handheld software should specify supported
BlackBerry device versions using the _blackberryVersion attribute.
Specify a range using the following rules:
• Square brackets [] indicate inclusive (closed) range matching.
184
A: Appendix: Format of .alx files
• Round brackets () indicate exclusive (open) range matching.
• Missing lower ranges imply 0.
• Missing upper ranges imply infinity.
For example, [4.0,) indicates any version between 4.0 and infinity.
The following example prevents modules from loading on versions of the handheld software earlier than 4.0.
<application id="<application_id>" _blackberryVersion="[4.0,)">
...
</application>
The following example provides alternate modules for different versions of the handheld software.
<application id="<application_id>">
...
<fileset _blackBerryVersion="(,4.0)">
... modules for handheld software versions earlier than 4.0
</fileset>
<fileset _blackBerryVersion="[4.0,)">
... modules for handheld software versions 4.0 and later
</fileset>
</application>
Elements in .alx files
Element
Attributes
Description
loader
version
The loader element contains one or more application elements.
application
id
The version attribute specifies the version of the Application Loader.
The application element contains the elements for a single application.
The application element can also contain additional nested application elements. Nesting
enables you to require that, when an application is loaded, its prerequisite modules also be loaded.
The id attribute specifies a unique identifier for the application. To provide uniqueness, use an ID that
includes your company domain, in reverse. For example, com.rim.samples.docs.helloworld.
library
id
The library element can be used instead of the application tab. It contains the elements for a
single library module. No nested modules are permitted. By default, a library module is hidden so that
it does not appear in the Application Loader.
Typically, use the library element as the target of a <requires> element, so that when a particular
application is loaded onto the BlackBerry device, a required library is also loaded.
Note: This element is supported in BlackBerry Desktop Software version 3.6 or later.
name
—
The name element provides a descriptive name for the application, which appears in the Application
Loader. It does not appear on the BlackBerry device.
description
—
The description element provides a brief description of the application, which appears in the
Application Loader. It does not appear on the BlackBerry device.
version
—
The version element provides the version number of the application, which appears in the Application
Loader. This version number is for information purposes only.
vendor
—
The vendor element provides the name of the company that created the application, which appears in
the Application Loader.
185
BlackBerry Application Developer Guide Volume 1: Fundamentals
Element
Attributes
Description
copyright
—
The copyright element provides copyright information, which appears in the Application Loader.
required
—
The required element enables you to force an application to be loaded. In the Application Loader, the
application is selected for installation, and the user cannot change this. Add the following line:
<required>true</required>.
The required tag should be used by corporate system administrators only; it is not intended for use
by third-party software vendors.
Note: This element is supported in BlackBerry Desktop Software version 3.5 or later.
hidden
—
The hidden element hides a package so that it does not appear to users in the Application Loader. Add
the following line: <hidden>true</hidden>.
Use this element in conjunction with the required element to load the application by default, or set
the requires tag to load this package if another application is loaded.
The hidden tag should be used by corporate system administrators only; it is not intended for use by
third-party software vendors.
Note: This element is supported in BlackBerry Desktop Software version 3.6 or later.
language
langid
The language tag enables you to override the text that appears in the Application Loader when the
Application Loader is running in the language specified by the langid attribute.
To support multiple languages, specify multiple language tags. To specify the name, description,
version, vendor, and copyright tags for each language, nest these tags in the language tag. If
you do not nest a tag, the text appears in the default language.
The langid attribute specifies the Win32 langid code for the language to which this information
applies. For example, some Win32 langid codes are: 0x0009 (English), 0x0007 (German), 0x000a
(Spanish), 0x000c (French).
requires
id
The requires element is an optional element that specifies the id of a package on which this
application depends. This element can appear more than once, if the application depends on more than
one other application.
When an application is loaded onto the user BlackBerry device, all packages that are specified by the
<requires> tag are also loaded.
Note: This element is supported in BlackBerry Desktop Software version 3.6 or later.
fileset
Java
radio
langid
color
The fileset element includes an optional directory element and one or more files elements. It
specifies a set of .cod files, in a single directory, to load onto the BlackBerry device. To load files from
more than one directory, include one or more fileset elements in the .alx file.
The Java attribute specifies the minimum version of the BlackBerry Java VM with which the .cod files
are compatible. The current VM is version 1.0. The Java attribute is required.
The radio attribute enables you to load different applications or modules depending on the network
type of the BlackBerry device. Possible values include Mobitex, DataTAC, GPRS, CDMA, and IDEN. The
radio attribute is optional.
The langid attribute enables you to load different applications or modules depending on the language
support that users add to the BlackBerry device. The value is a Win32 langid code; for example:
0x0009 (English), 0x0007 (German), 0x000a (Spanish), 0x000c (French). The langid attribute is
optional.
The color attribute enables you to load different applications or modules for color or monochrome
displays. The value is a Boolean; true means color display, and false means monochrome.
directory
186
—
The directory element provides the location of a set of files. The directory element is optional. If
you do not specify a directory, the files must be in the same location as the .alx file. The directory is
specified relative to the location of the .alx file.
A: Appendix: Format of .alx files
Element
Attributes
Description
files
—
The files element provides a list of one or more .cod files, in a single directory, to load onto the
BlackBerry device for an application.
187
B
Appendix: MDS services reference
HTTP requests
HTTP responses
HTTPS support
Transcoders
Creating transcoders
Compile and install transcoders
HTTP requests
A client opens a connection and sends an HTTP request message to a server. The server sends a response message,
which usually contains the requested resource.
<method> <resource_path><version>
Header1: value1
Header2: value2
Header3: value3
<optional message>
HTTP request variable
Description
method
Method names indicate an action, such as GET, HEAD, or POST. The commonly used method is GET, which
requests a resource from a server.
resource_path
The path that points to the requested resource is the part of the URL that appears after the host name. This is
also called the Request URL.
version
The version of HTTP that you are running, and is noted as “HTTP/x.x.” The BlackBerry Enterprise Server supports
versions 1.0 and 1.1.
header
The header provides information about the request or about any object that is sent in the message body.
optional message
The HTTP message can contain data. In a request, this is where user-typed data or uploaded files are sent to the
server. When an object accompanies the message, the request usually also includes headers that define its
properties.
HTTP responses
Upon receipt of an HTTP request message, the server sends a response message, which usually contains the
requested resource.
<HTTP version><status_code><reason>
Header1: value1
Header2: value2
Header3: value3
<message>
B: Appendix: MDS services reference
HTTP response variable Description
HTTP_version
This variable indicates the version of HTTP that you are running is noted as “HTTP/x.x.” The BlackBerry Enterprise
Server supports versions 1.0 and 1.1.
status_code
The status code is a numerical value that reflects the results of the initial request of the client. For example, 200
(OK) indicates successful transmission; 404 (Not Found) indicates that the requested URL could not be found.
reason
The reason is a text message that is associated with the status code.
header
The header provides information about the response and about the object that is being sent in the message body.
message
The HTTP message must contain data. In a response, this message provides content that was requested by the client;
the response also includes headers that define its properties.
Note: Applications should check the status code in HTTP response messages. Any code other than 200 (OK) indicates that an error
might have occurred when establishing the HTTP connection.
Push request response status codes
The BlackBerry MDS Connection Service (MDS Connection Service) returns two types of response codes for push
requests:
• Push Access Protocol response codes
• RIM Push response codes
Note: Visit www.wapforum.org for more information on Push Access Protocol response codes.
RIM Push request response codes
RIM Push Request
Response Codes Description
Explanation
200
OK
400
Any other error
The request completed successfully.
403
Access control error or unknown email address or
BlackBerry PIN specified.
The server received the request, but is unable to respond.
503
Server Busy Service Unavailable
At the present time, the server is not able to manage the request
due to temporary overloading or server maintenance.
HTTPS support
To provide additional authentication and security if your application accesses servers on the Internet, set up a
secure HTTP (HTTPS) connection over TLS.
189
BlackBerry Application Developer Guide Volume 1: Fundamentals
Certificate management for HTTPS
When the BlackBerry device requests an HTTPS connection in proxy mode, BlackBerry® MDS services sets up the
SSL connection on behalf of the BlackBerry device. System administrators configure MDS services either to enable
connections to untrusted servers, or to restrict access to trusted servers only. This configuration applies to
connections in proxy mode only; in end-to-end mode, the BlackBerry device sets up the SSL connection.
In the BlackBerry Manager, administrators edit MDS services properties and set TLS and HTTPS options. See the
BlackBerry Enterprise Server Administration Guide for more information.
Note: In the MDS services simulator, permit or deny access to untrusted servers by editing the rimpublic.property file. Set the
application.handler.https.allowUntrustedServer parameter to true or false. See "Configure the BlackBerry MDS
simulator" on page 177 for more information.
MDS Services trusts a server if MDS services contains the certificate.
Install a certificate using the keytool
1. Save the certificate.
2. Copy the certificate file to the C:\Java\j2re1.4.2\lib\security folder on the computer on which the MDS
services reside.
3. To import the certificate into the key store, use the keytool, which is available in the JRE bin folder, such as
C:\Java\j2re1.4.2\bin. For example, type:
keytool -import -file <cert_filename> -keystore cacerts
Visit http://java.sun.com/j2se/1.3/docs/tooldocs/win32/keytool.html for more information about the
keytool.
Transcoders
The BlackBerry MDS services support plug-in Java applications, called transcoders, that perform processing on
data that the BlackBerry device sends and receives.
The MDS services provide the following transcoders by default:
Transcoder name
Description
WML > WMLC
converts Wireless Markup Language (.wml) into a compact format
WMLScript > WMLScriptC
converts MIDlet applications to the BlackBerry format
JAD > COD: XML > WBXML converts text content in Extensible Markup Language (.xml) to the following WAP Binary XML (.wbxml) MIME
type: application/vnd.wap.wbxml.
SVG > PME
190
converts Scalable Vector Graphics (.svg) files to Plazmic Media Engine (.pme) binary file format that BlackBerry
devices support.
B: Appendix: MDS services reference
Transcoder name
Description
Image transcoder
converts the following image file types to Portable Network Graphics format (.png) files:
•
•
•
•
•
•
•
•
•
•
•
Joint Photographic Expert Group (.jpeg)
Graphics Interchange Format (.gif)
Tagged Image File Format (.tiff)
Portable Graymap Format (.pgm)
Portable Pixmap Format (.ppm)
Portable Any Map Format (.pnm): this includes ASCII and binary .pbm, .pgm and .ppm files
Icon Format (.ico)
Wireless Bitmap Format (.wbmp)
Portable Bitmap Format (.pbm)
Wireless Bitmap Format (.wbmp)
Bitmap Format (.bmp)
Note: The image transcoder converts the previous image formats to the following .PNG MIME type: image/vnd.rim.png.
You can also write your own transcoders to perform custom data processing. For example, you might write a
transcoder if your application is exchanging data with a server that is not designed for a BlackBerry device, and
the data that is sent from the server is in an inappropriate format for the BlackBerry device.
A transcoder can change the data format or remove extraneous information to reduce network traffic and to
support a simplified application on the BlackBerry device. For example, you might write a transcoder to convert
HTML content to WML.
Data transcoding process
If you write a server-side application specifically to support a custom application on the BlackBerry device, a
transcoder is not required. You can design the server application to output data in a suitable format.
You can also perform data processing as part of a separate server-side process, before data is sent to the
BlackBerry Enterprise Server.
191
BlackBerry Application Developer Guide Volume 1: Fundamentals
Transcoder API
Main transcoder class
Description
HttpContentTranscoder
This class provides methods to control HTTP request and response contents and properties.
All transcoders must extend this class and implement its abstract methods.
HttpContentTranscoderException
This exception is thrown to indicate that the transcoding process is not successful. The exception
is forwarded to the BlackBerry device as an IOException.
HttpHeader
This class provides methods for manipulating header fields in HTTP requests and responses.
HttpParameter
This class represents an HTTP query parameter. It provides methods for retrieving and setting
parameter names and values.
HttpRequest
This class extends the HttpTransmission class, and represents an HTTP request that contains
headers, parameters, and content.
HttpResponse
This class extends the HttpTransmission class, and represents an HTTP response that contains
headers, parameters, and content.
HttpTransmission
This class provides methods to retrieve and set content, headers, and parameters of HTTP requests
and responses.
See the API Reference for more information.
Create an HTTP content transcoder
To create an HTTP content transcoder with full control over HTTP request and response content, extend the
HttpContentTranscoder class. This transcoder can also modify, add, or remove the HTTP request and response
properties.
The transcoder must be defined in the net.rim.protocol.http.content.transcoder.<name> package,
where <name> is the identifier for the transcoder that is used in the mapping file. Its class name must be
Transcoder.
The transcoder location is either specified in the httpcontenttranscoders.property file or by an application.
Handle HTTP content transcoder exceptions
Any exception that a transcoder throws is sent to the application as an IOException. The associated detailed
message is also copied to the IOException.
Note: Instead of throwing an exception to the HTTP Connection Handler, a transcoder might also send an HTTP response to an
application, indicating that an internal server error has occurred.
Select transcoders
When the BlackBerry device requests content, the MDS services determine if a transcoder is required by comparing
the type of content the client requested with the type of content that the content server responds with. If the
content types are different, the MDS services check the httpcontenttranscoder.property file to determine whether
a transcoder is available to convert the content.
The x-rim-transcode-content header, in the HTTP request sent by the BlackBerry device, specifies the input
format of the content that the the MDS data optimization service converts. The MDS data optimization service
converts the content if the content meets the following conditions:
192
B: Appendix: MDS services reference
• The input format specified by the x-rim-transcode-content header is also specified in the Accept header
of the HTTP request that the MDS services send to the web server
• The web server responds with a content type, or output type that is different from the content type accepted
by the BlackBerry device.
• The httpcontenttranscoder.property file contains a transcoder that can convert the content the web server
sends to the MDS services to a format that the BlackBerry device accepts.
To determine whether a transcoder is required when content is pushed, the MDS services check the content-type
and x-rim-transcode-content headers in the server-side push application. If the content-type and x-rimtranscode-content headers are the same, the MDS data optimization service converts the content specified in
the headers to a format the BlackBerry device can display.
The httpcontenttranscoder.property file maps the input format to a given transcoder. In the following example,
the httpcontenttranscoder.property file converts the .wml input format to either .wbxml or .wmlc.
content-type: text/vnd.wap.wml
x-rim-transcode-content: text/vnd.wap.wml
You can also create custom transcoders that reformat or convert data an application requests. For example, you
could write a transcoder to convert HTML content to WML. See "Creating transcoders" on page 196 for more
information.
HTTP requests
The MDS Services use MIME types to determine whether the format of the content attached to a server HTTP
response matches the format of the content that the BlackBerry device requested.
The MDS services examine the list of available transcoders and extend the Accept header. For example, if a
request accepts a MIME type of WML and an HTML-to-WML transcoder exists, HTML is added to the Accept
header. See "Map transcoders" on page 195 for more information.
In the HTTP request, the application can include two headers to control the type of content that it receives:
• Accept header
• Content-Transcoder header
Header
Description
Accept
In the Accept header of an HTTP request, the application lists the MIME types that it accepts from the
content server. For example, if the application can accept content in WML or XML format, it sends the
following header in its HTTP request:
Accept: text/wml, text/xml
By default, when the Accept header lists more than one MIME type, the MDS services assign preferences
from left to right, where the first MIME type listed is assumed to be preferred.
The application can also assign quality factors to MIME types to indicate preferences. Quality factors range
from 0 (lowest preference) to 1 (highest preference). For example, the following header indicates that
compiled WML (WMLC) is preferred but WML is also accepted.
Accept: text/vnd.wap.wml;q=0.5, application/vnd.wap.wmlc;q=1
193
BlackBerry Application Developer Guide Volume 1: Fundamentals
Header
Description
Content-Transcoder
The Content-Transcoder header is a BlackBerry header that enables the application to specify a particular
transcoder to apply to any content before it is returned to the BlackBerry device. Using the ContentTranscoder header overrides the default process that the MDS services use to select a transcoder.
HTTP responses
The content server produces HTTP responses that include a Content-Type header. The Content-Type header
indicates the MIME type for a particular packet of data. For example, when the content server returns content in
HTML format, the HTTP response includes a Content-Type header with the value text/html.
The MDS Services compare the request that the application makes to the response that the content server
provides. The following sections demonstrate how the MDS services determine when to transcode content:
Response type
Description
No transcoding required
The application sends a request for content in WML format. The request contains the following
header:
Accept: text/vnd.wap.wml
In its response, the content server sends the following header:
Content-Type: text/vnd.wap.wml
Because the type of content that the server returns matches the type the BlackBerry device
requested, the MDS Services do not perform any conversion. It forwards the content to the
BlackBerry device unchanged.
Transcoding required
The application sends a request for content. The request contains the following header:
Accept: text/vnd.wap.wml; q=0.5, application/vnd.wap.wmlc; q=1
This header indicates that the application accepts content in either WML or compiled WML
(WMLC) formats, but the application prefers WMLC.
In its response, the content server sends the following header:
Content-Type: text/vnd.wap.wml
Because the type of content that the server returns does not match the type the BlackBerry
device requested, the MDS Services search for a transcoder that can convert the available
MIME type (WML) to the preferred MIME type (WMLC).
If an appropriate transcoder is not available, the MDS services forward the WML content to
the BlackBerry device unchanged, because the initial request indicated that the BlackBerry
device application does accepts WML content.
Each transcoder implements a method to create a hash table that maps the formats that the transcoder accepts as
input from a content server and the formats that the transcoder can create as output.
At start up, the MDS services use the hash table to modify the Accept header field before forwarding an HTTP
request from the BlackBerry device. For example, a BlackBerry device application sends an HTTP request with the
following Accept header:
Accept: application/vnd.wap.wmlc, text/vnd.wap.wmlscriptc
After reviewing the transcoder mapping table, the MDS data optimization service appends the following items to
the Accept header line:
application/vnd.wap.wmlscript, text/wml, and text/vnd.wap.wml
194
B: Appendix: MDS services reference
Accept: application/vnd.wap.wmlc, text/vnd.wap.wmlscriptc, application/vnd.wap.wmlscript,
text/wml, text/vnd.wap.wml
This extended Accept header now lists all MIME types that the content server can provide.
Map transcoders
The httpcontenttranscoderslist.property file, located in the MDS\config subdirectory of your BlackBerry Java
Development Environment (BlackBerry JDE) installation, specifies how the MDS data optimization service manage
the exchange of various content types between applications and content servers.
The following is an example of the httpcontenttranscoderslist.property file:
text/vnd.wap.wml->application/vnd.wap.wmlc:vnd.wap.wml
text/vnd.wap.wml->application/vnd.wap.wbxml:vnd.wap.wml
text/vnd.wap.wmlscript->application/vnd.wap.wmlscriptc:wmls
text/html->application/vnd.rim.html.filtered:html
text/vnd.wap.wml:vnd.wap.wml
text/vnd.sun.j2me.app-descriptor->application/vnd.rim.cod:vnd.rim.cod
default:pass
Each entry uses the following format:
<InputType> [-> <OutputType>]: <Action>
where:
• <InputType> is the MIME type that is available from the content server, or default
• <OutputType> is the MIME type that the BlackBerry device requests
• <Action> is one of the following values:
• transcoder package name, such as vnd.wap.wml
• Pass: send data without change
• Discard: discard data without sending it
The following sections explain the possible formats for entries in the httpcontenttranscoderslist.property file.
Format 1
An entry with the following format specifies the action that the MDS services perform when the type of content
that is available from the server is different from the type of content that the BlackBerry device has requested:
InputType -> OutputType:Transcoder OR RSV
For example, the application requests text/wml, but the content server only has text/xml. The MDS services find
this entry for this MIME type:
Text/xml -> Text/wml : vnd.wap.wml
According to this entry, the MDS services must use the vnd.wap.wml transcoder to convert XML content to WML.
Format 2
An entry with the following format specifies the action that the MDS services perform when the content server
sends content of a given type regardless of what the BlackBerry device has requested:
195
BlackBerry Application Developer Guide Volume 1: Fundamentals
InputType:Transcoder OR RSV
For example, if the content server has WML content only (text/vnd.wap.wml), the MDS services find the entry for
this MIME type:
text/vnd.wap.wml : vnd.wap.wml
According to the entry, the MDS services must apply the vnd.wap.wml transcoder to any WML content.
Default entry
A default entry specifies the default action that the MDS services perform if MDS services cannot find an entry for
a particular MIME type:
default : Transcoder or RSV
For example, If the MDS services cannot find an entry for the content in the default:pass default entry, the MDS
services forward the content to the BlackBerry device without change.
Creating transcoders
Convert HTML tags and content to uppercase
Follow transcoder package hierarchy
Define the HTTP content transcoder in the net.rim.protocol.http.content.transcoder.<transcoder
name> package. All HTTP content transcoders must be defined in the Transcoder package hierarchy.
package net.rim.protocol.http.content.transcoder.uppercasehtml;
Extend HTTPContentTranscoder
The class name for a transcoder must be Transcoder. Transcoders extend the HttpContentTranscoder class.
In this example, the HTTP content transcoder is defined in a public class named Transcoder.
public class Transcoder extends HttpContentTranscoder { ... }
Define HTTP headers
Define constants for HTTP headers and the strings that the transcoder adds to these headers.
private static final String CONTENTTYPE_HEADER_NAME = "Content-Type";
private static final String CONTENTLENGTH_HEADER_NAME = "Content-Length";
private static final String ACCEPT_HEADER_NAME = "Accept";
// Add this line to the Accept header field if it exists when
// the BlackBerry device issues an HTTP request.
private static final String ACCEPTLINE= "text/html";
// This line identifies the output content type that this transcoder produces.
private static final String OUTPUT_TYPE= "text/UPPERCASEHTML";
196
B: Appendix: MDS services reference
Create a mapping of input and output types
Your implementation of getMapOfOutputToAcceptLine() creates a mapping of the transcoder’s possible input
and output types.
At start up, the MDS services use the mapping to modify the Accept header field. The MDS services send the
modified header in an HTTP request to an HTTP server.
public HashMap getMapOfOutputToAcceptLine() {
HashMap mapping = new HashMap();
mapping.put(OUTPUT_TYPE, ACCEPTLINE);
return mapping;
}
Set the connection URL
Define a method to set the connection URL when the BlackBerry device requests an open HTTP connection.
public void setURL(URL newURL) {
url = newURL;
}
Define BlackBerry device request processing
Your implementation of transcodeDevice(HttpRequest) defines any processing on the BlackBerry device
request before the MDS services forward it to the destination server. The following example requires no
processing.
An application can request a specific transcoder by using the HTTP header field that is called ContentTranscoder.
public void transcodeDevice(HttpRequest request) throws HttpContentTranscoderException {
// Implementation.
}
Define BlackBerry device response processing
Your implementation of transcodeDevice(HttpResponse) defines any processing on the BlackBerry device
response before MDS services forwards it to the destination server. The following example requires no processing.
public void transcodeDevice(HttpResponse response) throws HttpContentTranscoderException {
// Implementation.
}
Define server request processing
Your implementation of transcodeServer(HttpRequest) defines any processing requirements for the content
server request before the MDS services forward it to the BlackBerry device.
public void transcodeServer(HttpRequest request) throws
HttpContentTranscoderException {
try {
// Retrieve the request content, which, in this case, is in HTML.
byte[] requestContent = request.getContent();
if (requestContent != null) {
197
BlackBerry Application Developer Guide Volume 1: Fundamentals
// Convert the content to String object.
String requestContentAsString = new
String(requestContent).toUpperCase();
// Convert the requestContentAsString to bytes again.
requestContent = requestContentAsString.getBytes();
}
else {
// Send an HTML message to indicate that the server
// is not responding with appropriate content.
StringBuffer sb = new StringBuffer();
sb.append("<HTML>\n");
sb.append("<HEAD>\n");
sb.append("<TITLE> UPPERCASEHTML TRANSCODER</title>\n");
sb.append("</HEAD>\n");
sb.append("<BODY>\n");
sb.append("SERVER IS NOT PUSHING APPROPRIATE CONTENT\n");
sb.append("</BODY\n");
sb.append("</HTML>\n");
requestContent = sb.toString().getBytes();
}
request.setContent(requestContent);
// Update the Content-Length
HttpHeader contentLengthHeader =
request.getHeader(CONTENTLENGTH_HEADER_NAME);
if (contentLengthHeader != null) {
contentLengthHeader.setValue("" + requestContent.length);
}
else {
// The server did not send the Content-Length.
// No update is needed.
}
// Update the Content-Type.
HttpHeader contentTypeHeader =
request.getHeader(CONTENTTYPE_HEADER_NAME);
if (contentTypeHeader != null) {
contentTypeHeader.setValue(OUTPUT_TYPE);
}
else {
// Add the Content Type here if the server does not specify one.
request.putHeader(new HttpHeader(
CONTENTTYPE_HEADER_NAME, OUTPUT_TYPE));
}
} catch (Throwable t) {
throw new HttpContentTranscoderException(t.toString());
}
}
Define server response processing
Your implementation of transcodeServer(HttpResponse) defines any processing requirements for the content
server response that includes content from the content server before the MDS Services forward it to the BlackBerry
device. If the response contains no content, the MDS Services forward the response to the BlackBerry device
without any changes.
public void transcodeServer(HttpResponse response) throws
HttpContentTranscoderException {
198
B: Appendix: MDS services reference
try {
// Retrieve the response content, which in this case is in HTML.
byte[] responseContent = response.getContent();
if (responseContent != null) {
// Convert the content to String object.
String responseContentAsString = new
String(responseContent).toUpperCase();
// Convert the responseContentAsString to bytes again.
responseContent = responseContentAsString.getBytes();
}
else {
// No response is received from the server.
StringBuffer sb = new StringBuffer();
sb.append("<HTML>\n");
sb.append("<HEAD>\n");
sb.append("<TITLE> UPPERCASEHTML TRANSCODER </title>\n");
sb.append("</HEAD>\n");
sb.append("<BODY>\n");
sb.append("SERVER IS NOT RESPONDING\n");
sb.append("</BODY\n");
sb.append("</HTML>\n");
responseContent = sb.toString().getBytes();
}
response.setContent(responseContent);
// Update the Content-Length.
HttpHeader contentLengthHeader =
response.getHeader(CONTENTLENGTH_HEADER_NAME);
if (contentLengthHeader != null) {
contentLengthHeader.setValue("" + responseContent.length);
} else {
// Server did not send Content-Length so no update is required.
}
// Update the Content-Type.
HttpHeader contentTypeHeader =
response.getHeader(CONTENTTYPE_HEADER_NAME);
if (contentTypeHeader != null) {
contentTypeHeader.setValue(OUTPUT_TYPE);
}
else {
// Add the Content Type here.
response.putHeader(new
HttpHeader(CONTENTTYPE_HEADER_NAME, OUTPUT_TYPE));
}
} catch (Throwable t) {
throw new HttpContentTranscoderException(t.toString());
}
}
Compile and install transcoders
1. Compile the transcoder class files. Include bmds.jar in the class path.
javac -classpath ".;MDS_home\samples\bmds.jar" Transcoder.java
2. Create a .jar file for the transcoder.
3. Install the transcoder .jar file in one of the following ways:
199
BlackBerry Application Developer Guide Volume 1: Fundamentals
• BlackBerry Enterprise Server: Add the transcoder .jar file into the lib\ext folder of the JRE. The .jar file
must be accessible to the Java Virtual Machine.
• Simulator: Add the transcoder .jar file to the MDS\classpath folder in the BlackBerry JDE.
4. Open the httpcontenttranscoderslist.property file, located in the MDS\config subdirectory of the
BlackBerry JDE installation.
5. To specify when to use the transcoder, add one or more entries. For example, to use the uppercasehtml
transcoder to convert HTML content to uppercase HTML, add this entry:
text/html -> text/UPPERCASEHTML : uppercasehtml
6. Save the property file.
7. Restart the MDS services or the BlackBerry MDS simulator.
200
Glossary
A
I
ALX
i18n
Application Loader XML
APDUs
internationalization
IP
Application Protocol Data Units
APN
Internet Protocol
IPPP
Access Point Name
ATR
IP Proxy Protocol
ISDN
Answer to reset
Integrated Services Digital Network
C
J
CA
JAD
Certificate Authority
cHTML
Java Application Descriptor
JAR
Compact Hypertext Markup Language
CLDC
Java Archive
JDWP
Connected Limited Device Configuration
Java Debug Wire Protocol
JRE
D
DSA
Digital Signature Algorithm
G
Java Runtime Environment
JTWI
Java Technology for the Wireless Industry
K
GUI
graphical user interface
GUID
globally unique identifier
KVM
Kilobyte virtual machine
BlackBerry Application Developer Guide Volume 2: Advanced Topics
L
R
LDAP
RRC
Lightweight Directory Access Protocol
LTPA
Radio Resource Control
RSA
Lightweight Third-Party Authentication
Public-key Encryption algorithm
RTC
M
real-time clock
MB
megabyte
MHz
S
SDK
megahertz
MIDlet
software development kit
SIM
MIDP application
MIDP
Subscriber Identity Module
Smart Card
Mobile Information Device Profile
MIME
A device used to securely store and transfer data
Smart Card Reader
Multipurpose Internet Mail Extensions
O
A wireless smart card reader for Bluetooth
enabled BlackBerry devices
SMS
OCSP
Online Certificate Status Protocol
Short Message Service
SRAM
static random access memory
P
SRP
PAP
Service Relay Protocol
Password Authentication Protocol
SSL
PIM
Secure Sockets Layer
personal information management
S/MIME
PIN
Secure Multipurpose Internet Mail Extensions
personal identification number
PNG
Portable Network Graphics
T
TCP
Transmission Control Protocol
202
Glossary
W
TIFF
Tag Image File Format
TLS
WAP
Wireless Application Protocol
Transport Layer Security
WBMP
wireless bitmap
U
UDP
User Datagram Protocol
WML
Wireless Markup Language
WMLC
URI
Uniform Resource Identifier
Wireless Markup Language Compiled
WTLS
URL
Uniform Resource Locator
Wireless Transport Layer Security
UTC
Universal Time Coordinate
203
Index
Numerics
32-bit processor
efficient programming, 31
A
acknowledgement
application-level, 139
transport-level, 139
adding
transcoders, 199
alerts, 15
alpha values
pixel transparency, 74
raster operations, 74
.alx files
examples, 183
format, 185
optional components, 184
using, 166
APIs
about, 8
Bluetooth, 103
CLDC, 11
collections, 13
compression, 13
hash tables, 14
lists, 14
MIDP, 11
network communication, 12
persistent storage, 12
streams, 13
system, 15
transcoding, 192
user interface, 39
utilities, 16
vectors, 14
application control
about, 16
application development
APIs, 8
building, 24
compiling, 24
creating source files, 23
IDE, 22, 27
Java support, 11
loading, 175
optimizing, 180
system times, 36
application loader
about, 183
deploying applications, 166
application suites, resource files, 133
application-level acknowledgement
about, 139
applications
application manager, 18
compiling, 24
creating application loader files, 166
deleting, 175
hot keys, 127
loading, 166
optional components, 184
reusing code, 20
testing, 171
testing on BlackBerry devices, 174
attributes
.alx files, 185
PAP DTD
audio formats, supported, 80
autotext fields
about, 47
filters, 46
B
BBDevMgr.exe, 175
Index
bitmap fields, 43
BitmapField class
getPredefinedBitmap(), 43
STAMP_MONOCHROME, 75
BlackBerry APIs
overview, 9
UI, 39
BlackBerry applications
main(), 18
properties, 168
BlackBerry device
memory usage, 15
notification, 15
persistent storage, 12
radio information, 15
system resources, 15
system times, 36
BlackBerry device management, 16
BlackBerry device simulator
connecting to desktop software, 173
starting, 171
BlackBerry Enterprise Server
troubleshooting push applications, 149
BlackBerry MDS simulator
configuring, 177
push support, 179
testing, 176
Bluetooth serial port connections
about, 103
closing, 104
opening, 103
BluetoothSerialPort class
about, 103
getSerialPortInfo(), 103
Boolean conditions, 30
browser
certificates, 190
push applications, 137
btspp protocol, 103
building projects, 24
button fields, 44
C
cancelling PAP push requests, 141
casting, 33
certificates, trusted servers, 190
choice fields, 44
CLDC APIs
about, 8
overview, 11
CLDC limitations, 12
code coverage, analyzing, 179
code examples
BaseApp.java, 20
BluetoothSerialPortDemo.java, 104
ContextMenuSample.java, 61
CountryInfo.java, 128
CountryInfo.java (with localization support), 131
CustomButtonField.java, 57
CustomPMEConnector.java, 92
DiagonalManager.java, 65
DrawDemo.java, 76
HelloWorld.java, 19
HTTPFetch.java, 96
HTTPPushDemo.java, 144
ImageDemo.java, 71
ITPolicyDemo.java, 136
MediaSample.java, 84
MediaSample2.java, 88
MobitexDemo.java, 114
ReceiveSms.java, 123
SampleListFieldCallback.java, 68
SendSms.java, 122
SMSDemo.java, 122
code libraries, programming guidelines, 30
code, reusing, 20
collections
about, 13
hash tables, 14
lists, 14
vectors, 14
color devices
drawing, 74
getARGB(), 69
comments, javadoc, 25
compiling, applications, 24
components, See fields
compression formats
205
BlackBerry Application Developer Guide Volume 1: Fundamentals
GZip, 13
ZLib, 13
connection types, overview, 12
context menus
about, 41
creating, 60
createMedia(), MediaManager class, 83
creating
context menus, 60
custom fields, 53
custom layout managers, 63
lists, 66
projects, 23
workspaces, 23
custom fields
appearance, 55
creating, 53
preferred field size, 54
using set and get methods, 56
custom managers
handling focus, 64
implementing subpaint(), 65
preferred field height, 63
preferred field width, 63
D
datagram connections
about, 111
opening, 112
Datagram interface
about, 111
setData(), 112
DatagramConnection interface
about, 111
newDatagram(), 112
date fields, 45
.debug files, installing, 174
debugging
attaching to BlackBerry device, 175
memory statistics, 181
objects in memory, 181
printing stack trace, 38
viewing objects in memory, 181
debugging tools
206
about, 179
code coverage, 179
dependencies, nested modules, 184
deploying applications
application loader files, 166
desktop software, 166
obfuscation, 24
using .cod files, 167
using .jar files, 167, 168
desktop software
connecting to BlackBerry device simulator, 173
version, 175
dialog boxes
about, 42
downloading
.cod files, 167
.jar files, 167, 168
drawing
about, 69
color devices, 74
drawing styles, 75
drawListRow(), ListFieldCallback class, 66
drawShadedFilledPath()
example, 75
Graphics class, 74
DrawStyle class
using drawing styles, 75
DrawStyle interface
custom fields, 73
E
edit fields, 46
editor macros, javadoc, 25
email server simulator
about, 173
modes, 173
enterEventDispatcher()
event handling, 18
UiApplication class, 18
Enumeration class, hiding data, 32
event dispatch thread
running applications, 51
event dispatch threads
event locks, 50
Index
events
about, 14
focus, 56
keyboard, 14
logging, 16
trackwheel, 14
user interface, 78
Exceptions
ClassCastException, 33
MediaException class, 82
F
Field class
constructors, 53
custom fields, 53
extending, 53
layout(), 54
paint(), 55
fields
autotext, 47
bitmap, 43
button, 44
choice, 44
creating custom, 53
date, 45
edit, 46
gauge, 47
label, 47
list, 48
numeric choice, 44
option, 45
password, 47
separator, 47
text, 46
file extensions
.alx, 166
.cod, 24
.jad, 166
.rrc, 126
.rrh, 126
final classes, programming guidelines, 30
focus events, 56
foreground events, managing, 51
G
garbage collection, efficient programming, 31
gauge fields, 47
get(), ListFieldCallback class, 67
getBoolean(), ITPolicy class, 135
getInputStream(), InputStream class, 147
getInteger(), ITPolicy class, 135
getOutputStream(), OutputStream class, 147
getPredefinedBitmap()
BitmapField class, 43
getPreferredHeight()
Field class, 54
Manager class, 63
getPreferredWidth()
Field class, 54
ListFieldCallback class, 67
Manager class, 63
getSerialPortInfo(), BluetoothSerialPort class, 103
getState(), MediaPlayer class, 82
getString(), ITPolicy class, 135
getSupportedContentTypes(), Manager class, 80
getUI(), MediaPlayer class, 83
GlobalEventListener interface, IT policy listeners, 135
Graphics class
drawing on the graphics context, 67
drawShadedFilledPath(), 74
getGlobalAlpha(), 74
implementing drawing styles, 73
inverting an area, 52
isColor(), 74
isDrawingStyleSet(), 75
numColors(), 74
setDrawingStyle(), 75
setGlobalAlpha(), 74
translating an area, 52
Graphics class, isRopSupported(), 74
GZip compression formats, 13
H
handheld software, versions, 8
hash tables, 14
headers
HTTP request, 188
HTTP response, 188
hot keys, 127
207
BlackBerry Application Developer Guide Volume 1: Fundamentals
HTTP
requests, 188
responses, 188
HTTPS
about, 189
certificates, 190
CLDC APIs, 11
CLDC limitations, 12
MIDP APIs, 11
multithreading, 12
javadocs, generating, 25
JavaLoader, 175
I
K
IDE
KeyboardListener interface, implemented by Screen,
creating projects, 23
creating source files, 23
creating workspaces, 22, 23
memory statistics tool, 181
objects tool, 181
profiler tool, 180
resources, 125
simulator, 171
using, 22, 27
initialization files, creating, 133
instanceof
evaluating casts, 33
evaluating conditions, 34
internet messaging address
mapping to PIN, 179
PIN mapping, 149
isColor(), Graphics class, 74
isDrawingStyleSet(), Graphics class, 75
isROPSupported()
Graphics class, 74
IT policies
about, 135
examples, 136
listening for changes, 135
retrieving, 135
ITPolicy class
getBoolean(), 135
getInteger(), 135
getString(), 135
J
.jad files, format, 166
Java
BlackBerry environment, 11
208
19
keyboards
events, 14
hot keys, 127
keytool
installing certificates, 190
L
label fields, 47
languages, See resources
layout
custom, 63
managers, 49
list fields, 48
listeners
keyboard, 14
overview, 14
trackwheel, 14
user interface events, 78
ListFieldCallback class
drawListRow(), 66
get(), 67
getPreferredWidth(), 67
lists
collection APIs, 14
creating, 66
drop-down, 44
list fields, 48
loading applications using JavaLoader, 175
localization
about, 125
resource header files, 126
logging events, 16
loops, optimizing, 31
Index
M
main screens, 19
main(), BlackBerry applications, 18
MainScreen class
about, 19
constructor, 19
makeMenu(), Screen class, 41
Manager class
getPreferredHeight(), 63
getPreferredWidth(), 63
nextFocus(), 64
sublayout(), 64
Manager class, getSupportedContentTypes(), 80
managers
about, 49
flow layout, 50
horizontal layout, 50
See also custom managers
MDS services
configuring, 179
managing certificates, 190
simulator, 176
transcoders, 190
MDS, See MDS services
media content
PME, 81
supported protocols, 81
MediaException class
about, 81
HTTP response codes, 82
MediaListener interface, events, 82
MediaManager class
about, 81
createMedia(), 83
MediaPlayer class
about, 81
getState(), 82
getUI(), 83
setMedia(), 83
start(), 84
memory
leaks, 181
viewing objects, 181
viewing statistics, 181
menu items
adding, 41
localized strings, 130
MenuItem class
about, 41
constructor, 41
menus
context, 60
context menus, 41, 60
messaging
simulating, 173
MIDlet applications
properties, 167
MIDP APIs
about, 8
overview, 11
persistent storage, 12
UI, 39
MIME encoding
reading streams, 13
writing streams, 13
Mobile Media API, about, 80
multithreading
about, 12
recommended practices, 37
N
network
configuring the simulator, 179
serial connections, 102
socket connections, 101
transcoders, 190
newDatagram(), DatagramConnection interface, 112
nextFocus(), Manager class, 64
notification, using alerts, 15
numColors(), Graphics class, 74
O
obfuscation, default, 24
objects tool, about, 181
onClose(), MainScreen class, 19
optimizing
casting, 33
conditions, 34
209
BlackBerry Application Developer Guide Volume 1: Fundamentals
division, 32
Enumeration, 32
expressions, 32
garbage collection, 31
loops, 31
memory, 37, 181
null parameters, 37
null return values, 37
objects, 181
performance, 30
profiler tool, 180
strings, 31
option fields, about, 45
optional components, .alx files, 184
P
paint(), Field class, 55
PAP push, See push access protocol
password fields, 47
peripherals
Bluetooth serial port connections, 103
serial port connections, 102
USB connections, 102
PIN
internet messaging address mapping, 149
mapping to internet messaging address, 179
pixel transparency, alpha values, 74
processor, programming guidelines, 31
profiler tool, about, 180
programming
adding text fields, 130
avoiding String(String), 31
Boolean conditions, 30
event dispatch thread, 51
event lock, 50
guidelines, 30
identifiers, 38
inner classes, 35
static strings, 31
UiApplication class, 18
using interfaces, 35
project properties, titles, 127
projects
building, 24
210
creating, 23
setting properties, 127
protocols
btspp (Bluetooth serial port), 103
media loading, 81
udp, 112
push access protocol, 137
push applications
about, 137
cancellation requests, 141
client/server, 144
client-side, 143
push access protocol, 139
query requests, 142
server-side, 146
simulator options, 179
troubleshooting, 149
types, 137
push requests
client/server, 137
pushScreen(), UiApplication class, 19
Q
querying, PAP push requests, 142
R
radio, retrieving information, 15
raster operations, support, 74
receiving, SMS messages, 123
reliable push, 139
requests, HTTP, 188
resource bundles, retrieving, 130
resource files
managing, 133
retrieving strings, 130
resource interfaces, implementing, 130
ResourceBundle class
about, 125
ResourceBundleFamily class, 125
resources
adding, 127
application title, 127
inheritance, 126
responses
Index
HTTP, 188
HTTP headers, 188
reusing code, 20
.rrc files, 126
.rrh files, 126
avoiding String(String), 31
static variables, 31
sublayout(), Manager class, 64
synchronization, testing, 173
system times, application development, 36
S
T
Screen class, makeMenu(), 41
screens
about, 19, 39
dialog boxes, 42
layout, 40
menus, 40
navigation, 40
security, certificates, 190
sending, SMS messages, 122
separator fields, 47
serial connections, using, 102
server connections
reading, 147
writing, 147
setData(), Datagram interface, 112
setDrawingStyle, Graphics class, 75
setMedia(), MediaPlayer class, 83
shift right, optimizing division, 32
short cuts, See hot keys
simulating messaging, 173
simulator
null modem cable, 173
using, 171
SMS
receiving, 123
sending, 122
sockets
about, 101
opening connections, 101
source files, creating in IDE, 23
SSL, See HTTPS
stack trace, printing, 38
STAMP_MONOCHROME, BitmapField class, 75
start(), MediaPlayer class, 84
storing data, 12
streams
overview, 13
String class
testing
applications, 171
backup and restore, 173
BlackBerry device simulator, 171
BlackBerry MDS simulator, 176
HTTP network connections, 176
using BlackBerry devices, 174
text fields, 46
threads
event dispatch thread, 51
event lock, 50
multithreading, 12, 37
Throwable, avoiding, 38
titles, localized, 126
trackwheel, events, 14
TrackwheelListener interface, implemented by Screen
class, 19
transcoding
about, 190
APIs, 192
installing, 199
mapping transcoders, 195
programming, 192
selecting, 192
writing, 196
translation, See resources
transport-level acknowldegement
about, 139
tunes
audio formats, 80
U
UDP connections, opening, 112
UDP, See User Datagram Protocol
UI components
AutoTextEditField, 47
BasicEditField, 46
211
BlackBerry Application Developer Guide Volume 1: Fundamentals
BitmapField class, 43
ButtonField, 44
code example, 19
DateField, 45
GaugeField, 47
ListField, 48
NumericChoiceField, 44
PasswordEditField, 47
RichTextField, 46
TreeField, 48
UiApplication class
about, 18
enterEventDispatcher(), 18
extending, 18
pushScreen(), 19
USB connections, using, 102
User Datagram Protocol, connections, 111
user interfaces
APIs, 39
components, 43
customizing, 53
dialog boxes, 42
drawing, 69
edit field filters, 46
event listeners, 78
fields, 43
focus, 56
212
labels, 47
layout, 49
listeners, 78
lists, 48
managers, 49
menus, 40
screens, 39
text fields, 46
text filters, 46
UiApplication class, 18
utilities, APIs, 16
V
verification, bytecode, 24
versions, handheld software, 8
viewing, objects, 181
W
workspaces, creating, 22, 23
X
XYPoint class, about, 51
XYRect class
about, 51
Z
ZLib compression formats, 13
©2005 Research In Motion Limited
Published in Canada.
Was this manual useful for you? yes no
Thank you for your participation!

* Your assessment is very important for improving the work of artificial intelligence, which forms the content of this project

Download PDF

advertisement