It is easy to develop an add-on. You only need:
Fork these slides: https://slides.com/firefoxos/fxos-nfc/
@CodingFree
Firefox OS has an NFC API.
But it doesn't have a background service to interact with other NFC devices.
This means that you need to open a specific Webapp to use NFC.
Fork these slides: https://slides.com/firefoxos/fxos-nfc/
@CodingFree
Fork these slides: https://slides.com/firefoxos/fxos-nfc/
@CodingFree
@CodingFree
Firstly, we have to define our manifest.json file:
It will be a Chrome manifest, quite different from the manifests used for Firefox OS Webapps.
Manifest File Format: Field summary.
Fork these slides: https://slides.com/firefoxos/fxos-nfc/
@CodingFree
Supported fields:
Fork these slides: https://slides.com/firefoxos/fxos-nfc/
Not supported:
@CodingFree
{
"manifest_version": 2, // WebApp Manifest = 1 (deprecated), WebExtension = 2
"version": "1.0", //My own version
"name": "NFC Sleep",
"description": "Turn off your WiFi and volume using a NFC Tag.",
"author": "Adrian Crespo",
"role": "addon", // Mandatory.
"type": "certified", // No effect! It's deliberately wrong,I wanted to point out that is has no effect!
"content_scripts": [
{
"matches": [
"app://system.gaiamobile.org/index.html" // My target will be the System App.
],
"js": [
"scripts/nfc.js" // My script
]
}
],
"icons": {
"1200": "/style/icons/1200.png", // Icons!
"128": "/style/icons/128.png", // Required by the Marketplace
"60": "/style/icons/60.png", // Standard size
"32": "/style/icons/32.png" // Why not?
}
}
Do you remember...?
Fork these slides: https://slides.com/firefoxos/fxos-nfc/
//... code ...
"content_scripts": [{
"css": [],
"js": ["scripts/nfc.js"]
}],
//... code ...
We have to zip the same
tree structure, or it won't
work!
(it's the same for the icons)
Our target will be the System App, because we specified it in the "matches" field.
It supports regular expressions:
// More code
"content_scripts": [
{
"matches": [
"app://system.gaiamobile.org/index.html"
],
"js": [
"scripts/nfc.js"
]
}
],
// More code
["http://www.mozilla.com/*"].
For any URL it would be like this:
["<all_urls>"]
More examples: match patterns.
Fork these slides: https://slides.com/firefoxos/fxos-nfc/
@CodingFree
First, notice that the wrapping function statement starts with (function... as opposed to just function....
(function foo(){ .. }) as an expression means the identifier foo is found only in the scope where the ... indicates, not in the outer scope (and this is safer and cleaner).
Extracted from: You Don't Know Javascript!
(because it is really awesome)
Fork these slides: https://slides.com/firefoxos/fxos-nfc/
@CodingFree
We are going to use the Notifications API (standard):
To create the notification:
Fork these slides: https://slides.com/firefoxos/fxos-nfc/
var notification = new window.Notification( ... )
@CodingFree
And we are going to use the NFC API:
Fork these slides: https://slides.com/firefoxos/fxos-nfc/
if(window.navigator.mozNfc)...
nfc.ontagfound(...);
ndefObject.ndefRecords(...);
ndefRecords.length;
ndefObject.ndefRecords;
ndefRecords[i].payload.wrappedJSObject;
The payload will be the orders for the System App.
@CodingFree
And we are going to use the NFC API:
Fork these slides: https://slides.com/firefoxos/fxos-nfc/
We are using wrappedJSObject because it is a nasty fix :(
The XPCOM model didn't allow me to read the payload directly, so I used that to "see" the object hidden by the wrapper.
It is fixed, but... if you find it, you will know how to fix it :)
@CodingFree
At last, we will use the Settings API to modify the volume of the mobile phone:
Fork these slides: https://slides.com/firefoxos/fxos-nfc/
It's easy to use: you need to use a lock to change the settings (to avoid race conditions), and then use set() to change the values.
We could disable the WiFi: 'wifi.enabled': false
window.navigator.mozSettings;
settings.createLock();
result = lock.set({...});
result.onsuccess;
result.onerror;
@CodingFree
(function () {
this._started = false;
this.tag = null;
start();
function notify(titleid, body, bodyid, onClick) {
console.log("A notification would be send: " + titleid);
var canSend = false;
if (Notification.permission === "granted") {
// If it's okay let's create a notification
canSend = true;
}
// Otherwise, we need to ask the user for permission
if (Notification.permission !== 'denied') {
Notification.requestPermission(function (permission) {
// If the user accepts, let's create a notification
if (permission === "granted") {
canSend = true;
}
});
}
if(canSend) {
var notification = new window.Notification(titleid, {
body: body,
icon: '/style/icons/32.png'
});
notification.onclick = function () {
notification.close();
if (onClick) {
new MozActivity({
name: "view",
data: {
type: "url",
url: body
}
});
}
};
}
}
function changeSettings(){
var settings = window.navigator.mozSettings;
var lock = settings.createLock();
var result = lock.set({
'wifi.enabled': false,
'bluetooth.enabled': false,
'powersave.enabled': true,
'ril.data.enabled': false,
'audio.volume.content': 0,
'audio.volume.notification': 0
});
result.onsuccess = function () {
console.log("NFC-Sleep: The setting has been changed");
notify("NFC-Sleep", "The setting has been changed");
}
result.onerror = function () {
console.log("NFC-Sleep: An error occure, the setting remain unchanged");
notify("NFC-Sleep", "An error occure, the setting remain unchanged");
}
}
function manageNDEFRecords(ndefRecords) {
console.log("NFC-Sleep: managing NDEF records.");
var ndefLen = ndefRecords ? ndefRecords.length : 0;
if(ndefLen != 0){
var outputString = '';
for (i = 0; i < ndefLen; i++) {
payload = dumpUint8Array(ndefRecords[i].payload.wrappedJSObject);
}
console.log("NFC-Sleep: "+payload);
if (payload.localeCompare("NFC-Pass1") === 0){
changeSettings();
}
}
}
function handleTagFound(ndefObject){
console.log("NFC-Sleep: Tag found");
var ndefRecords = ndefObject.ndefRecords;
var ndefLen = ndefRecords ? ndefRecords.length : 0;
// if no NDEF Records are contained, bail out.
if (!ndefLen) {
console.log("NFC-Sleep: The tag is blank")
return true;
}
console.log("NFC-Sleep: The tag is okay, lets read it");
manageNDEFRecords(ndefObject.ndefRecords);
return false;
}
function dumpUint8Array(array) {
if (!array) {
return 'null';
}
var str = '';
var i;
var arrayLen = array ? array.length : 0;
for (i = 0; i < arrayLen; i++) {
str += '' + hex2a(array[i].toString(16));
}
return str + '';
}
function hex2a(hexx) {
var hex = hexx.toString();//force conversion
var str = '';
for (var i = 0; i < hex.length; i += 2)
str += String.fromCharCode(parseInt(hex.substr(i, 2), 16));
return str;
}
function stop() {
if (!this._started) {
throw 'Instance was never start()\'ed but stop() is called.';
}
this._started = false;
window.removeEventListener('mozChromeEvent', this.handleEvent);
}
function start() {
console.log("NFC Sleep Running LOL");
if (this._started) {
throw 'Instance should not be start()\'ed twice.';
}
var nfc = window.navigator.mozNfc;
if (!nfc) {
console.log('Go home NFC, you are not available. Please, disable this addon.');
return;
} else {
console.log('NFC Sleep enabled.');
this._started = true;
nfc.ontagfound = handleTagFound.bind(this);
}
}
}());
Do you remember the ZIP file?
Just go to this webpage and upload it:
Fork these slides: https://slides.com/firefoxos/fxos-nfc/
It will be public as soon as it is reviewed by the Marketplace Reviewers Team.
@CodingFree
Thank you for attending the presenta
tion
Fork these slides: https://slides.com/firefoxos/fxos-nfc/
Feel free to ask me any question:
@CodingFree
@CodingFree
Fork these slides: https://slides.com/firefoxos/fxos-nfc/
@CodingFree