Life on Planet Firefox

Writing apps for the new Firefox OS phones

By

Cooking up an app for the Firefox OS is in no way difficult. All you need is a good measure of HTML and a dash of CSS. A few drops of JavaScript will bring it all to life.

Although the smartphone software market seems polarized between iOS and Android these days, other contenders out there are filling out or creating their own niches. Mozilla, for example is aiming at a modest part of the market share: the very low end phones. That doesn’t mean FirefoxOS phones are bad. Quite the contrary. The few models I have seen so far are perfectly adequate considering their price tag. Plus, they are real smartphones, with a great potential market in developing countries or just for those who feel that spending more than 100 bucks on a phone is a waste, which it is for most people.

Firefox OS can do most, if not all, of what you can do in Android and iOS, and it’s easy to make apps for it. If you can write HTML5, CSS3, and JavaScript to create a web app, you’ve already mastered 90% of what you need to know.

Even if you are bit rusty with your web technologies, I’ll try to show you in this article how to get from idea to marketplace quickly and easily.

The Hardware

It definitely helps to have a real device on which to test your software. The good news is that Firefox OS handsets are cheap, and you can pick up a ZTE Open for less than US$ 80 (or for as little as EUR 39 if you live in Spain). However, even if you don’t have a physical device, you can run, test, and debug your app in the Simulator.

The Simulator

The Simulator is a Firefox (as in the Firefox browser) plugin that allows you to run a Firefox OS emulator (Figure 1) and test your apps. Once installed, visit Tools | Web Developer | Firefox OS Simulator.

Figure 1: The Firefox OS Simulator allows you test your apps in an emulated environment.

The simulator comprises two parts: the dashboard and the emulator proper. At the top of the dashboard, from left to right, you can run the emulator, see a list of apps you have installed in the emulator, add a directory, or add a URL that contains the manifest of the Firefox OS app (more about that later). On the far right, within the list of apps, you can Refresh individual apps on the emulator when you make changes, and Connect Firefox’s integrated web development tools to the emulator to debug your JavaScript code, HTML, or CSS.

If you have a Firefox OS handset, you can also Push your app to it. To do this, you have to configure your phone by going to Settings on your device; then, scroll down and choose Device Information | More Information | Developer and check the Remote Debugging option. Now connect your handset to your computer using the USB data cable, and ... Presto! Your device pops up on the dashboard.

The emulator itself, apart from simulating a handset, has two menus at the top. File allows you to Quit the emulator, and App allows you to Refresh an installed app.

Note that the Firefox OS emulator is still in a very early stage of development; hence, it’s slow and resource hungry. It might also behave weirdly, lock up, or show results inconsistent with what you would see on a real phone, which can be annoying and kind of defeats the purpose of an emulator in the first place. However, unless you have a real Firefox OS device, it’s the best you can do.

The Assets

Before you start writing your app, you will want to grab the assets Mozilla has to offer, which you can use freely in your project. Not only will this make your life easier, but it helps maintain a consistent look and feel across all apps on the system.

The bag of goodies you really want to get is the Building blocks package, which includes all the fonts, icons, images, and CSS files (which in turn include styles for buttons, the status bar, etc.) you need to design an app. Plus, you’ll find plenty of examples that can help you see how these resources are used, as well as sample JavaScript code to power the whole lot. The Mozilla Building Blocks page offers comprehensive advice and even more examples to help you use the assets.

The Package

Another thing you need to do (otherwise you won’t be able to run your app on the Simulator or handset) is write the manifest. The manifest is a JSON summary that contains all the details of your app so Firefox OS can run it correctly.

The manifest.webapp file must be at the root of the app. The example in Listing 1 gives you an idea of what the file should contain.

Listing 1: Manifest.webapp for Life

01 {
02 "version": "0.1",
03 "name": "Life",
04 "description": "Conway's Game of Life",
05 "launch_path": "/index.html",
06 "icons": {
07 "60": "/img/LifeIcon60x60.png",
08 "128": "/img/LifeIcon128x128.png"
09 },
10 "developer": {
11 "name": "Paul Brown",
12 "url": "http://www.linux-magazine.com"
13 },
14 "installs_allowed_from": ["*"],
15 "default_locale": "en",
16 "orientation": ["portrait"]
17 }

Most of the fields are pretty self-explanatory; however, note in the icons section that you will have an icon 60x60 pixels and another 128x128 pixels. The handset uses the 60-pixel icon in its list of apps (Figure 2); the 128-pixel icon comes into play if you want to distribute your app through the Firefox OS marketplace, which I talk about a bit later. A handy guide shows you how to create a thematically consistent icon.

Figure 2: Firefox OS uses 60x60-pixel icons for its desktop.

The orientation field in line 16 allows you to decide how your app will be shown on the device: portrait, landscape, portrait-primary, landscape-primary, portrait-secondary, or landscape-secondary. For example, if you specify portrait-primary in your manifest file, your app appears in portrait mode with the top of your UI at the top of the device, and the bottom at the bottom of the device’s display. The portrait-secondary option flips the orientation 180 degrees. By using portrait, your app will flip in portrait mode depending on how the device is held, but it will not rotate 90 degrees when you turn the device on its side.

Combining these options, for example,

“orientation”: [“portrait”, “landscape-secondary”]

allows your app to flip either way in portrait mode (right way up or upside down) and will display correctly on one of its sides, but not the other. The Mozilla Developer Network has a good tutorial on how to write a good manifest.

The Software

In my example project, I’ll be implementing Conway’s Game of Life (GoL), probably one of the most popular and simplest life simulators. If you are unfamiliar with GoL, check out the “The Game of Life” box.

 
Figure 3: The pattern known as the “R-pentomino” generates an enormous number cells.

If you have had any experience with JavaScript in the last few years, you will have witnessed the rise of JavaScript libraries, none of which is more popular than jQuery. jQuery has simplified the creation of dynamic web programming to the point of forcing Flash nearly to extinction (which, by the way, is an excellent thing). jCanvas is an extension of JQuery that makes programming on a canvas object much easier.

In my implementation (Listing 2), I will use the HTML5 canvas object as a playing board (line 17).

Figure 4: Life for Firefox OS uses a canvas object for the playing field and implements two buttons.

To help, I will use jQuery and jCanvas (lines 7 and 8). In lines 150-159, you can see how easy it is draw a cell on the canvas. Note that because I consider a single pixel too tiny, I decided to go with a 2x2 box for the cells. With a 300x300 canvas, the playing field can hold 150x150 cells.

Listing 2: Life for Firefox OS (index.html)

001 <!DOCTYPE html>
002 <html>
003 <head>
004 <title>Game of Life</title>
005 
006 <!-- Include external JavaScript -->
007 <script src="js/jquery-2.0.3.js"></script>
008 <script src="js/jcanvas.min.js"></script>
009 
010 <!-- Style Sheets -->
011 <link rel="stylesheet" href="style/buttons.css">
012 <link rel="stylesheet" href="style/status.css">
013 
014 </head>
015 
016 <body>
017 <canvas width="300" height="300" style="border:1px solid black"></canvas>
018 <button id="operate">Start</button>
019 <button id="reset">Clear</button>
020 
021 <!-- Status Bar -->
022 <section role="status" id="cell-counter" hidden>
023 <p>Cells: <strong>0</strong></p>
024 </section>
025 
026 <script>
027 
028 var CULTURE=[];
029 var BUTTON_TEXT="Start";
030 var RUN;
031 
032 /*************
033 * 
034 * STATUS BAR
035 *
036 */
037 
038 $("canvas").dblclick(function(e)
039 {
040 $("#cell-counter" ).html( "<p>Cells: <strong>"+ CULTURE.length + "</strong></p>" );
041 $("#cell-counter").fadeIn().delay(2000).fadeOut('slow');
042 });
043 
044 /*************
045 * 
046 * EDIT MODE
047 *
048 */
049 
050 // Check position of pointer on canvas
051 $("canvas").click(function(e)
052 {
053 var canvas_pos = $("canvas").position();
054 var cellCoords= [Math.floor((e.pageX-canvas_pos.left)/2), Math.floor((e.pageY-canvas_pos.top)/2)]
055 editCell(cellCoords);
056 });
057 
058 
059 function editCell(coords)
060 {
061 var stringCoords='"'+ coords[0] + ',' + coords[1] +'"'
062 if($.inArray(stringCoords, CULTURE) === -1)
063 {
064 CULTURE.push(stringCoords);
065 drawPixel(coords);
066 }
067 else
068 {
069 CULTURE.splice(CULTURE.indexOf(stringCoords),1);
070 erasePixel(coords);
071 }
072 
073 }
074 
075 /*************
076 * 
077 * RUN MODE
078 *
079 */
080 
081 function mainLoop()
082 {
083 // This is the temporary array where we store
084 // the next culture
085 var nextCulture = [];
086 
087 // Here we store the cells we have already examined
088 var cellExamined = [];
089 
090 $.each(CULTURE, function(i, point)
091 {
092 var newX= convrt2Coords(point)[0];
093 var newY= convrt2Coords(point)[1];
094 
095 // nbx and nby are the cells we have to examine since
096 // they are neighbouring active cells
097 
098 for (nbx=newX-1;nbx<newX+2;nbx++)
099 {
100 for (nby=newY-1; nby<newY+2; nby++)
101 {
102 // But we'll only examine them if we haven't done so already
103 // (and they are not off the edge of the board).
104 if ($.inArray('"'+ nbx + ',' + nby +'"', cellExamined)===-1)
105 {
106 cellExamined.push('"'+ nbx + ',' + nby +'"');
107 if(nbx>=0 && nbx<=300 && nby>=0 && nby<=300)
108 {
109 // Check neighbours
110 var neighbours=0;
111 for (ncx=nbx-1; ncx<nbx+2; ncx++)
112 {
113 for (ncy=nby-1; ncy<nby+2; ncy++)
114 {
115 if (!(ncx==nbx && ncy==nby))
116 {
117 if($.inArray('"'+ ncx + ',' + ncy +'"', CULTURE)!==-1) neighbours++;
118 }
119 }
120 }
121 
122 switch(neighbours)
123 {
124 case (3):
125 // If number of neighbours is 3, a cell is born
126 nextCulture.push('"' + nbx + ',' + nby + '"'); 
127 case (2):
128 // If number of neighbours 2, leave alone
129 if ($.inArray('"' + nbx + ',' + nby + '"', CULTURE)!==-1)
130 {
131 nextCulture.push('"' + nbx + ',' + nby + '"');
132 }
133 }
134 }
135 }
136 }
137 }
138 });
139 
140 CULTURE = nextCulture;
141 drawPlayingField();
142 }
143 
144 /*************
145 * 
146 * MISC STUFF
147 *
148 */
149 
150 function drawPixel(coords)
151 {
152 $("canvas").drawRect
153 ({
154 fillStyle:"rgba(0, 0, 0, 1)",
155 x: coords[0]*2, y: coords[1]*2,
156 width: 2,
157 height: 2 
158 });
159 }
160 
161 function erasePixel(coords)
162 {
163 $("canvas").clearCanvas
164 ({
165 x: coords[0]*2, y: coords[1]*2,
166 width: 2,
167 height: 2 
168 });
169 }
170 
171 function drawPlayingField()
172 {
173 $("canvas").clearCanvas();
174 //Loop thru coors and draw pixels
175 $.each(CULTURE, function(i, point)
176 {
177 drawPixel(convrt2Coords(point));
178 });
179 }
180 
181 function convrt2Coords(coords)
182 {
183 var intCoords=[parseInt(coords.split(",")[0].slice(1)), parseInt(coords.split(",")[1])];
184 return intCoords;
185 }
186 
187 /*************
188 * 
189 * BUTTONS
190 *
191 */
192 
193 $("#operate").click(function()
194 {
195 $(this).toggleClass("active");
196 
197 if (BUTTON_TEXT=="Start")
198 {
199 if (CULTURE[0])
200 {
201 BUTTON_TEXT="Stop";
202 $(this).text(BUTTON_TEXT);
203 RUN=setInterval(mainLoop,1);
204 }
205 }
206 else
207 {
208 BUTTON_TEXT="Start";
209 clearInterval(RUN);
210 $(this).text(BUTTON_TEXT);
211 }
212 });
213 
214 $("#reset").click(function()
215 {
216 BUTTON_TEXT="Start";
217 clearInterval(RUN);
218 $("canvas").clearCanvas();
219 CULTURE=[];
220 });
221 
222 </script>
223 </body>
224 </html>

The code in Listing 2 also uses jQuery extensively to refer to and manipulate some of the elements, such as the status bar, which will slowly appear and then fade out if you tap the playing field twice (the equivalent of a double-click) and show you how many live cells are in the current generation (lines 38-42). Speaking of the status bar, the HTML to include it in your app is very simple (lines 22-24), although you will have to modify the status.css file to use the clean, elegant font provided by Mozilla (see Listing 3).

Figure 5: The status bar shows the number of living cells in a given generation.

Listing 3: Modified status.css File

01 /* ----------------------------------
02 * Status
03 * ---------------------------------- */
04 
05 @font-face
06 {
07 font-family: FiraSans;
08 src: url('/fonts/FiraSans/FiraSans-Regular.ttf');
09 }
10 
11 @font-face
12 {
13 font-family: FiraSans;
14 src: url('/fonts/FiraSans/FiraSans-Bold.ttf');
15 font-weight:bold;
16 }
17 
18 section[role="status"] {
19 background: rgba(64,64,64,1) url(status/images/ui/pattern.png) repeat left top;
20 overflow: hidden;
21 position: absolute;
22 z-index: 100;
23 left: 0;
24 right: 0;
25 bottom: 0;
26 color: #fff;
27 text-align: left;
28 }
29 
30 section[role="status"] p {
31 font-family: FiraSans;
32 font-size: 1.8rem;
33 font-weight: normal;
34 line-height: 2.2rem;
35 margin: 1rem 3rem;
36 padding: 0;
37 text-align: left;
38 }
39 
40 section[role="status"] p strong {
41 font-family: FiraSans, bold;
42 color: rgb(9, 149, 176);
43 }

The Start/Stop and Clear buttons are included in the user interface in lines 18 and 19 (Listing 2), respectively. When you click Start or Stop, you either start the mainLoop function (which runs the simulation) or stop it (lines 193-212).

The Clear button uses a jCanvas function to erase all pixels from the canvas and empties the CULTURE array that holds the coordinates of the live cells in the current generation (lines 214-220).

The biggest chunk of code (lines 81-142) is the mainloop mentioned above. This section calculates the next generation based on the current generation stored in CULTURE. The most obvious way of doing this is to loop over every cell in the 150x150 array and examine each of the eight possible neighbors, changing their state as necessary. However, this process is a very slow, very inefficient way of doing things.

Instead, the CULTURE array contains the coordinates of only the live cells in the current generation. By only examining live cells and their immediate neighbors, you can skip enormous empty chunks of the playing board. All the white space above, between and below the live cells is ignored (lines 90-138). The jQuery $.each() loops over all the elements in CULTURE and avoids examining a cell twice by storing it in the cellExamined array (line 106) and skipping it if it’s encountered again (line 104). The new cell configuration is gradually stored in the nextCulture array.

Note that the cells are stored as strings, so cell (130, 45) is stored as [130, 45]. Arrays in JavaScript are flat, so a two-dimensional array like

a = [[130, 45], [20, 130], [45, 10]]

is actually stored like

a = [130, 45, 20, 130, 45, 10]

making searches for duplicate coordinates (i.e., lines 62-71) very difficult. The conversion from string to numbers and back again, which is going on within the loops, most certainly has an effect on performance, but the only other way would be to store the cells as an array of objects. Unfortunately, looping and searching for duplicates within an array of objects is also difficult, hence the string-based solution.

Finally, nextCulture is dumped into CULTURE, and the new generation is drawn to the playing board (lines 140-141).

The Distribution

Now that your app works, it’s time to package it and get it distributed. The packaging process is very straightforward. All you need to do is create a ZIP file that has the manifest.webapp file in its root. In Linux, you’d cd into the root of your app and type:

zip -r <appname>.zip *

Now, you have two choices: You can host it yourself on your own site, something Mozilla is perfectly okay with, or you can upload it to the Firefox OS Marketplace (Figure 6). To use the Marketplace, you need a Firefox OS developer account; the submission process is very straightforward (Figure 7).

Figure 6: The Firefox OS Marketplace contains officially sanctioned and audited apps.
Figure 7: Submitting a packaged app to the marketplace is a simple, straightforward, four-step process.

Apart from getting more exposure with the marketplace, the wizard helps you weed out any errors you might have in your manifest and, in the future, you will be able to sell you apps using Mozilla’s framework.

Figure 8: Your app is easily installed once it is approved for the market.

Improving Life

If you run the game, your first complaint will pertain to the efficiency of the program. The program works well with small cultures but slows to a crawl as soon as the number of cells grows. There are probably ways to make GoL more efficient and the JavaScript more optimal that I have overlooked. Feel free to give the code a bash by downloading it and playing with it.

The second problem relates to usability. This app is screaming for a zoom function in edit mode. Even if the cells are 2x2 blocks on the canvas, they are tiny. No fat (or even thin) fingers will be able to place a cell accurately on the playing field without a stylus. Again, feel free to make your own changes and improvements.

Conclusion

The app itself is far from perfect, but it shows you how easy it is create an app for the Firefox OS mobile platform and some of the ways you can implement the assets Mozilla makes available.

If you already develop web apps using HTML5, you’re basically done. If not, HTML, CSS3, and jQuery are well-documented and relatively easy technologies to master, and you should be able to create your apps quickly and with little effort in no time.

Related content

  • Firefox Phone Apps

    Cooking up an app for the Firefox OS is in no way difficult. All you need is a good measure of HTML and a dash of CSS. A few drops of JavaScript will bring it all to life.

  • Treasure Hunt

    A geolocation guessing game based on the popular Wordle evaluates a player's guesses based on the distance from and direction to the target location. Mike Schilli turns this concept into a desktop game in Go using the photos from his private collection.

comments powered by Disqus
Subscribe to our Linux Newsletters
Find Linux and Open Source Jobs
Subscribe to our ADMIN Newsletters

Support Our Work

Linux Magazine content is made possible with support from readers like you. Please consider contributing when you’ve found an article to be beneficial.

Learn More

News