mind serializer and weblog
[ start | index | login ]
start > FullscreenCanvasExample

FullscreenCanvasExample

Created by ivonne. Last edited by case, one year and 208 days ago. Viewed 1,040 times. #30
[diff] [history] [edit] [rdf]
labels
attachments
CanvasTest.jad (276)
CanvasTest.jar (12391)
CanvasTest_src.zip (14241)
INFORMATION IS OUTDATED (needs reworked for correct build and link proecdures - Canvas/Displayable method move MIDP1 - MIDP2)

Midlets using Fullscreen

When creating games for mobile devices we always had the problem that we need to use the fullscreen display to get the maximum resolution.

There are 2 ways to display a midlet in fullscreen mode:

  • Nokia FullCanvas
  • MIDP 2.0 Fullscreen
But we want only one single JAR file which can run on all devices. The following chapters will explain how this can be done.

Test the example midlet:

The complete source code of the example:

Nokia FullCanvas

For Nokia devices there is a special super class to use fullscreen even on MIPD 1.0 devices. Your canvas implementation needs to extend com.nokia.mid.ui.FullCanvas.

import com.nokia.mid.ui.FullCanvas;
public class MyCanvas extends FullCanvas {
}

MIDP 2.0 Fullscreen

Since MIDP 2.0 the Canvas class supports setFullScreenMode() to switch between fullscreen mode and normal display.

import javax.microedition.lcdui.Canvas;
public class MyCanvas extends Canvas {
	public MyCanvas() {
		super();
		setFullScreenMode(true);
	}
}

Device specific implementation

To support fullscreen on each device you need to support 3 types of devices

  • MIDP 2.0 devices
  • MIDP 1.0 Nokia devices
  • MIDP 1.0 non-Nokia devices (= no fullscreen supported)
You need to build different JARs for each of these device type, because for example you can't call the setFullScreenMode() in MIDP 1.0 compiled code.

You can use a precompiler like >>Anteanna to change the super class of MyCanvas depended if Nokia device or not. For the constructor you can use another precompiler tag to check if MIDP 2.0 is supported and if you can call setFullScreenMode(). Check out eclipseME and Antenna.

This results in 3 different JARs. But the purpose of this example is to build only one JAR which runs on all 3 device types.

Check for Nokia device

To check if the device is a Nokia device you can use reflection.

public static boolean isNokiaDevice() {
	try {
		Class.forName("com.nokia.mid.ui.DeviceControl");
		return true;
	} catch (final Exception ex) {
	}
	return false;
}

Check for MIDP 2.0

To check if the device supports MIDP 2.0 you can check the system properties.

public static boolean isMidp20Supported() {
	final String profiles = System.getProperty("microedition.profiles");
	if (profiles.startsWith("MIDP-2.")) {
		return true;
	}
	return false;
}

JAR with mixed classes

Dynamic check can be used to decide which feature is supported by the device. But we need to build a Midlet with all these features in one JAR. This is possible by using a JAR with mixed classes:

  • all application classes compiled with MIDP 1.0
  • a canvas implementation using Nokia-FullCanvas
  • a canvas implemantation compiled with MIDP 2.0 to use setFullScreenMode()

Include Nokia specific features

The JAR file could contain a class which will only run on Nokia devices like MyNokiaCanvas. This class can use Nokia specific classes like com.nokia.mid.ui.DeviceControl to control the backlight level of the display.

import com.nokia.mid.ui.FullCanvas;
import com.nokia.mid.ui.DeviceControl;
public class MyNokiaCanvas extends FullCanvas {

public static void setBacklight(final int level) { if (level >= 0 && level <= 100) DeviceControl.setLights(0, level); } }

The application itself should use this Nokia specific feature only if the device is a Nokia device.

import javax.microedition.lcdui.Canvas;
public class MyCanvas extends Canvas {

public static void setBacklight(final int level) { if (isNokiaDevice()) { MyNokiaCanvas.setBacklight(level); } } }

The Java virtual machine will not access the MyNokiaCanvas class on none-Nokia device. So this code will run on both types of devices: Nokia or other vendor.

Include MIDP 2.0 features

Its possible to mix MIDP 1.0 and MIDP 2.0 classes within one JAR as long as the MIDP 2.0 class is only called by reflection if the device supports MIDP 2.0.

The JAD file needs to declare the midlet as MIDP 1.0.

MicroEdition-Configuration: CLDC-1.0
MicroEdition-Profile: MIDP-1.0

The JAR file could contain a class like My20Canvas which calls new MIDP 2.0 features like setFullScreenMode.

public class My20Canvas extends MyCanvas {

public void setFullScreenRequested(final boolean useFullScreen) { setFullScreenMode(useFullScreen); super.setFullScreenRequested(useFullScreen); } }

The normal canvas implemantation (MyCanvas) will ignore the request for fullscreen mode.

import javax.microedition.lcdui.Canvas;
public class MyCanvas extends Canvas {

public void setFullScreenRequested(final boolean useFullScreen) { // no full screen supported in MIDP 1.0 } }

(see also >>http://today.java.net/pub/a/today/2005/02/09/j2me1.html?page=2 for Step 7: Deploy for some infos on handling MIDP 1.0/2.0)

To include My20Canvas

  • Keep jad setting to MIDP 1.0 and CLDC 1.0
  • build the JAR with MIDP 2.0 and CLDC 1.0 (this might be a problem with eclipseME, but can be achieved with WTK). I have not researched, if preverification with CLDC 1.1 is compatible on CLDC 1.0 devices.
  • make sure, that manifest now holds the jad entries (MIDP1.0 and CLDC1.0)
Now the JAR will run on MIPD 1.0 and MIDP 2.0 devices.

There have been some issues using the antenna build files created with eclipseME. Mainly these were:

  • eclipseme-build.xml encoding was set to UTF-8, which might be a problem, if the sources are created with another Codepage
  • eclipseme-build.xml, wtkobfuscate task had incorrect path to additional libs (e.g. nokiaapi.jar)
  • eclipseme-build.xml wtkpreverify could also not see aditional jars and therefore a classpath refid was included
  • (if you want to have preprocessing, you will need to include the wtkpreprocess task into the build file and make build task depend on it. Details can be found in eclipseME and Antenna)

3 Canvas implementations: MyCanvas, My20Canvas, MyNokiaCanvas

To use specific Canvas feature we use 3 different Canvas implementations:

  • MyCanvas extends Canvas
  • My20Canvas extends MyCanvas
  • MyNokiaCanvas extends FullCanvas
During startup of the midlet we decide which class should be used:
  • if MIDP 2.0 supported => use My20Canvas
  • if MIDP 1.0 and Nokia device => use MyNokiaCanvas
  • if MIDP 1.0 and no Nokia device => use MyCanvas
public static Canvas getCanvas(final boolean useFullScreen) {

ICanvas theCanvas = null;

final boolean midp20 = isMidp20Supported(); if (midp20) { try { theCanvas = (ICanvas) (Class .forName("de.wintermute.midlet.My20Canvas")) .newInstance(); } catch (Exception e) { } }

if (theCanvas == null && useFullScreen) { try { Class.forName("com.nokia.mid.ui.FullCanvas"); theCanvas = (ICanvas) (Class .forName("de.wintermute.midlet.MyNokiaCanvas")) .newInstance(); } catch (Exception e2) { } }

if (theCanvas == null) { theCanvas = new MyCanvas(); }

theCanvas.setFullScreenRequested(useFullScreen); return (Canvas) theCanvas;

}

Delegation pattern to use Canvas implementation

To use one of the 3 specific Canvas implementations you can not just extend these classes. Therefor we use a delegation pattern. A new super class MyGui was used:

public abstract class MyGui implements IGui {

private Canvas theCanvas;

public final int getWidth() {

return theCanvas.getWidth(); }

}

Every method call which are usally implemented in Canvas super class (like getWidth) is now delegated to the canvas implementation itself.

In the other direction the canvas implementation needs to delegate events like keyPressed to the application.

public class MyCanvas extends Canvas implements ICanvas {

protected IGui gui;

protected void keyPressed(final int k) { gui.keyPressed(k); } }

Initialize the application GUI and Canvas

If you implement a graphical midlet, your usally have one class which extends Canvas.

public class TestGui extends Canvas {
}

Now you need to use MyGui as a super class.

public class TestGui extends MyGui {
}

Here you need to implement the same methods like extending Canvas directly. For example

public void paint(final Graphics g)

There is only one new method to implement.

To connect your GUI implementation with the specific Canvas class to use, you need to implement this init() method.

public interface IGui {
	public void init(final Canvas canvas, final MIDlet theMidlet);
}

Usally you should implement this like in the example:

public synchronized void init(final Canvas canvas, final MIDlet theMidlet) {

midlet = (CanvasTest) theMidlet; setCanvas(canvas);

// do the painting or other application tasks here updateCanvas(); repaint(); }

Starting the midlet

To start the midlet with the specific Canvas you need first to create a new instance of your application GUI and than initialize this GUI with the Canvas.

public class CanvasTest extends MIDlet {

private Canvas canvas = new MyCanvas(); private TestGui gui;

public CanvasTest() { // create the new GUI class gui = new TestGui(); // create the Canvas and start the GUI createNewCanvas(true); }

public void createNewCanvas(final boolean fullScreenRequested) { // get a new canvas implementation canvas = MyCanvas.getCanvas(fullScreenRequested); // initialize the GUI implemenation ((ICanvas) canvas).init(this, gui); } }

Toggle normal / fullscreen mode

Canvas objects are in normal mode by default. The normal vs. full-screen mode setting is controlled now by calling midlet.createNewCanvas() again. This will initialze the GUI implemenatation with the new Canvas by calling init().

Because the resolution will be different in fullscreen mode, you need to recalculate a size-depended values again, every time init() is called. If you working with a offscreen image for example to need to create a new image with the new size.

offScreenImage = Image.createImage(getWidth(), getHeight());

Calling setFullScreenMode(boolean) may result in sizeChanged() being called. Directly call of getWidth() might result in a wrong value. For this devices the My20Canvas needs to implement the callback method sizeChanged().

public class My20Canvas extends MyCanvas {

public void sizeChanged(final int newWidth, final int newHeight) {

// some devices use this callback to tell the new size // re-initialize the GUI class to use new width or height init(midlet, gui); } }

Commands in Nokia FullCanvas

If the device is a Nokia device and it only supports MIDP 1.0, we use the MyNokiaCanvas implementation.

The problem is that Nokia-FullCanvas does not support CommandListener. If you call addCommand() or setCommandListener() this will result in a IllegalStateException.

To use the same command handling for all 3 types of devices we need to create your own command handling for MyNokiaCanvas. We store the commands in a list and display this list as a Form when a specific game key is pressed.

public class MyNokiaCanvas extends FullCanvas implements ICanvas {

private Vector commands = new Vector(); private CommandListener listener;

public void setCommandListener(final CommandListener controller) {

try { super.setCommandListener(controller); } catch (IllegalStateException e) { // Nokia FullScreenCanvas does not support setCommandListener() // store our own listener listener = controller; } }

public void addCommand(final Command command) {

try { super.addCommand(command); } catch (IllegalStateException ex) { // Nokia FullScreenCanvas does not support addCommand() // store our own command

int i; for (i = 0; i < commands.size() && ((Command) commands.elementAt(i)).getPriority() < command .getPriority(); i++) ; commands.insertElementAt(command, i); } }

private void displayMenu() {

final List menuList = new List("Menu", List.IMPLICIT); menuList.addCommand(backCommand);

final Enumeration cmds = commands.elements(); while (cmds.hasMoreElements()) { final Command cmd = (Command) cmds.nextElement(); menuList.append(cmd.getLabel(), null); }

// establish commands menuList.setCommandListener(new CommandListener() {

public void commandAction(final Command command, final Displayable displayable) {

if (command == backCommand) { displayCanvas();

} else { final short index = (short) menuList.getSelectedIndex(); displayCanvas(); final Command cmd = (Command) commands.elementAt(index); listener.commandAction(cmd, null); } }

}); Display.getDisplay(midlet).setCurrent(menuList); }

protected void keyPressed(int k) {

// special handling for Nokia FullScreen: // use SOFTKEY 1 to display internal menu if (listener != null && k == FullCanvas.KEY_SOFTKEY1) { displayMenu(); return; }

// default key handling in the GUI class gui.keyPressed(k); }

}

no comments | post comment
Quick Links
WhatIsThis about?
Midlets (mobile apps)
TimeLine
Charley a dog's life
MovieReview
Impressum
Project (internal)

Logged in Users: (3)
… and 4 Guests.

< May 2008 >
SunMonTueWedThuFriSat
123
45678910
11121314151617
18192021222324
25262728293031

Icon-Snip more changes...

Blogs
>>++ vox.machina ++
>>Zitate - Sprüche - Aphorismen
>>Wil Wheaton
>>Mathematische Kleinigkeiten
>>William Gibson
>>instant-thinking
>>Over heard in NY

nearby  sites
link=http://www.mozilla.org/products/firefox/central.html
link=http://www.nutellausa.com/
link=http://snipsnap.org
link=http://www.amazon.de/exec/obidos/registry/wishlist/ref=cs_nav_top_2/028-7651535-0049343
RSS Feed RSS Feed
post to del.icio.us

Stats: 1169 snips by 16 users
created 5 years and 121 days ago

Powered by
>>SnipSnap 1.0b2-uttoxeter
with SnipScale 1.1.0



This work is licensed under a
>>Creative Commons License.

SEARCH