mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-26 06:11:37 +00:00
Bug 744344 - B2G RIL: Add DOM API for getting the list of available networks. r=philikon sr=sicking
Also added a new MobileOperatorInfo type that exposes operator name, MNC, MCC, and operator/network status, and accompanying emulator Marionette tests.
This commit is contained in:
parent
93d0243b85
commit
e5f515143e
@ -32,7 +32,11 @@ interface nsIDOMMozMobileConnection : nsIDOMEventTarget
|
||||
/**
|
||||
* Search for available networks.
|
||||
*
|
||||
* If successful, the request result will be an array of operator names.
|
||||
* If successful, the request's onsuccess will be called, and the request's
|
||||
* result will be an array of nsIDOMMozMobileOperatorInfo.
|
||||
*
|
||||
* Otherwise, the request's onerror will be called, and the request's error
|
||||
* will be either 'RadioNotAvailable', 'RequestNotSupported', or 'GenericFailure'.
|
||||
*/
|
||||
nsIDOMDOMRequest getNetworks();
|
||||
|
||||
@ -208,3 +212,34 @@ interface nsIDOMMozMobileConnectionInfo : nsISupports
|
||||
readonly attribute jsval relSignalStrength;
|
||||
|
||||
};
|
||||
|
||||
[scriptable, uuid(79217f7a-4401-4d75-9654-3b28bba698c9)]
|
||||
interface nsIDOMMozMobileOperatorInfo : nsISupports
|
||||
{
|
||||
/**
|
||||
* Short name of the network operator
|
||||
*/
|
||||
readonly attribute DOMString shortName;
|
||||
|
||||
/**
|
||||
* Long name of the network operator
|
||||
*/
|
||||
readonly attribute DOMString longName;
|
||||
|
||||
/**
|
||||
* Mobile Country Code (MCC) of the network operator
|
||||
*/
|
||||
readonly attribute unsigned short mcc;
|
||||
|
||||
/**
|
||||
* Mobile Network Code (MNC) of the network operator
|
||||
*/
|
||||
readonly attribute unsigned short mnc;
|
||||
|
||||
/**
|
||||
* State of this network operator.
|
||||
*
|
||||
* Possible values: 'available', 'connected', 'forbidden', or null (unknown)
|
||||
*/
|
||||
readonly attribute DOMString state;
|
||||
};
|
||||
|
5
dom/network/tests/marionette/manifest.ini
Normal file
5
dom/network/tests/marionette/manifest.ini
Normal file
@ -0,0 +1,5 @@
|
||||
|
||||
[test_mobile_networks.js]
|
||||
b2g = true
|
||||
browser = false
|
||||
qemu = true
|
52
dom/network/tests/marionette/test_mobile_networks.js
Normal file
52
dom/network/tests/marionette/test_mobile_networks.js
Normal file
@ -0,0 +1,52 @@
|
||||
/* 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/. */
|
||||
|
||||
// getNetworks() can take some time..
|
||||
MARIONETTE_TIMEOUT = 30000;
|
||||
|
||||
const WHITELIST_PREF = "dom.mobileconnection.whitelist";
|
||||
let uriPrePath = window.location.protocol + "//" + window.location.host;
|
||||
SpecialPowers.setCharPref(WHITELIST_PREF, uriPrePath);
|
||||
|
||||
ok(navigator.mozMobileConnection instanceof MozMobileConnection,
|
||||
"mozMobileConnection is instanceof " + navigator.mozMobileConnection.constructor);
|
||||
|
||||
let request = navigator.mozMobileConnection.getNetworks();
|
||||
ok(request instanceof DOMRequest,
|
||||
"request is instanceof " + request.constructor);
|
||||
|
||||
request.onerror = function() {
|
||||
ok(false, request.error);
|
||||
cleanUp();
|
||||
};
|
||||
|
||||
request.onsuccess = function() {
|
||||
ok('result' in request, "Request did not contain a result");
|
||||
let networks = request.result;
|
||||
|
||||
// The emulator RIL server should always return 2 networks:
|
||||
// {"longName":"Android","shortName":"Android","mcc":310,"mnc":260,"state":"available"}
|
||||
// {"longName":"TelKila","shortName":"TelKila","mcc":310,"mnc":295,"state":"available"}
|
||||
is(networks.length, 2);
|
||||
|
||||
let network1 = networks[0];
|
||||
is(network1.longName, "Android");
|
||||
is(network1.shortName, "Android");
|
||||
is(network1.mcc, 310);
|
||||
is(network1.mnc, 260);
|
||||
is(network1.state, "available");
|
||||
|
||||
let network2 = networks[1];
|
||||
is(network2.longName, "TelKila");
|
||||
is(network2.shortName, "TelKila");
|
||||
is(network2.mcc, 310);
|
||||
is(network2.mnc, 295);
|
||||
is(network2.state, "available");
|
||||
cleanUp();
|
||||
};
|
||||
|
||||
function cleanUp() {
|
||||
SpecialPowers.clearUserPref(WHITELIST_PREF);
|
||||
finish();
|
||||
}
|
@ -19,12 +19,15 @@ const RILCONTENTHELPER_CID =
|
||||
Components.ID("{472816e1-1fd6-4405-996c-806f9ea68174}");
|
||||
const MOBILECONNECTIONINFO_CID =
|
||||
Components.ID("{a35cfd39-2d93-4489-ac7d-396475dacb27}");
|
||||
const MOBILEOPERATORINFO_CID =
|
||||
Components.ID("{a6c8416c-09b4-46d1-bf29-6520d677d085}");
|
||||
|
||||
const RIL_IPC_MSG_NAMES = [
|
||||
"RIL:CardStateChanged",
|
||||
"RIL:VoiceInfoChanged",
|
||||
"RIL:DataInfoChanged",
|
||||
"RIL:EnumerateCalls",
|
||||
"RIL:GetAvailableNetworks",
|
||||
"RIL:CallStateChanged",
|
||||
"RIL:CallError",
|
||||
"RIL:GetCardLock:Return:OK",
|
||||
@ -65,6 +68,25 @@ MobileConnectionInfo.prototype = {
|
||||
relSignalStrength: null
|
||||
};
|
||||
|
||||
function MobileOperatorInfo() {}
|
||||
MobileOperatorInfo.prototype = {
|
||||
QueryInterface: XPCOMUtils.generateQI([Ci.nsIDOMMozMobileOperatorInfo]),
|
||||
classID: MOBILEOPERATORINFO_CID,
|
||||
classInfo: XPCOMUtils.generateCI({
|
||||
classID: MOBILEOPERATORINFO_CID,
|
||||
classDescription: "MobileOperatorInfo",
|
||||
flags: Ci.nsIClassInfo.DOM_OBJECT,
|
||||
interfaces: [Ci.nsIDOMMozMobileOperatorInfo]
|
||||
}),
|
||||
|
||||
// nsIDOMMozMobileOperatorInfo
|
||||
|
||||
shortName: null,
|
||||
longName: null,
|
||||
mcc: 0,
|
||||
mnc: 0,
|
||||
state: null
|
||||
};
|
||||
|
||||
function RILContentHelper() {
|
||||
this.voiceConnectionInfo = new MobileConnectionInfo();
|
||||
@ -108,8 +130,16 @@ RILContentHelper.prototype = {
|
||||
dataConnectionInfo: null,
|
||||
|
||||
getNetworks: function getNetworks(window) {
|
||||
//TODO bug 744344
|
||||
throw Components.Exception("Not implemented", Cr.NS_ERROR_NOT_IMPLEMENTED);
|
||||
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:GetAvailableNetworks", requestId);
|
||||
return request;
|
||||
},
|
||||
|
||||
getCardLock: function getCardLock(window, lockType) {
|
||||
@ -269,6 +299,9 @@ RILContentHelper.prototype = {
|
||||
case "RIL:EnumerateCalls":
|
||||
this.handleEnumerateCalls(msg.json);
|
||||
break;
|
||||
case "RIL:GetAvailableNetworks":
|
||||
this.handleGetAvailableNetworks(msg.json);
|
||||
break;
|
||||
case "RIL:CallStateChanged":
|
||||
this._deliverTelephonyCallback("callStateChanged",
|
||||
[msg.json.callIndex, msg.json.state,
|
||||
@ -276,9 +309,9 @@ RILContentHelper.prototype = {
|
||||
break;
|
||||
case "RIL:CallError":
|
||||
this._deliverTelephonyCallback("notifyError",
|
||||
[msg.json.callIndex,
|
||||
msg.json.error]);
|
||||
break;
|
||||
[msg.json.callIndex,
|
||||
msg.json.error]);
|
||||
break;
|
||||
case "RIL:GetCardLock:Return:OK":
|
||||
case "RIL:SetCardLock:Return:OK":
|
||||
case "RIL:UnlockCardLock:Return:OK":
|
||||
@ -319,6 +352,37 @@ RILContentHelper.prototype = {
|
||||
}
|
||||
},
|
||||
|
||||
handleGetAvailableNetworks: function handleGetAvailableNetworks(message) {
|
||||
debug("handleGetAvailableNetworks: " + JSON.stringify(message));
|
||||
|
||||
let requestId = message.requestId;
|
||||
let request = this.takeRequest(requestId);
|
||||
if (!request) {
|
||||
debug("no DOMRequest found with request ID: " + requestId);
|
||||
return;
|
||||
}
|
||||
|
||||
if (message.error) {
|
||||
debug("Received error from getAvailableNetworks: " + message.error);
|
||||
Services.DOMRequest.fireError(request, message.error);
|
||||
return;
|
||||
}
|
||||
|
||||
let networks = message.networks;
|
||||
for (let i = 0; i < networks.length; i++) {
|
||||
let network = networks[i];
|
||||
let info = new MobileOperatorInfo();
|
||||
|
||||
for (let key in network) {
|
||||
info[key] = network[key];
|
||||
}
|
||||
|
||||
networks[i] = info;
|
||||
}
|
||||
|
||||
Services.DOMRequest.fireSuccess(request, networks);
|
||||
},
|
||||
|
||||
_deliverTelephonyCallback: function _deliverTelephonyCallback(name, args) {
|
||||
if (!this._telephonyCallbacks) {
|
||||
return;
|
||||
|
@ -44,6 +44,7 @@ const RIL_IPC_MSG_NAMES = [
|
||||
"RIL:RejectCall",
|
||||
"RIL:HoldCall",
|
||||
"RIL:ResumeCall",
|
||||
"RIL:GetAvailableNetworks",
|
||||
"RIL:GetCardLock",
|
||||
"RIL:UnlockCardLock",
|
||||
"RIL:SetCardLock"
|
||||
@ -235,6 +236,9 @@ RadioInterfaceLayer.prototype = {
|
||||
case "RIL:ResumeCall":
|
||||
this.resumeCall(msg.json);
|
||||
break;
|
||||
case "RIL:GetAvailableNetworks":
|
||||
this.getAvailableNetworks(msg.json);
|
||||
break;
|
||||
case "RIL:GetCardLock":
|
||||
this.getCardLock(msg.json);
|
||||
break;
|
||||
@ -279,6 +283,9 @@ RadioInterfaceLayer.prototype = {
|
||||
case "callError":
|
||||
this.handleCallError(message);
|
||||
break;
|
||||
case "getAvailableNetworks":
|
||||
this.handleGetAvailableNetworks(message);
|
||||
break;
|
||||
case "voiceregistrationstatechange":
|
||||
this.updateVoiceConnection(message);
|
||||
break;
|
||||
@ -560,6 +567,15 @@ RadioInterfaceLayer.prototype = {
|
||||
ppmm.sendAsyncMessage("RIL:EnumerateCalls", calls);
|
||||
},
|
||||
|
||||
/**
|
||||
* Handle available networks returned by the 'getAvailableNetworks' request.
|
||||
*/
|
||||
handleGetAvailableNetworks: function handleGetAvailableNetworks(message) {
|
||||
debug("handleGetAvailableNetworks: " + JSON.stringify(message));
|
||||
|
||||
ppmm.sendAsyncMessage("RIL:GetAvailableNetworks", message);
|
||||
},
|
||||
|
||||
/**
|
||||
* Handle call error.
|
||||
*/
|
||||
@ -834,6 +850,10 @@ RadioInterfaceLayer.prototype = {
|
||||
this.worker.postMessage({type: "resumeCall", callIndex: callIndex});
|
||||
},
|
||||
|
||||
getAvailableNetworks: function getAvailableNetworks(requestId) {
|
||||
this.worker.postMessage({type: "getAvailableNetworks", requestId: requestId});
|
||||
},
|
||||
|
||||
get microphoneMuted() {
|
||||
return gAudioManager.microphoneMuted;
|
||||
},
|
||||
|
@ -207,6 +207,17 @@ const ERROR_SS_MODIFIED_TO_USSD = 24;
|
||||
const ERROR_SS_MODIFIED_TO_SS = 25;
|
||||
const ERROR_SUBSCRIPTION_NOT_SUPPORTED = 26;
|
||||
|
||||
const GECKO_ERROR_SUCCESS = null;
|
||||
const GECKO_ERROR_RADIO_NOT_AVAILABLE = "RadioNotAvailable";
|
||||
const GECKO_ERROR_GENERIC_FAILURE = "GenericFailure";
|
||||
const GECKO_ERROR_REQUEST_NOT_SUPPORTED = "RequestNotSupported";
|
||||
|
||||
const RIL_ERROR_TO_GECKO_ERROR = {};
|
||||
RIL_ERROR_TO_GECKO_ERROR[ERROR_SUCCESS] = GECKO_ERROR_SUCCESS;
|
||||
RIL_ERROR_TO_GECKO_ERROR[ERROR_RADIO_NOT_AVAILABLE] = GECKO_ERROR_RADIO_NOT_AVAILABLE;
|
||||
RIL_ERROR_TO_GECKO_ERROR[ERROR_GENERIC_FAILURE] = GECKO_ERROR_GENERIC_FAILURE;
|
||||
RIL_ERROR_TO_GECKO_ERROR[ERROR_REQUEST_NOT_SUPPORTED] = GECKO_ERROR_REQUEST_NOT_SUPPORTED;
|
||||
|
||||
// 3GPP 23.040 clause 9.2.3.6 TP-Message-Reference(TP-MR):
|
||||
// The number of times the MS automatically repeats the SMS-SUBMIT shall be in
|
||||
// the range 1 to 3 but the precise number is an implementation matter.
|
||||
@ -282,6 +293,11 @@ const CARD_APPTYPE_ISIM = 5;
|
||||
|
||||
const CARD_MAX_APPS = 8;
|
||||
|
||||
const NETWORK_STATE_UNKNOWN = "unknown";
|
||||
const NETWORK_STATE_AVAILABLE = "available";
|
||||
const NETWORK_STATE_CONNECTED = "connected";
|
||||
const NETWORK_STATE_FORBIDDEN = "forbidden";
|
||||
|
||||
const NETWORK_SELECTION_MODE_AUTOMATIC = 0;
|
||||
const NETWORK_SELECTION_MODE_MANUAL = 1;
|
||||
|
||||
@ -1351,6 +1367,9 @@ const GECKO_NETWORK_STATE_SUSPENDED = 2;
|
||||
const GECKO_NETWORK_STATE_DISCONNECTING = 3;
|
||||
const GECKO_NETWORK_STATE_DISCONNECTED = 4;
|
||||
|
||||
// Used for QUERY_AVAILABLE_NETWORKS status of "unknown"
|
||||
const GECKO_QAN_STATE_UNKNOWN = null;
|
||||
|
||||
const CALL_FAIL_UNOBTAINABLE_NUMBER = 1;
|
||||
const CALL_FAIL_NORMAL = 16;
|
||||
const CALL_FAIL_BUSY = 17;
|
||||
|
@ -1391,6 +1391,15 @@ let RIL = {
|
||||
this.getNetworkSelectionMode();
|
||||
},
|
||||
|
||||
/**
|
||||
* Get the available networks
|
||||
*/
|
||||
getAvailableNetworks: function getAvailableNetworks(options) {
|
||||
if (DEBUG) debug("Getting available networks");
|
||||
Buf.newParcel(REQUEST_QUERY_AVAILABLE_NETWORKS, options);
|
||||
Buf.sendParcel();
|
||||
},
|
||||
|
||||
/**
|
||||
* Get current calls.
|
||||
*/
|
||||
@ -2186,6 +2195,66 @@ let RIL = {
|
||||
}
|
||||
},
|
||||
|
||||
_processNetworks: function _processNetworks() {
|
||||
let strings = Buf.readStringList();
|
||||
let networks = [];
|
||||
|
||||
for (let i = 0; i < strings.length; i += 4) {
|
||||
let network = {
|
||||
longName: strings[i],
|
||||
shortName: strings[i + 1],
|
||||
mcc: 0, mnc: 0,
|
||||
state: null
|
||||
};
|
||||
|
||||
let networkTuple = strings[i + 2];
|
||||
try {
|
||||
this._processNetworkTuple(networkTuple, network);
|
||||
} catch (e) {
|
||||
debug("Error processing operator tuple: " + e);
|
||||
}
|
||||
|
||||
let state = strings[i + 3];
|
||||
if (state === NETWORK_STATE_UNKNOWN) {
|
||||
// TODO: looks like this might conflict in style with
|
||||
// GECKO_NETWORK_STYLE_UNKNOWN / nsINetworkManager
|
||||
state = GECKO_QAN_STATE_UNKNOWN;
|
||||
}
|
||||
|
||||
network.state = state;
|
||||
networks.push(network);
|
||||
}
|
||||
return networks;
|
||||
},
|
||||
|
||||
/**
|
||||
* The "numeric" portion of the operator info is a tuple
|
||||
* containing MCC (country code) and MNC (network code).
|
||||
* AFAICT, MCC should always be 3 digits, making the remaining
|
||||
* portion the MNC.
|
||||
*/
|
||||
_processNetworkTuple: function _processNetworkTuple(networkTuple, network) {
|
||||
let tupleLen = networkTuple.length;
|
||||
let mcc = 0, mnc = 0;
|
||||
|
||||
if (tupleLen == 5 || tupleLen == 6) {
|
||||
mcc = parseInt(networkTuple.substr(0, 3), 10);
|
||||
if (isNaN(mcc)) {
|
||||
throw new Error("MCC could not be parsed from network tuple: " + networkTuple );
|
||||
}
|
||||
|
||||
mnc = parseInt(networkTuple.substr(3), 10);
|
||||
if (isNaN(mnc)) {
|
||||
throw new Error("MNC could not be parsed from network tuple: " + networkTuple);
|
||||
}
|
||||
} else {
|
||||
throw new Error("Invalid network tuple (should be 5 or 6 digits): " + networkTuple);
|
||||
}
|
||||
|
||||
network.mcc = mcc;
|
||||
network.mnc = mnc;
|
||||
},
|
||||
|
||||
/**
|
||||
* Helper for processing received SMS parcel data.
|
||||
*
|
||||
@ -2938,7 +3007,16 @@ RIL[REQUEST_QUERY_NETWORK_SELECTION_MODE] = function REQUEST_QUERY_NETWORK_SELEC
|
||||
};
|
||||
RIL[REQUEST_SET_NETWORK_SELECTION_AUTOMATIC] = null;
|
||||
RIL[REQUEST_SET_NETWORK_SELECTION_MANUAL] = null;
|
||||
RIL[REQUEST_QUERY_AVAILABLE_NETWORKS] = null;
|
||||
RIL[REQUEST_QUERY_AVAILABLE_NETWORKS] = function REQUEST_QUERY_AVAILABLE_NETWORKS(length, options) {
|
||||
if (options.rilRequestError) {
|
||||
options.error = RIL_ERROR_TO_GECKO_ERROR[options.rilRequestError];
|
||||
this.sendDOMMessage(options);
|
||||
return;
|
||||
}
|
||||
|
||||
options.networks = this._processNetworks();
|
||||
this.sendDOMMessage(options);
|
||||
};
|
||||
RIL[REQUEST_DTMF_START] = null;
|
||||
RIL[REQUEST_DTMF_STOP] = null;
|
||||
RIL[REQUEST_BASEBAND_VERSION] = function REQUEST_BASEBAND_VERSION(length, options) {
|
||||
|
@ -15,6 +15,7 @@ skip = false
|
||||
[include:../../../../../dom/telephony/test/marionette/manifest.ini]
|
||||
[include:../../../../../dom/battery/test/marionette/manifest.ini]
|
||||
[include:../../../../../dom/sms/tests/marionette/manifest.ini]
|
||||
[include:../../../../../dom/network/tests/marionette/manifest.ini]
|
||||
|
||||
; marionette unit tests
|
||||
[include:unit/unit-tests.ini]
|
||||
|
Loading…
Reference in New Issue
Block a user