/**
* AppsCache is a singleton that will encapsulate mozApps.mgmt inside and
* expose neede API to callers. The reason why we need this is because
* mozApps.mgmt.getAll() costs a lot and the better way to do so is cache
* them inside this AppManager and automatically update it when install /
* uninstall event is received.
*
* API:
*
* AppsCache.apps().then(function(apps) {
* // installed apps in FxOS
* });
*
* @module AppsCache
*/
define(function(require) {
'use strict';
var mozApps = window.navigator.mozApps;
var mozAppsMgmt = mozApps && mozApps.mgmt;
var AppsCache = function() {
this._initPromise = null;
this._apps = [];
this._eventHandlers = {};
this._eventHandlers.oninstall = [];
this._eventHandlers.onuninstall = [];
};
AppsCache.prototype = {
/**
* apps is a method that would return a promise that would return
* cached apps.
*
* @access public
* @memberOf AppsCache
* @return {Promise}
*/
apps: function am_apps() {
var self = this;
return this._init().then(function() {
return self._apps;
});
},
/**
* Entry point
*
* @access private
* @memberOf AppsCache
* @return {Promise}
*/
_init: function am__init() {
var self = this;
if (!this._initPromise) {
this._initPromise = this._initApps().then(function() {
self._initEvents();
});
}
return this._initPromise;
},
/**
* Init needed events
*
* @access private
* @memberOf AppsCache
*/
_initEvents: function am__initEvents() {
var self = this;
mozAppsMgmt.oninstall = function(evt) {
var installedApp = evt.application;
self._apps.push(installedApp);
self._eventHandlers.oninstall.forEach(function(eventHandler) {
eventHandler(evt);
});
};
mozAppsMgmt.onuninstall = function(evt) {
var manifestURL = evt.application.manifestURL;
var removedAppIndex;
// installed apps are normally in the end, so let's iterate
// backward to find them quickly.
for (var i = self._apps.length - 1; i >= 0; i--) {
if (self._apps[i].manifestURL === manifestURL) {
removedAppIndex = i;
break;
}
}
if (removedAppIndex) {
self._apps.splice(removedAppIndex, 1);
self._eventHandlers.onuninstall.forEach(function(eventHandler) {
eventHandler(evt);
});
}
};
},
/**
* Init apps
*
* @access private
* @memberOf AppsCache
*/
_initApps: function am__initApps() {
var self = this;
var promise = new Promise(function(resolve, reject) {
var req = mozAppsMgmt.getAll();
req.onsuccess = function success(evt) {
self._apps = evt.target.result;
resolve(self._apps);
};
req.onerror = function error(evt) {
console.log('failed to get installed apps');
reject(req.error);
};
});
return promise;
},
/**
* Caller can add events when app is installed/uninstalled
*
* @access public
* @param {String} eventName
* @param {Function} callback
* @memberOf AppsCache
*/
addEventListener: function am_addEventListener(eventName, callback) {
if (this._eventHandlers[eventName]) {
this._eventHandlers[eventName].push(callback);
}
},
/**
* Caller can remove events when app is installed/uninstalled
*
* @access public
* @param {String} eventName
* @param {Function} callback
* @memberOf AppsCache
*/
removeEventListener: function am_removeEventListener(eventName, callback) {
if (this._eventHandlers[eventName]) {
var index = this._eventHandlers[eventName].indexOf(callback);
if (index >= 0) {
this._eventHandlers[eventName].splice(index, 1);
}
}
},
};
var appsCache = new AppsCache();
return appsCache;
});