Monday, July 6, 2009

Know your audience

Which handsets are actually downloading your Java ME application? How many users report that your applications runs fine with their handsets? The answers are available to GetJar developers at Download Stats - Compatibility report, but I had a problem with it...


Since 2009 May, 14 my chess board has two versions available, one for MIDP 1.0 handsets and another for MIDP 2.0. From this day onwards I evaluate weekly downloads with handset details. At June, 7 I noticed that the most active handset at MIDP 1.0 version (Nokia 3110c - with 11% of all downloads and 53% of new downloads since May, 14) has droped to zero downloads, but appeared at MIDP 2.0 version and now it is one of the top 10 downloaders.



  1. Nokia N73

  2. Nokia 6300

  3. Sony-Ericsson K800i

  4. Nokia N70-1

  5. Nokia 5800 XpressMusic

  6. Nokia 6600

  7. Nokia E71

  8. Nokia 5310 XpressMusic

  9. Nokia 3110c

  10. Sony-Ericsson W200i

According to the official site this device is really MIDP 2.0, so it was an error from GetJar to have it download MIDP 1.0 content to begin with. So what? Other 43 handsets are still downloading MIDP 1.0 version, below are the top 10 downloaders since May, 14.



  1. Nokia 3100

  2. Nokia 3120

  3. Samsung SGH D900i

  4. Nokia 3200

  5. Nokia N-Gage QD

  6. Nokia 6610i

  7. Sony-Ericson T610

  8. Samsung SGH U700

  9. Nokia N-Gage

  10. Nokia 7210


Related topics:

Tuesday, June 30, 2009

Adding a scrollbar

Sometimes you have more data to show than available space. One way to make this clear to the user is presenting a scroll bar.
Lets update our custom alert to paint a scroll bar when necessary.
Below is the source code of my simple scroll bar component:

import javax.microedition.lcdui.Graphics;

public class Scrollbar {

private int x, y, width, height;
private int total; // how much you have to present
private int position; // what you are presenting
private int backgroundColor = 0xffffff;
private int foregroundColor;
private int indicatorHeight;

/**
* @param part how much can be presented to the user at a time
*/
public Scrollbar(int x, int y, int w, int h,
int part, int total)
{
this.x = x; this.y = y; this.width = w; this.height = h;
this.total = total;
// the indicator height is calculated as a proportion of h
indicatorHeight = (part * h) / total;
// sanity test
if (indicatorHeight >= height) {
indicatorHeight = height / 2;
}
}

public void setPosition(int position) {
this.position = position;
}

public void setBackgroundColor(int backgroundColor) {
this.backgroundColor = backgroundColor;
}

public void setForegroundColor(int foregroundColor) {
this.foregroundColor = foregroundColor;
}

public void paint(Graphics g) {
int indicatorY = (this.position * this.height) / this.total;

// sanity test, can not draw below the height
if (indicatorY + this.indicatorHeight > height) {
indicatorY = height - this.indicatorHeight;
}

g.setColor(this.backgroundColor);
g.fillRect(x, y, width, height);
g.setColor(this.foregroundColor);
g.fillRect(x, indicatorY, width, indicatorHeight);
}
}

Now lets use the scroll bar. Define an Scrollbar attribute and create an instance right after you have initiated your message array:

// how many lines the user can see at a time
int maxLines = this.getHeight() / Font.getDefaultFont().getHeight();

if (maxLines < this.message.length) {
// 10 = scroll bar width. Remember to also subtract this value
// when initiating message array
this.scrollbar = new Scrollbar(getWidth() - 10, 0, 10, getHeight(),
maxLines, this.message.length)
}

At commandAction right after you update messageFirstLineShown:

if (this.scrollbar != null) {
this.scrollbar.setPosition(this.messageFirstLineShown);
}

At paint method:

if (this.scrollbar != null) {
this.scrollbar.paint(g);
}

Now, when the user press Next command he will see the scroll bar indicator move downwards.
This is a simple implementation with a simple usage. Feel free to change any part of it on your project.

Related topics:

Saturday, June 20, 2009

Key Repetition with TimerTask

It is not friendly to force your user to repeat key presses. My CustomImplicitList had this fault. If you wanted to move the selection using up/down keys or 2/8 numbers you had to press the key once for every change. To avoid this I made a simple change, adding the following method:

protected void keyRepeated(int keyCode) {
this.keyPressed(keyCode);
}

Now the user can press and hold a key to keep changing the selection, right? Wrong! Because not all Java ME Virtual Machines call keyRepeated. You can know it by calling Canvas.hasRepeatEvents(). So, how do we grant key repetition to these devices?

I could use a Thread and flag attributes to solve this problem, but I prefer creating an inner class at CustomImplicitList:

class KeyRepeatTask extends TimerTask {
public void run() {
if (isShown() && keyCode != Integer.MIN_VALUE) {
keyPressed(keyCode);
}
}
}

Two new attributes will help me control the key repetition:

private Timer keyRepeatTimer;
private int keyCode = Integer.MIN_VALUE;

To start the key repetition I added the following lines to the very start of keyPressed method:

if (this.hasRepeatEvents() == false && this.keyCode == Integer.MIN_VALUE) {
this.keyCode = keyCode;
this.keyRepeatTimer = new Timer();
// keep repeating the task at each 700 milliseconds
this.keyRepeatTimer.scheduleAtFixedRate(new KeyRepeatTask(), new Date(), 700);
}

To stop the key repetition I added the following method:

protected void keyReleased(int keyCode) {
if (this.keyRepeatTimer != null) {
this.keyCode = Integer.MIN_VALUE;
this.keyRepeatTimer.cancel();
this.keyRepeatTimer = null;
}
}

How did I test this? First I removed the implementation of keyRepeated and added hasRepeatEvents always returning false. Then I executed my use case on emulators and personal handsets. Of course this is not enough to guarantee the same behavior on all Java ME enabled handsets, as this is highly dependendent on the correct implementation of hasRepeatEvents but is a safe start.

If you find out this code does not work on your handset, please let me know.

Related topics: