Archive for the ‘ActionScript’ Category

Accessing HTML5 Geolocation via ActionScript

Read on to learn how to access the HTML5 Geolocation API using ActionScript in a web app. Using the patterns below you can get access to a visitor’s approximate location in applications that run in a desktop or laptop browser. Mobile ActionScript/Flex/AIR apps have convenient, built-in access to location via the flash.sensors.Geolocation Class. However, with a web app you have to cobble together your own code using¬†ExternalInterface.

The key to all this is using ExternalInterface’s addCallback(). ¬†This method lets you access ActionScript from JavaScript code in the wrapper HTML file, which if you didn’t know is the .html file that is used to launch Flash Player.

There are two steps to take that make it work:

Step 1. In addCallback() set the first parameter to the name of the function you will invoke in JavaScript to send data to your ActionScript method. Set the second parameter to the name of the actual ActionScript method. ActionScript will then recognize when the method specified in the second parameter is called. Essentially this sets up a listener in ActionScript.

Step 2. Set the¬†call() method so that it invokes a public JavaScript function. When it’s done running, then you fire off the JavaScript function specified in the first parameter of addCallback().

If that doesn’t make any sense, check out the code below to see how it all fits together. Note, you can either hard code your JavaScript in the wrapper HTML file, or you can do what I do below and inject it into the DOM at runtime using the document.insertScript pattern so you know it’s always there.

public function findLocation():void
{
	if (!Geolocation.isSupported)
	{
		const  VERIFY_GEOLOCATION:String =
			"document.insertScript = function(){" +
				"verify_geolocation = function(){"+
					"var geoEnabled = false;" +
					"if(navigator && navigator.geolocation)" +
					"{" +
					"    return geoEnabled = true;" +
					"}" +
					"else{" +
					"    return geoEnabled = false;" +
					"}"+
				"}"+
			"}";

		const  GET_GEOLOCATION:String =
			"document.insertScript = function(){" +
				"get_geolocation = function(){"+
					"var mySWF = document.getElementById('YourApplicationName');"+
					"navigator.geolocation.getCurrentPosition(function(position){"+
					"     mySWF.sendGeolocationToActionScript(position);"+
					"});"+
				"}"+
			"}";

		if(ExternalInterface.available)
		{
			//load the script into DOM
			ExternalInterface.call(VERIFY_GEOLOCATION);

			//call the JS function
			var geoEnabled:Boolean = ExternalInterface.call("verify_geolocation");

			if(geoEnabled == true){
				//Load the script into DOM
				ExternalInterface.call(GET_GEOLOCATION);

				//Step 1: set the ActionScript callback
				ExternalInterface.addCallback("sendGeolocationToActionScript",geolocationResultHandler);

				//Step 2: call the JS Function
				ExternalInterface.call("get_geolocation");
			}
		}
	}
}

//Access this Handler from JavaScript
public function geolocationResultHandler(obj:Object):void
{
	//Access the HTML5 Geolocation object properties just like you would in JavaScript
	Alert.show("Latitude: " + obj.coords.latitude + ", "Longitude: " + obj.coords.longitude );
}

Test Notes:

I compiled this code using FlashBuilder 4.6 using Apache Flex 4.6. The functionality was tested on Internet Explorer 9, Chrome 21 and Firefox 14.

References:

Adobe ActionScript Reference – ExternalInterface
Adobe Help – Accessing Flex from JavaScript

Tags: , , ,
Posted in ActionScript, FlashBuilder, HTML5 | No Comments »

How to upgrade your AIR SDK in FlashBuilder 4.6

This post walks through the steps for upgrading your AIR SDK. ¬†There are just a few tricks and I spell them out here since this isn’t a one-click, plug-in-play operation.¬†As of this writing, AIR 3.3 is the latest version, whereas FlashBuilder 4.6 came with v3.1 installed.

Why upgrade? In my case I had two reasons. First, I’d heard from a co-worker that AIR v3.3 compiled significantly faster. And, second I ran into a few flaky bugs and I wanted to test my builds using the latest SDK version.

1. Make a copy of the Flex SDK directory and place it in the same default sdk directory. On windows this is C:\Program Files (x86)\Adobe\Adobe Flash Builder 4.6\sdks. Rename the new directory you just created to something like “4.6A3.3″.

2. Download latest AIR SDK (zip) file from Adobe. Yep, even though Adobe open sourced Flex, they still produce AIR and the FlashPlayer runtime: http://www.adobe.com/devnet/air/air-sdk-download.html.

3. Merge the contents from the AIR SDK zip file into the new copy of the Flex SDK directory. There will be some files that you have to overwrite in order to get the latest version.

4. Instruct FlashBuilder to use the new SDK by going to Window > Preferences > Flash Builder > Installed Flex SDKs, and then click “Add”. If you want to keep track of the different AIR versions related to Flex then make up a new naming convention for the SDK such as “Flex 4.6 – AIR 3.3″.

5. For existing projects which are using the older versions of AIR, such as Flex mobile projects, you’ll need to manually update the app.xml file to use the correct SDK version number in the namespace (xmlns). This file can be found in your FlashBuilder Project using the Package Explorer. If you don’t make this change you’ll get a compiler error. Your app.xml namespace should look like this. Note that when you create a new mobile project it should automatically be created with the correct xmlns settings.

<?xml version="1.0" encoding="utf-8" standalone="no"?>
<application xmlns="http://ns.adobe.com/air/application/3.3">

<!-- Adobe AIR Application Descriptor File Template.

	Specifies parameters for identifying, installing, and launching AIR applications.

	xmlns - The Adobe AIR namespace: http://ns.adobe.com/air/application/3.3
			The last segment of the namespace specifies the version
			of the AIR runtime required for this application to run.

	minimumPatchLevel - The minimum patch level of the AIR runtime required to run
			the application. Optional.
-->

Here’s an example of the error you’ll get if you don’t do this. You’ll see something like “Namespace 3.1 in the application descriptor file should be equal or higher than the minimum version 3.3 required by the Flex SDK.”

References:

Adobe Doc – Overlay the AIR SDK with the Flex SDK

Tags: ,
Posted in ActionScript, FlashBuilder | No Comments »

Minimizing Wild GPS Fluctuations in Flex Mobile Apps

Under low accuracy situations, I‚Äôve noticed on both iPhone and Android that the GPS location can fluctuate wildly over a short period of time, sometime jumping 2500 ft (762m) or more within several seconds. By low accuracy I mean the GPS result indicated a horizontal accuracy of greater than 1000ft (305m). This creates a really poor user experience, so I quickly implemented a very rough algorithm to minimize these fluctuations. Here’s some psuedo-code that demonstrates the concept:

private _currentTime:Date;
private _lastUpdateTime:Date = null;
private const _DISTANCE_ACCURACY_THRESHOLD:Number = 2500; //feet
private const _TIME_ACCURACY_THRESHOLD:Number = 1000; //msecs

_timer = new Timer(100,0);
_timer.addEventListener(TimerEvent.TIMER,function(event:TimerEvent):void{
	_currentTime = new Date();
});
_timer.start();

//Calculate time elapsed since last update
var f:Number = _currentTime.time - _lastUpdateTime.time;

if(_lastUpdateTime != null)
{

	//Minimize annoying fluctuations.				
        //accuracy is a property from GPS result (horizontalAccuracy)
	if(f >= _TIME_ACCURACY_THRESHOLD 
		&& accuracy <= _DISTANCE_ACCURACY_THRESHOLD)
	{
		isValid = true;
	}
	else
	{
		_lastUpdateTime = _currentTime;
	}
}

The theory is that the distance and time between fluctuations calculate out to speeds greater than 2500 ft/1 second. You can adjust the parameters as you see fit. I also assumed that under normal driving (or walking!) conditions you wouldn’t be going that fast, right?

You could also write a native extension, but I didn’t have enough time to do that. The native Android SDK offers many ways to use the GPS that could eliminate these problems.

This could certainly use some tweaking, so if you have suggestions for improvement please post a comment or send me an email!

Tags: ,
Posted in ActionScript, GPS, Mobile | No Comments »

My recent Antarctica Flex/ActionScript app had a requirement for tokenized asynchronous requests. That way I could use a centralized HTTP controller through which every outbound request was submitted. By attaching a ‚Äútoken‚ÄĚ to each request, I could properly manage the response payload for the dozen‚Äôish different processes that were going on. In other words, you attach a unique identifier to the outbound request. When the server sends back its response to the client application, this unique identifier is passed along in the payload. Quite cool, right?!

I‚Äôve used this technique in heavy-duty, server-side applications before but¬†only a few times¬†in a web client. In practice it works brilliantly and it allowed me to easily organize¬†the HTTP responses from many different types of requests and keep them all straight. At the heart of controller was this pseudo-code. If you haven’t done this before, there are just a few tricks to make it work right. I’ve included all the code to make your life easier. The token variable is a String that you create and then pass to the AsynchResponder.

                               
_http = new HTTPService();
_http.concurrency = "multiple";
_http.requestTimeout = 20;
_http.method = "POST";

var asyncToken:AsyncToken = _http.send( paramsObject );  
                                     
//you pass the token variable in as a String
var token:String = "someValue";
var responder:AsyncResponder = new AsyncResponder(resultHandler,faultHandler,token);
asyncToken.addResponder(responder);

Elsewhere in the app, the other classes that used the controller received the response payload via the event bus and then filtered the response by the tokens using a switch/case statement. AppEvent is my custom event bus that would broadcast the payload to the entire application via an Event. This allowed me to fully decouple the http controller from being directly wired into my other classes. It made the app very flexible in that action would only be taken when the response came back. If you want a few more details about this architecture, then check out my blog post on it. Here’s the HTTP response handler pseudo-code that is inside the controller.

Just a note, the HTTPData Class is a custom object I wrote to manage the response data. You could manage the data anyway you like. This is just one example of how to do it.

private function resultHandler(result:Object, token:Object = null):void
{	
	var httpData:HTTPData = new HTTPData();
	httpData.result = result.result;
	httpData.token = token; 
	AppEvent.dispatch(AppEvent.HTTP_RESULT,httpData);
}

And, here’s the response handler that’s inside one of the applications pages (views) that recieve the payload via my event bus:

AppEvent.addListener(AppEvent.HTTP_RESULT,httpResultHandler);

/**
 * Handles setting up many of the user variables based on tokenized,
 * asynchronous HTTP requests.
 * @param event AppEvent from HTTP request.
 */
private function httpResultHandler(event:AppEvent):void
{
    var json:String = event.data.result as String;	
    
    //route the tokens through a switch/case statement
    switch(event.data.token)
    {
         case "getallgpspoints":
              parseGPSPoints2(json);
              break;
    }
}

You can download the entire controller example here. If you use it for your own work, you’ll have to comment out anything you don’t need like some of the import statements and the custom events. Have fun!

Tags: , , , , , , , ,
Posted in ActionScript, FlashBuilder, Internet | 1 Comment »

I was really frustrated the past few weeks when a major clock component of an app kept failing when viewed from different time zones. It was always supposed to show Antarctica time and only that. I searched and searched for definitive examples on the web, but never found what I needed.

At the heart of this is the ActionScript Date Class. It’s unfortunately a very poor implementation. I expected to simply have a property where you give the Class a timezone offset and presto you magically get the time for that location of the world. Silly me. In addition the documentation is incorrect in that the getTime() method does NOT in fact report the time in UTC. And, to make things even more fun, the getTimeZoneOffset() method returns minutes rather than milliseconds.

However, after enough iterations I was finally able to cobble together what seems to be a graceful solution. The trick is to use the getTime() method. Then add the time zone offset in milliseconds. This, in theory, gives you UTC time. Then add or subtract the number of hours in milliseconds for your fixed clock. Oh, and I also used the DateTimeFormatter to beautify everything up. Here’s the code to hopefully save someone else a bunch of additional coding:

var df:DateTimeFormatter = new DateTimeFormatter();
df.useUTC = false;
df.timeStyle = "short";
df.dateStyle = "medium";
var d:Date = new Date();

var millisecondsPerThreeHours:int = 1000 * 60 * 60 * 3; //using a -3 hour UTC offset
var timeZoneOffsetMilliSeconds:Number = d.getTimezoneOffset() * 60 * 1000;

d.setTime(d.getTime() + timeZoneOffsetMilliSeconds - millisecondsPerThreeHours);

var antarcticaTime2:String = d.toString();
antarcticaTimeTextArea.text = df.format(antarcticaTime2);
Tags: , , , , , , , , , , , , ,
Posted in ActionScript | No Comments »

Live From Antarctica ‚Äď the final 7th Summit.

Our team just finished a massive 5 weeks push to building an app for the Romero family, and in particular Jordan, to follow him on his climb of the final summit on the continent at the bottom of the world. You can find the app on his home page today http://jordanromero.com, or access it directly here http://edn1.esri.com/antarctica.

It was actually Jordan’s dream to climb the highest summits on the major continents. And, he is now on his way to accomplish all that…and before his 16th birthday during what is considered summer in Antarctica. I’m amazed at what he has done. I can’t help but think about what he might be able to accomplish in the future now that he has accomplished a feat that very few ever do.

The app is capturing live GPS coordinates (altitude, heading, speed, lat/lon), live weather and it also includes a Challenge component that anyone can take to conquer their own 7 summits on their own time by walking, swimming, running or biking.

I encourage you to check out the app and even take the Challenge!

For the techno-geeks reading this, here is some background info on the technology. GPS processing and ArcGIS mapping backend services were built in C#.NET by AL Laframboise. The Challenge service and REST endpoints were built in C#.NET by Nick Furness. I built the the Adobe Flex/ActionScript client application using Adobe FlashBuilder 4.5, and the ArcGIS API for Flex provided the client-side mapping. The look and feel were accomplished by the excellent help of UX engineer Frank Garofalo in Esri Professional Services. The client app uses a custom dependency injection model at the core, and the skins were built using Adobe Catalyst.

Tags: , , , , , , , , , , , , , , ,
Posted in ActionScript, Antarctica, C#, FlashBuilder | No Comments »