Backed out changeset f6b637a621ac (bug 864485)
authorEd Morley <emorley@mozilla.com>
Thu, 05 Sep 2013 11:52:32 +0100
changeset 158573 c1ea56013ce9fc179cc53a0fc09be591ade1b4e7
parent 158572 2c9350e98076a7a132968ee182015b3af636e2f6
child 158574 e273e39089cb81480e6a28c959151c645131012b
push id2961
push userlsblakk@mozilla.com
push dateMon, 28 Oct 2013 21:59:28 +0000
treeherdermozilla-beta@73ef4f13486f [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
bugs864485
milestone26.0a1
backs outf6b637a621acdd6d9be188a0d5834f828a0f007c
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
Backed out changeset f6b637a621ac (bug 864485)
b2g/installer/package-manifest.in
dom/system/gonk/RILContentHelper.js
dom/system/gonk/RadioInterfaceLayer.js
dom/system/gonk/nsIRadioInterfaceLayer.idl
dom/telephony/TelephonyFactory.cpp
dom/telephony/gonk/TelephonyProvider.js
dom/telephony/gonk/TelephonyProvider.manifest
dom/telephony/moz.build
dom/telephony/nsIGonkTelephonyProvider.idl
--- a/b2g/installer/package-manifest.in
+++ b/b2g/installer/package-manifest.in
@@ -466,18 +466,16 @@
 @BINPATH@/components/WifiWorker.js
 @BINPATH@/components/WifiWorker.manifest
 @BINPATH@/components/DOMWifiManager.js
 @BINPATH@/components/DOMWifiManager.manifest
 @BINPATH@/components/NetworkStatsManager.js
 @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@
 #endif
 @BINPATH@/components/nsINIProcessor.manifest
 @BINPATH@/components/nsINIProcessor.js
 @BINPATH@/components/nsPrompter.manifest
 @BINPATH@/components/nsPrompter.js
--- a/dom/system/gonk/RILContentHelper.js
+++ b/dom/system/gonk/RILContentHelper.js
@@ -66,23 +66,27 @@ const CELLBROADCASTETWSINFO_CID =
 const DOMMMIERROR_CID =
   Components.ID("{6b204c42-7928-4e71-89ad-f90cd82aff96}");
 
 const RIL_IPC_MSG_NAMES = [
   "RIL:CardStateChanged",
   "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",
   "RIL:SendMMI",
   "RIL:CancelMMI",
   "RIL:StkCommand",
   "RIL:StkSessionEnd",
   "RIL:DataError",
@@ -99,26 +103,32 @@ const RIL_IPC_MSG_NAMES = [
   "RIL:CfStateChanged",
   "RIL:IccOpenChannel",
   "RIL:IccCloseChannel",
   "RIL:IccExchangeAPDU",
   "RIL:ReadIccContacts",
   "RIL:UpdateIccContact",
   "RIL:SetRoamingPreference",
   "RIL:GetRoamingPreference",
+  "RIL:CdmaCallWaiting",
   "RIL:ExitEmergencyCbMode",
   "RIL:SetVoicePrivacyMode",
   "RIL:GetVoicePrivacyMode",
+  "RIL:ConferenceCallStateChanged",
   "RIL:OtaStatusChanged"
 ];
 
 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;
   this.retryCount = options.retryCount;
   this.success = options.success;
 }
 MobileIccCardLockResult.prototype = {
   __exposedProps__ : {lockType: 'r',
@@ -434,25 +444,27 @@ function RILContentHelper() {
 }
 
 RILContentHelper.prototype = {
   __proto__: DOMRequestIpcHelper.prototype,
 
   QueryInterface: XPCOMUtils.generateQI([Ci.nsIMobileConnectionProvider,
                                          Ci.nsICellBroadcastProvider,
                                          Ci.nsIVoicemailProvider,
+                                         Ci.nsITelephonyProvider,
                                          Ci.nsIIccProvider,
                                          Ci.nsIObserver,
                                          Ci.nsISupportsWeakReference]),
   classID:   RILCONTENTHELPER_CID,
   classInfo: XPCOMUtils.generateCI({classID: RILCONTENTHELPER_CID,
                                     classDescription: "RILContentHelper",
                                     interfaces: [Ci.nsIMobileConnectionProvider,
                                                  Ci.nsICellBroadcastProvider,
                                                  Ci.nsIVoicemailProvider,
+                                                 Ci.nsITelephonyProvider,
                                                  Ci.nsIIccProvider]}),
 
   // An utility function to copy objects.
   updateInfo: function updateInfo(srcInfo, destInfo) {
     for (let key in srcInfo) {
       destInfo[key] = srcInfo[key];
     }
   },
@@ -1264,19 +1276,21 @@ RILContentHelper.prototype = {
         requestId: requestId,
       }
     });
 
     return request;
   },
 
   _mobileConnectionListeners: null,
+  _telephonyListeners: null,
   _cellBroadcastListeners: null,
   _voicemailListeners: null,
   _iccListeners: null,
+  _enumerateTelephonyCallbacks: null,
 
   voicemailStatus: null,
 
   getVoicemailInfo: function getVoicemailInfo() {
     // Get voicemail infomation by IPC only on first time.
     this.getVoicemailInfo = function getVoicemailInfo() {
       return this.voicemailInfo;
     };
@@ -1328,16 +1342,34 @@ RILContentHelper.prototype = {
     this.registerListener("_mobileConnectionListeners", listener);
     cpmm.sendAsyncMessage("RIL:RegisterMobileConnectionMsg");
   },
 
   unregisterMobileConnectionMsg: function unregisteMobileConnectionMsg(listener) {
     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);
     cpmm.sendAsyncMessage("RIL:RegisterVoicemailMsg");
   },
 
   unregisterVoicemailMsg: function unregisteVoicemailMsg(listener) {
     this.unregisterListener("_voicemailListeners", listener);
@@ -1358,16 +1390,145 @@ RILContentHelper.prototype = {
     this.registerListener("_iccListeners", listener);
     cpmm.sendAsyncMessage("RIL:RegisterIccMsg");
   },
 
   unregisterIccMsg: function unregisterIccMsg(listener) {
     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) {
     if (topic == "xpcom-shutdown") {
       this.destroyDOMRequestHelper();
       Services.obs.removeObserver(this, "xpcom-shutdown");
     }
   },
@@ -1454,30 +1615,62 @@ RILContentHelper.prototype = {
                            "notifyDataChanged",
                            null);
         break;
       case "RIL:OtaStatusChanged":
         this._deliverEvent("_mobileConnectionListeners",
                            "notifyOtaStatusChanged",
                            [msg.json.data]);
         break;
+      case "RIL:EnumerateCalls":
+        this.handleEnumerateCalls(msg.json.calls);
+        break;
       case "RIL:GetAvailableNetworks":
         this.handleGetAvailableNetworks(msg.json);
         break;
       case "RIL:NetworkSelectionModeChanged":
         this.rilContext.networkSelectionMode = msg.json.data.mode;
         break;
       case "RIL:SelectNetwork":
         this.handleSelectNetwork(msg.json,
                                  RIL.GECKO_NETWORK_SELECTION_MANUAL);
         break;
       case "RIL:SelectNetworkAuto":
         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;
       case "RIL:VoicemailInfoChanged":
         this.updateInfo(msg.json.data, this.voicemailInfo);
         break;
       case "RIL:CardLockResult":
         if (msg.json.success) {
@@ -1588,16 +1781,21 @@ RILContentHelper.prototype = {
       }
       case "RIL:SetRoamingPreference":
         this.handleSimpleRequest(msg.json.requestId, msg.json.errorMsg, null);
         break;
       case "RIL:GetRoamingPreference":
         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;
       case "RIL:EmergencyCbModeChanged":
         let data = msg.json.data;
         this._deliverEvent("_mobileConnectionListeners",
                            "notifyEmergencyCbModeChanged",
                            [data.active, data.timeoutMs]);
@@ -1607,16 +1805,45 @@ RILContentHelper.prototype = {
         break;
       case "RIL:GetVoicePrivacyMode":
         this.handleSimpleRequest(msg.json.requestId, msg.json.errorMsg,
                                  msg.json.enabled);
         break;
     }
   },
 
+  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);
     } else {
       this.fireRequestSuccess(requestId, result);
     }
   },
 
@@ -1819,16 +2046,20 @@ RILContentHelper.prototype = {
       let mmiError = new this._window.DOMMMIError(result.serviceCode,
                                                   message.errorMsg,
                                                   null,
                                                   result.additionalInformation);
       Services.DOMRequest.fireDetailedError(request, mmiError);
     }
   },
 
+  _getRandomId: function _getRandomId() {
+    return gUUIDGenerator.generateUUID().toString();
+  },
+
   _deliverEvent: function _deliverEvent(listenerType, name, args) {
     let thisListeners = this[listenerType];
     if (!thisListeners) {
       return;
     }
 
     let listeners = thisListeners.slice();
     for (let listener of listeners) {
--- a/dom/system/gonk/RadioInterfaceLayer.js
+++ b/dom/system/gonk/RadioInterfaceLayer.js
@@ -41,16 +41,19 @@ function debug(s) {
 
 const RADIOINTERFACELAYER_CID =
   Components.ID("{2d831c8d-6017-435b-a80c-e5d422810cea}");
 const RADIOINTERFACE_CID =
   Components.ID("{6a7c91f0-a2b3-4193-8562-8969296c0b54}");
 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";
 const kSmsSendingObserverTopic           = "sms-sending";
 const kSmsSentObserverTopic              = "sms-sent";
 const kSmsFailedObserverTopic            = "sms-failed";
 const kSmsDeliverySuccessObserverTopic   = "sms-delivery-success";
 const kSmsDeliveryErrorObserverTopic     = "sms-delivery-error";
@@ -65,17 +68,40 @@ const kCellBroadcastDisabled            
 const kPrefenceChangedObserverTopic      = "nsPref:changed";
 const kClirModePreference                = "ril.clirMode";
 
 const DOM_MOBILE_MESSAGE_DELIVERY_RECEIVED = "received";
 const DOM_MOBILE_MESSAGE_DELIVERY_SENDING  = "sending";
 const DOM_MOBILE_MESSAGE_DELIVERY_SENT     = "sent";
 const DOM_MOBILE_MESSAGE_DELIVERY_ERROR    = "error";
 
-const RADIO_POWER_OFF_TIMEOUT = 30000;
+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 RIL_IPC_MOBILECONNECTION_MSG_NAMES = [
   "RIL:GetRilContext",
   "RIL:GetAvailableNetworks",
   "RIL:SelectNetwork",
   "RIL:SelectNetworkAuto",
   "RIL:SendMMI",
   "RIL:CancelMMI",
@@ -157,32 +183,86 @@ XPCOMUtils.defineLazyServiceGetter(this,
 XPCOMUtils.defineLazyServiceGetter(this, "gTimeService",
                                    "@mozilla.org/time/timeservice;1",
                                    "nsITimeService");
 
 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);
   return wap;
 });
 
 XPCOMUtils.defineLazyGetter(this, "PhoneNumberUtils", function () {
   let ns = {};
   Cu.import("resource://gre/modules/PhoneNumberUtils.jsm", ns);
   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,
                                            Ci.nsIObserver]),
 
     ril: null,
 
     // Manage message targets in terms of topic. Only the authorized and
@@ -205,32 +285,38 @@ XPCOMUtils.defineLazyGetter(this, "gMess
       this.ril = null;
 
       Services.obs.removeObserver(this, "xpcom-shutdown");
       this._unregisterMessageListeners();
     },
 
     _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);
       }
       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);
       }
     },
 
     _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);
       }
       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);
@@ -339,17 +425,25 @@ XPCOMUtils.defineLazyGetter(this, "gMess
       if (msg.name == "child-process-shutdown") {
         // By the time we receive child-process-shutdown, the child process has
         // already forgotten its permissions so we need to unregister the target
         // for every permission.
         this._unregisterMessageTarget(null, msg.target);
         return;
       }
 
-      if (RIL_IPC_MOBILECONNECTION_MSG_NAMES.indexOf(msg.name) != -1) {
+      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 (!msg.target.assertPermission("mobileconnection")) {
           if (DEBUG) {
             debug("MobileConnection message " + msg.name +
                   " from a content process with no 'mobileconnection' privileges.");
           }
           return null;
         }
       } else if (RIL_IPC_ICCMANAGER_MSG_NAMES.indexOf(msg.name) != -1) {
@@ -377,16 +471,19 @@ XPCOMUtils.defineLazyGetter(this, "gMess
           return null;
         }
       } else {
         if (DEBUG) debug("Ignoring unknown message type: " + msg.name);
         return null;
       }
 
       switch (msg.name) {
+        case "RIL:RegisterTelephonyMsg":
+          this._registerMessageTarget("telephony", msg.target);
+          return;
         case "RIL:RegisterMobileConnectionMsg":
           this._registerMessageTarget("mobileconnection", msg.target);
           return;
         case "RIL:RegisterIccMsg":
           this._registerMessageTarget("icc", msg.target);
           return;
         case "RIL:RegisterVoicemailMsg":
           this._registerMessageTarget("voicemail", msg.target);
@@ -417,16 +514,23 @@ XPCOMUtils.defineLazyGetter(this, "gMess
           this._resendQueuedTargetMessage();
           break;
         case "xpcom-shutdown":
           this._shutdown();
           break;
       }
     },
 
+    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,
         data: data
       });
     },
 
     sendVoicemailMessage: function sendVoicemailMessage(message, clientId, data) {
@@ -785,16 +889,71 @@ RadioInterface.prototype = {
   /**
    * Process a message from the content process.
    */
   receiveMessage: function receiveMessage(msg) {
     switch (msg.name) {
       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;
       case "RIL:SelectNetwork":
         this.workerMessenger.sendWithIPCMessage(msg, "selectNetwork");
         break;
       case "RIL:SelectNetworkAuto":
         this.workerMessenger.sendWithIPCMessage(msg, "selectNetworkAuto");
@@ -894,36 +1053,38 @@ RadioInterface.prototype = {
         this.workerMessenger.sendWithIPCMessage(msg, "queryVoicePrivacyMode");
         break;
     }
   },
 
   handleUnsolicitedWorkerMessage: function handleUnsolicitedWorkerMessage(message) {
     switch (message.rilMessageType) {
       case "callRing":
-        gTelephonyProvider.notifyCallRing();
+        this.handleCallRing();
         break;
       case "callStateChange":
-        gTelephonyProvider.notifyCallStateChanged(message.call);
+        // This one will handle its own notifications.
+        this.handleCallStateChange(message.call);
         break;
       case "callDisconnected":
-        gTelephonyProvider.notifyCallDisconnected(message.call);
+        // This one will handle its own notifications.
+        this.handleCallDisconnected(message.call);
         break;
       case "conferenceCallStateChanged":
-        gTelephonyProvider.notifyConferenceCallStateChanged(message.state);
+        this.handleConferenceCallStateChanged(message.state);
         break;
       case "cdmaCallWaiting":
-        gTelephonyProvider.notifyCdmaCallWaiting(message.number);
+        gMessageManager.sendTelephonyMessage("RIL:CdmaCallWaiting",
+                                             this.clientId, message.number);
         break;
       case "callError":
-        gTelephonyProvider.notifyCallError(message.callIndex, message.errorMsg);
+        this.handleCallError(message);
         break;
       case "suppSvcNotification":
-        gTelephonyProvider.notifySupplementaryService(message.callIndex,
-                                                      message.notification);
+        this.handleSuppSvcNotification(message);
         break;
       case "emergencyCbModeChange":
         this.handleEmergencyCbModeChange(message);
         break;
       case "networkinfochanged":
         this.updateNetworkInfo(message);
         break;
       case "networkselectionmodechange":
@@ -1562,16 +1723,175 @@ RadioInterface.prototype = {
       return;
     }
 
     if (DEBUG) this.debug("Data call settings: connect data call.");
     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
    */
   updateNetworkSelectionMode: function updateNetworkSelectionMode(message) {
     if (DEBUG) this.debug("updateNetworkSelectionMode: " + JSON.stringify(message));
     this.rilContext.networkSelectionMode = message.mode;
     gMessageManager.sendMobileConnectionMessage("RIL:NetworkSelectionModeChanged",
                                                 this.clientId, message);
   },
@@ -1581,16 +1901,33 @@ RadioInterface.prototype = {
    */
   handleEmergencyCbModeChange: function handleEmergencyCbModeChange(message) {
     if (DEBUG) this.debug("handleEmergencyCbModeChange: " + JSON.stringify(message));
     gMessageManager.sendMobileConnectionMessage("RIL:EmergencyCbModeChanged",
                                                 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.
    *
    * @param message
    *        A SMS message.
    */
   handleSmsWdpPortPush: function handleSmsWdpPortPush(message) {
     if (message.encoding != RIL.PDU_DCS_MSG_CODING_8BITS_ALPHABET) {
@@ -1967,16 +2304,18 @@ RadioInterface.prototype = {
           try {
             value = Services.prefs.getBoolPref(kCellBroadcastDisabled);
           } catch(e) {}
           this.workerMessenger.send("setCellBroadcastDisabled",
                                     { disabled: value });
         }
         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) {
             apnSetting.iface.shutdown();
           }
         }
         Services.obs.removeObserver(this, "xpcom-shutdown");
         Services.obs.removeObserver(this, kMozSettingsChangedObserverTopic);
@@ -2116,16 +2455,66 @@ RadioInterface.prototype = {
     if (DEBUG) this.debug("Setting radio power to " + value);
     this.workerMessenger.send("setRadioPower", { on: value });
   },
 
   rilContext: null,
 
   // 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);
   },
 
   _updateCallingLineIdRestrictionPref:
     function _updateCallingLineIdRestrictionPref(mode) {
     try {
@@ -2170,16 +2559,47 @@ RadioInterface.prototype = {
       if (response.success) {
         this._updateCallingLineIdRestrictionPref(response.clirMode);
       }
       target.sendAsyncMessage("RIL:SetCallingLineIdRestriction", response);
       return false;
     }).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.
    *
    * TODO: Support static/runtime settings, see bug 733331.
    */
   enabledGsmTableTuples: [
     [RIL.PDU_NL_IDENTIFIER_DEFAULT, RIL.PDU_NL_IDENTIFIER_DEFAULT],
   ],
@@ -2937,23 +3357,16 @@ RadioInterface.prototype = {
                                                  chappap: chappap,
                                                  pdptype: pdptype });
   },
 
   deactivateDataCall: function deactivateDataCall(cid, reason) {
     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) {
   this.radioInterface = radioInterface;
   this.apnSetting = apnSetting;
 
   this.connectedTypes = [];
 }
--- a/dom/system/gonk/nsIRadioInterfaceLayer.idl
+++ b/dom/system/gonk/nsIRadioInterfaceLayer.idl
@@ -73,23 +73,17 @@ interface nsIRilContext : nsISupports
 
   readonly attribute nsIDOMMozIccInfo iccInfo;
 
   readonly attribute nsIDOMMozMobileConnectionInfo voice;
 
   readonly attribute nsIDOMMozMobileConnectionInfo data;
 };
 
-[scriptable, function, uuid(3bc96351-53b0-47a1-a888-c74c64b60f25)]
-interface nsIRilSendWorkerMessageCallback : nsISupports
-{
-  boolean handleResponse(in jsval response);
-};
-
-[scriptable, uuid(61a8ca67-6113-4cd0-b443-e045f09863ed)]
+[scriptable, uuid(a50d65aa-00da-11e3-b954-7bfb233d98fc)]
 interface nsIRadioInterface : nsISupports
 {
   readonly attribute nsIRilContext rilContext;
 
   /**
    * PDP APIs
    */
   void setupDataCallByType(in DOMString apntype);
@@ -106,20 +100,16 @@ interface nsIRadioInterface : nsISupport
    */
   void getSegmentInfoForText(in DOMString text,
                              in nsIMobileMessageCallback request);
 
   void sendSMS(in DOMString number,
                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)]
 interface nsIRadioInterfaceLayer : nsISupports
 {
   readonly attribute unsigned long numRadioInterfaces;
 
   nsIRadioInterface getRadioInterface(in long clientId);
--- a/dom/telephony/TelephonyFactory.cpp
+++ b/dom/telephony/TelephonyFactory.cpp
@@ -1,30 +1,23 @@
 /* -*- Mode: C++; 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 "mozilla/dom/telephony/TelephonyFactory.h"
-#ifdef MOZ_WIDGET_GONK
-#include "nsIGonkTelephonyProvider.h"
-#endif
 #include "nsServiceManagerUtils.h"
 #include "nsXULAppAPI.h"
 #include "TelephonyIPCProvider.h"
 
 USING_TELEPHONY_NAMESPACE
 
 /* static */ already_AddRefed<nsITelephonyProvider>
 TelephonyFactory::CreateTelephonyProvider()
 {
   nsCOMPtr<nsITelephonyProvider> provider;
 
   if (XRE_GetProcessType() == GeckoProcessType_Content) {
     provider = new TelephonyIPCProvider();
-#ifdef MOZ_WIDGET_GONK
-  } else {
-    provider = do_CreateInstance(GONK_TELEPHONY_PROVIDER_CONTRACTID);
-#endif
   }
 
   return provider.forget();
 }
deleted file mode 100644
--- a/dom/telephony/gonk/TelephonyProvider.js
+++ /dev/null
@@ -1,525 +0,0 @@
-/* -*- 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]);
deleted file mode 100644
--- a/dom/telephony/gonk/TelephonyProvider.manifest
+++ /dev/null
@@ -1,2 +0,0 @@
-component {67d26434-d063-4d28-9f48-5b3189788155} TelephonyProvider.js
-contract @mozilla.org/telephony/gonktelephonyprovider;1 {67d26434-d063-4d28-9f48-5b3189788155}
--- a/dom/telephony/moz.build
+++ b/dom/telephony/moz.build
@@ -37,22 +37,13 @@ CPP_SOURCES += [
 ]
 
 IPDL_SOURCES += [
     'ipc/PTelephony.ipdl',
     'ipc/PTelephonyRequest.ipdl',
     '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
 
 LIBRARY_NAME = 'domtelephony_s'
deleted file mode 100644
--- a/dom/telephony/nsIGonkTelephonyProvider.idl
+++ /dev/null
@@ -1,31 +0,0 @@
-/* -*- 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);
-};