Archive for the ‘AIR’ Category

Memory usage during file upload in AIR

Saturday, March 29th, 2008

Uploading files in AIR is a little bit problematic these days.

Here is the code:

<?xml version="1.0" encoding="utf-8"?>
<mx:WindowedApplication xmlns:mx="http://www.adobe.com/2006/mxml" layout="absolute" showStatusBar="false" 
  initialize="onInitialize(event)">  
 
  <mx:Script>
    <![CDATA[
 
      import com.rwnage.s3.service.S3PostOptions;
      import flash.events.Event;
 
      public function onInitialize(event:Event):void {
        var accessKey:String = "0RXZ3R7Y034PA8VGNWR2";
        var bucketName:String = "rwnage_test";
        var objectName:String = "test_file";
        var contentType:String = "application/octet-stream";
        var secretAccessKey:String = "[PUT YOUR SECRET ACCESS KEY HERE]";      
 
        var postOptions:S3PostOptions = new S3PostOptions(bucketName, objectName, accessKey, 
          { contentType: contentType });
 
        var policy:String = postOptions.getPolicy();
        var signature:String = postOptions.getSignature(secretAccessKey, policy);
 
        html.htmlText = '<html><body> \
          <form name="upload" action="http://' + bucketName + '.s3.amazonaws.com/" method="post" enctype="multipart/form-data"> \
            Key to upload: <input type="input" name="key" value="' + objectName + '" /><br /> \
            Content-Type: <input type="input" name="Content-Type" value="' + contentType + '" /><br /> \
            <input type="hidden" name="AWSAccessKeyId" value="' + accessKey + '" /> \
            <input type="hidden" name="Policy" value="' + policy + '" /> \
            <input type="hidden" name="Signature" value="' + signature + '" /> \
            File: <input type="file" name="file" /> <br /> \
            <!-- The elements after this will be ignored --> \
            <input type="submit" name="submit" value="Upload to Amazon S3" /> \
          </form></body></html>';                                                     
      }
 
    ]]>
  </mx:Script>
 
  <mx:HTML id="html" width="100%" height="100%" paddingLeft="20" paddingTop="20"/>
 
</mx:WindowedApplication>

No I don’t normally use mx:script tags, its a test case.

Eventually it malloc fails and crashes. This issue is Mac only and also occurs during a FileReference (or File) upload.

Socket output progress in AIR

Thursday, January 17th, 2008

Currently when using the flash.net.Socket api, there is no way to
determine that buffered data has been written to the socket. (The flush method is non-blocking and applies only to the actionscript socket buffer).

This is a follow-up to a previous post.

This issue does not arise when using the new File api (and writing to
files), since an event has been included in
flash.filesystem.FileStream: OutputProgressEvent.OUTPUT_PROGRESS

If this (or a similar) event could be added to the Socket api, it
would allow us to:

  • Send large amounts of data on a socket (without causing large memory
    usage as data buffers in memory).
  • Measure the current progress of data being sent on the socket.

We came upon this limitation from using our AS3 http client library, and trying to send large
files as part of a multipart upload. However this issue would arise
when sending any significant amounts of data on a socket. For example, an FTP or bittorrent client would be impossible.

This issue has been discussed in other places, but is probably more
pressing now with the AIR releases.

Update: Vote on this bug (FP-6)

popen’ing

Wednesday, November 7th, 2007

I updated airake to work on windows (thanks Todd). Instead of using system (or %x), I am trying IO.popen:

IO.popen(@cmd) do |f|
  @output = f.read
  @process = Process.waitpid2(f.pid)[1]
end

and in windows you’ll need to cmd.exe /c it:

@cmd = RUBY_PLATFORM =~ /win32/ ? "cmd.exe /c #{cmd}" : cmd

This thread was helpful and I popened a new airake/runner.rb version. The FCSH daemon still doesn’t work in windows yet.

Update: Google Reader AIR app

Wednesday, October 31st, 2007

Download GReader-0_1_2.air

I updated the app to work in Leopard. I have no idea why but using the url, http://www.google.com/reader/view, instead of http://reader.google.com fixed it. I think that might mean there is a redirect issue? I changed the dock icon unread count to just show the number in the top right. Also I added an option to enable the hicksdesign google reader theme. I had to mess with it since apparently AIR webkit doesn’t support the css data uri scheme, which is annoying.

I apply the style through the javascript bridge:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
    [Embed(source="/assets/styles/greader/greader.css", mimeType="application/octet-stream")]
    private var cssClass:Class;

    private var html:HTML;
    ...

    public function applyStyle(e:Event):void {
      var cssByteArray:ByteArrayAsset = ByteArrayAsset(new cssClass());
      var css:String = cssByteArray.readUTFBytes(cssByteArray.length);
      
      var document:JavaScriptObject = html.htmlControl.window.document;
      
      var head:JavaScriptObject = document.getElementsByTagName("head")[0];
      var node:JavaScriptObject = document.createElement("style");
      node.type = "text/css";
      node.appendChild(document.createTextNode(css));
      head.appendChild(node); 
    }

Google Reader AIR app

Monday, October 29th, 2007

Download GReader-0_1.air

I was playing around with the actionscript to javascript bridge and built this Google Reader AIR app:

I find the unread count from ‘reading-list-unread-count’:

1
2
3
var html:HTML = ...
var window:JavaScriptObject = html.htmlControl.window;
var unread:String = window.document.getElementById("reading-list-unread-count").innerHTML.toString();

Then I generate a dock icon (ignore all the hard coded pixel math):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
[Embed(source="/assets/app_icons/greader/icon_128.png")]
private var iconClass:Class;

[Embed(source="/assets/fonts/Verdana.ttf", fontName="GReaderDockIconFont", mimeType="application/x-font-truetype")]
private var fontClass:Class;
....

private function draw():void {  
  var icon:BitmapAsset = BitmapAsset(new iconClass()); 
      
  var shape:Shape = new Shape();
  shape.graphics.beginBitmapFill(icon.bitmapData, new Matrix(), true, false);
  shape.graphics.drawRect(0, 0, dimensions, dimensions);
  shape.graphics.endFill();
  
  shape.graphics.beginFill(0xDF0013);
  shape.graphics.drawCircle(32, dimensions - 32, 32);
  shape.graphics.endFill();
  addChild(shape);
  
  if (unreadCount > 0) addChild(buildText());      
}

public function buildText():Bitmap {
  var countText:TextField = new TextField();
  countText.embedFonts = true;

  var format:TextFormat = new TextFormat();
  format.font = new fontClass().fontName;
  format.color = 0xFFFFFF;      
  format.size = 26;
  format.align = TextFormatAlign.CENTER;
  
  countText.defaultTextFormat = format;
  countText.selectable = false;      
  countText.text = unreadCount.toString();
  countText.height = 32;
  countText.width = 54;
  
  var bitmapData:BitmapData = new BitmapData(64, 32, true, 0x00000000);
  bitmapData.draw(countText);      
  var bitmap:Bitmap = new Bitmap(bitmapData);
  bitmap.smoothing = true;
  bitmap.y = 128 - 52;
  bitmap.x = 4;
  return bitmap;
}

Set the dock icon with the generated bitmap data:

1
2
if (Shell.shell.icon is InteractiveIcon) 
  InteractiveIcon(Shell.shell.icon).bitmaps = icons;

For more info on dynamic dock icons, see Generating Dynamic Dock and System Tray Icons in AIR

I think the next step is taking a bunch of greasemonkey js scripts and adding them in. This might be how you would do that:

1
2
3
4
5
6
7
8
var html:HTML = ...
var window:JavaScriptObject = html.htmlControl.window;      
var head:JavaScriptObject = window.document.getElementsByTagName("head")[0];         
var script:JavaScriptObject = window.document.createElement('script');
script.type = 'text/javascript';
//script.src = 'http://lolcats.com/script.js';
script.innerHTML = "alert('HAI.. KTHXBYE');";
head.appendChild(script);

Update: I’ve seen it tack the CPU when interacting in a couple places so I will try to figure out if its AIR webkit being buggy or me. Also will fix the external link lameness at some point.

Update: Oops. Looks like it doesn’t work in Leopard.

browsair – Letting sites live in your dock

Saturday, October 13th, 2007

I wrote an AIR project generator for airake called browsair. It will build you a AIR webkit browser app targeted at a web site, so you can let it live in you dock (or tray whatever), instead of that 4th tab on the 2nd firefox window.

Theoretically someone could make a packaged browser + greasemonkey + stylish AIR app for particular web sites that growl notifies and lives in the dock and be more in your face; but this scaffold right now is pretty basic.

I should also mention there is a website called airifier which does this as well, except I think they give you a packaged app only, without the source.

I also got a bunch of fixes into this version of airake; packaging is fixed, and there is a task for creating certificates, among other things. I just deployed version 0.2.4 to rubyforge so it should be up by the time you read this.

The usage:

browsair GReader http://reader.google.com path/to/rss_icon_128x128.png

Creates an AIR project for a google reader AIR app. In the GReader project, run:

rake air:package CERTIFICATE=path/to/cert.pfx

If you need to generate a certificate:

rake air:certificate CERTIFICATE=../ducktyper.pfx

I built a couple already if you want to bypass all that compiling:

(If you don’t have the AIR runtime installed, get it here)

Updated airake to support AIR/Flex Beta 2

Friday, October 5th, 2007

I updated airake to support new AIR/Flex beta 2 build.

sudo gem update airake

I changed the fcsh tasks to:

rake fcsh:start
rake fcsh:stop
rake fcsh:restart

airake – Rake tasks and generators for adobe AIR apps

Tuesday, September 11th, 2007

airake gives you tasks for compiling, debugging, testing and packaging Adobe AIR applications. It also has a basic project generator/scaffold. All this was made possible because of the prolific newgem and rubigen gems.

To get started, checkout airake.rubyforge.org

The tasks and project might be a little Flex specific (cause of the particular project we are working on), so feel free to poke around or contribute back. Also I only tested it on MacOSX.

Some of the FCSH (flex compiler shell) daemon and wrappers are from the Sprout project, so be sure to check them out.