Fixed-point arithmetic methods of BlackBerry with example

You can use the methods thet are provide in the net.rim.device.api.math package to enhance the mathematical versatility and processing speed of BlackBerry device applications that you create.

The math.Fixed32 class is a collection of fixed-point arithmetic methods that use the 16.16 convention to fix the decimal point. This conventiom designates the most-significant 16-bits of the 32-bit int as the fixed-point component of the value, and the remainder as the decimal component
The following code sample demonstrates how you can and cannot use the Fixed32 class for addition, subtraction, multiplication, division, value conversion, and trigonometry.

import net.rim.device.api.math.*;
public class demoFixed32
{
demoFixed32()
{
// convert an integer to fixed-point
int n = Fixed32.toFP(7); // 7.0
// convert a quantity in ten-thousandths to fixed-point
int m = Fixed32.tenThouToFP(70625); // 7.0625
// convert from fixed-point, truncate fractional component
int trunc = Fixed32.toInt(m); // 7
// multiply by ten thousand
int mult = Fixed32.toIntTenThou(m); // 70625
// add, subtract, negate, and compare
int result = m - n; // 7.0625 - 7.0 == 0.0625
result = -result; // -0.0625
result -= n; // -0.0625 - 7.0 == -7.0625
boolean b = (result == -m); // true
boolean bb = (m < n); // false
// do not use increment and decrement operators
result = Fixed32.toFP(2);
++result; // WRONG! result will NOT be 3
result = Fixed32.toFP(2);
result += Fixed32.toFP(1); // Correct: result will be 3
// Use * and / when multiplying or dividing by an integer scalar
// Use mul to multiply 2 fixed-point numbers
// Use div to divide 2 fixed-point numbers
m = Fixed32.tenThouToFP(12500); // 1.25
m *= 3; // OK: 1.25 * 3 == 3.75
m /= 2; // OK: 3.75 / 2 == 1.875
m = Fixed32.mul(m, Fixed32.tenThouToFP(15000)); // 1.875 * 1.5000 == 2.8125
m = Fixed32.div(m, m); // 2.8125 / 2.8125 == 1.0
// mul, div, sqrt, sind, cosd, tand, and atand2
// all work with 16.16 fixed-point numbers
m = Fixed32.tenThouToFP(172500); // 17.2500
n = Fixed32.sqrt(m); // sqrt(17.25)
n = Fixed32.sind(m); // sine of 17.25 degrees
n = Fixed32.cosd(m); // cosine of 17.25 degrees
result = Fixed32.atand2(-m, -m); // -135.0 degrees in fixed-point
}
}

Drawing a 3-D cube on BlackBerry

You can use the GL10 interface to draw a 3-D cube:

import java.nio.ByteBuffer;
import java.nio.FloatBuffer;
import javax.microedition.khronos.egl.EGL10;
import javax.microedition.khronos.egl.EGL11;
import javax.microedition.khronos.egl.EGLConfig;
import javax.microedition.khronos.egl.EGLContext;
import javax.microedition.khronos.egl.EGLDisplay;
import javax.microedition.khronos.egl.EGLSurface;
import javax.microedition.khronos.opengles.GL10;
import net.rim.device.api.system.Bitmap;
import net.rim.device.api.ui.Graphics;
import net.rim.device.api.ui.container.FullScreen;
class ThreeDCube extends FullScreen implements Runnable
{
private EGL11 _egl;
private EGLDisplay _eglDisplay;
private EGLConfig _eglConfig;
private EGLSurface _eglSurface;
private EGLContext _eglContext;
private GL10 _gl;
private Bitmap _offscreenBitmap;
private Graphics _offscreenGraphics;
private boolean _running;
private boolean _paused;
private FloatBuffer _cubeVertices, _cubeNormals, _cubeColors;
float _angle = 45f;
private int _vertexCount;
private static final float[] _vertices =
{
// front
-0.5f, 0.5f, 0.5f, -0.5f, -0.5f, 0.5f, 0.5f, 0.5f, 0.5f,
0.5f, 0.5f, 0.5f, -0.5f, -0.5f, 0.5f, 0.5f, -0.5f, 0.5f,
// right
0.5f, 0.5f, 0.5f, 0.5f, -0.5f, 0.5f, 0.5f, 0.5f, -0.5f,
0.5f, 0.5f, -0.5f, 0.5f, -0.5f, 0.5f, 0.5f, -0.5f, -0.5f,
// back
0.5f, 0.5f, -0.5f, 0.5f, -0.5f, -0.5f, -0.5f, 0.5f, -0.5f,
-0.5f, 0.5f, -0.5f, 0.5f, -0.5f, -0.5f, -0.5f, -0.5f, -0.5f,
// left
-0.5f, 0.5f, -0.5f, -0.5f, -0.5f, -0.5f, -0.5f, 0.5f, 0.5f,
-0.5f, 0.5f, 0.5f, -0.5f, -0.5f, -0.5f, -0.5f, -0.5f, 0.5f,
// top
-0.5f, 0.5f, -0.5f, -0.5f, 0.5f, 0.5f, 0.5f, 0.5f, -0.5f,
0.5f, 0.5f, -0.5f, -0.5f, 0.5f, 0.5f, 0.5f, 0.5f, 0.5f,
// bottom
-0.5f, -0.5f, 0.5f, -0.5f, -0.5f, -0.5f, 0.5f, -0.5f, 0.5f,
0.5f, -0.5f, 0.5f, -0.5f, -0.5f, -0.5f, 0.5f, -0.5f, -0.5f
};
private static final float[] _normals =
{
/* front */ 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1,
/* right */ 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0,
/* back */ 0, 0, -1, 0, 0, -1, 0, 0, -1, 0, 0, -1, 0, 0, -1, 0, 0, -1,
/* left */ -1, 0, 0, -1, 0, 0, -1, 0, 0, -1, 0, 0, -1, 0, 0, -1, 0, 0,
/* top */ 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0,
/* bottom */ 0, -1, 0, 0, -1, 0, 0, -1, 0, 0, -1, 0, 0, -1, 0, 0, -1, 0
};
private static final float[] _colors =
{
/* front – white */ 1,1,1,1, 1,1,1,1, 1,1,1,1, 1,1,1,1, 1,1,1,1,
1,1,1,1,
/* right – red */ 1,0,0,1, 1,0,0,1, 1,0,0,1, 1,0,0,1, 1,0,0,1,
1,0,0,1,
/* back – green */ 0,1,0,1, 0,1,0,1, 0,1,0,1, 0,1,0,1, 0,1,0,1,
0,1,0,1,
/* left – blue */ 0,0,1,1, 0,0,1,1, 0,0,1,1, 0,0,1,1, 0,0,1,1,
0,0,1,1,
/* top - yellow */ 1,1,0,1, 1,1,0,1, 1,1,0,1, 1,1,0,1, 1,1,0,1, 1,1,0,1,
/* bottom - magenta*/ 1,0,1,1, 1,0,1,1, 1,0,1,1, 1,0,1,1, 1,0,1,1, 1,0,1,1
};
ThreeDCube()
{
super(FullScreen.DEFAULT_MENU | FullScreen.DEFAULT_CLOSE);
}
private void initialize()
{
// Get EGL interface
_egl = (EGL11)EGLContext.getEGL();
// Get the EGL display
_eglDisplay = _egl.eglGetDisplay(EGL11.EGL_DEFAULT_DISPLAY);
// Initialize the display for EGL, null since we don't really need the
// version.
_egl.eglInitialize(_eglDisplay, null);
// Choose an EGL config
EGLConfig[] configs = new EGLConfig[1];
int[] numConfigs = new int[1];
int[] attrs =
{
EGL11.EGL_RED_SIZE, 5,
EGL11.EGL_GREEN_SIZE, 6,
EGL11.EGL_BLUE_SIZE, 5,
EGL11.EGL_NONE
};
_egl.eglChooseConfig(_eglDisplay, attrs, configs, 1, numConfigs);
_eglConfig = configs[0];
// Create an EGL window surface
_eglSurface = _egl.eglCreateWindowSurface
(_eglDisplay, _eglConfig, this, null);
// Create an EGL context
createEGLContext();
_cubeVertices = createVertexBuffer();
_cubeNormals = createNormalBuffer();
_cubeColors = createColorBuffer();
_vertexCount = _vertices.length / 3;
}
private FloatBuffer createVertexBuffer()
{
FloatBuffer buffer = ByteBuffer.allocateDirect(_vertices.length *
4).asFloatBuffer();
buffer.put(_vertices);
buffer.rewind();
return buffer;
}
private FloatBuffer createNormalBuffer()
{
FloatBuffer buffer = ByteBuffer.allocateDirect(_normals.length *
4).asFloatBuffer();
buffer.put(_normals);
buffer.rewind();
return buffer;
}
private FloatBuffer createColorBuffer()
{
FloatBuffer buffer = ByteBuffer.allocateDirect(_colors.length *
4).asFloatBuffer();
buffer.put(_colors);
buffer.rewind();
return buffer;
}
private void createEGLContext()
{
// Create an EGL context
_eglContext = _egl.eglCreateContext
(_eglDisplay, _eglConfig, EGL10.EGL_NO_CONTEXT, null);
// Get the GL interface for our new context
_gl = (GL10)_eglContext.getGL();
// Make our new context current
_egl.eglMakeCurrent
(_eglDisplay, _eglSurface, _eglSurface, _eglContext);
}
private void destroyEGL()
{
_egl.eglMakeCurrent(_eglDisplay, EGL10.EGL_NO_SURFACE,
EGL10.EGL_NO_SURFACE, EGL10.EGL_NO_CONTEXT);
_egl.eglDestroyContext(_eglDisplay, _eglContext);
_egl.eglDestroySurface(_eglDisplay, _eglSurface);
}
private void handleContextLost()
{
// Destroy our EGL context
_egl.eglMakeCurrent(_eglDisplay, EGL10.EGL_NO_SURFACE,
EGL10.EGL_NO_SURFACE, EGL10.EGL_NO_CONTEXT);
_egl.eglDestroyContext(_eglDisplay, _eglContext);
_eglContext = EGL10.EGL_NO_CONTEXT;
// Re-create our EGL context
createEGLContext();
}
/**
* Main render loop.
*/
public void run()
{
initialize();
int throttle = 0;
while (_running)
{
throttle = (int)System.currentTimeMillis();
// Idle If we are in the background
if (_paused)
{
synchronized (this)
{
try
{
wait();
}
catch (InterruptedException x) { }
}
}
updateBackBuffer();
renderFrame();
++_angle;
if (_angle >= 360f)
{
_angle = 0f;
}
//Determine how long the frame took to render.
throttle = (int)System.currentTimeMillis() - throttle;
//Throttle to 30 FPS to control CPU usage.
throttle = 33 - throttle;
if (throttle > 0)
{
// Throttle cpu usage
try
{
Thread.sleep(throttle);
}
catch (InterruptedException x) { }
}
}
destroyEGL();
}
private void renderFrame()
{
// Make our context and surface current and check for EGL_CONTEXT_LOST
if (!_egl.eglMakeCurrent(_eglDisplay, _eglSurface, _eglSurface,
_eglContext))
{
if (_egl.eglGetError() == EGL11.EGL_CONTEXT_LOST)
handleContextLost();
}
// Signal that we are about to begin OpenGL rendering
_egl.eglWaitNative(EGL10.EGL_CORE_NATIVE_ENGINE, _offscreenGraphics);
render(_gl);
// Signal that OpenGL ES rendering is complete
_egl.eglWaitGL();
// Swap the window surface to the display
_egl.eglSwapBuffers(_eglDisplay, _eglSurface);
}
private void render(GL10 gl)
{
// Set our GL viewport
gl.glViewport(0, 0, getWidth(), getHeight());
// Clear the surface
gl.glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
gl.glClear(GL10.GL_COLOR_BUFFER_BIT | GL10.GL_DEPTH_BUFFER_BIT);
gl.glMatrixMode(GL10.GL_PROJECTION);
gl.glLoadIdentity();
net.rim.device.api.opengles.GLUtils.gluPerspective(gl, 45.0f,
(float)getWidth()/(float)getHeight(), 0.15f, 100.0f);
gl.glMatrixMode(GL10.GL_MODELVIEW);
gl.glLoadIdentity();
// Setup drawing state
gl.glEnable(GL10.GL_DEPTH_TEST);
gl.glEnable(GL10.GL_LIGHTING);
gl.glEnable(GL10.GL_LIGHT0);
gl.glEnable(GL10.GL_COLOR_MATERIAL);
// Draw our cube
gl.glTranslatef(0, 0, -3.5f);
gl.glRotatef(_angle, 1.0f, 1.0f, 0.0f);
gl.glEnableClientState(GL10.GL_VERTEX_ARRAY);
gl.glEnableClientState(GL10.GL_NORMAL_ARRAY);
gl.glEnableClientState(GL10.GL_COLOR_ARRAY);
gl.glVertexPointer(3, GL10.GL_FLOAT, 0, _cubeVertices);
gl.glNormalPointer(GL10.GL_FLOAT, 0, _cubeNormals);
gl.glColorPointer(4, GL10.GL_FLOAT, 0, _cubeColors);
gl.glDrawArrays(GL10.GL_TRIANGLES, 0, _vertexCount);
}
/**
* Called by the UI system to paint the screen.
*/
protected void paint(Graphics g)
{
if (_offscreenBitmap != null)
g.drawBitmap(0, 0, _offscreenBitmap.getWidth(),
_offscreenBitmap.getHeight(), _offscreenBitmap, 0, 0);
}
/**
* Called when the visibility of our screen changes.
*
* @param visible true if our screen is being made visible,
* false if it's being hidden
*/
protected void onVisibilityChange(boolean visible)
{
if (visible)
{
resume();
}
else
{
pause();
}
}
/**
* Called when the screen is closing.
*/
public void close()
{
_running = false;
synchronized (this) { notifyAll(); }
super.close();
}
/**
* Keeps the back buffer in sync with the screen size.
*/
private void updateBackBuffer()
{
if (_offscreenBitmap != null)
{
if (_offscreenBitmap.getWidth() == getWidth() &&
_offscreenBitmap.getHeight() == getHeight())
return; // no change needed
}
_offscreenBitmap = new Bitmap(getWidth(), getHeight());
_offscreenGraphics = Graphics.create(_offscreenBitmap);
}
private void pause()
{
_paused = true;
}
private void resume()
{
if (_running)
{
// Pause the render loop
_paused = false;
synchronized (this) { notifyAll(); }
}
else
{
// Start the render thread.
_running = true;
new Thread(this).start();
}
}
}

Rendering a multicolor 2-D triangle on BlackBerry

The following code sample to demonstrates how to use JSR-239 to render a multicolor 2-D triangle:

import java.nio.*;
import javax.microedition.khronos.egl.*;
import javax.microedition.khronos.opengles.*;
import net.rim.device.api.ui.*;
import net.rim.device.api.ui.container.*;
import net.rim.device.api.system.*;
import net.rim.device.api.opengles.*;
public final class OpenGLTest extends UiApplication
{
public OpenGLTest()
{
pushScreen(new OpenGLTestScreen());
}
public static void main(String[] args)
{
new OpenGLTest().enterEventDispatcher();
}
}
class OpenGLTestScreen extends FullScreen implements Runnable
{
private EGL11 _egl;
private EGLDisplay _eglDisplay;
private EGLConfig _eglConfig;
private EGLSurface _eglSurface;
private EGLContext _eglContext;
private GL10 _gl;
private Bitmap _offscreenBitmap;
private Graphics _offscreenGraphics;
private FloatBuffer _vertexArray;
private FloatBuffer _colorArray;
private boolean _running;
private boolean _paused;
OpenGLTestScreen()
{
super(FullScreen.DEFAULT_MENU | FullScreen.DEFAULT_CLOSE);
}
private void initialize()
{
// Get EGL interface
_egl = (EGL11)EGLContext.getEGL();
// Get the EGL display
_eglDisplay = _egl.eglGetDisplay(EGL11.EGL_DEFAULT_DISPLAY);
// Initialize the display for EGL setting the version to null
_egl.eglInitialize(_eglDisplay, null);
// Choose an EGL config
EGLConfig[] configs = new EGLConfig[1];
int[] numConfigs = new int[1];
int[] attrs =
{
EGL11.EGL_RED_SIZE, 5,
EGL11.EGL_GREEN_SIZE, 6,
EGL11.EGL_BLUE_SIZE, 5,
EGL11.EGL_NONE
};
_egl.eglChooseConfig(_eglDisplay, attrs, configs, 1, numConfigs);
_eglConfig = configs[0];
// Create an EGL window surface
_eglSurface = _egl.eglCreateWindowSurface
(_eglDisplay, _eglConfig, this, null);
// Create an EGL context
createEGLContext();
// Specify vertices and colors for a triangle
float[] vertices =
{
-0.5f, -0.5f, 0.0f,
0.0f, 0.5f, 0.0f,
0.5f, -0.5f, 0.0f
};
float[] colors =
{
0.0f, 1.0f, 0.0f, 1.0f,
1.0f, 0.0f, 0.0f, 1.0f,
0.0f, 0.0f, 1.0f, 1.0f
};
_vertexArray = ByteBuffer.allocateDirect(3 * 3 * 4).asFloatBuffer();
_vertexArray.put(vertices);
_vertexArray.rewind();
_colorArray = ByteBuffer.allocateDirect(4 * 3 * 4).asFloatBuffer();
_colorArray.put(colors);
_colorArray.rewind();
}
private void createEGLContext()
{
// Create an EGL context
_eglContext = _egl.eglCreateContext
(_eglDisplay, _eglConfig, EGL10.EGL_NO_CONTEXT, null);
// Get the GL interface for the new context
_gl = (GL10)_eglContext.getGL();
// Make the new context current
_egl.eglMakeCurrent
(_eglDisplay, _eglSurface, _eglSurface, _eglContext);
}
private void destroyEGL()
{
_egl.eglMakeCurrent(_eglDisplay, EGL10.EGL_NO_SURFACE,
EGL10.EGL_NO_SURFACE, EGL10.EGL_NO_CONTEXT);
_egl.eglDestroyContext(_eglDisplay, _eglContext);
_egl.eglDestroySurface(_eglDisplay, _eglSurface);
}
private void handleContextLost()
{
// Destroy the EGL context
_egl.eglMakeCurrent(_eglDisplay, EGL10.EGL_NO_SURFACE,
EGL10.EGL_NO_SURFACE, EGL10.EGL_NO_CONTEXT);
_egl.eglDestroyContext(_eglDisplay, _eglContext);
_eglContext = EGL10.EGL_NO_CONTEXT;
// Re-create the EGL context
createEGLContext();
}
/**
* Main render loop.
*/
public void run()
{
initialize();
while (_running)
{
// Idle if this thread is in the background
if (_paused)
{
synchronized (this)
{
try
{
wait();
}
catch (InterruptedException x) { }
}
}
updateBackBuffer();
renderFrame();
// Throttle cpu usage
try
{
Thread.sleep(20);
}
catch (InterruptedException x) { }
}
destroyEGL();
}
private void renderFrame()
{
// Make the context and surface current and check for EGL_CONTEXT_LOST
if (!_egl.eglMakeCurrent(_eglDisplay, _eglSurface, _eglSurface,
_eglContext))
{
if (_egl.eglGetError() == EGL11.EGL_CONTEXT_LOST)
handleContextLost();
}
// Signal that OpenGL rendering is about to begin
_egl.eglWaitNative(EGL10.EGL_CORE_NATIVE_ENGINE, _offscreenGraphics);
render(_gl);
// Signal that OpenGL ES rendering is complete
_egl.eglWaitGL();
// Swap the window surface to the display
_egl.eglSwapBuffers(_eglDisplay, _eglSurface);
}
private void render(GL10 gl)
{
// Set the GL viewport
gl.glViewport(0, 0, getWidth(), getHeight());
// Clear the surface
gl.glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
gl.glClear(GL10.GL_COLOR_BUFFER_BIT | GL10.GL_DEPTH_BUFFER_BIT);
// Set the projection matrix
gl.glMatrixMode(GL10.GL_PROJECTION);
gl.glLoadIdentity();
GLUtils.gluPerspective
(gl, 45.0f, (float)getWidth()/(float)getHeight(), 0.15f, 10.0f);
// Draw the triangle
gl.glMatrixMode(GL10.GL_MODELVIEW);
gl.glLoadIdentity();
gl.glTranslatef(0.0f, 0.0f, -3.0f);
gl.glEnableClientState(GL10.GL_VERTEX_ARRAY);
gl.glEnableClientState(GL10.GL_COLOR_ARRAY);
gl.glVertexPointer(3, GL10.GL_FLOAT, 0, _vertexArray);
gl.glColorPointer(4, GL10.GL_FLOAT, 0, _colorArray);
gl.glDrawArrays(GL10.GL_TRIANGLES, 0, 3);
}
/**
* Called by the UI system to paint the screen.
*/
protected void paint(Graphics g)
{
if (_offscreenBitmap != null)
g.drawBitmap(0, 0, _offscreenBitmap.getWidth(),
_offscreenBitmap.getHeight(), _offscreenBitmap, 0, 0);
}
/**
* Called when the visibility of the screen changes.
*
* @param visible true if the screen is being made visible,
* false if hidden
*/
protected void onVisibilityChange(boolean visible)
{
if (visible)
{
resume();
}
else
{
pause();
}
}
/**
* Called when the screen is closing.
*/
public void close()
{
_running = false;
synchronized (this) { notifyAll(); }
super.close();
}
/**
* Keeps the back buffer in sync with the screen size.
*/
private void updateBackBuffer()
{
if (_offscreenBitmap != null)
{
if (_offscreenBitmap.getWidth() == getWidth() &&
_offscreenBitmap.getHeight() == getHeight())
return; // no change needed
}
_offscreenBitmap = new Bitmap(getWidth(), getHeight());
_offscreenGraphics = Graphics.create(_offscreenBitmap);
}
private void pause()
{
_paused = true;
}
private void resume()
{
if (_running)
{
// Pause the render loop
_paused = false;
synchronized (this) { notifyAll(); }
}
else
{
// Start the render thread.
_running = true;
new Thread(this).start();
}
}
}

Implementing a custom connector framework on BlackBerry

The following source can be used to implementing a custom connector framework on BlackBerry:

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://")) {
// 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() {
// ...
}
}
}

Access SVG content through a connection that MediaManager does not support on BlackBerry

The following code snippet is to access SVG content through a connection that MediaManager does not support on BlackBerry:

You can create a BlackBerry device application that can download SVG content from the Internet or from local storage using a connection that supports a custom protocol or has functionality that the MediaManager does not support or provide.

Import the required classes.

import java.io.*;
import net.rim.plazmic.mediaengine.*;
import net.rim.plazmic.mediaengine.io.*;

To implement a custom connector, implement the net.rim.plazmic.mediaengine.io.Connector interface.

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://")) {
// 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;
}
// Inner class that defines the connection class.
public static class MyProtocolConnection {
public MyProtocolConnection() {
// ...
}
public void close() {
// ...
}
}

To configure custom connector properties, implement setProperty(String, String).

public void setProperty(String property, String value) {
delegate.setProperty(property, value);
}

To release the custom connection, implement releaseConnection(ConnectionInfo).

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);
}
}

Responding to events when a BlackBerry device application downloads SVG content

The following source code will respond to events when a BlackBerry device application downloads SVG content

package com.rim.samples.device.mediaenginedemo;
import net.rim.plazmic.mediaengine.*;
import net.rim.plazmic.mediaengine.io.*;
/**
* The MediaListener implementation.
*/
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:
System.out.println("Media realized");
break;
case MEDIA_IO:
{
LoadingStatus s = (LoadingStatus)data;
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 = "nvalid 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;
}

}
}
}

Respond to events while downloading a .pme file

The following tutorial will teach you on how to respond to events while downloading a .pme file

Import the required class and interface.
import net.rim.plazmic.mediaengine.io.LoadingStatus;
import net.rim.plazmic.mediaengine.MediaListener;

Implement the net.rim.plazmic.mediaengine.MediaListener interface.
public final class MediaListenerImpl implements MediaListener {

In your implementation of MediaListener.mediaEvent(), when the MEDIA_IO event occurs, cast the Object in
the data parameter to a LoadingStatus object.
LoadingStatus s = (LoadingStatus)data;

Invoke LoadingStatus.getStatus() to download content and manage the status of the .pme file that the application is downloading.
switch(s.getStatus()) {

For each normal status, print a message to the console.
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;

If LoadingStatus.getStatus() returns a value equal to LoadingStatus.LOADING_FAILED, perform one or
more of the following actions:
To retrieve the error code, invoke LoadingStatus.getCode().
To retrieve the detailed message, invoke LoadingStatus.getMessage().
To retrieve the URL string of the content, invoke LoadingStatus.getSource().

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;

Using encoded images on BlackBerry

The following tutorial will help you on how to use encoded images on BlackBerry:

Access an encoded image through an input stream:
Import the required classes.
import java.io.InputStream;

Save the image to the project folder or sub-folder.
Add the image to the project in the BlackBerry Java Plug-in Eclipse or the BlackBerry Java Development Environment.

Invoke getClass().getResourceAsStream() to retrieve the image as an input stream of bytes.
private InputStream input;

Class _class = this.getClass();
input = _class.getResourceAsStream(“/images/example.png”);

Encode an image:
Import the required classes.
import net.rim.device.api.system.EncodedImage;

Invoke EncodedImage.createEncodedImage(). This method uses the unprocessed image data in the byte array
to create an instance of EncodedImage.

Check for an IllegalArgumentException, which EncodedImage.createEncodedImage() throws if the byte
array that you provide as a parameter does not contain a recognized image format.

// Store the contents of the image file.
private byte[] data = new byte[2430];
try {
// Read the image data into the byte array
input.read(data);
} catch (IOException e) {
// Handle exception.
}
try {
EncodedImage image = EncodedImage.createEncodedImage(data, 0, data.length);
} catch (IllegalArgumentException iae) {
System.out.println("Image format not recognized.");
}

Display an encoded image:
Import the required class.
import net.rim.device.api.ui.component.BitmapField;

Invoke BitmapField.setImage() to assign the encoded image to a BitmapField.

Invoke add() to add the BitmapField to the screen.
BitmapField field = new BitmapField();
field.setImage(image);
add(field);

Specify the decoding mode for an image:

Import the required class.
import net.rim.device.api.system.EncodedImage;

Invoke EncodedImage.setDecodeMode() using one of the following modes as a parameter:

Use DECODE_ALPHA to decode an alpha channel, if one exists (this is the default mode).Use DECODE_NATIVE to force decoding of the bitmap image to the native bitmap image type of the BlackBerry Device Software. Use DECODE_READONLY to mark the decoded bitmap image as read-only.

Specify the display size of an encoded image:
Import the required class.
import net.rim.device.api.system.EncodedImage;

Invoke EncodedImage.scaleImage32 ( int scaleX, int scaleY ). The passed scale value parameters must be
net.rim.device.api.math.Fixed32 numbers ( 0 < scale < 1 for upscaling, and scale > 1 for downscaling ).
scaleImage32 () creates a new EncodedImage instead of modifying the current one.

Store, Retrieve and compare two bitmap images on BlackBerry

Store, Retrieve and compare two bitmap images

To retrieve unprocessed image data:
Import the required class.
import net.rim.device.api.system.Bitmap;

Invoke Bitmap.getARGB() to retrieve the unprocessed image data from a region of a bitmap image and store the data in an integer array.
Bitmap original = Bitmap.getPredefinedBitmap(Bitmap.INFORMATION);
int[] argb = new int[original.getWidth() * original.getHeight()];

To store unprocessed image data:
Import the required class.
import net.rim.device.api.system.Bitmap;
Create a Bitmap object from an existing bitmap image.

Bitmap img = Bitmap.getPredefinedBitmap(Bitmap.INFORMATION);
//Initialize an integer array.
int[] argb = new int[img.getWidth() * img.getHeight()];

Invoke Bitmap.getARGB() to store the unprocessed image data from a new or pre-defined bitmap in an integer array.
img.getARGB(argb, 0, img.getWidth(), 0, 0, img.getWidth(), img.getHeight());

ToCompare two unprocessed images:
Import the required class.
import net.rim.device.api.system.Bitmap;

Invoke Bitmap.equals().

if(restored.equals(original)) {
System.out.println("Success! Bitmap renders correctly with RGB data.");
} else (!restored.equals(original)) {
System.out.println("Bitmap rendered incorrectly with RGB data.");
}

To compare two bitmap images to check if they are different:
Import the required class.
import net.rim.device.api.system.Bitmap;

Create two Bitmap objects from bitmap images to compare.
Bitmap _first = Bitmap.getBitmapResource(“first.png”);
Bitmap _last = Bitmap.getBitmapResource(“last.png”);

Create an XYRect object to reflect the differences between bit images.
XYRect diff = new XYRect(0, 0, _first.getWidth(),
_first.getHeight());

Compare the bitmap images by using the Bitmap.locateDifference ( XYRect diffRect, Bitmap bmp2, int offset_x, int offset_y ) method. This comparison is done within the provided XYRect reference and can be offset within the second bitmap image to an alternate position. The minimal difference between the bitmap images in the defined area is determined, with the XYRect reference modified with the new coordinates representing this area. An empty XYRect represents no difference between the two bitmaps within the given area.
_first.locateDifference( diff, _last, 0, 0 );

Display a row of images for scrolling in BlackBerry

The following tutorial will help you to display a row of images for scrolling:

Import the required classes and interfaces.

import net.rim.device.api.system.*;
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.ui.decor.*;
import net.rim.device.api.ui.extension.component.*;

Create the application framework by extending the UiApplication class. In main(), create an instance of the new class and invoke enterEventDispatcher() to enable the application to receive events. In the constructor, invoke pushScreen() to display the custom screen for the application. The PictureScrollFieldDemoScreen class, described below, represents the custom screen.

public class PictureScrollFieldDemo extends UiApplication
{
public static void main(String[] args)
{
PictureScrollFieldDemo app = new PictureScrollFieldDemo();
app.enterEventDispatcher();
}
public PictureScrollFieldDemo()
{
pushScreen(new PictureScrollFieldDemoScreen());
}
}

//Create the framework for the custom screen by extending the MainScreen class.
class PictureScrollFieldDemoScreen extends MainScreen
{
public PictureScrollFieldDemoScreen()
{
}
}

In the constructor, invoke setTitle() to set the text that appears in the title section of the screen.
setTitle(“PictureScrollField Demo”);

In the constructor, create and initialize three arrays to store the images to display in the PictureScrollField and the labels and tooltip text that appear when each image is selected. In this example, the PictureScrollField contains three images.

Bitmap[] images = new Bitmap[3];
String[] labels = new String[3];
String[] tooltips = new String[3];
images[0] = Bitmap.getBitmapResource(“img1.jpg”);
labels[0] = “Label for image 1″;
tooltips[0] = “Tooltip for image 1″;
images[1] = Bitmap.getBitmapResource(“img2.jpg”);
labels[1] = “Label for image 2″;
tooltips[1] = “Tooltip for image 2″;
images[2] = Bitmap.getBitmapResource(“img3.jpg”);
labels[2] = “Label for image 3″;
tooltips[2] = “Tooltip for image 3″;
In the constructor, create and initialize an array of ScrollEntry objects. A ScrollEntry represents each item in the
PictureScrollField.
ScrollEntry[] entries = ScrollEntry[3];
for (int i = 0; i < entries.length; i++)
{
entries[i] = new ScrollEntry(images[i], labels[i], tooltips[i]);
}

In the constructor, create and initialize the PictureScrollField with each image 150 pixels wide and 100 pixels high. Invoke setData() to set the entries in the PictureScrollField. The second paramater in setData() specifies which image position is selected by default.
PictureScrollField pictureScrollField = new PictureScrollField ( 150, 100);
pictureScrollField.setData ( entries, 0 );

In the constructor, set the style of the PictureScrollField. Invoke setHighlightStyle() to specify how the selected image is highlighted. Invoke setHighlightBorderColor() to specify the selected image’s border color. Invoke setBackground() to specify the background of the PictureScrollField. Invoke setLabelVisible() to specify whether the PictureScrollField displays the selected image’s label.

pictureScrollField.setHighlightStyle ( HighlightStyle.ILLUMINATE );
pictureScrollField.setHighlightBorderColor ( Color.BLUE );
pictureScrollField.setBackground ( BackgroundFactory
.createSolidTransparentBackground ( Color.RED,  150 ) );
pictureScrollField.setLabelsVisible ( true );

In the constructor, invoke add() to display the PictureScrollField.
add ( pictureScrollField );
Code sample: Displaying a row of images for scrolling

import net.rim.device.api.system.*;
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.ui.decor.*;
import net.rim.device.api.ui.extension.component.*;
public class PictureScrollFieldDemo extends UiApplication
{
public static void main ( String[] args )
{
PictureScrollFieldDemo app = new PictureScrollFieldDemo ();
app.enterEventDispatcher ();
}
public PictureScrollFieldDemo ()
{
pushScreen ( new PictureScrollFieldDemoScreen() );
}
}
class PictureScrollFieldDemoScreen extends MainScreen
{
public PictureScrollFieldDemoScreen ()
{
setTitle ( "PictureScrollField Demo" );
Bitmap[] images = new Bitmap[3];
String[] labels = new String[3];
String[] tooltips = new String[3];
images[0] = Bitmap.getBitmapResource ( "img1.jpg" );
labels[0] = "Label for image 1";
tooltips[0] = "Tooltip for image 1";
images[1] = Bitmap.getBitmapResource ( "img2.jpg" );
labels[1] = "Label for image 2";
tooltips[1] = "Tooltip for image 2";
images[2] = Bitmap.getBitmapResource ( "img3.jpg" );
labels[2] = "Label for image 3";
tooltips[2] = "Tooltip for image 3";
ScrollEntry[] entries = ScrollEntry[3];
for ( int i = 0; i < entries.length; i++ )
{
entries[i] = new ScrollEntry ( images[i],  labels[i], tooltips[i] );
}
PictureScrollField pictureScrollField = new PictureScrollField(150, 100);
pictureScrollField.setData ( entries,  0 );
pictureScrollField.setHighlightStyle ( HighlightStyle.ILLUMINATE );
pictureScrollField.setHighlightBorderColor ( Color.BLUE );
pictureScrollField.setBackground ( BackgroundFactory.createSolidTransparentBackground ( Color.RED, 150 ) );
pictureScrollField.setLabelsVisible ( true );
add ( pictureScrollField );
}
}