Monday, December 29, 2008

LWUIT Makeover Demo Running on Samsung F480

The makeover demo running on the Samsung F480 touch screen device. Ideally the UI should be padded for to be more accessible to finger navigation but I didn't have much time to work on this.

Tuesday, December 23, 2008

New LWUIT Drop Available Now

Chen and myself have been a bit slow with the drops lately, we have been remarkably busy with all the different goings on in LWUIT that we just didn't have the time to stabilize and run through the process of a binary drop.
Well, we made some time this past week and that drop is now out notable changes can be seen in Chen's announcement to the list. One of the nicer things in this drop is the incorporation of the LWUIT makeover demo as part of the drop, it has one major difference from the one Terrence and myself have been showing off which is the lack of icons. I just had to remove them since licensing and rights in Sun is a long and complicated process and I didn't want to go through it just to add some "zaz". You can add them yourselves through the silk icons set which has an amazing set of highly recommended icons.

Other than that Thorsten Schemm has contributed his excellent BlackBerry native port of LWUIT and placed it in the incubator! If you are serious about BlackBerry development you should check it out and collaborate on improving the LWUIT BlackBerry support.

Friday, December 19, 2008

Charting Components For LWUIT


My google alerts page poped up this article which I can only read using google translate... The animated gif on the page looks very and it did bring my attention to the fact that java4less now has LWUIT support in their chart components which seem like a very useful tool.

Thursday, December 11, 2008

Meet Chen & Jonathan Next Month

Chen Fishbein & Jonathan Knudsen will be leading a half day LWUIT tutorial event in Santa Clara on January 23rd, this would be a great opportunity to meet both of them and get into the inside track of LWUIT.

Jonathan is a great teacher/speaker and Chen's understanding of LWUIT and its architecture is second to none, I'm sure this tutorial would be a very rewarding and worthwhile event!
There is more information and registration details in the LWUIT project page.

Wednesday, December 10, 2008

Theres Something About LWUIT

A new Java.net project is aiming to get LWUIT onto TV set top boxes, its something we have been working on for quite some time and includes quite a bit of the DTV experience our center developed in recent years.
I don't know how much information can be discussed in public and right now the source code is still going through the long process at Sun but hopefully we will be able to show off this additional LWUIT platform.

The screenshot to the right is pretty much how the application looks, keep in mind that this is LWUIT running in true HD TV.

Thursday, December 4, 2008

Confusing LWUIT Mapping Application

A while back one of the comments to a blog post I wrote pointed to a mapping application claiming it was done in LWUIT, I mostly ignored it because it just didn't seem informed and didn't provide any evidence to the use of LWUIT (the name of the application and its look made it seem like it wasn't using LWUIT)...

I often discount things too quickly without looking into them properly, its a bad trait which I try to avoid but there is just so much noise I need to constantly filter... So Guidebee please take this as an apology, Chen actually did look into that and tried the application and it is a LWUIT application. Thats really cool since it looks very different from many of the LWUIT applications we use all the time. You can try it here and you can watch Guidebees youtube videos page for more videos. Their home page is probably this but I'm not really sure...

As a final note I have to say that the application looks great and such 3rd party applications suddenly coming out of nowhere is one of the best surprises a framework developer can get! Both Chen and I are completely blown away by some of the things you guys have been doing with LWUIT, lots of the stuff we see isn't public yet but the innovation and excitement is real and keeps us going. Thanks.

Monday, December 1, 2008

Redirecting output on S60 devices

Sometimes you are so used to something that you don't remember to check for changes... This is what happened to me now with S60 debugging, I have some issues that only occur on my battered device and they are impossible to reproduce on an emulator.
Sure I can use the Log but what I get is an exception from an unclear source, I always invoke printStackTrace so I know the trace is there... With SE devices I would just plugin a cable and see the stack but with the Nokia I have been at this bug for days. In desperation I searched the internet for ways to get at the system output for S60 with no result... I found a tool from SE called Redirect.SYS but its only for their flavor of Symbian.
Then I ran into this which I immediately discarded since its a Java JAR so naturally it won't have access to the System output... Should have paid more attention! Turns out Nokia has an undocumented API (it is now documented obviously) to access the stream of the output/error stream from Java! It works on my E61 which is making my debugging experience that much better.

I'm blogging about this because if I didn't know about it, I bet most of you guys don't either and the results for System.out printStackTrace and S60 Symbian Nokia are somewhat problematic (hopefully this will help).

Sunday, November 23, 2008

Your Own Kind Of Music

Majimob has introduced a new media player this month, what hasn't been stressed was the fact that it is built from the ground up on LWUIT. In less than 3 weeks this new media player was downloaded 200,000 times and the numbers are rising with the 1.1 version released this weekend. You can read allot about MajiPlayer in the site (which I urge you to do) but what might not be as immediately obvious is just how much LWUIT contributed to this unique player... The whole application was written in under 2 months (including version 1.1 which includes major new features), it works on a ridiculously large number of devices as is evident from the getjar statistics for downloads. The main reason for failures in getjar when such occur, is the need for a signing certificate and even that isn't too bad.
The stunning part is that the application utilizes MMAPI, File connector & restricted API's (digital certificate). All of these are especifically notorious in the porting community as porting "problems", yet MajiPlayer is still able to realize LWUITs vision of one jar for all devices. Resources for themes are downloadable on the fly with a rather cool AJAX based theme uploading tool (I understand downloading user generated themes is "in the pipe"), the selection of themes is also impressive for a small application.

This sort of approach allows majimob to utilize the economies of scale thus reducing prices and deriving profits from ads, the advertising integration in the unregistered version of MajiPlayer is unique for mobile phones and utilizes LWUIT extensively.

LWUITs features are used to the max throughout the application in very obvious ways, transitions, progress, dialogs, themes, fonts etc. are all extensively leveraged.

See more videos of MajiPlayer in action here.

Thursday, November 20, 2008

New Article About Animations And Transitions

Java.net published another fine LWUIT article by Biswajit Sarkar which deals with animations and transitions this time. This is really great news since I wanted to discuss transition authoring several times in the past and just didn't get the time to do anything in this area.
BTW transitions on components, dialogs etc. are already fully supportted in the latest drop with lots of fixes for that functionality in SVN.

Tuesday, November 4, 2008

Round & Round - Infinite Progress And Rotation

When looking at the Makeover demo I posted last week one might assume the rotating wheel animation is a standard animation or gif. This is not the case although I could have gone with that approach I chose to use a different tool to achieve this effect.
I built an infinite progress component which displays a rotating image as an animation, this considerably reduces JAR and heap space usage for an animation that looks quite similar to the one produced by a static animation (which we create from GIF). The reason for this is in the way animations work, animations have no sense of rotation, they store the change to the image (as lines) and when the image rotates the animation sees the entire image as changed and produces a "key frame". Key frames are large both in storage and in memory, to hold a 32x32 pixel animation with 8 keyframes I would need approximately 32x32x8+1024 (1024 for palette). This might not seem big, but with increase in resolution the size rises quite a bit...
Rotation is not always efficient, in fact it can be just as inefficient as a keyframe since it needs to create a new image. However, LWUIT has a special optimization on MIDP (this doesn't not apply to LWUIT on CDC) which uses the platforms built in rotation abilities for square angles (90, 180 & 270) hence removing completely the overhead of the image. This isn't enough since rotating on square angles would produce a jumpy effect, which is why I rotate once to 45 degrees and then rotate 2 images in square angles only thus producing what seems to be 8 images but only paying the cost for 2 images.

Another significant advantage is that unlike animations I can make full use of translucency since the alpha channel isn't removed in these images, this allows for flowing rotation effects.

The rotate method currently makes many assumptions and is mostly useful for square images, however it works rather nicely for all angles which is something that currently plain MIDP doesn't support.

public class InfiniteProgressIndicator extends com.sun.lwuit.Label {
private Image[] angles;
private int angle;

public InfiniteProgressIndicator(Image image) {
Image fourtyFiveDeg = image.rotate(45);
angles = new Image[] {image, fourtyFiveDeg, image.rotate(90), fourtyFiveDeg.rotate(90),
image.rotate(180), fourtyFiveDeg.rotate(180), image.rotate(270), fourtyFiveDeg.rotate(270)};
getStyle().setBgTransparency(0);
setIcon(image);
setAlignment(Component.CENTER);
}

public void initComponent() {
getComponentForm().registerAnimated(this);
}

public boolean animate() {
angle++;
setIcon(angles[Math.abs(angle % angles.length)]);
return true;
}
}

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

Thursday, September 25, 2008

Using Styles, Themes, and Painters with LWUIT

Biswajit Sarkar wrote an interesting article for java.net about themeing and styling LWUIT. The article features helpful diagrams and illustrations to explain some of the UI concepts behind LWUIT themeing.
The article leverages the resource editor which is a very good thing since the resource editor is indeed somewhat under documented.

Tuesday, September 23, 2008

Exciting Changes To LWUIT

A super geek like myself is excited about game development as much as he is excited about accounting software (I know I wrote both), in my case the new testing and recording framework I just committed to LWUIT are remarkably exciting and I don't think you need to be a hardcore geek like myself to get excited (am I delusional?).
I will try to write additional posts explaining what is going on and how you can use this in your applications but since this is all under heavy development and WILL CHANGE... SIGNIFICANTLY! I don't want to go into too many details.
Generally what you see here is the LWUIT demo mostly unchanged, you can adapt any application to support this and when you remove those lines of code the application doesn't have a trace of that functionality. Currently long clicks on the numbers 1,2,3 & 4 are assigned to the testing framework:
1: starts recording every operation I perform.
2: opens the assert screen where I can assert various states of the UI such as the label of the focused component or whether an exception was thrown.
3: Stops recording and names a script.
4: Opens the script manager where I can rename, delete & play my scripts (hopefully edit too in the future).

Scripts are stored using a model of their own so they can be stored anywhere the user wants to e.g. RMS, filesystem or even the network (in this example in RMS). Scripts can theoretically run on every device or simulator unchanged but this has some issues such as applications behaving differently in different resolutions might not be a bug...

I will blog more about this in the coming weeks as the code and logic finalizes and becomes more concrete.

Sunday, September 21, 2008

How Fast Is LWUIT? Check For Yourself

Performance is one of the main points of focus when working on small devices, speed and memory size are remarkably important and often contradictory requirements. Its very hard to deal with customer complaints of performance since this sort of behavior is very subjective to perception and hard to quantify, often devices would slow down during networking operations (since they grant the native network thread higher priority and ignore Java's thread priorities). On many occasions we would get complaints relating to a specific device performance and it would be very hard for us to see what specifically is taking time to perform on the given device.

To this extent we chose to develop LWUITSpeed which tries to stress a device VM as much as possible and produce a summary for performance on a given device. This summary can be reviewed and particular points of low performance for the device can be optimized, this tool is great both for optimizing LWUIT and has been used to optimize our native VM graphics libraries as well.

We hope you too can make use of this tool both to evaluate LWUITs performance and align your expectations for the performance of a specific device, this tool is now open source in the LWUIT source control repository.

Thursday, September 18, 2008

Cooking With LWUIT: The Movie

As I discussed the other day, Kirill inspired me to adapt the cookbook UI for LWUIT and mobile devices. The fact that it took me so little time and effort to accomplish a great UI mockup is a pretty decent testament to the power and flexibility of LWUIT.
Frankly there is so little work to do here it doesn't really justify too many separate posts... I started off with building a cookbook theme and adding some cut up images into it (pictured on the left) the rest was just creating the appropriate renderers and placing the content into LWUIT. As icing over the top I added some transitions to make everything work as one would expect.

The code is trivial.

Most of the lesson learned is in adapting photoshop design from the web and application world to the world of mobile devices. This mostly consists of removing UI elements and splitting the screen into smaller portions of importance within the application. The initial design didn't have any menus making the adaption even simpler in some cases.

The first video shows the cookbook running on the simulator while the second video here shows this running on a series 40 Nokia device with 2mb of ram.

Tuesday, September 16, 2008

Cooking With LWUIT Preview

Inspiration is powerful stuff, Kirill's blog often inspires and educates me (highly recommended even for non-Swing developers his blog is very informative on all things GUI). This past week he featured an excellent series covering the subject of creating a UI from a photoshop mockup, this is a remarkably common task with very little coverage especially when considering the amount of times we get asked to perform this task.

Rather than just pick up any application Kirill focused on an application that never really existed and has an imaginative mockup photoshop UI, he did an impressive job in showing off the power of his excellent (and gorgeous) Swing Substance Look And Feel. Can something like this be done in LWUIT???

No.

Sort of... Maybe. But not quite.

The UI is remarkable in its use of textures which have rather elaborate underlying special effects not really feasible on a phone what we can do is "cheat", we can use pre-rendered textures to reach a very similar effect. We also need to adapt the UI which just won't fit on even the largest phones available...

Unlike Kirill's series which deals with replicating 1 to 1 the photoshop design, this series is geared towards adapting an existing design used in applications or websites in order to move it to the cellular environment. I will write more about this in the next post and explain some of what I did but for now enjoy the teasers, a screenshot of the cookbook UI in LWUIT and the original cookbook image.

BTW any artifact you may see in the LWUIT image is purely my bad skills at gimp/photoshop shining through... I needed to do some cleaning up of the images and without a graphics department for this blog the quality leaves something to be desired ;-)

Sunday, September 14, 2008

Porting LWUIT Part I: Basics Of The Porting Layer

This series is intends for hackers who wish to port LWUIT itself, not for developers wishing to port applications written in LWUIT. LWUIT is portable on two fronts, the first allows us to run applications developed in LWUIT in many platforms. The second allows us to adapt LWUIT to additional platforms such as CDC, Android etc...

LWUIT's portability is achieved by abstracting the underlying platform in a porting layer which consists of 3 main classes and a few optional classes: Graphics, Implementation and SystemFont. All of these classes are very system specific and require the porting to additional platforms to take them into account, additionally a port might want to either remove or adapt the classes: MediaComponent, Transition3D, M3G and Log.

Since the other classes in LWUIT make use of these classes all we need to do in order to port LWUIT is create a build.xml file which copies the existing LWUIT code base and deletes these files. We then need to compile with our version of these files that makes use of the new API, e.g. when porting to CDC we no longer have GameCanvas of which the Implementation class derives, so we derive from java.awt.Component which is the closest counterpart.

The implementation class is completely hidden within LWUIT since it contains many hidden implementation details that are subject to change. However, several of its methods are used by LWUIT itself and this allows us to ease the porting work considerably. Since the class is hidden its API isn't "documented" and so it is likely that the task of porting will change in some ways in future versions of LWUIT (e.g. as we add functionality to LWUIT the implementation class would be modified/enhanced).

To understand this better the Implementation class in the Android port is based on the android.view.View class, while the LWUIT Graphics class delegates everything to the android.graphics.Canvas class. In the Java SE port, the implementation class is a JComponent while the Graphics class delegates to the java.awt.Graphics2D class.

Thursday, September 11, 2008

Yoav Demoing LWUIT For SDN (Sun Developer Network)

Yoav Barel the manager of the operator group and a major driving force behind LWUIT is interviewed here in the Sun Developer network videos. Without Yoav's vision and support we wouldn't have LWUIT it would never have reached the market and never would have become open source.
This discussion is a great summary introducing LWUIT.

Wednesday, September 10, 2008

Animated Focus Transition For Regular Components

Lists in LWUIT have a great animation by default to show the transition between elements in the list. Components placed in the form don't have that animation by default, but they can thanks to the ability to infinitely customize everything about LWUIT.
The animation is comprised of motion objects tracking the transition from one element to the next and painting an overlay before setting the actual focus element, the code is really very simple...
class FocusAnimation extends Form {
private Component futureFocus;
private Motion focusMotionX;
private Motion focusMotionY;
private Motion focusMotionWidth;
private Motion focusMotionHeight;
public FocusAnimation() {
super("Focus Animation");
for(int iter = 1 ; iter < 5 ; iter++) {
addComponent(new Button("Button " + iter));
}
addComponent(new TextArea("Multi-line text\nwith several\ndifferent lines", 3, 20));
addComponent(new List(new Object[] {"Entry 1", "Entry 2", "Entry 3"}));
addComponent(new ComboBox(new Object[] {"Entry 1", "Entry 2", "Entry 3"}));
}

public void setFocused(Component c) {
Component current = getFocused();
if(current != null && current != c) {
futureFocus = c;
focusMotionX = Motion.createSplineMotion(current.getAbsoluteX(), futureFocus.getAbsoluteX(), 300);
focusMotionY = Motion.createSplineMotion(current.getAbsoluteY(), futureFocus.getAbsoluteY(), 300);
focusMotionWidth = Motion.createSplineMotion(current.getWidth(), futureFocus.getWidth(), 300);
focusMotionHeight = Motion.createSplineMotion(current.getHeight(), futureFocus.getHeight(), 300);
focusMotionX.start();
focusMotionY.start();
focusMotionWidth.start();
focusMotionHeight.start();
super.setFocused(null);
} else {
super.setFocused(c);
}
}

public void paint(Graphics g) {
super.paint(g);
if(futureFocus != null) {
g.setColor(futureFocus.getStyle().getBgSelectionColor());
g.fillRect(focusMotionX.getValue(), focusMotionY.getValue(),
focusMotionWidth.getValue(), focusMotionHeight.getValue(),
(byte)140);
}
}

public boolean animate() {
boolean val = super.animate();
if(futureFocus != null && focusMotionX.isFinished()) {
super.setFocused(futureFocus);
futureFocus = null;
focusMotionX = null;
focusMotionY = null;
focusMotionWidth = null;
focusMotionHeight = null;
}
return val || futureFocus != null;
}
}

Sunday, September 7, 2008

LWUIT Application Alert: PaderSyncFM & MyWidz

One of the cool surprises we get is when someone just releases a LWUIT application out of the blue. A couple of such applications came out recently that seem very cool and attractive, first is Pader Sync File Manager which has been around for quite some time. They decided to overhaul their UI using LWUIT and are prompting this as one of the main features of their new release.
It seems like a cool and useful application but I had trouble with it under Symbian where you can't really control permissions properly (manufacturer/operator restrictions are really limiting here).

The other application is MyWidz it offers a widget based experience for installing widgets on the cell phone, seems somewhat similar to the Hydrazine project from Sun.

Wednesday, September 3, 2008

Running On The Smasung F480

I just uploaded a video showing LWUIT on the Samsung F480. This is one of the most impressive devices running LWUIT so far since it is running a high quality VM with proper 3D support on a touch screen device. This allows us to show off practically every featue of LWUIT on a single device.

If you are demoing a LWUIT application this device is high performance and allows your application to really shine, I highly recommend it.

Monday, September 1, 2008

LWUIT Running On The HTC Touch

This video shows LWUIT running on the HTC touch device using the PhoneME open source VM from java.net.
PhoneME is very fast and provides a high performance user experience on this device. However, the open source version doesn't have 3D support so we can't really demo those features in this device either.

Chen chose to use the stylus for this device since the touch screen doesn't respond well to direct touch by fingers.

Sunday, August 31, 2008

Porting LWUIT - The LWUIT Micro Backend

Porting LWUIT is something I need to blog on more, which is something I fully intend to do. In the meantime Guillaume Legris sent us a link to a port he is working on of LWUIT on top of the Micro Backend.
I wasn't even aware of the existence of the micro backend before this email, which shows off how open sourcing a product can result in such pleasant and unexpected surprises. If you are working on such porting projects we obviously will try to help, I also intend to start a series of posts about the task of porting LWUIT to other platforms in the near future.

Thursday, August 28, 2008

Pimp My LWUIT Part 6: GlassPane ScrollBar

I mentioned the GlassPane ScrollBar before but the code wasn't public yet. It has been out for some time now so I should probably refresh my previous post explaining how to achieve effects such as this as well as some other very cool special effects you can accomplish with such a tool.

A painter is an interface that abstracts the idea of painting, unlike a component which has a state and a hierarchy (everything from focus to enabled state, positioning etc..). Painter doesn't carry all of that complexity, it only paints a region and keeping state is purely optional. A painter can be as simple as an image (tiled, scaled, centered etc.) or as elaborate as a special effect like tinting, blurring, swirling etc... Since you decide what to paint and how to do so in runtime a painter can be very smart, it can adapt to device capabilities (e.g. using 3D or SVG when applicable and falling back to plain images when not), it can often scale better for different resolutions (since it can use primitive vector graphics).

All LWUIT components support background painters, this allows you to install custom code to paint the background of each and every LWUIT component without deriving or changing their source code. This is a very powerful tool allowing a developer the ability to customize the UI of LWUIT in unprecedented ways! With our current version we incorporated the glass pane this is a term borrowed directly from Swing however we implemented it differently. The LWUIT glass pane is a painter drawn on top of the form, this allows a developer to paint something after the form has completed painting without worrying about corruption.

Why not just derive from Form and override paint?

Because it might not be invoked... E.g. a Form with a button on it will invoke paint() the first time it is shown.
However when the user selects or presses the button this triggers a Button.repaint() call which will only call the paint method of the button (not the entire form). This is an efficient approach for painting but it will obviously circumvent any attempt at drawing something on top of that button without deriving it as well...

Deriving all the components in the form is not very feasible due to the complexity of repeatedly painting the same area (this matters when the glass pane/component is translucent), not to mention the labor involved in doing something like this...

Unlike deriving from a Form the glass pane is clever about individual component repaints, such components seamlessly trigger a paint of the glass pane itself with the proper clipping region to avoid a situation of painting the entire screen just to reconstruct a small area.

To change the original PimpLookAndFeel we just update bind to use the glass pane but most of the code remains the same (some coordinate calculations were changed and minor bugs were fixed so the full source is pasted bellow):
public class PimpLookAndFeel extends DefaultLookAndFeel {
private static final Image SCROLL_DOWN;
private static final Image SCROLL_UP;
private ScrollBarAnimation scrollAnimation;
private int opacity = 255;
private int imageOpacity;
private Image scrollBarImage;
private Component scrollComponent;
private float offsetRatio;
private float blockSizeRatio;

static {
Image sd = null;
Image su = null;
try {
sd = Image.createImage("/scrollbar-button-south.png");
su = Image.createImage("/scrollbar-button-north.png");
} catch(IOException ioErr) {
ioErr.printStackTrace();
}
SCROLL_DOWN = sd;
SCROLL_UP = su;
}

private Painter formPainer = new RadialGradientPainter(0xffd800, 0xfffa75);
public PimpLookAndFeel() {
Hashtable themeProps = new Hashtable();
themeProps.put("fgColor", "666666");
themeProps.put("SoftButton.fgColor", "666666");
themeProps.put("Title.fgColor", "0");
themeProps.put("fgSelectionColor", "0");
themeProps.put("bgColor", "ffd800");
themeProps.put("bgSelectionColor", "ffd800");
themeProps.put("transparency", "0");
themeProps.put("CommandList.margin", "6,6,6,6");
themeProps.put("Button.transparency", "130");
themeProps.put("border", Border.getEmpty());
UIManager.getInstance().setThemeProps(themeProps);

Style s = UIManager.getInstance().getComponentStyle("Menu");
s.setBorder(new DropShadowRoundedBorderLinearGradient(0xff0000, 0xffffff, true, 0xff, 10, 10));
s.setBgTransparency(255);
UIManager.getInstance().setComponentStyle("Menu", s);

s = UIManager.getInstance().getComponentStyle("Dialog");
s.setBorder(Border.createRoundBorder(10, 10));
s.setBgTransparency(170);
s.setBgColor(0);
s.setFgColor(0xffffff);
UIManager.getInstance().setComponentStyle("Dialog", s);

s = UIManager.getInstance().getComponentStyle("DialogBody");
s.setBorder(null);
s.setBgTransparency(0);
s.setFgColor(0xffffff);
s.setFgSelectionColor(0xffffff);
s.setFont(Font.createSystemFont(Font.FACE_PROPORTIONAL, Font.STYLE_BOLD, Font.SIZE_LARGE));
UIManager.getInstance().setComponentStyle("DialogBody", s);
}

public void bind(Component c) {
if(c instanceof Form) {
if(!(c instanceof Dialog)) {
c.getStyle().setBgPainter(formPainer);
}
final Form f = (Form)c;
f.getTitleStyle().setBgPainter(new LinearGradientPainter(0xffffff, 0xaaaaaa, false));
f.getSoftButtonStyle().setBgPainter(new LinearGradientPainter(0xaaaaaa, 0xffffff, false));

// install a glass pane that will draw the
PainterChain.installGlassPane(f, new Painter() {
public void paint(Graphics g, Rectangle rect) {
if(scrollComponent != null && scrollComponent.getComponentForm() == f) {
checkParentAnimation(scrollComponent, offsetRatio, blockSizeRatio, false);
drawScrollImpl(g, scrollComponent, offsetRatio, blockSizeRatio, true);
}
}
});
}
}

private void drawScrollImpl(Graphics gr, Component c, float offsetRatio, float blockSize, boolean vertical) {
int posX = c.getAbsoluteX() + c.getScrollX();
int posY = c.getAbsoluteY() + c.getScrollY();
gr.translate(posX, posY);
int margin = 3;
int width, height;
width = SCROLL_UP.getWidth();

// check the conditions requiring us to redraw the cached image
if(scrollBarImage == null || imageOpacity != opacity || scrollBarImage.getHeight() != c.getHeight()) {
int aX, aY, bX, bY;
aX = margin;
bX = aX;
aY = margin;
bY = c.getHeight() - margin - SCROLL_UP.getHeight();
height = c.getHeight() - SCROLL_UP.getHeight() * 2 - margin * 2;
scrollBarImage = Image.createImage(SCROLL_UP.getWidth() + margin * 2, c.getHeight());
Graphics g = scrollBarImage.getGraphics();
g.setColor(0);
g.fillRect(0, 0, scrollBarImage.getWidth(), scrollBarImage.getHeight());
g.setColor(0xffffff);
g.fillRect(aX, aY + SCROLL_UP.getHeight(), width, height);
g.drawImage(SCROLL_UP, aX, aY);
g.drawImage(SCROLL_DOWN, bX, bY);

aY += SCROLL_UP.getHeight();
g.setColor(0xcccccc);
g.fillRoundRect(aX + 2, aY + 2, width - 4, height - 4, 10, 10);
g.setColor(0x333333);
int offset = (int)(height * offsetRatio);
g.fillRoundRect(aX + 2, aY + 2 + offset, width - 4, (int)(height * blockSize), 10, 10);
scrollBarImage = scrollBarImage.modifyAlpha((byte)opacity, 0);
}

gr.drawImage(scrollBarImage, c.getWidth() - width - margin, 0);
gr.translate(-posX, -posY);
}


/**
* Draws a vertical scoll bar in the given component
*/

public void drawVerticalScroll(Graphics g, Component c, float offsetRatio, float blockSizeRatio) {
scrollComponent = c;
this.offsetRatio = offsetRatio;
this.blockSizeRatio = blockSizeRatio;
}

/**
* Scrollbar is drawn on top of existing widgets
*/

public int getVerticalScrollWidth() {
return 0;
}

/**
* Scrollbar is drawn on top of existing widgets
*/

public int getHorizontalScrollHeight() {
return 0;
}

private void checkParentAnimation(Component c, float offset, float blockSizeRatio, boolean vertical) {
if(scrollAnimation == null || (!scrollAnimation.isOK(offset, blockSizeRatio, c))) {
Form parent = c.getComponentForm();
scrollAnimation = new ScrollBarAnimation(parent, c, offset, blockSizeRatio, vertical);
}
}

private class ScrollBarAnimation implements Animation {
private Form parent;

private Component cmp;
private float scrollOffset;
private float blockSize;
private boolean vertical;

private Motion fadeMotion;
private long time = System.currentTimeMillis();

public ScrollBarAnimation(Form parent, Component cmp, float scrollOffset, float blockSize, boolean vertical) {
this.parent = parent;
parent.registerAnimated(this);
this.cmp = cmp;
this.scrollOffset = scrollOffset;
this.blockSize = blockSize;
this.vertical = vertical;
fadeMotion = Motion.createLinearMotion(255, 70, 2000);
opacity = 255;
}

public Component getComponent() {
return cmp;
}

public boolean isOK(float scrollOffset, float blockSize, Component cmp) {
if(scrollOffset == this.scrollOffset && blockSize == this.blockSize && cmp == this.cmp) {
return true;
}
if(parent != null) {
parent.deregisterAnimated(this);
}
return false;
}

public boolean animate() {
if(!parent.isVisible()) {
parent.deregisterAnimated(this);
return false;
}
if(fadeMotion != null) {
// wait one second before starting to fade...
if(time != 0) {
if(System.currentTimeMillis() - time >= 1000) {
fadeMotion.start();
time = 0;
}
return false;
}
int value = fadeMotion.getValue();
if(fadeMotion.isFinished()) {
fadeMotion = null;
}
if(opacity != value) {
opacity = value;
cmp.repaint();
}
return false;
}
parent.deregisterAnimated(this);
return false;
}

public void paint(Graphics g) {
}
}
}