This tutorial explains how to build a sample application
called CD Tracker, which demonstrates several unique features
of FlashAssist PRO. CD Tracker is a full-screen Pocket PC
application that saves data to a local file in XML format.
CD Tracker also accepts soft keyboard or handwriting recognition
input through an extended ActionScript command that displays
the soft input panel (SHOWSIP, HIDESIP). The user can show
or hide the soft input panel using the Pocket PC application
buttons.
To keep things simple, CD Tracker allows a user to store
one CD with three tracks. After you're done with this tutorial,
you may want to extend this application to make a fully-featured
CD tracker.
You can download the FLA files and PC installer for the
Pocket PC application on the first
page of this article. Note that the resulting SWF file
is designed to run inside a FlashAssist host application
and will not work the same if run inside Pocket IE. (In
other words, you will not be able to save data.)
The remainder of this tutorial shows you how to create
a Macromedia Flash movie that uses FlashAssist PRO ActionScript
and how to create the final application and installer using
FlashAssist PRO. The code samples in this article do not
show the additional debug code that's available to you in
the FLA files included in the downloadable ZIP file.
Establishing communication with the host application
The
CD Tracker movie (cdtrack.swf) will run inside a C++ host-application
generated by FlashAssist PRO. The host-application performs
two key functions:
- Creates a web-browser control and opens the HTML file
that displays the cdtrack.swf file
- Creates a socket server for communicating with cdtrack.swf
through an XMLSocket
The host-application socket server receives data and extended
commands from cdtrack.swf, writes data to a local file data
store, and executes extended commands (indicated by a leading
"!" character). When the application first launches,
the socket server looks for an existing file data store
and forwards any found data to cdtrack.swf.
To store data and execute commands, cdtrack.swf needs to
establish communication with the C++ host-app. This is accomplished
by opening the port that the host-application creates. To
avoid conflicts with other applications, the host-application
requests an available port from the Pocket PC operating
system and deposits the port number in a known file location
in loadVariables format. In the first frame, cdtrack.swf
uses the loadVariablesNum command to load the port number:
// port == 0 indicates no port available
to write to
port = 0;
// load port number from known location
loadVariablesNum("\\Windows\\siptest_FlashXMLServer_port.txt",
0);
// used to avoid an infinite loop waiting for port number
keepTrying = 50;
Frames 2 and 3 simply loop to wait for the port number
to load or for a timeout:
// wait for port to be supplied or
for timeout
if (port == 0 and keepTrying-->0) {
gotoAndPlay("waitforport");
}
Frame 4 creates an XMLSocket to establish communication,
using "localhost" to specify a port on the Pocket
PC. Two callback routines are defined: OnXMLConnect is called
after the connection attempt succeeds or fails; OnXMLReceive
is called when data is received from the host-application:
if (port != 0) {
socket = new XMLSocket();
socket.onConnect = OnXMLConnect;
socket.onXML = OnXMLReceive;
if (!socket.connect("localhost",
port)) {
port = 0;
}
}
OnXMLConnect is called after the connection attempt succeeds
or fails:
// If we failed to connect, set port
to zero to indicate failure
function OnXMLConnect(success) {
if (success) {
gotoAndPlay("main");
} else {
port = 0;
}
}
Loading and saving data
OnXMLReceive is called when data is received from the
host-application (at startup). OnXMLReceive transfers the
data from the XML nodes to input text variables. When cdtrack.swf
gets to frame 5 ("main"), it has loaded the persistent
data into the input fields:
function OnXMLReceive(doc) {
socketactivity = "data received";
var e = doc.firstChild;
socketactivity = "XML received";
if (e != null && e.nodeName
== "CDCollection") {
socketactivity = "CDCollection received";
e = e.firstChild;
}
if (e != null && e.nodeName
== "DATAOBJECT") {
socketactivity = "DATAOBJECT received";
title = e.attributes.TITLE;
artist = e.attributes.ARTIST;
track01 = e.attributes.TRACK01;
track02 = e.attributes.TRACK02;
track03 = e.attributes.TRACK03;
}
}
The SAVE button simply reverses the OnXMLReceive procedure,
loading the data into an XML structure and sending the XML
object to the host application via the XMLSocket:
on (release) {
if (port != 0) {
// format the data into a single XML node/tree for
// storage
newStore = new XML();
newRoot = newStore.createElement("CDCollection");
newStore.appendChild(newRoot);
newDataObject = newStore.createElement("DATAOBJECT");
newRoot.appendChild(newDataObject);
newDataObject.attributes.TITLE = title;
newDataObject.attributes.ARTIST = artist;
newDataObject.attributes.TRACK01 = track01;
newDataObject.attributes.TRACK02 = track02;
newDataObject.attributes.TRACK03 = track03;
socket.send(newStore);
}
By default, the host-application stores a single XML object
at a time. The XML object can be a tree structure with as
many nodes as needed. Note, however, that performance can
be poor for very large XML objects on the Pocket PC. The
C++ host-app can be extended to store multiple objects and
allow for more complex saving and loading commands.
Using the SHOWSIP/HIDESIP extended commands
The CD Tracker
sample application allows the user to input data using the
soft input panel (SIP), which is normally hidden in full-screen
mode. CD Tracker calls the extended commands SHOWSIP and HIDESIP,
which are implemented in C++ by FlashAssist PRO. Extended
commands are sent through the XMLSocket.send command and preceded
by an exclamation mark ("!"):
socket.send("!SHOWSIP");
Frame 5's routine ensures that the soft input panel is
shown when the user taps inside an input field, and that
it is hidden when the user taps outside an input field:
if (Selection.getFocus() == "_level0.title")
{
lastFocus = Selection.getFocus();
if (!sipup_title) {
sipup_title = true;
socket.send("!SHOWSIP");
}
sipup_artist = false;
sipup_track01 = false;
sipup_track02 = false;
sipup_track03 = false;
} else if (Selection.getFocus() == "_level0.artist")
{
lastFocus = Selection.getFocus();
if (!sipup_artist) {
sipup_artist = true;
socket.send("!SHOWSIP");
}
sipup_title = false;
sipup_track01 = false;
sipup_track02 = false;
sipup_track03 = false;
} else if (Selection.getFocus() == "_level0.track01")
{
lastFocus = Selection.getFocus();
if (!sipup_track01) {
sipup_track01 = true;
socket.send("!SHOWSIP");
}
sipup_title = false;
sipup_artist = false;
sipup_track02 = false;
sipup_track03 = false;
} else if (Selection.getFocus() == "_level0.track02")
{
lastFocus = Selection.getFocus();
if (!sipup_track02) {
sipup_track02 = true;
socket.send("!SHOWSIP");
}
sipup_title = false;
sipup_artist = false;
sipup_track01 = false;
sipup_track03 = false;
} else if (Selection.getFocus() == "_level0.track03")
{
lastFocus = Selection.getFocus();
if (!sipup_track03) {
sipup_track03 = true;
socket.send("!SHOWSIP");
}
sipup_artist = false;
sipup_track01 = false;
sipup_track02 = false;
} else {
if (sipup_title || sipup_artist
|| sipup_track01 || sipup_track02 || sipup_track03) {
socket.send("!HIDESIP");
sipup_title = false;
sipup_artist = false;
sipup_track01 = false;
sipup_track02 = false;
sipup_track03 = false;
}
}
The keyboard button at the bottom-right of the display
also allows the user to show the soft input panel at any
time:
on (release) {
socket.send("!SHOWSIP");
Selection.setFocus(_root.lastFocus);
Selection.setSelection(Selection.getEndIndex(),
Selection.getEndIndex());
}
Finally, the QUIT button is implemented, as with FlashAssist,
via a GetURL call:
GetURL("FLASHASSIST_QUIT")
|