« October 2009 | Main

November 19, 2009

Which Storage Devices Are Considered Removable?

AIR 2 has the ability to detect the mounting and un-mounting of storage volumes like flash drives, hard drives, some types of digital cameras, etc. (to see this in action, see A Demonstration of the New Storage Volume APIs in AIR 2). This feature basically piggybacks off of the operating system's detection of storage devices. In other words, if the OS thinks something is a mass storage device, AIR will also recognize it as such and throw a StorageVolumeChangeEvent. If the OS does not recognize the device as a storage volume, AIR will not react to it. (Note: it is possible to detect and communicate with any type of peripheral in AIR 2 using external processes launched with the new NativeProcess API; the StorageVolume APIs are only for, well, storage volumes.)

The StorageVolumeChangeEvent which is thrown in response to a volume being mounted contains a reference to the StorageVolume object representing the volume that was just mounted. The StorageVolume object contains several interesting properties:

The isRemovable property indicates whether the operating system considers the media it just detected as removable or not. Initially, this seemed pretty straightforward to me, but as I began playing with the APIs, I found I didn't always agree with the OS's assessment. For instance, my portable 500GB Western Digital USB hard drive is not considered removable even though I plug it in and remove it all the time (note that this is the operating system's decision -- not AIR's). And, for some reason, my Time Capsule is removable, but other network drives are not. Strange.

The table below shows the results of the testing I've done so far:

Type of Device StorageVolume.isRemovable
OS X Windows Linux
CD/DVD (fixed) true true true
USB Flash Drive true true true
USB Hard Drive false false true
FireWire Hard Drive ? ? ?
Shared Volume true ? n/a1
Network Drive false false n/a2
Storage Card Reader (empty) n/a3 false n/a3
Storage Card Reader (with SD/CF card) true true true

1 Linux doesn't have a concept of a shared volume.

2 No StorageVolumeChangeEvent is thrown when drives are mounted using SMB on Linux.

3 Windows considers empty card readers to be non-removable devices while OS X and Linux do not react to them at all.

I'm hoping to get other developers to try out whatever devices they have lying around on whichever OS they favor so we can make this chart as comprehensive as possible. If you have the opportunity to provide data for any of the missing cells, or if you have devices that aren't listed, please leave the information in the comments and I'll update the table. Over time, this should become a very valuable resource for developers googling for answers.

If you need a quick way to test, I threw together this little utility called StorageVolumeTest.air (source code) which will report all the StorageVolume properties as volumes are detected and mounted. This app requires the AIR 2 public beta which can be downloaded here.

For more information on the new storage volume detection capabilities of AIR 2, see Exploring the new file capabilities in Adobe AIR 2. Thanks for your help!

Posted by cantrell at 12:56 PM. Link | Comments (1) | References

November 18, 2009

Demonstration of Gesture APIs in AIR 2

I don't have a multi-touch computer (yet), but I do have a MacBook with a multi-touch trackpad which means I can write AIR 2 applications that incorporate gestures. The video below demonstrates a few of the new gesture APIs in AIR 2:

The code below shows how to indicate that you want to receive gesture events (as opposed to multi-touch, or no touch events at all), and registers for zoom, rotate, and pan gesture events (the watch variable refers to a Sprite which contains the bitmap image of the watch):

Multitouch.inputMode = MultitouchInputMode.GESTURE;
watch.addEventListener(TransformGestureEvent.GESTURE_ZOOM, onZoom);
watch.addEventListener(TransformGestureEvent.GESTURE_ROTATE, onRotate);
watch.addEventListener(TransformGestureEvent.GESTURE_PAN, onPan);

The three functions below show responding to each of the gesture events:

private function onZoom(e:TransformGestureEvent):void
{
    var watch:Sprite = e.target as Sprite;
    watch.scaleX *= e.scaleX;
    watch.scaleY *= e.scaleY;
}

private function onRotate(e:TransformGestureEvent):void
{
    var watch:Sprite = e.target as Sprite;
    watch.rotation += e.rotation;
}

private function onPan(e:TransformGestureEvent):void
{
    var watch:Sprite = e.target as Sprite;
    var watchBitmap:Bitmap = watch.getChildAt(0) as Bitmap;
    watchBitmap.x += e.offsetX;
    watchBitmap.y += e.offsetY;
}

For much more information on how multi-touch and gestures work in both AIR 2 and Flash Player 10.1 (including OS and hardware support, which gestures are supported where, and a thorough review of the APIs), and to download sample code, see Multi-touch and Gesture Support on the Flash Platform. Or, if you just want to see the code for this sample, you can download it here.

Posted by cantrell at 6:50 AM. Link | Comments (2) | References

November 16, 2009

AIR 2 Public Beta Resources

The AIR 2 public beta is now live! Below are all the links you'll need to learn more and get started:

Adobe Labs

Adobe Developer Center

Adobe TV

This Blog

Community

Posted by cantrell at 8:51 PM. Link | Comments (1) | References

November 13, 2009

A Demonstration of Encrypted Socket Support in AIR 2

I've been wanting to write my own email notifier in AIR for a long time, but without support for encrypted sockets, it wasn't easy to do. But now that AIR 2 added the new SecureSocket class, I was able to write a pretty functional email notifier in just a couple of days:

The new SecureSocket class extends Socket, so MenuMail can use either encrypted or non-encrypted sockets without really having to know the difference:

this.socket = (this.secure) ? new SecureSocket() : new Socket();

The MenuMail application, and all the code for MenuMail, will be available on Adobe Labs after the AIR 2 public beta launch (which is very close!).

Posted by cantrell at 7:20 AM. Link | Comments (4) | References

November 12, 2009

A Demonstration of the NativeProcess APIs in AIR 2

SearchCentral uses the new NativeProcess APIs in AIR 2 in order to integrate with Spotlight and provide very fast local file system search. Here's a demo:

The NativeProcess APIs are very simple to use. The code below invokes the mdfind command on OS X, and sets up an event listener to read the results from standard out:

private function onSearch():void
{
    var npInfo:NativeProcessStartupInfo = new NativeProcessStartupInfo();
    npInfo.executable = this.mdfindFile; // A reference to the mdfind command
    var args:Vector.<String> = new Vector.<String>;
    args.push("-interpret");
    args.push(this.searchTerm.text);
    npInfo.arguments = args;
    this.processBuffer = new ByteArray();
    this.nativeProcess = new NativeProcess();
    this.nativeProcess.addEventListener(ProgressEvent.STANDARD_OUTPUT_DATA, onStandardOutputData);
    this.nativeProcess.addEventListener(NativeProcessExitEvent.EXIT, onStandardOutputExit);
    this.setStatus("Searching for " + this.searchTerm.text + "...", true);
    this.nativeProcess.start(npInfo);
}

The code below shows buffering the data from standard out:

private function onStandardOutputData(e:ProgressEvent):void
{
    this.nativeProcess.standardOutput.readBytes(this.processBuffer, this.processBuffer.length);
}

And finally, the code blow is an abbreviated version of the function that parses the data from standard out and puts it into the data grid:

private function onStandardOutputExit(e:Event):void
{
    var output:String = new String(this.processBuffer);
    var outputArray:Array = output.split("\n");
    var data:Array = new Array();
    for each(var path:String in outputArray)
    {
        var f:File = new File(path);
        if (!f.exists) continue;
        var o:Object = new Object();
        if (f.isDirectory)
        {
            o.name = "/" + f.name;
        }
        else
        {
            o.name = f.name;
        }
        o.type = f.extension;
        o.lastModified = f.modificationDate;
        o.path = f.nativePath;
        data.push(o);
    }
    var dp:ArrayCollection = new ArrayCollection(data);
    this.fileGrid.dataProvider = dp;
    this.setStatus(dp.length + " items found");
}

The code for SearchCentral will be available on on Adobe Labs as soon as the AIR 2 Beta is public (very soon!). The code for SearchCentral is now available on Google Code. If you have any questions, drop them in the comments below.

Posted by cantrell at 7:25 AM. Link | Comments (6) | References

November 11, 2009

A Demonstration of the New Storage Volume APIs in AIR 2

Below is a screencast of an application I wrote called FileTile in order to validate the new storage volume APIs in AIR 2:

Detecting the mounting and unmounting of a storage volume in AIR 2 is very easy. The code below shows using the new StorageVolumeInfo class to register for mount and unmount events:

StorageVolumeInfo.storageVolumeInfo.addEventListener(StorageVolumeChangeEvent.STORAGE_VOLUME_MOUNT, onVolumeMount);
StorageVolumeInfo.storageVolumeInfo.addEventListener(StorageVolumeChangeEvent.STORAGE_VOLUME_UNMOUNT, onVolumeUnmount);

Below are the two functions that react to the mounting and unmounting of storage volumes:

private function onVolumeMount(e:StorageVolumeChangeEvent):void
{
    if (e.storageVolume.isRemovable)
    {
        this.nativeWindow.activate();
        this.volumeName.text = e.storageVolume.name;
        this.targetVolume = e.storageVolume.rootDirectory;
        this.currentVolumeNativePath = this.targetVolume.nativePath;
        this.start();
    }
}

private function onVolumeUnmount(e:StorageVolumeChangeEvent):void
{
    if (this.currentVolumeNativePath == e.rootDirectory.nativePath)
    {
        this.reset();
        this.mainView.selectedChild = instructionBox;
    }
}

FileTile is a free, open-source application. The code can be downloaded from Google Code.

Posted by cantrell at 6:52 AM. Link | Comments (0) | References

November 4, 2009

A Demonstration of the ServerSocket API in AIR 2

In order to validate the new ServerSocket APIs in AIR 2, I wrote an application called HTTPeek. HTTPeek is a proxy server that sits between your browser and the network, and can show you HTTP request and response headers. It can handle compressed content, chunked content, binary content, etc. Check out the video below to see it in action:

Most of the HTTPeek code is dedicated to implementing just enough of the HTTP protocol to be an effective proxy, but the socket portion of the code is actually not all that complex. And the creation of the ServerSocket itself is very simple. The function below gets called when the user clicks on the "Listen" button:

private function onListen():void
{
    this.sockets = new Array();
    this.server = new ServerSocket();
    this.server.addEventListener(Event.CONNECT, onConnect);
    try
    {
        this.server.bind(Number(this.portNumber.text), String(this.interfaces.value));
        this.server.listen();
        this.listenButton.label = "Close";
    }
    catch (e:Error)
    {
        Alert.show(e.message, "Error", Alert.OK);
        return;
    }
    this.debugButton.enabled = true;
}

HTTPeek is open-source and hosted here on Google Code. Feel free to check out the source to see how it works.

Posted by cantrell at 8:20 AM. Link | Comments (9) | References

November 3, 2009

Some Interesting AIR Marketplace Statistics

A little over a year ago, I wrote a Python script to screen scrape the entire Adobe AIR Marketplace, download all the listed AIR applications, crack open the installers, and extract some statistics. My primary interest was how many HTML-based AIR applications were listed versus SWF-based applications, but I recorded some other interesting stats, as well.

I ran the script again the other day (after some updating since screen scraping scripts always break), and here's what I found:

Statistic Data Description
Total AIR apps on the Marketplace 724 Total number of AIR applications listed on the Adobe AIR Marketplace as of 10/29/2009.
Total testable apps 536 The total number of applications I was able to download and test. 121 applications don't have direct links to their AIR files on the marketplace, and the rest couldn't be tested because of 404s or network timeouts.
Total SWF-based AIR apps 443 (82.6%) Total number of applications that use a SWF as their main content. There is no distinction between Flash and Flex apps.
Total confirmed AS2 apps 2 Total number of SWF-based applications that use ActionScript 2 rather than ActionScript 3. (I'd be alarmed if this were much higher.)
Total HTML-based AIR apps 93 (17.4%) Total number of applications that use an HTML file as their main content.

Some things to keep in mind about this data:

I plan on updating the script to look for any HTML/JS files in the application bundle in order to give an indication of the number of hybrid applications out there. I'll post the results when I have them.

So my questions for you guys are:

Posted by cantrell at 7:54 AM. Link | Comments (5) | References