Last night I wanted to take a look at file/directory traversing in a mobile AIR application. I had assumed it would "just work" but I wanted to be sure of that myself and see it in action. I was also curious as to how the various 'helper aliases' work. By that I mean the aliases AIR provides for the user's desktop and documents directory. These are nice, cross platform ways to point to common folders across different operating systems. I wasn't quite sure how they would work on the Android so I figured it was a good time to find out. The application I built is quite short so I'll post the code and then explain how the parts work.
<?xml version="1.0" encoding="utf-8"?>
<s:View xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:s="library://ns.adobe.com/flex/spark" title="Browse File Demo" viewActivate="init()">
<fx:Declarations>
<!-- Place non-visual elements (e.g., services, value objects) here -->
</fx:Declarations>
<fx:Script>
<![CDATA[
import mx.collections.ArrayCollection;
[Bindable] private var fileList:ArrayCollection;
private var dir:File;
private var initialDir:String;
[Bindable] private var enableUpDir:Boolean;
private function init():void {
// dir = File.documentsDirectory;
// dir = File.desktopDirectory;
//get root, but always default to first one
var roots:Array = File.getRootDirectories();
dir = roots[0];
initialDir = dir.nativePath;
enableUpDir = false;
listFiles();
trace(dir.nativePath);
}
private function listFiles():void {
trace("Listing "+dir.nativePath);
currentDirLabel.text = "Browsing: "+dir.nativePath;
fileList = new ArrayCollection(dir.getDirectoryListing());
trace("compare "+dir.nativePath+" to "+initialDir);
if(dir.nativePath != initialDir) enableUpDir = true;
else enableUpDir = false;
}
private function changeDir(evt:Event):void {
var sel:File = fileListing.selectedItem;
if(sel.isDirectory) {
dir = sel;
listFiles();
fileListing.selectedIndex=-1;
}
}
private function goUpDir(evt:Event):void {
var parent:File = dir.parent;
dir = parent;
listFiles();
}
private function displayFile(selectedFile:File):String {
if(selectedFile.isDirectory) return selectedFile.name+"/";
else return selectedFile.name;
}
]]>
</fx:Script>
<s:actionContent>
<s:Button height="100%" label="Go Up" enabled="{enableUpDir}" click="goUpDir(event)" />
</s:actionContent>
<s:layout>
<s:VerticalLayout paddingTop="10" paddingLeft="5" paddingRight="5" />
</s:layout>
<s:Label id="currentDirLabel" width="100%" height="75" />
<s:List id="fileListing" dataProvider="{fileList}" width="100%" height="100%" click="changeDir(event)" labelFunction="displayFile">
</s:List>
</s:View>
Before getting into the code, let me share a screen shot so you have an idea of what this thing does when run:

In the screen shot you can see that the application has a directory name printed on top and the contents in a list below. A simple button "Go Up" allows you to return to the higher level directory. Selecting a folder will move you into the folder but selecting a file will currently do nothing. The code begins with the init method. You can see that I started off testing the documents and desktop directory aliases. On the Android, these pointed to /mnt/sdcard - in other words, my SD Card. This seems to make perfect sense and is probably the closest analogy to the desktop or documents directory you are going to get on the phone. For the "real" application though I switched to using the root file system. On Windows this could be multiple drives. To keep it simple I simply grab the first value. I know that Android is Unix based so this would give me / as a root path. I could run this both on my desktop and my phone and it would work the same in either place.
The listFiles function handles getting the directory from the file object and deciding if the "Go Up" button should be enabled. I didn't check to see if any parent existed, but rather if I was at my original starting directory. I imagined a scenario where I'd want to keep my user within a particular area and not allow them to leave that.
Everything else is rather simple as well so I'll skip explaining them unless someone has a specific question. I've attached a zip of the entire project (which includes the APK if you are bored enough to install it) to this blog entry. Nothing too exciting here I guess but hopefully this will be useful to somebody out there.
Archived Comments
Ray, what IDE are you using for your AIR development and how do you install the application on your Android phone?
Thanks!
I'm using Burrito. It makes it -incredibly - easy. See this post: http://www.coldfusionjedi.c...
Good stuff. I wonder if the 'FileSystemXXX' controls would work with the mobile AIR stuff?? Here's a blog post that goes over how they work: http://www.swamicharan.com/...
Doesn't look like I was able to put the mx tag in my code at all.
@Ray,
You should just need to add the namespace to your app
xmlns:mx="library://ns.adobe.com/flex/mx"
along with your other namespaces
to be able to use the mx tag
@Gareth: I tried that (first needed to add the mx.swc as well), but it seems only a handful of components are in Hero so far (see: http://www.adobe.com/devnet.... I have to say I'm _really_ surprised that Alert isn't included yet.
Yo - apparently it does work:
http://technoracle.blogspot...
badass.
His or mine? ;) I added Mp3 playing to mine - will be blogging it tomorrow.
errr...both? ;)
Hey your nice app for Android i have tested on Galaxy Note 10.1 It works fine. But any directory don't listen because Adobe Air has not permission ( su and SuperSu.apk )
I have create custom directories for Android OS.
Example:
PhoneAndroidDrive() is return Drive as "/".
Any custom Directory like AndroidDataAppDirectory() ( public static function get AdnroidDataApp():File { try { .. } catch (e:Error}{} return _dataApp;}
And i have tested an application on Android - It works ->
Output: Android: /data/app
And more any custom directories for Android Support can you code simple;:
public class FileForAndroid extends File
{
private static var _dataApp:File = File.desktopDirectory;
private static var _androidAppPath:String = File.desktopDirectory.nativePath;
private static var _androidDrive:String = _androidAppPath.substr(0,1);
public static function get AndroidDataAppDirectory():File
{
return _dataApp:File = _dataApp:File.resolverPath(_androidDrive + "data/app");
}
This is simple but i would like to use try catch when Android's directory exits than FileForAndroid.AndroidDataAppDirectory() will be working and checking into Androidf OS.
How do it work after custom directory founds correct directory by Android OS?
Is it not dangerous? It looks like simple custom directory for Android OS Support like who want to use on Tablets or Smartphones.
I would like they get glad about easy workstation for AS3 Coding.
They have problem like FileSystem and NativeProcess
For NativeProcess like they call su from /system/xbin/su or /system/bin/su than it will show evelator right / access right like Windows Administrator right.
Is it possible for nativeprocess with Boolean when isAccessed is true than it calls to su binary and su will execute with SuperSU.apk .
Thanks# you for improvement and suggestion with Android OS :)
Unfortunately I can't understand your English at all. And I haven't used Flex Mobile in about 2 years, so I really don't know. Sorry!
If anyone is looking for the download, you can find it here: http://static.raymondcamden...