author | Ryan VanderMeulen <ryanvm@gmail.com> |
Tue, 30 Jul 2013 09:01:43 -0400 | |
changeset 152685 | dbd7d55d64ffb24fef1b83ac44477cb91957398c |
parent 152666 | 8911e64ad234b3519e2aa52b4144db67631b0ea9 (current diff) |
parent 152684 | 7476377d143fb6508fd8d3108f0a35c4d9da4e00 (diff) |
child 152786 | 129ce98f4cb24f84d8d18d2563aaade4facb2a76 |
push id | 2859 |
push user | akeybl@mozilla.com |
push date | Mon, 16 Sep 2013 19:14:59 +0000 |
treeherder | mozilla-beta@87d3c51cd2bf [default view] [failures only] |
perfherder | [talos] [build metrics] [platform microbench] (compared to previous push) |
milestone | 25.0a1 |
first release with | nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
|
last release without | nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
|
--- a/b2g/chrome/content/payment.js +++ b/b2g/chrome/content/payment.js @@ -4,64 +4,125 @@ * 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/. */ // This JS shim contains the callbacks to fire DOMRequest events for // navigator.pay API within the payment processor's scope. "use strict"; -dump("======================= payment.js ======================= \n"); +let _DEBUG = false; +function _debug(s) { dump("== Payment flow == " + s + "\n"); } +_debug("Frame script injected"); let { classes: Cc, interfaces: Ci, utils: Cu } = Components; Cu.import("resource://gre/modules/XPCOMUtils.jsm"); +Cu.import("resource://gre/modules/Services.jsm"); XPCOMUtils.defineLazyServiceGetter(this, "cpmm", "@mozilla.org/childprocessmessagemanager;1", "nsIMessageSender"); XPCOMUtils.defineLazyServiceGetter(this, "uuidgen", "@mozilla.org/uuid-generator;1", "nsIUUIDGenerator"); #ifdef MOZ_B2G_RIL -XPCOMUtils.defineLazyServiceGetter(this, "mobileConnection", +XPCOMUtils.defineLazyServiceGetter(this, "iccProvider", "@mozilla.org/ril/content-helper;1", - "nsIMobileConnectionProvider"); + "nsIIccProvider"); + +XPCOMUtils.defineLazyServiceGetter(this, "smsService", + "@mozilla.org/sms/smsservice;1", + "nsISmsService"); + +const kSilentSmsReceivedTopic = "silent-sms-received"; + +const MOBILEMESSAGECALLBACK_CID = + Components.ID("{b484d8c9-6be4-4f94-ab60-c9c7ebcc853d}"); + +// In order to send messages through nsISmsService, we need to implement +// nsIMobileMessageCallback, as the WebSMS API implementation is not usable +// from JS. +function SilentSmsRequest() { +} +SilentSmsRequest.prototype = { + __exposedProps__: { + onsuccess: 'rw', + onerror: 'rw' + }, + + QueryInterface: XPCOMUtils.generateQI([Ci.nsIMobileMessageCallback]), + + classID: MOBILEMESSAGECALLBACK_CID, + + set onsuccess(aSuccessCallback) { + this._onsuccess = aSuccessCallback; + }, + + set onerror(aErrorCallback) { + this._onerror = aErrorCallback; + }, + + notifyMessageSent: function notifyMessageSent(aMessage) { + if (_DEBUG) { + _debug("Silent message successfully sent"); + } + this._onsuccess(aMessage); + }, + + notifySendMessageFailed: function notifySendMessageFailed(aError) { + if (_DEBUG) { + _debug("Error sending silent message " + aError); + } + this._onerror(aError); + } +}; #endif - const kClosePaymentFlowEvent = "close-payment-flow-dialog"; -let _requestId; +let gRequestId; + +let gBrowser = Services.wm.getMostRecentWindow("navigator:browser"); let PaymentProvider = { - +#ifdef MOZ_B2G_RIL __exposedProps__: { paymentSuccess: 'r', paymentFailed: 'r', - iccIds: 'r' + iccIds: 'r', + mcc: 'r', + mnc: 'r', + sendSilentSms: 'r', + observeSilentSms: 'r', + removeSilentSmsObserver: 'r' }, +#else + __exposedProps__: { + paymentSuccess: 'r', + paymentFailed: 'r' + }, +#endif _closePaymentFlowDialog: function _closePaymentFlowDialog(aCallback) { // After receiving the payment provider confirmation about the // successful or failed payment flow, we notify the UI to close the // payment flow dialog and return to the caller application. let id = kClosePaymentFlowEvent + "-" + uuidgen.generateUUID().toString(); - let browser = Services.wm.getMostRecentWindow("navigator:browser"); - let content = browser.getContentWindow(); + let content = gBrowser.getContentWindow(); if (!content) { return; } let detail = { type: kClosePaymentFlowEvent, id: id, - requestId: _requestId + requestId: gRequestId }; // In order to avoid race conditions, we wait for the UI to notify that // it has successfully closed the payment flow and has recovered the // caller app, before notifying the parent process to fire the success // or error event over the DOMRequest. content.addEventListener("mozContentEvent", function closePaymentFlowReturn(evt) { @@ -72,54 +133,181 @@ let PaymentProvider = { content.removeEventListener("mozContentEvent", closePaymentFlowReturn); let glue = Cc["@mozilla.org/payment/ui-glue;1"] .createInstance(Ci.nsIPaymentUIGlue); glue.cleanup(); }); - browser.shell.sendChromeEvent(detail); + gBrowser.shell.sendChromeEvent(detail); + +#ifdef MOZ_B2G_RIL + this._cleanUp(); +#endif }, paymentSuccess: function paymentSuccess(aResult) { + if (_DEBUG) { + _debug("paymentSuccess " + aResult); + } + PaymentProvider._closePaymentFlowDialog(function notifySuccess() { - if (!_requestId) { + if (!gRequestId) { return; } cpmm.sendAsyncMessage("Payment:Success", { result: aResult, - requestId: _requestId }); + requestId: gRequestId }); }); }, paymentFailed: function paymentFailed(aErrorMsg) { + if (_DEBUG) { + _debug("paymentFailed " + aErrorMsg); + } + PaymentProvider._closePaymentFlowDialog(function notifyError() { - if (!_requestId) { + if (!gRequestId) { return; } cpmm.sendAsyncMessage("Payment:Failed", { errorMsg: aErrorMsg, - requestId: _requestId }); + requestId: gRequestId }); }); }, +#ifdef MOZ_B2G_RIL + // Until bug 814629 is done, we only have support for a single SIM, so we + // can only provide information for a single ICC. However, we return an array + // so the payment provider facing API won't need to change once we support + // multiple SIMs. + get iccIds() { -#ifdef MOZ_B2G_RIL - // Until bug 814629 is done, we only have support for a single SIM, so we - // can only provide a single ICC ID. However, we return an array so the - // payment provider facing API won't need to change once we support - // multiple SIMs. - return [mobileConnection.iccInfo.iccid]; -#else - return null; -#endif + return [iccProvider.iccInfo.iccid]; + }, + + get mcc() { + return [iccProvider.iccInfo.mcc]; + }, + + get mnc() { + return [iccProvider.iccInfo.mnc]; + }, + + _silentNumbers: null, + _silentSmsObservers: null, + + sendSilentSms: function sendSilentSms(aNumber, aMessage) { + if (_DEBUG) { + _debug("Sending silent message " + aNumber + " - " + aMessage); + } + + let request = new SilentSmsRequest(); + smsService.send(aNumber, aMessage, true, request); + return request; + }, + + observeSilentSms: function observeSilentSms(aNumber, aCallback) { + if (_DEBUG) { + _debug("observeSilentSms " + aNumber); + } + + if (!this._silentSmsObservers) { + this._silentSmsObservers = {}; + this._silentNumbers = []; + Services.obs.addObserver(this._onSilentSms.bind(this), + kSilentSmsReceivedTopic, + false); + } + + if (!this._silentSmsObservers[aNumber]) { + this._silentSmsObservers[aNumber] = []; + this._silentNumbers.push(aNumber); + smsService.addSilentNumber(aNumber); + } + + if (this._silentSmsObservers[aNumber].indexOf(aCallback) == -1) { + this._silentSmsObservers[aNumber].push(aCallback); + } }, + removeSilentSmsObserver: function removeSilentSmsObserver(aNumber, aCallback) { + if (_DEBUG) { + _debug("removeSilentSmsObserver " + aNumber); + } + + if (!this._silentSmsObservers || !this._silentSmsObservers[aNumber]) { + if (_DEBUG) { + _debug("No observers for " + aNumber); + } + return; + } + + let index = this._silentSmsObservers[aNumber].indexOf(aCallback); + if (index != -1) { + this._silentSmsObservers[aNumber].splice(index, 1); + if (this._silentSmsObservers[aNumber].length == 0) { + this._silentSmsObservers[aNumber] = null; + this._silentNumbers.splice(this._silentNumbers.indexOf(aNumber), 1); + smsService.removeSilentNumber(aNumber); + } + } else if (_DEBUG) { + _debug("No callback found for " + aNumber); + } + }, + + _onSilentSms: function _onSilentSms(aSubject, aTopic, aData) { + if (_DEBUG) { + _debug("Got silent message! " + aSubject.sender + " - " + aSubject.body); + } + + let number = aSubject.sender; + if (!number || this._silentNumbers.indexOf(number) == -1) { + if (_DEBUG) { + _debug("No observers for " + number); + } + return; + } + + this._silentSmsObservers[number].forEach(function(callback) { + callback(aSubject); + }); + }, + + _cleanUp: function _cleanUp() { + if (_DEBUG) { + _debug("Cleaning up!"); + } + + if (!this._silentNumbers) { + return; + } + + while (this._silentNumbers.length) { + let number = this._silentNumbers.pop(); + smsService.removeSilentNumber(number); + } + this._silentNumbers = null; + this._silentSmsObservers = null; + Services.obs.removeObserver(this._onSilentSms, kSilentSmsReceivedTopic); + } +#endif }; // We save the identifier of the DOM request, so we can dispatch the results // of the payment flow to the appropriate content process. addMessageListener("Payment:LoadShim", function receiveMessage(aMessage) { - _requestId = aMessage.json.requestId; + gRequestId = aMessage.json.requestId; }); addEventListener("DOMWindowCreated", function(e) { content.wrappedJSObject.mozPaymentProvider = PaymentProvider; }); + +#ifdef MOZ_B2G_RIL +// If the trusted dialog is not closed via paymentSuccess or paymentFailed +// a mozContentEvent with type 'cancel' is sent from the UI. We need to listen +// for this event to clean up the silent sms observers if any exists. +gBrowser.getContentWindow().addEventListener("mozContentEvent", function(e) { + if (e.detail.type === "cancel") { + PaymentProvider._cleanUp(); + } +}); +#endif
--- a/b2g/config/gaia.json +++ b/b2g/config/gaia.json @@ -1,4 +1,4 @@ { - "revision": "74877b52dcb397d6de83b682ac5d374cc6d508be", + "revision": "10f16f6a15f8a1c4b910548b4d0968baaac21c91", "repo_path": "/integration/gaia-central" }
--- a/dom/bluetooth/BluetoothA2dpManager.cpp +++ b/dom/bluetooth/BluetoothA2dpManager.cpp @@ -200,17 +200,16 @@ BluetoothA2dpManager::HandleSinkProperty const nsString& name = arr[0].name(); const BluetoothValue& value = arr[0].value(); if (name.EqualsLiteral("Connected")) { // Indicates if a stream is setup to a A2DP sink on the remote device. MOZ_ASSERT(value.type() == BluetoothValue::Tbool); mA2dpConnected = value.get_bool(); NotifyStatusChanged(); - NotifyAudioManager(); } else if (name.EqualsLiteral("Playing")) { // Indicates if a stream is active to a A2DP sink on the remote device. MOZ_ASSERT(value.type() == BluetoothValue::Tbool); mPlaying = value.get_bool(); } else if (name.EqualsLiteral("State")) { MOZ_ASSERT(value.type() == BluetoothValue::TnsString); HandleSinkStateChanged(StatusStringToSinkState(value.get_nsString())); } else { @@ -254,48 +253,40 @@ BluetoothA2dpManager::HandleSinkStateCha mSinkState = aState; } void BluetoothA2dpManager::NotifyStatusChanged() { MOZ_ASSERT(NS_IsMainThread()); + // Broadcast system message to Gaia NS_NAMED_LITERAL_STRING(type, BLUETOOTH_A2DP_STATUS_CHANGED_ID); InfallibleTArray<BluetoothNamedValue> parameters; BluetoothValue v = mA2dpConnected; parameters.AppendElement( BluetoothNamedValue(NS_LITERAL_STRING("connected"), v)); v = mDeviceAddress; parameters.AppendElement( BluetoothNamedValue(NS_LITERAL_STRING("address"), v)); if (!BroadcastSystemMessage(type, parameters)) { NS_WARNING("Failed to broadcast system message to settings"); - return; } -} -void -BluetoothA2dpManager::NotifyAudioManager() -{ - MOZ_ASSERT(NS_IsMainThread()); - + // Notify Gecko observers nsCOMPtr<nsIObserverService> obs = do_GetService("@mozilla.org/observer-service;1"); NS_ENSURE_TRUE_VOID(obs); - nsAutoString data; - data.AppendInt(mA2dpConnected); - if (NS_FAILED(obs->NotifyObservers(this, BLUETOOTH_A2DP_STATUS_CHANGED_ID, - data.BeginReading()))) { + mDeviceAddress.get()))) { NS_WARNING("Failed to notify bluetooth-a2dp-status-changed observsers!"); } } void BluetoothA2dpManager::OnGetServiceChannel(const nsAString& aDeviceAddress, const nsAString& aServiceUuid, int aChannel)
--- a/dom/bluetooth/BluetoothA2dpManager.h +++ b/dom/bluetooth/BluetoothA2dpManager.h @@ -68,23 +68,21 @@ public: private: BluetoothA2dpManager(); bool Init(); void HandleSinkStateChanged(SinkState aState); void HandleShutdown(); void NotifyStatusChanged(); - void NotifyAudioManager(); - - nsString mDeviceAddress; // A2DP data member bool mA2dpConnected; bool mPlaying; + nsString mDeviceAddress; SinkState mSinkState; // AVRCP data member bool mAvrcpConnected; nsString mAlbum; nsString mArtist; nsString mTitle; uint32_t mDuration;
--- a/dom/bluetooth/BluetoothCommon.h +++ b/dom/bluetooth/BluetoothCommon.h @@ -50,16 +50,17 @@ extern bool gBluetoothDebugFlag; #define KEY_REMOTE_AGENT "/B2G/bluetooth/remote_device_agent" #define KEY_MANAGER "/B2G/bluetooth/manager" #define KEY_ADAPTER "/B2G/bluetooth/adapter" /** * When connection status of Bluetooth profiles change, we'll notify observers * of following topics. */ +#define BLUETOOTH_HFP_STATUS_CHANGED_ID "bluetooth-hfp-status-changed" #define BLUETOOTH_SCO_STATUS_CHANGED_ID "bluetooth-sco-status-changed" #define BLUETOOTH_A2DP_STATUS_CHANGED_ID "bluetooth-a2dp-status-changed" // Bluetooth address format: xx:xx:xx:xx:xx:xx (or xx_xx_xx_xx_xx_xx) #define BLUETOOTH_ADDRESS_LENGTH 17 #define BLUETOOTH_ADDRESS_NONE "00:00:00:00:00:00" BEGIN_BLUETOOTH_NAMESPACE
--- a/dom/bluetooth/BluetoothHfpManager.cpp +++ b/dom/bluetooth/BluetoothHfpManager.cpp @@ -449,41 +449,50 @@ BluetoothHfpManager::Get() BluetoothHfpManager* manager = new BluetoothHfpManager(); NS_ENSURE_TRUE(manager->Init(), nullptr); sBluetoothHfpManager = manager; return sBluetoothHfpManager; } void -BluetoothHfpManager::NotifyStatusChanged(const nsAString& aType) +BluetoothHfpManager::NotifyStatusChanged(const char* aType) { - nsString type, name; + // Broadcast system message to Gaia BluetoothValue v; InfallibleTArray<BluetoothNamedValue> parameters; - type = aType; - + nsAutoString type, name; + type = NS_ConvertUTF8toUTF16(aType); name.AssignLiteral("connected"); - if (type.EqualsLiteral("bluetooth-hfp-status-changed")) { + + if (type.EqualsLiteral(BLUETOOTH_HFP_STATUS_CHANGED_ID)) { v = IsConnected(); - } else if (type.EqualsLiteral("bluetooth-sco-status-changed")) { + } else if (type.EqualsLiteral(BLUETOOTH_SCO_STATUS_CHANGED_ID)) { v = IsScoConnected(); } else { NS_WARNING("Wrong type for NotifyStatusChanged"); return; } parameters.AppendElement(BluetoothNamedValue(name, v)); name.AssignLiteral("address"); v = mDeviceAddress; parameters.AppendElement(BluetoothNamedValue(name, v)); if (!BroadcastSystemMessage(type, parameters)) { NS_WARNING("Failed to broadcast system message to settings"); - return; + } + + // Notify Gecko observers + nsCOMPtr<nsIObserverService> obs = + do_GetService("@mozilla.org/observer-service;1"); + NS_ENSURE_TRUE_VOID(obs); + + if (NS_FAILED(obs->NotifyObservers(this, aType, mDeviceAddress.get()))) { + NS_WARNING("Failed to notify bluetooth-sco-status-changed observsers!"); } } void BluetoothHfpManager::NotifyDialer(const nsAString& aCommand) { nsString type, name; BluetoothValue v; @@ -491,36 +500,16 @@ BluetoothHfpManager::NotifyDialer(const type.AssignLiteral("bluetooth-dialer-command"); name.AssignLiteral("command"); v = nsString(aCommand); parameters.AppendElement(BluetoothNamedValue(name, v)); if (!BroadcastSystemMessage(type, parameters)) { NS_WARNING("Failed to broadcast system message to dialer"); - return; - } -} - -void -BluetoothHfpManager::NotifyAudioManager(bool aStatus) -{ - MOZ_ASSERT(NS_IsMainThread()); - - nsCOMPtr<nsIObserverService> obs = - do_GetService("@mozilla.org/observer-service;1"); - NS_ENSURE_TRUE_VOID(obs); - - nsAutoString data; - data.AppendInt(aStatus); - - if (NS_FAILED(obs->NotifyObservers(this, - BLUETOOTH_SCO_STATUS_CHANGED_ID, - data.BeginReading()))) { - NS_WARNING("Failed to notify bluetooth-sco-status-changed observsers!"); } } void BluetoothHfpManager::HandleVolumeChanged(const nsAString& aData) { MOZ_ASSERT(NS_IsMainThread()); @@ -1488,17 +1477,17 @@ BluetoothHfpManager::OnConnectSuccess(Bl mRunnable = nullptr; } mFirstCKPD = true; // Cache device path for NotifySettings() since we can't get socket address // when a headset disconnect with us mSocket->GetAddress(mDeviceAddress); - NotifyStatusChanged(NS_LITERAL_STRING("bluetooth-hfp-status-changed")); + NotifyStatusChanged(BLUETOOTH_HFP_STATUS_CHANGED_ID); ListenSco(); BluetoothA2dpManager* a2dp = BluetoothA2dpManager::Get(); NS_ENSURE_TRUE_VOID(a2dp); a2dp->Connect(mDeviceAddress); } @@ -1543,17 +1532,17 @@ BluetoothHfpManager::OnDisconnect(Blueto // Do nothing when a listening server socket is closed. return; } mSocket = nullptr; DisconnectSco(); Listen(); - NotifyStatusChanged(NS_LITERAL_STRING("bluetooth-hfp-status-changed")); + NotifyStatusChanged(BLUETOOTH_HFP_STATUS_CHANGED_ID); Reset(); } void BluetoothHfpManager::OnUpdateSdpRecords(const nsAString& aDeviceAddress) { MOZ_ASSERT(NS_IsMainThread()); MOZ_ASSERT(!aDeviceAddress.IsEmpty()); @@ -1623,18 +1612,17 @@ BluetoothHfpManager::OnScoConnectSuccess { // For active connection request, we need to reply the DOMRequest if (mScoRunnable) { DispatchBluetoothReply(mScoRunnable, BluetoothValue(true), EmptyString()); mScoRunnable = nullptr; } - NotifyAudioManager(true); - NotifyStatusChanged(NS_LITERAL_STRING("bluetooth-sco-status-changed")); + NotifyStatusChanged(BLUETOOTH_SCO_STATUS_CHANGED_ID); mScoSocketStatus = mScoSocket->GetConnectionStatus(); } void BluetoothHfpManager::OnScoConnectError() { if (mScoRunnable) { @@ -1647,18 +1635,17 @@ BluetoothHfpManager::OnScoConnectError() ListenSco(); } void BluetoothHfpManager::OnScoDisconnect() { if (mScoSocketStatus == SocketConnectionStatus::SOCKET_CONNECTED) { ListenSco(); - NotifyAudioManager(false); - NotifyStatusChanged(NS_LITERAL_STRING("bluetooth-sco-status-changed")); + NotifyStatusChanged(BLUETOOTH_SCO_STATUS_CHANGED_ID); } } bool BluetoothHfpManager::IsConnected() { if (mSocket) { return mSocket->GetConnectionStatus() ==
--- a/dom/bluetooth/BluetoothHfpManager.h +++ b/dom/bluetooth/BluetoothHfpManager.h @@ -113,18 +113,17 @@ private: bool Init(); void Notify(const hal::BatteryInformation& aBatteryInfo); void Reset(); void ResetCallArray(); uint32_t FindFirstCall(uint16_t aState); uint32_t GetNumberOfCalls(uint16_t aState); void NotifyDialer(const nsAString& aCommand); - void NotifyStatusChanged(const nsAString& aType); - void NotifyAudioManager(bool aStatus); + void NotifyStatusChanged(const char* aType); bool SendCommand(const char* aCommand, uint32_t aValue = 0); bool SendLine(const char* aMessage); void UpdateCIND(uint8_t aType, uint8_t aValue, bool aSend = true); void OnScoConnectSuccess(); void OnScoConnectError(); void OnScoDisconnect();
--- a/dom/mobilemessage/interfaces/nsIMobileMessageCallback.idl +++ b/dom/mobilemessage/interfaces/nsIMobileMessageCallback.idl @@ -8,17 +8,17 @@ dictionary SmsThreadListItem { unsigned long long id; DOMString senderOrReceiver; unsigned long long timestamp; DOMString body; unsigned long long unreadCount; }; -[scriptable, builtinclass, uuid(a22d9aae-ee0a-11e2-949e-e770d0d3883f)] +[scriptable, uuid(ea5fb581-bee7-40a6-b2dc-c98b99a2dc49)] interface nsIMobileMessageCallback : nsISupports { /** * All SMS related errors. * Make sure to keep this list in sync with the list in: * embedding/android/GeckoSmsManager.java */ const unsigned short SUCCESS_NO_ERROR = 0;
--- a/dom/mobilemessage/interfaces/nsISmsService.idl +++ b/dom/mobilemessage/interfaces/nsISmsService.idl @@ -8,19 +8,24 @@ interface nsIDOMMozSmsMessage; interface nsIDOMMozSmsSegmentInfo; interface nsIMobileMessageCallback; %{C++ #define SMS_SERVICE_CID { 0xbada3cb8, 0xa568, 0x4dff, { 0xb5, 0x43, 0x52, 0xbb, 0xb3, 0x14, 0x31, 0x21 } } #define SMS_SERVICE_CONTRACTID "@mozilla.org/sms/smsservice;1" %} -[scriptable, builtinclass, uuid(c4b2ed2a-8714-11e2-bd2b-13f1a0759342)] +[scriptable, builtinclass, uuid(f0d5d11b-0326-4cb1-bb76-a3f912212287)] interface nsISmsService : nsISupports { boolean hasSupport(); nsIDOMMozSmsSegmentInfo getSegmentInfoForText(in DOMString text); void send(in DOMString number, in DOMString message, + in boolean silent, in nsIMobileMessageCallback request); + + boolean isSilentNumber(in DOMString number); + void addSilentNumber(in DOMString number); + void removeSilentNumber(in DOMString number); };
--- a/dom/mobilemessage/src/Constants.cpp +++ b/dom/mobilemessage/src/Constants.cpp @@ -9,12 +9,13 @@ namespace mobilemessage { const char* kSmsReceivedObserverTopic = "sms-received"; const char* kSmsRetrievingObserverTopic = "sms-retrieving"; const char* kSmsSendingObserverTopic = "sms-sending"; const char* kSmsSentObserverTopic = "sms-sent"; const char* kSmsFailedObserverTopic = "sms-failed"; const char* kSmsDeliverySuccessObserverTopic = "sms-delivery-success"; const char* kSmsDeliveryErrorObserverTopic = "sms-delivery-error"; +const char* kSilentSmsReceivedObserverTopic = "silent-sms-received"; } // namespace mobilemessage } // namespace dom } // namespace mozilla
--- a/dom/mobilemessage/src/Constants.h +++ b/dom/mobilemessage/src/Constants.h @@ -13,21 +13,17 @@ namespace mobilemessage { // Defined in the .cpp. extern const char* kSmsReceivedObserverTopic; extern const char* kSmsRetrievingObserverTopic; extern const char* kSmsSendingObserverTopic; extern const char* kSmsSentObserverTopic; extern const char* kSmsFailedObserverTopic; extern const char* kSmsDeliverySuccessObserverTopic; extern const char* kSmsDeliveryErrorObserverTopic; - -extern const char* kMmsSendingObserverTopic; -extern const char* kMmsSentObserverTopic; -extern const char* kMmsFailedObserverTopic; -extern const char* kMmsReceivedObserverTopic; +extern const char* kSilentSmsReceivedObserverTopic; #define DELIVERY_RECEIVED NS_LITERAL_STRING("received") #define DELIVERY_SENDING NS_LITERAL_STRING("sending") #define DELIVERY_SENT NS_LITERAL_STRING("sent") #define DELIVERY_ERROR NS_LITERAL_STRING("error") #define DELIVERY_NOT_DOWNLOADED NS_LITERAL_STRING("not-downloaded") #define DELIVERY_STATUS_NOT_APPLICABLE NS_LITERAL_STRING("not-applicable")
--- a/dom/mobilemessage/src/MobileMessageManager.cpp +++ b/dom/mobilemessage/src/MobileMessageManager.cpp @@ -119,17 +119,18 @@ MobileMessageManager::Send(JSContext* aC nsDependentJSString number; number.init(aCx, aNumber); nsRefPtr<DOMRequest> request = new DOMRequest(GetOwner()); nsCOMPtr<nsIMobileMessageCallback> msgCallback = new MobileMessageCallback(request); - nsresult rv = smsService->Send(number, aMessage, msgCallback); + // By default, we don't send silent messages via MobileMessageManager. + nsresult rv = smsService->Send(number, aMessage, false, msgCallback); NS_ENSURE_SUCCESS(rv, rv); JS::Rooted<JSObject*> global(aCx, aGlobal); rv = nsContentUtils::WrapNative(aCx, global, static_cast<nsIDOMDOMRequest*>(request.get()), aRequest); if (NS_FAILED(rv)) { NS_ERROR("Failed to create the js value!");
--- a/dom/mobilemessage/src/android/SmsService.cpp +++ b/dom/mobilemessage/src/android/SmsService.cpp @@ -35,22 +35,46 @@ SmsService::GetSegmentInfoForText(const NS_ENSURE_SUCCESS(rv, rv); nsCOMPtr<nsIDOMMozSmsSegmentInfo> info = new SmsSegmentInfo(data); info.forget(aResult); return NS_OK; } NS_IMETHODIMP -SmsService::Send(const nsAString& aNumber, const nsAString& aMessage, +SmsService::Send(const nsAString& aNumber, + const nsAString& aMessage, + const bool aSilent, nsIMobileMessageCallback* aRequest) { if (!AndroidBridge::Bridge()) { return NS_OK; } AndroidBridge::Bridge()->SendMessage(aNumber, aMessage, aRequest); return NS_OK; } +NS_IMETHODIMP +SmsService::IsSilentNumber(const nsAString& aNumber, + bool* aIsSilent) +{ + NS_NOTYETIMPLEMENTED("Implement me!"); + return NS_ERROR_NOT_IMPLEMENTED; +} + +NS_IMETHODIMP +SmsService::AddSilentNumber(const nsAString& aNumber) +{ + NS_NOTYETIMPLEMENTED("Implement me!"); + return NS_ERROR_NOT_IMPLEMENTED; +} + +NS_IMETHODIMP +SmsService::RemoveSilentNumber(const nsAString& aNumber) +{ + NS_NOTYETIMPLEMENTED("Implement me!"); + return NS_ERROR_NOT_IMPLEMENTED; +} + } // namespace mobilemessage } // namespace dom } // namespace mozilla
--- a/dom/mobilemessage/src/fallback/SmsService.cpp +++ b/dom/mobilemessage/src/fallback/SmsService.cpp @@ -27,17 +27,40 @@ SmsService::GetSegmentInfoForText(const { NS_ERROR("We should not be here!"); return NS_ERROR_FAILURE; } NS_IMETHODIMP SmsService::Send(const nsAString& aNumber, const nsAString& aMessage, + const bool aSilent, nsIMobileMessageCallback* aRequest) { NS_ERROR("We should not be here!"); - return NS_OK; + return NS_ERROR_FAILURE; +} + +NS_IMETHODIMP +SmsService::IsSilentNumber(const nsAString& aNumber, + bool* aIsSilent) +{ + NS_ERROR("We should not be here!"); + return NS_ERROR_FAILURE; +} + +NS_IMETHODIMP +SmsService::AddSilentNumber(const nsAString& aNumber) +{ + NS_ERROR("We should not be here!"); + return NS_ERROR_FAILURE; +} + +NS_IMETHODIMP +SmsService::RemoveSilentNumber(const nsAString& aNumber) +{ + NS_ERROR("We should not be here!"); + return NS_ERROR_FAILURE; } } // namespace mobilemessage } // namespace dom } // namespace mozilla
--- a/dom/mobilemessage/src/gonk/SmsService.cpp +++ b/dom/mobilemessage/src/gonk/SmsService.cpp @@ -37,18 +37,49 @@ SmsService::GetSegmentInfoForText(const NS_ENSURE_TRUE(mRadioInterface, NS_ERROR_FAILURE); return mRadioInterface->GetSegmentInfoForText(aText, aResult); } NS_IMETHODIMP SmsService::Send(const nsAString& aNumber, const nsAString& aMessage, + const bool aSilent, nsIMobileMessageCallback* aRequest) { NS_ENSURE_TRUE(mRadioInterface, NS_ERROR_FAILURE); - return mRadioInterface->SendSMS(aNumber, aMessage, aRequest); + return mRadioInterface->SendSMS(aNumber, aMessage, aSilent, aRequest); +} + +NS_IMETHODIMP +SmsService::IsSilentNumber(const nsAString& aNumber, + bool* aIsSilent) +{ + *aIsSilent = mSilentNumbers.Contains(aNumber); + return NS_OK; +} + +NS_IMETHODIMP +SmsService::AddSilentNumber(const nsAString& aNumber) +{ + if (mSilentNumbers.Contains(aNumber)) { + return NS_ERROR_UNEXPECTED; + } + + NS_ENSURE_TRUE(mSilentNumbers.AppendElement(aNumber), NS_ERROR_FAILURE); + return NS_OK; +} + +NS_IMETHODIMP +SmsService::RemoveSilentNumber(const nsAString& aNumber) +{ + if (!mSilentNumbers.Contains(aNumber)) { + return NS_ERROR_INVALID_ARG; + } + + NS_ENSURE_TRUE(mSilentNumbers.RemoveElement(aNumber), NS_ERROR_FAILURE); + return NS_OK; } } // namespace mobilemessage } // namespace dom } // namespace mozilla
--- a/dom/mobilemessage/src/gonk/SmsService.h +++ b/dom/mobilemessage/src/gonk/SmsService.h @@ -3,30 +3,33 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #ifndef mozilla_dom_mobilemessage_SmsService_h #define mozilla_dom_mobilemessage_SmsService_h #include "nsISmsService.h" #include "nsCOMPtr.h" #include "nsIRadioInterfaceLayer.h" +#include "nsTArray.h" +#include "nsString.h" namespace mozilla { namespace dom { namespace mobilemessage { class SmsService : public nsISmsService { public: NS_DECL_ISUPPORTS NS_DECL_NSISMSSERVICE SmsService(); protected: // TODO: Bug 854326 - B2G Multi-SIM: support multiple SIM cards for SMS/MMS nsCOMPtr<nsIRadioInterface> mRadioInterface; + nsTArray<nsString> mSilentNumbers; }; } // namespace mobilemessage } // namespace dom } // namespace mozilla #endif // mozilla_dom_mobilemessage_SmsService_h
--- a/dom/mobilemessage/src/ipc/PSms.ipdl +++ b/dom/mobilemessage/src/ipc/PSms.ipdl @@ -21,16 +21,17 @@ struct SendMmsMessageRequest nsString smil; MmsAttachmentData[] attachments; }; struct SendSmsMessageRequest { nsString number; nsString message; + bool silent; }; union SendMessageRequest { SendMmsMessageRequest; SendSmsMessageRequest; }; @@ -95,16 +96,18 @@ child: NotifySentMessage(MobileMessageData aMessageData); NotifyFailedMessage(MobileMessageData aMessageData); NotifyDeliverySuccessMessage(MobileMessageData aMessageData); NotifyDeliveryErrorMessage(MobileMessageData aMessageData); + NotifyReceivedSilentMessage(MobileMessageData aMessageData); + parent: /** * Sent when the child no longer needs to use sms. */ __delete__(); /** * Sent when the child makes an asynchronous request to the parent. @@ -116,13 +119,16 @@ parent: */ PMobileMessageCursor(IPCMobileMessageCursor request); sync HasSupport() returns (bool aHasSupport); sync GetSegmentInfoForText(nsString aText) returns (SmsSegmentInfoData aResult); + + AddSilentNumber(nsString aNumber); + RemoveSilentNumber(nsString aNumber); }; } // namespace mobilemessage } // namespace dom } // namespace mozilla
--- a/dom/mobilemessage/src/ipc/SmsChild.cpp +++ b/dom/mobilemessage/src/ipc/SmsChild.cpp @@ -104,16 +104,23 @@ SmsChild::RecvNotifyDeliverySuccessMessa bool SmsChild::RecvNotifyDeliveryErrorMessage(const MobileMessageData& aData) { NotifyObserversWithMobileMessage(kSmsDeliveryErrorObserverTopic, aData); return true; } +bool +SmsChild::RecvNotifyReceivedSilentMessage(const MobileMessageData& aData) +{ + NotifyObserversWithMobileMessage(kSilentSmsReceivedObserverTopic, aData); + return true; +} + PSmsRequestChild* SmsChild::AllocPSmsRequestChild(const IPCSmsRequest& aRequest) { MOZ_CRASH("Caller is supposed to manually construct a request!"); } bool SmsChild::DeallocPSmsRequestChild(PSmsRequestChild* aActor)
--- a/dom/mobilemessage/src/ipc/SmsChild.h +++ b/dom/mobilemessage/src/ipc/SmsChild.h @@ -50,16 +50,19 @@ protected: RecvNotifyFailedMessage(const MobileMessageData& aMessage) MOZ_OVERRIDE; virtual bool RecvNotifyDeliverySuccessMessage(const MobileMessageData& aMessage) MOZ_OVERRIDE; virtual bool RecvNotifyDeliveryErrorMessage(const MobileMessageData& aMessage) MOZ_OVERRIDE; + virtual bool + RecvNotifyReceivedSilentMessage(const MobileMessageData& aMessage) MOZ_OVERRIDE; + virtual PSmsRequestChild* AllocPSmsRequestChild(const IPCSmsRequest& aRequest) MOZ_OVERRIDE; virtual bool DeallocPSmsRequestChild(PSmsRequestChild* aActor) MOZ_OVERRIDE; virtual PMobileMessageCursorChild* AllocPMobileMessageCursorChild(const IPCMobileMessageCursor& aCursor) MOZ_OVERRIDE;
--- a/dom/mobilemessage/src/ipc/SmsIPCService.cpp +++ b/dom/mobilemessage/src/ipc/SmsIPCService.cpp @@ -110,23 +110,53 @@ SmsIPCService::GetSegmentInfoForText(con nsCOMPtr<nsIDOMMozSmsSegmentInfo> info = new SmsSegmentInfo(data); info.forget(aResult); return NS_OK; } NS_IMETHODIMP SmsIPCService::Send(const nsAString& aNumber, const nsAString& aMessage, + const bool aSilent, nsIMobileMessageCallback* aRequest) { return SendRequest(SendMessageRequest(SendSmsMessageRequest(nsString(aNumber), - nsString(aMessage))), + nsString(aMessage), + aSilent)), aRequest); } +NS_IMETHODIMP +SmsIPCService::IsSilentNumber(const nsAString& aNumber, + bool* aIsSilent) +{ + NS_ERROR("We should not be here!"); + return NS_ERROR_FAILURE; +} + +NS_IMETHODIMP +SmsIPCService::AddSilentNumber(const nsAString& aNumber) +{ + PSmsChild* smsChild = GetSmsChild(); + NS_ENSURE_TRUE(smsChild, NS_ERROR_FAILURE); + + smsChild->SendAddSilentNumber(nsString(aNumber)); + return NS_OK; +} + +NS_IMETHODIMP +SmsIPCService::RemoveSilentNumber(const nsAString& aNumber) +{ + PSmsChild* smsChild = GetSmsChild(); + NS_ENSURE_TRUE(smsChild, NS_ERROR_FAILURE); + + smsChild->SendRemoveSilentNumber(nsString(aNumber)); + return NS_OK; +} + /* * Implementation of nsIMobileMessageDatabaseService. */ NS_IMETHODIMP SmsIPCService::GetMessageMoz(int32_t aMessageId, nsIMobileMessageCallback* aRequest) { return SendRequest(GetMessageRequest(aMessageId), aRequest);
--- a/dom/mobilemessage/src/ipc/SmsParent.cpp +++ b/dom/mobilemessage/src/ipc/SmsParent.cpp @@ -146,16 +146,17 @@ SmsParent::SmsParent() obs->AddObserver(this, kSmsReceivedObserverTopic, false); obs->AddObserver(this, kSmsRetrievingObserverTopic, false); obs->AddObserver(this, kSmsSendingObserverTopic, false); obs->AddObserver(this, kSmsSentObserverTopic, false); obs->AddObserver(this, kSmsFailedObserverTopic, false); obs->AddObserver(this, kSmsDeliverySuccessObserverTopic, false); obs->AddObserver(this, kSmsDeliveryErrorObserverTopic, false); + obs->AddObserver(this, kSilentSmsReceivedObserverTopic, false); } void SmsParent::ActorDestroy(ActorDestroyReason why) { nsCOMPtr<nsIObserverService> obs = services::GetObserverService(); if (!obs) { return; @@ -163,16 +164,17 @@ SmsParent::ActorDestroy(ActorDestroyReas obs->RemoveObserver(this, kSmsReceivedObserverTopic); obs->RemoveObserver(this, kSmsRetrievingObserverTopic); obs->RemoveObserver(this, kSmsSendingObserverTopic); obs->RemoveObserver(this, kSmsSentObserverTopic); obs->RemoveObserver(this, kSmsFailedObserverTopic); obs->RemoveObserver(this, kSmsDeliverySuccessObserverTopic); obs->RemoveObserver(this, kSmsDeliveryErrorObserverTopic); + obs->RemoveObserver(this, kSilentSmsReceivedObserverTopic); } NS_IMETHODIMP SmsParent::Observe(nsISupports* aSubject, const char* aTopic, const PRUnichar* aData) { if (!strcmp(aTopic, kSmsReceivedObserverTopic)) { MobileMessageData msgData; @@ -246,16 +248,34 @@ SmsParent::Observe(nsISupports* aSubject NS_ERROR("Got a 'sms-delivery-error' topic without a valid message!"); return NS_OK; } unused << SendNotifyDeliveryErrorMessage(msgData); return NS_OK; } + if (!strcmp(aTopic, kSilentSmsReceivedObserverTopic)) { + nsCOMPtr<nsIDOMMozSmsMessage> smsMsg = do_QueryInterface(aSubject); + if (!smsMsg) { + return NS_OK; + } + + nsString sender; + if (NS_FAILED(smsMsg->GetSender(sender)) || + !mSilentNumbers.Contains(sender)) { + return NS_OK; + } + + MobileMessageData msgData = + static_cast<SmsMessage*>(smsMsg.get())->GetData(); + unused << SendNotifyReceivedSilentMessage(msgData); + return NS_OK; + } + return NS_OK; } bool SmsParent::GetMobileMessageDataFromMessage(nsISupports *aMsg, MobileMessageData &aData) { nsCOMPtr<nsIDOMMozMmsMessage> mmsMsg = do_QueryInterface(aMsg); @@ -316,16 +336,52 @@ SmsParent::RecvGetSegmentInfoForText(con aResult->segments() = segments; aResult->charsPerSegment() = charsPerSegment; aResult->charsAvailableInLastSegment() = charsAvailableInLastSegment; return true; } bool +SmsParent::RecvAddSilentNumber(const nsString& aNumber) +{ + if (mSilentNumbers.Contains(aNumber)) { + return true; + } + + nsCOMPtr<nsISmsService> smsService = do_GetService(SMS_SERVICE_CONTRACTID); + NS_ENSURE_TRUE(smsService, true); + + nsresult rv = smsService->AddSilentNumber(aNumber); + if (NS_SUCCEEDED(rv)) { + mSilentNumbers.AppendElement(aNumber); + } + + return true; +} + +bool +SmsParent::RecvRemoveSilentNumber(const nsString& aNumber) +{ + if (!mSilentNumbers.Contains(aNumber)) { + return true; + } + + nsCOMPtr<nsISmsService> smsService = do_GetService(SMS_SERVICE_CONTRACTID); + NS_ENSURE_TRUE(smsService, true); + + nsresult rv = smsService->RemoveSilentNumber(aNumber); + if (NS_SUCCEEDED(rv)) { + mSilentNumbers.RemoveElement(aNumber); + } + + return true; +} + +bool SmsParent::RecvPSmsRequestConstructor(PSmsRequestParent* aActor, const IPCSmsRequest& aRequest) { SmsRequestParent* actor = static_cast<SmsRequestParent*>(aActor); switch (aRequest.type()) { case IPCSmsRequest::TSendMessageRequest: return actor->DoRequest(aRequest.get_SendMessageRequest()); @@ -417,17 +473,17 @@ bool SmsRequestParent::DoRequest(const SendMessageRequest& aRequest) { switch(aRequest.type()) { case SendMessageRequest::TSendSmsMessageRequest: { nsCOMPtr<nsISmsService> smsService = do_GetService(SMS_SERVICE_CONTRACTID); NS_ENSURE_TRUE(smsService, true); const SendSmsMessageRequest &data = aRequest.get_SendSmsMessageRequest(); - smsService->Send(data.number(), data.message(), this); + smsService->Send(data.number(), data.message(), data.silent(), this); } break; case SendMessageRequest::TSendMmsMessageRequest: { nsCOMPtr<nsIMmsService> mmsService = do_GetService(MMS_SERVICE_CONTRACTID); NS_ENSURE_TRUE(mmsService, true); AutoJSContext cx; JS::Rooted<JS::Value> params(cx);
--- a/dom/mobilemessage/src/ipc/SmsParent.h +++ b/dom/mobilemessage/src/ipc/SmsParent.h @@ -32,16 +32,22 @@ public: protected: virtual bool RecvHasSupport(bool* aHasSupport) MOZ_OVERRIDE; virtual bool RecvGetSegmentInfoForText(const nsString& aText, SmsSegmentInfoData* aResult) MOZ_OVERRIDE; + virtual bool + RecvAddSilentNumber(const nsString& aNumber) MOZ_OVERRIDE; + + virtual bool + RecvRemoveSilentNumber(const nsString& aNumber) MOZ_OVERRIDE; + SmsParent(); virtual ~SmsParent() { MOZ_COUNT_DTOR(SmsParent); } virtual void ActorDestroy(ActorDestroyReason why); @@ -63,16 +69,19 @@ protected: virtual PMobileMessageCursorParent* AllocPMobileMessageCursorParent(const IPCMobileMessageCursor& aCursor) MOZ_OVERRIDE; virtual bool DeallocPMobileMessageCursorParent(PMobileMessageCursorParent* aActor) MOZ_OVERRIDE; bool GetMobileMessageDataFromMessage(nsISupports* aMsg, MobileMessageData& aData); + +private: + nsTArray<nsString> mSilentNumbers; }; class SmsRequestParent : public PSmsRequestParent , public nsIMobileMessageCallback { friend class SmsParent; bool mActorDestroyed;
--- a/dom/system/gonk/AudioManager.cpp +++ b/dom/system/gonk/AudioManager.cpp @@ -22,16 +22,17 @@ #include "nsPrintfCString.h" #include "mozilla/Hal.h" #include "mozilla/Services.h" #include "base/message_loop.h" #include "BluetoothCommon.h" #include "BluetoothProfileManagerBase.h" +#include "BluetoothHfpManager.h" #include "nsJSUtils.h" #include "nsCxPusher.h" using namespace mozilla::dom::gonk; using namespace android; using namespace mozilla::hal; using namespace mozilla; @@ -163,68 +164,88 @@ InternalSetAudioRoutes(SwitchState aStat status_t (*)(audio_devices_t, audio_policy_dev_state_t, const char*) >(AudioSystem::setDeviceConnectionState)) { InternalSetAudioRoutesICS(aState); } else { NS_NOTREACHED("Doesn't support audio routing on GB version"); } } +void +AudioManager::HandleBluetoothStatusChanged(nsISupports* aSubject, + const char* aTopic, + const nsCString aAddress) +{ + bool status; + if (!strcmp(aTopic, BLUETOOTH_SCO_STATUS_CHANGED_ID)) { + BluetoothHfpManager* hfp = + static_cast<BluetoothHfpManager*>(aSubject); + status = hfp->IsScoConnected(); + } else { + BluetoothProfileManagerBase* profile = + static_cast<BluetoothProfileManagerBase*>(aSubject); + status = profile->IsConnected(); + } + + audio_policy_dev_state_t audioState = status ? + AUDIO_POLICY_DEVICE_STATE_AVAILABLE : + AUDIO_POLICY_DEVICE_STATE_UNAVAILABLE; + + if (!strcmp(aTopic, BLUETOOTH_SCO_STATUS_CHANGED_ID)) { + if (audioState == AUDIO_POLICY_DEVICE_STATE_AVAILABLE) { + String8 cmd; + cmd.appendFormat("bt_samplerate=%d", kBtSampleRate); + AudioSystem::setParameters(0, cmd); + SetForceForUse(nsIAudioManager::USE_COMMUNICATION, nsIAudioManager::FORCE_BT_SCO); + } else { + int32_t force; + GetForceForUse(nsIAudioManager::USE_COMMUNICATION, &force); + if (force == nsIAudioManager::FORCE_BT_SCO) + SetForceForUse(nsIAudioManager::USE_COMMUNICATION, nsIAudioManager::FORCE_NONE); + } + } else if (!strcmp(aTopic, BLUETOOTH_A2DP_STATUS_CHANGED_ID)) { + AudioSystem::setDeviceConnectionState(AUDIO_DEVICE_OUT_BLUETOOTH_A2DP, + audioState, aAddress.get()); + if (audioState == AUDIO_POLICY_DEVICE_STATE_AVAILABLE) { + String8 cmd("bluetooth_enabled=true"); + AudioSystem::setParameters(0, cmd); + cmd.setTo("A2dpSuspended=false"); + AudioSystem::setParameters(0, cmd); + } else { + String8 cmd("bluetooth_enabled=false"); + AudioSystem::setParameters(0, cmd); + cmd.setTo("A2dpSuspended=true"); + AudioSystem::setParameters(0, cmd); + } + } else if (!strcmp(aTopic, BLUETOOTH_HFP_STATUS_CHANGED_ID)) { + AudioSystem::setDeviceConnectionState(AUDIO_DEVICE_OUT_BLUETOOTH_SCO_HEADSET, + audioState, aAddress.get()); + AudioSystem::setDeviceConnectionState(AUDIO_DEVICE_IN_BLUETOOTH_SCO_HEADSET, + audioState, aAddress.get()); + } +} + nsresult AudioManager::Observe(nsISupports* aSubject, const char* aTopic, const PRUnichar* aData) { if ((strcmp(aTopic, BLUETOOTH_SCO_STATUS_CHANGED_ID) == 0) || + (strcmp(aTopic, BLUETOOTH_HFP_STATUS_CHANGED_ID) == 0) || (strcmp(aTopic, BLUETOOTH_A2DP_STATUS_CHANGED_ID) == 0)) { - nsresult rv; - int status = NS_ConvertUTF16toUTF8(aData).ToInteger(&rv); - if (NS_FAILED(rv) || status > 1 || status < 0) { - NS_WARNING(nsPrintfCString("Wrong data value of %s", aTopic).get()); + nsCString address = NS_ConvertUTF16toUTF8(nsDependentString(aData)); + if (address.IsEmpty()) { + NS_WARNING(nsPrintfCString("Invalid address of %s", aTopic).get()); return NS_ERROR_FAILURE; } - nsAutoString tmp_address; - BluetoothProfileManagerBase* profile = - static_cast<BluetoothProfileManagerBase*>(aSubject); - profile->GetAddress(tmp_address); - nsAutoCString address = NS_ConvertUTF16toUTF8(tmp_address); - - audio_policy_dev_state_t audioState = status ? - AUDIO_POLICY_DEVICE_STATE_AVAILABLE : - AUDIO_POLICY_DEVICE_STATE_UNAVAILABLE; + HandleBluetoothStatusChanged(aSubject, aTopic, address); + return NS_OK; + } - if (!strcmp(aTopic, BLUETOOTH_SCO_STATUS_CHANGED_ID)) { - AudioSystem::setDeviceConnectionState(AUDIO_DEVICE_OUT_BLUETOOTH_SCO_HEADSET, - audioState, address.get()); - AudioSystem::setDeviceConnectionState(AUDIO_DEVICE_IN_BLUETOOTH_SCO_HEADSET, - audioState, address.get()); - if (audioState == AUDIO_POLICY_DEVICE_STATE_AVAILABLE) { - String8 cmd; - cmd.appendFormat("bt_samplerate=%d", kBtSampleRate); - AudioSystem::setParameters(0, cmd); - SetForceForUse(nsIAudioManager::USE_COMMUNICATION, nsIAudioManager::FORCE_BT_SCO); - } else { - // only force to none if the current force setting is bt_sco - int32_t force; - GetForceForUse(nsIAudioManager::USE_COMMUNICATION, &force); - if (force == nsIAudioManager::FORCE_BT_SCO) - SetForceForUse(nsIAudioManager::USE_COMMUNICATION, nsIAudioManager::FORCE_NONE); - } - } else if (!strcmp(aTopic, BLUETOOTH_A2DP_STATUS_CHANGED_ID)) { - AudioSystem::setDeviceConnectionState(AUDIO_DEVICE_OUT_BLUETOOTH_A2DP, - audioState, address.get()); - if (audioState == AUDIO_POLICY_DEVICE_STATE_AVAILABLE) { - String8 cmd("bluetooth_enabled=true"); - AudioSystem::setParameters(0, cmd); - cmd.setTo("A2dpSuspended=false"); - AudioSystem::setParameters(0, cmd); - } - } - } // To process the volume control on each audio channel according to // change of settings else if (!strcmp(aTopic, "mozsettings-changed")) { AutoSafeJSContext cx; nsDependentString dataStr(aData); JS::Rooted<JS::Value> val(cx); if (!JS_ParseJSON(cx, dataStr.get(), dataStr.Length(), &val) || !val.isObject()) { @@ -310,16 +331,19 @@ AudioManager::AudioManager() : mPhoneSta NS_WARNING("Failed to add bluetooth sco status changed observer!"); } if (NS_FAILED(obs->AddObserver(this, BLUETOOTH_A2DP_STATUS_CHANGED_ID, false))) { NS_WARNING("Failed to add bluetooth a2dp status changed observer!"); } if (NS_FAILED(obs->AddObserver(this, "mozsettings-changed", false))) { NS_WARNING("Failed to add mozsettings-changed oberver!"); } + if (NS_FAILED(obs->AddObserver(this, BLUETOOTH_HFP_STATUS_CHANGED_ID, false))) { + NS_WARNING("Failed to add bluetooth hfp status changed observer!"); + } for (int loop = 0; loop < AUDIO_STREAM_CNT; loop++) { AudioSystem::initStreamVolume(static_cast<audio_stream_type_t>(loop), 0, sMaxStreamVolumeTbl[loop]); mCurrentStreamVolumeTbl[loop] = sMaxStreamVolumeTbl[loop]; } // Force publicnotification to output at maximal volume SetStreamVolumeIndex(AUDIO_STREAM_ENFORCED_AUDIBLE, @@ -337,16 +361,19 @@ AudioManager::~AudioManager() { nsCOMPtr<nsIObserverService> obs = services::GetObserverService(); NS_ENSURE_TRUE_VOID(obs); if (NS_FAILED(obs->RemoveObserver(this, BLUETOOTH_SCO_STATUS_CHANGED_ID))) { NS_WARNING("Failed to remove bluetooth sco status changed observer!"); } if (NS_FAILED(obs->RemoveObserver(this, BLUETOOTH_A2DP_STATUS_CHANGED_ID))) { NS_WARNING("Failed to remove bluetooth a2dp status changed observer!"); } + if (NS_FAILED(obs->RemoveObserver(this, BLUETOOTH_HFP_STATUS_CHANGED_ID))) { + NS_WARNING("Failed to remove bluetooth hfp status changed observer!"); + } } NS_IMETHODIMP AudioManager::GetMicrophoneMuted(bool* aMicrophoneMuted) { if (AudioSystem::isMicrophoneMuted(aMicrophoneMuted)) { return NS_ERROR_FAILURE; } @@ -370,17 +397,22 @@ AudioManager::GetPhoneState(int32_t* aSt } NS_IMETHODIMP AudioManager::SetPhoneState(int32_t aState) { if (mPhoneState == aState) { return NS_OK; } - + // follow the switch audio path logic for android, Bug 897364 + int usage; + GetForceForUse(nsIAudioManager::USE_COMMUNICATION, &usage); + if (aState == PHONE_STATE_NORMAL && usage == nsIAudioManager::FORCE_BT_SCO) { + SetForceForUse(nsIAudioManager::USE_COMMUNICATION, nsIAudioManager::FORCE_NONE); + } #if ANDROID_VERSION < 17 if (AudioSystem::setPhoneState(aState)) { #else if (AudioSystem::setPhoneState(static_cast<audio_mode_t>(aState))) { #endif return NS_ERROR_FAILURE; }
--- a/dom/system/gonk/AudioManager.h +++ b/dom/system/gonk/AudioManager.h @@ -59,15 +59,19 @@ protected: int mCurrentStreamVolumeTbl[AUDIO_STREAM_CNT]; android::status_t SetStreamVolumeIndex(int32_t aStream, int32_t aIndex); android::status_t GetStreamVolumeIndex(int32_t aStream, int32_t *aIndex); private: nsAutoPtr<mozilla::hal::SwitchObserver> mObserver; nsCOMPtr<AudioChannelAgent> mPhoneAudioAgent; + + void HandleBluetoothStatusChanged(nsISupports* aSubject, + const char* aTopic, + const nsCString aAddress); }; } /* namespace gonk */ } /* namespace dom */ } /* namespace mozilla */ #endif // mozilla_dom_system_b2g_audiomanager_h__
--- a/dom/system/gonk/RadioInterfaceLayer.js +++ b/dom/system/gonk/RadioInterfaceLayer.js @@ -46,16 +46,17 @@ 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"; const kSmsSendingObserverTopic = "sms-sending"; const kSmsSentObserverTopic = "sms-sent"; const kSmsFailedObserverTopic = "sms-failed"; const kSmsDeliverySuccessObserverTopic = "sms-delivery-success"; const kSmsDeliveryErrorObserverTopic = "sms-delivery-error"; const kMozSettingsChangedObserverTopic = "mozsettings-changed"; const kSysMsgListenerReadyObserverTopic = "system-message-listener-ready"; const kSysClockChangeObserverTopic = "system-clock-change"; @@ -140,16 +141,20 @@ const RIL_IPC_CELLBROADCAST_MSG_NAMES = XPCOMUtils.defineLazyServiceGetter(this, "gPowerManagerService", "@mozilla.org/power/powermanagerservice;1", "nsIPowerManagerService"); XPCOMUtils.defineLazyServiceGetter(this, "gMobileMessageService", "@mozilla.org/mobilemessage/mobilemessageservice;1", "nsIMobileMessageService"); +XPCOMUtils.defineLazyServiceGetter(this, "gSmsService", + "@mozilla.org/sms/smsservice;1", + "nsISmsService"); + XPCOMUtils.defineLazyServiceGetter(this, "gMobileMessageDatabaseService", "@mozilla.org/mobilemessage/rilmobilemessagedatabaseservice;1", "nsIRilMobileMessageDatabaseService"); XPCOMUtils.defineLazyServiceGetter(this, "ppmm", "@mozilla.org/parentprocessmessagemanager;1", "nsIMessageBroadcaster"); @@ -1883,16 +1888,41 @@ RadioInterface.prototype = { } message.type = "sms"; message.sender = message.sender || null; message.receiver = this.getMsisdn(); message.body = message.fullBody = message.fullBody || null; message.timestamp = Date.now(); + if (gSmsService.isSilentNumber(message.sender)) { + message.id = -1; + message.threadId = 0; + message.delivery = DOM_MOBILE_MESSAGE_DELIVERY_RECEIVED; + message.deliveryStatus = RIL.GECKO_SMS_DELIVERY_STATUS_SUCCESS; + message.read = false; + + let domMessage = + gMobileMessageService.createSmsMessage(message.id, + message.threadId, + message.delivery, + message.deliveryStatus, + message.sender, + message.receiver, + message.body, + message.messageClass, + message.timestamp, + message.read); + + Services.obs.notifyObservers(domMessage, + kSilentSmsReceivedObserverTopic, + null); + return true; + } + // TODO: Bug #768441 // For now we don't store indicators persistently. When the mwi.discard // flag is false, we'll need to persist the indicator to EFmwis. // See TS 23.040 9.2.3.24.2 let mwi = message.mwi; if (mwi) { mwi.returnNumber = message.sender; @@ -1972,16 +2002,35 @@ RadioInterface.prototype = { handleSmsSent: function handleSmsSent(message) { if (DEBUG) this.debug("handleSmsSent: " + JSON.stringify(message)); let options = this._sentSmsEnvelopes[message.envelopeId]; if (!options) { return; } + if (options.silent) { + // There is no way to modify nsIDOMMozSmsMessage attributes as they are + // read only so we just create a new sms instance to send along with + // the notification. + let sms = options.sms; + options.request.notifyMessageSent( + gMobileMessageService.createSmsMessage(sms.id, + sms.threadId, + DOM_MOBILE_MESSAGE_DELIVERY_SENT, + sms.deliveryStatus, + sms.sender, + sms.receiver, + sms.body, + sms.messageClass, + sms.timestamp, + sms.read)); + return; + } + gMobileMessageDatabaseService.setMessageDelivery(options.sms.id, null, DOM_MOBILE_MESSAGE_DELIVERY_SENT, options.sms.deliveryStatus, function notifyResult(rv, domMessage) { // TODO bug 832140 handle !Components.isSuccessCode(rv) this.broadcastSmsSystemMessage("sms-sent", domMessage); @@ -2001,16 +2050,20 @@ RadioInterface.prototype = { if (DEBUG) this.debug("handleSmsDelivery: " + JSON.stringify(message)); let options = this._sentSmsEnvelopes[message.envelopeId]; if (!options) { return; } delete this._sentSmsEnvelopes[message.envelopeId]; + if (options.silent) { + return; + } + gMobileMessageDatabaseService.setMessageDelivery(options.sms.id, null, options.sms.delivery, message.deliveryStatus, function notifyResult(rv, domMessage) { // TODO bug 832140 handle !Components.isSuccessCode(rv) let topic = (message.deliveryStatus == RIL.GECKO_SMS_DELIVERY_STATUS_SUCCESS) ? kSmsDeliverySuccessObserverTopic @@ -2030,16 +2083,21 @@ RadioInterface.prototype = { let error = Ci.nsIMobileMessageCallback.UNKNOWN_ERROR; switch (message.errorMsg) { case RIL.ERROR_RADIO_NOT_AVAILABLE: error = Ci.nsIMobileMessageCallback.NO_SIGNAL_ERROR; break; } + if (options.silent) { + options.request.notifySendMessageFailed(error); + return; + } + gMobileMessageDatabaseService.setMessageDelivery(options.sms.id, null, DOM_MOBILE_MESSAGE_DELIVERY_ERROR, RIL.GECKO_SMS_DELIVERY_STATUS_ERROR, function notifyResult(rv, domMessage) { // TODO bug 832140 handle !Components.isSuccessCode(rv) options.request.notifySendMessageFailed(error); Services.obs.notifyObservers(domMessage, kSmsFailedObserverTopic, null); @@ -3140,17 +3198,17 @@ RadioInterface.prototype = { } let result = gMobileMessageService.createSmsSegmentInfo(options.segmentMaxSeq, options.segmentChars, options.segmentChars - charsInLastSegment); return result; }, - sendSMS: function sendSMS(number, message, request) { + sendSMS: function sendSMS(number, message, silent, request) { let strict7BitEncoding; try { strict7BitEncoding = Services.prefs.getBoolPref("dom.sms.strict7BitEncoding"); } catch (e) { strict7BitEncoding = false; } let options = this._fragmentText(message, null, strict7BitEncoding); @@ -3164,71 +3222,96 @@ RadioInterface.prototype = { requestStatusReport = true; } options.requestStatusReport = requestStatusReport; if (options.segmentMaxSeq > 1) { options.segmentRef16Bit = this.segmentRef16Bit; options.segmentRef = this.nextSegmentRef; } + let notifyResult = (function notifyResult(rv, domMessage) { + // TODO bug 832140 handle !Components.isSuccessCode(rv) + if (!silent) { + Services.obs.notifyObservers(domMessage, kSmsSendingObserverTopic, null); + } + + // If the radio is disabled or the SIM card is not ready, just directly + // return with the corresponding error code. + let errorCode; + if (!PhoneNumberUtils.isPlainPhoneNumber(options.number)) { + if (DEBUG) this.debug("Error! Address is invalid when sending SMS: " + + options.number); + errorCode = Ci.nsIMobileMessageCallback.INVALID_ADDRESS_ERROR; + } else if (!this._radioEnabled) { + if (DEBUG) this.debug("Error! Radio is disabled when sending SMS."); + errorCode = Ci.nsIMobileMessageCallback.RADIO_DISABLED_ERROR; + } else if (this.rilContext.cardState != "ready") { + if (DEBUG) this.debug("Error! SIM card is not ready when sending SMS."); + errorCode = Ci.nsIMobileMessageCallback.NO_SIM_CARD_ERROR; + } + if (errorCode) { + if (silent) { + request.notifySendMessageFailed(errorCode); + return; + } + + gMobileMessageDatabaseService + .setMessageDelivery(domMessage.id, + null, + DOM_MOBILE_MESSAGE_DELIVERY_ERROR, + RIL.GECKO_SMS_DELIVERY_STATUS_ERROR, + function notifyResult(rv, domMessage) { + // TODO bug 832140 handle !Components.isSuccessCode(rv) + request.notifySendMessageFailed(errorCode); + Services.obs.notifyObservers(domMessage, kSmsFailedObserverTopic, null); + }); + return; + } + + // Keep current SMS message info for sent/delivered notifications + options.envelopeId = this.createSmsEnvelope({ + request: request, + sms: domMessage, + requestStatusReport: options.requestStatusReport, + silent: silent + }); + + // This is the entry point starting to send SMS. + this.worker.postMessage(options); + }).bind(this); + let sendingMessage = { type: "sms", sender: this.getMsisdn(), receiver: number, body: message, deliveryStatusRequested: options.requestStatusReport, timestamp: Date.now() }; + if (silent) { + let deliveryStatus = RIL.GECKO_SMS_DELIVERY_STATUS_PENDING; + let delivery = DOM_MOBILE_MESSAGE_DELIVERY_SENDING; + let domMessage = + gMobileMessageService.createSmsMessage(-1, // id + 0, // threadId + delivery, + deliveryStatus, + sendingMessage.sender, + sendingMessage.receiver, + sendingMessage.body, + "normal", // message class + sendingMessage.timestamp, + false); + notifyResult(Cr.NS_OK, domMessage); + return; + } + let id = gMobileMessageDatabaseService.saveSendingMessage( - sendingMessage, - function notifyResult(rv, domMessage) { - - // TODO bug 832140 handle !Components.isSuccessCode(rv) - Services.obs.notifyObservers(domMessage, kSmsSendingObserverTopic, null); - - // If the radio is disabled or the SIM card is not ready, just directly - // return with the corresponding error code. - let errorCode; - if (!PhoneNumberUtils.isPlainPhoneNumber(options.number)) { - if (DEBUG) this.debug("Error! Address is invalid when sending SMS: " + - options.number); - errorCode = Ci.nsIMobileMessageCallback.INVALID_ADDRESS_ERROR; - } else if (!this._radioEnabled) { - if (DEBUG) this.debug("Error! Radio is disabled when sending SMS."); - errorCode = Ci.nsIMobileMessageCallback.RADIO_DISABLED_ERROR; - } else if (this.rilContext.cardState != "ready") { - if (DEBUG) this.debug("Error! SIM card is not ready when sending SMS."); - errorCode = Ci.nsIMobileMessageCallback.NO_SIM_CARD_ERROR; - } - if (errorCode) { - gMobileMessageDatabaseService - .setMessageDelivery(domMessage.id, - null, - DOM_MOBILE_MESSAGE_DELIVERY_ERROR, - RIL.GECKO_SMS_DELIVERY_STATUS_ERROR, - function notifyResult(rv, domMessage) { - // TODO bug 832140 handle !Components.isSuccessCode(rv) - request.notifySendMessageFailed(errorCode); - Services.obs.notifyObservers(domMessage, kSmsFailedObserverTopic, null); - }); - return; - } - - // Keep current SMS message info for sent/delivered notifications - options.envelopeId = this.createSmsEnvelope({ - request: request, - sms: domMessage, - requestStatusReport: options.requestStatusReport - }); - - // This is the entry point starting to send SMS. - this.worker.postMessage(options); - - }.bind(this)); + sendingMessage, notifyResult); }, registerDataCallCallback: function registerDataCallCallback(callback) { if (this._datacall_callbacks) { if (this._datacall_callbacks.indexOf(callback) != -1) { throw new Error("Already registered this callback!"); } } else {
--- a/dom/system/gonk/nsIRadioInterfaceLayer.idl +++ b/dom/system/gonk/nsIRadioInterfaceLayer.idl @@ -74,17 +74,17 @@ interface nsIRilContext : nsISupports readonly attribute nsIDOMMozIccInfo iccInfo; readonly attribute nsIDOMMozMobileConnectionInfo voice; readonly attribute nsIDOMMozMobileConnectionInfo data; }; -[scriptable, uuid(6dde3eaf-243d-4afa-abdb-95c94c2b1c7a)] +[scriptable, uuid(715c972b-97c5-48fd-a8b1-d50e6852153a)] interface nsIRadioInterface : nsISupports { /** * Activates or deactivates radio power. */ void setRadioEnabled(in bool value); readonly attribute nsIRilContext rilContext; @@ -114,16 +114,17 @@ interface nsIRadioInterface : nsISupport /** * SMS-related functionality. */ nsIDOMMozSmsSegmentInfo getSegmentInfoForText(in DOMString text); void sendSMS(in DOMString number, in DOMString message, + in boolean silent, in nsIMobileMessageCallback request); }; [scriptable, uuid(44b03951-1444-4c03-bd37-0bcb3a01b56f)] interface nsIRadioInterfaceLayer : nsISupports { readonly attribute unsigned long numRadioInterfaces;
--- a/dom/system/gonk/nsVolume.cpp +++ b/dom/system/gonk/nsVolume.cpp @@ -149,19 +149,19 @@ NS_IMETHODIMP nsVolume::GetIsFake(bool * *aIsFake = mIsFake; return NS_OK; } void nsVolume::LogState() const { if (mState == nsIVolume::STATE_MOUNTED) { - LOG("nsVolume: %s state %s @ '%s' gen %d locked %d", + LOG("nsVolume: %s state %s @ '%s' gen %d locked %d fake %d", NameStr().get(), StateStr(), MountPointStr().get(), - MountGeneration(), (int)IsMountLocked()); + MountGeneration(), (int)IsMountLocked(), (int)IsFake()); return; } LOG("nsVolume: %s state %s", NameStr().get(), StateStr()); } void nsVolume::Set(nsIVolume* aVolume) {
--- a/dom/system/gonk/nsVolumeService.cpp +++ b/dom/system/gonk/nsVolumeService.cpp @@ -372,16 +372,17 @@ nsVolumeService::UpdateVolume(nsIVolume* } NS_IMETHODIMP nsVolumeService::CreateFakeVolume(const nsAString& name, const nsAString& path) { if (XRE_GetProcessType() == GeckoProcessType_Default) { nsRefPtr<nsVolume> vol = new nsVolume(name, path, nsIVolume::STATE_INIT, -1); vol->SetIsFake(true); + vol->LogState(); UpdateVolume(vol.get()); return NS_OK; } ContentChild::GetSingleton()->SendCreateFakeVolume(nsString(name), nsString(path)); return NS_OK; } @@ -393,16 +394,17 @@ nsVolumeService::SetFakeVolumeState(cons { MonitorAutoLock autoLock(mArrayMonitor); vol = FindVolumeByName(name); } if (!vol || !vol->IsFake()) { return NS_ERROR_NOT_AVAILABLE; } vol->SetState(state); + vol->LogState(); UpdateVolume(vol.get()); return NS_OK; } ContentChild::GetSingleton()->SendSetFakeVolumeState(nsString(name), state); return NS_OK; }