Wednesday, August 11, 2010

Hotkey Implementation In Blackberry

Hotkey or keyboard shortcut is very good feature to have in the UI. This can be implemented in Blackberry. The character which is to be featured as hotkey is shown with underline.

For example, if we want 'C' to be hotkey in 'Cancel', then we will need to postfix character 'C' by unicode character '\u0332'; so in this case 'Cancel' will be as 'C\u0332ancel'.

To implement the hotkey functionality we need to override keyChar method of Screen class and give action on specified character.

Following is blackberry code which implements hotkey O and C for OK and Cancel buttons respectively.

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

/**
*

Main class of the application.
*/
public class Hotkey extends UiApplication
{
//statics ------------------------------------------------------------------
public static void main(String[] args)
{
Hotkey theApp = new Hotkey();

//To make the application enter the event thread and start processing messages, we invoke the enterEventDispatcher method
theApp.enterEventDispatcher();
}

public Hotkey()
{
pushScreen(new HotkeyTestScreen());
}
}

class HotkeyTestScreen extends MainScreen
{
private KButtonField m_oOKButtonField;
private KButtonField m_oCancelButtonField;

public HotkeyTestScreen()
{
super();

setTitle("Hotkey Test");

add(m_oOKButtonField = new KButtonField("O\u0332K"));

add(m_oCancelButtonField = new KButtonField("C\u0332ancel"));
}

protected boolean keyChar(char key, int status, int time)
{
boolean bReturn = true;

if(('O' == key) || ('o' == key))
{
m_oOKButtonField.fieldChangeNotify(0);
}
else if(('C' == key) || ('c' == key))
{
m_oCancelButtonField.fieldChangeNotify(0);
}
else
{
bReturn = super.keyChar(key, status, time);
}

return bReturn;
}

class KButtonField extends ButtonField
{
KButtonField(String strLabel)
{
super(strLabel);
}

public void fieldChangeNotify(int context)
{
Status.show(getLabel() + " button clicked!");
}
}
}

Thursday, May 6, 2010

URL Encoding Decoding In Blackberry or J2ME

URLs often contains characters outside the ASCII set, the URL has to be converted to valid ASCII format using URL encoding which replaces unsafe ASCII characters with "%" followed by two hexadecimal digits corresponding to the character values in the ISO-8859-1 character-set.

Following is the code to achieve just that. It is tested with Blackberry but can be used in J2ME applications too.

class UrlEncoderDecoder
{
static final String HEX_DIGITS = "0123456789ABCDEF";


/**
* @param arrData The string to encode
* @return The URL-encoded string
*/
protected static String fnUrlEncode(byte[] arrData)
{
StringBuffer strResult = new StringBuffer();

for(int i = 0; i < arrData.length; i++)
{
char c = (char)arrData[i];

switch( c )
{
case '_':
case '.':
case '*':
case '-':
case '/':
{
strResult.append(c);
break;
}
case ' ':
{
strResult.append('+');
break;
}
default:
{
if((c >= 'a' && c <= 'z') ||
(c >= 'A' && c <= 'Z') ||
(c >= '0' && c <= '9'))
{
strResult.append( c );
}
else
{
strResult.append('%');
strResult.append(HEX_DIGITS.charAt((c & 0xF0) >> 4 ));
strResult.append(HEX_DIGITS.charAt(c & 0x0F ));
}
}
}
} // for

return strResult.toString();
}

/**
* @param arrData The byte array containing the bytes of the string
* @return A decoded String
*/
protected static String fnUrlDecode(byte[] arrData)
{
String strDecodedData = "";

if(null != arrData)
{
byte[] arrDecodeBytes = new byte[arrData.length];

int nDecodedByteCount = 0;

try
{
for(int i = 0; i < arrData.length; i++ )
{
switch(arrData[i])
{
case '+':
{
arrDecodeBytes[nDecodedByteCount++] = (byte) ' ';
break ;
}
case '%':
{
arrDecodeBytes[nDecodedByteCount++] = (byte)((HEX_DIGITS.indexOf(arrData[++i]) << 4) +
(HEX_DIGITS.indexOf(arrData[++i])) );
break ;
}
default:
{
arrDecodeBytes[nDecodedByteCount++] = arrData[i];
}
}
}

strDecodedData = new String(arrDecodeBytes, 0, nDecodedByteCount) ;
}
catch(Exception e)
{
}
}

return strDecodedData;
}
}

Tuesday, May 4, 2010

AES Encryption

AES is a standard private-key or symmetric cryptography. It supports combination of key and block sizes of 128, 192, and 256.

In Blackberry AES encryption can be achieved as follows:

import java.io.*;
import net.rim.device.api.io.*;
import net.rim.device.api.crypto.*;

import net.rim.device.api.util.*;

/**
* This is utility class for doing AES encryption and decryption.
* It uses 'PKCS5' as padding.
*
*/
public class AESUtil
{
/**
* Encrypts data using specified key data using AES algorithm.
*
* @param arrKeyData Key data that will be used for encryption.
* @param arrData Data to be encrypted.
*
* @return Encryped data in byte array.
*/
public static byte[] fnEncrypt(byte[] arrKeyData, byte[] arrData)
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 oKey = new AESKey(arrKeyData);

AESEncryptorEngine oEngine = new AESEncryptorEngine(oKey);

PKCS5FormatterEngine oPKCS5Engine = new PKCS5FormatterEngine(oEngine);

ByteArrayOutputStream oOutput = new ByteArrayOutputStream();
BlockEncryptor encryptor = new BlockEncryptor(oPKCS5Engine, oOutput);

encryptor.write(arrData);
encryptor.close();
oOutput.close();


return oOutput.toByteArray();
}

/**
* Decrypts encrypted data using specified key data using AES algorithm.
*
* @param arrKeyData Key data that will be used for decryption.
* @param arrEncryptedData Encryped data that is to be decrypted.
*
* @return Decrypted data in byte array.
*/
public static byte[] fnDecrypt(byte[] arrKeyData, byte[] arrEncryptedData)
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 oKey = new AESKey(arrKeyData);

AESDecryptorEngine oEngine = new AESDecryptorEngine(oKey);

PKCS5UnformatterEngine oUEngine = new PKCS5UnformatterEngine(oEngine);

ByteArrayInputStream oInput = new ByteArrayInputStream(arrEncryptedData);
BlockDecryptor oDecryptor = new BlockDecryptor(oUEngine, oInput);


byte[] arrTemp = new byte[100];
DataBuffer oBuffer = new DataBuffer();

int nBytesRead = -1;

while(-1 < (nBytesRead = oDecryptor.read(arrTemp)))
{
oBuffer.write(arrTemp, 0, nBytesRead );
}

return oBuffer.getArray();
}
}

Thursday, April 22, 2010

Java Code For Binary Hexadecimal Conversion

In this post code for binary to hex coversion has been posted. This is pure java code and can be used in BlackBerry, J2ME and Java.

/**
* This class provides funcationlity to convert binary byte array to hexadecimal byte array as
* well as to convert hexadecimal byte array to binary byte array.
*/
public class BinHexConverter
{
private static String HEX_STRING = "0123456789ABCDEF";

public static byte[] convertHexToBinary(byte[] hex)
{
int block = 0;

byte[] data = new byte[hex.length / 2];

int index = 0;
boolean next = false;

for (int i=0; i<<= 4; int pos = HEX_STRING.indexOf(Character.toUpperCase((char) hex[i])); if (pos > -1)
{
block += pos;
}

if (next)
{
data[index] = (byte)(block & 0xff );
index++;
next = false;
}
else
{
next = true;
}
}

return data;
}

private static String convertBinary2Hex(byte[] binary)
{
StringBuffer buf = new StringBuffer();

int block = 0;

for (int i=0; i> 4));
buf.append(HEX_STRING.charAt(binary[i] & 0x0F));
}

return buf.toString();
}
}

/**
* Test class for binary to hex conversion.
*/
public class BinHexTester
{
public static void main(String[] args)
{
String strText = BinHexConverter.convertBinary2Hex("hellohello".getBytes());
System.out.println(strText);
}
}

Wednesday, April 21, 2010

PIM Listener Blackberry

Blackberry provides PIMListener to get notification regarding changes in the PIMItems. Following is a library class created to get notification regarding changes in contact, task, appointment and/or memo on blackberry device.

1. Create object of BBPIMListener.
2. Start listening for specified PIM types by calling method 'fnAddListener()'. Multiple types can be specified by using | (OR) operator. e.g. fnAddListener(BBPIMListener.CONTACT_LIST | BBPIMListener.MEMO_LIST)
3. Override methods to provide specific functionality. e.g. override method 'fnOnContactAdded()' to specify what has to be done on contact addition.

Here is code:

import net.rim.blackberry.api.pdap.*;
import javax.microedition.pim.*;
import java.util.*;

/**
* Library class for listening changes in contact list, task list, appointments
* and/or memos.
*
* @author Dipak
*/
public class BBPIMListener implements PIMListListener
{
public final int CONTACT_LIST = 1;
public final int TASK_LIST = 2;
public final int APPOINTMENT_LIST = 4;
public final int MEMO_LIST = 8;

public final int ADD = 1;
public final int DELETE = 2;
public final int UPDATE = 4;

private BlackBerryPIMList m_oContactList;
private BlackBerryPIMList m_oToDoList;
private BlackBerryPIMList m_oEventList;
private BlackBerryPIMList m_oMemoList;

/**
* Adds listener for specified PIM types and gives information related to
* changes in those.
* @param nType List type; one of CONTACT_LIST, TASK_LIST, APPOINTMENT_LIST,
* MEMO_LIST
*/
public void fnAddListener(int nType)
{
try
{
PIM oPIM = PIM.getInstance();

if(CONTACT_LIST == (nType & CONTACT_LIST))
{
// Contact listener
m_oContactList = (BlackBerryPIMList)oPIM.openPIMList(PIM.CONTACT_LIST, PIM.READ_WRITE);
m_oContactList.addListener(this);
}

if(TASK_LIST == (nType & TASK_LIST))
{
// Task listener
m_oToDoList = (BlackBerryPIMList)oPIM.openPIMList(PIM.TODO_LIST, PIM.READ_WRITE);
m_oToDoList.addListener(this);
}

if(APPOINTMENT_LIST == (nType & APPOINTMENT_LIST))
{
// Calendar listener
m_oEventList = (BlackBerryPIMList)oPIM.openPIMList(PIM.EVENT_LIST, PIM.READ_WRITE);
m_oEventList.addListener(this);
}

if(MEMO_LIST == (nType & MEMO_LIST))
{
// Memo listener
m_oMemoList = (BlackBerryMemoList)oPIM.openPIMList(BlackBerryPIM.MEMO_LIST, PIM.READ_WRITE);
m_oMemoList.addListener(this);
}
}
catch(PIMException e)
{
e.printStackTrace();
}
}

/**
* Removes listener added to the list specified by the user.
*/
public void fnRemoveListener()
{
if(null != m_oContactList)
{
m_oContactList.removeListener(this);
}

if(null != m_oToDoList)
{
m_oToDoList.removeListener(this);
}

if(null != m_oEventList)
{
m_oEventList.removeListener(this);
}

if(null != m_oMemoList)
{
m_oMemoList.removeListener(this);
}
}

// Occurs when an item is added to the PIM list.
public void itemAdded(PIMItem oItem)
{
fnNotifyPIMChange(ADD, null, oItem);
}

// Occurs when an item is removed from the PIM list.
public void itemRemoved(PIMItem oItem)
{
fnNotifyPIMChange(DELETE, null, oItem);
}

// Occurs when an item is updated within the PIM list.
public void itemUpdated(PIMItem oOldItem, PIMItem oNewItem)
{
fnNotifyPIMChange(UPDATE, oOldItem, oNewItem);
}

private void fnNotifyPIMChange(int nOperation, PIMItem oOldItem, PIMItem oNewItem)
{
if(oNewItem instanceof Contact)
{
switch(nOperation)
{
case ADD:
{
fnOnContactAdded((Contact)oNewItem);
break;
}
case DELETE:
{
fnOnContactDeleted((Contact)oNewItem);
break;
}
case UPDATE:
{
fnOnContactUpdated((Contact)oOldItem, (Contact)oNewItem);
break;
}
}
}
else if(oNewItem instanceof ToDo)
{
switch(nOperation)
{
case ADD:
{
fnOnTaskAdded((ToDo)oNewItem);
break;
}
case DELETE:
{
fnOnTaskDeleted((ToDo)oNewItem);
break;
}
case UPDATE:
{
fnOnTaskUpdated((ToDo)oOldItem, (ToDo)oNewItem);
break;
}
}
}
else if(oNewItem instanceof Event)
{
switch(nOperation)
{
case ADD:
{
fnOnAppointmentAdded((Event)oNewItem);
break;
}
case DELETE:
{
fnOnAppointmentDeleted((Event)oNewItem);
break;
}
case UPDATE:
{
fnOnAppointmentUpdated((Event)oOldItem, (Event)oNewItem);
break;
}
}
}
else if(oNewItem instanceof BlackBerryMemo)
{
switch(nOperation)
{
case ADD:
{
fnOnMemoAdded((BlackBerryMemo)oNewItem);
break;
}
case DELETE:
{
fnOnMemoDeleted((BlackBerryMemo)oNewItem);
break;
}
case UPDATE:
{
fnOnMemoUpdated((BlackBerryMemo)oOldItem, (BlackBerryMemo)oNewItem);
break;
}
}
}
}

/**
* Occurs when contact is added to contact list.
* @param oItem Contact that is added to the contact list.
*/
public void fnOnContactAdded(Contact oContact)
{
}

/**
* Occurs when Contact is deleted from contact list.
* @param oItem Contact that is deleted from the contact list.
*/
public void fnOnContactDeleted(Contact oContact)
{
}

/**
* Occurs when Contact is updated in contact list.
* @param oOldItem State of Contact before update.
* @param oNewItem New state of Contact as a result of update.
*/
public void fnOnContactUpdated(Contact oOldContact, Contact oNewContact)
{
}

/**
* Occurs when ToDo(i.e. task) is added to task list.
* @param oItem ToDo(i.e. task) that is added to the task list.
*/
public void fnOnTaskAdded(ToDo oToDo)
{
}

/**
* Occurs when ToDo(i.e. task) is deleted from task list.
* @param oItem ToDo(i.e. task) that is deleted from the task list.
*/
public void fnOnTaskDeleted(ToDo oToDo)
{
}

/**
* Occurs when ToDo(i.e. task) is updated in task list.
* @param oOldItem State of ToDo(i.e. task) before update.
* @param oNewItem New state of ToDo(i.e. task) as a result of update.
*/
public void fnOnTaskUpdated(ToDo oOldToDo, ToDo oNewToDo)
{
}

/**
* Occurs when Event(i.e. appointment) is added to appointment list.
* @param oItem Event(i.e. appointment) that is added to the appointment list.
*/
public void fnOnAppointmentAdded(Event oEvent)
{
}

/**
* Occurs when Event(i.e. appointment) is deleted from appointment list.
* @param oItem Event(i.e. appointment) that is deleted from the appointment list.
*/
public void fnOnAppointmentDeleted(Event oEvent)
{
}

/**
* Occurs when Event(i.e. appointment) is updated in appointment list.
* @param oOldItem State of Event(i.e. appointment) before update.
* @param oNewItem New state of Event(i.e. appointment) as a result of update.
*/
public void fnOnAppointmentUpdated(Event oOldEvent, Event oNewEvent)
{
}

/**
* Occurs when BlackBerryMemo(i.e. memo) is added to memo list.
* @param oItem BlackBerryMemo(i.e. memo) that is added to the memo list.
*/
public void fnOnMemoAdded(BlackBerryMemo oBlackBerryMemo)
{
}

/**
* Occurs when BlackBerryMemo(i.e. memo) is deleted from memo list.
* @param oItem BlackBerryMemo(i.e. memo) that is deleted from the memo list.
*/
public void fnOnMemoDeleted(BlackBerryMemo oBlackBerryMemo)
{
}

/**
* Occurs when BlackBerryMemo(i.e. memo) is updated in memo list.
* @param oOldItem State of BlackBerryMemo(i.e. memo) before update.
* @param oNewItem New state of BlackBerryMemo(i.e. memo) as a result of update.
*/
public void fnOnMemoUpdated(BlackBerryMemo oOldBlackBerryMemo, BlackBerryMemo oNewBlackBerryMemo)
{
}
}

Friday, March 12, 2010

Java Time Difference Function

In one of project, there was need to find difference between two timestamps. It is normally required when you have from and to time fields.

In our case we wanted difference between to time and from time like "12.21pm" and "11.21am". So I have written the following function. With specifying string format user will be able to get difference in seconds.

Click link for pattern format letters

Function:

public static long fnGetTimeDifference(String strFormat, String strFromTime, String strToTime)
{
long lDifference = -1;

try
{
SimpleDateFormat oSimpleDateFormat = new SimpleDateFormat(strFormat);

Date oFromTimeDate = oSimpleDateFormat.parse(strFromTime);
Date oToTimeDate = oSimpleDateFormat.parse(strToTime);

lDifference = (oToTimeDate.getTime() - oFromTimeDate.getTime()) / 1000;

System.out.println("Time Difference: " + lDifference + " seconds");
}
catch (ParseException e1)
{
e1.printStackTrace();
}

return lDifference;
}


Function call example:

fnGetTimeDifference(“hh:mma”, “11.21am”, “12.21pm”);

Thursday, February 25, 2010

Queue in Blackberry

The java.util or net.rim.device.api.util packages of blackberry does not have Queue class. In queue elements are removed in the same order in which they are added. This is called as FIFO, meaning First In First Out. Queue is data structure and is required for various purposes. Queue data structure works as normal queue you can see for getting tickets, boarding on plane or bus where the first person is served and the new person joins at the end of the queue.


Two basic operations that should be supported by queue are:

1. Enqueue: Inserts element at the end of queue.
2. Dequeue: Removes element from the top of the queue and return that element.


There can be various approach to do this, but this one is using Vector class of java.util package. (Instead of Vector, LinkedList will be useful but LinkedList is also not supported and for now I am not creating LinkedList class). In this approach, Vector is composited in Queue class.


Queue Class:

import java.util.*;

/**
* Queue.java
* A queue of objects in which elements are removed in the same order they have entered (FIFO).
* @author Dipak Vanarse
*/
public class Queue
{
private Vector m_oItems;

/**
* Constructor
*/
public Queue()
{
m_oItems = new Vector();
}

/**
* Inserts an element at the end of the queue.
* @param oElement Element to be inserted.
*/
public Object enqueue(Object oElement)
{
m_oItems.addElement(oElement);
return oElement;
}

/**
* Removes the element at the top of the queue.
* @return The removed element.
* @throws EmptyQueueException if the queue is empty.
*/
public Object dequeue() throws EmptyQueueException
{
// If there are no items in the list
if(0 == m_oItems.size())
{
// Exception
throw new EmptyQueueException();
}

// Remove element at the top and return it
Object oItem = m_oItems.elementAt(0);
m_oItems.removeElementAt(0);
return oItem;
}

/**
* @return The total number of elements in the queue.
*/
public int size()
{
return m_oItems.size();
}

/**
* @return true if the queue is empty, and false otherwise.
*/
public boolean empty()
{
return (0 == m_oItems.size());
}

/**
* Inspects the element at the top of the queue without removing it.
* @return A reference to the value at the front of a non-empty queue; null if the queue is empty
*/

public Object front()
{

if(m_oItems.size()== 0)
{
m_oItems.elementAt(0);
}

return
}
}