author | Ryan VanderMeulen <ryanvm@gmail.com> |
Wed, 03 Sep 2014 14:53:26 -0400 | |
changeset 203209 | 117271830c4d201543d85e835194fe89253282f3 |
parent 203127 | 5e9826980be5999a66f6c3f8c9d2a95762fa6788 (current diff) |
parent 203208 | e8fd97e5279e037a68c192be6b5a54c6bb45fe45 (diff) |
child 203256 | bfef88becbba6972b2a5c1f92afac2ab4a9f0d4c |
push id | 27423 |
push user | ryanvm@gmail.com |
push date | Wed, 03 Sep 2014 18:53:23 +0000 |
treeherder | mozilla-central@117271830c4d [default view] [failures only] |
perfherder | [talos] [build metrics] [platform microbench] (compared to previous push) |
reviewers | merge |
milestone | 35.0a1 |
first release with | nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
|
last release without | nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
|
dom/mobileconnection/interfaces/nsIMobileConnectionProvider.idl | file | annotate | diff | comparison | revisions |
--- a/b2g/chrome/content/settings.js +++ b/b2g/chrome/content/settings.js @@ -189,16 +189,34 @@ SettingsListener.observe('devtools.overl developerHUD.init(); } else { if (developerHUD) { developerHUD.uninit(); } } }); +#ifdef MOZ_WIDGET_GONK +let LogShake; +SettingsListener.observe('devtools.logshake', false, (value) => { + if (value) { + if (!LogShake) { + let scope = {}; + Cu.import('resource://gre/modules/LogShake.jsm', scope); + LogShake = scope.LogShake; + } + LogShake.init(); + } else { + if (LogShake) { + LogShake.uninit(); + } + } +}); +#endif + // =================== Device Storage ==================== SettingsListener.observe('device.storage.writable.name', 'sdcard', function(value) { if (Services.prefs.getPrefType('device.storage.writable.name') != Ci.nsIPrefBranch.PREF_STRING) { // We clear the pref because it used to be erroneously written as a bool // and we need to clear it before we can change it to have the correct type. Services.prefs.clearUserPref('device.storage.writable.name'); } Services.prefs.setCharPref('device.storage.writable.name', value);
new file mode 100644 --- /dev/null +++ b/b2g/components/LogCapture.jsm @@ -0,0 +1,91 @@ +/* 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/. */ +/* jshint moz: true */ +/* global Uint8Array, Components, dump */ + +'use strict'; + +this.EXPORTED_SYMBOLS = ['LogCapture']; + +/** + * readLogFile + * Read in /dev/log/{{log}} in nonblocking mode, which will return -1 if + * reading would block the thread. + * + * @param log {String} The log from which to read. Must be present in /dev/log + * @return {Uint8Array} Raw log data + */ +let readLogFile = function(logLocation) { + if (!this.ctypes) { + // load in everything on first use + Components.utils.import('resource://gre/modules/ctypes.jsm', this); + + this.lib = this.ctypes.open(this.ctypes.libraryName('c')); + + this.read = this.lib.declare('read', + this.ctypes.default_abi, + this.ctypes.int, // bytes read (out) + this.ctypes.int, // file descriptor (in) + this.ctypes.voidptr_t, // buffer to read into (in) + this.ctypes.size_t // size_t size of buffer (in) + ); + + this.open = this.lib.declare('open', + this.ctypes.default_abi, + this.ctypes.int, // file descriptor (returned) + this.ctypes.char.ptr, // path + this.ctypes.int // flags + ); + + this.close = this.lib.declare('close', + this.ctypes.default_abi, + this.ctypes.int, // error code (returned) + this.ctypes.int // file descriptor + ); + } + + const O_READONLY = 0; + const O_NONBLOCK = 1 << 11; + + const BUF_SIZE = 2048; + + let BufType = this.ctypes.ArrayType(this.ctypes.char); + let buf = new BufType(BUF_SIZE); + let logArray = []; + + let logFd = this.open(logLocation, O_READONLY | O_NONBLOCK); + if (logFd === -1) { + return null; + } + + let readStart = Date.now(); + let readCount = 0; + while (true) { + let count = this.read(logFd, buf, BUF_SIZE); + readCount += 1; + + if (count <= 0) { + // log has return due to being nonblocking or running out of things + break; + } + for(let i = 0; i < count; i++) { + logArray.push(buf[i]); + } + } + + let logTypedArray = new Uint8Array(logArray); + + this.close(logFd); + + return logTypedArray; +}; + +let cleanup = function() { + this.lib.close(); + this.read = this.open = this.close = null; + this.lib = null; + this.ctypes = null; +}; + +this.LogCapture = { readLogFile: readLogFile, cleanup: cleanup };
new file mode 100644 --- /dev/null +++ b/b2g/components/LogParser.jsm @@ -0,0 +1,301 @@ +/* jshint esnext: true */ +/* global DataView */ + +"use strict"; + +this.EXPORTED_SYMBOLS = ["LogParser"]; + +/** + * Parse an array read from a /dev/log/ file. Format taken from + * kernel/drivers/staging/android/logger.h and system/core/logcat/logcat.cpp + * + * @param array {Uint8Array} Array read from /dev/log/ file + * @return {Array} List of log messages + */ +function parseLogArray(array) { + let data = new DataView(array.buffer); + let byteString = String.fromCharCode.apply(null, array); + + let logMessages = []; + let pos = 0; + + while (pos < byteString.length) { + // Parse a single log entry + + // Track current offset from global position + let offset = 0; + + // Length of the entry, discarded + let length = data.getUint32(pos + offset, true); + offset += 4; + // Id of the process which generated the message + let processId = data.getUint32(pos + offset, true); + offset += 4; + // Id of the thread which generated the message + let threadId = data.getUint32(pos + offset, true); + offset += 4; + // Seconds since epoch when this message was logged + let seconds = data.getUint32(pos + offset, true); + offset += 4; + // Nanoseconds since the last second + let nanoseconds = data.getUint32(pos + offset, true); + offset += 4; + + // Priority in terms of the ANDROID_LOG_* constants (see below) + // This is where the length field begins counting + let priority = data.getUint8(pos + offset); + + // Reset pos and offset to count from here + pos += offset; + offset = 0; + offset += 1; + + // Read the tag and message, represented as null-terminated c-style strings + let tag = ""; + while (byteString[pos + offset] != "\0") { + tag += byteString[pos + offset]; + offset ++; + } + offset ++; + + let message = ""; + // The kernel log driver may have cut off the null byte (logprint.c) + while (byteString[pos + offset] != "\0" && offset < length) { + message += byteString[pos + offset]; + offset ++; + } + + // Un-skip the missing null terminator + if (offset === length) { + offset --; + } + + offset ++; + + pos += offset; + + // Log messages are occasionally delimited by newlines, but are also + // sometimes followed by newlines as well + if (message.charAt(message.length - 1) === "\n") { + message = message.substring(0, message.length - 1); + } + + // Add an aditional time property to mimic the milliseconds since UTC + // expected by Date + let time = seconds * 1000.0 + nanoseconds/1000000.0; + + // Log messages with interleaved newlines are considered to be separate log + // messages by logcat + for (let lineMessage of message.split("\n")) { + logMessages.push({ + processId: processId, + threadId: threadId, + seconds: seconds, + nanoseconds: nanoseconds, + time: time, + priority: priority, + tag: tag, + message: lineMessage + "\n" + }); + } + } + + return logMessages; +} + +/** + * Get a thread-time style formatted string from time + * @param time {Number} Milliseconds since epoch + * @return {String} Formatted time string + */ +function getTimeString(time) { + let date = new Date(time); + function pad(number) { + if ( number < 10 ) { + return "0" + number; + } + return number; + } + return pad( date.getMonth() + 1 ) + + "-" + pad( date.getDate() ) + + " " + pad( date.getHours() ) + + ":" + pad( date.getMinutes() ) + + ":" + pad( date.getSeconds() ) + + "." + (date.getMilliseconds() / 1000).toFixed(3).slice(2, 5); +} + +/** + * Pad a string using spaces on the left + * @param str {String} String to pad + * @param width {Number} Desired string length + */ +function padLeft(str, width) { + while (str.length < width) { + str = " " + str; + } + return str; +} + +/** + * Pad a string using spaces on the right + * @param str {String} String to pad + * @param width {Number} Desired string length + */ +function padRight(str, width) { + while (str.length < width) { + str = str + " "; + } + return str; +} + +/** Constant values taken from system/core/liblog */ +const ANDROID_LOG_UNKNOWN = 0; +const ANDROID_LOG_DEFAULT = 1; +const ANDROID_LOG_VERBOSE = 2; +const ANDROID_LOG_DEBUG = 3; +const ANDROID_LOG_INFO = 4; +const ANDROID_LOG_WARN = 5; +const ANDROID_LOG_ERROR = 6; +const ANDROID_LOG_FATAL = 7; +const ANDROID_LOG_SILENT = 8; + +/** + * Map a priority number to its abbreviated string equivalent + * @param priorityNumber {Number} Log-provided priority number + * @return {String} Priority number's abbreviation + */ +function getPriorityString(priorityNumber) { + switch (priorityNumber) { + case ANDROID_LOG_VERBOSE: + return "V"; + case ANDROID_LOG_DEBUG: + return "D"; + case ANDROID_LOG_INFO: + return "I"; + case ANDROID_LOG_WARN: + return "W"; + case ANDROID_LOG_ERROR: + return "E"; + case ANDROID_LOG_FATAL: + return "F"; + case ANDROID_LOG_SILENT: + return "S"; + default: + return "?"; + } +} + + +/** + * Mimic the logcat "threadtime" format, generating a formatted string from a + * log message object. + * @param logMessage {Object} A log message from the list returned by parseLogArray + * @return {String} threadtime formatted summary of the message + */ +function formatLogMessage(logMessage) { + // MM-DD HH:MM:SS.ms pid tid priority tag: message + // from system/core/liblog/logprint.c: + return getTimeString(logMessage.time) + + " " + padLeft(""+logMessage.processId, 5) + + " " + padLeft(""+logMessage.threadId, 5) + + " " + getPriorityString(logMessage.priority) + + " " + padRight(logMessage.tag, 8) + + ": " + logMessage.message; +} + +/** + * Pretty-print an array of bytes read from a log file by parsing then + * threadtime formatting its entries. + * @param array {Uint8Array} Array of a log file's bytes + * @return {String} Pretty-printed log + */ +function prettyPrintLogArray(array) { + let logMessages = parseLogArray(array); + return logMessages.map(formatLogMessage).join(""); +} + +/** + * Parse an array of bytes as a properties file. The structure of the + * properties file is derived from bionic/libc/bionic/system_properties.c + * @param array {Uint8Array} Array containing property data + * @return {Object} Map from property name to property value, both strings + */ +function parsePropertiesArray(array) { + let data = new DataView(array.buffer); + let byteString = String.fromCharCode.apply(null, array); + + let properties = {}; + + let propIndex = 0; + let propCount = data.getUint32(0, true); + + // first TOC entry is at 32 + let tocOffset = 32; + + const PROP_NAME_MAX = 32; + const PROP_VALUE_MAX = 92; + + while (propIndex < propCount) { + // Retrieve offset from file start + let infoOffset = data.getUint32(tocOffset, true) & 0xffffff; + + // Now read the name, integer serial, and value + let propName = ""; + let nameOffset = infoOffset; + while (byteString[nameOffset] != "\0" && + (nameOffset - infoOffset) < PROP_NAME_MAX) { + propName += byteString[nameOffset]; + nameOffset ++; + } + + infoOffset += PROP_NAME_MAX; + // Skip serial number + infoOffset += 4; + + let propValue = ""; + nameOffset = infoOffset; + while (byteString[nameOffset] != "\0" && + (nameOffset - infoOffset) < PROP_VALUE_MAX) { + propValue += byteString[nameOffset]; + nameOffset ++; + } + + // Move to next table of contents entry + tocOffset += 4; + + properties[propName] = propValue; + propIndex += 1; + } + + return properties; +} + +/** + * Pretty-print an array read from the /dev/__properties__ file. + * @param array {Uint8Array} File data array + * @return {String} Human-readable string of property name: property value + */ +function prettyPrintPropertiesArray(array) { + let properties = parsePropertiesArray(array); + let propertiesString = ""; + for(let propName in properties) { + propertiesString += propName + ": " + properties[propName] + "\n"; + } + return propertiesString; +} + +/** + * Pretty-print a normal array. Does nothing. + * @param array {Uint8Array} Input array + */ +function prettyPrintArray(array) { + return array; +} + +this.LogParser = { + parseLogArray: parseLogArray, + parsePropertiesArray: parsePropertiesArray, + prettyPrintArray: prettyPrintArray, + prettyPrintLogArray: prettyPrintLogArray, + prettyPrintPropertiesArray: prettyPrintPropertiesArray +};
new file mode 100644 --- /dev/null +++ b/b2g/components/LogShake.jsm @@ -0,0 +1,301 @@ +/* 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/. */ + +/** + * LogShake is a module which listens for log requests sent by Gaia. In + * response to a sufficiently large acceleration (a shake), it will save log + * files to an arbitrary directory which it will then return on a + * 'capture-logs-success' event with detail.logFilenames representing each log + * file's filename in the directory. If an error occurs it will instead produce + * a 'capture-logs-error' event. + */ + +/* enable Mozilla javascript extensions and global strictness declaration, + * disable valid this checking */ +/* jshint moz: true */ +/* jshint -W097 */ +/* jshint -W040 */ +/* global Services, Components, dump, LogCapture, LogParser, + OS, Promise, volumeService, XPCOMUtils, SystemAppProxy */ + +'use strict'; + +const Cu = Components.utils; +const Ci = Components.interfaces; + +Cu.import('resource://gre/modules/XPCOMUtils.jsm'); + +XPCOMUtils.defineLazyModuleGetter(this, 'LogCapture', 'resource://gre/modules/LogCapture.jsm'); +XPCOMUtils.defineLazyModuleGetter(this, 'LogParser', 'resource://gre/modules/LogParser.jsm'); +XPCOMUtils.defineLazyModuleGetter(this, 'OS', 'resource://gre/modules/osfile.jsm'); +XPCOMUtils.defineLazyModuleGetter(this, 'Promise', 'resource://gre/modules/Promise.jsm'); +XPCOMUtils.defineLazyModuleGetter(this, 'Services', 'resource://gre/modules/Services.jsm'); +XPCOMUtils.defineLazyModuleGetter(this, 'SystemAppProxy', 'resource://gre/modules/SystemAppProxy.jsm'); + +XPCOMUtils.defineLazyServiceGetter(this, 'powerManagerService', + '@mozilla.org/power/powermanagerservice;1', + 'nsIPowerManagerService'); + +XPCOMUtils.defineLazyServiceGetter(this, 'volumeService', + '@mozilla.org/telephony/volume-service;1', + 'nsIVolumeService'); + +this.EXPORTED_SYMBOLS = ['LogShake']; + +function debug(msg) { + dump('LogShake.jsm: '+msg+'\n'); +} + +/** + * An empirically determined amount of acceleration corresponding to a + * shake + */ +const EXCITEMENT_THRESHOLD = 500; +const DEVICE_MOTION_EVENT = 'devicemotion'; +const SCREEN_CHANGE_EVENT = 'screenchange'; +const CAPTURE_LOGS_ERROR_EVENT = 'capture-logs-error'; +const CAPTURE_LOGS_SUCCESS_EVENT = 'capture-logs-success'; + +// Map of files which have log-type information to their parsers +const LOGS_WITH_PARSERS = { + '/dev/__properties__': LogParser.prettyPrintPropertiesArray, + '/dev/log/main': LogParser.prettyPrintLogArray, + '/dev/log/system': LogParser.prettyPrintLogArray, + '/dev/log/radio': LogParser.prettyPrintLogArray, + '/dev/log/events': LogParser.prettyPrintLogArray, + '/proc/cmdline': LogParser.prettyPrintArray, + '/proc/kmsg': LogParser.prettyPrintArray, + '/proc/meminfo': LogParser.prettyPrintArray, + '/proc/uptime': LogParser.prettyPrintArray, + '/proc/version': LogParser.prettyPrintArray, + '/proc/vmallocinfo': LogParser.prettyPrintArray, + '/proc/vmstat': LogParser.prettyPrintArray +}; + +let LogShake = { + QueryInterface: XPCOMUtils.generateQI([Ci.nsIObserver]), + /** + * If LogShake is listening for device motion events. Required due to lag + * between HAL layer of device motion events and listening for device motion + * events. + */ + deviceMotionEnabled: false, + + /** + * If a capture has been requested and is waiting for reads/parsing. Used for + * debouncing. + */ + captureRequested: false, + + /** + * Start existing, observing motion events if the screen is turned on. + */ + init: function() { + // TODO: no way of querying screen state from power manager + // this.handleScreenChangeEvent({ detail: { + // screenEnabled: powerManagerService.screenEnabled + // }}); + + // However, the screen is always on when we are being enabled because it is + // either due to the phone starting up or a user enabling us directly. + this.handleScreenChangeEvent({ detail: { + screenEnabled: true + }}); + + SystemAppProxy.addEventListener(SCREEN_CHANGE_EVENT, this, false); + + Services.obs.addObserver(this, 'xpcom-shutdown', false); + }, + + /** + * Handle an arbitrary event, passing it along to the proper function + */ + handleEvent: function(event) { + switch (event.type) { + case DEVICE_MOTION_EVENT: + if (!this.deviceMotionEnabled) { + return; + } + this.handleDeviceMotionEvent(event); + break; + + case SCREEN_CHANGE_EVENT: + this.handleScreenChangeEvent(event); + break; + } + }, + + /** + * Handle an observation from Services.obs + */ + observe: function(subject, topic) { + if (topic === 'xpcom-shutdown') { + this.uninit(); + } + }, + + startDeviceMotionListener: function() { + if (!this.deviceMotionEnabled) { + SystemAppProxy.addEventListener(DEVICE_MOTION_EVENT, this, false); + this.deviceMotionEnabled = true; + } + }, + + stopDeviceMotionListener: function() { + SystemAppProxy.removeEventListener(DEVICE_MOTION_EVENT, this, false); + this.deviceMotionEnabled = false; + }, + + /** + * Handle a motion event, keeping track of 'excitement', the magnitude + * of the device's acceleration. + */ + handleDeviceMotionEvent: function(event) { + // There is a lag between disabling the event listener and event arrival + // ceasing. + if (!this.deviceMotionEnabled) { + return; + } + + var acc = event.accelerationIncludingGravity; + + var excitement = acc.x * acc.x + acc.y * acc.y + acc.z * acc.z; + + if (excitement > EXCITEMENT_THRESHOLD) { + if (!this.captureRequested) { + this.captureRequested = true; + captureLogs().then(logResults => { + // On resolution send the success event to the requester + SystemAppProxy._sendCustomEvent(CAPTURE_LOGS_SUCCESS_EVENT, { + logFilenames: logResults.logFilenames, + logPrefix: logResults.logPrefix + }); + this.captureRequested = false; + }, + error => { + // On an error send the error event + SystemAppProxy._sendCustomEvent(CAPTURE_LOGS_ERROR_EVENT, {error: error}); + this.captureRequested = false; + }); + } + } + }, + + handleScreenChangeEvent: function(event) { + if (event.detail.screenEnabled) { + this.startDeviceMotionListener(); + } else { + this.stopDeviceMotionListener(); + } + }, + + /** + * Stop logshake, removing all listeners + */ + uninit: function() { + this.stopDeviceMotionListener(); + SystemAppProxy.removeEventListener(SCREEN_CHANGE_EVENT, this, false); + Services.obs.removeObserver(this, 'xpcom-shutdown'); + } +}; + +function getLogFilename(logLocation) { + // sanitize the log location + let logName = logLocation.replace(/\//g, '-'); + if (logName[0] === '-') { + logName = logName.substring(1); + } + return logName + '.log'; +} + +function getSdcardPrefix() { + return volumeService.getVolumeByName('sdcard').mountPoint; +} + +function getLogDirectory() { + let d = new Date(); + d = new Date(d.getTime() - d.getTimezoneOffset() * 60000); + let timestamp = d.toISOString().slice(0, -5).replace(/[:T]/g, '-'); + // return directory name of format 'logs/timestamp/' + return OS.Path.join('logs', timestamp, ''); +} + +/** + * Captures and saves the current device logs, returning a promise that will + * resolve to an array of log filenames. + */ +function captureLogs() { + let logArrays = readLogs(); + return saveLogs(logArrays); +} + +/** + * Read in all log files, returning their formatted contents + */ +function readLogs() { + let logArrays = {}; + for (let loc in LOGS_WITH_PARSERS) { + let logArray = LogCapture.readLogFile(loc); + if (!logArray) { + continue; + } + let prettyLogArray = LOGS_WITH_PARSERS[loc](logArray); + + logArrays[loc] = prettyLogArray; + } + return logArrays; +} + +/** + * Save the formatted arrays of log files to an sdcard if available + */ +function saveLogs(logArrays) { + if (!logArrays || Object.keys(logArrays).length === 0) { + return Promise.resolve({ + logFilenames: [], + logPrefix: '' + }); + } + + let sdcardPrefix, dirName; + try { + sdcardPrefix = getSdcardPrefix(); + dirName = getLogDirectory(); + } catch(e) { + // Return promise failed with exception e + // Handles missing sdcard + return Promise.reject(e); + } + + debug('making a directory all the way from '+sdcardPrefix+' to '+(sdcardPrefix + '/' + dirName)); + return OS.File.makeDir(OS.Path.join(sdcardPrefix, dirName), {from: sdcardPrefix}) + .then(function() { + // Now the directory is guaranteed to exist, save the logs + let logFilenames = []; + let saveRequests = []; + + for (let logLocation in logArrays) { + debug('requesting save of ' + logLocation); + let logArray = logArrays[logLocation]; + // The filename represents the relative path within the SD card, not the + // absolute path because Gaia will refer to it using the DeviceStorage + // API + let filename = dirName + getLogFilename(logLocation); + logFilenames.push(filename); + let saveRequest = OS.File.writeAtomic(OS.Path.join(sdcardPrefix, filename), logArray); + saveRequests.push(saveRequest); + } + + return Promise.all(saveRequests).then(function() { + debug('returning logfilenames: '+logFilenames.toSource()); + return { + logFilenames: logFilenames, + logPrefix: dirName + }; + }); + }); +} + +LogShake.init(); +this.LogShake = LogShake;
--- a/b2g/components/moz.build +++ b/b2g/components/moz.build @@ -47,16 +47,19 @@ if CONFIG['MOZ_UPDATER']: ] EXTRA_JS_MODULES += [ 'AlertsHelper.jsm', 'AppFrames.jsm', 'ContentRequestHelper.jsm', 'ErrorPage.jsm', 'FxAccountsMgmtService.jsm', + 'LogCapture.jsm', + 'LogParser.jsm', + 'LogShake.jsm', 'SignInToWebsite.jsm', 'SystemAppProxy.jsm', 'TelURIParser.jsm', 'WebappsUpdater.jsm', ] if CONFIG['MOZ_WIDGET_TOOLKIT'] != 'gonk': EXTRA_JS_MODULES += [
new file mode 100644 index 0000000000000000000000000000000000000000..b1ed7f10ae86e16e9e6f1b14006182ceb278f5e3 GIT binary patch literal 4037 zc%1E*zi!h|6o+p_(;=#aSn0rNg%k(kI!QqlAPNzsfKV$Sf`tLy`ko|Koa@McB47(M z8xN3~M_}kwsiHz+gEwGd?gQW($Hhr)a$}MK(IJlFocrDLJB~jqc|yqfOz>K|utYM> z@#TdVmdS`XKxM5AirYl6v5UNc1*jXg!5iRp$b*=r=fb648v$RtXme_U<5CwvZ&Kb6 zYgM25h#Rg!P2;V9q5$e9lt9_F)E#67Es*<@&<@k7&87!$55d(Coc~mi07n^uDfVF| zs?T}b^0<racgrEUxBv8t1o<>c@GGD^LC!>k)8L=)u1bI-h=h)p$7j)7E@lVdEw5u5 zy1)fcrCi9JmH(UNy{#YWS^0lfULBS{6Al&S2S=H}>KenYwr5&;OY8cdwerS|o9iXm zL*WeF;*P=4Mh11uhHlg^xf6Frp{WhG4$8eI>aBs|F2<09bhVbz=?F^Q@ri!DlOrz^ z!);;L&=KM@7Qv-<16|M@*Rp8?wV>Y;4Eut+ptZTHIjDQK|E)_!|Kv`(*wKI@@HJ3& zLi0v1&$o8Jw!m*)l0Zfff_NR2;Y<fZyd8ml7tmEQe3Fj`*48Lzwq>waK~!)&9UZ6c zndTet!plU|WME`W)PI)+eEg7)@96IVCySye@-PM<G3e3BCOkfO)3M`khYe6_P3qrx zNjvOY{o0pOc12=`I95W2>evpCkH4<Y)Dt0e_MQmIa-J9sH+N4=5nI+1pMB(^+z&wB z6GuLDdu4{67z0l42?03VEGnrzF##~y6Cq$8o|uB2(i4k%zm}~~nZF(>Jt1~je1A}! ZsV73{>^%{Z<vcMOZtk9#BKDs=@eBW@U8n#6
new file mode 100644 index 0000000000000000000000000000000000000000..a8254853738e2083fbea3c659e4346c141214f2f GIT binary patch literal 65536 zc%1EB+j`r^wMHb_a$-BNb84D{qo!`!rX)yEltj6w?bvQ(*S1{AahjgcAut4C;Uo+| zitfJPx1Vf3!oJ$?u<!Q+^dFEE0T56eiv#syetjSe%mDu!*Q_<O2L3-qQT~5TQJ(DY zJsIrXxu@iDNqK90Nx7!HuDm^dUAdyXp<El|P%bN%$2f53^7x8!6@Qn<IFvV)H^*-x z_FKyP<F|14n)31Zn)04<9oN@!^)}x3w(`F64&uLq-**xIE`HxremH(l`2ZnT$L}Nd z4{*kTJ6Fdzlplf@hw>qw{}ACH;rb)I?PKMg@yCe$iSpt26U4rO`!^8&DbAnby&KBA z;|<*Zk#c2>L-`Ep_zX||7`!-?n>gRZ(?3x@8RJks$N6)l;-|>(PjUS-r0Zvh_jBdF z@y~Jp3+1En7dZa{;lBWH4f(AheRbu7aUG?jB0VbD8+cCx&o%M>CayJHYbc!-o^K(y zn@Ha#a@9usHqyC;^A@hRamJzSAl?q%-$A?%p5Ik&jCXOqh45R*-!F0gCBlD&eE$m1 z{Tk`{HTZsm=YE6xzeT!#i}?S6bmLHND?b?DMmc<`yfOX~*LRSfJK(vC=kB6Z@8Lc7 z5dU|G|2v$2k82#tSE#42kgxl=zK`c0pgbSo{vUAt2c+X6>gOS9`w`yr2<OL${}|zW z;M+qvJ;51=@<)^p4rL$beOw>lJ`Uxn^6B^~&R^p_U*r4?>3)Xt_(r)t{s!gxC%pGh zNawexzi&}~e@47NgZD28{|mzZitxXpUjK&o{SEEo@3{Uu!gbV(j(q$B<@XOfPf+g! z<<!M>7w<6;jzck#9}{PaGevk0;XRx!@ZeDT$Y&qdHqvF|{m&8p9M^}4e~9vSP+m9` z7xnDoJs$FpL-CPbANdGSPXXHL5z=>rbBJ?@^f5fg5I;gbB9vQ<c8x<B;5<P15bqx% z{xPnP@tzUljllB)>Bgb_6Yu{gdgp&4jS><P60d;JSG&F+sfO<{-=RfO)}v_j)xpE2 zQ2ss%%^?Yk60mk;_^uH06hHrQd}7jYA<C79+S5C&W>eFezh8PG%=oG68YNNIqA)J3 zm}T-a8rsD1{DLT#I$FDDP_iYGze^bH63;A%vg$Hn)zA4)$$Ek+^6&a)X%(->-l69Y zJrVQ?e|ga-5MBPKbiD+k``;;|CxK}B6VidrY`?UAUlSvFPxyPpi2QIAQ5KyGKchxm zUi#wsiR1V~)%A@-)$t7y<*VW~O)S4jyRl`FZt>_Vm_MK)vl-<7h^Z_JZ6nhCK&M_R zITw1wVWI}0H2<(~N7S+N&2XcEz=*mH8X1j~I64UeKVa&y>nw{uW?ila^=xY%zM?2w zrcJEcWR%dEYtH@&wWt=l9*y)aaceGNOlRmw#G*A~c3+a;_H2+33^k?$>P1CDcs-0g z&-Sc>ptA$*&j?3Bgl-s-sIZnV#~$^PNVIf}cx4QH$5aC!_1R;(Ng|?~zL!mg=>FG@ zZKT02&D+HX2M5~L1Ht^J%>svv3evILbBIgp)U!6)>gL8IH5<58pZEQ)?WwJ%)^2V$ zcT`QoFuA?KC3*djj@b9%AMlRgd#a79rY@Qynf0p=%c+)_{~13s4|7pgw9eUiUYg&4 zCg!2M=TTPo?>(%JKco&N8F9OcS{Ki6mh^r_`S^fD8xLY{V`FDS({8nzx3ry&CwHH2 z@W!xIel?B?jG#Br<XYPHR!iGCE88jj(I_a%|0)$Edo%noE7N~3PWql;{=Q$L{wZ&D zeHS)D6thG>I@54l&L0u0L|(oAedO6I@CTu9#zv%a8>}dE7ZUj^fIG+E4U3I1(e}rT z-z&*wRrxnz2N?xCm6g8_L$Dyq`lEwKoo!9n{MU@%2x66V?S&|pN$64p)CW7H0{&J$ z%KDUl>D)Pfmv}L^MPUqPB;jh*5<34d<4=SeRUP74F_id|C@WNu>@DUGsg<=rSH3<F z%0IMwwrcc==TS$5i2W}9q~EDfexsfr7S!~*%UqHDZ!-Q&YoQ>DX!$eMe<(9TJ6M=~ zs7n9u!NR0r5ZYe84DRyrr;#LL@_P%(XiSpPC{M;M1U0@hDJT4BfFU|ROlua|Mmqkw zNqZ!AO0<(RBIMkT-3>_8FNt!a0n6O<!v>=91CP{?jQWvl*EN-uP8)weeiD|cKgyN5 zxzWJj*kG=?^iD9F|47o|+0hF<a9n}%?z{ON-?MbzW4g#`zn9?`IqmQ={0jqd#r)!o z&QtkW-w&h88o+7%RWyLp_^W6Dr}0<O0KluVxO+18C3bjL60SdfR@?vj{v#p$ckeyB zf9Ib5WPk73{e$~^kMG@Gh*HV?dq_;%S6yaBG1tTRY-~6k@hX{rpYTHk8=7fu;rtl? zBkItg?|UP4I?(GLjfQ?Wn+JSN$inLs$>NL3dTOt$6K6<9OwTJ|LhFCR4+SgmnSIg$ zGEr8|k+=bQ!f%Cq5zK%I7U(Dlm%4s9nne-1{x;$74-FN$eA*8w#E+A;!dEp_TnjLX zGq4ZUfvff@37GvN*U(oKWv#WfEzAIgUZ(~w&%Dlv8#vIy!`w`)==G1j>Dp>$#V-q? z{wGs$XHuio1ELCk5<~nAY?JznNf9dloPeB~`6~EhM(dFI7VU+$)nBl)gqFWcO`E7G z_GwG3^Tn{qJka^@_oFD7L^&URLS{=L=fi(w1n0`%b4kk#&X1oNWIF1K<#&TAqq=Do zEBqDYAB|1l(sVzLf;gIbf1C`$g7ZJiKA&aM0}?K*gI(C%Y43^}10nN`i3g7A&_Ut) zPbK>QOan85Njg%tm+0{y;(y|K0kzw;7MDPT*8eR3k&TvEtc8g7fAs_ESq^2hCHQ=l zi`wq?c2kfK!rb_ABD&|@F<o*uw+>cG`|I&mz)YiH2~2eP9~s=~W1@noj4iB!i?%;A z{5>b8o<Y+_*qWF3NLnsGcRlM3)vm=|+L-RxuAR}rR$2lLFrNRIIFP-rYM}EKM5(0x znS}LWejckK4RA2uiDye8m$X)=`NfWyQYhr--q1taoURD0x0?w>&}aF{fQ>vu9onAB zJyID>RKQhD5I0BK{(<-{GDJl8zn-f`A@LZReN^NFBbMKt<^9;8$qeMeGK^69cSuK8 z%-26XUk~X~Y=;oTc4oRkwERWiSJB`@-%h-+Nazzc?QU8zKjo{yBqaggc=V`ln)MMN zh@ZRssv+_m6-oN*`v}nwMqbp{n{Cy%mgx;P=lA@`?%5OnbDjC|i7(LAz&^IA8AD1e zmwU=TS=~ejh^WW)ADypplKK4K2f6jnBctvI(V161C&<me@tNoRB-~0zocl+P-wOR< z)X$B;tGnW+|8o4uzC|O9e2)F%WFx{_Q{53Z0h;AUzwd=KKLsk#{U*;(jtlrj)<4?6 z>%UNa_gL)@xdNci2mUG6xc*Tcf1l<i;Z_ByJ~Mvk{Gnaue5#1we>RnW#37-p6NiSm z8OZCmlaM<OVazs`ECX}vZ?O~E7=AO`K-NrV3iFGa)<5@s^ny5gPK><!yKwuT^Lsr* z%}x89K=k;}`S~(%Q=P8+>De{l*DdDOh6XHSvHV&I|EeW+|Kp6Gx)jpiGe&xMq^EqI zsw#gkb`8g-UX*L>uZi?SNb#rL0CaS~DD)F^RA~PF&{Dgw`Cm-kk9p6}t-)S^d?W%? z&jiT-Aq^7~Y^nkqeQF#&_vY@lLi<0OyxJ}I{pMJ|JxQ4`e(rl}mC*k$^j{vw^w=yK z)WgJQ6~^n?`RDovbWh{34olRa^`4!Yg?zWct)d3;!bTFx)aZC=&WJhx3$v>`zLj!8 zSQEVdp5Fh+=U`tfT0qxsLomTGX*{Mw{oA=;#!~qw`KK_yv*XZOrT#A_q>i4<hqF1q zX!*-}s$-at_^`gB0y(qVY75o>CW;r|g<l*+X!#Ev;;Ck64``^CxZnzH|7rgG-rp%c zoAiIzW=4a{oyIqJ9v>X&$$FL1vsBwV!`6tSWcDMOf#O?%i=tfO-a!s6+n#qep#Hh; z7x;Otdyduntve#96L8rc8G+i3dp+J2A=~rr-al?PceiVuoy|_OrfJPqvr|j%Xxp2e z_Vms&`6pw`6f25S+iJC2oldRQ+}+W(TD7*e+um%pYpv~;)^5*2wPw4swe!7q#1`;7 zxth)~oTNh(f9z&8Kwkds3d_IGf{dpBlQe&;)!fb{U~+4j{Bb4$)$^O@%pZ^-6{Tu^ zYG#$eAAxL>w|4MvZZ+G@G<$O66}e0Jtsu;_|4%{JLjJdT^WW}F>F3vHU@y-9z|2go zru*Nt&!-Ata_5!#C!f~PC!e86W?$p52PL=XB>RDQ6rtnq$@ec94Y~d05|3Ef$ta=U zzc}F^<lRmy=I4q)-GJR2(mI>#K^TA5S>y+SfNyVP_$SJb&TZics^BaImGLL}k6AaJ z`6~I@kOaYEEmy`5L2$0^Z}Jr)ns@(LOYw_H!U;d$Rc8|F=KOCiR+j&wt)~g9;ZGd# z7Q@#n%YQd6ndGj9-}W&4I7KqJ8h*Y>HS&wTLsktxtgv(K|Ca9^GNWH0=BnZEwh9UU zC(SQX{!GVTm)PF9jK9gQVs~LCp)!6uWQNXHp3jM&m@Ei`qCOzB{Uskiu)T;TT5n;L z3w(}9ln$KP|7Jh{>f8@yvJe?eCZUDSzh&D$TbO{WQ2!$?4G9}8EJRl$e};y~Sbb`R zRL7t8zdX^sRh0KUiqQGzwEkc60cfH5FZ=Fd3e|jnG1>ZB7)5CNk6JEFk22Tu1XsQk z`2E}Y_~S;i;>$&;$o_TX<C5~Pgnw>-<d<8|q5t=LmG}RW%^%A7<eycZe~66p(7$K$ zuk`Dyg5_Uv`3K$946yM1AB+6GsH*xe=J!a2{Bv5CnRl<A-;9e!AmRIO7R%o~pYn&; z<s)$}iqP*5Wbz-WeZ$t1%@C;t*;Vv;q5MX=2}TPZh!+z7C_((D?{r7Ay<fI>2wSX| zUj0bykARZHQyf&!0`7QrWZ+j1LYgdt=#Fn3>U}zyin=KN`}2wK+rWvac3c=mbpM<1 zo2BmjV)?n_qhTz5^?i!}Qj{CJnpV@aR;}4=)|wr@;#}L^-Nl*zdv|I4g>H8LEtub8 z?)=lwP(f`s$jrbzP?T$boC=7I{re9$G<B)Xao+Q7cCWwz_-2LvKU@bYn1o*Om+Enr z#oYc6h|c05aBPF5K7r^|p#O2#D}CnVlN0qf1^a(y=YRNz`0E)@um^(eU$bunYBIsb zcYQ8?<?&%v_0JPxn0kJ$FA`k;sr&~;F1Eb?!S>%gqnLRa{*V&3Fa?3~zqo(z%e}p) z!ud^)Ew=Q>DF2R{{8hle=;{8s5Y{sO#V_tv%fIMHQYF977he|n-?w7QJ(PRC#`g-? zjziR?eGxsyZwJIQA%rp`5cscZO|`Y9shiuXw!3UyFvV|?hz|1`4ZweS#@|wxKN6() zUBVUxEzf^zYfDXzc4xWDN0vYNe=oQXdXE2s*6aw|0iWXMbN>rgMz;Ky{~u7K_$Rw; z?`Q2F(fyD6pPeFp`S>GL{$}_KHX3pMrkeZ-=C_7L;Wq{Mzv<qV(ic}z{;9n+Mf@vg zwQ(dQBqSsxBqSsxBqSsxBqSsxBqSsxBqSsxBqSsxBqSsxBqSsxBqSsxBqSsxBqSsx zBqSsxBqSsxBqSsxBqSsxBqSsxBqSsxBqSsxBqSsxBqSsxBqSsxBqSsxBqSsxBqSsx jBqSsxBqSsxBqSsxBqSsxBqSsxBqSsxBqSsx{$24ea`HxF
new file mode 100644 --- /dev/null +++ b/b2g/components/test/unit/test_logcapture.js @@ -0,0 +1,25 @@ +/* Any copyright is dedicated to the Public Domain. + http://creativecommons.org/publicdomain/zero/1.0/ */ + + +/** + * Test that LogCapture successfully reads from the /dev/log devices, returning + * a Uint8Array of some length, including zero. This tests a few standard + * log devices + */ +function run_test() { + Components.utils.import('resource:///modules/LogCapture.jsm'); + + function verifyLog(log) { + // log exists + notEqual(log, null); + // log has a length and it is non-negative (is probably array-like) + ok(log.length >= 0); + } + + let mainLog = LogCapture.readLogFile('/dev/log/main'); + verifyLog(mainLog); + + let meminfoLog = LogCapture.readLogFile('/proc/meminfo'); + verifyLog(meminfoLog); +}
new file mode 100644 --- /dev/null +++ b/b2g/components/test/unit/test_logparser.js @@ -0,0 +1,49 @@ +/* jshint moz: true */ + +const {utils: Cu, classes: Cc, interfaces: Ci} = Components; + +function run_test() { + Cu.import('resource:///modules/LogParser.jsm'); + + let propertiesFile = do_get_file('data/test_properties'); + let loggerFile = do_get_file('data/test_logger_file'); + + let propertiesStream = makeStream(propertiesFile); + let loggerStream = makeStream(loggerFile); + + // Initialize arrays to hold the file contents (lengths are hardcoded) + let propertiesArray = new Uint8Array(propertiesStream.readByteArray(65536)); + let loggerArray = new Uint8Array(loggerStream.readByteArray(4037)); + + propertiesStream.close(); + loggerStream.close(); + + let properties = LogParser.parsePropertiesArray(propertiesArray); + let logMessages = LogParser.parseLogArray(loggerArray); + + // Test arbitrary property entries for correctness + equal(properties['ro.boot.console'], 'ttyHSL0'); + equal(properties['net.tcp.buffersize.lte'], + '524288,1048576,2097152,262144,524288,1048576'); + + ok(logMessages.length === 58, 'There should be 58 messages in the log'); + + let expectedLogEntry = { + processId: 271, threadId: 271, + seconds: 790796, nanoseconds: 620000001, time: 790796620.000001, + priority: 4, tag: 'Vold', + message: 'Vold 2.1 (the revenge) firing up\n' + }; + + deepEqual(expectedLogEntry, logMessages[0]); +} + +function makeStream(file) { + var fileStream = Cc['@mozilla.org/network/file-input-stream;1'] + .createInstance(Ci.nsIFileInputStream); + fileStream.init(file, -1, -1, 0); + var bis = Cc['@mozilla.org/binaryinputstream;1'] + .createInstance(Ci.nsIBinaryInputStream); + bis.setInputStream(fileStream); + return bis; +}
new file mode 100644 --- /dev/null +++ b/b2g/components/test/unit/test_logshake.js @@ -0,0 +1,141 @@ +/** + * Test the log capturing capabilities of LogShake.jsm + */ + +/* jshint moz: true */ +/* global Components, LogCapture, LogShake, ok, add_test, run_next_test, dump */ +/* exported run_test */ + +/* disable use strict warning */ +/* jshint -W097 */ +'use strict'; + +const Cu = Components.utils; + +Cu.import('resource://gre/modules/LogCapture.jsm'); +Cu.import('resource://gre/modules/LogShake.jsm'); + +// Force logshake to handle a device motion event with given components +// Does not use SystemAppProxy because event needs special +// accelerationIncludingGravity property +function sendDeviceMotionEvent(x, y, z) { + let event = { + type: 'devicemotion', + accelerationIncludingGravity: { + x: x, + y: y, + z: z + } + }; + LogShake.handleEvent(event); +} + +// Send a screen change event directly, does not use SystemAppProxy due to race +// conditions. +function sendScreenChangeEvent(screenEnabled) { + let event = { + type: 'screenchange', + detail: { + screenEnabled: screenEnabled + } + }; + LogShake.handleEvent(event); +} + +function debug(msg) { + var timestamp = Date.now(); + dump('LogShake: ' + timestamp + ': ' + msg); +} + +add_test(function test_do_log_capture_after_shaking() { + // Enable LogShake + LogShake.init(); + + let readLocations = []; + LogCapture.readLogFile = function(loc) { + readLocations.push(loc); + return null; // we don't want to provide invalid data to a parser + }; + + // Fire a devicemotion event that is of shake magnitude + sendDeviceMotionEvent(9001, 9001, 9001); + + ok(readLocations.length > 0, + 'LogShake should attempt to read at least one log'); + + LogShake.uninit(); + run_next_test(); +}); + +add_test(function test_do_nothing_when_resting() { + // Enable LogShake + LogShake.init(); + + let readLocations = []; + LogCapture.readLogFile = function(loc) { + readLocations.push(loc); + return null; // we don't want to provide invalid data to a parser + }; + + // Fire a devicemotion event that is relatively tiny + sendDeviceMotionEvent(0, 9.8, 9.8); + + ok(readLocations.length === 0, + 'LogShake should not read any logs'); + + debug('test_do_nothing_when_resting: stop'); + LogShake.uninit(); + run_next_test(); +}); + +add_test(function test_do_nothing_when_disabled() { + debug('test_do_nothing_when_disabled: start'); + // Disable LogShake + LogShake.uninit(); + + let readLocations = []; + LogCapture.readLogFile = function(loc) { + readLocations.push(loc); + return null; // we don't want to provide invalid data to a parser + }; + + // Fire a devicemotion event that would normally be a shake + sendDeviceMotionEvent(0, 9001, 9001); + + ok(readLocations.length === 0, + 'LogShake should not read any logs'); + + run_next_test(); +}); + +add_test(function test_do_nothing_when_screen_off() { + // Enable LogShake + LogShake.init(); + + + // Send an event as if the screen has been turned off + sendScreenChangeEvent(false); + + let readLocations = []; + LogCapture.readLogFile = function(loc) { + readLocations.push(loc); + return null; // we don't want to provide invalid data to a parser + }; + + // Fire a devicemotion event that would normally be a shake + sendDeviceMotionEvent(0, 9001, 9001); + + ok(readLocations.length === 0, + 'LogShake should not read any logs'); + + // Restore the screen + sendScreenChangeEvent(true); + + LogShake.uninit(); + run_next_test(); +}); + +function run_test() { + debug('Starting'); + run_next_test(); +}
--- a/b2g/components/test/unit/xpcshell.ini +++ b/b2g/components/test/unit/xpcshell.ini @@ -1,14 +1,24 @@ [DEFAULT] head = tail = +support-files = + data/test_logger_file + data/test_properties + [test_bug793310.js] [test_bug832946.js] [test_fxaccounts.js] [test_signintowebsite.js] head = head_identity.js tail = +[test_logcapture.js] +# only run on b2g builds due to requiring b2g-specific log files to exist +skip-if = toolkit != "gonk" +[test_logparser.js] + +[test_logshake.js]
--- a/b2g/config/dolphin/sources.xml +++ b/b2g/config/dolphin/sources.xml @@ -10,25 +10,25 @@ <!--original fetch url was git://codeaurora.org/--> <remote fetch="https://git.mozilla.org/external/caf" name="caf"/> <!--original fetch url was https://git.mozilla.org/releases--> <remote fetch="https://git.mozilla.org/releases" name="mozillaorg"/> <!-- B2G specific things. --> <project name="platform_build" path="build" remote="b2g" revision="4b4336c73c081b39776d399835ce4853aee5cc1c"> <copyfile dest="Makefile" src="core/root.mk"/> </project> - <project name="gaia" path="gaia" remote="mozillaorg" revision="52670853c17fc0d3d33065c667c0ce124c93b98f"/> + <project name="gaia" path="gaia" remote="mozillaorg" revision="af04d8bc2111d4ea146239a89ff602206b85eaf5"/> <project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/> <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="6969df171e5295f855f12d12db0382048e6892e7"/> <project name="librecovery" path="librecovery" remote="b2g" revision="891e5069c0ad330d8191bf8c7b879c814258c89f"/> <project name="moztt" path="external/moztt" remote="b2g" revision="562d357b72279a9e35d4af5aeecc8e1ffa2f44f1"/> <project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/> <project name="valgrind" path="external/valgrind" remote="b2g" revision="daa61633c32b9606f58799a3186395fd2bbb8d8c"/> <project name="vex" path="external/VEX" remote="b2g" revision="47f031c320888fe9f3e656602588565b52d43010"/> - <project name="apitrace" path="external/apitrace" remote="apitrace" revision="7ddb07033043613303061416882c9b02ac3d76b6"/> + <project name="apitrace" path="external/apitrace" remote="apitrace" revision="2aa3a0d353812bb8732a122965ffdbf5f889ca12"/> <!-- Stock Android things --> <project groups="linux" name="platform/prebuilts/gcc/linux-x86/host/i686-linux-glibc2.7-4.6" path="prebuilts/gcc/linux-x86/host/i686-linux-glibc2.7-4.6" revision="95bb5b66b3ec5769c3de8d3f25d681787418e7d2"/> <project groups="linux" name="platform/prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.7-4.6" path="prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.7-4.6" revision="ebdad82e61c16772f6cd47e9f11936bf6ebe9aa0"/> <project groups="linux,arm" name="platform/prebuilts/gcc/linux-x86/arm/arm-eabi-4.7" path="prebuilts/gcc/linux-x86/arm/arm-eabi-4.7" revision="8b880805d454664b3eed11d0f053cdeafa1ff06e"/> <project groups="linux,arm" name="platform/prebuilts/gcc/linux-x86/arm/arm-linux-androideabi-4.7" path="prebuilts/gcc/linux-x86/arm/arm-linux-androideabi-4.7" revision="a1e239a0bb5cd1d69680bf1075883aa9a7bf2429"/> <project groups="linux,x86" name="platform/prebuilts/gcc/linux-x86/x86/i686-linux-android-4.7" path="prebuilts/gcc/linux-x86/x86/i686-linux-android-4.7" revision="c7931763d41be602407ed9d71e2c0292c6597e00"/> <project groups="linux,x86" name="platform/prebuilts/python/linux-x86/2.7.5" path="prebuilts/python/linux-x86/2.7.5" revision="83760d213fb3bec7b4117d266fcfbf6fe2ba14ab"/> <project name="device/common" path="device/common" revision="6a2995683de147791e516aae2ccb31fdfbe2ad30"/> @@ -122,17 +122,17 @@ <project name="platform/system/security" path="system/security" revision="ee8068b9e7bfb2770635062fc9c2035be2142bd8"/> <project name="platform/system/vold" path="system/vold" revision="118dec582647895a863dbbce8ec26bc7af457bbe"/> <!--original fetch url was http://sprdsource.spreadtrum.com:8085/b2g/android--> <remote fetch="https://git.mozilla.org/external/sprd-aosp" name="sprd-aosp"/> <default remote="sprd-aosp" revision="sprdb2g_gonk4.4" sync-j="4"/> <!-- Stock Android things --> <project name="platform/external/icu4c" path="external/icu4c" revision="2bb01561780583cc37bc667f0ea79f48a122d8a2"/> <!-- dolphin specific things --> - <project name="device/sprd" path="device/sprd" revision="4eac1e31bf69596bf229a6877c9aa3493ecd9fce"/> + <project name="device/sprd" path="device/sprd" revision="3ba0b8b4e3f55d68f84603218e522d054a723532"/> <project name="platform/external/wpa_supplicant_8" path="external/wpa_supplicant_8" revision="4e58336019b5cbcfd134caf55b142236cf986618"/> <project name="platform/frameworks/av" path="frameworks/av" revision="facca8d3e35431b66f85a4eb42bc6c5b24bd04da"/> <project name="platform/hardware/akm" path="hardware/akm" revision="6d3be412647b0eab0adff8a2768736cf4eb68039"/> <project groups="invensense" name="platform/hardware/invensense" path="hardware/invensense" revision="e6d9ab28b4f4e7684f6c07874ee819c9ea0002a2"/> <project name="platform/hardware/ril" path="hardware/ril" revision="865ce3b4a2ba0b3a31421ca671f4d6c5595f8690"/> <project name="kernel/common" path="kernel" revision="03effd4db31881b2dd8d57575694515327f9ea2e"/> <project name="platform/system/core" path="system/core" revision="53d584d4a4b4316e4de9ee5f210d662f89b44e7e"/> <project name="u-boot" path="u-boot" revision="df509ae75495aa409969973b97ee781037dee1fe"/>
--- a/b2g/config/emulator-ics/sources.xml +++ b/b2g/config/emulator-ics/sources.xml @@ -14,23 +14,23 @@ <!--original fetch url was git://github.com/apitrace/--> <remote fetch="https://git.mozilla.org/external/apitrace" name="apitrace"/> <default remote="caf" revision="refs/tags/android-4.0.4_r2.1" sync-j="4"/> <!-- Gonk specific things and forks --> <project name="platform_build" path="build" remote="b2g" revision="0d616942c300d9fb142483210f1dda9096c9a9fc"> <copyfile dest="Makefile" src="core/root.mk"/> </project> <project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/> - <project name="gaia.git" path="gaia" remote="mozillaorg" revision="52670853c17fc0d3d33065c667c0ce124c93b98f"/> + <project name="gaia.git" path="gaia" remote="mozillaorg" revision="af04d8bc2111d4ea146239a89ff602206b85eaf5"/> <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="6969df171e5295f855f12d12db0382048e6892e7"/> <project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/> <project name="platform_hardware_ril" path="hardware/ril" remote="b2g" revision="cd88d860656c31c7da7bb310d6a160d0011b0961"/> <project name="platform_external_qemu" path="external/qemu" remote="b2g" revision="c058843242068d0df7c107e09da31b53d2e08fa6"/> <project name="moztt" path="external/moztt" remote="b2g" revision="562d357b72279a9e35d4af5aeecc8e1ffa2f44f1"/> - <project name="apitrace" path="external/apitrace" remote="apitrace" revision="7ddb07033043613303061416882c9b02ac3d76b6"/> + <project name="apitrace" path="external/apitrace" remote="apitrace" revision="2aa3a0d353812bb8732a122965ffdbf5f889ca12"/> <!-- Stock Android things --> <project name="platform/abi/cpp" path="abi/cpp" revision="dd924f92906085b831bf1cbbc7484d3c043d613c"/> <project name="platform/bionic" path="bionic" revision="c72b8f6359de7ed17c11ddc9dfdde3f615d188a9"/> <project name="platform/bootable/recovery" path="bootable/recovery" revision="425f8b5fadf5889834c5acd27d23c9e0b2129c28"/> <project name="device/common" path="device/common" revision="42b808b7e93d0619286ae8e59110b176b7732389"/> <project name="device/sample" path="device/sample" revision="237bd668d0f114d801a8d6455ef5e02cc3577587"/> <project name="platform_external_apriori" path="external/apriori" remote="b2g" revision="11816ad0406744f963537b23d68ed9c2afb412bd"/> <project name="platform/external/bluetooth/bluez" path="external/bluetooth/bluez" revision="52a1a862a8bac319652b8f82d9541ba40bfa45ce"/>
--- a/b2g/config/emulator-jb/sources.xml +++ b/b2g/config/emulator-jb/sources.xml @@ -12,20 +12,20 @@ <!--original fetch url was https://git.mozilla.org/releases--> <remote fetch="https://git.mozilla.org/releases" name="mozillaorg"/> <!-- B2G specific things. --> <project name="platform_build" path="build" remote="b2g" revision="74465af039d2809454afdfef285285bb63146e1b"> <copyfile dest="Makefile" src="core/root.mk"/> </project> <project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/> <project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/> - <project name="gaia" path="gaia" remote="mozillaorg" revision="52670853c17fc0d3d33065c667c0ce124c93b98f"/> + <project name="gaia" path="gaia" remote="mozillaorg" revision="af04d8bc2111d4ea146239a89ff602206b85eaf5"/> <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="6969df171e5295f855f12d12db0382048e6892e7"/> <project name="moztt" path="external/moztt" remote="b2g" revision="562d357b72279a9e35d4af5aeecc8e1ffa2f44f1"/> - <project name="apitrace" path="external/apitrace" remote="apitrace" revision="7ddb07033043613303061416882c9b02ac3d76b6"/> + <project name="apitrace" path="external/apitrace" remote="apitrace" revision="2aa3a0d353812bb8732a122965ffdbf5f889ca12"/> <project name="valgrind" path="external/valgrind" remote="b2g" revision="daa61633c32b9606f58799a3186395fd2bbb8d8c"/> <project name="vex" path="external/VEX" remote="b2g" revision="47f031c320888fe9f3e656602588565b52d43010"/> <!-- Stock Android things --> <project groups="linux" name="platform/prebuilts/clang/linux-x86/3.1" path="prebuilts/clang/linux-x86/3.1" revision="5c45f43419d5582949284eee9cef0c43d866e03b"/> <project groups="linux" name="platform/prebuilts/clang/linux-x86/3.2" path="prebuilts/clang/linux-x86/3.2" revision="3748b4168e7bd8d46457d4b6786003bc6a5223ce"/> <project groups="linux" name="platform/prebuilts/gcc/linux-x86/host/i686-linux-glibc2.7-4.6" path="prebuilts/gcc/linux-x86/host/i686-linux-glibc2.7-4.6" revision="9025e50b9d29b3cabbbb21e1dd94d0d13121a17e"/> <project groups="linux" name="platform/prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.7-4.6" path="prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.7-4.6" revision="b89fda71fcd0fa0cf969310e75be3ea33e048b44"/> <project groups="linux,arm" name="platform/prebuilts/gcc/linux-x86/arm/arm-eabi-4.7" path="prebuilts/gcc/linux-x86/arm/arm-eabi-4.7" revision="2e7d5348f35575870b3c7e567a9a9f6d66f8d6c5"/>
--- a/b2g/config/emulator-kk/sources.xml +++ b/b2g/config/emulator-kk/sources.xml @@ -10,25 +10,25 @@ <!--original fetch url was git://codeaurora.org/--> <remote fetch="https://git.mozilla.org/external/caf" name="caf"/> <!--original fetch url was https://git.mozilla.org/releases--> <remote fetch="https://git.mozilla.org/releases" name="mozillaorg"/> <!-- B2G specific things. --> <project name="platform_build" path="build" remote="b2g" revision="4b4336c73c081b39776d399835ce4853aee5cc1c"> <copyfile dest="Makefile" src="core/root.mk"/> </project> - <project name="gaia" path="gaia" remote="mozillaorg" revision="52670853c17fc0d3d33065c667c0ce124c93b98f"/> + <project name="gaia" path="gaia" remote="mozillaorg" revision="af04d8bc2111d4ea146239a89ff602206b85eaf5"/> <project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/> <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="6969df171e5295f855f12d12db0382048e6892e7"/> <project name="librecovery" path="librecovery" remote="b2g" revision="891e5069c0ad330d8191bf8c7b879c814258c89f"/> <project name="moztt" path="external/moztt" remote="b2g" revision="562d357b72279a9e35d4af5aeecc8e1ffa2f44f1"/> <project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/> <project name="valgrind" path="external/valgrind" remote="b2g" revision="daa61633c32b9606f58799a3186395fd2bbb8d8c"/> <project name="vex" path="external/VEX" remote="b2g" revision="47f031c320888fe9f3e656602588565b52d43010"/> - <project name="apitrace" path="external/apitrace" remote="apitrace" revision="7ddb07033043613303061416882c9b02ac3d76b6"/> + <project name="apitrace" path="external/apitrace" remote="apitrace" revision="2aa3a0d353812bb8732a122965ffdbf5f889ca12"/> <!-- Stock Android things --> <project groups="linux" name="platform/prebuilts/gcc/linux-x86/host/i686-linux-glibc2.7-4.6" path="prebuilts/gcc/linux-x86/host/i686-linux-glibc2.7-4.6" revision="f92a936f2aa97526d4593386754bdbf02db07a12"/> <project groups="linux" name="platform/prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.7-4.6" path="prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.7-4.6" revision="6e47ff2790f5656b5b074407829ceecf3e6188c4"/> <project groups="linux,arm" name="platform/prebuilts/gcc/linux-x86/arm/arm-eabi-4.7" path="prebuilts/gcc/linux-x86/arm/arm-eabi-4.7" revision="1950e4760fa14688b83cdbb5acaa1af9f82ef434"/> <project groups="linux,arm" name="platform/prebuilts/gcc/linux-x86/arm/arm-linux-androideabi-4.7" path="prebuilts/gcc/linux-x86/arm/arm-linux-androideabi-4.7" revision="ac6eb97a37035c09fb5ede0852f0881e9aadf9ad"/> <project groups="linux,x86" name="platform/prebuilts/gcc/linux-x86/x86/i686-linux-android-4.7" path="prebuilts/gcc/linux-x86/x86/i686-linux-android-4.7" revision="737f591c5f95477148d26602c7be56cbea0cdeb9"/> <project groups="linux,x86" name="platform/prebuilts/python/linux-x86/2.7.5" path="prebuilts/python/linux-x86/2.7.5" revision="51da9b1981be481b92a59a826d4d78dc73d0989a"/> <project name="device/common" path="device/common" revision="798a3664597e6041985feab9aef42e98d458bc3d"/>
--- a/b2g/config/emulator/sources.xml +++ b/b2g/config/emulator/sources.xml @@ -14,23 +14,23 @@ <!--original fetch url was git://github.com/apitrace/--> <remote fetch="https://git.mozilla.org/external/apitrace" name="apitrace"/> <default remote="caf" revision="refs/tags/android-4.0.4_r2.1" sync-j="4"/> <!-- Gonk specific things and forks --> <project name="platform_build" path="build" remote="b2g" revision="0d616942c300d9fb142483210f1dda9096c9a9fc"> <copyfile dest="Makefile" src="core/root.mk"/> </project> <project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/> - <project name="gaia.git" path="gaia" remote="mozillaorg" revision="52670853c17fc0d3d33065c667c0ce124c93b98f"/> + <project name="gaia.git" path="gaia" remote="mozillaorg" revision="af04d8bc2111d4ea146239a89ff602206b85eaf5"/> <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="6969df171e5295f855f12d12db0382048e6892e7"/> <project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/> <project name="platform_hardware_ril" path="hardware/ril" remote="b2g" revision="cd88d860656c31c7da7bb310d6a160d0011b0961"/> <project name="platform_external_qemu" path="external/qemu" remote="b2g" revision="c058843242068d0df7c107e09da31b53d2e08fa6"/> <project name="moztt" path="external/moztt" remote="b2g" revision="562d357b72279a9e35d4af5aeecc8e1ffa2f44f1"/> - <project name="apitrace" path="external/apitrace" remote="apitrace" revision="7ddb07033043613303061416882c9b02ac3d76b6"/> + <project name="apitrace" path="external/apitrace" remote="apitrace" revision="2aa3a0d353812bb8732a122965ffdbf5f889ca12"/> <!-- Stock Android things --> <project name="platform/abi/cpp" path="abi/cpp" revision="dd924f92906085b831bf1cbbc7484d3c043d613c"/> <project name="platform/bionic" path="bionic" revision="c72b8f6359de7ed17c11ddc9dfdde3f615d188a9"/> <project name="platform/bootable/recovery" path="bootable/recovery" revision="425f8b5fadf5889834c5acd27d23c9e0b2129c28"/> <project name="device/common" path="device/common" revision="42b808b7e93d0619286ae8e59110b176b7732389"/> <project name="device/sample" path="device/sample" revision="237bd668d0f114d801a8d6455ef5e02cc3577587"/> <project name="platform_external_apriori" path="external/apriori" remote="b2g" revision="11816ad0406744f963537b23d68ed9c2afb412bd"/> <project name="platform/external/bluetooth/bluez" path="external/bluetooth/bluez" revision="52a1a862a8bac319652b8f82d9541ba40bfa45ce"/>
--- a/b2g/config/flame-kk/sources.xml +++ b/b2g/config/flame-kk/sources.xml @@ -10,25 +10,25 @@ <!--original fetch url was git://codeaurora.org/--> <remote fetch="https://git.mozilla.org/external/caf" name="caf"/> <!--original fetch url was https://git.mozilla.org/releases--> <remote fetch="https://git.mozilla.org/releases" name="mozillaorg"/> <!-- B2G specific things. --> <project name="platform_build" path="build" remote="b2g" revision="4b4336c73c081b39776d399835ce4853aee5cc1c"> <copyfile dest="Makefile" src="core/root.mk"/> </project> - <project name="gaia" path="gaia" remote="mozillaorg" revision="52670853c17fc0d3d33065c667c0ce124c93b98f"/> + <project name="gaia" path="gaia" remote="mozillaorg" revision="af04d8bc2111d4ea146239a89ff602206b85eaf5"/> <project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/> <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="6969df171e5295f855f12d12db0382048e6892e7"/> <project name="librecovery" path="librecovery" remote="b2g" revision="891e5069c0ad330d8191bf8c7b879c814258c89f"/> <project name="moztt" path="external/moztt" remote="b2g" revision="562d357b72279a9e35d4af5aeecc8e1ffa2f44f1"/> <project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/> <project name="valgrind" path="external/valgrind" remote="b2g" revision="daa61633c32b9606f58799a3186395fd2bbb8d8c"/> <project name="vex" path="external/VEX" remote="b2g" revision="47f031c320888fe9f3e656602588565b52d43010"/> - <project name="apitrace" path="external/apitrace" remote="apitrace" revision="7ddb07033043613303061416882c9b02ac3d76b6"/> + <project name="apitrace" path="external/apitrace" remote="apitrace" revision="2aa3a0d353812bb8732a122965ffdbf5f889ca12"/> <!-- Stock Android things --> <project groups="linux" name="platform/prebuilts/gcc/linux-x86/host/i686-linux-glibc2.7-4.6" path="prebuilts/gcc/linux-x86/host/i686-linux-glibc2.7-4.6" revision="95bb5b66b3ec5769c3de8d3f25d681787418e7d2"/> <project groups="linux" name="platform/prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.7-4.6" path="prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.7-4.6" revision="ebdad82e61c16772f6cd47e9f11936bf6ebe9aa0"/> <project groups="linux,arm" name="platform/prebuilts/gcc/linux-x86/arm/arm-eabi-4.7" path="prebuilts/gcc/linux-x86/arm/arm-eabi-4.7" revision="8b880805d454664b3eed11d0f053cdeafa1ff06e"/> <project groups="linux,arm" name="platform/prebuilts/gcc/linux-x86/arm/arm-linux-androideabi-4.7" path="prebuilts/gcc/linux-x86/arm/arm-linux-androideabi-4.7" revision="a1e239a0bb5cd1d69680bf1075883aa9a7bf2429"/> <project groups="linux,x86" name="platform/prebuilts/gcc/linux-x86/x86/i686-linux-android-4.7" path="prebuilts/gcc/linux-x86/x86/i686-linux-android-4.7" revision="c7931763d41be602407ed9d71e2c0292c6597e00"/> <project groups="linux,x86" name="platform/prebuilts/python/linux-x86/2.7.5" path="prebuilts/python/linux-x86/2.7.5" revision="a32003194f707f66a2d8cdb913ed1869f1926c5d"/> <project name="device/common" path="device/common" revision="96d4d2006c4fcb2f19a3fa47ab10cb409faa017b"/>
--- a/b2g/config/flame/sources.xml +++ b/b2g/config/flame/sources.xml @@ -12,20 +12,20 @@ <!--original fetch url was https://git.mozilla.org/releases--> <remote fetch="https://git.mozilla.org/releases" name="mozillaorg"/> <!-- B2G specific things. --> <project name="platform_build" path="build" remote="b2g" revision="74465af039d2809454afdfef285285bb63146e1b"> <copyfile dest="Makefile" src="core/root.mk"/> </project> <project name="librecovery" path="librecovery" remote="b2g" revision="891e5069c0ad330d8191bf8c7b879c814258c89f"/> <project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/> - <project name="gaia" path="gaia" remote="mozillaorg" revision="52670853c17fc0d3d33065c667c0ce124c93b98f"/> + <project name="gaia" path="gaia" remote="mozillaorg" revision="af04d8bc2111d4ea146239a89ff602206b85eaf5"/> <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="6969df171e5295f855f12d12db0382048e6892e7"/> <project name="moztt" path="external/moztt" remote="b2g" revision="562d357b72279a9e35d4af5aeecc8e1ffa2f44f1"/> - <project name="apitrace" path="external/apitrace" remote="apitrace" revision="7ddb07033043613303061416882c9b02ac3d76b6"/> + <project name="apitrace" path="external/apitrace" remote="apitrace" revision="2aa3a0d353812bb8732a122965ffdbf5f889ca12"/> <project name="valgrind" path="external/valgrind" remote="b2g" revision="daa61633c32b9606f58799a3186395fd2bbb8d8c"/> <project name="vex" path="external/VEX" remote="b2g" revision="47f031c320888fe9f3e656602588565b52d43010"/> <!-- Stock Android things --> <project groups="linux" name="platform/prebuilts/clang/linux-x86/3.1" path="prebuilts/clang/linux-x86/3.1" revision="e95b4ce22c825da44d14299e1190ea39a5260bde"/> <project groups="linux" name="platform/prebuilts/clang/linux-x86/3.2" path="prebuilts/clang/linux-x86/3.2" revision="471afab478649078ad7c75ec6b252481a59e19b8"/> <project groups="linux" name="platform/prebuilts/gcc/linux-x86/host/i686-linux-glibc2.7-4.6" path="prebuilts/gcc/linux-x86/host/i686-linux-glibc2.7-4.6" revision="95bb5b66b3ec5769c3de8d3f25d681787418e7d2"/> <project groups="linux" name="platform/prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.7-4.6" path="prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.7-4.6" revision="ebdad82e61c16772f6cd47e9f11936bf6ebe9aa0"/> <project groups="linux,arm" name="platform/prebuilts/gcc/linux-x86/arm/arm-eabi-4.7" path="prebuilts/gcc/linux-x86/arm/arm-eabi-4.7" revision="8b880805d454664b3eed11d0f053cdeafa1ff06e"/>
--- a/b2g/config/gaia.json +++ b/b2g/config/gaia.json @@ -1,9 +1,9 @@ { "git": { "git_revision": "", "remote": "", "branch": "" }, - "revision": "a0fe2fdc571f1a5eb5474e08773fac80f9bb9fbd", + "revision": "dc9488c3826ae1dbd0051ac19c83c5da1f4915a7", "repo_path": "/integration/gaia-central" }
--- a/b2g/config/hamachi/sources.xml +++ b/b2g/config/hamachi/sources.xml @@ -12,22 +12,22 @@ <!--original fetch url was git://github.com/apitrace/--> <remote fetch="https://git.mozilla.org/external/apitrace" name="apitrace"/> <default remote="caf" revision="b2g/ics_strawberry" sync-j="4"/> <!-- Gonk specific things and forks --> <project name="platform_build" path="build" remote="b2g" revision="0d616942c300d9fb142483210f1dda9096c9a9fc"> <copyfile dest="Makefile" src="core/root.mk"/> </project> <project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/> - <project name="gaia.git" path="gaia" remote="mozillaorg" revision="52670853c17fc0d3d33065c667c0ce124c93b98f"/> + <project name="gaia.git" path="gaia" remote="mozillaorg" revision="af04d8bc2111d4ea146239a89ff602206b85eaf5"/> <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="6969df171e5295f855f12d12db0382048e6892e7"/> <project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/> <project name="librecovery" path="librecovery" remote="b2g" revision="891e5069c0ad330d8191bf8c7b879c814258c89f"/> <project name="moztt" path="external/moztt" remote="b2g" revision="562d357b72279a9e35d4af5aeecc8e1ffa2f44f1"/> - <project name="apitrace" path="external/apitrace" remote="apitrace" revision="7ddb07033043613303061416882c9b02ac3d76b6"/> + <project name="apitrace" path="external/apitrace" remote="apitrace" revision="2aa3a0d353812bb8732a122965ffdbf5f889ca12"/> <!-- Stock Android things --> <project name="platform/abi/cpp" path="abi/cpp" revision="6426040f1be4a844082c9769171ce7f5341a5528"/> <project name="platform/bionic" path="bionic" revision="d2eb6c7b6e1bc7643c17df2d9d9bcb1704d0b9ab"/> <project name="platform/bootable/recovery" path="bootable/recovery" revision="746bc48f34f5060f90801925dcdd964030c1ab6d"/> <project name="platform/development" path="development" revision="2460485184bc8535440bb63876d4e63ec1b4770c"/> <project name="device/common" path="device/common" revision="0dcc1e03659db33b77392529466f9eb685cdd3c7"/> <project name="device/sample" path="device/sample" revision="68b1cb978a20806176123b959cb05d4fa8adaea4"/> <project name="platform_external_apriori" path="external/apriori" remote="b2g" revision="11816ad0406744f963537b23d68ed9c2afb412bd"/>
--- a/b2g/config/helix/sources.xml +++ b/b2g/config/helix/sources.xml @@ -10,17 +10,17 @@ <!--original fetch url was https://git.mozilla.org/releases--> <remote fetch="https://git.mozilla.org/releases" name="mozillaorg"/> <default remote="caf" revision="b2g/ics_strawberry" sync-j="4"/> <!-- Gonk specific things and forks --> <project name="platform_build" path="build" remote="b2g" revision="0d616942c300d9fb142483210f1dda9096c9a9fc"> <copyfile dest="Makefile" src="core/root.mk"/> </project> <project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/> - <project name="gaia.git" path="gaia" remote="mozillaorg" revision="52670853c17fc0d3d33065c667c0ce124c93b98f"/> + <project name="gaia.git" path="gaia" remote="mozillaorg" revision="af04d8bc2111d4ea146239a89ff602206b85eaf5"/> <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="6969df171e5295f855f12d12db0382048e6892e7"/> <project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/> <project name="librecovery" path="librecovery" remote="b2g" revision="891e5069c0ad330d8191bf8c7b879c814258c89f"/> <project name="moztt" path="external/moztt" remote="b2g" revision="562d357b72279a9e35d4af5aeecc8e1ffa2f44f1"/> <project name="gonk-patches" path="patches" remote="b2g" revision="223a2421006e8f5da33f516f6891c87cae86b0f6"/> <!-- Stock Android things --> <project name="platform/abi/cpp" path="abi/cpp" revision="6426040f1be4a844082c9769171ce7f5341a5528"/> <project name="platform/bionic" path="bionic" revision="d2eb6c7b6e1bc7643c17df2d9d9bcb1704d0b9ab"/>
--- a/b2g/config/nexus-4/sources.xml +++ b/b2g/config/nexus-4/sources.xml @@ -12,20 +12,20 @@ <!--original fetch url was https://git.mozilla.org/releases--> <remote fetch="https://git.mozilla.org/releases" name="mozillaorg"/> <!-- B2G specific things. --> <project name="platform_build" path="build" remote="b2g" revision="74465af039d2809454afdfef285285bb63146e1b"> <copyfile dest="Makefile" src="core/root.mk"/> </project> <project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/> <project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/> - <project name="gaia" path="gaia" remote="mozillaorg" revision="52670853c17fc0d3d33065c667c0ce124c93b98f"/> + <project name="gaia" path="gaia" remote="mozillaorg" revision="af04d8bc2111d4ea146239a89ff602206b85eaf5"/> <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="6969df171e5295f855f12d12db0382048e6892e7"/> <project name="moztt" path="external/moztt" remote="b2g" revision="562d357b72279a9e35d4af5aeecc8e1ffa2f44f1"/> - <project name="apitrace" path="external/apitrace" remote="apitrace" revision="7ddb07033043613303061416882c9b02ac3d76b6"/> + <project name="apitrace" path="external/apitrace" remote="apitrace" revision="2aa3a0d353812bb8732a122965ffdbf5f889ca12"/> <project name="valgrind" path="external/valgrind" remote="b2g" revision="daa61633c32b9606f58799a3186395fd2bbb8d8c"/> <project name="vex" path="external/VEX" remote="b2g" revision="47f031c320888fe9f3e656602588565b52d43010"/> <!-- Stock Android things --> <project groups="linux" name="platform/prebuilts/clang/linux-x86/3.1" path="prebuilts/clang/linux-x86/3.1" revision="5c45f43419d5582949284eee9cef0c43d866e03b"/> <project groups="linux" name="platform/prebuilts/clang/linux-x86/3.2" path="prebuilts/clang/linux-x86/3.2" revision="3748b4168e7bd8d46457d4b6786003bc6a5223ce"/> <project groups="linux" name="platform/prebuilts/gcc/linux-x86/host/i686-linux-glibc2.7-4.6" path="prebuilts/gcc/linux-x86/host/i686-linux-glibc2.7-4.6" revision="9025e50b9d29b3cabbbb21e1dd94d0d13121a17e"/> <project groups="linux" name="platform/prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.7-4.6" path="prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.7-4.6" revision="b89fda71fcd0fa0cf969310e75be3ea33e048b44"/> <project groups="linux,arm" name="platform/prebuilts/gcc/linux-x86/arm/arm-eabi-4.7" path="prebuilts/gcc/linux-x86/arm/arm-eabi-4.7" revision="2e7d5348f35575870b3c7e567a9a9f6d66f8d6c5"/>
--- a/b2g/config/wasabi/sources.xml +++ b/b2g/config/wasabi/sources.xml @@ -12,22 +12,22 @@ <!--original fetch url was git://github.com/apitrace/--> <remote fetch="https://git.mozilla.org/external/apitrace" name="apitrace"/> <default remote="caf" revision="ics_chocolate_rb4.2" sync-j="4"/> <!-- Gonk specific things and forks --> <project name="platform_build" path="build" remote="b2g" revision="0d616942c300d9fb142483210f1dda9096c9a9fc"> <copyfile dest="Makefile" src="core/root.mk"/> </project> <project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/> - <project name="gaia.git" path="gaia" remote="mozillaorg" revision="52670853c17fc0d3d33065c667c0ce124c93b98f"/> + <project name="gaia.git" path="gaia" remote="mozillaorg" revision="af04d8bc2111d4ea146239a89ff602206b85eaf5"/> <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="6969df171e5295f855f12d12db0382048e6892e7"/> <project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/> <project name="librecovery" path="librecovery" remote="b2g" revision="891e5069c0ad330d8191bf8c7b879c814258c89f"/> <project name="moztt" path="external/moztt" remote="b2g" revision="562d357b72279a9e35d4af5aeecc8e1ffa2f44f1"/> - <project name="apitrace" path="external/apitrace" remote="apitrace" revision="7ddb07033043613303061416882c9b02ac3d76b6"/> + <project name="apitrace" path="external/apitrace" remote="apitrace" revision="2aa3a0d353812bb8732a122965ffdbf5f889ca12"/> <project name="gonk-patches" path="patches" remote="b2g" revision="223a2421006e8f5da33f516f6891c87cae86b0f6"/> <!-- Stock Android things --> <project name="platform/abi/cpp" path="abi/cpp" revision="6426040f1be4a844082c9769171ce7f5341a5528"/> <project name="platform/bionic" path="bionic" revision="cd5dfce80bc3f0139a56b58aca633202ccaee7f8"/> <project name="platform/bootable/recovery" path="bootable/recovery" revision="e0a9ac010df3afaa47ba107192c05ac8b5516435"/> <project name="platform/development" path="development" revision="a384622f5fcb1d2bebb9102591ff7ae91fe8ed2d"/> <project name="device/common" path="device/common" revision="7c65ea240157763b8ded6154a17d3c033167afb7"/> <project name="device/sample" path="device/sample" revision="c328f3d4409db801628861baa8d279fb8855892f"/>
--- a/b2g/installer/package-manifest.in +++ b/b2g/installer/package-manifest.in @@ -436,16 +436,18 @@ @BINPATH@/components/MmsService.manifest @BINPATH@/components/MobileMessageDatabaseService.js @BINPATH@/components/MobileMessageDatabaseService.manifest @BINPATH@/components/RadioInterfaceLayer.js @BINPATH@/components/RadioInterfaceLayer.manifest @BINPATH@/components/RILContentHelper.js @BINPATH@/components/TelephonyService.js @BINPATH@/components/TelephonyService.manifest +@BINPATH@/components/MobileConnectionGonkService.js +@BINPATH@/components/MobileConnectionGonkService.manifest #endif // MOZ_WIDGET_GONK && MOZ_B2G_RIL #ifndef MOZ_WIDGET_GONK @BINPATH@/components/extensions.manifest @BINPATH@/components/addonManager.js @BINPATH@/components/amContentHandler.js @BINPATH@/components/amInstallTrigger.js @BINPATH@/components/amWebInstallListener.js
--- a/dom/bluetooth/BluetoothRilListener.cpp +++ b/dom/bluetooth/BluetoothRilListener.cpp @@ -108,22 +108,22 @@ MobileConnectionListener::NotifyUssdRece NS_IMETHODIMP MobileConnectionListener::NotifyDataError(const nsAString & message) { return NS_OK; } NS_IMETHODIMP -MobileConnectionListener::NotifyCFStateChange(bool success, - uint16_t action, - uint16_t reason, - const nsAString& number, - uint16_t timeSeconds, - uint16_t serviceClass) +MobileConnectionListener::NotifyCFStateChanged(bool success, + uint16_t action, + uint16_t reason, + const nsAString& number, + uint16_t timeSeconds, + uint16_t serviceClass) { return NS_OK; } NS_IMETHODIMP MobileConnectionListener::NotifyEmergencyCbModeChanged(bool active, uint32_t timeoutMs) { @@ -149,28 +149,46 @@ MobileConnectionListener::NotifyRadioSta } NS_IMETHODIMP MobileConnectionListener::NotifyClirModeChanged(uint32_t aMode) { return NS_OK; } +NS_IMETHODIMP +MobileConnectionListener::NotifyLastKnownNetworkChanged() +{ + return NS_OK; +} + +NS_IMETHODIMP +MobileConnectionListener::NotifyLastKnownHomeNetworkChanged() +{ + return NS_OK; +} + +NS_IMETHODIMP +MobileConnectionListener::NotifyNetworkSelectionModeChanged() +{ + return NS_OK; +} + bool MobileConnectionListener::Listen(bool aStart) { - nsCOMPtr<nsIMobileConnectionProvider> provider = - do_GetService(NS_RILCONTENTHELPER_CONTRACTID); - NS_ENSURE_TRUE(provider, false); + nsCOMPtr<nsIMobileConnectionService> service = + do_GetService(NS_MOBILE_CONNECTION_SERVICE_CONTRACTID); + NS_ENSURE_TRUE(service, false); nsresult rv; if (aStart) { - rv = provider->RegisterMobileConnectionMsg(mClientId, this); + rv = service->RegisterListener(mClientId, this); } else { - rv = provider->UnregisterMobileConnectionMsg(mClientId, this); + rv = service->UnregisterListener(mClientId, this); } return NS_SUCCEEDED(rv); } /** * TelephonyListener Implementation */ @@ -347,23 +365,23 @@ BluetoothRilListener::Listen(bool aStart } void BluetoothRilListener::SelectClient() { // Reset mClientId mClientId = mMobileConnListeners.Length(); - nsCOMPtr<nsIMobileConnectionProvider> connection = - do_GetService(NS_RILCONTENTHELPER_CONTRACTID); - NS_ENSURE_TRUE_VOID(connection); + nsCOMPtr<nsIMobileConnectionService> service = + do_GetService(NS_MOBILE_CONNECTION_SERVICE_CONTRACTID); + NS_ENSURE_TRUE_VOID(service); for (uint32_t i = 0; i < mMobileConnListeners.Length(); i++) { nsCOMPtr<nsIMobileConnectionInfo> voiceInfo; - connection->GetVoiceConnectionInfo(i, getter_AddRefs(voiceInfo)); + service->GetVoiceConnectionInfo(i, getter_AddRefs(voiceInfo)); if (!voiceInfo) { BT_WARNING("%s: Failed to get voice connection info", __FUNCTION__); continue; } nsString regState; voiceInfo->GetState(regState); if (regState.EqualsLiteral("registered")) {
--- a/dom/bluetooth/BluetoothRilListener.h +++ b/dom/bluetooth/BluetoothRilListener.h @@ -7,17 +7,17 @@ #ifndef mozilla_dom_bluetooth_bluetoothrillistener_h__ #define mozilla_dom_bluetooth_bluetoothrillistener_h__ #include "BluetoothCommon.h" #include "nsAutoPtr.h" #include "nsIIccProvider.h" -#include "nsIMobileConnectionProvider.h" +#include "nsIMobileConnectionService.h" #include "nsITelephonyService.h" BEGIN_BLUETOOTH_NAMESPACE class BluetoothRilListener; class IccListener : public nsIIccListener {
--- a/dom/bluetooth/bluedroid/hfp/BluetoothHfpManager.cpp +++ b/dom/bluetooth/bluedroid/hfp/BluetoothHfpManager.cpp @@ -14,17 +14,17 @@ #include "mozilla/dom/bluetooth/BluetoothTypes.h" #include "mozilla/Services.h" #include "mozilla/StaticPtr.h" #include "nsContentUtils.h" #include "nsIAudioManager.h" #include "nsIDOMIccInfo.h" #include "nsIIccProvider.h" #include "nsIMobileConnectionInfo.h" -#include "nsIMobileConnectionProvider.h" +#include "nsIMobileConnectionService.h" #include "nsIMobileNetworkInfo.h" #include "nsIObserverService.h" #include "nsISettingsService.h" #include "nsITelephonyService.h" #include "nsRadioInterfaceLayer.h" #include "nsServiceManagerUtils.h" #include "nsThreadUtils.h" @@ -607,18 +607,18 @@ BluetoothHfpManager::HandleVolumeChanged sBluetoothHfpInterface->VolumeControl(HFP_VOLUME_TYPE_SPEAKER, mCurrentVgs, new VolumeControlResultHandler()); } } void BluetoothHfpManager::HandleVoiceConnectionChanged(uint32_t aClientId) { - nsCOMPtr<nsIMobileConnectionProvider> connection = - do_GetService(NS_RILCONTENTHELPER_CONTRACTID); + nsCOMPtr<nsIMobileConnectionService> connection = + do_GetService(NS_MOBILE_CONNECTION_SERVICE_CONTRACTID); NS_ENSURE_TRUE_VOID(connection); nsCOMPtr<nsIMobileConnectionInfo> voiceInfo; connection->GetVoiceConnectionInfo(aClientId, getter_AddRefs(voiceInfo)); NS_ENSURE_TRUE_VOID(voiceInfo); nsString type; voiceInfo->GetType(type);
--- a/dom/bluetooth/bluez/BluetoothHfpManager.cpp +++ b/dom/bluetooth/bluez/BluetoothHfpManager.cpp @@ -23,17 +23,17 @@ #include "nsIObserverService.h" #include "nsISettingsService.h" #include "nsServiceManagerUtils.h" #ifdef MOZ_B2G_RIL #include "nsIDOMIccInfo.h" #include "nsIIccProvider.h" #include "nsIMobileConnectionInfo.h" -#include "nsIMobileConnectionProvider.h" +#include "nsIMobileConnectionService.h" #include "nsIMobileNetworkInfo.h" #include "nsITelephonyService.h" #include "nsRadioInterfaceLayer.h" #endif /** * BRSF bitmask of AG supported features. See 4.34.1 "Bluetooth Defined AT * Capabilities" in Bluetooth hands-free profile 1.6 @@ -601,18 +601,18 @@ BluetoothHfpManager::HandleVolumeChanged SendCommand(RESPONSE_VGS, mCurrentVgs); } } #ifdef MOZ_B2G_RIL void BluetoothHfpManager::HandleVoiceConnectionChanged(uint32_t aClientId) { - nsCOMPtr<nsIMobileConnectionProvider> connection = - do_GetService(NS_RILCONTENTHELPER_CONTRACTID); + nsCOMPtr<nsIMobileConnectionService> connection = + do_GetService(NS_MOBILE_CONNECTION_SERVICE_CONTRACTID); NS_ENSURE_TRUE_VOID(connection); nsCOMPtr<nsIMobileConnectionInfo> voiceInfo; connection->GetVoiceConnectionInfo(aClientId, getter_AddRefs(voiceInfo)); NS_ENSURE_TRUE_VOID(voiceInfo); nsString type; voiceInfo->GetType(type);
--- a/dom/bluetooth2/BluetoothAdapter.cpp +++ b/dom/bluetooth2/BluetoothAdapter.cpp @@ -33,37 +33,17 @@ NS_IMPL_CYCLE_COLLECTION_INHERITED(Bluet // QueryInterface implementation for BluetoothAdapter NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(BluetoothAdapter) NS_INTERFACE_MAP_END_INHERITING(DOMEventTargetHelper) NS_IMPL_ADDREF_INHERITED(BluetoothAdapter, DOMEventTargetHelper) NS_IMPL_RELEASE_INHERITED(BluetoothAdapter, DOMEventTargetHelper) -/* - * A comparator that does the comparison of BluetoothDevice instances. - * Two BluetoothDevices are equivalent if they have an identical address. - */ -class BluetoothDeviceComparator -{ -public: - bool Equals(const BluetoothDevice* aDeviceA, - const BluetoothDevice* aDeviceB) const - { - nsString addressA; - nsString addressB; - - aDeviceA->GetAddress(addressA); - aDeviceB->GetAddress(addressB); - - return addressA.Equals(addressB); - } -}; - -class StartDiscoveryTask : public BluetoothReplyRunnable +class StartDiscoveryTask MOZ_FINAL : public BluetoothReplyRunnable { public: StartDiscoveryTask(BluetoothAdapter* aAdapter, Promise* aPromise) : BluetoothReplyRunnable(nullptr, aPromise, NS_LITERAL_STRING("StartDiscovery")) , mAdapter(aAdapter) { MOZ_ASSERT(aPromise); @@ -204,20 +184,20 @@ public: } }; static int kCreatePairedDeviceTimeout = 50000; // unit: msec BluetoothAdapter::BluetoothAdapter(nsPIDOMWindow* aWindow, const BluetoothValue& aValue) : DOMEventTargetHelper(aWindow) - , mDiscoveryHandleInUse(nullptr) , mState(BluetoothAdapterState::Disabled) , mDiscoverable(false) , mDiscovering(false) + , mDiscoveryHandleInUse(nullptr) { MOZ_ASSERT(aWindow); MOZ_ASSERT(IsDOMBinding()); mPairingReqs = BluetoothPairingListener::Create(aWindow); const InfallibleTArray<BluetoothNamedValue>& values = aValue.get_ArrayOfBluetoothNamedValue(); @@ -299,17 +279,17 @@ BluetoothAdapter::SetPropertyByValue(con BT_APPEND_NAMED_VALUE(props, "Address", pairedDeviceAddresses[i]); BT_APPEND_NAMED_VALUE(props, "Paired", true); // Create paired device with 'address' and 'paired' attributes nsRefPtr<BluetoothDevice> pairedDevice = BluetoothDevice::Create(GetOwner(), BluetoothValue(props)); // Append to adapter's device array if the device hasn't been created - if (!mDevices.Contains(pairedDevice, BluetoothDeviceComparator())) { + if (!mDevices.Contains(pairedDevice)) { mDevices.AppendElement(pairedDevice); } } // Retrieve device properties, result will be handled by device objects. GetPairedDeviceProperties(pairedDeviceAddresses); } else { BT_WARNING("Not handling adapter property: %s", @@ -656,78 +636,93 @@ BluetoothAdapter::Pair(const nsAString& already_AddRefed<Promise> BluetoothAdapter::Unpair(const nsAString& aDeviceAddress, ErrorResult& aRv) { return PairUnpair(false, aDeviceAddress, aRv); } already_AddRefed<Promise> -BluetoothAdapter::EnableDisable(bool aEnable, ErrorResult& aRv) +BluetoothAdapter::Enable(ErrorResult& aRv) { nsCOMPtr<nsIGlobalObject> global = do_QueryInterface(GetOwner()); if (!global) { aRv.Throw(NS_ERROR_FAILURE); return nullptr; } nsRefPtr<Promise> promise = Promise::Create(global, aRv); NS_ENSURE_TRUE(!aRv.Failed(), nullptr); - // Ensure BluetoothService is available before modifying adapter state + /** + * Ensure + * - adapter is disabled, and + * - BluetoothService is available. + */ + BT_ENSURE_TRUE_REJECT(mState == BluetoothAdapterState::Disabled, + NS_ERROR_DOM_INVALID_STATE_ERR); BluetoothService* bs = BluetoothService::Get(); BT_ENSURE_TRUE_REJECT(bs, NS_ERROR_NOT_AVAILABLE); - // Modify adapter state to Enabling/Disabling if adapter is in a valid state - nsAutoString methodName; - if (aEnable) { - // Enable local adapter - BT_ENSURE_TRUE_REJECT(mState == BluetoothAdapterState::Disabled, - NS_ERROR_DOM_INVALID_STATE_ERR); - methodName.AssignLiteral("Enable"); - mState = BluetoothAdapterState::Enabling; - } else { - // Disable local adapter - BT_ENSURE_TRUE_REJECT(mState == BluetoothAdapterState::Enabled, - NS_ERROR_DOM_INVALID_STATE_ERR); - methodName.AssignLiteral("Disable"); - mState = BluetoothAdapterState::Disabling; - } - - // Notify applications of adapter state change to Enabling/Disabling - HandleAdapterStateChanged(); + // Set adapter state "Enabling" + SetAdapterState(BluetoothAdapterState::Enabling); // Wrap runnable to handle result nsRefPtr<BluetoothReplyRunnable> result = new BluetoothVoidReplyRunnable(nullptr, /* DOMRequest */ promise, - methodName); + NS_LITERAL_STRING("Enable")); - if (NS_FAILED(bs->EnableDisable(aEnable, result))) { - // Restore mState and notify applications of adapter state change - mState = aEnable ? BluetoothAdapterState::Disabled - : BluetoothAdapterState::Enabled; - HandleAdapterStateChanged(); - + if (NS_FAILED(bs->EnableDisable(true, result))) { + // Restore adapter state and reject promise + SetAdapterState(BluetoothAdapterState::Disabled); promise->MaybeReject(NS_ERROR_DOM_OPERATION_ERR); } return promise.forget(); } already_AddRefed<Promise> -BluetoothAdapter::Enable(ErrorResult& aRv) -{ - return EnableDisable(true, aRv); -} - -already_AddRefed<Promise> BluetoothAdapter::Disable(ErrorResult& aRv) { - return EnableDisable(false, aRv); + nsCOMPtr<nsIGlobalObject> global = do_QueryInterface(GetOwner()); + if (!global) { + aRv.Throw(NS_ERROR_FAILURE); + return nullptr; + } + + nsRefPtr<Promise> promise = Promise::Create(global, aRv); + NS_ENSURE_TRUE(!aRv.Failed(), nullptr); + + /** + * Ensure + * - adapter is enabled, and + * - BluetoothService is available. + */ + BT_ENSURE_TRUE_REJECT(mState == BluetoothAdapterState::Enabled, + NS_ERROR_DOM_INVALID_STATE_ERR); + BluetoothService* bs = BluetoothService::Get(); + BT_ENSURE_TRUE_REJECT(bs, NS_ERROR_NOT_AVAILABLE); + + // Set adapter state "Disabling" + SetAdapterState(BluetoothAdapterState::Disabling); + + // Wrap runnable to handle result + nsRefPtr<BluetoothReplyRunnable> result = + new BluetoothVoidReplyRunnable(nullptr, /* DOMRequest */ + promise, + NS_LITERAL_STRING("Disable")); + + if (NS_FAILED(bs->EnableDisable(false, result))) { + // Restore adapter state and reject promise + SetAdapterState(BluetoothAdapterState::Enabled); + promise->MaybeReject(NS_ERROR_DOM_OPERATION_ERR); + } + + return promise.forget(); } BluetoothAdapterAttribute BluetoothAdapter::ConvertStringToAdapterAttribute(const nsAString& aString) { using namespace mozilla::dom::BluetoothAdapterAttributeValues; @@ -763,18 +758,25 @@ BluetoothAdapter::IsAdapterAttributeChan return mDiscovering != aValue.get_bool(); default: BT_WARNING("Type %d is not handled", uint32_t(aType)); return false; } } void -BluetoothAdapter::HandleAdapterStateChanged() +BluetoothAdapter::SetAdapterState(BluetoothAdapterState aState) { + if (mState == aState) { + return; + } + + mState = aState; + + // Fire BluetoothAttributeEvent for changed adapter state nsTArray<nsString> types; BT_APPEND_ENUM_STRING(types, BluetoothAdapterAttribute, BluetoothAdapterAttribute::State); DispatchAttributeEvent(types); } void @@ -811,20 +813,17 @@ BluetoothAdapter::HandleDeviceFound(cons { MOZ_ASSERT(mDiscoveryHandleInUse); MOZ_ASSERT(aValue.type() == BluetoothValue::TArrayOfBluetoothNamedValue); // Create a temporary discovered BluetoothDevice to check existence nsRefPtr<BluetoothDevice> discoveredDevice = BluetoothDevice::Create(GetOwner(), aValue); - size_t index = mDevices.IndexOf(discoveredDevice, - 0, /* aStart */ - BluetoothDeviceComparator()); - + size_t index = mDevices.IndexOf(discoveredDevice); if (index == mDevices.NoIndex) { // New device, append it to adapter's device array mDevices.AppendElement(discoveredDevice); } else { // Existing device, discard temporary discovered device discoveredDevice = mDevices[index]; } @@ -852,20 +851,17 @@ BluetoothAdapter::HandlePairingRequest(c // Create a temporary device with deviceAddress for searching InfallibleTArray<BluetoothNamedValue> props; BT_APPEND_NAMED_VALUE(props, "Address", deviceAddress); nsRefPtr<BluetoothDevice> device = BluetoothDevice::Create(GetOwner(), props); // Find the remote device by address - size_t index = mDevices.IndexOf(device, - 0, /* aStart */ - BluetoothDeviceComparator()); - + size_t index = mDevices.IndexOf(device); if (index == mDevices.NoIndex) { BT_WARNING("Cannot find the remote device with address %s", NS_ConvertUTF16toUTF8(deviceAddress).get()); return; } // Notify application of pairing requests mPairingReqs->DispatchPairingEvent(mDevices[index], passkey, type); @@ -904,24 +900,21 @@ BluetoothAdapter::HandleDevicePaired(con BT_WARNING("HandleDevicePaired() is called when adapter isn't enabled."); return; } // Create paired device with 'address' and 'paired' attributes nsRefPtr<BluetoothDevice> pairedDevice = BluetoothDevice::Create(GetOwner(), aValue); - size_t index = mDevices.IndexOf(pairedDevice, - 0, /* aStart */ - BluetoothDeviceComparator()); - - if (index != mDevices.NoIndex) { + size_t index = mDevices.IndexOf(pairedDevice); + if (index == mDevices.NoIndex) { + mDevices.AppendElement(pairedDevice); + } else { pairedDevice = mDevices[index]; - } else { - mDevices.AppendElement(pairedDevice); } // Notify application of paired device BluetoothDeviceEventInit init; init.mDevice = pairedDevice; DispatchDeviceEvent(NS_LITERAL_STRING("devicepaired"), init); } @@ -934,26 +927,24 @@ BluetoothAdapter::HandleDeviceUnpaired(c BT_WARNING("HandleDeviceUnpaired() is called when adapter isn't enabled."); return; } // Create unpaired device with 'address' and 'paired' attributes nsRefPtr<BluetoothDevice> unpairedDevice = BluetoothDevice::Create(GetOwner(), aValue); - size_t index = mDevices.IndexOf(unpairedDevice, - 0, /* aStart */ - BluetoothDeviceComparator()); + size_t index = mDevices.IndexOf(unpairedDevice); nsString deviceAddress; - if (index != mDevices.NoIndex) { + if (index == mDevices.NoIndex) { + unpairedDevice->GetAddress(deviceAddress); + } else { mDevices[index]->GetAddress(deviceAddress); mDevices.RemoveElementAt(index); - } else { - unpairedDevice->GetAddress(deviceAddress); } // Notify application of unpaired device BluetoothDeviceEventInit init; init.mAddress = deviceAddress; DispatchDeviceEvent(NS_LITERAL_STRING("deviceunpaired"), init); }
--- a/dom/bluetooth2/BluetoothAdapter.h +++ b/dom/bluetooth2/BluetoothAdapter.h @@ -2,59 +2,52 @@ /* vim: set ts=2 et sw=2 tw=80: */ /* 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/. */ #ifndef mozilla_dom_bluetooth_bluetoothadapter_h__ #define mozilla_dom_bluetooth_bluetoothadapter_h__ +#include "BluetoothCommon.h" #include "mozilla/Attributes.h" #include "mozilla/DOMEventTargetHelper.h" #include "mozilla/dom/BluetoothAdapter2Binding.h" #include "mozilla/dom/BluetoothDeviceEvent.h" #include "mozilla/dom/Promise.h" -#include "BluetoothCommon.h" #include "nsCOMPtr.h" namespace mozilla { namespace dom { class DOMRequest; struct MediaMetaData; struct MediaPlayStatus; } } BEGIN_BLUETOOTH_NAMESPACE class BluetoothDevice; class BluetoothDiscoveryHandle; -class BluetoothSignal; class BluetoothNamedValue; class BluetoothPairingListener; +class BluetoothSignal; class BluetoothValue; class BluetoothAdapter : public DOMEventTargetHelper , public BluetoothSignalObserver { public: NS_DECL_ISUPPORTS_INHERITED - NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(BluetoothAdapter, DOMEventTargetHelper) - static already_AddRefed<BluetoothAdapter> - Create(nsPIDOMWindow* aOwner, const BluetoothValue& aValue); - - void Notify(const BluetoothSignal& aParam); - - void SetPropertyByValue(const BluetoothNamedValue& aValue); - - virtual void DisconnectFromOwner() MOZ_OVERRIDE; - + /**************************************************************************** + * Attribute Getters + ***************************************************************************/ BluetoothAdapterState State() const { return mState; } void GetAddress(nsString& aAddress) const { aAddress = mAddress; @@ -78,116 +71,159 @@ public: return mDiscoverable; } BluetoothPairingListener* PairingReqs() const { return mPairingReqs; } - /** - * Update this adapter's discovery handle in use (mDiscoveryHandleInUse). - * - * |mDiscoveryHandleInUse| is set to the latest discovery handle when adapter - * just starts discovery, and is reset to nullptr when discovery is stopped - * by some adapter. - * - * @param aDiscoveryHandle [in] the discovery handle to set. - */ - void SetDiscoveryHandleInUse(BluetoothDiscoveryHandle* aDiscoveryHandle); + /**************************************************************************** + * Event Handlers + ***************************************************************************/ + IMPL_EVENT_HANDLER(attributechanged); + IMPL_EVENT_HANDLER(devicepaired); + IMPL_EVENT_HANDLER(deviceunpaired); + IMPL_EVENT_HANDLER(a2dpstatuschanged); + IMPL_EVENT_HANDLER(hfpstatuschanged); + IMPL_EVENT_HANDLER(requestmediaplaystatus); + IMPL_EVENT_HANDLER(scostatuschanged); + + /**************************************************************************** + * Methods (Web API Implementation) + ***************************************************************************/ + already_AddRefed<Promise> Enable(ErrorResult& aRv); + already_AddRefed<Promise> Disable(ErrorResult& aRv); already_AddRefed<Promise> SetName(const nsAString& aName, ErrorResult& aRv); - already_AddRefed<Promise> - SetDiscoverable(bool aDiscoverable, ErrorResult& aRv); + already_AddRefed<Promise> SetDiscoverable(bool aDiscoverable, + ErrorResult& aRv); already_AddRefed<Promise> StartDiscovery(ErrorResult& aRv); already_AddRefed<Promise> StopDiscovery(ErrorResult& aRv); - - already_AddRefed<Promise> - Pair(const nsAString& aDeviceAddress, ErrorResult& aRv); - already_AddRefed<Promise> - Unpair(const nsAString& aDeviceAddress, ErrorResult& aRv); + already_AddRefed<Promise> Pair(const nsAString& aDeviceAddress, + ErrorResult& aRv); + already_AddRefed<Promise> Unpair(const nsAString& aDeviceAddress, + ErrorResult& aRv); /** * Get a list of paired bluetooth devices. * * @param aDevices [out] Devices array to return */ void GetPairedDevices(nsTArray<nsRefPtr<BluetoothDevice> >& aDevices); - already_AddRefed<Promise> EnableDisable(bool aEnable, ErrorResult& aRv); - already_AddRefed<Promise> Enable(ErrorResult& aRv); - already_AddRefed<Promise> Disable(ErrorResult& aRv); - + // Connection related methods already_AddRefed<DOMRequest> Connect(BluetoothDevice& aDevice, - const Optional<short unsigned int>& aServiceUuid, ErrorResult& aRv); + const Optional<short unsigned int>& aServiceUuid, + ErrorResult& aRv); already_AddRefed<DOMRequest> Disconnect(BluetoothDevice& aDevice, const Optional<short unsigned int>& aServiceUuid, ErrorResult& aRv); - already_AddRefed<DOMRequest> - GetConnectedDevices(uint16_t aServiceUuid, ErrorResult& aRv); + already_AddRefed<DOMRequest> GetConnectedDevices(uint16_t aServiceUuid, + ErrorResult& aRv); + // OPP file transfer related methods + already_AddRefed<DOMRequest> SendFile(const nsAString& aDeviceAddress, + nsIDOMBlob* aBlob, + ErrorResult& aRv); + already_AddRefed<DOMRequest> StopSendingFile(const nsAString& aDeviceAddress, + ErrorResult& aRv); already_AddRefed<DOMRequest> - SendFile(const nsAString& aDeviceAddress, nsIDOMBlob* aBlob, - ErrorResult& aRv); - already_AddRefed<DOMRequest> - StopSendingFile(const nsAString& aDeviceAddress, ErrorResult& aRv); - already_AddRefed<DOMRequest> - ConfirmReceivingFile(const nsAString& aDeviceAddress, bool aConfirmation, + ConfirmReceivingFile(const nsAString& aDeviceAddress, + bool aConfirmation, ErrorResult& aRv); + // SCO related methods already_AddRefed<DOMRequest> ConnectSco(ErrorResult& aRv); already_AddRefed<DOMRequest> DisconnectSco(ErrorResult& aRv); already_AddRefed<DOMRequest> IsScoConnected(ErrorResult& aRv); + // Handfree CDMA related methods already_AddRefed<DOMRequest> AnswerWaitingCall(ErrorResult& aRv); already_AddRefed<DOMRequest> IgnoreWaitingCall(ErrorResult& aRv); already_AddRefed<DOMRequest> ToggleCalls(ErrorResult& aRv); + // AVRCP related methods already_AddRefed<DOMRequest> SendMediaMetaData(const MediaMetaData& aMediaMetaData, ErrorResult& aRv); already_AddRefed<DOMRequest> - SendMediaPlayStatus(const MediaPlayStatus& aMediaPlayStatus, ErrorResult& aRv); + SendMediaPlayStatus(const MediaPlayStatus& aMediaPlayStatus, + ErrorResult& aRv); - IMPL_EVENT_HANDLER(a2dpstatuschanged); - IMPL_EVENT_HANDLER(hfpstatuschanged); - IMPL_EVENT_HANDLER(requestmediaplaystatus); - IMPL_EVENT_HANDLER(scostatuschanged); - IMPL_EVENT_HANDLER(attributechanged); - IMPL_EVENT_HANDLER(devicepaired); - IMPL_EVENT_HANDLER(deviceunpaired); + /**************************************************************************** + * Others + ***************************************************************************/ + static already_AddRefed<BluetoothAdapter> + Create(nsPIDOMWindow* aOwner, const BluetoothValue& aValue); + void Notify(const BluetoothSignal& aParam); // BluetoothSignalObserver nsPIDOMWindow* GetParentObject() const { return GetOwner(); } - virtual JSObject* - WrapObject(JSContext* aCx) MOZ_OVERRIDE; + virtual JSObject* WrapObject(JSContext* aCx) MOZ_OVERRIDE; + virtual void DisconnectFromOwner() MOZ_OVERRIDE; + + /** + * Set this adapter's discovery handle in use (mDiscoveryHandleInUse). + * + * |mDiscoveryHandleInUse| is set to the latest discovery handle when adapter + * just starts discovery, and is reset to nullptr when discovery is stopped + * by some adapter. + * + * @param aDiscoveryHandle [in] Discovery handle to set. + */ + void SetDiscoveryHandleInUse(BluetoothDiscoveryHandle* aDiscoveryHandle); private: BluetoothAdapter(nsPIDOMWindow* aOwner, const BluetoothValue& aValue); ~BluetoothAdapter(); - already_AddRefed<Promise> - PairUnpair(bool aPair, const nsAString& aDeviceAddress, ErrorResult& aRv); + /** + * Set adapter properties according to properties array + * + * @param aValue [in] Properties array to set with + */ + void SetPropertyByValue(const BluetoothNamedValue& aValue); + + /** + * Set adapter state and fire BluetoothAttributeEvent if state changed. + * + * @param aState [in] The new adapter state + */ + void SetAdapterState(BluetoothAdapterState aState); - bool IsAdapterAttributeChanged(BluetoothAdapterAttribute aType, - const BluetoothValue& aValue); - void HandleAdapterStateChanged(); - void HandlePropertyChanged(const BluetoothValue& aValue); - void DispatchAttributeEvent(const nsTArray<nsString>& aTypes); - BluetoothAdapterAttribute - ConvertStringToAdapterAttribute(const nsAString& aString); + /** + * Pair/Unpair adapter to device of given address. + * This function is called by methods Enable() and Disable(). + * + * @param aPair [in] Whether to pair or unpair adapter to device. + * @param aDeviceAddress [in] Address of device to pair/unpair. + * @param aRv [out] Error result to set in case of error. + */ + already_AddRefed<Promise> PairUnpair(bool aPair, + const nsAString& aDeviceAddress, + ErrorResult& aRv); + /** + * Retrieve properties of paired devices. + * + * @param aDeviceAddresses [in] Addresses array of paired devices + */ void GetPairedDeviceProperties(const nsTArray<nsString>& aDeviceAddresses); - void HandleDeviceFound(const BluetoothValue& aValue); - void HandlePairingRequest(const BluetoothValue& aValue); + /** + * Handle "PropertyChanged" bluetooth signal. + * + * @param aValue [in] Array of changed properties + */ + void HandlePropertyChanged(const BluetoothValue& aValue); /** * Handle DEVICE_PAIRED_ID bluetooth signal. * * @param aValue [in] Properties array of the paired device. * The array should contain two properties: * - nsString 'Address' * - bool 'Paired' @@ -200,45 +236,116 @@ private: * @param aValue [in] Properties array of the unpaired device. * The array should contain two properties: * - nsString 'Address' * - bool 'Paired' */ void HandleDeviceUnpaired(const BluetoothValue& aValue); /** + * Handle "DeviceFound" bluetooth signal. + * + * @param aValue [in] Properties array of the discovered device. + */ + void HandleDeviceFound(const BluetoothValue& aValue); + + /** + * Handle "PairingRequest" bluetooth signal. + * + * @param aValue [in] Array of information about the pairing request. + */ + void HandlePairingRequest(const BluetoothValue& aValue); + + /** + * Fire BluetoothAttributeEvent to trigger onattributechanged event handler. + */ + void DispatchAttributeEvent(const nsTArray<nsString>& aTypes); + + /** * Fire BluetoothDeviceEvent to trigger * ondeviceparied/ondeviceunpaired event handler. * * @param aType [in] Event type to fire * @param aInit [in] Event initialization value */ void DispatchDeviceEvent(const nsAString& aType, const BluetoothDeviceEventInit& aInit); /** - * mDevices holds references of all created device objects. - * It is an empty array when the adapter state is disabled. + * Convert string to BluetoothAdapterAttribute. + * + * @param aString [in] String to convert + */ + BluetoothAdapterAttribute + ConvertStringToAdapterAttribute(const nsAString& aString); + + /** + * Check whether value of given adapter property has changed. + * + * @param aType [in] Adapter property to check + * @param aValue [in] New value of the adapter property + */ + bool IsAdapterAttributeChanged(BluetoothAdapterAttribute aType, + const BluetoothValue& aValue); + + /**************************************************************************** + * Variables + ***************************************************************************/ + /** + * Current state of this adapter. Can be Disabled/Disabling/Enabled/Enabling. + */ + BluetoothAdapterState mState; + + /** + * BD address of this adapter. + */ + nsString mAddress; + + /** + * Human-readable name of this adapter. + */ + nsString mName; + + /** + * Whether this adapter can be discovered by nearby devices. + */ + bool mDiscoverable; + + /** + * Whether this adapter is discovering nearby devices. + */ + bool mDiscovering; + + /** + * Handle to fire pairing requests of different pairing types. + */ + nsRefPtr<BluetoothPairingListener> mPairingReqs; + + /** + * Handle to fire 'ondevicefound' event handler for discovered device. + * + * This variable is set to the latest discovery handle when adapter just + * starts discovery, and is reset to nullptr when discovery is stopped by + * some adapter. + */ + nsRefPtr<BluetoothDiscoveryHandle> mDiscoveryHandleInUse; + + /** + * Arrays of references to BluetoothDevices created by this adapter. + * This array is empty when adapter state is Disabled. * * Devices will be appended when * 1) Enabling BT: Paired devices reported by stack. * 2) Discovering: Discovered devices during discovery operation. * A device won't be appended if a device object with the same * address already exists. * * Devices will be removed when * 1) Starting discovery: All unpaired devices will be removed before this * adapter starts a new discovery. * 2) Disabling BT: All devices will be removed. */ nsTArray<nsRefPtr<BluetoothDevice> > mDevices; - nsRefPtr<BluetoothDiscoveryHandle> mDiscoveryHandleInUse; - nsRefPtr<BluetoothPairingListener> mPairingReqs; - BluetoothAdapterState mState; - nsString mAddress; - nsString mName; - bool mDiscoverable; - bool mDiscovering; }; END_BLUETOOTH_NAMESPACE #endif
--- a/dom/bluetooth2/BluetoothDevice.cpp +++ b/dom/bluetooth2/BluetoothDevice.cpp @@ -22,17 +22,17 @@ USING_BLUETOOTH_NAMESPACE NS_IMPL_CYCLE_COLLECTION_INHERITED(BluetoothDevice, DOMEventTargetHelper, mCod) NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(BluetoothDevice) NS_INTERFACE_MAP_END_INHERITING(DOMEventTargetHelper) NS_IMPL_ADDREF_INHERITED(BluetoothDevice, DOMEventTargetHelper) NS_IMPL_RELEASE_INHERITED(BluetoothDevice, DOMEventTargetHelper) -class FetchUuidsTask : public BluetoothReplyRunnable +class FetchUuidsTask MOZ_FINAL : public BluetoothReplyRunnable { public: FetchUuidsTask(Promise* aPromise, const nsAString& aName, BluetoothDevice* aDevice) : BluetoothReplyRunnable(nullptr /* DOMRequest */, aPromise, aName) , mDevice(aDevice) {
--- a/dom/bluetooth2/BluetoothDevice.h +++ b/dom/bluetooth2/BluetoothDevice.h @@ -28,25 +28,22 @@ class BluetoothValue; class BluetoothSignal; class BluetoothSocket; class BluetoothDevice MOZ_FINAL : public DOMEventTargetHelper , public BluetoothSignalObserver { public: NS_DECL_ISUPPORTS_INHERITED - NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(BluetoothDevice, DOMEventTargetHelper) - static already_AddRefed<BluetoothDevice> - Create(nsPIDOMWindow* aOwner, const BluetoothValue& aValue); - - void Notify(const BluetoothSignal& aParam); - + /**************************************************************************** + * Attribute Getters + ***************************************************************************/ void GetAddress(nsString& aAddress) const { aAddress = mAddress; } BluetoothClassOfDevice* Cod() const { return mCod; @@ -57,52 +54,120 @@ public: aName = mName; } bool Paired() const { return mPaired; } - void GetUuids(nsTArray<nsString>& aUuids) { + void GetUuids(nsTArray<nsString>& aUuids) const + { aUuids = mUuids; } + /**************************************************************************** + * Event Handlers + ***************************************************************************/ + IMPL_EVENT_HANDLER(attributechanged); + + /**************************************************************************** + * Methods (Web API Implementation) + ***************************************************************************/ already_AddRefed<Promise> FetchUuids(ErrorResult& aRv); - void SetPropertyByValue(const BluetoothNamedValue& aValue); - - BluetoothDeviceAttribute - ConvertStringToDeviceAttribute(const nsAString& aString); + /**************************************************************************** + * Others + ***************************************************************************/ + static already_AddRefed<BluetoothDevice> + Create(nsPIDOMWindow* aOwner, const BluetoothValue& aValue); - bool - IsDeviceAttributeChanged(BluetoothDeviceAttribute aType, - const BluetoothValue& aValue); - - void HandlePropertyChanged(const BluetoothValue& aValue); - - void DispatchAttributeEvent(const nsTArray<nsString>& aTypes); - - IMPL_EVENT_HANDLER(attributechanged); - + void Notify(const BluetoothSignal& aParam); // BluetoothSignalObserver nsPIDOMWindow* GetParentObject() const { return GetOwner(); } virtual JSObject* WrapObject(JSContext* aCx) MOZ_OVERRIDE; virtual void DisconnectFromOwner() MOZ_OVERRIDE; + /** + * Override operator== for device comparison + */ + bool operator==(BluetoothDevice& aDevice) const + { + nsString address; + aDevice.GetAddress(address); + return mAddress.Equals(address); + } + private: BluetoothDevice(nsPIDOMWindow* aOwner, const BluetoothValue& aValue); ~BluetoothDevice(); + /** + * Set device properties according to properties array + * + * @param aValue [in] Properties array to set with + */ + void SetPropertyByValue(const BluetoothNamedValue& aValue); + + /** + * Handle "PropertyChanged" bluetooth signal. + * + * @param aValue [in] Array of changed properties + */ + void HandlePropertyChanged(const BluetoothValue& aValue); + + /** + * Fire BluetoothAttributeEvent to trigger onattributechanged event handler. + */ + void DispatchAttributeEvent(const nsTArray<nsString>& aTypes); + + /** + * Convert string to BluetoothDeviceAttribute. + * + * @param aString [in] String to convert + */ + BluetoothDeviceAttribute + ConvertStringToDeviceAttribute(const nsAString& aString); + + /** + * Check whether value of given device property has changed. + * + * @param aType [in] Device property to check + * @param aValue [in] New value of the device property + */ + bool IsDeviceAttributeChanged(BluetoothDeviceAttribute aType, + const BluetoothValue& aValue); + + /**************************************************************************** + * Variables + ***************************************************************************/ + /** + * BD address of this device. + */ nsString mAddress; + + /** + * Class of device (CoD) that describes this device's capabilities. + */ nsRefPtr<BluetoothClassOfDevice> mCod; + + /** + * Human-readable name of this device. + */ nsString mName; + + /** + * Whether this device is paired or not. + */ bool mPaired; + + /** + * Cached UUID list of services which this device provides. + */ nsTArray<nsString> mUuids; - }; END_BLUETOOTH_NAMESPACE #endif
--- a/dom/bluetooth2/BluetoothManager.h +++ b/dom/bluetooth2/BluetoothManager.h @@ -21,55 +21,64 @@ class BluetoothAdapter; class BluetoothValue; class BluetoothManager : public DOMEventTargetHelper , public BluetoothSignalObserver { public: NS_DECL_ISUPPORTS_INHERITED - // Never returns null - static already_AddRefed<BluetoothManager> Create(nsPIDOMWindow* aWindow); - static bool CheckPermission(nsPIDOMWindow* aWindow); + /**************************************************************************** + * Event Handlers + ***************************************************************************/ + IMPL_EVENT_HANDLER(attributechanged); + IMPL_EVENT_HANDLER(adapteradded); + IMPL_EVENT_HANDLER(adapterremoved); + /**************************************************************************** + * Methods (Web API Implementation) + ***************************************************************************/ /** * Return default adapter if it exists, nullptr otherwise. The function is * called when applications access property BluetoothManager.defaultAdapter */ BluetoothAdapter* GetDefaultAdapter(); /** * Return adapters array. The function is called when applications call * method BluetoothManager.getAdapters() * * @param aAdapters [out] Adapters array to return */ void GetAdapters(nsTArray<nsRefPtr<BluetoothAdapter> >& aAdapters); - /** - * Create a BluetoothAdapter object based on properties array - * and append it into adapters array. - * - * @param aValue [in] Properties array to create BluetoothAdapter object - */ - void AppendAdapter(const BluetoothValue& aValue); - - IMPL_EVENT_HANDLER(attributechanged); - IMPL_EVENT_HANDLER(adapteradded); - IMPL_EVENT_HANDLER(adapterremoved); + /**************************************************************************** + * Others + ***************************************************************************/ + // Never returns null + static already_AddRefed<BluetoothManager> Create(nsPIDOMWindow* aWindow); + static bool CheckPermission(nsPIDOMWindow* aWindow); void Notify(const BluetoothSignal& aData); // BluetoothSignalObserver nsPIDOMWindow* GetParentObject() const { return GetOwner(); } virtual JSObject* WrapObject(JSContext* aCx) MOZ_OVERRIDE; virtual void DisconnectFromOwner() MOZ_OVERRIDE; + /** + * Create a BluetoothAdapter object based on properties array + * and append it into adapters array. + * + * @param aValue [in] Properties array to create BluetoothAdapter object + */ + void AppendAdapter(const BluetoothValue& aValue); + private: BluetoothManager(nsPIDOMWindow* aWindow); ~BluetoothManager(); /** * Start/Stop listening to bluetooth signal. * * @param aStart [in] Whether to start or stop listening to bluetooth signal
--- a/dom/bluetooth2/BluetoothRilListener.cpp +++ b/dom/bluetooth2/BluetoothRilListener.cpp @@ -108,22 +108,22 @@ MobileConnectionListener::NotifyUssdRece NS_IMETHODIMP MobileConnectionListener::NotifyDataError(const nsAString & message) { return NS_OK; } NS_IMETHODIMP -MobileConnectionListener::NotifyCFStateChange(bool success, - uint16_t action, - uint16_t reason, - const nsAString& number, - uint16_t timeSeconds, - uint16_t serviceClass) +MobileConnectionListener::NotifyCFStateChanged(bool success, + uint16_t action, + uint16_t reason, + const nsAString& number, + uint16_t timeSeconds, + uint16_t serviceClass) { return NS_OK; } NS_IMETHODIMP MobileConnectionListener::NotifyEmergencyCbModeChanged(bool active, uint32_t timeoutMs) { @@ -149,28 +149,46 @@ MobileConnectionListener::NotifyRadioSta } NS_IMETHODIMP MobileConnectionListener::NotifyClirModeChanged(uint32_t aMode) { return NS_OK; } +NS_IMETHODIMP +MobileConnectionListener::NotifyLastKnownNetworkChanged() +{ + return NS_OK; +} + +NS_IMETHODIMP +MobileConnectionListener::NotifyLastKnownHomeNetworkChanged() +{ + return NS_OK; +} + +NS_IMETHODIMP +MobileConnectionListener::NotifyNetworkSelectionModeChanged() +{ + return NS_OK; +} + bool MobileConnectionListener::Listen(bool aStart) { - nsCOMPtr<nsIMobileConnectionProvider> provider = - do_GetService(NS_RILCONTENTHELPER_CONTRACTID); - NS_ENSURE_TRUE(provider, false); + nsCOMPtr<nsIMobileConnectionService> service = + do_GetService(NS_MOBILE_CONNECTION_SERVICE_CONTRACTID); + NS_ENSURE_TRUE(service, false); nsresult rv; if (aStart) { - rv = provider->RegisterMobileConnectionMsg(mClientId, this); + rv = service->RegisterListener(mClientId, this); } else { - rv = provider->UnregisterMobileConnectionMsg(mClientId, this); + rv = service->UnregisterListener(mClientId, this); } return NS_SUCCEEDED(rv); } /** * TelephonyListener Implementation */ @@ -347,23 +365,23 @@ BluetoothRilListener::Listen(bool aStart } void BluetoothRilListener::SelectClient() { // Reset mClientId mClientId = mMobileConnListeners.Length(); - nsCOMPtr<nsIMobileConnectionProvider> connection = - do_GetService(NS_RILCONTENTHELPER_CONTRACTID); - NS_ENSURE_TRUE_VOID(connection); + nsCOMPtr<nsIMobileConnectionService> service = + do_GetService(NS_MOBILE_CONNECTION_SERVICE_CONTRACTID); + NS_ENSURE_TRUE_VOID(service); for (uint32_t i = 0; i < mMobileConnListeners.Length(); i++) { nsCOMPtr<nsIMobileConnectionInfo> voiceInfo; - connection->GetVoiceConnectionInfo(i, getter_AddRefs(voiceInfo)); + service->GetVoiceConnectionInfo(i, getter_AddRefs(voiceInfo)); if (!voiceInfo) { BT_WARNING("%s: Failed to get voice connection info", __FUNCTION__); continue; } nsString regState; voiceInfo->GetState(regState); if (regState.EqualsLiteral("registered")) {
--- a/dom/bluetooth2/BluetoothRilListener.h +++ b/dom/bluetooth2/BluetoothRilListener.h @@ -7,17 +7,17 @@ #ifndef mozilla_dom_bluetooth_bluetoothrillistener_h__ #define mozilla_dom_bluetooth_bluetoothrillistener_h__ #include "BluetoothCommon.h" #include "nsAutoPtr.h" #include "nsIIccProvider.h" -#include "nsIMobileConnectionProvider.h" +#include "nsIMobileConnectionService.h" #include "nsITelephonyService.h" BEGIN_BLUETOOTH_NAMESPACE class BluetoothRilListener; class IccListener : public nsIIccListener {
--- a/dom/bluetooth2/bluedroid/hfp/BluetoothHfpManager.cpp +++ b/dom/bluetooth2/bluedroid/hfp/BluetoothHfpManager.cpp @@ -14,17 +14,17 @@ #include "mozilla/dom/bluetooth/BluetoothTypes.h" #include "mozilla/Services.h" #include "mozilla/StaticPtr.h" #include "nsContentUtils.h" #include "nsIAudioManager.h" #include "nsIDOMIccInfo.h" #include "nsIIccProvider.h" #include "nsIMobileConnectionInfo.h" -#include "nsIMobileConnectionProvider.h" +#include "nsIMobileConnectionService.h" #include "nsIMobileNetworkInfo.h" #include "nsIObserverService.h" #include "nsISettingsService.h" #include "nsITelephonyService.h" #include "nsRadioInterfaceLayer.h" #include "nsServiceManagerUtils.h" #include "nsThreadUtils.h" @@ -610,18 +610,18 @@ BluetoothHfpManager::HandleVolumeChanged sBluetoothHfpInterface->VolumeControl(HFP_VOLUME_TYPE_SPEAKER, mCurrentVgs, new VolumeControlResultHandler()); } } void BluetoothHfpManager::HandleVoiceConnectionChanged(uint32_t aClientId) { - nsCOMPtr<nsIMobileConnectionProvider> connection = - do_GetService(NS_RILCONTENTHELPER_CONTRACTID); + nsCOMPtr<nsIMobileConnectionService> connection = + do_GetService(NS_MOBILE_CONNECTION_SERVICE_CONTRACTID); NS_ENSURE_TRUE_VOID(connection); nsCOMPtr<nsIMobileConnectionInfo> voiceInfo; connection->GetVoiceConnectionInfo(aClientId, getter_AddRefs(voiceInfo)); NS_ENSURE_TRUE_VOID(voiceInfo); nsString type; voiceInfo->GetType(type);
--- a/dom/bluetooth2/bluez/BluetoothHfpManager.cpp +++ b/dom/bluetooth2/bluez/BluetoothHfpManager.cpp @@ -23,17 +23,17 @@ #include "nsIObserverService.h" #include "nsISettingsService.h" #include "nsServiceManagerUtils.h" #ifdef MOZ_B2G_RIL #include "nsIDOMIccInfo.h" #include "nsIIccProvider.h" #include "nsIMobileConnectionInfo.h" -#include "nsIMobileConnectionProvider.h" +#include "nsIMobileConnectionService.h" #include "nsIMobileNetworkInfo.h" #include "nsITelephonyService.h" #include "nsRadioInterfaceLayer.h" #endif /** * BRSF bitmask of AG supported features. See 4.34.1 "Bluetooth Defined AT * Capabilities" in Bluetooth hands-free profile 1.6 @@ -601,18 +601,18 @@ BluetoothHfpManager::HandleVolumeChanged SendCommand(RESPONSE_VGS, mCurrentVgs); } } #ifdef MOZ_B2G_RIL void BluetoothHfpManager::HandleVoiceConnectionChanged(uint32_t aClientId) { - nsCOMPtr<nsIMobileConnectionProvider> connection = - do_GetService(NS_RILCONTENTHELPER_CONTRACTID); + nsCOMPtr<nsIMobileConnectionService> connection = + do_GetService(NS_MOBILE_CONNECTION_SERVICE_CONTRACTID); NS_ENSURE_TRUE_VOID(connection); nsCOMPtr<nsIMobileConnectionInfo> voiceInfo; connection->GetVoiceConnectionInfo(aClientId, getter_AddRefs(voiceInfo)); NS_ENSURE_TRUE_VOID(voiceInfo); nsString type; voiceInfo->GetType(type);
--- a/dom/ipc/ContentChild.cpp +++ b/dom/ipc/ContentChild.cpp @@ -149,16 +149,21 @@ #include "AudioChannelService.h" #include "JavaScriptChild.h" #include "mozilla/dom/DataStoreService.h" #include "mozilla/dom/telephony/PTelephonyChild.h" #include "mozilla/dom/time/DateCacheCleaner.h" #include "mozilla/net/NeckoMessageUtils.h" #include "mozilla/RemoteSpellCheckEngineChild.h" +#ifdef MOZ_B2G_RIL +#include "mozilla/dom/mobileconnection/MobileConnectionChild.h" +using namespace mozilla::dom::mobileconnection; +#endif + using namespace base; using namespace mozilla; using namespace mozilla::docshell; using namespace mozilla::dom::bluetooth; using namespace mozilla::dom::devicestorage; using namespace mozilla::dom::ipc; using namespace mozilla::dom::mobilemessage; using namespace mozilla::dom::indexedDB; @@ -1217,16 +1222,53 @@ ContentChild::DeallocPFileSystemRequestC mozilla::dom::FileSystemTaskBase* child = static_cast<mozilla::dom::FileSystemTaskBase*>(aFileSystem); // The reference is increased in FileSystemTaskBase::Start of // FileSystemTaskBase.cpp. We should decrease it after IPC. NS_RELEASE(child); return true; } +PMobileConnectionChild* +ContentChild::SendPMobileConnectionConstructor(PMobileConnectionChild* aActor, + const uint32_t& aClientId) +{ +#ifdef MOZ_B2G_RIL + // Add an extra ref for IPDL. Will be released in + // ContentChild::DeallocPMobileConnectionChild(). + static_cast<MobileConnectionChild*>(aActor)->AddRef(); + return PContentChild::SendPMobileConnectionConstructor(aActor, aClientId); +#else + MOZ_CRASH("No support for mobileconnection on this platform!");; +#endif +} + +PMobileConnectionChild* +ContentChild::AllocPMobileConnectionChild(const uint32_t& aClientId) +{ +#ifdef MOZ_B2G_RIL + NS_NOTREACHED("No one should be allocating PMobileConnectionChild actors"); + return nullptr; +#else + MOZ_CRASH("No support for mobileconnection on this platform!");; +#endif +} + +bool +ContentChild::DeallocPMobileConnectionChild(PMobileConnectionChild* aActor) +{ +#ifdef MOZ_B2G_RIL + // MobileConnectionChild is refcounted, must not be freed manually. + static_cast<MobileConnectionChild*>(aActor)->Release(); + return true; +#else + MOZ_CRASH("No support for mobileconnection on this platform!"); +#endif +} + PNeckoChild* ContentChild::AllocPNeckoChild() { return new NeckoChild(); } bool ContentChild::DeallocPNeckoChild(PNeckoChild* necko)
--- a/dom/ipc/ContentChild.h +++ b/dom/ipc/ContentChild.h @@ -186,16 +186,24 @@ public: RecvDataStoreNotify(const uint32_t& aAppId, const nsString& aName, const nsString& aManifestURL) MOZ_OVERRIDE; virtual PTestShellChild* AllocPTestShellChild() MOZ_OVERRIDE; virtual bool DeallocPTestShellChild(PTestShellChild*) MOZ_OVERRIDE; virtual bool RecvPTestShellConstructor(PTestShellChild*) MOZ_OVERRIDE; jsipc::JavaScriptChild *GetCPOWManager(); + PMobileConnectionChild* + SendPMobileConnectionConstructor(PMobileConnectionChild* aActor, + const uint32_t& aClientId); + virtual PMobileConnectionChild* + AllocPMobileConnectionChild(const uint32_t& aClientId) MOZ_OVERRIDE; + virtual bool + DeallocPMobileConnectionChild(PMobileConnectionChild* aActor) MOZ_OVERRIDE; + virtual PNeckoChild* AllocPNeckoChild() MOZ_OVERRIDE; virtual bool DeallocPNeckoChild(PNeckoChild*) MOZ_OVERRIDE; virtual PScreenManagerChild* AllocPScreenManagerChild(uint32_t* aNumberOfScreens, float* aSystemDefaultScale, bool* aSuccess) MOZ_OVERRIDE; virtual bool DeallocPScreenManagerChild(PScreenManagerChild*) MOZ_OVERRIDE;
--- a/dom/ipc/ContentParent.cpp +++ b/dom/ipc/ContentParent.cpp @@ -172,16 +172,21 @@ using namespace mozilla::system; #endif #ifdef ENABLE_TESTS #include "BackgroundChildImpl.h" #include "mozilla/ipc/PBackgroundChild.h" #include "nsIIPCBackgroundChildCreateCallback.h" #endif +#ifdef MOZ_B2G_RIL +#include "mozilla/dom/mobileconnection/MobileConnectionParent.h" +using namespace mozilla::dom::mobileconnection; +#endif + #if defined(MOZ_CONTENT_SANDBOX) && defined(XP_LINUX) #include "mozilla/Sandbox.h" #endif static NS_DEFINE_CID(kCClipboardCID, NS_CLIPBOARD_CID); static const char* sClipboardTextFlavors[] = { kUnicodeMime }; using base::ChildPrivileges; @@ -3089,16 +3094,42 @@ ContentParent::AllocPTestShellParent() bool ContentParent::DeallocPTestShellParent(PTestShellParent* shell) { delete shell; return true; } +PMobileConnectionParent* +ContentParent::AllocPMobileConnectionParent(const uint32_t& aClientId) +{ +#ifdef MOZ_B2G_RIL + nsRefPtr<MobileConnectionParent> parent = new MobileConnectionParent(aClientId); + // We release this ref in DeallocPMobileConnectionParent(). + parent->AddRef(); + + return parent; +#else + MOZ_CRASH("No support for mobileconnection on this platform!"); +#endif +} + +bool +ContentParent::DeallocPMobileConnectionParent(PMobileConnectionParent* aActor) +{ +#ifdef MOZ_B2G_RIL + // MobileConnectionParent is refcounted, must not be freed manually. + static_cast<MobileConnectionParent*>(aActor)->Release(); + return true; +#else + MOZ_CRASH("No support for mobileconnection on this platform!"); +#endif +} + PNeckoParent* ContentParent::AllocPNeckoParent() { return new NeckoParent(); } bool ContentParent::DeallocPNeckoParent(PNeckoParent* necko)
--- a/dom/ipc/ContentParent.h +++ b/dom/ipc/ContentParent.h @@ -458,16 +458,19 @@ private: const FileDescriptor& aGCLog, const FileDescriptor& aCCLog) MOZ_OVERRIDE; virtual bool DeallocPCycleCollectWithLogsParent(PCycleCollectWithLogsParent* aActor) MOZ_OVERRIDE; virtual PTestShellParent* AllocPTestShellParent() MOZ_OVERRIDE; virtual bool DeallocPTestShellParent(PTestShellParent* shell) MOZ_OVERRIDE; + virtual PMobileConnectionParent* AllocPMobileConnectionParent(const uint32_t& aClientId) MOZ_OVERRIDE; + virtual bool DeallocPMobileConnectionParent(PMobileConnectionParent* aActor) MOZ_OVERRIDE; + virtual bool DeallocPNeckoParent(PNeckoParent* necko) MOZ_OVERRIDE; virtual PExternalHelperAppParent* AllocPExternalHelperAppParent( const OptionalURIParams& aUri, const nsCString& aMimeContentType, const nsCString& aContentDisposition, const uint32_t& aContentDispositionHint, const nsString& aContentDispositionFilename,
--- a/dom/ipc/PContent.ipdl +++ b/dom/ipc/PContent.ipdl @@ -17,16 +17,17 @@ include protocol PExternalHelperApp; include protocol PDeviceStorageRequest; include protocol PFileDescriptorSet; include protocol PFMRadio; include protocol PFileSystemRequest; include protocol PHal; include protocol PImageBridge; include protocol PIndexedDB; include protocol PMemoryReportRequest; +include protocol PMobileConnection; include protocol PNecko; include protocol PScreenManager; include protocol PSharedBufferManager; include protocol PSms; include protocol PSpeechSynthesis; include protocol PStorage; include protocol PTelephony; include protocol PTestShell; @@ -305,16 +306,17 @@ intr protocol PContent manages PDeviceStorageRequest; manages PFileSystemRequest; manages PExternalHelperApp; manages PFileDescriptorSet; manages PFMRadio; manages PHal; manages PIndexedDB; manages PMemoryReportRequest; + manages PMobileConnection; manages PNecko; manages PScreenManager; manages PSms; manages PSpeechSynthesis; manages PStorage; manages PTelephony; manages PTestShell; manages PJavaScript; @@ -493,16 +495,18 @@ parent: sync IsSecureURI(uint32_t type, URIParams uri, uint32_t flags) returns (bool isSecureURI); PHal(); PIndexedDB(); + PMobileConnection(uint32_t clientId); + PNecko(); rpc PScreenManager() returns (uint32_t numberOfScreens, float systemDefaultScale, bool success); PSms();
--- a/dom/mobileconnection/DOMMMIError.cpp +++ b/dom/mobileconnection/DOMMMIError.cpp @@ -1,13 +1,13 @@ /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ /* vim: set ts=2 et sw=2 tw=80: */ /* 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/. */ + * 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/. */ #include "DOMMMIError.h" #include "mozilla/dom/DOMMMIErrorBinding.h" using namespace mozilla::dom; NS_IMPL_CYCLE_COLLECTION_CLASS(DOMMMIError) @@ -32,24 +32,8 @@ DOMMMIError::DOMMMIError(nsPIDOMWindow* { } JSObject* DOMMMIError::WrapObject(JSContext* aCx) { return DOMMMIErrorBinding::Wrap(aCx, this); } - -// WebIDL interface - -/* static */ already_AddRefed<DOMMMIError> -DOMMMIError::Constructor(const GlobalObject& aGlobal, - const nsAString& aServiceCode, - const nsAString& aName, - const nsAString& aMessage, - const Nullable<int16_t>& aInfo, - ErrorResult& aRv) { - nsCOMPtr<nsPIDOMWindow> window = do_QueryInterface(aGlobal.GetAsSupports()); - nsRefPtr<DOMMMIError> error = new DOMMMIError(window, aName, aMessage, - aServiceCode, aInfo); - - return error.forget(); -}
--- a/dom/mobileconnection/DOMMMIError.h +++ b/dom/mobileconnection/DOMMMIError.h @@ -1,13 +1,13 @@ /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ /* vim: set ts=2 et sw=2 tw=80: */ /* 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/. */ + * 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/. */ #ifndef mozilla_dom_MmiError_h #define mozilla_dom_MmiError_h #include "mozilla/dom/DOMError.h" namespace mozilla { namespace dom { @@ -21,20 +21,16 @@ public: DOMMMIError(nsPIDOMWindow* aWindow, const nsAString& aName, const nsAString& aMessage, const nsAString& aServiceCode, const Nullable<int16_t>& aInfo); virtual JSObject* WrapObject(JSContext* aCx) MOZ_OVERRIDE; // WebIDL interface - static already_AddRefed<DOMMMIError> - Constructor(const GlobalObject& aGlobal, const nsAString& aServiceCode, - const nsAString& aName, const nsAString& aMessage, - const Nullable<int16_t>& aInfo, ErrorResult& aRv); void GetServiceCode(nsString& aServiceCode) const { aServiceCode = mServiceCode; } Nullable<int16_t>
--- a/dom/mobileconnection/MobileCellInfo.cpp +++ b/dom/mobileconnection/MobileCellInfo.cpp @@ -12,31 +12,53 @@ using namespace mozilla::dom; NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(MobileCellInfo, mWindow) NS_IMPL_CYCLE_COLLECTING_ADDREF(MobileCellInfo) NS_IMPL_CYCLE_COLLECTING_RELEASE(MobileCellInfo) NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(MobileCellInfo) NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY NS_INTERFACE_MAP_ENTRY(nsISupports) + NS_INTERFACE_MAP_ENTRY(nsIMobileCellInfo) NS_INTERFACE_MAP_END MobileCellInfo::MobileCellInfo(nsPIDOMWindow* aWindow) : mWindow(aWindow) , mGsmLocationAreaCode(-1) , mGsmCellId(-1) , mCdmaBaseStationId(-1) , mCdmaBaseStationLatitude(-1) , mCdmaBaseStationLongitude(-1) , mCdmaSystemId(-1) , mCdmaNetworkId(-1) { SetIsDOMBinding(); } +MobileCellInfo::MobileCellInfo(int32_t aGsmLocationAreaCode, + int64_t aGsmCellId, + int32_t aCdmaBaseStationId, + int32_t aCdmaBaseStationLatitude, + int32_t aCdmaBaseStationLongitude, + int32_t aCdmaSystemId, + int32_t aCdmaNetworkId) + : mGsmLocationAreaCode(aGsmLocationAreaCode) + , mGsmCellId(aGsmCellId) + , mCdmaBaseStationId(aCdmaBaseStationId) + , mCdmaBaseStationLatitude(aCdmaBaseStationLatitude) + , mCdmaBaseStationLongitude(aCdmaBaseStationLongitude) + , mCdmaSystemId(aCdmaSystemId) + , mCdmaNetworkId(aCdmaNetworkId) +{ + // The instance created by this way is only used for IPC stuff. It won't be + // expose to JS directly, we will clone this instance to the one that is + // maintained in MobileConnectionChild. So we don't need SetIsDOMBinding() + // here. +} + void MobileCellInfo::Update(nsIMobileCellInfo* aInfo) { if (!aInfo) { return; } aInfo->GetGsmLocationAreaCode(&mGsmLocationAreaCode); @@ -46,10 +68,62 @@ MobileCellInfo::Update(nsIMobileCellInfo aInfo->GetCdmaBaseStationLongitude(&mCdmaBaseStationLongitude); aInfo->GetCdmaSystemId(&mCdmaSystemId); aInfo->GetCdmaNetworkId(&mCdmaNetworkId); } JSObject* MobileCellInfo::WrapObject(JSContext* aCx) { + MOZ_ASSERT(IsDOMBinding()); return MozMobileCellInfoBinding::Wrap(aCx, this); } + +// nsIMobileCellInfo + +NS_IMETHODIMP +MobileCellInfo::GetGsmLocationAreaCode(int32_t* aGsmLocationAreaCode) +{ + *aGsmLocationAreaCode = GsmLocationAreaCode(); + return NS_OK; +} + +NS_IMETHODIMP +MobileCellInfo::GetGsmCellId(int64_t* aGsmCellId) +{ + *aGsmCellId = GsmCellId(); + return NS_OK; +} + +NS_IMETHODIMP +MobileCellInfo::GetCdmaBaseStationId(int32_t* aCdmaBaseStationId) +{ + *aCdmaBaseStationId = CdmaBaseStationId(); + return NS_OK; +} + +NS_IMETHODIMP +MobileCellInfo::GetCdmaBaseStationLatitude(int32_t* aCdmaBaseStationLatitude) +{ + *aCdmaBaseStationLatitude = CdmaBaseStationLatitude(); + return NS_OK; +} + +NS_IMETHODIMP +MobileCellInfo::GetCdmaBaseStationLongitude(int32_t* aCdmaBaseStationLongitude) +{ + *aCdmaBaseStationLongitude = CdmaBaseStationLongitude(); + return NS_OK; +} + +NS_IMETHODIMP +MobileCellInfo::GetCdmaSystemId(int32_t* aCdmaSystemId) +{ + *aCdmaSystemId = CdmaSystemId(); + return NS_OK; +} + +NS_IMETHODIMP +MobileCellInfo::GetCdmaNetworkId(int32_t* aCdmaNetworkId) +{ + *aCdmaNetworkId = CdmaNetworkId(); + return NS_OK; +}
--- a/dom/mobileconnection/MobileCellInfo.h +++ b/dom/mobileconnection/MobileCellInfo.h @@ -9,25 +9,31 @@ #include "nsIMobileCellInfo.h" #include "nsPIDOMWindow.h" #include "nsWrapperCache.h" namespace mozilla { namespace dom { -class MobileCellInfo MOZ_FINAL : public nsISupports +class MobileCellInfo MOZ_FINAL : public nsIMobileCellInfo , public nsWrapperCache { public: + NS_DECL_NSIMOBILECELLINFO NS_DECL_CYCLE_COLLECTING_ISUPPORTS NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(MobileCellInfo) MobileCellInfo(nsPIDOMWindow* aWindow); + MobileCellInfo(int32_t aGsmLocationAreaCode, int64_t aGsmCellId, + int32_t aCdmaBaseStationId, int32_t aCdmaBaseStationLatitude, + int32_t aCdmaBaseStationLongitude, int32_t aCdmaSystemId, + int32_t aCdmaNetworkId); + void Update(nsIMobileCellInfo* aInfo); nsPIDOMWindow* GetParentObject() const { return mWindow; }
--- a/dom/mobileconnection/MobileConnection.cpp +++ b/dom/mobileconnection/MobileConnection.cpp @@ -1,32 +1,31 @@ /* 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/. */ #include "MobileConnection.h" +#include "MobileConnectionCallback.h" #include "mozilla/dom/CFStateChangeEvent.h" #include "mozilla/dom/DataErrorEvent.h" #include "mozilla/dom/MozClirModeEvent.h" #include "mozilla/dom/MozEmergencyCbModeEvent.h" #include "mozilla/dom/MozOtaStatusEvent.h" #include "mozilla/dom/ToJSValue.h" #include "mozilla/dom/USSDReceivedEvent.h" #include "mozilla/Preferences.h" #include "mozilla/Services.h" #include "nsIDOMDOMRequest.h" #include "nsIPermissionManager.h" #include "nsIVariant.h" #include "nsJSON.h" #include "nsJSUtils.h" #include "nsServiceManagerUtils.h" -#define NS_RILCONTENTHELPER_CONTRACTID "@mozilla.org/ril/content-helper;1" - #define CONVERT_STRING_TO_NULLABLE_ENUM(_string, _enumType, _enum) \ { \ uint32_t i = 0; \ for (const EnumEntry* entry = _enumType##Values::strings; \ entry->value; \ ++entry, ++i) { \ if (_string.EqualsASCII(entry->value)) { \ _enum.SetValue(static_cast<_enumType>(i)); \ @@ -36,16 +35,17 @@ #define CONVERT_ENUM_TO_STRING(_enumType, _enum, _string) \ { \ uint32_t index = uint32_t(_enum); \ _string.AssignASCII(_enumType##Values::strings[index].value, \ _enumType##Values::strings[index].length); \ } +using mozilla::ErrorResult; using namespace mozilla::dom; class MobileConnection::Listener MOZ_FINAL : public nsIMobileConnectionListener { MobileConnection* mMobileConnection; public: NS_DECL_ISUPPORTS @@ -72,17 +72,17 @@ private: NS_IMPL_ISUPPORTS(MobileConnection::Listener, nsIMobileConnectionListener) NS_IMPL_CYCLE_COLLECTION_CLASS(MobileConnection) NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(MobileConnection, DOMEventTargetHelper) // Don't traverse mListener because it doesn't keep any reference to - // MobileConnection but a raw pointer instead. Neither does mProvider because + // MobileConnection but a raw pointer instead. Neither does mService because // it's an xpcom service and is only released at shutting down. NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mVoice) NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mData) NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(MobileConnection, DOMEventTargetHelper) tmp->Shutdown(); @@ -100,44 +100,44 @@ NS_IMPL_ADDREF_INHERITED(MobileConnectio NS_IMPL_RELEASE_INHERITED(MobileConnection, DOMEventTargetHelper) MobileConnection::MobileConnection(nsPIDOMWindow* aWindow, uint32_t aClientId) : DOMEventTargetHelper(aWindow) , mClientId(aClientId) { SetIsDOMBinding(); - mProvider = do_GetService(NS_RILCONTENTHELPER_CONTRACTID); + mService = do_GetService(NS_MOBILE_CONNECTION_SERVICE_CONTRACTID); - // Not being able to acquire the provider isn't fatal since we check + // Not being able to acquire the service isn't fatal since we check // for it explicitly below. - if (!mProvider) { - NS_WARNING("Could not acquire nsIMobileConnectionProvider!"); + if (!mService) { + NS_WARNING("Could not acquire nsIMobileConnectionService!"); return; } mListener = new Listener(this); mVoice = new MobileConnectionInfo(GetOwner()); mData = new MobileConnectionInfo(GetOwner()); if (CheckPermission("mobileconnection")) { - DebugOnly<nsresult> rv = mProvider->RegisterMobileConnectionMsg(mClientId, mListener); + DebugOnly<nsresult> rv = mService->RegisterListener(mClientId, mListener); NS_WARN_IF_FALSE(NS_SUCCEEDED(rv), - "Failed registering mobile connection messages with provider"); + "Failed registering mobile connection messages with service"); UpdateVoice(); UpdateData(); } } void MobileConnection::Shutdown() { if (mListener) { - if (mProvider) { - mProvider->UnregisterMobileConnectionMsg(mClientId, mListener); + if (mService) { + mService->UnregisterListener(mClientId, mListener); } mListener->Disconnect(); mListener = nullptr; } } MobileConnection::~MobileConnection() @@ -170,61 +170,61 @@ MobileConnection::CheckPermission(const uint32_t permission = nsIPermissionManager::DENY_ACTION; permMgr->TestPermissionFromWindow(GetOwner(), aType, &permission); return permission == nsIPermissionManager::ALLOW_ACTION; } void MobileConnection::UpdateVoice() { - if (!mProvider) { + if (!mService) { return; } nsCOMPtr<nsIMobileConnectionInfo> info; - mProvider->GetVoiceConnectionInfo(mClientId, getter_AddRefs(info)); + mService->GetVoiceConnectionInfo(mClientId, getter_AddRefs(info)); mVoice->Update(info); } void MobileConnection::UpdateData() { - if (!mProvider) { + if (!mService) { return; } nsCOMPtr<nsIMobileConnectionInfo> info; - mProvider->GetDataConnectionInfo(mClientId, getter_AddRefs(info)); + mService->GetDataConnectionInfo(mClientId, getter_AddRefs(info)); mData->Update(info); } // WebIDL interface void MobileConnection::GetLastKnownNetwork(nsString& aRetVal) const { aRetVal.SetIsVoid(true); - if (!mProvider) { + if (!mService) { return; } - mProvider->GetLastKnownNetwork(mClientId, aRetVal); + mService->GetLastKnownNetwork(mClientId, aRetVal); } void MobileConnection::GetLastKnownHomeNetwork(nsString& aRetVal) const { aRetVal.SetIsVoid(true); - if (!mProvider) { + if (!mService) { return; } - mProvider->GetLastKnownHomeNetwork(mClientId, aRetVal); + mService->GetLastKnownHomeNetwork(mClientId, aRetVal); } // All fields below require the "mobileconnection" permission. MobileConnectionInfo* MobileConnection::Voice() const { return mVoice; @@ -236,66 +236,66 @@ MobileConnection::Data() const return mData; } void MobileConnection::GetIccId(nsString& aRetVal) const { aRetVal.SetIsVoid(true); - if (!mProvider) { + if (!mService) { return; } - mProvider->GetIccId(mClientId, aRetVal); + mService->GetIccId(mClientId, aRetVal); } Nullable<MobileNetworkSelectionMode> MobileConnection::GetNetworkSelectionMode() const { Nullable<MobileNetworkSelectionMode> retVal = Nullable<MobileNetworkSelectionMode>(); - if (!mProvider) { + if (!mService) { return retVal; } nsAutoString mode; - mProvider->GetNetworkSelectionMode(mClientId, mode); + mService->GetNetworkSelectionMode(mClientId, mode); CONVERT_STRING_TO_NULLABLE_ENUM(mode, MobileNetworkSelectionMode, retVal); return retVal; } Nullable<MobileRadioState> MobileConnection::GetRadioState() const { Nullable<MobileRadioState> retVal = Nullable<MobileRadioState>(); - if (!mProvider) { + if (!mService) { return retVal; } nsAutoString state; - mProvider->GetRadioState(mClientId, state); + mService->GetRadioState(mClientId, state); CONVERT_STRING_TO_NULLABLE_ENUM(state, MobileRadioState, retVal); return retVal; } void MobileConnection::GetSupportedNetworkTypes(nsTArray<MobileNetworkType>& aTypes) const { - if (!mProvider) { + if (!mService) { return; } nsCOMPtr<nsIVariant> variant; - mProvider->GetSupportedNetworkTypes(mClientId, - getter_AddRefs(variant)); + mService->GetSupportedNetworkTypes(mClientId, + getter_AddRefs(variant)); uint16_t type; nsIID iid; uint32_t count; void* data; // Convert the nsIVariant to an array. We own the resulting buffer and its // elements. @@ -317,253 +317,281 @@ MobileConnection::GetSupportedNetworkTyp } } NS_Free(data); } already_AddRefed<DOMRequest> MobileConnection::GetNetworks(ErrorResult& aRv) { - if (!mProvider) { + if (!mService) { aRv.Throw(NS_ERROR_FAILURE); return nullptr; } - nsCOMPtr<nsIDOMDOMRequest> request; - nsresult rv = mProvider->GetNetworks(mClientId, GetOwner(), - getter_AddRefs(request)); + nsRefPtr<DOMRequest> request = new DOMRequest(GetOwner()); + nsRefPtr<MobileConnectionCallback> requestCallback = + new MobileConnectionCallback(GetOwner(), request); + + nsresult rv = mService->GetNetworks(mClientId, requestCallback); if (NS_FAILED(rv)) { aRv.Throw(rv); return nullptr; } - return request.forget().downcast<DOMRequest>(); + return request.forget(); } already_AddRefed<DOMRequest> MobileConnection::SelectNetwork(MobileNetworkInfo& aNetwork, ErrorResult& aRv) { - if (!mProvider) { + if (!mService) { aRv.Throw(NS_ERROR_FAILURE); return nullptr; } - nsCOMPtr<nsIDOMDOMRequest> request; - nsresult rv = mProvider->SelectNetwork(mClientId, GetOwner(), &aNetwork, - getter_AddRefs(request)); + nsRefPtr<DOMRequest> request = new DOMRequest(GetOwner()); + nsRefPtr<MobileConnectionCallback> requestCallback = + new MobileConnectionCallback(GetOwner(), request); + + nsresult rv = mService->SelectNetwork(mClientId, &aNetwork, requestCallback); if (NS_FAILED(rv)) { aRv.Throw(rv); return nullptr; } - return request.forget().downcast<DOMRequest>(); + return request.forget(); } already_AddRefed<DOMRequest> MobileConnection::SelectNetworkAutomatically(ErrorResult& aRv) { - if (!mProvider) { + if (!mService) { aRv.Throw(NS_ERROR_FAILURE); return nullptr; } - nsCOMPtr<nsIDOMDOMRequest> request; - nsresult rv = mProvider->SelectNetworkAutomatically(mClientId, GetOwner(), - getter_AddRefs(request)); + nsRefPtr<DOMRequest> request = new DOMRequest(GetOwner()); + nsRefPtr<MobileConnectionCallback> requestCallback = + new MobileConnectionCallback(GetOwner(), request); + + nsresult rv = mService->SelectNetworkAutomatically(mClientId, + requestCallback); if (NS_FAILED(rv)) { aRv.Throw(rv); return nullptr; } - return request.forget().downcast<DOMRequest>(); + return request.forget(); } already_AddRefed<DOMRequest> MobileConnection::SetPreferredNetworkType(MobilePreferredNetworkType& aType, ErrorResult& aRv) { - if (!mProvider) { + if (!mService) { aRv.Throw(NS_ERROR_FAILURE); return nullptr; } nsAutoString type; CONVERT_ENUM_TO_STRING(MobilePreferredNetworkType, aType, type); - nsCOMPtr<nsIDOMDOMRequest> request; - nsresult rv = mProvider->SetPreferredNetworkType(mClientId, GetOwner(), type, - getter_AddRefs(request)); + nsRefPtr<DOMRequest> request = new DOMRequest(GetOwner()); + nsRefPtr<MobileConnectionCallback> requestCallback = + new MobileConnectionCallback(GetOwner(), request); + + nsresult rv = mService->SetPreferredNetworkType(mClientId, type, + requestCallback); if (NS_FAILED(rv)) { aRv.Throw(rv); return nullptr; } - return request.forget().downcast<DOMRequest>(); + return request.forget(); } already_AddRefed<DOMRequest> MobileConnection::GetPreferredNetworkType(ErrorResult& aRv) { - if (!mProvider) { + if (!mService) { aRv.Throw(NS_ERROR_FAILURE); return nullptr; } - nsCOMPtr<nsIDOMDOMRequest> request; - nsresult rv = mProvider->GetPreferredNetworkType(mClientId, GetOwner(), - getter_AddRefs(request)); + nsRefPtr<DOMRequest> request = new DOMRequest(GetOwner()); + nsRefPtr<MobileConnectionCallback> requestCallback = + new MobileConnectionCallback(GetOwner(), request); + + nsresult rv = mService->GetPreferredNetworkType(mClientId, requestCallback); if (NS_FAILED(rv)) { aRv.Throw(rv); return nullptr; } - return request.forget().downcast<DOMRequest>(); + return request.forget(); } already_AddRefed<DOMRequest> MobileConnection::SetRoamingPreference(MobileRoamingMode& aMode, ErrorResult& aRv) { - if (!mProvider) { + if (!mService) { aRv.Throw(NS_ERROR_FAILURE); return nullptr; } nsAutoString mode; CONVERT_ENUM_TO_STRING(MobileRoamingMode, aMode, mode); - nsCOMPtr<nsIDOMDOMRequest> request; - nsresult rv = mProvider->SetRoamingPreference(mClientId, GetOwner(), mode, - getter_AddRefs(request)); + nsRefPtr<DOMRequest> request = new DOMRequest(GetOwner()); + nsRefPtr<MobileConnectionCallback> requestCallback = + new MobileConnectionCallback(GetOwner(), request); + + nsresult rv = mService->SetRoamingPreference(mClientId, mode, requestCallback); if (NS_FAILED(rv)) { aRv.Throw(rv); return nullptr; } - return request.forget().downcast<DOMRequest>(); + return request.forget(); } already_AddRefed<DOMRequest> MobileConnection::GetRoamingPreference(ErrorResult& aRv) { - if (!mProvider) { + if (!mService) { aRv.Throw(NS_ERROR_FAILURE); return nullptr; } - nsCOMPtr<nsIDOMDOMRequest> request; - nsresult rv = mProvider->GetRoamingPreference(mClientId, GetOwner(), - getter_AddRefs(request)); + nsRefPtr<DOMRequest> request = new DOMRequest(GetOwner()); + nsRefPtr<MobileConnectionCallback> requestCallback = + new MobileConnectionCallback(GetOwner(), request); + + nsresult rv = mService->GetRoamingPreference(mClientId, requestCallback); if (NS_FAILED(rv)) { aRv.Throw(rv); + return nullptr; } - return request.forget().downcast<DOMRequest>(); + return request.forget(); } already_AddRefed<DOMRequest> MobileConnection::SetVoicePrivacyMode(bool aEnabled, ErrorResult& aRv) { - if (!mProvider) { + if (!mService) { aRv.Throw(NS_ERROR_FAILURE); return nullptr; } - nsCOMPtr<nsIDOMDOMRequest> request; - nsresult rv = mProvider->SetVoicePrivacyMode(mClientId, GetOwner(), aEnabled, - getter_AddRefs(request)); + nsRefPtr<DOMRequest> request = new DOMRequest(GetOwner()); + nsRefPtr<MobileConnectionCallback> requestCallback = + new MobileConnectionCallback(GetOwner(), request); + + nsresult rv = mService->SetVoicePrivacyMode(mClientId, aEnabled, + requestCallback); if (NS_FAILED(rv)) { aRv.Throw(rv); return nullptr; } - return request.forget().downcast<DOMRequest>(); + return request.forget(); } already_AddRefed<DOMRequest> MobileConnection::GetVoicePrivacyMode(ErrorResult& aRv) { - if (!mProvider) { + if (!mService) { aRv.Throw(NS_ERROR_FAILURE); return nullptr; } - nsCOMPtr<nsIDOMDOMRequest> request; - nsresult rv = mProvider->GetVoicePrivacyMode(mClientId, GetOwner(), - getter_AddRefs(request)); + nsRefPtr<DOMRequest> request = new DOMRequest(GetOwner()); + nsRefPtr<MobileConnectionCallback> requestCallback = + new MobileConnectionCallback(GetOwner(), request); + + nsresult rv = mService->GetVoicePrivacyMode(mClientId, requestCallback); if (NS_FAILED(rv)) { aRv.Throw(rv); return nullptr; } - return request.forget().downcast<DOMRequest>(); + return request.forget(); } already_AddRefed<DOMRequest> MobileConnection::SendMMI(const nsAString& aMMIString, ErrorResult& aRv) { - if (!mProvider) { + if (!mService) { aRv.Throw(NS_ERROR_FAILURE); return nullptr; } - nsCOMPtr<nsIDOMDOMRequest> request; - nsresult rv = mProvider->SendMMI(mClientId, GetOwner(), aMMIString, - getter_AddRefs(request)); + nsRefPtr<DOMRequest> request = new DOMRequest(GetOwner()); + nsRefPtr<MobileConnectionCallback> requestCallback = + new MobileConnectionCallback(GetOwner(), request); + + nsresult rv = mService->SendMMI(mClientId, aMMIString, requestCallback); if (NS_FAILED(rv)) { aRv.Throw(rv); return nullptr; } - return request.forget().downcast<DOMRequest>(); + return request.forget(); } already_AddRefed<DOMRequest> MobileConnection::CancelMMI(ErrorResult& aRv) { - if (!mProvider) { + if (!mService) { aRv.Throw(NS_ERROR_FAILURE); return nullptr; } - nsCOMPtr<nsIDOMDOMRequest> request; - nsresult rv = mProvider->CancelMMI(mClientId, GetOwner(), - getter_AddRefs(request)); + nsRefPtr<DOMRequest> request = new DOMRequest(GetOwner()); + nsRefPtr<MobileConnectionCallback> requestCallback = + new MobileConnectionCallback(GetOwner(), request); + + nsresult rv = mService->CancelMMI(mClientId, requestCallback); if (NS_FAILED(rv)) { aRv.Throw(rv); return nullptr; } - return request.forget().downcast<DOMRequest>(); + return request.forget(); } already_AddRefed<DOMRequest> MobileConnection::GetCallForwardingOption(uint16_t aReason, ErrorResult& aRv) { - if (!mProvider) { + if (!mService) { aRv.Throw(NS_ERROR_FAILURE); return nullptr; } - nsCOMPtr<nsIDOMDOMRequest> request; - nsresult rv = mProvider->GetCallForwarding(mClientId, GetOwner(), aReason, - getter_AddRefs(request)); + nsRefPtr<DOMRequest> request = new DOMRequest(GetOwner()); + nsRefPtr<MobileConnectionCallback> requestCallback = + new MobileConnectionCallback(GetOwner(), request); + + nsresult rv = mService->GetCallForwarding(mClientId, aReason, requestCallback); if (NS_FAILED(rv)) { aRv.Throw(rv); return nullptr; } - return request.forget().downcast<DOMRequest>(); + return request.forget(); } already_AddRefed<DOMRequest> MobileConnection::SetCallForwardingOption(const MozCallForwardingOptions& aOptions, ErrorResult& aRv) { - if (!mProvider) { + if (!mService) { aRv.Throw(NS_ERROR_FAILURE); return nullptr; } AutoJSAPI jsapi; if (!NS_WARN_IF(jsapi.Init(GetOwner()))) { aRv.Throw(NS_ERROR_FAILURE); return nullptr; @@ -571,32 +599,34 @@ MobileConnection::SetCallForwardingOptio JSContext *cx = jsapi.cx(); JS::Rooted<JS::Value> options(cx); if (!ToJSValue(cx, aOptions, &options)) { aRv.Throw(NS_ERROR_TYPE_ERR); return nullptr; } - nsCOMPtr<nsIDOMDOMRequest> request; - nsresult rv = mProvider->SetCallForwarding(mClientId, GetOwner(), options, - getter_AddRefs(request)); + nsRefPtr<DOMRequest> request = new DOMRequest(GetOwner()); + nsRefPtr<MobileConnectionCallback> requestCallback = + new MobileConnectionCallback(GetOwner(), request); + + nsresult rv = mService->SetCallForwarding(mClientId, options, requestCallback); if (NS_FAILED(rv)) { aRv.Throw(rv); return nullptr; } - return request.forget().downcast<DOMRequest>(); + return request.forget(); } already_AddRefed<DOMRequest> MobileConnection::GetCallBarringOption(const MozCallBarringOptions& aOptions, ErrorResult& aRv) { - if (!mProvider) { + if (!mService) { aRv.Throw(NS_ERROR_FAILURE); return nullptr; } AutoJSAPI jsapi; if (!NS_WARN_IF(jsapi.Init(GetOwner()))) { aRv.Throw(NS_ERROR_FAILURE); return nullptr; @@ -604,32 +634,34 @@ MobileConnection::GetCallBarringOption(c JSContext *cx = jsapi.cx(); JS::Rooted<JS::Value> options(cx); if (!ToJSValue(cx, aOptions, &options)) { aRv.Throw(NS_ERROR_TYPE_ERR); return nullptr; } - nsCOMPtr<nsIDOMDOMRequest> request; - nsresult rv = mProvider->GetCallBarring(mClientId, GetOwner(), options, - getter_AddRefs(request)); + nsRefPtr<DOMRequest> request = new DOMRequest(GetOwner()); + nsRefPtr<MobileConnectionCallback> requestCallback = + new MobileConnectionCallback(GetOwner(), request); + + nsresult rv = mService->GetCallBarring(mClientId, options, requestCallback); if (NS_FAILED(rv)) { aRv.Throw(rv); return nullptr; } - return request.forget().downcast<DOMRequest>(); + return request.forget(); } already_AddRefed<DOMRequest> MobileConnection::SetCallBarringOption(const MozCallBarringOptions& aOptions, ErrorResult& aRv) { - if (!mProvider) { + if (!mService) { aRv.Throw(NS_ERROR_FAILURE); return nullptr; } AutoJSAPI jsapi; if (!NS_WARN_IF(jsapi.Init(GetOwner()))) { aRv.Throw(NS_ERROR_FAILURE); return nullptr; @@ -637,32 +669,34 @@ MobileConnection::SetCallBarringOption(c JSContext *cx = jsapi.cx(); JS::Rooted<JS::Value> options(cx); if (!ToJSValue(cx, aOptions, &options)) { aRv.Throw(NS_ERROR_TYPE_ERR); return nullptr; } - nsCOMPtr<nsIDOMDOMRequest> request; - nsresult rv = mProvider->SetCallBarring(mClientId, GetOwner(), options, - getter_AddRefs(request)); + nsRefPtr<DOMRequest> request = new DOMRequest(GetOwner()); + nsRefPtr<MobileConnectionCallback> requestCallback = + new MobileConnectionCallback(GetOwner(), request); + + nsresult rv = mService->SetCallBarring(mClientId, options, requestCallback); if (NS_FAILED(rv)) { aRv.Throw(rv); return nullptr; } - return request.forget().downcast<DOMRequest>(); + return request.forget(); } already_AddRefed<DOMRequest> MobileConnection::ChangeCallBarringPassword(const MozCallBarringOptions& aOptions, ErrorResult& aRv) { - if (!mProvider) { + if (!mService) { aRv.Throw(NS_ERROR_FAILURE); return nullptr; } AutoJSAPI jsapi; if (!NS_WARN_IF(jsapi.Init(GetOwner()))) { aRv.Throw(NS_ERROR_FAILURE); return nullptr; @@ -670,144 +704,157 @@ MobileConnection::ChangeCallBarringPassw JSContext *cx = jsapi.cx(); JS::Rooted<JS::Value> options(cx); if (!ToJSValue(cx, aOptions, &options)) { aRv.Throw(NS_ERROR_TYPE_ERR); return nullptr; } - nsCOMPtr<nsIDOMDOMRequest> request; - nsresult rv = mProvider->ChangeCallBarringPassword(mClientId, - GetOwner(), - options, - getter_AddRefs(request)); + nsRefPtr<DOMRequest> request = new DOMRequest(GetOwner()); + nsRefPtr<MobileConnectionCallback> requestCallback = + new MobileConnectionCallback(GetOwner(), request); + + nsresult rv = mService->ChangeCallBarringPassword(mClientId, options, + requestCallback); if (NS_FAILED(rv)) { aRv.Throw(rv); return nullptr; } - return request.forget().downcast<DOMRequest>(); + return request.forget(); } already_AddRefed<DOMRequest> MobileConnection::GetCallWaitingOption(ErrorResult& aRv) { - if (!mProvider) { + if (!mService) { aRv.Throw(NS_ERROR_FAILURE); return nullptr; } - nsCOMPtr<nsIDOMDOMRequest> request; - nsresult rv = mProvider->GetCallWaiting(mClientId, GetOwner(), - getter_AddRefs(request)); + nsRefPtr<DOMRequest> request = new DOMRequest(GetOwner()); + nsRefPtr<MobileConnectionCallback> requestCallback = + new MobileConnectionCallback(GetOwner(), request); + + nsresult rv = mService->GetCallWaiting(mClientId, requestCallback); if (NS_FAILED(rv)) { aRv.Throw(rv); return nullptr; } - return request.forget().downcast<DOMRequest>(); + return request.forget(); } already_AddRefed<DOMRequest> MobileConnection::SetCallWaitingOption(bool aEnabled, ErrorResult& aRv) { - if (!mProvider) { + if (!mService) { aRv.Throw(NS_ERROR_FAILURE); return nullptr; } - nsCOMPtr<nsIDOMDOMRequest> request; - nsresult rv = mProvider->SetCallWaiting(mClientId, GetOwner(), aEnabled, - getter_AddRefs(request)); + nsRefPtr<DOMRequest> request = new DOMRequest(GetOwner()); + nsRefPtr<MobileConnectionCallback> requestCallback = + new MobileConnectionCallback(GetOwner(), request); + + nsresult rv = mService->SetCallWaiting(mClientId, aEnabled, requestCallback); if (NS_FAILED(rv)) { aRv.Throw(rv); return nullptr; } - return request.forget().downcast<DOMRequest>(); + return request.forget(); } already_AddRefed<DOMRequest> MobileConnection::GetCallingLineIdRestriction(ErrorResult& aRv) { - if (!mProvider) { + if (!mService) { aRv.Throw(NS_ERROR_FAILURE); return nullptr; } - nsCOMPtr<nsIDOMDOMRequest> request; - nsresult rv = mProvider->GetCallingLineIdRestriction(mClientId, GetOwner(), - getter_AddRefs(request)); + nsRefPtr<DOMRequest> request = new DOMRequest(GetOwner()); + nsRefPtr<MobileConnectionCallback> requestCallback = + new MobileConnectionCallback(GetOwner(), request); + + nsresult rv = mService->GetCallingLineIdRestriction(mClientId, + requestCallback); if (NS_FAILED(rv)) { aRv.Throw(rv); return nullptr; } - return request.forget().downcast<DOMRequest>(); + return request.forget(); } already_AddRefed<DOMRequest> MobileConnection::SetCallingLineIdRestriction(uint16_t aMode, ErrorResult& aRv) { - if (!mProvider) { + if (!mService) { aRv.Throw(NS_ERROR_FAILURE); return nullptr; } - nsCOMPtr<nsIDOMDOMRequest> request; - nsresult rv = mProvider->SetCallingLineIdRestriction(mClientId, - GetOwner(), - aMode, - getter_AddRefs(request)); + nsRefPtr<DOMRequest> request = new DOMRequest(GetOwner()); + nsRefPtr<MobileConnectionCallback> requestCallback = + new MobileConnectionCallback(GetOwner(), request); + + nsresult rv = mService->SetCallingLineIdRestriction(mClientId, aMode, + requestCallback); if (NS_FAILED(rv)) { aRv.Throw(rv); return nullptr; } - return request.forget().downcast<DOMRequest>(); + return request.forget(); } already_AddRefed<DOMRequest> MobileConnection::ExitEmergencyCbMode(ErrorResult& aRv) { - if (!mProvider) { + if (!mService) { aRv.Throw(NS_ERROR_FAILURE); return nullptr; } - nsCOMPtr<nsIDOMDOMRequest> request; - nsresult rv = mProvider->ExitEmergencyCbMode(mClientId, GetOwner(), - getter_AddRefs(request)); + nsRefPtr<DOMRequest> request = new DOMRequest(GetOwner()); + nsRefPtr<MobileConnectionCallback> requestCallback = + new MobileConnectionCallback(GetOwner(), request); + + nsresult rv = mService->ExitEmergencyCbMode(mClientId, requestCallback); if (NS_FAILED(rv)) { aRv.Throw(rv); return nullptr; } - return request.forget().downcast<DOMRequest>(); + return request.forget(); } already_AddRefed<DOMRequest> MobileConnection::SetRadioEnabled(bool aEnabled, ErrorResult& aRv) { - if (!mProvider) { + if (!mService) { aRv.Throw(NS_ERROR_FAILURE); return nullptr; } - nsCOMPtr<nsIDOMDOMRequest> request; - nsresult rv = mProvider->SetRadioEnabled(mClientId, GetOwner(), aEnabled, - getter_AddRefs(request)); + nsRefPtr<DOMRequest> request = new DOMRequest(GetOwner()); + nsRefPtr<MobileConnectionCallback> requestCallback = + new MobileConnectionCallback(GetOwner(), request); + + nsresult rv = mService->SetRadioEnabled(mClientId, aEnabled, requestCallback); if (NS_FAILED(rv)) { aRv.Throw(rv); return nullptr; } - return request.forget().downcast<DOMRequest>(); + return request.forget(); } // nsIMobileConnectionListener NS_IMETHODIMP MobileConnection::NotifyVoiceChanged() { if (!CheckPermission("mobileconnection")) { @@ -865,22 +912,22 @@ MobileConnection::NotifyDataError(const nsRefPtr<DataErrorEvent> event = DataErrorEvent::Constructor(this, NS_LITERAL_STRING("dataerror"), init); return DispatchTrustedEvent(event); } NS_IMETHODIMP -MobileConnection::NotifyCFStateChange(bool aSuccess, - unsigned short aAction, - unsigned short aReason, - const nsAString& aNumber, - unsigned short aSeconds, - unsigned short aServiceClass) +MobileConnection::NotifyCFStateChanged(bool aSuccess, + unsigned short aAction, + unsigned short aReason, + const nsAString& aNumber, + unsigned short aSeconds, + unsigned short aServiceClass) { if (!CheckPermission("mobileconnection")) { return NS_OK; } CFStateChangeEventInit init; init.mBubbles = false; init.mCancelable = false; @@ -967,8 +1014,26 @@ MobileConnection::NotifyClirModeChanged( init.mCancelable = false; init.mMode = aMode; nsRefPtr<MozClirModeEvent> event = MozClirModeEvent::Constructor(this, NS_LITERAL_STRING("clirmodechange"), init); return DispatchTrustedEvent(event); } + +NS_IMETHODIMP +MobileConnection::NotifyLastKnownNetworkChanged() +{ + return NS_OK; +} + +NS_IMETHODIMP +MobileConnection::NotifyLastKnownHomeNetworkChanged() +{ + return NS_OK; +} + +NS_IMETHODIMP +MobileConnection::NotifyNetworkSelectionModeChanged() +{ + return NS_OK; +}
--- a/dom/mobileconnection/MobileConnection.h +++ b/dom/mobileconnection/MobileConnection.h @@ -6,30 +6,30 @@ #define mozilla_dom_MobileConnection_h #include "MobileConnectionInfo.h" #include "MobileNetworkInfo.h" #include "mozilla/DOMEventTargetHelper.h" #include "mozilla/dom/DOMRequest.h" #include "mozilla/dom/MozMobileConnectionBinding.h" #include "nsCycleCollectionParticipant.h" -#include "nsIMobileConnectionProvider.h" +#include "nsIMobileConnectionService.h" #include "nsWeakPtr.h" namespace mozilla { namespace dom { class MobileConnection MOZ_FINAL : public DOMEventTargetHelper, private nsIMobileConnectionListener { /** * Class MobileConnection doesn't actually expose * nsIMobileConnectionListener. Instead, it owns an * nsIMobileConnectionListener derived instance mListener and passes it to - * nsIMobileConnectionProvider. The onreceived events are first delivered to + * nsIMobileConnectionService. The onreceived events are first delivered to * mListener and then forwarded to its owner, MobileConnection. See also bug * 775997 comment #51. */ class Listener; public: NS_DECL_ISUPPORTS_INHERITED NS_DECL_NSIMOBILECONNECTIONLISTENER @@ -159,17 +159,17 @@ public: IMPL_EVENT_HANDLER(radiostatechange) IMPL_EVENT_HANDLER(clirmodechange) private: ~MobileConnection(); private: uint32_t mClientId; - nsCOMPtr<nsIMobileConnectionProvider> mProvider; + nsCOMPtr<nsIMobileConnectionService> mService; nsRefPtr<Listener> mListener; nsRefPtr<MobileConnectionInfo> mVoice; nsRefPtr<MobileConnectionInfo> mData; bool CheckPermission(const char* aType) const; void
new file mode 100644 --- /dev/null +++ b/dom/mobileconnection/MobileConnectionCallback.cpp @@ -0,0 +1,319 @@ +/* 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/. */ + +#include "MobileConnectionCallback.h" + +#include "DOMMMIError.h" +#include "mozilla/dom/MobileNetworkInfo.h" +#include "mozilla/dom/MozMobileConnectionBinding.h" +#include "mozilla/dom/ToJSValue.h" +#include "nsJSUtils.h" +#include "nsServiceManagerUtils.h" + +using namespace mozilla::dom; + +NS_IMPL_ISUPPORTS(MobileConnectionCallback, nsIMobileConnectionCallback) + +MobileConnectionCallback::MobileConnectionCallback(nsPIDOMWindow* aWindow, + DOMRequest* aRequest) + : mWindow(aWindow) + , mRequest(aRequest) +{ +} + +/** + * Notify Success for Send/CancelMmi. + */ +nsresult +MobileConnectionCallback::NotifySendCancelMmiSuccess(const nsAString& aServiceCode, + const nsAString& aStatusMessage) +{ + MozMMIResult result; + result.mServiceCode.Assign(aServiceCode); + result.mStatusMessage.Assign(aStatusMessage); + + return NotifySendCancelMmiSuccess(result); +} + +nsresult +MobileConnectionCallback::NotifySendCancelMmiSuccess(const nsAString& aServiceCode, + const nsAString& aStatusMessage, + JS::Handle<JS::Value> aAdditionalInformation) +{ + AutoJSAPI jsapi; + if (!NS_WARN_IF(jsapi.Init(mWindow))) { + return NS_ERROR_FAILURE; + } + + JSContext* cx = jsapi.cx(); + RootedDictionary<MozMMIResult> result(cx); + + result.mServiceCode.Assign(aServiceCode); + result.mStatusMessage.Assign(aStatusMessage); + result.mAdditionalInformation.Construct().SetAsObject() = &aAdditionalInformation.toObject(); + + return NotifySendCancelMmiSuccess(result); +} + +nsresult +MobileConnectionCallback::NotifySendCancelMmiSuccess(const nsAString& aServiceCode, + const nsAString& aStatusMessage, + uint16_t aAdditionalInformation) +{ + MozMMIResult result; + result.mServiceCode.Assign(aServiceCode); + result.mStatusMessage.Assign(aStatusMessage); + result.mAdditionalInformation.Construct().SetAsUnsignedShort() = aAdditionalInformation; + + return NotifySendCancelMmiSuccess(result); +} + +nsresult +MobileConnectionCallback::NotifySendCancelMmiSuccess(const nsAString& aServiceCode, + const nsAString& aStatusMessage, + const nsTArray<nsString>& aAdditionalInformation) +{ + AutoJSAPI jsapi; + if (!NS_WARN_IF(jsapi.Init(mWindow))) { + return NS_ERROR_FAILURE; + } + + JSContext* cx = jsapi.cx(); + JS::Rooted<JS::Value> additionalInformation(cx); + + if (!ToJSValue(cx, aAdditionalInformation, &additionalInformation)) { + JS_ClearPendingException(cx); + return NS_ERROR_TYPE_ERR; + } + + return NotifySendCancelMmiSuccess(aServiceCode, aStatusMessage, + additionalInformation); +} + +nsresult +MobileConnectionCallback::NotifySendCancelMmiSuccess(const nsAString& aServiceCode, + const nsAString& aStatusMessage, + const nsTArray<IPC::MozCallForwardingOptions>& aAdditionalInformation) +{ + AutoJSAPI jsapi; + if (!NS_WARN_IF(jsapi.Init(mWindow))) { + return NS_ERROR_FAILURE; + } + + JSContext* cx = jsapi.cx(); + JS::Rooted<JS::Value> additionalInformation(cx); + + if (!ToJSValue(cx, aAdditionalInformation, &additionalInformation)) { + JS_ClearPendingException(cx); + return NS_ERROR_TYPE_ERR; + } + + return NotifySendCancelMmiSuccess(aServiceCode, aStatusMessage, + additionalInformation); +} + +nsresult +MobileConnectionCallback::NotifySendCancelMmiSuccess(const MozMMIResult& aResult) +{ + AutoJSAPI jsapi; + if (!NS_WARN_IF(jsapi.Init(mWindow))) { + return NS_ERROR_FAILURE; + } + + JSContext* cx = jsapi.cx(); + JS::Rooted<JS::Value> jsResult(cx); + + if (!ToJSValue(cx, aResult, &jsResult)) { + JS_ClearPendingException(cx); + return NS_ERROR_TYPE_ERR; + } + + return NotifySuccess(jsResult); +} + +/** + * Notify Success for GetCallForwarding. + */ +nsresult +MobileConnectionCallback::NotifyGetCallForwardingSuccess(const nsTArray<IPC::MozCallForwardingOptions>& aResults) +{ + AutoJSAPI jsapi; + if (!NS_WARN_IF(jsapi.Init(mWindow))) { + return NS_ERROR_FAILURE; + } + + JSContext* cx = jsapi.cx(); + JS::Rooted<JS::Value> jsResult(cx); + + if (!ToJSValue(cx, aResults, &jsResult)) { + JS_ClearPendingException(cx); + return NS_ERROR_TYPE_ERR; + } + + return NotifySuccess(jsResult); +} + +/** + * Notify Success. + */ +nsresult +MobileConnectionCallback::NotifySuccess(JS::Handle<JS::Value> aResult) +{ + nsCOMPtr<nsIDOMRequestService> rs = do_GetService(DOMREQUEST_SERVICE_CONTRACTID); + NS_ENSURE_TRUE(rs, NS_ERROR_FAILURE); + + return rs->FireSuccessAsync(mRequest, aResult); +} + +// nsIMobileConnectionCallback + +NS_IMETHODIMP +MobileConnectionCallback::NotifySuccess() +{ + return NotifySuccess(JS::UndefinedHandleValue); +} + +NS_IMETHODIMP +MobileConnectionCallback::NotifySuccessWithString(const nsAString& aResult) +{ + AutoJSAPI jsapi; + if (!NS_WARN_IF(jsapi.Init(mWindow))) { + return NS_ERROR_FAILURE; + } + + JSContext* cx = jsapi.cx(); + JS::Rooted<JS::Value> jsResult(cx); + + if (!ToJSValue(cx, aResult, &jsResult)) { + JS_ClearPendingException(cx); + return NS_ERROR_TYPE_ERR; + } + + return NotifySuccess(jsResult); +} + +NS_IMETHODIMP +MobileConnectionCallback::NotifySuccessWithBoolean(bool aResult) +{ + return aResult ? NotifySuccess(JS::TrueHandleValue) + : NotifySuccess(JS::FalseHandleValue); +} + +NS_IMETHODIMP +MobileConnectionCallback::NotifyGetNetworksSuccess(uint32_t aCount, + nsIMobileNetworkInfo** aNetworks) +{ + nsTArray<nsRefPtr<MobileNetworkInfo>> results; + for (uint32_t i = 0; i < aCount; i++) + { + nsRefPtr<MobileNetworkInfo> networkInfo = new MobileNetworkInfo(mWindow); + networkInfo->Update(aNetworks[i]); + results.AppendElement(networkInfo); + } + + AutoJSAPI jsapi; + if (!NS_WARN_IF(jsapi.Init(mWindow))) { + return NS_ERROR_FAILURE; + } + + JSContext* cx = jsapi.cx(); + JS::Rooted<JS::Value> jsResult(cx); + + if (!ToJSValue(cx, results, &jsResult)) { + JS_ClearPendingException(cx); + return NS_ERROR_TYPE_ERR; + } + + return NotifySuccess(jsResult); +} + +NS_IMETHODIMP +MobileConnectionCallback::NotifySendCancelMmiSuccess(JS::Handle<JS::Value> aResult) +{ + return NotifySuccess(aResult); +} + +NS_IMETHODIMP +MobileConnectionCallback::NotifyGetCallForwardingSuccess(JS::Handle<JS::Value> aResults) +{ + return NotifySuccess(aResults); +} + +NS_IMETHODIMP +MobileConnectionCallback::NotifyGetCallBarringSuccess(uint16_t aProgram, + bool aEnabled, + uint16_t aServiceClass) +{ + MozCallBarringOptions result; + result.mProgram.Construct().SetValue(aProgram); + result.mEnabled.Construct().SetValue(aEnabled); + result.mServiceClass.Construct().SetValue(aServiceClass); + + AutoJSAPI jsapi; + if (!NS_WARN_IF(jsapi.Init(mWindow))) { + return NS_ERROR_FAILURE; + } + + JSContext* cx = jsapi.cx(); + JS::Rooted<JS::Value> jsResult(cx); + if (!ToJSValue(cx, result, &jsResult)) { + JS_ClearPendingException(cx); + return NS_ERROR_TYPE_ERR; + } + + return NotifySuccess(jsResult); +} + +NS_IMETHODIMP +MobileConnectionCallback::NotifyGetClirStatusSuccess(uint16_t aN, uint16_t aM) +{ + MozClirStatus result; + result.mN.Construct(aN); + result.mM.Construct(aM); + + AutoJSAPI jsapi; + if (!NS_WARN_IF(jsapi.Init(mWindow))) { + return NS_ERROR_FAILURE; + } + + JSContext* cx = jsapi.cx(); + JS::Rooted<JS::Value> jsResult(cx); + if (!ToJSValue(cx, result, &jsResult)) { + JS_ClearPendingException(cx); + return NS_ERROR_TYPE_ERR; + } + + return NotifySuccess(jsResult); +}; + +NS_IMETHODIMP +MobileConnectionCallback::NotifyError(const nsAString& aName, + const nsAString& aMessage, + const nsAString& aServiceCode, + uint16_t aInfo, + uint8_t aArgc) +{ + nsCOMPtr<nsIDOMRequestService> rs = do_GetService(DOMREQUEST_SERVICE_CONTRACTID); + NS_ENSURE_TRUE(rs, NS_ERROR_FAILURE); + + nsRefPtr<DOMError> error; + switch (aArgc) { + case 0: + return rs->FireErrorAsync(mRequest, aName); + case 1: + error = new DOMMMIError(mWindow, aName, aMessage, EmptyString(), + Nullable<int16_t>()); + return rs->FireDetailedError(mRequest, error); + case 2: + error = new DOMMMIError(mWindow, aName, aMessage, aServiceCode, + Nullable<int16_t>()); + return rs->FireDetailedError(mRequest, error); + case 3: + error = new DOMMMIError(mWindow, aName, aMessage, aServiceCode, + Nullable<int16_t>(int16_t(aInfo))); + return rs->FireDetailedError(mRequest, error); + } + + return NS_ERROR_FAILURE; +}
new file mode 100644 --- /dev/null +++ b/dom/mobileconnection/MobileConnectionCallback.h @@ -0,0 +1,78 @@ +/* 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/. */ + +#ifndef mozilla_dom_MobileConnectionCallback_h +#define mozilla_dom_MobileConnectionCallback_h + +#include "mozilla/dom/DOMRequest.h" +#include "mozilla/dom/MobileConnectionIPCSerializer.h" +#include "nsCOMPtr.h" +#include "nsIMobileConnectionService.h" + +namespace mozilla { +namespace dom { + +/** + * A callback object for handling asynchronous request/response. This object is + * created when an asynchronous request is made and should be destroyed after + * Notify*Success/Error is called. + * The modules hold the reference of MobileConnectionCallback in OOP mode and + * non-OOP mode are different. + * - OOP mode: MobileConnectionRequestChild + * - non-OOP mode: MobileConnectionGonkService + * The reference should be released after Notify*Success/Error is called. + */ +class MobileConnectionCallback MOZ_FINAL : public nsIMobileConnectionCallback +{ +public: + NS_DECL_ISUPPORTS + NS_DECL_NSIMOBILECONNECTIONCALLBACK + + MobileConnectionCallback(nsPIDOMWindow* aWindow, DOMRequest* aRequest); + + /** + * Notify Success for Send/CancelMmi. + */ + nsresult + NotifySendCancelMmiSuccess(const nsAString& aServiceCode, + const nsAString& aStatusMessage); + nsresult + NotifySendCancelMmiSuccess(const nsAString& aServiceCode, + const nsAString& aStatusMessage, + JS::Handle<JS::Value> aAdditionalInformation); + nsresult + NotifySendCancelMmiSuccess(const nsAString& aServiceCode, + const nsAString& aStatusMessage, + uint16_t aAdditionalInformation); + nsresult + NotifySendCancelMmiSuccess(const nsAString& aServiceCode, + const nsAString& aStatusMessage, + const nsTArray<nsString>& aAdditionalInformation); + nsresult + NotifySendCancelMmiSuccess(const nsAString& aServiceCode, + const nsAString& aStatusMessage, + const nsTArray<IPC::MozCallForwardingOptions>& aAdditionalInformation); + nsresult + NotifySendCancelMmiSuccess(const MozMMIResult& aResult); + + /** + * Notify Success for GetCallForwarding. + */ + nsresult + NotifyGetCallForwardingSuccess(const nsTArray<IPC::MozCallForwardingOptions>& aResults); + +private: + ~MobileConnectionCallback() {} + + nsresult + NotifySuccess(JS::Handle<JS::Value> aResult); + + nsCOMPtr<nsPIDOMWindow> mWindow; + nsRefPtr<DOMRequest> mRequest; +}; + +} // name space dom +} // name space mozilla + +#endif // mozilla_dom_MobileConnectionCallback_h
--- a/dom/mobileconnection/MobileConnectionInfo.cpp +++ b/dom/mobileconnection/MobileConnectionInfo.cpp @@ -19,38 +19,87 @@ entry->value; \ ++entry, ++i) { \ if (_string.EqualsASCII(entry->value)) { \ _enum.SetValue(static_cast<_enumType>(i)); \ } \ } \ } +#define CONVERT_NULLABLE_ENUM_TO_STRING(_enumType, _enum, _string) \ +{ \ + if (_enum.IsNull()) { \ + _string.SetIsVoid(true); \ + } else { \ + uint32_t index = uint32_t(_enum.Value()); \ + _string.AssignASCII(_enumType##Values::strings[index].value, \ + _enumType##Values::strings[index].length); \ + } \ +} + using namespace mozilla::dom; NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(MobileConnectionInfo, mWindow, mNetworkInfo, mCellInfo) NS_IMPL_CYCLE_COLLECTING_ADDREF(MobileConnectionInfo) NS_IMPL_CYCLE_COLLECTING_RELEASE(MobileConnectionInfo) NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(MobileConnectionInfo) NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY NS_INTERFACE_MAP_ENTRY(nsISupports) + NS_INTERFACE_MAP_ENTRY(nsIMobileConnectionInfo) NS_INTERFACE_MAP_END MobileConnectionInfo::MobileConnectionInfo(nsPIDOMWindow* aWindow) : mConnected(false) , mEmergencyCallsOnly(false) , mRoaming(false) , mWindow(aWindow) { SetIsDOMBinding(); } +MobileConnectionInfo::MobileConnectionInfo(const nsAString& aState, + bool aConnected, + bool aEmergencyCallsOnly, + bool aRoaming, + nsIMobileNetworkInfo* aNetworkInfo, + const nsAString& aType, + const Nullable<int32_t>& aSignalStrength, + const Nullable<uint16_t>& aRelSignalStrength, + nsIMobileCellInfo* aCellInfo) + : mConnected(aConnected) + , mEmergencyCallsOnly(aEmergencyCallsOnly) + , mRoaming(aRoaming) + , mSignalStrength(aSignalStrength) + , mRelSignalStrength(aRelSignalStrength) +{ + // The instance created by this way is only used for IPC stuff. It won't be + // expose to JS directly, we will clone this instance to the one that is + // maintained in MobileConnectionChild. So we don't need SetIsDOMBinding() + // here. + + // Update mState and mType + CONVERT_STRING_TO_NULLABLE_ENUM(aState, MobileConnectionState, mState); + CONVERT_STRING_TO_NULLABLE_ENUM(aType, MobileConnectionType, mType); + + // Update mNetworkInfo + if (aNetworkInfo) { + mNetworkInfo = new MobileNetworkInfo(mWindow); + mNetworkInfo->Update(aNetworkInfo); + } + + // Update mCellInfo + if (aCellInfo) { + mCellInfo = new MobileCellInfo(mWindow); + mCellInfo->Update(aCellInfo); + } +} + void MobileConnectionInfo::Update(nsIMobileConnectionInfo* aInfo) { if (!aInfo) { return; } aInfo->GetConnected(&mConnected); @@ -109,10 +158,84 @@ MobileConnectionInfo::Update(nsIMobileCo } else { mCellInfo = nullptr; } } JSObject* MobileConnectionInfo::WrapObject(JSContext* aCx) { + MOZ_ASSERT(IsDOMBinding()); return MozMobileConnectionInfoBinding::Wrap(aCx, this); } + +// nsIMobileConnectionInfo + +NS_IMETHODIMP +MobileConnectionInfo::GetState(nsAString& aState) +{ + CONVERT_NULLABLE_ENUM_TO_STRING(MobileConnectionState, mState, aState); + return NS_OK; +} + +NS_IMETHODIMP +MobileConnectionInfo::GetConnected(bool* aConnected) +{ + *aConnected = Connected(); + return NS_OK; +} + +NS_IMETHODIMP +MobileConnectionInfo::GetEmergencyCallsOnly(bool* aEmergencyCallsOnly) +{ + *aEmergencyCallsOnly = EmergencyCallsOnly(); + return NS_OK; +} + +NS_IMETHODIMP +MobileConnectionInfo::GetRoaming(bool* aRoaming) +{ + *aRoaming = Roaming(); + return NS_OK; +} + +NS_IMETHODIMP +MobileConnectionInfo::GetNetwork(nsIMobileNetworkInfo** aInfo) +{ + NS_IF_ADDREF(*aInfo = GetNetwork()); + return NS_OK; +} + +NS_IMETHODIMP +MobileConnectionInfo::GetType(nsAString& aType) +{ + CONVERT_NULLABLE_ENUM_TO_STRING(MobileConnectionType, mType, aType); + return NS_OK; +} + +NS_IMETHODIMP +MobileConnectionInfo::GetSignalStrength(JS::MutableHandle<JS::Value> aSignal) +{ + if (mSignalStrength.IsNull()) { + aSignal.setNull(); + } else { + aSignal.setInt32(mSignalStrength.Value()); + } + return NS_OK; +} + +NS_IMETHODIMP +MobileConnectionInfo::GetRelSignalStrength(JS::MutableHandle<JS::Value> aSignal) +{ + if (mRelSignalStrength.IsNull()) { + aSignal.setNull(); + } else { + aSignal.setNumber(uint32_t(mRelSignalStrength.Value())); + } + return NS_OK; +} + +NS_IMETHODIMP +MobileConnectionInfo::GetCell(nsIMobileCellInfo** aInfo) +{ + NS_IF_ADDREF(*aInfo = GetCell()); + return NS_OK; +}
--- a/dom/mobileconnection/MobileConnectionInfo.h +++ b/dom/mobileconnection/MobileConnectionInfo.h @@ -12,25 +12,34 @@ #include "mozilla/dom/MozMobileConnectionInfoBinding.h" #include "nsIMobileConnectionInfo.h" #include "nsPIDOMWindow.h" #include "nsWrapperCache.h" namespace mozilla { namespace dom { -class MobileConnectionInfo MOZ_FINAL : public nsISupports +class MobileConnectionInfo MOZ_FINAL : public nsIMobileConnectionInfo , public nsWrapperCache { public: + NS_DECL_NSIMOBILECONNECTIONINFO NS_DECL_CYCLE_COLLECTING_ISUPPORTS NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(MobileConnectionInfo) MobileConnectionInfo(nsPIDOMWindow* aWindow); + MobileConnectionInfo(const nsAString& aState, bool aConnected, + bool aEmergencyCallsOnly, bool aRoaming, + nsIMobileNetworkInfo* aNetworkInfo, + const nsAString& aType, + const Nullable<int32_t>& aSignalStrength, + const Nullable<uint16_t>& aRelSignalStrength, + nsIMobileCellInfo* aCellInfo); + void Update(nsIMobileConnectionInfo* aInfo); nsPIDOMWindow* GetParentObject() const { return mWindow; }
--- a/dom/mobileconnection/MobileNetworkInfo.cpp +++ b/dom/mobileconnection/MobileNetworkInfo.cpp @@ -20,16 +20,32 @@ NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION( NS_INTERFACE_MAP_END MobileNetworkInfo::MobileNetworkInfo(nsPIDOMWindow* aWindow) : mWindow(aWindow) { SetIsDOMBinding(); } +MobileNetworkInfo::MobileNetworkInfo(const nsAString& aShortName, + const nsAString& aLongName, + const nsAString& aMcc, + const nsAString& aMnc, + const nsAString& aState) + : mShortName(aShortName) + , mLongName(aLongName) + , mMcc(aMcc) + , mMnc(aMnc) + , mState(aState) +{ + // The parent object is nullptr when MobileNetworkInfo is created by this way. + // And it won't be exposed to web content. + SetIsDOMBinding(); +} + void MobileNetworkInfo::Update(nsIMobileNetworkInfo* aInfo) { if (!aInfo) { return; } aInfo->GetShortName(mShortName); @@ -40,39 +56,16 @@ MobileNetworkInfo::Update(nsIMobileNetwo } JSObject* MobileNetworkInfo::WrapObject(JSContext* aCx) { return MozMobileNetworkInfoBinding::Wrap(aCx, this); } -// WebIDL interface - -/* static */ already_AddRefed<MobileNetworkInfo> -MobileNetworkInfo::Constructor(const GlobalObject& aGlobal, - const nsAString& aShortName, - const nsAString& aLongName, - const nsAString& aMcc, - const nsAString& aMnc, - const nsAString& aState, - ErrorResult& aRv) -{ - nsCOMPtr<nsPIDOMWindow> window = do_QueryInterface(aGlobal.GetAsSupports()); - nsRefPtr<MobileNetworkInfo> info = new MobileNetworkInfo(window); - - info->mShortName.Assign(aShortName); - info->mLongName.Assign(aLongName); - info->mMcc.Assign(aMcc); - info->mMnc.Assign(aMnc); - info->mState.Assign(aState); - - return info.forget(); -} - // nsIMobileNetworkInfo NS_IMETHODIMP MobileNetworkInfo::GetShortName(nsAString& aShortName) { aShortName = mShortName; return NS_OK; }
--- a/dom/mobileconnection/MobileNetworkInfo.h +++ b/dom/mobileconnection/MobileNetworkInfo.h @@ -22,35 +22,33 @@ class MobileNetworkInfo MOZ_FINAL : publ { public: NS_DECL_NSIMOBILENETWORKINFO NS_DECL_CYCLE_COLLECTING_ISUPPORTS NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(MobileNetworkInfo) MobileNetworkInfo(nsPIDOMWindow* aWindow); + MobileNetworkInfo(const nsAString& aShortName, const nsAString& aLongName, + const nsAString& aMcc, const nsAString& aMnc, + const nsAString& aState); + void Update(nsIMobileNetworkInfo* aInfo); nsPIDOMWindow* GetParentObject() const { return mWindow; } virtual JSObject* WrapObject(JSContext* aCx) MOZ_OVERRIDE; // WebIDL interface - static already_AddRefed<MobileNetworkInfo> - Constructor(const GlobalObject& aGlobal, const nsAString& aShortName, - const nsAString& aLongName, const nsAString& aMcc, - const nsAString& aMnc, const nsAString& aState, - ErrorResult& aRv); - Nullable<MobileNetworkState> GetState() const { uint32_t i = 0; for (const EnumEntry* entry = MobileNetworkStateValues::strings; entry->value; ++entry, ++i) { if (mState.EqualsASCII(entry->value)) {
new file mode 100644 --- /dev/null +++ b/dom/mobileconnection/gonk/MobileConnectionGonkService.js @@ -0,0 +1,1548 @@ +/* -*- Mode: js; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 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/Services.jsm"); +Cu.import("resource://gre/modules/systemlibs.js"); +Cu.import("resource://gre/modules/XPCOMUtils.jsm"); + +var RIL = {}; +Cu.import("resource://gre/modules/ril_consts.js", RIL); + +const MOBILECONNECTIONGONKSERVICE_CONTRACTID = + "@mozilla.org/mobileconnection/mobileconnectiongonkservice;1"; + +const MOBILECONNECTIONGONKSERVICE_CID = + Components.ID("{05e20430-fe65-4984-8df9-a6a504b24a91}"); +const MOBILENETWORKINFO_CID = + Components.ID("{a6c8416c-09b4-46d1-bf29-6520d677d085}"); +const MOBILECELLINFO_CID = + Components.ID("{0635d9ab-997e-4cdf-84e7-c1883752dff3}"); + +const NS_XPCOM_SHUTDOWN_OBSERVER_ID = "xpcom-shutdown"; +const NS_PREFBRANCH_PREFCHANGE_TOPIC_ID = "nsPref:changed"; +const NS_NETWORK_ACTIVE_CHANGED_TOPIC_ID = "network-active-changed"; + +const kPrefRilDebuggingEnabled = "ril.debugging.enabled"; + +XPCOMUtils.defineLazyServiceGetter(this, "gSystemMessenger", + "@mozilla.org/system-message-internal;1", + "nsISystemMessagesInternal"); + +XPCOMUtils.defineLazyServiceGetter(this, "gNetworkManager", + "@mozilla.org/network/manager;1", + "nsINetworkManager"); + +XPCOMUtils.defineLazyServiceGetter(this, "gRadioInterfaceLayer", + "@mozilla.org/ril;1", + "nsIRadioInterfaceLayer"); + +let DEBUG = RIL.DEBUG_RIL; +function debug(s) { + dump("MobileConnectionGonkService: " + s + "\n"); +} + +function MobileNetworkInfo() { + this.shortName = null; + this.longName = null; + this.mcc = null; + this.mnc = null; + this.stat = null; +} +MobileNetworkInfo.prototype = { + QueryInterface: XPCOMUtils.generateQI([Ci.nsIMobileNetworkInfo]), + classID: MOBILENETWORKINFO_CID, + classInfo: XPCOMUtils.generateCI({ + classID: MOBILENETWORKINFO_CID, + classDescription: "MobileNetworkInfo", + interfaces: [Ci.nsIMobileNetworkInfo] + }) +}; + +function MobileCellInfo() { + this.gsmLocationAreaCode = -1; + this.gsmCellId = -1; + this.cdmaBaseStationId = -1; + this.cdmaBaseStationLatitude = -2147483648; + this.cdmaBaseStationLongitude = -2147483648; + this.cdmaSystemId = -1; + this.cdmaNetworkId = -1; +} +MobileCellInfo.prototype = { + QueryInterface: XPCOMUtils.generateQI([Ci.nsIMobileCellInfo]), + classID: MOBILECELLINFO_CID, + classInfo: XPCOMUtils.generateCI({ + classID: MOBILECELLINFO_CID, + classDescription: "MobileCellInfo", + interfaces: [Ci.nsIMobileCellInfo] + }) +}; + +function CallForwardingOptions(aOptions) { + this.active = aOptions.active; + this.action = aOptions.action; + this.reason = aOptions.reason; + this.number = aOptions.number; + this.timeSeconds = aOptions.timeSeconds; + this.serviceClass = aOptions.serviceClass; +} +CallForwardingOptions.prototype = { + __exposedProps__ : {active: 'r', + action: 'r', + reason: 'r', + number: 'r', + timeSeconds: 'r', + serviceClass: 'r'}, +}; + +function MMIResult(aOptions) { + this.serviceCode = aOptions.serviceCode; + this.statusMessage = aOptions.statusMessage; + this.additionalInformation = aOptions.additionalInformation; +} +MMIResult.prototype = { + __exposedProps__ : {serviceCode: 'r', + statusMessage: 'r', + additionalInformation: 'r'}, +}; + +function MobileConnectionProvider(aClientId, aRadioInterface) { + this._clientId = aClientId; + this._radioInterface = aRadioInterface; + this._operatorInfo = {}; + // An array of nsIMobileConnectionListener instances. + this._listeners = []; + + this.supportedNetworkTypes = this._getSupportedNetworkTypes(); + // These objects implement the nsIMobileConnectionInfo interface, + // although the actual implementation lives in the content process. So are + // the child attributes `network` and `cell`, which implement + // nsIMobileNetworkInfo and nsIMobileCellInfo respectively. + this.voiceInfo = {connected: false, + emergencyCallsOnly: false, + roaming: false, + network: null, + cell: null, + type: null, + signalStrength: null, + relSignalStrength: null}; + this.dataInfo = {connected: false, + emergencyCallsOnly: false, + roaming: false, + network: null, + cell: null, + type: null, + signalStrength: null, + relSignalStrength: null}; +} +MobileConnectionProvider.prototype = { + _clientId: null, + _radioInterface: null, + _operatorInfo: null, + _listeners: null, + + /** + * 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. + */ + _selectingNetwork: null, + + voiceInfo: null, + dataInfo: null, + iccId: null, + networkSelectMode: null, + radioState: null, + lastKnownNetwork: null, + lastKnownHomeNetwork: null, + supportedNetworkTypes: null, + + /** + * A utility function to dump debug message. + */ + _debug: function(aMessage) { + dump("MobileConnectionProvider[" + this._clientId + "]: " + aMessage + "\n"); + }, + + /** + * A utility function to get supportedNetworkTypes from system property. + */ + _getSupportedNetworkTypes: function() { + let key = "ro.moz.ril." + this._clientId + ".network_types"; + let supportedNetworkTypes = libcutils.property_get(key, "").split(","); + for (let type of supportedNetworkTypes) { + // If the value in system property is not valid, use the default one which + // is defined in ril_consts.js. + if (RIL.GECKO_SUPPORTED_NETWORK_TYPES.indexOf(type) < 0) { + if (DEBUG) { + this._debug("Unknown network type: " + type); + } + supportedNetworkTypes = + RIL.GECKO_SUPPORTED_NETWORK_TYPES_DEFAULT.split(","); + break; + } + } + if (DEBUG) { + this._debug("Supported Network Types: " + supportedNetworkTypes); + } + return supportedNetworkTypes; + }, + + /** + * Helper for guarding us against invalid reason values for call forwarding. + */ + _isValidCallForwardingReason: function(aReason) { + switch (aReason) { + case Ci.nsIMobileConnectionService.CALL_FORWARD_REASON_UNCONDITIONAL: + case Ci.nsIMobileConnectionService.CALL_FORWARD_REASON_MOBILE_BUSY: + case Ci.nsIMobileConnectionService.CALL_FORWARD_REASON_NO_REPLY: + case Ci.nsIMobileConnectionService.CALL_FORWARD_REASON_NOT_REACHABLE: + case Ci.nsIMobileConnectionService.CALL_FORWARD_REASON_ALL_CALL_FORWARDING: + case Ci.nsIMobileConnectionService.CALL_FORWARD_REASON_ALL_CONDITIONAL_CALL_FORWARDING: + return true; + default: + return false; + } + }, + + /** + * Helper for guarding us against invalid action values for call forwarding. + */ + _isValidCallForwardingAction: function(aAction) { + switch (aAction) { + case Ci.nsIMobileConnectionService.CALL_FORWARD_ACTION_DISABLE: + case Ci.nsIMobileConnectionService.CALL_FORWARD_ACTION_ENABLE: + case Ci.nsIMobileConnectionService.CALL_FORWARD_ACTION_REGISTRATION: + case Ci.nsIMobileConnectionService.CALL_FORWARD_ACTION_ERASURE: + return true; + default: + return false; + } + }, + + /** + * Helper for guarding us against invalid program values for call barring. + */ + _isValidCallBarringProgram: function(aProgram) { + switch (aProgram) { + case Ci.nsIMobileConnectionService.CALL_BARRING_PROGRAM_ALL_OUTGOING: + case Ci.nsIMobileConnectionService.CALL_BARRING_PROGRAM_OUTGOING_INTERNATIONAL: + case Ci.nsIMobileConnectionService.CALL_BARRING_PROGRAM_OUTGOING_INTERNATIONAL_EXCEPT_HOME: + case Ci.nsIMobileConnectionService.CALL_BARRING_PROGRAM_ALL_INCOMING: + case Ci.nsIMobileConnectionService.CALL_BARRING_PROGRAM_INCOMING_ROAMING: + return true; + default: + return false; + } + }, + + /** + * Helper for guarding us against invalid options for call barring. + */ + _isValidCallBarringOptions: function(aOptions, aUsedForSetting) { + if (!aOptions || aOptions.serviceClass == null || + !this._isValidCallBarringProgram(aOptions.program)) { + return false; + } + + // For setting callbarring options, |enabled| and |password| are required. + if (aUsedForSetting && + (aOptions.enabled == null || aOptions.password == null)) { + return false; + } + + return true; + }, + + /** + * Helper for guarding us against invalid mode for clir. + */ + _isValidClirMode: function(aMode) { + switch (aMode) { + case Ci.nsIMobileConnectionService.CLIR_DEFAULT: + case Ci.nsIMobileConnectionService.CLIR_INVOCATION: + case Ci.nsIMobileConnectionService.CLIR_SUPPRESSION: + return true; + default: + return false; + } + }, + + /** + * Fix the roaming. RIL can report roaming in some case it is not + * really the case. See bug 787967 + */ + _checkRoamingBetweenOperators: function(aNetworkInfo) { + // TODO: Bug 864489 - B2G RIL: use ipdl as IPC in MozIccManager + // Should get iccInfo from IccGonkProvider. + let iccInfo = this._radioInterface.rilContext.iccInfo; + let operator = aNetworkInfo.network; + let state = aNetworkInfo.state; + + if (!iccInfo || !operator || + state !== RIL.GECKO_MOBILE_CONNECTION_STATE_REGISTERED) { + return false; + } + + let spn = iccInfo.spn && iccInfo.spn.toLowerCase(); + let longName = operator.longName && operator.longName.toLowerCase(); + let shortName = operator.shortName && operator.shortName.toLowerCase(); + + let equalsLongName = longName && (spn == longName); + let equalsShortName = shortName && (spn == shortName); + let equalsMcc = iccInfo.mcc == operator.mcc; + + let newRoaming = aNetworkInfo.roaming && + !(equalsMcc && (equalsLongName || equalsShortName)); + if (newRoaming === aNetworkInfo.roaming) { + return false; + } + + aNetworkInfo.roaming = newRoaming; + return true; + }, + + _updateInfo: function(aDestInfo, aSrcInfo) { + let isUpdated = false; + for (let key in aSrcInfo) { + // For updating MobileConnectionInfo + if (key === "cell" && aSrcInfo.cell) { + if (!aDestInfo.cell) { + aDestInfo.cell = new MobileCellInfo(); + } + isUpdated = this._updateInfo(aDestInfo.cell, aSrcInfo.cell) || isUpdated; + } else if (aDestInfo[key] !== aSrcInfo[key]) { + isUpdated = true; + aDestInfo[key] = aSrcInfo[key]; + } + } + return isUpdated; + }, + + _rulesToCallForwardingOptions: function(aRules) { + for (let i = 0; i < aRules.length; i++) { + let info = new CallForwardingOptions(aRules[i]); + aRules[i] = info; + } + }, + + _dispatchNotifyError: function(aCallback, aErrorMsg) { + Services.tm.currentThread.dispatch(() => aCallback.notifyError(aErrorMsg), + Ci.nsIThread.DISPATCH_NORMAL); + }, + + 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) { + this._listeners.splice(index, 1); + } + }, + + deliverListenerEvent: function(aName, aArgs) { + let listeners = this._listeners.slice(); + for (let listener of listeners) { + if (listeners.indexOf(listener) === -1) { + continue; + } + let handler = listener[aName]; + if (typeof handler != "function") { + throw new Error("No handler for " + aName); + } + try { + handler.apply(listener, aArgs); + } catch (e) { + if (DEBUG) { + this._debug("listener for " + aName + " threw an exception: " + e); + } + } + } + }, + + updateVoiceInfo: function(aNewInfo, aBatch = false) { + let isUpdated = this._updateInfo(this.voiceInfo, aNewInfo); + + // Make sure we also reset the operator and signal strength information + // if we drop off the network. + if (this.voiceInfo.state !== RIL.GECKO_MOBILE_CONNECTION_STATE_REGISTERED) { + this.voiceInfo.cell = null; + this.voiceInfo.network = null; + this.voiceInfo.signalStrength = null; + this.voiceInfo.relSignalStrength = null; + } else { + this.voiceInfo.network = this._operatorInfo; + } + + // Check roaming state + isUpdated = this._checkRoamingBetweenOperators(this.voiceInfo) || isUpdated; + + if (isUpdated && !aBatch) { + this.deliverListenerEvent("notifyVoiceChanged"); + } + }, + + updateDataInfo: function(aNewInfo, aBatch = false) { + let isUpdated = false; + + // For the data connection, the `connected` flag indicates whether + // there's an active data call. We get correct `connected` state here. + let active = gNetworkManager.active; + aNewInfo.connected = false; + if (active && + active.type === Ci.nsINetworkInterface.NETWORK_TYPE_MOBILE && + active.serviceId === this._clientId) { + aNewInfo.connected = true; + } + + isUpdated = this._updateInfo(this.dataInfo, aNewInfo); + + // Make sure we also reset the operator and signal strength information + // if we drop off the network. + if (this.dataInfo.state !== RIL.GECKO_MOBILE_CONNECTION_STATE_REGISTERED) { + this.dataInfo.cell = null; + this.dataInfo.network = null; + this.dataInfo.signalStrength = null; + this.dataInfo.relSignalStrength = null; + } else { + this.dataInfo.network = this._operatorInfo; + } + + // Check roaming state + isUpdated = this._checkRoamingBetweenOperators(this.dataInfo) || isUpdated; + + if (isUpdated && !aBatch) { + this.deliverListenerEvent("notifyDataChanged"); + } + }, + + updateOperatorInfo: function(aNewInfo, aBatch = false) { + let isUpdated = this._updateInfo(this._operatorInfo, aNewInfo); + + // Update lastKnownNetwork + if (this._operatorInfo.mcc && this._operatorInfo.mnc) { + let network = this._operatorInfo.mcc + "-" + this._operatorInfo.mnc; + if (this.lastKnownNetwork !== network) { + if (DEBUG) { + this._debug("lastKnownNetwork now is " + network); + } + + this.lastKnownNetwork = network; + this.deliverListenerEvent("notifyLastKnownNetworkChanged"); + } + } + + // If the voice is unregistered, no need to send notification. + if (this.voiceInfo.state !== RIL.GECKO_MOBILE_CONNECTION_STATE_REGISTERED && + isUpdated && !aBatch) { + this.deliverListenerEvent("notifyVoiceChanged"); + } + + // If the data is unregistered, no need to send notification. + if (this.dataInfo.state !== RIL.GECKO_MOBILE_CONNECTION_STATE_REGISTERED && + isUpdated && !aBatch) { + this.deliverListenerEvent("notifyDataChanged"); + } + }, + + updateSignalInfo: function(aNewInfo, aBatch = false) { + // If the voice is not registered, no need to update signal information. + if (this.voiceInfo.state === RIL.GECKO_MOBILE_CONNECTION_STATE_REGISTERED) { + if (this._updateInfo(this.voiceInfo, aNewInfo.voice) && !aBatch) { + this.deliverListenerEvent("notifyVoiceChanged"); + } + } + + // If the data is not registered, no need to update signal information. + if (this.dataInfo.state === RIL.GECKO_MOBILE_CONNECTION_STATE_REGISTERED) { + if (this._updateInfo(this.dataInfo, aNewInfo.data) && !aBatch) { + this.deliverListenerEvent("notifyDataChanged"); + } + } + }, + + updateIccId: function(aIccId) { + if (this.iccId === aIccId) { + return; + } + + this.iccId = aIccId; + this.deliverListenerEvent("notifyIccChanged"); + }, + + updateRadioState: function(aRadioState) { + if (this.radioState === aRadioState) { + return; + } + + this.radioState = aRadioState; + this.deliverListenerEvent("notifyRadioStateChanged"); + }, + + getNetworks: function(aCallback) { + this._radioInterface.sendWorkerMessage("getAvailableNetworks", null, + (function(aResponse) { + if (aResponse.errorMsg) { + aCallback.notifyError(aResponse.errorMsg); + return false; + } + + let networks = aResponse.networks; + for (let i = 0; i < networks.length; i++) { + let info = new MobileNetworkInfo(); + this._updateInfo(info, networks[i]); + networks[i] = info; + } + + aCallback.notifyGetNetworksSuccess(networks.length, networks); + return false; + }).bind(this)); + }, + + selectNetwork: function(aNetwork, aCallback) { + if (!aNetwork || + isNaN(parseInt(aNetwork.mcc, 10)) || + isNaN(parseInt(aNetwork.mnc, 10))) { + this._dispatchNotifyError(aCallback, RIL.GECKO_ERROR_INVALID_PARAMETER); + return; + } + + if (this._selectingNetwork) { + this._dispatchNotifyError(aCallback, "AlreadySelectingANetwork"); + return; + } + + let options = {mcc: aNetwork.mcc, mnc: aNetwork.mnc}; + this._selectingNetwork = options; + this._radioInterface.sendWorkerMessage("selectNetwork", options, + (function(aResponse) { + this._selectingNetwork = null; + if (aResponse.errorMsg) { + aCallback.notifyError(aResponse.errorMsg); + return false; + } + + aCallback.notifySuccess(); + return false; + }).bind(this)); + }, + + selectNetworkAutomatically: function(aCallback) { + if (this._selectingNetwork) { + this._dispatchNotifyError(aCallback, "AlreadySelectingANetwork"); + return; + } + + this._selectingNetwork = "automatic"; + this._radioInterface.sendWorkerMessage("selectNetworkAuto", null, + (function(aResponse) { + this._selectingNetwork = null; + if (aResponse.errorMsg) { + aCallback.notifyError(aResponse.errorMsg); + return false; + } + + aCallback.notifySuccess(); + return false; + }).bind(this)); + }, + + setPreferredNetworkType: function(aType, aCallback) { + if (this.radioState !== RIL.GECKO_RADIOSTATE_ENABLED) { + this._dispatchNotifyError(aCallback, RIL.GECKO_ERROR_RADIO_NOT_AVAILABLE); + return; + } + + this._radioInterface.sendWorkerMessage("setPreferredNetworkType", + {type: aType}, + (function(aResponse) { + if (aResponse.errorMsg) { + aCallback.notifyError(aResponse.errorMsg); + return false; + } + + aCallback.notifySuccess(); + return false; + }).bind(this)); + }, + + getPreferredNetworkType: function(aCallback) { + if (this.radioState !== RIL.GECKO_RADIOSTATE_ENABLED) { + this._dispatchNotifyError(aCallback, RIL.GECKO_ERROR_RADIO_NOT_AVAILABLE); + return; + } + + this._radioInterface.sendWorkerMessage("getPreferredNetworkType", null, + (function(aResponse) { + if (aResponse.errorMsg) { + aCallback.notifyError(aResponse.errorMsg); + return false; + } + + aCallback.notifySuccessWithString(aResponse.type); + return false; + }).bind(this)); + }, + + setRoamingPreference: function(aMode, aCallback) { + this._radioInterface.sendWorkerMessage("setRoamingPreference", + {mode: aMode}, + (function(aResponse) { + if (aResponse.errorMsg) { + aCallback.notifyError(aResponse.errorMsg); + return false; + } + + aCallback.notifySuccess(); + return false; + }).bind(this)); + }, + + getRoamingPreference: function(aCallback) { + this._radioInterface.sendWorkerMessage("queryRoamingPreference", null, + (function(aResponse) { + if (aResponse.errorMsg) { + aCallback.notifyError(aResponse.errorMsg); + return false; + } + + aCallback.notifySuccessWithString(aResponse.mode); + return false; + }).bind(this)); + }, + + setVoicePrivacyMode: function(aEnabled, aCallback) { + this._radioInterface.sendWorkerMessage("setVoicePrivacyMode", + {enabled: aEnabled}, + (function(aResponse) { + if (aResponse.errorMsg) { + aCallback.notifyError(aResponse.errorMsg); + return false; + } + + aCallback.notifySuccess(); + return false; + }).bind(this)); + }, + + getVoicePrivacyMode: function(aCallback) { + this._radioInterface.sendWorkerMessage("queryVoicePrivacyMode", null, + (function(aResponse) { + if (aResponse.errorMsg) { + aCallback.notifyError(aResponse.errorMsg); + return false; + } + + aCallback.notifySuccessWithBoolean(aResponse.enabled); + return false; + }).bind(this)); + }, + + sendMMI: function(aMmi, aCallback) { + this._radioInterface.sendWorkerMessage("sendMMI", {mmi: aMmi}, + (function(aResponse) { + aResponse.serviceCode = aResponse.mmiServiceCode || ""; + // We expect to have an IMEI at this point if the request was supposed + // to query for the IMEI, so getting a successful reply from the RIL + // without containing an actual IMEI number is considered an error. + if (aResponse.serviceCode === RIL.MMI_KS_SC_IMEI && + !aResponse.statusMessage) { + aResponse.errorMsg = aResponse.errorMsg || + RIL.GECKO_ERROR_GENERIC_FAILURE; + } + + if (aResponse.errorMsg) { + if (aResponse.additionalInformation) { + aCallback.notifyError(aResponse.errorMsg, "", + aResponse.serviceCode, + aResponse.additionalInformation); + } else { + aCallback.notifyError(aResponse.errorMsg, "", + aResponse.serviceCode); + } + return false; + } + + if (aResponse.isSetCallForward) { + this.deliverListenerEvent("notifyCFStateChanged", + [!aResponse.errorMsg, aResponse.action, + aResponse.reason, aResponse.number, + aResponse.timeSeconds, aResponse.serviceClass]); + } + + // MMI query call forwarding options request returns a set of rules that + // will be exposed in the form of an array of MozCallForwardingOptions + // instances. + if (aResponse.serviceCode === RIL.MMI_KS_SC_CALL_FORWARDING && + aResponse.additionalInformation) { + this._rulesToCallForwardingOptions(aResponse.additionalInformation); + } + + let mmiResult = new MMIResult(aResponse); + aCallback.notifySendCancelMmiSuccess(mmiResult); + return false; + }).bind(this)); + }, + + cancelMMI: function(aCallback) { + this._radioInterface.sendWorkerMessage("cancelUSSD", null, + (function(aResponse) { + if (aResponse.errorMsg) { + aCallback.notifyError(aResponse.errorMsg); + return false; + } + + aCallback.notifySuccess(); + return false; + }).bind(this)); + }, + + setCallForwarding: function(aOptions, aCallback) { + if (!aOptions || + !this._isValidCallForwardingReason(aOptions.reason) || + !this._isValidCallForwardingAction(aOptions.action)){ + this._dispatchNotifyError(aCallback, RIL.GECKO_ERROR_INVALID_PARAMETER); + return; + } + + let options = { + active: aOptions.active, + action: aOptions.action, + reason: aOptions.reason, + number: aOptions.number, + timeSeconds: aOptions.timeSeconds, + serviceClass: RIL.ICC_SERVICE_CLASS_VOICE + }; + + this._radioInterface.sendWorkerMessage("setCallForward", options, + (function(aResponse) { + if (aResponse.errorMsg) { + aCallback.notifyError(aResponse.errorMsg); + return false; + } + + this.deliverListenerEvent("notifyCFStateChanged", + [!aResponse.errorMsg, aResponse.action, + aResponse.reason, aResponse.number, + aResponse.timeSeconds, aResponse.serviceClass]); + + aCallback.notifySuccess(); + return false; + }).bind(this)); + }, + + getCallForwarding: function(aReason, aCallback) { + if (!this._isValidCallForwardingReason(aReason)){ + this._dispatchNotifyError(aCallback, RIL.GECKO_ERROR_INVALID_PARAMETER); + return; + } + + this._radioInterface.sendWorkerMessage("queryCallForwardStatus", + {reason: aReason}, + (function(aResponse) { + if (aResponse.errorMsg) { + aCallback.notifyError(aResponse.errorMsg); + return false; + } + + let infos = aResponse.rules; + this._rulesToCallForwardingOptions(infos); + aCallback.notifyGetCallForwardingSuccess(infos); + return false; + }).bind(this)); + }, + + setCallBarring: function(aOptions, aCallback) { + if (!this._isValidCallBarringOptions(aOptions, true)) { + this._dispatchNotifyError(aCallback, RIL.GECKO_ERROR_INVALID_PARAMETER); + return; + } + + let options = { + program: aOptions.program, + enabled: aOptions.enabled, + password: aOptions.password, + serviceClass: aOptions.serviceClass + }; + + this._radioInterface.sendWorkerMessage("setCallBarring", options, + (function(aResponse) { + if (aResponse.errorMsg) { + aCallback.notifyError(aResponse.errorMsg); + return false; + } + + aCallback.notifySuccess(); + return false; + }).bind(this)); + }, + + getCallBarring: function(aOptions, aCallback) { + if (!this._isValidCallBarringOptions(aOptions)) { + this._dispatchNotifyError(aCallback, RIL.GECKO_ERROR_INVALID_PARAMETER); + return; + } + + let options = { + program: aOptions.program, + password: aOptions.password, + serviceClass: aOptions.serviceClass + }; + + this._radioInterface.sendWorkerMessage("queryCallBarringStatus", options, + (function(aResponse) { + if (aResponse.errorMsg) { + aCallback.notifyError(aResponse.errorMsg); + return false; + } + + aCallback.notifyGetCallBarringSuccess(aResponse.program, + aResponse.enabled, + aResponse.serviceClass); + return false; + }).bind(this)); + }, + + changeCallBarringPassword: function(aOptions, aCallback) { + // Checking valid PIN for supplementary services. See TS.22.004 clause 5.2. + if (aOptions.pin == null || !aOptions.pin.match(/^\d{4}$/) || + aOptions.newPin == null || !aOptions.newPin.match(/^\d{4}$/)) { + this._dispatchNotifyError(aCallback, "InvalidPassword"); + return; + } + + let options = { + pin: aOptions.pin, + newPin: aOptions.newPin + }; + + this._radioInterface.sendWorkerMessage("changeCallBarringPassword", options, + (function(aResponse) { + if (aResponse.errorMsg) { + aCallback.notifyError(aResponse.errorMsg); + return false; + } + + aCallback.notifySuccess(); + return false; + }).bind(this)); + }, + + setCallWaiting: function(aEnabled, aCallback) { + this._radioInterface.sendWorkerMessage("setCallWaiting", + {enabled: aEnabled}, + (function(aResponse) { + if (aResponse.errorMsg) { + aCallback.notifyError(aResponse.errorMsg); + return false; + } + + aCallback.notifySuccess(); + return false; + }).bind(this)); + }, + + getCallWaiting: function(aCallback) { + this._radioInterface.sendWorkerMessage("queryCallWaiting", null, + (function(aResponse) { + if (aResponse.errorMsg) { + aCallback.notifyError(aResponse.errorMsg); + return false; + } + + aCallback.notifySuccessWithBoolean(aResponse.enabled); + return false; + }).bind(this)); + }, + + setCallingLineIdRestriction: function(aMode, aCallback) { + if (!this._isValidClirMode(aMode)) { + this._dispatchNotifyError(aCallback, RIL.GECKO_ERROR_INVALID_PARAMETER); + return; + } + + if (this.radioState !== RIL.GECKO_RADIOSTATE_ENABLED) { + this._dispatchNotifyError(aCallback, RIL.GECKO_ERROR_RADIO_NOT_AVAILABLE); + return; + } + + this._radioInterface.sendWorkerMessage("setCLIR", {clirMode: aMode}, + (function(aResponse) { + if (aResponse.errorMsg) { + aCallback.notifyError(aResponse.errorMsg); + return false; + } + + this.deliverListenerEvent("notifyClirModeChanged", [aResponse.mode]); + aCallback.notifySuccess(); + return false; + }).bind(this)); + }, + + getCallingLineIdRestriction: function(aCallback) { + if (this.radioState !== RIL.GECKO_RADIOSTATE_ENABLED) { + this._dispatchNotifyError(aCallback, RIL.GECKO_ERROR_RADIO_NOT_AVAILABLE); + return; + } + + this._radioInterface.sendWorkerMessage("getCLIR", null, + (function(aResponse) { + if (aResponse.errorMsg) { + aCallback.notifyError(aResponse.errorMsg); + return false; + } + + aCallback.notifyGetClirStatusSuccess(aResponse.n, aResponse.m); + return false; + }).bind(this)); + }, + + exitEmergencyCbMode: function(aCallback) { + this._radioInterface.sendWorkerMessage("exitEmergencyCbMode", null, + (function(aResponse) { + if (aResponse.errorMsg) { + aCallback.notifyError(aResponse.errorMsg); + return false; + } + + aCallback.notifySuccess(); + return false; + }).bind(this)); + }, + + setRadioEnabled: function(aEnabled, aCallback) { + this._radioInterface.sendWorkerMessage("setRadioEnabled", + {enabled: aEnabled}, + (function(aResponse) { + if (aResponse.errorMsg) { + aCallback.notifyError(aResponse.errorMsg); + return true; + } + + aCallback.notifySuccess(); + return true; + }).bind(this)); + }, +}; + +function MobileConnectionGonkService() { + this._providers = []; + + let numClients = gRadioInterfaceLayer.numRadioInterfaces; + for (let i = 0; i < numClients; i++) { + let radioInterface = gRadioInterfaceLayer.getRadioInterface(i); + let provider = new MobileConnectionProvider(i, radioInterface); + this._providers.push(provider); + } + + Services.prefs.addObserver(kPrefRilDebuggingEnabled, this, false); + Services.obs.addObserver(this, NS_NETWORK_ACTIVE_CHANGED_TOPIC_ID, false); + Services.obs.addObserver(this, NS_XPCOM_SHUTDOWN_OBSERVER_ID, false); + + debug("init complete"); +} +MobileConnectionGonkService.prototype = { + classID: MOBILECONNECTIONGONKSERVICE_CID, + classInfo: XPCOMUtils.generateCI({classID: MOBILECONNECTIONGONKSERVICE_CID, + contractID: MOBILECONNECTIONGONKSERVICE_CONTRACTID, + classDescription: "MobileConnectionGonkService", + interfaces: [Ci.nsIMobileConnectionGonkService, + Ci.nsIMobileConnectionService], + flags: Ci.nsIClassInfo.SINGLETON}), + QueryInterface: XPCOMUtils.generateQI([Ci.nsIMobileConnectionGonkService, + Ci.nsIMobileConnectionService, + Ci.nsIObserver]), + + // An array of MobileConnectionProvider instances. + _providers: null, + + _shutdown: function() { + Services.prefs.removeObserver(kPrefRilDebuggingEnabled, this); + Services.obs.removeObserver(this, NS_NETWORK_ACTIVE_CHANGED_TOPIC_ID); + Services.obs.removeObserver(this, NS_XPCOM_SHUTDOWN_OBSERVER_ID); + }, + + _updateDebugFlag: function() { + try { + DEBUG = RIL.DEBUG_RIL || + Services.prefs.getBoolPref(kPrefRilDebuggingEnabled); + } catch (e) {} + }, + + /** + * nsIMobileConnectionService interface. + */ + registerListener: function(aClientId, aListener) { + let provider = this._providers[aClientId]; + if (!provider) { + throw Cr.NS_ERROR_UNEXPECTED; + } + + provider.registerListener(aListener); + }, + + unregisterListener: function(aClientId, aListener) { + let provider = this._providers[aClientId]; + if (!provider) { + throw Cr.NS_ERROR_UNEXPECTED; + } + + provider.unregisterListener(aListener); + }, + + getVoiceConnectionInfo: function(aClientId) { + let provider = this._providers[aClientId]; + if (!provider) { + throw Cr.NS_ERROR_UNEXPECTED; + } + + return provider.voiceInfo; + }, + + getDataConnectionInfo: function(aClientId) { + let provider = this._providers[aClientId]; + if (!provider) { + throw Cr.NS_ERROR_UNEXPECTED; + } + + return provider.dataInfo; + }, + + getIccId: function(aClientId) { + let provider = this._providers[aClientId]; + if (!provider) { + throw Cr.NS_ERROR_UNEXPECTED; + } + + return provider.iccId; + }, + + getNetworkSelectionMode: function(aClientId) { + let provider = this._providers[aClientId]; + if (!provider) { + throw Cr.NS_ERROR_UNEXPECTED; + } + + return provider.networkSelectMode; + }, + + getRadioState: function(aClientId) { + let provider = this._providers[aClientId]; + if (!provider) { + throw Cr.NS_ERROR_UNEXPECTED; + } + + return provider.radioState; + }, + + getLastKnownNetwork: function(aClientId) { + let provider = this._providers[aClientId]; + if (!provider) { + throw Cr.NS_ERROR_UNEXPECTED; + } + + return provider.lastKnownNetwork; + }, + + getLastKnownHomeNetwork: function(aClientId) { + let provider = this._providers[aClientId]; + if (!provider) { + throw Cr.NS_ERROR_UNEXPECTED; + } + + return provider.lastKnownHomeNetwork; + }, + + getSupportedNetworkTypes: function(aClientId) { + let provider = this._providers[aClientId]; + if (!provider) { + throw Cr.NS_ERROR_UNEXPECTED; + } + + return provider.supportedNetworkTypes; + }, + + getNetworks: function(aClientId, aCallback) { + let provider = this._providers[aClientId]; + if (!provider) { + throw Cr.NS_ERROR_UNEXPECTED; + } + + provider.getNetworks(aCallback); + }, + + selectNetwork: function(aClientId, aNetwork, aCallback) { + let provider = this._providers[aClientId]; + if (!provider) { + throw Cr.NS_ERROR_UNEXPECTED; + } + + provider.selectNetwork(aNetwork, aCallback); + }, + + selectNetworkAutomatically: function(aClientId, aCallback) { + let provider = this._providers[aClientId]; + if (!provider) { + throw Cr.NS_ERROR_UNEXPECTED; + } + + provider.selectNetworkAutomatically(aCallback); + }, + + setPreferredNetworkType: function(aClientId, aType, aCallback) { + let provider = this._providers[aClientId]; + if (!provider) { + throw Cr.NS_ERROR_UNEXPECTED; + } + + provider.setPreferredNetworkType(aType, aCallback); + }, + + getPreferredNetworkType: function(aClientId, aCallback) { + let provider = this._providers[aClientId]; + if (!provider) { + throw Cr.NS_ERROR_UNEXPECTED; + } + + provider.getPreferredNetworkType(aCallback); + }, + + setRoamingPreference: function(aClientId, aMode, aCallback) { + let provider = this._providers[aClientId]; + if (!provider) { + throw Cr.NS_ERROR_UNEXPECTED; + } + + provider.setRoamingPreference(aMode, aCallback); + }, + + getRoamingPreference: function(aClientId, aCallback) { + let provider = this._providers[aClientId]; + if (!provider) { + throw Cr.NS_ERROR_UNEXPECTED; + } + + provider.getRoamingPreference(aCallback); + }, + + setVoicePrivacyMode: function(aClientId, aEnabled, aCallback) { + let provider = this._providers[aClientId]; + if (!provider) { + throw Cr.NS_ERROR_UNEXPECTED; + } + + provider.setVoicePrivacyMode(aEnabled, aCallback); + }, + + getVoicePrivacyMode: function(aClientId, aCallback) { + let provider = this._providers[aClientId]; + if (!provider) { + throw Cr.NS_ERROR_UNEXPECTED; + } + + provider.getVoicePrivacyMode(aCallback); + }, + + sendMMI: function(aClientId, aMmi, aCallback) { + let provider = this._providers[aClientId]; + if (!provider) { + throw Cr.NS_ERROR_UNEXPECTED; + } + + provider.sendMMI(aMmi, aCallback); + }, + + cancelMMI: function(aClientId, aCallback) { + let provider = this._providers[aClientId]; + if (!provider) { + throw Cr.NS_ERROR_UNEXPECTED; + } + + provider.cancelMMI(aCallback); + }, + + setCallForwarding: function(aClientId, aOptions, aCallback) { + let provider = this._providers[aClientId]; + if (!provider) { + throw Cr.NS_ERROR_UNEXPECTED; + } + + provider.setCallForwarding(aOptions, aCallback); + }, + + getCallForwarding: function(aClientId, aReason, aCallback) { + let provider = this._providers[aClientId]; + if (!provider) { + throw Cr.NS_ERROR_UNEXPECTED; + } + + provider.getCallForwarding(aReason, aCallback); + }, + + setCallBarring: function(aClientId, aOptions, aCallback) { + let provider = this._providers[aClientId]; + if (!provider) { + throw Cr.NS_ERROR_UNEXPECTED; + } + + provider.setCallBarring(aOptions, aCallback); + }, + + getCallBarring: function(aClientId, aOptions, aCallback) { + let provider = this._providers[aClientId]; + if (!provider) { + throw Cr.NS_ERROR_UNEXPECTED; + } + + provider.getCallBarring(aOptions, aCallback); + }, + + changeCallBarringPassword: function(aClientId, aOptions, aCallback) { + let provider = this._providers[aClientId]; + if (!provider) { + throw Cr.NS_ERROR_UNEXPECTED; + } + + provider.changeCallBarringPassword(aOptions, aCallback); + }, + + setCallWaiting: function(aClientId, aEnabled, aCallback) { + let provider = this._providers[aClientId]; + if (!provider) { + throw Cr.NS_ERROR_UNEXPECTED; + } + + provider.setCallWaiting(aEnabled, aCallback); + }, + + getCallWaiting: function(aClientId, aCallback) { + let provider = this._providers[aClientId]; + if (!provider) { + throw Cr.NS_ERROR_UNEXPECTED; + } + + provider.getCallWaiting(aCallback); + }, + + setCallingLineIdRestriction: function(aClientId, aMode, aCallback) { + let provider = this._providers[aClientId]; + if (!provider) { + throw Cr.NS_ERROR_UNEXPECTED; + } + + provider.setCallingLineIdRestriction(aMode, aCallback); + }, + + getCallingLineIdRestriction: function(aClientId, aCallback) { + let provider = this._providers[aClientId]; + if (!provider) { + throw Cr.NS_ERROR_UNEXPECTED; + } + + provider.getCallingLineIdRestriction(aCallback); + }, + + exitEmergencyCbMode: function(aClientId, aCallback) { + let provider = this._providers[aClientId]; + if (!provider) { + throw Cr.NS_ERROR_UNEXPECTED; + } + + provider.exitEmergencyCbMode(aCallback); + }, + + setRadioEnabled: function(aClientId, aEnabled, aCallback) { + let provider = this._providers[aClientId]; + if (!provider) { + throw Cr.NS_ERROR_UNEXPECTED; + } + + provider.setRadioEnabled(aEnabled, aCallback); + }, + + /** + * nsIMobileConnectionGonkService interface. + */ + notifyVoiceInfoChanged: function(aClientId, aVoiceInfo) { + if (DEBUG) { + debug("notifyVoiceInfoChanged for " + aClientId + ": " + + JSON.stringify(aVoiceInfo)); + } + + let provider = this._providers[aClientId]; + if (!provider) { + throw Cr.NS_ERROR_UNEXPECTED; + } + + provider.updateVoiceInfo(aVoiceInfo); + }, + + notifyDataInfoChanged: function(aClientId, aDataInfo) { + if (DEBUG) { + debug("notifyDataInfoChanged for " + aClientId + ": " + + JSON.stringify(aDataInfo)); + } + + let provider = this._providers[aClientId]; + if (!provider) { + throw Cr.NS_ERROR_UNEXPECTED; + } + + provider.updateDataInfo(aDataInfo); + }, + + notifyUssdReceived: function(aClientId, aMessage, aSessionEnded) { + if (DEBUG) { + debug("notifyUssdReceived for " + aClientId + ": " + + JSON.stringify(ussd)); + } + + let provider = this._providers[aClientId]; + if (!provider) { + throw Cr.NS_ERROR_UNEXPECTED; + } + + provider.deliverListenerEvent("notifyUssdReceived", + [aMessage, aSessionEnded]); + + let info = { + message: aMessage, + sessionEnded: aSessionEnded, + serviceId: aClientId + }; + + gSystemMessenger.broadcastMessage("ussd-received", info); + }, + + notifyDataError: function(aClientId, aMessage) { + if (DEBUG) { + debug("notifyDataError for " + aClientId + ": " + aMessage); + } + + let provider = this._providers[aClientId]; + if (!provider) { + throw Cr.NS_ERROR_UNEXPECTED; + } + + provider.deliverListenerEvent("notifyDataError", [aMessage]); + }, + + notifyEmergencyCallbackModeChanged: function(aClientId, aActive, aTimeoutMs) { + if (DEBUG) { + debug("notifyEmergencyCbModeChanged for " + aClientId + ": " + + JSON.stringify({active: aActive, timeoutMs: aTimeoutMs})); + } + + let provider = this._providers[aClientId]; + if (!provider) { + throw Cr.NS_ERROR_UNEXPECTED; + } + + provider.deliverListenerEvent("notifyEmergencyCbModeChanged", + [aActive, aTimeoutMs]); + }, + + notifyOtaStatusChanged: function(aClientId, aStatus) { + if (DEBUG) { + debug("notifyOtaStatusChanged for " + aClientId + ": " + aStatus); + } + + let provider = this._providers[aClientId]; + if (!provider) { + throw Cr.NS_ERROR_UNEXPECTED; + } + + provider.deliverListenerEvent("notifyOtaStatusChanged", [aStatus]); + }, + + notifyIccChanged: function(aClientId, aIccId) { + if (DEBUG) { + debug("notifyIccChanged for " + aClientId + ": " + aIccId); + } + + let provider = this._providers[aClientId]; + if (!provider) { + throw Cr.NS_ERROR_UNEXPECTED; + } + + provider.updateIccId(aIccId); + }, + + notifyRadioStateChanged: function(aClientId, aRadioState) { + if (DEBUG) { + debug("notifyRadioStateChanged for " + aClientId + ": " + aRadioState); + } + + let provider = this._providers[aClientId]; + if (!provider) { + throw Cr.NS_ERROR_UNEXPECTED; + } + + provider.updateRadioState(aRadioState); + }, + + notifyNetworkInfoChanged: function(aClientId, aNetworkInfo) { + if (DEBUG) { + debug("notifyNetworkInfoChanged for " + aClientId + ": " + + JSON.stringify(aNetworkInfo)); + } + + let provider = this._providers[aClientId]; + if (!provider) { + throw Cr.NS_ERROR_UNEXPECTED; + } + + let isVoiceUpdated = false; + let isDataUpdated = false; + let operatorMessage = aNetworkInfo[RIL.NETWORK_INFO_OPERATOR]; + let voiceMessage = aNetworkInfo[RIL.NETWORK_INFO_VOICE_REGISTRATION_STATE]; + let dataMessage = aNetworkInfo[RIL.NETWORK_INFO_DATA_REGISTRATION_STATE]; + let signalMessage = aNetworkInfo[RIL.NETWORK_INFO_SIGNAL]; + let selectionMessage = aNetworkInfo[RIL.NETWORK_INFO_NETWORK_SELECTION_MODE]; + + // Batch the *InfoChanged messages together + if (operatorMessage) { + provider.updateOperatorInfo(operatorMessage, true); + } + + if (voiceMessage) { + provider.updateVoiceInfo(voiceMessage, true); + } + + if (dataMessage) { + provider.updateDataInfo(dataMessage, true); + } + + if (signalMessage) { + provider.updateSignalInfo(signalMessage, true); + } + + if (selectionMessage) { + this.notifyNetworkSelectModeChanged(aClientId, selectionMessage.mode); + } + + if (voiceMessage || operatorMessage || signalMessage) { + provider.deliverListenerEvent("notifyVoiceChanged"); + } + + if (dataMessage || operatorMessage || signalMessage) { + provider.deliverListenerEvent("notifyDataChanged"); + } + }, + + notifySignalStrengthChanged: function(aClientId, aSignal) { + if (DEBUG) { + debug("notifySignalStrengthChanged for " + aClientId + ": " + + JSON.stringify(aSignal)); + } + + let provider = this._providers[aClientId]; + if (!provider) { + throw Cr.NS_ERROR_UNEXPECTED; + } + + provider.updateSignalInfo(aSignal); + }, + + notifyOperatorChanged: function(aClientId, aOperator) { + if (DEBUG) { + debug("notifyOperatorChanged for " + aClientId + ": " + + JSON.stringify(aOperator)); + } + + let provider = this._providers[aClientId]; + if (!provider) { + throw Cr.NS_ERROR_UNEXPECTED; + } + + provider.updateOperatorInfo(aOperator); + }, + + notifyNetworkSelectModeChanged: function(aClientId, aMode) { + if (DEBUG) { + debug("notifyNetworkSelectModeChanged for " + aClientId + ": " + aMode); + } + + let provider = this._providers[aClientId]; + if (!provider) { + throw Cr.NS_ERROR_UNEXPECTED; + } + + if (provider.networkSelectMode === aMode) { + return; + } + + provider.networkSelectMode = aMode; + provider.deliverListenerEvent("notifyNetworkSelectionModeChanged"); + }, + + notifySpnAvailable: function(aClientId) { + if (DEBUG) { + debug("notifySpnAvailable for " + aClientId); + } + + let provider = this._providers[aClientId]; + if (!provider) { + throw Cr.NS_ERROR_UNEXPECTED; + } + + // Update voice roaming state + provider.updateVoiceInfo({}); + + // Update data roaming state + provider.updateDataInfo({}); + }, + + notifyLastHomeNetworkChanged: function(aClientId, aNetwork) { + if (DEBUG) { + debug("notifyLastHomeNetworkChanged for " + aClientId + ": " + aNetwork); + } + + let provider = this._providers[aClientId]; + if (!provider) { + throw Cr.NS_ERROR_UNEXPECTED; + } + + if (provider.lastKnownHomeNetwork === aNetwork) { + return; + } + + provider.lastKnownHomeNetwork = aNetwork; + provider.deliverListenerEvent("notifyLastKnownHomeNetworkChanged"); + }, + + /** + * nsIObserver interface. + */ + observe: function(aSubject, aTopic, aData) { + switch (aTopic) { + case NS_NETWORK_ACTIVE_CHANGED_TOPIC_ID: + for (let i = 0; i < this._providers.length; i++) { + let provider = this._providers[i]; + // Update connected flag only. + provider.updateDataInfo({}); + } + break; + case NS_PREFBRANCH_PREFCHANGE_TOPIC_ID: + if (aData === kPrefRilDebuggingEnabled) { + this._updateDebugFlag(); + } + break; + case NS_XPCOM_SHUTDOWN_OBSERVER_ID: + this._shutdown(); + break; + } + } +}; + +this.NSGetFactory = XPCOMUtils.generateNSGetFactory([MobileConnectionGonkService]);
new file mode 100644 --- /dev/null +++ b/dom/mobileconnection/gonk/MobileConnectionGonkService.manifest @@ -0,0 +1,2 @@ +component {05e20430-fe65-4984-8df9-a6a504b24a91} MobileConnectionGonkService.js +contract @mozilla.org/mobileconnection/mobileconnectiongonkservice;1 {05e20430-fe65-4984-8df9-a6a504b24a91}
--- a/dom/mobileconnection/interfaces/moz.build +++ b/dom/mobileconnection/interfaces/moz.build @@ -3,14 +3,19 @@ # 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/. XPIDL_SOURCES += [ 'nsICellInfo.idl', 'nsIMobileCellInfo.idl', 'nsIMobileConnectionInfo.idl', - 'nsIMobileConnectionProvider.idl', + 'nsIMobileConnectionService.idl', 'nsIMobileNetworkInfo.idl', 'nsINeighboringCellInfo.idl', ] +if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'gonk' and CONFIG['MOZ_B2G_RIL']: + XPIDL_SOURCES += [ + 'nsIMobileConnectionGonkService.idl', + ] + XPIDL_MODULE = 'dom_mobileconnection'
new file mode 100644 --- /dev/null +++ b/dom/mobileconnection/interfaces/nsIMobileConnectionGonkService.idl @@ -0,0 +1,49 @@ +/* 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/. */ + +#include "nsIMobileConnectionService.idl" + +%{C++ +#define NS_MOBILECONNECTION_GONK_SERVICE_CONTRACTID \ + "@mozilla.org/mobileconnection/mobileconnectiongonkservice;1" +%} + +[scriptable, uuid(c5baceda-247a-4018-855d-ad5b00f2e4e2)] +interface nsIMobileConnectionGonkService : nsIMobileConnectionService +{ + void notifyNetworkInfoChanged(in unsigned long clientId, in jsval networkInfo); + + void notifyVoiceInfoChanged(in unsigned long clientId, in jsval voiceInfo); + + void notifyDataInfoChanged(in unsigned long clientId, in jsval dataInfo); + + void notifyDataError(in unsigned long clientId, in DOMString message); + + void notifySignalStrengthChanged(in unsigned long clientId, in jsval signal); + + void notifyOperatorChanged(in unsigned long clientId, in jsval info); + + void notifyOtaStatusChanged(in unsigned long clientId, in DOMString status); + + void notifyRadioStateChanged(in unsigned long clientId, + in DOMString radioState); + + void notifyUssdReceived(in unsigned long clientId, + in DOMString message, + in boolean sessionEnded); + + void notifyEmergencyCallbackModeChanged(in unsigned long clientId, + in boolean active, + in unsigned long timeoutMs); + + void notifyIccChanged(in unsigned long clientId, in DOMString iccId); + + void notifyNetworkSelectModeChanged(in unsigned long clientId, + in DOMString mode); + + void notifySpnAvailable(in unsigned long clientId); + + void notifyLastHomeNetworkChanged(in unsigned long clientId, + in DOMString network); +};
rename from dom/mobileconnection/interfaces/nsIMobileConnectionProvider.idl rename to dom/mobileconnection/interfaces/nsIMobileConnectionService.idl --- a/dom/mobileconnection/interfaces/nsIMobileConnectionProvider.idl +++ b/dom/mobileconnection/interfaces/nsIMobileConnectionService.idl @@ -1,21 +1,19 @@ /* 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/. */ #include "nsISupports.idl" -interface nsIDOMDOMRequest; -interface nsIDOMWindow; interface nsIMobileConnectionInfo; interface nsIMobileNetworkInfo; interface nsIVariant; -[scriptable, uuid(c6d98e6a-d96f-45fe-aa86-01453a6daf9e)] +[scriptable, uuid(bc0d4d76-fd3a-4593-818f-cb6ff87fbb55)] interface nsIMobileConnectionListener : nsISupports { /** * Notify when voice info is changed. */ void notifyVoiceChanged(); /** @@ -43,32 +41,32 @@ interface nsIMobileConnectionListener : void notifyDataError(in DOMString message); /** * Notify when call forwarding state is changed. * * @param success * Indicates whether the set call forwarding request is success. * @param action - * One of the nsIMobileConnectionProvider.CALL_FORWARD_ACTION_* values. + * One of the nsIMobileConnectionService.CALL_FORWARD_ACTION_* values. * @param reason - * One of the nsIMobileConnectionProvider.CALL_FORWARD_REASON_* values. + * One of the nsIMobileConnectionService.CALL_FORWARD_REASON_* values. * @param number * Phone number of forwarding address. * @param timeSeconds * The time in seconds should wait before call is forwarded. * @param serviceClass - * One of the nsIMobileConnectionProvider.ICC_SERVICE_CLASS_* values. + * One of the nsIMobileConnectionService.ICC_SERVICE_CLASS_* values. */ - void notifyCFStateChange(in boolean success, - in unsigned short action, - in unsigned short reason, - in DOMString number, - in unsigned short timeSeconds, - in unsigned short serviceClass); + void notifyCFStateChanged(in boolean success, + in unsigned short action, + in unsigned short reason, + in DOMString number, + in unsigned short timeSeconds, + in unsigned short serviceClass); /** * Notify when emergency callback mode is changed. * * @param active * Indicates whether the emergency callback mode is activated. * @param timeoutMs * The timeout in millisecond for emergency callback mode. @@ -96,27 +94,123 @@ interface nsIMobileConnectionListener : * Notify when radio state is changed. */ void notifyRadioStateChanged(); /** * Notify when clir mode is changed. * * @param mode - * One of the nsIMobileConnectionProvider.CLIR_* values. + * One of the nsIMobileConnectionService.CLIR_* values. */ void notifyClirModeChanged(in unsigned long mode); + + /** + * Notify when last known network is changed. + */ + void notifyLastKnownNetworkChanged(); + + /** + * Notify when last known home network is changed. + */ + void notifyLastKnownHomeNetworkChanged(); + + /** + * Notify when network selection mode is changed. + */ + void notifyNetworkSelectionModeChanged(); }; +%{C++ +#define NO_ADDITIONAL_INFORMATION 0 +%} + +[scriptable, builtinclass, uuid(e9d7c247-34c6-42bf-875b-f99b19db394f)] +interface nsIMobileConnectionCallback : nsISupports +{ + /** + * notify*Success*() will be called, when request is succeed. + */ + void notifySuccess(); + + void notifySuccessWithString(in DOMString result); + + void notifySuccessWithBoolean(in boolean result); + + void notifyGetNetworksSuccess(in uint32_t count, + [array, size_is(count)] in nsIMobileNetworkInfo networks); + + void notifySendCancelMmiSuccess(in jsval result /* MozMMIResult */); + + void notifyGetCallForwardingSuccess(in jsval results /* Array of MozCallForwardingOptions */); + + void notifyGetCallBarringSuccess(in unsigned short program, + in boolean enabled, + in unsigned short serviceClass); + + void notifyGetClirStatusSuccess(in unsigned short n, in unsigned short m); + + /** + * notifyError() will be called, when request is failed. + */ + [optional_argc] + void notifyError(in DOMString name, + [optional] in DOMString message, + [optional] in DOMString serviceCode, + [optional] in unsigned short additionalInformation); + +%{C++ + // non-virtual so it won't affect the vtable + inline nsresult NotifyError(const nsAString& aName) + { + return NotifyError(aName, EmptyString(), EmptyString(), + NO_ADDITIONAL_INFORMATION, 0 /* ARGC = 0 */); + } + // non-virtual so it won't affect the vtable + inline nsresult NotifyError(const nsAString& aName, + const nsAString& aMessage) + { + return NotifyError(aName, aMessage, EmptyString(), NO_ADDITIONAL_INFORMATION, + 1 /* ARGC = 1 */); + } + // non-virtual so it won't affect the vtable + inline nsresult NotifyError(const nsAString& aName, + const nsAString& aMessage, + const nsAString& aServiceCode) + { + return NotifyError(aName, aMessage, aServiceCode, NO_ADDITIONAL_INFORMATION, + 2 /* ARGC = 2 */); + } + // non-virtual so it won't affect the vtable + inline nsresult NotifyError(const nsAString& aName, + const nsAString& aMessage, + const nsAString& aServiceCode, + uint16_t aAdditionInformation) + { + return NotifyError(aName, aMessage, aServiceCode, aAdditionInformation, + 3 /* ARGC = 3 */); + } +%} + +}; + +%{C++ +#define NS_MOBILE_CONNECTION_SERVICE_CID \ + { 0xc6f229d4, 0x16e2, 0x4600, \ + { 0x87, 0x2a, 0x3d, 0x3d, 0xc5, 0xb8, 0x55, 0x41 } } +#define NS_MOBILE_CONNECTION_SERVICE_CONTRACTID \ + "@mozilla.org/mobileconnection/mobileconnectionservice;1" +%} + /** * XPCOM component (in the content process) that provides the mobile * network information. */ -[scriptable, uuid(2a3af80f-9f8e-447d-becd-034f95e4cd4d)] -interface nsIMobileConnectionProvider : nsISupports +[scriptable, uuid(b50ad32d-f70e-4729-a947-e8cfdb6ba81f)] +interface nsIMobileConnectionService : nsISupports { const long ICC_SERVICE_CLASS_VOICE = (1 << 0); const long ICC_SERVICE_CLASS_DATA = (1 << 1); const long ICC_SERVICE_CLASS_FAX = (1 << 2); const long ICC_SERVICE_CLASS_SMS = (1 << 3); const long ICC_SERVICE_CLASS_DATA_SYNC = (1 << 4); const long ICC_SERVICE_CLASS_DATA_ASYNC = (1 << 5); const long ICC_SERVICE_CLASS_PACKET = (1 << 6); @@ -164,20 +258,20 @@ interface nsIMobileConnectionProvider : const long CLIR_INVOCATION = 1; const long CLIR_SUPPRESSION = 2; /** * Called when a content process registers receiving unsolicited messages from * RadioInterfaceLayer in the chrome process. Only a content process that has * the 'mobileconnection' permission is allowed to register. */ - void registerMobileConnectionMsg(in unsigned long clientId, - in nsIMobileConnectionListener listener); - void unregisterMobileConnectionMsg(in unsigned long clientId, - in nsIMobileConnectionListener listener); + void registerListener(in unsigned long clientId, + in nsIMobileConnectionListener listener); + void unregisterListener(in unsigned long clientId, + in nsIMobileConnectionListener listener); /** * These two fields require the 'mobilenetwork' permission. */ DOMString getLastKnownNetwork(in unsigned long clientId); DOMString getLastKnownHomeNetwork(in unsigned long clientId); /** @@ -248,502 +342,451 @@ interface nsIMobileConnectionProvider : */ nsIVariant getSupportedNetworkTypes(in unsigned long clientId); /** * Search for available networks. * * @param clientId * Indicate the RIL client, 0 ~ (number of client - 1). - * @param window - * Current window. + * @param requestCallback + * Called when request is finished. * - * @return a nsIDOMDOMRequest - * - * If successful, the request's onsuccess will be called. And the request's + * If successful, the notifyGetNetworksSuccess() will be called. And the * result will be an array of nsIMobileNetworkInfo. * - * Otherwise, the request's onerror will be called, and the request's error - * will be either 'RadioNotAvailable', 'RequestNotSupported', - * 'IllegalSIMorME', or 'GenericFailure'. + * Otherwise, the notifyError() will be called, and the error will be either + * 'RadioNotAvailable', 'RequestNotSupported', 'IllegalSIMorME', or + * 'GenericFailure'. */ - nsIDOMDOMRequest getNetworks(in unsigned long clientId, - in nsIDOMWindow window); + void getNetworks(in unsigned long clientId, + in nsIMobileConnectionCallback requestCallback); /** * Manually selects the passed in network, overriding the radio's current * selection. * * @param clientId * Indicate the RIL client, 0 ~ (number of client - 1). - * @param window - * Current window. * @param network * The manually selecting network. + * @param requestCallback + * Called when request is finished. * - * @return a nsIDOMDOMRequest - * - * If successful, the request's onsuccess will be called. + * If successful, the notifySuccess() will be called. * - * Otherwise, the request's onerror will be called, and the request's error - * will be either 'RadioNotAvailable', 'RequestNotSupported', - * 'IllegalSIMorME', or 'GenericFailure'. + * Otherwise, the notifyError() will be called, and the error will be either + * 'RadioNotAvailable', 'RequestNotSupported', 'IllegalSIMorME', or + * 'GenericFailure'. */ - nsIDOMDOMRequest selectNetwork(in unsigned long clientId, - in nsIDOMWindow window, - in nsIMobileNetworkInfo network); + void selectNetwork(in unsigned long clientId, + in nsIMobileNetworkInfo network, + in nsIMobileConnectionCallback requestCallback); /** * Tell the radio to automatically select a network. * * @param clientId * Indicate the RIL client, 0 ~ (number of client - 1). - * @param window - * Current window. + * @param requestCallback + * Called when request is finished. * - * @return a nsIDOMDOMRequest - * - * If successful, the request's onsuccess will be called. + * If successful, the notifySuccess() will be called. * - * Otherwise, the request's onerror will be called, and the request's error - * will be either 'RadioNotAvailable', 'RequestNotSupported', - * 'IllegalSIMorME', or 'GenericFailure'. + * Otherwise, the notifyError() will be called, and the error will be either + * 'RadioNotAvailable', 'RequestNotSupported', 'IllegalSIMorME', or + * 'GenericFailure'. */ - nsIDOMDOMRequest selectNetworkAutomatically(in unsigned long clientId, - in nsIDOMWindow window); + void selectNetworkAutomatically(in unsigned long clientId, + in nsIMobileConnectionCallback requestCallback); /** * Set preferred network type. * * @param clientId * Indicate the RIL client, 0 ~ (number of client - 1). - * @param window - * Current window. * @param type * DOMString indicates the desired preferred network type. * Possible values: 'wcdma/gsm', 'gsm', 'wcdma', 'wcdma/gsm-auto', * 'cdma/evdo', 'cdma', 'evdo', 'wcdma/gsm/cdma/evdo', * 'lte/cdma/evdo', 'lte/wcdma/gsm', 'lte/wcdma/gsm/cdma/evdo' or * 'lte'. + * @param requestCallback + * Called when request is finished. * - * @return a nsIDOMDOMRequest - * - * If successful, the request's onsuccess will be called. + * If successful, the notifySuccess() will be called. * - * Otherwise, the request's onerror will be called, and the request's error - * will be either 'RadioNotAvailable', 'RequestNotSupported', - * 'InvalidParameter', 'IllegalSIMorME', or 'GenericFailure'. + * Otherwise, the notifyError() will be called, and the error will be either + * 'RadioNotAvailable', 'RequestNotSupported', 'InvalidParameter', + * 'IllegalSIMorME', or 'GenericFailure'. */ - nsIDOMDOMRequest setPreferredNetworkType(in unsigned long clientId, - in nsIDOMWindow window, - in DOMString type); + void setPreferredNetworkType(in unsigned long clientId, + in DOMString type, + in nsIMobileConnectionCallback requestCallback); /** * Query current preferred network type. * * @param clientId * Indicate the RIL client, 0 ~ (number of client - 1). - * @param window - * Current window. - * - * @return a nsIDOMDOMRequest + * @param requestCallback + * Called when request is finished. * - * If successful, the request's onsuccess will be called. And the request's - * result will be a string indicating the current preferred network type. - * The value will be either 'wcdma/gsm', 'gsm', 'wcdma', 'wcdma/gsm-auto', - * 'cdma/evdo', 'cdma', 'evdo', 'wcdma/gsm/cdma/evdo', 'lte/cdma/evdo', - * 'lte/wcdma/gsm', 'lte/wcdma/gsm/cdma/evdo' or 'lte'. + * If successful, the notifySuccessString() will be called. And the result + * will be a string indicating the current preferred network type. The value + * will be either 'wcdma/gsm', 'gsm', 'wcdma', 'wcdma/gsm-auto', 'cdma/evdo', + * 'cdma', 'evdo', 'wcdma/gsm/cdma/evdo', 'lte/cdma/evdo', 'lte/wcdma/gsm', + * 'lte/wcdma/gsm/cdma/evdo' or 'lte'. * - * Otherwise, the request's onerror will be called, and the request's error - * will be either 'RadioNotAvailable', 'RequestNotSupported', - * 'IllegalSIMorME', or 'GenericFailure'. + * Otherwise, the notifyError() will be called, and the error will be either + * 'RadioNotAvailable', 'RequestNotSupported', 'IllegalSIMorME', or + * 'GenericFailure'. */ - nsIDOMDOMRequest getPreferredNetworkType(in unsigned long clientId, - in nsIDOMWindow window); + void getPreferredNetworkType(in unsigned long clientId, + in nsIMobileConnectionCallback requestCallback); /** * Set roaming preference. * * @param clientId * Indicate the RIL client, 0 ~ (number of client - 1). - * @param window - * Current window. * @param mode * DOMString indicates the desired roaming preference. * Possible values: 'home', 'affiliated', or 'any'. + * @param requestCallback + * Called when request is finished. * - * @return a nsIDOMDOMRequest - * - * If successful, the request's onsuccess will be called. + * If successful, the notifySuccess() will be called. * - * Otherwise, the request's onerror will be called, and the request's error - * will be either 'RadioNotAvailable', 'RequestNotSupported', - * InvalidParameter', 'IllegalSIMorME', or 'GenericFailure'. + * Otherwise, the notifyError() will be called, and the error will be either + * 'RadioNotAvailable', 'RequestNotSupported', InvalidParameter', + * 'IllegalSIMorME', or 'GenericFailure'. */ - nsIDOMDOMRequest setRoamingPreference(in unsigned long clientId, - in nsIDOMWindow window, - in DOMString mode); + void setRoamingPreference(in unsigned long clientId, + in DOMString mode, + in nsIMobileConnectionCallback requestCallback); /** * Query current roaming preference. * * @param clientId * Indicate the RIL client, 0 ~ (number of client - 1). - * @param window - * Current window. + * @param requestCallback + * Called when request is finished. * - * @return a nsIDOMDOMRequest + * If successful, the notifySuccessWithString() will be called. And the result + * will be a string indicating the current roaming preference. The value will + * be either 'home', 'affiliated', or 'any'. * - * If successful, the request's onsuccess will be called. And the request's - * result will be a string indicating the current roaming preference. - * The value will be either 'home', 'affiliated', or 'any'. - * - * Otherwise, the request's onerror will be called, and the request's error - * will be either 'RadioNotAvailable', 'RequestNotSupported', - * 'IllegalSIMorME', or 'GenericFailure'. + * Otherwise, the notifyError() will be called, and the error will be either + * 'RadioNotAvailable', 'RequestNotSupported', 'IllegalSIMorME', or + * 'GenericFailure'. */ - nsIDOMDOMRequest getRoamingPreference(in unsigned long clientId, - in nsIDOMWindow window); + void getRoamingPreference(in unsigned long clientId, + in nsIMobileConnectionCallback requestCallback); /** * Set voice privacy preference. * * @param clientId * Indicate the RIL client, 0 ~ (number of client - 1). - * @param window - * Current window. * @param enabled * Boolean indicates the preferred voice privacy mode used in voice * scrambling in CDMA networks. 'True' means the enhanced voice security * is required. + * @param requestCallback + * Called when request is finished. * - * @return a nsIDOMDOMRequest - * - * If successful, the request's onsuccess will be called. + * If successful, the notifySuccess() will be called. * - * Otherwise, the request's onerror will be called, and the request's error - * will be either 'RadioNotAvailable', 'RequestNotSupported', - * 'IllegalSIMorME', or 'GenericFailure'. + * Otherwise, the notifyError() will be called, and the error will be either + * 'RadioNotAvailable', 'RequestNotSupported', 'IllegalSIMorME', or + * 'GenericFailure'. */ - nsIDOMDOMRequest setVoicePrivacyMode(in unsigned long clientId, - in nsIDOMWindow window, - in bool enabled); + void setVoicePrivacyMode(in unsigned long clientId, + in bool enabled, + in nsIMobileConnectionCallback requestCallback); /** * Query current voice privacy mode. * * @param clientId * Indicate the RIL client, 0 ~ (number of client - 1). - * @param window - * Current window. + * @param requestCallback + * Called when request is finished. * - * @return a nsIDOMDOMRequest + * If successful, the notifySuccessWithBoolean() will be called. And the result + * will be a boolean indicating the current voice privacy mode. * - * If successful, the request's onsuccess will be called. And the request's - * result will be a boolean indicating the current voice privacy mode. - * - * Otherwise, the request's onerror will be called, and the request's error - * will be either 'RadioNotAvailable', 'RequestNotSupported', - * 'IllegalSIMorME', or 'GenericFailure'. + * Otherwise, the notifyError() will be called, and the error will be either + * 'RadioNotAvailable', 'RequestNotSupported', 'IllegalSIMorME', or + * 'GenericFailure'. */ - nsIDOMDOMRequest getVoicePrivacyMode(in unsigned long clientId, - in nsIDOMWindow window); + void getVoicePrivacyMode(in unsigned long clientId, + in nsIMobileConnectionCallback requestCallback); /** * Send a MMI message. * * @param clientId * Indicate the RIL client, 0 ~ (number of client - 1). - * @param window - * Current window. * @param mmi * DOMString containing an MMI string that can be associated to a * USSD request or other RIL functionality. - * - * @return a nsIDOMDOMRequest + * @param requestCallback + * Called when request is finished. * - * If successful, the request's onsuccess will be called. And the request's - * result will be an object containing information about the operation. - * @see MozMMIResult for the detail of result. + * If successful, the notifySendCancelMmiSuccess() will be called. And the + * result will contain the information about the mmi operation. * - * Otherwise, the request's onerror will be called, and the request's error - * will be a DOMMMIError. - * @see DOMMMIError for the detail of error. + * Otherwise, the notifyError() will be called. */ - nsIDOMDOMRequest sendMMI(in unsigned long clientId, - in nsIDOMWindow window, - in DOMString mmi); + void sendMMI(in unsigned long clientId, + in DOMString mmi, + in nsIMobileConnectionCallback requestCallback); /** * Cancel the current MMI request if one exists. * * @param clientId * Indicate the RIL client, 0 ~ (number of client - 1). - * @param window - * Current window. - * - * @return a nsIDOMDOMRequest + * @param requestCallback + * Called when request is finished. * - * If successful, the request's onsuccess will be called. And the request's - * result will be an object containing information about the operation. - * @see MozMMIResult for the detail of result. + * If successful, the notifySendCancelMmiSuccess() will be called. And the + * result will contain the information about the mmi operation. * - * Otherwise, the request's onerror will be called, and the request's error - * will be a DOMMMIError. - * @see DOMMMIError for the detail of error. + * Otherwise, the notifyError() will be called. */ - nsIDOMDOMRequest cancelMMI(in unsigned long clientId, - in nsIDOMWindow window); + void cancelMMI(in unsigned long clientId, + in nsIMobileConnectionCallback requestCallback); /** * Queries current call forwarding options. * * @param clientId * Indicate the RIL client, 0 ~ (number of client - 1). - * @param window - * Current window. * @param reason * Indicates the reason the call is being forwarded. It shall be one of - * the nsIMobileConnectionProvider.CALL_FORWARD_REASON_* values. + * the nsIMobileConnectionService.CALL_FORWARD_REASON_* values. + * @param requestCallback + * Called when request is finished. * - * @return a nsIDOMDOMRequest - * - * If successful, the request's onsuccess will be called. And the request's + * If successful, the notifyGetCallForwardingSuccess() will be called. And the * result will be an array of MozCallForwardingOptions. * @see MozCallForwardingOptions for the detail of result. * - * Otherwise, the request's onerror will be called, and the request's error - * will be either 'RadioNotAvailable', 'RequestNotSupported', - * 'InvalidParameter', 'IllegalSIMorME', or 'GenericFailure'. + * Otherwise, the notifyError() will be called, and the error will be either + * 'RadioNotAvailable', 'RequestNotSupported', 'InvalidParameter', + * 'IllegalSIMorME', or 'GenericFailure'. */ - nsIDOMDOMRequest getCallForwarding(in unsigned long clientId, - in nsIDOMWindow window, - in unsigned short reason); + void getCallForwarding(in unsigned long clientId, + in unsigned short reason, + in nsIMobileConnectionCallback requestCallback); /** * Configures call forwarding options. * * @param clientId * Indicate the RIL client, 0 ~ (number of client - 1). - * @param window - * Current window. * @param options * An object containing the call forward rule to set. * @see MozCallForwardingOptions for the detail of options. + * @param requestCallback + * Called when request is finished. * - * @return a nsIDOMDOMRequest - * - * If successful, the request's onsuccess will be called. + * If successful, the notifySuccess() will be called. * - * Otherwise, the request's onerror will be called, and the request's error - * will be either 'RadioNotAvailable', 'RequestNotSupported', - * 'InvalidParameter', 'IllegalSIMorME', or 'GenericFailure' + * Otherwise, the notifyError() will be called, and the error will be either + * 'RadioNotAvailable', 'RequestNotSupported', 'InvalidParameter', + * 'IllegalSIMorME', or 'GenericFailure'. */ - nsIDOMDOMRequest setCallForwarding(in unsigned long clientId, - in nsIDOMWindow window, - in jsval options); + void setCallForwarding(in unsigned long clientId, + in jsval options, + in nsIMobileConnectionCallback requestCallback); /** * Queries current call barring status. * * @param clientId * Indicate the RIL client, 0 ~ (number of client - 1). - * @param window - * Current window. * @param options * An object containing the call barring rule to query. No need to * specify 'enabled' property. * @see MozCallBarringOptions for the detail of options. - * - * @return a nsIDOMDOMRequest + * @param requestCallback + * Called when request is finished. * - * If successful, the request's onsuccess will be called. And the request's - * result will be an object of MozCallBarringOptions with correct 'enabled' - * property indicating the status of this rule. - * @see MozCallBarringOptions for the detail of result. + * If successful, the notifyGetCallBarringSuccess() will be called. And the + * result will contain correct 'enabled' property indicating the status of + * this rule. * - * Otherwise, the request's onerror will be called, and the request's error - * will be either 'RadioNotAvailable', 'RequestNotSupported', - * 'InvalidParameter', 'IllegalSIMorME', or 'GenericFailure'. + * Otherwise, the notifyError() will be called, and the error will be either + * 'RadioNotAvailable', 'RequestNotSupported', 'InvalidParameter', + * 'IllegalSIMorME', or 'GenericFailure'. */ - nsIDOMDOMRequest getCallBarring(in unsigned long clientId, - in nsIDOMWindow window, - in jsval options); + void getCallBarring(in unsigned long clientId, + in jsval options, + in nsIMobileConnectionCallback requestCallback); /** * Configures call barring option. * * @param clientId * Indicate the RIL client, 0 ~ (number of client - 1). - * @param window - * Current window. * @param options * An object containing the call barring rule to set. * @see MozCallBarringOptions for the detail of options. + * @param requestCallback + * Called when request is finished. * - * @return a nsIDOMDOMRequest - * - * If successful, the request's onsuccess will be called. + * If successful, the notifySuccess() will be called. * - * Otherwise, the request's onerror will be called, and the request's error - * will be either 'RadioNotAvailable', 'RequestNotSupported', - * 'InvalidParameter', 'IllegalSIMorME', or 'GenericFailure' + * Otherwise, the notifyError() will be called, and the error will be either + * 'RadioNotAvailable', 'RequestNotSupported', 'InvalidParameter', + * 'IllegalSIMorME', or 'GenericFailure'. */ - nsIDOMDOMRequest setCallBarring(in unsigned long clientId, - in nsIDOMWindow window, - in jsval options); + void setCallBarring(in unsigned long clientId, + in jsval options, + in nsIMobileConnectionCallback requestCallback); /** * Change call barring facility password. * * @param clientId * Indicate the RIL client, 0 ~ (number of client - 1). - * @param window - * Current window. * @param options * An object containing information about pin and newPin, and, * this object must have both "pin" and "newPin" attributes * to change the call barring facility password. * @see MozCallBarringOptions for the detail of options. + * @param requestCallback + * Called when request is finished. * - * @return a nsIDOMDOMRequest - * - * If successful, the request's onsuccess will be called. + * If successful, the notifySuccess() will be called. * - * Otherwise, the request's onerror will be called, and the request's error - * will be either 'RadioNotAvailable', 'RequestNotSupported', - * 'InvalidParameter', 'IllegalSIMorME', or 'GenericFailure'. + * Otherwise, the notifyError() will be called, and the error will be either + * 'RadioNotAvailable', 'RequestNotSupported', 'InvalidParameter', + * 'IllegalSIMorME', or 'GenericFailure'. */ - nsIDOMDOMRequest changeCallBarringPassword(in unsigned long clientId, - in nsIDOMWindow window, - in jsval options); + void changeCallBarringPassword(in unsigned long clientId, + in jsval options, + in nsIMobileConnectionCallback requestCallback); /** * Configures call waiting options. * * @param clientId * Indicate the RIL client, 0 ~ (number of client - 1). - * @param window - * Current window. * @param enabled * Boolean indicates the desired call waiting status. + * @param requestCallback + * Called when request is finished. * - * @return a nsIDOMDOMRequest - * - * If successful, the request's onsuccess will be called. + * If successful, the notifySuccess() will be called. * - * Otherwise, the request's onerror will be called, and the request's error - * will be either 'RadioNotAvailable', 'RequestNotSupported', - * 'IllegalSIMorME', or 'GenericFailure'. + * Otherwise, the notifyError() will be called, and the error will be either + * 'RadioNotAvailable', 'RequestNotSupported', 'IllegalSIMorME', or + * 'GenericFailure'. */ - nsIDOMDOMRequest setCallWaiting(in unsigned long clientId, - in nsIDOMWindow window, - in bool enabled); + void setCallWaiting(in unsigned long clientId, + in bool enabled, + in nsIMobileConnectionCallback requestCallback); /** * Queries current call waiting options. * * @param clientId * Indicate the RIL client, 0 ~ (number of client - 1). - * @param window - * Current window. + * @param requestCallback + * Called when request is finished. * - * @return a nsIDOMDOMRequest + * If successful, the notifySuccessWithBoolean() will be called. And the result + * will be a boolean indicating the call waiting status. * - * If successful, the request's onsuccess will be called. And the request's - * result will be a boolean indicating the call waiting status. - * - * Otherwise, the request's onerror will be called, and the request's error - * will be either 'RadioNotAvailable', 'RequestNotSupported', - * 'IllegalSIMorME', or 'GenericFailure'. + * Otherwise, the notifyError() will be called, and the error will be either + * 'RadioNotAvailable', 'RequestNotSupported', 'IllegalSIMorME', or + * 'GenericFailure'. */ - nsIDOMDOMRequest getCallWaiting(in unsigned long clientId, - in nsIDOMWindow window); + void getCallWaiting(in unsigned long clientId, + in nsIMobileConnectionCallback requestCallback); /** * Enables or disables the presentation of the calling line identity (CLI) to * the called party when originating a call. * * @param clientId * Indicate the RIL client, 0 ~ (number of client - 1). - * @param window - * Current window. * @param clirMode - * One of the nsIMobileConnectionProvider.CLIR_* values. + * One of the nsIMobileConnectionService.CLIR_* values. + * @param requestCallback + * Called when request is finished. * - * @return a nsIDOMDOMRequest + * If successful, the notifySuccess() will be called. * - * If successful, the request's onsuccess will be called. - * - * Otherwise, the request's onerror will be called, and the request's error - * will be either 'RadioNotAvailable', 'RequestNotSupported', - * 'InvalidParameter', 'IllegalSIMorME', or 'GenericFailure'. + * Otherwise, the notifyError() will be called, and the error will be either + * 'RadioNotAvailable', 'RequestNotSupported', 'InvalidParameter', + * 'IllegalSIMorME', or 'GenericFailure'. */ - nsIDOMDOMRequest setCallingLineIdRestriction(in unsigned long clientId, - in nsIDOMWindow window, - in unsigned short clirMode); + void setCallingLineIdRestriction(in unsigned long clientId, + in unsigned short clirMode, + in nsIMobileConnectionCallback requestCallback); /** * Queries current CLIR status. * * @param clientId * Indicate the RIL client, 0 ~ (number of client - 1). - * @param window - * Current window. + * @param requestCallback + * Called when request is finished. * - * @return a nsIDOMDOMRequest - * - * If successful, the request's onsuccess will be called. And the request's + * If successful, the notifyGetClirStatusSuccess() will be called. And the * result will be a an object containing CLIR 'n' and 'm' parameter. * @see MozClirStatus for the detail of result. * - * Otherwise, the request's onerror will be called, and the request's error - * will be either 'RadioNotAvailable', 'RequestNotSupported', - * 'IllegalSIMorME', or 'GenericFailure'. + * Otherwise, the notifyError() will be called, and the error will be either + * 'RadioNotAvailable', 'RequestNotSupported', 'IllegalSIMorME', or + * 'GenericFailure'. */ - nsIDOMDOMRequest getCallingLineIdRestriction(in unsigned long clientId, - in nsIDOMWindow window); + void getCallingLineIdRestriction(in unsigned long clientId, + in nsIMobileConnectionCallback requestCallback); /** * Exit emergency callback mode. * * @param clientId * Indicate the RIL client, 0 ~ (number of client - 1). - * @param window - * Current window. + * @param requestCallback + * Called when request is finished. * - * @return a nsIDOMDOMRequest - * - * If successful, the request's onsuccess will be called. + * If successful, the notifySuccess() will be called. * - * Otherwise, the request's onerror will be called, and the request's error - * will be either 'RadioNotAvailable', 'RequestNotSupported', - * 'IllegalSIMorME', or 'GenericFailure'. + * Otherwise, the notifyError() will be called, and the error will be either + * 'RadioNotAvailable', 'RequestNotSupported', 'IllegalSIMorME', or + * 'GenericFailure'. */ - nsIDOMDOMRequest exitEmergencyCbMode(in unsigned long clientId, - in nsIDOMWindow window); + void exitEmergencyCbMode(in unsigned long clientId, + in nsIMobileConnectionCallback requestCallback); /** * Set radio enabled/disabled. * * @param clientId * Indicate the RIL client, 0 ~ (number of client - 1). - * @param window - * Current window. * @param enabled * Boolean indicates the desired radio power. True to enable the radio. - * - * @return a nsIDOMDOMRequest + * @param requestCallback + * Called when request is finished. * - * If successful, the request's onsuccess will be called. + * If successful, the notifySuccess() will be called. * - * Otherwise, the request's onerror will be called, and the request's error - * will be either 'InvalidStateError', 'RadioNotAvailable', - * 'IllegalSIMorME', or 'GenericFailure'. + * Otherwise, the notifyError() will be called, and the error will be either + * 'InvalidStateError', 'RadioNotAvailable', 'IllegalSIMorME', or + * 'GenericFailure'. * * Note: Request is not available when radioState is null, 'enabling', or * 'disabling'. Calling the function in above conditions will receive * 'InvalidStateError' error. */ - nsIDOMDOMRequest setRadioEnabled(in unsigned long clientId, - in nsIDOMWindow window, - in bool enabled); + void setRadioEnabled(in unsigned long clientId, + in bool enabled, + in nsIMobileConnectionCallback requestCallback); };
new file mode 100644 --- /dev/null +++ b/dom/mobileconnection/ipc/MobileConnectionChild.cpp @@ -0,0 +1,484 @@ +/* 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/. */ + +#include "MobileConnectionChild.h" + +#include "MobileConnectionCallback.h" +#include "mozilla/dom/MozMobileConnectionBinding.h" +#include "nsComponentManagerUtils.h" + +using namespace mozilla::dom; +using namespace mozilla::dom::mobileconnection; + +void +MobileConnectionChild::Init() +{ + nsIMobileConnectionInfo* rawVoice; + nsIMobileConnectionInfo* rawData; + nsTArray<nsString> types; + + SendInit(&rawVoice, &rawData, &mLastNetwork, &mLastHomeNetwork, &mIccId, + &mNetworkSelectionMode, &mRadioState, &types); + + // Use dont_AddRef here because this instances is already AddRef-ed in + // MobileConnectionIPCSerializer.h + nsCOMPtr<nsIMobileConnectionInfo> voice = dont_AddRef(rawVoice); + mVoice = new MobileConnectionInfo(nullptr); + mVoice->Update(voice); + + // Use dont_AddRef here because this instances is already AddRef-ed in + // MobileConnectionIPCSerializer.h + nsCOMPtr<nsIMobileConnectionInfo> data = dont_AddRef(rawData); + mData = new MobileConnectionInfo(nullptr); + mData->Update(data); + + + // Initial SupportedNetworkTypes + nsresult rv; + mSupportedNetworkTypes = do_CreateInstance(NS_VARIANT_CONTRACTID, &rv); + + if (NS_FAILED(rv)) { + return; + } + + uint32_t arrayLen = types.Length(); + if (arrayLen == 0) { + mSupportedNetworkTypes->SetAsEmptyArray(); + } else { + // Note: The resulting nsIVariant dupes both the array and its elements. + const char16_t** array = reinterpret_cast<const char16_t**> + (NS_Alloc(arrayLen * sizeof(const char16_t***))); + if (array) { + for (uint32_t i = 0; i < arrayLen; ++i) { + array[i] = types[i].get(); + } + + mSupportedNetworkTypes->SetAsArray(nsIDataType::VTYPE_WCHAR_STR, + nullptr, + arrayLen, + reinterpret_cast<void*>(array)); + NS_Free(array); + } + } +} + +void +MobileConnectionChild::Shutdown() +{ + if (mLive) { + mLive = false; + Send__delete__(this); + } + + mListeners.Clear(); + mVoice = nullptr; + mData = nullptr; + mSupportedNetworkTypes = nullptr; +} + +void +MobileConnectionChild::RegisterListener(nsIMobileConnectionListener* aListener) +{ + if (!mListeners.Contains(aListener)) { + mListeners.AppendObject(aListener); + } +} + +void +MobileConnectionChild::UnregisterListener(nsIMobileConnectionListener* aListener) +{ + mListeners.RemoveObject(aListener); +} + +MobileConnectionInfo* +MobileConnectionChild::GetVoiceInfo() +{ + return mVoice; +} + +MobileConnectionInfo* +MobileConnectionChild::GetDataInfo() +{ + return mData; +} + +void +MobileConnectionChild::GetIccId(nsAString& aIccId) +{ + aIccId = mIccId; +} + +void +MobileConnectionChild::GetRadioState(nsAString& aRadioState) +{ + aRadioState = mRadioState; +} + +nsIVariant* +MobileConnectionChild::GetSupportedNetworkTypes() +{ + return mSupportedNetworkTypes; +} + +void +MobileConnectionChild::GetLastNetwork(nsAString& aNetwork) +{ + aNetwork = mLastNetwork; +} + +void +MobileConnectionChild::GetLastHomeNetwork(nsAString& aNetwork) +{ + aNetwork = mLastHomeNetwork; +} + +void +MobileConnectionChild::GetNetworkSelectionMode(nsAString& aMode) +{ + aMode = mNetworkSelectionMode; +} + +bool +MobileConnectionChild::SendRequest(MobileConnectionRequest aRequest, + nsIMobileConnectionCallback* aRequestCallback) +{ + NS_ENSURE_TRUE(mLive, false); + + // Deallocated in MobileConnectionChild::DeallocPMobileConnectionRequestChild(). + MobileConnectionRequestChild* actor = new MobileConnectionRequestChild(aRequestCallback); + SendPMobileConnectionRequestConstructor(actor, aRequest); + + return true; +} + +void +MobileConnectionChild::ActorDestroy(ActorDestroyReason why) +{ + mLive = false; +} + +PMobileConnectionRequestChild* +MobileConnectionChild::AllocPMobileConnectionRequestChild(const MobileConnectionRequest& request) +{ + MOZ_CRASH("Caller is supposed to manually construct a request!"); +} + +bool +MobileConnectionChild::DeallocPMobileConnectionRequestChild(PMobileConnectionRequestChild* aActor) +{ + delete aActor; + return true; +} + +bool +MobileConnectionChild::RecvNotifyVoiceInfoChanged(nsIMobileConnectionInfo* const& aInfo) +{ + // Use dont_AddRef here because this instances is already AddRef-ed in + // MobileConnectionIPCSerializer.h + nsCOMPtr<nsIMobileConnectionInfo> voice = dont_AddRef(aInfo); + mVoice->Update(voice); + + for (int32_t i = 0; i < mListeners.Count(); i++) { + mListeners[i]->NotifyVoiceChanged(); + } + + return true; +} + +bool +MobileConnectionChild::RecvNotifyDataInfoChanged(nsIMobileConnectionInfo* const& aInfo) +{ + // Use dont_AddRef here because this instances is already AddRef-ed in + // MobileConnectionIPCSerializer.h + nsCOMPtr<nsIMobileConnectionInfo> data = dont_AddRef(aInfo); + mData->Update(data); + + for (int32_t i = 0; i < mListeners.Count(); i++) { + mListeners[i]->NotifyDataChanged(); + } + + return true; +} + +bool +MobileConnectionChild::RecvNotifyUssdReceived(const nsString& aMessage, + const bool& aSessionEnd) +{ + for (int32_t i = 0; i < mListeners.Count(); i++) { + mListeners[i]->NotifyUssdReceived(aMessage, aSessionEnd); + } + + return true; +} + +bool +MobileConnectionChild::RecvNotifyDataError(const nsString& aMessage) +{ + for (int32_t i = 0; i < mListeners.Count(); i++) { + mListeners[i]->NotifyDataError(aMessage); + } + + return true; +} + +bool +MobileConnectionChild::RecvNotifyCFStateChanged(const bool& aSuccess, + const uint16_t& aAction, + const uint16_t& aReason, + const nsString& aNumber, + const uint16_t& aTimeSeconds, + const uint16_t& aServiceClass) +{ + for (int32_t i = 0; i < mListeners.Count(); i++) { + mListeners[i]->NotifyCFStateChanged(aSuccess, aAction, aReason, aNumber, + aTimeSeconds, aServiceClass); + } + + return true; +} + +bool +MobileConnectionChild::RecvNotifyEmergencyCbModeChanged(const bool& aActive, + const uint32_t& aTimeoutMs) +{ + for (int32_t i = 0; i < mListeners.Count(); i++) { + mListeners[i]->NotifyEmergencyCbModeChanged(aActive, aTimeoutMs); + } + + return true; +} + +bool +MobileConnectionChild::RecvNotifyOtaStatusChanged(const nsString& aStatus) +{ + for (int32_t i = 0; i < mListeners.Count(); i++) { + mListeners[i]->NotifyOtaStatusChanged(aStatus); + } + + return true; +} + +bool +MobileConnectionChild::RecvNotifyIccChanged(const nsString& aIccId) +{ + mIccId.Assign(aIccId); + + for (int32_t i = 0; i < mListeners.Count(); i++) { + mListeners[i]->NotifyIccChanged(); + } + + return true; +} + +bool +MobileConnectionChild::RecvNotifyRadioStateChanged(const nsString& aRadioState) +{ + mRadioState.Assign(aRadioState); + + for (int32_t i = 0; i < mListeners.Count(); i++) { + mListeners[i]->NotifyRadioStateChanged(); + } + + return true; +} + +bool +MobileConnectionChild::RecvNotifyClirModeChanged(const uint32_t& aMode) +{ + for (int32_t i = 0; i < mListeners.Count(); i++) { + mListeners[i]->NotifyClirModeChanged(aMode); + } + + return true; +} + +bool +MobileConnectionChild::RecvNotifyLastNetworkChanged(const nsString& aNetwork) +{ + mLastNetwork.Assign(aNetwork); + + return true; +} + +bool +MobileConnectionChild::RecvNotifyLastHomeNetworkChanged(const nsString& aNetwork) +{ + mLastHomeNetwork.Assign(aNetwork); + + return true; +} + +bool +MobileConnectionChild::RecvNotifyNetworkSelectionModeChanged(const nsString& aMode) +{ + mNetworkSelectionMode.Assign(aMode); + + return true; +} + +/****************************************************************************** + * MobileConnectionRequestChild + ******************************************************************************/ + +void +MobileConnectionRequestChild::ActorDestroy(ActorDestroyReason why) +{ + mRequestCallback = nullptr; +} + +bool +MobileConnectionRequestChild::DoReply(const MobileConnectionReplySuccess& aReply) +{ + return NS_SUCCEEDED(mRequestCallback->NotifySuccess()); +} + +bool +MobileConnectionRequestChild::DoReply(const MobileConnectionReplySuccessString& aReply) +{ + return NS_SUCCEEDED(mRequestCallback->NotifySuccessWithString(aReply.result())); +} + +bool +MobileConnectionRequestChild::DoReply(const MobileConnectionReplySuccessBoolean& aReply) +{ + return NS_SUCCEEDED(mRequestCallback->NotifySuccessWithBoolean(aReply.result())); +} + +bool +MobileConnectionRequestChild::DoReply(const MobileConnectionReplySuccessNetworks& aReply) +{ + uint32_t count = aReply.results().Length(); + nsTArray<nsCOMPtr<nsIMobileNetworkInfo>> results; + for (uint32_t i = 0; i < count; i++) { + // Use dont_AddRef here because these instances are already AddRef-ed in + // MobileConnectionIPCSerializer.h + nsCOMPtr<nsIMobileNetworkInfo> item = dont_AddRef(aReply.results()[i]); + results.AppendElement(item); + } + + return NS_SUCCEEDED(mRequestCallback->NotifyGetNetworksSuccess(count, + const_cast<nsIMobileNetworkInfo**>(aReply.results().Elements()))); +} + +bool +MobileConnectionRequestChild::DoReply(const MobileConnectionReplySuccessMmi& aReply) +{ + nsAutoString serviceCode(aReply.serviceCode()); + nsAutoString statusMessage(aReply.statusMessage()); + AdditionalInformation info(aReply.additionalInformation()); + + nsRefPtr<MobileConnectionCallback> callback = static_cast<MobileConnectionCallback*>(mRequestCallback.get()); + + + // Handle union types + switch (info.type()) { + case AdditionalInformation::Tvoid_t: + return NS_SUCCEEDED(callback->NotifySendCancelMmiSuccess(serviceCode, + statusMessage)); + case AdditionalInformation::Tuint16_t: + return NS_SUCCEEDED(callback->NotifySendCancelMmiSuccess(serviceCode, + statusMessage, + info.get_uint16_t())); + case AdditionalInformation::TArrayOfnsString: + return NS_SUCCEEDED(callback->NotifySendCancelMmiSuccess(serviceCode, + statusMessage, + info.get_ArrayOfnsString())); + case AdditionalInformation::TArrayOfMozCallForwardingOptions: + return NS_SUCCEEDED(callback->NotifySendCancelMmiSuccess(serviceCode, + statusMessage, + info.get_ArrayOfMozCallForwardingOptions())); + + default: + MOZ_CRASH("Received invalid type!"); + } + + return false; +} + +bool +MobileConnectionRequestChild::DoReply(const MobileConnectionReplySuccessCallForwarding& aReply) +{ + nsRefPtr<MobileConnectionCallback> callback = static_cast<MobileConnectionCallback*>(mRequestCallback.get()); + return NS_SUCCEEDED(callback->NotifyGetCallForwardingSuccess(aReply.results())); +} + +bool +MobileConnectionRequestChild::DoReply(const MobileConnectionReplySuccessCallBarring& aReply) +{ + return NS_SUCCEEDED(mRequestCallback->NotifyGetCallBarringSuccess(aReply.program(), + aReply.enabled(), + aReply.serviceClass())); +} + +bool +MobileConnectionRequestChild::DoReply(const MobileConnectionReplySuccessClirStatus& aReply) +{ + return NS_SUCCEEDED(mRequestCallback->NotifyGetClirStatusSuccess(aReply.n(), + aReply.m())); +} + +bool +MobileConnectionRequestChild::DoReply(const MobileConnectionReplyError& aReply) +{ + return NS_SUCCEEDED(mRequestCallback->NotifyError(aReply.message())); +} + +bool +MobileConnectionRequestChild::DoReply(const MobileConnectionReplyErrorMmi& aReply) +{ + nsAutoString name(aReply.name()); + nsAutoString message(aReply.message()); + nsAutoString serviceCode(aReply.serviceCode()); + AdditionalInformation info(aReply.additionalInformation()); + + // Handle union types + switch (info.type()) { + case AdditionalInformation::Tuint16_t: + return NS_SUCCEEDED(mRequestCallback->NotifyError(name, + message, + serviceCode, + info.get_uint16_t())); + case AdditionalInformation::Tvoid_t: + default: + // If additionInfomation is not uint16_t, handle it as void_t. + return NS_SUCCEEDED(mRequestCallback->NotifyError(name, + message, + serviceCode)); + } + + return false; +} + +bool +MobileConnectionRequestChild::Recv__delete__(const MobileConnectionReply& aReply) +{ + MOZ_ASSERT(mRequestCallback); + + switch (aReply.type()) { + case MobileConnectionReply::TMobileConnectionReplySuccess: + return DoReply(aReply.get_MobileConnectionReplySuccess()); + case MobileConnectionReply::TMobileConnectionReplySuccessString: + return DoReply(aReply.get_MobileConnectionReplySuccessString()); + case MobileConnectionReply::TMobileConnectionReplySuccessBoolean: + return DoReply(aReply.get_MobileConnectionReplySuccessBoolean()); + case MobileConnectionReply::TMobileConnectionReplySuccessNetworks: + return DoReply(aReply.get_MobileConnectionReplySuccessNetworks()); + case MobileConnectionReply::TMobileConnectionReplySuccessMmi: + return DoReply(aReply.get_MobileConnectionReplySuccessMmi()); + case MobileConnectionReply::TMobileConnectionReplySuccessCallForwarding: + return DoReply(aReply.get_MobileConnectionReplySuccessCallForwarding()); + case MobileConnectionReply::TMobileConnectionReplySuccessCallBarring: + return DoReply(aReply.get_MobileConnectionReplySuccessCallBarring()); + case MobileConnectionReply::TMobileConnectionReplySuccessClirStatus: + return DoReply(aReply.get_MobileConnectionReplySuccessClirStatus()); + case MobileConnectionReply::TMobileConnectionReplyError: + return DoReply(aReply.get_MobileConnectionReplyError()); + case MobileConnectionReply::TMobileConnectionReplyErrorMmi: + return DoReply(aReply.get_MobileConnectionReplyErrorMmi()); + default: + MOZ_CRASH("Received invalid response type!"); + } + + return false; +}
new file mode 100644 --- /dev/null +++ b/dom/mobileconnection/ipc/MobileConnectionChild.h @@ -0,0 +1,221 @@ +/* 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/. */ + +#ifndef mozilla_dom_mobileconnection_MobileConnectionChild_h +#define mozilla_dom_mobileconnection_MobileConnectionChild_h + +#include "mozilla/dom/MobileConnectionCallback.h" +#include "mozilla/dom/MobileConnectionInfo.h" +#include "mozilla/dom/PMobileConnectionChild.h" +#include "mozilla/dom/PMobileConnectionRequestChild.h" +#include "nsCOMArray.h" +#include "nsCOMPtr.h" +#include "nsIMobileConnectionService.h" +#include "nsIVariant.h" + +namespace mozilla { +namespace dom { +namespace mobileconnection { + +/** + * Child actor of PMobileConnection. The object is created by + * MobileConnectionIPCService and destroyed after MobileConnectionIPCService is + * shutdown. For multi-sim device, more than one instance will + * be created and each instance represents a sim slot. + */ +class MobileConnectionChild : public PMobileConnectionChild +{ + NS_INLINE_DECL_REFCOUNTING(MobileConnectionChild) + +public: + MobileConnectionChild() + : mLive(true) + { + MOZ_COUNT_CTOR(MobileConnectionChild); + } + + void + Init(); + + void + Shutdown(); + + void + RegisterListener(nsIMobileConnectionListener* aListener); + + void + UnregisterListener(nsIMobileConnectionListener* aListener); + + MobileConnectionInfo* + GetVoiceInfo(); + + MobileConnectionInfo* + GetDataInfo(); + + void + GetIccId(nsAString& aIccId); + + void + GetRadioState(nsAString& aRadioState); + + nsIVariant* + GetSupportedNetworkTypes(); + + void + GetLastNetwork(nsAString& aNetwork); + + void + GetLastHomeNetwork(nsAString& aNetwork); + + void + GetNetworkSelectionMode(nsAString& aMode); + + bool + SendRequest(MobileConnectionRequest aRequest, + nsIMobileConnectionCallback* aRequestCallback); + +protected: + virtual + ~MobileConnectionChild() + { + MOZ_COUNT_DTOR(MobileConnectionChild); + Shutdown(); + } + + virtual void + ActorDestroy(ActorDestroyReason why) MOZ_OVERRIDE; + + virtual PMobileConnectionRequestChild* + AllocPMobileConnectionRequestChild(const MobileConnectionRequest& request) MOZ_OVERRIDE; + + virtual bool + DeallocPMobileConnectionRequestChild(PMobileConnectionRequestChild* aActor) MOZ_OVERRIDE; + + virtual bool + RecvNotifyVoiceInfoChanged(nsIMobileConnectionInfo* const& aInfo) MOZ_OVERRIDE; + + virtual bool + RecvNotifyDataInfoChanged(nsIMobileConnectionInfo* const& aInfo) MOZ_OVERRIDE; + + virtual bool + RecvNotifyUssdReceived(const nsString& aMessage, + const bool& aSessionEnd) MOZ_OVERRIDE; + + virtual bool + RecvNotifyDataError(const nsString& aMessage) MOZ_OVERRIDE; + + virtual bool + RecvNotifyCFStateChanged(const bool& aSuccess, const uint16_t& aAction, + const uint16_t& aReason, const nsString& aNumber, + const uint16_t& aTimeSeconds, const uint16_t& aServiceClass) MOZ_OVERRIDE; + + virtual bool + RecvNotifyEmergencyCbModeChanged(const bool& aActive, + const uint32_t& aTimeoutMs) MOZ_OVERRIDE; + + virtual bool + RecvNotifyOtaStatusChanged(const nsString& aStatus) MOZ_OVERRIDE; + + virtual bool + RecvNotifyIccChanged(const nsString& aIccId) MOZ_OVERRIDE; + + virtual bool + RecvNotifyRadioStateChanged(const nsString& aRadioState) MOZ_OVERRIDE; + + virtual bool + RecvNotifyClirModeChanged(const uint32_t& aMode) MOZ_OVERRIDE; + + virtual bool + RecvNotifyLastNetworkChanged(const nsString& aNetwork) MOZ_OVERRIDE; + + virtual bool + RecvNotifyLastHomeNetworkChanged(const nsString& aNetwork) MOZ_OVERRIDE; + + virtual bool + RecvNotifyNetworkSelectionModeChanged(const nsString& aMode) MOZ_OVERRIDE; + +private: + bool mLive; + nsCOMArray<nsIMobileConnectionListener> mListeners; + nsCOMPtr<nsIWritableVariant> mSupportedNetworkTypes; + nsRefPtr<MobileConnectionInfo> mVoice; + nsRefPtr<MobileConnectionInfo> mData; + nsString mIccId; + nsString mRadioState; + nsString mLastNetwork; + nsString mLastHomeNetwork; + nsString mNetworkSelectionMode; +}; + +/****************************************************************************** + * PMobileConnectionRequestChild + ******************************************************************************/ + +/** + * Child actor of PMobileConnectionRequest. The object is created when an + * asynchronous request is made and destroyed after receiving the response sent + * by parent actor. + */ +class MobileConnectionRequestChild : public PMobileConnectionRequestChild +{ +public: + MobileConnectionRequestChild(nsIMobileConnectionCallback* aRequestCallback) + : mRequestCallback(aRequestCallback) + { + MOZ_COUNT_CTOR(MobileConnectionRequestChild); + MOZ_ASSERT(mRequestCallback); + } + + bool + DoReply(const MobileConnectionReplySuccess& aReply); + + bool + DoReply(const MobileConnectionReplySuccessString& aReply); + + bool + DoReply(const MobileConnectionReplySuccessBoolean& aReply); + + bool + DoReply(const MobileConnectionReplySuccessNetworks& aReply); + + bool + DoReply(const MobileConnectionReplySuccessMmi& aReply); + + bool + DoReply(const MobileConnectionReplySuccessCallForwarding& aReply); + + bool + DoReply(const MobileConnectionReplySuccessCallBarring& aReply); + + bool + DoReply(const MobileConnectionReplySuccessClirStatus& aReply); + + bool + DoReply(const MobileConnectionReplyError& aReply); + + bool + DoReply(const MobileConnectionReplyErrorMmi& aReply); + +protected: + virtual + ~MobileConnectionRequestChild() + { + MOZ_COUNT_DTOR(MobileConnectionRequestChild); + } + + virtual void + ActorDestroy(ActorDestroyReason why) MOZ_OVERRIDE; + + virtual bool + Recv__delete__(const MobileConnectionReply& aReply) MOZ_OVERRIDE; + +private: + nsCOMPtr<nsIMobileConnectionCallback> mRequestCallback; +}; + +} // namespace mobileconnection +} // namespace dom +} // namespace mozilla + +#endif // mozilla_dom_mobileconnection_MobileConnectionChild_h
new file mode 100644 --- /dev/null +++ b/dom/mobileconnection/ipc/MobileConnectionIPCSerializer.h @@ -0,0 +1,749 @@ +/* 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/. */ + +#ifndef dom_mobileconnection_src_ipc_MobileConnectionIPCSerialiser_h +#define dom_mobileconnection_src_ipc_MobileConnectionIPCSerialiser_h + +#include "ipc/IPCMessageUtils.h" +#include "mozilla/dom/MobileCellInfo.h" +#include "mozilla/dom/MobileConnectionInfo.h" +#include "mozilla/dom/MobileNetworkInfo.h" +#include "MozMobileConnectionBinding.h" + +using mozilla::AutoSafeJSContext; +using mozilla::dom::MobileNetworkInfo; +using mozilla::dom::MobileCellInfo; +using mozilla::dom::MobileConnectionInfo; + +typedef nsIMobileCellInfo* nsMobileCellInfo; +typedef nsIMobileConnectionInfo* nsMobileConnectionInfo; +typedef nsIMobileNetworkInfo* nsMobileNetworkInfo; + +namespace IPC { + +struct MozCallForwardingOptions : public mozilla::dom::MozCallForwardingOptions +{ + bool operator==(const MozCallForwardingOptions& aOther) const + { + return // Compare mActive + ((!mActive.WasPassed() && !aOther.mActive.WasPassed()) || + (mActive.WasPassed() && aOther.mActive.WasPassed() && + mActive.Value() == aOther.mActive.Value())) && + // Compare mAction + ((!mAction.WasPassed() && !aOther.mAction.WasPassed()) || + (mAction.WasPassed() && aOther.mAction.WasPassed() && + mAction.Value() == aOther.mAction.Value())) && + // Compare mReason + ((!mReason.WasPassed() && !aOther.mReason.WasPassed()) || + (mReason.WasPassed() && aOther.mReason.WasPassed() && + mReason.Value() == aOther.mReason.Value())) && + // Compare mNumber + ((!mNumber.WasPassed() && !aOther.mNumber.WasPassed()) || + (mNumber.WasPassed() && aOther.mNumber.WasPassed() && + mNumber.Value() == aOther.mNumber.Value())) && + // Compare mTimeSeconds + ((!mTimeSeconds.WasPassed() && !aOther.mTimeSeconds.WasPassed()) || + (mTimeSeconds.WasPassed() && aOther.mTimeSeconds.WasPassed() && + mTimeSeconds.Value() == aOther.mTimeSeconds.Value())) && + // Compare mServiceClass + ((!mServiceClass.WasPassed() && !aOther.mServiceClass.WasPassed()) || + (mServiceClass.WasPassed() && aOther.mServiceClass.WasPassed() && + mServiceClass.Value() == aOther.mServiceClass.Value())); + }; +}; + +struct MozCallBarringOptions : mozilla::dom::MozCallBarringOptions +{ + bool operator==(const MozCallBarringOptions& aOther) const + { + return // Compare mEnabled + ((!mEnabled.WasPassed() && !aOther.mEnabled.WasPassed()) || + (mEnabled.WasPassed() && aOther.mEnabled.WasPassed() && + mEnabled.Value() == aOther.mEnabled.Value())) && + // Compare mPassword + ((!mPassword.WasPassed() && !aOther.mPassword.WasPassed()) || + (mPassword.WasPassed() && aOther.mPassword.WasPassed() && + mPassword.Value() == aOther.mPassword.Value())) && + // Compare mProgram + ((!mProgram.WasPassed() && !aOther.mProgram.WasPassed()) || + (mProgram.WasPassed() && aOther.mProgram.WasPassed() && + mProgram.Value() == aOther.mProgram.Value())) && + // Compare mServiceClass + ((!mServiceClass.WasPassed() && !aOther.mServiceClass.WasPassed()) || + (mServiceClass.WasPassed() && aOther.mServiceClass.WasPassed() && + mServiceClass.Value() == aOther.mServiceClass.Value())); + }; +}; + +/** + * nsIMobileNetworkInfo Serialize/De-serialize. + */ +template <> +struct ParamTraits<nsIMobileNetworkInfo*> +{ + typedef nsIMobileNetworkInfo* paramType; + + // Function to serialize a MobileNetworkInfo. + static void Write(Message *aMsg, const paramType& aParam) + { + bool isNull = !aParam; + WriteParam(aMsg, isNull); + // If it is a null object, then we are done. + if (isNull) { + return; + } + + nsString pString; + aParam->GetShortName(pString); + WriteParam(aMsg, pString); + + aParam->GetLongName(pString); + WriteParam(aMsg, pString); + + aParam->GetMcc(pString); + WriteParam(aMsg, pString); + + aParam->GetMnc(pString); + WriteParam(aMsg, pString); + + aParam->GetState(pString); + WriteParam(aMsg, pString); + + // We release the ref here given that ipdl won't handle reference counting. + aParam->Release(); + } + + // Function to de-serialize a MobileNetworkInfo. + static bool Read(const Message *aMsg, void **aIter, paramType* aResult) + { + // Check if is the null pointer we have transfered. + bool isNull; + if (!ReadParam(aMsg, aIter, &isNull)) { + return false; + } + + if (isNull) { + *aResult = nullptr; + return true; + } + + nsString shortName; + nsString longName; + nsString mcc; + nsString mnc; + nsString state; + + // It's not important to us where it fails, but rather if it fails + if (!(ReadParam(aMsg, aIter, &shortName) && + ReadParam(aMsg, aIter, &longName) && + ReadParam(aMsg, aIter, &mcc) && + ReadParam(aMsg, aIter, &mnc) && + ReadParam(aMsg, aIter, &state))) { + return false; + } + + *aResult = new MobileNetworkInfo(shortName, + longName, + mcc, + mnc, + state); + // We release this ref after receiver finishes processing. + NS_ADDREF(*aResult); + + return true; + } +}; + +/** + * nsIMobileCellInfo Serialize/De-serialize. + */ +template <> +struct ParamTraits<nsIMobileCellInfo*> +{ + typedef nsIMobileCellInfo* paramType; + + // Function to serialize a MobileCellInfo. + static void Write(Message *aMsg, const paramType& aParam) + { + bool isNull = !aParam; + WriteParam(aMsg, isNull); + // If it is a null object, then we are done. + if (isNull) { + return; + } + + int32_t pLong; + int64_t pLongLong; + + aParam->GetGsmLocationAreaCode(&pLong); + WriteParam(aMsg, pLong); + + aParam->GetGsmCellId(&pLongLong); + WriteParam(aMsg, pLongLong); + + aParam->GetCdmaBaseStationId(&pLong); + WriteParam(aMsg, pLong); + + aParam->GetCdmaBaseStationLatitude(&pLong); + WriteParam(aMsg, pLong); + + aParam->GetCdmaBaseStationLongitude(&pLong); + WriteParam(aMsg, pLong); + + aParam->GetCdmaSystemId(&pLong); + WriteParam(aMsg, pLong); + + aParam->GetCdmaNetworkId(&pLong); + WriteParam(aMsg, pLong); + + // We release the ref here given that ipdl won't handle reference counting. + aParam->Release(); + } + + // Function to de-serialize a MobileCellInfo. + static bool Read(const Message *aMsg, void **aIter, paramType* aResult) + { + // Check if is the null pointer we have transfered. + bool isNull; + if (!ReadParam(aMsg, aIter, &isNull)) { + return false; + } + + if (isNull) { + *aResult = nullptr; + return true; + } + + int32_t gsmLac; + int64_t gsmCellId; + int32_t cdmaBsId; + int32_t cdmaBsLat; + int32_t cdmaBsLong; + int32_t cdmaSystemId; + int32_t cdmaNetworkId; + + // It's not important to us where it fails, but rather if it fails + if (!(ReadParam(aMsg, aIter, &gsmLac) && + ReadParam(aMsg, aIter, &gsmCellId) && + ReadParam(aMsg, aIter, &cdmaBsId) && + ReadParam(aMsg, aIter, &cdmaBsLat) && + ReadParam(aMsg, aIter, &cdmaBsLong) && + ReadParam(aMsg, aIter, &cdmaSystemId) && + ReadParam(aMsg, aIter, &cdmaNetworkId))) { + return false; + } + + *aResult = new MobileCellInfo(gsmLac, gsmCellId, cdmaBsId, cdmaBsLat, + cdmaBsLong, cdmaSystemId, cdmaNetworkId); + // We release this ref after receiver finishes processing. + NS_ADDREF(*aResult); + + return true; + } +}; + +/** + * nsIMobileConnectionInfo Serialize/De-serialize. + */ +template <> +struct ParamTraits<nsIMobileConnectionInfo*> +{ + typedef nsIMobileConnectionInfo* paramType; + + // Function to serialize a MobileConnectionInfo. + static void Write(Message *aMsg, const paramType& aParam) + { + bool isNull = !aParam; + WriteParam(aMsg, isNull); + // If it is a null object, then we are done. + if (isNull) { + return; + } + + AutoSafeJSContext cx; + nsString pString; + bool pBool; + nsCOMPtr<nsIMobileNetworkInfo> pNetworkInfo; + nsCOMPtr<nsIMobileCellInfo> pCellInfo; + JS::Rooted<JS::Value> pJsval(cx); + int32_t pInt32; + + aParam->GetState(pString); + WriteParam(aMsg, pString); + + aParam->GetConnected(&pBool); + WriteParam(aMsg, pBool); + + aParam->GetEmergencyCallsOnly(&pBool); + WriteParam(aMsg, pBool); + + aParam->GetRoaming(&pBool); + WriteParam(aMsg, pBool); + + aParam->GetType(pString); + WriteParam(aMsg, pString); + + aParam->GetNetwork(getter_AddRefs(pNetworkInfo)); + // Release ref when WriteParam is finished. + WriteParam(aMsg, pNetworkInfo.forget().take()); + + aParam->GetCell(getter_AddRefs(pCellInfo)); + // Release ref when WriteParam is finished. + WriteParam(aMsg, pCellInfo.forget().take()); + + // Serialize jsval signalStrength + aParam->GetSignalStrength(&pJsval); + isNull = !pJsval.isInt32(); + WriteParam(aMsg, isNull); + + if (!isNull) { + pInt32 = pJsval.toInt32(); + WriteParam(aMsg, pInt32); + } + + // Serialize jsval relSignalStrength + aParam->GetRelSignalStrength(&pJsval); + isNull = !pJsval.isInt32(); + WriteParam(aMsg, isNull); + + if (!isNull) { + pInt32 = pJsval.toInt32(); + WriteParam(aMsg, pInt32); + } + + // We release the ref here given that ipdl won't handle reference counting. + aParam->Release(); + } + + // Function to de-serialize a MobileConectionInfo. + static bool Read(const Message* aMsg, void **aIter, paramType* aResult) + { + // Check if is the null pointer we have transfered. + bool isNull; + if (!ReadParam(aMsg, aIter, &isNull)) { + return false; + } + + if (isNull) { + *aResult = nullptr; + return true; + } + + AutoSafeJSContext cx; + nsString state; + bool connected; + bool emergencyOnly; + bool roaming; + nsString type; + nsIMobileNetworkInfo* networkInfo = nullptr; + nsIMobileCellInfo* cellInfo = nullptr; + Nullable<int32_t> signalStrength; + Nullable<uint16_t> relSignalStrength; + + // It's not important to us where it fails, but rather if it fails + if (!(ReadParam(aMsg, aIter, &state) && + ReadParam(aMsg, aIter, &connected) && + ReadParam(aMsg, aIter, &emergencyOnly) && + ReadParam(aMsg, aIter, &roaming) && + ReadParam(aMsg, aIter, &type) && + ReadParam(aMsg, aIter, &networkInfo) && + ReadParam(aMsg, aIter, &cellInfo))) { + return false; + } + + // De-serialize jsval signalStrength + if (!ReadParam(aMsg, aIter, &isNull)) { + return false; + } + + if (!isNull) { + int32_t value; + + if (!ReadParam(aMsg, aIter, &value)) { + return false; + } + + signalStrength.SetValue(value); + } + + // De-serialize jsval relSignalStrength + if (!ReadParam(aMsg, aIter, &isNull)) { + return false; + } + + if (!isNull) { + int32_t value; + + if (!ReadParam(aMsg, aIter, &value)) { + return false; + } + + relSignalStrength.SetValue(uint16_t(value)); + } + + *aResult = new MobileConnectionInfo(state, + connected, + emergencyOnly, + roaming, + networkInfo, + type, + signalStrength, + relSignalStrength, + cellInfo); + // We release this ref after receiver finishes processing. + NS_ADDREF(*aResult); + // We already clone the data into MobileConnectionInfo, so release the ref + // of networkInfo and cellInfo here. + NS_IF_RELEASE(networkInfo); + NS_IF_RELEASE(cellInfo); + + return true; + } +}; + +/** + * MozCallForwardingOptions Serialize/De-serialize. + */ +template <> +struct ParamTraits<MozCallForwardingOptions> +{ + typedef MozCallForwardingOptions paramType; + + // Function to serialize a MozCallForwardingOptions. + static void Write(Message *aMsg, const paramType& aParam) + { + bool wasPassed = false; + bool isNull = false; + + // Write mActive + wasPassed = aParam.mActive.WasPassed(); + WriteParam(aMsg, wasPassed); + if (wasPassed) { + isNull = aParam.mActive.Value().IsNull(); + WriteParam(aMsg, isNull); + if (!isNull) { + WriteParam(aMsg, aParam.mActive.Value().Value()); + } + } + + // Write mAction + wasPassed = aParam.mAction.WasPassed(); + WriteParam(aMsg, wasPassed); + if (wasPassed) { + isNull = aParam.mAction.Value().IsNull(); + WriteParam(aMsg, isNull); + if (!isNull) { + WriteParam(aMsg, aParam.mAction.Value().Value()); + } + } + + // Write mReason + wasPassed = aParam.mReason.WasPassed(); + WriteParam(aMsg, wasPassed); + if (wasPassed) { + isNull = aParam.mReason.Value().IsNull(); + WriteParam(aMsg, isNull); + if (!isNull) { + WriteParam(aMsg, aParam.mReason.Value().Value()); + } + } + + // Write mNumber + wasPassed = aParam.mNumber.WasPassed(); + WriteParam(aMsg, wasPassed); + if (wasPassed) { + WriteParam(aMsg, aParam.mNumber.Value()); + } + + // Write mTimeSeconds + wasPassed = aParam.mTimeSeconds.WasPassed(); + WriteParam(aMsg, wasPassed); + if (wasPassed) { + isNull = aParam.mTimeSeconds.Value().IsNull(); + WriteParam(aMsg, isNull); + if (!isNull) { + WriteParam(aMsg, aParam.mTimeSeconds.Value().Value()); + } + } + + // Write mServiceClass + wasPassed = aParam.mServiceClass.WasPassed(); + WriteParam(aMsg, wasPassed); + if (wasPassed) { + isNull = aParam.mServiceClass.Value().IsNull(); + WriteParam(aMsg, isNull); + if (!isNull) { + WriteParam(aMsg, aParam.mServiceClass.Value().Value()); + } + } + } + + // Function to de-serialize a MozCallForwardingOptions. + static bool Read(const Message *aMsg, void **aIter, paramType* aResult) + { + bool wasPassed = false; + bool isNull = false; + + // Read mActive + if (!ReadParam(aMsg, aIter, &wasPassed)) { + return false; + } + if (wasPassed) { + aResult->mActive.Construct(); + if (!ReadParam(aMsg, aIter, &isNull)) { + return false; + } + + if (!isNull) { + if (!ReadParam(aMsg, aIter, &aResult->mActive.Value().SetValue())) { + return false; + } + } + } + + // Read mAction + if (!ReadParam(aMsg, aIter, &wasPassed)) { + return false; + } + if (wasPassed) { + aResult->mAction.Construct(); + if (!ReadParam(aMsg, aIter, &isNull)) { + return false; + } + + if (!isNull) { + if (!ReadParam(aMsg, aIter, &aResult->mAction.Value().SetValue())) { + return false; + } + } + } + + // Read mReason + if (!ReadParam(aMsg, aIter, &wasPassed)) { + return false; + } + if (wasPassed) { + aResult->mReason.Construct(); + if (!ReadParam(aMsg, aIter, &isNull)) { + return false; + } + + if (!isNull) { + if (!ReadParam(aMsg, aIter, &aResult->mReason.Value().SetValue())) { + return false; + } + } + } + + // Read mNumber + if (!ReadParam(aMsg, aIter, &wasPassed)) { + return false; + } + if (wasPassed) { + if (!ReadParam(aMsg, aIter, &aResult->mNumber.Construct())) { + return false; + } + } + + // Read mTimeSeconds + if (!ReadParam(aMsg, aIter, &wasPassed)) { + return false; + } + if (wasPassed) { + aResult->mTimeSeconds.Construct(); + if (!ReadParam(aMsg, aIter, &isNull)) { + return false; + } + + if (!isNull) { + if (!ReadParam(aMsg, aIter, &aResult->mTimeSeconds.Value().SetValue())) { + return false; + } + } + } + + // Read mServiceClass + if (!ReadParam(aMsg, aIter, &wasPassed)) { + return false; + } + if (wasPassed) { + aResult->mServiceClass.Construct(); + if (!ReadParam(aMsg, aIter, &isNull)) { + return false; + } + + if (!isNull) { + if (!ReadParam(aMsg, aIter, &aResult->mServiceClass.Value().SetValue())) { + return false; + } + } + } + + return true; + } +}; + +/** + * MozCallBarringOptions Serialize/De-serialize. + */ +template <> +struct ParamTraits<MozCallBarringOptions> +{ + typedef MozCallBarringOptions paramType; + + // Function to serialize a MozCallBarringOptions. + static void Write(Message *aMsg, const paramType& aParam) + { + bool wasPassed = false; + bool isNull = false; + + // Write mProgram + wasPassed = aParam.mProgram.WasPassed(); + WriteParam(aMsg, wasPassed); + if (wasPassed) { + isNull = aParam.mProgram.Value().IsNull(); + WriteParam(aMsg, isNull); + if (!isNull) { + WriteParam(aMsg, aParam.mProgram.Value().Value()); + } + } + + // Write mEnabled + wasPassed = aParam.mEnabled.WasPassed(); + WriteParam(aMsg, wasPassed); + if (wasPassed) { + isNull = aParam.mEnabled.Value().IsNull(); + WriteParam(aMsg, isNull); + if (!isNull) { + WriteParam(aMsg, aParam.mEnabled.Value().Value()); + } + } + + // Write mPassword + wasPassed = aParam.mPassword.WasPassed(); + WriteParam(aMsg, wasPassed); + if (wasPassed) { + WriteParam(aMsg, aParam.mPassword.Value()); + } + + // Write mServiceClass + wasPassed = aParam.mServiceClass.WasPassed(); + WriteParam(aMsg, wasPassed); + if (wasPassed) { + isNull = aParam.mServiceClass.Value().IsNull(); + WriteParam(aMsg, isNull); + if (!isNull) { + WriteParam(aMsg, aParam.mServiceClass.Value().Value()); + } + } + + // Write mPin + wasPassed = aParam.mPin.WasPassed(); + WriteParam(aMsg, wasPassed); + if (wasPassed) { + WriteParam(aMsg, aParam.mPin.Value()); + } + + // Write mNewPin + wasPassed = aParam.mNewPin.WasPassed(); + WriteParam(aMsg, wasPassed); + if (wasPassed) { + WriteParam(aMsg, aParam.mNewPin.Value()); + } + } + + // Function to de-serialize a MozCallBarringOptions. + static bool Read(const Message *aMsg, void **aIter, paramType* aResult) + { + bool wasPassed = false; + bool isNull = false; + + // Read mProgram + if (!ReadParam(aMsg, aIter, &wasPassed)) { + return false; + } + if (wasPassed) { + aResult->mProgram.Construct(); + if (!ReadParam(aMsg, aIter, &isNull)) { + return false; + } + + if (!isNull) { + if (!ReadParam(aMsg, aIter, &aResult->mProgram.Value().SetValue())) { + return false; + } + } + } + + // Read mEnabled + if (!ReadParam(aMsg, aIter, &wasPassed)) { + return false; + } + if (wasPassed) { + aResult->mEnabled.Construct(); + if (!ReadParam(aMsg, aIter, &isNull)) { + return false; + } + + if (!isNull) { + if (!ReadParam(aMsg, aIter, &aResult->mEnabled.Value().SetValue())) { + return false; + } + } + } + + // Read mPassword + if (!ReadParam(aMsg, aIter, &wasPassed)) { + return false; + } + if (wasPassed) { + if (!ReadParam(aMsg, aIter, &aResult->mPassword.Construct())) { + return false; + } + } + + // Read mServiceClass + if (!ReadParam(aMsg, aIter, &wasPassed)) { + return false; + } + if (wasPassed) { + aResult->mServiceClass.Construct(); + if (!ReadParam(aMsg, aIter, &isNull)) { + return false; + } + + if (!isNull) { + if (!ReadParam(aMsg, aIter, &aResult->mServiceClass.Value().SetValue())) { + return false; + } + } + } + + // Read mPin + if (!ReadParam(aMsg, aIter, &wasPassed)) { + return false; + } + if (wasPassed) { + if (!ReadParam(aMsg, aIter, &aResult->mPin.Construct())) { + return false; + } + } + + // Read mNewPin + if (!ReadParam(aMsg, aIter, &wasPassed)) { + return false; + } + if (wasPassed) { + if (!ReadParam(aMsg, aIter, &aResult->mNewPin.Construct())) { + return false; + } + } + + return true; + } +}; + +} // namespace IPC + +#endif // dom_mobileconnection_src_ipc_MobileConnectionIPCSerialiser_h
new file mode 100644 --- /dev/null +++ b/dom/mobileconnection/ipc/MobileConnectionIPCService.cpp @@ -0,0 +1,394 @@ +/* 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/. */ + +#include "MobileConnectionIPCService.h" + +#include "mozilla/dom/ContentChild.h" +#include "mozilla/Preferences.h" +#include "mozilla/StaticPtr.h" + +using namespace mozilla; +using namespace mozilla::dom; +using namespace mozilla::dom::mobileconnection; + +NS_IMPL_ISUPPORTS(MobileConnectionIPCService, nsIMobileConnectionService) + +StaticRefPtr<MobileConnectionIPCService> sService; + +/* static */MobileConnectionIPCService* +MobileConnectionIPCService::GetSingleton() +{ + MOZ_ASSERT(NS_IsMainThread()); + + if (sService) { + return sService; + } + + sService = new MobileConnectionIPCService(); + return sService; +} + +MobileConnectionIPCService::MobileConnectionIPCService() +{ + int32_t numRil = Preferences::GetInt("ril.numRadioInterfaces", 1); + for (int32_t i = 0; i < numRil; i++) { + // Deallocated in ContentChild::DeallocPMobileConnectionChild(). + nsRefPtr<MobileConnectionChild> client = new MobileConnectionChild(); + NS_ASSERTION(client, "This shouldn't fail!"); + + ContentChild::GetSingleton()->SendPMobileConnectionConstructor(client, i); + client->Init(); + + mClients.AppendElement(client); + } +} + +MobileConnectionIPCService::~MobileConnectionIPCService() +{ + uint32_t count = mClients.Length(); + for (uint32_t i = 0; i < count; i++) { + mClients[i]->Shutdown(); + } + + mClients.Clear(); +} + +nsresult +MobileConnectionIPCService::SendRequest(uint32_t aClientId, + MobileConnectionRequest aRequest, + nsIMobileConnectionCallback* aRequestCallback) +{ + if (aClientId >= mClients.Length()) { + return NS_ERROR_FAILURE; + } + + mClients[aClientId]->SendRequest(aRequest, aRequestCallback); + return NS_OK; +} + +// nsIMobileConnectionService + +NS_IMETHODIMP +MobileConnectionIPCService::RegisterListener(uint32_t aClientId, + nsIMobileConnectionListener* aListener) +{ + if (aClientId >= mClients.Length()) { + return NS_ERROR_FAILURE; + } + + mClients[aClientId]->RegisterListener(aListener); + return NS_OK; +} + +NS_IMETHODIMP +MobileConnectionIPCService::UnregisterListener(uint32_t aClientId, + nsIMobileConnectionListener* aListener) +{ + if (aClientId >= mClients.Length()) { + return NS_ERROR_FAILURE; + } + + mClients[aClientId]->UnregisterListener(aListener); + return NS_OK; +} + +NS_IMETHODIMP +MobileConnectionIPCService::GetLastKnownNetwork(uint32_t aClientId, + nsAString& aLastNetwork) +{ + if (aClientId >= mClients.Length()) { + return NS_ERROR_FAILURE; + } + + mClients[aClientId]->GetLastNetwork(aLastNetwork); + return NS_OK; +} + +NS_IMETHODIMP +MobileConnectionIPCService::GetLastKnownHomeNetwork(uint32_t aClientId, + nsAString& aLastNetwork) +{ + if (aClientId >= mClients.Length()) { + return NS_ERROR_FAILURE; + } + + mClients[aClientId]->GetLastHomeNetwork(aLastNetwork); + return NS_OK; +} + +NS_IMETHODIMP +MobileConnectionIPCService::GetVoiceConnectionInfo(uint32_t aClientId, + nsIMobileConnectionInfo** aInfo) +{ + if (aClientId >= mClients.Length()) { + return NS_ERROR_FAILURE; + } + + nsCOMPtr<nsIMobileConnectionInfo> info = mClients[aClientId]->GetVoiceInfo(); + info.forget(aInfo); + + return NS_OK; +} + +NS_IMETHODIMP +MobileConnectionIPCService::GetDataConnectionInfo(uint32_t aClientId, + nsIMobileConnectionInfo** aInfo) +{ + if (aClientId >= mClients.Length()) { + return NS_ERROR_FAILURE; + } + + nsCOMPtr<nsIMobileConnectionInfo> info = mClients[aClientId]->GetDataInfo(); + info.forget(aInfo); + + return NS_OK; +} + +NS_IMETHODIMP +MobileConnectionIPCService::GetIccId(uint32_t aClientId, nsAString& aIccId) +{ + if (aClientId >= mClients.Length()) { + return NS_ERROR_FAILURE; + } + + mClients[aClientId]->GetIccId(aIccId); + return NS_OK; +} + +NS_IMETHODIMP +MobileConnectionIPCService::GetNetworkSelectionMode(uint32_t aClientId, + nsAString& aNetworkSelectionMode) +{ + if (aClientId >= mClients.Length()) { + return NS_ERROR_FAILURE; + } + + mClients[aClientId]->GetNetworkSelectionMode(aNetworkSelectionMode); + return NS_OK; +} + +NS_IMETHODIMP +MobileConnectionIPCService::GetRadioState(uint32_t aClientId, + nsAString& aRadioState) +{ + if (aClientId >= mClients.Length()) { + return NS_ERROR_FAILURE; + } + + mClients[aClientId]->GetRadioState(aRadioState); + return NS_OK; +} + +NS_IMETHODIMP +MobileConnectionIPCService::GetSupportedNetworkTypes(uint32_t aClientId, + nsIVariant** aSupportedTypes) +{ + if (aClientId >= mClients.Length()) { + return NS_ERROR_FAILURE; + } + + nsCOMPtr<nsIVariant> supportedTypes = mClients[aClientId]->GetSupportedNetworkTypes(); + supportedTypes.forget(aSupportedTypes); + + return NS_OK; +} + +NS_IMETHODIMP +MobileConnectionIPCService::GetNetworks(uint32_t aClientId, + nsIMobileConnectionCallback* aRequest) +{ + return SendRequest(aClientId, GetNetworksRequest(), aRequest); +} + +NS_IMETHODIMP +MobileConnectionIPCService::SelectNetwork(uint32_t aClientId, + nsIMobileNetworkInfo* aNetwork, + nsIMobileConnectionCallback* aRequest) +{ + nsCOMPtr<nsIMobileNetworkInfo> network = aNetwork; + // We release the ref after serializing process is finished in + // MobileConnectionIPCSerializer. + return SendRequest(aClientId, SelectNetworkRequest(network.forget().take()), aRequest); +} + +NS_IMETHODIMP +MobileConnectionIPCService::SelectNetworkAutomatically(uint32_t aClientId, + nsIMobileConnectionCallback* aRequest) +{ + return SendRequest(aClientId, SelectNetworkAutoRequest(), aRequest); +} + + +NS_IMETHODIMP +MobileConnectionIPCService::SetPreferredNetworkType(uint32_t aClientId, + const nsAString& aType, + nsIMobileConnectionCallback* aRequest) +{ + return SendRequest(aClientId, + SetPreferredNetworkTypeRequest(nsAutoString(aType)), + aRequest); +} + +NS_IMETHODIMP +MobileConnectionIPCService::GetPreferredNetworkType(uint32_t aClientId, + nsIMobileConnectionCallback* aRequest) +{ + return SendRequest(aClientId, GetPreferredNetworkTypeRequest(), aRequest); +} + +NS_IMETHODIMP +MobileConnectionIPCService::SetRoamingPreference(uint32_t aClientId, + const nsAString& aMode, + nsIMobileConnectionCallback* aRequest) +{ + return SendRequest(aClientId, + SetRoamingPreferenceRequest(nsAutoString(aMode)), + aRequest); +} + +NS_IMETHODIMP +MobileConnectionIPCService::GetRoamingPreference(uint32_t aClientId, + nsIMobileConnectionCallback* aRequest) +{ + return SendRequest(aClientId, GetRoamingPreferenceRequest(), aRequest); +} + +NS_IMETHODIMP +MobileConnectionIPCService::SetVoicePrivacyMode(uint32_t aClientId, + bool aEnabled, + nsIMobileConnectionCallback* aRequest) +{ + return SendRequest(aClientId, SetVoicePrivacyModeRequest(aEnabled), aRequest); +} + +NS_IMETHODIMP +MobileConnectionIPCService::GetVoicePrivacyMode(uint32_t aClientId, + nsIMobileConnectionCallback* aRequest) +{ + return SendRequest(aClientId, GetVoicePrivacyModeRequest(), aRequest); +} + +NS_IMETHODIMP +MobileConnectionIPCService::SendMMI(uint32_t aClientId, + const nsAString& aMmi, + nsIMobileConnectionCallback* aRequest) +{ + return SendRequest(aClientId, SendMmiRequest(nsAutoString(aMmi)), aRequest); +} + +NS_IMETHODIMP +MobileConnectionIPCService::CancelMMI(uint32_t aClientId, + nsIMobileConnectionCallback* aRequest) +{ + return SendRequest(aClientId, CancelMmiRequest(), aRequest); +} + +NS_IMETHODIMP +MobileConnectionIPCService::SetCallForwarding(uint32_t aClientId, + JS::Handle<JS::Value> aOptions, + nsIMobileConnectionCallback* aRequest) +{ + AutoSafeJSContext cx; + IPC::MozCallForwardingOptions options; + if(!options.Init(cx, aOptions)) { + return NS_ERROR_TYPE_ERR; + } + + return SendRequest(aClientId, SetCallForwardingRequest(options), aRequest); +} + +NS_IMETHODIMP +MobileConnectionIPCService::GetCallForwarding(uint32_t aClientId, + uint16_t aReason, + nsIMobileConnectionCallback* aRequest) +{ + return SendRequest(aClientId, GetCallForwardingRequest(aReason), aRequest); +} + +NS_IMETHODIMP +MobileConnectionIPCService::SetCallBarring(uint32_t aClientId, + JS::Handle<JS::Value> aOptions, + nsIMobileConnectionCallback* aRequest) +{ + AutoSafeJSContext cx; + IPC::MozCallBarringOptions options; + if(!options.Init(cx, aOptions)) { + return NS_ERROR_TYPE_ERR; + } + + return SendRequest(aClientId, SetCallBarringRequest(options), aRequest); +} + +NS_IMETHODIMP +MobileConnectionIPCService::GetCallBarring(uint32_t aClientId, + JS::Handle<JS::Value> aOptions, + nsIMobileConnectionCallback* aRequest) +{ + AutoSafeJSContext cx; + IPC::MozCallBarringOptions options; + if(!options.Init(cx, aOptions)) { + return NS_ERROR_TYPE_ERR; + } + + return SendRequest(aClientId, GetCallBarringRequest(options), aRequest); +} + +NS_IMETHODIMP +MobileConnectionIPCService::ChangeCallBarringPassword(uint32_t aClientId, + JS::Handle<JS::Value> aOptions, + nsIMobileConnectionCallback* aRequest) +{ + AutoSafeJSContext cx; + IPC::MozCallBarringOptions options; + if(!options.Init(cx, aOptions)) { + return NS_ERROR_TYPE_ERR; + } + + return SendRequest(aClientId, ChangeCallBarringPasswordRequest(options), aRequest); +} + +NS_IMETHODIMP +MobileConnectionIPCService::SetCallWaiting(uint32_t aClientId, + bool aEnabled, + nsIMobileConnectionCallback* aRequest) +{ + return SendRequest(aClientId, SetCallWaitingRequest(aEnabled), aRequest); +} + +NS_IMETHODIMP +MobileConnectionIPCService::GetCallWaiting(uint32_t aClientId, + nsIMobileConnectionCallback* aRequest) +{ + return SendRequest(aClientId, GetCallWaitingRequest(), aRequest); +} + +NS_IMETHODIMP +MobileConnectionIPCService::SetCallingLineIdRestriction(uint32_t aClientId, + uint16_t aMode, + nsIMobileConnectionCallback* aRequest) +{ + return SendRequest(aClientId, SetCallingLineIdRestrictionRequest(aMode), aRequest); +} + +NS_IMETHODIMP +MobileConnectionIPCService::GetCallingLineIdRestriction(uint32_t aClientId, + nsIMobileConnectionCallback* aRequest) +{ + return SendRequest(aClientId, GetCallingLineIdRestrictionRequest(), aRequest); +} + +NS_IMETHODIMP +MobileConnectionIPCService::ExitEmergencyCbMode(uint32_t aClientId, + nsIMobileConnectionCallback* aRequest) +{ + return SendRequest(aClientId, ExitEmergencyCbModeRequest(), aRequest); +} + +NS_IMETHODIMP +MobileConnectionIPCService::SetRadioEnabled(uint32_t aClientId, + bool aEnabled, + nsIMobileConnectionCallback* aRequest) +{ + return SendRequest(aClientId, SetRadioEnabledRequest(aEnabled), aRequest); +}
new file mode 100644 --- /dev/null +++ b/dom/mobileconnection/ipc/MobileConnectionIPCService.h @@ -0,0 +1,42 @@ +/* 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/. */ + +#ifndef mozilla_dom_mobileconnection_MobileConnectionIPCService_h +#define mozilla_dom_mobileconnection_MobileConnectionIPCService_h + +#include "nsCOMPtr.h" +#include "MobileConnectionChild.h" +#include "nsIMobileConnectionService.h" + +namespace mozilla { +namespace dom { +namespace mobileconnection { + +class MobileConnectionIPCService MOZ_FINAL : public nsIMobileConnectionService +{ +public: + NS_DECL_ISUPPORTS + NS_DECL_NSIMOBILECONNECTIONSERVICE + + static MobileConnectionIPCService* + GetSingleton(); + +private: + MobileConnectionIPCService(); + + ~MobileConnectionIPCService(); + + /** Send request */ + nsresult + SendRequest(uint32_t aClientId, MobileConnectionRequest aRequest, + nsIMobileConnectionCallback* aRequestCallback); + + nsTArray<nsRefPtr<MobileConnectionChild>> mClients; +}; + +} // name space mobileconnection +} // name space dom +} // name space mozilla + +#endif // mozilla_dom_mobileconnection_MobileConnectionIPCService_h
new file mode 100644 --- /dev/null +++ b/dom/mobileconnection/ipc/MobileConnectionParent.cpp @@ -0,0 +1,729 @@ +/* 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/. */ + +#include "MobileConnectionParent.h" + +#include "mozilla/AppProcessChecker.h" +#include "mozilla/dom/BindingUtils.h" +#include "mozilla/dom/MobileConnectionIPCSerializer.h" +#include "mozilla/dom/MozMobileConnectionBinding.h" +#include "mozilla/dom/ToJSValue.h" +#include "nsIVariant.h" +#include "nsJSUtils.h" + +using namespace mozilla; +using namespace mozilla::dom; +using namespace mozilla::dom::mobileconnection; + +MobileConnectionParent::MobileConnectionParent(uint32_t aClientId) + : mClientId(aClientId) + , mLive(true) +{ + MOZ_COUNT_CTOR(MobileConnectionParent); + + mService = do_GetService(NS_MOBILE_CONNECTION_SERVICE_CONTRACTID); + NS_ASSERTION(mService, "This shouldn't fail!"); + + if (mService) { + mService->RegisterListener(mClientId, this); + } +} + +void +MobileConnectionParent::ActorDestroy(ActorDestroyReason why) +{ + mLive = false; + if (mService) { + mService->UnregisterListener(mClientId, this); + mService = nullptr; + } +} + +bool +MobileConnectionParent::RecvPMobileConnectionRequestConstructor(PMobileConnectionRequestParent* aActor, + const MobileConnectionRequest& aRequest) +{ + MobileConnectionRequestParent* actor = static_cast<MobileConnectionRequestParent*>(aActor); + + switch (aRequest.type()) { + case MobileConnectionRequest::TGetNetworksRequest: + return actor->DoRequest(aRequest.get_GetNetworksRequest()); + case MobileConnectionRequest::TSelectNetworkRequest: + return actor->DoRequest(aRequest.get_SelectNetworkRequest()); + case MobileConnectionRequest::TSelectNetworkAutoRequest: + return actor->DoRequest(aRequest.get_SelectNetworkAutoRequest()); + case MobileConnectionRequest::TSetPreferredNetworkTypeRequest: + return actor->DoRequest(aRequest.get_SetPreferredNetworkTypeRequest()); + case MobileConnectionRequest::TGetPreferredNetworkTypeRequest: + return actor->DoRequest(aRequest.get_GetPreferredNetworkTypeRequest()); + case MobileConnectionRequest::TSetRoamingPreferenceRequest: + return actor->DoRequest(aRequest.get_SetRoamingPreferenceRequest()); + case MobileConnectionRequest::TGetRoamingPreferenceRequest: + return actor->DoRequest(aRequest.get_GetRoamingPreferenceRequest()); + case MobileConnectionRequest::TSetVoicePrivacyModeRequest: + return actor->DoRequest(aRequest.get_SetVoicePrivacyModeRequest()); + case MobileConnectionRequest::TGetVoicePrivacyModeRequest: + return actor->DoRequest(aRequest.get_GetVoicePrivacyModeRequest()); + case MobileConnectionRequest::TSendMmiRequest: + return actor->DoRequest(aRequest.get_SendMmiRequest()); + case MobileConnectionRequest::TCancelMmiRequest: + return actor->DoRequest(aRequest.get_CancelMmiRequest()); + case MobileConnectionRequest::TSetCallForwardingRequest: + return actor->DoRequest(aRequest.get_SetCallForwardingRequest()); + case MobileConnectionRequest::TGetCallForwardingRequest: + return actor->DoRequest(aRequest.get_GetCallForwardingRequest()); + case MobileConnectionRequest::TSetCallBarringRequest: + return actor->DoRequest(aRequest.get_SetCallBarringRequest()); + case MobileConnectionRequest::TGetCallBarringRequest: + return actor->DoRequest(aRequest.get_GetCallBarringRequest()); + case MobileConnectionRequest::TChangeCallBarringPasswordRequest: + return actor->DoRequest(aRequest.get_ChangeCallBarringPasswordRequest()); + case MobileConnectionRequest::TSetCallWaitingRequest: + return actor->DoRequest(aRequest.get_SetCallWaitingRequest()); + case MobileConnectionRequest::TGetCallWaitingRequest: + return actor->DoRequest(aRequest.get_GetCallWaitingRequest()); + case MobileConnectionRequest::TSetCallingLineIdRestrictionRequest: + return actor->DoRequest(aRequest.get_SetCallingLineIdRestrictionRequest()); + case MobileConnectionRequest::TGetCallingLineIdRestrictionRequest: + return actor->DoRequest(aRequest.get_GetCallingLineIdRestrictionRequest()); + case MobileConnectionRequest::TExitEmergencyCbModeRequest: + return actor->DoRequest(aRequest.get_ExitEmergencyCbModeRequest()); + case MobileConnectionRequest::TSetRadioEnabledRequest: + return actor->DoRequest(aRequest.get_SetRadioEnabledRequest()); + default: + MOZ_CRASH("Received invalid request type!"); + } + + return false; +} + +PMobileConnectionRequestParent* +MobileConnectionParent::AllocPMobileConnectionRequestParent(const MobileConnectionRequest& request) +{ + if (!AssertAppProcessPermission(Manager(), "mobileconnection")) { + return nullptr; + } + + MobileConnectionRequestParent* actor = new MobileConnectionRequestParent(mClientId); + // Add an extra ref for IPDL. Will be released in + // MobileConnectionParent::DeallocPMobileConnectionRequestParent(). + actor->AddRef(); + return actor; +} + +bool +MobileConnectionParent::DeallocPMobileConnectionRequestParent(PMobileConnectionRequestParent* aActor) +{ + // MobileConnectionRequestParent is refcounted, must not be freed manually. + static_cast<MobileConnectionRequestParent*>(aActor)->Release(); + return true; +} + +bool +MobileConnectionParent::RecvInit(nsMobileConnectionInfo* aVoice, + nsMobileConnectionInfo* aData, + nsString* aLastKnownNetwork, + nsString* aLastKnownHomeNetwork, + nsString* aIccId, + nsString* aNetworkSelectionMode, + nsString* aRadioState, + nsTArray<nsString>* aSupportedNetworkTypes) +{ + NS_ENSURE_TRUE(mService, false); + + NS_ENSURE_SUCCESS(mService->GetVoiceConnectionInfo(mClientId, aVoice), false); + NS_ENSURE_SUCCESS(mService->GetDataConnectionInfo(mClientId, aData), false); + NS_ENSURE_SUCCESS(mService->GetLastKnownNetwork(mClientId, *aLastKnownNetwork), false); + NS_ENSURE_SUCCESS(mService->GetLastKnownHomeNetwork(mClientId, *aLastKnownHomeNetwork), false); + NS_ENSURE_SUCCESS(mService->GetIccId(mClientId, *aIccId), false); + NS_ENSURE_SUCCESS(mService->GetNetworkSelectionMode(mClientId, *aNetworkSelectionMode), false); + NS_ENSURE_SUCCESS(mService->GetRadioState(mClientId, *aRadioState), false); + + nsCOMPtr<nsIVariant> variant; + mService->GetSupportedNetworkTypes(mClientId, getter_AddRefs(variant)); + + uint16_t type; + nsIID iid; + uint32_t count; + void* data; + if (NS_FAILED(variant->GetAsArray(&type, &iid, &count, &data))) { + return false; + } + + // We expect the element type is wstring. + if (type == nsIDataType::VTYPE_WCHAR_STR) { + char16_t** rawArray = reinterpret_cast<char16_t**>(data); + for (uint32_t i = 0; i < count; ++i) { + nsDependentString networkType(rawArray[i]); + aSupportedNetworkTypes->AppendElement(networkType); + } + } + NS_Free(data); + + return true; +} + +// nsIMobileConnectionListener + +NS_IMPL_ISUPPORTS(MobileConnectionParent, nsIMobileConnectionListener) + +NS_IMETHODIMP +MobileConnectionParent::NotifyVoiceChanged() +{ + NS_ENSURE_TRUE(mLive, NS_ERROR_FAILURE); + + nsresult rv; + nsCOMPtr<nsIMobileConnectionInfo> info; + rv = mService->GetVoiceConnectionInfo(mClientId, getter_AddRefs(info)); + NS_ENSURE_SUCCESS(rv, rv); + + // We release the ref after serializing process is finished in + // MobileConnectionIPCSerializer. + return SendNotifyVoiceInfoChanged(info.forget().take()) ? NS_OK : NS_ERROR_FAILURE; +} + +NS_IMETHODIMP +MobileConnectionParent::NotifyDataChanged() +{ + NS_ENSURE_TRUE(mLive, NS_ERROR_FAILURE); + + nsresult rv; + nsCOMPtr<nsIMobileConnectionInfo> info; + rv = mService->GetDataConnectionInfo(mClientId, getter_AddRefs(info)); + NS_ENSURE_SUCCESS(rv, rv); + + // We release the ref after serializing process is finished in + // MobileConnectionIPCSerializer. + return SendNotifyDataInfoChanged(info.forget().take()) ? NS_OK : NS_ERROR_FAILURE; +} + +NS_IMETHODIMP +MobileConnectionParent::NotifyUssdReceived(const nsAString& aMessage, + bool aSessionEnded) +{ + NS_ENSURE_TRUE(mLive, NS_ERROR_FAILURE); + + return SendNotifyUssdReceived(nsAutoString(aMessage), aSessionEnded) + ? NS_OK : NS_ERROR_FAILURE; +} + +NS_IMETHODIMP +MobileConnectionParent::NotifyDataError(const nsAString& aMessage) +{ + NS_ENSURE_TRUE(mLive, NS_ERROR_FAILURE); + + return SendNotifyDataError(nsAutoString(aMessage)) ? NS_OK : NS_ERROR_FAILURE; +} + +NS_IMETHODIMP +MobileConnectionParent::NotifyCFStateChanged(bool aSuccess, + uint16_t aAction, + uint16_t aReason, + const nsAString &aNumber, + uint16_t aTimeSeconds, + uint16_t aServiceClass) +{ + NS_ENSURE_TRUE(mLive, NS_ERROR_FAILURE); + + return SendNotifyCFStateChanged(aSuccess, aAction, aReason, + nsAutoString(aNumber), aTimeSeconds, + aServiceClass) ? NS_OK : NS_ERROR_FAILURE; +} + +NS_IMETHODIMP +MobileConnectionParent::NotifyEmergencyCbModeChanged(bool aActive, + uint32_t aTimeoutMs) +{ + NS_ENSURE_TRUE(mLive, NS_ERROR_FAILURE); + + return SendNotifyEmergencyCbModeChanged(aActive, aTimeoutMs) + ? NS_OK : NS_ERROR_FAILURE; +} + +NS_IMETHODIMP +MobileConnectionParent::NotifyOtaStatusChanged(const nsAString& aStatus) +{ + NS_ENSURE_TRUE(mLive, NS_ERROR_FAILURE); + + return SendNotifyOtaStatusChanged(nsAutoString(aStatus)) + ? NS_OK : NS_ERROR_FAILURE; +} + +NS_IMETHODIMP +MobileConnectionParent::NotifyIccChanged() +{ + NS_ENSURE_TRUE(mLive, NS_ERROR_FAILURE); + + nsAutoString iccId; + mService->GetIccId(mClientId, iccId); + + return SendNotifyIccChanged(iccId) ? NS_OK : NS_ERROR_FAILURE; +} + +NS_IMETHODIMP +MobileConnectionParent::NotifyRadioStateChanged() +{ + NS_ENSURE_TRUE(mLive, NS_ERROR_FAILURE); + + nsresult rv; + nsAutoString radioState; + rv = mService->GetRadioState(mClientId, radioState); + NS_ENSURE_SUCCESS(rv, rv); + + return SendNotifyRadioStateChanged(radioState) ? NS_OK : NS_ERROR_FAILURE; +} + +NS_IMETHODIMP +MobileConnectionParent::NotifyClirModeChanged(uint32_t aMode) +{ + NS_ENSURE_TRUE(mLive, NS_ERROR_FAILURE); + + return SendNotifyClirModeChanged(aMode) ? NS_OK : NS_ERROR_FAILURE; +} + +NS_IMETHODIMP +MobileConnectionParent::NotifyLastKnownNetworkChanged() +{ + NS_ENSURE_TRUE(mLive, NS_ERROR_FAILURE); + + nsresult rv; + nsAutoString network; + rv = mService->GetLastKnownNetwork(mClientId, network); + NS_ENSURE_SUCCESS(rv, rv); + + return SendNotifyLastNetworkChanged(network) ? NS_OK : NS_ERROR_FAILURE; +} + +NS_IMETHODIMP +MobileConnectionParent::NotifyLastKnownHomeNetworkChanged() +{ + NS_ENSURE_TRUE(mLive, NS_ERROR_FAILURE); + + nsresult rv; + nsAutoString network; + rv = mService->GetLastKnownHomeNetwork(mClientId, network); + NS_ENSURE_SUCCESS(rv, rv); + + return SendNotifyLastHomeNetworkChanged(network) ? NS_OK : NS_ERROR_FAILURE; +} + +NS_IMETHODIMP +MobileConnectionParent::NotifyNetworkSelectionModeChanged() +{ + NS_ENSURE_TRUE(mLive, NS_ERROR_FAILURE); + + nsresult rv; + nsAutoString mode; + rv = mService->GetNetworkSelectionMode(mClientId, mode); + NS_ENSURE_SUCCESS(rv, rv); + + return SendNotifyNetworkSelectionModeChanged(mode) ? NS_OK : NS_ERROR_FAILURE; +} + +/****************************************************************************** + * PMobileConnectionRequestParent + ******************************************************************************/ + +void +MobileConnectionRequestParent::ActorDestroy(ActorDestroyReason why) +{ + mLive = false; + mService = nullptr; +} + +bool +MobileConnectionRequestParent::DoRequest(const GetNetworksRequest& aRequest) +{ + NS_ENSURE_TRUE(mService, false); + + return NS_SUCCEEDED(mService->GetNetworks(mClientId, this)); +} + +bool +MobileConnectionRequestParent::DoRequest(const SelectNetworkRequest& aRequest) +{ + NS_ENSURE_TRUE(mService, false); + + // Use dont_AddRef here because this instances is already AddRef-ed in + // MobileConnectionIPCSerializer.h + nsCOMPtr<nsIMobileNetworkInfo> network = dont_AddRef(aRequest.network()); + return NS_SUCCEEDED(mService->SelectNetwork(mClientId, network, this)); +} + +bool +MobileConnectionRequestParent::DoRequest(const SelectNetworkAutoRequest& aRequest) +{ + NS_ENSURE_TRUE(mService, false); + + return NS_SUCCEEDED(mService->SelectNetworkAutomatically(mClientId, this)); +} + +bool +MobileConnectionRequestParent::DoRequest(const SetPreferredNetworkTypeRequest& aRequest) +{ + NS_ENSURE_TRUE(mService, false); + + return NS_SUCCEEDED(mService->SetPreferredNetworkType(mClientId, aRequest.type(), this)); +} + +bool +MobileConnectionRequestParent::DoRequest(const GetPreferredNetworkTypeRequest& aRequest) +{ + NS_ENSURE_TRUE(mService, false); + + return NS_SUCCEEDED(mService->GetPreferredNetworkType(mClientId, this)); +} + +bool +MobileConnectionRequestParent::DoRequest(const SetRoamingPreferenceRequest& aRequest) +{ + NS_ENSURE_TRUE(mService, false); + + return NS_SUCCEEDED(mService->SetRoamingPreference(mClientId, aRequest.mode(), this)); +} + +bool +MobileConnectionRequestParent::DoRequest(const GetRoamingPreferenceRequest& aRequest) +{ + NS_ENSURE_TRUE(mService, false); + + return NS_SUCCEEDED(mService->GetRoamingPreference(mClientId, this)); +} + +bool +MobileConnectionRequestParent::DoRequest(const SetVoicePrivacyModeRequest& aRequest) +{ + NS_ENSURE_TRUE(mService, false); + + return NS_SUCCEEDED(mService->SetVoicePrivacyMode(mClientId, aRequest.enabled(), this)); +} + +bool +MobileConnectionRequestParent::DoRequest(const GetVoicePrivacyModeRequest& aRequest) +{ + NS_ENSURE_TRUE(mService, false); + + return NS_SUCCEEDED(mService->GetVoicePrivacyMode(mClientId, this)); +} + +bool +MobileConnectionRequestParent::DoRequest(const SendMmiRequest& aRequest) +{ + NS_ENSURE_TRUE(mService, false); + + return NS_SUCCEEDED(mService->SendMMI(mClientId, aRequest.mmi(), this)); +} + +bool +MobileConnectionRequestParent::DoRequest(const CancelMmiRequest& aRequest) +{ + NS_ENSURE_TRUE(mService, false); + + return NS_SUCCEEDED(mService->CancelMMI(mClientId, this)); +} + +bool +MobileConnectionRequestParent::DoRequest(const SetCallForwardingRequest& aRequest) +{ + NS_ENSURE_TRUE(mService, false); + + AutoSafeJSContext cx; + JS::Rooted<JS::Value> options(cx); + if (!ToJSValue(cx, aRequest.options(), &options)) { + JS_ClearPendingException(cx); + return false; + } + + return NS_SUCCEEDED(mService->SetCallForwarding(mClientId, options, this)); +} + +bool +MobileConnectionRequestParent::DoRequest(const GetCallForwardingRequest& aRequest) +{ + NS_ENSURE_TRUE(mService, false); + + return NS_SUCCEEDED(mService->GetCallForwarding(mClientId, aRequest.reason(), this)); +} + +bool +MobileConnectionRequestParent::DoRequest(const SetCallBarringRequest& aRequest) +{ + NS_ENSURE_TRUE(mService, false); + + AutoSafeJSContext cx; + JS::Rooted<JS::Value> options(cx); + if (!ToJSValue(cx, aRequest.options(), &options)) { + JS_ClearPendingException(cx); + return false; + } + + return NS_SUCCEEDED(mService->SetCallBarring(mClientId, options, this)); +} + +bool +MobileConnectionRequestParent::DoRequest(const GetCallBarringRequest& aRequest) +{ + NS_ENSURE_TRUE(mService, false); + + AutoSafeJSContext cx; + JS::Rooted<JS::Value> options(cx); + if (!ToJSValue(cx, aRequest.options(), &options)) { + JS_ClearPendingException(cx); + return false; + } + + return NS_SUCCEEDED(mService->GetCallBarring(mClientId, options, this)); +} + +bool +MobileConnectionRequestParent::DoRequest(const ChangeCallBarringPasswordRequest& aRequest) +{ + NS_ENSURE_TRUE(mService, false); + + AutoSafeJSContext cx; + JS::Rooted<JS::Value> options(cx); + if (!ToJSValue(cx, aRequest.options(), &options)) { + JS_ClearPendingException(cx); + return false; + } + + return NS_SUCCEEDED(mService->ChangeCallBarringPassword(mClientId, options, this)); +} + +bool +MobileConnectionRequestParent::DoRequest(const SetCallWaitingRequest& aRequest) +{ + NS_ENSURE_TRUE(mService, false); + + return NS_SUCCEEDED(mService->SetCallWaiting(mClientId, aRequest.enabled(), this)); +} + +bool +MobileConnectionRequestParent::DoRequest(const GetCallWaitingRequest& aRequest) +{ + NS_ENSURE_TRUE(mService, false); + + return NS_SUCCEEDED(mService->GetCallWaiting(mClientId, this)); +} + +bool +MobileConnectionRequestParent::DoRequest(const SetCallingLineIdRestrictionRequest& aRequest) +{ + NS_ENSURE_TRUE(mService, false); + + return NS_SUCCEEDED(mService->SetCallingLineIdRestriction(mClientId, aRequest.mode(), this)); +} + +bool +MobileConnectionRequestParent::DoRequest(const GetCallingLineIdRestrictionRequest& aRequest) +{ + NS_ENSURE_TRUE(mService, false); + + return NS_SUCCEEDED(mService->GetCallingLineIdRestriction(mClientId, this)); +} + +bool +MobileConnectionRequestParent::DoRequest(const ExitEmergencyCbModeRequest& aRequest) +{ + NS_ENSURE_TRUE(mService, false); + + return NS_SUCCEEDED(mService->ExitEmergencyCbMode(mClientId, this)); +} + +bool +MobileConnectionRequestParent::DoRequest(const SetRadioEnabledRequest& aRequest) +{ + NS_ENSURE_TRUE(mService, false); + + return NS_SUCCEEDED(mService->SetRadioEnabled(mClientId, aRequest.enabled(), this)); +} + +nsresult +MobileConnectionRequestParent::SendReply(const MobileConnectionReply& aReply) +{ + NS_ENSURE_TRUE(mLive, NS_ERROR_FAILURE); + + return Send__delete__(this, aReply) ? NS_OK : NS_ERROR_FAILURE; +} + +// nsIMobileConnectionListener + +NS_IMPL_ISUPPORTS(MobileConnectionRequestParent, nsIMobileConnectionCallback); + +NS_IMETHODIMP +MobileConnectionRequestParent::NotifySuccess() +{ + return SendReply(MobileConnectionReplySuccess()); +} + +NS_IMETHODIMP +MobileConnectionRequestParent::NotifySuccessWithString(const nsAString& aResult) +{ + return SendReply(MobileConnectionReplySuccessString(nsAutoString(aResult))); +} + +NS_IMETHODIMP +MobileConnectionRequestParent::NotifySuccessWithBoolean(bool aResult) +{ + return SendReply(MobileConnectionReplySuccessBoolean(aResult)); +} + +NS_IMETHODIMP +MobileConnectionRequestParent::NotifyGetNetworksSuccess(uint32_t aCount, + nsIMobileNetworkInfo** aNetworks) +{ + nsTArray<nsIMobileNetworkInfo*> networks; + for (uint32_t i = 0; i < aCount; i++) { + nsCOMPtr<nsIMobileNetworkInfo> network = aNetworks[i]; + // We release the ref after serializing process is finished in + // MobileConnectionIPCSerializer. + networks.AppendElement(network.forget().take()); + } + return SendReply(MobileConnectionReplySuccessNetworks(networks)); +} + +NS_IMETHODIMP +MobileConnectionRequestParent::NotifySendCancelMmiSuccess(JS::Handle<JS::Value> aResult) +{ + AutoSafeJSContext cx; + RootedDictionary<MozMMIResult> result(cx); + + if (!result.Init(cx, aResult)) { + return NS_ERROR_TYPE_ERR; + } + + // No additionInformation passed + if (!result.mAdditionalInformation.WasPassed()) { + return SendReply(MobileConnectionReplySuccessMmi(result.mServiceCode, + result.mStatusMessage, + AdditionalInformation(mozilla::void_t()))); + } + + OwningUnsignedShortOrObject& additionInformation = result.mAdditionalInformation.Value(); + + if (additionInformation.IsUnsignedShort()) { + return SendReply(MobileConnectionReplySuccessMmi(result.mServiceCode, + result.mStatusMessage, + AdditionalInformation(uint16_t(additionInformation.GetAsUnsignedShort())))); + } + + if (additionInformation.IsObject()) { + uint32_t length; + JS::Rooted<JS::Value> value(cx); + JS::Rooted<JSObject*> object(cx, additionInformation.GetAsObject()); + + if (!JS_IsArrayObject(cx, object) || + !JS_GetArrayLength(cx, object, &length) || length <= 0 || + // Check first element to decide the format of array. + !JS_GetElement(cx, object, 0, &value)) { + return NS_ERROR_TYPE_ERR; + } + + // Check first element to decide the format of array. + if (value.isString()) { + // String[] + nsTArray<nsString> infos; + for (uint32_t i = 0; i < length; i++) { + if (!JS_GetElement(cx, object, i, &value) || !value.isString()) { + return NS_ERROR_TYPE_ERR; + } + + nsAutoJSString str; + if (!str.init(cx, value.toString())) { + return NS_ERROR_FAILURE; + } + infos.AppendElement(str); + } + + return SendReply(MobileConnectionReplySuccessMmi(result.mServiceCode, + result.mStatusMessage, + AdditionalInformation(infos))); + } else { + // IPC::MozCallForwardingOptions[] + nsTArray<IPC::MozCallForwardingOptions> infos; + for (uint32_t i = 0; i < length; i++) { + IPC::MozCallForwardingOptions info; + if (!JS_GetElement(cx, object, i, &value) || !info.Init(cx, value)) { + return NS_ERROR_TYPE_ERR; + } + + infos.AppendElement(info); + } + + return SendReply(MobileConnectionReplySuccessMmi(result.mServiceCode, + result.mStatusMessage, + AdditionalInformation(infos))); + } + } + + return NS_ERROR_TYPE_ERR; +} + +NS_IMETHODIMP +MobileConnectionRequestParent::NotifyGetCallForwardingSuccess(JS::Handle<JS::Value> aResults) +{