Thursday, October 30, 2008

Makeover Demo on actual device

The makeover demo is pretty fancy, however despite its eye candy the demo itself is very light.
It doesn't use any background images and most of its effects are very simple/fast. To show this off the demo is running here on a standard S40 device with 2mb of heap, most of the time is spent connecting to the internet to download data. The animations are very smooth, even smoother than the simulator video I posted previously.

I think this demo is a great representation of LWUIT's speed since it doesn't carry the overhead of the images necessary for the other demos. However, it still looks reasonably polished for most intents and purposes.

Monday, October 27, 2008

LWUIT Makeover: SVG/MIDP & LWUIT

The LWUIT Makeover demo is an excellent tool for comparing the different approaches for building MIDP UI. While LWUIT's differences to MIDP are more clear to most, some people still have questions regarding LWUIT as opposed to SVG.
When compared to LCDUI the LWUIT interface is much richer and allows greater control, this will probably still be the case even in MIDP 3.0's timeframe since a lightweight UI by its very nature is more customizable than a heavyweight UI (as is the case in Swing vs. SWT/AWT). Another advantage in compared to current LCDUI is portability, LCDUI's custom items have quite a few portability and usability issues across devices which don't exist with MIDP...

The greater advnatages however are in MVC, the List in the demo is scrollable and fetches data only when necessary thanks to LWUIT's MVC support. This is far more intuitive and actually easier to write than odd paging mechanisms that are often necessary for such results! This is also just as efficient and arguably even more efficient than the typical paging algorithm.

When compared to SVG most of the same advantages still persist with some additional benefits. LWUIT is much faster than todays SVG devices, it is also far more portable, while writing cross device SVG code is not trivial the main problem is in the fact that many current devices still don't support 226 (newer devices from the major manufactures have finally stepped up to the plate). Basic tasks are often very difficult in SVG, things such as text input are not integrated and need programming. The separation of view and logic is very powerful in SVG but not very intuitive to program, it is also harder to draw elements on the fly in some cases.

Changing the look and feel in SVG is possible by replacing some image elements but it is not quite the same thing, features such as transitions etc. all have to be coded specifically for an application.

SVG is great when you need to do Flash like graphics applications, LWUIT doesn't ofer much in that department. When you need to build component based applications SVG isn't as capable as LWUIT (in my obviously biased opinion), however if you need to combine them we offer that ability via SVGImage which allows animations and DOM manipulation.

Thursday, October 23, 2008

LWUIT Makeover Demo

Been a while since I last posted, with all the holidays and things going on I barely have time to breath... However, the holidays are finally over and I hope to get into the ritual of posting more frequently again.
The makeover demo is a very cool demo developed by Terrence Barr to show off SVG support in in MIDP and how you can take an existing MIDP application and port it to SVG. Terrence will be speaking soon at OreDev and needed a good looking LWUIT demo, so we worked on a LWUIT version of the same demo. This took me less than a days work, mostly because Terrence already did all the heavy lifting of REST support and UI design and I just needed to leverage LWUIT here.

The demo is very simple, you type a search qwery into the first dialog then get a list of locations to which you can get a zoomable scrollable map and some additional details. All information is real and retrieved from Yahoo's REST web services directly over the air, this works on actual devices even on S40 devices...

Next time I will try to talk about some of the advantages for using LWUIT when compared to the SVG/MIDP versions. I hope we can publish the source code to give developers a better feel of a more real world demo application than the LWUIT demo.

Monday, October 6, 2008

Testing LWUIT Applications

Its been some time since I last blogged, mostly due to the holidays around here so I'm only partially available and just remarkably busy.
Last time I blogged about one of the cooler features I've been working on, the automatic testing framework to which I just committed some technical changes. This is still work in progress but the general direction is pretty solid and I think we can start discussing it.

The general idea behind these features is to enable debugging using very little code, so we can build a debug version of the application without changing application code and thus automate testing of this application. The code exists in DebugController and it essentially replaces the underlying implementation class with an internal DebugImplementation, the controller is far more capable as an API than a simple recorder, it allows Java based automation and testing allowing you to write unit tests in Java for your applications. To use the debug controller you must avoid Display.init(this) and instead call DebugController.init and everything should work as expected.... Sort of...

If you use the standard DebugController.init(this) method you won't get the automated script recording feature demoed previously, unlike Display's init method the debug controller accepts another argument: ScriptStore.

A ScriptStore is a model for storing recorded scripts thus allowing the developer (you) to store your scripts anywhere you want. Why didn't we provide a default implementation of this???

Well:
1. RMS exists only in MIDP (not in CDC).
2. GCF isn't always supported in the same way and might require permissions.
3. Networking needs a server component or storage space.

However, for you this should be pretty easy since it allows you to store your scripts on the server side for sharing between phones or on the device itself for fast access (just like you would expect from MVC!). To ease your life a bit here is a simple RMS based implementation of such a store use with caution since the format of the underlying scripts is sure to change in the future so don't grow too invested.
class RMSStore implements DebugController.ScriptStore {
private ListModel model;
public ListModel getStoredScriptNameList() throws IOException {
if(model == null) {
try {
RecordStore r = RecordStore.openRecordStore("scriptNames", true);
RecordEnumeration e = r.enumerateRecords(null, null, false);
Vector result = new Vector();
while (e.hasNextElement()) {
String s = new String(e.nextRecord());
result.addElement(s);
}
e.destroy();
r.closeRecordStore();
model = new DefaultListModel(result);
} catch (RecordStoreException ex) {
ex.printStackTrace();
throw new IOException(ex.getMessage());
}
}
return model;
}

public void storeScript(Script s) throws IOException {
try {
if(model != null) {
model.addItem(s.getTitle());
}
RecordStore r = RecordStore.openRecordStore("scriptNames", true);
byte[] b = s.getTitle().getBytes();
r.addRecord(b, 0, b.length);
r.closeRecordStore();
r = RecordStore.openRecordStore("script-" + s.getTitle(), true);
b = DebugController.scriptToBytes(s);
r.addRecord(b, 0, b.length);
r.closeRecordStore();
} catch (RecordStoreException ex) {
ex.printStackTrace();
throw new IOException(ex.getMessage());
}
}

public Script loadScript(String name) throws IOException {
try {
RecordStore r = RecordStore.openRecordStore("script-" + name, true);
RecordEnumeration e = r.enumerateRecords(null, null, false);
Script s = DebugController.scriptFromBytes(e.nextRecord());
e.destroy();
r.closeRecordStore();
return s;
} catch (RecordStoreException ex) {
ex.printStackTrace();
throw new IOException(ex.getMessage());
}
}

public void deleteScript(String name) throws IOException {
try {
if(model != null) {
for(int iter = 0 ; iter < model.getSize() ; iter++) {
if(model.getItemAt(iter).equals(name)) {
model.removeItem(iter);
}
}
}
RecordStore.deleteRecordStore("script-" + name);
RecordStore r = RecordStore.openRecordStore("scriptNames", true);
RecordEnumeration e = r.enumerateRecords(null, null, false);
while(e.hasNextElement()) {
int id = e.nextRecordId();
String entry = new String(r.getRecord(id));
if(entry.equals(name)) {
r.deleteRecord(id);
break;
}
}
e.destroy();
r.closeRecordStore();
} catch (RecordStoreException ex) {
ex.printStackTrace();
throw new IOException(ex.getMessage());
}
}
}