Wednesday, March 4, 2009

Code : Capture Signature on the BlackBerry Storm

2 comments

The BlackBerry Storm incorporates a touchscreen which can be used to capture and collect signatures. The following sample application demonstrates how to accomplish this by using the TouchEvent API to capture touch points and then using a BitmapField to draw the signature. A complete working sample can be downloaded here.

Code : Access and Obtain Service Books

0 comments

The BlackBerry JDE 4.0 has a package, net.rim.device.api.servicebook, that allows the retrieval of service book information on a BlackBerry device.

The example below uses both the ServiceBook and ServiceRecord classes to obtain the APN of the WAP Browser service book:

import net.rim.device.api.system.*;
import net.rim.device.api.servicebook.*;
public class ServiceBookExample extends Application {
ServiceRecord[] _sRecordsArray; //Creates a ServiceRecord array.
ServiceBook _servicebook; //Creates a ServiceBook variable.
String cidValue, sbName, sbAPN;
public static void main(String[] args)
{
// Create a new instance of the application and
// start the event thread.
ServiceBookExample app = new ServiceBookExample();
app.enterEventDispatcher();
}
public ServiceBookExample() {
// Returns a reference to the service book from the factory.
_servicebook = ServiceBook.getSB();
// Returns an array of all registered service records.
_sRecordsArray = _servicebook.getRecords();
// Loops through the service record array
// and obtains specific information relating
// to each item and prints it to the debugging output.
for(int i = 0; i < _sRecordsArray.length; i++) {
// Obtains the Service Book CID
cidValue = _sRecordsArray[i].getCid();
// Obtains the Name of the Service Book
sbName = _sRecordsArray[i].getName();
if(cidValue.equals("BrowserConfig")
&& sbName.startsWith("WAP Browser")) {
// Obtains the Service Book's APN
// (Associated Access Point Name)
String sbAPN = _sRecordsArray[i].getAPN();
}
}
}
}

For a complete listing of available methods, please see the API reference included within the BlackBerry JDE 4.0. Additional information can be found in Chapter 10 of the BlackBerry Application Developer Guide Volume 2.

Code : Determine if a microSD card has been inserted

0 comments

The BlackBerry® Pearl™ 8100 smartphone was the first BlackBerry device to support microSD cards. Along with microSD card support, the BlackBerry Pearl 8100 smartphone was the first BlackBerry device to support JSR 75, the FileConnection API. In addition to providing the ability to store data to the internal memory and microSD card, this API also allows an application developer to determine if a microSD card has been inserted into the BlackBerry Pearl 8100 smartphone.

String root = null;
Enumeration e = FileSystemRegistry.listRoots();
while (e.hasMoreElements()) {
root = (String) e.nextElement();
if( root.equalsIgnoreCase(“sdcard/”) ) {
//device has a microSD inserted
} else if( root.equalsIgnoreCase(“store/”) ) {
//internal memory identifier
}
}

The above code will allow a developer to determine if a microSD card is currently inserted, while the code below will notify the developer if this state ever changes (card removed/card inserted). Note that the listener must be added to FileSystemRegistry via the addFileSystemListener() method.

public class MySDListener implements FileSystemListener {
public void rootChanged(int state, String rootName) {
if( state == ROOT_ADDED ) {
if( rootName.equalsIgnoreCase(“sdcard/”) ) {
//microSD card inserted
}
} else if( state == ROOT_REMOVED ) {
//perform the same check as above
}
}
}

As of the last updated date of this article, an API did not exist to determine if the BlackBerry device could support microSD regardless of whether or not a card was inserted. However, the BlackBerry device model number can be used to determine microSD card support since the list of BlackBerry devices that support this feature is finite.

String modelNum = DeviceInfo.getDeviceName();
if(modelNum.startsWith("8") && !modelNum.startsWith("87")) {
//microSD card supported
}

Tuesday, March 3, 2009

Code : BlockDecryptor class

0 comments

I need to encrypt the string using AES encryption and CBC mode.

The way given in one of the post 'How to - Use Basic Encryption'. This code works fine.

But when I am encrypting the string using blockdescryptor and CBCBlockDescryptor the string is not encrypted fully.

Now the question was “How can I encrypt the string properly?”.

Following is the code:

private static byte[] encrypt(byte[] keyData, byte[] data) throws CryptoException, IOException

{

// Create the AES key to use for encrypting the data.

// This will create an AES key using as much of the keyData
// as possible.
AESKey key = new AESKey(keyData, 0, 128);

// Now, we want to encrypt the data.
// First, create the encryptor engine that we use for the actual
// encrypting of the data.
AESEncryptorEngine engine = new AESEncryptorEngine(key);

String strInitVector = "1234567890123456";
byte[] initVector = strInitVector.getBytes();
// Create a new initialization vector using the 8 bytes in initVector
InitializationVector iv = new InitializationVector(initVector);
// Create a BlockEncryptor to hide the engine details away.
ByteArrayOutputStream output = new ByteArrayOutputStream();
BlockEncryptor encryptor = new BlockEncryptor(new CBCEncryptorEngine(engine, iv) , output);
//BlockEncryptor encryptor = new BlockEncryptor(fengine , output);
encryptor.write(data, 0, data.length);
int nSize = output.size();
encryptor.flush();
output.close();
//encryptor.close(); // At this line application is throwing uncaught exception

// Now, the encrypted data is sitting in the ByteArrayOutputStream.
// We simply want to retrieve it.
return output.toByteArray();
}

The string given for encryption is "The quick brown fox jumped over the lazy dog".

Actual encrypted string from PHP for this string is of 42 characters. Where as my application is giving me the encrypted string of 32 characters. After decryption I am getting the plain text as "The quick brown fox jumped over ".

I have tried the same thing,appended '0' byte at the end of the string if the string length is less than block length.

And, It is working perfect.

How to - Use Basic Encryption

1 comments

Data sent between a BlackBerry device and the BlackBerry Enterprise Server™ is encrypted using Triple DES (Date Encryption Standard) or AES (Advanced Encrption Standard). This is performed automatically and does not require application implementation to use it.

There are cases where encrypting data can be required, such as secure communication with an external application using the BlackBerry Mobile Data Server. Communication between the BlackBerry and BlackBerry Mobile Data Server would be automatically encrypted but communication between the BlackBerry Mobile Data Server and an application server would not unless implemented in the BlackBerry application.

Note: The BlackBerry supports https, tls and ssl for secure communication beyond the BlackBerry Mobile Data Server.

The following is an example of how to utilize basic encryption using AES on the BlackBerry:

package com.rim.samples.crypto;
import java.io.*;
import net.rim.device.api.crypto.*;
import net.rim.device.api.util.*;
/**
* This sample code provides information on how to encrypt and
* decrypt data using the most common symmetric key algorithm
* in use today. That algorithm is the Advanced Encryption Standard (AES).
*/
public class BasicCryptoDeveloperLab
{
public static void main( String[] args )
{
try {
// Create the data that you want to encrypt.
String message = "Welcome to the RIM Crypto API.";
byte[] data = message.getBytes();
// Create the key we want to use for encryption and decryption.
// Note that the RandomSource class provides cryptographically random
// data which is suitable for use when creating keys. This is different
// than using the Random class.
byte[] keyData = RandomSource.getBytes( 256 );
// Encrypt the data using
byte[] ciphertext = encrypt( keyData, data );
// Decrypt the data.
byte[] plaintext = decrypt( keyData, ciphertext );
String message2 = new String( plaintext );
if( message.equals( message2 )) {
// The encryption/decryption operation worked as expected.
System.out.println( "Congratulations! You just encrypted and decrypted data." );
} else {
System.out.println( "Oops. The decrypted message should equal the original.
Check your code." );
}
} catch( CryptoException e ) {
System.out.println("An unexpected exception occurred.
Please verify your work or ask for help.");
} catch( IOException e ) {
System.out.println("An unexpected exception occurred.
Please verify your work or ask for help.");
}
}
private static byte[] encrypt( byte[] keyData, byte[] data )
throws CryptoException, IOException
{
// Create the AES key to use for encrypting the data.
// This will create an AES key using as much of the keyData
// as possible.
AESKey key = new AESKey( keyData );
// Now, we want to encrypt the data.
// First, create the encryptor engine that we use for the actual
// encrypting of the data.
AESEncryptorEngine engine = new AESEncryptorEngine( key );
// Since we cannot guarantee that the data will be of an equal block
// length we want to use a padding engine (PKCS5 in this case).
PKCS5FormatterEngine fengine = new PKCS5FormatterEngine( engine );
// Create a BlockEncryptor to hide the engine details away.
ByteArrayOutputStream output = new ByteArrayOutputStream();
BlockEncryptor encryptor = new BlockEncryptor( fengine, output );
// Now, all we need to do is write our data to the output stream.
// But before doing so, let's calculate a hash on the data as well.
// A digest provides a one way hash function to map a large amount
// of data to a unique 20 byte value (in the case of SHA1).
SHA1Digest digest = new SHA1Digest();
digest.update( data );
byte[] hash = digest.getDigest();
// Now, write out all of the data and the hash to ensure that the
// data was not modified in transit.
encryptor.write( data );
encryptor.write( hash );
encryptor.close();
output.close();
// Now, the encrypted data is sitting in the ByteArrayOutputStream.
// We simply want to retrieve it.
return output.toByteArray();
}
private static byte[] decrypt( byte[] keyData, byte[] ciphertext )
throws CryptoException, IOException
{
// First, create the AESKey again.
AESKey key = new AESKey( keyData );
// Now, create the decryptor engine.
AESDecryptorEngine engine = new AESDecryptorEngine( key );
// Since we cannot guarantee that the data will be of an equal block length
// we want to use a padding engine (PKCS5 in this case).
PKCS5UnformatterEngine uengine = new PKCS5UnformatterEngine( engine );
// Create the BlockDecryptor to hide the decryption details away.
ByteArrayInputStream input = new ByteArrayInputStream( ciphertext );
BlockDecryptor decryptor = new BlockDecryptor( uengine, input );
// Now, read in the data. Remember that the last 20 bytes represent
// the SHA1 hash of the decrypted data.
byte[] temp = new byte[ 100 ];
DataBuffer buffer = new DataBuffer();
for( ;; ) {
int bytesRead = decryptor.read( temp );
buffer.write( temp, 0, bytesRead );
if( bytesRead < 100 ) {
// We ran out of data.
break;
}
}
byte[] plaintextAndHash = buffer.getArray();
int plaintextLength = plaintextAndHash.length - SHA1Digest.DIGEST_LENGTH;
byte[] plaintext = new byte[ plaintextLength ];
byte[] hash = new byte[ SHA1Digest.DIGEST_LENGTH ];
System.arraycopy( plaintextAndHash, 0, plaintext, 0, plaintextLength );
System.arraycopy( plaintextAndHash, plaintextLength, hash, 0,
SHA1Digest.DIGEST_LENGTH );
// Now, hash the plaintext and compare against the hash
// that we found in the decrypted data.
SHA1Digest digest = new SHA1Digest();
digest.update( plaintext );
byte[] hash2 = digest.getDigest();
if( !Arrays.equals( hash, hash2 )) {
throw new RuntimeException();
}
return plaintext;
}
}

Monday, March 2, 2009

Code : Allow a background listener to detect and update a GUI application

1 comments

When alternate entry points are used, an application may consists of both a background listening thread and a foreground graphical user interface (GUI) application. In many cases, it is desired that the background listening thread detects that the GUI portion of an application is running, and updates the screen to alert the user of an event.

The following example makes use of two entry points. The FolderListener is set to auto-start through an alternate entry point, and the GUI portion of the application is started when the user clicks on the application icon on their BlackBerry device.

Note: This example uses a FolderListener, but this principle can be applied to any background listening thread.

Create an alternate entry point for an application:

  1. Create a project in the BlackBerry Java Development Environment (JDE).
  2. Right-click the project and click Properties.
  3. Click the Application tab.
  4. In the Project type drop-down list, click Alternate CLDC Application Entry Point.
  5. In the Alternate entry point for drop-down list, select the project that you wish to auto-start.
  6. In the Arguments passed to field, type init (This can be any string, init is used in the sample below).
  7. Select the System module option.
  8. Select the Auto-run on startup option.
  9. Click OK.

/**
* FolderListenerGUI.java
*/
package com.samples.folderListener;
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.*;
public class FolderListenerGUI extends UiApplication
{
private MainScreen mainScreen;
private static RichTextField newMailNotifier;
public static void main(String[] args)
{
boolean startup = false;
//Check parameters to see if the application was entered
//through the alternate application entry point.
for (int i=0; i<args.length; ++i)
{
if (args[i].startsWith("init"))
{
startup = true;
}
}
if (startup)
{
//Entered through the alternate application entry point.
//Enable folderlistener on startup.
FolderListenerApp.waitForSingleton();
} else
{
//Entered by selecting the application icon on the ribbon.
//Start the FolderListenerGUI.
FolderListenerGUI app = new FolderListenerGUI();
app.enterEventDispatcher();
}
}
public FolderListenerGUI()
{
//Pass a reference to the FolderListenerGUI
//to the FolderListenerApp.
FolderListenerApp.waitForSingleton().
setFolderListenerGUI(this);
//Initialize mainScreen.
mainScreen = new MainScreen();
//Initialize the fields.
newMailNotifier = new RichTextField("No mail yet...",
RichTextField.NON_FOCUSABLE);
LabelField title = new LabelField("Folder Listener GUI",
LabelField.ELLIPSIS | LabelField.USE_ALL_WIDTH);
mainScreen.setTitle(title);
mainScreen.add(newMailNotifier);
//Display the main screen
pushScreen(mainScreen);
}
//Update the RichTextField with a new mail message.
public static void NewMailArrived()
{
newMailNotifier.setText("New mail arrived!");
}
//Remove the FolderListenerGUI instance from
//FolderListenerApp on exit.
protected void onExit()
{
//Remove the reference to FolderListenerGUI
//from FolderListenerApp.
FolderListenerApp.waitForSingleton().unsetFolderListenerGUI();
}
}
/**
* FolderListenerApp.java
*
*/
package com.samples.folderListener;
import net.rim.blackberry.api.mail.*;
import net.rim.blackberry.api.mail.event.*;
import net.rim.device.api.system.*;
import net.rim.blackberry.api.mail.*;
public final class FolderListenerApp implements FolderListener {
private FolderListenerGUI folderListenerGUI = null;
public static final long RTSID_MY_APP = 0x7451402f595f81a5L;
public FolderListenerApp()
{
try
{
//Get the store from the default instance.
Store store = Session.getDefaultInstance().getStore();
//Add the folder listener to the store.
store.addFolderListener(this);
}
catch (Exception e)
{
System.out.println(e.toString());
}
}
//Returns an instance of the running FolderListenerApp.
public static FolderListenerApp waitForSingleton()
{
//Ensure this is a singleton instance.
//Open the RuntimeStore.
RuntimeStore store = RuntimeStore.getRuntimeStore();
//Obtain the reference of FolderListenerApp.
Object obj = store.get(RTSID_MY_APP);
//If obj is null, there is no current reference
//to FolderListenerApp. Start a new instance
// of FolderListenerApp if one is not running.
if (obj == null)
{
//Store a reference to this instance in the RuntimeStore.
store.put(RTSID_MY_APP, new FolderListenerApp());
return (FolderListenerApp)store.get(RTSID_MY_APP);
} else
{
return (FolderListenerApp)obj;
}
}
//Called when a new message is created.
public void messagesAdded(FolderEvent e)
{
//Get the message that fired the folder event.
Message orginalMessage = e.getMessage();
//Get the folder the message is in.
Folder messageFolder = orginalMessage.getFolder();
//Is the new message in the Inbox?
if (messageFolder.getType() == Folder.INBOX)
{
//Check if the FolderListenerGUI is running.
if (folderListenerGUI != null)
{
//Grab the lock for the running FolderListenerGUI.
folderListenerGUI.invokeAndWait(new Runnable()
{
public void run()
{
//Call the NewMailArrived method to update the
//screen with a notification.
folderListenerGUI.NewMailArrived();
}
});
}
}
}
//Passes in reference to the FolderListenerGUI that is running.
public void setFolderListenerGUI(FolderListenerGUI folderGUI)
{
folderListenerGUI = folderGUI;
}
//Set the reference to the FolderListenerGUI to null
//(when it is shut down).
public void unsetFolderListenerGUI()
{
folderListenerGUI = null;
}
//Not used in this sample.
public void messagesRemoved(FolderEvent e)
{
}
}

What Is – TooManyThreadsError

0 comments

A single application can create up to 16 threads. The total number of threads that can exist on a BlackBerry device from all applications is 128. Therefore, if an application has already created 16 threads, the 17th attempt fails and a TooManyThreadsError exception is thrown. Similarly, if there are 128 threads already created on the BlackBerry device and an application attempts to create another thread, a TooManyThreadsError exception is thrown.

What Is - Blocking operation not permitted on event dispatch thread

0 comments

The dispatch thread (or main event thread) processes system messages. Blocking this thread prevents system messages from being processed, which leads to a message queue overflow and termination of the application. To prevent it, BlackBerry Device Software 4.1 and later no longer allow an application to initiate a call to a blocking method from the main event thread.

However, if an application attempts to block on the main event thread, an exception is thrown and the Blocking operation not permitted on event dispatch thread statement appears. To resolve this issue, move any blocking operations into their own threads.

Examples of blocking methods are as follows:

  • the read method of the InputStream class
  • the acceptAndOpen method of the StreamConnectionNotifier interface
  • the doModal method of the Dialog class