Devel Blog – CoPLaS

Blog about things, I'm currently interested in. Now Android, Grails, jQuery and Java.

About me

Developer from Slovak Republic, EU. Currently interested in Java, Grails and Flex.

CV - Curriculum Vitae

I had to add extra “space” to Bitmap image, finally got it working, but still it seems “stupid” solution.
I had to display many Bitmap images using ImageViews, but to some of them it was necessary to add extra space on the top, some of them on the left. (Using margins was one possibility, preparing images to the right size other)

Finally I got this working, but I don’t like this solution :( .

public Bitmap addOffsets(Bitmap bmp, int width, int height, int xoffset, int yoffset) {
  Bitmap bmOffsets = Bitmap.createBitmap(width + xoffset, height + yoffset, bmp.getConfig());
  Canvas canvas = new Canvas(bmOffsets);
  canvas.drawBitmap(bmp, xoffset, yoffset, null);
  return bmOffsets;
}

Any idea of better way, how to do it?

I developed some android applications (e.g. Ideal time for Car Wash) and today something strange happend… I updated SDK Tools and ADT to revision 17 and apps using external jars as AndroidQuery, Admob, OrmLite failed to run on devices from Eclipse. Next I found, that the problem was not in the device, because emulator was giving the same exceptions:

logcat (many like this):

03-22 14:26:59.398: E/dalvikvm(663): Could not find class 'com.androidquery.AQuery', referenced from method com.idealtimefor.IdealTimeForActivity.onCreate

and then:

03-22 14:26:59.618: E/AndroidRuntime(663): java.lang.NoClassDefFoundError: com.androidquery.AQuery
03-22 14:26:59.618: E/AndroidRuntime(663): at com.idealtimefor.IdealTimeForActivity.onCreate(IdealTimeForActivity.java:91)

etc..
After about a hour (I created new project, copy paste all to it, clean, change android version, reading some forum posts and blogs  etc..) I realized, that I had jars in “lib” folder and some working apps had it in “libs” folder. So I renamed lib folder to “libs” and the magic happened - all was working again… I really have no idea, why after update this happened…

For many years, there exists discrimination of some (mostly) central and eastern members of EU. They can’t sell their Android applications on Android market. Most interesting is, that Slovakia, Slovenia, Estonia and Greece has EURO as their currency, but Google is “unable” to send money to these countries. As far as I know, Google is sending money from Ireland to EU countries, so I really don’t understand, what is the difference between sending euros to Austria, Germany etc. and sending euros to Slovakia, Slovenia, Estonia and Greece.

Also there is one of objectives of the union:

  • an internal market where competition is free and undistorted;

But in this case, I think that this objective is not followed, because for example German developers can sell their products to Slovak customers, but Slovak developers can’t sell their applications to German customers.

Map of EU (and some non EU) members, that can sell applications on Android market:

http://support.google.com/androidmarket/developer/bin/answer.py?hl=en&answer=150324

Not discriminating software developers from many EU countries by big companies can help to fight Economic crisis.

(Also this is in contrast with Google’s own informal corporate motto “Don’t be evil”…)

Pavel Michal Pavlasek

Software developer from Slovakia, EU

It is possible to call Flex from Javascript using ExternalInterface.

In Flex, just add ExternalInterface.addCallback in method called when creationComplete event is called.

I created example – call flex Alert.show method from flex button and from javascript.

Flex:

<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="absolute"
 creationComplete="onCreationComplete()">
<mx:Script>
<![CDATA[
import mx.controls.Alert;
public function onCreationComplete() : void {
     if (ExternalInterface.available) {
          ExternalInterface.addCallback("alertFlex", alertFlex);
     }
}

public function alertFlex(value:String):void {
     Alert.show( "alertFlex called from: " +value);
}
]]>
</mx:Script>
<mx:Button x="358" y="19" label="showAlert" click="alertFlex('flex')"/>
</mx:Application>

Javascript:

If id of the object (or embeded) is for example TestJavascriptCall, (view source of html in demo to see more), javascript call of alertFlex method will look like this:

<a href="#" onClick="TestJavascriptCall.alertFlex('javascript'); return false;">alert flex</>

Demo : click here.
(View Source is enabled.)

1. Download Flash Builder 4 – currently beta 4 (previously known as Flex Builder) from http://labs.adobe.com/technologies/flashbuilder4/
2. Install
3. Download Air 2 (currently beta) from http://labs.adobe.com/downloads/air2.html

  • Adobe AIR 2 SDK
  • Adobe AIR 2 Runtime

4. Install or update Air 2 Runtime
5. Install AIR 2 SDK

  • copy old SDK folder SDK
  • folder Adobe\Adobe Flash Builder Beta 2\sdks\4.0.0 to for example 4.0.0b
  • replace with files inside SDK zip

5. Setup Flash Builder 4 to use the “patched” Flex SDK (Flex4+AIR2 – for example 4.0.0b)
Window/Preferences/Flash Builder/Installed Flex SDKs

6. Create a new project – File/New/Flex project – Application type – Desktop

7. Edit project, add event handler to applicationComplete event – for example named appCompleteHandler, add your first AIR2 code – launch local file with default local application.

  • File is in my case named “comp_server.ods” and located in Documents of logged user (OS – Windows Vista) – line 12.
  • To be sure, I will print absolute location of that file to console – line 13.
  • Next – launch default application f.openWithDefaultApplication();line 14.

8. Save, build and launch – when application starts, it opens file (in my case – “comp_server.ods”) with default application (in my case Calc from OpenOfice.org)

9. Congrats – your first AIR2 application is running and opens local file in default application.

In this series of posts I will try to explain how to use Blaze DS in existing Flex/Java application.

First I expected it will be simple. I created test application using Blaze DS – just copy paste of some examples. But when I wanted to enable Blaze DS in existing app I realized there are some problems (described later, finally I solved them all ;) ).

Straightforward way for me was:

1. create simple Blaze DS server project and matching flex client project to test communication
2. merge server with existing server, same to do with client.

So the blaze DS application I created (just copy paste from some web examples) has main.xml file on the “Flex client” side and EchoService.java on the “Java server” side. Server just responses to the client call. Client displays response at the textarea component. If everything is OK it looks like next image.

blazeds3

I wanted to just merge this into existing project, but then I found, that Project/Properties/Flex server settings are all disabled in properties of existing (non BlazeDS) application.

blazeds1

Next I found that this properties are stored in .flexProperties file:

Blaze DS client test app:

<?xml version="1.0" encoding="UTF-8"?>
<flexProperties flexServerType="2" serverContextRoot="/blazeds"
serverRoot="C:/develop/blazeds/war" serverRootURL="http://127.0.0.1:8081/blazeds/"
toolCompile="true" useServerFlexSDK="false" version="1"/>

Existing app:

<?xml version="1.0" encoding="UTF-8"?>
<flexProperties flexServerType="0" toolCompile="true" useServerFlexSDK="false" version="1"/>

So I decided to add this directly to this directly.
added:

serverContextRoot=”/blazeds” serverRoot=”C:/develop/blazeds/war” serverRootURL=”http://127.0.0.1:8081/blazeds/

changed:
flexServerType=”2″ from flexServerType=”0″

Next I added main.mxml and polling.mxml to src folder of existing flex application (from the test BlazeDS application) and opened the project in Flex Builder. Settings at Project/Properties/Flex server are OK, so I started BlazeDS server and verified, if it communicates to existing server.

No :( . I’ve received:

Received fault: [RPC Fault faultString="[MessagingError message='Destination 'echoServiceDestination' either does not exist or the destination has no channels defined (and the application does not define any default channels.)']” faultCode=”InvokeFailed” faultDetail=”Couldn’t establish a connection to ‘echoServiceDestination’”]

So I decided to merge server app too:
copy
war\WEB-INF\flex\

add to web.xml:

<!-- Http Flex Session attribute and binding listener support -->
    <listener>
        <listener-class>flex.messaging.HttpFlexSession</listener-class>
    </listener>
    <!-- MessageBroker Servlet -->
    <servlet>
        <servlet-name>MessageBrokerServlet</servlet-name>
        <display-name>MessageBrokerServlet</display-name>
        <servlet-class>flex.messaging.MessageBrokerServlet</servlet-class>
        <init-param>
            <param-name>services.configuration.file</param-name>
            <param-value>/WEB-INF/flex/services-config.xml</param-value>
       </init-param>
        <load-on-startup>1</load-on-startup>
    </servlet>
    <servlet-mapping>
        <servlet-name>MessageBrokerServlet</servlet-name>
        <url-pattern>/messagebroker/*</url-pattern>
    </servlet-mapping>

copy src java server

copy \war\WEB-INF\lib\

Next I changed settings at Project/Properties/Flex server to new Flex server and click Apply and OK. Same error still.

I changed the original flex builder settings (of the Test Flex client) to match new server and It worked. So problem is somewhere in the new merged client :( .

I found that I had not Additional compiler arguments (Project properties/Flex compiler)
-services “c:\develop\PokerBlackBelt\WebContent\WEB-INF\flex\services-config.xml”

blazeds2
So I added that and recompiled.

That was the problem! It works now perfectly.

In the next posts I will solve the problem of absolute paths used in several places now (like Additional compiler arguments).  Also I will show how to use webtier compiler for flex (online java compiler from *.mxml) to *.swf.

You can download test blaze DS application from here and try this yourself.

I just had a problem with adding icon to a Panel title dynamically. When it is embedded, there is no problem. Than I found IconUtility Component for Dynamic Run-Time Icons and hoped everything will be fine in 5 minutes. I just tried example:

<mx:Button id="example" label="Example"
        icon="{IconUtility.getClass(example, 'http://michal.pavlasek.sk/us.png', 16, 16)}" />



All worked OK, so I tried to set titleIcon property on Panel:

[code lang="actionscript"]

import com.benstucki.utilities.IconUtility;

]]>

titleIcon="{IconUtility.getClass(testIconPanel, 'http://www.pavlasek.sk/devel/us.png', 16, 16)}">



[/code]

…and no icon were displayed.

After a while when I debugged IconUtility I realized that there is Dictionary object used, but problem was that key (in key-value pair) was the UIComponent that has the icon. All is OK for the button, but when used for Panel, the object is not Panel but Panel.titleBar property. Unfortunately it is not public but protected property so it is necessary to extend Panel. Here is example, first panel is just Panel and therefore no icon is in title, second is extended panel – IconPanel, there is one new property: titleIconSrc:String (view source enabled – use right mouse button):

Get Adobe Flash player


[code lang="actionscript"] xmlns:panel="panel.*" viewSourceURL="flex/panelIcon/srcview/index.html">

import com.benstucki.utilities.IconUtility;

]]>

titleIcon="{IconUtility.getClass(testIconPanel, 'http://www.pavlasek.sk/devel/us.png', 16, 16)}">

titleIconSrc="http://www.pavlasek.sk/devel/ico2.png">


[/code]

IconPanel.mxml
[code lang="actionscript"] creationComplete="onCreationComplete()" titleIcon="{ico}">


import com.benstucki.utilities.IconUtility;

[Inspectable]
[Bindable]
public var titleIconSrc:String;

[Bindable]
private var ico:Class;

private function onCreationComplete():void {
ico = IconUtility.getClass(this.titleBar, titleIconSrc, 16, 16);
}

]]>


[/code]

In Flash player it was possible until version 10 to upload files only by FileReference.upload method (there were some ugly hacks – such as uploading in external iframe).

Uploading files using directly FileReference.upload has some serious problems problems. Especially on Firefox, Flash player plugin creates it’s own request (different UserAgent, session and so) so on server it is handled in different session. All the parameters has to be sent, or some hacks has to be done (I manually set the jsessionid to each request).

And after all known hacks, it has still some serious problems using SSL – if the certificate is not validly imported to client machine, it just crashes without asking, if it has to trust it and so. See bugs:

Since v. 10 (and Flex 4), there is possibility to read local files directly, so I decided to try to upload files not using FileReference.upload method. But to read data as ByteArray and send it as POST request to server.

I found interesting class -UploadPostHelper in this article. Next I merged that example with my old code – browse for file and changed the method from FileReference.upload to FileReference.load. Server is java servlet using apache commons FileUpload – saves file to temp folder and sends XML response – all form items from post request and file uploaded – name and absolute path.

Adobe has changed security in flash player 10, it is impossible to send files in background (probably all requests now needs user interaction). It has to be in some user-action (click…) event handler, so I have two buttons, one for browse for a file, one for upload. Using just method that handles Event.COMPLETE (FileReference) causes Security sandbox violation.



Here is my Client code (UploadTest.mxml):
[code lang="actionscript"]


import mx.controls.Alert;

static public const SERVER_URL:String = "http://localhost:8081/flash10upload/servlet/FlexUpload";

private var fileReference:FileReference = new FileReference();

private function onLoad():void {
fileReference = new FileReference();
var myFilter:FileFilter = new FileFilter("Text","*.txt");
fileReference.browse([myFilter]);
fileReference.addEventListener(Event.SELECT,onFileSelect);
fileReference.addEventListener(Event.COMPLETE,onFileComplete);
}

private function onFileSelect(event:Event):void {
fileReference.load();
}

private function onFileComplete(event:Event):void {
Alert.show("File Loaded, click upload...");
uploadBtn.enabled = true;
}

private function upload():void {
var byteArray:ByteArray = new ByteArray();
var fileName:String = fileReference.name;
var uploadPath:String = SERVER_URL;
var parameters:Object = new Object();
parameters.test = "test1";

fileReference.data.readBytes(byteArray,0,fileReference.data.length);

var urlRequest:URLRequest = new URLRequest();
urlRequest.url = uploadPath;
urlRequest.contentType = 'multipart/form-data; boundary=' + UploadPostHelper.getBoundary();
urlRequest.method = URLRequestMethod.POST;
urlRequest.data = UploadPostHelper.getPostData(fileName, byteArray, parameters);
urlRequest.requestHeaders.push( new URLRequestHeader( 'Cache-Control', 'no-cache' ) );

var urlLoader:URLLoader = new URLLoader();
urlLoader.dataFormat = URLLoaderDataFormat.BINARY;
urlLoader.addEventListener(Event.COMPLETE, onComplete);
urlLoader.addEventListener(IOErrorEvent.IO_ERROR, onError);
urlLoader.addEventListener(SecurityErrorEvent.SECURITY_ERROR, onError);
urlLoader.load(urlRequest);
}

private function onComplete(eventObj:Event):void {
var ldr:URLLoader = eventObj.currentTarget as URLLoader;

Alert.show(ldr.data , "complete");
}

private function onError(eventObj:ErrorEvent):void {
Alert.show("onError");
}

]]>







[/code]




Here is my Server code (FlexUploadServlet):
[code lang="java"]
package sk.pavlasek.flash10Upload.web;

import java.io.File;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.util.List;

import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.commons.fileupload.FileItem;
import org.apache.commons.fileupload.FileItemFactory;
import org.apache.commons.fileupload.FileUploadException;
import org.apache.commons.fileupload.disk.DiskFileItemFactory;
import org.apache.commons.fileupload.servlet.ServletFileUpload;
import org.apache.log4j.Logger;

public class FlexUploadServlet extends HttpServlet {

private static final long serialVersionUID = 4588660828164350807L;

private static final Logger log = Logger.getLogger(FlexUploadServlet.class);

public void doPost(HttpServletRequest req, HttpServletResponse res)
throws UnsupportedEncodingException {
res.setDateHeader("Expires", -1);
res.setDateHeader("Last-Modified", System.currentTimeMillis());
res.setHeader("Pragma", "");
res.setHeader("Cache-Control", "");

req.setCharacterEncoding("UTF-8");
res.setCharacterEncoding("UTF-8");

File disk = null;
FileItemFactory factory = new DiskFileItemFactory();
List items = null;
ServletFileUpload upload = new ServletFileUpload(factory);
ServletOutputStream out = null;

try {
res.setContentType("text/xml");
out = res.getOutputStream();
out.println("");

items = upload.parseRequest(req);
for (FileItem item : items) {

if (item.isFormField()) {
out.println(" + "\" value=\"" + item.getString() + "\" />");
} else {
String tempdir = System.getProperty("java.io.tmpdir");

if (!(tempdir.endsWith("/") || tempdir.endsWith("\\"))) {
tempdir = tempdir + System.getProperty("file.separator");
}

String fileName = tempdir + item.getName();
disk = new File(fileName);
item.write(disk);
log.debug(disk.getAbsolutePath());

out.println("");
out.println("" + item.getName()
+ "
");
out.println("" + disk.getAbsolutePath() + "");
out.println("
");
}
}
out.println("");
out.close();
} catch (FileUploadException fue) {
fue.printStackTrace();
} catch (IOException ioe) {
ioe.printStackTrace();
} catch (Exception e) {
e.printStackTrace();
}
}
}

[/code]



Download:

I finished some enhancements for my ESFlvPlayer.

Now it is capable to play flash videos randomly, play all flv files from some directory, full screen mode, smoother mode, loop, when end of play-list to first video, play randomly, drag and drop changes order in play-list. I merged some components for video playback in flex and made some necessary changes. There will probably be many bugs there :) .

Enjoy (Show source enabled).

Archive of air and zip of project for Flex Builder (View source enabled in application):

Try the latest ESFlvPlayer here:




Download ESFlvPlayer now.


This application requires the Adobe® AIR™ runtime to be installed for
Mac OS or
Windows.

If you need to install Adobe AIR:

ESFlvPlayer – Part 1

June 5th, 2008

I made some search to find components to build my ESFlvPlayer.

I decided to use VideoDisplay to display video, but then I found there is no FullScreen mode. Next I found “hacked” version of VideoDisplay – FSVideoDisplay, that uses some properties from namespace mx_internal ;) Press Esc to return to normal mode from FullScreen mode.

To list files from disc and specify what file to play I used flash.filesystem.File (not my code, I found it somewhere in flex conference on google). Fragment of source code:

private var file:File = File.documentsDirectory;

private function fileOpen():void {
	file.browseForOpen("Select a file");
	file.addEventListener(Event.SELECT, onSelect);
}

private function onSelect(event:Event):void {
	vUrl = file.url;
	vName = file.name;
	myVideo.play();
	timer.visible=true
}

<component:FSVideoDisplay x="70" y="26" width="379" height="234" id="myVideo"
	source="{vUrl}"/>
	<mx:Button click="fileOpen()" label="Open" x="70" y="289"/>

Next steps will be:

  • Better player component – I found some, I just need to add full screen mode to that component (just merge two components ;) )
  • Add playlist

Archive of air and zip of project for Flex Builder (View source enabled in application):

Try the latest ESFlvPlayer here:




Download ESFlvPlayer now.


This application requires the Adobe® AIR™ runtime to be installed for
Mac OS or
Windows.

If you need to install Adobe AIR: