Opera Platform™ SDK

Beta documentation


Abstract

This document covers the Opera Platform™ SDK, and describes methods and best practices for developing applications within the Opera Platform™ Application Framework This document is considered final documentation for this technical preview of the Opera Platform™ SDK. Given the Technical Preview state of the Opera Platform™ SDK, this document does not provide a guarantee against future API changes.

Summary

The Opera Platform™ SDK is a framework for developing and running Web based applications on mobile phones. It consists of three parts: the Application Player, the Application Framework and Applications.

Table of contents

  1. Introduction
    1. Before you start
    2. Opera
    3. Opera Platform™ DOM Interface
    4. Opera Platform™ Application Framework
    5. Opera Platform™ Web Applications
  2. Getting Started
    1. What is included in the Opera Platform™ SDK
    2. Installing Opera Platform™
      1. Windows Smartphone 2003
      2. Symbian Series60
    3. Installing Opera Platform™
      1. Symbian Series60
      2. Windows Smartphone 2003
    4. Required Tools
    5. Recommended Tools
  3. Deploying your first Opera Platform™ Project
    1. Packaging Your Application
      1. Symbian Series60 SIS
      2. Microsoft Smartphone 2003 CAB
    2. Deploying Your Service
  4. Building your first application
    1. Creating the HTML document
    2. Styling your application
    3. Creating your script
    4. Making your application an Opera Platform application
      1. Include Opera Platform javascript files
      2. Include the Opera Platform global stylesheet
      3. Creating an application definition
      4. Define an application class
      5. Adding application to registeredapps.xml
      6. Putting it all together
  5. Opera Platform™ applications
    1. System applications
    2. Applications
    3. CSS Styling rules
    4. Icons, themes and branding
    5. Application loading and unloading
    6. Memory
    7. CPU
    8. Network access
      1. Internet Connection Strategy: Series 60
    9. Menus
      1. Creating menus
      2. Menus and IDs
      3. Adding menu items
      4. Adding and changing actions
      5. Getting a named menu item
      6. Disabling a menu entry
      7. Removing a menu entry
      8. Dynamic menus
      9. Submenus
    10. Dialogs
      1. Info dialogs
      2. Warning dialogs
      3. Error dialogs
      4. Question dialogs
      5. Input dialogs
      6. Showing dialogs
    11. Setting navigation bar labels
      1. Menu button strategy
    12. The Navigation Bar
    13. The History Stack
      1. Explicitly removing elements from the history stack
    14. Localizing the Opera Platform™ Application Framework
      1. Softkey menus
      2. The application grid
      3. URL Manager
      4. Menu strings
  6. Reference
    1. O2_OutboundMessage
    2. O2_InboundMessage class constructor
    3. O2_UserServicePrototype class constructor
    4. O2_callAfterInstantiation
    5. guidList.xml
    6. menu.xml
    7. uriList.xml
    8. registeredApps.xml
    9. appdef.xml
    10. Message members
    11. Utilities
    12. O2_Command
    13. O2_MenuController
    14. O2_MenuItem
    15. O2_DialogController
    16. CSS Rules
      1. themes.xml
    17. Opera Platform™
    18. Quitting and/or reloading Opera Platform™
    19. opera.register()
    20. Deleting cookies
      1. Series 60
  7. Security
  8. Tips & Resources
    1. Tips
      1. Asynchronous operations
      2. Pass parameters to an onclick
      3. Prototyped methods
      4. Public methods
      5. Private methods
      6. Privileged methods
      7. Static methods
      8. Inline event handlers
      9. The self trick
      10. Singleton pattern
    2. Resources
      1. javascript
      2. Other

1. Introduction

Opera Platform™ is an SDK and a Web Application Framework that is built on top of the Opera Browser with the Opera Platform™, and facilitates creating locally or remotely hosted web applications on devices. These devices are typically mobile phones, but the Opera Platform™ Application Framework is not limited to running on any particular platform or operating system.

This documentation covers the Opera Platform™ SDK, also refered to as the Opera Platform™ Application Framework and how you can use this to create these web applications.

1.1. Before you start

An author that wants to author Opera Platform™ Web Applications needs to be familiar with the following technologies and specifications:

1.2. Opera

At the heart of the Opera Platform™ Application Framework lies the Opera web browser. The browser provides all the neccessary means to create an application by providing a web browser with support for web standards: HTML, CSS, javascript

1.3. Opera Platform™ DOM Interface

The Opera Platform™ DOM Interface provides a javascript interface for accessing and interacting with the device's native capabilities. This interface is covered in detail in the Opera Platform™ DOM Interface specification.

1.4. Opera Platform™ Application Framework

The Opera Platform™ Application Framework provides the developer with a set of base functionality that enables the user to write Client-Side Web Applications, known as Opera Platform™ Web Applications.

1.5. Opera Platform™ Web Applications

Opera Platform™ Web Applications are an application that uses the Opera Platform™ Application Framework, and the underlying functionality offered by the framework and the application player.

2. Getting Started

2.1. What is included in the Opera Platform™ SDK

The Opera Platform™ SDK is a framework and a tool set for creating web based application for mobile devices. The Opera Platform™ SDK consists of the base framework, documentation, some example web applications and tools for packaging and deploying projects.

The Opera Platform™ SDK contains everything a developer needs to create web based applications for mobile devices.

2.2. Installing Opera Platform™

Opera Platform™ is provided as an installable archive for Windows Smartphone 2003 and Symbian Series60. The installation process consists of transferring the archive to the device, and installing it on the device.

These instructions provide a step by step guide on how to install Opera Platform™ on the device on the supported devices.

2.2.1. Windows Smartphone 2003

  1. Download Opera Platform™ and Opera home plug-in cab files
  2. Connect the device to ActiveSync
  3. Open ActiveSync and click Explore
  4. Go to My Smartphone
  5. Navigate to \Storage\windows\Start Menu\Accessories.
  6. Copy the two cab files to this directory.
  7. Terminate all running instances of Opera by clicking Start Menu → System Management → Task Manager".
  8. Click on Start and then Accessories in the Start Menu.
  9. You should now see the files that you cut and paste into the Accessories folder, click on the Opera Platform™ cab file to start the installation of the browser.
  10. Do the same with the "homescreen plug-in" cab file. Click on it to install.
  11. This will install Opera and Opera Platform™ to \Storage\Application Data\Opera\, and make an entry for it in the Windows Smartphone application menu.

2.2.2. Symbian Series60

  1. Use Bluetooth, or any other suitable connection, to transfer the Opera Platform™ SIS to the device.
  2. Open the received message on the device and choose install. Choose to install the application on the memory card.
  3. The installer will create an Opera Platform™ application launcher on the Symbian Series60 application menu.
  4. Open the application menu and click on the Opera Platform™ icon to start Opera Platform™.

2.3. Installing Opera Platform™

A deployable Opera Platform™ project consists of a install package which installs in the correct folder, defined by Opera Platform™. The package has to be transferred and opened on the device.

2.3.1. Symbian Series60

The install procedure is the same as when installing Opera Platform™. Transfer the Opera Platform™ package to the device and open it. The package has to be installed on the same drive as Opera Platform™. For best performance it is recommended to install both on the memory card.

An alternative install procedure is to copy the Opera Platform™ content directly to the Opera Platform™ folder on the device. It is possible to use a PC memory writer to access the device memory directly from the PC. It is also possible to get direct access to the device by using P3NFS, a tool which only is available for Linux, this is described in the "Recommended Tools" section. An alternative method is to use Nokia PC Suite to copy the content to the device, and then use a file explorer on the device to copy it to the correct location. The content of the Opera Platform™ project should be placed so that the home.html is located in the folder "E:\System\Opera\OP\".

2.3.2. Windows Smartphone 2003

There is two ways of installing the Opera Platform™ content on the device. Either use a cab installer or copying the content of the Opera Platform™ project directly.

The install instructions for installing a cab file with Opera Platform™ content is the same as when installing Opera Platform™. The cab installer will automatically install the content in the correct location.

Microsoft ActiveSync gives direct access to the device memory and it is possible to copy the content directly from a computer to the device. The advantage of this compared to using a cab installer, is that it is quicker and the possibility of transferring only parts of the project.

The default location of the Opera Platform™ content on the device is '\Storage\Application Data\Opera\Oxygen'. Open ActiveSync and choose 'Explore', go to 'My Smartphone' and locate the directory. Copy the Opera Platform™ content into this folder, so that the home.html is located in the Oxygen directory.

2.4. Required Tools

The tools required for developing and installing Opera Platform™ is software for transferring data to the device, a text editor for developing and a connection method to the device.

It is possible to connect to the devices with Bluetooth, IR or USB connection. Most Smartphone devices come shipped with a USB cable, which is the fastest method of connection. Symbian Series60 phones seldom come with the required cable, and Bluetooth is the preferred transfer method.

Microsoft ActiveSync is required to transferring files to Windows Smartphone 2003 devices. ActiveSync is downloadable and available from the Microsoft web site. The software is not available for other Operating Systems.

2.5. Recommended Tools

A convenient way of developing on a Symbian Series60 device is by using P3NFS on from a Linux system. P3NFS is a server and client which makes it possible to connect the device hard drive directly to the local file system. This makes it possible to develop directly on the device, without having to transfer the content for each change. P3NFS is not available for any other operating systems than Linux.

Nokia PC Suite is a tool which makes it possible to connect the device to the local file system on a Microsoft Windows machine. Nokia PC Suite does not give directly access to the whole device, but it is usable for transferring to the device and then copy it from the device to the defined Opera Platform™ location.

There are several Symbian Series60 tools available for helping the development of Opera Platform™ applications. FExplorer is an advanced file explorer which gives access to the whole file system on the device. This can be used to copy the required files to the Opera Platform™ folder. Another useful application is "Memmon" which is a memory monitor tool for Symbian. The tool makes it possible to monitor the memory usage of the application, and can be used to detect memory issues with the applications.

When developing Opera Platform™ Applications on desktop with the Opera Browser, there are several tools which helps with development. The DOMConsole is an web extension to Opera which gives a detailed representation of the DOM tree. These tools are available here.

3. Deploying your first Opera Platform™ Project

A finished Opera Platform™ project consist of a directory which contains Opera Platform™ and the Opera Platform™ Application Framework. Each application has an own directory that is included in registeredServices.xml.

The file home.html in the top level directory defines the starting point of the framework. The content has to be installed on the device, and on start up, the Opera browser will look for this file in a specified location.

Deploying an Opera Platform™ project is a task of packaging the Opera Platform™ Application Framework and Application files into a installable package, that easily can be distributed and installed on the different phone models.

The different phone operating systems has their own install package format, but both has approximately the same functionality. The two formats which are supported by the Opera Platform™ SDK is the Windows Smartphone 2003 "CAB" format, and the Symbian Series60 "SIS" format.

There are free tools available which makes installable packages for both SIS and CAB, but some of these have compatibility issues. The Opera Platform™ SDK provides scripts to assist with creating install packages.

3.1. Packaging Your Application

3.1.1. Symbian Series60 SIS

Creating a SIS file is a process of first creating a package file which describes the archive and where to put the files, and then run this through Makesis. Makesis will read the package file and create a SIS archive from the specified files.

The sisgen tool which is available in the Opera Platform™ SDK does this process automatically. Launch the tool from the command line with the sis output file as the first argument, and the path to the Opera Platform™ project as the second argument.

Please note that sisgen uses a developer Symbian Unique Number developer, which only should be used for development, and not for distribution. A product specific Unique Number can be obtained from the Symbian web pages.

Windows:

 c:\perl sisgen.pl --help
 c:\perl sisgen.pl platform.sis platform\

Linux:

 $ ./sisgen.pl --help
 $ ./sisgen.pl platform.sis platform/

The tool will then create the package file for the specified directory. The files will be installed in the directory on the device which Opera is set to look for them. The package file and the directory will then be runned through the MAKESIS program, which will create the SIS file.

3.1.2. Microsoft Smartphone 2003 CAB

The CAB format is a Microsoft archiving format, and the Smartphone CAB installers consist of all the files packed in this format together with a setup.xml file that describes the install process. This structure and the setup.xml file is created automatically by Cabwiz, but to create installers for Opera Platform™ this process has to be done manually.

The cabgen tool is a part of Opera Platform™ SDK and does this process automatically. It creates the setup.xml file and puts all the files in the Opera Platform™ project into the required form. It then creates an input file to the traditional CAB archive tool Makecab, which again creates the CAB Installer. This tool use the Microsoft MAKECAB utility, which is only available for Windows.

Windows:

    c:\perl cabgen.pl --help

    c:\perl cabgen.pl -f platform.cab c:\Platform 
  

The CabGen tool will create a CAB Installer which installs the Opera Platform™ content files into the correct folder on the device.

3.2. Deploying Your Service

When the archive with Opera Platform™ Framework and the wanted Opera Platform™ Application is created, the deployment process consists of installing the archives on the device.

The procedure of installing Opera Platform™ and the required applications is described in the "Installing Opera Platform™" and "Installing Opera Platform™" section.

4. Building your first application

We will here walk through how to make a simple application with Opera Platform™. To start with, we will construct the application as a simple web application, independent of Opera Platform™. Then we will make it a full-flegded Opera Platform™ application.

The example application displays a "Fortune Cookie". This is just a short saying or proverb. The application will retrieve the fortune cookie from a web server and update the screen. It will also support updating the cookie when the user clicks a button.

4.1. Creating the HTML document

An Opera Platform™ application is started when an application HTML page is loaded. The application HTML document is no different from other HTML documents, with a few exceptions. We will get to those later. For now, we create a tiny skeleton html file like this:

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
  <head>
    <title>Fortune cookie</title>
    <script type="text/javascript">
    var FortuneApplication = function() {
      // do nothing.
    }
    </script>
  </head>
  <body>
    <h1>Hello world!</h1>
  </body>
</html>

When opened in the browser, the "Hello world!" header is displayed. The javascript function/class is also loaded, but does nothing.

4.2. Styling your application

Once you have created an application document, you are free to style it using all regular web techniques. CSS rules can be added in separate documents, or directly in the application document.

The new version of our application document now has a stylesheet attached, and we have added some html tags that we will later manipulate using javascript:

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
  <head>
    <title>Fortune cookie</title>
    <link 
      rel='stylesheet' type='text/css'
      media='handheld, screen, projection'
      href='FortuneCookie.css' />
    <script type="text/javascript">
      var FortuneApplication = function() {
        // do nothing.
      }
    </script>
  </head>
  <body>
    <h1>Fortune Cookie</h1>
    <p id="cookie" class="cookiecontainer">
      Fortune cookie appears here.
    </p>
    <p><button>Fetch</button></p>
  </body>
</html>

4.3. Creating your script

The next step is to create the javascript code that does the actual work of fetching data and displaying it. Throughout this example and in the Opera Platform™ SDK in general, the code is heavily object-oriented. The code should be fairly straightforward.

This code creates a class for fetching fortune cookies using XMLHttpRequest. Whenever a fortune is received, it calls a list of callback functions, whose responsibility it is to update the state of the page.

When the page is loaded, we set up the fortune fetching object and attach an event listener to the button, so we can refresh the fortune cookie by clicking the button. This code does not require Opera Platform™, and can be run in Opera.

One should be aware that testing this application needs to be done in the Opera Platform™ desktop build, which provides relaxed security that allows for cross-domain XMLHttpRequest.

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
  <head>
    <title>Fortune cookie</title>
    <!-- Add a handheld stylesheet
    <link 
      rel='stylesheet' type='text/css'
      media='handheld, screen, projection'
      href='FortuneCookie.css' />
    <script type="text/javascript">
      // A helper class that fetches a fortune from a web server. 
      // It notifies objects that have registered as listeners 
      // whenever it is updated.
      var FortuneFetcher = function(url) {
        this.url = url;  // url of fortunes
        this.conn = null;
        this.fortune = null;
        this.listeners = [];
              
        // Callback function used for xmlhttprequest.
        this.HttpCallback = function() {
          if (this.readyState==4) {
            if (this.status==200 || this.status==304) {
              this.fortuneFetcher.parseFortune(this.responseXML);
              this.fortuneFetcher.notifyListeners();
            } else {
              // If an error occurs here, we silently ignore it.
            }
          }
        }

        // Send a http request to retrieve a new fortune cookie
        this.update = function() {
          this.conn = new XMLHttpRequest();
          // save this, as "this" refers to the XMLHttpRequest
          // object when the callback is called
          this.conn.fortuneFetcher = this; 
          this.conn.onreadystatechange = this.HttpCallback ;
          
          /** The following line is a hack. It appends a random integer
           *  to the request as a GET parameter. This fools the webserver
           *  and browser into always returning a new fortune. Without it
           *  we could be getting cached data.
           */
          var fullUrl = this.url + "?" + Math.floor(Math.random()*100000);
          this.conn.open('GET', fullUrl, true);
          this.conn.send(null);
        }

        // Parse the xml returned from the http request.
        this.parseFortune = function(xml) {
          var e = xml.getElementsByTagName('fortune')[0];
          if (e) {
            // get the text of the fortune. Normally, this might grab 
            // more than just the data of the first childnode, but 
            // this will do for the example.
            this.fortune = e.childNodes[0].nodeValue;
          } else {
            this.fortune = "not able to load fortune!";
          }
        }

        // Adds a callback function that is called whenever a new 
        // fortune is received.
        this.addEventListener = function(func) {
          this.listeners.push(func);
        }

        // Calls all the registered callback functions, with the new 
        // fortune as the parameter.
        this.notifyListeners = function() {
          for (var n=0, func; func=this.listeners[n]; n++) {
            func(this.fortune);
          }
        }
      }

function displayFortune(f) {
  var container = document.getElementById('fortune');
  // delete everything in the fortune paragraph
  while (container.removeChild(container.childNodes[0] )) {}
  container.appendChild(document.createTextNode(f));
}

document.onload=function () {
  fetcher = new FortuneFetcher("http://oxine.opera.com/fortune.php");
  fetcher.addEventListener(displayFortune);
  fetcher.update();
  var e = document.getElementById('updatebutton');
  e.addEventListener('click', function() {fetcher.update()} , false );
}

</script>
  </head>
  <body>
    <h1>Fortune Cookie</h1>
    <p id="fortune" class="cookiecontainer">
      Fortune cookie appears here.
    </p>
    <p><button id="updatebutton">Fetch</button></p>
  </body>
</html>

4.4. Making your application an Opera Platform™ application

Now we will convert the web application to an Opera Platform™ application. This requires a few steps:

  1. Include the Opera Platform™ application framework files
  2. Include the Opera Platform™ global stylesheet
  3. Create a application definition for the application
  4. Define a application class
  5. Move the initialization of the application into the application class
  6. Add the application to the list of Opera Platform™ registered applications

4.4.1. Include Opera Platform™ javascript files

In order for Opera Platform™ applications to work properly, the Opera Platform™ javascript core files needs to be loaded. This is done by adding a script tag to the html header. The Opera Platform™ javascript core is called oxygen.js and is placed in the root Opera Platform™ directory.

4.4.2. Include the Opera Platform™ global stylesheet

Including the global Opera Platform™ stylesheet means that our application will inherit style rules from the system itself. This is good since we want to keep the look and feel of the system consistent. The application will work without the Opera Platform™ stylesheet though.

The Opera Platform™ stylesheet is included just like any other stylesheet. The stylesheet is called persistentStyles.css and is located in the /crown/persistentStyles/ directory.

4.4.3. Creating an application definition

An application definition file contains configuration data about an application. All applications must have an application definition in order to run. The application definition is kept in the same directory as the application itself, and must always be called "appdef.xml".

Our fortune application has the following application definition:

<?xml version="1.0"?>
<serviceDefinition>
  <name>Hello world</name>
  <guid>hw0123456789</guid>
  <version>0.1</version>
  <screenName>Hello!</screenName>
  <author>Opera Software ASA</author>
  <javascriptNS>Fortunes</javascriptNS>
  <icon>serviceIcon.png</icon>
  <menupriority>123</menupriority>
</serviceDefinition>

Full documentation of the application definition file can be found in chapter 5.9, but we will quickly cover the interesting bits of the file here:

name The name of the application
guid A uniqe identifier for the application. No two applications can have the same guid.
version The version of the application
screenName The name used for the menu entry for the application. This is typically quite short, so it can fit underneath an icon.
menupriority Where in an application menu the application icon will be shown. A higher number means a higher menu priority, meaning the icon will appear earlier in the menus. A negative value means that the application icon will not be displayed in the application menu.
icon The path to an image file to be used as an icon for the application.
author Identifies the author of the application.
javascriptNS The name of the javascript class in the application's javascript that will be instantiated when the application is loaded.

The most important piece of information in the application definition is the javascript namespace. We will refer to this as the "application class". When an Opera Platform™ application is loaded, the system creates an instance of the application class.

The reason for this is that when the Opera Platform™ application is loaded, Opera Platform™ creates an instance of the application class.

4.4.4. Define an application class

The application class is defined as any other class in javascript, but it inherits properties from the Opera Platform™ application prototype automatically. This means that there are several methods the application developer can implement in order to get access to Opera Platform™ functionality. Some examples are methods to receive messages from other Opera Platform™ applications, receiving keypress events from joysticks and softkeys, as well as making menus and so on.

The most important method to implement is the "OnMessageReceived" method. Whenever a message is sent to the application, this method is called with the message as a parameters. A message is a container that can contain one or more message members.

For our simple fortune cookie application, the most important member is the "Init" member. This is sent to the application when it has been loaded. It is intended to be the place in an application to initialize resources and so on. In our regular web application, we used the onload event to initialize, now we move that data into the onMessageReceived handler.

4.4.5. Adding application to registeredapps.xml

Finally, the application is ready to run. The only step that remains is to add it to Opera Platform™'s list of registered applications. This file is called registeredapps.xml. The entry in registeredapps must point to the main application document.

An entry in registeredapps.xml looks like this:

<url serviceid='729' shortname='Fortunes' >Fortunes/index.html</url>

The service id property must be unique in the registeredapps file.

4.4.6. Putting it all together

The final version of the application document contains a full-flegded Opera Platform™ application:


<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
  <head>
    <title>
      Fortune cookie
    </title>
    <link rel='stylesheet' type='text/css' media='handheld, screen, projection' href='FortuneCookie.css' />
    <link rel='stylesheet' type='text/css' media='screen,handheld,projection' href='../chrome/persistentStyles/persistentStyles.css' />
    <!-- Add the Opera Platform™ Core -->
    <script type="text/javascript" src="../oxygen.js"></script>
    <script type="text/javascript">    
      /**
       * Main application class. supports displaying and refreshing fortunes.
       */
      var Fortunes = function() {

        this.fetcher = null;
        
        /**
         * Handle all incoming messages.
         *
         */         
        this.onMessageReceived = function(message) {        
          // If the message contains an Init member.
          if (message.containsMembers('Init') ) {
            this.fetcher = new FortuneFetcher("http://oxine.opera.com/fortune.php");
            this.fetcher.addEventListener(this.displayFortune);    
            var e = document.getElementById('updatebutton');
            e.app=this;
            e.addEventListener('click', function() {this.app.refreshFortune() }, false );
            this.refreshFortune();
          }
        }

        /**
         * Inserts the fortune cookie into the DOM.
         */        
        this.displayFortune = function(fortune) {
          var container = document.getElementById('fortune');
          while (container.removeChild(container.childNodes[0] )) {} // delete everything in the fortune paragraph
          container.appendChild(document.createTextNode(fortune));        
        }
        
        /**
         * Refresh fortune cookie
         */
        this.refreshFortune = function() {
          this.fetcher.update();
        }
       
      }

      /**
       * A helper class that fetches a fortune from a web server. It notifies
       * objects that have registered as listeners whenever it is updated.
       *
       */
      var FortuneFetcher = function(url) {
        this.url = url;  // url of fortunes
        this.conn = null;
        this.fortune = null;
        this.listeners = [];
              
        /**
         * Callback function used for xmlhttprequest.
         *
         */
        this.HttpCallback = function() {
          if (this.readyState==4) {
            if (this.status==200 || this.status==304) {
              this.fortuneFetcher.parseFortune(this.responseXML);
              this.fortuneFetcher.notifyListeners();
            } else {
              // If an error occurs here, we silently ignore it.
            }
          }          
        }
              
        /** 
         * Send a http request to retrieve a new fortune cookie
         */
        this.update = function() {
          this.conn = new XMLHttpRequest();
          this.conn.fortuneFetcher = this; // save this, since "this" is wrong when the callback is called.
          this.conn.onreadystatechange = this.HttpCallback ;
          
          this.conn.open('GET', this.url, true);
          this.conn.send(null);
        }

        /**
         * Parse the xml returned from the http request.
         */
        this.parseFortune = function(xml) {
          var e = xml.getElementsByTagName('fortune')[0];
          if (e) {
            // get the text of the fortune. Normally, this might grab more then
            // just the data of the first childnode, but this will do for the
            // example.
            this.fortune = e.childNodes[0].nodeValue
          } else {
            this.fortune = "not able to load fortune!";
          }          
        }

        /**
         * Adds a callback function that is called whenever a new fortune
         * is received.
         */
        this.addEventListener = function(func) {
          this.listeners.push(func);
        }

        /**
         * Calls all the registered callback functions, with the new 
         * fortune as the parameter.
         */
        this.notifyListeners = function() {
          for (var n=0, func; func=this.listeners[n]; n++) {
            func(this.fortune);
          }
        }      
      }


</script>

  </head>
  <body>
    <h1>
Fortune Cookie
    </h1>
<p id="fortune" class="cookiecontainer">
This is where the fortune cookie will appear.
</p>
<hr>
<p>
<button id="updatebutton">Fetch</button>
</p>
  </body>
</html>

5. Opera Platform™ applications

The applications in the Opera Platform™ SDK come in two different flavors: System applications and regular applications.

5.1. System applications

System applications are applications that provide housekeeping or low-level helper functionality that can be used by regular Opera Platform™ applications. These are typically loaded permanently into memory.

5.2. Applications

Applications live in separate global objects, in javascript terminology known as window objects. These applications can reside locally, or in different domains.

These applications can set up event listeners for broadcast messages, as specified by the Web Applications 1.0 specification. Additionally, these applications can create and send messages, thereby providing a loose coupling between the framework and other applications. Typically the applications reside in directories on the devices filesystem, and consist of XHTML, CSS, javascript, images, configuration and other resources. The application is described in the application description file.

5.3. CSS Styling rules

Styling Opera Platform™ applications is an optional feature of the Opera Platform™ SDK. The application developer can either leave the responsibility to the Opera Platform™ Application Framework, or the developer can make all styling in the application. A combination of the two methods can also be chosen. By linking to the stylesheet chrome/persistentStyles/persistentStyles.css a number of very basic styles are predeclared.

In addition to normal CSS styling rules, authors should be aware of Opera's Extensible Rendering Architecture, ERA. Descriptions of how these rendering modes work are covered in two articles; MyOpera developer community: Making Small Devices Look Great and Opera's rendering modes.

In the Opera Platform™ Application Framework, the topmost window is rendered in SSR-mode, while any applications are running inside an IFRAME, and are thus rendered in regular screen rendering mode.

5.4. Icons, themes and branding

When an Opera Platform™ SDK application is run, styling rules from the chosen user theme will be automatically applied to the service. The location of the default theme is determined in the file core/textStringsMainDocument. Example:

var o2_startupsetting_o2_theme='./themes/baseTheme/style.css';

Default application icons are stored in the chrome/icons folder, and are PNG images with the dimension 64×80 pixels that hold multiple images. The location of the icon for an application is determined by the icon element of a appdef.xml file.

Application icon layout

  1. The application grid active image: 40×42 pixels. This icon is placed in the top left corner of the icon file.
  2. The application grid inactive image: 40×42 pixels. This icon is placed in the bottomleft corner of the icon file.
  3. The list view active image. 16×17 pixels. This icon is placed in the top right corner of the icon file.
  4. The list view inactive image16×17 pixels This icon is placed in the bottom right corner of the icon file.

A sample template for Adobe Photoshop containing a sample icon is available. This template file contains preset guidelines that assists in creating icons.

5.5. Application loading and unloading

Normally, the Opera Platform™ Application Framework will dynamically load and unload applications as needed, and will only keep one regular application in memory at one given time. If needed, this behavior can be changed, and an application can be made persistent in memory by adding type="persistentApp" to registeredapps.xml. Be aware that keeping applications persistent in memory should be done only after careful considerations, because devices typically have limited memory capabilities.

5.6. Memory

Profiling javascript's memory usage is very difficult to do in a desktop browser. Browsers generally don't guarantee that they release any used memory to the operating system. As such, it is highly recommended to do the actual memory profiling on real target devices. On devices we need to observe the available memory using a tool. In addition, the Opera Platform™ DOM Interface provides two methods for checking memory usage on the device from javascript:

interface System {
  ...
  readonly attribute unsigned long long totalMemory;
  readonly attribute unsigned long long freeMemory;
};

5.7. CPU

Observing the CPU usage of an application on the desktop usually does not provide information directly transferable to mobile devices. The CPU usage of an application on the desktop might be negligible, while it has a significant impact on a mobile device.

While there may not always be good direct methods to measure CPU usage, this is most easily observed with visual debugging: Applications will feel unresponsive and slow once CPU usage is higher than desired.

5.8. Network access

The Opera Platform™ DOM Interface provides the neccessary means to check the availability of networks such as GPRS, GSM and similar. The getInterfaceStatus(interfaceName) call returns a short in the form of a bit mask. Exact information about this bitmask is provided in the Opera Platform™ DOM Interface specification.

In addition to checking individual networks, one can attach event listeners to the interfaceChanged event on the device object.

interface InterfaceEvent : Event {
  readonly attribute DOMString          interface;
  readonly attribute unsigned short     status;
  void initInterfaceEvent(in DOMString typeArg, 
                          in boolean canBubbleArg, 
                          in boolean cancelableArg, 
                          in DOMString interfaceArg, 
                          in unsigned short statusArg);

  // For DOM Level 3 support
  void initInterfaceEventNS(in DOMString namespaceURI,
                            in DOMString typeArg, 
                            in boolean canBubbleArg, 
                            in boolean cancelableArg, 
                            in DOMString interfaceArg, 
                            in unsigned short statusArg);
}

5.8.1. Internet Connection Strategy: Series 60

When Opera Platform™ connects to the Internet, the following strategy is used:

  1. First, try the APN with highest priority
  2. If this is not successful, Opera Platform™ asks the user
  3. If connecting with the APN given in 2) is successful, this APN will be used, if still present.
  4. If the previous APN is not present, the user will be asked again

If only one APN is defined, the user will never be asked, and similarily, if the APN with the highest priority works, the user will never be asked.

If the underlying operating system returns an error message, the user will be asked for another access point.

Should the user have set up or selected an APN where external access is not available, for instance an MMS APN, the application developer can initiate an APN reset, by making a call to the opera.resetAPN() method. After this method has been called, Opera should again ask which access point to use when a network connection is required.

Note that this strategy only applies to Symbian/Series 60 devices, as Windows Smartphone devices have a different connection strategy where the wanted AP is specified outside of the application.

5.9. Menus

Menus in Opera Platform™ Applications are most easily created using the built-in Menu API. Creating a menu is done in the Init event of an application:

5.9.1. Creating menus

this.createMenu();

If a developer wants to create a menu with predefined menu contents, the path to and name of the menu file is included as an argument:

this.createMenu('menufile.xml');

When the menu has been created, a global menu object named o2_menu is available, and you can control the menu's behavior and content by calling the relevant methods for the menu.

5.9.2. Menus and IDs

When a menu has been created, an initial menu with the id main is automatically created, and it can be queried and acted upon using regular dot notation.

5.9.3. Adding menu items

To add new items to a menu, the method addChild() is called on the menu in question. Adding a menu item to the root menu is done this way:

o2_menu.main.addChild(String label, String ID, new O2_Command(function))

label is the menu label. ID is the id of the menu item, that can be used for later processing.

The O2_Command is a new instance of a command that should be associated with the menu. An example call to create a menu entry can thus look like this:

o2_menu.main.addChild("Test item","test_item_1",
                       new O2_Command(function(){alert('Test item clicked')} )

5.9.4. Adding and changing actions

If a menu has been created from an XML file, it might not have any action associated with it. In that case, the action for a named menu entry can be changed/added using the o2_menu.setActionOnItem() method:

o2_menu.setActionOnItem(new O2_Command(function), String ID)

5.9.5. Getting a named menu item

To get a handle to a menu entry, the getItem() method is used:

o2_menu.getItem(String ID)

ID is a reference to the ID of the menu item for which the handle is wanted.

5.9.6. Disabling a menu entry

A menu entry can be disabled using the disable() method on a menu item:

o2_menu.getItem(String ID).disable()

5.9.7. Removing a menu entry

A menu entry can be removed using the removeChild() method on a menu item:

o2_menu.getItem(String ID).removeChild(String ID);

5.9.8. Dynamic menus

A developer can have different menus, for instance for different views:addMenu() method:

o2_Menu.addMenu(String MenuID)

MenuID is the ID for the given menu. This can later be addressed by regular dot-notation:

o2_menu.addMenu('test_menu');
o2_menu.test_menu.addChild("test item","test_item", 
                           new O2_Command(function(){alert('test')});

Switching to the new menu is done by making a call to the o2_menu.setActiveMenu() method:

o2_menu.addMenu('view_2'); // create a new menu
o2_menu.view_2.addChild("test item","test_item", 
                           new O2_Command(function(){alert('test')});
o2_menu.setActiveMenu('view_2); // The active menu will now be 'view_2'

5.9.9. Submenus

Adding submenus is achieved by adding child menus to a given menu entry using regular dot notation, referencing the id of the menu entry you want to add child entries to:

o2_menu.main.addChild('Open sub','entry_1',
                      new O2_Command(function(){alert('test')});
// The following code will create a submenu item as a child of 
// 'entry_1'
o2_menu.main.entry_1.addChild(('Submenu item','entry_2',
                      new O2_Command(function(){alert('Submenu')});

5.10. Dialogs

Dialogs, such as warning and information dialogs in the Opera Platform™ Application Framework are created using the built-in dialog API. There is a dialog demo application included with the Opera Platform™ SDK that can be examined.

Creating a dialog is done by making a call to this.createDialogController(). This will create the dialog as a singleton, making it available to the developer in the o2_dialogs object

The default dialog type is an informational dialog.

this.createDialogController()

After the dialog singleton has been created, a dialog is added by calling the o2_dialogs.addDialog() method.

5.10.1. Info dialogs

A simple information dialog can be created this way:

var infoDialog=o2_dialogs.addDialog('test_info');
infoDialog.type='info';
infoDialog.text='Some text';

This will create an info dialog with the label Some text.

5.10.2. Warning dialogs

Warning dialogs behave exactly like informational dialogs, except they use different default styling.

var infoDialog=o2_dialogs.addDialog('test_warning');
infoDialog.type='warning';
infoDialog.text='A warning';

5.10.3. Error dialogs

Error dialogs behave exactly like info and informational dialogs, except they use different default styling.

var infoDialog=o2_dialogs.addDialog('test_error');
infoDialog.type='error';
infoDialog.text='An error has occured';

5.10.4. Question dialogs

A slightly more complex dialog, is the question dialog. This dialog provides two options, for instance Yes and No, or OK and Cancel. The following example will create a dialog named test_question with the question Are you really sure?, with the options Yes and No:

o2_dialogs.addDialog(
  'test_question', 
  'Are you really sure?', 
  'question', 
  'Yes', 
  'No', 
  new O2_Command(function(){alert('false')}), 
  new O2_Command(function(){alert('true')})
);

5.10.5. Input dialogs

The input dialogs automatically creates text input fields when created. When the dialog is closed, any input values are available in an array named o2_dialogs.inputValues. The labels for the text inputs are given as the last argument to the addDialog method:

 2_dialogs.addDialog(
  'test_inputs', 
  'First and last name, please', 
  'input', 
  'Ok test', 
  'Cancel Test', 
  new O2_Command(function(){alert('false')}), 
  new O2_Command(function(){alert(o2_dialogs.inputValues.join('\n\n'))}),
  ['your first name:', 'your second name:']
);

5.10.6. Showing dialogs

To display a dialog, a call is made to the dialog's show() method. The example below shows how to display the dialog from the previous example:

o2_dialogs.test_inputs.show()

5.11. Setting navigation bar labels

To set default values for the navigation bar labels, a developer can call the o2_menu.setPriority1Text and o2_menu.setPriority2Text:

o2_menu.setPriority1Text( text );
o2_menu.setPriority2Text ( text );

If the developer omits to set the navigation bar text, these texts default to Options and Back respectively. The default texts can be overridden in the file library/textStringsMenu.js

If the menu is set to close with the same keyboard shortcut as it is opened, the text for this label can be set using o2_menu.setCancelText():

o2_menu.setCancelText(String text)

5.11.1. Menu button strategy

An application developer can choose to close the menu with the same key it is opened with by calling o2_menu.closeWithOpenButton(true):

o2_menu.closeWithOpenButton(boolean)

If this is set to false (default), the menu will have a separate cancel button.

5.12. The Navigation Bar

The contents of the navigation bar in Opera Platform™ can be set dynamically by passing messages using utilities.sendInfoToNavigationbar():

utilities.sendInfoToNavigationBar( navbarDestination, content );

The navbarElement is one of four:

The utilities.sendInfoToNavigationbar accepts setting multiple values at once. The following example will set both softkey texts by passing one message:

utilties.sendInfoToNavigationBar( "priority1Text", "Example 1", "priority2Text","Example 2" )

5.13. The History Stack

In the Opera Platform™ Application Framework, the purpose of the history stack is to create a stack of functions that are called when you go back in history, so an application developer can control in which state an application is put when the user presses the "Back" key.

Adding something to the history stack is done by making a call to the method addToHistoryStack( <Function> function, <mixed> arguments ) where function is a function reference, and arguments is a variable number of arguments that will be passed to the function when it is called. Calling the function at the top of the history stack is done by making a call to callLastFromHistoryStack(). Note, this will not remove the function from the stack.

When the back button is pressed, the following happens:

  1. The topmost element on the history stack is removed
  2. The new topmost element on the stack is executed.

5.13.1. Explicitly removing elements from the history stack

If a developer needs to explicitly remove the topmost element on the stack, this is done by calling the method popHistoryStack().

5.14. Localizing the Opera Platform™ Application Framework

Certain parts of the Opera Platform™ Application Framework can be localized by editing the appropriate localization documents. These documents are all javascript files containing a number of variable declarations.

5.14.1. Softkey menus

The localizable strings in the application-level softkey menus is localized by editing the file /core/textStringsMainDocument. Below are the default contents of this file.

/* ServiceManager */
// All occurences of 0xa0 are used to prevent reflow problems
var O2_Text_ServiceManager_LoadingService='Loading Service ...';
/* Adapter */
/* WMSmartphone2003 */
var O2_Text_Adapter_WMSmartphone2003Profile_CommandPriority1Frontpage='Menu';
var O2_Text_Adapter_WMSmartphone2003Profile_CommandPriority2Frontpage='Start';
var O2_Text_Adapter_WMSmartphone2003Profile_CommandPriority1RegularService=String.fromCharCode(0xa0); 
var O2_Text_Adapter_WMSmartphone2003Profile_CommandPriority2RegularService='Start';
/* Desktop */
var O2_Text_Adapter_DesktopProfile_CommandPriority1Frontpage='Menu';
var O2_Text_Adapter_DesktopProfile_CommandPriority2Frontpage='Camera';
var O2_Text_Adapter_DesktopProfile_CommandPriority1RegularService=String.fromCharCode(0xa0);
var O2_Text_Adapter_DesktopProfile_CommandPriority2RegularService='Back';
/* Series 60 */
var O2_Text_Adapter_Serie60Profile_CommandPriority1Frontpage='Menu';
var O2_Text_Adapter_Serie60Profile_CommandPriority2Frontpage='Camera';
var O2_Text_Adapter_Serie60Profile_CommandPriority1RegularService=String.fromCharCode(0xa0);
var O2_Text_Adapter_Serie60Profile_CommandPriority2RegularService='Back';

5.14.2. The application grid

The localizable strings in the application grid are localized by editing the file /AppGridNew/textStringsAppGrid.js. Below are the default contents of this file.

var O2_Text_AppGrid_Menu_MoveToFolder='Move to folder';
var O2_Text_AppGrid_Menu_MoveToFolderRootName='Root';
var O2_Text_AppGrid_Menu_NoMenuItemIsSelected='No menu item is selected';
var O2_Text_AppGrid_Menu_NameForNewFolder='The name of the new folder:';
var O2_Text_AppGrid_Menu_NoMenuEntryIsSelected='No menu entry is selected';
var O2_Text_AppGrid_Menu_ViewTypeGrid3='Grid 3';
var O2_Text_AppGrid_Menu_ViewTypeGrid4='Grid 4';
var O2_Text_AppGrid_Menu_ViewTypeList='List';
var O2_Text_AppGrid_Menu_ApplicationCanNotBeDeleted='This application can not be deleted';
var O2_Text_AppGrid_Menu_DefaultPriority1Text='Options';
var O2_Text_AppGrid_Menu_DefaultPriority2Text='Back';
var O2_Text_AppGrid_Menu_InteractionPriority1Text='Ok';
var O2_Text_AppGrid_Menu_InteractionPriority2Text='Cancel';
var O2_Text_AppGrid_Menu_ThisWillDeleteAllSettings='This will delete all your settings';

5.14.3. URL Manager

The localizable strings in the URL manager are localized by editing the file /URLManager/textStringsURLManager.js. Below are the default contents of this file.

var O2_Text_URLManager_Menu_NewBookmarkName='Name of the bookmark:';
var O2_Text_URLManager_Menu_NewBookmarkURL='Address for the new bookmark:';
var O2_Text_URLManager_Menu_NewBookmarkInfo='(http://www. will be added automatically if protocol is missing)';
var O2_Text_URLManager_Menu_NoBMSelected='No bookmark selected';
var O2_Text_URLManager_Menu_DefaultPriority1Text='Options';
var O2_Text_URLManager_Menu_DefaultPriority2Text='Back';
var O2_Text_URLManager_Menu_InteractionPriority1Text='Ok';
var O2_Text_URLManager_Menu_InteractionPriority2Text='Cancel';

5.14.4. Menu strings

The localizable strings in the application menus are localized by editing the file /library/textStringsMenu.js. Below are the default contents of this file.

// menus
var O2_Text_MenuClass_defaultPriority1Text='Options';
var O2_Text_MenuClass_defaultPriority2Text='Back';
var O2_Text_MenuClass_cancelText='Cancel';
var O2_Text_MenuClass_openText='Select';
var O2_Text_MenuClass_interactionPriority1Text='Ok';
var O2_Text_MenuClass_interactionPriority2Text='Cancel';

// dialog
var O2_Text_DialogClass_defaultPriority1Text='Options';
var O2_Text_DialogClass_defaultPriority2Text='Back';
var O2_Text_DialogClass_cancelText='Cancel';
var O2_Text_DialogClass_openText='Ok';

6. Reference

6.1. O2_OutboundMessage

An application developer never needs to construct this class directly. All the work is done by O2_UserServicePrototype.createMessage().

Method summary

class O2_OutboundMessage {
  void addMember(<string> memberName, <mixed> data)
  void addReceivers(<number> argument1, argument2, ...)
  void send()
}
void addMember(<string> memberName, <mixed> data)
Will assign member data to a member in this message. The content of data can be of type: DOMElement, DocumentFragment, DOMTextNode, String,Number, Array or Object. The format of the data will be persisted to the receiver. This will be stored in a keyvalue store where memberName is the key.
void addReceivers(<number> argument1, argument2, ...)
If an application knows the application id(s) of the receivers, it's possible to attach the receivers here. This function iterates the arguments list so it should be called as addReceivers(receiver1, receiver2, ...).
void send()
Will send this message to all applications in the receiver list. If no receiver list is present the message will go to all applications that subscribes to this member.

6.2. O2_InboundMessage class constructor

An application developer never needs to construct this class directly. This object is passed to the message handler when receiving a message.

Method summary

class O2_InboundMessage {
  <boolean> object containsMembers(<string> argument1, argument2, ...)
  <mixed> object getMember(<string> memberName)
  number getSenderId()
}
<boolean> object containsMembers(argument1, argument2, ...)
Check if the message contains the given list of member names. Returns true or false depending on the contained members. This function iterates the arguments list so it should be called as containsMembers(memberName1, memberName2, ...)
<mixed> object getMember(<string> memberName)
Gets the related member data for the member with a given name. The content of data can be of the following types: DOMElement, DocumentFragment, DOMTextNode, String or Number. The format of the data will be persisted to the receiver. MemberName must be unique or it will be overwritten.
number getSenderId()
Returns the sender id of an inbound message. This sender id can be used to direct O2_OutboundMessage for replies to the sender.

6.3. O2_UserServicePrototype class constructor

This is the constructor for the prototype of the created application . There is no need to assign this prototype directly, the framework will do it for you when it creates an instance of your application.

Method summary

class O2_UserServicePrototype {
  <O2_OutboundMessage> object createMessage()
  void sendMessage(<string> memberName, <mixed> data=null, <int> receiver='')
  void goToFullScreen()
  void leaveFullscreen()
  void addToHistoryStack(<function> function, <mixed> parameter 1, ...<mixed> parameter n)
  void callLastFromHistoryStack()
  void createMenu(<string> url='')
  void createDialogController(<string> url='')
  "abstract" void onBack()
  "abstract" void onBack()
  "abstract" void onBlur()
  "abstract" void onMessageReceived(<O2_InboundMessage>)
  "abstract" void onFocus()
  "abstract"; void onKeypress(<string> keyName)
  void popHistoryStack()
   void sendDebugInfo(string, priority)
};
<O2_OutboundMessage> object createMessage()
Creates a message that can be sent to other applications
void sendMessage(<string> memberName, <mixed> data=null, <int> receiver='')
The short way to create and send a message, if the message contains only one or none member.
void goToFullScreen()
This call removes the navigationbar from the screen.
void leaveFullscreen()
This call brings back the navigationbar.
"abstract" void onBack()
This function is "abstract" and can be overwritten by the application developer. The framework will call this function each time the user press the back button. This function will decrement the history point if the history point is 1 or higher. The history point can be set by sending a SetHistoryPointTo message to the framework. When the value gets to 0 the framework should navigate back to the frontpage.
"abstract" void onBlur()
This function is "abstract" and can be overwritten by the application developer. The framework will call this function when the application gets removed from the view.
"abstract" void onMessageReceived(<O2_InboundMessage> msg)
This function is "abstract" and should be overwritten by the application developer. The framework will call this function each time a member is sent to this application. Messages can be sent either if directly targeted at this application or if the applicationhas subscribed to the member. The application developer should query the incoming message for member data.
"abstract" void onFocus()
This function is "abstract" and can be overwritten by the application developer. The framework will call this function when an application is loaded into the view.
"abstract" void onKeypress(<string> keyName)
This function is "abstract" and can should be overwritten by the application developer if it needs to observe the users keypresses. The only argument recieved is the keyName of the pressed key. The keyNames can be of the following types: CommandPriority1, CommandPriority2, JoystickLeft, JoystickUp, JoystickRight, JoystickDown, JoystickGo. The only key that always will be sent to the application is the CommandPriority1. To get a callback on the other keys you must call the utilities.requestActivateKeypresses("keyName1", "keyName2", ...) in the onFocus(). The keyName can be of the following types: CommandPriority2, JoystickLeftRight, JoystickUpDown, JoystickGo
void popHistoryStack()
This will remove the topmost item from the history stack. Note that this will neither return the history stack item, nor will it execute the item when executed.
void sendDebugInfo(string, priority)
If the debug application is install, this will send string as a debug message to the debug application, with 0 <= priority <= 6, where 0 is the lowest priority and 6 is the highest.

6.4. O2_callAfterInstantiation

Compiled applications in the Opera Platform™ Application Framework can be extended by declaring a function named O2_callAfterInstantiation at the end of the last script tag in an application. Example:

O2_callAfterInstantiation=function(){

/* A constructor function to extend the compiled application*/} 

Please note that there is no need to call this function, as this will be handled by the Opera Platform™ Application Framework.

6.5. guidList.xml

The GUIDList is located in and read by the device application and contains a reference to the native applications running on the device. Other applications can query the Application manager with the "insert name of Request GUID" and receive a "insert name of Response GUID msg" containing this GUIDList.

The interface for this is described in RequestGUIDList and ResponseGUIDList.

<?xml version="1.0" encoding="UTF-8"?>
<guidList>
  <item>
    <screenName>Log</screenName>
    <guid>103</guid>
    <launchName>MissedCallHandler</launchName>
    <icon>../theme1/img/appgridIcon4.png</icon>
    <menupriority>-1</menupriority>
  </item>
</guidList>
    

Elements of item:

Element

Description

screenName

The name of this native application suitable for showing on the screen.

guid

Required element containing the identifier for the application

menuPriority

A priority indicating the visual priority in appGrid.

icon

Optional element containing the URI of the icon to use in the application grid and list view.

6.6. menu.xml

Menus in appGrid can be defined using this format.

<?xml version="1.0" encoding="UTF-8"?>
<menus>
  <menu name='main'>
    <entry value='ref_1'>first entry</entry>
    <entry value='submenu_1'>a submenu</entry>
    <entry value='ref_2'>second entry</entry>
    <entry value='ref_3'>third entry</entry>
  </menu>
  <menu name='submenu-1'>
    <entry value='ref_4'>first entry in submenu</entry>
  </menu>
>/menus>
    

Elements of menus:

Element

Description

menu

Describes a menu. This element must have a required name attribute with a unique name identifying the menu. The root menu needs to have the name set to "main"

entry

A entry in the menu. The entry will be a property from a menu with the name from the attribute value. That means for the above example the first entry will be o2_menu.main.ref_1 and the first entry in the submenu o2_menu.main.submenu_1.ref_4.

6.7. uriList.xml

The uriList contains a list of bookmarks suitable for showing in the appGrid.

The interface for this is described in RequestURIList and ResponseURIList.

<?xml version="1.0" encoding="UTF-8"?>
<uriList>
  <item>
    <screenName>Opera</screenName>
    <uri>http://www.opera.com</uri>
    <guid>100</guid>
    <icon>../theme1/img/Opera.png</icon>
    <menupriority>490</menupriority>
  </item>
</uriList>

Elements of item:

Element

Description

screenName

The name of this native application suitable for showing on the screen.

uri

The uri to launch

guid

An unique identifier

icon

Optional element containing the icon to use in application grid

menuPriority

A priority indicating the visual priority in appGrid

6.8. registeredApps.xml

This file is located in the root directory and contains an entry for each application that should be loaded.

<?xml version="1.0" encoding="UTF-8"?>
<services>
  <url serviceid="200">fortuneService/fortuneService.html</url>
  <url serviceid="201" activeFrontpage="true" type="persistentService">Frontpage/newFrontpage.html</url> 
</services>
    

Elements of services:

Element

Description

url

An entry indicating an application. Must have an unique number as the id of the application. In the future this id will be assigned by the system that will be persisted. Can have an optional activeFrontpage attribute if this is a frontpage application. The value of this element should give a pointer to the location of the application's HTML file. The optional type attribute can have one value, persistentService. When this attribute is present, the Opera Platform™ Application Framework will not dynamically unload the application.

6.9. appdef.xml

The appdef.xml file resides within the directory of a given application, and contains the Application definition for the application, and describes how the application expects to interact with the framework and other applications running on the device. This file is loaded by the framework, which sends a discovery message to the framework. A typical application file looks like this:

<?xml version="1.0"?>
 <serviceDefinition>
  <name>GoogleSearch</name>
  <guid>8f74c420-cc29-11d9-8cd5-0800200c9a66</guid>
  <screenName>Google</screenName>
  <author>Opera Software ASA</author>
  <javascriptNS>GoogleSearch</javascriptNS>
  <generatedEvents></generatedEvents>
  <supportedEvents></supportedEvents>
  <icon>../theme1/appgridIcons/appgridIcon14.png</icon>
  <menupriority>665</menupriority>
 </serviceDefinition>
    

Elements of serviceDefinition:

Element

Description

name

Required element containing the name of the application.

guid

Required element containing the application identifier. Needs to be unique and should be generated with a GUID tool.

screenName

Required element containing the name of the application as shown to the user

javascriptNS

Required element containing the name of the constructor function for this application. A helper function will create a new instance of this constructor and attach the O2_ServicePrototype as the prototype of the new instance of this constructor.

generatedEvents

Optional element containing a comma separated list of messages generated by this application. An application can not send messages not previously listed here.

supportedEvents

Optional element containing a comma separated list of messages this application can handle.

icon

Optional element containing a URI of an icon to use in application grid. The URI can either be a relative or absolute URI.

menupriority

Optional element describing the priority of this application in the application grid. Setting the menu priority to -1 will hide the application from the application grid.

6.10. Message members

Messages lets the applications in the Opera Platform™ Application Framework communicate with each other. You can receive messages by subscribing to them with an entry in the appdef.xml file for a given application. Messages are received with the onMessageReceived callback in your application and created with the createMessage method.

Storing state example

var stateData = "<prefs><pref key='subscribedFeeds' expiresAt='" 
stateData += new Date(2010, 0, 1).toGMTString() + "'>" + data + "</pref></prefs>";
var msg = myService.createMessage();
msg.addMember("StoreStateRequest", stateData);
//msg.addMember("SetStateRequest", "subscribedFeeds=" + data);
 msg.send();

Reading state example.

var msg = myService.createMessage();
msg.addMember("GetStateRequest", "readItems");
msg.send();

this.onMessageReceived = function(message) {
  if (message.containsMembers("GetStateResponse")) {
    var data = message.getMember("GetStateResponse");
    var begin = -1, key = "", val = "";
    if (data != "") {
      begin = data.indexOf("=");
    }
    if (begin > -1) {
      key = data.substr(0, begin);
      val = data.substr(begin + 1, data.length);
    }

    switch (key) {
      case "subscribedFeeds":
        var subscribedFeeds = [];
        subscribedFeeds = val.split(myDelimiter);
        break;
      defalt:
      	alert("Received unknown state key");
    }
  }
}

In the future we should give a simpler API for reading state information

Init
Description
This messages is sent to the application after it's registered with core
SetStateRequest
Description
Will assign the given value to the key in state store. The key will stay in the store until Opera is restarted.
Type
String
Example
mykey
See Also
StoreStateRequest, GetStateRequest, DeleteStateRequest
GetStateRequest
Description
Get data for a given key
Type
String
Example
mykey
Returns
GetStateResponse
GetStateResponse
Description
Returns state information for a given key. If key isn't found the value will be empty
Type
String
Example
foundKey=value
See Also
GetStateRequest
DeleteStateRequest
Description
Delete data for a given key
Type
String
Example
deleteThisKey
StoreStateRequest
Description
Will store the given state and persist it between restarts of the device
Type
Element
Example
<prefs>
  <pref key="keyName1" expiresAt="[gmtTime]">value1</pref>
  <pref key="keyName2" expiresAt="[gmtTime]">value2</pref>
</prefs>
SetHistoryPointTo
Description
This is sent to the application responsible for history managment and tells the current navigation level for the application. The callback function onBack will be called each time this level is decreased by the user (pressing the back button).
Type
Number
Example
1
UpdateClockAndDate
Description
General Information about Clock and Date. Broadcasted.
Type
String
Example
hour;minutes;day;short name of the day;long name of the day;month;short name of the month; \ long name of the month;year
UpdateSignalStrength
Description
A Number for the Signal Strength between 0 and 6. Broadcasted
Type
Integer
UpdateBatterySignal
Description
A Number for the Signal Strength between -2 and 9.-2 for Mains and -1 for Charging. Broadcasted
Type
Integer
UpdateMissedCalls
Description
A Number for the missed Calls
Type
Integer
RequestServiceList
Description
To ask the System for a List with all loaded Services
Type
Empty
ResponseServiceList
Description
The Response to the RequestServiceList
Type
DOM Element
Example
<serviceList>
  <item>
    <uniqueNr>Unique Number</uniqueNr>
    <screenName>The Name for the Service</screenName>
    <menupriority>A Number to set the Position in a Menu</menupriority>
    <icon>Path to a Icon</icon>
  </item>
  <item>...</item>
</serviceList>
RequestGUIDList
Description
To ask the System for a List with all available Applications
Type
empty
ResponseGUIDList
Description
The Response to the RequestGUIDList
Type
DOM Element
Example
<guidList>
  <item>
    <screenName>The Name for the Application</screenName>
    <confidence>A Number</confidence>
    <icon>Path to a Icon</icon>
    <menupriority>A Number to set the Position in a Menu</menupriority>
    <guid>Unique Number for that Application</guid>
  </item>
  <item>...</item>
</guidList>
See Also
OpenApplication
OpenApplication
Description
Requests an application that has sent a GUID list to open an application. The content is the value of the guid element for that application.
Type
String
See Also
ResponseGUIDList
RequestURIList
Description
To ask the System for a List with all Bookmarks
Type
empty
ResponseURIList
Description
The Response to the RequestURIList
Example
<uriList>
  <item>
    <guid>Unique Number for that Bookmark</guid>
    <screenName>The Name for the Bookmark</screenName>
    <uri>The url for that Bookmark</uri>
    <icon>Path to a Icon</icon>
    <menupriority>A Number to set the Position in a Menu</menupriority>
    <confidence>A Number</confidence>
  </item>
  <item>...</item>
</uriList>
DisplayService
Description
Displays a specific service. The content is the unique service ID.
Type
Integer
Example
var message=this.createMessage(); // inside the Service Constructor
  message.addMember('DisplayService', id from Service as Integer);
  message.send();

6.11. Utilities

The utilities object contains a number of helper functions for working with the Opera Platform™ Application Framework.

void sendInfoToNavigationbar( <String> navbarDestination, <String> content, … )
Will send content to the various elements of the navigation bar. See The navigation bar reference.
void requestActivateKeypresses(<string> keypress, ...)
Requests certain keypresses to be activated in the application. This function takes a variable numberof arguments, where the keypresses can be either of the following: CommandPriority2, JoystickLeftRight, JoystickUpDown or JoystickGo.
void requestDeactivateKeypresses(<string> keypress, ...)
Requests certain keypresses to be deactivated in the application. This function takes a variable number of arguments, where the keypresses can be either of the following: CommandPriority2, JoystickLeftRight, JoystickUpDown or JoystickGo.
void storeVal(<string> name, <string> value, <int> time=360*24*60*60*1000)
To store a cookie.
<string> value getVal(<string> name)
To get a cookie.
void deleteVal(<string> name)
To delete a cookie.

6.12. O2_Command

O2_Command is a wrapper for executing function calls on certain objects with parameters

Method summary

class O2_Command {
  void execute()
}
O2_Command(<Function> function, <Object> object, <mixed> Arguments ...)
O2_Command is a wrapper for a function call on certain objects with parameters. function is the function that is requested called. The second argument, object, is the object upon which function should act. Finally, the O2_Command constructor takes a variable number of arguments that are passed as arguments to function
void execute()
This method takes no arguments, and returns void. When this method is called on an O2_command object, the function defined in O2_Command is called.

6.13. O2_MenuController

The O2_MenuController is used for creating menus activated by the softkeys on a device.

Method summary

class O2_MenuController {
  void addMenu(<String> menuId)
  void callAfterClose(<Function> functionRef)
  void callBeforeOpen(<Function> functionRef)
  void cleanup()
  void closeWithOpenButton(<boolean> value)
  object getItem(<String> itemId)
  boolean isOpen()
  void setActionOnItem(<O2_Command> action, <String> itemId)
  void setActiveMenu(<String> menuId)
  void setCancelText(<String> text)
  void setCenterText(<String> text)
  void setOpenText(<String> text)
  void setPriority1Text(<String> text)
  void setPriority2Text(<String> text)
}
addMenu()
The addMenu method creates a new menu object that can be accessed through the O2_Menu object. This method takes one argument, itemId which is a string providing a unique ID for the menu.
callAfterClose()
This method takes a function as argument.The function provided will always be called whenever a menu is closed.
callBeforeOpen()
This method takes a function as an argument. The function provided will always be called whenever a menu is opened
cleanup()
This method will, if called, close the menu, and reset all properties of the menu to the default value.
closeWithOpenButton()
Defines the behaviour of the open/close buttons for a menu. If this method is called with the argument true, the menu will close with the same key/button as it opens with. In any other case, the menu will have a separate button for opening and closing.
getItem()
Returns an object reference to a given menu item, provided by the itemId argument passed to the method.
isOpen()
This method takes no arguments, and returns true if a menu is open, false otherwise.
setActionOnItem()
This menu assigns the O2_Command given to the item with the given itemId.
setActiveMenu()
This method takes a menuId as argument, and sets the active menu to be the given menu.
setCancelText()
This method takes a string as an argument, and sets the text label of the default cancel/close action for a menu
setCenterText()
This method takes a string as an argument, and sets the text label for the center area of the navigation bar.
setOpenText()
This method takes a string as an argument, and sets the text label for the open button on the navigation bar. This is only to be used when closeWithOpenButton is set to false.
setPriority1Text()
This method takes a string as an argument, and sets the text label of the priority 1 button after the menu is closed.
setPriority2Text()
This method takes a string as an argument, and sets the text label of the priority 2 button after the menu is closed.

6.14. O2_MenuItem

The O2_MenuItem class provides methods for handling individual menu entries

class O2_MenuItem {
  void  addChild(<String> text, <String> itemId, 
            <O2_Command> action, <boolean> enabled, 
            <String> className)
  void  disable()
  void  enable()
  void  removeChild(<String> itemId)
  void  setAction(<O2_Command> action)
}
addChild()
Adds a menu item to the item, with the string text. The itemId is a unique ID for the item being added. O2_Command is a function to be executed. This is added as a new O2_Command object. Lastly, class is a CSS class name for the menu item.
disable()
This method disables the menu entry so it can no longer be selected. This method returns void and takes no arguments.
enable()
This method enables a previously disabled menu entry so it can be selected and accept input events. This method returns void and takes no arguments.
removeChild()
This method takes an itemId reference to a menu entry and removes it from the menu.
setAction()
The setAction method accepts an O2_Command as parameter, and sets an action to be executed when the menu entry is activated (clicked).

6.15. O2_DialogController

The O2_DialogController class is used to manage dialogs.

class  O2_DialogController {
  object addDialog(<String> dialogId, <String> text, <String> type,
                   <String> priority1Text, <String> priority2Text,
                   <O2_Command|function> actionFalse, <O2_Command|function> actionTrue,
                   <Array> labelInputs, <String> additionalClassname)
  void   callAfterClose(<function> function)
  void   callBeforeOpen(<function> function)
  void   closeDialog()
  void   setDefaultCancelText(<String> text)
  void   SetDefaultCenterText(<String> text)
  void   SetDefaultOKText(<String> text)
  void   SetDefaultPriority1Text(<String> text)
  void   SetDefaultPriority2Text(<String> text)
}
addDialog()
This method is used to create a new dialog. The arguments are as follows:
callAfterClose()
A reference to a function that should be called after the dialog is closed.
callBeforeOpen()
A reference to a function that should be called before the dialog is opened.
closeDialog()
Closes the currently open dialog
setDefaultCancelText()
This method takes a string as an argument, and sets the text label of the default cancel/close action for the dialog
setDefaultCenterText()
This method takes a string as an argument, and sets the text label for the center area of the navigation bar.
setDefaultOpenText()
This method takes a string as an argument, and sets the text label for the open button on the navigation bar.
setPriority1Text()
This method takes a string as an argument, and sets the text label of the priority 1 button after the dialog is closed.
setPriority2Text()
This method takes a string as an argument, and sets the text label of the priority 2 button after the dialog is closed.

6.16. CSS Rules

Themes in the Opera Platform™ SDK are put into the themes folder.

6.16.1. themes.xml

The themes.xml file is located directly in the themes folder and contains information about the installed themes. This file contains a <themes> element containing one or more <theme> element, containing data about the theme. An example themes.xml file looks like this:

<?xml version="1.0"?>
<themes>
  <heading>Theme Selector</heading>
  <theme>
    <name>Opera</name>
    <description>Opera standard theme.</description>
    <previewicon>opera/themeThumb.png</previewicon>
    <stylebase>opera/style.css</stylebase>
  </theme>
</themes>

Elements of theme (All elements are required):

Element Description
name The name of the theme
description A short description of the theme
previewicon A relative URI describing the location of the theme directory. The path is relative to the themes folder.
stylebase A relative URI describing the location of the theme's CSS file. The path is relative to the themes folder. To ensure the integrity of the Opera Platform™ application, this file should mostly contain colour and background overrides for the elements. Authors are adviced to clone the file baseTheme/style.css.

6.17. Opera Platform™

The Opera Platform™ DOM Interface specification describes a DOM Interface to let telecom operators write Web-based portals that interact with their customers devices. These Interfaces provide access to device status flags, messaging, OS applications, and related features. .

6.18. Quitting and/or reloading Opera Platform™

Quitting the Opera Platform™ is achieved by making a call to the window.close() method on the topmost window.

Reloading the Opera Platform™ can be done by making a call to the top.location.reload(true) method. The true parameter forces Opera Platform™ to disregard any caching when reloading.

6.19. opera.register()

the opera.register() method is used for registering the current copy of Opera Platform™:

class Opera
bool register(DOMString serial)

The serial number must be valid registration code for the selected device. If the registration code is valid, Opera Platform™ will return true. If the registration code is invalid, the value false will be returned.

6.20. Deleting cookies

If you create versions of the Opera Platform™ Application Framework that uses incompatible cookie formats, the cookies must be deleted manually.

6.20.1. Series 60

Locate the file System/Data/Opera/OP/cookies4.dat, and delete the file. If Opera Platform™ is installed in the phone's internal memory, this file is located on the C: drive. If Opera Platform™ is located on an external memory card, this file is located on the E: drive. Getting access to this file requires use of a tool such as FExplorer.

7. Security

Each application in the Opera Platform™ Application Framework run in separate iframes, and thus in separate javascript window objects. The implication of this is that applications residing on different domains will not be able to interact and/or in other ways interfere with each other.

Desktop security

The version of Opera for Desktop that is released with the Opera Platform™ SDK has relaxed cross-domain restrictions to allow for testing applications that interact with third-party web sites and services. These relaxed security restrictions means that this version of Opera under no circumstance should be used for browsing regular and/or untrusted web sites.

8. Tips & Resources

This section contains various tips and tricks we have used with success when developing services in Opera Platform™.

8.1. Tips

8.1.1. Asynchronous operations

Whenever you access a resource using XMLHttpRequest, never ever use it as a synchronous operation. If the network is slow, or the resource is unavailable, a synchronous event will lock the operation of the browser, and even possibly the device.

8.1.2. Pass parameters to an onclick

Save the parameters in the element and refer to it with this.

   ele = createElement("li");
   ele.counter = 4;
   ele.onclick = function() { myfunc(this.counter) };
   

8.1.3. Prototyped methods

It's best to put code in the prototype if you need to create more than one object. This will reduce memory footprint since all objects will share the function.

   function SomeClass(valueAttrib)
   {
      this.value = valueAttrib;
   }
   SomeClass.prototype.toString = function() { return this.value; }
   

8.1.4. Public methods

These are public methods that are accessible and changeable from the outside. It's easiest to put the public methods on the prototype.

   function SomeClass()
   {
   }
   SomeClass.prototype.public = function() { return "I'm public"; }

8.1.5. Private methods

These methods will not be changeable to accessible from the outside nor from the prototype.

   function SomeClass()
   {
      var private = function() { return "I'm private";}
   }
   

8.1.6. Privileged methods

This type of method is public accesible, but not possible to modify. Using this type of decleration could have the side effect of producing larger memory footprint vs. the prototype way of declaring public methods.

   function SomeClass()
   {
      this.privileged = function() { return "I'm privileged"; }
   }
   var o = new SomeClass();
   o.privileged(); // allowed
   o.privileged = function() { return "This is not allowed"; } // not allowed
   

8.1.7. Static methods

Sometimes it creating static methods on an object can be useful:

   function SomeClass() {}
   SomeClass.static = function() { return "I'm static";}
   SomeClass.static(); // works fine
   

8.1.8. Inline event handlers

Sometimes, when attaching event listeners, it can be handy to define the event handlers inline, as anonymous functions, to prevent namespace pollution:

   document.addEventHandler("click", function(ev) { 
     alert(ev.target + " was clicked") 
   }
   

8.1.9. The self trick

When you call a function from setInterval or setTimeout this will no longer point to the object. This also applies if you try to call a private function from a privileged or public method. The trick is to use a local variable that is valid in the current scope.

   function F()
   {
      var self = this;
      var handler = function() { self.handleMore(); }
      this.timeout = function()
    setTimeout(handler, 1000);

     this.handleMore = function() { alert("handled") 
  }

8.1.10. Singleton pattern

Singletons are created by creating a new instance of an anonymous function.

   var mySingleton = new function() { ... }
   

8.2. Resources

Below is a list of useful resources, tutorials and specifications.

8.2.1. javascript

8.2.2. Other