Using AIR 1.5.1 InovkeReason for friendlier applications

I recently discovered a new feature of AIR 1.5.1 that makes AIR applications more consumer friendly in certain situations. When you have your application set to start on user login using “NativeApplication.nativeApplication.startAtLogin = true”, you may want the application to start as a background process rather than show the entire application at login. In AIR 1.5.1 there is a new property of the InvokeEvent called “reason” that will report if the application was started at login or was started when the users invokes the application by launching the application.

By capturing this event and testing for InovokeReason.LOGIN, you can keep your application invisible and only show the windows docked in the system tray. If a users starts the application it will be InvokeReason.STANDARD and you can then show the application as normal. I find it annoying to have a ton of windows popping up on my screen when I restart my computer.

I usually set up an InvokeEvent when a users clicks on the system tray icon to activate the application and bring it to the forefront. I initially set WindowsApplicatoin visible=”false” so the application is invisible on start. If the the InvokeEventReason is “LOGIN”, I keep the application invisible, in other cases I activate the application and bring it to the forefront.

It should be noted that the InvokeEvent fires on application start up as well as from running the the application from the IDE (so you can’t test it fully unless you install the application and login again). Also, because of timing of events at start up, the application is invisible even when you set it to active, so it will blink if the InvokeEventReason is STANDARD. To avoid this behavior, I use the “windowComplete” event of the WindowedApplication to add the InvokeEvent listeners. So the code might look something like the following:

Read More »

Posted in AIR | Tagged , , | 6 Comments

Adding Mac OS X Close Behavior to AIR 1.5 Application

Just a quick post because I have seen this done on other sites but it no longer is valid in AIR 1.5. Most Mac OS X applications minimize to system tray on closing the application using the “x” close button on the app. To achieve this in AIR 1.5 you will need to do the following on creationComplete event of the main application:

// on application creation complete setup default Mac OS X behavior
private function init():void
{
    if (NativeApplication.supportsMenu) {  // we are on a Mac
         //this.nativeWindow.addEventListener(InvokeEvent.INVOKE, handleAppInvoke);
         NativeApplication.nativeApplication.addEventListener(InvokeEvent.INVOKE, handleAppInvoke);
         this.nativeWindow.addEventListener(Event.CLOSING, handleAppHide);
         NativeApplication.nativeApplication.addEventListener(Event.EXITING, handleAppExit);
         NativeApplication.nativeApplication.autoExit = false;
    } else {  // we are on a Windows machine
       this.nativeWindow.addEventListener(Event.CLOSING, handleAppClosing);
    NativeApplication.nativeApplication.autoExit = true;
    }
}

// active that application
private function handleAppInvoke(event:InvokeEvent):void
{
                this.nativeWindow.activate();
}

// close all open windows
private function handleAppClosing(event:Event):void
{  
       event.preventDefault();
    for (var i:int = NativeApplication.nativeApplication.openedWindows.length - 1; i >= 0; --i) {
        NativeWindow(NativeApplication.nativeApplication.openedWindows[i]).close();
    }
}

// hide the application instead of closing it
private function handleAppHide(event:Event):void
{
    if( this.nativeWindow.visible ) { // if the window is visible the event behaviour is canceld and the window is hidden
        event.preventDefault();
            this.nativeWindow.visible = false;
        }
}

// close all open windows, remove event listener for hiding application and close applicatin
private function handleAppExit(event:Event):void
{
    this.nativeWindow.removeEventListener(Event.CLOSING, handleAppHide);
               
    for (var i:int = NativeApplication.nativeApplication.openedWindows.length - 1; i >= 0; --i) {
        NativeWindow(NativeApplication.nativeApplication.openedWindows[i]).close();
    }
    this.close();
}

- Mister

Posted in AIR | Tagged , | 5 Comments

Garbage Collection and Event Listeners

On a recent AIR project I have become aware and subsequently obsessed with memory. My concerns have centered around garbage collection and event listeners, specifically how you clean up event listeners to allow Garbage Collection (GC) to clean up objects. Most DisplayObjects implement the EventDispatcher class that allows it to broadcast events. Trolling around the googleverse I found some interesting ways to insure that you break strong references to allow clean up or manually remove event listeners on your own to make your application more memory savvy.

When you use addEventListener() method and register a event listener to an object you create reference. By default any object that has a reference to a listener will keep that reference until it is removed using the removeEventListener() method. Strong references will not be cleaned up by Flash player GC and remain in memory until the application is closed or the world ends, whichever comes first. This makes for a horribly leaky AIR applications, especially those applications that may run for days on the user’s system without being restarted.

Use Additional Parameters of Listener

The addEventListener() method does have some additional (and seldom used) parameters to create a weak reference when adding the listener to an object. On of those parameters is “useWeakReference”, the 5th parameter of the method. To utilize this parameter you need to set it from false to true:

addEventListener(type:String, listener:Function, useCapture:Boolean = false, priority:int = 0, useWeakReference:Boolean = false);
.....

var button:Button = new Button()
button.addEventListener(MouseEvent.click, handleMouseClick, false, 0, true);

private function handleMouseClick(event:MouseEvent):void
{
 // handle the event
}

Read More »

Posted in AIR, Flash, Flex, Flex 3 | Tagged , , , , | 3 Comments

AIR :: NativeMenu issue on Mac

I think the NativeMenu is a great option for AIR applications as you can get a consistent look for the application that matches the operating system. The other advantage is that NativeMenu’s are “outside” of the application and do not get clipped as they would if you just created a popup Canvas with a List control. However, I could not get the native menu to appear as a popup in my tests. In fact, it would often result in crashing the AIR application when i did NativeMenu.display();.

If I call a function that creates a NativeMenu from a button click everything works great. If I call the same function to create the menu from an event (like receiving data from a service call), the menu is not created and the application crashes upon subsequent attempts to create the menu. In addition, trying to create a NativeMenu popup on “createComplete” of the application also causes a crash.

So let’s say you have an application that you want to show a NativeMenu as a popup on startup of the application so you run the following:

< ?xml version="1.0" encoding="utf-8"?>
<mx :WindowedApplication xmlns:mx="http://www.adobe.com/2006/mxml" layout="absolute" creationComplete="init()"  width="540" height="388" >
   
    <mx :Style source="styles.css"/>
   
    </mx><mx :Script>
        < ![CDATA[
            private function init():void
            {
                var nativeMenu:NativeMenu = new NativeMenu();
                var menuItem1:NativeMenuItem = new NativeMenuItem("Menu Item 1");
                var menuItem2:NativeMenuItem = new NativeMenuItem("Menu Item 2");
                nativeMenu.addItem(menuItem1);
                nativeMenu.addItem(menuItem2);
               
                NativeApplication.nativeApplication.menu.display(this.stage, 100, 100);
               
            }
        ]]>
    </mx>

Read More »

Posted in AIR, Flex | Tagged , , , , | 1 Comment

Placing a ContextMenu on TextArea in AIR 1.5

The TextArea in Flex comes with its own contextual menu, so adding one does absolutely nothing but leave you wondering what the heck you are doing wrong. In the bug report there is a bit of a work around for AIR 1.5 which requires you to access the “textField” property of the TextArea and add your contextMenu to that item. Apparently there are not enough people using custom contextMenu’s to justify fixing the bug. The problem gets a bit trickier as the textField is protected in Flex Builder 3, so you can’t just do:

myTextArea.textfield.contextMenu = myMenu;

You need to expose or get at the textField to add the menu. You can do this by using mx_internal (careful, kid, or you’ll put your eye out with that thing!). So you can throw a little hack together to get your context menu on your text area:

private function createMenu():void
{
     var mainMenu:ContextMenu = new ContextMenu();
   
     var menuitem:ContextMenuItem = new ContextMenuItem("hello mom!");
     menuitem.addEventListener(ContextMenuEvent.MENU_ITEM_SELECT, handleContextMenuEvent);
     mainMenu.addItem(menuitem);

     textInput.contextMenu = mainMenu;

     var txt:TextField = textInput.mx_internal::getTextField() as TextField;
     txt.contextMenu = mainMenu;
}

private function handleContextMenuEvent(event:ContextMenuEvent):void
{
    var menuitem:ContextMenuItem = event.target as ContextMenuItem;
    trace("context menu event: " + menuitem);
}

<mx :TextArea id="textInput"  width="100%" height="100%">

Read More »

Posted in AIR, Cairngorm | Tagged , , , , , , , , | 1 Comment

Dude, where’s my phone (GPS)

I thought I had lost my phone for the past day, I looked every where and called it a few times, no luck. So I remembered I had the InstaMapper GPS software installed. You can send an SMS to the phone with your InstaMapper key to activate the GPS and have it report its location. Worked perfectly, apparently the phone is at my house some place hanging out without me, nice. I think its pretty cool that you can activate applications this way with the G1 phone.

Since iPhones don’t allow applications to run in the background, it wouldn’t have been possible, just another lost phone ringing with nobody to hear its plea to be found. I recommend anyone with a G1 to use InstaMapper. I also created an AIR application that tracks your device with Google Maps.

-Mr

Posted in Flash Remoting | 2 Comments

HTTP Status 201 causing Flex #2032 Error in IE only

I ran into a problem right when we were going to launch a new Flex web-based application to production (of course) with Internet Explorer and Flex. I was calling an RESTful service that returns XML and using the built-in Flex HTTPService with either POST/GET as the method for the request. Most of the service calls either return a HTTP Status Code of 200 (OK) or they throw an error. For one POST request that returned a HTTP Status of “201 Created” Flex threw up a 2032 Stream Error in response. Here is a brief definition of the error:

The referenced resource does not exist or the swf is trying to access a file across a restricted domain.

This error causes Flex to report a fault error on the request even though it was successful. The 201 status code is handled fine in all other browsers except IE (6 & 7). I did some research on the issue thinking it must be something easy to fix, that many others have run across before me. It seems the error is out there for lots of different reasons.

One post reported that IE was having a caching issues, and the way to solve it was to add a random number on the end of your service calls or you have to set the response headers in your server side page to prevent caching. This one sounds similar to a FireFox issue I ran into a couple years back, but didn’t effect the results:

Read More »

Posted in API, Flash, Flex | Tagged , , , , , , | 3 Comments

Smooth Scrolling HorizontalList

This example is based on Alex Harui’s Smooth Scrolling List. It just changes the code to work with the HorizontalList control rather than the List control. The SmoothHorizontalScrollingList class extends the HorizontalList control adding the needed functionality to allow smooth scrolling:

Read More »

Posted in Component, Flex | Tagged , | 13 Comments

PhoneSeek :: Adobe AIR application

PhoneSeek is an application to track any device that uses InstaMapper. InstaMapper is free real-time GPS tracking service. To use InstaMapper you need a GPS enabled device with the free InstaMapper tracking software installed along with a API Key from InstaMapper’s web site for each device you own. You can track mobile phones (iPhone, G1, Blackberry) or even automobiles.

Use Case

With PhoneSeek I can add my InstaMapper API Key for my phone and track it from the desktop. I can also add and track multiple devices. On my G1 phone, I installed the Android version of the InstaMapper tracking software. This software allows me to send my phone’s GPS data to InstaMapper service where I can view it either on their website or consume the data through InstaMapper’s web service. In PhoneSeek I just add the API Key to begin tracking the advice as soon as your phone starts to transmit GPS data.

Get PhoneSeek

Download the latest version from this location.

Development Background

PhoneSeek might be used to track devices from your family members, or maybe track down a lost or stolen phone. However, Phoneseek was basically created as a test project to learn PureMVC and also experiment with the new Google Maps API SWC for Adobe AIR. Previous versions of the Google Maps API SWC only worked for web-based applications.

Coming from Cairngorm to PureMVC was quite an experience. At first it was really painful because I had a tendency to over think things, or try to structure things more the Cairngorm ways (like dude, where are my delegates and commands). I really had a hard time understanding where to put certain code, like update code, or code to set the window location on startup, and even how to pass around value objects used by more than one view. It took some time to get used to the PureMVC way, but all in all, its not a bad framework to work with. However, I still prefer Cairngorm and have since started to investigate and really enjoy Mate.

The graphics used in the application were created by me or from DragonArtz Designs. I highly recommend the retro icon set from DragonArtz and give that site credit for the graphics I used. Sorry there is no support for the application since its just a demo of some of the features from InstaMapper and Google Maps for AIR.

Enjoy!

-Mister

Posted in AIR, API, Android, Cairngorm, ColdFusion, Mate | Tagged , , , , | 5 Comments

The New Type of Dot-Com Work Force?

Today, I was inspired to write a brief post about my beliefs towards the ideal work environment. I was inspired by an article about creators of Twitter and their experience coming from the early dot-com era of blow-out parties and slackers with bank rolls, to having a more mature dot-com. My favorite quote from a the article references the work culture:

Really, it’s like any other office, except there’s hardly anybody there. They’re all working at home. … “There’s not a lot of foosball going on here,” CEO Evan Williams, 36, says. “People are working on what needs to be done. I know when I’ve been in those cultures, there’s just a lot more goofing off. That burns a lot of cycles that don’t need to be burned. Part of it’s an age thing. My first couple of companies, I only socialized with work people. A high percentage of people here have spouses, have families. They can go home.”

You can tell that Evan Williams really gets the whole “age” thing about the new type of dot-com work culture and understands that there is a paradigm shift in the programming workforce. We are moving from the young hungry programmers working 24/7 in drab caves and subsisting on only pizza and caffeine to new start up companies that have “seasoned” programmers living balanced lives while still producing quality work.

My background

I have been in large companies, education institutions, small companies, and even worked ( way too briefly ) for myself. I have had opportunities to experience a lot of different company cultures. For me it is usually the CEO that sets both the pace and the environment vibe for each company (especially if you are on your own). What I have always noticed is that most companies are reluctant to embrace new modes and thoughts for working. We live in a completely wired world with people and resources all over the planet, yet most employers still hold on to the belief that they need to see your face every day in order for you to accomplish your work. I think the real reason is simple, they don’t believe it works or understand how it works. Despite the countless productivity studies to the contrary, if your boss doesn’t see people in the office, they get freaked out, simple as that.

Read More »

Posted in Misc | 2 Comments


  • Thanksmister on Twitter

    View Michael Ritchie's profile on LinkedIn