JavaFx 2.0 – Presenter

Hi,

As I mentioned in previous post I spend some time to try JavaFx 2.0 beta release. After playing a little with the tutorials, I try myself writing code that would include JavaFx Node transition, effects and coordinates manipulation.

I tried writing a simple slide presenter where slide would be defined in the graphic system coordinate as javafx.scene.Group and could be added to a com.mrlonee.presenter.Presenter. A little video of the sample presenter application is available :

[local /wp-content/uploads/2011/06/presenter.avi Presenter]

Here is a snapshot of the global view proposed by the application when it is launched

Initial overview is performed by scaling down the root node.

//Initial Scale
slideRoot.scaleXProperty().set(0.2);
slideRoot.scaleYProperty().set(0.2);

This presenter is responsible for proposing a container Group and a simple method to present next or previous element.

public interface Presenter{
 
public void addElementToPresent(final Node node);
 
public void presentNextElement();
 
public void presentPreviousElement();
 
public void presentElement(final Node node);
 
public Group getRootNode();
}

Slide declaration is for now done by constructing Nodes. Here is an example of what I’ve done for my sample application :

/*
* Hello slide
*/
Distant lightEffectDistant = new Light.Distant();
lightEffectDistant.azimuthProperty().set(-135);
 
Text text = new TextBuilder()
.content("Hello").x(0).y(300).fill(Color.GREEN).font(new Font(50))
.effect(new LightingBuilder().light(lightEffectDistant).surfaceScale(5.0).build())
.build();
 
presenterServices.addElementToPresent(text);
 
/*
* Slide 1
*/
List slide1Stops = new ArrayList();
slide1Stops.add(new StopBuilder().offset(0.0).color(Color.BLUE).build());
slide1Stops.add(new StopBuilder().offset(1.0).color(Color.DARKBLUE).build());
 
Group slide1 = new GroupBuilder().children(
new RectangleBuilder()
.x(0).y(0).width(200).height(150)
.fill(new LinearGradientBuilder().startX(0.5).startY(0.0).endX(1.0).endY(0.0)
.stops(slide1Stops).proportional(true).cycleMethod(CycleMethod.REPEAT).build())
.build(),
 
new TextBuilder().x(60).y(70).font(new Font(30))
.textAlignment(TextAlignment.CENTER).content("JavaFx")
.smooth(true).fill(Color.WHITE)
.effect(new DropShadowBuilder().offsetX(3.0).offsetY(3.0).build()).build(),
 
new TextBuilder().x(75).y(90).font(new Font(20))
.textAlignment(TextAlignment.CENTER).content("Rocks")
.smooth(true).fill(Color.WHITE).build()
).translateX(-200).translateY(-300).build();
 
presenterServices.addElementToPresent(slide1);
 
/*
* Slide 2
*/
List slide2Stops = new ArrayList();
slide2Stops.add(new StopBuilder().offset(0.2).color(Color.RED).build());
slide2Stops.add(new StopBuilder().offset(0.8).color(Color.RED.darker()).build());
slide2Stops.add(new StopBuilder().offset(1.0).color(Color.RED).build());
 
Group slide2 = new GroupBuilder().children(
new CircleBuilder()
.centerX(200).centerY(200).radius(200)
.fill(new RadialGradientBuilder().centerX(0.3).centerY(0.3).stops(slide2Stops).build())
.build(),
 
new TextBuilder().x(115).y(180).font(new Font(30))
.textAlignment(TextAlignment.CENTER).content("MrLoNee Too !")
.effect(new ReflectionBuilder().fraction(0.8).build())
.smooth(true).fill(Color.WHITE).build()
).translateX(400).translateY(400).build();
 
presenterServices.addElementToPresent(slide2);

Transition between each element is composed of a translate and and scale transition played together. It gives the effect that we scale up and down while translating to the next slide to present as follow

The translation code is above :

Timeline animationTransition = new TimelineBuilder()
.keyFrames(
new KeyFrame(Duration.ZERO,
new KeyValue( this.root.translateXProperty(), fromX),
new KeyValue( this.root.translateYProperty(), fromY)
),
new KeyFrame(Duration.ZERO,
new KeyValue( this.root.scaleXProperty(), this.root.scaleXProperty().get()),
new KeyValue( this.root.scaleYProperty(), this.root.scaleYProperty().get())
),
new KeyFrame(Duration.valueOf(300),
new KeyValue( this.root.scaleXProperty(), 0.7),
new KeyValue( this.root.scaleYProperty(), 0.7)
),
new KeyFrame(Duration.valueOf(150),
new KeyValue( this.root.translateXProperty(), fromX + (toX - fromX)/6),
new KeyValue( this.root.translateYProperty(), fromY + (toY - fromY)/6)
),
new KeyFrame(Duration.valueOf(450),
new KeyValue( this.root.translateXProperty(), fromX + (toX - fromX)*5/6),
new KeyValue( this.root.translateYProperty(), fromY + (toY - fromY)*5/6)
),
new KeyFrame(Duration.valueOf(600),
new KeyValue(this.root.translateXProperty(), toX),
new KeyValue(this.root.translateYProperty(), toY)
),
new KeyFrame(Duration.valueOf(600),
new KeyValue( this.root.scaleXProperty(), finalScale),
new KeyValue( this.root.scaleYProperty(), finalScale)
)
)
.build();

A Thumb view is built by the presenter as you add element to present. This thumb view just add a cyan circle node that is surrounded by a blue circle as the slide with thumb circle index  is presented. An example for third slide would be :

The source code is available in presenter.jar file in download page !

Feel free to try it. I might upgrade it with :

  • scale each slide so that it take the whole frame size
  • propose real node thumb to navigate when there is many slide
  • propose a way to choose what animation transition shall be taken
  • propose a slide editor (well it may be long I suppose…)

I still have to find a way to perform a scale animation that is using a custom scale center. I could use it to finish to scale so that the currently presented slide takes the whole frame width/height instead of using 1.0 scale of the slide.

LoNee

JavaFx – Exciting 2.0

Yesterday I received an e-mail from javafx4you with the following title : “JavaFx 2.0 beta is now available for download”. I had only a few moment to process this information because I already had plans, but I take time to download the beta version and install it on my computer.

After 2 minutes of coding I wrote a simple Stage just to see it running before leaving, but unfortunately my JDK version (64bit) did not fit the JavaFx jar (only 32 bit available for now). So I Took some time to download the 32 bit version of the last JDK… and Yes, the code did work !

So I go on and took time to write the full demo code availabe here.

The result is a cool cicle animation and blur effect stage. It seems to be very powerfull as the animation are really easy to describe and run… And graphical effects seem to be easy to compose.

I then tried to play with the event and add a mouseEnter mouseExited listener on each circle of the scene. The API is very close to Swing listeners, swing guy will not be very surprise, except that it seems to be the same approach than Android API, it is not a addMouseListener() method but a setOnMouseEntered(). So not a list of observer but a single observer ? I tried to add two different listener, and only the second one was called !

Moreover, JavaFx follow the same Single Threading rule than Swing. When in swing you use SwingUtilities.invokeLater() you shall now use Platform.runLater() for JavaFx. Swing/JavaFx integration seems to be managed through the javafx.embed.JFXPanel component that is a swing component. So integrating JavaFx into Swing is done ! Don’t forget to transfer event from Swing Thread to JavaFx Thread to respect the coding rule !

Now new experience can start, with easier graphic manipulation. I hope I will have time to try things again.

LoNee

Android – SMSReader

Trying to improve my Android understanding, and reading 01Informatique paper about TextToSpeech Android API, I wrote a little SMSReader application. This simple application allow you to start/stop a service that will read every received SMS. It can be usefull for example when you are driving !

It allows me to be introduced to Android android.app.Service and android.app.BroadcastReceiver components. It also give me a chance to try the application state save/recover concept that is hidden behind the android.app.Activity component.

Global Architecture is simple. It is composed of three components :

  • SMSReaderSpeakerService that is responsible for performing the SMS speak
  • SMSReaderActivity that is responsible for starting the user service by activating the SMSReaderSpeakerService
  • SMSReaderReceiver that is responsible for receiving SMS_Received broadcast event and pass it to the SMSReaderSpeakerService.

SMSReaderSpeakerService inherits from android.app.Service component. This kind of components are long-life component that can be started and perform background operations. My first version of the SMSReader tried to perform the speaking operation on the BroadcastReceiver (SMSReaderReceiver) component. But executing time-consuming operation like TextToSpeech can not be done on such component. Their life have to be short !

So here is the SMSReaderSpeakerService. It can handle three actions declared in the AndroidManifest.xml file :

<service android:name=”.SMSReaderSpeakerService”>
<intent-filter>
<action android:name=”com.mrlonee.SMS_SPEAK” />
<action android:name=”com.mrlonee.SMS_SPEAKER_ACTIVE” />
<action android:name=”com.mrlonee.SMS_SPEAK_CONFIGURATION” />
</intent-filter>
</service>

It means that sending one of these message to this service will do something ! SMS_SPEAK is to perform context messages Speak. SMS_SPEAKER_ACTIVE is to activate/desactivate the service for user (through the SMSReaderActivity component). SMS_SPEAK_CONNFIGURATION can be used to configure the TextToSpeech language that will be used.

SMSReaderActivity is the simple one toggle button HMI. It only own a toggle button that send and SMS_SPEAK_ACTIVE Itent to the SMSReaderSpeakerService Service, adding a parameter value that is a boolean indicating if the service is started or not. Here is the main code :

<em>if(toggleButton.isChecked()){
Intent speakerIntent = new Intent("com.mrlonee.SMS_SPEAKER_ACTIVE");
speakerIntent.putExtra("ACTIVE", true);
this.getApplicationContext().startService(speakerIntent);
}
else{
Intent speakerIntent = new Intent("com.mrlonee.SMS_SPEAKER_ACTIVE");
speakerIntent.putExtra("ACTIVE", false);
this.getApplicationContext().startService(speakerIntent);
}</em>

I tried to perform activity state save/restore mechanism, because an activity can be killed when your operating system needs some resources. It was a pain in the ass to manage to do so. I thought it would be simple, as the activity component life cycle seemed to be clear for me, but I discovered that it was difficult to manage all cases (creation, restore, close, background) and transitions. Finally the code that worked for me in most case was the onSaveInstanceState()/onRestoreInstanceState() duet. But I know it does not cover all the cases.

SMSReaderReceiver is a Broadcast receiver I simply declared in the AndroidManifest.xml file as a android.provider.Telephony.SMS_RECEIVED action consumer using the following receiver section :

<receiver android:name=”.SMSReaderReceiver”>
<intent-filter>
<action android:name=”android.provider.Telephony.SMS_RECEIVED” />
</intent-filter>
</receiver>

Its only work is to decode the incming SMS_RECEIVED parameters to pass it to the SMSReaderSpeakerService in an Intent with messages in parameters like this :

@Override
public void onReceive(final Context context, final Intent intent){

List<String> messages = new ArrayList<String>();
Bundle bundle = intent.getExtras();
if (bundle != null){
//—retrieve the SMS message received—
Object[] pdus = (Object[]) bundle.get(“pdus”);
for (int i=0; i<pdus.length; i++){
StringBuilder str = new StringBuilder();
SmsMessage smsMessage = SmsMessage.createFromPdu((byte[])pdus[i]);
if(smsMessage.isEmail()){
str.append(“Mail de “);
}
else{
str.append(“SMS de “);
}

str.append(smsMessage.getOriginatingAddress()).append(“. “).append(smsMessage.getMessageBody().toString());

messages.add(str.toString());
}

Intent speakerIntent = new Intent(“com.mrlonee.SMS_SPEAK”);
speakerIntent.putExtra(“SMS”, messages.toArray(new String[messages.size()]));
context.startService(speakerIntent);
}
}

To finish I would say that the components responsibilities are easy to identify in the way android propose to structure your application. Activity for HMI, Service for Background performed operations and BroadcastReceiver for system and others applications event receiving. Intent can be used to communicate through components. What despite me is the fact that the component communication is done using a key/value interface object. You can not be sure when you write your application that the components interface are the one you expect. You will discover this at runtime ! I would prefer having something like injection between components that allow you to perform compiled interface call instead of using such key/value system. It seems to me that this way of communication is safer.

Anyway, you can find the whole Eclipse project in a zip file here ! You will need Android Eclipse plugin to look at the SMSSpeaker project. The .apk file is also available here.

This program could be improved by replacing the SMS originator number by its name in the phone contacts list if it exists ! Help yourself, and send me your improvement !

LoNee

Clean Code

Today I would like to talk about a book I’ve read that has changed my programmer’s life. Clean Code : a handbook of agile software craftsmanship. This book start by describing common software issues and schemas that brings your project to fail. It claims that developing software is not easy, it is a real pain and you have to improve your programming skills if you want to finish your software products. Clean code is the base of a good application. It involves refactoring, code review, automatic unit test…

The book can be read in french at this link for chapter 1 & 2 . Take a time, read it, and you will start to realize that developers have real responsibilities on development choices, and they can not hide behind sentences like “I have not enough time to make it right, I will do it later…”.

Well, good time reading this book ! Thanks to CHU that suggest me to read it to improve my coding skills.

LoNee