/* global BaseModule, asyncStorage, SIMSlotManager, SettingsHelper,
CallForwardingsIcon, LazyLoader */
'use strict';
(function() {
// Must be in sync with nsIDOMMozMobileCFInfo interface.
var _cfReason = {
CALL_FORWARD_REASON_UNCONDITIONAL: 0,
CALL_FORWARD_REASON_MOBILE_BUSY: 1,
CALL_FORWARD_REASON_NO_REPLY: 2,
CALL_FORWARD_REASON_NOT_REACHABLE: 3,
CALL_FORWARD_REASON_ALL_CALL_FORWARDING: 4,
CALL_FORWARD_REASON_ALL_CONDITIONAL_CALL_FORWARDING: 5
};
var _cfAction = {
CALL_FORWARD_ACTION_DISABLE: 0,
CALL_FORWARD_ACTION_ENABLE: 1,
CALL_FORWARD_ACTION_QUERY_STATUS: 2,
CALL_FORWARD_ACTION_REGISTRATION: 3,
CALL_FORWARD_ACTION_ERASURE: 4
};
/**
* The module initializes the call forwarding icon states and update the icons
* when call forwarding states changed.
* As we are not able to query the current call forwarding states from the
* carrier on startup, we initialized the icon state based on the cached
* information. When call forwarding states are changed, the module caches
* the state along with the corresponding iccId.
* @class CallForwarding
* @requires SIMSlotManager
* @requires SettingsHelper
*/
function CallForwarding() {
this._slots = null;
this._callForwardingHelper = null;
this._defaultCallForwardingIconStates = null;
this._callForwardingIconInitializedStates = null;
}
CallForwarding.STATES = [
'enabled'
];
CallForwarding.SETTINGS = [
'ril.cf.enabled'
];
BaseModule.create(CallForwarding, {
name: 'CallForwarding',
/**
* Add related event handlers. The sim cards may not be ready when starting.
* We register to "simslot-cardstatechange" and "simslot-iccinfochange" for
* updating the icons when ready. When users query the current call
* forwarding states in settings app, 'ril.cf.carrier.enabled' is used to
* notify the state changes. When users change the call forwarding states in
* settings app, we will receive the 'cfstatechange' event. All the events
* must be watched to have correct icon states.
* @memberof CallForwarding.prototype
*/
_addEventHandlers: function() {
window.addEventListener('simslot-cardstatechange', (function(event) {
this._initCallForwardingState(event.detail);
}).bind(this));
window.addEventListener('simslot-iccinfochange', (function(event) {
this._initCallForwardingState(event.detail);
}).bind(this));
// Get notified when users query the latest call forwarding states in
// settings app
navigator.mozSettings.addObserver('ril.cf.carrier.enabled',
(function(event) {
var detail = event.settingValue;
if (detail) {
this._onCallForwardingStateChanged(detail.index, detail.enabled);
}
}).bind(this));
this._slots.forEach(function(slot) {
var conn = slot.conn;
conn.addEventListener('cfstatechange',
this._updateCallForwardingIconState.bind(this, slot));
}, this);
},
/**
* Initialize the icon states based on iccId and cached information.
* @param {SIMSlot} slot The target sim slot.
* @memberof CallForwarding.prototype
*/
_initCallForwardingState: function(slot) {
var index = slot.index;
var simCard = slot.simCard;
if (this._callForwardingIconInitializedStates[index]) {
return;
}
var that = this;
var cardState = simCard && simCard.cardState;
var iccid = simCard && simCard.iccInfo && simCard.iccInfo.iccid;
// Disable call forwarding icon and early return when:
// 1. sim card not present, or
// 2. sim card state is not ready, or
// 3. sim card iccId is not available.
if (!simCard || cardState !== 'ready' || !iccid) {
that._callForwardingHelper.get(function(states) {
states[index] = false;
that._callForwardingHelper.set(states);
});
return;
}
asyncStorage.getItem('ril.cf.enabled.' + iccid, function(value) {
if (value === null) {
value = false;
}
that._callForwardingHelper.get(function(states) {
states[index] = value;
that._callForwardingHelper.set(states, function() {
that._callForwardingIconInitializedStates[index] = true;
});
});
});
},
/**
* Gets called when receiving "cfstatechange". It updates the cached
* information and icon states.
* @param {SIMSlot} slot The target sim slot.
* @param {Event} event The event.
* @memberof CallForwarding.prototype
*/
_updateCallForwardingIconState: function(slot, event) {
if (!event ||
(event.reason != _cfReason.CALL_FORWARD_REASON_UNCONDITIONAL &&
event.reason != _cfReason.CALL_FORWARD_REASON_ALL_CALL_FORWARDING)) {
return;
}
var index = slot.index;
var simCard = slot.simCard;
var enabled = false;
switch (event.action) {
case _cfAction.CALL_FORWARD_ACTION_REGISTRATION:
case _cfAction.CALL_FORWARD_ACTION_ENABLE:
enabled = true;
break;
case _cfAction.CALL_FORWARD_ACTION_ERASURE:
enabled = false;
break;
default:
enabled = false;
break;
}
this._callForwardingHelper.get((function(states) {
states[index] = enabled;
this._callForwardingHelper.set(states);
}).bind(this));
if (!simCard) {
return;
}
var iccid = simCard.iccInfo && simCard.iccInfo.iccid;
asyncStorage.setItem('ril.cf.enabled.' + iccid, enabled);
},
/**
* Gets called when 'ril.cf.carrier.enabled' changes. It updates the cached
* information and icon states.
* @param {Number} index The index of the sim card being changed.
* @param {Boolean} enabled The call forwarding state.
* @memberof CallForwarding.prototype
*/
_onCallForwardingStateChanged: function(index, enabled) {
this._callForwardingHelper.get((function(states) {
states[index] = enabled;
this._callForwardingHelper.set(states);
}).bind(this));
var simCard = this._slots[index].simCard;
if (!simCard) {
return;
}
var iccid = simCard.iccInfo && simCard.iccInfo.iccid;
asyncStorage.setItem('ril.cf.enabled.' + iccid, enabled);
},
enabled: function(index) {
return this._enabled[index];
},
/**
* Start the module.
* @memberof CallForwarding.prototype
*/
_start: function() {
this._slots = SIMSlotManager.getSlots();
this._enabled = [];
this._defaultCallForwardingIconStates =
Array.prototype.map.call(this._slots, function() { return false; });
this._callForwardingIconInitializedStates =
Array.prototype.map.call(this._slots, function() { return false; });
// XXX:
// We should use observe/read/write functionality in baseModule
// and remove the usage here.
LazyLoader.load(['shared/js/settings_helper.js']).then(() => {
this._callForwardingHelper =
SettingsHelper('ril.cf.enabled',
this._defaultCallForwardingIconStates);
this._addEventHandlers();
// Initialize the icon states
this._slots.forEach(function(slot) {
this._initCallForwardingState(slot);
}, this);
}).catch((err) => {
console.error(err);
});
},
'_observe_ril.cf.enabled': function(value) {
this._enabled = value || [];
var isAnyEnabled =
this._enabled.some(function(enabled) { return enabled; });
if (!this.icon && isAnyEnabled) {
LazyLoader.load(['js/call_forwarding_icon.js']).then(function() {
this.icon = new CallForwardingsIcon(this);
this.icon.start();
}.bind(this)).catch(function(err) {
console.error(err);
});
}
this.icon && this.icon.update();
}
});
})();