Bug 864485 - 3/3: Gonk backend specific. r=hsinyi

This commit is contained in:
Vicamo Yang 2013-09-05 00:38:57 +08:00
parent 87edb4ea24
commit 6764f35073
9 changed files with 608 additions and 666 deletions

View File

@ -471,6 +471,8 @@
@BINPATH@/components/NetworkStatsManager.manifest
@BINPATH@/components/NetworkInterfaceListService.manifest
@BINPATH@/components/NetworkInterfaceListService.js
@BINPATH@/components/TelephonyProvider.manifest
@BINPATH@/components/TelephonyProvider.js
#endif
#ifdef MOZ_ENABLE_DBUS
@BINPATH@/components/@DLL_PREFIX@dbusservice@DLL_SUFFIX@

View File

@ -71,17 +71,13 @@ const RIL_IPC_MSG_NAMES = [
"RIL:IccInfoChanged",
"RIL:VoiceInfoChanged",
"RIL:DataInfoChanged",
"RIL:EnumerateCalls",
"RIL:GetAvailableNetworks",
"RIL:NetworkSelectionModeChanged",
"RIL:SelectNetwork",
"RIL:SelectNetworkAuto",
"RIL:CallStateChanged",
"RIL:EmergencyCbModeChanged",
"RIL:VoicemailNotification",
"RIL:VoicemailInfoChanged",
"RIL:CallError",
"RIL:SuppSvcNotification",
"RIL:CardLockResult",
"RIL:CardLockRetryCount",
"RIL:USSDReceived",
@ -108,11 +104,9 @@ const RIL_IPC_MSG_NAMES = [
"RIL:UpdateIccContact",
"RIL:SetRoamingPreference",
"RIL:GetRoamingPreference",
"RIL:CdmaCallWaiting",
"RIL:ExitEmergencyCbMode",
"RIL:SetVoicePrivacyMode",
"RIL:GetVoicePrivacyMode",
"RIL:ConferenceCallStateChanged",
"RIL:OtaStatusChanged"
];
@ -120,10 +114,6 @@ XPCOMUtils.defineLazyServiceGetter(this, "cpmm",
"@mozilla.org/childprocessmessagemanager;1",
"nsISyncMessageSender");
XPCOMUtils.defineLazyServiceGetter(this, "gUUIDGenerator",
"@mozilla.org/uuid-generator;1",
"nsIUUIDGenerator");
function MobileIccCardLockResult(options) {
this.lockType = options.lockType;
this.enabled = options.enabled;
@ -449,7 +439,6 @@ RILContentHelper.prototype = {
QueryInterface: XPCOMUtils.generateQI([Ci.nsIMobileConnectionProvider,
Ci.nsICellBroadcastProvider,
Ci.nsIVoicemailProvider,
Ci.nsITelephonyProvider,
Ci.nsIIccProvider,
Ci.nsIObserver,
Ci.nsISupportsWeakReference]),
@ -459,7 +448,6 @@ RILContentHelper.prototype = {
interfaces: [Ci.nsIMobileConnectionProvider,
Ci.nsICellBroadcastProvider,
Ci.nsIVoicemailProvider,
Ci.nsITelephonyProvider,
Ci.nsIIccProvider]}),
// An utility function to copy objects.
@ -1281,11 +1269,9 @@ RILContentHelper.prototype = {
},
_mobileConnectionListeners: null,
_telephonyListeners: null,
_cellBroadcastListeners: null,
_voicemailListeners: null,
_iccListeners: null,
_enumerateTelephonyCallbacks: null,
voicemailStatus: null,
@ -1347,24 +1333,6 @@ RILContentHelper.prototype = {
this.unregisterListener("_mobileConnectionListeners", listener);
},
registerTelephonyMsg: function registerTelephonyMsg(listener) {
debug("Registering for telephony-related messages");
this.registerListener("_telephonyListeners", listener);
cpmm.sendAsyncMessage("RIL:RegisterTelephonyMsg");
},
unregisterTelephonyMsg: function unregisteTelephonyMsg(listener) {
this.unregisterListener("_telephonyListeners", listener);
// We also need to make sure the listener is removed from
// _enumerateTelephonyCallbacks.
let index = this._enumerateTelephonyCallbacks.indexOf(listener);
if (index != -1) {
this._enumerateTelephonyCallbacks.splice(index, 1);
if (DEBUG) debug("Unregistered enumerateTelephony callback: " + listener);
}
},
registerVoicemailMsg: function registerVoicemailMsg(listener) {
debug("Registering for voicemail-related messages");
this.registerListener("_voicemailListeners", listener);
@ -1395,135 +1363,6 @@ RILContentHelper.prototype = {
this.unregisterListener("_iccListeners", listener);
},
enumerateCalls: function enumerateCalls(callback) {
debug("Requesting enumeration of calls for callback: " + callback);
// We need 'requestId' to meet the 'RILContentHelper <--> RadioInterfaceLayer'
// protocol.
let requestId = this._getRandomId();
cpmm.sendAsyncMessage("RIL:EnumerateCalls", {
clientId: 0,
data: {
requestId: requestId
}
});
if (!this._enumerateTelephonyCallbacks) {
this._enumerateTelephonyCallbacks = [];
}
this._enumerateTelephonyCallbacks.push(callback);
},
startTone: function startTone(dtmfChar) {
debug("Sending Tone for " + dtmfChar);
cpmm.sendAsyncMessage("RIL:StartTone", {
clientId: 0,
data: dtmfChar
});
},
stopTone: function stopTone() {
debug("Stopping Tone");
cpmm.sendAsyncMessage("RIL:StopTone", {clientId: 0});
},
dial: function dial(number) {
debug("Dialing " + number);
cpmm.sendAsyncMessage("RIL:Dial", {
clientId: 0,
data: number
});
},
dialEmergency: function dialEmergency(number) {
debug("Dialing emergency " + number);
cpmm.sendAsyncMessage("RIL:DialEmergency", {
clientId: 0,
data: number
});
},
hangUp: function hangUp(callIndex) {
debug("Hanging up call no. " + callIndex);
cpmm.sendAsyncMessage("RIL:HangUp", {
clientId: 0,
data: callIndex
});
},
answerCall: function answerCall(callIndex) {
cpmm.sendAsyncMessage("RIL:AnswerCall", {
clientId: 0,
data: callIndex
});
},
rejectCall: function rejectCall(callIndex) {
cpmm.sendAsyncMessage("RIL:RejectCall", {
clientId: 0,
data: callIndex
});
},
holdCall: function holdCall(callIndex) {
cpmm.sendAsyncMessage("RIL:HoldCall", {
clientId: 0,
data: callIndex
});
},
resumeCall: function resumeCall(callIndex) {
cpmm.sendAsyncMessage("RIL:ResumeCall", {
clientId: 0,
data: callIndex
});
},
conferenceCall: function conferenceCall() {
cpmm.sendAsyncMessage("RIL:ConferenceCall", {
clientId: 0
});
},
separateCall: function separateCall(callIndex) {
cpmm.sendAsyncMessage("RIL:SeparateCall", {
clientId: 0,
data: callIndex
});
},
holdConference: function holdConference() {
cpmm.sendAsyncMessage("RIL:HoldConference", {
clientId: 0
});
},
resumeConference: function resumeConference() {
cpmm.sendAsyncMessage("RIL:ResumeConference", {
clientId: 0
});
},
get microphoneMuted() {
return cpmm.sendSyncMessage("RIL:GetMicrophoneMuted", {clientId: 0})[0];
},
set microphoneMuted(value) {
cpmm.sendAsyncMessage("RIL:SetMicrophoneMuted", {
clientId: 0,
data: value
});
},
get speakerEnabled() {
return cpmm.sendSyncMessage("RIL:GetSpeakerEnabled", {clientId: 0})[0];
},
set speakerEnabled(value) {
cpmm.sendAsyncMessage("RIL:SetSpeakerEnabled", {
clientId: 0,
data: value
});
},
// nsIObserver
observe: function observe(subject, topic, data) {
@ -1620,9 +1459,6 @@ RILContentHelper.prototype = {
"notifyOtaStatusChanged",
[msg.json.data]);
break;
case "RIL:EnumerateCalls":
this.handleEnumerateCalls(msg.json.calls);
break;
case "RIL:GetAvailableNetworks":
this.handleGetAvailableNetworks(msg.json);
break;
@ -1637,35 +1473,6 @@ RILContentHelper.prototype = {
this.handleSelectNetwork(msg.json,
RIL.GECKO_NETWORK_SELECTION_AUTOMATIC);
break;
case "RIL:CallStateChanged": {
let data = msg.json.data;
this._deliverEvent("_telephonyListeners",
"callStateChanged",
[data.callIndex, data.state,
data.number, data.isActive,
data.isOutgoing, data.isEmergency,
data.isConference]);
break;
}
case "RIL:ConferenceCallStateChanged": {
let data = msg.json.data;
this._deliverEvent("_telephonyListeners",
"conferenceCallStateChanged",
[data]);
break;
}
case "RIL:CallError": {
let data = msg.json.data;
this._deliverEvent("_telephonyListeners",
"notifyError",
[data.callIndex, data.errorMsg]);
break;
}
case "RIL:SuppSvcNotification":
this._deliverEvent("_telephonyListeners",
"supplementaryServiceNotification",
[msg.json.callIndex, msg.json.notification]);
break;
case "RIL:VoicemailNotification":
this.handleVoicemailNotification(msg.json.data);
break;
@ -1786,11 +1593,6 @@ RILContentHelper.prototype = {
this.handleSimpleRequest(msg.json.requestId, msg.json.errorMsg,
msg.json.mode);
break;
case "RIL:CdmaCallWaiting":
this._deliverEvent("_telephonyListeners",
"notifyCdmaCallWaiting",
[msg.json.data]);
break;
case "RIL:ExitEmergencyCbMode":
this.handleExitEmergencyCbMode(msg.json);
break;
@ -1810,35 +1612,6 @@ RILContentHelper.prototype = {
}
},
handleEnumerateCalls: function handleEnumerateCalls(calls) {
debug("handleEnumerateCalls: " + JSON.stringify(calls));
let callback = this._enumerateTelephonyCallbacks.shift();
if (!calls.length) {
callback.enumerateCallStateComplete();
return;
}
for (let i in calls) {
let call = calls[i];
let keepGoing;
try {
keepGoing =
callback.enumerateCallState(call.callIndex, call.state, call.number,
call.isActive, call.isOutgoing,
call.isEmergency, call.isConference);
} catch (e) {
debug("callback handler for 'enumerateCallState' threw an " +
" exception: " + e);
keepGoing = true;
}
if (!keepGoing) {
break;
}
}
callback.enumerateCallStateComplete();
},
handleSimpleRequest: function handleSimpleRequest(requestId, errorMsg, result) {
if (errorMsg) {
this.fireRequestError(requestId, errorMsg);
@ -2051,10 +1824,6 @@ RILContentHelper.prototype = {
}
},
_getRandomId: function _getRandomId() {
return gUUIDGenerator.generateUUID().toString();
},
_deliverEvent: function _deliverEvent(listenerType, name, args) {
let thisListeners = this[listenerType];
if (!thisListeners) {

View File

@ -46,9 +46,6 @@ const RADIOINTERFACE_CID =
const RILNETWORKINTERFACE_CID =
Components.ID("{3bdd52a9-3965-4130-b569-0ac5afed045e}");
const nsIAudioManager = Ci.nsIAudioManager;
const nsITelephonyProvider = Ci.nsITelephonyProvider;
const kNetworkInterfaceStateChangedTopic = "network-interface-state-changed";
const kSmsReceivedObserverTopic = "sms-received";
const kSilentSmsReceivedObserverTopic = "silent-sms-received";
@ -73,30 +70,7 @@ const DOM_MOBILE_MESSAGE_DELIVERY_SENDING = "sending";
const DOM_MOBILE_MESSAGE_DELIVERY_SENT = "sent";
const DOM_MOBILE_MESSAGE_DELIVERY_ERROR = "error";
const CALL_WAKELOCK_TIMEOUT = 5000;
const RADIO_POWER_OFF_TIMEOUT = 30000;
const RIL_IPC_TELEPHONY_MSG_NAMES = [
"RIL:EnumerateCalls",
"RIL:GetMicrophoneMuted",
"RIL:SetMicrophoneMuted",
"RIL:GetSpeakerEnabled",
"RIL:SetSpeakerEnabled",
"RIL:StartTone",
"RIL:StopTone",
"RIL:Dial",
"RIL:DialEmergency",
"RIL:HangUp",
"RIL:AnswerCall",
"RIL:RejectCall",
"RIL:HoldCall",
"RIL:ResumeCall",
"RIL:RegisterTelephonyMsg",
"RIL:ConferenceCall",
"RIL:SeparateCall",
"RIL:HoldConference",
"RIL:ResumeConference"
];
const RADIO_POWER_OFF_TIMEOUT = 30000;
const RIL_IPC_MOBILECONNECTION_MSG_NAMES = [
"RIL:GetRilContext",
@ -188,6 +162,10 @@ XPCOMUtils.defineLazyServiceGetter(this, "gSystemWorkerManager",
"@mozilla.org/telephony/system-worker-manager;1",
"nsISystemWorkerManager");
XPCOMUtils.defineLazyServiceGetter(this, "gTelephonyProvider",
"@mozilla.org/telephony/telephonyprovider;1",
"nsIGonkTelephonyProvider");
XPCOMUtils.defineLazyGetter(this, "WAP", function () {
let wap = {};
Cu.import("resource://gre/modules/WapPushManager.js", wap);
@ -200,64 +178,6 @@ XPCOMUtils.defineLazyGetter(this, "PhoneNumberUtils", function () {
return ns.PhoneNumberUtils;
});
function convertRILCallState(state) {
switch (state) {
case RIL.CALL_STATE_ACTIVE:
return nsITelephonyProvider.CALL_STATE_CONNECTED;
case RIL.CALL_STATE_HOLDING:
return nsITelephonyProvider.CALL_STATE_HELD;
case RIL.CALL_STATE_DIALING:
return nsITelephonyProvider.CALL_STATE_DIALING;
case RIL.CALL_STATE_ALERTING:
return nsITelephonyProvider.CALL_STATE_ALERTING;
case RIL.CALL_STATE_INCOMING:
case RIL.CALL_STATE_WAITING:
return nsITelephonyProvider.CALL_STATE_INCOMING;
default:
throw new Error("Unknown rilCallState: " + state);
}
}
function convertRILSuppSvcNotification(notification) {
switch (notification) {
case RIL.GECKO_SUPP_SVC_NOTIFICATION_REMOTE_HELD:
return nsITelephonyProvider.NOTIFICATION_REMOTE_HELD;
case RIL.GECKO_SUPP_SVC_NOTIFICATION_REMOTE_RESUMED:
return nsITelephonyProvider.NOTIFICATION_REMOTE_RESUMED;
default:
throw new Error("Unknown rilSuppSvcNotification: " + notification);
}
}
/**
* Fake nsIAudioManager implementation so that we can run the telephony
* code in a non-Gonk build.
*/
let FakeAudioManager = {
microphoneMuted: false,
masterVolume: 1.0,
masterMuted: false,
phoneState: nsIAudioManager.PHONE_STATE_CURRENT,
_forceForUse: {},
setForceForUse: function setForceForUse(usage, force) {
this._forceForUse[usage] = force;
},
getForceForUse: function setForceForUse(usage) {
return this._forceForUse[usage] || nsIAudioManager.FORCE_NONE;
}
};
XPCOMUtils.defineLazyGetter(this, "gAudioManager", function getAudioManager() {
try {
return Cc["@mozilla.org/telephony/audiomanager;1"]
.getService(nsIAudioManager);
} catch (ex) {
//TODO on the phone this should not fall back as silently.
if (DEBUG) debug("Using fake audio manager.");
return FakeAudioManager;
}
});
XPCOMUtils.defineLazyGetter(this, "gMessageManager", function () {
return {
QueryInterface: XPCOMUtils.generateQI([Ci.nsIMessageListener,
@ -290,9 +210,6 @@ XPCOMUtils.defineLazyGetter(this, "gMessageManager", function () {
_registerMessageListeners: function _registerMessageListeners() {
ppmm.addMessageListener("child-process-shutdown", this);
for (let msgname of RIL_IPC_TELEPHONY_MSG_NAMES) {
ppmm.addMessageListener(msgname, this);
}
for (let msgname of RIL_IPC_MOBILECONNECTION_MSG_NAMES) {
ppmm.addMessageListener(msgname, this);
}
@ -309,9 +226,6 @@ XPCOMUtils.defineLazyGetter(this, "gMessageManager", function () {
_unregisterMessageListeners: function _unregisterMessageListeners() {
ppmm.removeMessageListener("child-process-shutdown", this);
for (let msgname of RIL_IPC_TELEPHONY_MSG_NAMES) {
ppmm.removeMessageListener(msgname, this);
}
for (let msgname of RIL_IPC_MOBILECONNECTION_MSG_NAMES) {
ppmm.removeMessageListener(msgname, this);
}
@ -430,15 +344,7 @@ XPCOMUtils.defineLazyGetter(this, "gMessageManager", function () {
return;
}
if (RIL_IPC_TELEPHONY_MSG_NAMES.indexOf(msg.name) != -1) {
if (!msg.target.assertPermission("telephony")) {
if (DEBUG) {
debug("Telephony message " + msg.name +
" from a content process with no 'telephony' privileges.");
}
return null;
}
} else if (RIL_IPC_MOBILECONNECTION_MSG_NAMES.indexOf(msg.name) != -1) {
if (RIL_IPC_MOBILECONNECTION_MSG_NAMES.indexOf(msg.name) != -1) {
if (!msg.target.assertPermission("mobileconnection")) {
if (DEBUG) {
debug("MobileConnection message " + msg.name +
@ -476,9 +382,6 @@ XPCOMUtils.defineLazyGetter(this, "gMessageManager", function () {
}
switch (msg.name) {
case "RIL:RegisterTelephonyMsg":
this._registerMessageTarget("telephony", msg.target);
return;
case "RIL:RegisterMobileConnectionMsg":
this._registerMessageTarget("mobileconnection", msg.target);
return;
@ -519,13 +422,6 @@ XPCOMUtils.defineLazyGetter(this, "gMessageManager", function () {
}
},
sendTelephonyMessage: function sendTelephonyMessage(message, clientId, data) {
this._sendTargetMessage("telephony", message, {
clientId: clientId,
data: data
});
},
sendMobileConnectionMessage: function sendMobileConnectionMessage(message, clientId, data) {
this._sendTargetMessage("mobileconnection", message, {
clientId: clientId,
@ -894,61 +790,6 @@ RadioInterface.prototype = {
case "RIL:GetRilContext":
// This message is sync.
return this.rilContext;
case "RIL:EnumerateCalls":
this.enumerateCalls(msg.target, msg.json.data);
break;
case "RIL:GetMicrophoneMuted":
// This message is sync.
return this.microphoneMuted;
case "RIL:SetMicrophoneMuted":
this.microphoneMuted = msg.json.data;
break;
case "RIL:GetSpeakerEnabled":
// This message is sync.
return this.speakerEnabled;
case "RIL:SetSpeakerEnabled":
this.speakerEnabled = msg.json.data;
break;
case "RIL:StartTone":
this.workerMessenger.send("startTone", { dtmfChar: msg.json.data });
break;
case "RIL:StopTone":
this.workerMessenger.send("stopTone");
break;
case "RIL:Dial":
this.dial(msg.json.data);
break;
case "RIL:DialEmergency":
this.dialEmergency(msg.json.data);
break;
case "RIL:HangUp":
this.workerMessenger.send("hangUp", { callIndex: msg.json.data });
break;
case "RIL:AnswerCall":
this.workerMessenger.send("answerCall", { callIndex: msg.json.data });
break;
case "RIL:RejectCall":
this.workerMessenger.send("rejectCall", { callIndex: msg.json.data });
break;
case "RIL:HoldCall":
this.workerMessenger.send("holdCall", { callIndex: msg.json.data });
break;
case "RIL:ResumeCall":
this.workerMessenger.send("resumeCall", { callIndex: msg.json.data });
break;
case "RIL:ConferenceCall":
this.workerMessenger.send("conferenceCall");
break;
case "RIL:SeparateCall":
this.workerMessenger.send("separateCall",
{ callIndex: msg.json.data });
break;
case "RIL:HoldConference":
this.workerMessenger.send("holdConference");
break;
case "RIL:ResumeConference":
this.workerMessenger.send("resumeConference");
break;
case "RIL:GetAvailableNetworks":
this.workerMessenger.sendWithIPCMessage(msg, "getAvailableNetworks");
break;
@ -1058,28 +899,26 @@ RadioInterface.prototype = {
handleUnsolicitedWorkerMessage: function handleUnsolicitedWorkerMessage(message) {
switch (message.rilMessageType) {
case "callRing":
this.handleCallRing();
gTelephonyProvider.notifyCallRing();
break;
case "callStateChange":
// This one will handle its own notifications.
this.handleCallStateChange(message.call);
gTelephonyProvider.notifyCallStateChanged(message.call);
break;
case "callDisconnected":
// This one will handle its own notifications.
this.handleCallDisconnected(message.call);
gTelephonyProvider.notifyCallDisconnected(message.call);
break;
case "conferenceCallStateChanged":
this.handleConferenceCallStateChanged(message.state);
gTelephonyProvider.notifyConferenceCallStateChanged(message.state);
break;
case "cdmaCallWaiting":
gMessageManager.sendTelephonyMessage("RIL:CdmaCallWaiting",
this.clientId, message.number);
gTelephonyProvider.notifyCdmaCallWaiting(message.number);
break;
case "callError":
this.handleCallError(message);
gTelephonyProvider.notifyCallError(message.callIndex, message.errorMsg);
break;
case "suppSvcNotification":
this.handleSuppSvcNotification(message);
gTelephonyProvider.notifySupplementaryService(message.callIndex,
message.notification);
break;
case "emergencyCbModeChange":
this.handleEmergencyCbModeChange(message);
@ -1727,165 +1566,6 @@ RadioInterface.prototype = {
this.setupDataCallByType("default");
},
/**
* Track the active call and update the audio system as its state changes.
*/
_activeCall: null,
updateCallAudioState: function updateCallAudioState(options) {
if (options.conferenceState === nsITelephonyProvider.CALL_STATE_CONNECTED) {
gAudioManager.phoneState = nsIAudioManager.PHONE_STATE_IN_CALL;
if (this.speakerEnabled) {
gAudioManager.setForceForUse(nsIAudioManager.USE_COMMUNICATION,
nsIAudioManager.FORCE_SPEAKER);
}
return;
}
if (options.conferenceState === nsITelephonyProvider.CALL_STATE_UNKNOWN ||
options.conferenceState === nsITelephonyProvider.CALL_STATE_HELD) {
if (!this._activeCall) {
gAudioManager.phoneState = nsIAudioManager.PHONE_STATE_NORMAL;
}
return;
}
if (!options.call) {
return;
}
if (options.call.isConference) {
if (this._activeCall && this._activeCall.callIndex == options.call.callIndex) {
this._activeCall = null;
}
return;
}
let call = options.call;
switch (call.state) {
case nsITelephonyProvider.CALL_STATE_DIALING: // Fall through...
case nsITelephonyProvider.CALL_STATE_ALERTING:
case nsITelephonyProvider.CALL_STATE_CONNECTED:
call.isActive = true;
this._activeCall = call;
gAudioManager.phoneState = nsIAudioManager.PHONE_STATE_IN_CALL;
if (this.speakerEnabled) {
gAudioManager.setForceForUse(nsIAudioManager.USE_COMMUNICATION,
nsIAudioManager.FORCE_SPEAKER);
}
if (DEBUG) {
this.debug("Active call, put audio system into PHONE_STATE_IN_CALL: "
+ gAudioManager.phoneState);
}
break;
case nsITelephonyProvider.CALL_STATE_INCOMING:
call.isActive = false;
if (!this._activeCall) {
// We can change the phone state into RINGTONE only when there's
// no active call.
gAudioManager.phoneState = nsIAudioManager.PHONE_STATE_RINGTONE;
if (DEBUG) {
this.debug("Incoming call, put audio system into " +
"PHONE_STATE_RINGTONE: " + gAudioManager.phoneState);
}
}
break;
case nsITelephonyProvider.CALL_STATE_HELD: // Fall through...
case nsITelephonyProvider.CALL_STATE_DISCONNECTED:
call.isActive = false;
if (this._activeCall &&
this._activeCall.callIndex == call.callIndex) {
// Previously active call is not active now.
this._activeCall = null;
}
if (!this._activeCall) {
// No active call. Disable the audio.
gAudioManager.phoneState = nsIAudioManager.PHONE_STATE_NORMAL;
if (DEBUG) {
this.debug("No active call, put audio system into " +
"PHONE_STATE_NORMAL: " + gAudioManager.phoneState);
}
}
break;
}
},
_callRingWakeLock: null,
_callRingWakeLockTimer: null,
_cancelCallRingWakeLockTimer: function _cancelCallRingWakeLockTimer() {
if (this._callRingWakeLockTimer) {
this._callRingWakeLockTimer.cancel();
}
if (this._callRingWakeLock) {
this._callRingWakeLock.unlock();
this._callRingWakeLock = null;
}
},
/**
* Handle an incoming call.
*
* Not much is known about this call at this point, but it's enough
* to start bringing up the Phone app already.
*/
handleCallRing: function handleCallRing() {
if (!this._callRingWakeLock) {
this._callRingWakeLock = gPowerManagerService.newWakeLock("cpu");
}
if (!this._callRingWakeLockTimer) {
this._callRingWakeLockTimer =
Cc["@mozilla.org/timer;1"].createInstance(Ci.nsITimer);
}
this._callRingWakeLockTimer
.initWithCallback(this._cancelCallRingWakeLockTimer.bind(this),
CALL_WAKELOCK_TIMEOUT, Ci.nsITimer.TYPE_ONE_SHOT);
gSystemMessenger.broadcastMessage("telephony-new-call", {});
},
/**
* Handle call state changes by updating our current state and the audio
* system.
*/
handleCallStateChange: function handleCallStateChange(call) {
if (DEBUG) this.debug("handleCallStateChange: " + JSON.stringify(call));
call.state = convertRILCallState(call.state);
if (call.state == nsITelephonyProvider.CALL_STATE_DIALING) {
gSystemMessenger.broadcastMessage("telephony-new-call", {});
}
this.updateCallAudioState({call: call});
gMessageManager.sendTelephonyMessage("RIL:CallStateChanged",
this.clientId, call);
},
/**
* Handle call disconnects by updating our current state and the audio system.
*/
handleCallDisconnected: function handleCallDisconnected(call) {
if (DEBUG) this.debug("handleCallDisconnected: " + JSON.stringify(call));
call.state = nsITelephonyProvider.CALL_STATE_DISCONNECTED;
let duration = ("started" in call && typeof call.started == "number") ?
new Date().getTime() - call.started : 0;
let data = {
number: call.number,
duration: duration,
direction: call.isOutgoing ? "outgoing" : "incoming"
};
gSystemMessenger.broadcastMessage("telephony-call-ended", data);
this.updateCallAudioState({call: call});
gMessageManager.sendTelephonyMessage("RIL:CallStateChanged",
this.clientId, call);
},
handleConferenceCallStateChanged: function handleConferenceCallStateChanged(state) {
debug("handleConferenceCallStateChanged: " + state);
state = state != null ? convertRILCallState(state) :
nsITelephonyProvider.CALL_STATE_UNKNOWN;
this.updateCallAudioState({conferenceState: state});
gMessageManager.sendTelephonyMessage("RIL:ConferenceCallStateChanged",
this.clientId, state);
},
/**
* Update network selection mode
*/
@ -1905,23 +1585,6 @@ RadioInterface.prototype = {
this.clientId, message);
},
/**
* Handle call error.
*/
handleCallError: function handleCallError(message) {
gMessageManager.sendTelephonyMessage("RIL:CallError",
this.clientId, message);
},
/**
* Handle supplementary service notification.
*/
handleSuppSvcNotification: function handleSuppSvcNotification(message) {
message.notification = convertRILSuppSvcNotification(message.notification);
gMessageManager.sendTelephonyMessage("RIL:SuppSvcNotification",
this.clientId, message);
},
/**
* Handle WDP port push PDU. Constructor WDP bearer information and deliver
* to WapPushManager.
@ -2309,8 +1972,6 @@ RadioInterface.prototype = {
}
break;
case "xpcom-shutdown":
// Cancel the timer for the call-ring wake lock.
this._cancelCallRingWakeLockTimer();
// Shutdown all RIL network interfaces
for each (let apnSetting in this.apnSettings.byAPN) {
if (apnSetting.iface) {
@ -2460,56 +2121,6 @@ RadioInterface.prototype = {
// Handle phone functions of nsIRILContentHelper
enumerateCalls: function enumerateCalls(target, message) {
if (DEBUG) this.debug("Requesting enumeration of calls for callback");
this.workerMessenger.send("enumerateCalls", message, (function(response) {
for (let call of response.calls) {
call.state = convertRILCallState(call.state);
call.isActive = this._activeCall ?
call.callIndex == this._activeCall.callIndex : false;
}
target.sendAsyncMessage("RIL:EnumerateCalls", response);
return false;
}).bind(this));
},
_validateNumber: function _validateNumber(number) {
// note: isPlainPhoneNumber also accepts USSD and SS numbers
if (PhoneNumberUtils.isPlainPhoneNumber(number)) {
return true;
}
this.handleCallError({
callIndex: -1,
errorMsg: RIL.RIL_CALL_FAILCAUSE_TO_GECKO_CALL_ERROR[RIL.CALL_FAIL_UNOBTAINABLE_NUMBER]
});
if (DEBUG) {
this.debug("Number '" + number + "' doesn't seem to be a viable number." +
" Drop.");
}
return false;
},
dial: function dial(number) {
if (DEBUG) this.debug("Dialing " + number);
number = PhoneNumberUtils.normalize(number);
if (this._validateNumber(number)) {
this.workerMessenger.send("dial", { number: number,
isDialEmergency: false });
}
},
dialEmergency: function dialEmergency(number) {
if (DEBUG) this.debug("Dialing emergency " + number);
// we don't try to be too clever here, as the phone is probably in the
// locked state. Let's just check if it's a number without normalizing
if (this._validateNumber(number)) {
this.workerMessenger.send("dial", { number: number,
isDialEmergency: true });
}
},
_sendCfStateChanged: function _sendCfStateChanged(message) {
gMessageManager.sendMobileConnectionMessage("RIL:CfStateChanged",
this.clientId, message);
@ -2564,37 +2175,6 @@ RadioInterface.prototype = {
}).bind(this));
},
get microphoneMuted() {
return gAudioManager.microphoneMuted;
},
set microphoneMuted(value) {
if (value == this.microphoneMuted) {
return;
}
gAudioManager.microphoneMuted = value;
if (!this._activeCall) {
gAudioManager.phoneState = nsIAudioManager.PHONE_STATE_NORMAL;
}
},
get speakerEnabled() {
return (gAudioManager.getForceForUse(nsIAudioManager.USE_COMMUNICATION) ==
nsIAudioManager.FORCE_SPEAKER);
},
set speakerEnabled(value) {
if (value == this.speakerEnabled) {
return;
}
let force = value ? nsIAudioManager.FORCE_SPEAKER :
nsIAudioManager.FORCE_NONE;
gAudioManager.setForceForUse(nsIAudioManager.USE_COMMUNICATION, force);
if (!this._activeCall) {
gAudioManager.phoneState = nsIAudioManager.PHONE_STATE_NORMAL;
}
},
/**
* List of tuples of national language identifier pairs.
*
@ -3362,6 +2942,13 @@ RadioInterface.prototype = {
this.workerMessenger.send("deactivateDataCall", { cid: cid,
reason: reason });
},
sendWorkerMessage: function sendWorkerMessage(rilMessageType, message,
callback) {
this.workerMessenger.send(rilMessageType, message, function (response) {
return callback.handleResponse(response);
});
}
};
function RILNetworkInterface(radioInterface, apnSetting) {

View File

@ -78,7 +78,13 @@ interface nsIRilContext : nsISupports
readonly attribute nsIDOMMozMobileConnectionInfo data;
};
[scriptable, uuid(a50d65aa-00da-11e3-b954-7bfb233d98fc)]
[scriptable, function, uuid(3bc96351-53b0-47a1-a888-c74c64b60f25)]
interface nsIRilSendWorkerMessageCallback : nsISupports
{
boolean handleResponse(in jsval response);
};
[scriptable, uuid(61a8ca67-6113-4cd0-b443-e045f09863ed)]
interface nsIRadioInterface : nsISupports
{
readonly attribute nsIRilContext rilContext;
@ -105,6 +111,10 @@ interface nsIRadioInterface : nsISupports
in DOMString message,
in boolean silent,
in nsIMobileMessageCallback request);
void sendWorkerMessage(in DOMString type,
[optional] in jsval message,
[optional] in nsIRilSendWorkerMessageCallback callback);
};
[scriptable, uuid(44b03951-1444-4c03-bd37-0bcb3a01b56f)]

View File

@ -4,6 +4,9 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "mozilla/dom/telephony/TelephonyFactory.h"
#ifdef MOZ_WIDGET_GONK
#include "nsIGonkTelephonyProvider.h"
#endif
#include "nsServiceManagerUtils.h"
#include "nsXULAppAPI.h"
#include "TelephonyIPCProvider.h"
@ -17,6 +20,10 @@ TelephonyFactory::CreateTelephonyProvider()
if (XRE_GetProcessType() == GeckoProcessType_Content) {
provider = new TelephonyIPCProvider();
#ifdef MOZ_WIDGET_GONK
} else {
provider = do_CreateInstance(GONK_TELEPHONY_PROVIDER_CONTRACTID);
#endif
}
return provider.forget();

View File

@ -0,0 +1,525 @@
/* -*- 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/XPCOMUtils.jsm");
Cu.import("resource://gre/modules/Services.jsm");
var RIL = {};
Cu.import("resource://gre/modules/ril_consts.js", RIL);
const GONK_TELEPHONYPROVIDER_CONTRACTID =
"@mozilla.org/telephony/gonktelephonyprovider;1";
const GONK_TELEPHONYPROVIDER_CID =
Components.ID("{67d26434-d063-4d28-9f48-5b3189788155}");
const kPrefenceChangedObserverTopic = "nsPref:changed";
const kXpcomShutdownObserverTopic = "xpcom-shutdown";
const nsIAudioManager = Ci.nsIAudioManager;
const nsITelephonyProvider = Ci.nsITelephonyProvider;
const CALL_WAKELOCK_TIMEOUT = 5000;
let DEBUG;
function debug(s) {
dump("TelephonyProvider: " + s + "\n");
}
XPCOMUtils.defineLazyGetter(this, "gAudioManager", function getAudioManager() {
try {
return Cc["@mozilla.org/telephony/audiomanager;1"]
.getService(nsIAudioManager);
} catch (ex) {
//TODO on the phone this should not fall back as silently.
// Fake nsIAudioManager implementation so that we can run the telephony
// code in a non-Gonk build.
if (DEBUG) debug("Using fake audio manager.");
return {
microphoneMuted: false,
masterVolume: 1.0,
masterMuted: false,
phoneState: nsIAudioManager.PHONE_STATE_CURRENT,
_forceForUse: {},
setForceForUse: function setForceForUse(usage, force) {
this._forceForUse[usage] = force;
},
getForceForUse: function setForceForUse(usage) {
return this._forceForUse[usage] || nsIAudioManager.FORCE_NONE;
}
};
}
});
XPCOMUtils.defineLazyServiceGetter(this, "gPowerManagerService",
"@mozilla.org/power/powermanagerservice;1",
"nsIPowerManagerService");
XPCOMUtils.defineLazyServiceGetter(this, "gSystemMessenger",
"@mozilla.org/system-message-internal;1",
"nsISystemMessagesInternal");
XPCOMUtils.defineLazyGetter(this, "gRadioInterface", function () {
let ril = Cc["@mozilla.org/ril;1"].getService(Ci["nsIRadioInterfaceLayer"]);
// TODO: Bug 854326 - B2G Multi-SIM: support multiple SIM cards for SMS/MMS
return ril.getRadioInterface(0);
});
XPCOMUtils.defineLazyGetter(this, "gPhoneNumberUtils", function () {
let ns = {};
Cu.import("resource://gre/modules/PhoneNumberUtils.jsm", ns);
return ns.PhoneNumberUtils;
});
function TelephonyProvider() {
this._listeners = [];
this._updateDebugFlag();
Services.obs.addObserver(this, kPrefenceChangedObserverTopic, false);
Services.obs.addObserver(this, kXpcomShutdownObserverTopic, false);
}
TelephonyProvider.prototype = {
classID: GONK_TELEPHONYPROVIDER_CID,
classInfo: XPCOMUtils.generateCI({classID: GONK_TELEPHONYPROVIDER_CID,
contractID: GONK_TELEPHONYPROVIDER_CONTRACTID,
classDescription: "TelephonyProvider",
interfaces: [Ci.nsITelephonyProvider,
Ci.nsIGonkTelephonyProvider],
flags: Ci.nsIClassInfo.SINGLETON}),
QueryInterface: XPCOMUtils.generateQI([Ci.nsITelephonyProvider,
Ci.nsIGonkTelephonyProvider,
Ci.nsIObserver]),
_callRingWakeLock: null,
_callRingWakeLockTimer: null,
_cancelCallRingWakeLockTimer: function _cancelCallRingWakeLockTimer() {
if (this._callRingWakeLockTimer) {
this._callRingWakeLockTimer.cancel();
}
if (this._callRingWakeLock) {
this._callRingWakeLock.unlock();
this._callRingWakeLock = null;
}
},
// An array of nsITelephonyListener instances.
_listeners: null,
_notifyAllListeners: function _notifyAllListeners(aMethodName, aArgs) {
let listeners = this._listeners.slice();
for (let listener of listeners) {
if (this._listeners.indexOf(listener) == -1) {
// Listener has been unregistered in previous run.
continue;
}
let handler = listener[aMethodName];
try {
handler.apply(listener, aArgs);
} catch (e) {
debug("listener for " + aMethodName + " threw an exception: " + e);
}
}
},
/**
* Track the active call and update the audio system as its state changes.
*/
_activeCall: null,
_updateCallAudioState: function _updateCallAudioState(aCall,
aConferenceState) {
if (aConferenceState === nsITelephonyProvider.CALL_STATE_CONNECTED) {
gAudioManager.phoneState = nsIAudioManager.PHONE_STATE_IN_CALL;
if (this.speakerEnabled) {
gAudioManager.setForceForUse(nsIAudioManager.USE_COMMUNICATION,
nsIAudioManager.FORCE_SPEAKER);
}
return;
}
if (aConferenceState === nsITelephonyProvider.CALL_STATE_UNKNOWN ||
aConferenceState === nsITelephonyProvider.CALL_STATE_HELD) {
if (!this._activeCall) {
gAudioManager.phoneState = nsIAudioManager.PHONE_STATE_NORMAL;
}
return;
}
if (!aCall) {
return;
}
if (aCall.isConference) {
if (this._activeCall && this._activeCall.callIndex == aCall.callIndex) {
this._activeCall = null;
}
return;
}
switch (aCall.state) {
case nsITelephonyProvider.CALL_STATE_DIALING: // Fall through...
case nsITelephonyProvider.CALL_STATE_ALERTING:
case nsITelephonyProvider.CALL_STATE_CONNECTED:
aCall.isActive = true;
this._activeCall = aCall;
gAudioManager.phoneState = nsIAudioManager.PHONE_STATE_IN_CALL;
if (this.speakerEnabled) {
gAudioManager.setForceForUse(nsIAudioManager.USE_COMMUNICATION,
nsIAudioManager.FORCE_SPEAKER);
}
if (DEBUG) {
debug("Active call, put audio system into PHONE_STATE_IN_CALL: " +
gAudioManager.phoneState);
}
break;
case nsITelephonyProvider.CALL_STATE_INCOMING:
aCall.isActive = false;
if (!this._activeCall) {
// We can change the phone state into RINGTONE only when there's
// no active call.
gAudioManager.phoneState = nsIAudioManager.PHONE_STATE_RINGTONE;
if (DEBUG) {
debug("Incoming call, put audio system into PHONE_STATE_RINGTONE: " +
gAudioManager.phoneState);
}
}
break;
case nsITelephonyProvider.CALL_STATE_HELD: // Fall through...
case nsITelephonyProvider.CALL_STATE_DISCONNECTED:
aCall.isActive = false;
if (this._activeCall &&
this._activeCall.callIndex == aCall.callIndex) {
// Previously active call is not active now.
this._activeCall = null;
}
if (!this._activeCall) {
// No active call. Disable the audio.
gAudioManager.phoneState = nsIAudioManager.PHONE_STATE_NORMAL;
if (DEBUG) {
debug("No active call, put audio system into PHONE_STATE_NORMAL: " +
gAudioManager.phoneState);
}
}
break;
}
},
_convertRILCallState: function _convertRILCallState(aState) {
switch (aState) {
case RIL.CALL_STATE_ACTIVE:
return nsITelephonyProvider.CALL_STATE_CONNECTED;
case RIL.CALL_STATE_HOLDING:
return nsITelephonyProvider.CALL_STATE_HELD;
case RIL.CALL_STATE_DIALING:
return nsITelephonyProvider.CALL_STATE_DIALING;
case RIL.CALL_STATE_ALERTING:
return nsITelephonyProvider.CALL_STATE_ALERTING;
case RIL.CALL_STATE_INCOMING:
case RIL.CALL_STATE_WAITING:
return nsITelephonyProvider.CALL_STATE_INCOMING;
default:
throw new Error("Unknown rilCallState: " + aState);
}
},
_convertRILSuppSvcNotification: function _convertRILSuppSvcNotification(aNotification) {
switch (aNotification) {
case RIL.GECKO_SUPP_SVC_NOTIFICATION_REMOTE_HELD:
return nsITelephonyProvider.NOTIFICATION_REMOTE_HELD;
case RIL.GECKO_SUPP_SVC_NOTIFICATION_REMOTE_RESUMED:
return nsITelephonyProvider.NOTIFICATION_REMOTE_RESUMED;
default:
throw new Error("Unknown rilSuppSvcNotification: " + aNotification);
}
},
_validateNumber: function _validateNumber(aNumber) {
// note: isPlainPhoneNumber also accepts USSD and SS numbers
if (gPhoneNumberUtils.isPlainPhoneNumber(aNumber)) {
return true;
}
let errorMsg = RIL.RIL_CALL_FAILCAUSE_TO_GECKO_CALL_ERROR[RIL.CALL_FAIL_UNOBTAINABLE_NUMBER];
let currentThread = Services.tm.currentThread;
currentThread.dispatch(this.notifyCallError.bind(this, -1, errorMsg),
Ci.nsIThread.DISPATCH_NORMAL);
if (DEBUG) {
debug("Number '" + aNumber + "' doesn't seem to be a viable number. Drop.");
}
return false;
},
_updateDebugFlag: function _updateDebugFlag() {
try {
DEBUG = RIL.DEBUG_RIL ||
Services.prefs.getBoolPref("ril.debugging.enabled");
} catch (e) {}
},
/**
* nsITelephonyProvider interface.
*/
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) {
throw Cr.NS_ERROR_UNEXPECTED;
}
this._listeners.splice(index, 1);
},
enumerateCalls: function(aListener) {
if (DEBUG) debug("Requesting enumeration of calls for callback");
gRadioInterface.sendWorkerMessage("enumerateCalls", null,
(function(response) {
for (let call of response.calls) {
call.state = this._convertRILCallState(call.state);
call.isActive = this._activeCall ?
(call.callIndex == this._activeCall.callIndex) : false;
aListener.enumerateCallState(call.callIndex, call.state, call.number,
call.isActive, call.isOutgoing,
call.isEmergency, call.isConference);
}
aListener.enumerateCallStateComplete();
return false;
}).bind(this));
},
dial: function(aNumber, aIsEmergency) {
if (DEBUG) debug("Dialing " + (aIsEmergency ? "emergency " : "") + aNumber);
// we don't try to be too clever here, as the phone is probably in the
// locked state. Let's just check if it's a number without normalizing
if (!aIsEmergency) {
aNumber = gPhoneNumberUtils.normalize(aNumber);
}
if (this._validateNumber(aNumber)) {
gRadioInterface.sendWorkerMessage("dial", { number: aNumber,
isDialEmergency: aIsEmergency });
}
},
hangUp: function(aCallIndex) {
gRadioInterface.sendWorkerMessage("hangUp", { callIndex: aCallIndex });
},
startTone: function(aDtmfChar) {
gRadioInterface.sendWorkerMessage("startTone", { dtmfChar: aDtmfChar });
},
stopTone: function() {
gRadioInterface.sendWorkerMessage("stopTone");
},
answerCall: function(aCallIndex) {
gRadioInterface.sendWorkerMessage("answerCall", { callIndex: aCallIndex });
},
rejectCall: function(aCallIndex) {
gRadioInterface.sendWorkerMessage("rejectCall", { callIndex: aCallIndex });
},
holdCall: function(aCallIndex) {
gRadioInterface.sendWorkerMessage("holdCall", { callIndex: aCallIndex });
},
resumeCall: function(aCallIndex) {
gRadioInterface.sendWorkerMessage("resumeCall", { callIndex: aCallIndex });
},
conferenceCall: function conferenceCall() {
gRadioInterface.sendWorkerMessage("conferenceCall");
},
separateCall: function separateCall(aCallIndex) {
gRadioInterface.sendWorkerMessage("separateCall", { callIndex: aCallIndex });
},
holdConference: function holdConference() {
gRadioInterface.sendWorkerMessage("holdConference");
},
resumeConference: function resumeConference() {
gRadioInterface.sendWorkerMessage("resumeConference");
},
get microphoneMuted() {
return gAudioManager.microphoneMuted;
},
set microphoneMuted(aMuted) {
if (aMuted == this.microphoneMuted) {
return;
}
gAudioManager.microphoneMuted = aMuted;
if (!this._activeCall) {
gAudioManager.phoneState = nsIAudioManager.PHONE_STATE_NORMAL;
}
},
get speakerEnabled() {
let force = gAudioManager.getForceForUse(nsIAudioManager.USE_COMMUNICATION);
return (force == nsIAudioManager.FORCE_SPEAKER);
},
set speakerEnabled(aEnabled) {
if (aEnabled == this.speakerEnabled) {
return;
}
let force = aEnabled ? nsIAudioManager.FORCE_SPEAKER :
nsIAudioManager.FORCE_NONE;
gAudioManager.setForceForUse(nsIAudioManager.USE_COMMUNICATION, force);
if (!this._activeCall) {
gAudioManager.phoneState = nsIAudioManager.PHONE_STATE_NORMAL;
}
},
/**
* nsIGonkTelephonyProvider interface.
*/
/**
* Handle call disconnects by updating our current state and the audio system.
*/
notifyCallDisconnected: function notifyCallDisconnected(aCall) {
if (DEBUG) debug("handleCallDisconnected: " + JSON.stringify(aCall));
aCall.state = nsITelephonyProvider.CALL_STATE_DISCONNECTED;
let duration = ("started" in aCall && typeof aCall.started == "number") ?
new Date().getTime() - aCall.started : 0;
let data = {
number: aCall.number,
duration: duration,
direction: aCall.isOutgoing ? "outgoing" : "incoming"
};
gSystemMessenger.broadcastMessage("telephony-call-ended", data);
this._updateCallAudioState(aCall, null);
this._notifyAllListeners("callStateChanged", [aCall.callIndex,
aCall.state,
aCall.number,
aCall.isActive,
aCall.isOutgoing,
aCall.isEmergency,
aCall.isConference]);
},
/**
* Handle call error.
*/
notifyCallError: function notifyCallError(aCallIndex, aErrorMsg) {
this._notifyAllListeners("notifyError", [aCallIndex, aErrorMsg]);
},
/**
* Handle an incoming call.
*
* Not much is known about this call at this point, but it's enough
* to start bringing up the Phone app already.
*/
notifyCallRing: function notifyCallRing() {
if (!this._callRingWakeLock) {
this._callRingWakeLock = gPowerManagerService.newWakeLock("cpu");
}
if (!this._callRingWakeLockTimer) {
this._callRingWakeLockTimer =
Cc["@mozilla.org/timer;1"].createInstance(Ci.nsITimer);
}
this._callRingWakeLockTimer
.initWithCallback(this._cancelCallRingWakeLockTimer.bind(this),
CALL_WAKELOCK_TIMEOUT, Ci.nsITimer.TYPE_ONE_SHOT);
gSystemMessenger.broadcastMessage("telephony-new-call", {});
},
/**
* Handle call state changes by updating our current state and the audio
* system.
*/
notifyCallStateChanged: function notifyCallStateChanged(aCall) {
if (DEBUG) debug("handleCallStateChange: " + JSON.stringify(aCall));
aCall.state = this._convertRILCallState(aCall.state);
if (aCall.state == nsITelephonyProvider.CALL_STATE_DIALING) {
gSystemMessenger.broadcastMessage("telephony-new-call", {});
}
this._updateCallAudioState(aCall, null);
this._notifyAllListeners("callStateChanged", [aCall.callIndex,
aCall.state,
aCall.number,
aCall.isActive,
aCall.isOutgoing,
aCall.isEmergency,
aCall.isConference]);
},
notifyCdmaCallWaiting: function notifyCdmaCallWaiting(aNumber) {
this._notifyAllListeners("notifyCdmaCallWaiting", [aNumber]);
},
notifySupplementaryService: function notifySupplementaryService(aCallIndex,
aNotification) {
let notification = this._convertRILSuppSvcNotification(aNotification);
this._notifyAllListeners("supplementaryServiceNotification",
[aCallIndex, notification]);
},
notifyConferenceCallStateChanged: function notifyConferenceCallStateChanged(aState) {
if (DEBUG) debug("handleConferenceCallStateChanged: " + aState);
aState = aState != null ? convertRILCallState(aState) :
nsITelephonyProvider.CALL_STATE_UNKNOWN;
this._updateCallAudioState(null, aState);
this._notifyAllListeners("conferenceCallStateChanged", [aState]);
},
/**
* nsIObserver interface.
*/
observe: function observe(aSubject, aTopic, aData) {
switch (aTopic) {
case kPrefenceChangedObserverTopic:
if (aData === "ril.debugging.enabled") {
this._updateDebugFlag();
}
break;
case kXpcomShutdownObserverTopic:
// Cancel the timer for the call-ring wake lock.
this._cancelCallRingWakeLockTimer();
Services.obs.removeObserver(this, kPrefenceChangedObserverTopic);
Services.obs.removeObserver(this, kXpcomShutdownObserverTopic);
break;
}
}
};
this.NSGetFactory = XPCOMUtils.generateNSGetFactory([TelephonyProvider]);

View File

@ -0,0 +1,2 @@
component {67d26434-d063-4d28-9f48-5b3189788155} TelephonyProvider.js
contract @mozilla.org/telephony/gonktelephonyprovider;1 {67d26434-d063-4d28-9f48-5b3189788155}

View File

@ -42,6 +42,15 @@ IPDL_SOURCES += [
'ipc/TelephonyTypes.ipdlh'
]
if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'gonk':
XPIDL_SOURCES += [
'nsIGonkTelephonyProvider.idl',
]
EXTRA_COMPONENTS += [
'gonk/TelephonyProvider.js',
'gonk/TelephonyProvider.manifest',
]
FAIL_ON_WARNINGS = True
LIBXUL_LIBRARY = True

View File

@ -0,0 +1,31 @@
/* -*- Mode: idl; 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/. */
#include "nsITelephonyProvider.idl"
%{C++
#define GONK_TELEPHONY_PROVIDER_CONTRACTID \
"@mozilla.org/telephony/gonktelephonyprovider;1"
%}
[scriptable, uuid(0d106c7e-ba47-48ee-ba48-c92002d401b6)]
interface nsIGonkTelephonyProvider : nsITelephonyProvider
{
void notifyCallDisconnected(in jsval call);
void notifyCallError(in long callIndex,
in AString error);
void notifyCallRing();
void notifyCallStateChanged(in jsval call);
void notifyCdmaCallWaiting(in AString number);
void notifySupplementaryService(in long callIndex,
in AString notification);
void notifyConferenceCallStateChanged(in unsigned short state);
};