System Services

This section describes each of the system services. Very few of the services apply to the News application, so most of the code samples in this section are simple ones to illustrate the service calls and handlers.

The system services are accessed through Mojo.Service.Request(), or the equivalent scene controller method this.controller.serviceRequest():

Mojo.Service.Request("palm://serviceName", options, requestOptions);

The arguments are described in Chapter 8, but briefly:

serviceName

Is a URI-formatted string that uniquely specifies the service name.

options

Includes the designated method, parameters, and callback functions.

requestOptions

Is either set to true, requesting automatic subscription renewal on error, or an object with a resubscribe property and/or a useNativeParser property.

Warning

Be careful to prevent garbage collection of your service requests. Recall from Chapter 8 that requests made with this.controller.serviceRequest() are garbage-collected and destroyed when the scene is popped. You should use Mojo.Service.Request() to save the request object and handle termination of the request yourself to prevent garbage collection.

Service requests do not complete when you make the call; they are all asynchronous. If it’s possible that the life of your request will outlast the life of the assistant when the call is made, you must use Mojo.Service.Request().

Accelerometer

Applications can respond to high-level orientation, and shake events or elect to receive raw accelerometer data through acceleration events. You will use framework controller functions or event listeners to receive accelerometer events.

You can use the orientation events to rotate your application to track the orientation of the device between portrait and landscape modes. Shake events can be applied in creative ways as alternatives for user input, such as start/stop indicators. The raw acceleration data is useful for games or other applications that can integrate device movement directly into the application’s interaction with the user.

Orientation changes

It’s extremely simple to have your application respond to changes in screen orientation. Within your stage assistant or main scene assistant, set your application’s card stage window to a free orientation through the stage controller’s setWindowOrientation() method:

if (this.controller.stageController.setWindowOrientation) {
 this.controller.stageController.setWindowOrientation("free");
}

The system will rotate the stage window, following the orientation of the device between up (normal portrait), right (clockwise rotation from up), down (portrait, but the reverse of up), or left (counter-clockwise from up). You can use the same method to force an orientation with any of up, down, left, or right passed as the argument string.

There is a corresponding getWindowOrientation() method to retrieve the current stage window orientation.

If you want to take a specific action in response to a window’s orientation change, you can add a listener to the stage window for the orientationchange event, and then respond to the change:

this.controller.listen(document, "orientationchange",
    this.handleOrientation.bindAsEventListener(this));
.
.
.
MyAssistant.prototype.handleOrientation(event)
     Mojo.Log.info("Orientation change position: ", event.position, " pitch: ",
       event.pitch, " roll: ", event.roll);
};

The new orientation data are passed as properties to the event object described in Table 9-1.

Table 9-1. Orientation change event properties

Property

Value

Description

position

Integer

Numeric value from 0 to 5, where:

0 = face up

1 = face down

2 = up, or normal portrait

3 = down, or reverse portrait

4 = left, or landscape, left side down

5 = right, or landscape, right side down

roll

Float

Righthanded rotation about the x-axis (in degrees)

pitch

Float

Righthanded rotation about the y-axis (in degrees)

Pitch and roll are absolute values with respect to the device being face up and flat on a table (in this position, they’re guaranteed to be within [−90 degrees, 90 degrees]). Start with the device flat on the table in portrait mode with the bottom of the device facing you; pitch and roll in this position are both 0.

As you tilt the device toward you, pitch changes from 0 to −90 (when the device is completely vertical). Start again with the device flat: tilting the device away from you, the pitch increases from 0 to 90. Tilting to the right increases the roll from 0 to 90. Tilting left changes roll from 0 to −90.

When the device is face up and completely vertical the pitch is −90 degrees. As you continue to tilt the device toward you, the pitch goes to 0 (face down). The same is true of the roll. When you tilt the right side perpendicular with the ground, the roll will be 90. As you continue rotating (so that the device is face down), the roll decreases to 0.

With these definitions, you can see that there are two orientations where you’ll get the same angles (one when face up and one when face down). You can use the z-axis to distinguish the two cases.

Shake

There are three events: shakestart, shaking, and shakeend. As you would expect, the start and end events are sent as soon as a shaking motion starts or stops. Shaking events are sent regularly while shaking continues, at the same rate as raw events, or 4Hz. The events include a magnitude property (in units of gravitational acceleration or g’s), where a large value indicates more vigorous shaking:

this.controller.listen(document, "shaking",
  this.handleShaking.bindAsEventListener(this));
.
.
.
MyAssistant.prototype.shaking(event)    {
     Mojo.Log.info("Shaking with magnitude: ", event.magnitude);
);

In practice, you may not need to listen to the shake start and end events unless you have some specific actions for those events. The shaking events will be sent as soon as the shaking motion commences, and will cease when the motion stops.

Raw acceleration

Detailed acceleration data is provided with each acceleration event, which are sent regularly whenever the device is in motion. While this information is accurate enough for games and similar dynamic applications, it won’t be sufficient to allow inertial position tracking applications. Note that acceleration events are targeted at the window and do not bubble up to the containing context:

this.controller.listen(document, "acceleration",
    this.handleAcceleration.bindAsEventListener(this));
.
.
.
MyAssistant.prototype.acceleration(event)    {
     Mojo.Log.info("X: ", event.accelX, "; Y:", event.accelY,
       "; Z:", event.accelZ, "; time: ", event.time);

Acceleration events contain additional properties, listed in Table 9-2.

Table 9-2. Acceleration event properties

Property

Value

Description

accelX

Float

Acceleration along the x-axis (in g’s)

accelY

Float

Acceleration along the y-axis (in g’s)

accelZ

Float

Acceleration along the z-axis (in g’s)

Alarms

You should use the JavaScript window methods setInterval() or setTimeout() to return to your application after a delay:

var wakeupFunction = function() {
        Mojo.Log.info("It's a wakeup call!");
};
window.setTimeout(wakeupFunction, 20000);

This is a lightweight delay timer, which executes a function after a specified period. In this example code, wakeupFunction is executed after a delay of 20 seconds. This type of alarm will work as long as the device is awake and where some imprecision is acceptable.

In all other situations, you will want to use the Alarm service, which is based on the device’s real-time clock (RTC). Alarms are intended to wake applications while minimized or maximized, or to drive polling for dashboard applications. Alarms will:

  • Accurately account for time changes; timeouts are accurately tracked across device sleep states, timezone changes, manual changes to time settings, or other changes that affect the displayed or perceived time on the device.

  • Wake the device up from sleep; if needed, timers will wake up the device when the alarm fires.

  • Fire after a specified delay or at a specified date and time.

  • Make a specific service request when the alarm fires; commonly it will be an applicationManager service request to call the originating application’s handleLaunch method, but can be any service call.

A good example of an alarm at work is using the Alarm service to wake an application up periodically:

this.controller.serviceRequest("palm://com.palm.power/timeout", {
    method: "set",
    parameters: {
        key: "com.palm.app.news.update",
        in: News.feedUpdateInterval,
        wakeup: "true",
        uri: "palm://com.palm.applicationManager/open",
        params: {
            id: "com.palm.app.news",
            params: {action: "updateFeed"}
        }
    },
    onSuccess: this.onSuccessHandler,
    onFailure: this.onFailureHandler
});

This example from News sets a relative alarm according to the requested News.feedUpdateInterval and requests that it wake up the device if it is asleep. When the alarm fires, it will use the Application Manager to launch News (even if News isn’t running at the time) with a launch parameter indicating that this is an alarm for feed updates. You will learn more about handling launch events and using alarms with background applications in Chapter 10.

Another option is to set an alarm at a specific date and time:

this.controller.serviceRequest("palm://com.palm.power/timeout", {
    method: "set",
    parameters: {
        key: "com.palm.app.news.daily",
        at: "04-23-2009 03:30:00",
        wakeup: "true",
        uri: "palm://com.palm.applicationManager/open",
        params: {
            id: "com.palm.app.news",
            params: {action: "updateFeed"}
        }
    },
    onSuccess: this.onSuccessHandler,
    onFailure: this.onFailureHandler
});

In this example, News could be set to update the news feeds at 3:30 A.M. GMT. This calendar alarm uses the at property (in place of the in property for a relative alarm) to set the date and time for the alarm. By definition, you must set calendar alarms for each occurrence; there isn’t a provision at this time for periodic or recurring alarms.

To clear the alarm, use the clear method:

this.controller.serviceRequest("palm://com.palm.power/timeout", {
    method: "clear",
    parameters: {
        key: "com.palm.app.news.daily",
    },
    onSuccess: this.onSuccessHandler,
    onFailure: this.onFailureHandler
});

The alarm’s key property is used to clear the periodic alarm that was set with that property.

Some additional notes about alarms:

  • Setting a relative alarm causes the device to wake and fire the alarm at a fixed time in the future. This is independent of time changes on the device by either the user or an external source (such as network time or timezone changes). The maximum period for relative alarms is 24 hours and the minimum is 5 minutes, but calendar alarms do not have a 24-hour time limit.

  • Alarms are preserved across reboots. If an alarm expires while the device is shut down, the alarm will fire when the device starts up again.

  • If the alarm service call fails, one retry attempt will be made 30 seconds later.

  • These alarms are coarse-grained alarms, so don’t expect millisecond or even one-second resolution. At worst, an alarm may fire a few seconds from the intended time.

Because the Alarm service can wake up your application even while the device is asleep, the service is integral to running an application in the background. We’ll use alarms to turn News into a background application in Chapter 10.

Connection Manager

Use the Connection Manager’s getStatus method to get updates on the device connection status. Some applications need to manage data access based on the connection state or type of connection available:

this.controller.serviceRequest("palm://com.palm.connectionmanager", {
    method: "getStatus",
    parameters: {subscribe:true},
    onSuccess: this.onSuccessHandler,
    onFailure: this.onFailureHandler
});

The response will provide the connection status at the time of the call. Use the subscription option to register for updates each time the connection status changes. In every case, the onSuccess callback is made with a single response argument, an object describing the connection status. The return value is set to true and the connection properties are provided as described in Table 9-3.

Table 9-3. Response properties for connection status

Name

Description

isInternetConnectionAvailable

Set to true when a connection is present

wifi

Object describing the WiFi connection status, with properties for state (connected or disconnected), ipAddress, ssid, and bssid

wan

Object describing the WAN connection status, with properties for state, ipAddress, and type (unknown, unusable, gprs, edge, umts, hsdpa, 1x, and evdo)

btpan

Object describing the Bluetooth Personal Area Network connection status, with properties for state, ipAddress, and panUser

Location Services

Palm webOS provides basic location services to get one or more location fixes. You can specify fixes by mode. In automatic mode, the system picks the most appropriate mode based upon your accuracy and response time requirements. Specific fix types include assisted GPS and Cell ID with or without WiFi ID.

Get current position

You can get the current position from the built-in GPS or through Cell ID or WiFi ID, depending on what’s available. The simplest call uses all default settings:

this.controller.serviceRequest("palm://com.palm.location", {
    method: "getCurrentPosition",
    parameters: {},
    onSuccess: this.locationSuccess.bind(this),
    onFailure: this.locationFailure.bind(this)
});

The default settings will provide a new (not cached), medium accuracy (within 350 meters) fix within 5 to 20 seconds. Through different property settings, you can force greater or less accuracy, faster or slower response times, and agree to accept a cached fix. Typically, greater accuracy means a slower response to the request.

The Location service tries to get a fix with the requested accuracy. If it is not able to get a fix within the maximum allowed time, it returns the best match from the cache. If there is no entry in the cache, the service returns a timeout error.

If the Location service can get a fix, the onSuccess function will be called with a response object with the properties described in Table 9-4.

Table 9-4. Response properties for Location service position fix

Property

Description

errorCode

Set to zero if the request is successful; a nonzero value otherwise (see Table 9-5 for a complete list of error codes)

timestamp

The time (in milliseconds) when the location fix was created

latitude

A number representing the latitude in degrees of the location; valid range is −90.0, 90.0

longitude

A number representing the longitude in degrees of the location; valid range is −180.0, 180.0

horizAccuracy

Horizontal accuracy of the location in meters; if unknown, value is −1

heading

A number representing the compass azimuth in degrees; valid range is 0.0, 360.0; if unknown, value is −1

velocity

A number representing velocity in meters per second; if unknown, value is −1

vertAccuracy

Vertical accuracy of the location in meters; if unknown, value is −1

If there’s an error, the onFailure function is called with a nonzero errorCode. A list of possible errors is provided in Table 9-5.

Table 9-5. Location service error codes

Error Code

Description

0

Success

1

Timeout

2

Position Unavailable

3

Unknown

4

GPS Permanent Error

5

Location Service Off

6

Permission denied: user hasn’t agreed to location service terms of use

Tracking

Use the startTracking method to get a series of fixes. Tracking is effective for navigation applications or anywhere you want to update the device location over a period of time. A new tracking fix is provided about once a second:

this.trackingHandle = this.controller.serviceRequest("palm://com.palm.location", {
    method: "startTracking",
    parameters:{subscribe: true},
    onSuccess: this.trackingSuccess.bind(this),
    onFailure: this.trackingFailure.bind(this)
});

You need to subscribe to this service and save the request object so that you can cancel the tracking request when you are done with it:

this.trackingHandle.cancel();

The onSuccess function will be called with a response object that has the same properties provided with the getCurrentPosition method; they are described in Table 9-4. As with getCurrentPosition, you can get tracking fixes even without GPS, although at a reduced level of accuracy (Cell ID or WiFi ID are less accurate than GPS).

If there’s an error, the onFailure function is called. You will continue to receive tracking fixes even after an error, since most errors are transient. In one case though, GPS Permanent Error, the error will persist, but you can still receive tracking data from Cell ID or WiFi ID.

Note

If you receive a GPS Permanent Error, you can still receive location services through Cell ID and WiFi ID. In this case, the error will be reported with a callback to the specified onFailure function, but thereafter you will receive ongoing tracking fixes through the onSuccess callback.

Reverse location

An additional Location service provides you with a physical address when provided with a location described with latitude/longitude values:

this.controller.serviceRequest("palm://com.palm.location", {
    method: "getReverseLocation",
    parameters: {
        latitude: "37.7779",
        longitude: "-122.414"
    },
    onSuccess: this.reverseSuccess.bind(this),
    onFailure: this.reverseFailure.bind(this)
});

If successful, the onSuccess callback is passed a response object with a single address property. The address is two or three lines, each delimited by semicolons, where the street address is optional:

street address;
locality (eg. in the US, city, state, zipcode);
country

For example, this code sample would return the following string:

98th 8th St ;San Francisco, CA 94103 ;USA

Power Management

The device will automatically go to sleep after a period of inactivity, where inactivity is primarily defined as the absence of user interaction: gestures, touches, or keyboard input. The user can set a preference to trigger sleep after a minimum of 30 seconds or a maximum of 3 minutes. Some system services, such as audio or video playback will defer sleep, but if you need to keep the device awake, you can use the activityStart() and activityEnd() methods in the Power Management service.

You would use these service methods if your application performs an extended operation, such as syncing or downloading a lot of data, or if your application includes a passive viewing feature like a slide show. You will also use this in background applications where you need more than the few seconds allotted during an alarm wakeup.

Alert the Power Management service that you are starting an activity that will require the device to stay awake:

this.controller.serviceRequest("palm://com.palm.power/com/palm/power", {
    method: "activityStart",
    parameters: {
        id: "com.palm.app.news.update-1",
        duration_ms: '120000'
    },
    onSuccess: this.activitySuccess.bind(this),
    onFailure: this.activityFailure.bind(this)
});

Provide a unique ID, which should be your application ID with an activity name and an occurrence count. This recommended format will allow you to distinguish between requests and manage multiple requests if needed, but the only requirement is that the ID string be unique. The activity’s expected duration is provided in milliseconds and cannot exceed 900,000 milliseconds (15 minutes).

The power management service will automatically terminate your activity request at the end of its duration or 15 minutes, whichever is shorter. You should notify the service when your activity completes, as every bit of power efficiency is important:

this.controller.serviceRequest("palm://com.palm.power/com/palm/power", {
    method: "activityEnd",
    parameters: {
        id: "com.palm.app.news.update-1"
    },
    onSuccess: this.activitySuccess.bind(this),
    onFailure: this.activityFailure.bind(this)
});

The only parameter is the id provided to the activityStart() method. Activities are not canceled when an application is closed, so you should use activityEnd() in your cleanup() method when there are any outstanding activity requests.

System Properties

Applications can request a named system property, which is currently limited to retrieving the unique device ID. Generally, the requested system property is named as a string to parameter.key; in this case, the device ID is named com.palm.properties.nduid:

this.controller.serviceRequest("palm://com.palm.preferences/systemProperties", {
    method: "getSysProperty" ,
    parameters:{"key": "com.palm.properties.nduid" },
    onSuccess: this.onSuccessHandler
    }
});

The nduid is a hardware-encoded device ID that is guaranteed to be unique. An example device ID is a66690b3632bb592b29c6a15416717b9ee072b3f.

On a successful callback, you will find the device ID as the value assigned to the key, com.palm.properties.nduid. In this example:

this.onSuccessHandler = function() {
    Mojo.Log.info("Success; nduid = ", response["com.palm.properties.nduid"]);
};

The device ID is the recommended way to uniquely identify the user or their device. The device ID is better than the phone number or device serial number because it is guaranteed to be unique to a specific device, yet it is difficult for others to use it to identify a specific user. The phone number is considered private user information and should never be used or transmitted with any user data. The serial number is printed on the device, making it easier to associate a device to a specific user.

System Services

The system is designed to expose a set of services enabling applications to access some general system settings. Currently, the only exposed service is one that provides the system time.

Make the request to the getSystemTime method, and optionally subscribe to notifications of changes to the time or timezone:

this.controller.serviceRequest("palm://com.palm.systemservice/time", {
    method: "getSystemTime",
    parameters: {subscribe: true},
    onSuccess: this.timeSuccess.bind(this),
    onFailure: this.timeFailure.bind(this)
});

Whether the subscribe property is set or not, the onSuccess function will be called initially with the response object as an argument. The properties are described in Table 9-6.

Table 9-6. Response properties for system time

Property

Description

localTime

The time for the current timezone in seconds

offset

Offset from UTC in minutes

timezone

Current timezone in the “TZ” environment variable format

Note

In most cases, you can use the JavaScript Date object to get the current date and time. The getSystemTime service method gives you the timezone and allows you to subscribe to time changes, which may be important to your application. In most other cases, the Date object is a lightweight and more versatile source of date and time information.

System Sounds

The System Sounds service is used to create audio feedback for direct user actions. This might include button or keypad clicks, transition sounds, action audio, or any audible response to a user action. It’s not intended for sustained audio, such as background audio or any lengthy playback. The call is limited to a static list of sounds and is not customizable.

The specified sounds will be played as soon as the call is received, with low latency. Call System Sounds using the playFeedback method, with the requested sound name as a string assigned to the name property:

this.controller.serviceRequest("palm://com.palm.audio/systemsounds", {
    method: "playFeedback",
    parameters:{name: "shutter",
        onSuccess: this.onSuccessHandler,
        onFailure: this.onFailureHandler
    }
});

The callbacks will receive the response object with returnValue set to true if the sound played successfully; otherwise, it will be set to false. If false is returned, the errorText property will include an indication of the type of error encountered.

The available sounds are enumerated in Appendix B, and you can find them on the Palm developer site.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
18.218.132.6