Merge birch to m-c.

This commit is contained in:
Ryan VanderMeulen 2013-07-30 09:01:43 -04:00
commit c359eea4e4
28 changed files with 661 additions and 180 deletions

View File

@ -9,10 +9,13 @@
"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",
@ -23,23 +26,82 @@ XPCOMUtils.defineLazyServiceGetter(this, "uuidgen",
"nsIUUIDGenerator");
#ifdef MOZ_B2G_RIL
XPCOMUtils.defineLazyServiceGetter(this, "mobileConnection",
XPCOMUtils.defineLazyServiceGetter(this, "iccProvider",
"@mozilla.org/ril/content-helper;1",
"nsIMobileConnectionProvider");
#endif
"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
@ -47,8 +109,7 @@ let PaymentProvider = {
// 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;
}
@ -56,7 +117,7 @@ let PaymentProvider = {
let detail = {
type: kClosePaymentFlowEvent,
id: id,
requestId: _requestId
requestId: gRequestId
};
// In order to avoid race conditions, we wait for the UI to notify that
@ -77,49 +138,176 @@ let PaymentProvider = {
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 });
});
},
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
// 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() {
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

View File

@ -1,4 +1,4 @@
{
"revision": "74877b52dcb397d6de83b682ac5d374cc6d508be",
"revision": "10f16f6a15f8a1c4b910548b4d0968baaac21c91",
"repo_path": "/integration/gaia-central"
}

View File

@ -205,7 +205,6 @@ BluetoothA2dpManager::HandleSinkPropertyChanged(const BluetoothSignal& aSignal)
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);
@ -259,6 +258,7 @@ BluetoothA2dpManager::NotifyStatusChanged()
{
MOZ_ASSERT(NS_IsMainThread());
// Broadcast system message to Gaia
NS_NAMED_LITERAL_STRING(type, BLUETOOTH_A2DP_STATUS_CHANGED_ID);
InfallibleTArray<BluetoothNamedValue> parameters;
@ -272,25 +272,16 @@ BluetoothA2dpManager::NotifyStatusChanged()
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!");
}
}

View File

@ -73,13 +73,11 @@ private:
void HandleShutdown();
void NotifyStatusChanged();
void NotifyAudioManager();
nsString mDeviceAddress;
// A2DP data member
bool mA2dpConnected;
bool mPlaying;
nsString mDeviceAddress;
SinkState mSinkState;
// AVRCP data member

View File

@ -55,6 +55,7 @@ extern bool gBluetoothDebugFlag;
* 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"

View File

@ -454,17 +454,18 @@ BluetoothHfpManager::Get()
}
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");
@ -478,7 +479,15 @@ BluetoothHfpManager::NotifyStatusChanged(const nsAString& aType)
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!");
}
}
@ -496,26 +505,6 @@ BluetoothHfpManager::NotifyDialer(const nsAString& aCommand)
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!");
}
}
@ -1493,7 +1482,7 @@ BluetoothHfpManager::OnConnectSuccess(BluetoothSocket* aSocket)
// 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();
@ -1548,7 +1537,7 @@ BluetoothHfpManager::OnDisconnect(BluetoothSocket* aSocket)
DisconnectSco();
Listen();
NotifyStatusChanged(NS_LITERAL_STRING("bluetooth-hfp-status-changed"));
NotifyStatusChanged(BLUETOOTH_HFP_STATUS_CHANGED_ID);
Reset();
}
@ -1628,8 +1617,7 @@ BluetoothHfpManager::OnScoConnectSuccess()
mScoRunnable = nullptr;
}
NotifyAudioManager(true);
NotifyStatusChanged(NS_LITERAL_STRING("bluetooth-sco-status-changed"));
NotifyStatusChanged(BLUETOOTH_SCO_STATUS_CHANGED_ID);
mScoSocketStatus = mScoSocket->GetConnectionStatus();
}
@ -1652,8 +1640,7 @@ BluetoothHfpManager::OnScoDisconnect()
{
if (mScoSocketStatus == SocketConnectionStatus::SOCKET_CONNECTED) {
ListenSco();
NotifyAudioManager(false);
NotifyStatusChanged(NS_LITERAL_STRING("bluetooth-sco-status-changed"));
NotifyStatusChanged(BLUETOOTH_SCO_STATUS_CHANGED_ID);
}
}

View File

@ -118,8 +118,7 @@ private:
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);

View File

@ -13,7 +13,7 @@ dictionary SmsThreadListItem
unsigned long long unreadCount;
};
[scriptable, builtinclass, uuid(a22d9aae-ee0a-11e2-949e-e770d0d3883f)]
[scriptable, uuid(ea5fb581-bee7-40a6-b2dc-c98b99a2dc49)]
interface nsIMobileMessageCallback : nsISupports
{
/**

View File

@ -13,7 +13,7 @@ interface nsIMobileMessageCallback;
#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();
@ -22,5 +22,10 @@ interface nsISmsService : nsISupports
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);
};

View File

@ -14,6 +14,7 @@ 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

View File

@ -18,11 +18,7 @@ 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")

View File

@ -124,7 +124,8 @@ MobileMessageManager::Send(JSContext* aCx, JS::Handle<JSObject*> aGlobal,
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);

View File

@ -40,7 +40,9 @@ SmsService::GetSegmentInfoForText(const nsAString & aText,
}
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()) {
@ -51,6 +53,28 @@ SmsService::Send(const nsAString& aNumber, const nsAString& aMessage,
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

View File

@ -32,10 +32,33 @@ SmsService::GetSegmentInfoForText(const nsAString & aText,
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

View File

@ -42,11 +42,42 @@ SmsService::GetSegmentInfoForText(const nsAString & aText,
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

View File

@ -8,6 +8,8 @@
#include "nsISmsService.h"
#include "nsCOMPtr.h"
#include "nsIRadioInterfaceLayer.h"
#include "nsTArray.h"
#include "nsString.h"
namespace mozilla {
namespace dom {
@ -23,6 +25,7 @@ public:
protected:
// TODO: Bug 854326 - B2G Multi-SIM: support multiple SIM cards for SMS/MMS
nsCOMPtr<nsIRadioInterface> mRadioInterface;
nsTArray<nsString> mSilentNumbers;
};
} // namespace mobilemessage

View File

@ -26,6 +26,7 @@ struct SendSmsMessageRequest
{
nsString number;
nsString message;
bool silent;
};
union SendMessageRequest
@ -100,6 +101,8 @@ child:
NotifyDeliveryErrorMessage(MobileMessageData aMessageData);
NotifyReceivedSilentMessage(MobileMessageData aMessageData);
parent:
/**
* Sent when the child no longer needs to use sms.
@ -121,6 +124,9 @@ parent:
sync GetSegmentInfoForText(nsString aText)
returns (SmsSegmentInfoData aResult);
AddSilentNumber(nsString aNumber);
RemoveSilentNumber(nsString aNumber);
};
} // namespace mobilemessage

View File

@ -109,6 +109,13 @@ SmsChild::RecvNotifyDeliveryErrorMessage(const MobileMessageData& aData)
return true;
}
bool
SmsChild::RecvNotifyReceivedSilentMessage(const MobileMessageData& aData)
{
NotifyObserversWithMobileMessage(kSilentSmsReceivedObserverTopic, aData);
return true;
}
PSmsRequestChild*
SmsChild::AllocPSmsRequestChild(const IPCSmsRequest& aRequest)
{

View File

@ -55,6 +55,9 @@ protected:
virtual bool
RecvNotifyDeliveryErrorMessage(const MobileMessageData& aMessage) MOZ_OVERRIDE;
virtual bool
RecvNotifyReceivedSilentMessage(const MobileMessageData& aMessage) MOZ_OVERRIDE;
virtual PSmsRequestChild*
AllocPSmsRequestChild(const IPCSmsRequest& aRequest) MOZ_OVERRIDE;

View File

@ -115,13 +115,43 @@ SmsIPCService::GetSegmentInfoForText(const nsAString & aText,
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.
*/

View File

@ -151,6 +151,7 @@ SmsParent::SmsParent()
obs->AddObserver(this, kSmsFailedObserverTopic, false);
obs->AddObserver(this, kSmsDeliverySuccessObserverTopic, false);
obs->AddObserver(this, kSmsDeliveryErrorObserverTopic, false);
obs->AddObserver(this, kSilentSmsReceivedObserverTopic, false);
}
void
@ -168,6 +169,7 @@ SmsParent::ActorDestroy(ActorDestroyReason why)
obs->RemoveObserver(this, kSmsFailedObserverTopic);
obs->RemoveObserver(this, kSmsDeliverySuccessObserverTopic);
obs->RemoveObserver(this, kSmsDeliveryErrorObserverTopic);
obs->RemoveObserver(this, kSilentSmsReceivedObserverTopic);
}
NS_IMETHODIMP
@ -251,6 +253,24 @@ SmsParent::Observe(nsISupports* aSubject, const char* aTopic,
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;
}
@ -320,6 +340,42 @@ SmsParent::RecvGetSegmentInfoForText(const nsString& aText,
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)
@ -422,7 +478,7 @@ SmsRequestParent::DoRequest(const SendMessageRequest& aRequest)
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: {

View File

@ -37,6 +37,12 @@ protected:
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()
{
@ -68,6 +74,9 @@ protected:
bool
GetMobileMessageDataFromMessage(nsISupports* aMsg, MobileMessageData& aData);
private:
nsTArray<nsString> mSilentNumbers;
};
class SmsRequestParent : public PSmsRequestParent

View File

@ -27,6 +27,7 @@
#include "BluetoothCommon.h"
#include "BluetoothProfileManagerBase.h"
#include "BluetoothHfpManager.h"
#include "nsJSUtils.h"
#include "nsCxPusher.h"
@ -168,58 +169,78 @@ InternalSetAudioRoutes(SwitchState aState)
}
}
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;
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);
}
}
HandleBluetoothStatusChanged(aSubject, aTopic, address);
return NS_OK;
}
// To process the volume control on each audio channel according to
// change of settings
else if (!strcmp(aTopic, "mozsettings-changed")) {
@ -315,6 +336,9 @@ AudioManager::AudioManager() : mPhoneState(PHONE_STATE_CURRENT),
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,
@ -342,6 +366,9 @@ AudioManager::~AudioManager() {
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
@ -375,7 +402,12 @@ 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

View File

@ -64,6 +64,10 @@ protected:
private:
nsAutoPtr<mozilla::hal::SwitchObserver> mObserver;
nsCOMPtr<AudioChannelAgent> mPhoneAudioAgent;
void HandleBluetoothStatusChanged(nsISupports* aSubject,
const char* aTopic,
const nsCString aAddress);
};
} /* namespace gonk */

View File

@ -51,6 +51,7 @@ 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";
@ -145,6 +146,10 @@ 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");
@ -1888,6 +1893,31 @@ RadioInterface.prototype = {
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.
@ -1977,6 +2007,25 @@ RadioInterface.prototype = {
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,
@ -2006,6 +2055,10 @@ RadioInterface.prototype = {
}
delete this._sentSmsEnvelopes[message.envelopeId];
if (options.silent) {
return;
}
gMobileMessageDatabaseService.setMessageDelivery(options.sms.id,
null,
options.sms.delivery,
@ -2035,6 +2088,11 @@ RadioInterface.prototype = {
break;
}
if (options.silent) {
options.request.notifySendMessageFailed(error);
return;
}
gMobileMessageDatabaseService.setMessageDelivery(options.sms.id,
null,
DOM_MOBILE_MESSAGE_DELIVERY_ERROR,
@ -3145,7 +3203,7 @@ RadioInterface.prototype = {
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");
@ -3169,6 +3227,57 @@ RadioInterface.prototype = {
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(),
@ -3178,52 +3287,26 @@ RadioInterface.prototype = {
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) {

View File

@ -79,7 +79,7 @@ interface nsIRilContext : nsISupports
readonly attribute nsIDOMMozMobileConnectionInfo data;
};
[scriptable, uuid(6dde3eaf-243d-4afa-abdb-95c94c2b1c7a)]
[scriptable, uuid(715c972b-97c5-48fd-a8b1-d50e6852153a)]
interface nsIRadioInterface : nsISupports
{
/**
@ -119,6 +119,7 @@ interface nsIRadioInterface : nsISupports
void sendSMS(in DOMString number,
in DOMString message,
in boolean silent,
in nsIMobileMessageCallback request);
};

View File

@ -154,9 +154,9 @@ 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;
}

View File

@ -377,6 +377,7 @@ 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;
}
@ -398,6 +399,7 @@ nsVolumeService::SetFakeVolumeState(const nsAString& name, int32_t state)
return NS_ERROR_NOT_AVAILABLE;
}
vol->SetState(state);
vol->LogState();
UpdateVolume(vol.get());
return NS_OK;
}