Oct

26

Accessing RESTful WebServices with JavaScript

By marcos

Introduction

The most used architecture to develop WRT widgets is shown in the below picture. There is a server that provide some data and the widget consumes that data. The communication between the widget and the server application can be done in a restful web service. This post is about the definition of a restful web service specification and the implementation of a javascript library to access that web service.

The RESTful Web Service Specification

A RESTful web service (also called a RESTful web API) is a simple web service implemented using HTTP and the principles of Representational state transfer (REST). This is a style of software architecture for distributed hypermedia systems such as the World Wide Web.

In a RESTful web service the developer has access to “resources” and that “resources” can be created, retrieved, updated or deleted. The definition of RESTful web service can be thought of as comprising three aspects:

  • The base URI for the web service such as http://example.com/resources/
  • The MIME type of the data supported by the web service. This is often JSON, XML or YAML but can be any other valid MIME type.
  • The set of operations supported by the web service using HTTP methods (e.g. POST, GET, PUT or DELETE).

The following table shows how the HTTP verbs are typically used to implement a RESTful web service.

RESTful Web Service HTTP methods
Resource GET PUT POST DELETE
Collection URI such as http://example.com/resources/ List the members of the collection complete with their member URIs for further navigation. For example list all the cars for sale. Meaning defined as ‘replace the entire collection with another collection’. Create a new entry in the collection where the ID is assigned automatically by the collection. The ID created is usually included as part of the data returned by this operation. Meaning defined as ‘delete the entire collection’.
Member URI such as http://example.com/resources/7HOU57Y Retrieve a representation of the addressed member of the collection expressed in an appropriate MIME type Update the addressed member of the collection or create it with the specified ID. Treats the addressed member as a collection in its own right and creates a new subordinate of it. Delete the addressed member of the collection.

The Specification

It was specified a restful web service using the HTTP methods shown above. For each CRUD operation has been defined a mean for all possible HTTP responses. It is shown below:

PUT HTTP method (Create)

  • Success = 200
  • The operation has been accepted, but not executed yet = 202
  • Client error = 4xx
    • Data conflict = 409
    • Forbidden operation = 403
  • Server error = 5xx
    • Default = 500
    • Overload = 503

GET HTTP method (Retrieve)

  • Success = 200
  • Client error = 4xx
    • Resource not found = 404
    • Forbidden operation = 403
  • Server error = 5xx
    • Default = 500
    • Overload = 503

POST HTTP method (Update)

  • Success = 200
  • The operation has been accepted, but not executed yet = 202
  • Client error = 4xx
    • Resource not found = 404
    • Data conflict = 409
    • Forbidden operation = 403
  • Server error = 5xx
    • Default = 500
    • Overload = 503

DELETE HTTP method (Delete)

  • Success = 200
  • The operation has been accepted, but not executed yet = 202
  • Client error = 4xx
    • Resource not found = 404
    • Forbidden operation = 403
  • Server error = 5xx
    • Default = 500
    • Overload = 503

Each http method used is shown in the follow list:

  • 200 - OK - Success.
  • 201 - Created - Resource has been created.
  • 202 - Accepted - Operation has been accepted, but not executed yet. May be stored to be executed in the future.
  • 403 - Forbidden - Forbidden access, the code 404 can be returned for security reasons.
  • 409 - Not Found - Resource not found.
  • 500 - Internal Server Error - A server error.
  • 503 - Service Unavailable - The server is busy and the client can configure the Retry-After:xx (xx in seconds) parameter in the HTTP response.

Implementation

JavaScript client

The client code to access the RESTful web service was developed with just one class. Each CRUD operation has two listeners. One method is executed when a success occurs; and the other is executed when an error occurs. For example, onRetrieveError will be executed if a required resource is not found in the server and the HTTP code 404 is returned. There are the following listeners in the RestfulResource class:

  • onCreateSuccess(responseText)
  • onCreateError(responseStatus)
  • onRetrieveSuccess(responseText)
  • onRetrieveError(responseStatus)
  • onUpdateSuccess(responseText)
  • onUpdateError(responseStatus)
  • onDeleteSuccess(responseText)
  • onDeleteError(responseStatus)

The CRUD operations:

  • create(jsonObject)
  • retrieve(id)
  • update(jsonObject)
  • delete(id)

The RestfulResource class

function RestfulResource(resource_url){
 
this.resource_url = resource_url
 
this.xmlhttp = new XMLHttpRequest();
 
/**
* Get the resource or a list of resources calling the RESTful web service with the GET http method
* @param id The id of the resource, if is null a list of resources will be retrieved.
*/
this.retrieve = function(id){
var url = this.resource_url
if(id != null)
url = this.resource_url.concat("/"+id)
 
var self = this;
this.xmlhttp.onreadystatechange=function(){
if (self.xmlhttp.readyState==4){
if (self.xmlhttp.status==200){
self.onRetrieveSuccess.call(self,self.xmlhttp.responseText);
}else{
self.onRetrieveError.call(self,self.xmlhttp.statusText);
}
}
}
this.xmlhttp.open("GET",url,true);
this.xmlhttp.send(null);
}
 
/*
* The method called when a resource is successfully retrieved.
*/
this.onRetrieveSuccess = function(responseText){
alert("onRetrieveSuccess method "+responseText);
}
 
/*
* The method called when a resource is not created.
*/
this.onRetrieveError = function(statusText){
alert("onRetrieveError method "+statusText);
}
 
/**
* Create the resource calling the RESTful web service with the PUT http method
* @param jsonObject The jsonObject that will be created.
*/
this.create = function(jsonObject){
var jsonString = JSON.stringify(jsonObject);
var self = this;
this.xmlhttp.onreadystatechange=function(){
if (self.xmlhttp.readyState==4){
if (self.xmlhttp.status==200){
self.onCreateSuccess.call(self,self.xmlhttp.responseText);
}else{
self.onCreateError.call(self,self.xmlhttp.statusText);
}
}
}
this.xmlhttp.open("PUT",this.resource_url,true);
this.xmlhttp.setRequestHeader("Content-type", "application/json");
this.xmlhttp.setRequestHeader("Content-length", jsonString.length);
this.xmlhttp.setRequestHeader("Connection", "close");
this.xmlhttp.send(jsonString);
}
 
/*
* The method called when the resource is successfully created.
*/
this.onCreateSuccess = function(responseText){
alert("onCreateSuccess method "+responseText);
}
 
/*
* The method called when the resource can't be created.
*/
this.onCreateError = function(statusText){
alert("onCreateError method "+statusText);
}
 
/**
* Update a resource calling the RESTful web service with the POST http method
* @param id The id of the resource, if is null a list of resources will be retrieved.
* @return The retrieved resource.
*/
this.update = function(jsonObject){
var jsonString = JSON.stringify(jsonObject);
var self = this;
this.xmlhttp.onreadystatechange=function(){
if (self.xmlhttp.readyState==4){
if (self.xmlhttp.status==200){
self.onUpdateSuccess.call(self,self.xmlhttp.responseText);
}else{
self.onUpdateError.call(self,self.xmlhttp.statusText);
}
}
}
this.xmlhttp.open("POST",this.resource_url,true);
this.xmlhttp.setRequestHeader("Content-type", "application/json");
this.xmlhttp.setRequestHeader("Content-length", jsonString.length);
this.xmlhttp.setRequestHeader("Connection", "close");
this.xmlhttp.send(jsonString);
}
 
/**
* The method called when the resource is successfully updated.
*/
this.onUpdateSuccess = function(responseText){
alert("onUpdateSuccess method "+responseText);
}
 
/**
* The method called when the resource can't be updated.
*/
this.onUpdateError = function(statusText){
alert("onUpdateError method "+statusText);
}
 
/**
* Remove a resource calling the RESTful web service with the DELETE http method
* @param id The id of the resource.
*/
this.remove = function(id){
var url = this.resource_url.concat("/"+id);
var self = this;
this.xmlhttp.onreadystatechange=function(){
if (self.xmlhttp.readyState==4){
if (self.xmlhttp.status==200){
self.onRemoveSuccess.call(self,self.xmlhttp.responseText);
}else{
self.onRemoveError.call(self,self.xmlhttp.statusText);
}
}
}
this.xmlhttp.open("DELETE",url,true);
this.xmlhttp.send(null);
}
 
/**
* The method called when the resource is successfully removed.
*/
this.onRemoveSuccess = function(responseText){
alert("onRemoveSuccess method "+responseText);
}
 
/**
* The method called when the resource can't be removed.
*/
this.onRemoveError = function(statusText){
alert("onRemoveError method "+statusText);
}
 
}

The RESTful web services (PHP and Grails)

Here, there are some implementation examples of web services using the specification above. As you can see, there are simple and small, very easy to understand. They implement the CRUD operations on an Author class, with only two attributes (id and name).

PHP

id = $id;
$this->name = $name;
}
}
 
switch($method){
case "GET":
if(isset($id)){
$result = mysql_query('SELECT * FROM author WHERE id = '.substr($id,1,strlen($id)));
}else{
$result = mysql_query('SELECT * FROM author');
}
$jsonObjects = array();
while($row = mysql_fetch_array($result)){
$author = new Author($row['id'],$row['name']);
array_push($jsonObjects,$author);
}
if(count($jsonObjects) > 0){
echo $json->serialize( $jsonObjects );
}else{
header("HTTP/1.1 404 Not Found");
}
 
break;
case "PUT":
$body = @file_get_contents('php://input');
 
$newJsonObject = $json->unserialize( $body , true );
 
$insertAuthor = 'INSERT INTO author (name)VALUES(\''.$newJsonObject->name.'\')';
 
mysql_query($insertAuthor);
 
echo "Created";
 
break;
case "POST":
$body = @file_get_contents('php://input');
 
$editJsonObject = $json->unserialize( $body , true );
 
$result = mysql_query('SELECT * FROM author WHERE id = '.$editJsonObject->id);
 
if($result == false){
header("HTTP/1.1 404 Not Found");
break;
}
 
$updateAuthor = 'UPDATE author set name = \''.$editJsonObject->name.'\' where id = '.$editJsonObject->id;
 
if(!mysql_query($updateAuthor)){
header("HTTP/1.1 500 Internal Server Error");
break;
}
break;
case "DELETE":
if(isset($id)){
if(mysql_num_rows(mysql_query('SELECT * FROM author WHERE id = '.substr($id,1,strlen($id)))) == 0){
header("HTTP/1.1 404 Not Found");
break;
}
$deleteAuthor = "DELETE FROM author WHERE id = ".substr($id,1,strlen($id));
if(!mysql_query($deleteAuthor)){
header("HTTP/1.1 500 Internal Server Error");
break;
}
}else{
header("HTTP/1.1 404 Not Found");
break;
}
break;
}
 
mysql_close($conn);
?>

Grails

import grails.converters.*
 
class RestfulController {
 
def authors = {
def method = request.getMethod()
def jsonObject = null;
switch(method){
case "GET":
if(!params.id){
def result = Author.list()
response.status = 200
render result as deep.JSON
}else{
def result = Author.findById(params.id)
if(result){
response.status = 200
render result as deep.JSON
}else{
response.status = 404
render "Entity not found"
}
}
break;
 
case "POST":
if(params.json)
jsonObject = JSON.parse(params.json)
if(jsonObject.id){
response.status = 200
def entity = Author.findById(jsonObject.id)
if(entity){
entity.properties = jsonObject
if(entity.save()){
response.status = 200
render "Updated"
}else{
response.status = 500
render "Entity not updated"
}
}else{
response.status = 404
render "Entity not found"
}
}else{
response.status = 404
render "Entity not found"
}
 
break;
 
case "PUT":
if(params.json)
jsonObject = JSON.parse(params.json)
def entity = new Author(jsonObject)
if(entity.save()){
response.status = 200
render "Created"
}else{
response.status = 500
render "Entity not saved"
}
break;
 
case "DELETE":
if(params.id){
def entity = Author.findById(params.id)
if(entity){
try {
entity.delete(flush:true)
response.status = 200
render "Deleted"
}
catch(org.springframework.dao.DataIntegrityViolationException e) {
response.status = 500
render "Entity not deleted"
}
}else{
response.status = 404
render "Entity not found"
}
}else{
response.status = 404
render "Entity not found"
}
break;
}
}
 
def books = {
def method = request.getMethod()
def jsonObject = null;
switch(method){
case "GET":
if(!params.id){
def result = Book.list()
response.status = 200
render result as deep.JSON
}else{
def result = Book.findById(params.id)
if(result){
response.status = 200
render result as deep.JSON
}else{
response.status = 404
render "Entity not found"
}
}
break;
 
case "POST":
if(params.json)
jsonObject = JSON.parse(params.json)
if(jsonObject.id){
response.status = 200
def entity = Book.findById(jsonObject.id)
if(entity){
entity.properties = jsonObject
if(entity.save()){
response.status = 200
render "Updated"
}else{
response.status = 500
render "Entity not updated"
}
}else{
response.status = 404
render "Entity not found"
}
}else{
response.status = 404
render "Entity not found"
}
 
break;
 
case "PUT":
if(params.json)
jsonObject = JSON.parse(params.json)
def entity = new Book(jsonObject)
if(entity.save()){
response.status = 200
render "Created"
}else{
response.status = 500
render "Entity not saved"
}
break;
 
case "DELETE":
if(params.id){
def entity = Book.findById(params.id)
if(entity){
try {
entity.delete(flush:true)
response.status = 200
render "Deleted"
}
catch(org.springframework.dao.DataIntegrityViolationException e) {
response.status = 500
render "Entity not deleted"
}
}else{
response.status = 404
render "Entity not found"
}
}else{
response.status = 404
render "Entity not found"
}
break;
}
}
 
}

Downloads

The JavaScript client code to access the RESTful web service (restful.zip)

A WRT example widget using the JavaScript library to access a RESTful web service (widget.wgz).

References

  • http://en.wikipedia.org/wiki/Representational_State_Transfer

Sep

3

Static GoogleMaps® API in JavaScript

By artur

Hey,

thinking in make better the work of the programmers I create an API to retrieve static maps using the GoogleMaps® system. So, in this way, your work can be so much easy using this API made for JavaScript.

To get this API click here and to see the API documentation click here.

Now, I’ll show you some examples of how to use the Map API.

First example (showing the map automatically):

One way to retrieve the map is using the <div> tag. Put all the values you want to your map and use the showMap() tag. It’s really necessary that you set the map id with the same value of the div.

<body onload="init();">
<div id=map></div>
</body>
/**
 * Embedded Systems and Pervasive Computing Lab
 * WRT Effort - http://efforts.embedded.ufcg.edu.br/wrt 
 *
 * @author Artur
 */
function init() {
	map = new Map(40.702147, -74.015794);
	map.id = "map";
	map.color = "green";
	map.name = "y";
	map.width = 400;
	map.height = 200;
	map.showMap();
}

Example 1

Second example (retrieving the map’s source):

Other way to retrieve the map is using the <img> tag. You set the parameters and using the method getSource() you can define the src value.

<body onload="init();">
<img src="" id=map>
</body>

/**
 * Embedded Systems and Pervasive Computing Lab
 * WRT Effort - http://efforts.embedded.ufcg.edu.br/wrt 
 *
 * @author Artur
 */
function init() {
		map = new Map(40.702147, -74.015794);
		map.color = "blue";
		map.name = "x";
		map.width = 300;
		map.height = 300;
		document.getElementById("map").src = map.getSource();
	}

So,

Example 2

Third example (using external data source, like GPS):

First, getting the GPS information. You define the device operations:

/**
 * Embedded Systems and Pervasive Computing Lab
 * WRT Effort - http://efforts.embedded.ufcg.edu.br/wrt 
 *
 * @author Artur
 */
function setup()
{
  try {
    so = device.getServiceObject("Service.Location", "ILocation");
    getLocation();
  }
  catch (e) {   
      alert('(006) Error ::setup ' + e);
  }
}

After that, the get location method:

function getLocation() {
	try {
		var updateoptions = new Object();
		updateoptions.PartialUpdates = false;
 
		var criteria = new Object();
		criteria.LocationInformationClass = "GenericLocationInfo";
		criteria.Updateoptions = updateoptions;
 
		var result = so.ILocation.GetLocation(criteria, result);
		var errCode = result.ErrorCode;
		if (errCode) {
			alert("(005) GPS Error: " + errCode + " " + result.ErrorMessage);
		}
	} catch (e) {
		alert("(004) ::getLocation error: " + e);
	}
}

Finally, the call back function:

function result(transId, eventCode, result)
{
    var errCode = result.ErrorCode;
    if (errCode) {
        alert("(003) GPS Error: " + errCode + " " + result.ErrorMessage);
    }
    else {
        map = new Map(result.ReturnValue.Latitude,
                        result.ReturnValue.Longitude);
        map.id = "map";
        map.color = "yellow";
        map.name = "Artur";
        map.width = 500;
        map.height = 250;
        map.showMap();
    }
}

Example 3

If you like it and want to see these examples, click here to get the first two examples and here to get the GPS example.

See you soon.

Aug

10

Problems with WRT variables

By artur

Hi folks,

developing here in a project I discovered a “bug” in the WRT. When you use the window.location, the variables “device”, “menu” and “widget” are lost. So you cannot use the services for example or persist information using preferenceForKey.

The solution was use the tag iframe.

<iframe src="page.html"></iframe>

So when you need to use the device , menu and widget variables in the iframe page, just put in the JavaScript file the variable parent to refer the main page.

Examples:

var phonebook = parent.device.getServiceObject("Service.Contact", "IDataSource");

or

parent.menu.hideSoftkeys();

Jul

9

How to retrieve contacts informations

By artur

What’s up?

A feature from the S60 5th Edition is to retrieve the contacts information using WRT. You can get names, phone numbers, e-mail…

I will show how to get these information and use however you want. In the HTML file, I put a tag span to show the result.

<span id=result></span>

You can put also a field to search specific contacts.

<input id="search" type="text">
<input type="button" value="Search" onclick="refresh();">

Now the JavaScript. First, you have to define the provider and the interface of the service object.

/**
 * Embedded Systems and Pervasive Computing Lab
 *
 * @author Artur Farias
 */
 
 var phonebook;
 var NO_ITEMS_ERROR_CODE = 1012;
 
 function phonebook()
 {
 	try
	{
	     phonebook = device.getServiceObject("Service.Contact", "IDataSource");
	} catch (e) {
	     alert("Service Not Avaible");
	}
 
	refresh();
 }

After that, let’s create the function “refresh()”. The function’s begin is to define the search filter. We get the value of the search field and set to the criteria filter.

function refresh()
 {
 	var criteria = new Object();
	criteria.Type = 'Contact';
 
	var search = document.getElementById("search").value;
	if(search != "")
	{
		criteria.Filter = new Object();
		criteria.Filter.SearchVal = search;
	}

Then, we retrieve the contacts list.

try
	{
		contacts = phonebook.IDataSource.GetList(criteria);
	} catch (e) {
		alert("An error occur while retrieving contacts");
	}

After get the list, show the result in HTML file.

if (contacts.ErrorCode != 0) {
		if (contacts.ErrorCode != NO_ITEMS_ERROR_CODE) {
			alert(contacts.ErrorMessage);
		}
		return;
	} else {
		var result = "";
		var contact;
 
		for(var i = 0; (contact = contacts.ReturnValue.getNext()) != undefined; i++)
		{
			result += "<div>Name: ";
			if(contact.FirstName != undefined)
			{
				result += contact.FirstName.Value;
			}
 
			if(contact.LastName != undefined)
			{
				result += " " + contact.LastName.Value;
			}
 
			result += "<br> Phone: ";
 
			if(contact.MobilePhoneGen != undefined)
			{
				result += contact.MobilePhoneGen.Value;
			} 
 
			result += "</div><br>";
		}
 
		document.getElementById("result").innerHTML = result;
	}
 }

If you have more doubts, e-mail me or see this article at Forum Nokia.

You can download wgz example here.

May

12

A Simple Game Using JavaScript

By artur

Hi yourself,

here I’ll show how to create a simple game for WRT using just JavaScript commands.

First, the idea of the game. It’s a puzzle, with 9 slots, but one slot is empty. When you push a slot, if one of the adjacent slots is empty, they trade their places.

You create a WRT Project and in the main html you define a table 3×3 with the images.

We need to define the principal function “change()”. Create a JavaScript to be the logic and define the function. The main idea is to know how to trade the slots, or better, how to trade the pictures.
For this, you might use the structure below:

document.getElementById(id)

When you put this with the id of the picture, you retrieve the Image Object. Then you use the .src to get the image address.

document.getElementById(id).src

Therefore, the clicked image gets the address of the empty slot (if it is near) and the empty slot gets the clicked image address. Like that:

var address = document.getElementById(clickedImageId).src;
 
document.getElementById(clickedImageId).src = document.getElementById(emptySlotId).src;
document.getElementById(emptySlotId).src = address;

And now you can create your own puzzle. Enjoy it.

You can dowload the WGZ file clicking here or if you prefer, the ZIP file with the sources here.

Apr

22

How to access GPS location using S60 5th Edition API

By artur

In the application showed in this post you can see how to develop a location based rss reader using WRT with the position of the device (using the new S60 5th edition WRT API).

First of all, let’s see the problem:

Think you’re in an environment where news are provided as a rss file. This news could be an advertisement, an event, a shop or anything else you want.

Think also you are using a mobile phone with a RSS reader inside this environment and there is a large amount of news (a big rss file) about this environment, but you’re only interested in the news nearest your location.

This situation is showed in the picture below. You’ll get information (news) about sector C, even you’re in the sector A of the shopping center.

This situation becomes a problem to the user when the amount of information about the environment (the shopping center) is too large (sector A + sector B + sector C).

This problem can be fixed if the rss reader of the mobile phone retrieves only information (news) about the sector where the user is inside it. This can be done attributing a position (latitude and longitude) for each ‘item’ of the ‘rss’ file of the environment, as showed in the following picture.

So, the user has to send his position in the request of the rss file to get only information about the sector where he is inside it.

For example, if the user is inside the sector A, he’ll get only information about item 1 and 2, but not about item 3,4,5 or 6. So, we can realize that only the shops who item 1 and 2 represent are inside the sector A.

An example of the development of a RSS server with filtered content is showed in this post.

Ok, now we have a RSS Server that filter the rss content based in the location given as parameter in the request. But, we need a mobile client to send the location of the device and read the filtered RSS content.

In the WRT API for 5th edition S60, the developer can get the GPS position using the new Service class. This class access the GPS position (and many other resources) of the mobile phone and retrieve a lot of information about location. Below it’s showed a code example of how to get this information and send the request to the RSS Server of the previous picture.

var so;
 
// Called from onload()
function setupLocation()
{
  try {
    //Retrieves the Service object to the ILocation interface
    so = device.getServiceObject("Service.Location", "ILocation");
  }
  catch (e) {
    alert(' ' +e);
  }
}
 
// Get Location
function getLocationAsync() {
 
    // This specifies update option used while retrieving location estimation.
    var updateoptions = new Object();
    // Setting PartialUpdates to 'FALSE' ensures that user get atleast
    // BasicLocationInformation (Longitude, Lattitude, and Altitude.) is the default when no LocationInformationClass criteria is given.
    updateoptions.PartialUpdates = false;
 
    var criteria = new Object();
 
    criteria.Updateoptions = updateoptions;
 
    try {
    //Executes the GetLocation method and sets the callbackLocation as the callback function to be called.
    so.ILocation.GetLocation(criteria,callbackLocation);
    } catch (e) {
        alert ("getLocationAsync: " + e);
    }
}
 
//Callback function that send the GPS position to the server
function callbackLocation(transId, eventCode, result){
    var latitude = result.ReturnValue.Latitude;
    var longitude = result.ReturnValue.Longitude;
    //Sends the position latitude and longitude to the server using the XMLHttpRequest class.
    var req = null;
    try {
        req = new XMLHttpRequest();
        // Make sure that the browser supports overrideMimeType
        if (typeof req.overrideMimeType != "undefined") {
            req.overrideMimeType("text/xml");
        }
        req.onreadystatechange = function() {
          // Request states are 0 through 4, where 4 equals complete
            if (req.readyState == 4) {
                // Server returns numeric code 200 for "OK".
                if (req.status == 200) {
                    //Handling the retrieved content from the server.
                    ...
                }
            } else {
              alert("There was a problem retrieving the RSS file.");
            }
        }
        // is the server URL to retrieve the RSS filtered file.
        var url = "?d="+date.getMilliseconds()+"&amp;latitude="+latitude+"&amp;longitude="+longitude;
        req.open(url);
        req.send(null);
    } catch (ex) {
        alert(ex);
    }
}

The application also show a static map with the location of the user and the location of each retrieved item.

Dec

1

Accessing Car Information Using The Mobile Phone

By artur

Hi everyone, how do you do?

Here, I will explain an idea we had, how the problem was appearing and how we solve these problems.

The idea consists in access the informations about any car (actually, we have done for 11 brands) retrieving data from a bluetooth communication layer between the OBD II server in the car and the S60 WRT application.

So, the first issue appeared: “How we get data from the layer if the WRT cannot use the bluetooth device?”
Solution thought: “Using a Python Local Server which get data from the bluetooth layer and send to the WRT application.” (see more).

Connecting... Main Screen

After this, we needed to do the engine, i.e, show the panel of the car with speed, rpm, throttle, fuel and possible errors. We have the data, however how to make the application seems like a real car? Creating a interface seeming a real car, but how to rotate the pointers and animates the panel?

This was the second issue we had.
The solution? Use Flash inside the WRT.

And finally, we needed to show the possible errors retrieved from the OBD II server in the car. But, there are 11 brands in our application and the same code differs for each brand. So, how can we know which error is?
Using the profile information about the car and accessing some XML files from a external server to know which error is.

Well, that’s was our ideas and problems. In next posts, we’ll explain better and more specific about all the issues and solutions we had.

See you soon, =)

Nov

23

How to do an image gallery in WRT

By marcos

In this post we’ll show you how to do an image gallery using the WRTKit and the new S60 5th edition WRT API.

Extending WRTKit

In this post was showed how the developer can extend the WRTKit and to create new UI components. To do the image gallery, let’s to do the same thing. The image gallery will be a UI components that can be added in other applications easily.

Below you see the class diagram of the image gallery (with all methods and attributes) and how it extends the WRTKit.

Let’s unterstand this picture:

  • The Control class is a base class of the WRTKit. All UI components have to extend this class, directly or indirectly. There are many methods and attributes in this class, but for now we have to understand only two attributes, contentElement and controlElement.
  1. The controlElement is the base html element of any WRT application, all UI components (Button, Label, Text and the gallery we’re doing) have to be added in this attribute using the controleElement.appendChild method.
  2. The contentElement is the base html element of a specific UI component. If an UI component have more than one html elements (images, links, buttons, etc), all this elements have to be added in the contentElement. After this, the contentElement has to be added in the controlElement attribute to be showed in the screen.
  • The Gallery class is the image gallery we’re doing. This class has three attributes (backImageContentPane, images and lockedImage), let’s understand each one of them:
  1. backImageContentPane is an image html element, this is the background of the gallery, this is necessary because we can’t capture mouse events that occurs on div html elements (The contentElement is a div html element because it will have all images of the mobile phone inside it).
  2. images is a array with the file path and file name of all pictures of the mobile phone. The file information about the pictures will be get using the new S60 5th edition WRT API. This’ll be showed below in this post.
  3. lockedImage is an image html element, this is the image selected by the user. In this application the user can move any picture to any position of the Gallery component. To do this, he has to click an image (locking a image to do actions on it) and then click in another position of the gallery. The image will be moved to the new position.

Getting Media Information

How was told previously on this post, the images attribute of the Gallery class is an array with file path and name about all the pictures in the mobile phone. To get this information we can use the new S60 5th Edition WRT API.

This new API provide some interfaces to access and manage device resources, like GPS, SMS, Contacts and Media. The below code show the first step to access this resources, let’s see the code and understand it.

    try {
        var so = device.getServiceObject("Service.MediaManagement", "IDataSource");
        console.info("setup: so: %s", so);
    } catch(e) {
        alert('Error:' +e);
    }
 
    // Setup input params using dot syntax
    var criteria = new Object();
    criteria.Type = 'FileInfo';
    criteria.Filter = new Object();
    criteria.Filter.FileType = 'Image';
    criteria.Sort = new Object();
    criteria.Sort.Key = 'FileSize';
 
    try {
        // Media Management supports asynchronous call
       so.IDataSource.GetList(criteria, callback);
    } catch (e) {
        alert ("Error: " + e);
    }

First of all, you have to get access to S60 resources. This must be done with the device.getServiceObject method. This method receives two parameters: A service and an interface to be used.

  • The service parameter represents the service you want to use. There are a lot of services available, but in this post we’ll use only media management service. The media management service give to the developer access to media informations about any media that exist in the mobile phone (video, audio or image).
  • The second parameter of device.getServiceObject is the access interface to get the informations about the service.

An other important line in the code is where the information of the service is retrieved. The so.IDataSource.GetList is the method to do this. This method retrieves a list with informations about all media files that exists in the mobile phone.

To do this job, this method receives two parameters:

  • The first parameter is a criteria object used to filter the retrieved information (for example, you maybe want to retrieve only video files). This criteria object is also used to sort the list retrieved. In our gallery application, we filtered the retrieved information (using the criteria parameter) to get only information about image files.
    criteria.Filter = new Object();
    criteria.Filter.FileType = 'Image';
  • The second parameter is a callback function. Let’s understand how the callback function works and how the developer can use it:

    This function is called by the device (not by the developer) when the information is retrieved. The developer have to implement this function, but never call it. It has three attributes, the last attribute is the more important because it has all the retrieved information after the criteria be applied. Below you can see the code of this callback function

// This is the asynchronous callback handler
function callback(transId, eventCode, result)
{
  console.info("callback: transId: %d  eventCode: %d result.ErrorCode: %d", transId, eventCode, result.ErrorCode);
  showImages(result.ReturnValue);
}

In the above code, the callback function calls a showImage method with the returned value as parameter, let’s understand this function.

 
function showImages(iterator)
{
  try
  {
    iterator.reset();
    var item;
    var gallery = new Gallery(null,null,"100%",500);
    while (( item = iterator.getNext()) != undefined ){
      gallery.addImage(item.FileNameAndPath);
    }
    listView.addControl(gallery);
    gallery.load();
  }
  catch(e)
  {
    alert(' ' + e);
  }
  return msg;
}

In the showImages function we iterate over the list and add each file path and name to the gallery object. This object is an instance of the new UI component we have previously created in this post. After add all images in the gallery object the develper have to call the gallery.load method to generate and show the gallery.

Notice that you don’t need to use the Gallery component with a 5th device. You can retrieve file path and name from any other location (maybe an url location) or you can retrieve the media device information using a different way. But this work is very easy when using the new S60 5th edition WRT API. The below two pictures maybe help you to understand how this works.

Getting information without S60 5th edition WRT API. The information exist, but you have to develop a way to get it. Maybe a XML file, using a internal web server to get resource information or anything else.

Getting information with S60 5th edition WRT API. The work is very more easy, how we have seen in this post.

If you want to get the entire example application showed in this post, click here.

Nov

14

How to create a new UI component in the WRTKit

By marcos

The WRTKit is a complete library of JavaScript code, CSS style rules and graphical elements that are required to implement the kind of sophisticated, customizable, application-like user interfaces. It gives widget developers an easy way to create high quality user interfaces without having to worry about the problems that would otherwise plague their widgets. To install the WRTKit see the post.

The WRTKit folder has the following structure:

  • Resources (Images and CSS files)
  • UI (The user interface components, a lot of .js files)
  • Utils (utils .js files, When this post was write there is only a Logger.js file)
  • WRTKit.js (Import all the .js files in the UI folder)

Let’s see in more details the UI folder, This folder contains all the UI components of the WRTKit, we have to understand them before start the creation of new UI components.

In the UI folder, there is a Control.js file where is defined the Control class, this is an abstract base class for all user interface controls. Controls like FormButton, Label, TextArea, TextField and many more Controls are classes that inherit from Control class, directly or indirectly. Any new Control must inherits from Control class too.

The below code shows how to extend the Control class:

// Constructor.
function Map(id, caption,latitude,longitude) {
    if (id != UI_NO_INIT_ID) {
        this.init(id,caption,latitude,longitude);
    }
}
 
// Map inherits from Control.
Map.prototype = new Control(UI_NO_INIT_ID);

Remember that you have to put both files (Your new class and WRTKit.js) in the html code as showed below:

<script src="Map.js"/> <!-- If you save your new class as Map.js -->
<script src="WRTKit/WRTKit.js"/>

The Control class has a controlElement attribute who is a div element. Any HTML element that you want to put inside your new Control has to be included inside the attribute controlElement. For example, if you want a image in your Map control, you can do this using the follow code:

//document.createElement is a Javascript default method to create any HTML element at runtime.
var mapImage = document.createElement("img");
//After create you can get and set attributes of the element created.
mapImage.src = "url to the image";
//Now you can add the new element into the control element of the new Map control.
this.controlElement.appendChild(mapImage);

I’ve created a Map control class that access the google map static API, you can download it from here. You’ll also need a CSS code in your main HTML. (Should be an imported CSS file)

/* Caption for controls (captionElement) */
.ControlCaptionMap {
    font-weight: bold;
    padding: 3px 0px 0px 3px;
    color: #FF0000;
    horizontal-align: center;
    text-align: center;
}
 
/* Caption for controls (captionElement) */
.ControlMap {
    padding: 3px 0px 0px 3px;
    horizontal-align: center;
    vertical-align: middle;
    text-align: center;
}

After import this class into your HTML file, you can use it with the below code:

listView = new ListView(null, "List Selection");
mapControl = new Map("MyMap","",-7,-35);
listView.addControl(mapControl);
mapControl.reloadMap("You're Here!");

An example application using this class will be posted soon in this blog.

Sep

7

How to persist data in a mobile device with Widsets

By marcos

The Widsets API has a Store class. This class must be used when you want to storage and retrieve data in the mobile phone.

The Store class can persist the following classes: ByteArray, InputStream and Value. In this post we’ll only see how to persist an instance of the Value class.

First of all, let’s understand the Value class. An instance of this class can be of the following types: boolean, int, long, String, Binary, Binding (a key-value pair) and List (a list of instances of the Value class).

In our example we’ll use both Binding and List types to simulate a data table, with the structure and data showed below:


//The complete table is represented with a Value instance.
Value tbUsers = [];

//The two records.
Value user1 = ["name"=>"Marcos","age"=>;27];
Value user2 = ["name"=>"Fábio","age"=>;26];

//Now, we’ll add any user into the table.
tbUsers.add(user1);
tbUsers.add(user2);

To get an instance of Store classe you must use the following code:
Store store = getStore();

Now, you can save the data into the table (tbUsers) using the below code:
store.put("tbUsers",v);

That’s all!

If you want to retrieve all data from the table (tbUsers) you can use the below code:

Store store = getStore();
Value tableUsers = store.getValue("tbUsers");


for(int i = 0;i < tableUsers.size();i++){
printf(tableUsers.operator_get(i).operator_get("name"));
printf(tableUsers.operator_get(i).operator_get("age"));
}