9. Device Storage

Welcome to Episode 9 of the Firefox OS App Development Tutorial. In the previous episode, we looked at how you can use Web Activities in your Firefox OS Applications. In this episode, we shall look at how you can access device storage in your Firefox OS Apps and we will see how to browse through the content on your SD card, pictures, videos and music areas on your phone.

9.1. Prerequisites

  • You have setup your machine with the Firefox OS simulator. If not you can check out Overview and Development Setup, which takes you through the entire setup.
  • You have a basic understanding of writing Firefox OS Apps. If not, I strongly suggest refering to earlier episodes, especially Hello World, that covers how to write your first Firefox OS App.

9.2. What this Episode covers

  • Device Storage and how to use the Device Storage APIs.
  • Sample Firefox OS Application that covers how to access Device Storage.

9.3. Episode 9 in Action

Let us check out the application in action first to understand what we are trying to do here.

What we shall write is a mobile application that will allow us browse through the files that are present on the different storage areas of the device. These different storage areas include the SD card, pictures, videos, and music. It will give you enough information to see how to access the files, get the file metadata. The episode does not cover how to write or create new files but the Storage API does provide that facility too, should you need that in your application.

All right then, the first screen of the mobile app is shown below:

Opening image of Device Storage app

The screen has 4 buttons that will allow you to browse the contents of the particular device storage area on your phone.

Keep in mind that the SD card browsing will not work on the simulator, but it should work fine on the device. I am able to browse videos, music, and pictures just fine on the simulator.

When you click on the “Browse Music” button, it will access the music storage area and list down the contents. I believe the simulator goes and fetches it from the “Music” folder on the OS that you running it on and, in my case, it lists the files that are there in the “Music” folder. Notice that we list down the files and also other associated meta data like when it was last updated, file type, and the file size.

Similarly, when you click on the “Browse Pictures” button, it will display all the images that are present in the Pictures storage area. I simply show a little preview by creating an image element as shown below. Once again, we not only list the files but also display the meta data: last updated, file type and file size.

App displaying pictures

9.4. Download Full Source Code

I suggest that you begin with a full download of the project source code. Since the project depends on libraries like jQuery and jQuery Mobile, it will save you the hassle of downloading the dependent libraries.

Go ahead & download the code from: https://github.com/anicholakos/DeviceStorage

Extract all the code in some folder. On my machine, the code is present in /home/anicholakos/Projects/DeviceStorage but it could be any directory of your choice. You should see a folder structure inside of DeviceStorage, that looks something like this:

Folder structure of DeviceStorage

9.5. Firefox OS Device Storage

The Device Storage API in Firefox OS is used to access the file system. Until now we had seen how to use persistence in our application via the LocalStorage and IndexedDB APIs and when you use those APIs you are pretty much dealing with storage but at a high level. You are not dealing with individual files and directories and reading/writing to them.

The Device Storage API is just about that. Reading and writing to files directly. The Firefox OS exposes 5 storage areas that you can read and write from. They are:

  • Apps
  • SD card
  • Videos
  • Music
  • Pictures

The first storage area i.e. apps is available for certified applications only. This area is used by applications to read/write their data. We shall not attempt to do anything with that in this episode.

The other four areas stand for pretty much what their names indicate and you can read and write to any of the areas.

The API is fairly simple. All you need to do is invoke the navigator.getDeviceStorage() method and pass the storage area name to it, such as “SD card”, “music”, “pictures”, and “videos”, which will return a DeviceStorage Object that you can use to access the storage area.

You have methods that let you browse/list down the contents of the storage area (which we shall see in the code later on). There are methods available for additional stuff too like:

  • Determining free space
  • Writing/creating a file
  • Deleting a file

Keep in mind that access to the storage area is a privileged operation and hence you must define the type of your application as privileged in the manifest.webapp file that we shall see in the next section. Additionally, you will have to specify the permissions (read or readwrite) for each of the storage areas that you wish to access in your application.

9.6. DeviceStorage Application

OK, let’s get going with understanding the code and how we can access Device Storage in our application.

9.7. DeviceStorage Application - manifest.webapp

The first thing we should discuss is the manifest file. This should be familiar now and it has the standard attributes like name, version, etc. There is nothing special happening here.

The permissions are the most important over here. To access the storage areas in Firefox OS, your application needs to be a privileged application, so we are defining that in the “type”: “privileged” entry.

Next we need to mention what permissions our application needs. You have to create an entry for as many storage areas that you want to access in your application and also the type of access that you want i.e. read or readwrite. The readwrite mode will be needed if you plan to create/modify files.

You will notice in the manifest that we have provided readwrite permissions for each of the 4 storage areas (SD card, videos, music, and pictures).

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
{
    "version":"1.0",
	"name": "Device Storage",
    "description": "This app demonstrates how to use Device Storage",
    "launch_path": "/index.html",
	"fullscreen": "false",
    "icons": {
        "16": "/images/icon_016.png",
        "32": "/images/icon_032.png",
        "48": "/images/icon_048.png",
        "128": "/images/icon_128.png"
    },
	"developer": {
        "name": "Romin Irani",
        "url": "http://www.rominirani.com"
    },
    "default_locale": "en",
	"type": "privileged",
	"permissions": {
	  "device-storage:videos":  { "access": "readwrite" },
	  "device-storage:pictures":{ "access": "readwrite" },
	  "device-storage:sdcard":  { "access": "readwrite" },
	  "device-storage:music":   { "access": "readwrite" }
	}
}

9.8. DeviceStorage Application - index.html

Next up is the index.html page and it is a simple jQuery Mobile page.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
<!DOCTYPE html> 
<html>

<head>
	<meta charset="utf-8">
	<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0,user-scalable=0"> 
	<title>Notes</title> 
	<link rel="stylesheet" href="jquery.mobile-1.4.5.min.css" />
	<script src="jquery-2.1.4.min.js"></script>
	<script src="jquery.mobile-1.4.5.min.js"></script>
	<script src="app.js"></script>
</head> 
	
<body> 

<!-- Start of first page: #home -->
<div data-role="page" id="home">

	<div data-role="header" data-position="fixed" id="header">
	    <h3>Device Storage</h3>  
	</div><!-- /header -->

	<div data-role="content">
		<a href="#" id="browseSDCard"   data-role="button" class="big">Browse SD Card</a>
		<a href="#" id="browseVideos"   data-role="button" class="big">Browse Videos</a>
		<a href="#" id="browseMusic"    data-role="button" class="big">Browse Music</a>
		<a href="#" id="browsePictures" data-role="button" class="big">Browse Pictures</a>
		<div id="results"></div>
	</div><!-- /content -->

</div><!-- /page home -->

</body>
</html>

Let us discuss the index.html page in detail now:

  • We have included the script in app.js file on line 11.
  • There is only 1 page in the mobile app as seen on line 17.
  • This page has several buttons, which when clicked will display the contents of that storage area in the #results div shown on line 24-27.

9.9. DeviceStorage Application - app.js

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
function listContents(storagename) {
    //Clear up the list first
    $('#results').html("");
    var files = navigator.getDeviceStorage(storagename);
    var cursor = files.enumerate();
    cursor.onsuccess = function() {
        //alert("Got something");
        var file = this.result;
        if (file != null) {
            var imageElement = $('<img height="100" width="75">');
            imageElement.attr('src', window.URL.createObjectURL(file));
            $("<p>" + file.name + "," + file.lastModifiedDate + "," +
                file.type + "," + file.size + "</p>").appendTo(
                '#results');
            imageElement.appendTo("#results");
            this.done = false;
        } else {
            this.done = true;
        }
        if (!this.done) {
            this.continue();
        }
    }
}
$(document).ready(function() {
    $("#browseSDCard").click(function() {
        listContents('sdcard');
    });
    $("#browseVideos").click(function() {
        listContents('videos');
    });
    $("#browseMusic").click(function() {
        listContents('music');
    });
    $("#browsePictures").click(function() {
        listContents('pictures');
    });
});

Let us discuss the source code in detail now.

  • First, the standard stuff. On line 25, the standard jQuery ready function is fired and you will find various click handlers defined for the 4 buttons.
  • Each of the button click handlers invokes the same function listContents, which is provided a single parameter i.e. the name of the storage area to browser/list the contents.
  • The listContents function is defined on line 1.
  • Pay attention to line 4, where we make a call to the navigator.getDeviceStorage (storagename) method. This is a standard call and we can pass either sdcard, videos, music or pictures to it. The return value is a object that we can use to enumerate the different files present over there.
  • We use a cursor that we will use to enumerate through all the files. This cursor instance is obtained via the enumerate() function on the files object.
  • If the cursor is obtained successfully, the onsuccess callback method is invoked. In this method, we simply go through each result. Remember the this.result gives a File object that has attributes like name, lastModifiedDate, type and size.
  • So we are simply creating an image element and other meta data information element and appending it to the #results element in the page.
  • If the file object is null, it means that there are no more elements and we can mark the done attribute as true. If it is not done, then we move to the next record via the continue method.

9.10. Local Installation and Testing

This completes our discussion of writing Firefox OS applications that access Device Storage. Now comes the part of seeing it actually work. All we need to test out this application is:

  • You should have installed the Firefox OS simulator add-on in your Firefox Browser.
  • A working internet connection from your machine.
  • You should have downloaded/written the application as described above. We will assume that the index.html and manifest.webapp file are present in a folder names DeviceStorage. You should navigate to your own directory structure when called to later.

Steps to install the application in your Firefox OS Simulator should be familiar to you now. Simply launch the Firefox OS Simulator in your Firefox Browser. From the Dashboard, click on the “Add Directory” button and point it to the manifest.webapp file for the DeviceStorage application. On successful validation, the application will be installed and it will come up in your OS Simulator. For sample screenshots, refer to the section at the beginning of this blog post for Episode 9 in Action.

9.11. Next Steps

Device Storage is a key feature that you can use to write your own files and also create applications like File Explorer, etc. It can also be used to have a better control in imaging applications, where you want to access all the files present, and read/write to them via your own code. I recommend going through the official documentation on Device Storage and try to create a file, etc.

Keep in mind not to use the Device Storage as a general mechanism for persistence. If you want to build application level persistence in your application, it is recommended that you still use LocalStorage and/or IndexedDB API.

Until the next episode, stay tuned and give me feedback.