By leveraging taskbar and Dock functionality in your AIR application, you can enhance your application’s usability. This ability is especially useful when you want to notify the user that an event of interest has occurred.
On Windows, you can place an additional representation of your application (other than the taskbar button) in the form of an icon in the system tray (also called the notification area) of the taskbar. On a Mac, you can place an icon referencing your application in the Dock when the application is running. To get the attention of the user when something important happens, you can make a system tray icon flash (Windows) or the Dock icon of your application bounce (Mac).
On both operating systems, you can also add menus to the icons in the system tray or Dock.
Because the implementations in this chapter are operating system
specific, it is a best practice to first check which operating system and
associated icon is supported on the user’s computer. You can check which
icon types are supported using the static NativeApplication
properties:
supportsDockIcon
and supportsSystemTrayIcon
. Both types of icons
support menus and custom images, but Table 13-1 outlines some differences.
System Tray Icon (Windows) | Dock Icon (Mac) |
This icon is visible only when you set an image. | This is always visible, showing the image specified inside the application descriptor, unless you set a different image. |
You can set tooltip text. | You cannot set a tooltip text. |
You can listen for mouse events dispatched by the system tray icon. | Clicking the Dock icon
doesn’t dispatch any events; however, you can detect a click on the
icon by listening to the |
The code you need to check the available icon type is as follows:
if(NativeApplication.supportsDockIcon){ //Dock available }else if (NativeApplication.supportsSystemTrayIcon){ // taskbar and system tray available }
Assign an Array
containing the
new image or images to the bitmaps
property of the icon
object in your
NativeApplication
instance.
The icon
property of NativeApplication
is an InteractiveIcon
instance that represents the
application icon(s). The bitmaps
property of InteractiveIcon
holds the
images that will be shown inside the system tray on your Windows
taskbar. This property expects an array of several images and enables
you to define several sizes of your icon image. AIR automatically
selects the image according to the current display size of the system
tray icon (set on the operating system level). At runtime, AIR will
detect the dimensions of the icons in the array, and the bitmap in the
array closest to the display size will be used and scaled if necessary.
Most typical sizes (in pixels) are 16 × 16, 32 × 32, 48 × 48, and 128 ×
128.
To set the icon in your application’s taskbar button, you specify it in your application descriptor file (see Setting the Default Program Menu Folder).
This example demonstrates how to add an Array
of images to the bitmaps
property of your application icon.
The images you put in the Array
must be of type BitmapData
. A
BitmapData
object represents the
pixels of a Bitmap
object.
The full MXML code for the example is as follows:
<?xml version="1.0" encoding="utf-8"?> <mx:WindowedApplication xmlns:mx="http://www.adobe.com/2006/mxml" applicationComplete="init()" layout="absolute" title="Recipe 13.1: Adding an icon to the Windows taskbar" > <mx:Script > <![CDATA[ //embed the images to use as icon import mx.core.BitmapAsset; [Embed(source="app:/assets/icons/flashing/Icon_fl_32.png")] public var img32:Class; [Embed(source="app:/assets/icons/flashing/Icon_fl_16.png")] public var img16:Class; //define the bitmapData object private var icon32:BitmapAsset; private var icon16:BitmapAsset; private function init():void{ //define bitmapData object icon32= (new img32()as BitmapAsset); icon16= (new img16()as BitmapAsset); //assign the bitmapData objects to the icon.bitmaps if(NativeApplication.supportsSystemTrayIcon){ this.nativeApplication.icon.bitmaps =[icon32.bitmapData, icon16.bitmapData]; } } ]]> </mx:Script> </mx:WindowedApplication>
You first embed the images in your AIR application by using the
Embed
directive so that they are
available at runtime. You then instantiate the embedded assets and
store them in local variables that you can readily access when needed.
When the application is fully loaded (as indicated by the dispatch of
the applicationComplete
event), you
make a new instance of every loaded image, which is actually a
BitmapAsset
instance, so you cast
the object to a BitmapAsset
object,
as shown here:
icon32= (new img32() as BitmapAsset); ...
Lastly, you can now access the bitmapData
property of the Bitmap
, so put the image instances in an
Array
, and assign that Array
to the icon.bitmaps
property of the NativeApplication
object.
This example adds four sizes of the icon image:
this.nativeApplication.icon.bitmaps =[ icon32.bitmapDta,icon16.bitmapData];
This example demonstrates how to add an Array
of images to the icon.bitmaps
property. The images you put in
the Array
must be of type BitmapData
. A BitmapData
object represents the pixels of a
Bitmap
object.
This is the code when developing AIR applications with JavaScript:
<html > <head> <title>Recipe 13.1: Adding an icon to the Windows system tray</title> <script src="AIRAliases.js" type="text/javascript"></script> <script type="text/javascript"> var iconLoadComplete = function(event) { if (air.NativeApplication.supportsSystemTrayIcon) { air.NativeApplication.nativeApplication.icon.bitmaps = new runtime.Array(event.target.content.bitmapData); } } function init(){ var iconLoad = new air.Loader(); iconLoad.contentLoaderInfo.addEventListener(air.Event.COMPLETE,iconLoadComplete); iconLoad.load(new air.URLRequest("assets/Icon_16.png")); } </script> </head> <body onLoad="init()"> </body> </html>
First, define a new air.Loader
instance to load the icon file.
To initiate the loading process, you call the load
method of the air.Loader
class. The load
method needs a URLRequest
object. This object contains the
location information of the image file that needs to be loaded. This
example loads one image file (Icon_16.png). When the icon is loaded, you
assign it to the icon.bitmaps
property in order for it to show in the system tray.
Make an instance of the NativeMenu
class, and assign it to the
icon.menu
property of the NativeApplication
object. On Windows, the
system tray icon is represented by the SystemTrayIcon
property.
To attach a menu to the system tray icon, you use the NativeMenu
instance. The following examples
first embed several sizes of the icon image, read the bitmapData
of the images, and assign the data
to the icon.bitmaps
property of the
NativeApplication
object. This
approach is similar to Adding an Icon to the System Tray (Windows), but this time you
using only two sizes of the icon image.
The example code in bold indicates the line where you
instantiate a new NativeMenu
object
and attach one item to that menu with the label “Close.” To know when
the menu item is clicked, you add a listener for the Event.SELECT
event. Finally, you attach the
menu to the SystemTrayIcon.menu
property. When you run the example and right-click the system tray,
your custom menu will pop up. When you click the close menu item, the
nativeApplication
is exited
(NativeApplication.exit
).
The example code is as follows:
<?xml version="1.0" encoding="utf-8"?> <mx:WindowedApplication xmlns:mx="http://www.adobe.com/2006/mxml" applicationComplete="init()" layout="absolute" title="Recipe 13.2: Adding a custom menu to the systemtray icon (windows)" > <mx:Script > <![CDATA[ //embed the images to use as icon import mx.core.BitmapAsset; [Embed(source="app:/assets/icons/flashing/Icon_fl_32.png")] public var img32:Class; [Embed(source="app:/assets/icons/flashing/Icon_fl_16.png")] public var img16:Class; //define the bitmapData object private var icon32:BitmapAsset; private var icon16:BitmapAsset; private function init():void{ //define bitmapData object icon32= (new img32()as BitmapAsset); icon16= (new img16()as BitmapAsset); //assign the bitmapData objects to the icon.bitmaps if(NativeApplication.supportsSystemTrayIcon){ this.nativeApplication.icon.bitmaps =[icon32.bitmapData,icon16.bitmapData]; } var myMenu:NativeMenu = new NativeMenu(); myMenu.addItem(new NativeMenuItem("Close",false)); myMenu.addEventListener(Event.SELECT,closeApp); //add the menu to the system tray icon if(NativeApplication.supportsSystemTrayIcon){ SystemTrayIcon(NativeApplication.nativeApplication.icon).menu = myMenu; } } private function closeApp(event:Event):void{ this.nativeApplication.exit(); } ]]> </mx:Script> </mx:WindowedApplication>
In this example, you first load the icon file as you did
in Adding an Icon to the System Tray (Windows). Next
you create a new air.NativeMenu
object with one air.NativeMenuItem
object. When the user clicks the application, the closeApp
function is called:
var myMenu = new air.NativeMenu(); myMenu.addItem(new air.NativeMenuItem("Close application",false)); myMenu.addEventListener(air.Event.SELECT,closeApp);
The closeApp
function calls
the exit
method of the NativeApplication
class to close the
application.
To attach the menu to the system tray icon, set your custom menu
as the value for the icon.menu
property of the NativeApplication
instance. Before you do so, however, check that the guest operating
system supports system tray icons using the air.NativeApplication.supportsSystemTrayIcon
property of the NativeApplication
class:
//set the menu of the system tray icon if (air.NativeApplication.supportsSystemTrayIcon) { air.NativeApplication.nativeApplication.icon.menu = myMenu; }
The full example JavaScript code is as follows:
<html > <head> <title>Recipe 13.2: Adding a custom menu to the systemtray icon (windows)</title> <script src="AIRAliases.js" type="text/javascript"></script> <script type="text/javascript"> var iconLoadComplete = function(event) { if(air.NativeApplication.supportsSystemTrayIcon) { air.NativeApplication.nativeApplication.icon.bitmaps = new runtime.Array(event.target.content.bitmapData); } } function init(){ var iconLoad = new air.Loader(); iconLoad.contentLoaderInfo.addEventListener(air.Event.COMPLETE,iconLoadComplete); iconLoad.load(new air.URLRequest("assets/Icon_16.png")); //define a menu var myMenu = new air.NativeMenu(); myMenu.addItem(new air.NativeMenuItem("Close application",false)); myMenu.addEventListener(air.Event.SELECT,closeApp); //set the menu of the system tray icon if (air.NativeApplication.supportsSystemTrayIcon) { air.NativeApplication.nativeApplication.icon.menu = myMenu; } } function closeApp(event){ air.NativeApplication.nativeApplication.exit(); } </script> </head> <body onLoad="init()"> </body> </html>
You want to attach a menu to the Dock icon on a Mac.
Make an instance of the NativeMenu
class, and assign it to the
icon.menu
property of the NativeApplication
object. The Dock icon is
represented as an instance of the DockItem
class.
The technique you use to attach a menu to the Dock icon on a Mac is the same as demonstrated in Adding a Custom Menu to the System Tray Icon (Windows). You will, however, need to check for Dock icon support on the user’s operating system.
To check that the Dock icon is supported, test the
Boolean value of NativeApplication.supportsDockIcon
. If it is
supported, you can copy the example from Adding a Custom Menu to the System Tray Icon (Windows) in full and
change the if
structure to
this:
//add the menu to the system tray icon if(NativeApplication.supportsDockIcon){ DockIcon(NativeApplication.nativeApplication.icon).menu = myMenu; }
To check that the Dock icon is supported, you test the
Boolean value of air.NativeApplication.supportsDockIcon
. You
will copy the example code from Adding a Custom Menu to the System Tray Icon (Windows) and change the
if
structure according to the
following code:
//set the menu of the Dock icon if (air.NativeApplication.supportsDockIcon) { air.NativeApplication.nativeApplication.icon.menu = myMenu; }
Assign an Array
containing the
new icon image (or several icon images with different sizes) to the
icon.bitmaps
property of the NativeApplication
object.
Changing the system tray icon or Dock icon is as easy as assigning
a new icon image to the icon.bitmaps
property of the NativeApplication
object.
You cannot change the icon image used for your application on the taskbar button of your application window (on Windows). That image is always the image you specified as the icon image in your application descriptor file (see Setting the Default Program Menu Folder).
The following example creates an animated system tray or Dock icon (depending on the user’s operating system) by constantly changing the icon at a given time interval, similar to the way a traditional GIF animation works, sequencing images over time.
As you did earlier, you first load the different sizes of the primary icon image. This time you load a second set of icon images with the slightly altered versions of the primary icon with some color changes. When you continuously change the icon to one of those two icon images, the user has the illusion that the icon is flashing in your system tray or Dock.
You implement the “flashing icon” behavior by using a
Timer
object with a timer interval
set to 500 milliseconds. The Timer
class gives you the possibility of running code on a specific time
sequence. You have to set up an event listener for the TimerEvent.TIMER
event, and then at each
interval, the changeIcon
function
is executed that assigns the new array of images to the icon.bitmaps
property. These parts of the
code are highlighted in bold.
<?xml version="1.0" encoding="utf-8"?> <mx:WindowedApplication xmlns:mx="http://www.adobe.com/2006/mxml" applicationComplete="init()" layout="absolute"> <mx:Script > <![CDATA[ import mx.core.BitmapAsset; [Embed(source="app:/assets/icons/flashing/Icon_fl_128.png")] public var img128:Class; [Embed(source="app:/assets/icons/flashing/Icon_fl_48.png")] public var img48:Class; [Embed(source="app:/assets/icons/flashing/Icon_fl_32.png")] public var img32:Class; [Embed(source="app:/assets/icons/flashing/Icon_fl_16.png")] [Bindable] public var img16:Class; [Embed(source="app:/assets/icons/Icon_128.png")] [Bindable] public var imgfl128:Class; [Embed(source="app:/assets/icons/Icon_48.png")] [Bindable] public var imgfl48:Class; [Embed(source="app:/assets/icons/Icon_32.png")] [Bindable] public var imgfl32:Class; [Embed(source="app:/assets/icons/Icon_16.png")] [Bindable] public var imgfl16:Class; private var iconfl128:BitmapData private var iconfl48:BitmapData private var iconfl32:BitmapData private var iconfl16:BitmapData private var icon128:BitmapData private var icon48:BitmapData private var icon32:BitmapData private var icon16:BitmapData private function init():void{ //define bitmapData object icon128= (new img128()as BitmapAsset).bitmapData; icon48= (new img48()as BitmapAsset).bitmapData; icon32= (new img32()as BitmapAsset).bitmapData; icon16= (new img16()as BitmapAsset).bitmapData; iconfl128= (new imgfl128()as BitmapAsset).bitmapData; iconfl48= (new imgfl48()as BitmapAsset).bitmapData; iconfl32= (new imgfl32()as BitmapAsset).bitmapData; iconfl16= (new imgfl16()as BitmapAsset).bitmapData; //define timer object var tmr:Timer = new Timer(500); tmr.addEventListener(TimerEvent.TIMER,changeImage); tmr.start(); } private function changeImage(event:TimerEvent):void{ if(event.target.currentCount%2){ this.nativeApplication.icon.bitmaps =[icon128,icon48,icon32,icon16]; }else{ this.nativeApplication.icon.bitmaps =[iconfl128,iconfl48,iconfl32,iconfl16]; } } ]]> </mx:Script> </mx:WindowedApplication>
In JavaScript, you use an air.Timer
object to create the illusion of a
flashing icon. Every time the air.TimerEvent.TIMER
event is dispatched,
you execute the changeImage
function that assigns one of the two icons to the icon.bitmaps
property of the air.NativeApplication.nativeApplication
instance.
<html > <head> <title>Recipe 13.4: CHANGING THE DOC OR TASKBAR ICON</title> <script src="AIRAliases.js" type="text/javascript"></script> <script type="text/javascript"> var iconsNormal = ["Icon_16.png","Icon_32.png"]; var iconsFlashing = ["Icon_fl_16.png","Icon_fl_32.png"]; //arrays that hold the icons there bitmapdata var bitmapDataArrNormal =[]; var bitmapDataArrFlashing =[]; function iconNormalComplete(event) { bitmapDataArrNormal.push(event.target.content.bitmapData); } function iconFlashingComplete(event) { bitmapDataArrFlashing.push(event.target.content.bitmapData); } function init(){ //load the icons loadIcons(iconsNormal,0); loadIcons(iconsFlashing,1) //start a new timer to change the icon //every 500 miliseconds var tmr = new air.Timer(500); tmr.addEventListener(air.TimerEvent.TIMER,changeIcon); tmr.start(); } function changeIcon(event){ // if(event.target.currentCount%2){ air.NativeApplication.nativeApplication.icon.bitmaps = bitmapDataArrNormal; }else{ air.NativeApplication.nativeApplication.icon.bitmaps = bitmapDataArrFlashing; } } function loadIcons(arr,flag){ for(var i=0;i<arr.length;i++){ //define the loader var iconLoad = new air.Loader(); //register the right listener if(flag){ iconLoad.contentLoaderInfo.addEventListener(air.Event.COMPLETE,iconFlashingComplete); }else{ iconLoad.contentLoaderInfo.addEventListener(air.Event.COMPLETE,iconNormalComplete); } //load the icon image iconLoad.load(new air.URLRequest("assets/"+ arr[i])); } } </script> </head> <body onLoad="init()"> </body> </html>
If the operating system supports window-level notification, you
can make the Dock icon “bounce” by calling the DockItem.bounce
method.
You can pass a NotificationType
to the bounce
method to inform the
user that something critical has happened (the application continuously
bounces until the application is in the foreground) or just to give the
user some information (a single bounce). The two appropriate NoticationType
constants are NotificationType.CRITICAL
and NotificationType.INFORMATIONAL
.
To determine whether the operating system has this notification
capability, you access NativeWindow.supportsNotification
.
The following example shows a small application that has
two buttons defined. When clicked, the buttons notify the user in
either a critical or informational way. After checking that the
operating system supports Dock icons, you can cast the NativeApplication.icon
property to an instance of the DockIcon
class.
<?xml version="1.0" encoding="utf-8"?> <mx:WindowedApplication xmlns:mx="http://www.adobe.com/2006/mxml" layout="vertical" title="Recipe 13.5: Bouncing the dock icon (MAC)" deactivate="bounce()" > <mx:Script > <![CDATA[ private function bounce():void { if (NativeApplication.supportsDockIcon) { var myIcon:DockIcon = NativeApplication.nativeApplication.icon as DockIcon; var type:String = critical.selected ? NotificationType.CRITICAL : NotificationType.INFORMATIONAL; myIcon.bounce(type); } } ]]> </mx:Script> <mx:RadioButtonGroup id="notificationType" /> <mx:RadioButton id="critical" group="{notificationType}" label="NOTIFY THE USER CRITICAL" selected="true"/> <mx:RadioButton id="informational" group="{notificationType}" label="NOTIFY THE USER INFORMATIONAL"/> </mx:WindowedApplication>
In AIR, you define the notification types in the
air.NotificationType
class. You can
bounce the icon of the air.NativeApplication
instance by calling
the bounce
method:
<html > <head> <title>Recipe 13.5: Bouncing the dock icon (MAC)</title> <script src="AIRAliases.js" type="text/javascript"></script> <script type="text/javascript"> function notify() { if (air.NativeApplication.supportsDockIcon) { var critical = document.getElementById("critical"); var type = (critical.checked ? air.NotificationType.CRITICAL : air.NotificationType.INFORMATIONAL); if (air.NativeApplication.supportsDockIcon) { air.NativeApplication.nativeApplication.icon.bounce(type); } } } function setListener() { nativeWindow.addEventListener('deactivate', notify); } </script> </head> <body onload="setListener()"> <form > <div><input id="critical" type="radio" name="notify" value="NOTIFY THE USER CRITICAL" checked="checked" />NOTIFY THE USER CRITICAL</div> <div><input id="information" type="radio" name="notify" value="NOTIFY THE USER INFORMATIONAL" />NOTIFY THE USER INFORMATIONAL</div> </form> </body> </html>
If the operating system supports window-level notification, you
can make the taskbar and window flash by calling the NativeWindow.notifyUser
method.
You can pass a NotificationType
to the notifyUser
method to inform
the user that something critical has happened (the taskbar flashes until
the application is in the foreground) or just to give the user some
information (the taskbar and window flashes only ones). The two
appropriate NoticationType
constants
are NotificationType.CRITICAL
and
NotificationType.INFORMATIONAL
. To
determine whether the operating system has this notification capability,
you access NativeWindow.supportsNotification
.
The following example shows how to implement this
notification with the NativeWindow
class. When the application window is deactivated (is not on the
foreground), the taskbar and window flash to get the attention of the
user:
<?xml version="1.0" encoding="utf-8"?> <mx:WindowedApplication xmlns:mx="http://www.adobe.com/2006/mxml" layout="vertical" title="Recipe 13.6: Flashing the window/taskbar (WINDOWS)" deactivate="notify()" > <mx:Script > <![CDATA[ private function notify():void{ if(NativeWindow.supportsNotification && NativeApplication.supportsSystemTrayIcon){ var type:String = critical.selected ? NotificationType.CRITICAL : NotificationType.INFORMATIONAL; this.nativeWindow.notifyUser(type); } } ]]> </mx:Script> <mx:RadioButtonGroup id="notificationType" /> <mx:RadioButton id="critical" group="{notificationType}" label="NOTIFIY THE USER CRITICAL" selected="true"/> <mx:RadioButton id="informational" group="{notificationType}" label="NOTIFIY THE USER INFORMATIONAL"/> </mx:WindowedApplication>
The following example shows how to implement the
notification with the air.NativeWindow
class. When the application
window is deactivated (is not on the foreground), the taskbar and
window flash to get the attention of the user:
<html > <head> <title>Recipe 13.6: Flashing the system tray icon (WINDOWS)</title> <script src="AIRAliases.js" type="text/javascript"></script> <script type="text/javascript"> function notify(){ if(air.NativeApplication.supportsSystemTrayIcon && air.NativeWindow.supportsNotification) { var critical = document.getElementById('critical'), var type = (critical.checked ? air.NotificationType.CRITICAL : air.NotificationType.INFORMATIONAL); nativeWindow.notifyUser(type); } } function setListener(){ nativeWindow.addEventListener('deactivate',notify); } </script> </head> <body onLoad="setListener()"> <form > <div><input id="critical" type="radio" name="notify" value="NOTIFY THE USER CRITICAL" checked="checked" />NOTIFY THE USER CRITICAL</div> <div><input id="information" type="radio" name="notify" value="NOTIFY THE USER INFORMATIONAL" />NOTIFY THE USER INFORMATIONAL</div> </form> </body> </html>