michael@0: /* Any copyright is dedicated to the Public Domain. michael@0: * http://creativecommons.org/publicdomain/zero/1.0/ */ michael@0: michael@0: MARIONETTE_TIMEOUT = 60000; michael@0: michael@0: const DATA_KEY = "ril.data.enabled"; michael@0: const DATA_ROAMING_KEY = "ril.data.roaming_enabled"; michael@0: const APN_KEY = "ril.data.apnSettings"; michael@0: michael@0: SpecialPowers.setBoolPref("dom.mozSettings.enabled", true); michael@0: SpecialPowers.addPermission("mobileconnection", true, document); michael@0: SpecialPowers.addPermission("settings-read", true, document); michael@0: SpecialPowers.addPermission("settings-write", true, document); michael@0: michael@0: let settings = window.navigator.mozSettings; michael@0: let connection = window.navigator.mozMobileConnections[0]; michael@0: ok(connection instanceof MozMobileConnection, michael@0: "connection is instanceof " + connection.constructor); michael@0: michael@0: michael@0: let pendingEmulatorCmdCount = 0; michael@0: function sendCmdToEmulator(cmd, callback) { michael@0: ++pendingEmulatorCmdCount; michael@0: michael@0: runEmulatorCmd(cmd, function(result) { michael@0: --pendingEmulatorCmdCount; michael@0: michael@0: is(result[0], "OK", "Emulator response"); michael@0: michael@0: if (callback) { michael@0: callback(); michael@0: } michael@0: }); michael@0: } michael@0: michael@0: let tasks = { michael@0: // List of test fuctions. Each of them should call |tasks.next()| when michael@0: // completed or |tasks.finish()| to jump to the last one. michael@0: _tasks: [], michael@0: _nextTaskIndex: 0, michael@0: michael@0: push: function(func) { michael@0: this._tasks.push(func); michael@0: }, michael@0: michael@0: next: function() { michael@0: let index = this._nextTaskIndex++; michael@0: let task = this._tasks[index]; michael@0: try { michael@0: task(); michael@0: } catch (ex) { michael@0: ok(false, "test task[" + index + "] throws: " + ex); michael@0: // Run last task as clean up if possible. michael@0: if (index != this._tasks.length - 1) { michael@0: this.finish(); michael@0: } michael@0: } michael@0: }, michael@0: michael@0: finish: function() { michael@0: this._tasks[this._tasks.length - 1](); michael@0: }, michael@0: michael@0: run: function() { michael@0: this.next(); michael@0: } michael@0: }; michael@0: michael@0: function setSetting(key, value, callback) { michael@0: let setLock = settings.createLock(); michael@0: let obj = {}; michael@0: obj[key] = value; michael@0: michael@0: let setReq = setLock.set(obj); michael@0: setReq.addEventListener("success", function onSetSuccess() { michael@0: ok(true, "set '" + key + "' to " + obj[key]); michael@0: if (callback) { michael@0: callback(); michael@0: } michael@0: }); michael@0: setReq.addEventListener("error", function onSetError() { michael@0: ok(false, "cannot set '" + key + "'"); michael@0: tasks.finish(); michael@0: }); michael@0: } michael@0: michael@0: function getSetting(key, callback) { michael@0: let getLock = settings.createLock(); michael@0: michael@0: let getReq = getLock.get(key); michael@0: getReq.addEventListener("success", function onGetSuccess() { michael@0: ok(true, "get " + key + " setting okay"); michael@0: let value = getReq.result[key]; michael@0: callback(value); michael@0: }); michael@0: getReq.addEventListener("error", function onGetError() { michael@0: ok(false, "cannot get '" + key + "'"); michael@0: tasks.finish(); michael@0: }); michael@0: } michael@0: michael@0: function setEmulatorAPN(callback) { michael@0: let apn = michael@0: [ michael@0: [ michael@0: {"carrier":"T-Mobile US", michael@0: "apn":"epc.tmobile.com", michael@0: "mmsc":"http://mms.msg.eng.t-mobile.com/mms/wapenc", michael@0: "types":["default","supl","mms"]} michael@0: ] michael@0: ]; michael@0: setSetting(APN_KEY, apn, callback); michael@0: } michael@0: michael@0: function setEmulatorRoaming(roaming, callback) { michael@0: log("Setting emulator roaming state: " + roaming + "."); michael@0: michael@0: // Set voice registration state first and then data registration state. michael@0: let cmd = "gsm voice " + (roaming ? "roaming" : "home"); michael@0: sendCmdToEmulator(cmd, function() { michael@0: michael@0: connection.addEventListener("voicechange", function onvoicechange() { michael@0: connection.removeEventListener("voicechange", onvoicechange); michael@0: log("mobileConnection.voice.roaming is now '" michael@0: + connection.voice.roaming + "'."); michael@0: is(connection.voice.roaming, roaming, "voice.roaming"); michael@0: michael@0: let cmd = "gsm data " + (roaming ? "roaming" : "home"); michael@0: sendCmdToEmulator(cmd, function() { michael@0: michael@0: connection.addEventListener("datachange", function ondatachange() { michael@0: connection.removeEventListener("datachange", ondatachange); michael@0: log("mobileConnection.data.roaming is now '" michael@0: + connection.data.roaming + "'."); michael@0: is(connection.data.roaming, roaming, "data.roaming"); michael@0: if (callback) { michael@0: callback(); michael@0: } michael@0: }); michael@0: }); michael@0: }); michael@0: }); michael@0: } michael@0: michael@0: function setEmulatorHome(callback) { michael@0: let voiceRegistration = false; michael@0: let dataRegistration = false; michael@0: michael@0: if (connection.voice.state != "registered") { michael@0: sendCmdToEmulator("gsm voice home", function() { michael@0: connection.addEventListener("voicechange", function onvoicechange() { michael@0: connection.removeEventListener("voicechange", onvoicechange); michael@0: log("mobileConnection.voice.state is now '" michael@0: + connection.voice.state + "'."); michael@0: is(connection.voice.state, "registered", "voice.state"); michael@0: voiceRegistration = true; michael@0: }); michael@0: }); michael@0: } else { michael@0: voiceRegistration = true; michael@0: } michael@0: michael@0: if (connection.data.state != "registered") { michael@0: sendCmdToEmulator("gsm data home", function() { michael@0: connection.addEventListener("datachange", function ondatachange() { michael@0: connection.removeEventListener("datachange", ondatachange); michael@0: log("mobileConnection.data.state is now '" michael@0: + connection.data.state + "'."); michael@0: is(connection.data.state, "registered", "data.state"); michael@0: dataRegistration = true; michael@0: }); michael@0: }); michael@0: } else { michael@0: dataRegistration = true; michael@0: } michael@0: michael@0: waitFor(callback, function() { michael@0: return (voiceRegistration && dataRegistration); michael@0: }); michael@0: } michael@0: michael@0: michael@0: tasks.push(function verifyInitialState() { michael@0: log("Verifying initial state."); michael@0: michael@0: // Want to start test with mobileConnection.data.state 'registered', michael@0: // This is the default state; if it is not currently this value then set it. michael@0: setEmulatorHome(function() { michael@0: // Want to start test with data off, michael@0: // This is the default state; if it is not currently this value then set it. michael@0: getSetting(DATA_KEY, function(result) { michael@0: let value = result; michael@0: log("Starting data enabled: " + value); michael@0: if (value) { michael@0: setSetting(DATA_KEY, false); michael@0: michael@0: connection.addEventListener("datachange", function ondatachange() { michael@0: connection.removeEventListener("datachange", ondatachange); michael@0: log("mobileConnection.data.connected is now '" michael@0: + connection.data.connected + "'."); michael@0: is(connection.data.connected, false, "data.connected"); michael@0: setEmulatorAPN(function() { michael@0: tasks.next(); michael@0: }); michael@0: }); michael@0: } else { michael@0: setEmulatorAPN(function() { michael@0: tasks.next(); michael@0: }); michael@0: } michael@0: }); michael@0: }); michael@0: }); michael@0: michael@0: tasks.push(function testEnableData() { michael@0: log("Turn data on."); michael@0: michael@0: connection.addEventListener("datachange", function ondatachange() { michael@0: connection.removeEventListener("datachange", ondatachange); michael@0: log("mobileConnection.data.connected is now '" michael@0: + connection.data.connected + "'."); michael@0: is(connection.data.connected, true, "data.connected"); michael@0: tasks.next(); michael@0: }); michael@0: michael@0: setSetting(DATA_KEY, true); michael@0: }); michael@0: michael@0: tasks.push(function testUnregisterDataWhileDataEnabled() { michael@0: log("Set data registration unregistered while data enabled."); michael@0: michael@0: // When data registration is unregistered, all data calls michael@0: // will be automatically deactivated. michael@0: sendCmdToEmulator("gsm data unregistered", function() { michael@0: connection.addEventListener("datachange", function ondatachange() { michael@0: log("mobileConnection.data.state is now '" michael@0: + connection.data.state + "'."); michael@0: if (connection.data.state == "notSearching") { michael@0: connection.removeEventListener("datachange", ondatachange); michael@0: log("mobileConnection.data.connected is now '" michael@0: + connection.data.connected + "'."); michael@0: is(connection.data.connected, false, "data.connected"); michael@0: tasks.next(); michael@0: } michael@0: }); michael@0: }); michael@0: }); michael@0: michael@0: tasks.push(function testRegisterDataWhileDataEnabled() { michael@0: log("Set data registration home while data enabled."); michael@0: michael@0: // When data registration is registered, data call will be michael@0: // (re)activated by gecko if ril.data.enabled is set to true. michael@0: sendCmdToEmulator("gsm data home", function() { michael@0: connection.addEventListener("datachange", function ondatachange() { michael@0: connection.removeEventListener("datachange", ondatachange); michael@0: log("mobileConnection.data.state is now '" michael@0: + connection.data.state + "'."); michael@0: is(connection.data.state, "registered", "data.state"); michael@0: michael@0: connection.addEventListener("datachange", function ondatachange() { michael@0: connection.removeEventListener("datachange", ondatachange); michael@0: log("mobileConnection.data.connected is now '" michael@0: + connection.data.connected + "'."); michael@0: is(connection.data.connected, true, "data.connected"); michael@0: tasks.next(); michael@0: }); michael@0: }); michael@0: }); michael@0: }); michael@0: michael@0: tasks.push(function testDisableDataRoamingWhileRoaming() { michael@0: log("Disable data roaming while roaming."); michael@0: michael@0: setSetting(DATA_ROAMING_KEY, false); michael@0: michael@0: // Wait for roaming state to change, then data connection should michael@0: // be disconnected due to data roaming set to off. michael@0: setEmulatorRoaming(true, function() { michael@0: connection.addEventListener("datachange", function ondatachange() { michael@0: connection.removeEventListener("datachange", ondatachange); michael@0: log("mobileConnection.data.connected is now '" michael@0: + connection.data.connected + "'."); michael@0: is(connection.data.connected, false, "data.connected"); michael@0: tasks.next(); michael@0: }); michael@0: }); michael@0: }); michael@0: michael@0: tasks.push(function testEnableDataRoamingWhileRoaming() { michael@0: log("Enable data roaming while roaming."); michael@0: michael@0: // Data should be re-connected as we enabled data roaming. michael@0: connection.addEventListener("datachange", function ondatachange() { michael@0: connection.removeEventListener("datachange", ondatachange); michael@0: log("mobileConnection.data.connected is now '" michael@0: + connection.data.connected + "'."); michael@0: is(connection.data.connected, true, "data.connected"); michael@0: tasks.next(); michael@0: }); michael@0: michael@0: setSetting(DATA_ROAMING_KEY, true); michael@0: }); michael@0: michael@0: tasks.push(function testDisableDataRoamingWhileNotRoaming() { michael@0: log("Disable data roaming while not roaming."); michael@0: michael@0: // Wait for roaming state to change then set data roaming back michael@0: // to off. michael@0: setEmulatorRoaming(false, function() { michael@0: setSetting(DATA_ROAMING_KEY, false); michael@0: michael@0: // No change event will be received cause data connection state michael@0: // remains the same. michael@0: window.setTimeout(function() { michael@0: is(connection.data.connected, true, "data.connected"); michael@0: tasks.next(); michael@0: }, 1000); michael@0: }); michael@0: }); michael@0: michael@0: tasks.push(function testDisableData() { michael@0: log("Turn data off."); michael@0: michael@0: connection.addEventListener("datachange", function ondatachange() { michael@0: connection.removeEventListener("datachange", ondatachange); michael@0: log("mobileConnection.data.connected is now '" michael@0: + connection.data.connected + "'."); michael@0: is(connection.data.connected, false, "data.connected"); michael@0: tasks.next(); michael@0: }); michael@0: michael@0: setSetting(DATA_KEY, false); michael@0: }); michael@0: michael@0: // WARNING: All tasks should be pushed before this!!! michael@0: tasks.push(function cleanUp() { michael@0: if (pendingEmulatorCmdCount) { michael@0: window.setTimeout(cleanUp, 100); michael@0: return; michael@0: } michael@0: michael@0: SpecialPowers.removePermission("mobileconnection", document); michael@0: SpecialPowers.removePermission("settings-write", document); michael@0: SpecialPowers.removePermission("settings-read", document); michael@0: SpecialPowers.clearUserPref("dom.mozSettings.enabled"); michael@0: finish(); michael@0: }); michael@0: michael@0: tasks.run(); michael@0: