Você está na página 1de 242

Developing AIR Applications with with Adobe Flash CS3

2007 Adobe Systems Incorporated. All rights reserved. Developing AIR Applications with Adobe Flash CS3 If this guide is distributed with software that includes an end user agreement, this guide, as well as the software described in it, is furnished under license and may be used or copied only in accordance with the terms of such license. Except as permitted by any such license, no part of this guide may be reproduced, stored in a retrieval system, or transmitted, in any form or by any means, electronic, mechanical, recording, or otherwise, without the prior written permission of Adobe Systems Incorporated. Please note that the content in this guide is protected under copyright law even if it is not distributed with software that includes an end user license agreement. The content of this guide is furnished for informational use only, is subject to change without notice, and should not be construed as a commitment by Adobe Systems Incorporated. Adobe Systems Incorporated assumes no responsibility or liability for any errors or inaccuracies that may appear in the informational content contained in this guide. Please remember that existing artwork or images that you may want to include in your project may be protected under copyright law. The unauthorized incorporation of such material into your new work could be a violation of the rights of the copyright owner. Please be sure to obtain any permission required from the copyright owner. Any references to company or person names in sample templates are for demonstration purposes only and are not intended to refer to any actual organization or person. Adobe, the Adobe logo, Dreamweaver, Flash, ColdFusion, and JRun are either registered trademarks or trademarks of Adobe Systems Incorporated in the United States and/or other countries. Microsoft and Windows are either registered trademarks or trademarks of Microsoft Corporation in the United States and/or other countries. Apple and Mac OS are trademarks of Apple Inc., registered in the United States and other countries. All other trademarks are the property of their respective owners. Adobe Systems Incorporated, 345 Park Avenue, San Jose, California 95110, USA. Notice to U.S. Government End Users. The Software and Documentation are Commercial Items, as that term is defined at 48 C.F.R. 2.101, consisting of Commercial Computer Software and Commercial Computer Software Documentation, as such terms are used in 48 C.F.R. 12.212 or 48 C.F.R. 227.7202, as applicable. Consistent with 48 C.F.R. 12.212 or 48 C.F.R. 227.7202-1 through 227.7202-4, as applicable, the Commercial Computer Software and Commercial Computer Software Documentation are being licensed to U.S. Government end users (a) only as Commercial Items and (b) with only those rights as are granted to all other end users pursuant to the terms and conditions herein. Unpublished-rights reserved under the copyright laws of the United States. Adobe Systems Incorporated, 345 Park Avenue, San Jose, CA 95110-2704, USA. For U.S. Government End Users, Adobe agrees to comply with all applicable equal opportunity laws including, if appropriate, the provisions of Executive Order 11246, as amended, Section 402 of the Vietnam Era Veterans Readjustment Assistance Act of 1974 (38 USC 4212), and Section 503 of the Rehabilitation Act of 1973, as amended, and the regulations at 41 CFR Parts 60-1 through 60-60, 60-250, and 60-741. The affirmative action clause and regulations contained in the preceding sentence shall be incorporated by reference.

Contents
Installation instructions
Installing Adobe AIR

Getting started
Introducing Adobe AIR Creating your first AIR application using Flash CS3

Using the AIR development tools


Using Flash CS3 for Adobe AIR applications Using the ActionScript AIR API Previewing an Adobe AIR application Creating Adobe AIR application and installer files Signing your application

Application development essentials


AIR Security Installation and Updates Sandboxes Writing to disk Working securely with untrusted content Best security practices for developers Code Signing Setting application properties

Working with windows and menus


Working with windows AIR window basics Creating windows Manipulating windows Listening for window events Using full-screen window mode Screens Screen basics

Enumerating the screens Working with native menus AIR menu basics Creating native menus

Working with files and data


Working with the file system AIR file basics Working with File objects Getting file system information Working with directories Working with files Using the encrypted local store Drag and Drop Drag and drop basics Supporting the drag-out gesture Supporting the drag-in gesture HTML Drag and drop Copy and Paste Copy-and-paste basics Reading from and writing to the system clipboard Clipboard data formats Working with local SQL databases About local SQL databases Common SQL database tasks Creating and modifying a database Using synchronous and asynchronous database operations Strategies for working with SQL databases

Adding content to AIR applications


Rendering PDF content in AIR applications

Interacting with the operating system


Interacting with the operating system Application invocation Capturing command line arguments Registering file types Reading the application descriptor file Getting the runtime version and patch level

Detecting AIR capabilities Tracking user presence Taskbar icons Application termination

Networking and communications


Monitoring network connectivity URL requests Using the URLRequest class Changes to the URLStream class Opening a URL in the default system web browser Scripting and communications between applications and content Using the LocalConnection class in AIR applications Scripting between content in different domains

Distributing and updating applications


Distributing AIR applications Digitally signing an AIR file Distributing and installing using the seamless install feature Distributing and installing an AIR file without using the seamless install feature Updating AIR applications programmatically New functionality in Adobe AIR New runtime classes Runtime classes with new functionality New Flex components Service monitoring framework classes

AIR Quick Starts


How to build the quick start sample applications with Flash CS3 Building a text-file editor Adding native menus to an AIR application Interacting with a window Creating a transparent window application Launching native windows Creating toast-style windows Controlling the display order of windows Dragging, copying, and pasting data Creating resizable, non-rectangular windows Measuring the virtual desktop Using the system tray and dock icons

Index

Part 1: Installation instructions


Installing Adobe AIR . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .6

Chapter 3: Installing Adobe AIR


Adobe AIR allows you to build rich Internet applications that run on the desktop. To begin, you must install the runtime on your computer. Once you've installed the runtime, download the sample applications to see AIR in action and to evaluate the underlying code.

Install the runtime


Use the following instructions to download and install the Windows and Mac OS X versions of AIR. You only need to install the runtime once for each computer that will run AIR applications.
Install the runtime on a Windows computer 1 Download the runtime installation file (AIR1_win_beta2.exe) from Adobe Labs

(http://labs.adobe.com/downloads/air.html).
2 3

Double-click the AIR1_win_beta2.exe file. In the installation window, follow the prompts to complete the installation.

4 If you have created or modified the mms.cfg file used by Flash Player, remove it while running AIR applications. On Windows, the file is located in the Macromedia Flash Player folder within the system directory (for example, C:\winnt\system32\macromed\flash\mms.cfg on a default Windows XP installation). Install the runtime on Mac OS 1 Download the runtime installation file (AIR1_mac_beta2.dmg) from Adobe Labs

(http://labs.adobe.com/downloads/air.html).
2 3 4

Double-click the AIR1_mac_beta2.dmg file. In the installation window, follow the prompts to complete the installation. If the Installer displays an Authenticate window, enter your Mac OS user name and password.

5 If you have created or modified the mms.cfg file used by Flash Player, remove it while running AIR applications. On Mac OS, the file is located at /Library/Application Support/Macromedia/mms.cfg.

Install and run the AIR sample applications


The Beta 2 release of AIR includes a number of sample applications.
1 2 3 4

Download the sample AIR file from Adobe Labs (http://labs.adobe.com/technologies/air/samples/). Double-click the AIR file. In the Installation window, select installation options, and then click Continue. After the installation is complete, open the application: On Windows, double-click the application's icon on the desktop or select it from the Windows Start menu.

ADOBE PRODUCT X.0 7


User Guide

On Mac OS, double-click the application's icon, which is installed in the Applications sub-directory of your user directory (for example, in Macintosh HD/Users/JoeUser/Applications/) by default.
The application opens in the runtime environment. Note: Check the AIR Beta 2 release notes for updates to these instructions, which are located here: http://labs.adobe.com/wiki/index.php/AIR:Release_Notes.

Run an AIR application


Once you have installed the runtime and the AIR application you want to run, running the application is as simple as running any other desktop application:

On a Windows computer, double-click the application's icon (which may be installed on the desktop or in a folder), or select the application from the Start menu. On Mac OS, double-click the application in the folder in which it was installed. The default installation directory is the Applications subdirectory of the user directory.

Part 1: Getting started


Introducing Adobe AIR . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .9 Creating your first AIR application using Flash CS3 . . . . . . . . . . . . . . . . . . . . . . . . . . . .4

Chapter 1: Introducing Adobe AIR


Adobe AIR is a cross-operating system runtime that allows you to leverage your existing web development skills (Flash, Flex, HTML, JavaScript, Ajax) to build and deploy Rich Internet Applications (RIAs) to the desktop. AIR enables you to work in familiar environments, to leverage the tools and approaches you find most comfortable, and by supporting Flash, Flex, HTML, JavaScript, and Ajax, to build the best possible experience that meets your needs. For example, applications can be developed using one or a combination of technologies below:

Flash / Flex / ActionScript HTML / JavaScript / CSS / Ajax PDF can be leveraged with any application

As a result, AIR applications can be:

Based on Flash or Flex: Application whose root content is Flash/Flex (SWF)

Based on Flash or Flex with HTML or PDF. Applications whose root content is Flash/Flex (SWF) with HTML (HTML, JS, CSS) or PDF content included
HTML-based. Application whose root content is HTML, JS, CSS

HTML-based with Flash/Flex or PDF. Applications whose root content is HTML with Flash/Flex (SWF) or PDF content included
Users interact with AIR applications in the same way that they interact with native desktop applications. The runtime is installed once on the user's computer, and then AIR applications are installed and run just like any other desktop application.

Since AIR is an application runtime, it has little or no visible user interface and you have complete control over the application and the experience it provides to users. The runtime provides a consistent cross-operating system platform and framework for deploying applications and therefore eliminates cross-browser testing by ensuring consistent functionality and interactions across desktops. Instead of developing for a specific operating system, you target the runtime. This has a number of benefits:

Applications developed for AIR run across multiple operating systems without any additional work by you. The runtime ensures consistent and predictable presentation and interactions across all the operating systems supported by AIR. Applications can be built faster by enabling you to leverage existing web technologies and design patterns. This allows you to extend your web based applications to the desktop without learning traditional desktop development technologies or the complexity of native code. This is easier than using lower level languages such as C and C++, and does away with the need to learn complex low-level APIs specific to each operating system.
When developing applications for AIR, you can leverage a rich set of frameworks and APIs:

APIs specific to AIR provided by the runtime and the AIR framework

ActionScript APIs used in SWF files and Flex framework (as well as other ActionScript based libraries and frameworks)

ADOBE PRODUCT X.0 10


User Guide

AIR delivers a new paradigm that dramatically changes how applications can be created, deployed, and experienced. You gain more creative control and can extend your Flash, Flex, HTML, and Ajax-based applications to the desktop, without learning traditional desktop development technologies.

11

Chapter 2: Creating your first AIR application using Flash CS3


This topic gives you a quick, hands-on tutorial on how to create an Adobe AIR application using Flash CS3. It teaches you how to create and package a simple Hello Adobe AIR application using Adobe Flash CS3 Professional and the Adobe AIR update. To create and run the Hello Adobe AIR application, you must first install the Adobe AIR runtime and the Adobe AIR update for Flash CS3. For more information on installing Adobe AIR for Flash CS3, see Setting up Flash CS3 for Adobe AIR.

Creating the Hello Adobe AIR application in Flash


Creating an Adobe AIR application in Flash is very much like creating any other Flash application. The differences are that you begin by creating a new Adobe AIR Flash file from the Welcome screen and conclude by creating application and installer settings and installing your AIR application. The following procedure guides you through the process of creating a simple Hello Adobe AIR application using Flash CS3.
To create the Hello Adobe AIR application 1 Launch Flash. 2 In the Welcome Screen, click on Flash File (Adobe AIR) to create an empty FLA file with Adobe AIR publish settings. 3 Click OK to respond to the summary dialog, Authoring for Adobe AIR with Flash CS3. This dialog takes a few seconds to come up the first time. 4 Select the Text tool in the Tools panel and create a static text field (the default) in the center of the Stage. Make it wide enough to contain 15 to 20 characters. 5 6

Enter the text Hello Adobe AIR in the text field. Save the file, giving it a name (e.g. helloAIR).

Testing the application


To test the Hello Adobe AIR application 1 Press Ctrl + Enter or select Control ->Test Movie to test the application with the AIR runtime. 2 To use the Debug Movie feature, you must add ActionScript code to the application. You can try it quickly by adding a trace statement like the following:
trace("Running AIR application using Debug Movie");

Press Ctrl + Shift + Enter, or select Control->Debug Movie to run the application with Debug Movie.

ADOBE PRODUCT X.0 12


User Guide

4 Select the Commands > AIR - Applications and Installer Settings menu item to open the AIR - Application & Installer Settings dialog .

5 Click the Select Icon Images button and open the Icon Images dialog. You will see the Adobe custom icons here and you should notice the custom icon settings. You will also see the icons for your application here when you install your applications AIR file. The icons are not needed for this application so you can close this dialog when you're finished. 6

Sign the Adobe AIR package with a self-signed digital certificate:


a b

Click the Set button for the Digital Signature prompt to open the Digital Signature dialog box. Click the Create... button to open the Self-signed digital certificate dialog box

c Complete the entries for Publisher name Organizational unit, Organizational name, E-mail, Country, Password, and Confirm Password.

ADOBE PRODUCT X.0 13


User Guide

Specify the type of certificate.

The certificate Type option refers to the certificates level of security: 1024-RSA uses a 1024-bit key (less secure), and 2048-RSA uses a 2048-bit key (more secure). When youre finished click OK. e Save the information in a certificate file by completing the Save as entry or clicking the Browse... button to browse to a folder location. (For example, C:/Temp/mycert.pfx).
f

Enter the same password that you assigned in step c in the Digital Signature dialog box and click OK.

For more information about signing your Adobe AIR applications, see Signing your application on page 27. 7 To create the application and installer file, click the Publish button in the Application and Installer Settings dialog. Note that you must execute Test Movie or Debug Movie to create the SWF and application.xml files before creating the AIR file.
8 9

To install the application, double click the AIR file in the same folder where you saved your application. Click the Install button in the Application Install dialog.

10 Review the Installation Preferences and Location settings and make sure that the Start application after instal-

lation checkbox is checked. Then click Continue.


11 Click Finish when the Installation Completed message appears.

The Hello Adobe AIR application should look like this:

ADOBE PRODUCT X.0 14


User Guide

Converting a Flash application to an Adobe AIR application


You can also convert an existing Flash application to an AIR application. For more information, see Setting Adobe AIR publish settings on page 17.

15

Part 1: Using the AIR development tools


Creating an AIR application using the command line tools . . . . . . . . . . . . . . . . . . . . .28 Using Flash CS3 for Adobe AIR applications . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .16

16

Chapter 1: Using Flash CS3 for Adobe AIR applications


The Adobe AIR update for Flash CS3 lets you transform a Flash file into a desktop application. For example, you might have a set of Flash files that interact with each other to display XML data. You can use the AIR update for Flash to package this set of pages into a small application that can be installed on a users computer. When the user runs the application from the desktop, the application loads and displays the website in its own application window, independent of a browser. The user can then browse the files locally on their computer without an Internet connection. The process of creating and deploying an Adobe AIR application consists of creating an Adobe AIR FLA file, setting the appropriate publish settings for Adobe AIR, developing the application, and creating the Adobe AIR application and installer files to deploy and execute the application. This section covers the following topics: Creating a new Adobe AIR file on page 16 Setting Adobe AIR publish settings on page 17 Using the ActionScript AIR API on page 19 Previewing an Adobe AIR application on page 20 Debugging an Adobe AIR application on page 20 Using the Commands menu on page 21 Creating Adobe AIR application and installer files on page 21 Signing your application on page 27 Creating a custom application descriptor file on page 14

Creating a new Adobe AIR file


You can create new Adobe AIR Flash files using the Flash Welcome screen or you can create a new Flash File and convert it to an Adobe AIR Flash file. For information on converting a Flash File to an Adobe AIR file, see Setting Adobe AIR publish settings on page 17. You cannot create an Adobe AIR file, however, by using the New Document dialog box. Note: If youve disabled the Flash Welcome screen so that it doesnt show by default, you can cause it to show again by selecting Edit > Preferences, selecting the General category, and selecting Welcome Screen from the On Launch pop-up menu.
To create a new Adobe AIR file 1 Start Flash or, if you have already started Flash, close any open documents to return to the Welcome screen. 2

On the Welcome Screen, click the Flash File (Adobe AIR) option.

ADOBE PRODUCT X.0 17


User Guide

The following Alert dialog displays to tell you how to access the Adobe AIR application settings and how to access the Help documentation.

You can bypass this alert box in the future by clicking the Dont show me again checkbox but there is no provision for causing it to display again. The following section explains how to convert a Flash file to an Adobe AIR file.

Setting Adobe AIR publish settings


You can access the publish settings for an Adobe AIR file by selecting the File > Publish Settings menu item.
To set Adobe AIR publish settings 1 From the Flash Welcome screen, open a Flash File (Adobe AIR) document. 2

Select File > Publish Settings and click the Flash tab to see the Adobe AIR publish settings.

ADOBE PRODUCT X.0 18


User Guide

Publish Settings dialog box with Adobe AIR settings

Adobe AIR 1.0 is automatically selected in the Version menu when you open an Adobe AIR document, and the ActionScript setting is automatically set to ActionScript 3.0. The Local playback security setting is grayed out because it is irrelevant for an Adobe AIR SWF file. If you opened an existing Flash file or created a new one, you can use the Publish Settings dialog box to convert it to an Adobe AIR Flash file.

ADOBE PRODUCT X.0 19


User Guide

To convert a Flash file to an Adobe AIR Flash file: 1 Open an existing Flash file or create a new one using the Welcome screen or the New Document dialog box (File

> New).
2 3

Select Publish Settings from the File menu (File > Publish Settings). On the Flash tab, select Adobe AIR 1.0 from the Version drop down menu. The ActionScript version entry will be disabled because ActionScript 3.0 is the only option for an AIR file.

The remaining default options are the same for both a Flash file and an Adobe AIR file.

5 Click the Publish button and then the OK button to close the Publish Settings dialog box. The Properties inspector dialog box should now indicate that the Player target is Adobe AIR 1.0.

Note: When you choose the Adobe AIR 1.0 profile, Flash automatically adds the location of the AIR playerglobal.swc file to the Classpath environment variable to enable you to use the ActionScript AIR APIs. However, if you switch from Adobe AIR 1.0 to Flash Player 9, Flash does not automatically revert to the default profile or change the Classpath setting to use the playerglobal.swc for Flash Player 9. If you change the publish setting from Adobe AIR 1.0 to Flash Player 9, you must manually change the publish profile to Default. For additional information on the Publish Settings dialog, see Using Flash in Flash Help. You can also convert a Flash file to an Adobe AIR Flash file using the Commands menu.
To convert an existing Flash application to an Adobe AIR application using the Commands menu 1 Open the FLA file for your Flash application. 2 Select the Commands > AIR - Application and Package Settings menu item.

The following alert box should appear, asking if you want to convert the file to Adobe AIR publish settings:

3 Click OK to convert the FLA file to Adobe AIR publish settings. 4 You can test movie, debug movie, and package AIR files.

Using the ActionScript AIR API


For information on the Adobe AIR ActionScript APIs that you can use in your application, see the Adobe AIR ActionScript 3.0 Language Reference. For a list of Adobe AIR ActionScript APIs, see Appendix: New functionality in Adobe AIR on page 1.

ADOBE PRODUCT X.0 20


User Guide

Previewing an Adobe AIR application


You can preview a Flash page as it would appear in an AIR application. Previewing is useful when you want to see what the page will look like in the application without having to repackage the entire application.
1 2

Make sure youve set the publish settings for an Adobe AIR application. Select Control > Test Movie or press Control + Enter.

If you have not set application settings through the AIR - Application and Installer Settings dialog, Flash generates a default application descriptor (swfname-app.xml) file for you in the same folder where the SWF file is written. If you have set application settings using the AIR - Application and Installer Settings dialog, the application descriptor file will reflect those settings.

Debugging an Adobe AIR application


The Adobe AIR SWF file can be debugged just like a Flash Player 9 ActionScript 3.0 SWF file, with the exception of remote debugging.
To enable debugging for an Adobe AIR file 1 Make sure youve set Adobe AIR publishing settings. 2 Add ActionScript code to the Actions panel (Window > Actions). For testing, you could simply add a trace() statement like the following one to the Actions panel, on the first frame of the Timeline:
trace("My application is running");

Select Debug > Debug Movie or Press Control + Shift + Enter.

Flash launches the ActionScript debugger and exports the SWF file with debug information. If you have not set application settings through the AIR - Application and Installer Settings dialog, Flash generates a default application descriptor (swfname-app.xml) file for you in the same folder where the SWF file is written. If you have set application settings using the AIR - Application and Installer Settings dialog, the application descriptor file will reflect those settings. If your application does not include any ActionScript code, Flash displays the following alert box when you select Debug > Debug Movie or Press Control + Shift + Enter to debug your application.

ADOBE PRODUCT X.0 21


User Guide

Using the Commands menu


Adobe AIR adds two new menu items to the Flash Commands menu: AIR Application and Installer settings and AIR - Create AIR file. The following illustration shows these menu items.

Commands menu with Adobe AIR commands

Use the AIR - Application and Installer Settings item to open the Application and Installer Settings dialog box. For more information, see Creating Adobe AIR application and installer files on page 21. Use the AIR - Create AIR File item to export a SWF file and create an AIR file when you have already set the package settings for the application.

Creating Adobe AIR application and installer files


After youve completed your application you must create the Adobe AIR and installer files to deploy it. Use the Application and Installer Settings dialog box to create the Adobe AIR application and installer files. You must save the Adobe AIR FLA file before you open the Application and Installer Settings dialog box.
To create the Adobe AIR and installer files 1 In Flash, open the page or set of pages that make up your Adobe AIR application. 2 3

Select Commands > AIR - Application and Installer Settings. Complete the Application and Installer Settings dialog box, and then click the Publish button.

The Application and Installer Settings dialog box looks like this:

ADOBE PRODUCT X.0 22


User Guide

Application and Installer dialog box

This dialog box is divided into three sections: Application settings, Application descriptor file settings, and Installer settings. For more information on these dialog box settings see the following sections.

ADOBE PRODUCT X.0 23


User Guide

Application settings
The Application settings section of the Application and Installer Settings dialog box has the following options:
Application Filename is the name of the main file of the application. Defaults to the name of the SWF file. Application Name is the name used by the installer to generate the application file name and the application folder. The name must contain only valid characters for files or folder names. Defaults to the name of the FLA file. Application ID identifies your application with a unique ID. You can change the default ID if you prefer. Do not use

spaces or special characters in the ID. The only valid characters are 0-9, a-z, A-Z, . (dot), and - (dash). Defaults to com.adobe.example.application_name
Version specifies a version number for your application. Defaults to blank. Optional. Description lets you enter a description of the application to display when the user installs the application. Defaults

to blank. Optional.
Copyright lets you enter a copyright notice to display when the user installs the application. Optional. Window Style refers to the visual style to be used for the applications user interface. You can specify System Chrome,

which refers to the visual style that is used by the operating system. You can also specify Custom Chrome (opaque) or Custom Chrome (transparent). To display your application without the system chrome, select None.
Icon Optional. Lets you specify an icon for the application. The icon is shown after you install the application and

run it in Adobe AIR runtime. You can specify four different sizes for the icon (128, 48, 32, and 16 pixels) to allow for the different views in which the icon will appear in the file browser in thumbnail, detail, and tile views, etc., as a desktop icon, and in the title of the AIR application window, as well as other instances. The following illustration shows the Icon images dialog box with the default Adobe AIR application icons.

ADOBE PRODUCT X.0 24


User Guide

If you specify an image, it must be of the size (128, 48, 32, or 16) that you specify or the application installation will fail. If you do not specify a file for each of the image sizes, the image of the closest size will be scaled to fit for the given use. To specify an icon, click the Select Icon Images button. In the Application Custom Icons dialog box that appears, click the folder for each icon size and select the icon file to use. The files must be in PNG format Defaults to the AIR application icon if no icon files are specified.

Application descriptor file settings


The application settings that you specify are saved to the application_name.xml file. You have the option, however, of indicating to Flash that you want to use a custom application descriptor file by checking the Use custom application descriptor file checkbox.
Use custom application descriptor file lets you browse to a custom application descriptor file.

If you check the Use custom application descriptor file checkbox, the Application settings section of the dialog box is grayed out as the following illustration shows.

ADOBE PRODUCT X.0 25


User Guide

Use the text input field below the checkbox or click the folder icon to specify the location of the custom application descriptor file. For more information on the application descriptor file, see Creating a custom application descriptor file on page 14.

ADOBE PRODUCT X.0 26


User Guide

Installer settings
The third section of the Application and Installer Settings dialog box contains settings that pertain to installing the application.
Digital signature All Adobe AIR applications must be signed to be installed on another system. For information about assigning a digital signature to a Flash Adobe AIR application, see Signing your application on page 27. Program menu folder The location where the application is placed in the Start menu > Programs tree on Windows after the AIR application is installed. Destination specifies where to save the AIR file. The default location is the directory where you saved the FLA file.

Click the folder icon to select a different location. The default package name is the application name with the .air file extension.
Included Files/Folders specifies which files and folders to include in your application. Click the Plus (+) button to

add files, and the folder button to add folders. To delete a file or folder from your list, select the file or folder and click the Minus (-) button. By default, the application descriptor file and the main SWF file are automatically added to the package list. The package list shows these files even if you have not yet published the Adobe AIR FLA file. The package list displays the files and folders in a flat structure. Files in a folder are not listed and full path names to files are shown but are truncated if necessary. Icon files are not included in the list. When the files are packaged, Flash copies icon files to a folder that is relative to the location of the SWF file and deletes the folder after packaging is complete.
Help button Opens online Help in the default browser. The in-product Help file simply contains links to the online help. This ensures that when you search for AIR keywords in the Help panel, you can find the corresponding online Help pages. Create AIR File button Packages the FLA file, the SWF file, the application descriptor file, the application icon files

and the files listed in the Included files text box. This button is grayed out if a digital signature has not been set.
Ok button Closes the Application and Installer dialog box and saves the application settings. Cancel button Closes the Application and Installer dialog without saving the application settings.

Failure of application and installer file creation


Creation of the application and installer files will fail in the following instances:

The application ID string has an incorrect length or contains invalid characters. The application ID string can be between 17 and 237 characters and can include the following characters: 0-9, a-z, A-Z, . (dot), - (hyphen).
Files in the installer list do not exist The sizes of custom icon files are incorrect The AIR destination folder does not have write access You have not signed the application or have not specified that it is an Adobe AIRI application to be signed later

Creating a custom application descriptor file


The application descriptor file is an XML file that you can edit with one of many text editors. To create a custom application descriptor file, edit the values to specify the values you want. The default values are shown here:

appid = com.AIR.flash.swfname

ADOBE PRODUCT X.0 27


User Guide

application File name = swfname application name = swfname version = 1.0 description = blank copyright = blank systemChrome = standard, type = normal transparent = false visible = true

See also

Setting application properties on page 41

Signing your application


All Adobe AIR applications must be signed to be installed on another system. Flash provides the ability, however, to create Adobe AIR installer files without signing (called an AIRI package) so that the application can be signed later. This provides for cases in which the certificate is on a different machine or signing is handled separately from application development. Clicking the Digital signature Set button on the Application and Installer settings dialog box opens the Digital Signature dialog box. This dialog box has two radio buttons that allow you to either sign your Adobe AIR application with a digital certificate or prepare an AIRI package. If you sign your Adobe AIR application, you can either use a digital certificate granted by a root certificate authority or create a self-signed certificate. A self-signed certificate is easy to create but is not as trustworthy as a certificate granted by a root certificate authority.

ADOBE PRODUCT X.0 28


User Guide

To sign an Adobe AIR application with a pre-purchased digital certificate from a root certificate authority

Select a certificate file from the drop down menu or click the Browse button to locate a certificate file.
1 2 3 4

Click the Browse button. Select the certificate. Enter a password. Click OK

For more information on signing your AIR application, see Digitally signing an AIR file on page 166. To create a self-signed digital certificate, click the Create button to open the Self-signed digital certificate dialog box.

To sign the Adobe AIR package with a self-signed digital certificate 1 Complete the entries for Publisher name, Organizational unit, Organizational name, Email, Country, Password,

and Confirm Password.


2

Specify the type of certificate. The certificate Type option refers to the certificates level of security: 1024-RSA uses a 1024-bit key (less secure), and 2048-RSA uses a 2048-bit key (more secure). When youre finished click OK.

3 Save the information in a certificate file by completing the Save as entry or clicking the Browse button to browse to a folder location. 4

Enter the password you assigned in the first step in the Digital Signature dialog box and click OK.

You can also create an AIR Intermediate (AIRI) application without a digital signature. A user will not be able to install the application on a desktop, however, until you add a digital signature.

ADOBE PRODUCT X.0 29


User Guide

To prepare an AIRI package that will be signed later

Select Prepare an AIRI package that will be signed later and click OK. After you have set a digital certificate, the Set button changes to a Change button. If you choose to prepare an AIRI package that is to be signed later, the digital signature status changes to reflect that and the Set button changes to a Change button.

30

Part 1: Application development essentials


AIR Security. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .31 Setting application properties . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .41

31

Chapter 3: AIR Security


Although the AIR security model is an evolution of the Flash Player security model, the security contract is quite different from the security contract applied to content in a browser. This contract offers developers a secure means of broader functionality for rich experiences with freedoms that would be inappropriate for a browser-based applications. AIR applications run with the same user privileges as native applications. In general, these privileges allow for broad access to operating system capabilities such as reading and writing files, starting applications, drawing to the screen, communicating with the network, etc. Operating system restrictions that apply to native applications, such as userspecific privileges, equally apply to AIR applications. AIR applications are written using either compiled bytecode (Flash/Flex content) or interpreted script (JavaScript, HTML) so that memory management is provided by the runtime. This minimizes the chances of AIR applications being affected by vulnerabilities related to memory management, such as buffer overflows and memory corruption. These are some of the most common vulnerabilities affecting desktop applications written in native code. This section contains the following topics:

Installation and Updates on page 31 Sandboxes on page 34 Writing to disk on page 36 Working securely with untrusted content on page 37 Best security practices for developers on page 38 Code Signing on page 39

Installation and Updates


AIR applications are distributed via AIR installer files which use the air extension. When the AIR runtime is installed and an AIR installer file is opened, the runtime administers the installation process. Note: Developers can specify a version, and application name, and a publisher source, but the initial application installation workflow itself cannot be modified. This restriction is advantageous for users because all AIR applications share a secure, streamlined, and consistent installation procedure administered by the AIR runtime. If application customization is necessary, it can be provided when the application is first executed. AIR applications first require the AIR runtime to be installed on a user's computer, similar to how SWF files first require the Flash Player browser plug-in to be installed. The runtime is installed to the following location on a user's computer:

Mac OS X: /Library/Frameworks/ Windows: C:\Program Files\Common Files\Adobe AI

The runtime can be installed in two ways: in an express install or a manual install.

ADOBE PRODUCT X.0 32


User Guide

Express install (runtime and application)


The express install provides developers which a streamlined install experience for users who do not have Adobe AIR installed yet. In the express install method, the developer creates a SWF file that presents the application for installation. When a user clicks in the SWF file to install the application, the SWF file attempts to detect the runtime. If the runtime cannot be detected it will be installed, and the runtime is activated immediately with the installation process for the developer's application.

Manual install
Alternatively, the user can manually download and install the runtime before opening an AIR file. The developer can then distribute an AIR file by a number of means (e-mail, an HTML link on a website, etc.) When the AIR file is opened, the runtime is activated and begins to process the application install. For more information on this process, see Distributing AIR applications on page 166.

Application Installation Flow


The AIR security model allows users to decide whether to install an AIR application. The AIR install experience provides several improvements over native application install technologies that make this trust decision easier for users:

The AIR runtime provides a consistent install experience on all web browsers on all operating systems. Most native application install experiences depend upon the browser or other application to provide security information, if it is provided at all. The AIR application install experience identifies the source of the application and information about what privileges will be available to the application if the user allows the installation to proceed. The install process of an AIR application is administered by the AIR runtime, which cannot be manipulated by the application being installed.
In general, users should not install any desktop application that comes from a source that they do not trust, or that cannot be verified. The burden of proof on security for native applications is equally true for AIR applications as it is for other installable applications.

Application Destination
The installation directory of an AIR applications is determined by the first of three possible options:
1

The user customizes the destination during installation. The application installs to wherever the user specifies.

2 If the user does not change the install destination, the application installs to the default path as determined by the runtime:

Mac OS X: ~/Applications/ Windows XP and earlier: C:\Program Files\ Windows Vista: ~/Apps/

If the developer specifies an installFolder setting in the application descriptor file, the application is installed to a subpath of this directory.

ADOBE PRODUCT X.0 33


User Guide

The AIR file system


The install process for AIR applications copies all files that the developer has included within the AIR installer file onto the user's local machine. The installed application is composed of:

Windows: A directory containing all files included in the AIR installer file. The AIR runtime also creates an exe file as during the installation of the AIR application. OS X: An app file. This file's contents include all of the contents of the AIR installer file. It can be inspected using the "Show Package Contents" option in Finder. The AIR runtime creates this app file as part of the installation of the AIR application.
An AIR application is run by:

Windows: Running the install folders .exe file, or a shortcut that corresponds to this file (i.e. Start Menu, Desktop)
OS X: Running the .app file or an alias that points to it. The application file system also includes subdirectories related to the function of the application. For example, information written to encrypted local storage is saved to a subdirectory in a directory named after the application identifier (appId) of the application.

AIR application storage


AIR applications have privileges to write to any location on the user's hard drive; however, developers are encouraged to use the app-storage:/ path for local storage related to their application. Files written to app-storage:/ from an application will be located in a standard location depending on the user's operating system:

On Mac OS X: the storage directory of an application is <appData>/<appId>/Local is the user's "preferences folder," typically /Users/<user>/Library/Preferences

Store/ where <appData>

On Windows: the storage directory of an application is <appData>\<appId>\Local Store\ where

<appData> is the user's CSIDL_APPDATA "Special Folder," typically C:\Documents and Settings\<userName>\Application Data

You can access the application storage directory via the air.File.applicationStorageDirectory property. You can access its contents using the resolvePath() method of the File class. For details, see Working with the file system on page 79.

Updating Adobe AIR


Adobe AIR does not automatically update for the beta release. The newest version of the runtime can be found at http://labs.adobe.com/downloads/air.html.

Updating AIR applications


Development and deployment of software updates are one of the biggest security challenges facing native code applications. The AIR API provides a mechanism to improve this: the Updater.update() method can be invoked upon launch to check a remote location for an AIR file. If an update is appropriate, the AIR file is downloaded, installed, and the application restarts. Developers can use this class not only to provide new functionality but also respond to potential security vulnerabilities.

ADOBE PRODUCT X.0 34


User Guide

Note: Developers can specify the version of an application by setting the version property of the application descriptor file. AIR does not interpret the version string in any way. Thus version 3.0 is not assumed to be more current than version 2.0. It is up to the developer to maintain meaningful versioning. For details, see Defining properties in the application descriptor file on page 42.

Uninstalling an AIR application


AIR applications can be uninstalled by:

On Windows: Using the Add/Remove Programs panel to remove the application. On Mac OS X: Deleting the app file from the install location.

Removing an AIR application removes all files in the application directory, but does not remove files that the application may have written to the local disk outside of the application directory, including files written to local storage. Removing AIR applications does not revert changes the AIR application has made to files outside of the application directory.

Uninstalling Adobe AIR


AIR can be uninstalled:

On Windows: by running Add/Remove Programs from the Control Panel, selecting Adobe AIR and selecting "Remove"
On Mac OS X: by running the Adobe AIR Uninstaller application in the Applications directory.

Sandboxes
AIR provides a comprehensive security architecture that defines permissions accordingly to each file in an AIR application, both internal and external. Permissions are granted to files according to their origin, and are assigned into logical security groupings called sandboxes. The AIR runtime security model of sandboxes is composed of the Flash Player security model with the addition of the application sandbox. Files that are not in the application sandbox have security restrictions similar to those specified by the Flash Player security model. A chart of each sandbox and their characteristics is below:
application remote

local-trusted

local-with-networking

The file resides in the application directory and operates with the full set of AIR privileges The file is from an Internet URL, and operates under domainbased sandbox rules analogous to those of remote files in the Flash Player. The file is a local file and has been trusted by the user, using either the Settings Manager or a Flash Player trust configuration file. The file can both read from local data sources and communicate with the Internet, but does not have the full set of AIR privileges. The file is a local SWF file published with a networking designation, but has not been explicitly trusted by the user. The file can communicate with the Internet but cannot read from local data sources.

ADOBE PRODUCT X.0 35


User Guide

local-with-filesystem

The file is a local scripting file that was not published with a networking designation and has not been explicitly trusted by the user. This includes JavaScript files that have not been trusted. The file can read from local data sources but cannot communicate with the Internet.

The runtime uses these security sandboxes to define the range of data that a file may access and the operations it may execute. To maintain local security, the files in each sandbox are isolated from the files of other sandboxes. For example, a SWF file loaded into an AIR application from an external Internet website is placed into the remote sandbox, and does not by default have permission to script into files that reside in the application directory, which are assigned to the application sandbox. This topic focuses primarily on the application sandbox and its relationship to other sandboxes in the AIR application. Developers that use content that will be assigned to other sandboxes should read further documentation on the Flash Player security model. See the Flash Player Security chapter in the Programming ActionScript 3.0 documentation and the Adobe Flash Player 9 Security white paper.

The application sandbox


When an application is installed, all files included within an AIR installer file are installed onto the user's computer into an application directory. Developers can reference this directory in code through the app-resource:/ URL scheme (see Using AIR URL schemes in URLRequest object URLs on page 160). All files within the application directory tree are assigned to the application sandbox when the application is run and are blessed with the full privileges available to an AIR application, including interaction with the local file system. Many AIR applications use only these locally installed files to run the application, but AIR applications are not restricted to just the files within the application directory they can load any type of file from any source. This includes files local to the user's computer as well as files from available external sources, such as those on a local network or on the Internet. File type has no impact on security restrictions; loaded HTML files have the same security privileges as loaded SWF files from the same source. Content in the application security sandbox has access to AIR APIs that are content in other sandboxes are prevented from using. For example, the Shell.shell.applicationDescriptor property, which returns the contents of the application descriptor file for the application, is restricted to content in the application security sandbox. Another example of a restricted API is the FileStream class, which contains methods for reading and writing to the local file system. APIs that are restricted to content in the application security sandbox are indicated with the AIR logo in the Flex 3 Language Reference.

Privileges of content in non-application sandboxes


Files loaded from a network or Internet location are assigned to the remote sandbox. Files loaded from outside the application directory are assigned to either the local-with-filesystem, local-with-networking, or the local-trusted sandbox, depending on how the file was created and if the user has explicitly trusted the file through the Flash Player Global Settings Manager. Unlike content in the application security sandbox, content in a non-application security sandbox can call the eval() function to execute dynamically generated code at any time. Code in a non-application sandbox does not have access to the window.runtime object, and as such this code cannot execute AIR APIs. If content in a non-application security sandbox calls the following code, the application throws a TypeError exception:
try { window.runtime.flash.system.Shell.shell.exit();

ADOBE PRODUCT X.0 36


User Guide

} catch (e) { alert(e); }

The exception type is TypeError (undefined value), because content in the non-application sandbox does not recognize the window.runtime object, so it is seen as an undefined value.

Writing to disk
Applications running in a web browser have only limited interaction with the user's local file system. This is because web browsers implement security policies that ensure that a user's computer cannot be compromised by web content. For example, SWF files running through Flash Player in a browser cannot directly interact with files already on a user's computer. Shared objects can be written to a user's computer for the purpose of maintaining user preferences and other data, but this is the limit of file system interaction. Because AIR applications are natively installed, they have a different security contract, one which includes the capability to read and write across the local file system. This freedom comes with high responsibility for developers. Accidental application insecurities jeopardize not only the functionality of the application, but the integrity of the user's machine. For this reason, developers are strongly advised to read this section as well as the Best security practices for developers on page 38 section.

Network files and the remote sandbox


AIR developers can access and write files to the local file system using several path conventions:
app-resource:/

An alias to the application directory. Files accessed from this path will be assigned the application sandbox and have the full privileges granted by the runtime.
app-storage:/

An alias to the local storage directory, standardized by the runtime. Files accessed from this path will be assigned a non-application sandbox.
file:///

An alias that represents the root of the user's hard disk. Files accessed from this path are assigned an application sandbox if it exists in the application directory, and a non-application sandbox otherwise. Note: AIR applications cannot modify content in the app-resource:/ directory, due to security concerns and because administrator settings may not allow it. Unless there are administrator restrictions to the user's computer, AIR applications are privileged to write to any location on the user's hard drive. Developers are advised to use the app-storage:/ path for local storage related to their application. Files written to app-storage:/ from an application will be located in a standard location depending on the user's operating system:

On Mac OS X: the storage directory of an application is <appData>/<appId>/Local Store/ where <appData> is the user's preferences folder. This is typically /Users/<user>/Library/Preferences

ADOBE PRODUCT X.0 37


User Guide

On Windows: the storage directory of an application is <appData>\<appId>\Local Store\ where <appData> is the user's CSIDL_APPDATA Special Folder. This is typically C:\Documents and
Settings\<userName>\Application Data

If an application is designed to interact with existing files in the user's file system, the developer is advised to read the Best security practices for developers on page 38 section.

Working securely with untrusted content


Content not assigned to the application sandbox can provide additional scripting functionality to your application, but only if it meets the security criteria of the runtime. This section explains the AIR security contract with nonapplication content.

Security.allowDomain()
AIR applications restrict scripting access for non-application content more stringently than the Flash Player 9 browser plug-in restricts scripting access for untrusted content. For example, in Flash Player in the browser, when a SWF file that is assigned to the local-trusted sandbox calls the System.allowDomain() method, scripting access is granted to any SWF loaded from the specified domain, reassigning this remote file from the remote sandbox to the local-trusted sandbox. The analogous approach is not permitted from application content in AIR applications, since it would grant unreasonable access unto the non-application file into the user's file system. Remote files cannot directly access the application sandbox, regardless of calls to the Security.allowDomain() method.

Scripting between application and non-application content


AIR applications that script between application and non-application content have more complex security arrangements. Files that are not in the application sandbox are only allowed to access the properties and methods of files in the application sandbox through the use of a sandbox bridge. A sandbox bridge acts as a gateway between application content and non-application content, providing explicit interaction between the two files. When used correctly, sandbox bridges provide an extra layer of security, restricting non-application content from accessing object references that are part of application content. The benefit of sandbox bridges is best illustrated through example. Suppose an AIR music store application wants to provide an API to advertisers who want to create their own SWF files to be added to the store application. The store wants to provide advertisers with methods to look up artists and CD's from the store, but also wants to isolate some methods and properties from the third-party SWF for security reasons. A sandbox bridge can provide this functionality. By default, content loaded externally into an AIR application at runtime does not have access to any methods or properties in the main application. With a custom sandbox bridge implementation, a developer can provide services to the remote content without exposing these methods or properties. Consider the sandbox bridge as a pathway between trusted and untrusted content, providing communication between loader and loadee content without exposing object references. For more information on how to securely use sandbox bridges, see Scripting between content in different domains on page 162

ADOBE PRODUCT X.0 38


User Guide

Best security practices for developers


Although AIR applications are built using web technologies, it is important for developers to note that they are not working within the browser security sandbox. This means that it is possible to build AIR applications that can do harm to the local system, either intentionally or unintentionally. AIR attempts to minimize this risk, but there are still ways where vulnerabilities can be introduced. This section covers important potential insecurities.

Risk from importing files into the application security sandbox


Files that exist in the application directory are assigned to the application sandbox and have the full privileges of the runtime. Applications that write to the local file system are advised to write to app-storage:/. This directory exists separately from the application files on the user's computer, hence the files are not assigned to the application sandbox and present a reduced security risk. Developers are advised to consider the following:

Include a file in an AIR file (in the installed application) only if absolutely necessary.

Include a scripting file in an AIR file (in the installed application) only its behavior is fully understood and trusted. Do not write to or modify content in the application resource directory. The AIR runtime prevents applications from writing or modifying files and directories using the app-resource:/ URL scheme by throwing a SecurityError exception. Do not use data from a network source as parameters to methods of the AIR API that may lead to code execution. This includes use of the Loader.loadBytes() method and the JavaScript eval() function.

Risk from using an external source to determine paths


An AIR application can be compromised when using external data or content so you must take special care when using data from the network or file system. The onus of trust is ultimately up to the developer and the network connections they make, but loading foreign data is inherently risky, and should not be used for input into sensitive operations. Developers are advised against the following:

Using data from a network source to determine a file name Using data from a network source to construct a URL that you will use to send private information

Risk from using, storing, or transmitting unsecure credentials


Storing user credentials on the user's local file system inherently introduces the risk that these credentials may be compromised. Developers are advised to consider the following:

If credentials must be stored locally, to encrypt the credentials when writing to the local file system. Do not transmit unencrypted user credentials to a network source unless that source is trusted.

Never specify a default password in credential creation let users create their own. Users who leave the default expose their credentials to an attacker that already knows the default password
The AIR runtime provides an encrypted storage unique to each installed application, via the EncryptedLocalStore class. For details, see Using the encrypted local store on page 100.

ADOBE PRODUCT X.0 39


User Guide

Risk from a downgrade attack


During application install, the runtime checks to ensure that a version of the application is not currently installed. If an application is already installed, the runtime compares the version string against the version that is being installed. If this string is different, the user can choose to upgrade their installation. There runtime does not guarantee that the newly installed version is actually newer than the older version, only that it is different. An attacker can distribute an older version to the user in order to circumvent a security weakness. For this reason, the developer is advised to make version checks when the application is run. It is a good idea to have applications check the network for required updates. That way, even if an attacker gets the user to run an old version, that old version will recognize that it needs to be updated. Also, using a very clear versioning scheme for your application makes it more difficult to trick users into installing a downgraded version. For details on providing application versions, see Defining properties in the application descriptor file on page 42.

Code Signing
All AIR installer files are required to be code signed. Code signing is a cryptographic process of confirming that the specified origin of software is accurate. AIR applications can be signed either by linking a certificate from an external certificate authority (CA) or by constructing your own certificate. Certificates are created using adt from the SDK or using either Flash, Flex Builder, or another graphical front-end that uses adt for certificate generation. For more general information about digitally signing AIR applications, see Digitally signing an AIR file on page 166.

Signing AIR applications with an existing certificate


To associate an AIR installer file with an existing certificate, use the following syntax
adt -package ( -certificate <pfx-file> )? ( -password <password> )? <air-file> <app-desc> <fileOrDir> ( -C <dir> <fileOrDir>+ ) <pfx-file> is the path and name to the existing file that contains the certificate to be associated with the application <password> is the password assigned to the certificate during its creation

The other options are unrelated to security and are described in Creating an AIR application using the command line tools on page 28.

Signing AIR applications with a self-signed certificate


Alternatively, application installer files can be constructed with a self-signed certificate. A self-signed certificate is not backed by a certificate authority (CA) and provides no external confirmation that the origin of the installer file is indeed what the runtime says it is. For AIR developers who choose not to purchase a certificate, this step is required in order to create an installer file. To create a self-signed certificate, using ADT, use the following syntax:
adt -certificate -cn <name> ( -ou <org-unit> )? ( -o <org-name> )? ( -c <country> )? <keytype> <pfx-file> <password>

The following options are available to adt in the construction of a self-signed certificate:
<name> is the name of the application

ADOBE PRODUCT X.0 40


User Guide

<org-unit> (optional) is the department within an organization that is creating the installer file <org-name> (optional) is the name of the organization that is creating the installer file. <country> (optional) is the two-letter country code that represents the installer files country of origin <key-type> is the type of encryption used to create the certificate. Acceptable options include 1024-RSA and 2048-RSA <pfx-file> is the path and name, including extension, of the file created that will contain the certificate <password> is the password associated with the certificate. this password is later required when using adt to associate an installer file to a certificate.

Note: When choosing a password, it is best to use a password that is a combination of uppercase letters, lowercase letters, punctuation characters, and numbers. It is also safest to never store the password on the same computer that contains the certificate, or to not store a password on a machine at all. One way to pick a long password is to thing of a memorable short sentence or long phrase and then add some personally memorable numbers and punctuation (such as 3665 MELba !@# toast).

See also

Scripting between content in different domains on page 162

41

Chapter 4: Setting application properties


Aside from all the files and other assets that make up your Adobe AIR applications, an AIR application requires an application descriptor, an XML file which defines the basic properties of the application. When developing AIR applications using Flash CS3 with the AIR plug-in, the application descriptor file is automatically generated when you create a new AIR project. You can access a panel to change the application descriptor settings from the menu Commands > AIR - Application and Installer Settings. You can also edit the application descriptor file by hand.

The application descriptor file structure


The application descriptor file, application.xml, contains the properties of the entire application, such as its name, the version, copyright, and so on. Any file name can be used for the application descriptor file. When you create an AIR file using the default settings in Flash CS3, the application descriptor file is renamed to application.xml and placed inside a special directory in the AIR package. Here's an example of an application descriptor file:
<?xml version="1.0" encoding="utf-8" ?> <application appId="com.adobe.air.examples.HelloWorld" version="2.0" xmlns="http://ns.adobe.com/air/application/1.0.M5"> <name>AIR Hello World</name> <title>HelloWorld -- AIR Example</title> <description> This is the Hello World sample file from the Adobe AIR documentation. </description> <copyright>Copyright 2006</copyright> <initialWindow> <title>Hello World</title> <content> HelloWorld-debug.swf </content> <systemChrome>none</systemChrome> <transparent>true</transparent> <visible>true</visible> <width>640</width> <height>480</height> </initialWindow> <installFolder>Adobe/Examples</installFolder> <icon> <image16x16>icons/smallIcon.png</image16x16> <image32x32>icons/mediumIcon.jpg</image32x32> <image48x48>icons/bigIcon.gif</image48x48> <image128x128>icons/biggestIcon.png</image128x128> </icon> <handleUpdates/> <fileTypes> <fileType> <name>adobe.VideoFile</name> <extension>avf</extension> <description>Adobe Video File</description> <contentType>application/vnd.adobe.video-file</contentType>

ADOBE PRODUCT X.0 42


User Guide

</fileType> </fileTypes> </application>

Defining properties in the application descriptor file


At its root, the application descriptor file contains an application property that has several attributes:
<application appId="com.adobe.air.HelloWorld" version="1.0" xmlns="http://ns.adobe.com/air/application/1.0.M5"> appId A unique application identifier. The attribute value is restricted to the following characters:

09 az AZ . (dot) - (hyphen)

The value must contain 1 to 212 characters. The appId string typically uses a dot-separated hierarchy, in alignment with a reversed DNS domain address, a Java package or class name, or an OS X Universal Type Identifier. The DNS-like form is not enforced, and AIR does not create any association between the name and actual DNS domains.
version Specifies the version information for the application. (It has no relation to the version of the runtime). The version string is an application-defined designator. AIR does not interprete the version string in any way. Thus version 3.0 is not assumed to be more current than version 2.0. Examples: "1.0", ".4", "0.5", "4.9", "1.3.4a". xmlns The AIR namespace, which you must define as the default XML namespace. The namespace will change with each release of AIR. The last segment of the namespace, such as 1.0.M5, indicates the AIR runtime version required by the application. minimumPatchLevel Together with the AIR namespace, determines the version of the AIR runtime required by the

application. Typically, the user will be prompted to download and install the required version or patch, if necessary.

Defining the applications name, description, copyright, and installation folder


name The name of the application. You must define this element. <name>TestApp</name>

In Windows, this is displayed in the applications title bar and in the Windows Start menu. On Mac OS, it is displayed in the menu bar when the application is running.
title (Optional) The title displayed by the AIR application installer. description (Optional) Displayed in the AIR application installer. <description>An MP3 player.</description> copyright (Optional) The copyright information for the AIR application.

ADOBE PRODUCT X.0 43


User Guide

<copyright>Copyright 2006 [YourCompany, Inc.]</copyright> installFolder (Optional) Identifies the subdirectory of the default installation directory. <installFolder>Acme</installFolder>

On Windows, the default installation subdirectory is the Program Files directory. On Mac OS, it is the ./Applications directory. For example, if the installFolder property is set to "Acme" and an application is named "ExampleApp", then the application will be installed in C:\Program Files\Acme\Example on Windows and in ./Applications/Acme/Example.app on MacOS. Use the forward-slash (/) character as the directory separator character if you want to specify a nested subdirectory, as in the following:
<installFolder>Acme/Power Tools</installFolder>

The installFolder property can contain any Unicode (UTF-8) character except the following, which are prohibited from use as folder names on various file systems:
Character various * Hex Code

0x00 x1F x2A x22 x3A x3C x3E x3F x5C x7C

" : > < ? \ |

The installFolder property is optional. If you specify no installFolder property, the application is installed in a subdirectory of the default installation directory, based on the name property.
programMenuFolder (Optional) Identifies the location in which to place shortcuts to the application in the

Windows All Programs menu. (Ignored on other operating systems.) The restrictions on the characters that are allowed in the value of the property are the same as those for the installFolder property.
<programMenuFolder>Acme/Applications</programMenuFolder>

Defining the properties of the initial application window


When an AIR application is loaded, the runtime uses the values in the initialWindow element to create the initial window for the application. The runtime then loads the file specified in the content element into the window.
<initialWindow> <content>AIRTunes.swf</content> <title>AIR Tunes</title> <systemChrome>none</systemChrome> <transparent>true</transparent>

ADOBE PRODUCT X.0 44


User Guide

<visible>true</visible> <minimizable>true</minimizable> <maximizable>true</maximizable> <resizable>true</resizable> <width>400</width> <height>600</height> <x>150</x> <y>150</y> <minSize>300 300</minSize> <maxSize>800 800</maxSize> </initialWindow>

The children of the initialWindow element set the properties of the window into which the root content file will be loaded.
content The value specified for the content element is the URL for the main content file of the application. This may be either a SWF file or an HTML file. The URL is specified relative to the root of the application.xml file. title The window title. systemChrome If you set this attribute to standard, the standard system chrome supplied by the operating system is displayed. If you set it to none, no system chrome is displayed. The system chrome setting cannot be changed at run time. transparent Set this to "true" if you want the application window to support alpha blending. The transprent property of a window cannot be changed after the window has been created. A window with transparency may draw more slowly and require more memory than otherwise. The transparent setting cannot be changed at run time.

Important: You can only set transparent="true" when systemChrome="none".


visible Set this to "true" if you want to have the main window be visible as soon as it is created. The default value

is "false". You may want to leave the main window hidden initially, so that changes to the window s position, size, and the layout of its contents are not shown. You can then display the window by setting the stage.nativeWindow.visible property (for the main window) to true. For details, see Working with windows on page 48.
width, height, x, y The initial bounds of the main window of the application. If you do not set these values,

the window size is determined by the settings in the root SWF file or, in the case of HTML, by the operating system.
minSize, maxSize The minimum and maximum sizes of the window. If you do not set these values, they will be

determined by the operating system.


minimizable, maximizable, resizable Specifies whether the window can be minimized, maximized, and resized. By default, these settings default to true.

Note: On operating systems, such as Mac OS X, for which maximizing windows is a resizing operation, both maximizable and resizable must be set to false to prevent the window from being zoomed or resized.

See also

Working with windows on page 48

Specifying icon files


The icon property specifies one or more icon files to be used for the application. Including an icon is optional. If you do not specify an icon property, the operating system will display a default icon.

ADOBE PRODUCT X.0 45


User Guide

The path specified is relative to the application root directory. The PNG, GIF, and JPEG formats are supported. You can specify all of the following icon sizes:
<icon> <image16x16>icons/smallIcon.png</image16x16> <image32x32>icons/mediumIcon.jpg</image32x32> <image48x48>icons/bigIcon.gif</image48x48> <image128x128>icons/biggestIcon.png</image128x128> </icon>

If an image is specified, it must be the size specified. If all sizes are not provided, the closest size will be scaled to fit for a given use of the icon by the operating system. Note: The icons specified are not automatically added to the AIR package. The icon files must be included in their correct relative locations when the application is packaged.

Signaling the inclusion of an update interface


Normally, AIR installs and updates applications using the default installation dialog. However, you can define your own mechanism for updating an application using the AIR Updater API. To indicate that your application should handle the update process itself, you must include the handleUpdates element in the application descriptor file:
<handleUpdates/>

When the installed version of your application includes the handleUpdates element in the application descriptor file and the user then double-clicks on the AIR file for a new version (the appId attributes must match), the runtime opens the installed version of the application, rather than the default AIR application installer. Your application logic can then determine how to proceed with the update operation. Note: The handleUpdates mechanism only works when the application is already installed and the user double-clicks the AIR file. For more information, see Updating AIR applications programmatically on page 174.

Registering file types


The fileTypes property lets you define the file types that can be registered for the AIR application.
<fileTypes> <fileType> <name>adobe.VideoFile</name> <extension>avf</extension> <description>Adobe Video File</description> <contentType>application/vnd.adobe.video-file</contentType> <icon> <image16x16>icons/AIRApp_16.png</image16x16> <image32x32>icons/AIRApp_32.png</image32x32> <image48x48>icons/AIRApp_48.png</image48x48> <image128x128>icons/AIRApp_128.png</image128x128> </icon> </fileType> </fileTypes>

The fileTypes element is optional. If present, you can specify any number of file type registrations.

ADOBE PRODUCT X.0 46


User Guide

The name and extension elements are required for each fileType definition that you include. Note that the extension is specified without the preceding period. The description element is optional. The contentType property is also optional. Icons can be specified for the file extension, using the same format as the application icon element. When a file type is registered with an AIR application, the application will be invoked whenever a user opens a file of that type. If the application is already running, AIR will dispatch the invoke event to the running instance. Otherwise, AIR will launch the application first. In both cases, the file name and location can be retrieved from the InvokeEvent object dispatched by the application Shell object.

See also

Capturing command line arguments on page 146

47

Part 1: Working with windows and menus


Working with windows . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .48 Screens . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .1 Working with native menus. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .1

48

Chapter 6: Working with windows


You use the classes provided by the Adobe AIR windowing API to create and manipulate windows.
GETTING STARTED

AIR window basics on page 48 Interacting with a window on page 17 Creating a transparent window application on page 22 Launching native windows on page 27 Creating toast-style windows on page 31 Creating resizable, non-rectangular windows on page 47 Controlling the display order of windows on page 36

DEVELOPMENT TASKS

Creating windows on page 52 Manipulating windows on page 54 Listening for window events on page 60 Using full-screen window mode on page 61

LANGUAGE REFERENCE

NativeWindow NativeWindowInitOptions

MORE INFORMATION:

You may be able to find more information about working the AIR File API in the AIR Developer Center (http://www.adobe.com/devnet/air/flash/). Search the site using the keywords AIR windows.

AIR window basics


The windowing API contains the following classes.
Package flash.display Classes NativeWindow, NativeWindowInitOptions Window string constants are defined in the following classes: NativeWindowDisplayState, NativeWindowResize, NativeWindowSystemChrome, NativeWindowType flash.events NativeWindowBoundsEvent, NativeWindowDisplayStateEvent, NativeWindowErrorEvent

AIR provides an easy-to-use, cross-platform window API for creating native operating system windows using Flash, Flex, and HTML programming techniques.

ADOBE PRODUCT X.0 49


User Guide

With AIR, you have a wide latitude in developing the look-and-feel of your application. The windows you create can look like a standard desktop application, matching Apple style when run on the Mac, and conforming to Microsoft conventions when run on Windows. Or you can use the skinnable, extendible chrome provided by the Flex framework to establish your own style no matter where your application is run. You can even draw your own windows with vector and bitmap artwork with full support for transparency and alpha blending against the desktop. Tired of rectangular windows? Draw a round one. AIR supports two distinct APIs for working with windows: the Flash-oriented NativeWindow class and the HTMLoriented JavaScript Window class. Windows created with the NativeWindow class use the Flash stage and display list directly. To add a visual object to a NativeWindow, you add the object to the display list of the windows stage. Windows created with JavaScript use HTML, CSS, and JavaScript to display content. To add a visual object to an HTML window, you add that content to the HTML DOM. Note: HTML windows are a special category of NativeWindow. The AIR host adds a nativeWindow property to HTML windows that provides access to the underlying NativeWindow instance. The first window of your application is automatically created for you by AIR based on the parameters specified in the initialWindow element of the application descriptor file. If the root content is a SWF file, a NativeWindow instance is created and the SWF is loaded into the window. If the root content is an HTML file, an HTML window is created and the HTML page is loaded. Native windows use an event-based programming model. Changing any properties or calling methods on the window object that may affect the display or behavior of application components dispatches notification events to which interested components can listen. For example, when the system chrome maximize button is clicked by a user the following sequence of events occurs: 1 The user clicks the maximize button.
2 3 4 5 6

A displayStateChanging event is dispatched by the window If no registered listeners cancel the event, the window is maximized

A displayStateChange event is dispatched by the window to notify listeners that the change has been made. In addition, events for related changes are dispatched: A move event is dispatched if the top, left corner of the window moved because of the maximize operation. A resize event is dispatched if the window size changed because of the maximize operation

A similar sequence of events is dispatched for minimizing, restoring, closing, moving, and resizing a window. For detailed information about the window API classes, methods, properties, and events, see the AIR ActionScript 3.0 Language Reference (http://www.adobe.com/go/learn_flex3_aslr). For general information about using the Flash display list, see the Display Programming section of the Programming ActionScript 3.0 (http://www.adobe.com/go/programmingAS3) reference.

See also

The application descriptor file structure on page 41

ADOBE PRODUCT X.0 50


User Guide

Styles of Native Windows


The basic appearance and functional style of window is determined by three properties: type, systemChrome, and transparent. The type property sets the function of the window. The systemChrome property sets whether the window uses chrome supplied by native operating system. The transparent property sets whether the supports alpha blending with the desktop environment. These properties are set on the NativeWindowInitOptions object used to create the window and cannot be changed. The properties of the initial window created automatically on application start up are set in the application descriptor file. The type property cannot be set in the application descriptor and is always normal. Some settings of these properties are mutually incompatible: systemChrome cannot be set to standard when either transparent is true or type is lightweight.
Window Type

The type property combines certain chrome and visibility attributes of the native operating system to create three functional types of window. The type property can only be set when creating a new NativeWindow. AIR supports the following window types: Normal A typical window. Normal windows use the full-size chrome and appear on the Windows task bar and the Mac OS X window menu. Utility A tool palette. Utility windows use a slimmer version of the system chrome and do not appear on the Windows task bar and the Mac OS-X window menu. Lightweight Lightweight windows have little or no chrome and do not appear on the Windows task bar and the Mac OS X window menu. In addition, lightweight windows do not have the System (Alt-Space) menu on Windows. Lightweight windows are suitable for notification bubbles and controls such as combo-boxes that open a short-lived display area. When the lightweight type is used, systemChrome must be set to none.
Window chrome

Window chrome is the set of controls that allow users to manipulate a window in the desktop environment. For an AIR application, you have the following choices for window chrome: System chrome System chrome displays your window within the set of standard controls created and styled by the users operating system. Use system chrome to make your application look like a standard desktop application for the operating system in which it is run. System chrome is managed by the system, your application has no direct access to the controls themselves, but can react to the events dispatched when the controls are used. If system chrome is used for a window, the transparency property must be set to false. Note: In this Beta release, the Alternate systemChrome setting is not supported.
Custom chrome When you create a window with no system chrome then you must add your own controls to handle

the interactions between a user and the window. You are also free to make transparent, non-rectangular windows.
Window transparency

To allow alpha blending of a window with the desktop or other windows, set the window's transparent property to true. The transparent property must be set before the window is created and cannot be changed. The transparent property is set in the NativeWindowInitOptions object used to create a window. (For the initial window created for your application, the initialization options are taken from attributes of the initialWindow element in the application descriptor file.) A transparent window has no default background. Any window area not occupied by a display object will be invisible. If a display object has an alpha setting of less than one, then any thing below the object will show through, including other display objects in the same window, other windows, and the desktop. Rendering large alpha-blended areas can be slow, so the effect should be used conservatively.

ADOBE PRODUCT X.0 51


User Guide

Transparent windows are useful when you want to create: Applications with borders that are irregular in shape

Applications that must fade out or appear to be invisible

Transparency cannot be used for windows with system chrome.

A visual window catalogue


The following table demonstrates the visual effects of different combinations of window property settings.
Type Standard System Chrome normal Transparent Not supported Mac OS X Microsoft Windows

Utility

normal

Not supported

Any

none

false

Any

none

true

Limitations in the Beta Release

The following window-related features are not supported in this Beta release: The windowing API does not currently support the Toolbars|OS X Toolbar or the OS X Proxy Icon.

Alternate system chrome

ADOBE PRODUCT X.0 52


User Guide

Creating windows
AIR provides the following primary means for creating applications windows: AIR automatically creates the first window for every application. This window is initialized according to the settings defined in the application descriptor file. If the root content identified in the descriptor is a SWF file, then you can access the properties and methods of the window instance through the Stage.nativeWindow property and the NativeWindow API. In addition, the main class of the SWF file must extend from Sprite or a subclass of Sprite. If the root content is an HTML file, then you can access the properties and methods of the window through the JavaScript Window objects nativeWindow property.

You can create a new instance of the NativeWindow class. New NativeWindows are initialized by the NativeWindowInitOptions object passed to the window constructor. You can access the properties and methods directly from the object reference returned by the constructor.
You can use the HTMLControl.createRootWindow() method to create a window to display HTML content.

You can use the JavaScript Window.open() method to open new windows from JavaScript code. The properties and methods of JavaScript-created windows can only be accessed through JavaScript and the window can only display HTML. JavaScript-created HTML windows automatically include system chrome.
Note: You can create new NativeWindows from JavaScript code (through the AIR window.runtime property). This section contains the following topics: Creating a new NativeWindow on page 52

Adding content to a window on page 53 Example: Creating windows with ActionScript on page 54

Creating a new NativeWindow


To create a new NativeWindow, create a NativeWindowInitOptions object and pass it to the NativeWindow constructor.
var options:NativeWindowInitOptions = new NativeWindowInitOptions(); options.systemChrome = NativeWindowSystemChrome.STANDARD; options.transparent = false; var newWin:NativeWindow = new NativeWindow(options);

To avoid displaying the intermediate states of the window as you set its bounds, position, and contents, do not set the NativeWindow.visible property to true or call the activate() method until you have finished initializing the window. The NativeWindowInitOptions object sets those properties of a window that cannot be changed after the window has been created. Note: Setting systemChrome="standard" and transparent="true" is not a supported combination. Once the window is created, you may initialize its properties and load content into the window using the stage property and Flash display list techniques. Note: To determine the maximum and minimum window sizes allowed on the current operating system, use the following static NativeWindow properties:
var maxOSSize:Point = NativeWindow.systemMaxSize; var minOSSize:Point = NativeWindow.systemMinSize;

ADOBE PRODUCT X.0 53


User Guide

Adding content to a window


To add content to a native window, add display objects to the window stage. You can create display objects dynamically or load existing content with the flash.display.Loader class. Within an HTML window, you can add content by changing the location property (to load a new page) or inserting HTML content into the DOM. When you load SWF content, or HTML content containing JavaScript, you must take the AIR security model into consideration. Any content in the application security sandbox, that is content installed with your application and loadable with the app-resource: URL scheme, will have full privileges to access all the AIR APIs. Any content loaded from outside this sandbox will be restricted both from accessing the security-restricted AIR APIs and from crossscripting other content. JavaScript content outside the application sandbox will not be able to use the nativeWindow or htmlControl properties of the JavaScript Window object. To allow safe cross-scripting, you can use a sandbox bridge to provide a limited interface between application content and non-application content.
Loading a SWF or image

You can load Flash or images into the display list of a native window using the flash.display.Loader class.
package { import import import import flash.display.Sprite; flash.events.Event; flash.net.URLRequest; flash.display.Loader;

public class LoadedSWF extends Sprite { public function LoadedSWF(){ var loader:Loader = new Loader(); loader.load(new URLRequest("visual.swf")); loader.contentLoaderInfo.addEventListener(Event.COMPLETE,loadFlash); } private function loadFlash(event:Event):void{ addChild(event.target.loader); } } }

Visual Flash content added to an HTML window must be displayed either on top of the HTML content as an overlay, or beneath transparent HTML content. Such content must also be positioned and resized separately from the HTML content. You can load a SWF file that contains library code for use in an HTML-based application. The simplest way to load a SWF in an HTML window is to use the script tag, but you can also use the flash.display.Loader API directly. Note: Older SWF files created using ActionScript 1 or 2 will share global state such as class definitions, singletons, and global variables if they are loaded into the same window. If such a SWF relies on untouched global state to work correctly, it cannot be loaded more than once into the same window, or loaded into the same window as another SWF using overlapping class definitions and variables. This content can be loaded into separate windows.
Loading HTML content into a NativeWindow

To load HTML content into a NativeWindow, you can either add an HTMLControl object to the window stage and load the HTML content into the HTMLControl, or create a new window that already contains an HTMLControl object by using the HTMLControl.createRootWindow()method. The following example displays HTML content within a 300 by 500 pixel display area on the stage of a native window:
//newWindow is a NativeWindow instance

ADOBE PRODUCT X.0 54


User Guide

var htmlView:HTMLControl = new HTMLControl(); html.width = 300; html.height = 500; //set the stage so display objects are added to the top-left and not scaled newWindow.stage.align = "TL"; newWindow.stage.scaleMode = "noScale"; newWindow.stage.addChild( htmlView ); //urlString is the URL of the HTML page to load htmlView.load( new URLRequest(urlString) ); Loading Flash content within an HTML page

In this Beta release, displaying Flash content embedded in an HTML page within an instance of a HTMLControl is not supported. Any Flash objects in the page will be displayed as blank rectangles. You can, however, load or create Flash content using the AIR APIs and add it to the HTML window as an overlay or underlay to the HTML layer.

See also

Adding HTML content to SWF-based applications on page 162 Scripting between content in different domains on page 162

Example: Creating windows with ActionScript


The following example illustrates how to create new windows using ActionScript.
public function createNativeWindow():void { //create the init options var options:NativeWindowInitOptions = new NativeWindowInitOptions(); options.transparent = false; options.systemChrome = NativeWindowSystemChrome.STANDARD; options.type = NativeWindowType.NORMAL; //create the window var newWindow:NativeWindow = new NativeWindow(options); newWindow.title = "A title"; newWindow.width = 600; newWindow.height = 400; //add a sprite to the window newWindow.stage.align = StageAlign.TOP_LEFT; newWindow.stage.scaleMode = StageScaleMode.NO_SCALE; //activate and show the new window newWindow.activate(); }

Manipulating windows
This section highlights using the properties and methods of the NativeWindow class to manipulate the appearance and behavior of application windows and includes the following topics: Getting a NativeWindow instance on page 55

Activating, showing and hiding windows on page 55

ADOBE PRODUCT X.0 55


User Guide

Maximizing, minimizing, and restoring a window on page 55 Changing the window display order on page 56 Closing a window on page 56 Allowing cancellation of window operations on page 57 Example: Minimizing, maximizing, restoring and closing a window on page 57 Example: Resizing and moving windows on page 59

Getting a NativeWindow instance


To manipulate a window, you must first get the window instance. You can get a window instance from one of the following places: The window constructor That is, the window constructor for a new NativeWindow. The window stage That is, stage.nativeWindow. Any display object on the stage That is, myDisplayObject.stage.nativeWindow. A window event The target property of the event object references the window that dispatched the event. The global nativeWindow property of an HTMLControl or HTML window That is, window.nativeWindow. The shell object Shell.shell.activeWindow references the active window of an application (but returns null if the active window is not a window of this AIR application). The Shell.shell.openedWindows array contains all of the windows in an AIR application that have not been closed.

Activating, showing and hiding windows


To activate a window, call the NativeWindow.activate() method. Activating a window will bring the window to front, give it keyboard and mouse focus, and, if necessary, make it visible by restoring the window or setting visible=true. Activating a window will not change the ordering of other windows in the application. To show a hidden window without activating it, set the visible property to true. This will bring the window to the front, but will not take the keyboard or mouse focus. To hide a window from view, set the NativeWindow.visible property to false. Hiding a window will suppress the display of both the window, any related task bar icons, and, on MacOS X, the entry in the Windows menu. Note: On Mac OS X, it is not possible to completely hide a minimized window that has a dock icon. If the visible property is set to false on a minimized window, the dock icon for the window will still be displayed. If the user clicks the icon, the window will be restored to a visible state and displayed.

Maximizing, minimizing, and restoring a window


To maximize the window, use the NativeWindow.maximize() method.
myWindow.maximize();

To minimize the window, use the NativeWindow.minimize() method.


myWindow.minimize();

Restoring a window returns it to the size that it was before it was either minimized or maximized. To restore the window (that is, return it to the size that it was before it was either minimized or maximized), use the NativeWindow.restore() method.
myWindow.restore();

ADOBE PRODUCT X.0 56


User Guide

Note: The behavior that results from maximizing an AIR window is different than the Mac OS X standard behavior. Rather than toggling between an application-defined standard size and the last size set by the user, AIR windows toggle between the size last set by the application or user and the full usable area of the screen.

Changing the window display order


AIR provides two display order groups for windows, controlled by the setting of the alwaysInFront property. A window can be placed in the normal group, which should be used for almost all windows, by setting alwaysInFront=false. Windows in the second group are always displayed in front of windows in the normal group, even the windows of other applications. Because this behavior can be disruptive to a user, the always in front group should only be used when necessary and appropriate. Examples of justified uses of this display order group are: Temporary pop-up display windows for controls such as tooltips, pop-up lists, custom menus, or comboboxes. Because these windows should close when they lose focus, the annoyance of blocking a user from viewing another window can be avoided.

Screensavers

Extremely urgent error messages and alerts. When an irrevocable change may occur if the user does not respond in a timely manner, it may be justified to push an alert widow to the forefront. However, most errors and alerts can be handled in the normal window display order. (Please refer to the AIR end user license agreement (EULA) for information on AIRs suitability for time-critical applications such as aircraft and nuclear power plant control.)
Short-lived toast-style windows. Full-screen windows for games or video

Note: AIR does not enforce proper use of the alwaysInFront property. However, if your application disrupts a users workflow, it is very likely to be consigned to that same users trash can. The NativeWindow class provides the following methods for setting the display order of a window relative to other windows: alwaysInFront property Specifies in which display-order grouping a window will be placed. In almost all cases alwaysInFront=false is the best setting. Changing the value from false to true will also bring the window to the front of all windows (but will not activate it). Changing the value from true to false will put the window at the front of the normal display order group (but behind all the windows in the always in front group). Setting the property to the current value will not change the window display order. orderToFront() Brings the window to the front of its display order group. orderInFrontOf() Brings the window in front of another window. orderToBack() Sends the window behind all other windows in its display order group. orderBehind() Sends the window directly behind another window. Note: If a window is hidden (visible=false) or minimized, then calling the display order methods will have no affect.

Closing a window
To close a window, use the NativeWindow.close method. Closing a window unloads the contents of the window, but if other objects have references to this content, the content objects will not be destroyed. The NativeWindow.close() method executes asynchronously, the application that is contained in the window continues to run during the closing process. The close method dispatches a close event when the close operation is complete. The NativeWindow object is still technically valid, but accessing most properties and methods on a closed window will generate an IllegalOperationError. You cannot reopen a closed window. Check the closed property of a window to test whether a window has been closed. To simply hide a window from view, set the NativeWindow.visible property to false.

ADOBE PRODUCT X.0 57


User Guide

If the Shell.autoExit property is true, which is the default, then the application exits when its last window closes.

Allowing cancellation of window operations


When a window uses system chrome, user interaction with the window can be canceled by listening for, and canceling the default behavior of the appropriate events. For example, when a user clicks the system chrome close button, the closing event is dispatched. If any registered listener calls the preventDefault() method of the event, then the window will not close. When a window does not use system chrome, notification events for intended changes are not automatically dispatched before the change is made. Hence, if you call the methods for closing a window, changing the window state, or set any of the window bounds properties, the change cannot be canceled. To notify components in your application before a window change is actually made, your application logic can dispatch the relevant notification event using the dispatchEvent() method of the window. For example, the following logic implements a cancelable event handler for a window close button:
public function onCloseCommand(event:MouseEvent):void{ var closingEvent:Event = new Event(Event.CLOSING,true,true); dispatchEvent(closing); if(!closingEvent.isDefaultPrevented()){ win.close(); } }

Note that the dispatchEvent() method returns false if the event preventDefault() method is called by a listener. However, it can also return false for other reasons, so it is better to explicitly use the isDefaultPrevented() method to test whether the change should be canceled.

Example: Minimizing, maximizing, restoring and closing a window


The following short MXML application demonstrates the Window maximize(), minimize(), restore(), and close() methods.
<?xml version="1.0" encoding="utf-8"?> <mx:WindowedApplication xmlns:mx="http://www.adobe.com/2006/mxml" layout="vertical">

<mx:Script> <![CDATA[ public function minimizeWindow():void { this.stage.nativeWindow.minimize(); } public function maximizeWindow():void { this.stage.nativeWindow.maximize(); } public function restoreWindow():void { this.stage.nativeWindow.restore(); } public function closeWindow():void

ADOBE PRODUCT X.0 58


User Guide

{ this.stage.nativeWindow.close(); } ]]> </mx:Script> <mx:VBox> <mx:Button <mx:Button <mx:Button <mx:Button </mx:VBox>

label="Minimize" click="minimizeWindow()"/> label="Restore" click="restoreWindow()"/> label="Maximize" click="maximizeWindow()"/> label="Close" click="closeWindow()"/>

</mx:WindowedApplication>

The following ActionScript example for Flash creates four clickable text fields that trigger the NativeWindow minimize(), maximize(), restore(), and close() methods.
package { import flash.display.Sprite; import flash.events.MouseEvent; import flash.text.TextField; public class MinimizeExample extends Sprite { public function MinimizeExample():void { var minTextBtn:TextField = new TextField(); minTextBtn.x = 10; minTextBtn.y = 10; minTextBtn.text = "Minimize"; minTextBtn.background = true; minTextBtn.border = true; minTextBtn.selectable = false; addChild(minTextBtn); minTextBtn.addEventListener(MouseEvent.CLICK, onMinimize); var maxTextBtn:TextField = new TextField(); maxTextBtn.x = 120; maxTextBtn.y = 10; maxTextBtn.text = "Maximize"; maxTextBtn.background = true; maxTextBtn.border = true; maxTextBtn.selectable = false; addChild(maxTextBtn); maxTextBtn.addEventListener(MouseEvent.CLICK, onMaximize); var restoreTextBtn:TextField = new TextField(); restoreTextBtn.x = 230; restoreTextBtn.y = 10; restoreTextBtn.text = "Restore"; restoreTextBtn.background = true; restoreTextBtn.border = true; restoreTextBtn.selectable = false; addChild(restoreTextBtn); restoreTextBtn.addEventListener(MouseEvent.CLICK, onRestore); var closeTextBtn:TextField = new TextField(); closeTextBtn.x = 340; closeTextBtn.y = 10; closeTextBtn.text = "Close Window";

ADOBE PRODUCT X.0 59


User Guide

closeTextBtn.background = true; closeTextBtn.border = true; closeTextBtn.selectable = false; addChild(closeTextBtn); closeTextBtn.addEventListener(MouseEvent.CLICK, onCloseWindow); } function onMinimize(event:MouseEvent):void { this.stage.nativeWindow.minimize(); } function onMaximize(event:MouseEvent):void { this.stage.nativeWindow.maximize(); } function onRestore(event:MouseEvent):void { this.stage.nativeWindow.restore(); } function onCloseWindow(event:MouseEvent):void { this.stage.nativeWindow.close(); } } }

Example: Resizing and moving windows


An AIR application can initiate a system-controlled operation to resize or move its containing window. The process that is used to complete the operation depends on whether the call to the method that completes the operation is made from within a mouseDown event. Note: To resize or move a window, you must first obtain a reference to the NativeWindow instance. For information about how to obtain a window reference, see Getting a NativeWindow instance on page 55. To resize a window, use the NativeWindow.startResize() method. This method triggers a system-controlled resizing of the window. When this method is called from a mouseDown event, the resizing process is mouse-driven and completes when the operating system receives a mouseUp event. A call to the NativeWindow.startResize() method that is not made from a mouseDown event triggers a system-controlled resizing operation that may be mouse-driven or keyboard-driven but remains consistent with the default resizing sequence for the operating system. To move a window without resizing it, use the NativeWindow.startMove() method. Like the startResize() method, when the startMove() method is called from a mouseDown event, the move process is mouse-driven and completes when the operating system receives a mouseUp event. A call to the NativeWindow.startMove() method that is not made from a mouseDown event triggers a system-controlled move that may be mouse-driven or keyboarddriven but remains consistent with the default move sequence for the operating system. For more information about the startResize and startMove methods, see the AIR ActionScript 3.0 Language Reference. The following example shows how to initiate resizing and moving operations on a window:
package { import flash.display.Sprite; import flash.events.MouseEvent; import flash.display.NativeWindowResize; public class NativeWindowResizeExample extends Sprite

ADOBE PRODUCT X.0 60


User Guide

{ public function NativeWindowResizeExample():void { // Fills a background area. this.graphics.beginFill(0xFFFFFF); this.graphics.drawRect(0, 0, 400, 300); this.graphics.endFill(); // Creates a square area where a mouse down will trigger a resize. var resizeHandle:Sprite = createSprite(0xCCCCCC, 20, this.width - 20, this.height - 20); resizeHandle.addEventListener(MouseEvent.MOUSE_DOWN, onStartResize); // Creates a square area where a mouse down will trigger a move. var moveHandle:Sprite = createSprite(0xCCCCCC, 20, this.width - 20, 0); moveHandle.addEventListener(MouseEvent.MOUSE_DOWN, onStartMove); } public function createSprite(color:int, size:int, x:int, y:int):Sprite { var s:Sprite = new Sprite(); s.graphics.beginFill(color); s.graphics.drawRect(0, 0, size, size); s.graphics.endFill(); s.x = x; s.y = y; this.addChild(s); return s; } public function onStartResize(event:MouseEvent):void { this.stage.nativeWindow.startResize(NativeWindowResize.BOTTOM_RIGHT); } public function onStartMove(event:MouseEvent):void { this.stage.nativeWindow.startMove(); } } }

Listening for window events


To listen for the events dispatched by a window, register a listener with the window instance. For example, to listen for the closing event, register a listener with the window as follows:
myWindow.addEventListener(Event.CLOSING, onClosingEvent);

When an event is dispatched, the target property references the window sending the event. Most window events have two related messages. The first message signals that a window change is imminent (and can be canceled), while the second message signals that the change has occurred. For example, when a user clicks the close button of a window, the closing event message is dispatched. If no listeners cancel the event, the window closes and the close event is dispatched to any listeners. Events in the flash.events.Event class: ACTIVATE

ADOBE PRODUCT X.0 61


User Guide

DEACTIVATE CLOSING CLOSE

NativeWindowBoundsEvent: Use the beforeBounds and afterBounds properties to determine the window bounds before and after the impending or completed change. MOVING

MOVE RESIZING RESIZE

NativeWindowDisplayStateEvent: Use the beforeDisplayState and afterDisplayState properties to determine the window display state before and after the impending or completed change. DISPLAY_STATE_CHANGING

DISPLAY_STATE_CHANGE

Using full-screen window mode


Setting the displayState property of the Stage to StageDisplayState.FULL_SCREEN puts the window in fullscreen mode, and keyboard input is permitted in this mode. (In SWF content running in a browser, keyboard input is not permitted). To exit full-screen mode, the user presses the Escape key. For example, the following Flex code defines a simple AIR application that sets up a simple full-screen terminal:
<?xml version="1.0" encoding="utf-8"?> <mx:WindowedApplication xmlns:mx="http://www.adobe.com/2006/mxml" layout="vertical" applicationComplete="init()" backgroundColor="0x003030" focusRect="false"> <mx:Script> <![CDATA[ private function init():void { stage.displayState = StageDisplayState.FULL_SCREEN; focusManager.setFocus(terminal); terminal.text = "Welcome to the dumb terminal app. Press the ESC key to exit..\n"; terminal.selectionBeginIndex = terminal.text.length; terminal.selectionEndIndex = terminal.text.length; } ]]> </mx:Script> <mx:TextArea id="terminal" height="100%" width="100%" scroll="false" backgroundColor="0x003030" color="0xCCFF00" fontFamily="Lucida Console" fontSize="44"/> </mx:WindowedApplication>

ADOBE PRODUCT X.0 62


User Guide

The following ActionScript example for Flash simulates a simple full-screen text terminal.
{ import import import import flash.display.Sprite; flash.display.StageDisplayState; flash.text.TextField; flash.text.TextFormat;

public class FullScreenTerminalExample extends Sprite { public function FullScreenTerminalExample():void { var terminal:TextField = new TextField(); terminal.multiline = true; terminal.wordWrap = true; terminal.selectable = true; terminal.background = true; terminal.backgroundColor = 0x00333333; this.stage.displayState = StageDisplayState.FULL_SCREEN; addChild(terminal); terminal.width = 550; terminal.height = 400; terminal.text = "Welcome to the dumb terminal application. Press the ESC key to exit.\n_"; var tf:TextFormat = new TextFormat(); tf.font = "Courier New"; tf.color = 0x00CCFF00; tf.size = 12; terminal.setTextFormat(tf); terminal.setSelection(terminal.text.length - 1, terminal.text.length); } } }

63

Chapter 7: Screens
Use the classes provided by the AIR screen API to discover information about the desktop display screens attached to a computer.
GETTING STARTED

Screen basics on page 63 Measuring the virtual desktop on page 1

DEVELOPMENT TASKS

Enumerating the screens on page 64

LANGUAGE REFERENCE

Screen

MORE INFORMATION

You may be able to find more information about working the AIR File API in the AIR Developer Center (http://www.adobe.com/devnet/air/flash/). Search the site using the keywords AIR screens.

Screen basics
The screen API contains a single class, Screen, which provides static members for getting system screen information, and instance members for describing a particular screen. A computer system may have several monitors or displays attached, which may correspond to several desktop screens arranged in a virtual space. The AIR Screen class provides information about the screens, their relative arrangement, and their usable space. If more than one monitor maps to the same screen, only one screen exists. If the size of a screen is larger than the display area of the monitor, there is no way to determine which portion of the screen is currently visible. A screen represents an independent desktop display area. Screens are described as rectangles within the virtual desktop. The top-left corner of screen designated as the primary display is the origin of the virtual desktop coordinate system. All values used to describe a screen are provided in pixels.

ADOBE PRODUCT X.0 64


User Guide

In this screen arrangement, two screens exist on the virtual desktop. The coordinates of the top-left corner of the main screen (#1) are always (0,0). If the screen arrangement is changed to designate screen #2 as the main screen, then the coordinates of screen #1 will become negative. Menubars, taskbars and docks are excluded when reporting the usable bounds for a screen.

For detailed information about the screen API class, methods, properties, and events, see the AIR ActionScript 3.0 Language Reference (http://www.adobe.com/go/learn_air_aslr).

Enumerating the screens


You can enumerate the screens of the virtual desktop with the following screen methods and properties:
Screen.screens Provides an array of Screen objects describing the available screens. Note that the order of the

array is not significant.


Screen.mainScreen Provides a Screen object for the main screen. On Mac OS X, this will be the screen displaying

the menu bar. On Windows, this will be the system-designated primary screen.
Screen.getScreensForRectangle() Provides an array of Screen objects describing the screens intersected by the given rectangle. The rectangle passed to this method is in pixel coordinates on the virtual desktop. If no screens are intersected by the rectangle, then the array will be empty.

You should not save the values returned by these methods and properties. The user or operating system can change the available screens and their arrangement at any time.

Example: Moving a window between screens


This example uses the screen API to move a window between multiple screens in response to pressing the arrow keys. To move the window to the next screen, the example gets the screens array and sorts it either vertically or horizontally (depending on the arrow key pressed). The code then walks through the sorted array, comparing each screen to the coordinates of the current screen. To identify the current screen of the window, the example calls Screen.getScreensForRectangle(), passing in the window bounds.

ADOBE PRODUCT X.0 65


User Guide

package { import import import import import import

flash.display.Sprite; flash.display.Screen; flash.events.KeyboardEvent; flash.ui.Keyboard; flash.display.StageAlign; flash.display.StageScaleMode;

public class ScreenExample extends Sprite { public function ScreenExample() { stage.align = StageAlign.TOP_LEFT; stage.scaleMode = StageScaleMode.NO_SCALE; stage.addEventListener(KeyboardEvent.KEY_DOWN,onKey); } private function onKey(event:KeyboardEvent):void{ if(Screen.screens.length > 1){ switch(event.keyCode){ case Keyboard.LEFT : moveLeft(); break; case Keyboard.RIGHT : moveRight(); break; case Keyboard.UP : moveUp(); break; case Keyboard.DOWN : moveDown(); break; } } } private function moveLeft():void{ var currentScreen = getCurrentScreen(); var left:Array = Screen.screens; left.sort(sortHorizontal); for(var i:int = 0; i < left.length - 1; i++){ if(left[i].bounds.left < stage.nativeWindow.bounds.left){ stage.nativeWindow.x += left[i].bounds.left - currentScreen.bounds.left; stage.nativeWindow.y += left[i].bounds.top - currentScreen.bounds.top; } } } private function moveRight():void{ var currentScreen:Screen = getCurrentScreen(); var left:Array = Screen.screens; left.sort(sortHorizontal); for(var i:int = left.length - 1; i > 0; i--){ if(left[i].bounds.left > stage.nativeWindow.bounds.left){ stage.nativeWindow.x += left[i].bounds.left - currentScreen.bounds.left; stage.nativeWindow.y += left[i].bounds.top - currentScreen.bounds.top; } }

ADOBE PRODUCT X.0 66


User Guide

} private function moveUp():void{ var currentScreen:Screen = getCurrentScreen(); var top:Array = Screen.screens; top.sort(sortVertical); for(var i:int = 0; i < top.length - 1; i++){ if(top[i].bounds.top < stage.nativeWindow.bounds.top){ stage.nativeWindow.x += top[i].bounds.left - currentScreen.bounds.left; stage.nativeWindow.y += top[i].bounds.top - currentScreen.bounds.top; break; } } } private function moveDown():void{ var currentScreen:Screen = getCurrentScreen(); var top:Array = Screen.screens; top.sort(sortVertical); for(var i:int = top.length - 1; i > 0; i--){ if(top[i].bounds.top > stage.nativeWindow.bounds.top){ stage.nativeWindow.x += top[i].bounds.left - currentScreen.bounds.left; stage.nativeWindow.y += top[i].bounds.top - currentScreen.bounds.top; break; } } } private function sortHorizontal(a:Screen,b:Screen):int{ if (a.bounds.left > b.bounds.left){ return 1; } else if (a.bounds.left < b.bounds.left){ return -1; } else {return 0;} } private function sortVertical(a:Screen,b:Screen):int{ if (a.bounds.top > b.bounds.top){ return 1; } else if (a.bounds.top < b.bounds.top){ return -1; } else {return 0;} } private function getCurrentScreen():Screen{ var current:Screen; var screens:Array = Screen.getScreensForRectangle(stage.nativeWindow.bounds); (screens.length > 0) ? current = screens[0] : current = Screen.mainScreen; return current; } } }

67

Chapter 8: Working with native menus


Use the classes in the Native Menu API to define application, window, context, and pop-up menus.
GETTING STARTED

AIR menu basics on page 67 Adding native menus to an AIR application on page 12

DEVELOPMENT TASKS

Creating native menus on page 71

LANGUAGE REFERENCE

NativeMenu NativeMenuItem

MORE INFORMATION

You may be able to find more information about working the AIR File API in the AIR Developer Center (http://www.adobe.com/devnet/air/flash/). Search the site using the keywords AIR menus.

AIR menu basics


The native menu classes allow you to access the native menu features of the operating system on which your application is running. NativeMenu objects can be used for application menus (available on OS X), window menus (available on Windows), context menus, and pop-up menus.

Types of menus
AIR supports the following types of menus:
Application menus Application menus can be accessed through the Shell class on operating systems that support them. On Mac OS X, an application menu is automatically provided by the operating system. Your application can use the AIR menu API to add items and submenu s to the standard menus as well as add handlers for the existing menu commands. You can also replace the standard menu entirely. Window menus Menus can be added to a window by creating a new NativeMenu object and assigning it to the
NativeWindow.menu property on operating systems that support them. Window menus are supported on the

Windows operating system, but not Mac OS X. Native menus can only be used for windows that have system chrome.
Context menus Context menus can be added to InteractiveObjects and document elements in an HTMLControl.

You would typically use the Webkit API for context menus on an HTML element, but you could also use a context menu directly on the HTMLControl and modify it based on the element which generated the open menu event.
Dock and system tray icon menus Menus can be added to the dock or system tray icons by creating a new NativeMenu object and assign it to the Shell.shell.icon.menu property. On Mac OS X, the new menu will be added above the standard items in the menu. On Windows, there is no default menu.

ADOBE PRODUCT X.0 68


User Guide

Custom menus Native menus are drawn by the operating system and as such exist outside the Flash and HTML rendering models. You are, of course, free to draw your own non-native menus. However, the AIR menu classes do not provide an owner draw facility.

Menu structure
A menu contains one or more menu items. A menu item can be a command, a submenu, or a separator. Normally, a menu item is a command. A menu item becomes a submenu when you assign a NativeMenu object to the submenu property of the item. A menu item becomes a separator when you set the isSeparator parameter of the item constructor to true. The root-level menu in the structure contains the submenu items that appear on the menu bar. Only submenu items should be added to the root menu of application and window menus. (Although some operating systems will display command items on the menu bar, putting commands directly on the menu bar is still unconventional.) Command and separator items can be used at the root level of pop-up and context menus. The following diagram illustrates the structure of a typical menu. The root menu contains submenu items for a File menu and an Edit menu. The File menu contains two commands and a submenu item for opening recent documents (which has a menu containing three items). The Edit menu contains three commands and a separator.

ADOBE PRODUCT X.0 69


User Guide

To view a code example that creates this menu see Example: Window and application menu.

Menu events
Menus and menu items both dispatch displaying and select events:
Displaying: Immediately before a menu is displayed, the menu and its menu items will dispatch a displaying event to any registered listeners. The displaying event gives you an opportunity to update the menu contents or item appearance before it is shown to the user. For example, in the handler for the displaying event of an Open Recent menu, you could change the menu items to reflect the current list of recently viewed documents.

ADOBE PRODUCT X.0 70


User Guide

The target property of the event object will always be the menu that is about to be displayed. The currentTarget will be the object on which the listener is registered, either the menu itself, or one of its items.
Select: When a command item is chosen by the user, the item will dispatch a select event to any registered listeners.

Submenu and separator items cannot be selected and so never dispatch a select event. Select events bubble up from items to their containing menu, on up to the root menu. You can listen for select events directly on an item and you can listen higher up in the menu structure. When you listen for the select event on a menu, you can identify the selected item using the event target property. As the event bubbles up through the menu hierarchy, the currentTarget property of the event object identifies the current menu object.

Mnemonics
Mnemonics are part of the operating system keyboard interface to menus. Both Mac OS X and Windows allow users to open menus and select commands with the keyboard, but there are subtle differences. On Mac OS X, the user types the first letter or two of the menu or command and then types return. On Windows, only a single letter is significant. By default, the significant letter is the first character in the label, but if you assign a mnemonic to the menu item, then the designated letter will become the significant character. If two items in a menu have the same significant character (whether or not a mnemonic has been assigned), then the users keyboard interaction with the menu changes slightly. Instead of pressing a single letter to select the menu or command, the user must press the letter as many times as necessary to highlight the desired item and then press the enter key to complete the selection. To maintain a consistent behavior, it is generally advisable to assign a unique mnemonic to each item in a menu for window menus. Specify the mnemonic character as an index into the label string. The index of the first character in a label is 0. Thus, to use r as the mnemonic for a menu item labeled, Format, you would set the mnemonicIndex property equal to 2.
var item:NativeMenuItem = new NativeMenuItem("Format"); item.mnemonicIndex = 2;

Note: If you are localizing the menu labels, be sure to update the mnemonic indexes as well as the label strings. (AIR does not provide built-in support for localization.)

Menu item state


Menu items have the two state properties, checked and enabled:
checked Set to true to display a check mark next to the item label.
var item:NativeMenuItem = new NativeMenuItem("Format"); item.checked = true;

enabled toggle the value between true and false to control whether the command is enabled. Disabled items are visually grayed-out and do not dispatch select events.
var item:NativeMenuItem = new NativeMenuItem("Format"); item.enabled = false;

Attaching an object to a menu item


The data property of the NativeMenuItem class allows you to reference an arbitrary object in each item. For example, in an Open Recent menu, you could assign the File object for each document to each menu item.
var file:File = new File("app-storage:/GreatGatsby.pdf"); var menuItem:NativeMenuItem = docMenu.addItem(new NativeMenuItem(file.name)); menuItem.data = file;

ADOBE PRODUCT X.0 71


User Guide

Creating native menus



Creating a new menu on page 71 Defining menu items, submenus, and separators on page 71 Creating a context menu on page 72 Displaying a pop-up menu on page 73 Handling menu events on page 73 Defining menus declaratively on page 73 Example: Window and application menu on page 74

Creating a new menu


To create a menu, create a new NativeMenu object to serve as the root of the menu:
var root:NativeMenu = new NativeMenu();

In the root menu of a window or application, all the items must be submenus. (The root of a context menu can contain all three types of menu items.) AIR provides two ways to create submenus. You can create the menu item and assign the submenu in one step with the addSubmenu() method:
var editMenu:NativeMenuItem = root.addSubmenu(new NativeMenu(), "Edit");

You can also create the menu item and assign the submenu separately:
var editMenu:NativeMenuItem = root.addItem("Edit"); editMenu.submenu = new NativeMenu();

After the menu is created, you can assign it as an application, window, icon, or context menu:
Setting the application menu: Shell.shell.menu = root; Setting a window menu: nativeWindowObject.menu = root; Setting a context menu interactiveObject.contextMenu = root; Setting a dock icon menu DockIcon(Shell.shell.icon).menu = root; Setting a system tray icon menu SystemTrayIcon(Shell.shell.icon).menu = root;

Defining menu items, submenus, and separators


A menu item can be a command, a submenu, or a separator. A menu item becomes a separator if you set the isSeparator parameter to true in the item constructor. An item is a submenu if you assign a NativeMenu object to its submenu property (or create the item using the addSubmenu() method). Otherwise, the item is a command. Only command items will dispatch select events. Items appear in the menu in the order in which they are added, unless you add the items at a specific index, for example by using the addItemAt() method of a menu object.

ADOBE PRODUCT X.0 72


User Guide

Creating a command: var copy:NativeMenuItem = new NativeMenuItem("Copy",false); copy.addEventListener(Event.SELECT,onCopyCommand); editMenu.addItem(copy); Creating a submenu: var editMenu:NativeMenuItem = new NativeMenuItem("Edit", false); editMenu.submenu = new NativeMenu();

You can also create an item and its submenu in one step using the parent menus addSubmenu() method:
var editMenu:NativeMenuItem = root.addSubmenu(new NativeMenu(), "Edit"); Creating a separator: var separatorA:NativeMenuItem = new NativeMenuItem("A", true); editMenu.addItem(separatorA);

Creating a context menu


In AIR, the ContextMenu API classes inherit from the NativeMenu classes. The ContextMenu classes provide an event property, ContextMenuEvent.mouseTarget, that identifies the object that was clicked to open the menu. Context menus can be assigned to any Flash object that inherits from the InteractiveObject class. To assign a context menu to an object, set the contextMenu property. The root of a context menu can contain items for commands and separators in addition to submenus. There are no built-in items in an AIR context menu. The following example creates a simple edit context menu for an interactive object:
var editContextMenu:ContextMenu = new ContextMenu(); var item:NativeMenuItem; item = editContextMenu.addItem(new ContextMenuItem("Cut")); item.name="Cut"; editContextMenu.addItem(new ContextMenuItem("Copy")); item.name="Copy"; editContextMenu.addItem(new ContextMenuItem("Paste")); item.name="Paste"; editContextMenu.addEventListener(ContextMenuEvent.MENU_ITEM_SELECT, function(event:ContextMenuEvent):void{ var command:NativeMenuItem = event.target as NativeMenuItem; switch (command.name){ case "Cut" : doCutCommand(event.mouseTarget); break; case "Copy" : doCopyCommand(event.mouseTarget); break; case "Paste" : doPasteCommand(event.mouseTarget); break; } }); this.contextMenu = editContextMenu; //Where "this" is an InteractiveObject

ADOBE PRODUCT X.0 73


User Guide

Displaying a pop-up menu


You can display a pop-up menu at an arbitrary time and location above a window, by calling the menu display() method. The following method displays a menu defined by a popupMenu object in response to a mouse click:
private function onMouseClick(event:MouseEvent):void{ popupMenu.display(event.target.stage, event.stageX, event.stageY); }

Note: The menu does not need to be displayed in response to an event. Any method can call the display() function.

Handling menu events


When a menu item is clicked, an event is dispatched. An AIR application responds to a users selection by adding listeners to NativeMenuItem instances. The following code traces the name of the menu item that was activated:
var submenu:NativeMenu = new NativeMenu(); var red:NativeMenuItem = new NativeMenuItem("Red"); red.addEventListener(Event.SELECT,announceSelection) var green:NativeMenuItem = new NativeMenuItem("Green"); green.addEventListener(Event.SELECT,announceSelection) var blue:NativeMenuItem = new NativeMenuItem("Blue"); blue.addEventListener(Event.SELECT,announceSelection) var menuItem:NativeMenuItem = new NativeMenuItem("Change Color"); submenu.addItem(red); submenu.addItem(green); submenu.addItem(blue); menuItem.submenu = submenu; Shell.shell.menu.addItem(menuItem); function announceSelection(e:Event):void { var menuItem:NativeMenuItem = e.target as NativeMenuItem; trace(menuItem.label + has been selected) }

Note: As an alternative to listening for select events on each item in a menu, you can listen for select events on a menu or submenu and use the target property of the event object to get the NativeMenuItem object for the selected menu command.

Defining menus declaratively


Coding the properties of a menu and menu items can be a bit tedious. However, since menus have a natural hierarchical structure, it is straightforward to write a function that creates a menu using an XML-formatted definition. The following class extends NativeMenu, taking an XML object in its constructor, to do just that:
package { import flash.display.NativeMenu; import flash.display.NativeMenuItem; import flash.events.Event; public class DeclarativeMenu extends NativeMenu { public function DeclarativeMenu(XMLMenuDefinition:XML):void{ super(); addChildrenToMenu(this, XMLMenuDefinition.children()); }

ADOBE PRODUCT X.0 74


User Guide

private function addChildrenToMenu(menu:NativeMenu, children:XMLList):NativeMenuItem{ var menuItem:NativeMenuItem; var submenu:NativeMenu; for each (var child:XML in children){ if(String(child.@label).length > 0){ menuItem = new NativeMenuItem(child.@label); menuItem.name = child.name(); } else { menuItem = new NativeMenuItem(child.name()); menuItem.name = child.name(); } menu.addItem(menuItem); if(child.children().length() > 0){ menuItem.submenu = new NativeMenu(); addChildrenToMenu(menuItem.submenu,child.children()); } } return menuItem; } }//End class }//End package

To create a menu with this class, pass an XML menu definition as follows:
var menuDefinition:String = "<root>" + "<FileMenu label='File'>" + "<NewMenu label='New'>" + "<NewTextFile label='Text file'/>" + "<NewFolder label='Folder'/>" + "<NewProject label='Project'/>" + "</NewMenu>" + "<OpenCommand label='Open'/>" + "<SaveCommand label='Save'/>" + "</FileMenu>" + "<EditMenu label='Edit'/>" + "<CutCommand label='Cut'/>" + "<CopyCommand label='Copy'/>" + "<PasteCommand label='Paste'/>" + "<EditMenu/>" + "<FoodItems label='Food Items'>" + "<Jellyfish/>" + "<Tripe/>" + "<Gizzard/>" + "</FoodItems>" + "</root>"; var test:DeclarativeMenu = new DeclarativeMenu(new XML(menuDefinition));

To listen for menu events, you could listen at the root menu level and use the event.target.name property to detect which command was selected. You could also look up items in the menu by name and add individual event listeners.

Example: Window and application menu


The following example creates the menu shown in Menu structure.

ADOBE PRODUCT X.0 75


User Guide

The menu is designed to work both under Windows, for which only window menus are supported, and under Mac OS X, for which only application menus are supported. To make the distinction, the MenuExample class constructor checks the static supportsMenu properties of the NativeWindow and Shell classes. If NativeWindow.supportsMenu is true, then the constructor creates a new NativeMenu object for the window and then creates and adds the File and Edit submenus. If Shell.supportsMenu is true, then the constructor creates and adds the File and Edit menus to the existing menu provided by the OS X operating system. The example also illustrates menu event handling. The select event is handled at the item level and also at the menu level. Each menu in the chain from the menu containing the selected item to the root menu will respond to the selection event. The displaying event is used with the Open Recent menu. Just before the menu is opened, the items in the menu are refreshed from the recent Documents array (which doesnt actually change in this example). Although not shown in this example, you can also listen for displaying events on individual items.
package { import import import import import import import flash.display.NativeMenu; flash.display.NativeMenuItem; flash.display.NativeWindow; flash.display.Sprite; flash.events.Event; flash.filesystem.File; flash.system.Shell;

public class MenuExample extends Sprite { private var recentDocuments:Array = new Array(new File("c:/GreatGatsby.pdf"), new File("c:/WarAndPeace.pdf"), new File("c:/Iliad.pdf")); public function MenuExample() { var fileMenu:NativeMenuItem; var editMenu:NativeMenuItem; if(NativeWindow.supportsMenu){ stage.nativeWindow.menu = new NativeMenu(); stage.nativeWindow.menu.addEventListener(Event.SELECT, selectCommandMenu); fileMenu = stage.nativeWindow.menu.addItem(new NativeMenuItem("File")); fileMenu.submenu = createFileMenu(); editMenu = stage.nativeWindow.menu.addItem(new NativeMenuItem("Edit")); editMenu.submenu = createEditMenu(); } if(Shell.supportsMenu){ Shell.shell.menu.addEventListener(Event.SELECT, selectCommandMenu); fileMenu = Shell.shell.menu.addItem(new NativeMenuItem("File")); fileMenu.submenu = createFileMenu(); editMenu = Shell.shell.menu.addItem(new NativeMenuItem("Edit")); editMenu.submenu = createEditMenu(); } } public function createFileMenu():NativeMenu{ var fileMenu:NativeMenu = new NativeMenu(); fileMenu.addEventListener(Event.SELECT,selectCommandMenu); var newCommand:NativeMenuItem = fileMenu.addItem(new NativeMenuItem("New")); newCommand.addEventListener(Event.SELECT,selectCommand); var saveCommand:NativeMenuItem = fileMenu.addItem(new NativeMenuItem("Save")); saveCommand.addEventListener(Event.SELECT,selectCommand); var openRecentMenu:NativeMenuItem =

ADOBE PRODUCT X.0 76


User Guide

fileMenu.addItem(new NativeMenuItem("Open Recent")); openRecentMenu.submenu = new NativeMenu(); openRecentMenu.submenu.addEventListener(Event.DISPLAYING, updateRecentDocumentMenu); openRecentMenu.submenu.addEventListener(Event.SELECT,selectCommandMenu); return fileMenu; } public function createEditMenu():NativeMenu{ var editMenu:NativeMenu = new NativeMenu(); editMenu.addEventListener(Event.SELECT,selectCommandMenu); var copyCommand:NativeMenuItem = editMenu.addItem(new NativeMenuItem("Copy")); copyCommand.addEventListener(Event.SELECT,selectCommand); var pasteCommand:NativeMenuItem = editMenu.addItem(new NativeMenuItem("Paste")); pasteCommand.addEventListener(Event.SELECT,selectCommand); editMenu.addItem(new NativeMenuItem("",true)); var preferencesCommand:NativeMenuItem = editMenu.addItem(new NativeMenuItem("Preferences")); preferencesCommand.addEventListener(Event.SELECT,selectCommand); return editMenu; } private function updateRecentDocumentMenu(event:Event):void{ trace("Updating recent document menu."); var docMenu:NativeMenu = NativeMenu(event.target); for each(var item:NativeMenuItem in docMenu.items){ docMenu.removeItem(item); } for each(var file:File in recentDocuments){ var menuItem:NativeMenuItem = docMenu.addItem(new NativeMenuItem(file.name)); menuItem.data = file; menuItem.addEventListener(Event.SELECT, selectRecentDocument); } } private function selectRecentDocument(event:Event):void{ trace("Selected recent document: " + event.target.data.name); } private function selectCommand(event:Event):void{ trace("Selected command: " + event.target.label); } private function selectCommandMenu(event:Event):void{ if(event.currentTarget.parent){ var menuItem:NativeMenuItem = findItemForMenu(NativeMenu(event.currentTarget)); if(menuItem){ trace("Select event for \"" + event.target.label + "\" command handled by menu: " + menuItem.label); } } else {

ADOBE PRODUCT X.0 77


User Guide

trace("Select event for \"" + event.target.label + "\" command handled by root menu."); } } private function findItemForMenu(menu:NativeMenu):NativeMenuItem{ for each(var item:NativeMenuItem in menu.parent.items){ if(item){ if(item.submenu == menu){ return item; } } } return null; } } }

78

Part 1: Working with files and data


Working with the file system. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .79 Drag and Drop. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .102 Copy and Paste . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .1 Working with local SQL databases . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .1

79

Chapter 10: Working with the file system


You use the classes provided by the Adobe AIR file system API to access the file system of the host computer. Using these classes, you can access and manage directories and files, create directories and files, write data to files, and so on. Information on understanding and using the File API classes is available in the following categories:
GETTING STARTED

AIR file basics on page 79 Building a text-file editor on page 8

DEVELOPMENT TASKS

Working with File objects on page 80 Working with directories on page 86 Working with files on page 88 Using the encrypted local store on page 100

LANGUAGE REFERENCE

File FileStream FileMode

MORE INFORMATION

You may be able to find more information about working the AIR File API in the AIR Developer Center (http://www.adobe.com/devnet/air/flash/). Search the site using the keywords AIR filesystem.

AIR file basics


Adobe AIR provides classes that you can use to access, create, and manage both files and folders. These classes, contained in the flash.filesystem package, are used as follows:
File A File object represents a path to a file or directory. You use a file object to create a pointer to a file or folder,

initiating interaction with the file or folder.


FileMode The FileMode class defines string constants used in the fileMode parameter of the open() and
openAsync() methods of the FileStream class. The fileMode parameter of these methods determines the capabilities available to the FileStream object once the file is opened, which include writing, reading, appending, and updating.

FileStream A FileStream object is used to open files for reading and writing. Once youve created a File object that

points to a new or existing file, you pass that pointer to the FileStream object so that you can open and then manipulate data within the file. Some methods in the File class have both synchronous and asynchronous versions:

File.copyTo() and File.copyToAsync()

ADOBE PRODUCT X.0 80


User Guide

File.deleteDirectory() and File.deleteDirectoryAsync() File.deleteFile() and File.deleteFileAsync() File.getDirectoryListing() and File.getDirectoryListingAsync() File.moveTo() and File.moveToAsync() File.moveToTrash() and File.moveToTrashAsync()

Also, FileStream operations work synchronously or asynchronously depending on how the FileStream object opens the file: by calling the open() or by calling openAsync() method. The asynchronous versions let you initiate processes that run in the background and dispatch events when complete (or when error events occur). Other code can execute while these asynchronous background processes are taking place. With asynchronous versions of the operations, you need to set up event listener functions, using the addEventListener() method of the File or FileStream object that calls the function. The synchronous versions let you write simpler code that does not rely on setting up event listeners. However, since other code cannot execute while a synchronous method is executing, important processes, such as display object rendering and animation, may be paused.

Working with File objects


The File object is a pointer to a file or directory in the file system. The File class extends the FileReference class. The FileReference class, which is available in Flash Player as well as AIR, represents a pointer to a file, but the File class adds properties and methods that are not exposed in Flash Player (in a SWF running in a browser), due to security considerations. You can use the File class for the following:

Getting the path to special directories, including the user directory, the user's documents directory, the directory from which the application was launched, and the application directory
Coping files and directories Moving files and directories Deleting files and directories (or moving them to the trash) Listing files and directories contained in a directory Creating temporary files and folders

Once a File object points to a file path, you can use it to read and write files, using the FileStream class. A File object can point to the path of a file or directory that does not yet exist. You can use such a File object in creating a new file or directory.

Paths of File objects


Each File object has two properties that each define its path:
nativePath This specifies the platform-specific path to a file. For example, on Windows a path might be "c:\Sample

directory\test.txt" whereas on Mac OS it could be "/Sample directory/test.txt". Note that a nativePath property uses the backslash (\) character as the directory separator character on Windows, and it uses the forward slash (/) character on Mac OS.

ADOBE PRODUCT X.0 81


User Guide

url This may use the file URL scheme to point to a file. For example, on Windows a path might be

"file:///c:/Sample%20directory/test.txt" whereas on Mac OS it could be "file:///Sample%20directory/test.txt". The runtime includes other special URL schemes besides file, and these are described in Supported URL schemes on page 84. The File class includes properties for pointing to standard directories on both Mac and Windows, and these are described in the following section.

Pointing a File object to a directory


There are a number of ways to set a File object to point to a directory.
Pointing to an explicit directory

You can point a File object to the user's home directory. On Windows, the home directory is the parent of the "My Documents" directory (for example, "C:\Documents and Settings\userName\My Documents"). On Mac OS, it is the Users/userName directory. The following code sets a File object to point to an AIR Test subdirectory of the home directory:
var file:File = File.userDirectory.resolvePath("AIR Test");

You can point a File object to the user's documents directory. On Windows, this is typically the "My Documents" directory (for example, "C:\Documents and Settings\userName\My Documents"). On Mac OS, it is the Users/userName/Documents directory. The following code sets a File object to point to an AIR Test subdirectory of the documents directory:
var file:File = File.documentsDirectory.resolvePath("AIR Test");

You can point a File object to the desktop. The following code sets a File object to point to an AIR Test subdirectory of the desktop:
var file:File = File.desktopDirectory.resolvePath("AIR Test");

You can point a File object to the application storage directory. For every AIR application, there is a unique associated path that defines the application store directory. You may want to use this directory to store application-specific data (such as user data or preferences files). For example, the following code points a File object to a preferences file, prefs.xml, contained in the application storage directory:
var file:File = File.applicationStorageDirectory; file = file.resolvePath("prefs.xml");

You can point a File object to the directory in which the application was installed, known as the application resource directory. You can reference this directory using the File.applicationResourceDirectory property. You may use this directory to examine the application descriptor file or other resources installed with the application. For example, the following code points a File object to a directory named images in the application resource directory:
var file:File = File.applicationResourceDirectory; file = file.resolvePath("images");

The File.getRootDirectories() method lists all root volumes, such as C: and mounted volumes, on a Windows computer. On Mac, this method always returns the unique root directory for the machine (the "/" directory). You can point the File object to an explicit directory by setting the nativePath property of the File object, as in the following example (on Windows):
var file:File = new File();

ADOBE PRODUCT X.0 82


User Guide

file.nativePath = "C:\\AIR Test\\";

You can use the resolvePath() method to obtain a path relative to another given path. For example, the following code sets a File object to point to an "AIR Test" subdirectory of the user's home directory:
var file:File = File.userDirectory; file = file.resolvePath("AIR Test");

You can also use the url property of a File object to point it to a directory based on a URL string, as in the following:
var urlStr:String = "file:///C:/AIR Test/"; var file:File = new File() file.url = urlStr;

You can also use the nativePath property of a File object to set an explicit path. For example, the following code, when run on a Windows computer, sets a File object to the AIR Test subdirectory of the C: drive:
var file:File = new File(); file.nativePath = "C:\\AIR Test";

For more information, see Modifying File paths on page 84. You can get the directory location from which an application is invoked, by checking the currentDirectory property of the InvokeEvent object dispatched when the application is invoked. For details, see Capturing command line arguments on page 146.
Letting the user browse to select a directory

The File class includes the browseForDirectory() method, which presents a system dialog box in which the user can select a directory to assign to the object. The browseForDirectory() method is asynchronous; it dispatches a select event, if the user selects a directory and clicks the Open button, or it dispatches a cancel event if the user clicks the Cancel button. For example, the following code lets the user select a directory and outputs the directory path upon selection:
var file:File = new File(); file.addEventListener(Event.SELECT, dirSelected); file.browseForDirectory(); function dirSelected(e:Event):void { trace(file.nativePath); }

Pointing a File object to a file


There are a number of ways to set the file to which a File object points.
Pointing to an explicit file path

You can use the resolvePath() method to obtain a path relative to another given path. For example, the following code sets a File object to point to a log.txt file within the application storage directory:
var file:File = File.applicationStorageDirectory; file = file.resolvePath("log.txt");

You can use the url property of a File object to point it to a file or directory based on a URL string, as in the following:
var urlStr:String = "file:///C:/AIR Test/test.txt"; var file:File = new File() file.url = urlStr;

ADOBE PRODUCT X.0 83


User Guide

You can also pass the URL to the File() constructor function, as in the following:
var urlStr:String = "file:///C:/AIR Test/test.txt"; var file:File = new File(urlStr);

Note that url property always returns the URI-encoded version of the URL (for example, blank spaces are replaced with "%20):
file.url = "file:///c:/AIR Test"; trace(file.url); // file:///c:/AIR%20Test

You can also use the nativePath property of a File object to set an explicit path. For example, the following code, when run on a Windows computer, sets a File object to the test.txt file in the AIR Test subdirectory of the C: drive:
var file:File = new File(); file.nativePath = "C:/AIR Test/test.txt";

You can also pass this path to the File() constructor function, as in the following:
var file:File = new File("C:/AIR Test/test.txt");

On Windows you can use the forward slash (/) or backslash (\) character as the path delimiter for the nativePath property. On Mac OS, use the forward slash (/) character as the path delimiter for the nativePath :
var file:File = new File(/Users/dijkstra/AIR Test/test.txt");

For more information, see Modifying File paths on page 84.


Enumerating files in a directory

You can use the getDirectoryListing() method of a File object to get an array of File objects pointing to files and subdirectories at the root level of a directory. For more information, see Enumerating directories on page 86.
Letting the user browse to select a file

The File class includes the following methods that present a system dialog box in which the user can select a file to assign to the object:

browseForOpen() browseForSave() browseForMultiple() For example, the following code presents the user with an Open dialog box in which the user can select a file.
var fileToOpen:File = File.documentsDirectory; selectTextFile(fileToOpen); function selectTextFile(root:File):void { var txtFilter:FileFilter = new FileFilter("Text", "*.as;*.css;*.html;*.txt;*.xml"); root.browseForOpen("Open", [txtFilter]); root.addEventListener(Event.SELECT, fileSelected); } function fileSelected(event:Event):void { trace(fileToOpen.nativePath); }

If the application has another browser dialog box open when you call a browse method, the runtime throws an error.

ADOBE PRODUCT X.0 84


User Guide

Modifying File paths


You can also modify the path of an existing File object by calling the resolvePath() method or by modifying the nativePath or url property of the object, as in the following examples (on Windows):
var file1:File = File.documentsDirectory; file1 = file1.resolvePath("AIR Test"); trace(file1.nativePath); // C:\Documents and Settings\userName\My Documents\AIR Test var file2:File = File.documentsDirectory; file2 = file2.resolvePath(".."); trace(file2.nativePath); // C:\Documents and Settings\userName var file3:File = File.documentsDirectory; file3.nativePath += "/subdirectory"; trace(file3.nativePath); // C:\Documents and Settings\userName\My Documents\subdirectory var file4:File = new File(); file.url = "file:///c:/AIR Test/test.txt" trace(file3.nativePath); // C:\AIR Test\test.txt

When using the nativePath property, you use either the forward slash (/) or backslash (\) character as the directory separator character on Windows; use the forward slash (/) character on Mac OS. On Windows, remember to type the backslash character twice in a string literal.

Supported URL schemes


You can use any of the following URL schemes in defining the url property of a File object:
file Use this to specify a path relative to the root of the file system. For example: file:///c:/AIR Test/test.txt app-resource Use this to specify a path relative to the root directory of the installed application (the directory that

contains the application.xml file for the installed application). For example, the following path points to an images subdirectory of the directory of the installed application:
app-resource:/images app-storage Use this to specify a path relative to the application store directory. For each installed application, AIR

defines a unique application store directory, which is a useful place to store data specific to that application. For example, the following path points to a prefs.xml file in a settings subdirectory of the application store directory:
app-storage:/settings/prefs.xml

Finding the relative path between two files


You can use the getRelativePath() method to find the relative path between two files:
var file1:File = File.documentsDirectory.resolvePath("AIR Test"); var file2:File = File.documentsDirectory file2 = file2.resolvePath("AIR Test/bob/test.txt"); trace(file1.getRelativePath(file2)); // bob/test.txt

The second parameter of the getRelativePath() method, the useDotDot parameter, allows for .. syntax to be returned in results, to indicate parent directories:
var file1:File = File.documentsDirectory; file1 = file1.resolvePath("AIR Test"); var file2:File = File.documentsDirectory; file2 = file2.resolvePath("AIR Test/bob/test.txt");

ADOBE PRODUCT X.0 85


User Guide

var file3:File = File.documentsDirectory; file3 = file3.resolvePath("AIR Test/susan/test.txt"); trace(file2.getRelativePath(file1, true)); // ../.. trace(file3.getRelativePath(file2, true)); // ../../bob/test.txt

Obtaining canonical versions of file names


File and path names are usually not case sensitive. In the following, two File objects point to the same file:
File.documentsDirectory.resolvePath("test.txt"); File.documentsDirectory.resolvePath("TeSt.TxT");

However, documents and directory names do include capitalization. For example, the following assumes that there is a folder named AIR Test in the documents directory, as in the following examples:
var file:File = File.documentsDirectory.resolvePath("AIR test"); trace(file.nativePath); // ... AIR test file.canonicalize(); trace(file.nativePath); // ... AIR Test

The canonicalize method converts the nativePath object to use the correct capitalization for the file or directory name. You can also use the canonicalize() method to convert short file names ("8.3" names) to long file names on Windows, as in the following examples:
var path:File = new File(); path.nativePath = "C:\\AIR~1"; path.canonicalize(); trace(path.nativePath); // C:\AIR Test

Getting file system information


The File class includes the following static properties that provide some useful information about the file system:
File.lineEnding The line-ending character sequence used by the host operating system. On Mac OS, this is the

line-feed character. On Windows, this is the carriage return character followed by the line-feed character.
File.separator The host operating system's path component separator character. On Mac OS, this is the forward

slash (/) character. On Windows, it is the backslash (\) character. The Capabilities class also includes useful system information that may be useful when working with files:
File.systemCharSet The default encoding used for files by the host operating system. This pertains to the character set used by the operating system, corresponding to its language. Capabilities.hasIME Specifies whether the player is running on a system that does (true) or does not (false)

have an input method editor (IME) installed.


Capabilities.language Specifies the language code of the system on which the player is running. Capabilities.os Specifies the current operating system.

ADOBE PRODUCT X.0 86


User Guide

Working with directories


The runtime provides you with capabilities to work with directories on the local file system. For details on creating File objects that point to directories, see Pointing a File object to a directory on page 81. Using the File API, you can accomplish the following tasks:

Creating directories on page 86 Creating a temporary directory on page 86 Enumerating directories on page 86 Copying and moving directories on page 87 Deleting directory contents on page 87

Creating directories
The File.createDirectory() method lets you create a directory. For example, the following code creates a directory named AIR Test as a subdirectory of the user's home directory:
var dir:File = File.userDirectory.resolvePath("AIR Test"); dir.createDirectory();

If the directory already exists, the createDirectory() method does nothing. Also, in some modes, a FileStream object will create directories when opening files. Missing directories are created when you instantiate a FileStream instance with the fileMode parameter of the FileStream() constructor set to FileMode.APPEND or FileMode.WRITE. For more information, see Workflow for reading and writing files on page 90.

Creating a temporary directory


The File class includes a createTempDirectory() method, which creates a new directory in the temporary directory folder for the System, as in the following example:
var temp:File = File.createTempDirectory();

The createTempDirectory() method automatically creates a unique temporary directory (saving you the work of determining a new unique location). You may use a temporary directory to temporarily store temporary files used for a session of the application. Note that there is a createTempFile() method, for creating new, unique temporary files in the System temporary directory. You may want to delete the temporary directory before closing the application, as it is not automatically deleted.

Enumerating directories
You can use the getDirectoryListing() method or the getDirectoryListingAsync() method of a File object to get an array of File objects pointing to files and subfolders in a directory. For example, the following code lists the contents of the user's documents directory (without examining subdirectories):
var directory:File = File.documentsDirectory;

ADOBE PRODUCT X.0 87


User Guide

var contents:Array = directory.getDirectoryListing(); for (var i:uint = 0; i < contents.length; i++) { trace(contents[i].name, contents[i].size); }

When using the asynchronous version of the method, the directoryListing event object has a files property that is the array of File objects pertaining to the directories:
var directory:File = File.documentsDirectory; directory.getDirectoryListingAsync(); directory.addEventListener(FileListEvent.DIRECTORY_LISTING, dirListHandler); function dirListHandler(event:FileListEvent):void { var contents:Array = event.files; for (var i:uint = 0; i < contents.length; i++) { trace(contents[i].name, contents[i].size); } }

Copying and moving directories


You can copy or move a directory, using the same methods as you would to copy or move a file. For example, the following code copies a directory synchronously:
var sourceDir:File = File.documentsDirectory.resolvePath("AIR Test"); var resultDir:File = File.documentsDirectory.resolvePath("AIR Test Copy"); sourceDir.copyTo(resultDir);

Note that when you specify true for the overwrite parameter of the copyTo() method, all files and folders in an existing target directory are deleted and replaced with the files and folders in the source directory (even if the target file does not exist in the source directory). For details, see Copying and moving files on page 89.

Deleting directory contents


The File class includes a deleteDirectory() method and a deleteDirectoryAsync() method. These both delete directories, the first working synchronously, the second working asynchronously (see AIR file basics on page 79). Both methods include a deleteDirectoryContents parameter (which takes a Boolean value); when this parameter is set to true (the default value is false) the call to the method deletes non-empty directories. For example, the following code synchronously deletes the AIR Test subdirectory of the user's documents directory:
var directory:File = File.documentsDirectory.resolvePath("AIR Test"); directory.deleteDirectory(true);

The following code asynchronously deletes the AIR Test subdirectory of the user's documents directory:
var directory:File = File.documentsDirectory.resolvePath("AIR Test"); directory.addEventListener(Event.COMPLETE, completeHandler) directory.deleteDirectoryAsync(true); function completeHandler(event:Event):void { trace("Deleted.") }

ADOBE PRODUCT X.0 88


User Guide

Also included are the moveToTrash() and moveToTrashAsync methods, which you can use to move a directory to the System trash. For details, see Moving a file to the trash on page 90.

Working with files


Using the AIR file API, you can add basic file interaction capabilities to your applications. For example, you can read and write files, copy and delete files, and so on. Since your applications can access the local file system, you should refer to Introducing Adobe AIR on page 9, if you haven't already done so. Note: You can associate a file type with an AIR application (so that double-clicking it opens the application). For details, see Registering file types on page 148. Using the File API, you can accomplish the following tasks:

Getting file information on page 88 Copying and moving files on page 89 Deleting a file on page 89 Moving a file to the trash on page 90 Creating a temporary file on page 90

Getting file information


The File class includes the following properties that provide information about a file or directory to which a File object points:
File property Description The creation date of the file on the local disk. Obsoleteuse the extension property. (This property reports the Macintosh creator type of the file, which is only used in Mac OS versions prior to Mac OS X.) Whether the referenced file or directory exists. The file extension, which is the part of the name following (and not including) the final dot ("."). If there is no dot in the filename, the extension is null. An Icon object containing to the icons defined for the file. Whether the File object reference is to a directory. The date that the file on the local disk was last modified. The name of the file on the local disk. The full path in the host operating system representation. See Paths of File objects on page 80. The folder that contains the folder or file represented by the File object. This property is null if the File object references a file or directory in the root of the filesystem. The size of the file on the local disk in bytes. Obsoleteuse the extension property. (On the Macintosh, this property is the four-character file type, which is only used in Mac OS versions prior to Mac OS X.) The URL for the file or directory. See Paths of File objects on page 80.

creationDate creator

exists extension

icon isDirectory modificationDate name nativePath parent

size type

url

ADOBE PRODUCT X.0 89


User Guide

For details on these properties, see the File class entry in the ActionScript 3.0 Language Reference.

Copying and moving files


The File class includes two methods for copying files or directories: copyTo() and copyToAsync(). The File class includes two methods for moving files or directories: moveTo() and moveToAsync(). The copyTo() and moveTo() methods work synchronously, and the copyToAsync() and moveToAsync() methods work asynchronously (see AIR file basics on page 79). To copy or move a file, you set up two File objects. One points to the file to copy or move, and it is the object that calls the copy or move method, the other points to the destination (result) path. The following copies a test.txt file from the AIR Test subdirectory of the user's documents directory to a file named copy.txt in the same directory:
var original:File = File.documentsDirectory.resolvePath("AIR Test/test.txt"); var newFile:File = File.resolvePath("AIR Test/copy.txt"); original.copyTo(newFile, true);

Note that in this example, the value of overwrite parameter of the copyTo() method (the second parameter) is set to true. By setting this to true, an existing target file is overwritten. This parameter is optional. If you set it to false (the default value), the operation dispatches an IOErrorEvent event if the target file already exists (and the file is not copied). The Async versions of the copy and move methods work asynchronously. Use the addEventListener() method to monitor completion of the task or error conditions, as in the following code:
var original = File.documentsDirectory; original = original.resolvePath("AIR Test/test.txt"); var destination:File = File.documentsDirectory; destination = destination.resolvePath("AIR Test 2/copy.txt"); original.addEventListener(Event.COMPLETE, fileMoveCompleteHandler); original.addEventListener(IOErrorEvent.IO_ERROR, fileMoveIOErrorEventHandler); original.moveToAsync(destination); function fileMoveCompleteHandler(event:Event):void { trace(event.target); // [object File] } function fileMoveIOErrorEventHandler(event:IOErrorEvent):void { trace("I/O Error."); }

The File class also includes the File.moveToTrash() and File.moveToTrashAsync() methods, which move a file or directory to the system trash.

Deleting a file
The File class includes a deleteFile() method and a deleteFileAsync() method. These both delete files, the first working synchronously, the second working asynchronously (see AIR file basics on page 79). For example, the following code synchronously deletes the test.txt file in the user's documents directory:
var directory:File = File.documentsDirectory.resolvePath("test.txt"); directory.deleteFile();

ADOBE PRODUCT X.0 90


User Guide

The following code asynchronously deletes the test.txt subdirectory of the user's documents directory:
var file:File = File.documentsDirectory.resolvePath("test.txt"); file.addEventListener(Event.COMPLETE, completeHandler) file.deleteFileAsync(); function completeHandler(event:Event):void { trace("Deleted.") }

Also included are the moveToTrash() and moveToTrashAsync methods, which you can use to move a file or directory to the System trash. For details, see Moving a file to the trash on page 90.

Moving a file to the trash


The File class includes a moveToTrash() method and a moveToTrashAsync() method. These both send a file or directory to the System trash, the first working synchronously, the second working asynchronously (see AIR file basics on page 79). For example, the following code synchronously moves the test.txt file in the user's documents directory to the System trash:
var file:File = File.documentsDirectory.resolvePath("test.txt"); file.moveToTrash();

Creating a temporary file


The File class includes a createTempFile() method, which creates a new file in the temporary directory folder for the System, as in the following example:
var temp:File = File.createTempFile();

The createTempFile() method automatically creates a unique temporary file (saving you the work of determining a new unique location). You may use a temporary file to temporarily store information used in a session of the application. Note that there is also a createTempDirectory() method, for creating a new, unique temporary directory in the System temporary directory. You may want to delete the temporary file before closing the application, as it is not automatically deleted.

Workflow for reading and writing files


The FileStream class lets AIR applications read and write to the file system. The workflow for reading and writing files is as follows.
1. Initialize a File object that points to the path.

This is the path of the file that you want to work with (or a file that you will later create).
var file:File = File.documentsDirectory; file = file.resolvePath("AIR Test/testFile.txt");

This example uses the File.documentsDirectory property and the resolvePath() method of a File object to initialize the File object. However, there are many other ways to point a File object to a file. For more information, see Pointing a File object to a file on page 82.

ADOBE PRODUCT X.0 91


User Guide

2. Initialize a FileStream object. 3. Call the open() method or the openAsync() method.

The method you call depends on whether you want to open the file for synchronous or asynchronous operations. Use the File object as the file parameter of the open method. For the fileMode parameter, specify a constant from the FileMode class that specifies the way in which you will use the file. For example, the following code initializes a FileStream object that will be used to create a file and overwrite any existing data:
var fileStream:FileStream = new FileStream(); fileStream.open(file, FileMode.WRITE);

For more information, see Initializing a FileStream object, and opening and closing files on page 92 and FileStream open modes on page 92.
4. If you opened the file asynchronously (using the openAsync() method), add and set up event listeners for the FileStream object.

These event listener methods will respond to events dispatched by the FileStream object in a variety of situations, such as when data is read in from the file, when I/O errors are encountered, or when the complete amount of data to be written has been written. For details, see Asynchronous programming and the events generated by a FileStream object opened asynchronously on page 96.
5. Include code for reading and writing data, as needed.

There are a number of methods of the FileStream class related to reading and writing. (They each begin with "read" or "write".) The method you choose to use to read or write data depends on the format of the data in the target file. For example, if the data in the target file is UTF-encoded text, you may use the readUTFBytes() and writeUTFBytes() methods. If you want to deal with the data as byte arrays, you may use the readByte(), readBytes(), writeByte(), and writeBytes() methods. For details, see Data formats, and choosing the read and write methods to use on page 96.
6. Call the close() method of the FileStream object when you are done working with the file.

This makes the file available to other applications. For details, see Initializing a FileStream object, and opening and closing files on page 92. The sections that follow provide more details on using the AIR file APIs to read and write files. For examples of using FileStream object to read and write files, see the following topics:

Building a text-file editor on page 9 Reading and writing from an XML preferences file on page 17 Building a directory search application on page 13

Working with FileStream objects


This section contains the following topics:

FileStream open modes

ADOBE PRODUCT X.0 92


User Guide

FileStream open modes The position property of a FileStream object The read buffer and the bytesAvailable property of a FileStream object Asynchronous programming and the events generated by a FileStream object opened asynchronously Data formats, and choosing the read and write methods to use

FileStream open modes

The open() and openAsync() method of a FileStream object each include a fileMode parameter, which defines a number of properties for a file stream, including the following:

The ability to read from the file The ability to write to the file Whether data will always be appended past the end of the file (when writing) What to do when the file does not exist (and when its parent directories do not exist)

The following table summarizes the various file modes (which you can specify as the fileMode parameter of the open() and openAsync() methods):
FileMode.READ Specifies that the file is open for reading only. FileMode.WRITE Specifies that the file is open for writing. If the file does not exist, it is created when the FileStream

object is opened. If the file does exist, any existing data is deleted.
FileMode.APPEND Specifies that the file is open for appending. The file is created if it does not exist. If the file

already exists, existing data is not overwritten, and all writing begins at the end of the file.
FileMode.UPDATE Specifies that the file is open for reading and writing. If the file does not exist, it is created.

Specify this mode for random read/write access to the file. You can read from any position in the file, and when writing to the file, only the bytes written overwrite existing bytes (all other bytes remain unchanged).
Initializing a FileStream object, and opening and closing files

When you open a FileStream object, you make it available to read and write data to a file. You open a FileStream object by passing a File object to the open() or openAsync() method of the FileStream object:
var myFile:File = File.documentsDirectory.resolvePath("AIR Test/test.txt"); var myFileStream:FileStream = new FileStream(); myFileStream.open(myFile, FileMode.READ);

The fileMode parameter (the second parameter of the open() and openAsync() methods), specifies the mode in which to open the file: for read, write, append, or update. For details, see the previous section, FileStream open modes on page 92. If you use the openAsync() method to open the file for asynchronous file operations, set up event listeners to handle the asynchronous events:
var myFile:File = File.documentsDirectory.resolvePath("AIR Test/test.txt"); var myFileStream:FileStream = new FileStream(); myFileStream.addEventListener(Event.COMPLETE, completeHandler); myFileStream.addEventListener(ProgressEvent.PROGRESS, progressHandler); myFileStream.addEventListener(IOErrorEvent.IOError, errorHandler); myFileStream.open(myFile, FileMode.READ); function completeHandler(event:Event):void {

ADOBE PRODUCT X.0 93


User Guide

// ... } function progressHandler(event:ProgressEvent):void { // ... } function errorHandler(event:IOErrorEvent):void { // ... }

The file is opened for synchronous or asynchronous operations, depending upon whether you use the open() or openAsync() method. For details, see AIR file basics on page 79. If you set the fileMode parameter to FileMode.READ or FileMode.UPDATE in the open method of the FileStream object, data is read into the read buffer as soon as you open the FileStream object. For details, see The read buffer and the bytesAvailable property of a FileStream object on page 94. You can call the close() method of a FileStream object to close the associated file, making it available for use by other applications.
The position property of a FileStream object

The position property of a FileStream object determines where data will be read or written on the next read or write method. Prior to a read or write operation, set the position property to any valid position in the file. For example, the following code writes the string "hello" (in UTF encoding) at position 8 in the file:
var myFile:File = File.documentsDirectory.resolvePath("AIR Test/test.txt"); var myFileStream:FileStream = new FileStream(); myFileStream.open(myFile, FileMode.UPDATE); myFileStream.position = 8; myFileStream.writeUTFBytes("hello");

When you first open a FileStream object, the position property is set to 0. Prior to a read operation, the value of position must be at least 0 and less than the number of bytes in the file (which are existing positions in the file). The value of the position property is modified only in the following conditions:

When you explicitly set the position property. When you call a read method. When you call a write method.

When you call a read or write method of a FileStream object, the position property is immediately incremented by the number of bytes that you will read or write. Depending on the read method you use, this will mean that the position property is either incremented by the number of bytes you specify to read, or by the number of bytes available. When you call a read or write method subsequently, it will read or write starting at the new position.
var myFile:File = File.documentsDirectory.resolvePath("AIR Test/test.txt"); var myFileStream:FileStream = new FileStream(); myFileStream.open(myFile, FileMode.UPDATE); myFileStream.position = 4000; trace(myFileStream.position); // 4000 myFileStream.writeBytes(myByteArray, 0, 200); trace(myFileStream.position); // 4200

ADOBE PRODUCT X.0 94


User Guide

There is, however, one exception: for a FileStream opened in append mode, the position property is not changed after a call to a write method. (In append mode, data is always written to the end of the file, independent of the value of the position property.) Note that for a file opened for asynchronous operations, the write operation does not complete before the next line of code is executed. However, you can call multiple asynchronous methods sequentially, and the runtime will execute them in order:
var myFile:File = File.documentsDirectory.resolvePath("AIR Test/test.txt"); var myFileStream:FileStream = new FileStream(); myFileStream.openAsync(myFile, FileMode.WRITE); myFileStream.writeUTFBytes("hello"); myFileStream.writeUTFBytes("world"); myFileStream.addEventListener(Event.CLOSE, closeHandler); myFileStream.close() trace("started."); closeHandler(event:Event):void { trace("finished."); }

The trace output for this code is the following:


started. finished.

You can specify the position value immediately after you call a read or write method (or at any time), and the next read or write operation will take place starting at that position. For example, note that the following code sets the position property right after a call to the writeBytes() operation, and the position is set to that value (300) even after the write operation completes:
var myFile:File = File.documentsDirectory.resolvePath("AIR Test/test.txt"); var myFileStream:FileStream = new FileStream(); myFileStream.openAsync(myFile, FileMode.UPDATE); myFileStream.position = 4000; trace(myFileStream.position); // 4000 myFileStream.writeBytes(myByteArray, 0, 200); myFileStream.position = 300; trace(myFileStream.position); // 300

The read buffer and the bytesAvailable property of a FileStream object

When a FileStream object with read capabilities (one in which the fileMode parameter of the open() or openAsync() method was set to READ or UPDATE) is opened, the runtime stores the data in an internal buffer. The FileStream object begins reading data into the buffer as soon as you open the file (by calling the open() or openAsync() method of the FileStream object). For a file opened for synchronous operations (using the open() method), you can always set the position pointer to any valid position (within the bounds of the file) and begin reading any amount of data (within the bounds of the file), as shown in the following code (which assumes that the file contains at least 100 bytes):
var myFile:File = File.documentsDirectory.resolvePath("AIR Test/test.txt"); var myFileStream:FileStream = new FileStream(); myFileStream.open(myFile, FileMode.READ); myFileStream.position = 10; myFileStream.readBytes(myByteArray, 0, 20); myFileStream.position = 89; myFileStream.readBytes(myByteArray, 0, 10);

ADOBE PRODUCT X.0 95


User Guide

Whether a file is opened for synchronous or asynchronous operations, the read methods always read from the "available" bytes, represented by the bytesAvalable property. When reading synchronously, all of the bytes of the file are available all of the time. When reading asynchronously, the bytes become available starting at the position specified by the position property, in a series of asynchronous buffer fills signalled by progress events. For files opened for synchronous operations, the bytesAvailable property is always set to represent the number of bytes from the position property to the end of the file (all bytes in the file are always available for reading). For files opened for asynchronous operations, you need to ensure that the read buffer has consumed enough data prior to calling a read method. For a file opened asynchronously, as the read operation progresses, the data from the file, starting at the position specified when the read operation started, is added to the buffer, and the bytesAvailable property increments with each byte read. The bytesAvailable property indicates the number of bytes available starting with the byte at the position specified by the position property to the end of the buffer. Periodically, the FileStream object sends a progress event. For a file opened asynchronously, as data becomes available in the read buffer, the FileStream object periodically dispatches the progress event. For example, the following code reads data into a ByteArray object, bytes, as it is read into the buffer:
var bytes:ByteArray = new ByteArray(); var myFile:File = File.documentsDirectory.resolvePath("AIR Test/test.txt"); var myFileStream:FileStream = new FileStream(); myFileStream.addEventListener(ProgressEvent.PROGRESS, progressHandler); myFileStream.openAsync(myFile, FileMode.READ); function progressHandler(event:ProgressEvent):void { myFileStream.readBytes(bytes, myFileStream.position, myFileStream.bytesAvailable); }

For a file opened asynchronously, only the data in the read buffer can be read. Furthermore, as you read the data, it is removed from the read buffer. For read operations, you will need to ensure that the data exists in the read buffer prior to calling the read operation. You may do this by setting up a progress handler. For example, the following code reads 8000 bytes of data starting from position 4000 in the file:
var myFile:File = File.documentsDirectory.resolvePath("AIR Test/test.txt"); var myFileStream:FileStream = new FileStream(); myFileStream.addEventListener(ProgressEvent.PROGRESS, progressHandler); myFileStream.addEventListener(Event.COMPLETE, completed); myFileStream.openAsync(myFile, FileMode.READ); myFileStream.position = 4000; var str:String = ""; function progressHandler(event:Event):void { if (myFileStream.bytesAvailable > 8000 ) { str += myFileStream.readMultiByte(8000, "iso-8859-1"); } }

ADOBE PRODUCT X.0 96


User Guide

During a write operation, the FileStream object does not read data into the read buffer. When a write operation completes (all data in the write buffer is written to the file), the FileStream object starts a new read buffer (assuming that the associated FileStream object was opened with read capabilities), and starts reading data into the read buffer, starting from the position specified by the position property. The position property may be the position of the last byte written, or it may be a different position, if the user specifies a different value for the position object after the write operation.
Asynchronous programming and the events generated by a FileStream object opened asynchronously

When a file is opened asynchronously (using the openAsync() method), reading and writing files are done asynchronously. As data is read into the read buffer and as output data is being written, other ActionScript code can execute. This means that you will need to register for events generated by the FileStream object opened asynchronously. By registering for the progress event, you can be notified as new data becomes available for reading, as in the following code:
var myFile:File = File.documentsDirectory.resolvePath("AIR Test/test.txt"); var myFileStream:FileStream = new FileStream(); myFileStream.addEventListener(ProgressEvent.PROGRESS, progressHandler); myFileStream.openAsync(myFile, FileMode.READ); var str:String = ""; function progressHandler(event:ProgressEvent):void { str += myFileStream.readMultiByte(myFileStream.bytesAvailable, "iso-8859-1"); }

You can read the entire data by registering for the complete event, as in the following code:
var myFile:File = File.documentsDirectory.resolvePath("AIR Test/test.txt"); var myFileStream:FileStream = new FileStream(); myFileStream.addEventListener(Event.COMPLETE, completed); myFileStream.openAsync(myFile, FileMode.READ); var str:String = ""; function completeHandler(event:Event):void { str = myFileStream.readMultiByte(myFileStream.bytesAvailable, "iso-8859-1"); }

In much the same way that input data is buffered to enable asynchronous reading, data that you write on an asynchronous stream is buffered and written to the file asynchronously. As data is written to a file, the FileStream object periodically dispatched an OutputProgressEvent object. An OutputProgressEvent object includes a bytesPending property that is set to the number of bytes remaining to be written. You can register for the outputProgressEvent to be notified as this buffer is actually written to the file, perhaps in order to display a progress dialog. However in general it is not necessary to do so. In particular, you may call the close() method without concern for the unwritten bytes. The FileStream object will continue writing data and the close event will be delivered after the final byte is written to the file and the underlying file is closed.
Data formats, and choosing the read and write methods to use

Every file is a set of bytes on a disk. In ActionScript, the data from a file can always be represented as a ByteArray. For example, the following code reads the data from a file into a ByteArray object named bytes:
var myFile:File = File.documentsDirectory.resolvePath("AIR Test/test.txt"); var myFileStream:FileStream = new FileStream();

ADOBE PRODUCT X.0 97


User Guide

myFileStream.addEventListener(Event.COMPLETE, completed); myFileStream.openAsync(myFile, FileMode.READ); function completeHandler(event:Event):void { myFileStream.readBytes(bytes, 0, myFileStream.bytesAvailable); }

Similarly, the following code writes data from a ByteArray named bytes to a file:
var myFile:File = File.documentsDirectory.resolvePath("AIR Test/test.txt"); var myFileStream:FileStream = new FileStream(); myFileStream.open(myFile, FileMode.WRITE); myFileStream.writeBytes(bytes, 0, bytes.length);

However, often you do not want to store the data in an ActionScript ByteArray object. And often the data file will be in a specified file format. For example, the data in the file may be in a text file format, and you may want to represent such data in a String object. For this reason, the FileStream class includes read and write methods for reading and writing data to and from types other than ByteArray objects. For example, the readMultiByte() method lets you read data from a file and store it to a string, as in the following code:
var myFile:File = File.documentsDirectory.resolvePath("AIR Test/test.txt"); var myFileStream:FileStream = new FileStream(); myFileStream.addEventListener(Event.COMPLETE, completed); myFileStream.openAsync(myFile, FileMode.READ); var str:String = ""; function completeHandler(event:Event):void { str = myFileStream.readMultiByte(myFileStream.bytesAvailable, "iso-8859-1"); }

Note that the second parameter of the readMultiByte() method specifies the text format that ActionScript uses to interpret the data ("iso-8859-1" in the example). ActionScript supports a number of common character set encodings, and these are listed in the ActionScript Language Reference (see Supported character sets at http://livedocs.macromedia.com/flex/2/langref/charset-codes.html). The FileStream class also includes the readUTFBytes() method, which reads data from the read buffer into a string using the UTF-8 character set. Since characters in the UTF-8 character set is are of a variable length, you should not try to use readUTFBytes() in a method that responds to the progress event, since the data at the end of the read buffer may represent an incomplete character. (This is also true when using the readMultiByte() method with a variable-length character encoding.) For this reason, you should read the entire data when the FileStream object dispatches the complete event. There are also similar write methods, writeMultiByte() and writeUTFBytes(), for working with String objects and text files. Note that the readUTF() and the writeUTF() methods (not to be confused with readUTFBytes() and writeUTFBytes()) also read and write the text data to a file, but they assume that the text data is preceded by data specifying the length of the text data, which is not a common practice in standard text files. Some UTF-encoded text files begin with a "UTF-BOM" (byte order mark) character that defines the endianess as well as the encoding format (such as UTF-16 or UTF-32).

ADOBE PRODUCT X.0 98


User Guide

For an example of reading and writing to a text file, see Example: Reading an XML file into an XML object on page 98. The readObject() and writeObject() are convenient ways to store and retrieve data for complex ActionScript objects. The data is encoded in AMF (ActionScript Message Format). This format is proprietary to ActionScript. Applications other than AIR, Flash Player, Flash Media Server, and Flex Data Services do not have built-in APIs for working with data in this format. There are a number of other read and write methods (such as readDouble() and writeDouble()). However, if you use these, make sure that the file format matches the formats of the data defined by these methods. File formats are often more complex than simple text formats. For example, an MP3 file includes compressed data that can only be interpreted with the decompression and decoding algorithms specific to MP3 files. MP3 files also may include ID3 tags that contain metatag information about the file (such as the title and artist for a song). There are multiple versions of the ID3 format, but the simplest (ID3 version 1) is discussed in the Example: Reading and writing data with random access on page 99 section. Other files formats (for images, databases, application documents, etc.) have quite different structures, and to work with their data in ActionScript, you need to understand how the data is structured.

Example: Reading an XML file into an XML object


This section shows how to read and write to a text file that contains XML data. Reading from the file is easy. Simply initialize the File and FileStream objects, and set up an event listener for the complete event:
var file:File = File.documentsDirectory.resolvePath("AIR Test/preferences.xml"); var fileStream:FileStream = new FileStream(); fileStream.open(file, FileMode.READ); var prefsXML:XML = XML(fileStream.readUTFBytes(fileStream.bytesAvailable)); fileStream.close();

Similarly, writing the data to the file is as easy as setting up an appropriate File and FileStream objects, and then calling a write method of the FileStream object, passing the string version of the XML data to the write method as in the following code:
var file:File = File.documentsDirectory.resolvePath("AIR Test/preferences.xml"); fileStream = new FileStream(); fileStream.open(file, FileMode.WRITE); var outputString:String = '<?xml version="1.0" encoding="utf-8"?>\n'; outputString += prefsXML.toXMLString(); fileStream.writeUTFBytes(outputString); fileStream.close();

Note that these examples use the readUTFBytes() and writeUTFBytes() methods, because they assume that the files are in UTF-8 format. If this is not the case, you may need to use a different method (see Data formats, and choosing the read and write methods to use on page 96). The previous examples use FileStream objects opened for synchronous operation. You can also open files for asynchronous operations (which rely on event listener functions to respond to events). For example, the following code shows how to read an XML file asynchronously:
var file:File = File.documentsDirectory.resolvePath("AIR Test/preferences.xml"); var fileStream:FileStream = new FileStream();

ADOBE PRODUCT X.0 99


User Guide

fileStream.addEventListener(Event.COMPLETE, processXMLData); fileStream.open(file, FileMode.READ); var prefsXML:XML; function processXMLData(event:Event):void { prefsXML = XML(fileStream.readUTFBytes(fileStream.bytesAvailable)); fileStream.close(); }

The processXMLData() method is invoked when the entire file is read into the read buffer (when the FileStream object dispatches the complete event). It calls the readUTFBytes() method to get a string version of the read data, and it creates an XML object, prefsXML, based on that string. To see a sample application that shows these capabilities, see Reading and writing from an XML preferences file on page 17.

Example: Reading and writing data with random access


MP3 files can include ID3 tags, which are sections at the beginning or end of the file that contain metadata identifying the recording. The ID3 tag format itself has gone through a number of revisions. This section describes how to read and write from an MP3 file that contains the simplest ID3 format: ID3 version 1.0. This example will not be reading and writing to the file sequentially from start to finish, and this is known as random access to file data. An MP3 file that contains an ID3 version 1 tag includes the ID3 data at the end of the file, in the final 128 bytes. When accessing a file for random read/write access, it is important to specify FileMode.UPDATE as the fileMode parameter for the open() or openAsync() method:
var file:File = File.documentsDirectory.resolvePath("My Music/Sample ID3 v1.mp3"); var fileStr:FileStream = new FileStream(); fileStr.open(file, FileMode.UPDATE); var file = air.File.documentsDirectory.resolvePath("My Music/Sample ID3 v1.mp3"); var fileStr = new air.FileStream(); fileStr.open(file, air.FileMode.UPDATE);

This lets you both read and write to the file. Upon opening the file, you can set the position pointer to the position 128 bytes before the end of the file,
fileStr.position = file.size - 128;

We set the position to this location in the file because the ID3 v1.0 format specifies that the ID3 tag data is stored in the last 128 bytes of the file. The specification also says the following:

The first 3 bytes of the tag contain the string "TAG". The next 30 characters contain the title for the MP3 track, as a string. The next 30 characters contain the name of the artist, as a string. The next 30 characters contain the name of the album, as a string. The next 4 characters contain the year, as a string. The next 30 characters contain the comment, as a string. The next byte contains a code indicating the track's genre. All text data is in ISO 8859-1 format.

ADOBE PRODUCT X.0 100


User Guide

The id3TagRead() method checks the data after it is read in (upon the complete event):
function id3TagRead():void { if (fileStr.readMultiByte(3, "iso-8859-1").match(/tag/i)) { var id3Title:String = fileStr.readMultiByte(30, "iso-8859-1"); var id3Artist:String = fileStr.readMultiByte(30, "iso-8859-1"); var id3Album:String = fileStr.readMultiByte(30, "iso-8859-1"); var id3Year:String = fileStr.readMultiByte(4, "iso-8859-1"); var id3Comment:String = fileStr.readMultiByte(30, "iso-8859-1"); var id3GenreCode:String = fileStr.readByte().toString(10); } } function id3TagRead() { if (fileStr.readMultiByte(3, "iso-8859-1").match(/tag/i)) { var id3Title = fileStr.readMultiByte(30, "iso-8859-1"); var id3Artist = fileStr.readMultiByte(30, "iso-8859-1"); var id3Album = fileStr.readMultiByte(30, "iso-8859-1"); var id3Year = fileStr.readMultiByte(4, "iso-8859-1"); var id3Comment = fileStr.readMultiByte(30, "iso-8859-1"); var id3GenreCode = fileStr.readByte().toString(10); } }

You can also perform a random-access write to the file. For example, you could parse the id3Title variable to ensure that it is correctly capitalized (using methods of the String class), and then write a modified string, called newTitle, to the file, as in the following:
fileStr.position = file.length - 125; // 128 - 3 fileStr.writeMultiByte(newTitle, "iso-8859-1");

To conform with the ID3 version 1 standard, the length of the newTitle string should be 30 characters, padded at the end with the character with the code 0 (String.fromCharCode(0)).

Using the encrypted local store


A persistent encrypted local store is available for each AIR application installed on a users machine. This lets you save and retrieve data that is stored on the users local hard drive in an encrypted format that cannot be deciphered by other applications or users. A separate encrypted local store is used for each AIR application, and each AIR application uses a separate encrypted local store for each user. You may want to use the encrypted local store to store information that must be secured, such as login credentials for web services. AIR uses DPAPI on Windows and KeyChain on Mac OS to associate the encrypted local store to each application and user. The encrypted local store uses AES-CBC 128-bit encryption. Information in the encrypted local data store is only available to AIR application content in the application security sandbox.

ADOBE PRODUCT X.0 101


User Guide

Use the setItem() and removeItem() static methods of the EncryptedLocalStore class to store and retrieve data from the local store. The data is stored in a hash table, using strings as keys, with the data stored as byte arrays. For example, the following code stores a string in the encrypted local store:
var str:String = "Bob"; var bytes:ByteArray = new ByteArray(); bytes.writeUTFBytes(str); EncryptedLocalStore.setItem("firstName", bytes); var storedValue:ByteArray = EncryptedLocalStore.getItem("firstName"); trace(storedValue.readUTFBytes(storedValue.length)); // "Bob"

You can delete a value from the encrypted local store by using the EncryptedLocalStore.removeItem() method, as in the following example:
EncryptedLocalStore.removeItem("firstName");

102

Chapter 11: Drag and Drop


Use the classes in the drag-and-drop API to support user-interface drag-and-drop gestures. With the drag-and-drop API, you can allow a user to drag data between your AIR application and other applications, as well as between components within your application. Supported transfer formats include:

Bitmaps Files Text URLs Serialized objects Object references (only valid within the originating application)

GETTING STARTED

Drag and drop basics on page 102 Dragging, copying, and pasting data on page 40

DEVELOPMENT TASKS

Supporting the drag-out gesture on page 103 Supporting the drag-in gesture on page 106 HTML Drag and drop on page 107

LANGUAGE REFERENCE

DragManager DragOptions Clipboard NativeDragEvent

MORE INFORMATION

You may be able to find more information about working the AIR File API in the AIR Developer Center (http://www.stage.adobe.com/devnet/air/flash/). Search the site using the keywords AIR drag and drop.

Drag and drop basics


The drag-and-drop API contains the following classes.
Package flash.desktop Classes DragManager, DragOptions, Clipboard Constants used with the drag-and-drop API are defined in the following classes: DragActions, ClipboardFormat, ClipboardTransferModes flash.events NativeDragEvent

ADOBE PRODUCT X.0 103


User Guide

The drag-and-drop gesture has three stages:


Initiation A user initiates a drag-and-drop operation by dragging from a component, or an item in a component, while holding down the mouse button. If the drag is initiated from an AIR application, the component is typically designated as the drag initiator and will dispatch nativeDragStart and nativeDragComplete events for the drag operation. An AIR application starts a drag operation by calling the DragManager.doDrag() method in response to a mouseDown or mouseMove event. Dragging While holding down the mouse button, the user moves the mouse cursor to another component, appli-

cation, or to the desktop. AIR optionally displays a proxy image during the drag. When the user moves the mouse over a possible drop target in an AIR application, the drop target dispatches a nativeDragEnter event. The event handler can inspect the event object to determine whether the dragged data is available in a format that the target accepts and, if so, let the user drop the data onto it by calling the DragManager.acceptDrop() method.
Drop The user releases the mouse over an eligible drop target. If the target is an AIR application or component, then

the component dispatches a nativeDragDrop event. The event handler can access the transferred data from the event object. If the target is outside AIR, the operating system handles the drop. In both cases, a nativeDragComplete event is dispatched by the initiating object. The DragManager class controls both drag-in and drag-out gestures. All the members of the DragManager class are static, so an instance of this class does not need to be created.
The Clipboard object

Data that is dragged into or out of an application or component is contained in a Clipboard object. (Copy-and-paste operations also use Clipboard objects.) A single Clipboard object can make available different representations of the same information to increase the likelihood that another application can understand and use the data. For example, an image might be included as image data, a serialized Bitmap object, and as a file. Rendering of the data in a format can be deferred so that the data is not actually created until it is read. A Clipboard object has a limited lifespan. Once a drag gesture has started, the Clipboard object can only be accessed from within an event handler for the nativeDragEnter, nativeDragOver, and nativeDragDrop events. An application object can be transferred as a reference and as a serialized object. References are only valid within the originating application. Serialized object transfers are valid between AIR applications, but can only be used with objects that remain valid when serialized and deserialized.

Supporting the drag-out gesture


To support the drag-out gesture, your application (or, more typically, a component of your application) must create a Clipboard object in response to a mouseDown event and send it to the DragManager.doDrag() method. Your application should then listen for the nativeDragComplete event on the initiating object to determine what action to take when the gesture is completed or abandoned by the user.

ADOBE PRODUCT X.0 104


User Guide

Preparing data for transfer


To prepare data or an object for transfer out of a component or application, create a Clipboard object and add the information to be transferred in one or more formats. By supplying information in multiple formats, you increase the ability of other applications to use that information. You can use the standard data formats to pass data that can be translated automatically to native clipboard formats, and application-defined formats to pass objects. If it is computationally expensive to convert the information to be transferred into a particular format, you can supply the name of a handler function that will perform the conversion if and only if that format is read by the receiving component or application. For more information see Clipboard data formats on page 111. The following example illustrates how to create a Clipboard object containing a bitmap in several formats: a Bitmap object, a native bitmap format, and a file list format containing the file from which the bitmap was originally loaded.
import flash.desktop.Clipboard; import flash.display.Bitmap; import flash.filesystem.File; public function createClipboard(image:Bitmap, sourceFile:File):Clipboard{ var transfer:Clipboard = new Clipboard(); transfer.setData(image,"CUSTOM_BITMAP",true); //Flash object by value and by reference transfer.setData(image.bitmapData,ClipboardFormats.BITMAP_FORMAT,false); transfer.setData(new Array(sourceFile),ClipboardFormats.FILE_LIST_FORMAT,false); return transfer; }

Starting a drag-out operation


To start a drag operation, call the DragManager.doDrag() method in response to a mouse down event. doDrag() is a static method that takes the following parameters:
initiator The object from which the drag originates, and which will receive the dragStart and dragComplete

events. The initiator must be a DisplayObject.


clipboard The Clipboard object containing the data to be transferred. The Clipboard object is referenced in the

NativeDragEvent objects.
dragImage (Optional) A BitmapData object to display during the drag. The image can specify an alpha value. (Note that Microsoft Windows always applies a fixed alpha fade to drag images). offset (Optional) A Point object specifying the offset of the drag image from the mouse hotspot. Use negative

coordinates to move the drag image up and left relative to the mouse cursor. If no offset is provided, the top, left corner of the drag image will be positioned at the mouse hotspot.
actionsAllowed (Optional) A NativeDragOptions object specifying which actions (copy, move, or link) are valid for drag operation. If no object is provided, all actions are permitted. The DragOptions object is referenced in NativeDragEvent objects to enable a potential drag target to check that the allowed actions are compatible with the target components purpose. For example, a trash component might only accept drag gestures that allow the move action.

The following example illustrates how to start a drag operation for a bitmap object loaded from a file. The example loads an image and, on a mouseDown event, starts the drag operation.
import import import import import flash.desktop.DragManager; flash.display.Sprite; flash.desktop.Clipboard; flash.display.Bitmap; flash.filesystem.File;

public class DragOutExample extends Sprite { protected var fileURL:String = "app-resource:/image.jpg";

ADOBE PRODUCT X.0 105


User Guide

protected var display:Bitmap; private function init():void { DragManager.init(); loadImage(); } private function onMouseDown(event:MouseEvent):void { var bitmapFile:File = new File(fileURL); var transferObject:Clipboard = createClipboard(display,bitmapFile); DragManager.doDrag(this,transferObject,display.bitmapData,new Point(-mouseX,mouseY)); } public function createClipboard(image:Bitmap, sourceFile:File):Clipboard { var transfer:Clipboard = new Clipboard(); transfer.setData(image,Bitmap",false); //Flash object by value and by reference transfer.setData(image.bitmapData,"bitmap",false); //Standard bitmap format transfer.setData(new Array(sourceFile),"file list",false); //Standard file list format return transfer; } private function loadImage():void { var url:URLRequest = new URLRequest(fileURL); var loader:Loader = new Loader(); loader.load(url,new LoaderContext()); loader.contentLoaderInfo.addEventListener(Event.COMPLETE,onLoadComplete); } private function onLoadComplete(event:Event):void { display = event.target.loader.content; var flexWrapper:UIComponent = new UIComponent(); flexWrapper.addChild(event.target.loader.content); addChild(flexWrapper); flexWrapper.addEventListener(MouseEvent.MOUSE_DOWN,onMouseDown); } }

Completing a drag-out transfer


When a user drops the dragged item by releasing the mouse, a nativeDragComplete event is dispatched by the initiator object. If your application should modify the source data according to the drop action, you can check the dropAction property of the event object and then take the appropriate action. For example, if the action is move, you might remove the source item from its original location. If a drag gesture is abandoned by the user, the action will always be none. Note: When passing DisplayObjects by reference within an application, adding the transferred object as a child of a new parent will automatically remove the object from its original parent.

Dragging Sprites
Sprite objects have a separate drag API which allows drag gestures to be used to move sprites around on the stage of a window. You can use both APIs at the same time to allow moving a sprite around its current stage as well as out of the stage. However, the DragManager API will take precedence visually that is, the drag image or mouse pointer will be shown rather than the live, possibly animated, sprite.

ADOBE PRODUCT X.0 106


User Guide

Supporting the drag-in gesture


To support the drag-in gesture, your application (or, more typically, a visual component of your application) must respond to nativeDragEnter or nativeDragOver events. The following sequence of events is typical for a drop operation:

The user drags a clipboard object over a component. The component dispatches a nativeDragEnter event.

The nativeDragEnter event handler checks the formats available and, if relevant, the allowed actions. If the component can handle the drop, it calls DragManager.acceptDragDrop().
The DragManager changes the mouse cursor to indicate that the object can be dropped. The user drops the object over the component. A nativeDragDrop event is dispatched by the receiving component. The receiving component reads the data in the desired format from the Clipboard object within the event object.

If the drag gesture originated within an AIR application, then a nativeDragComplete event is dispatched by the initiating display object. If the gesture originated outside AIR, no feedback is sent.

Acknowledging a drag-in gesture


When a user drags a clipboard item within the bounds of a visual component, the component dispatches nativeDragEnter and nativeDragOver events. To determine whether the clipboard item can be dropped on the component, the handlers for these events should check the available formats in the Clipboard object referenced by the event clipboard property. If desired, the component can also check the allowed actions by examining the DragOptions object referenced in the event. If the component can handle the drop, the event handler must call the DragManager.acceptDragDrop() method, passing a reference to the receiving component and the drag actions that the component supports. If more than one component responds to the drag-in gesture, the last component to respond takes precedence. The acceptDragDrop() call is valid until the mouse leaves the bounds of the accepting object, triggering the nativeDragExit event (or until the drop occurs). The following example illustrates an event handler for a nativeDragEnter or nativeDragOver event:
import flash.desktop.DragManager; import flash.desktop.DragActions; import flash.events.NativeDragEvent; public function onDragIn(event:NativeDragEvent):void{ if(event.clipboard.hasFormat("text")){ DragManager.setFeedback(DragActions.MOVE); DragManager.acceptDragDrop(this); //this is the receiving component } }

If more than one drag action is specified, or no action is specified, the effective action reported back to the initiating object will follow precedence: copy, move, link. If none of the actions set by the receiving component matches an action allowed by the drag gesture, then the receiving component will not be eligible to take the drop.

Completing the drop


When the user drops a clipboard item on a component that has accepted the gesture, the component will dispatch a nativeDragDrop event. The handler for this event can extract the data from the clipboard property of the event object.

ADOBE PRODUCT X.0 107


User Guide

When the clipboard contains an application-defined format, the transfer mode parameter determines whether the reference or the serialized version of the object within the data format is obtained. The following example illustrates an event handler for the nativeDragDrop event:
import flash.desktop.Clipboard; import flash.events.NativeDragEvent; public function onDrop(event:NativeDragEvent):void{ if(event.clipboard.hasFormat(ClipboardFormats.TEXT_FORMAT)){ var text:String = String(event.clipboard.getData(ClipboardFormats.TEXT_FORMAT)); }

Once the event handler exits, the Clipboard object is no longer valid. Any attempt to access the object or its data will throw an exception.

Updating the visual appearance of a component


A component can update its visual appearance based on the NativeDragEvents:
nativeDragStart The initiating component can use the nativeDragStart event to provide visual feedback that the

drag gesture originated from that component.


nativeDragEnter A potential receiving component can use this event take the focus, or indicate visually that it can

or cannot accept the drop.


nativeDragOver A potential receiving component can use this event to respond to the movement of the mouse within the component, such as when the mouse enters a hot region of a complex component like a map. nativeDragExit A potential receiving component can use this event to restore its state when a drag gesture moves outside its bounds. nativeDragComplete The initiating component can use this event to update its associated data model, such as by removing an item from a list, and to restore its visual state.

Tracking mouse position during a drag-in gesture


Once a drag gesture has entered a component, nativeDragOver events are dispatched by that component. These events are dispatched whenever the mouse moves and also on a short interval. The nativeDragOver event object can be used to determine the position of the mouse over the component. This can be helpful in situations where the receiving component is complex, but is not made up of sub-components such as a map.

HTML Drag and drop


To drag data into and out of an HTML-based application (or into and out of the HTML displayed in an HTMLControl), you can use HTML drag and drop events. The HTML drag-and-drop API allows you to drag to and from DOM elements in the HTML content. The events dispatched by the initiator element from which a drag originates, are:
ondragstart dispatched when the user starts the drag gesture. The handler for this event can prevent the drag, if

necessary, by calling the event objects cancelDefault() method. To control whether the dragged data may be copied, linked, or moved, set the effectAllowed property. Selected text is put onto the clipboard automatically, but you can put data onto the clipboard using the dataTransfer property of the event object.

ADOBE PRODUCT X.0 108


User Guide

ondrag dispatched continuously during the drag gesture. ondragend dispatched when the user releases the mouse button to end the drag gesture.

The events dispatched by a drag target are:


ondragenter dispatched when the drag gesture enters the boundaries of the element. The handler for this event

should set the dataTransfer.dropEffect property to indicate whether the drop will result in a copy, move, or link action.
ondragover dispatched continuously while the drag gesture remains within the element boundaries. ondragleave dispatched when the drag gesture leaves the element boundaries. ondragdrop dispatched when the user drops the data onto the element. The data being dragged can only be accessed

within the handler for this event.

Setting the dragged data


You can set the data to be dragged in the handler for the ondragstart event using the dataTransfer property:
function doDragStart(evt) { evt.dataTransfer.setData("text/plain","A picture of George"); evt.dataTransfer.setData("image/x-vnd.adobe.air.bitmap", document.getElementById("imageOfGeorge"); evt.dataTransfer.setData("application/x-vnd.adobe.air.file-list", new Array(georgeJPG)); evt.dataTransfer.effectAllowed = "all"; } Use the dataTransfer.setData() method to put data onto the clipboard, passing in the mime type and data to

transfer. The valid data mime types are:


Text "text/plain" URL "text/uri-list" Bitmap "image/x-vnd.adobe.air.bitmap" File list "application/x-vnd.adobe.air.file-list"

Getting the dropped data


You can access the dropped data in the handler for the ondragdrop event:
function doDrop(evt) { droppedText = evt.dataTransfer.getData("text/plain"); } Use the dataTransfer.getData() method to read the data onto the clipboard, passing in the mime type of the data

format to read.

About drag effects


The initiator of the drag gesture can limit the allowed effects by setting the dataTransfer.effectAllowed property in the handler for the ondragstart event. The following string values can be used:
none No drag operations are allowed. copy The data should be copied to the destination, leaving the original in place.

ADOBE PRODUCT X.0 109


User Guide

link The data should be shared with the drop destination using a link back to the original. move The data should be copied to the destination and removed from the original location. copyLink The data can be copied or linked. copyMove The data can be copied or moved. This is the default value. linkMove The data can be linked or moved. all The data can be copied, moved, or linked.

The target of the drag gesture should set the dataTransfer.dropEffect property to indicate the action taken. The value should be one of the actions allowed by the initiator, but this is not enforced (it is up to the application logic to take the appropriate action). The dropEffect is typically set in the handler for the ondragenter handler, but can be set in any of the events dispatched by the drag target (except ondragleave).
function doDragStart(evt) { evt.dataTransfer.setData("text/plain","Text to drag"); evt.dataTransfer.effectAllowed = "all"; } function doDragEnter(evt) { evt.dataTransfer.dropEffect = "move"; }

110

Chapter 12: Copy and Paste


Use the classes in the clipboard API to copy information to and from the system clipboard. The data formats that can be transferred into or out of an AIR application include:

Bitmaps Files Text URL strings Serialized objects Object references (only valid within the originating application)

GETTING STARTED

Copy-and-paste basics on page 110 Dragging, copying, and pasting data on page 40

DEVELOPMENT TASKS

Reading from and writing to the system clipboard on page 111 Clipboard data formats on page 111

LANGUAGE REFERENCE

Clipboard ClipboardFormats ClipboardTransferMode

MORE INFORMATION

You may be able to find more information about working the AIR clipboard API in the AIR Developer Center (http://www.stage.adobe.com/devnet/air/flash/). Search the site using the keywords AIR copy and paste.

Copy-and-paste basics
The copy-and-paste API contains the following classes.
Package flash.desktop Classes Clipboard, Constants used with the copy-and-paste API are defined in the following classes: ClipboardFormats, ClipboardTransferMode

The static Clipboard.generalClipboard property represents the operating system clipboard. Access the system clipboard through the static Clipboard.generalClipboard property. Clipboard objects are also used to transfer data through the drag-and-drop API. The Clipboard class provides methods for reading and writing data to clipboard objects.

ADOBE PRODUCT X.0 111


User Guide

The data on the clipboard is represented by an instance of a Clipboard object. Different representations of the same information can be made available in a single Clipboard object to increase the ability of other applications to understand and use the data. For example, an image might be included as image data, a serialized Bitmap object, and as a file. Rendering of the data in a format can be deferred so that the format is not actually created until the data in that format is read. An application object can be transferred as a reference and as a serialized object. References are only valid within the originating application. Serialized object transfers are valid between Adobe AIR applications, but can only be used with objects that remain valid when serialized and deserialized.

See also

Clipboard data formats on page 111

Reading from and writing to the system clipboard


To read the clipboard, call the getData() method of the Clipboard.generalClipbooard, passing in the name of the format to read:
import flash.desktop.Clipboard; import flash.desktop.ClipboardFormats; if(Clipboard.generalClipboard.hasFormat(ClipboardFormats.TEXT_FORMAT)){ var text:String = Clipboard.generalClipboard.getData(ClipboardFormats.TEXT_FORMAT); } To write to the clipboard, add the data to Clipboard.generalClipboard in one or more formats. Any existing data

in the same format will be overwritten automatically. However, it is a good practice to also clear the system clipboard before writing new data to it to make sure that unrelated data in any other formats is also deleted.
import flash.desktop.Clipboard; import flash.desktop.ClipboardFormats; Clipboard.generalClipboard.clear(); var textToCopy:String = "Copy to clipboard."; Clipboard.generalClipboard.addData(ClipboardFormats.TEXT_FORMAT,textToCopy,false);

Clipboard data formats


Clipboard formats describe the data placed in a Clipboard object. AIR automatically translates the standard data formats between ActionScript data types and system clipboard formats. In addition, application objects can be transferred within and between AIR applications using application-defined formats. A Clipboard object can contain representations of the same information in different formats. For example, a Clipboard object representing a Sprite could include a reference format for use within the same application, a serialized format for use by another AIR application, a bitmap format for use by an image editor, and a file list format, perhaps with deferred rendering to encode a PNG file, for dragging a representation of the Sprite to the file system.

Standard data formats


The constants defining the standard format names are provided in the ClipboardFormats class:

ADOBE PRODUCT X.0 112


User Guide

TEXT_FORMAT Text-format data is translated to and from the ActionScript String class. BITMAP_FORMAT Bitmap-format data is translated to and from the ActionScript BitmapData class. FILE_LIST_FORMAT File-list-format data is translated to and from an array of ActionScript File objects. URL_FORMAT URL-format data is translated to and from the ActionScript String class.

When copying and pasting data in response to an oncopy, oncut, or onpaste event in HTML content, mime types must be used instead of the ClipboardFormat strings. The valid data mime types are:
Text "text/plain" URL "text/uri-list" Bitmap "image/x-vnd.adobe.air.bitmap" File list "application/x-vnd.adobe.air.file-list"

Custom data formats


You can use application-defined custom formats to transfer objects as references or in serialized form. References are only valid within the originating application. Serialized objects may be valid in other AIR applications as well (when the receiving application knows how to use the serialized data). To add a serialized object to a Clipboard object, set the serializable parameter to true when calling the Clipboard.setData() method. The format name can be one of the standard formats or an arbitrary string defined by your application.
public function createClipboardObject(object:Object):Clipboard{ var transfer:Clipboard = new Clipboard(); transfer.setData("object", object, true); }

To extract a serialized object from the clipboard object (after a drop or paste operation), use the same format name and the cloneOnly or clonePreferred transfer modes.
var transfer:Object = clipboard.getData("object", ClipboardTransferMode.CLONE_ONLY);

A reference is always added to the Clipboard object. To extract the reference from the clipboard object (after a drop or paste operation), instead of the copy, use the originalOnly or originalPreferred transfer modes:
var transferedObject:Object = clipboard.getData("object", ClipboardTransferMode.ORIGINAL_ONLY);

References are only valid if the Clipboard object originates from the current AIR application. Use the originalPreferred transfer mode to access the reference when it is available, and the serialized clone when the reference is not available.

Deferred rendering
If creating a data format is computationally expensive, you can use deferred rendering by supplying a function that supplies the data on demand. The function is only called if a receiver of the drop or paste operation requests data in the deferred format. The rendering function is added to a Clipboard object using the setDataHandler() method and must return the data in the expected format. If a data format of the same type is added to a Clipboard object with the setData() method, that data will take precedence over the deferred version (the rendering function will never be called).

ADOBE PRODUCT X.0 113


User Guide

The following example illustrates implementing a function to provide deferred rendering. When the Copy button in the example is pressed, the application clears the system clipboard to ensure that no data is left over from previous clipboard operations, then puts the renderData() function onto the clipboard with the clipboard setDataHandler() method. When the Paste button is pressed, the application accesses the clipboard and sets the destination text. Since the text data format on the clipboard has been set with a function rather than a string, the clipboard will call the renderData() function. The renderData() function returns the text in the source TextArea, which is then assigned to the destination TextArea. Notice that if you edit the source text before pressing the Paste button, the edit will be reflected in the pasted text, even when the edit occurs after the copy button was pressed. This is because the rendering function doesnt copy the source text until the paste button is pressed. (When using deferred rendering in a real application, you might want to copy or protect the source data in some way to prevent this problem.)
package { import import import import import

flash.desktop.Clipboard; flash.desktop.ClipboardFormats; flash.display.Sprite; flash.text.TextField; flash.events.MouseEvent;

public class DeferredRenderingExample extends Sprite { var sourceTxt:TextField; var destinationTxt:TextField; public function DeferredRenderingExample():void { sourceTxt = createTextField(10, 10, 210, 380, false); addChild(sourceTxt); sourceTxt.text = "Neque porro quisquam est qui dolorem " + "ipsum quia dolor sit amet, consectetur, adipisci velit." destinationTxt = createTextField(330, 10, 210, 380, false); addChild(destinationTxt); var copyBtn:TextField = createTextField(230, 50, 90, 20, true); copyBtn.text = "Copy"; addChild(copyBtn); copyBtn.addEventListener(MouseEvent.CLICK, onCopy); var pasteBtn:TextField = createTextField(230, 80, 90, 20, true); pasteBtn.text = "Paste"; addChild(pasteBtn); pasteBtn.addEventListener(MouseEvent.CLICK, onPaste); } private function createTextField(x:Number, y:Number, width:Number, height:Number, isBtn:Boolean = false):TextField { var newTxt:TextField = new TextField(); newTxt.x = x; newTxt.y = y; newTxt.height = height; newTxt.width = width; newTxt.border = true; newTxt.background = true; if (isBtn)

ADOBE PRODUCT X.0 114


User Guide

{ newTxt.backgroundColor = 0xDDDDDDEE; newTxt.selectable = false; } else { newTxt.multiline = true; newTxt.wordWrap = true; newTxt.backgroundColor = 0xEEEEEEEE; } return newTxt; } public function onCopy(event:MouseEvent):void { Clipboard.generalClipboard.clear(); Clipboard.generalClipboard.setDataHandler(ClipboardFormats.TEXT_FORMAT, renderData); } public function onPaste(event:MouseEvent):void { destinationTxt.text = Clipboard.generalClipboard.getData(ClipboardFormats.TEXT_FORMAT) as String; } public function renderData():String { trace("Rendering data"); var sourceStr:String = sourceTxt.text; if (sourceTxt.selectionEndIndex > sourceTxt.selectionBeginIndex) { // something is selected return sourceStr.substring(sourceTxt.selectionBeginIndex, sourceTxt.selectionEndIndex); } else { return sourceStr; } } } }

115

Chapter 13: Working with local SQL databases


Adobe AIR includes the capability of creating and working with local SQL databases. The runtime includes a SQL database engine with support for many standard SQL features, using the open source SQLite database system. A local SQL database can be used for storing local, persistent data, which can be application data, application user settings, documents, or any other type of data that you might want your application to save locally. This section contains the following topics:

About local SQL databases Common SQL database tasks Creating and modifying a database Using synchronous and asynchronous database operations Strategies for working with SQL databases

About local SQL databases


Adobe AIR includes a SQL-based relational database engine that runs within the runtime, with data stored locally in database files on the computer on which the AIR application runs (for example, on the computers hard drive). Because the database runs and data files are stored locally, a database can be used by an AIR application regardless of whether a network connection is available. Thus, if you have experience with SQL and relational databases, the runtimes local SQL database engine provides a convenient mechanism for storing persistent, local application data. However, because the data is local to a single computer, data is not automatically shared among users on different computers, and the local SQL database engine doesnt provide any capability to execute SQL statements against a remote or server-based database. The AIR local SQL database functionality can be used for any purpose for which you might want to store application data on a users local computer. Adobe AIR includes several mechanisms for storing data locally, each of which has different advantages. The following are some possible uses for a local SQL database in your AIR application:

For a data-oriented application (for example an address book), a database can be used to store the main application data. For a document-oriented application, where users create documents to save and possibly share, each document could be saved as a database file, in a user-designated location. (Note, however, that any AIR application would be able to open the database file, so a separate encryption mechanism would be recommended for potentially sensitive documents.) For a network-aware application, a database can be used to store a local cache of application data, or to store data temporarily when a network connection isnt available. You could create a mechanism for synchronizing the local database with the network data store. For any application, a database can be used to store individual users application settings, such as user options or application information like window size and position.

ADOBE PRODUCT X.0 116


User Guide

About AIR databases and database files


An individual Adobe AIR local SQL database is stored as a single file in the computers file system. The runtime includes the SQL database engine that manages creation and structuring of database files and manipulation and retrieval of data from a database file. The runtime does not specify how or where database data is stored on the file system; rather, each database is stored completely within a single file. You can specify the location in the file system where the database file is stored, and a single AIR application can access one or many separate databases (i.e. separate database files). Because the runtime stores each database as a single file on the file system, a database file can be accessed by all application users on a single computer, or each user can have a separate database file, according to the design of the application and the constraints on file access specified by the operating system.

About relational databases


A relational database is a mechanism for storing (and retrieving) data on a computer. Data is organized into tables: rows represent records or items, and columns (sometimes called fields) divide each record into individual values. For example, an address book application might contain a friends table. Each row in the table could represent a single friend stored in the database. The tables columns might represent data such as first name, last name, birth date, and so forth. For each friend row in the table, the database stores a separate value for each column. Relational databases are designed to store complex data, where one item is associated with or related to items of another type. In a relational database, any data that has a one-to-many relationshipwhere a single record can be related to multiple records of a different typeshould be divided among different tables. For example, suppose you want your address book application to store multiple phone numbers for each friend; this is a one-to-many relationship. The friends table could contain all the personal information for each friend, and a separate phone numbers table could contain all the phone numbers for all the friends. In addition to storing the data about friends and phone numbers, each table would need a piece of data to keep track of the relationship between the two tablesto match individual friend records with their phone numbers. This data is known as a primary keya unique identifier that distinguishes each row in a table from other rows in that table. The primary key can be a natural key, meaning its one of the items of data that naturally distinguishes each record in a table. In the friends table, if you knew that none of your friends share a birth date, you could use the birth date column as the primary key (a natural key) of the friends table. If there is no natural key, you would create a separate primary key column such as a friend idan artificial value that the application uses to distinguish between rows. Using a primary key, you can set up relationships between multiple tables. For instance, suppose the friends table has a column friend id that contains a unique number for each row (each friend). The related phone numbers table can be structured with a column containing the friend id of the friend to whom the phone number belongs, and another column containing the actual phone number. That way, no matter how many phone numbers are a single friend has, they can all be stored in the phone numbers table and can be linked to the related friend using the friend id primary key. When a primary key from one table is used in a related table to specify the connection between the records, the value in the related table is known as a foreign key. Unlike many databases, the AIR local database engine does not allow you to create foreign key constraints, which are constraints that automatically check that an inserted or updated foreign key value has a corresponding row in the primary key table. Nevertheless, foreign key relationships are an important part of the structure of a relational database, and foreign keys should be used when creating relationships between tables in your database.

ADOBE PRODUCT X.0 117


User Guide

About SQL
Structured Query Language (SQL) is used with relational databases to manipulate and retrieve data. SQL is a descriptive language rather than a procedural language: instead of giving the computer instructions on how it should retrieve data, a SQL statement describes the set of data you want, and the computer determines how to retrieve that data. The SQL language has been standardized by the American National Standards Institute (ANSI). The Adobe AIR local SQL database supports most of the SQL-92 standard. For specific descriptions of the SQL language supported in Adobe AIR, see the appendix SQL support in local databases in the Adobe AIR language reference.

About SQL database classes


To work with local SQL databases in ActionScript 3.0, you use instances of these classes in the flash.data package:

flash.data.SQLConnection Provides the means to create and open databases (database files), as well as methods for performing database-level operations and for controlling database transactions. flash.data.SQLStatement Represents a single SQL statement (a single query or command) that is executed on a database, including defining the statement text and setting parameter values. flash.data.SQLResult Provides a way to get information about or results from executing a statement, such as the result rows from a SELECT statement, the number of rows affected by an UPDATE or DELETE statement, and so forth.
To obtain schema information describing the structure of a database, you use these classes in the flash.data package:

flash.data.SQLSchemaResult Serves as a container for database schema results generated by calling the

SQLConnection.loadSchema() method.

flash.data.SQLTableSchema Provides information describing a single table in a database. flash.data.SQLViewSchema Provides information describing a single view in a database. flash.data.SQLColumnSchema Provides information describing a single column of a table or view in a

database.
flash.data.SQLIndexSchema Provides information describing a single index in a database. flash.data.SQLTriggerSchema Provides information describing a single trigger in a database.

Other classes in the flash.data package provide constants that are used with the SQLConnection class and the SQLColumnSchema class:

flash.data.SQLColumnNameStyle Defines a set of constants representing the possible values for the

SQLConnection.columnNameStyle property.

flash.data.SQLTransactionLockType Defines a set of constants representing the possible values for the

option parameter of the SQLConnection.begin() method.

flash.data.SQLCollationType Defines a set of constants representing the possible values for the

SQLColumnSchema.defaultCollationType property and the defaultCollationType parameter of the SQLColumnSchema() constructor.

In addition, the following classes in the flash.events package represent the events (and supporting constants) that you will use:

ADOBE PRODUCT X.0 118


User Guide

flash.events.SQLEvent Defines the events that are dispatched when any of the SQLConnection or SQLStatement operations execute successfully. Each operation has an associated event type, all of which are defined by the SQLEvent class. flash.events.SQLErrorEvent Defines the event that is dispatched when any of the SQLConnection or SQLStatement operations results in an error. flash.events.SQLUpdateEvent Defines the event that is dispatched by a SQLConnection instance when table data in one of its connected databases changes as a result of an INSERT, UPDATE, or DELETE SQL statement being executed.
Finally, the following classes in the flash.errors package provide information about database operation errors:

flash.errors.SQLError Provides information about a database operation error, including the operation that was being attempted and the cause of the failure. flash.errors.SQLErrorCode Defines a set of constants representing the possible values for the SQLError classs code property, which indicates the type of error that led to a failed operation. flash.errors.SQLErrorOperation Defines a set of constants representing the possible values for the SQLError classs operation property, which indicates the database operation that resulted in an error.

Common SQL database tasks


This section describes the most common tasks that you will perform when youre working with local SQL databases. This includes connecting to a database, adding data to and retrieving data from tables in a database, and issues to keep in mind while performing these tasks, such as working with data types and handling errors. Note that there are also several database tasks that are things youll deal with less frequently, but youll often need to do before you can perform the tasks in this section. For example, before you can connect to a database and retrieve data from a table, youll need to create the database and create the table structure in the database. Those less-frequent initial setup tasks are discussed in the section Creating and modifying a database on page 131. You can choose whether to perform database operations asynchronously, meaning the database engine runs in the background and notifies you when the operation succeeds or fails by dispatching an event, or synchronously, meaning the database operations are performed one after another, and the entire application (including updates to the screen) waits for the operations to complete before executing other code. This section introduces common database operations and demonstrates how to perform them asynchronously, which is generally the best approach. For details on performing these operations synchronously, see the section Using synchronous and asynchronous database operations on page 132.

Connecting to a database
Before you can perform any database operations, you need to first open a connection to the database file. A SQLConnection instance is used to represent a connection to one or more databases. The first database that is connected using a SQLConnection instance, known as the main database, is connected using the open() method. Opening a database is an asynchronous operation, meaning you must register for the SQLConnection instances open event in order to know when the open() operation completes, and the SQLConnection instances error event to determine if the operation fails. The following example shows how to open an existing database file named DBSample.db, located in the users application storage directory.
import flash.data.SQLConnection; import flash.events.SQLErrorEvent;

ADOBE PRODUCT X.0 119


User Guide

import flash.events.SQLEvent; import flash.filesystem.File; var conn:SQLConnection = new SQLConnection(); conn.addEventListener(SQLEvent.OPEN, openHandler); conn.addEventListener(SQLErrorEvent.ERROR, errorHandler); var dbFile:File = File.applicationStorageDirectory.resolvePath("DBSample.db"); conn.open(dbFile, false); function openHandler(event:SQLEvent):void { trace("the database was opened successfully"); } function errorHandler(event:SQLErrorEvent):void { trace("Error code:", event.error.code); trace("Details:", event.error.message); }

Notice that in the open() method call, the second argument is false. Specifying false for the second parameter (autoCreate) causes the runtime to dispatch an error if the specified file doesnt exist. If you pass true for the autoCreate parameter (or leave it off and only specify a file location as the first parameter), the runtime will attempt to create a new database file if the specified file doesnt exist.

Working with SQL statements


An individual SQL statement (a query or command) is represented in the runtime as a SQLStatement object. Follow these steps to create and execute a SQL statement:
1. Create a SQLStatement instance

The SQLStatement object represents the SQL statement in your application.


var selectData:SQLStatement = new SQLStatement();

2. Specify which database the query will run against.

To do this, set the SQLStatement objects sqlConnection property to the SQLConnection instance thats connected with the desired database.
// A SQLConnection named "conn" has been created previously selectData.sqlConnection = conn;

3. Specify the actual SQL statement.

Create the statement text as a String and assign it to the SQLStatement instances text property.
selectData.text = "SELECT col1, col2 FROM my_table WHERE col1 = :param1";

4. (Optional) Define functions to handle the result of the execute operation.

Use the addEventListener() method to register functions as listeners for the SQLStatement instances result and error events.
// using listener methods and addEventListener(); selectData.addEventListener(SQLEvent.RESULT, resultHandler); selecteData.addEventListener(SQLErrorEvent.ERROR, errorHandler);

ADOBE PRODUCT X.0 120


User Guide

private function resultHandler(event:SQLEvent):void { // do something after the statement execution succeeds } private function errorHandler(event:SQLErrorEvent):void { // do something after the statement execution fails }

Alternatively, you can specify listener functions by creating a Responder object that refers to the listener functions and passing it to the execute() method call.
// using a Responder var selectResponder = new Responder(onResult, onError); private function onResult(result:SQLResult):void { // do something after the statement execution succeeds } private function onError(error:SQLError):void { // do something after the statement execution fails }

5. If the statement text includes parameter definitions, assign values for those parameters.

To do this, use the SQLStatement instances parameters associative array property.


selectData.parameters["param1"] = 25;

6. Execute the SQL statement.

Call the SQLStatement instances execute() method.


// using listener methods selectData.execute(); // using a Responder selectData.execute(-1, selectResponder);

For specific examples that demonstrate these steps, see the following sections:

Retrieving data from a database Inserting data Changing or deleting data

Using parameters in statements

Frequently you will use a single SQL statement multiple times in an application, with slight variation. For example, consider an inventory-tracking application where a user can add new inventory items to the database. The application code that adds an inventory item to the database executes a SQL INSERT statement that actually adds the data to the database. However, each time the statement is executed there will be a slight variationthe actual values that are inserted in the table will be specific to the inventory item being added.

ADOBE PRODUCT X.0 121


User Guide

In cases like the one described here, where you have a SQL statement thats used multiple times except that it uses different values in the statement, the best approach is to use a SQL statement that includes parameters rather than literal values in the SQL text. A parameter is a placeholder in the statement text that is replaced with an actual value each time the statement is executed. To use parameters in a SQL statement, you create the SQLStatement instance and assign the SQL statement that uses parameter placeholders rather than literal values to its text property. You then define the value for each parameter by setting the value of an element in the SQLStatement instances parameters property. The parameters property is an associative array, so you set a particular value using the following syntax:
statement.parameters[parameter_identifier] = value;

The parameter_identifier is a string if youre using a named parameter, or an integer index if youre using an unnamed parameter.
Using named parameters

A parameter can be a named parameter, meaning it has a specific name that you use to match the parameter value to its placeholder location in the statement text. You use the : or @ character followed by the parameter name to indicate a named parameter, as in the following examples:
:itemName @firstName

The following code listing demonstrates the use of named parameters:


var sql:String = "INSERT INTO inventoryItems (name, productCode)" + "VALUES (:name, :productCode)"; var addItemStmt:SQLStatement = new SQLStatement(); addItemStmt.sqlConnection = conn; addItemStmt.text = sql; // set parameter values addItemStmt.parameters[":name"] = "Item name"; addItemStmt.parameters[":productCode"] = "12345"; addItemStmt.execute(); Using unnamed parameters

As an alternative to using named parameters, you can also use unnamed parameters. In that case you denote a parameter in a SQL statement using a ? character. Each parameter is assigned a numeric index, according to the order of the parameters in the statement, starting with index 1 for the first parameter. The following example demonstrates a version of the previous example, using unnamed parameters.
var sql:String = "INSERT INTO inventoryItems (name, productCode)" + "VALUES (?, ?)"; var addItemStmt:SQLStatement = new SQLStatement(); addItemStmt.sqlConnection = conn; addItemStmt.text = sql; // set parameter values addItemStmt.parameters[1] = "Item name"; addItemStmt.parameters[2] = "12345"; addItemStmt.execute();

ADOBE PRODUCT X.0 122


User Guide

Benefits of using parameters

Using parameters in a SQL statement provides several benefits:


Better performance A SQLStatement instance that uses parameters can execute more efficiently compared to one that dynamically creates the SQL text each time it executes, because it is prepared a single time and can then be executed multiple times using different parameter values, without needing to recompile the SQL statement. Explicit data typing Parameters are used to allow for typed substitution of values that are unknown at the time the SQL statement is constructed. The use of parameters is the only way to guarantee the storage class for a value passed in to the database. When parameters are not used, all values are converted from their text representation to a storage class based on the associated column's type affinity. For more information on storage classes and column affinity, see the section Data type support in the appendix SQL support in local databases in the Adobe AIR language reference. Greater security The use of parameters helps prevent a malicious technique known as a SQL injection attack. In a SQL injection attack, a user enters SQL code in a user-accessible location (for example, a data entry field). If application code constructs a SQL statement by directly concatenating user input into the SQL text, the user-entered SQL code will be executed against the database. The following listing shows an example of concatenating user input into SQL text. Do not use this technique:
// assume the variables "username" and "password" // contain user-entered data var sql:String = "SELECT userId " + "FROM users " + "WHERE username = '" + username + "' " + " AND password = '" + password + "'"; var statement:SQLStatement = new SQLStatement(); statement.text = sql;

Using statement parameters instead of concatenating user-entered values into a statement's text prevents a SQL injection attack, because the parameter values are treated explicitly as substituted values, rather than becoming part of the literal statement text. The following is the recommended alternative to the previous listing:
// assume the variables "username" and "password" // contain user-entered data var sql:String = "SELECT userId " + "FROM users " + "WHERE username = :username " + " AND password = :password"; var statement:SQLStatement = new SQLStatement(); statement.text = sql; // set parameter values statement.parameters[":username"] = username; statement.parameters[":password"] = password;

Retrieving data from a database


To retrieve existing data from a database, you create a SQLStatement instance, assign the desired SQL SELECT statement to the instances text property, then call the execute() method. For details on the syntax of the SELECT statement, see the appendix SQL support in local databases in the Adobe AIR language reference.
var selectStmt:SQLStatement = new SQLStatement(); selectStmt.sqlConnection = conn; selectStmt.text = "SELECT itemId, itemName, price FROM products";

ADOBE PRODUCT X.0 123


User Guide

// resultHandler and errorHandler are listener methods described in // a subsequent code listing selectStmt.addEventListener(SQLEvent.RESULT, resultHandler); selectStmt.addEventListener(SQLErrorEvent.ERROR, errorHandler); selectStmt.execute();

When the statement finishes executing, the SQLStatement instance dispatches a result event (SQLEvent.RESULT) indicating that the statement was run successfully. Alternatively, if a Responder object is passed as an argument in the execute() call, the Responder objects result handler function is called. Each row of data in the result becomes an Object instance whose properties names match the result sets column names and whose properties contain the values from the result sets columns. For example, if a SELECT statement specifies a result set with three columns named itemId, itemName, and price, for each row in the result set an Object instance is created with properties named itemId, itemName, and price, containing the values from their respective columns.
function resultHandler(event:SQLEvent):void { var result:SQLResult = selectStmt.getResult(); var numResults:int = result.data.length; for (var i:int = 0; i < numResults; i++) { var row:Object = result.data[i]; var output:String = "itemId: " + row.itemId; output += "; itemName: " + row.itemName; output += "; price: " + row.price; trace(output); } } function errorHandler(event:SQLErrorEvent):void { // Information about the error is available in the // event.error property, which is an instance of // the SQLError class. }

As the preceding code listing shows, the result objects are contained in an array that is available as the data property of a SQLResult instance. If youre using an event listener, to retrieve that SQLResult instance you call the SQLStatement instances getResult() method. If you specify a Responder argument in the execute() call, the SQLResult instance is passed to the result handler function as an argument. In either case, once you have the SQLResult object you can access the result rows using the data array property. The following code listing defines a SQLStatement instance whose text is a SELECT statement. The statement retrieves rows containing the firstName and lastName column values of all the rows of a table named employees. When the execution completes, the selectResult() method is called, and the resulting rows of data are retrieved using SQLStatement.getResult() and displayed using the trace() method. Note that this listing assumes there is a SQLConnection instance named conn that has already been instantiated and is already connected to the database. It also assumes that the employees table has already been created and populated with data.
import import import import import flash.data.SQLConnection; flash.data.SQLResult; flash.data.SQLStatement; flash.events.SQLErrorEvent; flash.events.SQLEvent;

// ... create and open the SQLConnection instance named conn // create the SQL statement

ADOBE PRODUCT X.0 124


User Guide

var selectStmt:SQLStatement = new SQLStatement(); selectStmt.sqlConnection = conn; // define the SQL text var sql:String = "SELECT firstName, lastName " + "FROM employees"; selectStmt.text = sql; // register listeners for the result and error events selectStmt.addEventListener(SQLEvent.RESULT, selectResult); selectStmt.addEventListener(SQLErrorEvent.ERROR, selectError); // execute the statement selectStmt.execute(); function selectResult(event:SQLEvent):void { var result:SQLResult = selectStmt.getResult(); var numRows:int = result.data.length; for (var i:int = 0; i < numRows; i++) { var output:String = ""; for (var columnName:String in result.data[i]) { output += columnName + ": " + result.data[i][columnName] + "; "; } trace("row[" + i.toString() + "]\t", output); } } function selectError(event:SQLErrorEvent):void { trace("Error code:", event.error.code); trace("Details:", event.error.message); } Defining the data type of SELECT result data

By default, each row returned by a SELECT statement is created as an Object instance whose properties names match the result set's column names, and with the value of each column used as the value of its associated property. Before executing a SQL SELECT statement you can set the itemClass property of the SQLStatement instance to a class, and each row returned by the SELECT statement is created as an instance of the designated class. The runtime matches the column names in the SELECT result set to the names of the properties in the specified class in order to know which value to assign to which property. Any class assigned as an itemClass property value must have a constructor that does not require any parameters. In addition, the class must have a single property for each column returned by the SELECT statement. It is considered an error if a column in the SELECT list does not have a matching property name in the itemClass class.
Retrieving SELECT results in parts

By default, a SELECT statement execution retrieves all the rows of the result set at one time. Once the statement completes, you will usually process the retrieved data in some way, such as creating objects or displaying the data on the screen. If the statement returns a large number of rows, processing all the data at once can be demanding for the computer, which in turn will cause the user interface to pause and not refresh itself.

ADOBE PRODUCT X.0 125


User Guide

You can improve the perceived performance of your application by instructing the runtime to return a specific number of result rows at a time. Doing so will cause the initial result data to return more quickly. It also allows you to divide the result rows into sets, so that the user interface is updated after each set of rows is processed. When you call a SQLStatement instances execute() method, specify a value for the prefetch parameter (the execute() methods first parameter) to indicate the number of result rows to retrieve when the statement executes:
var stmt:SQLStatement = new SQLStatement(); stmt.sqlConnection = conn; stmt.text = "SELECT ..."; stmt.addEventListener(SQLEvent.RESULT, selectResult); stmt.execute(20); // only the first 20 rows (or fewer) will be returned

The statement dispatches the result event, indicating that the first set of result rows are available. The resulting SQLResult instances data property contains the rows of data, and its complete property indicates whether there are additional result rows to retrieve. To retrieve subsequent result rows, call the SQLStatement instances next() method. Like the execute() method, the next() methods first parameter is used to indicate how many rows to retrieve the next time the result event is dispatched.
function selectResult(event:SQLEvent):void { var result:SQLResult = stmt.getResult(); if (result.data != null) { // ... loop through the rows or perform other processing if (!result.complete) { stmt.next(20); // retrieve the next 20 rows } else { stmt.removeEventListener(SQLEvent.RESULT, selectResult); } } }

The SQLStatement dispatches a result event each time the next() method returns a subsequent set of result rows, so the same listener function can be used to continue processing results until all the rows are retrieved. For more information, see the language reference descriptions for the SQLStatement.execute() method (the prefetch parameter description) and the SQLStatement.next() method.

Inserting data
To add data to a table in a database, you create and execute a SQLStatement instance using a SQL INSERT statement. The following example uses a SQLStatement instance to add a row of data to the already-existing employees table. Note that this listing assumes that there is a SQLConnection instance named conn that has already been instantiated and is already connected to a database. It also assumes that the employees table has already been created.
import import import import import flash.data.SQLConnection; flash.data.SQLResult; flash.data.SQLStatement; flash.events.SQLErrorEvent; flash.events.SQLEvent;

// ... create and open the SQLConnection instance named conn // create the SQL statement var insertStmt:SQLStatement = new SQLStatement();

ADOBE PRODUCT X.0 126


User Guide

insertStmt.sqlConnection = conn; // define the SQL text var sql:String = "INSERT INTO employees (firstName, lastName, salary) " + "VALUES ('Bob', 'Smith', 8000)"; insertStmt.text = sql; // register listeners for the result and failure (status) events insertStmt.addEventListener(SQLEvent.RESULT, insertResult); insertStmt.addEventListener(SQLErrorEvent.ERROR, insertError); // execute the statement insertStmt.execute(); function insertResult(event:SQLEvent):void { trace("INSERT statement succeeded"); } function insertError(event:SQLErrorEvent):void { trace("Error code:", event.error.code); trace("Details:", event.error.message); }

Retrieving a database-generated primary key of an inserted row

Often after inserting a row of data into a table, you will want to retrieve a database-generated primary key or row identifier value for the newly-inserted row. For example, once you insert a row in one table, you might want to add rows in a related table, inserting the primary key value as a foreign key in the related table. The primary key of a newly-inserted row can be retrieved in a way thats similar to the way result data is retrieved after a SELECT statement is executedusing the SQLResult object associated with the statement execution. Like with a SELECT or any other SQL statement, when an INSERT statement execution completes and the result event is dispatched, the runtime creates a SQLResult instance that is accessed by calling the SQLStatement objects getResult() method (if youre using an event listener) or as the argument passed to the result handler function (if you specified a Responder in the execute() call). The SQLResult instance has a property, lastInsertRowID, that contains the row identifier of the most-recently inserted row if the executed SQL statement is an INSERT statement.
insertStmt.text = "INSERT INTO ..."; insertStmt.addEventListener(SQLEvent.RESULT, resultHandler); insertStmt.execute(); private function resultHandler(event:SQLEvent):void { var result:SQLResult = insertStmt.getResult(); var primaryKey:Number = result.lastInsertRowID; // do something with the primary key }

Note that the row identifier may or may not be the value of the column that is designated as the primary key column in the table structure, according to the following rule:

If the table is defined with a primary key column whose affinity (column data type) is INTEGER, the

lastInsertRowID property contains the value that was inserted into that row (or the value generated by the

runtime if its an AUTOINCREMENT column).

ADOBE PRODUCT X.0 127


User Guide

If the table is defined with multiple primary key columns (a composite key) or with a single primary key column whose affinity is not INTEGER , behind the scenes the database generates a row identifier value for the row, and that generated value is the value of the lastInsertRowID property. The value is always the row identifier of the most-recently inserted row. If an INSERT statement causes a trigger to fire, which in turn inserts a row, the lastInsertRowID property will contain the row identifier of the last row inserted by the trigger, rather than the row created by the INSERT statement.
Consequently, if you want to have an explicitly defined primary key column whose value available after an INSERT command through the SQLResult.lastInsertRowID property, the column must be defined as an INTEGER PRIMARY KEY column. Note, however, that even if your table does not include an explicit INTEGER PRIMARY KEY column, it is equally acceptable to use the database-generated row identifier as a primary key for your table in the sense of defining relationships with related tables. The row identifier column value is available in any SQL statement by using one of the special column names ROWID, _ROWID_, or OID. You can create a foreign key column in a related table, and use the row identifier value as the foreign key column value, just as you would with an explicitly-declared INTEGER PRIMARY KEY column. In that sense, if you are using an arbitrary primary key rather than a natural key, and as long as you dont mind the runtime generating the primary key value for you, it makes little difference whether you use an INTEGER PRIMARY KEY column or the system-generated row identifier as a tables primary key for defining a foreign key relationship with between two tables. For more information about primary keys and generated row identifiers, see the sections titled CREATE TABLE and Expressions in the appendix SQL support in local databases in the Adobe AIR language reference.

Changing or deleting data


The process for executing other data manipulation operations is identical to the process used to execute a SQL SELECT or INSERT statement; you simply substitute a different SQL statement in the SQLStatement instances text property:

To change existing data in a table, use an UPDATE statement. To delete one or more rows of data from a table, use a DELETE statement.

For descriptions of these statements, see the appendix SQL support in local databases in the Adobe AIR language reference.

Handling database errors


In general, database error handling is similar to other runtime error handlingyou should write code that is prepared for errors that may occur, and respond to the errors rather than leave it up to the runtime to do so. The SQLErrorCode class defines a set of constants that represent the set of errors that can occur during the various database operations. In a general sense, the possible database errors can be divided into three categories: connection errors, SQL syntax errors, and constraint errors.
Connection errors

Most database errors are connection errors, and they can occur during any operation. Although there are strategies for preventing connection errors, there is rarely a simple way to gracefully recover from a connection error if the database is a critical part of your application. Most connection errors have to do with how the runtime interacts with the operating system, the file system, and the database file. For example, a connection error will occur if the user doesnt have permission to create a database file in a particular location on the file system. The following strategies will help you to prevent connection errors:

ADOBE PRODUCT X.0 128


User Guide

Use user-specific database files Rather than using a single database file for all users who use the application on a

single computer, give each user their own database file, stored in a location thats associated with the users account such as the applications storage directory, the users documents folder, the users desktop, and so forth.
Consider different user types Test your application with different types of user accounts, on different operating systems. Dont assume that the user will have administrator permission on the computer, or that the individual who installed the application is the user whos running the application. Consider various file locations If you allow users to specify the location where a database file is saved or the location of a database file to open, consider the possible file locations that users might specify. In addition, consider defining limits on where users can store (or from where they can open) database files. For example, you might only allow users to open files that are within their user accounts storage location.

If a connection error occurs, it most likely happens on the first attempt to create or open the database. This means that the user will be unable to do any database-related operations in the application. For certain types of errors, such as read-only or permission errors, one possible recovery technique is to implement application logic that copies the database file to (or creates a new database file in) a different location where the user does have permission to create and write to files.
Syntax errors

A syntax error occurs when a SQL statement is incorrectly formed, and the application attempts to prepare or execute the statement. Because local database SQL statements are created as strings, compile-time SQL syntax checking is not possible, and all SQL statements must be executed (or prepared) to check their syntax. Use the following strategies to prevent SQL syntax errors:
Test all SQL statements thoroughly If possible, while developing your application test your SQL statements separately before encoding them as statement text in the application code. In addition, use a code-testing approach such as unit testing to create a set of tests that exercise every possible option and variation in the code. Use statement parameters and avoid concatenating (dynamically generating) SQL Using parameters, and avoiding

dynamically-built SQL statements, means that the same SQL statement text is used each time a statement is executed. Consequently, its much easier to test your statements and limit the possible variation. If you must dynamically generate a SQL statement, keep the dynamic parts of the statement to a minimum, and carefully validate any user input to make sure it wont cause syntax errors.
Use prepared SQL statements In many ways this is simply a combination of the two previous strategies. Prepared statements cant be dynamically generated. Syntax checking happens when a statement is prepared, so if you use prepared SQL statements in your application, and explicitly prepare all statements, each statement is tested. For more on using prepared statements, see Use prepared statements on page 137.

To recover from a syntax error, an application would need complex logic to be able to examine a SQL statement and correct its syntax. By following the previous guidelines for preventing syntax errors, you should also be able to identify any potential run-time sources of SQL syntax errors (such as user input used in a statement). To recover from a syntax error, you could provide the user with a specific error message guiding him or her to what needs to be corrected to make the statement execute correctly.
Constraint errors

Constraint errors occur when an INSERT or UPDATE statement attempts to add data to a column that violates one of the defined constraints for the table or column. The following constraints can be defined:
Unique constraint Indicates that across all the rows in a table, there cannot be duplicate values in one column (or,

when multiple columns are combined in a unique constraint, the combination of values in those columns must not be duplicated). In other words, in terms of the specified unique column(s), each row must be distinct.

ADOBE PRODUCT X.0 129


User Guide

Primary key constraint In terms of the data that a constraint allows and doesnt allow, a primary key constraint is

identical to a unique constraint.


Not null constraint Specifies that a single column cannot store a NULL value and consequently that in every row, that

column must have a value.


Check constraint Allows you to specify an arbitrary constraint on one or more tables. Common examples of check constraints are a rule that define that a columns value must be within certain bounds (for example, that a numeric columns value must be larger than 0), or one that specifies relationships between column values (for example, that a columns value must be different than the value of another column in the same row).

The runtime does not enforce constraints on foreign key values (foreign key values arent required to match an existing primary key value). The runtime also does not enforce the data type of columns values (although under some conditions the runtime converts an inserted values to another data type that matches its columns specified type). See the section Data type support in the appendix SQL support in local databases in the Adobe AIR language reference for more information. In addition to the predefined constraint types, the runtime SQL engine supports the use of triggers. A trigger is a predefined set of instructions that are carried out when a certain action happens, such as when data is inserted into or deleted from a particular table. One possible use of a trigger is to examine data changes and cause an error to occur if specified conditions arent met. Consequently, a trigger can serve the same purpose as a constraint, and the strategies for preventing and recovering from constraint errors also apply to trigger-generated errors. However, the error code for trigger-generated errors (the constant SQLErrorCode.ABORT) is different from the error code for constraint errors (the constant SQLErrorCode.CONSTRAINT). Because constraints are specified when a table is created, triggers must be explicitly created, and Adobe AIR doesnt specify any additional constraints on tables or columns, the set of constraints that apply to a particular table can be identified ahead of time and can be taken into account both in preventing and in recovering from constraint errors. Because constraint errors are dependent on data that is to be added to a database, and often on the relationship between the new data and other data that already exists in the database, constraint errors are difficult to systematically predict and prevent. The following strategies can help you avoid many constraint errors:
Carefully plan database structure and constraints The purpose of constraints is to enforce application rules and help protect the integrity of the databases data. When youre planning your application, consider how to structure your database to support your application. As part of that process, you will want to identify rules about your data, such as whether certain values are required, whether a value has a default, whether duplicate values are allowed, and so forth. Those rules will guide you in defining database constraints. Explicitly specify column names An INSERT statement can be written without explicitly specifying the columns into

which values are to be inserted, but doing so is an unnecessary risk. By explicitly naming the columns into which values are to be inserted, you can allow for automatically generated values, columns with default values, and columns that allow NULL values. In addition, by doing so you can ensure that all NOT NULL columns have an explicit value inserted.
Use default values Whenever you specify a NOT NULL constraint for a column, if at all possible you should also

specify a default value in the column definition. Application code can also provide default values, for example checking if a String variable is null and assigning it a value before using it to set a statement parameter value.
Validate user-entered data Check user-entered data ahead of time to make sure that it obeys limits specified by constraints, especially in the case of NOT NULL and CHECK constraints. Naturally, a UNIQUE constraint is more difficult to check for because doing so would require executing a SELECT query to determine whether the data is unique.

ADOBE PRODUCT X.0 130


User Guide

Use triggers You can write a trigger that validates (and possibly replaces) inserted data or takes other actions to correct invalid data. This can prevent a constraint error from occurring.

Fortunately, while constraint errors are perhaps more difficult to prevent than other types of errors, there are several strategies to recover from constraint errors in ways that dont make the application unstable or unusable:
Use conflict algorithms When you define a constraint on a column, and when you create an INSERT or UPDATE statement, you have the option of specifying a conflict algorithm, defining what action the database should take when a constraint violation occurs. The possible actions can range from ending a single statement or a whole transaction, to ignoring the error or even replacing old data with the new data in order to conform to a constraint. For more information see the section ON CONFLICT (conflict algorithms) in the appendix SQL support in local databases in the Adobe AIR language reference. Provide corrective feedback Since the set of constraints that can affect a particular SQL command can be identified ahead of time, you can anticipate constraint errors that a statement could cause. With that knowledge, you can build application logic to respond to a constraint error, such as by showing the user a helpful error message that allows him or her to correct the error and attempt the operation again. For example, if an application includes a data entry form for entering new products, and the product name column in the database is defined with a UNIQUE constraint, the action of inserting a new product row in the database could cause a constraint error. Consequently, if a constraint error occurs, the application could prompt the user to indicate that the specified product name is already in use, and encourage the user to choose a different name (or perhaps allow the user to view information about the other product with the same name).

Working with database data types


When a table is created in a database, part of the SQL statement for creating the table involves defining the affinity, or preferred data type, for each column in the table. Although affinity declarations can be omitted, its a good idea to explicitly declare column affinity in your CREATE TABLE SQL statements. This section describes concepts and techniques that youll want to keep in mind for dealing with database data types from ActionScript or JavaScript. For more information about the available column affinity types and using data types in SQL statements, see the section Data type support in the appendix SQL support in local databases in the Adobe AIR language reference..
Data type conversion between a database and application code

As a general rule, any object that you store in a database using an INSERT statement should be returned as an instance of the same data type when you execute a SELECT statement. However, one complicating factor that can make this not happen is the affinity of the database column in which the value is stored. When a value is stored in a column, the database attempts to convert the value to a particular data type in order to match the declared affinity of the column. For example, if a database column is declared with NUMERIC affinity, the database will attempt to convert inserted data into a numeric storage class (INTEGER or REAL) and will only store it in another form if the data cant be converted. This means that if the String 12345 is inserted into a NUMERIC column, the database will automatically convert it to the integer value 12345 before storing it in the databaseand when its retrieved with a SELECT statement, it will be returned as an instance of a numeric data type (such as Number) rather than as a String instance. The best way to avoid undesirable data type conversion is to define each column with the affinity that matches the type of data that it will store, and only insert values into that column whose data type matches the defined affinity. That way, when you insert the data it wont be converted unexpectedly (and possibly lose its intended meaning as a result) and when you retrieve it, it will be returned as the original data type.

ADOBE PRODUCT X.0 131


User Guide

Creating and modifying a database


This section covers database tasks that are less-frequently used, but are generally necessary for most applications. This section covers the following topics:

Creating a new database Creating database tables

Like the previous section, this section demonstrates how to perform these operations asynchronously, which is generally the best approach. For details on performing these operations synchronously, see the section Using synchronous and asynchronous database operations on page 132.

Creating a new database


To create a new database file, you create a SQLConnection instance and call its open() method, as you would to open a connection to an existing database file. By specifying a file parameter that indicates a file location that does not exist, the open() method will create a new database file at that location, then open a connection to the newlycreated database. When using the open() method to create a new database file, you can use the autoClean and pageSize parameters to define those characteristics of the database being created. The following code listing shows the process of creating a new database file (a new database). In this case, the database file is saved in the applications storage directory, with the file name DBSample.db:
import import import import flash.data.SQLConnection; flash.events.SQLErrorEvent; flash.events.SQLEvent; flash.filesystem.File;

var conn:SQLConnection = new SQLConnection(); conn.addEventListener(SQLEvent.OPEN, openHandler); conn.addEventListener(SQLErrorEvent.ERROR, errorHandler); var dbFile:File = File.applicationStorageDirectory.resolvePath("DBSample.db"); conn.open(dbFile); function openHandler(event:SQLEvent):void { trace("the database was created successfully"); } function errorHandler(event:SQLErrorEvent):void { trace("Error code:", event.error.code); trace("Details:", event.error.message); }

A databases file name can be any valid file name, with any file extension. If you call the open() method with null for the file parameter, a new in-memory database is created rather than a database file on disk.

Creating database tables


Creating a table in a database involves executing a SQL statement on that database, using the same process that you use to execute a SQL statement such as SELECT, INSERT, and so forth. To create a table, you use a CREATE TABLE statement, which includes definitions of columns and constraints for the new table.

ADOBE PRODUCT X.0 132


User Guide

The following example demonstrates creating a new table named employees in an existing database file. Note that this code assumes there is a SQLConnection instance named conn that is already instantiated and is already connected to a database.
import import import import flash.data.SQLConnection; flash.data.SQLStatement; flash.events.SQLErrorEvent; flash.events.SQLEvent;

// ... create and open the SQLConnection instance named conn var createStmt:SQLStatement = new SQLStatement(); createStmt.sqlConnection = conn; var sql:String = "CREATE TABLE IF NOT EXISTS employees (" + " empId INTEGER PRIMARY KEY AUTOINCREMENT, " + " firstName TEXT, " + " lastName TEXT, " + " salary NUMERIC CHECK (salary > 0)" + ")"; createStmt.text = sql; createStmt.addEventListener(SQLEvent.RESULT, createResult); createStmt.addEventListener(SQLErrorEvent.ERROR, createError); createStmt.execute(); function createResult(event:SQLEvent):void { trace("Table created"); } function createError(event:SQLErrorEvent):void { trace("Error code:", event.error.code); trace("Details:", event.error.message); }

Using synchronous and asynchronous database operations


Previous sections have described common database operations such as retrieving, inserting, updating, and deleting data, as well as creating a database file and tables and other objects within a database. The examples have demonstrated how to perform these operations asynchronouslyyou instruct the database to perform the operation, it does its work in the background, and when the operation is completed (or when it fails) an event is dispatched, which your code can listen for and use to carry out subsequent operations. This approach has a significant advantage: because the runtime performs the database operations in the background while the main application code continues executing. If the database operation takes a notable amount of time, the application continues to run and most importantly the user can continue to interact with it without the screen freezing. Nevertheless, asynchronous operation code can be more complex to write because multiple dependent operations must be divided up among various event listener methods rather than being able to write a sequence of steps.

ADOBE PRODUCT X.0 133


User Guide

In addition to asynchronous database operations, the runtime also allows you to execute database operations synchronously. The decision to execute operations asynchronously or synchronously isnt made on an operationby-operation basis; instead its specified by passing a value for the SQLConnection constructors isSync parameter when you create a SQLConnection instance. (The default value, which is used when no argument is passed, is false, meaning the connection doesnt use synchronous execution.) Once a SQLConnection instance is created, its execution mode (synchronous or asynchronous) is fixed; all database operations that are performed on any database thats opened using that SQLConnection instance will execute using the specified mode. This is true regardless of whether the operation is performed by calling a SQLConnection method (such as opening a connection using SQLConnection.open() or beginning a transaction using SQLConnection.begin()), or if the operation is a SQL statement such as a SELECT query thats executed using a SQLStatement instance whose sqlConnection property is set to the SQLConnection instance.

Using synchronous database operations


There is little difference in the actual code that you use to execute and respond to operations when using synchronous execution, except that you write the code as a series of steps rather than registering event listeners. To execute operations synchronously, when you create the SQLConnection instance, you must explicitly provide a true value for the SQLConnection() constructors isSync parameter (the methods only parameter). The code to create a SQLConnection instance that executes its operations synchronously looks like this:
// performs operations synchronously var conn:SQLConnection = new SQLConnection(true);

By creating it that way, all operations will be performed synchronously for that SQLConnection object. You can execute a series of database operations in succession within a single code block, as in the following example:
var conn:SQLConnection = new SQLConnection(true); var dbFile:File = File.applicationStorageDirectory.resolvePath("DBSample.db"); // open the database conn.open(dbFile, false); // start a transaction conn.begin(); // add the customer record to the database var insertCustomer:SQLStatement = new SQLStatement(); insertCustomer.sqlConnection = conn; insertCustomer.text = "INSERT INTO customers (firstName, lastName) " + "VALUES ('Bob', 'Jones')"; insertCustomer.execute(); var customerId:Number = insertCustomer.getResult().lastInsertRowID; // add a related phone number record for the customer var insertPhoneNumber:SQLStatement = new SQLStatement(); insertPhoneNumber.sqlConnection = conn; insertPhoneNumber.text = "INSERT INTO customerPhoneNumbers (customerId, number) " + "VALUES (:customerId, '800-555-1234')"; insertPhoneNumber.parameters[":customerId"] = customerId; insertPhoneNumber.execute(); // commit the transaction conn.commit();

ADOBE PRODUCT X.0 134


User Guide

As you can see, you call the same methods to perform database operations whether youre using synchronous or asynchronous execution. The key differences between the two approaches have to do with executing operations that depend on other operations (such as SELECT result rows or the primary key of the row added by an INSERT statement) and handling errors that can occur with any database operation.
Executing operations that depend on other operations

When youre using synchronous execution mode, instead of writing code that listens for an event to determine when an operation completes, you can assume that if an operation in one line of code completes successfully, execution will continue with the next line of code. Consequently, if you need to perform an operation that depends on the success of another operation or execute some code after a particular statement completes, you can simply write the dependent code immediately following the operation on which it depends. For instance, if your application needs to begin a transaction, execute an INSERT statement, retrieve the primary key of the inserted row, insert that primary key into another row of a different table, and finally commit the transaction, the code can all be written as a series of statements, as shown in the following example:
var conn:SQLConnection = new SQLConnection(true); var dbFile:File = File.applicationStorageDirectory.resolvePath("DBSample.db"); // open the database conn.open(dbFile, false); // start a transaction conn.begin(); // add the customer record to the database var insertCustomer:SQLStatement = new SQLStatement(); insertCustomer.sqlConnection = conn; insertCustomer.text = "INSERT INTO customers (firstName, lastName) " + "VALUES ('Bob', 'Jones')"; insertCustomer.execute(); var customerId:Number = insertCustomer.getResult().lastInsertRowID; // add a related phone number record for the customer var insertPhoneNumber:SQLStatement = new SQLStatement(); insertPhoneNumber.sqlConnection = conn; insertPhoneNumber.text = "INSERT INTO customerPhoneNumbers (customerId, number) " + "VALUES (:customerId, '800-555-1234')"; insertPhoneNumber.parameters[":customerId"] = customerId; insertPhoneNumber.execute(); // commit the transaction conn.commit(); Handling errors with synchronous execution

Rather than writing code that listens for an error event to determine that an operation has failed, with synchronous execution you surround any code that could trigger errors in a set of try..catch..finally code blocks. You wrap the error-throwing code in the try block, and the actions to perform in response to each type of error in separate catch blocks. Any code that should always be executed regardless of success or failure (for example, closing a database connection thats no longer needed) is placed in a finally block. The following example demonstrates this, adding to the previous one by adding error handling code:
var conn:SQLConnection = new SQLConnection(true); var dbFile:File = File.applicationStorageDirectory.resolvePath("DBSample.db");

ADOBE PRODUCT X.0 135


User Guide

// open the database conn.open(dbFile, false); // start a transaction conn.begin(); try { // add the customer record to the database var insertCustomer:SQLStatement = new SQLStatement(); insertCustomer.sqlConnection = conn; insertCustomer.text = "INSERT INTO customers (firstName, lastName)" + "VALUES ('Bob', 'Jones')"; insertCustomer.execute(); var customerId:Number = insertCustomer.getResult().lastInsertRowID; // add a related phone number record for the customer var insertPhoneNumber:SQLStatement = new SQLStatement(); insertPhoneNumber.sqlConnection = conn; insertPhoneNumber.text = "INSERT INTO customerPhoneNumbers (customerId, number)" + "VALUES (:customerId, '800-555-1234')"; insertPhoneNumber.parameters[":customerId"] = customerId; insertPhoneNumber.execute(); // if we've gotten this far without errors, commit the transaction conn.commit(); } catch (error:SQLError) { // rollback the transaction conn.rollback(); }

Understanding the asynchronous execution model


One common misconception about the AIR local database asynchronous execution model is that you cant start executing a SQLStatement instance if another SQLStatement is currently executing against the same database connection. In fact this isnt true. While a SQLStatement instance is executing you cant change the text property of the statement; however, if you follow the recommended practice of using separate SQLStatement instances for each different SQL statement that you want to execute, you can call the execute() method of a SQLStatement while another SQLStatement instance is still executing, without causing an error. Internally, when youre executing database operations using asynchronous execution mode, each database connection (each SQLConnection instance) has its own queue or list of operations that it is instructed to perform. The runtime executes each operation in sequence, in the order they are added to the queue. When you create a SQLStatement instance and call its execute() method, that statement execution operation is added to the queue for the connection. If no operation is currently executing on that SQLConnection instance, the statement begins executing in the background. If within the same block of code you create another SQLStatement instance and also call that methods execute() method, that second statement execution operation is added to the queue immediately after the first statement. As soon as the first statement finishes executing, the runtime moves to the next operation in the queue. This happens in the background, even while the result event for the first operation is being dispatched in the main application code. The following code demonstrates this technique:

ADOBE PRODUCT X.0 136


User Guide

// Using asynchronous execution mode var stmt1:SQLStatement = new SQLStatement(); stmt1.sqlConnection = conn; // ... Set statement text and parameters, and register event listeners ... stmt1.execute(); // At this point stmt1's execute() operation is added to conn's execution queue. var stmt2:SQLStatement = new SQLStatement(); stmt2.sqlConnection = conn; // ... Set statement text and parameters, and register event listeners ... stmt2.execute(); // At this point stmt2's execute() operation is added to conn's execution queue. // When stmt1 finishes executing, stmt2 will immediately begin executing // in the background.

A side effect of the database automatically executing subsequent queued statements is that if one statement or operation depends on the outcome of another operation, when youre using asynchronous execution mode you wont be able to make changes to the second statement once its execute() method is called, so you must wait for the event indicating the first operation completes before starting the next operation. For instance, if you want to execute a statement in the context of a transaction, the statement execution depends on the operation of opening the transaction. In that case, after calling the SQLConnection.begin() method to open the transaction, you would need to wait for the SQLConnection instance to dispatch its begin event before calling the SQLStatement instances execute() method. The simplest way to organize your application to ensure that the operations are executed properly is to create a method thats registered as a listener for the begin event, and call the SQLStatement.execute() method within that listener.

Strategies for working with SQL databases


There are various ways that an application can access and work with a local SQL database, in terms of how the application code can be organized, the sequence and timing of how operations are performed, and so forth. The techniques you choose can have an impact on how easy it is to develop your application, how easy it is to modify the application in future updates, and how well the application performs from the users perspective. This section includes the following topics:

Improving database performance Working with multiple databases Distributing a pre-populated database Best practices for working with local SQL databases

Improving database performance


This section describes several techniques that are built into Adobe AIR that allow you to improve the performance of database operations in your application:

Use prepared statements Minimize runtime processing

ADOBE PRODUCT X.0 137


User Guide

In addition to the techniques described in this section, the way a SQL statement is written can also impact database performance. Frequently, there are multiple ways to write a SQL SELECT statement to retrieve a particular result set, and in some cases the different approaches will require more or less effort from the database engine. This aspect of improving database performancedesigning SQL statements for better performanceis not covered in the Adobe AIR documentation.
Use prepared statements

Before any SQL statement is executed, the runtime prepares (compiles) it to determine the steps that will be performed internally to carry out the statement. When you call SQLStatement.execute(), the statement is automatically prepared before it is executed. You can also call the SQLStatement.prepare() method in advance, which will cause the statement to be prepared ahead of time so that it can be executed immediately when execute() is called (as long as the SQLStatement.text property hasnt changed in the mean time). In order to gain the maximum benefit from prepared statements, if values need to change between statement executions you should use statement parameters (specified using the SQLStatement.parameters associative array property) to customize your statement,. Unlike changing the SQLStatement instances text property, changing the values of statement parameters does not require the statement to be prepared again. For more information about using parameters in statements, see Using parameters in statements on page 120. Like executing a statement using the SQLStatement classs execute() method, preparing a statement using the prepare() method is an asynchronous operation. The statement preparation doesnt complete immediately, and you determine whether it succeeds or fails (and the reason for any failure) using event listeners. You can register event listeners using the addEventListener() method (specifying the SQLEvent.PREPARE and SQLErrorEvent.ERROR event types) or by passing a Responder object as an argument in the prepare() method call. Because preparing a statement is an operation that is potentially demanding, a good strategy is to wait until the initial start-up operations of your application have completed, or for another idle time in the application, and call the prepare() method at that point. For instance, if your application doesnt access the database at all in order to display its initial screen, you could wait until that screen display, then open the database connection using SQLConnection.open(), and finally create the SQLStatement instances and call the prepare() method for each one. Alternatively, your application might open and immediately display some data, such as the result of a particular query. In that case, youd want to just go ahead and execute the SQLStatement instance for that query, then (after the initial data is loaded and displayed) create SQLStatement instances for other database operations and call the prepare() method on them. A key aspect of using a prepared SQLStatement instance is that your application needs to keep a reference to the SQLStatement instance once it has been prepared, meaning it shouldnt be declared as a function-scope variable. In practice, the best way to do this is to structure your application so that a SQL statement (or a group of statements that are executed in combination) is wrapped in a single class. The SQLStatement instance or instances can be member variables of the class, meaning they will persist as long as the instance of the wrapper class exists in the application. In the most simple case, you can simply define a variable containing the SQLStatement instance outside of a function, (for example, as a member variable in an ActionScript class, or as a non-function variable in a JavaScript file) so that the instance persists in memory. You can then call the prepare() method of that instance when you want to prepare the statement, and later set parameter values and call its execute() method when you want to actually run the query.

ADOBE PRODUCT X.0 138


User Guide

Group multiple operations in a transaction

When youre executing a large number of SQL statements that involve adding or changing data (INSERT or UPDATE statements), you can get a significant increase in performance by executing all the statements within an explicit transaction. If you dont explicitly begin a transaction, each of the statements runs in its own implicit transaction, meaning that after each statement finishes executing the runtime writes the resulting data to the database file on the disk. On the other hand, if you explicitly create a transaction and execute the statements in the context of that transaction, the runtime will make all the changes in memory, and will write all the changes to the database file at one time when the transaction is committed. Because writing the data to disk is usually the most time-intensive part of the operation, writing to the disk one time rather than once per SQL statement can give you significantly better performance.
Minimize runtime processing

Using the following techniques can prevent unneeded work on the part of the database engine and make applications perform better:

Always explicitly specify database names in statementsuse main if its the main databaseto prevent the runtime from having to check each database to find the matching table (and to avoid the possibility of having the runtime choose the wrong database).
Always explicitly specify column names in SELECT and INSERT statements.

Break up SELECT statements that retrieve large numbers of rows: see Retrieving SELECT results in parts on page 124.

Working with multiple databases


Use the SQLConnection.attach() method to open a connection to an additional database on a SQLConnection instance that already has an open database. You give the attached database a name using the name parameter in the attach() method call. When writing statements to manipulate that database, you can then use that name in a prefix (using the form database-name.table-name) to qualify any table names in your SQL statements, indicating to the runtime that the table can be found in the named database. You can execute a single SQL statement that includes tables from multiple databases that are connected to the same SQLConnection instance. If a transaction is created on the SQLConnection instance, that transaction applies to all SQL statements that are executed using the SQLConnection instance, regardless of which attached database the statement runs on. Alternatively, you can also create multiple SQLConnection instances in an application, each of which is connected to one or multiple databases. One important point to keep in mind if you use this approach is that database transactions are not shared across SQLConnection instances. Consequently, if you connect to the same database file using multiple SQLConnection instances, you cannot rely on both connections data changes being applied in the expected manner. For example, if two operations are performed against the same database through different SQLConnection instances, and the application has an error after one operation takes place, the database data could be left in an intermediate state that would not be reversible and might affect the application.

Distributing a pre-populated database


When you use an AIR local SQL database in your application, its likely that the application will expect a certain database structure. Some applications will also expect pre-populated data in their database file. One approach to creating the initial structure of the database for the application is to have the application check for the existence of its database file in a particular location. if the file doesnt exist, the application can execute a set of commands to create the database file, create the database structure, and populate the tables with the initial data.

ADOBE PRODUCT X.0 139


User Guide

As an alternative to creating the database, structure, and data programmatically, you can distribute a pre-populated database with your application by including the database file in the applications AIR package. This has the benefit of removing the need for a complex set of program instructions (the code that creates the database and its tables) that are only used once in the lifetime of the application, but still add to the size and complexity of the application. One important issue to keep in mind if youre using the approach of including a pre-created database in your AIR file has to do with the initial location where the database file is placed when the application is installed. Like all files that are included in an AIR package, a bundled database file will be installed in the applications resource directory. However, because the user who is running the application may not necessarily be the user who installed the application, that user may not have the necessary permission from the operating system to write to the file in its default location. Instead, it is recommended that you use the file that is included in the AIR package as a template database, from which individual users databases can be created. The first time a user runs the application, the original database file can be copied into the users application storage directory (or another location), and that database can be the one thats actually used by the application, thereby avoiding the issue.

Best practices for working with local SQL databases


The following list is a set of suggested techniques you can use to improve the performance, security, and ease of maintenance of your applications when working with local SQL databases:
Pre-create database connections Even if your application doesnt need to execute any statements when it first loads, instantiate a SQLConnection object and call its open() method ahead of time (such as after the initial application startup) to avoid delays when running statements. Re-use database connections If you will be accessing a certain database throughout the execution time of your

application, keep a reference to a SQLConnection instance, and reuse it throughout the application.
Use asynchronous execution mode When writing data-access code it can be tempting to execute operations

synchronously rather than asynchronously, because using synchronous operations frequently requires shorter and less complex code. However, as described in Using synchronous and asynchronous database operations on page 132, synchronous operations can have a performance impact that is obvious to users and detrimental to their experience with an application, because the applications code (including the code that refreshes the display) waits for the database operations to complete before running. The amount of time the operation takes will vary according to the operation and particularly the amount of data it affects. For instance, A SQL INSERT statement that only adds a single row to the database will take less time than a SELECT statement that retrieves thousands of rows of data. However, when youre using synchronous execution to perform multiple operations, while the time each operation takes may be very short, the application will be frozen until all synchronous operations are completed, so the cumulative time of multiple operations strung together may be enough to stall your application. You should use asynchronous operations as a standard approach, especially with operations that involve large numbers of rows. You should only use synchronous operations when you cant achieve certain functionality using asynchronous programming, when youve considered the performance trade-offs that your applications users will face, and when youve tested your application so that you know how your applications performance is actually affected. While it may involve more complex coding, remember that you only have to write the code once, but the applications users may have to use it repeatedly. Note that in many cases, by using a separate SQLStatement instance for each SQL statement to be executed, multiple SQL operations can be queued up at one time, which makes asynchronous code similar to synchronous code in terms of how code is written. For more information, see

ADOBE PRODUCT X.0 140


User Guide

Use prepared SQL statements For any SQL statement that will be executed more than once in an application, create the SQLStatement instance and call its prepare() method ahead of time to reduce processing time later. For example, your application might load its initial screen or initial set of data to get the user started, then instantiate the SQLStatement instances and call their prepare() methods. See Use prepared statements on page 137 for more information. Use statement parameters Use SQLStatement parametersnever concatenate user input into statement text. Doing so makes your application more secure (it prevents the possibility of SQL injection attacks), makes it possible to use objects in queries (rather than only SQL literal values), and makes statements run more efficiently (because they can be reused without needing to be recompiled each time theyre executed). Use constants for column and parameter names When you dont specify an itemClass for a SQLStatement, to

avoid spelling errors, define constants for column names and use the constants in the statement text and for the property names when retrieving values from result objects.

See also

Improving database performance on page 136

141

Part 1: Adding content to AIR applications


Adding HTML content to SWF-based applications. . . . . . . . . . . . . . . . . . . . . . . . . . .162 Rendering PDF content in AIR applications. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .142

142

Chapter 15: Rendering PDF content in AIR applications


AIR applications can render not only SWF files and HTML content but also PDF files. PDF files, implemented using HTMLControl objects and the WebKit engine, can either stretch across the full height and width of your application or alternatively as a portion of the interface. The Acrobat Reader browser plug-in controls display of PDF files in an Adobe AIR application, so modifications to Reader's toolbar interface (position, anchoring, visibility, etc.) will persist in subsequent viewing of PDF files in both AIR applications and the browser.

Detecting PDF Capability


If the user does not have an installed version of Adobe Reader 8.1 plug-in or greater, PDF content will not display in an AIR application; the HTMLControl instance will remain unaffected. To detect if a user can render PDF content, first check the HTMLControl.pdfCapability property. This property will return one of the following constants of the HTMLPDFCapability class:
HTMLPDFCapability.STATUS_OK A A sufficient version (8.1 or greater) of Acrobat Reader is detected and PDF content can be loaded into an HTMLControl object HTMLPDFCapability.ERROR_INSTALLED_READER_NOT_FOUND A No version of Acrobat Reader is detected. An

HTMLControl object cannot display PDF content.


HTMLPDFCapability.ERROR_INSTALLED_READER_TOO_OLD A Acrobat Reader has been detected, but the version is

too old. An HTMLConrol object cannot display PDF content.


HTMLPDFCapability.ERROR_PREFERRED_READER_TOO_OLD A A sufficient version (8.1 or later) of Acrobat Reader is detected, but the version of Acrobat Reader that is setup to handle PDF content is older than Reader 8.1. An HTMLConrol object cannot display PDF content.

Note: On Windows, if Adobe Acrobat or Acrobat Reader version 7.x or above is currently running on the user's system, that version is used even if a later version that supports loading PDF loaded in an HTMLControl object is installed. In this case, if the value of the pdfCampability property is HTMLPDFCapability.STATUS_OK, when an AIR application attempts to load PDF content into an HTMLControl object, the older version of Acrobat or Reader displays an alert, without an error message displayed the Apollo runtime. If this is a possibility situation for your end users, you may consider providing them with instructions to close Acrobat while running your application. You may consider displaying these instructions if the PDF content does not load within an acceptable time frame. The following code detects whether a user can display PDF content in an AIR application, and if not traces the error code that corresponds to the HTMLPDFCapability error object:

import flash.html.HTMLControl; import flash.net.URLRequest; if(HTMLControl.pdfCapability == HTMLPDFCapability.STATUS_OK) { trace("PDF content can be displayed"); } else {

ADOBE PRODUCT X.0 143


User Guide

trace("PDF cannot be displayed. Error code: " + HTMLControl.pdfCapability); }

Adding a PDF to the display


You can add a PDF within the Adobe Reader interface to an AIR application by creating an HTMLControl instance, setting its dimensions, and loading the path of a PDF. The following example loads a PDF from an external site. Replace the URLRequest with the path to an available external PDF.
var request:URLRequest = new URLRequest("http://www.exampledomain.com/test.pdf"); pdf = new HTMLControl(); pdf.height = 800; pdf.width = 600; pdf.load(request); container.addChild(pdf);

Known limitations in the beta release


The beta release version of Adobe AIR includes the following limitations:

PDF content does not display in a window (a NativeWindow object) that is transparent (where the transparent property is set to true). The display order of a PDF file operates differently than other display objects in an Apollo application. Although a PDF will correctly clip according to HTML display order, it will always sit on top of content in the AIR application's display order. The visual properties of an HTMLControl object that contains a PDF file cannot be changed. Changes to an HTMLControl object's filters, alpha, rotation, or scaling will render the PDF file invisible until the properties are reset. Within a PDF file, links to content within the PDF file will update the scroll position of the PDF. Links to content outside the PDF will redirect the HTMLControl object that contains the PDF. Links that target a new window will be ignored.

Forms
PDF files that contain forms will only post correctly if form posting uses a supported link format and returns PDF or HTML. Adobe discourages the use of forms that return FDF or rely heavily on JavaScript communication. Collaborative PDF forms will not function correctly in AIR 1.0.

144

Part 1: Interacting with the operating system


Application invocation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .145 Capturing command line arguments . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .146 Registering file types. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .148 Reading the application descriptor file . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .149 Getting the runtime version and patch level . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .149 Detecting AIR capabilities . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .149 Tracking user presence. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .150 Taskbar icons . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .150 Application termination. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .154

145

Chapter 17: Interacting with the operating system


Though AIR applications are designed to run on multiple operating systems that support the AIR runtime, there are ways in which you may want the AIR application to interact with the host operating system. For instance, you may want to capturing command line arguments passed when the application was launched. The Shell class defines properties, methods, and events useful in interacting with the operating system. This section contains the following topics: Application invocation on page 145

Capturing command line arguments on page 146 Registering file types on page 148 Reading the application descriptor file on page 149 Getting the runtime version and patch level on page 149 Detecting AIR capabilities on page 149 Tracking user presence on page 150 Taskbar icons on page 150 Application termination on page 154

Application invocation
An AIR application is invoked when the user (or the operating system): launches the application from the desktop shell

uses the application as a command on a command-line shell opens a type of file for which the application is the default opening application (Mac OS X) clicks the application icon in the dock taskbar (whether or not the application is currently running)

chooses to launch the application from the installer (either at the end of a new installation process, or after double-clicking the AIR file for an already installed application). begins an update of an AIR application when the installed version has signaled that it should handle application updates itself by including a <handleUpdates/> flag in the application descriptor
Whenever an AIR application is invoked, AIR dispatches an InvokeEvent object through the singleton Shell object. To allow an application time to initialize itself and register an event listener, invoke events are queued instead of discarded when there are no registered listeners for the event. As soon as a listener is registered, all the queued events are delivered. Only one instance of an AIR application will be started. When an already running application is invoked again, AIR dispatches a new invocation event to the running instance. It is an AIR applications responsibility to respond to an invocation event and take the appropriate action (such as opening a new document window to display the file contents).

ADOBE PRODUCT X.0 146


User Guide

An invocation event object contains any arguments passed to the application, as well as the directory from which the application has been invoked. If the application was invoked because of a file-type association, then the full path to the file is included in the command line arguments. Likewise, if the application was invoked because of an application update, the full path to the update AIR file is provided. The invocation event object is defined by the AIR InvokeEvent class. Your application can handle invocation events by registering a listener with its Shell object:
Shell.shell.addEventListener(InvokeEvent.INVOKE,onInvokeEvent);

And defining an event handler:


var arguments:Array; var currentDir:File; public function onInvokeEvent(invocation:InvokeEvent):void{ arguments = invocation.arguments; currentDir = invocation.currentDirectory; }

See also

Setting application properties on page 41 Presenting a custom application update user interface on page 175

Capturing command line arguments


The command line arguments associated with the invocation of an AIR application are delivered in the invoke event dispatched by the Shell object. The InvokeEvent.arguments property contains an array of the arguments passed by the operating system when an AIR application is invoked. If the arguments contain relative file paths, you can typically resolve the paths using the currentDirectory property. The arguments passed to an AIR program are treated as white-space delimited strings, unless enclosed in double quotes:
Arguments tick tock tick "tick tock" "tick" tock \"tick\" \"tock\" Array {tick,tock} {tick,tick tock} {tick,tock} {"tick","tock"}

The InvokeEvent.currentDirectory property contains a File object representing the directory from which the application was launched. When an application is invoked because a file of a type registered by the application is opened, the native path to the file is included in the command-line arguments as a string. (It is your applications responsibility to open or perform the intended operation on the file.) Likewise, when an application handles updates itself, the native path to the AIR file will be included when a user double-clicks an AIR file containing an application with a matching application ID. You can access the file using the resolve() method of the currentDirectory File object:
if((invokeEvent.currentDirectory != null)&&(invokeEvent.arguments.length > 0)){ dir = invokeEvent.currentDirectory; fileToOpen = dir.resolvePath(invokeEvent.arguments[0]); }

You should also validate that an argument is indeed a path to a file.

ADOBE PRODUCT X.0 147


User Guide

Example: Invocation event log


The following example demonstrates how to register listeners for and handle the InvokeEvent. The example logs all the invocation events received and displays the current directory and command-line arguments. Note: To create the following example using Flash CS3, first create a new Flash File (Adobe AIR). In the ActionScript 3.0 Settings panel (File > Publish Settings... > Settings button) enter the name InvokeEventLogExample in the Document class field. Save the Flash file with the name InvokeEventLogExample.fla. Next create a new ActionScript File in the same folder. Enter the following code into the ActionScript file and then save the file with the name InvokeEventLogExample.as.
package { import import import import

flash.display.Sprite; flash.events.InvokeEvent; flash.system.Shell; flash.text.TextField;

public class InvokeEventLogExample extends Sprite { public var log:TextField; public function InvokeEventLogExample() { log = new TextField(); log.x = 15; log.y = 15; log.width = 520; log.height = 370; log.background = true; addChild(log); Shell.shell.addEventListener(InvokeEvent.INVOKE, onInvoke); } public function onInvoke(invokeEvent:InvokeEvent):void { var now:String = new Date().toTimeString(); logEvent("Invoke event received: " + now); if(invokeEvent.currentDirectory != null) { logEvent("Current directory=" + invokeEvent.currentDirectory.nativePath); } else { logEvent("--no directory information available--"); } if(invokeEvent.arguments.length > 0) { logEvent("Arguments: " + invokeEvent.arguments.toString()); } else { logEvent("--no arguments--"); } } public function logEvent(entry:String):void

ADOBE PRODUCT X.0 148


User Guide

{ log.appendText(entry + "\n"); trace(entry); } } } <?xml version="1.0" encoding="utf-8"?> <mx:WindowedApplication xmlns:mx="http://www.adobe.com/2006/mxml" layout="vertical" invoke="onInvoke(event)" title="Invocation Event Log"> <mx:Script> <![CDATA[ import flash.events.InvokeEvent; import flash.system.Shell; public function onInvoke(invokeEvent:InvokeEvent):void{ var now:String = new Date().toTimeString(); logEvent("Invoke event received: " + now); if(invokeEvent.currentDirectory != null){ logEvent("Current directory=" + invokeEvent.currentDirectory.nativePath); } else { logEvent("--no directory information available--"); } if(invokeEvent.arguments.length > 0){ logEvent("Arguments: " + invokeEvent.arguments.toString()); } else { logEvent("--no arguments--"); } } public function logEvent(entry:String):void { log.text += entry + "\n"; trace(entry); } ]]> </mx:Script> <mx:TextArea id="log" width="100%" height="100%" editable="false" valueCommit="log.verticalScrollPosition=log.textHeight;"/> </mx:WindowedApplication>

Registering file types


You can register an application to be the default system application for handling specific file extensions. To do this, add the file extension to the list of registered file types in the application descriptor file, as in the following:
<fileTypes> <fileType> <name>adobe.VideoFile</name> <extension>avf</extension> <description>Adobe Video File</description> <contentType>application/vnd.adobe.video-file</contentType> </fileType> </fileTypes>

More than one <fileType> element can be placed within the <fileTypes> element to register more than one extension.

ADOBE PRODUCT X.0 149


User Guide

For details, see Registering file types on page 45.

Reading the application descriptor file


You can read the application descriptor file of the currently running application, as an XML object, by getting the applicationDescriptor property of the Shell object, as in the following:
var appXml:XML = Shell.shell.applicationDescriptor;

The Shell object also has an id property, that is the application ID for the file, as illustrated in the following code:
trace(Shell.shell.id);

For more information, see The application descriptor file structure on page 41.

Getting the runtime version and patch level


The Shell object also has a runtimeVersion property, which is the version of the runtime in which the application is running (a string, such as "1.0.5"), and a runtimePatchLevel property, which is the patch level of the runtime (a number, such as 2960), as illustrated in the following code:
trace(Shell.shell.runtimeVersion); trace(Shell.shell.runtimePatchLevel);

Detecting AIR capabilities


For a file that is bundled with the Adobe AIR application, the Security.sandboxType property is set to the value defined by the Security.APPLICATION constant. So, you can check to see if a file is in the Adobe AIR security sandbox, and load other content (which may or may not contain APIs specific to AIR) accordingly, as in the following:
if (Security.sandboxType == Security.APPLICATION) { // Load SWF that contains AIR APIs } else { // Load SWF that does not contain AIR APIs }

All resources that are not installed with the AIR application are put in the same security sandboxes as they would be placed in if they were running in Flash Player in a web browser. Remote resources are put in sandboxes according to their source domains, and local resources are put in the local-with-networking, local-with-filesystem, or localtrusted sandbox.

ADOBE PRODUCT X.0 150


User Guide

Although content outside of the AIR application security sandbox may access AIR runtime APIs, but some functionality (such as attempting to read files from the filesystem) will result in a runtime security exception. You can check if the Capabilities.playerType static property is set to Security.APPLICATION to see if content is in the runtime (and not running in Flash Player running in a browser). For more information, see AIR Security on page 31.

Tracking user presence


The Shell object dispatches two events that help you detect when a user is actively using a computer. If no mouse or keyboard activity is detected in the interval determined by the Shell.idleThreshold property, then the Shell will dispatch a user idle event. When the next keyboard or mouse input occurs, the Shell object will dispatch a user present event. The idleThreshold interval is measured in seconds and has a default value of 300 (5 minutes). You can also get the number of seconds since the last user input from the Shell.shell.lastUserInput property. The following lines of code, set the idle threshold to 2 minutes and listen for both the user idle and user present events:
Shell.shell.idleThreshold = 120; Shell.shell.addEventListener(Event.USER_IDLE,function(event:Event){ trace(Idle); }); Shell.shell.addEventListener(Event.USER_PRESENT,function(event:Event){ trace(Present); });

Note: Only a single idle event will be dispatched between present events.

Taskbar icons
Many operating systems provide a taskbar, such as the Mac OS X dock, that can contain an icon to represent an application. AIR provides an interface for interacting with the application task bar icon through the Shell.shell.icon property. AIR creates the Shell.shell.icon object automatically (whether or not the icon is visible). The object type will always be a subclass of InteractiveIcon, either DockIcon or SystemTrayIcon, depending on the operating system. You can determine which subclass AIR supports on the current operating system using the Shell.supportsDockIcon and Shell.supportsSystemTrayIcon properties. The InteractiveIcon base class provides the properties width, height, and bitmaps, which you can use to change the image used for the icon, but accessing properties specific to DockIcon or SystemTrayIcon on the wrong operating system will generate runtime exceptions. To set or change the image used for an icon, create an array containing one or more images and assign it to the Shell.shell.icon.bitmaps property. The size of taskbar icons is very different on different operating systems. You can provide multiple sizes of images in the bitmaps array to avoid scaling. If more than one image is supplied in the array, AIR will select the size closest to the current display size of the taskbar icon, scaling it if necessary. The following example sets the image for a taskbar icon:
Shell.shell.icon.bitmaps = [bmp16x16.bitmapData, bmp128x128.bitmapData];

You can animate the icon by resetting the bitmaps property with an array containing a different image in response to the stage enterFrame event or a timer event. (Only one image in a bitmaps array is used.)

ADOBE PRODUCT X.0 151


User Guide

To remove the icon from the task bar on Windows, or restore the default icon appearance on Mac OS X, set bitmaps to an empty array:
Shell.shell.icon.bitmaps = [];

Dock icons
AIR supports dock icons when Shell.supportsDockIcon is true. The Shell.shell.icon property represents the application icon on the dock (not a window dock icon).
Dock icon menus

You can add commands to the standard dock menu by creating a new NativeMenu object containing the commands and assigning it to the Shell.shell.icon.menu property. The items in the menu will be displayed above the standard dock icon menu items.
Bouncing the dock

You can bounce the dock icon by calling the Shell.shell.icon.bounce() method. If you set the bounce() priority parameter to informational, then the icon will bounce once. If you set it to critical, then the icon will bounce until the user activates the application. Constants for the priority parameter are defined in the NotificationType class. Note: The icon will not bounce if the application is already active.
Dock icon events

When the dock icon is clicked, the Shell object will dispatch an InvokeEvent. If the application is not running, the system will launch it; otherwise, the invocation event will be delivered to the running version.

System Tray icons


AIR supports system tray icons when Shell.supportsSystemTrayIcon is true. System tray icons are displayed in the notification area of the taskbar. No icon is displayed by default, to show an icon, assign an array containing BitmapData objects to the icon bitmaps property. To change the icon image, assign an array containing the new images to bitmaps. To remove the icon, set bitmaps to null. Note: In this Beta release, the system tray icon will disappear if you close all the windows in an application, even if the application is still running in the background. To work around this problem, retain a hidden window (set visible=false for the window).
System tray icon menus

You can add a menu to the system tray icon by creating a new NativeMenu object and assigning it to the Shell.shell.icon.menu property (no default menu is provided by the operating system) The system tray icon is accessed by right-clicking the icon.
System tray icon tooltips

Add a tooltip to an icon by setting the tooltip property:


Shell.shell.icon.tooltip = Application name; System tray icon events

The system tray icon dispatches ScreenMouseEvents for click, mouseDown, mouseUp, rightClick, rightMouseDown, and rightMouseUp events. You can use these events, along with a menu, to allow users to interact with your application when it has no visible windows.

ADOBE PRODUCT X.0 152


User Guide

Example: Creating an application with no windows

The following example creates an AIR application which has a system tray icon, but no visible windows. The system tray icon has a menu with a single command for exiting the application.
package { import import import import import import import import import flash.display.Loader; flash.display.NativeMenu; flash.display.NativeMenuItem; flash.display.NativeWindow; flash.display.Sprite; flash.display.SystemTrayIcon; flash.events.Event; flash.net.URLRequest; flash.system.Shell;

public class SysTrayApp extends Sprite { Shell.shell.autoExit = false; var iconLoader:Loader = new Loader(); var iconMenu:NativeMenu = new NativeMenu(); var exitCommand:NativeMenuItem = iconMenu.addItem(new NativeMenuItem("Exit")); exitCommand.addEventListener(Event.SELECT,function(event:Event):void{ Shell.shell.icon.bitmaps = []; Shell.shell.exit(); }); if(Shell.supportsSystemTrayIcon){ Shell.shell.autoExit = false; iconLoader.contentLoaderInfo.addEventListener(Event.COMPLETE, iconLoadComplete); iconLoader.load(new URLRequest("icons/AIRApp_16.png")); var systray:SystemTrayIcon = Shell.shell.icon as SystemTrayIcon; systray.tooltip = "AIR application"; systray.menu = iconMenu; } if(Shell.supportsDockIcon){ iconLoader.contentLoaderInfo.addEventListener(Event.COMPLETE, iconLoadComplete); iconLoader.load(new URLRequest("icons/AIRApp_128.png")); var dock:DockIcon = Shell.shell.icon as DockIcon; dock.menu = iconMenu; } //In this Beta release, you must keep a window open or the icon will be removed //stage.nativeWindow.close(); stage.nativeWindow.visible = false; } private function iconLoadComplete(event:Event):void { Shell.shell.icon.bitmaps = [event.target.content.bitmapData]; } } }

ADOBE PRODUCT X.0 153


User Guide

When you set the dock icon image, the change will only apply while the application is running. When the user quits, the icon image will revert to the icon specified in the application descriptor (or the operating system default icon if no icon image has been provided). This example assumes that there are image files named AIRApp_16.png and AIRApp_128.png in an icons subdirectory of the application. (Sample icon files are included with the AIR SDK.)

Window taskbar icons


Iconified representations of windows are typically displayed in the window area of a taskbar or dock to allow users to easily access background or minimized windows.
Highlighting the taskbar window icon

When a window is in the background, you can notify the user that an event of interest related to the window has occurred. On Mac OS X, you can notify the user by bouncing the application dock icon (as described in Bouncing the dock on page 151). On Windows, you can highlight the window taskbar icon by calling the windows notifyUser() method. The type parameter passed to the method determines the urgency of the notification: NotificationType.CRITICAL: the window icon will flash until the user brings the window to the foreground.

NotificationType.INFORMATIONAL: the window icon will highlight by changing color.

var type:String; if(critical){ type = NotificationType.CRITICAL; } else{ type = NotificationType.INFORMATIONAL; } stage.nativeWindow.notifyUser(type);

Calling the window notifyUser() method on an operating system that does not support window-level notification will have no affect. Use the NativeWindow.supportsNotification property to determine if window notification is supported.
Creating windows without taskbar window icons

On the Windows operating system, you can prevent the window from appearing on the taskbar by creating windows of type utility or lightweight. Invisible windows also do not appear on the taskbar. Because the initial window is necessarily of type, normal, in order to create an application without any windows that appear in the taskbar, you must leave the initial window created at startup invisible. To do this, add <visible>false</visible> to the <initalWindow> element of the application descriptor file (and dont set visible=true or call activate() on the window). In the NativeWindowInitOption object used to create any new windows, set type to NativeWindowType.UTILITY or NativeWindowType.LIGHTWEIGHT.
Changing the image of a window taskbar icon

On Windows, you can change the icon that is displayed on the window system chrome title bar and in the iconified representation of the window in the task bar. To change the icon image, assign an array containing the BitmapData objects for the new image to the windows icon property. (You can use the Loader class to load image files.) Because not all windows have an icon, you should check that the property is not null before attempting to assign a value to it.
if(nativeWindow.icon != null){ nativeWindow.icon.bitmaps = new Array(loadedImage.bitmapData); }

ADOBE PRODUCT X.0 154


User Guide

Note: AIR does not support changing window icons on the dock under Mac OS X. (You can only change the dock icon for a running application.)

Application termination
The quickest way to end it all is to call Shell.shell.exit() and this works fine when your application has no data to save or resources to clean up. Calling exit() will automatically close all windows and then terminate the application. However, to allow windows or other components of your application to interrupt the termination process, perhaps to save vital data, you must dispatch the proper warning events before calling exit(). Another consideration in gracefully shutting down an application is providing a single execution path, no matter how the shut-down process starts. Application termination can be triggered by the user (or OS) in the following ways: Closing the last application window when Shell.shell.autoExit=true.

Application exit command from the OS, for example, when the user chooses exit application command from the default menu. This will only happen on Mac OS X; Windows does not provide an application exit command through system chrome.
Computer shut down.

When exit command is mediated through the operating system by one of these routes, the Shell object will dispatch an exiting event. If no listeners cancel the exiting event, any open windows are closed. Each window will dispatch a closing and then a close event. If any of the windows cancel the closing event, the shut-down process will halt. If the order of window closure is an issue for your application, then you should listen for the exiting event from the Shell and close the windows in the proper order yourself. This might be the case, for example, if you have a document window with tool palettes. It might be inconvenient, or worse, if the system closed the palettes, but the user decided to cancel the exit command to save some data. On Windows, the only time you will get the exiting event is after closing the last window (when autoExit=true). A good practice for exiting the application, which provides consistent behavior on all platforms and whether or not the exit sequence is initiated via operating system chrome or menu commands, or initiated through application logic, is to: 1 Always dispatch an exiting event through the Shell object before calling exit() in application code and check that another component of your application doesnt cancel the event.
public function applicationExit():void{ var exitingEvent:Event = new Event(Event.EXITING,false,true); Shell.shell.dispatchEvent(exitingEvent); if(!exitingEvent.isDefaultPrevented()){ Shell.shell.exit(); } }

2 Listen for the exiting event and in the handler close any windows (dispatching a closing event first) and then perform any needed clean up tasks such as saving application data, deleting temporary files, etc. Only synchronous methods should be used to ensure that they will finish before the application quits.

If the order in which your windows are closed doesnt matter, then you can loop through the Shell.shell.openedWindows array and close each window in turn. If order does matter, then you will have to provide a means of closing the windows in the correct sequence.
private function onExiting(exitingEvent:Event):void{

ADOBE PRODUCT X.0 155


User Guide

var winClosingEvent:Event; for each(var win:NativeWindow in Shell.shell.openedWindows){ winClosingEvent = new Event(Event.CLOSING,false,true); win.dispatchEvent(winClosingEvent); if(!winClosingEvent.isDefaultPrevented()){ win.close(); } else{ exitingEvent.preventDefault(); } } if(!exitingEvent.isDefaultPrevented()){ //perform cleanup } }

Windows should always handle their own clean up by listening for the window closing event.

4 Only one exiting listener should be used in your application since handlers called earlier cannot know whether subsequent handlers will cancel the exiting event (and it would be unwise to rely on the order of execution).

156

Part 1: Networking and communications


Monitoring network connectivity. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .1 URL requests . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .1 Scripting and communications between applications and content . . . . . . . . . . . . . .162

157

Chapter 19: Monitoring network connectivity


The air.net package includes three classes that can be used to detect network connectivity: ServiceMonitor, SocketMonitor, and URLMonitor. These classes are not available automatically in the runtime. To use these classes in ActionScript code (in SWF development), include the ServiceMonitor.swc file in the compiler. To use these classes in JavaScript code (in HTML development), load the ServiceMonitor.swf file (via a script tag), as in the following:
<script src="ServiceMonitor.swf" type="application/swf">

Service Monitoring
Your AIR application can run in environments with uncertain and changing network connectivity. To help an application manage connections to online resources, Adobe AIR sends a network change event whenever a network connection becomes available or unavailable. The network change event is dispatched by the applications flash.system.Shell object. To react to this event, add a listener:
Shell.shell.addEventListener(Event.NETWORK_CHANGE, onNetworkChange);

And define an event handler function:


function onNetworkChange(event:Event) { //Check resource availability }

The Event.NETWORK_CHANGE event does not indicate a change in all network activity, only that a network connection has changed. AIR does not attempt to interpret the meaning of the network change. A networked computer may have many real and virtual connections, so losing a connection does not necessarily mean losing a resource. On the other hand, new connections do not guarantee improved resource availability, either. Sometimes a new connection can even block access to resources previously available (for example, when connecting to a VPN). In general, the only way for an application to determine whether it can connect to a remote resource is to try it. To this end, the service monitoring frameworks in the air.net package provide AIR applications with an event-based means of responding to changes in network connectivity to a specified host. Note: The service monitoring framework detects whether a server responds acceptably to a request. This does not guarantee full connectivity. Scalable web services often use caching and load-balancing appliances to redirect traffic to a cluster of web servers. In this situation, service providers only provide a partial diagnosis of network connectivity.

Service monitoring basics


The service monitor framework, separate from the AIR framework, resides in the file servicemonitor.swc. This file must be included in your build process in order to use the framework.

ADOBE PRODUCT X.0 158


User Guide

The ServiceMonitor class implements the framework for monitoring network services and provides a base functionality for service monitors. By default, an instance of the ServiceMonitor class will dispatch events regarding network connectivity. These events will be dispatched, when the instance is created and whenever a network change is detected by Adobe AIR. Additionally, you can set the pollInterval property of a ServiceMonitor instance to check connectivity at a specified interval in milliseconds, regardless of general network connectivity events. An instance of ServiceMonitor will not check network connectivity until the start() method is called. The URLMonitor class, subclassing the ServiceMonitor class, detects changes in HTTP connectivity for a specified URLRequest. The SocketMonitor class, also subclassing the ServiceMonitor class, detects changes in connectivity to a specified host at a specified port.

Detecting HTTP connectivity


The URLMonitor class determines if HTTP requests can be made to a specified address at port 80 (the typical port for HTTP communication). The following code uses an instance of the URLMonitor class to detect connectivity changes to the Adobe website:
import air.net.URLMonitor; import flash.net.URLRequest; import flash.events.StatusEvent; var monitor:URLMonitor; monitor = new URLMonitor(new URLRequest('http://www.adobe.com')); monitor.addEventListener(StatusEvent.STATUS, announceStatus); monitor.start(); function announceStatus(e:StatusEvent):void { trace("Status change. Current status: " + monitor.available); }

Detecting Socket connectivity


AIR applications can also use socket connections for push-model connectivity. Firewalls and network routers typically restrict network communication on unauthorized ports for security reasons. For this reason, developers must consider that users may not have the capability of making socket connections. Similar to the URLMonitor example, the following code uses an instance of the SocketMonitor class to detect connectivity changes to a socket connection at 6667, a common port for IRC.
import air.net.ServiceMonitor; import flash.events.StatusEvent; socketMonitor = new SocketMonitor('www.adobe.com',80); socketMonitor.addEventListener(StatusEvent.STATUS, socketStatusChange); socketMonitor.start(); function announceStatus(e:StatusEvent):void { trace("Status change. Current status: " + socketMonitor.available); }

159

Chapter 20: URL requests


The new Adobe AIR functionality related to networking and communications is not available to SWF content running in the browser. This functionality is only available to content in the application security sandbox. For content in other sandboxes (such as content in a network sandbox, like the sandbox for www.example.com), calling any of these APIs will cause Adobe AIR to throw a SecurityError exception. For other information on using ActionScript 3.0 networking and communications capabilities, see Programming ActionScript 3.0, delivered with both Adobe Flash CS3 and Adobe Flex Builder 2.0. This section contains the following topics:

Using the URLRequest class Changes to the URLStream class Opening a URL in the default system web browser

This section describes AIR networking and communication APIfunctionality uniquely provided to applications running in the AIR runtime. It does not describe networking and communications functionality inherent to HTML and JavaScript that would function in a web browser (such as the capabilities provided by the XMLHttpRequest class).

Using the URLRequest class


The URLRequest class lets you define more than simply the URL string. AIR adds some new properties to the URLRequest class, which are only available to AIR content running in the application security sandbox.
URLRequest properties

The URLRequest class includes the following properties which are available to content only in the AIR application security sandbox:
followRedirects Specifies whether redirects are to be followed (true, the default value) or not (false). This is only supported in the runtime. manageCookies Specifies whether the HTTP protocol stack should manage cookies (true, the default value) or not (false) for this request. This is only supported in the runtime. shouldAuthenticate Specifies whether authentication requests should be handled (true) for this request. This is

only supported in the runtime. The default is to authenticate requeststhis may cause an authentication dialog box to be displayed if the server requires credentials to be shown. You can also set the user name and passwordsee Setting login credentials for a URLRequest object on page 160.
shouldCacheResponse Specifies whether successful response data should be cached for this request. This is only

supported in the runtime. The default is to cache the response (true).


useCache Specifies whether the local cache should be consulted before this URLRequest fetches data. This is only

supported in the runtime. The default (true) is to use the local cached version, if available.
userAgent Specifies the user-agent string to be used in the HTTP request.

ADOBE PRODUCT X.0 160


User Guide

The following properties of a URLRequest object can be set by content in any sandbox (not just the AIR application security sandbox):
contentType The MIME content type of any data sent with the URL request. data An object containing data to be transmitted with the URL request. digest A secure "digest" to a cached file to track Flash Player cache. method Controls the HTTP request method, such as a GET or POST operation. (Content running in the AIR application security domain can specify strings other than "GET" or "POST" as the method property. Any HTTP verb is allowed and "GET" is the default method. See AIR Security on page 31.) requestHeaders The array of HTTP request headers to be appended to the HTTP request. url Specifies the URL to be requested.

Note: The HTMLControl class has related properties for settings pertaining to content loaded by an HTMLControl object. For details, see Loading HTML content from a URL on page 163.
Setting login credentials for a URLRequest object

The setLoginCredentials() method lets you set the user name and password to use for the URLRequest object, as illustrated in the following code:
var urlReq:URLRequest = new URLRequest(); urlRequest.setLoginCredentials("www.example.com", "Babbage", "cs1791!!");

The URLRequestDefaults class lets you define default settings for URLRequest objects. For example, the following code sets the default values for the manageCookies and useCache properties:
URLRequestDefaults.manageCookies = false; URLRequestDefaults.useCache = false;

The URLRequestDefaults class includes a setLoginCredentialsForHost() method that lets you specify a default user name and password to use for a specific host. The host, which is defined in the hostname parameter of the method, can be a domain, such as "www.example.com", or a domain and a port number, such as "www.example.com:80". Note that "example.com", "www.example.com", and "sales.example.com" are each considered unique hosts. These credentials are only used if the server requires them. If the user has already authenticated (for example, by using the authentication dialog box) then you cannot change the authenticated user by calling the setLoginCredentialsForHost() method. For example, the following code sets the default user name and password to use at www.example.com:
URLRequestDefaults.setLoginCredentialsForHost("www.example.com", "Ada", "love1816$X");

Each property of URLRequestDefaults settings apply to only the application domain of the content setting the property. However, the setLoginCredentialsForHost() method applies to content in all application domains within an AIR application. This way, an application can log into a host and have all content within the application be logged in with the specified credentials. For more information, see the URLRequestDefaults class in the Flex Language Reference for Apollo.

Using AIR URL schemes in URLRequest object URLs


You can also use the following schemes when defining a URL for a URLRequest object:

ADOBE PRODUCT X.0 161


User Guide

http: and https: Use these as you would use them in a web browser. file: Use this to specify a path relative to the root of the file system. For example: file:///c:/AIR Test/test.txt app-resource: Use this to specify a path relative to the root directory of the installed application (the directory that contains the application descriptor file for the installed application). For example, the following path points to a resources subdirectory of the directory of the installed application: app-resource:/resources

When running in the ADL application, the application resource directory is set to the directory that contains the application descriptor file.
app-storage:/ Use this to specify a path relative to the application store directory. For each installed application,

AIR defines a unique application store directory, which is a useful place to store data specific to that application. For example, the following path points to a prefs.xml file in a settings subdirectory of the application store directory:
app-storage:/settings/prefs.xml

You can use a URLRequest object that uses any of these URL schemes to define the URL request for a number of different objects, such as a FileStream or a Sound object. You can also use these schemes in HTML content running in AIR; for example, you can use them in the src attribute of an img tag. However, you can only use these AIR URL schemes in content in the application resource directory. For more information, see AIR Security on page 31.

Changes to the URLStream class


The URLStream class provides low-level access to downloading data from URLs. In the runtime, the URLStream class includes a new event: httpResponseStatus. Unlike the httpStatus event, the httpResponseStatus event is delivered before any response data. The httpResponseStatus event (defined in the HTTPStatusEvent class) includes a responseURL property, which is the URL that the response was returned from, and a responseHeaders property, which is an array of URLRequestHeader objects representing the response headers that the response returned.

Opening a URL in the default system web browser


You can use navigateToURL() function to open a URL in the default system web browser. For the URLRequest object you pass as the request parameter of this function, only the url property is used.

162

Chapter 21: Scripting and communications between applications and content


This section covers the following topics:

Using the LocalConnection class in AIR applications Scripting between content in different domains

Using the LocalConnection class in AIR applications


The LocalConnection class enables communications between AIR applications, as well as among AIR applications and SWF content running in the browser. The connect() method of the LocalConnection class uses a connectionName parameter to identify applications. In content running in the AIR application security sandbox (content installed with the AIR application), AIR uses the string app# followed by the application ID for the AIR application (defined in the application descriptor file) in place of the domain used by SWF content running in the browser. For example a connectionName for an application with the application ID com.example.air.MyApp, the connectionName resolves to "app#com.example.air.MyApp:connectionName".

Scripting between content in different domains


AIR applications are granted special privileges when they are installed. It is crucial that the same privileges not be leaked to other content, including remote files and local files that are not part of the application. Normally, content from other domains cannot call scripts in other domains. To protect AIR applications from accidental leakage of privileged information or control, the following restrictions are place on content in the application security sandbox (content installed with the application):

The Security.allowDomain() method cannot be called from the application security sandbox. Importing non-application content into the application sandbox by setting the

LoaderContext.securityDomain or the LoaderContext.applicationDomain property is prevented.

But there are still cases where the main AIR application wants content from a remote domain to have controlled access to scripts in the main AIR application, or vice versa. To accomplish this, the AIR runtime provides a sandbox bridge mechanism, which serves as a gateway between the two, providing explicit interaction between remote and application security sandboxes. Suppose an AIR music store application wants to allow remote SWF files to broadcast the price of albums, but does not want the remote SWF file to disclose whether the price is a sale price. To do this, a StoreAPI class provides a method to acquire the price, but obscures the sale price. An instance of this StoreAPI class is then assigned to the parentSandboxBridge property of the LoaderInfo object of the Loader object that loads the remote SWF.

ADOBE PRODUCT X.0 163


User Guide

The following is the code for the AIR music store:


<?xml version="1.0" encoding="utf-8"?> <mx:WindowedApplication xmlns:mx="http://www.adobe.com/2006/mxml" layout="absolute" title="Hello World" creationComplete="initApp()"> <mx:Script> import flash.display.Loader; import flash.net.URLRequest; import flash.html.HTMLControl; private var child:Loader; private var isSale:Boolean = false; private function initApp():void { var request:URLRequest = new URLRequest("http://[www.yourdomain.com]/PriceQuoter.swf") child = new Loader(); child.contentLoaderInfo.parentSandboxBridge = new StoreAPI(this); child.load(request); container.addChild(child); } public function getRegularAlbumPrice():String { return "$11.99"; } public function getSaleAlbumPrice():String { return "$9.99"; } public function getAlbumPrice():String { if(isSale) { return getSaleAlbumPrice(); } else { return getRegularAlbumPrice(); } } </mx:Script> <mx:UIComponent id="container" /> </mx:WindowedApplication>

The following code represents an example of a PriceQuoter SWF file that reports the stores price, but cannot report the sale price:
package { import flash.display.Sprite; import flash.system.Security; import flash.text.*; public class PriceQuoter extends Sprite { private var storeRequester:Object; public function PriceQuoter() { trace("Initializing child SWF"); trace("Child sandbox: " + Security.sandboxType); storeRequester = loaderInfo.parentSandboxBridge; var tf:TextField = new TextField(); tf.autoSize = TextFieldAutoSize.LEFT; addChild(tf);

ADOBE PRODUCT X.0 164


User Guide

tf.appendText("Store price of album is: " + storeRequester.getAlbumPrice()); tf.appendText("\n"); tf.appendText("Sale price of album is: " + storeRequester.getSaleAlbumPrice()); } } }

When exposing sandbox bridges, it's important to expose high-level APIs that limit the degree to which they can be abused. Keep in mind that the content calling your bridge implementation may be compromised. So, for example, exposing a "readFile(path:String)" method via a bridge is vulnerable to abuse. It would be better to expose a "readApplicationSetting()" API that doesn't take a path. The more semantic approach limits the damage that an application can do once part of it is compromised. For more information on security, see AIR Security on page 31.

165

Part 1: Distributing and updating applications


Distributing AIR applications . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .166 Updating AIR applications programmatically . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .174

166

Chapter 23: Distributing AIR applications


When you package an application into an AIR installation file, you must provide a provide a digital code-signing certificate with which to sign the application. Digitally signing the file provides assurance that your application has not been altered since it was signed. In addition, if the digital certificate was issued by the Verisign or Thawte certificate authorities, your users can confirm your identity as the publisher and signer. For information about how to package an application into an AIR file using the AIR update for Flash, see Creating Adobe AIR application and installer files on page 21. For information about how to package an application into an AIR file using the AIR SDK see Exporting an AIR installation file using the AIR Developer Tool on page 32. Once you package an AIR application there are a couple of ways to distribute it:

You can install it by sending the AIR package to the end user just as you would distribute any file. For example, you can send the AIR package as an e-mail attachment or as a link in a web page.
Using a seamless install installation link in a web page. AIR applications are easy to install and run. The seamless install feature lets users install the latest version of the AIR runtime (if it is not installed) when clicking the link to install a specific AIR application. Once the AIR application is installed, users simply double-click the application icon to run it, just like any other desktop application. This section contains the following topics:

Digitally signing an AIR file on page 166 Distributing and installing using the seamless install feature on page 168 Distributing and installing an AIR file without using the seamless install feature on page 172

Digitally signing an AIR file


Digitally signing your AIR installation files with a certificate issued by a recognized certificate authority (CA) provides significant assurance to your users that the application they are installing has not been accidentally or maliciously altered and identifies you as the signer (publisher). AIR recognizes code signing certificates issued by the Verisign and Thawte certificate authorities. AIR will display the publisher name during installation when you have signed the AIR file with a Verisign or Thawte certificate. Important: A malicious entity could forge an AIR file with your identity if it somehow obtains your signing keystore file or discovers your private key. The security assurances, limitations and legal obligations involving the use of code- signing certificates are outlined in the Certificate Practice Statements (CPS) and subscriber agreements published by the certificate authority. For more information refer to: Verisign CPS (http://www.verisign.com/repository/CPS/) Verisign Subscribers Agreement (https://www.verisign.com/repository/subscriber/SUBAGR.html) Thawte CPS (http://www.thawte.com/cps/index.html)

ADOBE PRODUCT X.0 167


User Guide

Thawte Code Signing Developers Agreement (http://www.thawte.com/ssl-digital- certificates/free-guides-whitepapers/pdf/develcertsign.pdf)

AIR code signing


When an AIR file is signed, a digital signature is included in the installation file. The signature includes a digest of the package, which is used to verify that the AIR file has not been altered since it was signed, and it includes information about the signing certificate, which is used to verify the publisher identity (if the certificate was issued by Verisign or Thawte). AIR uses the public key infrastructure (PKI) supported through the operating system is certificate store. The computer on which an AIR application is installed must trust the root certificate of the Verisign and Thawte certificate authorities for the publisher information to be verified. If an AIR file is signed with a certificate that does not chain to the Verisign or Thawte root certificates, and this includes all self-signed certificates, then the publisher information cannot be verified. While AIR can determine that the AIR package has not been altered since it was signed, there is no way to know who actually created and signed the file.

Certificate format
The AIR signing tools accept PKCS#12 keystore files (which typically use a .pfx or .p12 file extension). These files can be generated from a certificate using a variety of third- party tools, including the Java Keytool utility included with the JDK, and the Microsoft pvk2pfx utility included with Windows development tools. In addition, many browsers, including Internet Explorer and Firefox, can export or backup keystore files in the proper format. You can use an existing class-3, high assurance code signing certificate or you can obtain a new one. The certificate issued by the certificate authority must be one of the following types:

Verisign:

Microsoft Authenticode Digital ID Sun Java Signing Digital ID

Thawte: Apple Developer Certificate JavaSoft Developer Certificate Microsoft Authenticode Certificate

Adobe developer certificates will be offered by these CAs in the future. Although there will be Adobe developer certificates, existing code-signing certificates issued by these CAs will continue to be supported. Note: You cannot use an SSL certificate to sign AIR files.

Obtaining a certificate
To obtain a certificate, you must typically visit the Verisign or Thawte web site and complete the procurement process. The tools used to produce the keystore file needed by the AIR tools will depend on the type of certificate purchased, how the certificate is stored on the receiving computer, and, in some cases, the browser used to obtain the certificate. For example, to obtain and export a Microsoft Authenticode certificate, Verisign or Thawte will require you to use Microsoft Internet Explorer. The certificate can then be exported as a .pfx file directly from the Internet Explorer user interface.

ADOBE PRODUCT X.0 168


User Guide

You can generate a self-signed certificate using the ADT tool used to package AIR installation files. A number of third-party tools can also be used. For instructions on how to generate a self-signed certificate, as well as instructions on signing an AIR file, see Exporting an AIR installation file using the AIR Developer Tool on page 32. You can also export and sign AIR files using Flex Builder, Dreamweaver, and the AIR update for Flash.

Terminology
This section provides a glossary of some of the key terminology you should understand when making decisions about how to sign your application for public distribution.
Certificate Authority (CA) An entity in a public-key infrastructure network that serves as a trusted third party and ultimately certifies the identity of the owner of a public key. A CA normally issues digital certificates, signed by its own private key, to attest that it has verified the identity of the certificate holder. Certificate Practice Statement (CPS) Sets forth the practices and policies of the certificate authority in issuing and

verifying certificates. The CPS is part of the contract between the CA and its subscribers and relying parties. It also outlines the policies for identify verification and the level of assurances offered by the certificates they provide.
Certificate Revocation List (CRL) A list of issued certificates that have been revoked and should no longer be relied

upon.
Digital Certificate A digital document that contains information about the identity of the owner, the owners public key, the identity of the certificate itself, and which is signed by the issuing certificate authority. Digital Signature An encrypted message or digest that can only be decrypted with the public key half of a publicprivate key pair. In a PKI, a digital signature will contain one or more digital certificates that are ultimately traceable to the certificate authority. A digital signature can be used to validate that a message (or computer file) has not been altered since it was signed (within the limits of assurance provided by the cryptographic algorithm used), and, assuming one trusts the issuing certificate authority, the identity of the signer. Private Key The private half of a two-part, public-private key asymmetric cryptography system. The private key

must be kept secret and should never be transmitted over a network. Digitally signed messages are encrypted with the private key by the signer.
Public Key The public half of a two-part, public-private key asymmetric cryptography system. The public key is

openly available and is used to decrypt messages encrypted with the private key.
Public Key Infrastructure (PKI) A system of trust in which certificate authorities attest to the identity of the owners

of public keys. Clients of the network rely on the digital certificates issued by a trusted CA to verify the identity of the signer of a digital message (or file).

Distributing and installing using the seamless install feature


The seamless install feature lets you provide a link in a web page that lets the user install an AIR application by simply clicking the link. If the AIR runtime is not installed, the user is given the option to install it. The seamless install feature also lets users install the AIR application without downloading the AIR file to their machine. The seamless install link is a link in a SWF file (badge.swf) that has special capabilities that allow it to download the AIR runtime. The SWF file, and its source code, is provided to you for distribution on your website.

ADOBE PRODUCT X.0 169


User Guide

Note: The instructions in this topic provide information on setting parameters of the badge.swf file provided by Adobe. We also provide the source code for the badge.swf file, which you can customize.
Add a seamless install link to a page 1 Add the badge.swf file to the web server.

This file is provided in the lib directory of the AIR SDK. To customize the SWF file, see Modifying the badge.swf file on page 172.
2 Embed the SWF file in the HTML page, at the point that you want the link (contained in the badge.swf file) to appear. 3

Adjust the FlashVars parameter definitions for the following:

appurl (required)The URL of the AIR file to be downloaded. This must be an absolute, not relative, URL. airversion (required)For this beta release, set this to 1.0.M5.

appnameThe name of the application to display in the badge SWF file text when the runtime is not installed.
buttoncolorThe color of the download button (specified as a hex value, such as FFCC00).

messagecolorThe color of the text message displayed below the button when the runtime is not installed (specified as a hex value, such as FFCC00).
imageurlThe URL of the image (optional) to display in the badge.

For details, see Adjusting the code in the HTML page that contains the badge.swf file on page 170.
Installing the AIR application from a seamless install link in a web page

Once you have added the seamless install link to a page, you (or any user) can install the AIR application by clicking the link in the SWF file.
1 2

Navigate to the HTML page in a web browser that has Flash Player (version 6 or later) installed. In the web page, click the link in the badge.swf file.

If you have installed the AIR runtime, skip to the next step.

If you have not installed the AIR runtime, a dialog box is displayed asking whether you would like to install it. Install the AIR runtime (see Install the runtime on page 2), and then proceed with the next step.
3

In the Installation window, leave the default settings selected, and then click Continue. On a Windows computer, AIR automatically does the following:

Installs the application into c:\Program Files\ Creates a desktop shortcut for application Creates a Start Menu shortcut Adds an entry for application in the Add/Remove Programs Control Panel

On Mac OS, the installer adds the application to the Applications subdirectory of the user directory (for example, in the /Applications directory in Mac OS).
4 5

When the installation is complete, click Finish. Select the options you want, and then click the Install button.

ADOBE PRODUCT X.0 170


User Guide

Adjusting the code in the HTML page that contains the badge.swf file
You need to add FlashVars parameter definitions for the URL variable, and modify the path to the badge.swf file (if needed). SWF files are embedded in a page using the EMBED and OBJECT tags, as in the following:
<object classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000" id="HelloWorld" width="215" height="138" codebase="http://fpdownload.macromedia.com/get/flashplayer/current/swflash.cab"> <param name="movie" value="badge.swf" /> <param name="FlashVars" value="appUrl=AIRFileURL.air&airversion=1.0.M5" /> <embed src="badge.swf" quality="high" bgcolor="#869ca7" FlashVars="appUrl=AIRFileURL.air&airversion=1.0.M5" width="215" height="138" name="HelloWorld" align="middle" play="true" type="application/x-shockwave-flash" pluginspage="http://www.adobe.com/go/getflashplayer"> </embed> </object>

The boldface lines represent code that you need to add and modify to reflect the URL of your AIR file and the badge.swf file. However, this is a simplified version of code embedding a SWF file. In most HTML pages, SWF files are embedded with more complicated code. For example, Flex Builder and Flash CS3 both insert code as described in the Flash Player Detection Kit (http://www.adobe.com/products/flashplayer/download/detection_kit/), as shown below:
<script language="JavaScript" type="text/javascript"> <!-// Version check for the Flash Player that has the ability to start Player Product Install (6.0r65) var hasProductInstall = DetectFlashVer(6, 0, 65); // Version check based upon the values defined in globals var hasRequestedVersion = DetectFlashVer(requiredMajorVersion, requiredMinorVersion, requiredRevision); // Check to see if a player with Flash Product Install is available and the version does not meet the requirements for playback if ( hasProductInstall && !hasRequestedVersion ) { // MMdoctitle is the stored document.title value used by the installation process to close the window that started the process // This is necessary in order to close browser windows that are still utilizing the older version of the player after installation has completed // DO NOT MODIFY THE FOLLOWING FOUR LINES // Location visited after installation is complete if installation is required var MMPlayerType = (isIE == true) ? "ActiveX" : "PlugIn"; var MMredirectURL = window.location; document.title = document.title.slice(0, 47) + " - Flash Player Installation"; var MMdoctitle = document.title; AC_FL_RunContent( "src", "playerProductInstall", "FlashVars", "MMredirectURL="+MMredirectURL+'&MMplayerType='+MMPlayerType+'&MMdoctitle='+MMdoctitle+"&a ppUrl=AIRFileURL.air&airversion=1.0.M5", "width", "215", "height", "138", "align", "middle", "id", "badge", "quality", "high", "bgcolor", "#869ca7",

ADOBE PRODUCT X.0 171


User Guide

"name", "badge", "allowScriptAccess","sameDomain", "type", "application/x-shockwave-flash", "pluginspage", "http://www.adobe.com/go/getflashplayer" ); } else if (hasRequestedVersion) { // if we've detected an acceptable version // embed the Flash Content SWF when all tests are passed AC_FL_RunContent( "src", "badge", "width", "215", "height", "138", "align", "middle", "id", "badge", "quality", "high", "bgcolor", "#869ca7", "name", "badge", "flashvars",'historyUrl=history.htm%3F&lconid=' + lc_id + ' &appUrl=AIRFileURL.air&airversion=1.0.M5', "allowScriptAccess","sameDomain", "type", "application/x-shockwave-flash", "pluginspage", "http://www.adobe.com/go/getflashplayer" ); } else { // flash is too old or we can't detect the plugin var alternateContent = 'Alternate HTML content should be placed here. ' + 'This content requires the Adobe Flash Player. ' + '<a href=http://www.adobe.com/go/getflash/>Get Flash</a>'; document.write(alternateContent); // insert non-flash content } // --> </script> <noscript> <object classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000" id="badge" width="100%" height="100%" codebase="http://fpdownload.macromedia.com/get/flashplayer/current/swflash.cab"> <param name="movie" value="badge.swf" /> <param name="FlashVars" value="appInstallUrl=AIRFileURL.air&airversion=1.0.M5" /> <param name="quality" value="high" /> <param name="bgcolor" value="#869ca7" /> <param name="allowScriptAccess" value="sameDomain" /> <embed src="badge.swf" quality="high" bgcolor="#869ca7" FlashVars="appUrl=AIRFileURL.air&airversion=1.0.M5" width="215" height="138" name="badge" align="middle" play="true" loop="false" quality="high" allowScriptAccess="sameDomain" type="application/x-shockwave-flash" pluginspage="http://www.adobe.com/go/getflashplayer"> </embed> </object> </noscript>

In this code, there are many more lines to modify, as the code embeds the SWF file in a number of ways (including via JavaScript calls). Be sure to modify AIRFileURL.air to point to the URL (or relative path) of your AIR file, and modify it each place it is referenced in the code. If necessary, also modify the path to the badge.swf file, and modify it each place it is referenced in the code.

ADOBE PRODUCT X.0 172


User Guide

Modifying the badge.swf file


The AIR SDK provides the source files for the badge.swf file. These files are included in the src folder of the SDK:
badge.fla The source Flash file used to compile the badge.swf file. The badge.fla file compiles into a SWF 6 file

(which can be loaded in Flash Player versions 6 and later).


install.as An ActionScript 2.0 script file referenced in the badge.fla file. This script is written with ActionScript

2.0 class (rather than ActionScript 3.0) for support in Flash Player versions 6 and later. Details are provided below. You can use Flash to redesign the visual interface of the badge.fla file. The install.as file includes code for installing the AIR runtime. It uses the flash.system.ProductManager class, which is used to download and install extensions to Flash Player (in this case, the AIR runtime) that originate from www.adobe.com. In the badge.swf file, the class is used to install the AIR Detection Add-In, a browser add-in that is used to install the AIR runtime, check the runtime version, and launch the AIR application installer. The Flash.system.ProductManager class is generally undocumented because it can only be used to install extensions that originate from www.adobe.com. We recommend that you do not modify the script in the install.as file. If the AIR Detection Add-In is not installed, the user is asked to grant permission to install it. Once the AIR Detection Add-In is installed, it launches the AIR runtime. If the AIR runtime does not exist, the AIR Detection Add-In asks the user to grant permission to install the AIR runtime. Once the AIR runtime is installed, the badge.swf file proceeds to install the requested AIR file, by opening the AIR application installer (which also gives the user the choice to proceed with installing the AIR application). Both the AIR Detection Add-In and the AIR runtime are signed. Neither the badge.swf file, the AIR Detection Add-In, nor the AIR application installer send any information about the identity of the AIR file you are installing to adobe.com.

Distributing and installing an AIR file without using the seamless install feature
If you choose not to use the seamless install feature, you can simply send the AIR file to the recipient. For example, you can send the AIR file as an e-mail attachment or as a link in a web page. Once the user downloads the AIR application, the user follows these instructions to install it.
1 2

Double-click the AIR file. In the Installation window, leave the default settings selected, and then click Continue. In Windows, AIR automatically does the following:

Installs the application into the Program Files directory Creates a desktop shortcut for application Creates a Start Menu shortcut Adds an entry for application in the Add / Remove Programs Control Panel

In the Mac OS, by default the application is added to the Applications subdirectory of the user directory. If the application is already installed, the installer gives the user the choice of opening the existing version of the application or updating to the version in the downloaded AIR file. The installer identifies the application using the application ID (appID) in the AIR file.

ADOBE PRODUCT X.0 173


User Guide

When the installation is complete, click Finish.

An application can also install a new version via ActionScript or JavaScript. For more information, see Updating AIR applications programmatically on page 174.

Running an AIR application


Once you have installed the runtime and the AIR application, running the application is as simple as running any other desktop application:

On a Windows computer, double-click the application's icon (which may be installed on the desktop or in a folder), or select the application from the Start menu. On Mac OS, double-click the application in the folder in which it was installed. The default installation directory is the /Applications directory.

174

Chapter 24: Updating AIR applications programmatically


Users can install or update an AIR application by double-clicking an AIR file on their computer, and the AIR installer application will manage the installation, alerting the user if they are updating an already existing application. However, you can also have an installed application update itself to a new version, using the Updater class. The Updater class includes an update() method that lets you point to an AIR file on the users computer and update to that version.

About updating applications


The Updater class (in the flash.system package) includes one method, update(), which you can use to update the currently running application with a different version. For example, if the user has a version of the AIR file ("Sample_App_v2.air") located on the desktop, the following code updates the application:
var updater:Updater = new Updater(); var airFile:File = File.desktopDirectory.resolve("Sample_App_v2.air"); var version:String = "2.01"; updater.update(airFile, version);

Results of the method call


When an application in the runtime calls the update() method, the runtime closes the application, and it then attempts to install the new version from the AIR file. The runtime checks that the application ID specified in the AIR file matches the application ID for the application calling the update() method. It also checks that the version string matches the version string passed to the update() method. If installation completes successfully, the runtime opens the new version of the application. Otherwise (if the installation cannot complete), it re-opens the existing (preinstall) version of the application. When testing an application using ADL, calling the update() method installs and runs a new version of the application only if the runtime is installed. If the runtime is not installed, the call to the update() results in a runtime exception.

About the version string


The string that is specified as the version parameter of the update() method must match the string in the version attribute of the main application element of the application descriptor file for the AIR file to be installed. Specifying the version parameter is required for security reasons. By requiring the application to verify the version number in the AIR file, the application will not inadvertently install an older version, which might contain a security vulnerability that has been fixed in the currently installed application. The version string can be of any format. For instance, it can be "2.01" or "version 2". The format of this string is left for you, the application developer, to decide.

ADOBE PRODUCT X.0 175


User Guide

If an Adobe AIR application downloads an AIR file via the web, it is a good practice to have a mechanism by which the web service can notify the Adobe AIR application of the version being downloaded. The application can then use this string as the version parameter of the update() method. If the AIR file is obtained by some other means, in which the version of the AIR file is unknown, the AIR application can examine the AIR file to determine the version information. (An AIR file is a ZIP-compressed archive, and the application descriptor file is the second record in the archive.) For details on the application descriptor file, see Setting application properties on page 41.

Presenting a custom application update user interface


AIR includes a default update interface:

This interface is always used the first time a user installs a version of an application on a machine. However, you can define your own interface to use for subsequent instances. To do this specify a handleUpdates element in the application descriptor file for the application:
<handleUpdates/>

When the application is installed, when the user opens an AIR file with an application ID matching the installed application, the runtime opens the application, rather than the default AIR application installer. For more information, see Signaling the inclusion of an update interface on page 45. The application can decide, when it is invoked (when the Shell.shell object dispatches an invoke event) whether to update the application (using the Updater class). If it decides to update, it can present its own installation interface (which differs from its standard running interface) to the user.

ADOBE PRODUCT X.0 176


User Guide

Downloading an AIR file to the users computer


To use the Updater class, you must first save an AIR file locally to the user's machine. For example, the following code reads an AIR file from a URL (http://example.com/air/updates/Sample_App_v2.air) and saves the AIR file to the application storage directory:
var urlString:String = "http://example.com/air/updates/Sample_App_v2.air"; var urlReq:URLRequest = new URLRequest(urlString); var urlStream:URLStream = new URLStream(); var fileData:ByteArray = new ByteArray(); urlStream.addEventListener(Event.COMPLETE, loaded); urlStream.load(urlReq); function loaded(event:Event):void { urlStream.readBytes(fileData, 0, urlStream.bytesAvailable); writeAirFile(); } function writeAirFile():void { var file:File = File.applicationStorageDirectory.resolve("My App v2.air"); var fileStream:FileStream = new FileStream(); fileStream.addEventListener(Event.CLOSE, fileClosed); fileStream.openAsync(file, FileMode.WRITE); fileStream.writeBytes(fileData, 0, fileData.length); fileStream.close(); } function fileClosed(event:Event):void { trace("The AIR file is written."); }

See also

Workflow for reading and writing files on page 90.

Checking to see if an application is running for the first time


Once you have updated an application you may want to provide the user with "getting started" or "welcome" message. To do this, you will want the application, upon launching, to check to see it is running for the first time, so that you can determine whether to display the message upon. One way to do this is to save a file to the application store directory upon initializing the application (for example, when a top-level Flex component dispatches the applicationComplete event). Every time the application starts up, it should check for the existence of that file. If the file does not exist, then the application is running for the first time. If the file exists, the application has already run at least once. If the file exists and contains a version number older than the current version number, then you know the user is running the new version for the first time. Here is a Flex example:
<?xml version="1.0" encoding="utf-8"?> <mx:WindowedApplication xmlns:mx="http://www.adobe.com/2006/mxml" layout="vertical"

ADOBE PRODUCT X.0 177


User Guide

title="Sample Version Checker Application" applicationComplete="init()"> <mx:Script> <![CDATA[ import flash.filesystem.*; public var file:File; public var currentVersion:String = "1.2"; public function init():void { file = File.applicationStorageDirectory.resolve("Preferences/version.txt"); trace(file.nativePath); if(file.exists) { checkVersion(); } else { firstRun(); } } private function checkVersion():void { var stream:FileStream = new FileStream(); stream.open(file, FileMode.READ); var prevVersion:String = stream.readUTFBytes(stream.bytesAvailable); stream.close(); if (prevVersion != currentVersion) { log.text = "You have updated to version " + currentVersion + ".\n"; } else { saveFile(); } log.text += "Welcome to the application."; } private function firstRun():void { log.text = "Thank you for installing the application. \n" + "This is the first time you have run it."; saveFile(); } private function saveFile():void { var stream:FileStream = new FileStream(); stream.open(file, FileMode.WRITE); stream.writeUTFBytes(currentVersion); stream.close(); } ]]> </mx:Script> <mx:TextArea id="log" width="100%" height="100%" /> </mx:WindowedApplication>

If your application saves data locally (such as, in the application storage directory), you may want to check for any previously saved data (from previous versions) upon first run.

Chapter 25: New functionality in Adobe AIR


This appendix provides an overview of the new functionality in AIR that is not available to SWF content running in Flash Player. This appendix contains the following sections:

New runtime classes Runtime classes with new functionality New Flex components Service monitoring framework classes

New runtime classes


The following runtime classes are new in Adobe AIR. They are not available to SWF content running in the browser:
Class Clipboard ClipboardFormats CompressionAlgorithm ClipboardTransferMode DockIcon DragActions DragManager DragOptions DRMAuthenticateEvent DRMStatusEvent EncryptedLocalStore File FileListEvent FileMode FileStream HTMLControl HTMLHistoryItem HTMLHost Package flash.desktop flash.desktop flash.utils flash.desktop flash.display flash.desktop flash.desktop flash.desktop flash.events flash.events flash.filesystem flash.filesystem flash.events flash.filesystem flash.filesystem flash.html flash.html flash.html

ADOBE PRODUCT X.0 2


User Guide

Class HTMLPDFCapability HTMLUncaughtJavaScriptExceptionEvent HTMLWindowCreateOptions Icon InteractiveIcon InvokeEvent JavaScriptFunction JavaScriptObject NativeDragEvent NativeMenu NativeMenuItem NativeWindow NativeWindowBoundsEvent NativeWindowDisplayState NativeWindowDisplayStateEvent NativeWindowErrorEvent NativeWindowIcon NativeWindowInitOptions NativeWindowResize NativeWindowSystemChrome NativeWindowType NotificationType OutputProgressEvent Screen Shell SQLCollationType SQLColumnNameStyle SQLColumnSchema SQLConnection SQLError SQLErrorCode SQLErrorEvent SQLErrorOperation

Package flash.html flash.html flash.html flash.desktop flash.display flash.events flash.html flash.html flash.events flash.display flash.display flash.display flash.events flash.display flash.events flash.events flash.display flash.display flash.display flash.display flash.display flash.display flash.events flash.display flash.system flash.data flash.data flash.data flash.data flash.errors flash.errors flash.events flash.errors

ADOBE PRODUCT X.0 3


User Guide

Class SQLEvent SQLIndexSchema SQLResult SQLSchema SQLSchemaResult SQLStatement SQLTableSchema SQLTransactionLockType SQLTriggerSchema SQLUpdateEvent SQLViewSchema SystemTrayIcon Updater URLRequestDefaults XMLSignatureValidator TransferableTransferMode URLRequestDefaults Updater

Package flash.events flash.data flash.data flash.data flash.data flash.data flash.data flash.data flash.data flash.events flash.data flash.display flash.system flash.net flash.utils flash.desktop flash.net flash.system

Most of these classes are available only to content in the AIR application security sandbox (see Introducing Adobe AIR on page 9). However, the following classes are also available to content running in other sandboxes:

Door URLRequest.

Runtime classes with new functionality


The following classes are available to SWF content running in the browser, but AIR provides additional properties or methods:

ADOBE PRODUCT X.0 4


User Guide

Class HTTPStatusEvent

Property or Method

HTTP_RESPONSE_STATUS responseURL responseHeaders

URLRequest

followRedirects manageCookies shouldAuthenticate shouldCacheResponse userAgent userCache setLoginCredentials()

URLStream Stage Security

httpResponseStatus event nativeWindow APPLICATION

Most of these new properties and methods are available only to content in the AIR application security sandbox. However, the new members in the URLRequest classes are also available to content running in other sandboxes. The ByteArray.compress() and ByteArray.uncompress() methods each include a new algorithm parameter, allowing you to choose between deflate and zlib compression.

New Flex components


The following Flex components are available when developing content for the AIR runtime:

FileEvent FileSystemComboBox FileSystemDataGrid FileSystemEnumerationMode FileSystemHistoryButton FileSystemList FileSystemSizeDisplayMode FileSystemTree HTML WindowedApplication

ADOBE PRODUCT X.0 5


User Guide

Service monitoring framework classes


The air.net package contains classes for network detection. This package is only available to content running in Adobe AIR. It is included in the ServiceMonitor.swc file. The package includes the following classes:

ServiceMonitor SocketMonitor URLMonitor

Part 1: AIR Quick Starts


How to build the quick start sample applications with Flash CS3 . . . . . . . . . . . . . . . . .7 Building a text-file editor . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .8 Adding native menus to an AIR application . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .12 Interacting with a window . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .17 Creating a transparent window application . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .22 Launching native windows . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .27 Creating toast-style windows . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .31 Controlling the display order of windows . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .36 Dragging, copying, and pasting data . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .40 Creating resizable, non-rectangular windows. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .47 Measuring the virtual desktop. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .1 Using the system tray and dock icons . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .1

Chapter 27: How to build the quick start sample applications with Flash CS3
The Flash Quick Start applications contained in Developing AIR Applications with Adobe Flash CS3 demonstrate some of the most important or popular aspects of Adobe AIR features. They give you a quick tutorial introduction to how these Adobe AIR features work and how you can use them in your own applications. This section gives you an overview of how to access and install the Adobe AIR Quick Start applications for Flash.

Set up, download, and install


Here are general instructions to follow to download and prepare to run each of the AIR Quick Start applications for Flash, using the Adobe AIR update for Flash CS3. Set up your development environment so that you can work with the sample code and compile and test the applications. To set your development environment so that you can work with the sample code, see Installing Adobe AIR on page 6 to install the Adobe AIR runtime and Setting up Flash CS3 for Adobe AIR on page 1 to install the Adobe AIR update for Flash CS3.
1 2 Download the sample application source files from the online location indicated in each of the Quick Start topics.

Note: The sample applications are provided as is, for instructional purposes.
Installing the Quick Start application source files 1 Download the sample application files into a folder on your computer. Create a new folder for each, if you like. 2 3

With Flash CS3 for Adobe AIR installed and configured, you're ready to test the samples.

The installer (AIR) file for each sample application is included with the download files. To install the application, double click the AIR file in the same folder where you saved the Quick Start application.
4 To examine the inner workings of the sample application, extract the source files from the .ZIP file into the project folder that you created. Open the .FLA and .AS files to view the elements and source code. You can also use the AIR-related items in the Flash CS3 Commands menu to inspect the AIR application descriptor properties and to generate a new AIR file. For more information, see Creating Adobe AIR application and installer files on page 21.

Next steps
Read the individual quick-start topics to gain an understanding of how each of the applications work and for an explanation of its ActionScript code. For more information on creating Adobe AIR applications with Flash CS3, see Using Flash CS3 for Adobe AIR applications on page 16.

Chapter 28: Building a text-file editor


The Text Editor sample application shows a number of features of working with files in Adobe AIR, including the following:

Setting up a File object to point to a file path. Getting the system-specific path (nativePath) for the file. Using the FileMode and FileStream classes to read data from the file. Using the FileMode and FileStream classes to write data from the file. Using events to handle asynchronous processes.

Note: This is a sample application provided, as is, for instructional purposes.

Testing the application


The TextEditor application is intentionally simple. The intent is to show you the basics of how to work with files in Adobe AIR.

The installer (AIR) file for this sample application is available in the Samples directory included with the documentation at the AIR pre-release site. The application is a straightforward, but simple, editor of plain text files. The application uses UTF-8 encoding for reading and writing all text files.

ADOBE PRODUCT X.0 9


User Guide

Files used to build the application


The application is built from the following source files:
File TextEditor.fla com/air/flash/TextEditor.as Description The FLA file which contains the main AIR application assets. The ActionScript file which contains the AIR application code. Details of the code are discussed in Understanding the code on page 9. The AIR application descriptor file Sample AIR icon files.

TextEditor-app.xml icons/ApolloApp_16.png icons/ApolloApp_32.png icons/ApolloApp_48.png icons/ApolloApp_128.png

You can download the source files for this example at http://download.macromedia.com/pub/labs/air/quickstart_apps/b1/TextEditorFlash.zip.

Understanding the code


This article does not describe all of the Flex components used in the MXML code for the file. For information on these, see the Flex 3 Language Reference.

Pointing a File object to a file


The appCompleteHandler() method sets the defaultFile File object to point to a pre-defined path:
defaultFile = File.documentsDirectory.resolve("test.txt");

This code sets the File object to point to the test.txt file in the user's documents directory. In Windows, this is the My Documents directory. In Mac OS, it is the /Users/userName/Documents directory. The defaultFile file is later passed to Open and Save As pop-up windows, if the user has not yet selected a file path.

Reading a file
The openFile() method contains code that opens a file chooser dialog box. When the user selects a file and clicks the OK button. The fileOpenSelected() method is called. The method first initiates the file File object to point to the path specified by the user:
currentFile = event.file;

Next the stream FileStream object is closed (in case it currently has a file open) and the stream FileStream object are initialized:
if (stream != null) { stream.close(); } stream = new FileStream();

ADOBE PRODUCT X.0 10


User Guide

stream.openAsync(currentFile, FileMode.READ);

Note: The fileMode parameter of the openAsync() method is set to FileMode.READ. This lets you read the file. Event handlers are set up to respond to the complete and ioError events:
stream.addEventListener(Event.COMPLETE, fileReadHandler); stream.addEventListener(IOErrorEvent.IO_ERROR, readIOErrorHandler);

AIR begins reading the file asynchronously, and the runtime automatically starts reading the file in and firing events. Note that you can add these event listeners after calling the openAsync() method, because the runtime will complete executing this ActionScript code (the block of code that includes the calls to addEventListener() methods) before responding to any events. Note: This sample application shows how to read a file asynchronously. You can also read the file synchronously by calling the open() method when opening the file, rather than calling the openAsync() method. For more information, see Working with the file system on page 1. If the stream object dispatches an ioError event, the readIOErrorHandler() displays an error message for the end user. When the file is read in fully, the stream object dispatches the complete event, and the fileReadHandler()) method reads and processes the file. The readUTFBytes() method of the stream object returns a string by reading UTF-8 characters from specified number of bytes. Since the stream object just dispatched complete event, the bytesAvailable property represents the total length of the file, and it is passed as the length property of the call to the readUTFBytes() method:
var str:String = stream.readUTFBytes(stream.bytesAvailable);

The following code replaces the line ending characters from the file with the "\n" newline character, which is used in a TextField object in a SWF file. It then assigns the string to the text property of the Text control:
var lineEndPattern:RegExp = new RegExp(File.lineEnding, "g"); str = str.replace(lineEndPattern, "\n"); mainTextField.text = str;

Writing data to a file


The saveFile() contains code that writes the text to the file. First, the method checks to see if the main File object is set:
if (currentFile)

The currentFile object is undefined when the user first opens the application, and when the user clicks the New button. If there is no currentFile defined, then the saveAs() method is called (in the else block), which lets the user select a file path for saving the file. Next the stream FileStream object is closed (if it is currently open) and then it is initialized:
if (stream != null) { stream.close(); } stream = new FileStream(); stream.openAsync(currentFile, FileMode.WRITE);

Note that the mode parameter of the openAsync() method is set to FileMode.WRITE. This lets you write to the file.

ADOBE PRODUCT X.0 11


User Guide

An event handlers is set up to respond to the any ioError events:


stream.addEventListener(IOErrorEvent.IO_ERROR, writeIOErrorHandler);

The following code replaces the "\n" newline character, which is used in a TextField object in a SWF file, with the line ending character used in text files in the file system (File.lineEnding) It then assigns the string to the text property of the Text control:
var str:String = mainTextField.text; str = str.replace(/\r/g, "\n"); str = str.replace(/\n/g, File.lineEnding);

The writeUTFBytes() method of the stream object writes a string to the file in UTF-8 format and then closes the file:
stream.writeUTFBytes(str); stream.close();

If the stream object dispatches an ioError event, the writeIOErrorHandler() displays an error message to the end user.

12

Chapter 29: Adding native menus to an AIR application


Operating systems provide built-in (or native) facilities for creating menus. The AIR NativeMenu classes provide an interface for creating and modifying native operating system menus as well as for adding event listeners to handle menu events. The AIRMenus sample application illustrates how to create the various kinds of native menus supported by AIR. Note: This is a sample application provided, as is, for instructional purposes.

About AIR menus


Adobe AIR supports the following types of menus:
Application menus Application menus, only supported on Mac OS X, appear in a global menu bar provided by the operating system. OS X provides a default menu for each application. Your AIR application can either use the default menu by adding event listeners to the relevant menu commands, modify the default menu by adding and removing commands and submenus, or replace the default menu with a new one. (The AIR Menus sample replaces the default menu.)

Access the application menu through the Shell.shell.menu property. Use the Shell.supportsMenu property to test whether your application is running in an environment with application menu support.
Window menus Window menus, only supported natively on the Microsoft Windows operating system, appear

below the title bar of a window. No default menu is supplied so you must create a new NativeMenu object to assign as the window menu. Access a window menu through the menu property of the window. Use the NativeWindow.supportsMenu property to test whether your application is running in an environment with window menu support. Window menus can only be used with windows that have system chrome.
Context menus Context menus can be attached to any InteractiveObject by setting the contextMenu property of the object to a NativeMenu. No default context menu is provided in AIR. Dock icon menus On Mac OS X, you can add a menu to the application dock icon. The menu items in the new menu

will appear in addition to the default operating system menu items.


System tray icon menus On Windows, you can add a menu to the system tray icon. No default menu is provided. Pop-up menus A native menu can be displayed anywhere in an application by calling the menu display() method.

The AIR Menus sample application


The AIR Menus sample application creates a native menu containing File, Edit, and Help submenus and uses it in each of the supported menu locations. When a menu command is chosen, its label is printed to the window by a menu event handler.

ADOBE PRODUCT X.0 13


User Guide

The following screenshot shows the application in action on Windows:

Testing the application


Launch the AIR Menus sample. Select a menu item from the application menu bar or the window menu bar. Rightclick or command-click in the window to open a context menu. Click or left-click in the window to open a pop-up menu. Click and hold the dock icon to open the dock menu. Right-click on the system tray icon to open the system tray menu. Any time you select a menu command it will be listed on the window.

Files used to build the application


The application includes the following source files:

File AIRMenus.as AIRMenuIcon.as

Description The main application file. Details of the code are discussed in the Understanding the code section. Extends the Icon class to embed the images used for the dock and system tray icons (which are also used for the application icon). The application descriptor file. See Setting application properties on page 41. Sample icon files.

AIRMenus-app.xml icons/ApolloApp_16.png icons/ApolloApp_32.png icons/ApolloApp_48.png icons/ApolloApp_128.png

You can download the source files for this example at http://download.macromedia.com/pub/labs/air/quickstart_apps/b2/AIRMenus.zip.

See also

Building the quick-start sample applications with Flex on page 7

ADOBE PRODUCT X.0 14


User Guide

Understanding the code


For more information about using Flash classes, such as the TextField used by AIRMenus, see Programming ActionScript 3.0 and the ActionScript 3.0 Language Reference.

Creating a menu
To create a menu, you start with a new NativeMenu object and add commands, submenus and separators to it. The top, or root, level menu of application and window menus should only contain submenus. Command and separator items in the root level menu will not be displayed by all operating systems, and even on those that do display them, such items would be non-standard and likely to confuse users. The AIR Menus example uses a function to create the root menu, which is called for each type of menu supported by AIR. The function creates three example submenus, labeled File, Edit, and Help. The NativeMenu objects for these submenus are, in turn, created by other functions:
private function createRootMenu():NativeMenu{ var menu:NativeMenu = new NativeMenu(); menu.addSubmenu(createFileMenu(),"File"); menu.addSubmenu(createEditMenu(),"Edit"); menu.addSubmenu(createHelpMenu(),"Help"); return menu; }

The functions which create the submenus, use the addItem() method to add commands and separators. Each menu object contains an items array. Since all of the events dispatched when a menu is selected are handled by the same function, the items array is used to attach the listener to all the items.
private function createFileMenu():NativeMenu{ var menu:NativeMenu = new NativeMenu(); menu.addItem(new NativeMenuItem("New")); menu.addItem(new NativeMenuItem("Open")); menu.addItem(new NativeMenuItem("Save")); menu.addItem(new NativeMenuItem("",true));//separator menu.addItem(new NativeMenuItem("Exit")); for each (var item:NativeMenuItem in menu.items){ item.addEventListener(Event.SELECT,itemSelected); } return menu; }

Setting application and dock menus


When AIR supports application menus on an operating system, the static Shell.supportsMenu property will be true. The Mac OS X operating system provides a default application menu. You have the option of using the provided menu (most of the commands will do nothing unless you add event listeners), perhaps adding new items and submenus, or replacing the menu entirely. The AIR Menus example takes the second approach.
if(Shell.supportsMenu){ Shell.shell.menu = createRootMenu(); }

ADOBE PRODUCT X.0 15


User Guide

When AIR supports dock icons on an operating system, the static Shell.supportsDockIcon will be true. The dock icon is represented by the Shell.shell.icon property. The icon object is created automatically. You can change the appearance of the dock icon by setting the icon.bitmaps property. Mac OS X provides a default menu for the dock icon. You can add additional items to the dock menu by adding the items to a NativeMenu object and assigning it to the icon.menu property.
if(Shell.supportsDockIcon){ DockIcon(Shell.shell.icon).menu = createRootMenu(); Shell.shell.icon.bitmaps = new AIRMenuIcon().bitmaps; }

Setting window and system tray menus


When AIR supports window menus on an operating system, the static NativeWindow.supportsMenu property will be true. No default window menu is provided by the Windows operating system, so you must assign a new menu object to the window:
if(NativeWindow.supportsMenu){ stage.nativeWindow.menu = createRootMenu(); }

When AIR supports system tray icons on an operating system, the static Shell.supportsSystemTrayIcon will be true. The system tray icon is represented by the Shell.shell.icon property. The icon object is created automatically. To show the icon in the notification area of the taskbar, you only need to assign an array containing the icon image to the icon bitmaps property. To remove the icon from the taskbar, set bitmaps to an empty array. Add a menu to the system tray icon by assigning a NativeMenu object to the icon.menu property. You must cast the object to the SystemTrayIcon class to access the menu property.
if(Shell.supportsSystemTrayIcon){ Shell.shell.icon.bitmaps = new AIRMenuIcon().bitmaps; SystemTrayIcon(Shell.shell.icon).tooltip = "AIR Menus"; SystemTrayIcon(Shell.shell.icon).menu = createRootMenu(); }

Be careful about using SystemTrayIcon properties on the wrong operating system. An Mac OS X, for example, the Shell.shell.icon object is of type, DockIcon. Attempting to set the tooltip would generate a runtime error.

Setting a context menu


Every InteractiveObject has a contextMenu property. When set, a command-click or right-mouse click on the object will open the context menu.
textDisplay.contextMenu = createRootMenu();

A context menu can have commands, submenus, and separators in the root menu.

Setting a pop-up menu


Menus can be displayed anywhere over a window by calling the display() method of the NativeMenu object.
private function popUpMenu(event:MouseEvent):void{ popUp.display(stage, event.stageX, event.stageY); }

A pop-up menu can have commands, submenus, and separators in the root menu.

ADOBE PRODUCT X.0 16


User Guide

Responding to menu events


Menu items dispatch a select event when they are selected by the user. The AIR Menus example uses the same event handler for every item. To add a event listener, call the addEventListener() method of the item:
item.addEventListener(Event.SELECT,itemSelected);

Select events also bubble up through the menu hierarchy. Each parent menu in the chain will also dispatch a select event. The target property of the event object will be the NativeMenuItem object of the selected command; the currentTarget property will be the NativeMenu object of the current menu. This example responds to each select event by adding a line describing the event to the TextField in the window.
private function itemSelected(event:Event):void{ textDisplay.appendText(selectCount++ + ". Selected item: " + event.target.label + "\n"); }

Also available, but not used in this example are displaying events. Displaying events are dispatched by a menu just before it is displayed. You can use displaying events to update the menu or items within it to reflect the current state of the application. For example, if your application used a menu to let users open recently viewed documents, you could update the menu to reflect the current list inside the handler for the displaying event.

17

Chapter 30: Interacting with a window


The PixelPerfect sample application performs basic tasks on window objects. These tasks include creating, resizing, moving, and closing windows.

Using the PixelPerfect AIR application


The PixelPerfect sample application creates a transparent pixel ruler on the operating system desktop. The pixel ruler is represented by a window that can be moved, resized, and changed with respect to display state.

Note: This is a sample application provided, as is, for instructional purposes. The PixelPerfect application demonstrates how you can use the AIR window API to:

Open multiple windows Obtain a reference to a window. Use mouse events to trigger operations on a window. Use the startResize() method of the NativeWindow class to resize a window. Use the constants of the NativeWindowResize class to specify how a window resize operation is completed. Use the startMove() method of the NativeWindow class to move a window. Use the close() method of the NativeWindow class to close a window. Use full screen mode
You can download the source files for this example at http://download.macromedia.com/pub/labs/air/quickstart_apps/b2/PixelPerfect.zip

See also

Understanding the code on page 18 Building the quick-start sample applications with Flex on page 7

ADOBE PRODUCT X.0 18


User Guide

Create the PixelPerfect project as a Flex application


The application includes the following source files:
PixelPerfect.as An ActionScript class that launches a new ruler window and then exits. Ruler.as The ruler window class. Extends the NativeWindow class. Located in package: com.adobe.pixelperfect. PixelPerfect-app.xml The AIR application descriptor file. icons/AIRApp_128.png Sample AIR icon file.

Install the source files in Flex Builder 1 Open Flex Builder. 2 3 4

Select File > New, and then select AIR Project. Enter PixelPerfect as the Project Name. Click Next. Leave the Use Default Location and Use Default SDK options selected. Click Next.

5 Change the Main application file to PixelPerfect.as on the Set The Build Paths For The New AIR Project page,. Leave the other settings as is. Click next to advance to the Application XML Properties page. 6 7

Fill in the Name, Description, and Copyright text boxes, as desired and click Finish. Your project is created. Copy the source files into the project folder (maintaining the package folder structure).

CLOSE PROCEDURE
Install the application 1 Double-click the PixelPerfect.air file. 2

Click Continue. AIR installs the application.

CLOSE PROCEDURE
Run the application

In Windows, double-click the desktop shortcut for the application or select the file from the Start menu. In Mac OS, double-click the PixelPerfect application icon, which is installed in the Applications subdirectory of the user directory by default.
CLOSE PROCEDURE

Understanding the code


PixelPerfect presents a simple user interface that lets users access the NativeWindow API to modify application windows based on user input. PixelPerfect supports the following user interactions:
Context menu Right-click on the window to open a menu of window commands. Drag corners or sides to resize The mouseDown event triggers application logic to run that calculates the mouse position and, if appropriate, makes a call to the NativeWindow.startResize() method. Drag the middle to move The mouseDown event triggers application logic to run that calculates the mouse position and, if appropriate, makes a call to the NativeWindow.startMove() method.

ADOBE PRODUCT X.0 19


User Guide

Arrow keys move one pixel at a time The keyDown event triggers application logic that detects if an arrow key was pressed. If it was, the NativeWindow.x or NativeWindow.y property is either increased or decreased by 1, depending on whether the arrow that was pressed was the DOWN arrow key, the UP arrow key, the LEFT arrow key, or the RIGHT arrow key. This process occurs each time the user presses an arrow key. Shift + arrow keys resize one pixel at a time The keyDown event triggers application logic that detects if the SHIFT key was pressed in combination with an arrow key. If such a key combination was pressed, the NativeWindow.width or Window.height property is either increased or decreased by 1, depending on whether the arrow that was pressed was the DOWN arrow key, the UP arrow key, the LEFT arrow key, or the RIGHT arrow key. This process occurs each time the user presses the SHIFT key in combination with an arrow key. Mouse wheel changes opacity The event listener that was created to detect activity from the mouse wheel makes a call to an event
handler that determines the extent and direction in which the mouse wheel is turned. These values are used to modify the alpha property, which affects the level of transparency that is applied to the background color.

Double-click to quit The doubleClick event triggers application logic that makes an explicit call to the Window.close()
method.

Press n to create a new window The keyDown event triggers application logic that detects if the N key was pressed. If so, a new instance of the Ruler class (which extends NativeWindow) is created, displaying a new ruler window.

Creating a Window
To create a window, PixelPerfect instantiates a new Ruler object. The Ruler class extends the NativeWindow class. In the Ruler constructor, the NativeWindowInitOptions object is created and passed to the NativeWindow super class constructor:
public function Ruler(width:uint = 300, height:uint = 300, x:uint = 50, y:uint = 50, alpha:Number = .4){ var winArgs:NativeWindowInitOptions = new NativeWindowInitOptions(); winArgs.systemChrome = NativeWindowSystemChrome.NONE; winArgs.transparent = true; super(false, winArgs); //...

The rest of the constructor initializes the properties of the new window and its members.

Resizing the application window


The startResize() method receives a constant value defined by the NativeWindowResize class that indicates the edge or corner of the window from which the user is dragging the window to resize it. The startResize() method triggers a system-controlled resizing of the window. The application also explicitly sets the window bounds in response to keyboard events. In this case, no resize events are involved. The following code snippet sets the window bounds inside a switch statement:
switch (e.keyCode) { case Keyboard.DOWN: if (e.shiftKey) height += 1; else y += 1; drawTicks(); break; case Keyboard.UP: if (e.shiftKey) height -= 1;

ADOBE PRODUCT X.0 20


User Guide

else y -= 1; drawTicks(); break; case Keyboard.RIGHT: if (e.shiftKey) width += 1; else x += 1; drawTicks(); break; case Keyboard.LEFT: if (e.shiftKey) width -= 1; else x -= 1; drawTicks(); break; case 78: createNewRuler(); break; }

This code snippet also shows the key events used to move the window and to create new windows.

Moving the application window


The startMove() method is used to begin a system-controlled move of the window. The PixelPerfect sample application uses this method when the mouse device controls the move. When the arrow keys control the parameters of the move, PixelPerfect changes the window bounds, one pixel at a time, by incrementing or decrementing the x or y property of the window. (The code is included in the switch statement in the preceding code snippet.)

Changing the transparency of the application window


The visible background of the window is a Sprite object that was added to the ruler stage. The application changes the transparency of the background by adjusting the alpha property of the background sprite in response to mouse wheel events:
private function onMouseWheel(e:MouseEvent):void { var delta:int = (e.delta < 0) ? -1 : 1; if (sprite.alpha >= .1 || e.delta > 0) sprite.alpha += (delta / 50); }

For a window to be transparent against the desktop, the window must be created with transparency enabled by setting transparent property to true in the NativeWindowsInitOptions object passed to the window constructor. The transparency state of a window cannot be changed once the window is created.

Closing the application window


When a doubleclick event is dispatched, PixelPerfect calls the close() method of the window.
private function onDoubleClick(e:Event):void { close();

ADOBE PRODUCT X.0 21


User Guide

When a windows's close() method is called, the NativeWindow object does not dispatch a closing event. To allow cancellation of the close operation, dispatch the closing event in your event handler:
private function onDoubleClick(e:Event):void var closing:Event = new Event(Event.CLOSING,true,true); dispatchEvent(closing); if(!closing.isDefaultPrevented()){ close(); } }

A close event is dispatched after the window is closed, signaling the completion of the close process. After a window is closed, it cannot be reopened. Closing the window frees the resources associated with the window (unless they are referenced elsewhere) so that they can be garbage collected. The application is responsible for closing its windows so that the associated resources can be freed. When the last window of an application is closed, the application also exits. This default behavior can be changed by setting the Shell object autoExit property to false. For more information about the methods and properties of the AIR windowing API, see the AIR ActionScript 3.0 Reference.

See also

Working with windows on page 48

22

Chapter 31: Creating a transparent window application


The WeatherStation sample application illustrates the following Adobe AIR features:

A window with a transparent background and a non-rectangular border Window control buttons for minimizing and closing the window Moving the window by responding to the "move" event
The WeatherStation sample also shows how some powerful Flash Player features can be used within an Adobe AIR application, including:

Calling an HTTP service to retrieve weather forecast data Storing and retrieving application settings using a SharedObject
Note: This is a sample application provided, as is, for instructional purposes.

About transparent window applications


Adobe AIR supports both opaque and transparent application windows. Transparent windows let the operating system's desktop show through, while opaque windows obscure the desktop area behind them. An AIR window can use the borders, title bar, menu bar, and window control buttons (known collectively as system chrome) that are standard for the operating system. Your application uses the standard system chrome elements when the <systemChrome> element in the application descriptor file is set to standard (the default setting). A window that uses system chrome is always opaque. The Flex WindowedApplication component provides an alternate set of window chrome elements and a rectangular window frame. The WindowedApplication component's window is always opaque as well. If you want your application to be transparent, it should not use system chrome or the WindowedApplication component. This means that the application must provide its own mechanisms for controlling the window and its background.

The WeatherStation example application


The WeatherStation application window is partially transparent and it does not use system chrome, so it displays rounded and irregular borders instead of the usual rectangular frame. It also displays images that extend beyond the visual border of the application. The application queries weather forecast data from the Yahoo! Weather service based on a U.S. ZIP code. Data is returned from the service as XML and the application then parses, formats and displays the data. The following graphic shows the application in action:

ADOBE PRODUCT X.0 23


User Guide

Files used to build the application


The application includes the following source files:

File WeatherStation.mxml

Description The main application file in MXML for Flex 2. Details of the code are discussed in the Understanding the code section. Defines the HTTPService call and its parameters. The application descriptor file. Images used for the custom window chrome buttons.

WeatherServices.mxml WeatherStation-app.xml assets/close_icon.png assets/minimize_icon.png icons/AIRApp_16.png icons/AIRApp_32.png icons/AIRApp_48.png icons/AIRApp_128.png

Sample icon files.

You can download the source files for this example at http://download.macromedia.com/pub/labs/air/quickstart_apps/b2/WeatherStation.zip.

See also

Building the quick-start sample applications with Flex on page 7

Understanding the code


The WeatherStation application performs other interesting functions such as communicating with a remote HTTP service, parsing an XML result using the new ActionScript 3.0 E4X syntax, and storing and retrieving settings data using a SharedObject. For more information about these functions, see Programming ActionScript 3.0 and the ActionScript 3.0 Language Reference. This topic does not describe all of the Flex components used in the MXML code for this application. For more information on the Flex components, see the Flex 2.0 Language Reference.

ADOBE PRODUCT X.0 24


User Guide

Setting the window transparency


The transparency of the application window is controlled in two places. First, the application descriptor file for the application contains two elements that affect window transparency: the <systemChrome> element and the <transparent> element. The <transparent> element must be set to true. The <systemChrome> element should be set to none or else the standard system window title bar and buttons will be used, and the application background will be opaque. The following example shows these elements within the <initialWindow> element of the WeatherStation application descriptor file:
<initialWindow> <title>WeatherStation</title> <content>WeatherStation.swf</content> <systemChrome>none</systemChrome> <transparent>true</transparent> <!-- additional settings... --> </initialWindow>

Second, the CSS styles that are applied to the Flex 2 Application component can affect how that component's background is displayed and whether it is opaque or transparent. To make sure the background is transparent, the WeatherStation.mxml file includes the following CSS style declaration:
<mx:Style> Application { background-color:""; background-image:""; padding: 0px; } /* additional style declarations... */ </mx:Style>

Moving the application window


A user can move the WeatherStation window around on the desktop by clicking anywhere in the background of the window, holding the mouse down, and dragging the window to another location. To trigger the window-moving process, the application monitors and responds to the MouseEvent.MOUSE_DOWN event. First, the Application declaration specifies that the initApp() method will handle the creationComplete event.
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" xmlns="*" usePreloader="false" creationComplete="initApp()" layout="absolute" width="250" paddingRight="0" paddingLeft="0">

After the application is loaded, the initApp() method sets up mouseDown event listeners on the two visible VBox components. When the user presses the mouse button while the cursor is over one of these VBox components, the onMouseDown() method is loaded.
// adds mouseDown listeners so a click and drag on the background or the

ADOBE PRODUCT X.0 25


User Guide

// display area lets you move the window this.bgBox.addEventListener(MouseEvent.MOUSE_DOWN, onMouseDown); this.tempBox.addEventListener(MouseEvent.MOUSE_DOWN, onMouseDown);

The onMouseDown() method shows how simple it can be to start the window moving sequence:
private function onMouseDown(evt:MouseEvent):void { stage.nativeWindow.startMove(); }

Calling the NativeWindow.startMove() method results in the window moving around the desktop in response to mouse movements until the mouse button is released. You don't need to write additional code to control the window moving and stopping sequence; it is handled automatically.

Minimizing and closing the application window


The WeatherStation application uses small Button components to let the user minimize or close the application. Each button's click event is set to trigger an appropriate method, as follows:
<mx:Button id="minimizeBtn" icon="@Embed('assets/minimize_icon.png')" width="16" height="16" click="onMinimize(event)" /> <mx:Button id="closeBtn" icon="@Embed('assets/close_icon.png')" width="16" height="16" click="onClose(event)" />

When the minimize button is clicked, the onMinimize() method calls the NativeWindow.minimize() method:
private function onMinimize(evt:MouseEvent):void { stage.nativeWindow.minimize(); }

When the close button is clicked, the onClose() method calls the NativeWindow.close() method:
private function onClose(evt:MouseEvent):void { stage.nativeWindow.close(); }

The NativeWindow.close() method terminates the application. It does so asynchronously, and a close event is started when the application is about to stop. The application can listen for the close event and perform various clean-up or housekeeping functions before the application stops.

Casting a shadow on the desktop


The WeatherStation window appears to cast a shadow on the desktop as if it were floating above it. In fact, the drop shadow is not applied to the window itself. It is applied to the bgBox VBox component that's used as a background element, and it casts a shadow on the applications window's transparent background. This makes it seem like the shadow is falling on the desktop instead.

ADOBE PRODUCT X.0 26


User Guide

To achieve this effect, the application first defines an instance of the flash.filters.DropShadowFilter class.
public var shadowFilter:DropShadowFilter;

The initApp() method then sets the parameters of the filter and applies the filter to the bgBox component and a number of other components, as follows:
// creates a generic drop shadow to use on components that don't accept CSS shadow styles shadowFilter = new DropShadowFilter(); shadowFilter.color = 0x000000; shadowFilter.alpha = 0.4; shadowFilter.blurX = 5; shadowFilter.blurY = 5; shadowFilter.distance = 5; // 'external' shadows addShadow(this.bgBox); addShadow(this.largeImage); // 'internal' shadows addShadow(this.locationTxt); addShadow(this.tempTxt); addShadow(this.conditionTxt); addShadow(this.additionalTxt);

Because the largeImage Image object extends beyond the boundaries of the bgBox component's background, it also needs a shadow to make the illusion complete. The other display components are only given shadows because they seem to stand out better that way. The same DropShadowFilter instance is applied to each of the components in the addShadow() method:
/** * Adds a standard drop shadow to a display object. */ public function addShadow(comp:DisplayObject):void { comp.filters = [this.shadowFilter]; }

Each component is passed as an argument to this method and treated as a DisplayObject instance (so the same method could be used for DisplayObject instances that are not Flex UIComponent instances too). Each object's filters array is then set to an array containing the one shadowFilter object.

27

Chapter 32: Launching native windows


The Window Launcher sample application shows a number of features for opening native windows in Adobe AIR, including the following:

Setting the window type. Setting the window chrome Turning on transparency Setting the window title Setting the window position and size Setting the whether a window is resizable, minimizable, and maximizable

Note: This is a sample application provided, as is, for instructional purposes.

Installing and testing the application


The WindowLauncher application is intentionally simple. The intent is to show you the basics of how to open new windows in AIR.

The Window Launcher sample application on Microsoft Windows, flanked by four different kinds of native windows.

ADOBE PRODUCT X.0 28


User Guide

Files used to build the application


The application is built from the following source files:
File WindowLauncher.mxml Description The main application file in MXML for Flex. Details of the code are discussed in Understanding the code on page 28. The AIR application descriptor file. Sample AIR icon files.

WindowLauncher-app.xml icons/AIRApp_16.png icons/AIRApp_32.png icons/AIRApp_48.png icons/AIRApp_128.png

You can download the source files for this example at http://download.macromedia.com/pub/labs/air/quickstart_apps/b2/WindowLauncher.zip.

See also

Building the quick-start sample applications with Flex on page 7

Understanding the code


This article does not describe the Flex components used in the MXML code for the file. For information on these, see the Flex 2.0 Language Reference.

Setting window initialization options


Before a new native window can be created, you must first create a NativeWindowInitOptions object and set its properties. These properties cannot be changed after the window is created. The following lines in the createNewWindow() method of the sample application create the NativeWindowInitOptions object and set its properties based on the MXML controls of the launcher window:
var options:NativeWindowInitOptions = new NativeWindowInitOptions(); options.maximizable = maximizableOption.selected; options.minimizable = minimizableOption.selected; options.resizable = resizableOption.selected; options.transparent = transparentOption.selected; options.systemChrome = Chrome.selectedItem.optionString; options.type = windowType.selectedItem.optionString;

Note: Transparency is not supported for windows that use system chrome. Likewise, system chrome can not be used for lightweight windows. These rules are enforced in Window Launcher by validating the settings as they are made.

ADOBE PRODUCT X.0 29


User Guide

Creating the window


Create a native window with the NativeWindow class constructor. Pass the NativeWindowInitOptions object created earlier to the window constructor. The following lines from the createNewWindow() method create the new window and set the properties based on the MXML controls of the launcher window:
var newWindow:NativeWindow = new NativeWindow(options); newWindow.title = titleString.text; newWindow.alwaysInFront = alwaysInFrontOption.selected; newWindow.x = Number(xPosition.text); newWindow.y = Number(yPosition.text); newWindow.width = Number(widthValue.text); newWindow.height = Number(heightValue.text);

These properties of the window can be changed at any time before a window is closed. The width and height properties set the outer dimensions of the window, including the size of any system chrome. Thus a window without system chrome has a smaller client area than a window with chrome.

Adding content and setting stage properties


A native window is created with a stage that represents the client (drawable) area of the window. This stage is the root container of the display tree. Add content to the client area of a native window by adding a DisplayList object (or an object that inherits from DisplayList) to the stage or another DisplayObject already on the stage with the addChild() method. The stagescaleMode and align properties determine how the stage (and any objects on it) behave when the window is resized. The stageScaleMode property sets how the stage scales and clips when a window is resized:
noScale The stage is not scaled. The size of the stage changes directly with the bounds of the window. Objects may be clipped if the window is resized smaller. showAll The stage scales while maintaining the original aspect ratio. Objects in the original view area are never clipped. Padding is added to the stage area when the window is resized to a different aspect ratio. noBorder The stage scales while maintaining the original aspect ratio. Objects in the original view are clipped if the

window is resized to a different aspect ratio.


exactFit The stage scales without regard to the original aspect ratio. Objects are distorted when the window is resized to a different aspect ratio.

The stage align property sets the edge or corner to which the stage origin is anchored when the window is resized. For example, if you set the stage align property to bottomRight, when the window is resized larger from the bottom, right corner, the stage origin also moves down and to the right in relation to the window. To then place an object in the top, left corner, you use negative coordinates. The stage origin always starts in the top, left-hand corner of the window no matter which alignment value is chosen. The following lines from the createNewWindow() method of the sample application set the stage properties based on the MXML control settings and draws some example content into the window by creating a Sprite and calling its graphics methods to draw a grid of rectangles.
newWindow.stage.align = stageAlignment.selectedItem.optionString; newWindow.stage.scaleMode = ScaleMode.selectedItem.optionString; var client:Sprite = new Sprite(); var rectSize:int = 40; var rectSpace:int = 4; with(client.graphics){

ADOBE PRODUCT X.0 30


User Guide

lineStyle(1,0,1); beginFill(0x234578,.5); for(var i:int = 0; i <= Math.floor(newWindow.stage.stageWidth/rectSize); i++){ for (var j:int = 0; j <= Math.floor(newWindow.stage.stageHeight/rectSize); j++){ drawRoundRect(i*rectSize,j*rectSize, rectSize-rectSpace,rectSize-rectSpace,10,10); }//j loop }//i loop endFill(); } newWindow.stage.addChild(client);

Adding interactivity and making the window visible


The final lines of the createNewWindow() method add event handlers to the new window. Two event handlers are added to windows with no chrome to move and close the window.
//Add handlers to move and close the window if there is no chrome. if(options.systemChrome == NativeWindowSystemChrome.NONE){ newWindow.stage.doubleClickEnabled = true; newWindow.stage.addEventListener(KeyboardEvent.KEY_DOWN, function(e:Event):void{e.target.stage.window.close();}); newWindow.stage.addEventListener(MouseEvent.MOUSE_DOWN, function(e:Event):void{e.target.stage.window.startMove();}) }

After the window has been created, content added, and event handlers attached, the final step is to make the window visible:
newWindow.visible = true;

31

Chapter 33: Creating toast-style windows


When an application needs to display informational messages without disturbing the users workflow, toast-style windows can be the right solution. The WordUp sample application creates toast windows with the following attributes: Chromeless

Displayed above other windows Does not steal the keyboard or mouse focus Expires so the user doesnt have to close them Persists when the user is away from the computer
The WordUp sample illustrates how to use the following AIR APIs: NativeWindow To create and display the toast windows

Shell To detect user presence and to use the dock or system tray icons Screen To layout multiple toast windows on the desktop without overlapping
Note: This is a sample application provided, as is, for instructional purposes.

The WordUp sample application


The WordUp sample application runs in the background with no main window. When a timer with a randomized interval fires, the application displays a toast window with a random message. After about five seconds, the message expires and the toast window will close automatically. To detect when the user is present, the application listens for userIdle and userPresent events from the Shell object. When the userIdle event is dispatched, message expiration is suspended until the next userPresent event. This keeps the messages on the screen until the user has a chance to read them. A userIdle event is dispatched when no keyboard or mouse input has been detected within an interval determined by the Shell.idleThreshold property. The default interval is a reasonable five minutes, but WordUp resets the value to be very short so the change in application behavior can be more easily observed. The following screenshot shows the application in action (on Windows):

ADOBE PRODUCT X.0 32


User Guide

Testing the application


Launch the WordUp application. On Windows, a system tray icon will be displayed in the notification area of the taskbar. On Mac OS X, the normal triangle under the dock icon will show that the application is running. After about five seconds, the first message will pop-up from the bottom of the screen. It will then disappear after a few moments. If you leave your computer idle for several seconds, the messages will stay on screen until you make a mouse or keyboard input, and then will remain for a few seconds longer to give you time to read the messages. To exit the application, on Windows, right-click on the system tray icon and select Exit WordUp from the menu. On Mac OS X, click the dock icon to activate the application and select Quit WordUp from the application menu.

Files used to build the application


The application includes the following source files:

File WordUp.as

Description The main application file. Listens for message events from the MessageCenter and passes the message to the DisplayManager for display. Extends the Icon class to embed the icon assets for this application. The application descriptor file. See Setting application properties on page 41. Manages the creation, placement, and expiration of message windows. Extends the NativeWindow class to create a toast-style window displaying a text message. Dispatches message events. (In WordUp the messages are random text strings and dispatched on a timer interval.) Extends the Event class to add a message property.

WordUpIcon.as WordUp-app.xml display/DisplayManager.as display/MessageWindow.as messages/MessageCenter.as

messages/MessageEvent.as

messages/RandomMessageGenerator.as Generates a random text string. icons/WordUpIcon16.png icons/WordUpIcon32.png icons/WordUpIcon48.png icons/WordUpIcon128.png Sample icon files used both for the desktop application icon and the system tray or dock icon.

You can download the source files for this example at http://download.macromedia.com/pub/labs/air/quickstart_apps/b2/WordUp.zip.

See also

Building the quick-start sample applications with Flex on page 7

Understanding the code


For more information about non-AIR specific functions and APIs, see Programming ActionScript 3.0 and the ActionScript 3.0 Language Reference.

ADOBE PRODUCT X.0 33


User Guide

Initializing a windowless application


The first step to creating a windowless application is to make sure that the initial window that is created automatically by AIR never becomes visible. The visibility of this window is controlled in two places. The first place is within the <initialWindow> element of the application descriptor file. If <visible>true</visible> is placed within this element, then the window will be visible on application startup. The second place window visibility is controlled is the visible property of the window itself. The visible property can be set directly. It is also set to true when the window activate() method is called. Note: If you are using the mx:WindowedApplication component from the Flex Framework to define your initial window, you must also set the components visible property to false. It is often a good idea to give the user some indication that an application is running, even when it has no visible windows. On Mac OS X, the application dock icon serves this purpose. On Windows, the system tray icon can be used. The dock icon automatically appears in the dock when the application is running and provides a default menu for exiting the application so WordUp doesnt need to change the dock icon properties. The system tray icon will only be shown if you assign an image. You can also provide a tooltip and a menu. WordUp detects whether it is running on an operating system that supports system tray icons using the static Shell.supportsSystemTrayIcon property. If so, it adds a tooltip and a menu containing an exit command:
Shell.shell.icon.bitmaps = icon.bitmaps; if(Shell.supportsSystemTrayIcon){ var sysTray:SystemTrayIcon = Shell.shell.icon as SystemTrayIcon; sysTray.tooltip = "WordUp"; sysTray.menu = new NativeMenu(); var exitCommand:NativeMenuItem = sysTray.menu.addItem(new NativeMenuItem("Exit WordUp")); exitCommand.addEventListener(Event.SELECT,function(event:Event):void{ Shell.shell.exit(); }); }

To initialize the application logic, WordUp creates a new DisplayManager object, which manages the pop-up toast windows, and a new MessageCenter object, which periodically generates an event containing a random message:
displayManager = new DisplayManager(); messageCenter = new MessageCenter(); messageCenter.addEventListener(MessageCenter.NEW_MESSAGE, onMessage);

The onMessage() event handler function passes the message text to the display manager, which creates a new message window. Since the initial window created by AIR is not needed, ideally it could be closed. However, there is a defect in this Beta release of AIR that results in the system tray icon disappearing if the initial window is closed.
Shell.shell.autoExit = false; //stage.nativeWindow.close(); }

Creating a toast-style window


The MessageWindow class extends NativeWindow. The constructor sets the appropriate NativeWindowInitOptions for the window. The important options are:
options.type = NativeWindowType.LIGHTWEIGHT; options.systemChrome = NativeWindowSystemChrome.NONE; options.transparent = true;

ADOBE PRODUCT X.0 34


User Guide

These options define a window with no system chrome and which wont appear on the Windows taskbar or OS X windows menu. In addition, the window alwaysInFront property is set to true so that the message will appear above other windows. To regulate the life span of a message window, the window listens to custom lifeTick events from the DisplayManager object:
manager.addEventListener(DisplayManager.LIFE_TICK,lifeTick,false,0,true);

When this event is dispatched, the window decrements its time-to-live counter. When the counter reaches zero, the window closes itself (removing the event listener to aid garbage collection):
public function lifeTick(event:Event):void{ timeToLive--; if(timeToLive < 1){ close(); } } public override function close():void{ manager.removeEventListener(DisplayManager.LIFE_TICK,lifeTick); super.close(); }

The MessageWindow class overrides the close() method so that if the message window is closed in response to a mouse event, the event listener will also be removed.

Placing the message window


WordUp uses the Screen API to find a spot to display the new message. The findSpotForMessage() function searches for an open area starting with the lower-right-hand corner of the first screen in the Screen.screens array. When it finds an open spot, it launches the window from the bottom of the screen to its appointed destination. To check whether a message window is already displayed in a given spot, WordUp loops through the Shell.shell.openedWindows array. It tests whether the rectangle defined by the area being considered intersects the rectangle defined by the window bounds:
private function isOccupied(x:int,y:int):Boolean{ var occupied:Boolean = false; var testRect:Rectangle = new Rectangle(x,y,MessageWindow.stockWidth,MessageWindow.stockHeight); for each (var window:NativeWindow in Shell.shell.openedWindows){ occupied = occupied || window.bounds.intersects(testRect); } return occupied; }

Detecting user presence


WordUp uses the Shell userIdle and userPresent events to determine whether the user is actively using the computer.
Shell.shell.idleThreshold = idleTime; Shell.shell.addEventListener(Event.USER_IDLE,onIdle); Shell.shell.addEventListener(Event.USER_PRESENT,onPresence);

In response to these events, WordUp suspends or restarts the DisplayManager timer that dispatches lifeTick events to the message windows:
//When the computer is idle, don't remove the messages private function onIdle(event:Event):void{ displayManager.pauseExpiration(); trace("Idling.");

ADOBE PRODUCT X.0 35


User Guide

} //On return, let windows expire again private function onPresence(event:Event):void{ displayManager.resumeExpiration(); trace("Resuming."); }

36

Chapter 34: Controlling the display order of windows


Adobe AIR provides several methods and properties for controlling the display order of application windows. The Z sample application illustrates the following AIR features:

Activating a window Pulling a window to the top of the display order Pushing a window to the bottom of the display order Ordering a window relative to another application window Keeping a window in front of other windows
Note: This is a sample application provided, as is, for instructional purposes.

About window depth sorting


AIR allows you to sort windows into two display order groups based on the value of the alwaysInFront property. Any windows with alwaysInFront = true will be displayed in front of any windows with alwaysInFront=false. (They will also be displayed in front of other windows of other applications, so some caution should be exercised before setting this property.) AIR provides four methods for ordering the display depth of a window relative to other windows:

orderToFront() orderToBack() orderInFrontOf(NativeWindow) orderInBackOf(NativeWindow)

In addition, the activate() method will also order the window to the front. Changing the value of the alwaysInFront property may also change the ordering of a window. For example, changing the value from true to false will order the window behind any other alwaysInFront windows, but still in front of other windows. When you use the orderInFrontOf() or orderInBackOf() methods, the window will take on the alwaysInFront setting of the target window. The window ordering methods return a boolean value that indicates whether the ordering operation succeeded. The only reason an ordering operation may fail is if the window being ordered is not visible.

The Z sample application


The Z application draws three example windows that allow you to experiment with the depth ordering APIs and how they interact with user manipulation of the windows. On Windows, a fourth window supplies a menu bar which contains menu commands for the depth ordering methods and properties. The following screenshot shows the application in action (on Windows):

ADOBE PRODUCT X.0 37


User Guide

Testing the application


Launch the Z application. Use the application or window menu to exercise the native window depth ordering methods and properties on the three geometric windows.

Files used to build the application


The application includes the following source files:

File Z.as Z-app.xml window/ZWindow.as

Description The main application file. Details of the code are discussed in the Understanding the code section. The application descriptor file. See Setting application properties on page 41. Extends the NativeWindow class to customize the behavior of the example windows in the Z application. Extends ZWindow to draw a circular window. Extends ZWindow to draw a rectangular window. Extends ZWindow to draw a triangular window. Sample icon files.

window/CircularZWindow.as window/RectangularZWindow.as window/TriangularZWindow.as icons/ZIcon16.png icons/ZIcon32.png icons/ZIcon48.png icons/ZIcon128.png

You can download the source files for this example at http://download.macromedia.com/pub/labs/air/quickstart_apps/b2/Z.zip.

ADOBE PRODUCT X.0 38


User Guide

See also

Building the quick-start sample applications with Flex on page 7

Understanding the code


The Z application provides three example windows that can be ordered through menu commands. A base class, ZWindow, is defined to establish the window behaviors. The subclasses, CircularZWindow, TriangularZWindow, and RectangularZWindow, extend this base class to draw a distinctive geometric shape. The ordering commands are dispatched through a native menu. Each window defines a menu through the makeZOrderMenu() method. The method is called by the main Z application class for each window to add the windows menu as a submenu to either the application menu or the main Z window menu (depending on which type of menu the operating system supports):
private function createWindowMenu():NativeMenu{ var menu:NativeMenu = new NativeMenu(); for each(var zWindow:ZWindow in ZWindow.zWindows){ menu.addSubmenu(zWindow.makeZOrderMenu(), zWindow.title); } return menu; }

The makeZOrderMenu() method returns a NativeMenu object containing the menu commands and submenus. The first two items in the menu show the window alwaysInFront and visible settings. To make sure the state of the menu matches the state of the window, the menu item checked property is updated in response to the menu displaying event. The displaying event is dispatched immediately before the menu is made visible.
var stateAlwaysInFront:NativeMenuItem = menu.addItem(new NativeMenuItem("Always in front")); stateAlwaysInFront.addEventListener(Event.SELECT, toggleAlwaysInFront); var stateVisible:NativeMenuItem = menu.addItem(new NativeMenuItem("Visible")); stateVisible.addEventListener(Event.SELECT, toggleVisibility); menu.addEventListener(Event.DISPLAYING, function(event:Event):void{ stateAlwaysInFront.checked = alwaysInFront; stateVisible.checked = visible; });

Separator items are created by setting the isSeparator parameter to true in the item constructor.
menu.addItem(new NativeMenuItem("",true));//separator

Command items are added by adding an item with the appropriate label and attaching an event listener that carries out the command. For example, the following statement adds the activate command:
var commandActivate:NativeMenuItem = menu.addItem(new NativeMenuItem("Activate")); commandActivate.addEventListener(Event.SELECT, activateCommand);

The event handler simply calls the window activate() method.


private function activateCommand(event:Event):void{ activate(); }

ADOBE PRODUCT X.0 39


User Guide

Since the menu is defined in the window itself, there is no need to determine which window the command should be applied to. However, for the Order in front of and Order behind commands, the second window needed for the command must be identified. To do this, the ZWindow object is assigned to the menu item data property when a window submenu is populated. The Z application creates a submenu containing an item for each of the orderable windows:
var submenuOrderInFront:NativeMenuItem = menu.addSubmenu(createWindowSubmenu(),"Order in front of"); submenuOrderInFront.submenu.addEventListener(Event.SELECT, orderInFrontCommand);

The items in the submenu are added by the displayWindows() method by looping through the static ZWindow.zWindows array, which contains every instance of a ZWindow.
private function displayWindows(event:Event):void{ for each(var existing:NativeMenuItem in event.target.items){ event.target.removeItem(existing); } for each(var zWindow:ZWindow in ZWindow.zWindows){ var item:NativeMenuItem = event.target.addItem(new NativeMenuItem(zWindow.title)); item.data = zWindow; item.addEventListener(Event.SELECT,function(event:Event):void{ }); } }

To make it easier to access the ZWindow object for the windows listed in the menu, the window object is assigned to the menu item data property. The data property is of type object, so you can assign any object to it. This allows the assigned object to be accessed through the event object target property when handling the menu item select event:
private function orderInFrontCommand(event:Event):void{ orderInFrontOf(event.target.data as ZWindow); }

40

Chapter 35: Dragging, copying, and pasting data


The Scrappy sample application shows a number of features of the drag-and-drop and copy-and-paste APIs in Adobe AIR, including the following:

Creating a Clipboard object to contain the information or objects to be transferred through drag and drop or the system clipboard.
Starting a drag operation. Receiving dropped information or objects. Rendering the standard data formats using Adobe AIR and Flash objects. Writing to the system clipboard. Reading from the system clipboard.

Note: This is a sample application provided, as is, for instructional purposes.

Installing and testing the application


The Scrappy application is intentionally simple. The intent is to show you the basics of how to transfer data using drag and drop and copy and paste in Adobe AIR.

To use Scrappy, drag files, bitmaps, URLs, and text to the window. The application accepts dragged items in any of the standard formats supported by AIR. You can also paste (v) items into the window, as well as cut (x), copy (c) and delete (Del) existing items.

ADOBE PRODUCT X.0 41


User Guide

Note: Not all applications post bitmap data to the clipboard in a format supported by AIR.

Files used to build the application


The application is built from the following source files:
File Scrappy.as Description The main application file in ActionScript. Details of the code are discussed in Understanding the code on page 41. The base class for displaying the dragged or pasted information. Extends Scrap to display text. Extends Scrap to display images. Extends Scrap to display HTML and XML documents. Extends Scrap to load and display files. Opens a window to display the about.html file. Describes this sample application and provides some items to drag into the main window. The AIR application descriptor file (see The application descriptor file structure on page 41) Sample AIR icon files.

scraps/Scrap.as scraps/TextScrap.as scraps/BitmapScrap.as scraps/HTMLScrap.as scraps/FileScrap.as AboutWindow.as about.html Scrappy-app.xml icons/AIRApp_16.png icons/AIRApp_32.png icons/AIRApp_48.png icons/AIRApp_128.png

You can download the source files for this example at http://download.macromedia.com/pub/labs/air/quickstart_apps/b2/Scrappy.zip.

See also

Building the quick-start sample applications with Flex on page 7.

Understanding the code


The following sections discuss how the code related to AIR works in this sample application. This article does not describe all of the ActionScript classes used in the application. For information on these, see the Flex 3 Language Reference. Note: This article demonstrates the use of the flash.desktop.DragManager class in an ActionScript project. If you are building a Flex application, you should use the Flex mx.managers.DragManager class.

ADOBE PRODUCT X.0 42


User Guide

Creating the canvas


Scrappy uses a full-window sprite that acts as the window backdrop and the target for drag-and-drop operations. To allow a Sprite, or other display object to act as a receiver for a drag gesture, you must listen for the NativeDragEvents dispatched from that object. The Scrappy class defines the following members for creating the window, the drop target sprite and the event listeners:
public var dragTarget:Sprite = new Sprite(); public var about:NativeWindow; public function Scrappy():void{ super(); addEventListener(Event.ADDED_TO_STAGE, onStaged); stage.align = StageAlign.TOP_LEFT; stage.scaleMode = StageScaleMode.NO_SCALE; stage.stageFocusRect = false; dragTarget.focusRect = false; addChild(dragTarget); } public function onStaged(event:Event):void{ dragTarget.addEventListener(NativeDragEvent.NATIVE_DRAG_ENTER,onDragIn); dragTarget.addEventListener(NativeDragEvent.NATIVE_DRAG_DROP,onDrop); dragTarget.addEventListener(NativeDragEvent.NATIVE_DRAG_EXIT,onDragExit); stage.addEventListener(MouseEvent.MOUSE_DOWN,onMouseDown); stage.addEventListener(KeyboardEvent.KEY_DOWN,onKeyDown); stage.window.addEventListener(NativeWindowBoundsEvent.RESIZE, onResize); stage.window.addEventListener(Event.CLOSE,onClose);

} The important events for the drag target are: nativeDragEnter, which tells you when a drag gesture enters within the display object area; nativeDragExit, which tells you when a drag gesture leaves the display object area; and nativeDragDrop, which tells you that the drop has occurred on the display object. You can also listen for the nativeDragOver event instead of the nativeDragEnter event if you need to track the position of the mouse over the target. The target will dispatch nativeDragOver events whenever the mouse moves (as well as on a short interval) The keyDown event on the stage is used to check for the paste command. The event listener is attached to the stage because a sprite will only receive keyboard events when it has focus.

Dropping data onto the canvas


To allow a user to drop data onto a target, you must:
1 2 3

Check the format of the data. Accept the drag gesture with DragManager.acceptDrop(). Handle the nativeDragDrop event.

Checking the dragged data

To check the data being dragged into the target, access the clipboard property of the NativeDragEvent object:
public function onDragIn(event:NativeDragEvent):void{ var transferable:Clipboard = event.clipboard; if(transferable.hasFormat(ClipboardFormats.BITMAP_FORMAT) ||

ADOBE PRODUCT X.0 43


User Guide

transferable.hasFormat(ClipboardFormats.FILE_LIST_FORMAT) || transferable.hasFormat(ClipboardFormats.TEXT_FORMAT) || transferable.hasFormat(ClipboardFormats.URL_FORMAT) || transferable.hasFormat("SCRAP")){ DragManager.acceptDragDrop(dragTarget); } }

The Scrappy application can accept each of the four standard formats. It also defines a custom format, SCRAP, which contains a reference to a Scrap object created within the Scrappy application itself. In some situations, you might also want to check the allowedActions property of the event object before accepting the drop.
Accepting the gesture

The call to DragManager.acceptDrop() allows the passed in display object to receive the drop. The DragManager will change the display cursor to indicate that the drop is possible. If the user releases the mouse button while over the same display object (and before a nativeDragExit event occurs), then the designated display object will dispatch a nativeDragDrop event.
Taking the drop

After the drop occurs on an eligible display object, you can access the data through the clipboard property of the nativeDragDrop event object. You may also set a drag-and-drop action to indicate which of the three actions, copy, move, or link should be taken. The chosen action is communicated back to the drag initiator object in the nativeDragComplete event. Scrappy passes the Clipboard object from the nativeDragDrop event to the Scrap class factory method, which creates new Scrap objects based on the data format and adds the returned display object to the stage.
public function onDrop(event:NativeDragEvent):void{ DragManager.dropAction = "copy"; var scrap:Scrap = Scrap.createScrap(event.clipboard,false,event.stageX,event.stageY); addChild(scrap); scrap.grabFocus(); }

Displaying information with the Scrap class


The scrap package classes act as containers for information dropped or pasted into the Scrappy window. The base Scrap class extends Sprite to add functions for handling user interaction with scrap objects, including dragging out of the window, deleting, and copying. The Scrap class also implements a static factory method for creating new scrap objects. The scrap subclasses extend Scrap to handle the standard formats of data that can be transferred. To render the data, these classes add child display objects to the scrap, such as a TextField or an HTMLControl. They also handle adding data in the correct format to the Clipboard object when a scrap is dragged out of the application. The Scrap subclasses are:
TextScrap Uses a TextField to display text data. BitmapScrap Uses a Bitmap object to display bitmap data. HTMLScrap Uses an HTMLControl to load and display URLs (including file URLs). FileScrap Loads and displays the file contents, or displays the file name and icon. For the handful of file types

Scrappy understands, the FileScrap constructor loads the data and creates one of other types of Scrap object to render it.

ADOBE PRODUCT X.0 44


User Guide

Scrap Factory

The scrap factory class, Scrap.createScrap(), takes a Clipboard object, checks the data formats available, and then creates the appropriate type of scrap object to display the data.
public static function createScrap(data:Clipboard, makeCopy:Boolean, placeX:int, placeY:int):Scrap{ var scrap:Scrap; if(data.hasFormat("SCRAP")){ scrap = Scrap(data.dataForFormat("SCRAP",ClipboardTransferMode.ORIGINAL_ONLY)); } else if(data.hasFormat(ClipboardFormats.BITMAP_FORMAT)){ scrap = new BitmapScrap(BitmapData(data.getData( ClipboardFormats.BITMAP_FORMAT))); } else if(data.hasFormat(ClipboardFormats.TEXT_FORMAT)){ scrap = new TextScrap(String(data.getData( ClipboardFormats.TEXT_FORMAT))); } else if(data.hasFormat(ClipboardFormats.FILE_LIST_FORMAT)){ var dropfiles:Array = data.getData(ClipboardFormats.FILE_LIST_FORMAT) as Array; for each (var file:File in dropfiles) { scrap = new FileScrap(file); } } else if(data.hasFormat(ClipboardFormats.URL_FORMAT)){ scrap = new HTMLScrap(String(data.getData( ClipboardFormats.URL_FORMAT))); } scrap.x = placeX + offset.x; scrap.y = placeY + offset.y; return scrap; }

If the Clipboard object contains the format, SCRAP, then the drag must have originated from the Scrappy application itself (or from another AIR application that uses the SCRAP format name). This can happen if, for example, the user drags a scrap out of the application window and then back into the window. By setting the transfer mode to originalPreferred, a reference to the original scrap will be returned when available. This avoids duplicating the scrap object when it originates in the current application. The originalOnly transfer mode should not be used in this case, because there is a chance the original object will be deleted in the middle of a cut-and-paste operation. Note: Copying serialized data is not implemented in this version of Scrappy. Because Scraps are complex objects, they can not be simply deserialized and used as is. An additional step is required to rebuild a valid Scrap object from the properties of the anonymous object returned by the deserializer.

Dragging data out of the canvas


To allow a user to drag an object out of an application, you must:
1 2 3

Respond to a mouseDown or mouseMove event. Create a Clipboard object containing the data or object to drag. Start the drag operation from the mouseDown or mouseMove event handler by calling

DragManager.doDrag().

ADOBE PRODUCT X.0 45


User Guide

Scrappy uses two separate drag APIs. As long as a drag gesture stays within the bounds of the main window, Scrappy uses the Sprite drag API, which provides a somewhat smoother operation for positioning sprites. When the drag gesture leaves the window, Scrappy transitions the drag gesture to the DragManager API, which allows data to be dragged to other applications.
Preparing to drag

When the Scrap object being moved leaves the window, it dispatches a rollOut event. The handler for this event stops the Sprite-controlled drag and gets a Clipboard object by calling the function, addTransferableData(). The addTransferableData() function creates a new Clipboard object and adds a reference to the current Scrap object by using a custom format name. The addTransferableData function is overridden in the Scrap subclasses to add the data appropriate to that subclass in addition to the reference format.
protected function onDragOut(event:Event):void{ parent.removeEventListener(MouseEvent.ROLL_OUT,onDragOut); this.stopDrag(); offset.x = -mouseX; offset.y = -mouseY; var transferObject:Clipboard = addTransferableData(); DragManager.doDrag(this,transferObject,getImage(),offset); } protected function addTransferableData():Clipboard{ var transfer:Clipboard = new Clipboard(); transfer.setData("SCRAP",this,true); return transfer; } Starting the drag operation

The call to DragManager.doDrag(), starts the DragManager-controlled part of the drag gesture. The initiator parameter of the method designates the display object that begun the drag gesture, and, more importantly, the object that will dispatch the nativeDragComplete event when the user releases the mouse button. The clipboard parameter is the Clipboard object. Once the doDrag() is called, the object can only be accessed in the event handlers of the NativeDragEvents. You can supply an image to display while the drag gesture is in progress. Scrappy creates an image by drawing the sprite into a BitmapData object. The offset point lets you offset the image from the mouse hotspot.
Completing the drop

When the drop occurs, the object passed to DragManager.doDrag() as the initiator will dispatch a nativeDragComplete event. The action selected by the drop target is reported in the dropAction property of the event. Scrappy only supports the copy action for external transfers, so no action needs to be taken.

Copying and pasting data


Compared to drag and drop, copy and paste are very simple operations. The static property Clipboard.generalClipboard represents the operating system clipboard. You can write data directly to the clipboard with Clipboard.generalClipboard.setData() and you can read data with Clipboard.generalClipboard.getData() (normally you should check whether the data format is appropriate before reading the data). Note: In this Beta release, the traditional key combinations used for copy, cut, and paste commands, Ctrl-c, Ctrl-x, and Ctrl-v, are handled internally by the runtime and do not generate keyboard events.

ADOBE PRODUCT X.0 46


User Guide

Paste

Scrappy implements a paste command on the main window. In response to a paste command (v), the application passes the clipboard data to the factory method Scrap.createScrap(), which is also used to create scraps for drop operations.
public function doPaste():void{ var scrap:Scrap = Scrap.createScrap(Clipboard.generalClipboard, stage.stageWidth/4,stage.stageHeight/4); addChild(scrap); scrap.grabFocus(); }

The pasted scrap is always placed in the same spot on the stage.
Copy

Copy is implemented by the Scrap base class. The function calls the addTransferable() function to get the data from the Scrap object (this is the same function used for drag-and-drop). You cannot assign a Clipboard object directly to the Clipboard.generalClipboard property, so you must copy each of the formats individually:
public function doCopy():void{ var transferObject:Clipboard = addTransferableData(); for each( var format:String in Clipboard.generalClipboard.formats){ Clipboard.generalClipboard.setData(format, transferObject.getData(format),true); } } Cut

Cut just copies the scrap object to the clipboard, then deletes it.

47

Chapter 36: Creating resizable, nonrectangular windows


Rectangular windows are fine, and appropriate for most applications. However, just because they are the easiest to draw doesnt mean that all your windows have to be curve impoverished. The !Square sample application creates a window based on the ellipse, rather than the rectangle. The window uses vector graphics for its chrome, so there are no issues with bitmap scaling to limit the window size or aspect ratio. The !Square sample illustrates how to extend the NativeWindow class to create windows with alternative visuals and behavior using the AIR APIs and the rich Flash graphics capabilities. Note: This is a sample application provided, as is, for instructional purposes.

The !Square sample application


The !Square sample application. The following graphic shows the application in action:

Testing the application


Launch the !Square application. Resize the window using any of the eight grippers along the window drag bar. Move the window using the drag bar. Drag the white disk to the edge of the window to observe that any part of the disk which is outside the window client area is properly clipped.

Files used to build the application


The application includes the following source files:

File Launcher.as Launcher-app.xml window/RoundWindow.as

Description A stub class that creates the main application window and closes. The application descriptor file. See Setting application properties on page 41. Extends the NativeWindow class.

ADOBE PRODUCT X.0 48


User Guide

window/ClippedStage.as

Extends the Sprite class to create a content container that clips anything outside the window client area. Implements the gripper controls for resizing the window. A utility class providing some functions for calculating geometric relationships. An embedded texture graphic for the gripper bitmap fill. A class providing some sample content for the window. A visual object. Simulates spring forces. Graphics files used for the desktop application icon.

window/EllipticalGripper.as window/GeometryUtils.as window/texture.png content/BouncingEye.as content/EyeBall.as content/Spring.as icons/!SquareIcon16.png icons/!SquareIcon32.png icons/!SquareIcon48.png icons/!SquareIcon128.png

You can download the source files for this example at http://download.macromedia.com/pub/labs/air/quickstart_apps/b2/!Square.zip.

See also

Building the quick-start sample applications with Flex on page 7

Understanding the code


The !Square application uses several graphics functions not specific to AIR. For more information about these functions, see Programming ActionScript 3.0 and the ActionScript 3.0 Language Reference.

Extending the NativeWindow class


The RoundWindow class extends the AIR NativeWindow class to specialize the constructor and to define the methods and properties to draw its window chrome.
Specializing the constructor public function RoundWindow(title:String=""){ var initOptions:NativeWindowInitOptions = new NativeWindowInitOptions(); initOptions.systemChrome = NativeWindowSystemChrome.NONE; initOptions.transparent = true; super(initOptions); bounds = new Rectangle(0,0,viewWidth,viewHeight); this.title = title; stage.align = StageAlign.TOP_LEFT; stage.scaleMode = StageScaleMode.NO_SCALE; stage.addChild(clippedStage); addWindowDressing(); addEventListener(NativeWindowBoundsEvent.RESIZE,onBoundsChange); draw(viewWidth,viewHeight); activate(); }

ADOBE PRODUCT X.0 49


User Guide

Setting required listeners addEventListener(NativeWindowBoundsEvent.RESIZE,onBoundsChange);

Drawing elliptical borders


with(border.graphics){ clear(); beginFill(bevelColor,1); drawEllipse(0,0,viewWidth,viewHeight); drawEllipse(4,4,viewWidth-8,viewHeight-8); endFill(); beginFill(borderColor,1); drawEllipse(4,4,viewWidth-8,viewHeight-8); drawEllipse(16,16,viewWidth-32,viewHeight-32); endFill(); beginFill(bevelColor,1); drawEllipse(16,16,viewWidth-32,viewHeight-32); drawEllipse(20,20,viewWidth-40,viewHeight-40); endFill(); }

Drawing a section of an ellipse

Because the Graphics class does not have a function for drawing just a piece of an elliptical arc, drawing the resizing gripper onto the border is actually more challenging than drawing the border itself. You could use the curveTo() method, but calculating the proper control point locations to match the elliptical border has its own mathematical challenges. For this task, !Square uses a simpler polyline technique based on the parametric equation of the ellipse. A point on the border is calculated based on the height and width and angle from the midpoint of the ellipse. Then the next point is calculated by increasing the angle a small amount and a line is drawn between them. This process is repeated until the desired arc is drawn. The following formula can be used to calculate a point along the ellipse, given the angle, and the width and the height of the ellipse:

ADOBE PRODUCT X.0 50


User Guide

The grippers are arranged around the border at preset angles, so the angle is known. The width and height of the ellipse is the width and height of the window for the outer edge of the window border (viewWidth and viewHeight), and the width and height minus the thickness of the border for the inner edge of the window border. The drawing routine uses this formula to calculate the x and y coordinates of the four corners of the gripper, points A, B, C, and D:
var A.x A.y var B.x B.y var C.x C.y var D.x D.y A:Point = new Point(); = Math.cos(startAngle) * viewWidth/2; = Math.sin(startAngle) * viewHeight/2; B:Point = new Point(); = Math.cos(startAngle) * (viewWidth-40)/2; = Math.sin(startAngle) * (viewHeight-40)/2; C:Point = new Point(); = Math.cos(stopAngle) * (viewWidth-40)/2; = Math.sin(stopAngle) * (viewHeight-40)/2; D:Point = new Point(); = Math.cos(stopAngle) * viewWidth/2; = Math.sin(stopAngle) * viewHeight/2;

The start and stop angles are calculated from the preset gripper angle, plus and minus the angular width of the gripper. Defining these quantities as angles rather than lengths makes the math a bit easier and also provides a more pleasing effect when the window is resized since the gripper size stays proportional to the border size.
var startAngle:Number = (angleRadians - spreadRadians); var stopAngle:Number = (angleRadians + spreadRadians);

The routine next draws the shape of the gripper between the four points:

First, a straight line is drawn from A to B:


moveTo(A.x,A.y); lineTo(B.x,B.y);

Next, a series of line segments is drawn between B and C. If enough segments are used, then the visual effect is indistinguishable from an actual curve. !Square uses ten segments, which seems sufficient.
for(var i:int = 1; i < 10; i++){ lineTo(Math.cos(startAngle + i * incAngle) * (viewWidth-40)/2, Math.sin(startAngle + i * incAngle) * (viewHeight-40)/2); }

Another straight line is drawn from C to D and the shape is closed by drawing a polyline segment from D back to A. The shape is started with the beginBitmapFill() method so when endFill() is called the area defined by the drawing commands is filled with a bitmap texture.

ADOBE PRODUCT X.0 51


User Guide

Clipping the client area

The RoundWindow class uses a sprite with a clipping mask applied as the container for its contents. Any content objects that are drawn outside the border of the window will be clipped. Window chrome elements are added directly to the stage so that they will not be clipped. Clipping can be implemented in Flash by setting the mask property of a Sprite object with another Sprite object. The masking sprite is not drawn, but only the parts in the first sprite that fall under the area defined by the masks graphics commands will be visible. In !Square, the clipped sprite is defined by the ClippedStage class. This class creates a clipping mask using the familiar commands for drawing an ellipse based on the width and height of the window. Any part of an object added as a child of the ClippedStage object that falls outside the ellipse will be clipped.
private function setClipMask(bounds:Rectangle):void{ ellipticalMask.graphics.clear(); ellipticalMask.graphics.beginFill(0xffffff,1); ellipticalMask.graphics.drawEllipse(0,0,bounds.width,bounds.height); ellipticalMask.graphics.endFill(); }

The class also listens for resize events from the parent window and responds by redrawing the clipping mask based on the new window dimensions.
private function onResize(event:NativeWindowBoundsEvent):void{ setClipMask(event.afterBounds); }

This type of clipping is not limited to simple shapes, so the technique can be used for any window that has areas which should be masked.

Resizing an elliptical window


To resize the window, the border and grippers must be redrawn based on the new width and height of the window. The resize event object includes an afterBounds property that reports the new dimensions. The width and height from this property are passed to the window draw() method.
private function onBoundsChange(boundsEvent:NativeWindowBoundsEvent):void{ draw(boundsEvent.afterBounds.width,boundsEvent.afterBounds.height); }

Dont forget to clear the graphics before drawing the new border.

Handling content in an elliptical window


Because the content in the !Square window is aware of its container (the springs are attached to the border), it must react to changes in window size and shape. It does this by listening for the window resize event and recalculating the dependent variables.
private function onResize(event:NativeWindowBoundsEvent):void{ center.x = event.afterBounds.width/2; center.y = event.afterBounds.height/2; eye.x -= event.afterBounds.x - event.beforeBounds.x; eye.y -= event.afterBounds.y - event.beforeBounds.y; for each (var spring:Spring in springs){ spring.outerEnd = calculateSpringAnchorPoint(spring.anchorAngle); } }

ADOBE PRODUCT X.0 52


User Guide

Since the content is always animated, it does not need to be redrawn by the resize listener. Redrawing will occur on the next frame event anyway. For non-animated content, you may need to resize or reposition the window content objects directly.

53

Chapter 37: Measuring the virtual desktop


The Screens sample application illustrates how to get information about the screens available to an application using the AIR Screen API. Note: This is a sample application provided, as is, for instructional purposes.

About the virtual desktop


The virtual desktop is composed of one or more screens. A main screen is designated and the origin of the virtual desktop is placed at the top-left-hand corner of this screen. (Positive values are to the right and down, as you would expect on a computer display.) Thus you should be prepared for negative coordinates when dealing with screens. The usable area of a screen excludes any task bars, menu bars, sidebars, or other bars that are always drawn in front of any windows. AIR provides dimensions for both the entire screen and the usable area.

The Screens sample application


The Screens application draws a representation of the screens on the virtual desktop, including a scaled down version of itself. The usable area of each screen is shown in blue. The area that is within the screen, but outside the usable area is shown in grey. A lighter blue highlight is displayed on the screen the application window is on. The following screenshot shows the application in action:

Testing the application


Launch the Screen application. You can move the application window around, change monitor resolution and color depth, and change the size and location of task bars to observe the effects on the screen information reported by the AIR Screen API. Use the arrow keys to jump the window from screen to screen.

Files used to build the application


The application includes the following source files:

ADOBE PRODUCT X.0 54


User Guide

File Screens.as Screens-app.xml icons/ApolloApp_16.png icons/ApolloApp_32.png icons/ApolloApp_48.png icons/ApolloApp_128.png

Description The main application file. Details of the code are discussed in the Understanding the code section. The application descriptor file. See Setting application properties on page 41. Sample icon files.

You can download the source files for this example at http://download.macromedia.com/pub/labs/air/quickstart_apps/.

See also

Building the quick-start sample applications with Flex on page 7

Understanding the code


The Screen application uses several graphics functions not specific to AIR. For more information about these functions, see Programming ActionScript 3.0 and the ActionScript 3.0 Language Reference.

Computing the virtual bounds


A bounds is a rectangle that describes both location and dimension. The virtual desktop bounds is the bounding box that encloses all of the screens. To compute this bounding box, the Screens application loops through each screen in the array of Screen objects provided by the static Screen.screens property and compares each side of the screen to the current side of the bounding box. If the screen value is further out than the current bounding box value, the bound box value is pushed out to match the screen. The result is a bounds rectangle that encloses all the screens.
private function computeVirtualBounds(screens:Array):Rectangle{ var bounds:Rectangle = new Rectangle(); for each (var screen:Screen in screens){ if(bounds.left > screen.bounds.left){bounds.left = screen.bounds.left;} if(bounds.right < screen.bounds.right){bounds.right = screen.bounds.right;} if(bounds.top > screen.bounds.top){bounds.top = screen.bounds.top;} if(bounds.bottom < screen.bounds.bottom){bounds.bottom = screen.bounds.bottom;} } return bounds; }

Sizing the application window proportionally to the screen


Once the size of the virtual desktop is computed, the size of the application window can be determined. The width of the window is constrained to be 60% of the width of the main screen (plus a little extra for a border). The height of the window is scaled proportionally to the virtual desktop so that the window will be just tall enough to display the entire scaled down representation:
var scale:Number = (Screen.mainScreen.bounds.width * .6)/virtualScreenBounds.width; stage.stageWidth = Screen.mainScreen.bounds.width * .6 + border * 2; stage.stageHeight = virtualScreenBounds.height * scale + border * 2;

ADOBE PRODUCT X.0 55


User Guide

The Screen object for the operating-system designated main screen can be accessed using the static mainScreen property of the Screen class.

Drawing a representation of the screens


Since the Screens application class extends Sprite, the sprite graphics routines are used to draw the representation of the screens. The screens in the desktop are drawn using the screen coordinates and a transformation matrix is set on the main sprite to translate and scale the screen coordinates into the display area of the window. The transformation matrix is created with the Matrix class createBox() method. This method take the horizontal and vertical scale factors as parameters. The same scale is used for both and is computed by dividing the display area of the window by the total width of the virtual desktop. The createBox() method also takes parameters for how much to shift (or translate) the representation so that it lines up properly on the window. The redraw() method computes the transformation matrix, assigns it to the main sprites transform.matrix property and then calls the functions that draw the elements of the screen representation. The method is called in response to the enterFrame event.
private function redraw(event:Event):void{ virtualScreenBounds = computeVirtualBounds(Screen.screens); var scale:Number = (stage.nativeWindow.width - border * 2)/virtualScreenBounds.width; virtualScreenToWindowTransform.createBox(scale,scale,0, border - (virtualScreenBounds.x * scale), border - (virtualScreenBounds.y * scale)); transform.matrix = virtualScreenToWindowTransform; graphics.clear(); drawScreenRepresentation(); highlightScreens(); drawWindowModel(); }

To draw the screens, the drawScreenRepresentation() method loops through the screens and draws a rectangle for the entire screen and another for the usable area:
with(graphics){ //Draw screen rectangle beginFill(screenColor,.5); drawRect(screen.bounds.left, screen.bounds.top, screen.bounds.width, screen.bounds.height); endFill(); //Draw rectangle for usable screen area beginFill(usableScreenColor,.5); drawRect(screen.visibleBounds.left, screen.visibleBounds.top, screen.visibleBounds.width, screen.visibleBounds.height); endFill(); //...

The method also draws several labels. To avoid having to add and remove TextField objects on each animation frame, The labels are drawn into a bitmap with the BitmapData.draw() method. The resulting label bitmaps are drawn to the main sprite using a bitmap fill.

ADOBE PRODUCT X.0 56


User Guide

Using bitmap fills


A non-intuitive aspect of using a bitmap fill is that the fill is registered to the origin of the sprite, not the top-left corner of the area to be filled. For repeating textures this may not be an issue, but it can leave the words drawn in the label quite far outside the filled area. The solution is to use another transformation matrix to move the label bitmap to the filled area. The following lines draw a bitmap containing the words Main Screen to the center of the main screen:
//Draw label to show which screen is the "main" screen var mainLabelBitmap:BitmapData = drawLabel("Main Screen"); labelTransform = new Matrix(1,0,0,1,(Screen.mainScreen.visibleBounds.width mainLabelBitmap.width)/2, (Screen.mainScreen.visibleBounds.height mainLabelBitmap.height)/2); with(graphics){ beginBitmapFill(mainLabelBitmap,labelTransform,false); drawRect((Screen.mainScreen.visibleBounds.width - mainLabelBitmap.width)/2, (Screen.mainScreen.visibleBounds.height - mainLabelBitmap.height)/2, mainLabelBitmap.width, mainLabelBitmap.height); endFill(); mainLabelBitmap = null; }

Moving a window between screens


The Screens application lets you jump the window from screen to screen using the arrow keys. To figure out where to move the window, the application must determine which screen it is currently on and which, if any, screens lie in the chosen direction. The current screen can be determined using the static Screen.getScreensForRectangle() method. This method returns an array of all screens with which the rectangle intersects. The following function passes the window bounds into the function and returns the first screen in the resulting array:
private function getCurrentScreen():Screen{ var current:Screen; var screens:Array = Screen.getScreensForRectangle(stage.nativeWindow.bounds); (screens.length > 0) ? current = screens[0] : current = Screen.mainScreen; return current; }

If the window is somehow off any screen, the main screen is returned. To find the proper screen to which to move the window, the array of screens is vertically or horizontally sorted and then the relevant coordinates are compared by walking through the sorted array. The following method moves the window to the left:
/*Moves the window to the next screen to the left*/ private function moveLeft():void{ var currentScreen:Screen = getCurrentScreen(); var left:Array = Screen.screens; left.sort(sortHorizontal); for(var i:int = 0; i < left.length - 1; i++){ if(left[i].bounds.left < stage.nativeWindow.bounds.left){ stage.nativeWindow.x += left[i].bounds.left - currentScreen.bounds.left; stage.nativeWindow.y += left[i].bounds.top - currentScreen.bounds.top; } } }

The sort method called above uses the following sorting function to compare screen coordinates:

ADOBE PRODUCT X.0 57


User Guide

private function sortHorizontal(a:Screen, b:Screen):int{ if (a.bounds.left > b.bounds.left){ return 1; } else if (a.bounds.left < b.bounds.left){ return -1; } else {return 0;} }

58

Chapter 38: Using the system tray and dock icons


Dock and system tray icons provide a convenient means to let users access an application that has no visible windows. The Stopwatch sample application illustrates the following Adobe AIR features: Setting and animating the icon image

Using mouse events on the icon Bouncing the dock icon


Note: This is a sample application provided, as is, for instructional purposes.

About application icons


Applications are provided on both the Mac OS X and Windows operating systems, although the conventions for using these icons on each system are a bit different. The application icon object in AIR, which provides an interface for interacting with the application icon, is created automatically. The object type will be a subclass of the InteractiveIcon class, but the exact type depends on the operating system on which an application is running. On Mac OS X, the icon will be a DockIcon object. On Windows, the icon will be a SystemTrayIcon object. The InteractiveIcon class defines the bitmaps property of the icon, so you can always set the image data. The other useful properties like menu and tooltip are defined by the subclass. You must make sure that you do not attempt to access the members of the wrong icon class or you will get a run-time exception. You can check which icon type is available using the static Shell properties: supportsDockIcon and supportsSystemTrayIcon.

Dock icons
Dock icons provide a means for users to easily access applications. An application icon is shown in the dock whenever the application is running. At the users discretion the icon can be kept in the dock even when the application is not running. The image used for the icon in both cases is the icon specified in the application descriptor file. When your application is running, you can change the icon image by setting the Shell.shell.icon.bitmaps property. When the application shuts down, the icon, if left in the dock, will revert back to the original image. In addition to setting the icon image, you can add a menu to the dock icon. When you add a menu, the items are displayed above the standard, operating-system provided menu. Although you cannot listen for mouse events on the dock icon directly, an invoke event is dispatched by the Shell object whenever the user clicks on the dock icon.

System tray icons


On Windows, the official purpose of the system tray is to notify the user that important application events have occurred, such as the arrival of an e-mail hence the official name of the system tray is the notification area. In practice the system tray has become a place where users can access applications that do not ordinarily display windows.

ADOBE PRODUCT X.0 59


User Guide

System tray icons support a menu, a tooltip, and will dispatch events for mouse events.

The Stopwatch sample application


The Stopwatch application creates a 60-second timer utility that animates the system tray or dock icon as it counts down. Stopwatch illustrates how to use and animate system tray and dock icons. The following screenshot shows the application window (in non-minimized state):

Testing the application


Launch the Stopwatch application. Click the triangular start button to start the watch. Note that the system tray or dock icon changes as the time ticks down. Click the small yellow button to minimize the application to the system tray or dock. The stopwatch window will automatically reappear when the countdown reaches zero. You can also click on the icon to restore the window.

Files used to build the application


The application includes the following source files:

File Stopwatch.as Stopwatch-app.xml Clock.as HandControl.as GoButton.as

Description The main application file. Details of the code are discussed in the Understanding the code section. The application descriptor file. See Setting application properties on page 41. Defines the clock control used to set and display the timer. Defines the second hand, which is a subcomponent of the clock. Defines the start/stop button.

ADOBE PRODUCT X.0 60


User Guide

MinimizeButton.as CloseButton.as icons/StopWatchIcon16.png icons/StopWatchIcon32.png icons/StopWatchIcon48.png icons/StopWatchIcon128.png

Defines the minimize button. Defines the close button. Sample icon files.

You can download the source files for this example at http://download.macromedia.com/pub/labs/air/quickstart_apps/b2/Stopwatch.zip.

See also

Building the quick-start sample applications with Flex on page 7

Understanding the code


Stopwatch uses three functions related to the application icon: dock() minimizes the application to the dock or system tray.

undock() restores the application. changeIcon() updates the icon to reflect the current visual state of the stopwatch.

The application defines two sets of functions for these operations, one for Windows and one for Mac OS X. When the application is initialized at run time, the dock, undock, and changeIcon function objects are set to the version designed for the current operating system. On Mac OS X, the function references are set and a listener is added to detect when the user clicks on the dock icon:
dock = OSXdock; undock = OSXundock; changeIcon = OSXchangeIcon; Shell.shell.addEventListener(InvokeEvent.INVOKE,onIconClick);

Clicks on the dock icon can be detected by listening to Shell invoke events. On Windows, the function references are set, a tooltip is added and then a click event listener is added directly to the system tray icon object:
dock = DOSdock; undock = DOSundock; changeIcon = DOSchangeIcon; SystemTrayIcon(Shell.shell.icon).tooltip = "Stopwatch"; SystemTrayIcon(Shell.shell.icon).addEventListener(MouseEvent.CLICK, onIconClick);

Animating the icon


The icon is animated by updating the Shell.shell.icon.bitmaps array on every one second tick of the stopwatch timer. A function is defined by the Clock class, which defines the stopwatch visuals and logic, to get a BitmapData object containing a snapshot of the clock display:
public function get bitmapData():BitmapData{ var clockImage:BitmapData = new BitmapData(this.width, this.height,true,0x00ffffff); clockImage.draw(this); return clockImage;

ADOBE PRODUCT X.0 61


User Guide

To create a transparent icon image, the new BitmapData object must be created with the transparent parameter of its constructor set to true. In addition, the fill color should be set using the 32-bit ARGB color value, setting the alpha component to 0, for example, in hexadecimal format, you could use: 0x00ffffff. On Windows, the system tray icon is so small that the animation effect is too subtle. To compensate, a color transform is used to invert the colors of the icon for every other frame.
public function DOSchangeIcon():void{ var matrix:Matrix = new Matrix(16/clock.width,0,0,16/clock.height); var icon:BitmapData = new BitmapData(16,16,true,0x00ffffff); if(alternate){ icon.draw(clock.bitmapData,matrix,null,null,null,true); } else { icon.draw(clock.bitmapData,matrix,invert,null,null,true); } Shell.shell.icon.bitmaps = [icon]; alternate = !alternate; }

The color transform is defined as:


private var invert:ColorTransform = new ColorTransform(-1,-1,-1,1,255,255,255,0);

which subtracts the value of each color component from 255. In addition, rather than let the operating system scale the icon image down to 16x16 pixels, the clock bitmapData is scaled down by drawing it into a new BitmapData object using a transformation matrix.

Notifying the user


On Mac OS X, the dock icon can be used to notify the user that an event of interest has occurred. In Stopwatch, the dock icon is bounced when the timer reaches zero by calling icon.bounce(). If the critical notification type is used, the dock icon will bounce until the user activates the application. If the informational type is used, the dock icon will bounce once. (If the application already has focus, the dock icon will not bounce at all.) Windows does not use the same notification scheme. You can change the system tray icon image or pop-up a lightweight window containing a message, but the system tray icon cannot be bounced. A window-level notification function is provided on Windows. This function, notifyUser(), called on the NativeWindow object, will highlight or flash the windows taskbar entry. Stopwatch checks which type of icon the current operating system supports and calls either the DockIcon.bounce() or the NativeWindow.notifyUser() function.
public function notify():void{ if(Shell.supportsDockIcon){ var dock:DockIcon = Shell.shell.icon as DockIcon; dock.bounce(NotificationType.CRITICAL); } else if (Shell.supportsSystemTrayIcon){ stage.nativeWindow.notifyUser(NotificationType.CRITICAL); } }

Index
A adobe-app URL scheme 84 application storage director 84 application store directory 81 app-storage URL scheme 84 appStoreDirectory property (File class) 81 asynchronous methods 79 B browseForDirectory() method (File class) 82 browseForOpen() method (File class) 83 browseForSave() method (File class) 83 browsing to select a directory 82 browsing to select a file 83 C clearing directories 87 copying directories 87 copying files 89 copyTo() method (File class) 89 copyToAsync() method (File class) 89 createDirectory() method (File class) 86 createTempDirectory() method (File class) 86, 90 createTempFile() method (File class) 90 creating directories 86 creationDate property (File class) 88 creator property (File class) 88 D deleteDirectory() method (File class) 87 deleteDirectoryAsync() method (File class) 87 deleteFile() method (File class) 89 deleteFileAsync() method (File class) 89 deleting directories 87, 90 deleting files 89, 90 desktop directory 81 desktopDirectory property (File class) 81 directories 81, 86 copying 87 creating 86 deleting 87, 90 enumerating 86 moving 87 referencing 81 directory chooser dialog boxes 82 documents directory 81 documentsDirectory property (File class) 81 E encoding property (File class) 85 enumerating directories 86 exists property (File class) 88 F file API 79 file chooser dialog boxes 83 File class 79, 80 appStoreDirectory property 80 browseForDirectory() method 82 browseForOpen() method 83 browseForSave() method 83 copyTo() method 89 copyToAsync() method 89 createDirectory() method 86 createTempDirectory() method 86, 90 createTempFile() method 90 creationDate property 88 creator property 88 deleteDirectory() method 87 deleteDirectoryAsync() method 87 deleteFile() method 89 deleteFileAsync() method 89 desktopDirectory property 80 documentsDirectory property 80 encoding property 85 exists property 88 isDirectory property 88 lineEnding property 85 listDirectory() method 86 listDirectoryAsync() method 86 listRootDirectories method 80 modificationDate property 88 moveTo() method 89 moveToAsync() method 89 moveToTrash() method 90 moveToTrashAsync() method 90 name property 88 nativePath property 80, 88

2 INDEX

parent property 88 relativize() method 84 resolve() method 80 root volumes 80 separator property 85 size property 88 type property 88 url property 80, 88 userDirectory property 80 file URL scheme 84 FileMode class 79 files copying 89 deleting 89, 90 moving 89 reading 90 referencing 82 writing 90 FileStream class 79 H home directory 81

moveTo() method (File class) 89 moveToAsync() method (File class) 89 moveToTrash() method (File class) 90 moveToTrashAsync() method (File class) 90 moving directories 87 moving files 89 My Documents directory (Windows) 81 N name property (File class) 88 nativePath property (File class) 81, 88 P parent property (File class) 88 path delimiter (file system) 82 paths (file and directory) 84 paths, relative 84 R

T temporary directories 86 temporary files 90 trash (deleting a file) 90 type property (File class) 88 U url property (File class) 81, 88 URL schemes 84 userDirectory property (File class) 81 W writing files 90

I isDirectory property (File class) 88 L lineEnding property (File class) 85 listDirectory() method (File class) 86 listDirectoryAsync() method (File class) 86 listRootDirectories method (File class) 81 M modificationDate property (File class) 88

reading files 90 relative paths (between files) 84 relativize() method (File class) 84 resolve() method (File class) 81 root volumes 81 S separator property (File class) 85 size property (File class) 88 start-up directory of an application 81 synchronous methods 79

Você também pode gostar