05
Jan
09

Cross Platform AIR Application on Flex Gumbo - Context Awareness Manager to gather, detect and translate system info

The cure in adopting AIR as a cross platform application as well as creating mobile applications is to be able to know the user’s system capabilities as well as track changes in its environment.

The AIR Context Awareness Manager can help you develop a cross-platform application which is operation system (OS) independent.

AIR Context Awareness Manager API can be utilized to gather and track information available in our application. We can split the information gathered into three categories:

1. System capability and support.
2. User activity.
3. Track changes in system.

As new capabilities will be available we can add them to the manager.

Download SWC, example and source code from Google code:
http://code.google.com/p/contextawarenessmanager/

Adobe AIR is available on PC, MAC and Linux, and as Adobe Open Screen Project materializes into a reality with the announcement of Flash 10 and AIR available on mobile devices, the challenge will increase.

Platforms are usually capable of adjusting to many changes in the device on their own. For instance, system track network errors and displaying an error message, however, our application cannot rely entirely on the platform to adjust correctly and we may want to make changes in the application once changes in the device occur. For instance, our AIR application can go into offline mode once we are not connected to the internet.

In essence our AIR application should have the ability to react and adjust during the entire lifetime of the application, additionally our application is responsible for hiding issues and constraints of the mobile device from the user. For instance, user doesn’t care that our system has low network download speed and will blame our application on choppy video.

In order to achieve that kind of awareness in our application, we should be able to be aware of the changes as well as translate the context. That’s where Context Awareness comes into place. Context Awareness means that once we get information regarding the application platform and as changes are made in the platform environment we need to translate the information and understand what it means as well as react accordingly.

Most of the system capability information is available through the flash.system.Capabilities API. The Capabilities that API provides are properties that describe the system and flash player that are hosting the application. ContextVO will hold the capability properties as well as other properties.

Detecting System Capabilities


          public function ContextVO()
          {
               avHardwareDisable = Capabilities.avHardwareDisable;
               hasAccessibility = Capabilities.hasAccessibility;
               hasAudio = Capabilities.hasAudio;
               hasAudioEncoder  = Capabilities.hasAudioEncoder;
               hasEmbeddedVideo = Capabilities.hasEmbeddedVideo;
               hasMP3 = Capabilities.hasMP3;
               hasPrinting = Capabilities.hasPrinting;
               hasScreenBroadcast = Capabilities.hasScreenBroadcast;
               hasScreenPlayback = Capabilities.hasScreenPlayback;
               hasStreamingAudio = Capabilities.hasStreamingAudio;
               hasVideoEncoder = Capabilities.hasVideoEncoder;
               isDebugger = Capabilities.isDebugger;
               language = Capabilities.language;
               localFileReadDisable = Capabilities.localFileReadDisable;
               manufacturer = Capabilities.manufacturer;
               os = Capabilities.os;
               osName = Capabilities.os.substr(0, 3).toLowerCase();
               pixelAspectRatio = Capabilities.pixelAspectRatio;
               playerType = Capabilities.playerType;
               screenColor = Capabilities.screenColor;
               screenDPI = Capabilities.screenDPI;
               screenResolutionX = Capabilities.screenResolutionX;
               screenResolutionY = Capabilities.screenResolutionY;
               serverString = Capabilities.serverString;
               version = Capabilities.version;
          }

Detecting System Support


private function setSystemSupportCapability():void
{
     contextVO.supportsDockIcon = NativeApplication.supportsDockIcon;
     contextVO.supportsMenu = NativeApplication.supportsMenu;
     contextVO.supportsSystemTrayIcon = NativeApplication.supportsSystemTrayIcon;
     contextVO.supportsMenu = NativeWindow.supportsMenu;
     contextVO.supportsNotification = NativeWindow.supportsNotification;
     contextVO.supportsTransparency = NativeWindow.supportsTransparency;
     contextVO.systemMaxSize = NativeWindow.systemMaxSize;
     contextVO.systemMinSize = NativeWindow.systemMinSize;
}

Detecting User Presence


private function detectUserPresence():void
{
     nativeApp.idleThreshold = idleThresholdTime;
     nativeApp.addEventListener(Event.USER_IDLE, onUserIdleHandler);
     nativeApp.addEventListener(Event.USER_PRESENT, onUserPresentHandler);
}
private function onUserIdleHandler(evt:Event):void
{
     var lastUserInput:Number = NativeApplication.nativeApplication.timeSinceLastUserInput;
     var event:Event = new Event(USER_IDLE, true);
     contextVO.isUserPresent = false;
     contextVO.lastUserInput = lastUserInput;
     this.dispatchEvent(event);
}
private function onUserPresentHandler(evt:Event):void
{
     var event:Event = new Event(USER_PRESENT, true);
     contextVO.isUserPresent = true;
     this.dispatchEvent(event);
}

Detecting network connectivity changes


private function detectNetworkChanges():void
{
     nativeApp.addEventListener(Event.NETWORK_CHANGE, onNetworkStatusChange);
}
private function onNetworkStatusChange(evt:Event):void
{
     var event:Event = new Event(NETWORK_CHANGE, true);
     contextVO.isNetworkChanged = true;
     this.dispatchEvent(event);
}

Detecting HTTP connectivity


private function detectHTTPConnectivity():void
{
     monitor = new URLMonitor(new URLRequest(siteToTrack));
     monitor.addEventListener(StatusEvent.STATUS, onHTTPConnectivityChange);
     monitor.start();
}
private function onHTTPConnectivityChange(evt:StatusEvent):void
{
    var event:Event;
    contextVO.isHTTPAvaliable = monitor.available;
    event = (monitor.available) ? new Event(HTTP_CONNECTIVITY_TRUE, true) :
         new Event(HTTP_CONNECTIVITY_FALSE, true);</p>
<p>     this.dispatchEvent(event);
}

Detecting socket connectivity


private function detectSocketConnectivity():void
{
     socketMonitor = new SocketMonitor(siteSocketMonitor,portToCheck);
     socketMonitor.addEventListener(StatusEvent.STATUS, onSocketStatusChange);
     socketMonitor.start();
}
private function onSocketStatusChange(evt:StatusEvent):void
{
     var event:Event;
     contextVO.isSocketMonitorAvailable = socketMonitor.available;
     event = (socketMonitor.available) ? new Event(SOCKET_CONNECTIVITY_TRUE, true) :
         new Event(SOCKET_CONNECTIVITY_FALSE, true);
     this.dispatchEvent(event);
}

Detecting Local Drives


private function detectLocalDrivers():void
{
     contextVO.currentAvaliableDrives = (contextVO.osName=="mac") ?
          new File('/Volumes/').getDirectoryListing() : File.getRootDirectories() ;
}
public function refreshLocalDrives():void
{
     detectLocalDrivers();
}

Detecting WindowedApplication movement


private function detectWindowedApplicationMovment():void
{
     Application.application.addEventListener(NativeWindowBoundsEvent.MOVING, onWindowedApplicationMovment);
}
private function onWindowedApplicationMovment(evt:NativeWindowBoundsEvent):void
{
     var event:Event = new Event(NATIVE_WINDOW_MOVED, true);
     contextVO.windowPositionAfterBounds = evt.afterBounds;
     contextVO.windowPositionBeforeBounds = evt.beforeBounds;
     this.dispatchEvent(event);
}

Getting the runtime version and patch level


private function setRuntimeInformation():void
{
     contextVO.getRuntimeVersion = nativeApp.runtimeVersion;
     contextVO.getRuntimePatchLevel = nativeApp.runtimePatchLevel;
}

I have created an example of a monitor application that will display the changes across the application. Take a look at the code below:

Context Awareness Manager


<WindowedApplication xmlns="http://ns.adobe.com/mxml/2009"
	layout="absolute"
	creationComplete="init()">

	<Script>
		<![CDATA[
			import com.elad.framework.utils.ContextAwarenessManager;

			private var contextAwareness:ContextAwarenessManager = ContextAwarenessManager.getInstance();

			private function init():void
			{
				contextAwareness.addEventListener(ContextAwarenessManager.USER_IDLE, onUserHandler);
				contextAwareness.addEventListener(ContextAwarenessManager.USER_PRESENT, onUserHandler);
				contextAwareness.addEventListener(ContextAwarenessManager.HTTP_CONNECTIVITY_TRUE, onHTTPConnectivityChange);
				contextAwareness.addEventListener(ContextAwarenessManager.HTTP_CONNECTIVITY_FALSE, onHTTPConnectivityChange);
				contextAwareness.addEventListener(ContextAwarenessManager.NATIVE_WINDOW_MOVED, onWindowedApplicationMovment);
				contextAwareness.addEventListener(ContextAwarenessManager.NETWORK_CHANGE, onNetworkStatusChange);
				contextAwareness.addEventListener(ContextAwarenessManager.SOCKET_CONNECTIVITY_FALSE, onSocketStatusChange);
				contextAwareness.addEventListener(ContextAwarenessManager.SOCKET_CONNECTIVITY_TRUE, onSocketStatusChange);

				contextAwareness.start();
				textArea.text = "Start Tracking";
			}

			private function onUserHandler(evt:Event):void
			{
				textArea.text += "\nisUserPresent: "+contextAwareness.contextVO.isUserPresent.toString();
				textArea.text += "\nlastUserInput: "+contextAwareness.contextVO.lastUserInput.toString();
			}

			private function onNetworkStatusChange(evt:Event):void
			{
				textArea.text += "\nisNetworkChanged: "+contextAwareness.contextVO.isNetworkChanged.toString();
			}

			private function onHTTPConnectivityChange(evt:Event):void
			{
			    textArea.text += "\nisHTTPAvaliable: "+contextAwareness.contextVO.isHTTPAvaliable.toString();
			}

			private function onSocketStatusChange(evt:Event):void
			{
				textArea.text += "\nisSocketMonitorAvailable: "+contextAwareness.contextVO.isSocketMonitorAvailable.toString();
			}

			private function onWindowedApplicationMovment(evt:Event):void
			{
				textArea.text += "\nwindowPositionAfterBounds: "+contextAwareness.contextVO.windowPositionAfterBounds.toString();
				textArea.text += "\nwindowPositionBeforeBounds: "+contextAwareness.contextVO.windowPositionBeforeBounds.toString();
			}

			private function showCapabilitiesClickHandler(event:MouseEvent):void
			{
				textArea.text += "\navHardwareDisable: "+contextAwareness.contextVO.avHardwareDisable.toString();
				textArea.text += "\nhasAccessibility: "+contextAwareness.contextVO.hasAccessibility.toString();
				textArea.text += "\nhasAudio: "+contextAwareness.contextVO.hasAudio.toString();
				textArea.text += "\nhasAudioEncoder : "+contextAwareness.contextVO.hasAudioEncoder.toString();
				textArea.text += "\nhasEmbeddedVideo: "+contextAwareness.contextVO.hasEmbeddedVideo.toString();
				textArea.text += "\nhasMP3: "+contextAwareness.contextVO.hasMP3.toString();
				textArea.text += "\nhasPrinting: "+contextAwareness.contextVO.hasPrinting.toString();
				textArea.text += "\nhasScreenBroadcast: "+contextAwareness.contextVO.hasScreenBroadcast.toString();
				textArea.text += "\nhasScreenPlayback: "+contextAwareness.contextVO.hasScreenPlayback.toString();
				textArea.text += "\nhasStreamingAudio: "+contextAwareness.contextVO.hasStreamingAudio.toString();
				textArea.text += "\nhasVideoEncoder: "+contextAwareness.contextVO.hasVideoEncoder.toString();
				textArea.text += "\nisDebugger: "+contextAwareness.contextVO.isDebugger.toString();
				textArea.text += "\nlanguage: "+contextAwareness.contextVO.language.toString();
				textArea.text += "\nlocalFileReadDisable: "+contextAwareness.contextVO.localFileReadDisable.toString();
				textArea.text += "\nmanufacturer: "+contextAwareness.contextVO.manufacturer.toString();
				textArea.text += "\nos: "+contextAwareness.contextVO.os.toString();
				textArea.text += "\nosName: "+contextAwareness.contextVO.osName.toString();
				textArea.text += "\npixelAspectRatio: "+contextAwareness.contextVO.pixelAspectRatio.toString();
				textArea.text += "\nplayerType: "+contextAwareness.contextVO.playerType.toString();
				textArea.text += "\nscreenColor: "+contextAwareness.contextVO.screenColor.toString();
				textArea.text += "\nscreenDPI: "+contextAwareness.contextVO.screenDPI.toString();
				textArea.text += "\nscreenResolutionX: "+contextAwareness.contextVO.screenResolutionX.toString();
				textArea.text += "\nscreenResolutionY: "+contextAwareness.contextVO.screenResolutionY.toString();
				textArea.text += "\nserverString: "+contextAwareness.contextVO.serverString.toString();
				textArea.text += "\nversion: "+contextAwareness.contextVO.version.toString();
			}

			private function showSystemSupportClickHandler(event:MouseEvent):void
			{
				textArea.text += "\nsupportsDockIcon: "+contextAwareness.contextVO.supportsDockIcon.toString();
				textArea.text += "\nsupportsMenu: "+contextAwareness.contextVO.supportsMenu.toString();
				textArea.text += "\nsupportsSystemTrayIcon: "+contextAwareness.contextVO.supportsSystemTrayIcon.toString();
				textArea.text += "\nsupportsNotification: "+contextAwareness.contextVO.supportsNotification.toString();
				textArea.text += "\nsupportsTransparency: "+contextAwareness.contextVO.supportsTransparency.toString();
				textArea.text += "\nsystemMaxSize: "+contextAwareness.contextVO.systemMaxSize.toString();
				textArea.text += "\nsystemMinSize: "+contextAwareness.contextVO.systemMinSize.toString();
			}

		]]>
	</Script>

	<VBox width="100%" height="100%" >
		<TextArea id="textArea" width="100%" height="95%" />

		<HBox>
			<Button label="Show System Capabilities" click="showCapabilitiesClickHandler(event)" />
			<Button label="Show System Support" click="showSystemSupportClickHandler(event)" />
		</HBox>

		<HBox>
			<Button label="Start Tracking" click="contextAwareness.start(); textArea.text+='\nStart Tracking';" />
			<Button label="Stop Tracking" click="contextAwareness.stop(); textArea.text+='\nStop Tracking';" />
			<Button label="Clear TextArea" click="textArea.text=''" />
		</HBox>		

	</VBox>

</WindowedApplication>

Download SWC, example and source code from Google code:
http://code.google.com/p/contextawarenessmanager/


3 Responses to “Cross Platform AIR Application on Flex Gumbo - Context Awareness Manager to gather, detect and translate system info”


  1. 1 a Jan 21st, 2009 at 12:29 am

    its giving error

    Could not resolve to a component implementation. crossPlatform/src crossPlatform.mxml line 4 1232515555656 542892

    for this tag

  2. 2 elad.ny Jan 23rd, 2009 at 9:15 am

    The project needs to be compiled with Flex 4 (Gumbo)

  3. 3 elad.ny Jun 2nd, 2009 at 5:50 pm

    The project was converted to work with FB 4. The FXP file can be downloaded from here:
    http://code.google.com/p/contextawarenessmanager/downloads/list

    Application.application is now FlexGlobals.topLevelApplication and I have changed the example the rest is working correctly.