From 5b8c158332aa7529c86c7ecab110435846748739 Mon Sep 17 00:00:00 2001 From: "Szu-Yu Chen [:aknow]" Date: Thu, 21 Nov 2013 09:09:14 -0500 Subject: [PATCH] Bug 856553 - Part 4: Add setRadioEnabled API (ril). r=hsinyi --- dom/system/gonk/RILContentHelper.js | 39 ++- dom/system/gonk/RadioInterfaceLayer.js | 395 ++++++++++++++++--------- dom/system/gonk/ril_consts.js | 6 + dom/system/gonk/ril_worker.js | 39 +-- 4 files changed, 324 insertions(+), 155 deletions(-) diff --git a/dom/system/gonk/RILContentHelper.js b/dom/system/gonk/RILContentHelper.js index 3e0df151a7f2..f9c4b5e09fe6 100644 --- a/dom/system/gonk/RILContentHelper.js +++ b/dom/system/gonk/RILContentHelper.js @@ -101,6 +101,8 @@ const RIL_IPC_MSG_NAMES = [ "RIL:SetRoamingPreference", "RIL:GetRoamingPreference", "RIL:ExitEmergencyCbMode", + "RIL:SetRadioEnabled", + "RIL:RadioStateChanged", "RIL:SetVoicePrivacyMode", "RIL:GetVoicePrivacyMode", "RIL:OtaStatusChanged" @@ -459,6 +461,7 @@ function RILContentHelper() { this.rilContexts[clientId] = { cardState: RIL.GECKO_CARDSTATE_UNKNOWN, networkSelectionMode: RIL.GECKO_NETWORK_SELECTION_UNKNOWN, + radioState: null, iccInfo: null, voiceConnectionInfo: new MobileConnectionInfo(), dataConnectionInfo: new MobileConnectionInfo() @@ -611,6 +614,7 @@ RILContentHelper.prototype = { } this.rilContexts[cId].cardState = rilContext.cardState; this.rilContexts[cId].networkSelectionMode = rilContext.networkSelectionMode; + this.rilContexts[cId].radioState = rilContext.detailedRadioState; this.updateIccInfo(cId, rilContext.iccInfo); this.updateConnectionInfo(rilContext.voice, this.rilContexts[cId].voiceConnectionInfo); this.updateConnectionInfo(rilContext.data, this.rilContexts[cId].dataConnectionInfo); @@ -657,6 +661,11 @@ RILContentHelper.prototype = { return context && context.networkSelectionMode; }, + getRadioState: function getRadioState(clientId) { + let context = this.getRilContext(clientId); + return context && context.radioState; + }, + /** * The networks that are currently trying to be selected (or "automatic"). * This helps ensure that only one network per client is selected at a time. @@ -1362,6 +1371,25 @@ RILContentHelper.prototype = { return request; }, + setRadioEnabled: function setRadioEnabled(clientId, window, enabled) { + if (window == null) { + throw Components.Exception("Can't get window object", + Cr.NS_ERROR_UNEXPECTED); + } + let request = Services.DOMRequest.createRequest(window); + let requestId = this.getRequestId(request); + + cpmm.sendAsyncMessage("RIL:SetRadioEnabled", { + clientId: clientId, + data: { + requestId: requestId, + enabled: enabled, + } + }); + + return request; + }, + _mobileConnectionListeners: null, _cellBroadcastListeners: null, _voicemailListeners: null, @@ -1767,6 +1795,16 @@ RILContentHelper.prototype = { "notifyEmergencyCbModeChanged", [data.active, data.timeoutMs]); break; + case "RIL:SetRadioEnabled": + this.handleSimpleRequest(data.requestId, data.errorMsg, null); + break; + case "RIL:RadioStateChanged": + this.rilContexts[clientId].radioState = data; + this._deliverEvent(clientId, + "_mobileConnectionListeners", + "notifyRadioStateChanged", + null); + break; case "RIL:SetVoicePrivacyMode": this.handleSimpleRequest(data.requestId, data.errorMsg, null); break; @@ -2094,4 +2132,3 @@ RILContentHelper.prototype = { this.NSGetFactory = XPCOMUtils.generateNSGetFactory([RILContentHelper, DOMMMIError, IccCardLockError]); - diff --git a/dom/system/gonk/RadioInterfaceLayer.js b/dom/system/gonk/RadioInterfaceLayer.js index 3750851a2a75..306d63f50f81 100644 --- a/dom/system/gonk/RadioInterfaceLayer.js +++ b/dom/system/gonk/RadioInterfaceLayer.js @@ -21,6 +21,7 @@ Cu.import("resource://gre/modules/XPCOMUtils.jsm"); Cu.import("resource://gre/modules/Services.jsm"); Cu.import("resource://gre/modules/Sntp.jsm"); Cu.import("resource://gre/modules/systemlibs.js"); +Cu.import("resource://gre/modules/Promise.jsm"); var RIL = {}; Cu.import("resource://gre/modules/ril_consts.js", RIL); @@ -106,6 +107,7 @@ const RIL_IPC_MOBILECONNECTION_MSG_NAMES = [ "RIL:SetRoamingPreference", "RIL:GetRoamingPreference", "RIL:ExitEmergencyCbMode", + "RIL:SetRadioEnabled", "RIL:SetVoicePrivacyMode", "RIL:GetVoicePrivacyMode" ]; @@ -417,6 +419,11 @@ XPCOMUtils.defineLazyGetter(this, "gMessageManager", function () { return null; } + if (msg.name === "RIL:SetRadioEnabled") { + // Special handler for SetRadioEnabled. + return gRadioEnabledController.receiveMessage(msg); + } + return radioInterface.receiveMessage(msg); }, @@ -466,7 +473,131 @@ XPCOMUtils.defineLazyGetter(this, "gMessageManager", function () { }; }); -// Initialize shared preference 'ril.numRadioInterfaces' according to system +XPCOMUtils.defineLazyGetter(this, "gRadioEnabledController", function () { + return { + ril: null, + pendingMessages: [], // For queueing "RIL:SetRadioEnabled" messages. + timer: null, + request: null, + deactivatingDeferred: {}, + + init: function init(ril) { + this.ril = ril; + }, + + receiveMessage: function(msg) { + if (DEBUG) debug("setRadioEnabled: receiveMessage: " + JSON.stringify(msg)); + this.pendingMessages.push(msg); + if (this.pendingMessages.length === 1) { + this._processNextMessage(); + } + }, + + isDeactivatingDataCalls: function() { + return this.request !== null; + }, + + finishDeactivatingDataCalls: function(clientId) { + if (DEBUG) debug("setRadioEnabled: finishDeactivatingDataCalls: " + clientId); + let deferred = this.deactivatingDeferred[clientId]; + if (deferred) { + deferred.resolve(); + } + }, + + _processNextMessage: function() { + if (this.pendingMessages.length === 0) { + return; + } + + let msg = this.pendingMessages.shift(); + this._handleMessage(msg); + }, + + _handleMessage: function(msg) { + if (DEBUG) debug("setRadioEnabled: handleMessage: " + JSON.stringify(msg)); + let radioInterface = this.ril.getRadioInterface(msg.json.clientId || 0); + + if (!radioInterface.isValidStateForSetRadioEnabled()) { + radioInterface.setRadioEnabledResponse(msg.target, msg.json.data, + "InvalidStateError"); + this._processNextMessage(); + return; + } + + if (radioInterface.isDummyForSetRadioEnabled(msg.json.data)) { + radioInterface.setRadioEnabledResponse(msg.target, msg.json.data); + this._processNextMessage(); + return; + } + + if (msg.json.data.enabled) { + radioInterface.receiveMessage(msg); + this._processNextMessage(); + } else { + this.request = (function() { + radioInterface.receiveMessage(msg); + this._processNextMessage(); + }).bind(this); + + // In some DSDS architecture with only one modem, toggling one radio may + // toggle both. Therefore, for safely turning off, we should first + // explicitly deactivate all data calls from all clients. + this._deactivateDataCalls().then(() => { + if (DEBUG) debug("setRadioEnabled: deactivation done"); + this._executeRequest(); + }); + + this._createTimer(); + } + }, + + _deactivateDataCalls: function() { + if (DEBUG) debug("setRadioEnabled: deactivating data calls..."); + this.deactivatingDeferred = {}; + + let promise = Promise.resolve(); + for (let i = 0, N = this.ril.numRadioInterfaces; i < N; ++i) { + promise = promise.then(this._deactivateDataCallsForClient(i)); + } + + return promise; + }, + + _deactivateDataCallsForClient: function(clientId) { + return (function() { + let deferred = this.deactivatingDeferred[clientId] = Promise.defer(); + this.ril.getRadioInterface(clientId).deactivateDataCalls(); + return deferred.promise; + }).bind(this); + }, + + _createTimer: function() { + if (!this.timer) { + this.timer = Cc["@mozilla.org/timer;1"].createInstance(Ci.nsITimer); + } + this.timer.initWithCallback(this._executeRequest, RADIO_POWER_OFF_TIMEOUT, + Ci.nsITimer.TYPE_ONE_SHOT); + }, + + _cancelTimer: function() { + if (this.timer) { + this.timer.cancel(); + } + }, + + _executeRequest: function() { + if (typeof this.request === "function") { + if (DEBUG) debug("setRadioEnabled: executeRequest"); + this._cancelTimer(); + this.request(); + this.request = null; + } + } + }; +}); + +// Initialize shared preference "ril.numRadioInterfaces" according to system // property. try { Services.prefs.setIntPref(kPrefRilNumRadioInterfaces, (function () { @@ -532,6 +663,7 @@ CdmaIccInfo.prototype = { function RadioInterfaceLayer() { gMessageManager.init(this); + gRadioEnabledController.init(this); let options = { debug: debugPref, @@ -685,7 +817,7 @@ WorkerMessenger.prototype = { * An optional message object to send. * @param callback [optional] * An optional callback function which is called when worker replies - * with an message containing a 'rilMessageToken' attribute of the + * with an message containing a "rilMessageToken" attribute of the * same value we passed. This callback function accepts only one * parameter -- the reply from worker. It also returns a boolean * value true to keep current token-callback mapping and wait for @@ -720,7 +852,7 @@ WorkerMessenger.prototype = { * @param rilMessageType * A text string for worker message type. * @param ipcType [optinal] - * A text string for ipc message type. 'msg.name' if omitted. + * A text string for ipc message type. "msg.name" if omitted. * * @TODO: Bug 815526 - deprecate RILContentHelper. */ @@ -758,6 +890,7 @@ function RadioInterface(options) { this.rilContext = { radioState: RIL.GECKO_RADIOSTATE_UNAVAILABLE, + detailedRadioState: null, cardState: RIL.GECKO_CARDSTATE_UNKNOWN, networkSelectionMode: RIL.GECKO_NETWORK_SELECTION_UNKNOWN, iccInfo: null, @@ -792,10 +925,7 @@ function RadioInterface(options) { this.operatorInfo = {}; - // Read the 'ril.radio.disabled' setting in order to start with a known - // value at boot time. let lock = gSettingsService.createLock(); - lock.get("ril.radio.disabled", this); // Read preferred network type from the setting DB. lock.get("ril.radio.preferredNetworkType", this); @@ -805,11 +935,11 @@ function RadioInterface(options) { lock.get("ril.data.enabled", this); lock.get("ril.data.apnSettings", this); - // Read the 'time.clock.automatic-update.enabled' setting to see if + // Read the "time.clock.automatic-update.enabled" setting to see if // we need to adjust the system clock time by NITZ or SNTP. lock.get(kSettingsClockAutoUpdateEnabled, this); - // Read the 'time.timezone.automatic-update.enabled' setting to see if + // Read the "time.timezone.automatic-update.enabled" setting to see if // we need to adjust the system timezone by NITZ. lock.get(kSettingsTimezoneAutoUpdateEnabled, this); @@ -836,11 +966,11 @@ function RadioInterface(options) { this.portAddressedSmsApps[WAP.WDP_PORT_PUSH] = this.handleSmsWdpPortPush.bind(this); this._sntp = new Sntp(this.setClockBySntp.bind(this), - Services.prefs.getIntPref('network.sntp.maxRetryCount'), - Services.prefs.getIntPref('network.sntp.refreshPeriod'), - Services.prefs.getIntPref('network.sntp.timeout'), - Services.prefs.getCharPref('network.sntp.pools').split(';'), - Services.prefs.getIntPref('network.sntp.port')); + Services.prefs.getIntPref("network.sntp.maxRetryCount"), + Services.prefs.getIntPref("network.sntp.refreshPeriod"), + Services.prefs.getIntPref("network.sntp.timeout"), + Services.prefs.getCharPref("network.sntp.pools").split(";"), + Services.prefs.getIntPref("network.sntp.port")); } RadioInterface.prototype = { @@ -863,11 +993,11 @@ RadioInterface.prototype = { /** * A utility function to copy objects. The srcInfo may contain - * 'rilMessageType', should ignore it. + * "rilMessageType", should ignore it. */ updateInfo: function updateInfo(srcInfo, destInfo) { for (let key in srcInfo) { - if (key === 'rilMessageType') { + if (key === "rilMessageType") { continue; } destInfo[key] = srcInfo[key]; @@ -876,7 +1006,7 @@ RadioInterface.prototype = { /** * A utility function to compare objects. The srcInfo may contain - * 'rilMessageType', should ignore it. + * "rilMessageType", should ignore it. */ isInfoChanged: function isInfoChanged(srcInfo, destInfo) { if (!destInfo) { @@ -884,7 +1014,7 @@ RadioInterface.prototype = { } for (let key in srcInfo) { - if (key === 'rilMessageType') { + if (key === "rilMessageType") { continue; } if (srcInfo[key] !== destInfo[key]) { @@ -991,6 +1121,9 @@ RadioInterface.prototype = { case "RIL:ExitEmergencyCbMode": this.workerMessenger.sendWithIPCMessage(msg, "exitEmergencyCbMode"); break; + case "RIL:SetRadioEnabled": + this.setRadioEnabled(msg.target, msg.json.data); + break; case "RIL:GetVoicemailInfo": // This message is sync. return this.voicemailInfo; @@ -1115,10 +1248,6 @@ RadioInterface.prototype = { case "stksessionend": gMessageManager.sendIccMessage("RIL:StkSessionEnd", this.clientId, null); break; - case "setRadioEnabled": - let lock = gSettingsService.createLock(); - lock.set("ril.radio.disabled", !message.on, null, null); - break; case "exitEmergencyCbMode": this.handleExitEmergencyCbMode(message); break; @@ -1481,71 +1610,44 @@ RadioInterface.prototype = { this.clientId, status); }, - handleRadioStateChange: function handleRadioStateChange(message) { - this._changingRadioPower = false; + _isRadioChanging: function _isRadioChanging() { + let state = this.rilContext.detailedRadioState; + return state == RIL.GECKO_DETAILED_RADIOSTATE_ENABLING || + state == RIL.GECKO_DETAILED_RADIOSTATE_DISABLING; + }, + _convertRadioState: function _converRadioState(state) { + switch (state) { + case RIL.GECKO_RADIOSTATE_OFF: + return RIL.GECKO_DETAILED_RADIOSTATE_DISABLED; + case RIL.GECKO_RADIOSTATE_READY: + return RIL.GECKO_DETAILED_RADIOSTATE_ENABLED; + default: + return RIL.GECKO_DETAILED_RADIOSTATE_UNKNOWN; + } + }, + + handleRadioStateChange: function handleRadioStateChange(message) { let newState = message.radioState; if (this.rilContext.radioState == newState) { return; } this.rilContext.radioState = newState; + this.handleDetailedRadioStateChanged(this._convertRadioState(newState)); + //TODO Should we notify this change as a card state change? - - this._ensureRadioState(); }, - _ensureRadioState: function _ensureRadioState() { - if (DEBUG) { - this.debug("Reported radio state is " + this.rilContext.radioState + - ", desired radio enabled state is " + this._radioEnabled); - } - if (this._radioEnabled == null) { - // We haven't read the initial value from the settings DB yet. - // Wait for that. + handleDetailedRadioStateChanged: function handleDetailedRadioStateChanged(state) { + if (this.rilContext.detailedRadioState == state) { return; } - if (!this._sysMsgListenerReady) { - // The UI's system app isn't ready yet for us to receive any - // events (e.g. incoming SMS, etc.). Wait for that. - return; - } - if (this.rilContext.radioState == RIL.GECKO_RADIOSTATE_UNKNOWN) { - // We haven't received a radio state notification from the RIL - // yet. Wait for that. - return; - } - if (this._changingRadioPower) { - // We're changing the radio power currently, ignore any changes. - return; - } - - if (this.rilContext.radioState == RIL.GECKO_RADIOSTATE_OFF && - this._radioEnabled) { - this._changingRadioPower = true; - this.setRadioEnabled(true); - } - if (this.rilContext.radioState == RIL.GECKO_RADIOSTATE_READY && - !this._radioEnabled) { - this._changingRadioPower = true; - this.powerOffRadioSafely(); - } + this.rilContext.detailedRadioState = state; + gMessageManager.sendMobileConnectionMessage("RIL:RadioStateChanged", + this.clientId, state); }, - _radioOffTimer: null, - _cancelRadioOffTimer: function _cancelRadioOffTimer() { - if (this._radioOffTimer) { - this._radioOffTimer.cancel(); - } - }, - _fireRadioOffTimer: function _fireRadioOffTimer() { - if (DEBUG) this.debug("Radio off timer expired, set radio power off right away."); - this.setRadioEnabled(false); - }, - - /** - * Clean up all existing data calls before turning radio off. - */ - powerOffRadioSafely: function powerOffRadioSafely() { + deactivateDataCalls: function deactivateDataCalls() { let dataDisconnecting = false; for each (let apnSetting in this.apnSettings.byApn) { for each (let type in apnSetting.types) { @@ -1556,16 +1658,12 @@ RadioInterface.prototype = { } } } - if (dataDisconnecting) { - if (this._radioOffTimer == null) { - this._radioOffTimer = Cc["@mozilla.org/timer;1"].createInstance(Ci.nsITimer); - } - this._radioOffTimer.initWithCallback(this._fireRadioOffTimer.bind(this), - RADIO_POWER_OFF_TIMEOUT, Ci.nsITimer.TYPE_ONE_SHOT); - this._radioOffAfterDataDisconnected = true; - return; + + // No data calls exist. It's safe to proceed the pending radio power off + // request. + if (gRadioEnabledController.isDeactivatingDataCalls() && !dataDisconnecting) { + gRadioEnabledController.finishDeactivatingDataCalls(this.clientId); } - this.setRadioEnabled(false); }, /** @@ -1611,8 +1709,8 @@ RadioInterface.prototype = { // Combine APN, user name, and password as the key of |byApn| object to // refer to the corresponding APN setting. let apnKey = inputApnSetting.apn + - (inputApnSetting.user || '') + - (inputApnSetting.password || ''); + (inputApnSetting.user || "") + + (inputApnSetting.password || ""); if (!this.apnSettings.byApn[apnKey]) { this.apnSettings.byApn[apnKey] = inputApnSetting; @@ -1729,7 +1827,7 @@ RadioInterface.prototype = { if (DEBUG) this.debug("Don't connect data call when Wifi is connected."); return; } - if (this._changingRadioPower) { + if (this._isRadioChanging()) { // We're changing the radio power currently, ignore any changes. return; } @@ -1936,7 +2034,7 @@ RadioInterface.prototype = { // At this point we could send a message to content to notify the user // that storing an incoming SMS failed, most likely due to a full disk. if (DEBUG) { - this.debug("Could not store SMS, error code " + rv); + this.debug("Could not store SMS " + message.id + ", error code " + rv); } return; } @@ -1946,8 +2044,8 @@ RadioInterface.prototype = { }.bind(this); if (message.messageClass != RIL.GECKO_SMS_MESSAGE_CLASSES[RIL.PDU_DCS_MSG_CLASS_0]) { - gMobileMessageDatabaseService.saveReceivedMessage(message, - notifyReceived); + message.id = gMobileMessageDatabaseService.saveReceivedMessage(message, + notifyReceived); } else { message.id = -1; message.threadId = 0; @@ -2005,7 +2103,7 @@ RadioInterface.prototype = { // Process pending radio power off request after all data calls // are disconnected. if (datacall.state == RIL.GECKO_NETWORK_STATE_UNKNOWN && - this._radioOffAfterDataDisconnected) { + gRadioEnabledController.isDeactivatingDataCalls()) { let anyDataConnected = false; for each (let apnSetting in this.apnSettings.byApn) { for each (let type in apnSetting.types) { @@ -2019,10 +2117,8 @@ RadioInterface.prototype = { } } if (!anyDataConnected) { - if (DEBUG) this.debug("All data connections are disconnected, set radio off."); - this._radioOffAfterDataDisconnected = false; - this._cancelRadioOffTimer(); - this.setRadioEnabled(false); + if (DEBUG) this.debug("All data connections are disconnected."); + gRadioEnabledController.finishDeactivatingDataCalls(this.clientId); } } }, @@ -2215,9 +2311,7 @@ RadioInterface.prototype = { observe: function observe(subject, topic, data) { switch (topic) { case kSysMsgListenerReadyObserverTopic: - Services.obs.removeObserver(this, kSysMsgListenerReadyObserverTopic); - this._sysMsgListenerReady = true; - this._ensureRadioState(); + this.setRadioEnabledInternal({enabled: true}, null); break; case kMozSettingsChangedObserverTopic: let setting = JSON.parse(data); @@ -2272,33 +2366,17 @@ RadioInterface.prototype = { } }, - // Flag to determine whether the UI's system app is ready to receive - // events yet. - _sysMsgListenerReady: false, - - // Flag to determine the radio state to start with when we boot up. It - // corresponds to the 'ril.radio.disabled' setting from the UI. - _radioEnabled: null, - - // Flag to ignore any radio power change requests during We're changing - // the radio power. - _changingRadioPower: false, - - // Flag to determine if we need to set radio off when we are notified a data - // call has been disconnected. - _radioOffAfterDataDisconnected: false, - // Data calls setting. dataCallSettings: null, apnSettings: null, // Flag to determine whether to update system clock automatically. It - // corresponds to the 'time.clock.automatic-update.enabled' setting. + // corresponds to the "time.clock.automatic-update.enabled" setting. _clockAutoUpdateEnabled: null, // Flag to determine whether to update system timezone automatically. It - // corresponds to the 'time.clock.automatic-update.enabled' setting. + // corresponds to the "time.clock.automatic-update.enabled" setting. _timezoneAutoUpdateEnabled: null, // Remember the last NITZ message so that we can set the time based on @@ -2346,11 +2424,6 @@ RadioInterface.prototype = { // nsISettingsServiceCallback handle: function handle(aName, aResult) { switch(aName) { - case "ril.radio.disabled": - if (DEBUG) this.debug("'ril.radio.disabled' is now " + aResult); - this._radioEnabled = !aResult; - this._ensureRadioState(); - break; case "ril.radio.preferredNetworkType": if (DEBUG) this.debug("'ril.radio.preferredNetworkType' is now " + aResult); this.setPreferredNetworkType(aResult); @@ -2422,10 +2495,6 @@ RadioInterface.prototype = { handleError: function handleError(aErrorMessage) { if (DEBUG) this.debug("There was an error while reading RIL settings."); - // Default radio to on. - this._radioEnabled = true; - this._ensureRadioState(); - // Clean data call setting. this.dataCallSettings.oldEnabled = false; this.dataCallSettings.enabled = false; @@ -2438,11 +2507,6 @@ RadioInterface.prototype = { // nsIRadioInterface - setRadioEnabled: function setRadioEnabled(value) { - if (DEBUG) this.debug("Setting radio power to " + value); - this.workerMessenger.send("setRadioPower", { on: value }); - }, - rilContext: null, // Handle phone functions of nsIRILContentHelper @@ -2510,6 +2574,62 @@ RadioInterface.prototype = { }).bind(this)); }, + isValidStateForSetRadioEnabled: function() { + let state = this.rilContext.radioState; + + return !this._isRadioChanging() && + (state == RIL.GECKO_RADIOSTATE_READY || + state == RIL.GECKO_RADIOSTATE_OFF); + }, + + isDummyForSetRadioEnabled: function(message) { + let state = this.rilContext.radioState; + + return (state == RIL.GECKO_RADIOSTATE_READY && message.enabled) || + (state == RIL.GECKO_RADIOSTATE_OFF && !message.enabled); + }, + + setRadioEnabledResponse: function(target, message, errorMsg) { + if (errorMsg) { + message.errorMsg = errorMsg; + } + + target.sendAsyncMessage("RIL:SetRadioEnabled", { + clientId: this.clientId, + data: message + }); + }, + + setRadioEnabled: function setRadioEnabled(target, message) { + if (DEBUG) { + this.debug("setRadioEnabled: " + JSON.stringify(message)); + } + + if (!this.isValidStateForSetRadioEnabled()) { + this.setRadioEnabledResponse(target, message, "InvalidStateError"); + return; + } + + if (this.isDummyForSetRadioEnabled(message)) { + this.setRadioEnabledResponse(target, message); + return; + } + + let callback = (function(response) { + this.setRadioEnabledResponse(target, response); + return false; + }).bind(this); + + this.setRadioEnabledInternal(message, callback); + }, + + setRadioEnabledInternal: function setRadioEnabledInternal(message, callback) { + let state = message.enabled ? RIL.GECKO_DETAILED_RADIOSTATE_ENABLING + : RIL.GECKO_DETAILED_RADIOSTATE_DISABLING; + this.handleDetailedRadioStateChanged(state); + this.workerMessenger.send("setRadioEnabled", message, callback); + }, + /** * List of tuples of national language identifier pairs. * @@ -2586,7 +2706,7 @@ RadioInterface.prototype = { // Bug 816082, when strict7BitEncoding is enabled, we should replace // characters that can't be encoded with GSM 7-Bit alphabets with '*'. - c = '*'; + c = "*"; if (langTable.indexOf(c) >= 0) { length++; } else if (langShiftTable.indexOf(c) >= 0) { @@ -2808,7 +2928,7 @@ RadioInterface.prototype = { // Bug 816082, when strict7BitEncoding is enabled, we should replace // characters that can't be encoded with GSM 7-Bit alphabets with '*'. - c = '*'; + c = "*"; if (langTable.indexOf(c) >= 0) { inc = 1; } @@ -2978,7 +3098,8 @@ RadioInterface.prototype = { if (DEBUG) this.debug("Error! Address is invalid when sending SMS: " + options.number); errorCode = Ci.nsIMobileMessageCallback.INVALID_ADDRESS_ERROR; - } else if (!this._radioEnabled) { + } else if (this.rilContext.detailedRadioState == + RIL.GECKO_DETAILED_RADIOSTATE_DISABLED) { if (DEBUG) this.debug("Error! Radio is disabled when sending SMS."); errorCode = Ci.nsIMobileMessageCallback.RADIO_DISABLED_ERROR; } else if (this.rilContext.cardState != "ready") { @@ -3063,7 +3184,7 @@ RadioInterface.prototype = { ? kSmsDeliverySuccessObserverTopic : kSmsDeliveryErrorObserverTopic; - // Broadcasting a 'sms-delivery-success' system message to open apps. + // Broadcasting a "sms-delivery-success" system message to open apps. if (topic == kSmsDeliverySuccessObserverTopic) { this.broadcastSmsSystemMessage(topic, domMessage); } @@ -3152,8 +3273,8 @@ RadioInterface.prototype = { return; } - gMobileMessageDatabaseService.saveSendingMessage(sendingMessage, - notifyResult); + let id = gMobileMessageDatabaseService.saveSendingMessage( + sendingMessage, notifyResult); }, registerDataCallCallback: function registerDataCallCallback(callback) { @@ -3393,11 +3514,11 @@ RILNetworkInterface.prototype = { dns2: null, get httpProxyHost() { - return this.apnSetting.proxy || ''; + return this.apnSetting.proxy || ""; }, get httpProxyPort() { - return this.apnSetting.port || ''; + return this.apnSetting.port || ""; }, /** @@ -3525,7 +3646,7 @@ RILNetworkInterface.prototype = { } if (this.state == datacall.state) { - if (datacall.state != GECKO_NETWORK_STATE_CONNECTED) { + if (datacall.state != RIL.GECKO_NETWORK_STATE_CONNECTED) { return; } // State remains connected, check for minor changes. diff --git a/dom/system/gonk/ril_consts.js b/dom/system/gonk/ril_consts.js index ee09e3810dd6..6e995427dd7f 100644 --- a/dom/system/gonk/ril_consts.js +++ b/dom/system/gonk/ril_consts.js @@ -2379,6 +2379,12 @@ this.GECKO_RADIOSTATE_UNAVAILABLE = null; this.GECKO_RADIOSTATE_OFF = "off"; this.GECKO_RADIOSTATE_READY = "ready"; +this.GECKO_DETAILED_RADIOSTATE_UNKNOWN = null; +this.GECKO_DETAILED_RADIOSTATE_ENABLING = "enabling"; +this.GECKO_DETAILED_RADIOSTATE_ENABLED = "enabled"; +this.GECKO_DETAILED_RADIOSTATE_DISABLING = "disabling"; +this.GECKO_DETAILED_RADIOSTATE_DISABLED = "disabled"; + this.GECKO_CARDSTATE_UNDETECTED = null; this.GECKO_CARDSTATE_ILLEGAL = "illegal"; this.GECKO_CARDSTATE_UNKNOWN = "unknown"; diff --git a/dom/system/gonk/ril_worker.js b/dom/system/gonk/ril_worker.js index fa8f98f0eb55..b599c4b3295b 100644 --- a/dom/system/gonk/ril_worker.js +++ b/dom/system/gonk/ril_worker.js @@ -944,15 +944,15 @@ let RIL = { }, /** - * Request the phone's radio power to be switched on or off. + * Request the phone's radio to be enabled or disabled. * - * @param on - * Boolean indicating the desired power state. + * @param enabled + * Boolean indicating the desired state. */ - setRadioPower: function setRadioPower(options) { + setRadioEnabled: function setRadioEnabled(options) { Buf.newParcel(REQUEST_RADIO_POWER, options); Buf.writeInt32(1); - Buf.writeInt32(options.on ? 1 : 0); + Buf.writeInt32(options.enabled ? 1 : 0); Buf.sendParcel(); }, @@ -1413,9 +1413,7 @@ let RIL = { } this.cachedDialRequest.onerror = onerror; this.cachedDialRequest.callback = this.sendDialRequest.bind(this, options); - - // Change radio setting value in settings DB to enable radio. - this.sendChromeMessage({rilMessageType: "setRadioEnabled", on: true}); + this.setRadioEnabled({enabled: true}); return; } @@ -5184,18 +5182,25 @@ RIL[REQUEST_OPERATOR] = function REQUEST_OPERATOR(length, options) { this._processOperator(operatorData); }; RIL[REQUEST_RADIO_POWER] = function REQUEST_RADIO_POWER(length, options) { - if (options.rilRequestError) { - if (this.cachedDialRequest && options.on) { - // Turning on radio fails. Notify the error of making an emergency call. - this.cachedDialRequest.onerror(GECKO_ERROR_RADIO_NOT_AVAILABLE); - this.cachedDialRequest = null; + if (options.rilMessageType == null) { + // The request was made by ril_worker itself. + if (options.rilRequestError) { + if (this.cachedDialRequest && options.enabled) { + // Turning on radio fails. Notify the error of making an emergency call. + this.cachedDialRequest.onerror(GECKO_ERROR_RADIO_NOT_AVAILABLE); + this.cachedDialRequest = null; + } + return; } + + if (this._isInitialRadioState) { + this._isInitialRadioState = false; + } + return; } - if (this._isInitialRadioState) { - this._isInitialRadioState = false; - } + this.sendChromeMessage(options); }; RIL[REQUEST_DTMF] = null; RIL[REQUEST_SEND_SMS] = function REQUEST_SEND_SMS(length, options) { @@ -6020,7 +6025,7 @@ RIL[UNSOLICITED_RESPONSE_RADIO_STATE_CHANGED] = function UNSOLICITED_RESPONSE_RA if (this._isInitialRadioState) { // Even radioState is RADIO_STATE_OFF, we still have to maually turn radio off, // otherwise REQUEST_GET_SIM_STATUS will still report CARD_STATE_PRESENT. - this.setRadioPower({on: false}); + this.setRadioEnabled({enabled: false}); } let newState;