Bug 833229 - 3.e/4: implement GonkVoicemailService. r=echen

This commit is contained in:
Vicamo Yang 2014-09-26 13:00:25 +08:00
parent ce2931cf92
commit 0e6fe8c43a
8 changed files with 317 additions and 175 deletions

View File

@ -448,6 +448,8 @@
@BINPATH@/components/RILContentHelper.js
@BINPATH@/components/TelephonyService.js
@BINPATH@/components/TelephonyService.manifest
@BINPATH@/components/VoicemailService.js
@BINPATH@/components/VoicemailService.manifest
#endif // MOZ_WIDGET_GONK && MOZ_B2G_RIL
#ifndef MOZ_WIDGET_GONK

View File

@ -33,7 +33,6 @@ const NS_PREFBRANCH_PREFCHANGE_TOPIC_ID = "nsPref:changed";
const kPrefRilNumRadioInterfaces = "ril.numRadioInterfaces";
const kPrefRilDebuggingEnabled = "ril.debugging.enabled";
const kPrefVoicemailDefaultServiceId = "dom.voicemail.defaultServiceId";
let DEBUG;
function debug(s) {
@ -58,8 +57,6 @@ const ICCCARDLOCKERROR_CID =
const RIL_IPC_MSG_NAMES = [
"RIL:CardStateChanged",
"RIL:IccInfoChanged",
"RIL:VoicemailNotification",
"RIL:VoicemailInfoChanged",
"RIL:CardLockResult",
"RIL:CardLockRetryCount",
"RIL:StkCommand",
@ -171,12 +168,6 @@ CdmaIccInfo.prototype = {
prlVersion: 0
};
function VoicemailInfo() {}
VoicemailInfo.prototype = {
number: null,
displayName: null
};
function CellBroadcastMessage(clientId, pdu) {
this.serviceId = clientId;
this.gsmGeographicalScope = RIL.CB_GSM_GEOGRAPHICAL_SCOPE_NAMES[pdu.geographicalScope];
@ -263,36 +254,27 @@ function RILContentHelper() {
if (DEBUG) debug("Number of clients: " + this.numClients);
this.rilContexts = [];
this.voicemailInfos = [];
this.voicemailStatuses = [];
for (let clientId = 0; clientId < this.numClients; clientId++) {
this.rilContexts[clientId] = {
cardState: RIL.GECKO_CARDSTATE_UNKNOWN,
iccInfo: null
};
this.voicemailInfos[clientId] = new VoicemailInfo();
}
this.voicemailDefaultServiceId = this.getVoicemailDefaultServiceId();
this.initDOMRequestHelper(/* aWindow */ null, RIL_IPC_MSG_NAMES);
this._windowsMap = [];
this._cellBroadcastListeners = [];
this._voicemailListeners = [];
this._iccListeners = [];
Services.obs.addObserver(this, NS_XPCOM_SHUTDOWN_OBSERVER_ID, false);
Services.prefs.addObserver(kPrefRilDebuggingEnabled, this, false);
Services.prefs.addObserver(kPrefVoicemailDefaultServiceId, this, false);
}
RILContentHelper.prototype = {
__proto__: DOMRequestIpcHelper.prototype,
QueryInterface: XPCOMUtils.generateQI([Ci.nsICellBroadcastProvider,
Ci.nsIVoicemailService,
Ci.nsIIccProvider,
Ci.nsIObserver,
Ci.nsISupportsWeakReference]),
@ -300,7 +282,6 @@ RILContentHelper.prototype = {
classInfo: XPCOMUtils.generateCI({classID: RILCONTENTHELPER_CID,
classDescription: "RILContentHelper",
interfaces: [Ci.nsICellBroadcastProvider,
Ci.nsIVoicemailService,
Ci.nsIIccProvider]}),
updateDebugFlag: function() {
@ -658,52 +639,8 @@ RILContentHelper.prototype = {
},
_cellBroadcastListeners: null,
_voicemailListeners: null,
_iccListeners: null,
voicemailInfos: null,
voicemailStatuses: null,
voicemailDefaultServiceId: 0,
getVoicemailDefaultServiceId: function() {
let id = Services.prefs.getIntPref(kPrefVoicemailDefaultServiceId);
if (id >= gNumRadioInterfaces || id < 0) {
id = 0;
}
return id;
},
getVoicemailInfo: function(clientId) {
// Get voicemail infomation by IPC only on first time.
this.getVoicemailInfo = function getVoicemailInfo(clientId) {
return this.voicemailInfos[clientId];
};
for (let cId = 0; cId < gNumRadioInterfaces; cId++) {
let voicemailInfo =
cpmm.sendSyncMessage("RIL:GetVoicemailInfo", {clientId: cId})[0];
if (voicemailInfo) {
this.updateInfo(voicemailInfo, this.voicemailInfos[cId]);
}
}
return this.voicemailInfos[clientId];
},
getVoicemailNumber: function(clientId) {
return this.getVoicemailInfo(clientId).number;
},
getVoicemailDisplayName: function(clientId) {
return this.getVoicemailInfo(clientId).displayName;
},
getVoicemailStatus: function(clientId) {
return this.voicemailStatuses[clientId];
},
registerListener: function(listenerType, clientId, listener) {
if (!this[listenerType]) {
return;
@ -737,22 +674,6 @@ RILContentHelper.prototype = {
}
},
registerVoicemailMsg: function(listener) {
if (DEBUG) debug("Registering for voicemail-related messages");
// To follow the listener registration scheme, we add a dummy clientId 0.
// All voicemail events are routed to listener for client id 0.
// See |handleVoicemailNotification|.
this.registerListener("_voicemailListeners", 0, listener);
cpmm.sendAsyncMessage("RIL:RegisterVoicemailMsg");
},
unregisterVoicemailMsg: function(listener) {
// To follow the listener unregistration scheme, we add a dummy clientId 0.
// All voicemail events are routed to listener for client id 0.
// See |handleVoicemailNotification|.
this.unregisterListener("_voicemailListeners", 0, listener);
},
registerCellBroadcastMsg: function(listener) {
if (DEBUG) debug("Registering for Cell Broadcast related messages");
// Instead of registering multiple listeners for Multi-SIM, we reuse
@ -786,8 +707,6 @@ RILContentHelper.prototype = {
case NS_PREFBRANCH_PREFCHANGE_TOPIC_ID:
if (data == kPrefRilDebuggingEnabled) {
this.updateDebugFlag();
} else if (data == kPrefVoicemailDefaultServiceId) {
this.voicemailDefaultServiceId = this.getVoicemailDefaultServiceId();
}
break;
@ -886,12 +805,6 @@ RILContentHelper.prototype = {
"notifyIccInfoChanged",
null);
break;
case "RIL:VoicemailNotification":
this.handleVoicemailNotification(clientId, data);
break;
case "RIL:VoicemailInfoChanged":
this.updateInfo(data, this.voicemailInfos[clientId]);
break;
case "RIL:CardLockResult": {
let requestId = data.requestId;
let requestWindow = this._windowsMap[requestId];
@ -1033,46 +946,6 @@ RILContentHelper.prototype = {
this.fireRequestSuccess(message.requestId, contact);
},
handleVoicemailNotification: function(clientId, message) {
let changed = false;
if (!this.voicemailStatuses[clientId]) {
this.voicemailStatuses[clientId] = new VoicemailStatus(clientId);
}
let voicemailStatus = this.voicemailStatuses[clientId];
if (voicemailStatus.hasMessages != message.active) {
changed = true;
voicemailStatus.hasMessages = message.active;
}
if (voicemailStatus.messageCount != message.msgCount) {
changed = true;
voicemailStatus.messageCount = message.msgCount;
} else if (message.msgCount == -1) {
// For MWI using DCS the message count is not available
changed = true;
}
if (voicemailStatus.returnNumber != message.returnNumber) {
changed = true;
voicemailStatus.returnNumber = message.returnNumber;
}
if (voicemailStatus.returnMessage != message.returnMessage) {
changed = true;
voicemailStatus.returnMessage = message.returnMessage;
}
if (changed) {
// To follow the event delivering scheme, we add a dummy clientId 0.
// All voicemail events are routed to listener for client id 0.
this._deliverEvent(0,
"_voicemailListeners",
"notifyStatusChanged",
[voicemailStatus]);
}
},
_deliverEvent: function(clientId, listenerType, name, args) {
if (!this[listenerType]) {
return;

View File

@ -127,11 +127,6 @@ const RIL_IPC_ICCMANAGER_MSG_NAMES = [
"RIL:MatchMvno"
];
const RIL_IPC_VOICEMAIL_MSG_NAMES = [
"RIL:RegisterVoicemailMsg",
"RIL:GetVoicemailInfo"
];
const RIL_IPC_CELLBROADCAST_MSG_NAMES = [
"RIL:RegisterCellBroadcastMsg"
];
@ -250,9 +245,6 @@ XPCOMUtils.defineLazyGetter(this, "gMessageManager", function() {
for (let msgName of RIL_IPC_ICCMANAGER_MSG_NAMES) {
ppmm.addMessageListener(msgName, this);
}
for (let msgname of RIL_IPC_VOICEMAIL_MSG_NAMES) {
ppmm.addMessageListener(msgname, this);
}
for (let msgname of RIL_IPC_CELLBROADCAST_MSG_NAMES) {
ppmm.addMessageListener(msgname, this);
}
@ -263,9 +255,6 @@ XPCOMUtils.defineLazyGetter(this, "gMessageManager", function() {
for (let msgName of RIL_IPC_ICCMANAGER_MSG_NAMES) {
ppmm.removeMessageListener(msgName, this);
}
for (let msgname of RIL_IPC_VOICEMAIL_MSG_NAMES) {
ppmm.removeMessageListener(msgname, this);
}
for (let msgname of RIL_IPC_CELLBROADCAST_MSG_NAMES) {
ppmm.removeMessageListener(msgname, this);
}
@ -384,14 +373,6 @@ XPCOMUtils.defineLazyGetter(this, "gMessageManager", function() {
}
return null;
}
} else if (RIL_IPC_VOICEMAIL_MSG_NAMES.indexOf(msg.name) != -1) {
if (!msg.target.assertPermission("voicemail")) {
if (DEBUG) {
debug("Voicemail message " + msg.name +
" from a content process with no 'voicemail' privileges.");
}
return null;
}
} else if (RIL_IPC_CELLBROADCAST_MSG_NAMES.indexOf(msg.name) != -1) {
if (!msg.target.assertPermission("cellbroadcast")) {
if (DEBUG) {
@ -409,9 +390,6 @@ XPCOMUtils.defineLazyGetter(this, "gMessageManager", function() {
case "RIL:RegisterIccMsg":
this._registerMessageTarget("icc", msg.target);
return null;
case "RIL:RegisterVoicemailMsg":
this._registerMessageTarget("voicemail", msg.target);
return null;
case "RIL:RegisterCellBroadcastMsg":
this._registerMessageTarget("cellbroadcast", msg.target);
return null;
@ -450,13 +428,6 @@ XPCOMUtils.defineLazyGetter(this, "gMessageManager", function() {
});
},
sendVoicemailMessage: function(message, clientId, data) {
this._sendTargetMessage("voicemail", message, {
clientId: clientId,
data: data
});
},
sendCellBroadcastMessage: function(message, clientId, data) {
this._sendTargetMessage("cellbroadcast", message, {
clientId: clientId,
@ -1883,11 +1854,6 @@ function RadioInterface(aClientId, aWorkerMessenger) {
imsi: null
};
this.voicemailInfo = {
number: null,
displayName: null
};
this.operatorInfo = {};
let lock = gSettingsService.createLock();
@ -2067,9 +2033,6 @@ RadioInterface.prototype = {
case "RIL:MatchMvno":
this.matchMvno(msg.target, msg.json.data);
break;
case "RIL:GetVoicemailInfo":
// This message is sync.
return this.voicemailInfo;
}
return null;
},
@ -2183,8 +2146,7 @@ RadioInterface.prototype = {
this.handleIccMbdn(message);
break;
case "iccmwis":
gMessageManager.sendVoicemailMessage("RIL:VoicemailNotification",
this.clientId, message.mwi);
this.handleIccMwis(message.mwi);
break;
case "stkcommand":
this.handleStkProactiveCommand(message);
@ -2763,8 +2725,7 @@ RadioInterface.prototype = {
mwi.returnNumber = message.sender;
mwi.returnMessage = message.fullBody;
gMessageManager.sendVoicemailMessage("RIL:VoicemailNotification",
this.clientId, mwi);
this.handleIccMwis(mwi);
// Dicarded MWI comes without text body.
// Hence, we discard it here after notifying the MWI status.
@ -2968,13 +2929,16 @@ RadioInterface.prototype = {
},
handleIccMbdn: function(message) {
let voicemailInfo = this.voicemailInfo;
let service = Cc["@mozilla.org/voicemail/voicemailservice;1"]
.getService(Ci.nsIGonkVoicemailService);
service.notifyInfoChanged(this.clientId, message.number, message.alphaId);
},
voicemailInfo.number = message.number;
voicemailInfo.displayName = message.alphaId;
gMessageManager.sendVoicemailMessage("RIL:VoicemailInfoChanged",
this.clientId, voicemailInfo);
handleIccMwis: function(mwi) {
let service = Cc["@mozilla.org/voicemail/voicemailservice;1"]
.getService(Ci.nsIGonkVoicemailService);
service.notifyStatusChanged(this.clientId, mwi.active, mwi.msgCount,
mwi.returnNumber, mwi.returnMessage);
},
handleIccInfoChange: function(message) {

View File

@ -0,0 +1,260 @@
/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/. */
"use strict";
const {classes: Cc, interfaces: Ci, utils: Cu, results: Cr} = Components;
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
Cu.import("resource://gre/modules/Services.jsm");
XPCOMUtils.defineLazyGetter(this, "RIL", function () {
let obj = {};
Cu.import("resource://gre/modules/ril_consts.js", obj);
return obj;
});
const GONK_VOICEMAIL_SERVICE_CONTRACTID =
"@mozilla.org/voicemail/gonkvoicemailservice;1";
const GONK_VOICEMAIL_SERVICE_CID =
Components.ID("{c332f318-1cce-4f02-b676-bb5031d10736}");
const NS_MOBILE_CONNECTION_SERVICE_CONTRACTID =
"@mozilla.org/mobileconnection/mobileconnectionservice;1";
const NS_XPCOM_SHUTDOWN_OBSERVER_ID = "xpcom-shutdown";
const NS_PREFBRANCH_PREFCHANGE_TOPIC_ID = "nsPref:changed";
const kPrefRilDebuggingEnabled = "ril.debugging.enabled";
const kPrefDefaultServiceId = "dom.voicemail.defaultServiceId";
let DEBUG;
function debug(s) {
dump("VoicemailService: " + s);
}
function VoicemailProvider(aServiceId) {
this.serviceId = aServiceId;
}
VoicemailProvider.prototype = {
QueryInterface: XPCOMUtils.generateQI([Ci.nsIVoicemailProvider]),
// nsIVoicemail interface
serviceId: 0,
number: null,
displayName: null,
hasMessages: false,
messageCount: 0,
returnNumber: null,
returnMessage: null,
};
function VoicemailService() {
// Initialize |this._providers|.
let mcService = Cc[NS_MOBILE_CONNECTION_SERVICE_CONTRACTID]
.getService(Ci.nsIMobileConnectionService);
let numItems = mcService.numItems;
this._providers = [];
for (let i = 0; i < numItems; i++) {
this._providers.push(new VoicemailProvider(i));
}
this._listeners = [];
// Must be initialized after |this._providers|.
this._defaultServiceId = this._getDefaultServiceId();
this._updateDebugFlag();
Services.prefs.addObserver(kPrefRilDebuggingEnabled, this, false);
Services.prefs.addObserver(kPrefDefaultServiceId, this, false);
Services.obs.addObserver(this, NS_XPCOM_SHUTDOWN_OBSERVER_ID, false);
}
VoicemailService.prototype = {
classID: GONK_VOICEMAIL_SERVICE_CID,
classInfo: XPCOMUtils.generateCI({
classID: GONK_VOICEMAIL_SERVICE_CID,
contractID: GONK_VOICEMAIL_SERVICE_CONTRACTID,
classDescription: "VoicemailService",
interfaces: [
Ci.nsIVoicemailService,
Ci.nsIGonkVoicemailService
],
flags: Ci.nsIClassInfo.SINGLETON
}),
QueryInterface: XPCOMUtils.generateQI([
Ci.nsIVoicemailService,
Ci.nsIGonkVoicemailService,
Ci.nsIObserver
]),
_defaultServiceId: null,
_providers: null,
_updateDebugFlag: function() {
try {
DEBUG = RIL.DEBUG_RIL ||
Services.prefs.getBoolPref(kPrefRilDebuggingEnabled);
} catch (e) {}
},
_getDefaultServiceId: function() {
let id = Services.prefs.getIntPref(kPrefDefaultServiceId);
if (id >= this.numItems || id < 0) {
id = 0;
}
return id;
},
_listeners: null,
_notifyListeners: function(aMethodName, aItem) {
let listeners = this._listeners.slice();
for (let listener of listeners) {
try {
listener[aMethodName].call(listener, aItem);
} catch (e) {
if (DEBUG) {
debug("listener for " + aMethodName + " threw an exception: " + e);
}
}
}
},
/**
* nsIVoicemailService interface
*/
get numItems() {
return this._providers.length;
},
getItemByServiceId: function(aServiceId) {
let provider = this._providers[aServiceId];
if (!provider) {
throw Cr.NS_ERROR_INVALID_ARG;
}
return provider;
},
getDefaultItem: function() {
return this.getItemByServiceId(this._defaultServiceId);
},
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) {
return Cr.NS_ERROR_FAILURE;
}
this._listeners.splice(index, 1);
},
/**
* nsIGonkVoicemailService interface
*/
notifyStatusChanged: function(aServiceId, aHasMessages, aMessageCount,
aReturnNumber, aReturnMessage) {
if (DEBUG) {
debug("notifyStatusChanged: " +
JSON.stringify(Array.prototype.slice.call(arguments)));
}
let provider = this.getItemByServiceId(aServiceId);
let changed = false;
if (provider.hasMessages != aHasMessages) {
provider.hasMessages = aHasMessages;
changed = true;
}
if (provider.messageCount != aMessageCount) {
provider.messageCount = aMessageCount;
changed = true;
} else if (aMessageCount == -1) {
// For MWI using DCS the message count is not available
changed = true;
}
if (provider.returnNumber != aReturnNumber) {
provider.returnNumber = aReturnNumber;
changed = true;
}
if (provider.returnMessage != aReturnMessage) {
provider.returnMessage = aReturnMessage;
changed = true;
}
if (changed) {
this._notifyListeners("notifyStatusChanged", provider);
}
},
notifyInfoChanged: function(aServiceId, aNumber, aDisplayName) {
if (DEBUG) {
debug("notifyInfoChanged: " +
JSON.stringify(Array.prototype.slice.call(arguments)));
}
let provider = this.getItemByServiceId(aServiceId);
let changed = false;
if (provider.number != aNumber) {
provider.number = aNumber;
changed = true;
}
if (provider.displayName != aDisplayName) {
provider.displayName = aDisplayName;
changed = true;
}
if (changed) {
this._notifyListeners("notifyInfoChanged", provider);
}
},
/**
* nsIObserver interface.
*/
observe: function(aSubject, aTopic, aData) {
switch (aTopic) {
case NS_PREFBRANCH_PREFCHANGE_TOPIC_ID:
if (aData === kPrefRilDebuggingEnabled) {
this._updateDebugFlag();
} else if (aData === kPrefDefaultServiceId) {
this._defaultServiceId = this._getDefaultServiceId();
}
break;
case NS_XPCOM_SHUTDOWN_OBSERVER_ID:
Services.prefs.removeObserver(kPrefRilDebuggingEnabled, this);
Services.prefs.removeObserver(kPrefDefaultServiceId, this);
Services.obs.removeObserver(this, NS_XPCOM_SHUTDOWN_OBSERVER_ID);
// Remove all listeners.
this._listeners = [];
break;
}
}
};
this.NSGetFactory = XPCOMUtils.generateNSGetFactory([VoicemailService]);

View File

@ -0,0 +1,7 @@
# 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/.
component {c332f318-1cce-4f02-b676-bb5031d10736} VoicemailService.js
contract @mozilla.org/voicemail/gonkvoicemailservice;1 {c332f318-1cce-4f02-b676-bb5031d10736}

View File

@ -0,0 +1,25 @@
/* 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 "nsIVoicemailService.idl"
[scriptable, uuid(d21dbc55-f540-417d-aa3e-9e890764e957)]
interface nsIGonkVoicemailService : nsIVoicemailService
{
/**
* Called when a voicemail notification has been received by the network.
*/
void notifyStatusChanged(in unsigned long serviceId,
in bool hasMessages,
in long messageCount,
in DOMString returnNumber,
in DOMString returnMessage);
/**
* Called when other voicemail attributes changed.
*/
void notifyInfoChanged(in unsigned long serviceId,
in DOMString number,
in DOMString displayName);
};

View File

@ -34,6 +34,16 @@ UNIFIED_SOURCES += [
'VoicemailStatus.cpp',
]
if CONFIG['MOZ_B2G_RIL']:
if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'gonk':
XPIDL_SOURCES += [
'gonk/nsIGonkVoicemailService.idl',
]
EXTRA_COMPONENTS += [
'gonk/VoicemailService.js',
'gonk/VoicemailService.manifest',
]
FAIL_ON_WARNINGS = True
LOCAL_INCLUDES += [

View File

@ -6,7 +6,8 @@ MARIONETTE_CONTEXT = "chrome";
Cu.import("resource://gre/modules/Promise.jsm");
const VOICEMAIL_SERVICE_CONTRACTID = "@mozilla.org/ril/content-helper;1";
const VOICEMAIL_SERVICE_CONTRACTID =
"@mozilla.org/voicemail/gonkvoicemailservice;1";
const PREF_RIL_NUM_RADIO_INTERFACES = "ril.numRadioInterfaces";
const PREF_DEFAULT_SERVICE_ID = "dom.voicemail.defaultServiceId";