DurianBerry Digest March 2011

26
Amri Shodiq’s DurianBerry Digest March, 2011 HOW TO SOLVE “ATTEMPT TO PUSH SCREEN WHILE ALREADY DISPLAYED!”? 2 WHAT IS THE BEST WAY TO ADJUST YOUR BLACKBERRY APPLICATIONS TO VARIOUS SCREEN SIZE? 3 WHAT IS ANOTHER WAY TO KNOW BLACKBERRY’S USER LOCATION? 4 HOW TO USE BLACKBERRY CAMERA PROGRAMMATICALLY? 6 WILL INSTAGRAM CAME TO BLACKBERRY? 10 HOW TO GET URL PICTURE THAT WE POST VIA GRAPH API? 11 HOW TO SHOW THE TIME IN OUR BLACKBERRY APP LIKE FACEBOOK DID? 11 HOW TO DETECT IF A MEDIA CARD AVAILABLE IN BLACKBERRY? 13 HOW TO DELETE A FILE PROGRAMMATICALLY IN BLACKBERRY? 13 HOW TO GET A FILE’S CONTENT PROGRAMMATICALLY IN BLACKBERRY? 14 HOW TO CALCULATE THE NUMBER OF ROWS NEEDED FOR A GIVEN STRING? 15 1 | DurianBerry Digest

Transcript of DurianBerry Digest March 2011

Page 1: DurianBerry Digest March 2011

Amri Shodiq’s

DurianBerry DigestMarch, 2011

HOW TO SOLVE “ATTEMPT TO PUSH SCREEN WHILE ALREADY DISPLAYED!”? 2

WHAT IS THE BEST WAY TO ADJUST YOUR BLACKBERRY APPLICATIONS TO VARIOUS SCREEN SIZE? 3

WHAT IS ANOTHER WAY TO KNOW BLACKBERRY’S USER LOCATION? 4

HOW TO USE BLACKBERRY CAMERA PROGRAMMATICALLY? 6

WILL INSTAGRAM CAME TO BLACKBERRY? 10

HOW TO GET URL PICTURE THAT WE POST VIA GRAPH API? 11

HOW TO SHOW THE TIME IN OUR BLACKBERRY APP LIKE FACEBOOK DID? 11

HOW TO DETECT IF A MEDIA CARD AVAILABLE IN BLACKBERRY? 13

HOW TO DELETE A FILE PROGRAMMATICALLY IN BLACKBERRY? 13

HOW TO GET A FILE’S CONTENT PROGRAMMATICALLY IN BLACKBERRY? 14

HOW TO CALCULATE THE NUMBER OF ROWS NEEDED FOR A GIVEN STRING? 15

HOW TO MAKE TOOLTIPS IN BLACKBERRY OUR APPLICATION? 17

1 | D u r i a n B e r r y D i g e s t

Page 2: DurianBerry Digest March 2011

How to solve “Attempt to push Screen while already displayed!”?I tried to implement a waiting screen for my Blackberry application. I wrote a class namedViewLoading.java. This

class extends PopupScreen and I put in it a LabelField with “Loading…” text and an AnimatedGIFField. For the sake

of memory usage, I just want to instantiate this screen only once for the entire application execution.

So, this are what I did:

1. Make a private variable in my ViewController (this is my controller class for all Views to controll all screens), named

loading.

2. Make two public method to show the waiting screen, called showLoading(), and to hide it, calledhideLoading().

3. In the showLoading() method I wrote code like this:

if (loading == null) loading = new ViewLoading(); if (!loading.isDisplayed()) {   UiApplication.getUiApplication().invokeLater(new Runnable() {      public void run() {         UiApplication.getUiApplication().pushScreen(loading);      }   });}

I think that is the best practice to do it. Unfortunately it’s not. When my code tried to call this method from a

background thread, there’s an IllegalArgumentException occure. This is happen when there are more than one

background thread tried to call showLoading() at nearly the same time. I think what happen is:

Thread A called showLoading

Thread B called showLoading, at nearly the same time with (but after) A

Thread A check if loading is displayed and it received false

Thread B doing so, and received false also

Thread A trying to push loading into the screen stack, it works

Thread B trying to push loading into the screen stack (because B knows that loading is not displayed, but it’s wrong),

it failed because loading has been displayed and throw IllegalArgumentException

Here is what I did to my code to solve the problem.

if (loading == null) loading = new ViewLoading(); if (!loading.isDisplayed()) {   UiApplication.getUiApplication().invokeLater(new Runnable() {      public void run() {         try {            UiApplication.getUiApplication().pushScreen(loading);         } catch (Exception e) {         }      }   });}

Yes, I catch the Exception without do anything there. I did relatively the same for hideLoading(). Of course without the

first line. It works.

2 | D u r i a n B e r r y D i g e s t

Page 3: DurianBerry Digest March 2011

I once add System.out.println(“Ex: “+e.getMessage()); in the catch block, then I found the message is “Attempt to

push Screen while already displayed!“. Make sense isn’t it?

Although this code works, I doubt that this is the best practice for this case. Is there anyone know how to implement it

better?

What is the best way to adjust your Blackberry applications to various screen size?One of the most complained problem in Blackberry application development is Blackberry’s various screen size.

Providing a single compiled software for each type of device is not everyone’s choice. What we want is a single

compiled software would match every (most) type. Then, the problem is how to do so? The answer is scaling!

But what things must we scale?

1. integers, when we able to scale integers, then we would be able to scale another

2. Fonts, each type has it’s own proportion of fonts so we need to scale them

3. images, I prefer to use EncodedImages than Bitmaps because they’re simply scalable

First, we need to define a standard density

private static final int STANDARD_DENSITY = 9708;

I use Onyx as the standard. Onyx’s screen dimension is 480 x 360. I will design all the images used in my application

using 480 x 360. The magic number 9708 came from Onyx’s vertical resolution.

Then I will scale down the design based on device’s vertical resolution. So I need a ratio.

private static final int RATIO32 = Fixed32.div(   Fixed32.toFP(Display.getVerticalResolution()),   Fixed32.toFP(STANDARD_DENSITY));

So, how do we scale integers?

public static int scaleInt(int value) {   return Fixed32.toInt(value * RATIO32);}

Then, how do we scale Fonts?

public static Font scaleFont(Font f) {   return f.derive(f.getStyle(), Fixed32.toInt(f.getHeight() * RATIO32),      Ui.UNITS_px);

3 | D u r i a n B e r r y D i g e s t

Page 4: DurianBerry Digest March 2011

}

The last one, how do we scale EncodedImages?

public static EncodedImage scaleImage(EncodedImage original) {   if (Display.getVerticalResolution() == STANDARD_DENSITY) {      return original;   } else      return ImageTools.scaleImageToHeight(original,         Fixed32.toInt(original.getHeight() * RATIO32));}

Well, that’s what I do. What about you? Do you have any solution better than this?

If so, share it here!

What is another way to know Blackberry’s user location?Yes, we could use RIM’s Locate Service. It’s good and pretty fast. The problem is the data completeness. I’ve used

this service in my application, using cell tower, not GPS. It’s just not work at some points. So, we must use other

service that supply more complete data. For complement. When RIM’s Locate Service failed, then we switch to

another service.

Yes, there are some location service. IMHO, the most powerfull one is Google’s secret API for google maps. And,

here I will share how I use this service, for educational only.

The fact, is that I couldn’t use this service directly from Blackberry device when we connect via BIS-B network, I don’t

know why. I presume that Google blacklisted MDS’s IP address. So, we need to make some kind of proxy to the

service. Well, I’ve implemented one a year ago. I wrote it a year ago and keep it secret. Well, it’s not fully my code. I

translate it from Android code written by a cool guy, Poorman.

Here is the code.

<?php    define("FAILED_TO_POST_DATA", -1);    define("INVALID_LAC_OR_CID", -2);    define("CANNOT_DETERMINE_LOCATION", -3);     if (isset($_REQUEST["lac"]) && isset($_REQUEST["cid"])) {        $data =                "x00x0e".                "x00x00x00x00x00x00x00x00".                "x00x00".                "x00x00".                "x00x00".                "x1b".                "x00x00x00x00".                "x00x00x00x00".

4 | D u r i a n B e r r y D i g e s t

Page 5: DurianBerry Digest March 2011

                "x00x00x00x00".                "x00x00".                "x00x00x00x00".                "x00x00x00x00".                "x00x00x00x00".                "x00x00x00x00".                "xffxffxffxff".                "x00x00x00x00";         $is_umts_cell = ($cid > 65535);        if ($is_umts_cell) // GSM: 4 hex digits, UTMS: 6 hex digits            $data[0x1c] = 5;        else            $data[0x1c] = 3;         $hexlac = substr("00000000".dechex($_REQUEST["lac"]),-8);        $hexcid = substr("00000000".dechex($_REQUEST["cid"]),-8);         $data[0x1f] = pack("H*",substr($hexcid,0,2));        $data[0x20] = pack("H*",substr($hexcid,2,2));        $data[0x21] = pack("H*",substr($hexcid,4,2));        $data[0x22] = pack("H*",substr($hexcid,6,2));         $data[0x23] = pack("H*",substr($hexlac,0,2));        $data[0x24] = pack("H*",substr($hexlac,2,2));        $data[0x25] = pack("H*",substr($hexlac,4,2));        $data[0x26] = pack("H*",substr($hexlac,6,2));         /* I used file_get_contents() at my laptop webserver, but it seems like the PHP version         * at my hosting company is old and it is not supporting that.         * For the hosting company, here we're using cURL.         */        $use_curl = false;        if ($use_curl) {            $ch = curl_init();            curl_setopt($ch, CURLOPT_URL, "http://www.google.com/glm/mmap");            curl_setopt($ch, CURLOPT_HEADER, true);            curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);            curl_setopt($ch, CURLOPT_BINARYTRANSFER, 1);            curl_setopt($ch, CURLOPT_HTTPHEADER, Array("Content-type: application/binary"));            curl_setopt($ch, CURLOPT_POSTFIELDS, $data);            curl_setopt($ch, CURLOPT_POST, 1);            $response = curl_exec($ch);            if (curl_errno($ch))                exit(FAILED_TO_POST_DATA);             $header_size = curl_getinfo($ch, CURLINFO_HEADER_SIZE);            $str = substr($response, $header_size);             curl_close($ch);        } else {            $context = array (                'http' => array (                    'method' => 'POST',                    'header'=> "Content-type: application/binaryrn"

5 | D u r i a n B e r r y D i g e s t

Page 6: DurianBerry Digest March 2011

                                . "Content-Length: " . strlen($data) . "rn",                                'content' => $data                )            );            $xcontext = stream_context_create($context);            $str=file_get_contents("http://www.google.com/glm/mmap", FALSE, $xcontext);        }         $opcode1 = ((ord($str[0]) << 8)) | ord($str[1]);        $opcode2 = ord($str[2]);         if (($opcode1 != 0x0e) || ($opcode2 != 0x1b))            exit(INVALID_LAC_OR_CID);         $retcode = ((ord($str[3]) << 24) | (ord($str[4]) << 16) | (ord($str[5]) << 8) | (ord($str[6])));        if ($retcode != 0)            exit(INVALID_LAC_OR_CID);         $lat = ((ord($str[7]) << 24) | (ord($str[8]) << 16) | (ord($str[9]) << 8) | (ord($str[10]))) / 1000000;        $lon = ((ord($str[11]) << 24) | (ord($str[12]) << 16) | (ord($str[13]) << 8) | (ord($str[14]))) / 1000000;         // exit script if cannot geocode cell e.g. not on google's database        if ($lat == 0 and $lon == 0)            exit(CANNOT_DETERMINE_LOCATION);         echo $lat . ',' . $lon;    }?>

So, how about that? Cool isn’t it?

You can try the code by access the code at: http://www.durianberry.com/api/latlong.php?lac=10001&cid=4390.

Replace the lac and cid parameter with your device’s LAC and cell id.

To get the LAC and Cell ID of Blackberry device, you could use these lines

int cellId = GPRSInfo.getCellInfo().getCellId();int lac = GPRSInfo.getCellInfo().getLAC();

Do you have a better solution than using Google’s data?

How to use Blackberry camera programmatically?Some days ago, one of Indonesia Blackberry Developer community member ask about how to capture image using

Blackberry’s camera, and then send it using email.  Actually, I have a simple reusable code to do this.

6 | D u r i a n B e r r y D i g e s t

Page 7: DurianBerry Digest March 2011

Cameras are often used in today’s application since the 2010′s trend of picture sharing led by Facebook as well as

Instagram (iPhone app). So, in my humble opinion, the existance of a ready made and simple to use API for taking

picture with Blackberry is a must. I wonder why noone shared this simple code yet.

Basically, there are 2 ways to capture image with Blackberry:

1. Use native Blackberry camera application by using Invoke API.

2. Use J2ME Video Control.

So, here is my code to capture image using Blackberry. I’ll share the second way. I hope this would be usefull for

anyone need it.

package com.durianberry.nc.view; import javax.microedition.media.Manager;import javax.microedition.media.Player;import javax.microedition.media.control.VideoControl; import net.rim.device.api.system.EncodedImage;import net.rim.device.api.ui.Field;import net.rim.device.api.ui.Graphics;import net.rim.device.api.ui.Screen;import net.rim.device.api.ui.UiApplication;import net.rim.device.api.ui.component.LabelField;import net.rim.device.api.ui.container.MainScreen;import net.rim.device.api.ui.container.VerticalFieldManager; /** * NcCamera is a simple yet ready made screen to capture picture using * Blackberry. * @author Amri Shodiq */public class NcCamera extends MainScreen {    private VideoControl videoControl;    private Field videoField;    private EncodedImage pictureTaken = null;    private boolean initialized = false;    private boolean result;     public static boolean CAPTURING_DONE = true;    public static boolean CAPTURING_CANCELED = false;     private VerticalFieldManager main;     private static NcCamera instance;     public NcCamera() {        super(NO_VERTICAL_SCROLL);        main = new VerticalFieldManager(USE_ALL_WIDTH | USE_ALL_HEIGHT) {            // I wan't to force the backgound to black            public void paintBackground(Graphics g) {                g.setBackgroundColor(0x000000);                g.clear();            }        };        super.add(main);    }

7 | D u r i a n B e r r y D i g e s t

Page 8: DurianBerry Digest March 2011

     public void add(Field field) {        main.add(field);    }     public EncodedImage getPictureTaken() {        return pictureTaken;    }     public Screen getThisScreen() {        return this;    }     public void reset() {        pictureTaken = null;        result = CAPTURING_CANCELED;    }     public boolean showDialog() {        result = CAPTURING_CANCELED;        UiApplication.getUiApplication().invokeAndWait(new Runnable() {            public void run() {                UiApplication.getUiApplication().pushModalScreen(getThisScreen());                if (pictureTaken != null) result = CAPTURING_DONE;            }        });        return result;    }     public static NcCamera getInstance() {        if (instance == null) instance = new NcCamera();        return instance;    }     public void onDisplay() {        if (!initialized) {            initializeCamera();            if (videoField!=null) add(videoField);            else {                LabelField sorry = new LabelField("Sorry, we cannot use camera right now.") {                    // I need to force the label to be white colored to be visible above                    // it's underlying manager (that is black).                    public void paint(Graphics g) {                        int color = g.getColor();                        g.setColor(0xffffff);                        super.paint(g);                        g.setColor(color);                    }                };                add(sorry);            }            initialized = true;        }    }

8 | D u r i a n B e r r y D i g e s t

Page 9: DurianBerry Digest March 2011

     private void initializeCamera() {        try {            // Create a player for the Blackberry's camera            Player player = Manager.createPlayer("capture://video?encoding=jpeg&width=1024&height=768");             // Set the player to the REALIZED state (see Player javadoc)            player.realize();             videoControl = (VideoControl) player.getControl("VideoControl");             if (videoControl != null) {                videoField = (Field) videoControl.initDisplayMode(                        VideoControl.USE_GUI_PRIMITIVE,                        "net.rim.device.api.ui.Field");                videoControl.setDisplayFullScreen(true);                videoControl.setVisible(true);            }             player.start();        } catch (Exception e) {        }    }     protected boolean invokeAction(int action) {        boolean handled = super.invokeAction(action);         if (!handled) {            switch (action) {            case ACTION_INVOKE: // Trackball click            {                takePicture();                return true;            }            }        }        return handled;    }     public boolean keyDown(int keycode,            int time) {        if (keycode == 1769472) { // escape pressed            reset();            close();            return true;        }        return super.keyDown(keycode, time);    }     public void takePicture() {        try {            // Retrieve the raw image from the VideoControl and            // create a screen to display the image to the user.            byte[] raw = videoControl.getSnapshot(null);             // save the picture taken into pictureTaken variable

9 | D u r i a n B e r r y D i g e s t

Page 10: DurianBerry Digest March 2011

            pictureTaken = EncodedImage.createEncodedImage(raw, 0, raw.length);            result = CAPTURING_DONE;             close();        } catch (Exception e) {        }    } }

Use this code using it’s static method getInstance() that will make an instance (and only one for the entire

application, so this way should make the application memory friendly), and then call showDialog() that will push this

screen. The next step is, if the dialog returning CAPTURING_DONE constant, then we could retrieve the previous

picture taken with camera using method getPictureTaken().

Here is an example of how to use it:

if (NcCamera.getInstance().showDialog() == NcCamera.CAPTURING_DONE) {    Dialog.alert("Image captured.");    EncodedImage result = NcCamera.getInstance().getPictureTaken();} else    Dialog.alert("Capturing canceled.");

That’s it. It’s easy right? Do you have a better idea?

Will Instagram came to Blackberry? 

I found this Instagram post.

Well, it’s quite insulting. What to say? People will insults until you prove the

opposite. Will we be able to mimic Instagram’s ability to capture, make filters and

then share pictures just like Instagram do?

Anyone will accept this insulting challenge? We’ll see.

10 | D u r i a n B e r r y D i g e s t

Page 11: DurianBerry Digest March 2011

How to get URL picture that we post via Graph API?Last night I’m struggling with Facebook API for Blackberry (that is written by Eki Baskoro). Well, I need to upload a

photo to Facebook (since I have no budget to host my own photos). Unfortunately, the API (version 4.5) has not

ready yet with photo upload. So I need to implement some methods on it to make it work.

This noon I found it works (on a simulator, not tested on real device yet). Then, came the second problem (the first

was how to upload the photo). The second problem is how to get the picture’s URL, since Graph API only returns the

photo ID. The return is just like this:

{"id":1850561300489}

So, we need to do something, right?

I found this reference: http://developers.facebook.com/docs/reference/api/photo/. This page told me that we could

access the detail photo API.

Here is the URL: https://graph.facebook.com/<photo-id>?access_token=<your-access-token>. The return is a

JSON Object containing id, name (title of the picture), picture (picture that resized into a smaller size), source (original

picture), link (link to a single page photo), and comments (comments for this image). We could use these information

to make a good wall post containing this picture (source) that linked to single page photo (link).

That’s it. Sorry, no source code this time. Maybe you could check the next release of Facebook’s Blackberry API.

What do you think? Do you think I should contact Eki to inform that I’ve implemented a method that I think important?

How to show the time in our Blackberry app like Facebook did?Do you notice how Facebook show the status’s time in our wall? Correct, it is said something like ‘two days ago’ or ‘a

minute ago’. Well, Twitter was done the same way before, but it’s changed. I don’t know why. This is actually a good

way to show time of posts or statuses in a timeline.

If you need to do so with your Blackberry application, then read this post carefully. I’ll show you how to do that in

Blackberry.

I wrote this simple code about 6 months ago when I tried to write my own Twitter client for Blackberry. I’ll show you

the logic. And, yes, of course the code.

The logic is simple:

1. We know the time T, pointing to an exact time of event in the past. We expressed it in long since we used

System.currentTimeMilis() to record the time T. We save it in variable named epoch.

2. We compare epoch with System.currentTimeMilis() a.k.a. exactly right now and save the result in variable

named difference.

3. We compare difference with some predefined constants from DateTimeUtilites (provided by RIM), for

example DateTimeUtilities.ONEMINUTE.

11 | D u r i a n B e r r y D i g e s t

Page 12: DurianBerry Digest March 2011

4. When difference less than DateTimeUtilities.ONEMINUTE, that means the event T occured less than one minute

ago. Then, we need to know the exact number of seconds elapsed. We will divide difference

with DateTimeUtilities.ONESECOND. We save the number in avariable named timeInt. We could do the rest for

another unit of time with relatively the same way. See the code for details.

5. If the value of timeInt less than or equal to DateTimeUtilities.ONESECOND, than we could say the time is ‘just now’

or ‘one second ago’. Else, we could say ‘<timeInt> seconds ago’.

Just like that. Easy huh?

And, here is as I promise, the code:

public static String epocToFacebookStyleString(long epoch) {        long now = System.currentTimeMillis();        long difference = now - epoch;         String timeStr = "";        int timeInt = 0;        if (difference < DateTimeUtilities.ONEMINUTE) {            timeInt = (int) (difference / DateTimeUtilities.ONESECOND);            if (timeInt <= 1)                timeStr = " just now";            else                timeStr = String.valueOf(timeInt) + " seconds ago";        } else if (difference < DateTimeUtilities.ONEHOUR) {            timeInt = (int) (difference / DateTimeUtilities.ONEMINUTE);            if (timeInt == 1)                timeStr = " a minute ago";            else                timeStr = String.valueOf(timeInt) + " minutes ago";        } else if (difference < DateTimeUtilities.ONEDAY) {            timeInt = (int) (difference / DateTimeUtilities.ONEHOUR);            if (timeInt == 1)                timeStr = " an hour ago";            else                timeStr = String.valueOf(timeInt) + " hours ago";        } else if (difference < DateTimeUtilities.ONEWEEK) {            timeInt = (int) (difference / DateTimeUtilities.ONEDAY);            if (timeInt == 1)                timeStr = " yesterday";            else                timeStr = String.valueOf(timeInt) + " days ago";        } else if (difference < DateTimeUtilities.ONEMONTH) {            timeInt = (int) (difference / DateTimeUtilities.ONEWEEK);            if (timeInt == 1)                timeStr = " a week ago";            else                timeStr = String.valueOf(timeInt) + " weeks ago";        } else if (difference < DateTimeUtilities.ONEYEAR) {            timeInt = (int) (difference / DateTimeUtilities.ONEMONTH);            if (timeInt == 1)                timeStr = " a month ago";            else                timeStr = String.valueOf(timeInt) + " months ago";        } else {            timeInt = (int) (difference / DateTimeUtilities.ONEYEAR);            if (timeInt == 1)

12 | D u r i a n B e r r y D i g e s t

Page 13: DurianBerry Digest March 2011

                timeStr = " a year ago";            else                timeStr = String.valueOf(timeInt) + " years ago";        }         return timeStr;    }

How to detect if a Media Card available in Blackberry?Sometimes, little mistakes makes our software looks bad. Just a simple condition that we never check before will

make users think that our software just doesn’t work. What if we tried to save a file to media card (programmatically),

but unfortunately the media card is not present? Exception of course. And what if the exception accidentally not

trapped?

Correct! Disaster.

Here is a simple code to detect if a Media Card available in Blackberry device.

public static boolean isSDCardAvailable() {        String root = null;        boolean result = false;        Enumeration e = FileSystemRegistry.listRoots();        while (e.hasMoreElements()) {            root = (String) e.nextElement();            if (root.equalsIgnoreCase("sdcard/")) {                result = true;            }        }        return result;    }

How to delete a file programmatically in Blackberry?Delete file is a simple task. Be carefull of the file’s path or your user will receive error message that you did not found

in the simulator.

First I check the file path’s validity and try to correct it if it is mistaken.

You could delete a file, for a given path, programmatically using these lines of code.

public static void deleteFile(String path) {        if (path.startsWith("file://")) {

13 | D u r i a n B e r r y D i g e s t

Page 14: DurianBerry Digest March 2011

            // do nothing        } else if (!path.startsWith("/"))            path = "file:///" + path;        else if (path.startsWith("//"))            path = "file:/" + path;        else            path = "file://" + path;         try {            FileConnection file = (FileConnection) Connector.open(path,                    Connector.READ_WRITE);            if (file.exists()) {                file.setWritable(true);                file.delete();            }            file.close();        } catch (IOException ex) {            System.out.println("File cannot be deleted");        }    }

How to get a file’s content programmatically in Blackberry?Getting file content (not in resource) is a must have technique for a programmer. We could show an image from a

media card in our application, but we must first get the image file’s content. We could show the content of a text file in

media card, but we must get this text file’s content first.

I’m pretty sure popular softwares like Blackberry’s built in Memo Pad, Ever Note and other text of image editor

software did this in relatively the same way.

Here is a sample code to show you how to get a file content programmatically in Blackberry.

/**     * Method to get all bytes from a file.     *     * @param path     * @return     * @throws IOException     */    public static byte[] getFileContent(String path) throws IOException {        FileConnection file = null;         if (path.startsWith("file://"))            path = path.substring(7);        else if (!path.startsWith("/"))            path = "/" + path;         try {            file = (FileConnection) Connector.open("file://" + path,                    Connector.READ);

14 | D u r i a n B e r r y D i g e s t

Page 15: DurianBerry Digest March 2011

            int fileSize = (int) file.fileSize();            if (fileSize > 0) {                byte[] data = new byte[fileSize];                InputStream input = file.openInputStream();                input.read(data);                Thread.yield();                input.close();                return data;            } else {                throw new NullPointerException("File " + path + " is empty.");            }        } catch (IOException e) {            throw e;        } finally {            if (file != null && file.isOpen())                file.close();        }    }

How to calculate the number of rows needed for a given String?Ever wonder how LabelField works? LabelField is just a pretty simple Field in Blackberry, but can you code yourself?

LabelField could calculate how many rows it needed to the given text parameter.

Actually to calculate the number of rows needed is not that simple. Just given String is not enough, you need another

two parameters. They are width and Font. When width is given, you know the boundary, that decide when to start a

new line. Given Font, you’ll know the space needed for a given text.

Ok, here is the code as always:

/**     * To calculate how many rows needed to draw for a given text, assumed not     * contain any carriage return (enter).     * @param text     * @param font     * @param width     */    public static int calculateRowNeeded(String text, Font font, int width) {        if (text.length() > 0) {            String[] texts = split(text, " ");            int len = texts.length;            if (len > 0) {                int i = 0;                int row = 1, left = 0, w;                while (i<len) {                    w = font.getAdvance(texts[i]);                    if (left + w < width) {                        left += w + font.getAdvance(" ");                    } else {

15 | D u r i a n B e r r y D i g e s t

Page 16: DurianBerry Digest March 2011

                        left = 0;                        row ++;                    }                    i++;                }                return row;            } else return 0;        } else return 0;    }

I know. I know.You’ll absolutely ask me what is split() anyway? Yes, split is just another method to split a String for a given delimiters returning array of String. Here is the code.

public static String[] split(String strString, String strDelimiter) {        int iOccurrences = 0;        int iIndexOfInnerString = 0;        int iIndexOfDelimiter = 0;        int iCounter = 0;         // Check for null input strings.        if (strString == null) {            throw new NullPointerException("Input string cannot be null.");        }        // Check for null or empty delimiter        // strings.        if (strDelimiter.length() <= 0 || strDelimiter == null) {            throw new NullPointerException("Delimeter cannot be null or empty.");        }         // If strString begins with delimiter        // then remove it in        // order        // to comply with the desired format.         if (strString.startsWith(strDelimiter)) {            strString = strString.substring(strDelimiter.length());        }         // If strString does not end with the        // delimiter then add it        // to the string in order to comply with        // the desired format.        if (!strString.endsWith(strDelimiter)) {            strString += strDelimiter;        }         // Count occurrences of the delimiter in        // the string.        // Occurrences should be the same amount        // of inner strings.        while ((iIndexOfDelimiter = strString.indexOf(strDelimiter,                iIndexOfInnerString)) != -1) {            iOccurrences += 1;            iIndexOfInnerString = iIndexOfDelimiter + strDelimiter.length();

16 | D u r i a n B e r r y D i g e s t

Page 17: DurianBerry Digest March 2011

        }         // Declare the array with the correct        // size.        String[] strArray = new String[iOccurrences];         // Reset the indices.        iIndexOfInnerString = 0;        iIndexOfDelimiter = 0;         // Walk across the string again and this        // time add the        // strings to the array.        while ((iIndexOfDelimiter = strString.indexOf(strDelimiter,                iIndexOfInnerString)) != -1) {             // Add string to            // array.            strArray[iCounter] = strString.substring(iIndexOfInnerString,                    iIndexOfDelimiter);             // Increment the            // index to the next            // character after            // the next            // delimiter.            iIndexOfInnerString = iIndexOfDelimiter + strDelimiter.length();             // Inc the counter.            iCounter += 1;        }        return strArray;    }

How to make tooltips in Blackberry our application?This question is asked frequently by Blackberry software developers. Even the good one.

The background is usual, RIM doesn’t provide such functionality by

default. Yes, they have it in their applications such as Facebook, but

the simply did not give any class or method in a class to do this. This

problem is frustating for some developers since most of their clients

requested this functionality but no standarized way to do this. Some

experienced developers has shared their code to help. For

example Naviina.

Well, their code was just work, but I think they over do this feature.

They used Timer and TimerTask just to make the tooltip autohide

after 20 seconds. Actually, in my experience, Timer and TimerTask

17 | D u r i a n B e r r y D i g e s t

Page 18: DurianBerry Digest March 2011

potentially cause a very bad and deadly TooManyThreadErrorException. Beware, you should stop any Timer when

you no longer use it.

I wrote my own class to implement tooltip functionality. It’s not a really pretty on but you can have the idea from this

implementation. And the tooltip will not autohide, but when you leave the field, the tooltip will dissapear of course.

You can have the class as you like:

package com.durianberry.tutorial; import net.rim.device.api.system.Display;import net.rim.device.api.ui.Field;import net.rim.device.api.ui.Font;import net.rim.device.api.ui.Graphics;import net.rim.device.api.ui.Manager;import net.rim.device.api.ui.Screen;import net.rim.device.api.ui.XYRect;import net.rim.device.api.ui.component.ButtonField;import net.rim.device.api.ui.component.LabelField;import net.rim.device.api.ui.container.HorizontalFieldManager;import net.rim.device.api.ui.container.MainScreen; /** * You can extends BasicScreen to implement your own screens * that will have tooltip functionality. Of course, you need to * remove the lines inside BasicScreen's constructor. * * @author Amri Shodiq * */public class BasicScreen extends MainScreen {    public BasicScreen() {        /**         * Here is example of how to use it. Pay attention to         * the first LabelField (labelled with 'B') and         * the ButtonField. We need to override their onFocus()         * and onUnfocus() method to get this work.         *         * Remove these lines if you wan't to use it in your         * projects.         */         HorizontalFieldManager h = new HorizontalFieldManager(                USE_ALL_WIDTH);        h.setPadding(10, 10, 10, 10);         h.add(new LabelField(" A ", FOCUSABLE));        h.add(new LabelField(" B ", FOCUSABLE) {            protected void onFocus(int direction) {                super.onFocus(direction);                showTooltip("B focused", this);            }            protected void onUnfocus() {                super.onUnfocus();                hideTooltip();            }        });

18 | D u r i a n B e r r y D i g e s t

Page 19: DurianBerry Digest March 2011

        h.add(new LabelField(" C ", FOCUSABLE) {            protected void onFocus(int direction) {                super.onFocus(direction);                showTooltip("C focused", this);            }            protected void onUnfocus() {                super.onUnfocus();                hideTooltip();            }        });         add(h);         ButtonField button = new ButtonField("Focus this to show " +                "tooltip") {            protected void onFocus(int direction) {                super.onFocus(direction);                showTooltip("Now, the button is focused", this);            }            protected void onUnfocus() {                super.onUnfocus();                hideTooltip();            }        };        // make distance with the labels above        button.setMargin(50, 10, 10, 10);         add(button);         add(new LabelField("And another thing", FOCUSABLE));    }     public void paint(Graphics g) {        super.paint(g);         // Three lines below to show tooltip as needed.        if (showTooltip) {            drawTooltip(g);        }    }     /*************************************************************     *     * This lines below used to implement tooltip functionality. *     *     *************************************************************/     /**     * Getting exact location and dimension of a given field.     * We need this to place our tooltip below the given field.     */    protected XYRect getFieldExtent(Field field) {        int cy = field.getTop();        int cx = field.getLeft();        Manager m = field.getManager();        while (m != null) {            cy += m.getTop() - m.getVerticalScroll();

19 | D u r i a n B e r r y D i g e s t

Page 20: DurianBerry Digest March 2011

            cx += m.getLeft() - m.getHorizontalScroll();            if (m instanceof Screen)                break;            m = m.getManager();        }        return new XYRect(cx, cy, field.getWidth(), field                .getHeight());    }     private Font tooltipFont = getFont(); // initialized with default screen's font    private String tooltipText;    private int tooltipX, tooltipY, count, tooltipYDistance = ScaleTools.scaleInt(4);    private boolean showTooltip;    private int tooltipBgColor = 0x000000, tooltipBorderColor = 0x666666,        tooltipFontColor = 0xFFFFFF, tooltipAlpha = 0xAA;     protected void hideTooltip() {        showTooltip = false;        invalidate();    }     protected void showTooltip(String text, Field attachedTo) {        if (showTooltip) hideTooltip();         tooltipText = text;        XYRect fieldPosition = getFieldExtent(attachedTo);        // to get tooltip's center point        tooltipX = fieldPosition.x + fieldPosition.width / 2;        // this line make tooltip placed under the attached field        tooltipY = fieldPosition.y + attachedTo.getHeight();         showTooltip = true;         invalidate();    }     protected void drawTooltip(Graphics g) {        int oldColor = g.getColor();         Font font = tooltipFont;         int padding = ScaleTools.scaleInt(8);        int borderSize = ScaleTools.scaleInt(2);         g.setFont(font);        int x = tooltipX -                (g.getFont().getAdvance(tooltipText) + padding) / 2;        int y = tooltipY + tooltipYDistance;        int width = font.getAdvance(tooltipText) + 2 * padding;        int height = font.getHeight() + 2 * padding;         // keep the tooltip inside screen's width range        if ((x + width) > Display.getWidth()) {            x = Display.getWidth() - padding - width;        }

20 | D u r i a n B e r r y D i g e s t

Page 21: DurianBerry Digest March 2011

        if (x < 0) {            x = padding;        }         // we make a semi transparent rounded rectangle with border        g.setGlobalAlpha(tooltipAlpha);         g.setColor(tooltipBorderColor);        g.fillRoundRect(x, y, width, height, font.getHeight(),                font.getHeight());        g.setColor(tooltipBgColor);        g.fillRoundRect(x + borderSize, y + borderSize,                width - 2 * borderSize, height - 2 * borderSize,                font.getHeight() - borderSize,                font.getHeight() - borderSize);         // we make the text's color solid so user will see it clearly        g.setGlobalAlpha(0xFF);         g.setColor(tooltipFontColor);        g.drawText(tooltipText, x + padding, y + padding);         g.setFont(font);        g.setColor(oldColor);    }     // This lines provide functionalities to customize tooltip's    // appearance    public void setTooltipYDistance(int tooltipYDistance) {        this.tooltipYDistance = tooltipYDistance;    }     public void setTooltipBgColor(int tooltipBgColor) {        this.tooltipBgColor = tooltipBgColor;    }     public void setTooltipBorderColor(int tooltipBorderColor) {        this.tooltipBorderColor = tooltipBorderColor;    }     public void setTooltipFontColor(int tooltipFontColor) {        this.tooltipFontColor = tooltipFontColor;    }     public void setTooltipAlpha(int tooltipAlpha) {        this.tooltipAlpha = tooltipAlpha;    }     public void setTooltipFont(Font tooltipFont) {        this.tooltipFont = tooltipFont;    } }

And here is an example of using BasicScreen in a very simple way.

21 | D u r i a n B e r r y D i g e s t

Page 22: DurianBerry Digest March 2011

package com.durianberry.tutorial; import net.rim.device.api.ui.UiApplication; public class AppMain extends UiApplication {    public AppMain() {        pushScreen(new BasicScreen());    }     public static void main(String[] args) {        new AppMain().enterEventDispatcher();    } }

What do you think? Is it helpful? Do not hesitate to press Like button below or post any comment.

22 | D u r i a n B e r r y D i g e s t

This content is based on my blog posts at

http://amrishodiq.durianberry.com. Any question, critics or suggestion, please simply comment on the blog

post or email me, [email protected]

I hope this information help others.