gecko/dom/cellbroadcast/gonk/CellBroadcastService.js

304 lines
11 KiB
JavaScript

/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/. */
"use strict";
const {classes: Cc, interfaces: Ci, utils: Cu, results: Cr} = Components;
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
Cu.import("resource://gre/modules/Services.jsm");
XPCOMUtils.defineLazyGetter(this, "RIL", function () {
let obj = {};
Cu.import("resource://gre/modules/ril_consts.js", obj);
return obj;
});
const kMozSettingsChangedObserverTopic = "mozsettings-changed";
const kSettingsCellBroadcastDisabled = "ril.cellbroadcast.disabled";
const kSettingsCellBroadcastSearchList = "ril.cellbroadcast.searchlist";
XPCOMUtils.defineLazyServiceGetter(this, "gCellbroadcastMessenger",
"@mozilla.org/ril/system-messenger-helper;1",
"nsICellbroadcastMessenger");
XPCOMUtils.defineLazyServiceGetter(this, "gSettingsService",
"@mozilla.org/settingsService;1",
"nsISettingsService");
XPCOMUtils.defineLazyServiceGetter(this, "gRadioInterfaceLayer",
"@mozilla.org/ril;1",
"nsIRadioInterfaceLayer");
const GONK_CELLBROADCAST_SERVICE_CONTRACTID =
"@mozilla.org/cellbroadcast/gonkservice;1";
const GONK_CELLBROADCAST_SERVICE_CID =
Components.ID("{7ba407ce-21fd-11e4-a836-1bfdee377e5c}");
const CELLBROADCASTMESSAGE_CID =
Components.ID("{29474c96-3099-486f-bb4a-3c9a1da834e4}");
const CELLBROADCASTETWSINFO_CID =
Components.ID("{59f176ee-9dcd-4005-9d47-f6be0cd08e17}");
const NS_XPCOM_SHUTDOWN_OBSERVER_ID = "xpcom-shutdown";
let DEBUG;
function debug(s) {
dump("CellBroadcastService: " + s);
}
function CellBroadcastService() {
this._listeners = [];
this._updateDebugFlag();
let lock = gSettingsService.createLock();
/**
* Read the settings of the toggle of Cellbroadcast Service:
*
* Simple Format: Boolean
* true if CBS is disabled. The value is applied to all RadioInterfaces.
* Enhanced Format: Array of Boolean
* Each element represents the toggle of CBS per RadioInterface.
*/
lock.get(kSettingsCellBroadcastDisabled, this);
/**
* Read the Cell Broadcast Search List setting to set listening channels:
*
* Simple Format:
* String of integers or integer ranges separated by comma.
* For example, "1, 2, 4-6"
* Enhanced Format:
* Array of Objects with search lists specified in gsm/cdma network.
* For example, [{'gsm' : "1, 2, 4-6", 'cdma' : "1, 50, 99"},
* {'cdma' : "3, 6, 8-9"}]
* This provides the possibility to
* 1. set gsm/cdma search list individually for CDMA+LTE device.
* 2. set search list per RadioInterface.
*/
lock.get(kSettingsCellBroadcastSearchList, this);
Services.obs.addObserver(this, NS_XPCOM_SHUTDOWN_OBSERVER_ID, false);
Services.obs.addObserver(this, kMozSettingsChangedObserverTopic, false);
}
CellBroadcastService.prototype = {
classID: GONK_CELLBROADCAST_SERVICE_CID,
classInfo: XPCOMUtils.generateCI({classID: GONK_CELLBROADCAST_SERVICE_CID,
contractID: GONK_CELLBROADCAST_SERVICE_CONTRACTID,
classDescription: "CellBroadcastService",
interfaces: [Ci.nsICellBroadcastService,
Ci.nsIGonkCellBroadcastService],
flags: Ci.nsIClassInfo.SINGLETON}),
QueryInterface: XPCOMUtils.generateQI([Ci.nsICellBroadcastService,
Ci.nsIGonkCellBroadcastService,
Ci.nsISettingsServiceCallback,
Ci.nsIObserver]),
// An array of nsICellBroadcastListener instances.
_listeners: null,
// Setting values of Cell Broadcast SearchList.
_cellBroadcastSearchList: null,
_updateDebugFlag: function() {
try {
DEBUG = RIL.DEBUG_RIL ||
Services.prefs.getBoolPref(kPrefRilDebuggingEnabled);
} catch (e) {}
},
_retrieveSettingValueByClient: function(aClientId, aSettings) {
return Array.isArray(aSettings) ? aSettings[aClientId] : aSettings;
},
/**
* Helper function to set CellBroadcastDisabled to each RadioInterface.
*/
setCellBroadcastDisabled: function(aSettings) {
let numOfRilClients = gRadioInterfaceLayer.numRadioInterfaces;
let responses = [];
for (let clientId = 0; clientId < numOfRilClients; clientId++) {
gRadioInterfaceLayer
.getRadioInterface(clientId)
.sendWorkerMessage("setCellBroadcastDisabled",
{ disabled: this._retrieveSettingValueByClient(clientId, aSettings) });
}
},
/**
* Helper function to set CellBroadcastSearchList to each RadioInterface.
*/
setCellBroadcastSearchList: function(aSettings) {
let numOfRilClients = gRadioInterfaceLayer.numRadioInterfaces;
let responses = [];
for (let clientId = 0; clientId < numOfRilClients; clientId++) {
let newSearchList = this._retrieveSettingValueByClient(clientId, aSettings);
let oldSearchList = this._retrieveSettingValueByClient(clientId,
this._cellBroadcastSearchList);
if ((newSearchList == oldSearchList) ||
(newSearchList && oldSearchList &&
newSearchList.gsm == oldSearchList.gsm &&
newSearchList.cdma == oldSearchList.cdma)) {
return;
}
gRadioInterfaceLayer
.getRadioInterface(clientId).sendWorkerMessage("setCellBroadcastSearchList",
{ searchList: newSearchList },
(function callback(aResponse) {
if (DEBUG && !aResponse.success) {
debug("Failed to set new search list: " + newSearchList +
" to client id: " + clientId);
}
responses.push(aResponse);
if (responses.length == numOfRilClients) {
let successCount = 0;
for (let i = 0; i < responses.length; i++) {
if (responses[i].success) {
successCount++;
}
}
if (successCount == numOfRilClients) {
this._cellBroadcastSearchList = aSettings;
} else {
// Rollback the change when failure.
let lock = gSettingsService.createLock();
lock.set(kSettingsCellBroadcastSearchList,
this._cellBroadcastSearchList, null);
}
}
return false;
}).bind(this));
}
},
/**
* nsICellBroadcastService interface
*/
registerListener: function(aListener) {
if (this._listeners.indexOf(aListener) >= 0) {
throw Cr.NS_ERROR_UNEXPECTED;
}
this._listeners.push(aListener);
},
unregisterListener: function(aListener) {
let index = this._listeners.indexOf(aListener);
if (index < 0) {
throw Cr.NS_ERROR_UNEXPECTED;
}
this._listeners.splice(index, 1);
},
/**
* nsIGonkCellBroadcastService interface
*/
notifyMessageReceived: function(aServiceId,
aGsmGeographicalScope,
aMessageCode,
aMessageId,
aLanguage,
aBody,
aMessageClass,
aTimestamp,
aCdmaServiceCategory,
aHasEtwsInfo,
aEtwsWarningType,
aEtwsEmergencyUserAlert,
aEtwsPopup) {
// Broadcast CBS System message
gCellbroadcastMessenger.notifyCbMessageReceived(aServiceId,
aGsmGeographicalScope,
aMessageCode,
aMessageId,
aLanguage,
aBody,
aMessageClass,
aTimestamp,
aCdmaServiceCategory,
aHasEtwsInfo,
aEtwsWarningType,
aEtwsEmergencyUserAlert,
aEtwsPopup);
// Notify received message to registered listener
for (let listener of this._listeners) {
try {
listener.notifyMessageReceived(aServiceId,
aGsmGeographicalScope,
aMessageCode,
aMessageId,
aLanguage,
aBody,
aMessageClass,
aTimestamp,
aCdmaServiceCategory,
aHasEtwsInfo,
aEtwsWarningType,
aEtwsEmergencyUserAlert,
aEtwsPopup);
} catch (e) {
debug("listener threw an exception: " + e);
}
}
},
/**
* nsISettingsServiceCallback interface.
*/
handle: function(aName, aResult) {
switch (aName) {
case kSettingsCellBroadcastSearchList:
if (DEBUG) {
debug("'" + kSettingsCellBroadcastSearchList +
"' is now " + JSON.stringify(aResult));
}
this.setCellBroadcastSearchList(aResult);
break;
case kSettingsCellBroadcastDisabled:
if (DEBUG) {
debug("'" + kSettingsCellBroadcastDisabled +
"' is now " + JSON.stringify(aResult));
}
this.setCellBroadcastDisabled(aResult);
break;
}
},
/**
* nsIObserver interface.
*/
observe: function(aSubject, aTopic, aData) {
switch (aTopic) {
case kMozSettingsChangedObserverTopic:
if ("wrappedJSObject" in aSubject) {
aSubject = aSubject.wrappedJSObject;
}
this.handle(aSubject.key, aSubject.value);
break;
case NS_XPCOM_SHUTDOWN_OBSERVER_ID:
Services.obs.removeObserver(this, NS_XPCOM_SHUTDOWN_OBSERVER_ID);
Services.obs.removeObserver(this, kMozSettingsChangedObserverTopic);
// Remove all listeners.
this._listeners = [];
break;
}
}
};
this.NSGetFactory = XPCOMUtils.generateNSGetFactory([CellBroadcastService]);