зеркало из https://github.com/mozilla/gecko-dev.git
Bug 873351 - B2G SMS: move SMS code out of RadioInterfaceLayer to SmsService. r=gene
This commit is contained in:
Родитель
bee1a6fcff
Коммит
dd5f4ce90a
|
@ -460,6 +460,8 @@
|
|||
@BINPATH@/components/RadioInterfaceLayer.js
|
||||
@BINPATH@/components/MmsService.manifest
|
||||
@BINPATH@/components/MmsService.js
|
||||
@BINPATH@/components/SmsService.manifest
|
||||
@BINPATH@/components/SmsService.js
|
||||
@BINPATH@/components/RILContentHelper.js
|
||||
@BINPATH@/components/MobileMessageDatabaseService.manifest
|
||||
@BINPATH@/components/MobileMessageDatabaseService.js
|
||||
|
|
|
@ -446,6 +446,8 @@
|
|||
@BINPATH@/components/RadioInterfaceLayer.js
|
||||
@BINPATH@/components/MmsService.manifest
|
||||
@BINPATH@/components/MmsService.js
|
||||
@BINPATH@/components/SmsService.manifest
|
||||
@BINPATH@/components/SmsService.js
|
||||
@BINPATH@/components/RILContentHelper.js
|
||||
@BINPATH@/components/MobileMessageDatabaseService.manifest
|
||||
@BINPATH@/components/MobileMessageDatabaseService.js
|
||||
|
|
|
@ -25,6 +25,7 @@ XPIDL_SOURCES += [
|
|||
if CONFIG['MOZ_B2G_RIL']:
|
||||
XPIDL_SOURCES += [
|
||||
'nsIRilMobileMessageDatabaseService.idl',
|
||||
'nsIRilSmsService.idl',
|
||||
]
|
||||
|
||||
XPIDL_MODULE = 'dom_mobilemessage'
|
||||
|
|
|
@ -0,0 +1,11 @@
|
|||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||
* You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "nsISmsService.idl"
|
||||
|
||||
[scriptable, uuid(f216903c-bdf5-4988-b894-f62fd91df114)]
|
||||
interface nsIRilSmsService : nsISmsService
|
||||
{
|
||||
void notifyMessageReceived(in jsval message);
|
||||
};
|
|
@ -13,7 +13,7 @@ interface nsIMobileMessageCallback;
|
|||
#define SMS_SERVICE_CONTRACTID "@mozilla.org/sms/smsservice;1"
|
||||
%}
|
||||
|
||||
[scriptable, builtinclass, uuid(f0d5d11b-0326-4cb1-bb76-a3f912212287)]
|
||||
[scriptable, uuid(7ef8e361-9db6-46ed-badc-2901e1049e5d)]
|
||||
interface nsISmsService : nsISupports
|
||||
{
|
||||
boolean hasSupport();
|
||||
|
@ -25,7 +25,6 @@ interface nsISmsService : nsISupports
|
|||
in boolean silent,
|
||||
in nsIMobileMessageCallback request);
|
||||
|
||||
boolean isSilentNumber(in DOMString number);
|
||||
void addSilentNumber(in DOMString number);
|
||||
void removeSilentNumber(in DOMString number);
|
||||
};
|
||||
|
|
|
@ -31,11 +31,5 @@ LOCAL_INCLUDES = \
|
|||
# subdirectory (and the ipc one).
|
||||
LOCAL_INCLUDES += $(VPATH:%=-I%)
|
||||
|
||||
ifdef MOZ_B2G_RIL
|
||||
LOCAL_INCLUDES += \
|
||||
-I$(topsrcdir)/dom/system/gonk \
|
||||
$(NULL)
|
||||
endif
|
||||
|
||||
include $(topsrcdir)/config/rules.mk
|
||||
include $(topsrcdir)/ipc/chromium/chromium-config.mk
|
||||
|
|
|
@ -5,16 +5,18 @@
|
|||
|
||||
#include "SmsServicesFactory.h"
|
||||
#include "nsXULAppAPI.h"
|
||||
#include "SmsService.h"
|
||||
#include "SmsIPCService.h"
|
||||
#ifndef MOZ_B2G_RIL
|
||||
#include "MobileMessageDatabaseService.h"
|
||||
#include "MmsService.h"
|
||||
#include "SmsService.h"
|
||||
#endif
|
||||
#include "nsServiceManagerUtils.h"
|
||||
|
||||
#define RIL_MMSSERVICE_CONTRACTID "@mozilla.org/mms/rilmmsservice;1"
|
||||
#define RIL_MOBILE_MESSAGE_DATABASE_SERVICE_CONTRACTID "@mozilla.org/mobilemessage/rilmobilemessagedatabaseservice;1"
|
||||
#define RIL_MOBILE_MESSAGE_DATABASE_SERVICE_CONTRACTID \
|
||||
"@mozilla.org/mobilemessage/rilmobilemessagedatabaseservice;1"
|
||||
#define RIL_SMSSERVICE_CONTRACTID "@mozilla.org/sms/rilsmsservice;1"
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
@ -28,7 +30,11 @@ SmsServicesFactory::CreateSmsService()
|
|||
if (XRE_GetProcessType() == GeckoProcessType_Content) {
|
||||
smsService = new SmsIPCService();
|
||||
} else {
|
||||
#ifdef MOZ_B2G_RIL
|
||||
smsService = do_GetService(RIL_SMSSERVICE_CONTRACTID);
|
||||
#else
|
||||
smsService = new SmsService();
|
||||
#endif
|
||||
}
|
||||
|
||||
return smsService.forget();
|
||||
|
@ -42,7 +48,8 @@ SmsServicesFactory::CreateMobileMessageDatabaseService()
|
|||
mobileMessageDBService = new SmsIPCService();
|
||||
} else {
|
||||
#ifdef MOZ_B2G_RIL
|
||||
mobileMessageDBService = do_GetService(RIL_MOBILE_MESSAGE_DATABASE_SERVICE_CONTRACTID);
|
||||
mobileMessageDBService =
|
||||
do_GetService(RIL_MOBILE_MESSAGE_DATABASE_SERVICE_CONTRACTID);
|
||||
#else
|
||||
mobileMessageDBService = new MobileMessageDatabaseService();
|
||||
#endif
|
||||
|
|
|
@ -53,14 +53,6 @@ SmsService::Send(const nsAString& aNumber,
|
|||
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)
|
||||
{
|
||||
|
|
|
@ -39,14 +39,6 @@ SmsService::Send(const nsAString& aNumber,
|
|||
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)
|
||||
{
|
||||
|
|
|
@ -1,85 +0,0 @@
|
|||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||
* You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "SmsMessage.h"
|
||||
#include "SmsService.h"
|
||||
#include "jsapi.h"
|
||||
#include "SmsSegmentInfo.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
namespace mobilemessage {
|
||||
|
||||
NS_IMPL_ISUPPORTS1(SmsService, nsISmsService)
|
||||
|
||||
SmsService::SmsService()
|
||||
{
|
||||
nsCOMPtr<nsIRadioInterfaceLayer> ril = do_GetService("@mozilla.org/ril;1");
|
||||
if (ril) {
|
||||
ril->GetRadioInterface(0, getter_AddRefs(mRadioInterface));
|
||||
}
|
||||
NS_WARN_IF_FALSE(mRadioInterface, "This shouldn't fail!");
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
SmsService::HasSupport(bool* aHasSupport)
|
||||
{
|
||||
*aHasSupport = true;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
SmsService::GetSegmentInfoForText(const nsAString & aText,
|
||||
nsIDOMMozSmsSegmentInfo** aResult)
|
||||
{
|
||||
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, 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
|
|
@ -1,35 +0,0 @@
|
|||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#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
|
|
@ -0,0 +1,994 @@
|
|||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
|
||||
* vim: sw=2 ts=2 sts=2 et filetype=javascript
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||
* You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
"use strict";
|
||||
|
||||
const {classes: Cc, interfaces: Ci, utils: Cu, results: Cr} = Components;
|
||||
|
||||
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||
Cu.import("resource://gre/modules/Services.jsm");
|
||||
|
||||
var RIL = {};
|
||||
Cu.import("resource://gre/modules/ril_consts.js", RIL);
|
||||
|
||||
const RIL_SMSSERVICE_CONTRACTID = "@mozilla.org/sms/rilsmsservice;1";
|
||||
const RIL_SMSSERVICE_CID =
|
||||
Components.ID("{46a9ed78-3574-40a1-9f12-ea179942d67f}");
|
||||
|
||||
const DELIVERY_STATE_RECEIVED = "received";
|
||||
const DELIVERY_STATE_SENDING = "sending";
|
||||
const DELIVERY_STATE_SENT = "sent";
|
||||
const DELIVERY_STATE_ERROR = "error";
|
||||
|
||||
// Observer topics to send.
|
||||
const kSmsReceivedObserverTopic = "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 kSilentSmsReceivedObserverTopic = "silent-sms-received";
|
||||
|
||||
// Observer topics to watch.
|
||||
const kPrefenceChangedObserverTopic = "nsPref:changed";
|
||||
const kXpcomShutdownObserverTopic = "xpcom-shutdown";
|
||||
|
||||
// Preference keys.
|
||||
const kPrefKeyRilDebuggingEnabled = "ril.debugging.enabled";
|
||||
|
||||
XPCOMUtils.defineLazyServiceGetter(this, "gMobileMessageDatabaseService",
|
||||
"@mozilla.org/mobilemessage/rilmobilemessagedatabaseservice;1",
|
||||
"nsIRilMobileMessageDatabaseService");
|
||||
|
||||
XPCOMUtils.defineLazyServiceGetter(this, "gMobileMessageService",
|
||||
"@mozilla.org/mobilemessage/mobilemessageservice;1",
|
||||
"nsIMobileMessageService");
|
||||
|
||||
XPCOMUtils.defineLazyServiceGetter(this, "gSystemMessenger",
|
||||
"@mozilla.org/system-message-internal;1",
|
||||
"nsISystemMessagesInternal");
|
||||
|
||||
XPCOMUtils.defineLazyGetter(this, "gRadioInterface", function () {
|
||||
let ril = Cc["@mozilla.org/ril;1"].getService(Ci["nsIRadioInterfaceLayer"]);
|
||||
// TODO: Bug 854326 - B2G Multi-SIM: support multiple SIM cards for SMS/MMS
|
||||
return ril.getRadioInterface(0);
|
||||
});
|
||||
|
||||
XPCOMUtils.defineLazyGetter(this, "gPhoneNumberUtils", function () {
|
||||
let ns = {};
|
||||
Cu.import("resource://gre/modules/PhoneNumberUtils.jsm", ns);
|
||||
return ns.PhoneNumberUtils;
|
||||
});
|
||||
|
||||
XPCOMUtils.defineLazyGetter(this, "WAP", function () {
|
||||
let WAP = {};
|
||||
Cu.import("resource://gre/modules/WapPushManager.js", WAP);
|
||||
return WAP;
|
||||
});
|
||||
|
||||
XPCOMUtils.defineLazyGetter(this, "gMessageManager", function () {
|
||||
let ns = {};
|
||||
Cu.import("resource://gre/modules/RilMessageManager.jsm", ns);
|
||||
return ns.RilMessageManager;
|
||||
});
|
||||
|
||||
let DEBUG;
|
||||
function debug(s) {
|
||||
dump("SmsService: " + s + "\n");
|
||||
}
|
||||
|
||||
/**
|
||||
* SmsService
|
||||
*/
|
||||
function SmsService() {
|
||||
// Update |DEBUG|.
|
||||
this.observe(null, kPrefenceChangedObserverTopic,
|
||||
kPrefKeyRilDebuggingEnabled);
|
||||
|
||||
this.silentNumbers = [];
|
||||
|
||||
this.portAddressedSmsApps = {};
|
||||
this.portAddressedSmsApps[WAP.WDP_PORT_PUSH] =
|
||||
this._handleSmsWdpPortPush.bind(this);
|
||||
|
||||
Services.obs.addObserver(this, kPrefenceChangedObserverTopic, false);
|
||||
Services.obs.addObserver(this, kXpcomShutdownObserverTopic, false);
|
||||
}
|
||||
SmsService.prototype = {
|
||||
|
||||
classID: RIL_SMSSERVICE_CID,
|
||||
classInfo: XPCOMUtils.generateCI({classID: RIL_SMSSERVICE_CID,
|
||||
contractID: RIL_SMSSERVICE_CONTRACTID,
|
||||
classDescription: "SmsService",
|
||||
interfaces: [Ci.nsIRilSmsService,
|
||||
Ci.nsISmsService],
|
||||
flags: Ci.nsIClassInfo.SINGLETON}),
|
||||
QueryInterface: XPCOMUtils.generateQI([Ci.nsIObserver,
|
||||
Ci.nsIRilSmsService,
|
||||
Ci.nsISmsService]),
|
||||
|
||||
/**
|
||||
* List of tuples of national language identifier pairs.
|
||||
*
|
||||
* TODO: Support static/runtime settings, see bug 733331.
|
||||
*/
|
||||
enabledGsmTableTuples: [
|
||||
[RIL.PDU_NL_IDENTIFIER_DEFAULT, RIL.PDU_NL_IDENTIFIER_DEFAULT],
|
||||
],
|
||||
|
||||
/**
|
||||
* Use 16-bit reference number for concatenated outgoint messages.
|
||||
*
|
||||
* TODO: Support static/runtime settings, see bug 733331.
|
||||
*/
|
||||
segmentRef16Bit: false,
|
||||
|
||||
/**
|
||||
* Get valid SMS concatenation reference number.
|
||||
*/
|
||||
segmentRef: 0,
|
||||
get nextSegmentRef() {
|
||||
let ref = this.segmentRef++;
|
||||
|
||||
this.segmentRef %= (this.segmentRef16Bit ? 65535 : 255);
|
||||
|
||||
// 0 is not a valid SMS concatenation reference number.
|
||||
return ref + 1;
|
||||
},
|
||||
|
||||
statusReportPendingMessageIds: null,
|
||||
|
||||
portAddressedSmsApps: null,
|
||||
|
||||
silentNumbers: null,
|
||||
|
||||
_getStrict7BitEncoding: function _getStrict7BitEncoding() {
|
||||
try {
|
||||
return Services.prefs.getBoolPref("dom.sms.strict7BitEncoding");
|
||||
} catch (e) {
|
||||
return false;
|
||||
}
|
||||
},
|
||||
|
||||
_getRequestStatusReport: function _getRequestStatusReport() {
|
||||
try {
|
||||
return Services.prefs.getBoolPref("dom.sms.requestStatusReport");
|
||||
} catch (e) {
|
||||
return true;
|
||||
}
|
||||
},
|
||||
|
||||
_getMsisdn: function _getMsisdn() {
|
||||
let iccInfo = gRadioInterface.rilContext.iccInfo;
|
||||
let number = iccInfo ? iccInfo.msisdn : null;
|
||||
|
||||
// Workaround an xpconnect issue with undefined string objects.
|
||||
// See bug 808220
|
||||
if (number === undefined || number === "undefined") {
|
||||
return null;
|
||||
}
|
||||
return number;
|
||||
},
|
||||
|
||||
/**
|
||||
* Calculate encoded length using specified locking/single shift table
|
||||
*
|
||||
* @param message
|
||||
* message string to be encoded.
|
||||
* @param langTable
|
||||
* locking shift table string.
|
||||
* @param langShiftTable
|
||||
* single shift table string.
|
||||
* @param strict7BitEncoding
|
||||
* Optional. Enable Latin characters replacement with corresponding
|
||||
* ones in GSM SMS 7-bit default alphabet.
|
||||
*
|
||||
* @return encoded length in septets.
|
||||
*
|
||||
* @note that the algorithm used in this function must match exactly with
|
||||
* GsmPDUHelper#writeStringAsSeptets.
|
||||
*/
|
||||
_countGsm7BitSeptets: function _countGsm7BitSeptets(message,
|
||||
langTable,
|
||||
langShiftTable,
|
||||
strict7BitEncoding) {
|
||||
let length = 0;
|
||||
for (let msgIndex = 0; msgIndex < message.length; msgIndex++) {
|
||||
let c = message.charAt(msgIndex);
|
||||
if (strict7BitEncoding) {
|
||||
c = RIL.GSM_SMS_STRICT_7BIT_CHARMAP[c] || c;
|
||||
}
|
||||
|
||||
let septet = langTable.indexOf(c);
|
||||
|
||||
// According to 3GPP TS 23.038, section 6.1.1 General notes, "The
|
||||
// characters marked '1)' are not used but are displayed as a space."
|
||||
if (septet == RIL.PDU_NL_EXTENDED_ESCAPE) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (septet >= 0) {
|
||||
length++;
|
||||
continue;
|
||||
}
|
||||
|
||||
septet = langShiftTable.indexOf(c);
|
||||
if (septet < 0) {
|
||||
if (!strict7BitEncoding) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Bug 816082, when strict7BitEncoding is enabled, we should replace
|
||||
// characters that can't be encoded with GSM 7-Bit alphabets with '*'.
|
||||
c = '*';
|
||||
if (langTable.indexOf(c) >= 0) {
|
||||
length++;
|
||||
} else if (langShiftTable.indexOf(c) >= 0) {
|
||||
length += 2;
|
||||
} else {
|
||||
// We can't even encode a '*' character with current configuration.
|
||||
return -1;
|
||||
}
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
// According to 3GPP TS 23.038 B.2, "This code represents a control
|
||||
// character and therefore must not be used for language specific
|
||||
// characters."
|
||||
if (septet == RIL.PDU_NL_RESERVED_CONTROL) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// The character is not found in locking shfit table, but could be
|
||||
// encoded as <escape><char> with single shift table. Note that it's
|
||||
// still possible for septet to has the value of PDU_NL_EXTENDED_ESCAPE,
|
||||
// but we can display it as a space in this case as said in previous
|
||||
// comment.
|
||||
length += 2;
|
||||
}
|
||||
|
||||
return length;
|
||||
},
|
||||
|
||||
/**
|
||||
* Calculate user data length of specified message string encoded in GSM 7Bit
|
||||
* alphabets.
|
||||
*
|
||||
* @param message
|
||||
* a message string to be encoded.
|
||||
* @param strict7BitEncoding
|
||||
* Optional. Enable Latin characters replacement with corresponding
|
||||
* ones in GSM SMS 7-bit default alphabet.
|
||||
*
|
||||
* @return null or an options object with attributes `dcs`,
|
||||
* `userDataHeaderLength`, `encodedFullBodyLength`, `langIndex`,
|
||||
* `langShiftIndex`, `segmentMaxSeq` set.
|
||||
*
|
||||
* @see #_calculateUserDataLength().
|
||||
*/
|
||||
_calculateUserDataLength7Bit: function _calculateUserDataLength7Bit(message,
|
||||
strict7BitEncoding) {
|
||||
let options = null;
|
||||
let minUserDataSeptets = Number.MAX_VALUE;
|
||||
for (let i = 0; i < this.enabledGsmTableTuples.length; i++) {
|
||||
let [langIndex, langShiftIndex] = this.enabledGsmTableTuples[i];
|
||||
|
||||
const langTable = RIL.PDU_NL_LOCKING_SHIFT_TABLES[langIndex];
|
||||
const langShiftTable = RIL.PDU_NL_SINGLE_SHIFT_TABLES[langShiftIndex];
|
||||
|
||||
let bodySeptets = this._countGsm7BitSeptets(message,
|
||||
langTable,
|
||||
langShiftTable,
|
||||
strict7BitEncoding);
|
||||
if (bodySeptets < 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
let headerLen = 0;
|
||||
if (langIndex != RIL.PDU_NL_IDENTIFIER_DEFAULT) {
|
||||
headerLen += 3; // IEI + len + langIndex
|
||||
}
|
||||
if (langShiftIndex != RIL.PDU_NL_IDENTIFIER_DEFAULT) {
|
||||
headerLen += 3; // IEI + len + langShiftIndex
|
||||
}
|
||||
|
||||
// Calculate full user data length, note the extra byte is for header len
|
||||
let headerSeptets = Math.ceil((headerLen ? headerLen + 1 : 0) * 8 / 7);
|
||||
let segmentSeptets = RIL.PDU_MAX_USER_DATA_7BIT;
|
||||
if ((bodySeptets + headerSeptets) > segmentSeptets) {
|
||||
headerLen += this.segmentRef16Bit ? 6 : 5;
|
||||
headerSeptets = Math.ceil((headerLen + 1) * 8 / 7);
|
||||
segmentSeptets -= headerSeptets;
|
||||
}
|
||||
|
||||
let segments = Math.ceil(bodySeptets / segmentSeptets);
|
||||
let userDataSeptets = bodySeptets + headerSeptets * segments;
|
||||
if (userDataSeptets >= minUserDataSeptets) {
|
||||
continue;
|
||||
}
|
||||
|
||||
minUserDataSeptets = userDataSeptets;
|
||||
|
||||
options = {
|
||||
dcs: RIL.PDU_DCS_MSG_CODING_7BITS_ALPHABET,
|
||||
encodedFullBodyLength: bodySeptets,
|
||||
userDataHeaderLength: headerLen,
|
||||
langIndex: langIndex,
|
||||
langShiftIndex: langShiftIndex,
|
||||
segmentMaxSeq: segments,
|
||||
segmentChars: segmentSeptets,
|
||||
};
|
||||
}
|
||||
|
||||
return options;
|
||||
},
|
||||
|
||||
/**
|
||||
* Calculate user data length of specified message string encoded in UCS2.
|
||||
*
|
||||
* @param message
|
||||
* a message string to be encoded.
|
||||
*
|
||||
* @return an options object with attributes `dcs`, `userDataHeaderLength`,
|
||||
* `encodedFullBodyLength`, `segmentMaxSeq` set.
|
||||
*
|
||||
* @see #_calculateUserDataLength().
|
||||
*/
|
||||
_calculateUserDataLengthUCS2: function _calculateUserDataLengthUCS2(message) {
|
||||
let bodyChars = message.length;
|
||||
let headerLen = 0;
|
||||
let headerChars = Math.ceil((headerLen ? headerLen + 1 : 0) / 2);
|
||||
let segmentChars = RIL.PDU_MAX_USER_DATA_UCS2;
|
||||
if ((bodyChars + headerChars) > segmentChars) {
|
||||
headerLen += this.segmentRef16Bit ? 6 : 5;
|
||||
headerChars = Math.ceil((headerLen + 1) / 2);
|
||||
segmentChars -= headerChars;
|
||||
}
|
||||
|
||||
let segments = Math.ceil(bodyChars / segmentChars);
|
||||
|
||||
return {
|
||||
dcs: RIL.PDU_DCS_MSG_CODING_16BITS_ALPHABET,
|
||||
encodedFullBodyLength: bodyChars * 2,
|
||||
userDataHeaderLength: headerLen,
|
||||
segmentMaxSeq: segments,
|
||||
segmentChars: segmentChars,
|
||||
};
|
||||
},
|
||||
|
||||
/**
|
||||
* Calculate user data length and its encoding.
|
||||
*
|
||||
* @param message
|
||||
* a message string to be encoded.
|
||||
* @param strict7BitEncoding
|
||||
* Optional. Enable Latin characters replacement with corresponding
|
||||
* ones in GSM SMS 7-bit default alphabet.
|
||||
*
|
||||
* @return an options object with some or all of following attributes set:
|
||||
*
|
||||
* @param dcs
|
||||
* Data coding scheme. One of the PDU_DCS_MSG_CODING_*BITS_ALPHABET
|
||||
* constants.
|
||||
* @param userDataHeaderLength
|
||||
* Length of embedded user data header, in bytes. The whole header
|
||||
* size will be userDataHeaderLength + 1; 0 for no header.
|
||||
* @param encodedFullBodyLength
|
||||
* Length of the message body when encoded with the given DCS. For
|
||||
* UCS2, in bytes; for 7-bit, in septets.
|
||||
* @param langIndex
|
||||
* Table index used for normal 7-bit encoded character lookup.
|
||||
* @param langShiftIndex
|
||||
* Table index used for escaped 7-bit encoded character lookup.
|
||||
* @param segmentMaxSeq
|
||||
* Max sequence number of a multi-part messages, or 1 for single one.
|
||||
* This number might not be accurate for a multi-part message until
|
||||
* it's processed by #_fragmentText() again.
|
||||
*/
|
||||
_calculateUserDataLength: function _calculateUserDataLength(message,
|
||||
strict7BitEncoding) {
|
||||
let options = this._calculateUserDataLength7Bit(message, strict7BitEncoding);
|
||||
if (!options) {
|
||||
options = this._calculateUserDataLengthUCS2(message);
|
||||
}
|
||||
|
||||
if (DEBUG) debug("_calculateUserDataLength: " + JSON.stringify(options));
|
||||
return options;
|
||||
},
|
||||
|
||||
/**
|
||||
* Fragment GSM 7-Bit encodable string for transmission.
|
||||
*
|
||||
* @param text
|
||||
* text string to be fragmented.
|
||||
* @param langTable
|
||||
* locking shift table string.
|
||||
* @param langShiftTable
|
||||
* single shift table string.
|
||||
* @param segmentSeptets
|
||||
* Number of available spetets per segment.
|
||||
* @param strict7BitEncoding
|
||||
* Optional. Enable Latin characters replacement with corresponding
|
||||
* ones in GSM SMS 7-bit default alphabet.
|
||||
*
|
||||
* @return an array of objects. See #_fragmentText() for detailed definition.
|
||||
*/
|
||||
_fragmentText7Bit: function _fragmentText7Bit(text, langTable, langShiftTable,
|
||||
segmentSeptets,
|
||||
strict7BitEncoding) {
|
||||
let ret = [];
|
||||
let body = "", len = 0;
|
||||
for (let i = 0, inc = 0; i < text.length; i++) {
|
||||
let c = text.charAt(i);
|
||||
if (strict7BitEncoding) {
|
||||
c = RIL.GSM_SMS_STRICT_7BIT_CHARMAP[c] || c;
|
||||
}
|
||||
|
||||
let septet = langTable.indexOf(c);
|
||||
if (septet == RIL.PDU_NL_EXTENDED_ESCAPE) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (septet >= 0) {
|
||||
inc = 1;
|
||||
} else {
|
||||
septet = langShiftTable.indexOf(c);
|
||||
if (septet == RIL.PDU_NL_RESERVED_CONTROL) {
|
||||
continue;
|
||||
}
|
||||
|
||||
inc = 2;
|
||||
if (septet < 0) {
|
||||
if (!strict7BitEncoding) {
|
||||
throw new Error("Given text cannot be encoded with GSM 7-bit Alphabet!");
|
||||
}
|
||||
|
||||
// Bug 816082, when strict7BitEncoding is enabled, we should replace
|
||||
// characters that can't be encoded with GSM 7-Bit alphabets with '*'.
|
||||
c = '*';
|
||||
if (langTable.indexOf(c) >= 0) {
|
||||
inc = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ((len + inc) > segmentSeptets) {
|
||||
ret.push({
|
||||
body: body,
|
||||
encodedBodyLength: len,
|
||||
});
|
||||
body = c;
|
||||
len = inc;
|
||||
} else {
|
||||
body += c;
|
||||
len += inc;
|
||||
}
|
||||
}
|
||||
|
||||
if (len) {
|
||||
ret.push({
|
||||
body: body,
|
||||
encodedBodyLength: len,
|
||||
});
|
||||
}
|
||||
|
||||
return ret;
|
||||
},
|
||||
|
||||
/**
|
||||
* Fragment UCS2 encodable string for transmission.
|
||||
*
|
||||
* @param text
|
||||
* text string to be fragmented.
|
||||
* @param segmentChars
|
||||
* Number of available characters per segment.
|
||||
*
|
||||
* @return an array of objects. See #_fragmentText() for detailed definition.
|
||||
*/
|
||||
_fragmentTextUCS2: function _fragmentTextUCS2(text, segmentChars) {
|
||||
let ret = [];
|
||||
for (let offset = 0; offset < text.length; offset += segmentChars) {
|
||||
let str = text.substr(offset, segmentChars);
|
||||
ret.push({
|
||||
body: str,
|
||||
encodedBodyLength: str.length * 2,
|
||||
});
|
||||
}
|
||||
|
||||
return ret;
|
||||
},
|
||||
|
||||
/**
|
||||
* Fragment string for transmission.
|
||||
*
|
||||
* Fragment input text string into an array of objects that contains
|
||||
* attributes `body`, substring for this segment, `encodedBodyLength`,
|
||||
* length of the encoded segment body in septets.
|
||||
*
|
||||
* @param text
|
||||
* Text string to be fragmented.
|
||||
* @param options
|
||||
* Optional pre-calculated option object. The output array will be
|
||||
* stored at options.segments if there are multiple segments.
|
||||
* @param strict7BitEncoding
|
||||
* Optional. Enable Latin characters replacement with corresponding
|
||||
* ones in GSM SMS 7-bit default alphabet.
|
||||
*
|
||||
* @return Populated options object.
|
||||
*/
|
||||
_fragmentText: function _fragmentText(text, options, strict7BitEncoding) {
|
||||
if (!options) {
|
||||
options = this._calculateUserDataLength(text, strict7BitEncoding);
|
||||
}
|
||||
|
||||
if (options.dcs == RIL.PDU_DCS_MSG_CODING_7BITS_ALPHABET) {
|
||||
const langTable = RIL.PDU_NL_LOCKING_SHIFT_TABLES[options.langIndex];
|
||||
const langShiftTable = RIL.PDU_NL_SINGLE_SHIFT_TABLES[options.langShiftIndex];
|
||||
options.segments = this._fragmentText7Bit(text,
|
||||
langTable, langShiftTable,
|
||||
options.segmentChars,
|
||||
strict7BitEncoding);
|
||||
} else {
|
||||
options.segments = this._fragmentTextUCS2(text,
|
||||
options.segmentChars);
|
||||
}
|
||||
|
||||
// Re-sync options.segmentMaxSeq with actual length of returning array.
|
||||
options.segmentMaxSeq = options.segments.length;
|
||||
|
||||
return options;
|
||||
},
|
||||
|
||||
/**
|
||||
* A helper to broadcast the system message to launch registered apps
|
||||
* like Costcontrol, Notification and Message app... etc.
|
||||
*
|
||||
* @param aName
|
||||
* The system message name.
|
||||
* @param aDomMessage
|
||||
* The nsIDOMMozSmsMessage object.
|
||||
*/
|
||||
_broadcastSystemMessage: function _broadcastSystemMessage(aName, aDomMessage) {
|
||||
if (DEBUG) debug("Broadcasting the SMS system message: " + aName);
|
||||
|
||||
// Sadly we cannot directly broadcast the aDomMessage object
|
||||
// because the system message mechamism will rewrap the object
|
||||
// based on the content window, which needs to know the properties.
|
||||
gSystemMessenger.broadcastMessage(aName, {
|
||||
type: aDomMessage.type,
|
||||
id: aDomMessage.id,
|
||||
threadId: aDomMessage.threadId,
|
||||
delivery: aDomMessage.delivery,
|
||||
deliveryStatus: aDomMessage.deliveryStatus,
|
||||
sender: aDomMessage.sender,
|
||||
receiver: aDomMessage.receiver,
|
||||
body: aDomMessage.body,
|
||||
messageClass: aDomMessage.messageClass,
|
||||
timestamp: aDomMessage.timestamp,
|
||||
read: aDomMessage.read
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
* Handle WDP port push PDU. Constructor WDP bearer information and deliver
|
||||
* to WapPushManager.
|
||||
*
|
||||
* @param message
|
||||
* A SMS message.
|
||||
*/
|
||||
_handleSmsWdpPortPush: function _handleSmsWdpPortPush(message) {
|
||||
if (message.encoding != RIL.PDU_DCS_MSG_CODING_8BITS_ALPHABET) {
|
||||
if (DEBUG) {
|
||||
debug("Got port addressed SMS but not encoded in 8-bit alphabet." +
|
||||
" Drop!");
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
let options = {
|
||||
bearer: WAP.WDP_BEARER_GSM_SMS_GSM_MSISDN,
|
||||
sourceAddress: message.sender,
|
||||
sourcePort: message.header.originatorPort,
|
||||
destinationAddress: this.rilContext.iccInfo.msisdn,
|
||||
destinationPort: message.header.destinationPort,
|
||||
};
|
||||
WAP.WapPushManager.receiveWdpPDU(message.fullData, message.fullData.length,
|
||||
0, options);
|
||||
},
|
||||
|
||||
_isSilentNumber: function _isSilentNumber(number) {
|
||||
return this.silentNumbers.indexOf(number) >= 0;
|
||||
},
|
||||
|
||||
/**
|
||||
* nsISmsService methods.
|
||||
*/
|
||||
|
||||
// TODO: Bug 859616 - WebSMS: return undefined if the API is unsupported on
|
||||
// the platform, not null
|
||||
hasSupport: function hasSupport() {
|
||||
return true;
|
||||
},
|
||||
|
||||
getSegmentInfoForText: function getSegmentInfoForText(text) {
|
||||
let strict7BitEncoding = this._getStrict7BitEncoding();
|
||||
|
||||
let options = this._fragmentText(text, null, strict7BitEncoding);
|
||||
let charsInLastSegment;
|
||||
if (options.segmentMaxSeq) {
|
||||
let lastSegment = options.segments[options.segmentMaxSeq - 1];
|
||||
charsInLastSegment = lastSegment.encodedBodyLength;
|
||||
if (options.dcs == RIL.PDU_DCS_MSG_CODING_16BITS_ALPHABET) {
|
||||
// In UCS2 encoding, encodedBodyLength is in octets.
|
||||
charsInLastSegment /= 2;
|
||||
}
|
||||
} else {
|
||||
charsInLastSegment = 0;
|
||||
}
|
||||
|
||||
let result = gMobileMessageService.createSmsSegmentInfo(options.segmentMaxSeq,
|
||||
options.segmentChars,
|
||||
options.segmentChars - charsInLastSegment);
|
||||
return result;
|
||||
},
|
||||
|
||||
send: function send(number, message, silent, request) {
|
||||
let strict7BitEncoding = this._getStrict7BitEncoding();
|
||||
let requestStatusReport = this._getRequestStatusReport();
|
||||
|
||||
let options = this._fragmentText(message, null, strict7BitEncoding);
|
||||
options.number = gPhoneNumberUtils.normalize(number);
|
||||
options.requestStatusReport = requestStatusReport && !silent;
|
||||
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 (!gPhoneNumberUtils.isPlainPhoneNumber(options.number)) {
|
||||
if (DEBUG) debug("Error! Address is invalid when sending SMS: " +
|
||||
options.number);
|
||||
errorCode = Ci.nsIMobileMessageCallback.INVALID_ADDRESS_ERROR;
|
||||
} else if (gRadioInterface.rilContext.radioState !=
|
||||
RIL.GECKO_RADIOSTATE_READY) {
|
||||
if (DEBUG) debug("Error! Radio is disabled when sending SMS.");
|
||||
errorCode = Ci.nsIMobileMessageCallback.RADIO_DISABLED_ERROR;
|
||||
} else if (gRadioInterface.rilContext.cardState !=
|
||||
RIL.GECKO_CARDSTATE_READY) {
|
||||
if (DEBUG) 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
|
||||
.setMessageDeliveryByMessageId(domMessage.id,
|
||||
null,
|
||||
DELIVERY_STATE_ERROR,
|
||||
RIL.GECKO_SMS_DELIVERY_STATUS_ERROR,
|
||||
null,
|
||||
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
|
||||
let context = {
|
||||
request: request,
|
||||
sms: domMessage,
|
||||
requestStatusReport: options.requestStatusReport,
|
||||
silent: silent
|
||||
};
|
||||
|
||||
// This is the entry point starting to send SMS.
|
||||
gRadioInterface.sendWorkerMessage("sendSMS", options,
|
||||
(function(context, response) {
|
||||
if (response.errorMsg) {
|
||||
// Failed to send SMS out.
|
||||
let error = Ci.nsIMobileMessageCallback.UNKNOWN_ERROR;
|
||||
switch (message.errorMsg) {
|
||||
case RIL.ERROR_RADIO_NOT_AVAILABLE:
|
||||
error = Ci.nsIMobileMessageCallback.NO_SIGNAL_ERROR;
|
||||
break;
|
||||
}
|
||||
|
||||
if (context.silent) {
|
||||
context.request.notifySendMessageFailed(error);
|
||||
return false;
|
||||
}
|
||||
|
||||
gMobileMessageDatabaseService
|
||||
.setMessageDeliveryByMessageId(context.sms.id,
|
||||
null,
|
||||
DELIVERY_STATE_ERROR,
|
||||
RIL.GECKO_SMS_DELIVERY_STATUS_ERROR,
|
||||
null,
|
||||
function notifyResult(rv, domMessage) {
|
||||
// TODO bug 832140 handle !Components.isSuccessCode(rv)
|
||||
context.request.notifySendMessageFailed(error);
|
||||
Services.obs.notifyObservers(domMessage, kSmsFailedObserverTopic, null);
|
||||
});
|
||||
return false;
|
||||
} // End of send failure.
|
||||
|
||||
if (response.deliveryStatus) {
|
||||
// Message delivery.
|
||||
gMobileMessageDatabaseService
|
||||
.setMessageDeliveryByMessageId(context.sms.id,
|
||||
null,
|
||||
context.sms.delivery,
|
||||
message.deliveryStatus,
|
||||
null,
|
||||
function notifyResult(rv, domMessage) {
|
||||
// TODO bug 832140 handle !Components.isSuccessCode(rv)
|
||||
let topic = (message.deliveryStatus == RIL.GECKO_SMS_DELIVERY_STATUS_SUCCESS)
|
||||
? kSmsDeliverySuccessObserverTopic
|
||||
: kSmsDeliveryErrorObserverTopic;
|
||||
Services.obs.notifyObservers(domMessage, topic, null);
|
||||
});
|
||||
|
||||
// Send transaction has ended completely.
|
||||
return false;
|
||||
} // End of message delivery.
|
||||
|
||||
// Message sent.
|
||||
if (context.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 = context.sms;
|
||||
context.request.notifyMessageSent(
|
||||
gMobileMessageService.createSmsMessage(sms.id,
|
||||
sms.threadId,
|
||||
DELIVERY_STATE_SENT,
|
||||
sms.deliveryStatus,
|
||||
sms.sender,
|
||||
sms.receiver,
|
||||
sms.body,
|
||||
sms.messageClass,
|
||||
sms.timestamp,
|
||||
sms.read));
|
||||
// We don't wait for SMS-DELIVER-REPORT for silent one.
|
||||
return false;
|
||||
}
|
||||
|
||||
gMobileMessageDatabaseService
|
||||
.setMessageDeliveryByMessageId(context.sms.id,
|
||||
null,
|
||||
DELIVERY_STATE_SENT,
|
||||
context.sms.deliveryStatus,
|
||||
null,
|
||||
(function notifyResult(rv, domMessage) {
|
||||
// TODO bug 832140 handle !Components.isSuccessCode(rv)
|
||||
this._broadcastSystemMessage("sms-sent", domMessage);
|
||||
|
||||
if (context.requestStatusReport) {
|
||||
context.sms = domMessage;
|
||||
}
|
||||
|
||||
context.request.notifyMessageSent(domMessage);
|
||||
Services.obs.notifyObservers(domMessage, kSmsSentObserverTopic, null);
|
||||
}).bind(this));
|
||||
|
||||
// Only keep current context if we have requested for delivery report.
|
||||
return context.requestStatusReport;
|
||||
}).bind(this, context)); // End of |sendWorkerMessage| callback.
|
||||
}).bind(this); // End of DB saveSendingMessage callback.
|
||||
|
||||
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 = DELIVERY_STATE_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, notifyResult);
|
||||
},
|
||||
|
||||
addSilentNumber: function addSilentNumber(number) {
|
||||
if (this._isSilentNumber(number)) {
|
||||
throw Cr.NS_ERROR_UNEXPECTED;
|
||||
}
|
||||
|
||||
this.silentNumbers.push(number);
|
||||
},
|
||||
|
||||
removeSilentNumber: function removeSilentNumber(number) {
|
||||
let index = this.silentNumbers.indexOf(number);
|
||||
if (index < 0) {
|
||||
throw Cr.NS_ERROR_INVALID_ARG;
|
||||
}
|
||||
|
||||
this.silentNumbers.splice(index, 1);
|
||||
},
|
||||
|
||||
/**
|
||||
* nsIRilSmsService methods.
|
||||
*/
|
||||
|
||||
notifyMessageReceived: function notifyMessageReceived(message) {
|
||||
if (DEBUG) debug("notifyMessageReceived: " + JSON.stringify(message));
|
||||
|
||||
// FIXME: Bug 737202 - Typed arrays become normal arrays when sent to/from workers
|
||||
if (message.encoding == RIL.PDU_DCS_MSG_CODING_8BITS_ALPHABET) {
|
||||
message.fullData = new Uint8Array(message.fullData);
|
||||
}
|
||||
|
||||
// Dispatch to registered handler if application port addressing is
|
||||
// available. Note that the destination port can possibly be zero when
|
||||
// representing a UDP/TCP port.
|
||||
if (message.header && message.header.destinationPort != null) {
|
||||
let handler = this.portAddressedSmsApps[message.header.destinationPort];
|
||||
if (handler) {
|
||||
handler(message);
|
||||
}
|
||||
gRadioInterface.sendWorkerMessage("ackSMS", { result: RIL.PDU_FCS_OK });
|
||||
return;
|
||||
}
|
||||
|
||||
if (message.encoding == RIL.PDU_DCS_MSG_CODING_8BITS_ALPHABET) {
|
||||
// Don't know how to handle binary data yet.
|
||||
gRadioInterface.sendWorkerMessage("ackSMS", { result: RIL.PDU_FCS_OK });
|
||||
return;
|
||||
}
|
||||
|
||||
message.type = "sms";
|
||||
message.sender = message.sender || null;
|
||||
message.receiver = this._getMsisdn();
|
||||
message.body = message.fullBody = message.fullBody || null;
|
||||
message.timestamp = Date.now();
|
||||
|
||||
if (this._isSilentNumber(message.sender)) {
|
||||
message.id = -1;
|
||||
message.threadId = 0;
|
||||
message.delivery = DELIVERY_STATE_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);
|
||||
gRadioInterface.sendWorkerMessage("ackSMS", { result: RIL.PDU_FCS_OK });
|
||||
return;
|
||||
}
|
||||
|
||||
// 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;
|
||||
mwi.returnMessage = message.fullBody;
|
||||
gMessageManager.sendVoicemailMessage("RIL:VoicemailNotification",
|
||||
this.clientId, mwi);
|
||||
gRadioInterface.sendWorkerMessage("ackSMS", { result: RIL.PDU_FCS_OK });
|
||||
return;
|
||||
}
|
||||
|
||||
let notifyReceived = function notifyReceived(rv, domMessage) {
|
||||
let success = Components.isSuccessCode(rv);
|
||||
|
||||
// Acknowledge the reception of the SMS.
|
||||
gRadioInterface.sendWorkerMessage("ackSMS", {
|
||||
result: (success ? RIL.PDU_FCS_OK
|
||||
: RIL.PDU_FCS_MEMORY_CAPACITY_EXCEEDED)
|
||||
});
|
||||
|
||||
if (!success) {
|
||||
// At this point we could send a message to content to notify the user
|
||||
// that storing an incoming SMS failed, most likely due to a full disk.
|
||||
if (DEBUG) {
|
||||
debug("Could not store SMS " + message.id + ", error code " + rv);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
this._broadcastSystemMessage("sms-received", domMessage);
|
||||
Services.obs.notifyObservers(domMessage, kSmsReceivedObserverTopic, null);
|
||||
}.bind(this);
|
||||
|
||||
if (message.messageClass == RIL.GECKO_SMS_MESSAGE_CLASSES[RIL.PDU_DCS_MSG_CLASS_0]) {
|
||||
message.id = -1;
|
||||
message.threadId = 0;
|
||||
message.delivery = DELIVERY_STATE_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);
|
||||
|
||||
notifyReceived(Cr.NS_OK, domMessage);
|
||||
return;
|
||||
}
|
||||
|
||||
message.id =
|
||||
gMobileMessageDatabaseService.saveReceivedMessage(message,
|
||||
notifyReceived);
|
||||
},
|
||||
|
||||
/**
|
||||
* nsIObserver methods.
|
||||
*/
|
||||
|
||||
observe: function observe(subject, topic, data) {
|
||||
switch (topic) {
|
||||
case kPrefenceChangedObserverTopic:
|
||||
if (data === "ril.debugging.enabled") {
|
||||
try {
|
||||
DEBUG = RIL.DEBUG_RIL ||
|
||||
Services.prefs.getBoolPref("ril.debugging.enabled");
|
||||
} catch(e) {}
|
||||
}
|
||||
break;
|
||||
|
||||
case kXpcomShutdownObserverTopic:
|
||||
Services.obs.removeObserver(this, kPrefenceChangedObserverTopic);
|
||||
Services.obs.removeObserver(this, kXpcomShutdownObserverTopic);
|
||||
break;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
this.NSGetFactory = XPCOMUtils.generateNSGetFactory([SmsService]);
|
|
@ -0,0 +1,3 @@
|
|||
# SmsService.js
|
||||
component {46a9ed78-3574-40a1-9f12-ea179942d67f} SmsService.js
|
||||
contract @mozilla.org/sms/rilsmsservice;1 {46a9ed78-3574-40a1-9f12-ea179942d67f}
|
|
@ -123,14 +123,6 @@ SmsIPCService::Send(const nsAString& aNumber,
|
|||
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)
|
||||
{
|
||||
|
|
|
@ -36,6 +36,7 @@ else:
|
|||
CPP_SOURCES += [
|
||||
'MobileMessageDatabaseService.cpp',
|
||||
'MmsService.cpp',
|
||||
'SmsService.cpp',
|
||||
]
|
||||
|
||||
EXPORTS.mozilla.dom += [
|
||||
|
@ -60,7 +61,6 @@ CPP_SOURCES += [
|
|||
'SmsMessage.cpp',
|
||||
'SmsParent.cpp',
|
||||
'SmsSegmentInfo.cpp',
|
||||
'SmsService.cpp',
|
||||
'SmsServicesFactory.cpp',
|
||||
]
|
||||
|
||||
|
@ -70,6 +70,8 @@ if CONFIG['MOZ_B2G_RIL']:
|
|||
'gonk/MmsService.manifest',
|
||||
'gonk/MobileMessageDatabaseService.js',
|
||||
'gonk/MobileMessageDatabaseService.manifest',
|
||||
'gonk/SmsService.js',
|
||||
'gonk/SmsService.manifest',
|
||||
]
|
||||
|
||||
IPDL_SOURCES += [
|
||||
|
|
|
@ -47,13 +47,6 @@ const RILNETWORKINTERFACE_CID =
|
|||
Components.ID("{3bdd52a9-3965-4130-b569-0ac5afed045e}");
|
||||
|
||||
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";
|
||||
|
@ -119,17 +112,9 @@ 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");
|
||||
"@mozilla.org/sms/rilsmsservice;1",
|
||||
"nsIRilSmsService");
|
||||
|
||||
XPCOMUtils.defineLazyServiceGetter(this, "gSettingsService",
|
||||
"@mozilla.org/settingsService;1",
|
||||
|
@ -155,12 +140,6 @@ XPCOMUtils.defineLazyServiceGetter(this, "gTelephonyProvider",
|
|||
"@mozilla.org/telephony/telephonyprovider;1",
|
||||
"nsIGonkTelephonyProvider");
|
||||
|
||||
XPCOMUtils.defineLazyGetter(this, "WAP", function () {
|
||||
let wap = {};
|
||||
Cu.import("resource://gre/modules/WapPushManager.js", wap);
|
||||
return wap;
|
||||
});
|
||||
|
||||
XPCOMUtils.defineLazyGetter(this, "PhoneNumberUtils", function () {
|
||||
let ns = {};
|
||||
Cu.import("resource://gre/modules/PhoneNumberUtils.jsm", ns);
|
||||
|
@ -467,9 +446,6 @@ function RadioInterface(options) {
|
|||
Services.obs.addObserver(this, kScreenStateChangedTopic, false);
|
||||
|
||||
Services.prefs.addObserver(kCellBroadcastDisabled, this, false);
|
||||
|
||||
this.portAddressedSmsApps = {};
|
||||
this.portAddressedSmsApps[WAP.WDP_PORT_PUSH] = this.handleSmsWdpPortPush.bind(this);
|
||||
}
|
||||
RadioInterface.prototype = {
|
||||
|
||||
|
@ -697,11 +673,8 @@ RadioInterface.prototype = {
|
|||
this.clientId, message);
|
||||
break;
|
||||
case "sms-received":
|
||||
let ackOk = this.handleSmsReceived(message);
|
||||
if (ackOk) {
|
||||
this.workerMessenger.send("ackSMS", { result: RIL.PDU_FCS_OK });
|
||||
}
|
||||
return;
|
||||
gSmsService.notifyMessageReceived(message);
|
||||
break;
|
||||
case "cellbroadcast-received":
|
||||
message.timestamp = Date.now();
|
||||
gMessageManager.sendCellBroadcastMessage("RIL:CellBroadcastReceived",
|
||||
|
@ -748,18 +721,6 @@ RadioInterface.prototype = {
|
|||
}
|
||||
},
|
||||
|
||||
getMsisdn: function getMsisdn() {
|
||||
let iccInfo = this.rilContext.iccInfo;
|
||||
let number = iccInfo ? iccInfo.msisdn : null;
|
||||
|
||||
// Workaround an xpconnect issue with undefined string objects.
|
||||
// See bug 808220
|
||||
if (number === undefined || number === "undefined") {
|
||||
return null;
|
||||
}
|
||||
return number;
|
||||
},
|
||||
|
||||
updateNetworkInfo: function updateNetworkInfo(message) {
|
||||
let voiceMessage = message[RIL.NETWORK_INFO_VOICE_REGISTRATION_STATE];
|
||||
let dataMessage = message[RIL.NETWORK_INFO_DATA_REGISTRATION_STATE];
|
||||
|
@ -1326,184 +1287,6 @@ RadioInterface.prototype = {
|
|||
this.clientId, message);
|
||||
},
|
||||
|
||||
/**
|
||||
* Handle WDP port push PDU. Constructor WDP bearer information and deliver
|
||||
* to WapPushManager.
|
||||
*
|
||||
* @param message
|
||||
* A SMS message.
|
||||
*/
|
||||
handleSmsWdpPortPush: function handleSmsWdpPortPush(message) {
|
||||
if (message.encoding != RIL.PDU_DCS_MSG_CODING_8BITS_ALPHABET) {
|
||||
if (DEBUG) {
|
||||
this.debug("Got port addressed SMS but not encoded in 8-bit alphabet." +
|
||||
" Drop!");
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
let options = {
|
||||
bearer: WAP.WDP_BEARER_GSM_SMS_GSM_MSISDN,
|
||||
sourceAddress: message.sender,
|
||||
sourcePort: message.header.originatorPort,
|
||||
destinationAddress: this.rilContext.iccInfo.msisdn,
|
||||
destinationPort: message.header.destinationPort,
|
||||
};
|
||||
WAP.WapPushManager.receiveWdpPDU(message.fullData, message.fullData.length,
|
||||
0, options);
|
||||
},
|
||||
|
||||
/**
|
||||
* A helper to broadcast the system message to launch registered apps
|
||||
* like Costcontrol, Notification and Message app... etc.
|
||||
*
|
||||
* @param aName
|
||||
* The system message name.
|
||||
* @param aDomMessage
|
||||
* The nsIDOMMozSmsMessage object.
|
||||
*/
|
||||
broadcastSmsSystemMessage: function broadcastSmsSystemMessage(aName, aDomMessage) {
|
||||
if (DEBUG) this.debug("Broadcasting the SMS system message: " + aName);
|
||||
|
||||
// Sadly we cannot directly broadcast the aDomMessage object
|
||||
// because the system message mechamism will rewrap the object
|
||||
// based on the content window, which needs to know the properties.
|
||||
gSystemMessenger.broadcastMessage(aName, {
|
||||
type: aDomMessage.type,
|
||||
id: aDomMessage.id,
|
||||
threadId: aDomMessage.threadId,
|
||||
delivery: aDomMessage.delivery,
|
||||
deliveryStatus: aDomMessage.deliveryStatus,
|
||||
sender: aDomMessage.sender,
|
||||
receiver: aDomMessage.receiver,
|
||||
body: aDomMessage.body,
|
||||
messageClass: aDomMessage.messageClass,
|
||||
timestamp: aDomMessage.timestamp,
|
||||
read: aDomMessage.read
|
||||
});
|
||||
},
|
||||
|
||||
portAddressedSmsApps: null,
|
||||
handleSmsReceived: function handleSmsReceived(message) {
|
||||
if (DEBUG) this.debug("handleSmsReceived: " + JSON.stringify(message));
|
||||
|
||||
// FIXME: Bug 737202 - Typed arrays become normal arrays when sent to/from workers
|
||||
if (message.encoding == RIL.PDU_DCS_MSG_CODING_8BITS_ALPHABET) {
|
||||
message.fullData = new Uint8Array(message.fullData);
|
||||
}
|
||||
|
||||
// Dispatch to registered handler if application port addressing is
|
||||
// available. Note that the destination port can possibly be zero when
|
||||
// representing a UDP/TCP port.
|
||||
if (message.header && message.header.destinationPort != null) {
|
||||
let handler = this.portAddressedSmsApps[message.header.destinationPort];
|
||||
if (handler) {
|
||||
handler(message);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
if (message.encoding == RIL.PDU_DCS_MSG_CODING_8BITS_ALPHABET) {
|
||||
// Don't know how to handle binary data yet.
|
||||
return true;
|
||||
}
|
||||
|
||||
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;
|
||||
mwi.returnMessage = message.fullBody;
|
||||
gMessageManager.sendVoicemailMessage("RIL:VoicemailNotification",
|
||||
this.clientId, mwi);
|
||||
return true;
|
||||
}
|
||||
|
||||
let notifyReceived = function notifyReceived(rv, domMessage) {
|
||||
let success = Components.isSuccessCode(rv);
|
||||
|
||||
// Acknowledge the reception of the SMS.
|
||||
this.workerMessenger.send("ackSMS", {
|
||||
result: (success ? RIL.PDU_FCS_OK
|
||||
: RIL.PDU_FCS_MEMORY_CAPACITY_EXCEEDED)
|
||||
});
|
||||
|
||||
if (!success) {
|
||||
// At this point we could send a message to content to notify the user
|
||||
// that storing an incoming SMS failed, most likely due to a full disk.
|
||||
if (DEBUG) {
|
||||
this.debug("Could not store SMS " + message.id + ", error code " + rv);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
this.broadcastSmsSystemMessage("sms-received", domMessage);
|
||||
Services.obs.notifyObservers(domMessage, kSmsReceivedObserverTopic, null);
|
||||
}.bind(this);
|
||||
|
||||
if (message.messageClass != RIL.GECKO_SMS_MESSAGE_CLASSES[RIL.PDU_DCS_MSG_CLASS_0]) {
|
||||
message.id = gMobileMessageDatabaseService.saveReceivedMessage(message,
|
||||
notifyReceived);
|
||||
} else {
|
||||
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);
|
||||
|
||||
notifyReceived(Cr.NS_OK, domMessage);
|
||||
}
|
||||
|
||||
// SMS ACK will be sent in notifyReceived. Return false here.
|
||||
return false;
|
||||
},
|
||||
|
||||
/**
|
||||
* Handle data call state changes.
|
||||
*/
|
||||
|
@ -1923,622 +1706,6 @@ RadioInterface.prototype = {
|
|||
}).bind(this));
|
||||
},
|
||||
|
||||
/**
|
||||
* List of tuples of national language identifier pairs.
|
||||
*
|
||||
* TODO: Support static/runtime settings, see bug 733331.
|
||||
*/
|
||||
enabledGsmTableTuples: [
|
||||
[RIL.PDU_NL_IDENTIFIER_DEFAULT, RIL.PDU_NL_IDENTIFIER_DEFAULT],
|
||||
],
|
||||
|
||||
/**
|
||||
* Use 16-bit reference number for concatenated outgoint messages.
|
||||
*
|
||||
* TODO: Support static/runtime settings, see bug 733331.
|
||||
*/
|
||||
segmentRef16Bit: false,
|
||||
|
||||
/**
|
||||
* Get valid SMS concatenation reference number.
|
||||
*/
|
||||
_segmentRef: 0,
|
||||
get nextSegmentRef() {
|
||||
let ref = this._segmentRef++;
|
||||
|
||||
this._segmentRef %= (this.segmentRef16Bit ? 65535 : 255);
|
||||
|
||||
// 0 is not a valid SMS concatenation reference number.
|
||||
return ref + 1;
|
||||
},
|
||||
|
||||
/**
|
||||
* Calculate encoded length using specified locking/single shift table
|
||||
*
|
||||
* @param message
|
||||
* message string to be encoded.
|
||||
* @param langTable
|
||||
* locking shift table string.
|
||||
* @param langShiftTable
|
||||
* single shift table string.
|
||||
* @param strict7BitEncoding
|
||||
* Optional. Enable Latin characters replacement with corresponding
|
||||
* ones in GSM SMS 7-bit default alphabet.
|
||||
*
|
||||
* @return encoded length in septets.
|
||||
*
|
||||
* @note that the algorithm used in this function must match exactly with
|
||||
* GsmPDUHelper#writeStringAsSeptets.
|
||||
*/
|
||||
_countGsm7BitSeptets: function _countGsm7BitSeptets(message, langTable, langShiftTable, strict7BitEncoding) {
|
||||
let length = 0;
|
||||
for (let msgIndex = 0; msgIndex < message.length; msgIndex++) {
|
||||
let c = message.charAt(msgIndex);
|
||||
if (strict7BitEncoding) {
|
||||
c = RIL.GSM_SMS_STRICT_7BIT_CHARMAP[c] || c;
|
||||
}
|
||||
|
||||
let septet = langTable.indexOf(c);
|
||||
|
||||
// According to 3GPP TS 23.038, section 6.1.1 General notes, "The
|
||||
// characters marked '1)' are not used but are displayed as a space."
|
||||
if (septet == RIL.PDU_NL_EXTENDED_ESCAPE) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (septet >= 0) {
|
||||
length++;
|
||||
continue;
|
||||
}
|
||||
|
||||
septet = langShiftTable.indexOf(c);
|
||||
if (septet < 0) {
|
||||
if (!strict7BitEncoding) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Bug 816082, when strict7BitEncoding is enabled, we should replace
|
||||
// characters that can't be encoded with GSM 7-Bit alphabets with '*'.
|
||||
c = '*';
|
||||
if (langTable.indexOf(c) >= 0) {
|
||||
length++;
|
||||
} else if (langShiftTable.indexOf(c) >= 0) {
|
||||
length += 2;
|
||||
} else {
|
||||
// We can't even encode a '*' character with current configuration.
|
||||
return -1;
|
||||
}
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
// According to 3GPP TS 23.038 B.2, "This code represents a control
|
||||
// character and therefore must not be used for language specific
|
||||
// characters."
|
||||
if (septet == RIL.PDU_NL_RESERVED_CONTROL) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// The character is not found in locking shfit table, but could be
|
||||
// encoded as <escape><char> with single shift table. Note that it's
|
||||
// still possible for septet to has the value of PDU_NL_EXTENDED_ESCAPE,
|
||||
// but we can display it as a space in this case as said in previous
|
||||
// comment.
|
||||
length += 2;
|
||||
}
|
||||
|
||||
return length;
|
||||
},
|
||||
|
||||
/**
|
||||
* Calculate user data length of specified message string encoded in GSM 7Bit
|
||||
* alphabets.
|
||||
*
|
||||
* @param message
|
||||
* a message string to be encoded.
|
||||
* @param strict7BitEncoding
|
||||
* Optional. Enable Latin characters replacement with corresponding
|
||||
* ones in GSM SMS 7-bit default alphabet.
|
||||
*
|
||||
* @return null or an options object with attributes `dcs`,
|
||||
* `userDataHeaderLength`, `encodedFullBodyLength`, `langIndex`,
|
||||
* `langShiftIndex`, `segmentMaxSeq` set.
|
||||
*
|
||||
* @see #_calculateUserDataLength().
|
||||
*/
|
||||
_calculateUserDataLength7Bit: function _calculateUserDataLength7Bit(message, strict7BitEncoding) {
|
||||
let options = null;
|
||||
let minUserDataSeptets = Number.MAX_VALUE;
|
||||
for (let i = 0; i < this.enabledGsmTableTuples.length; i++) {
|
||||
let [langIndex, langShiftIndex] = this.enabledGsmTableTuples[i];
|
||||
|
||||
const langTable = RIL.PDU_NL_LOCKING_SHIFT_TABLES[langIndex];
|
||||
const langShiftTable = RIL.PDU_NL_SINGLE_SHIFT_TABLES[langShiftIndex];
|
||||
|
||||
let bodySeptets = this._countGsm7BitSeptets(message,
|
||||
langTable,
|
||||
langShiftTable,
|
||||
strict7BitEncoding);
|
||||
if (bodySeptets < 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
let headerLen = 0;
|
||||
if (langIndex != RIL.PDU_NL_IDENTIFIER_DEFAULT) {
|
||||
headerLen += 3; // IEI + len + langIndex
|
||||
}
|
||||
if (langShiftIndex != RIL.PDU_NL_IDENTIFIER_DEFAULT) {
|
||||
headerLen += 3; // IEI + len + langShiftIndex
|
||||
}
|
||||
|
||||
// Calculate full user data length, note the extra byte is for header len
|
||||
let headerSeptets = Math.ceil((headerLen ? headerLen + 1 : 0) * 8 / 7);
|
||||
let segmentSeptets = RIL.PDU_MAX_USER_DATA_7BIT;
|
||||
if ((bodySeptets + headerSeptets) > segmentSeptets) {
|
||||
headerLen += this.segmentRef16Bit ? 6 : 5;
|
||||
headerSeptets = Math.ceil((headerLen + 1) * 8 / 7);
|
||||
segmentSeptets -= headerSeptets;
|
||||
}
|
||||
|
||||
let segments = Math.ceil(bodySeptets / segmentSeptets);
|
||||
let userDataSeptets = bodySeptets + headerSeptets * segments;
|
||||
if (userDataSeptets >= minUserDataSeptets) {
|
||||
continue;
|
||||
}
|
||||
|
||||
minUserDataSeptets = userDataSeptets;
|
||||
|
||||
options = {
|
||||
dcs: RIL.PDU_DCS_MSG_CODING_7BITS_ALPHABET,
|
||||
encodedFullBodyLength: bodySeptets,
|
||||
userDataHeaderLength: headerLen,
|
||||
langIndex: langIndex,
|
||||
langShiftIndex: langShiftIndex,
|
||||
segmentMaxSeq: segments,
|
||||
segmentChars: segmentSeptets,
|
||||
};
|
||||
}
|
||||
|
||||
return options;
|
||||
},
|
||||
|
||||
/**
|
||||
* Calculate user data length of specified message string encoded in UCS2.
|
||||
*
|
||||
* @param message
|
||||
* a message string to be encoded.
|
||||
*
|
||||
* @return an options object with attributes `dcs`, `userDataHeaderLength`,
|
||||
* `encodedFullBodyLength`, `segmentMaxSeq` set.
|
||||
*
|
||||
* @see #_calculateUserDataLength().
|
||||
*/
|
||||
_calculateUserDataLengthUCS2: function _calculateUserDataLengthUCS2(message) {
|
||||
let bodyChars = message.length;
|
||||
let headerLen = 0;
|
||||
let headerChars = Math.ceil((headerLen ? headerLen + 1 : 0) / 2);
|
||||
let segmentChars = RIL.PDU_MAX_USER_DATA_UCS2;
|
||||
if ((bodyChars + headerChars) > segmentChars) {
|
||||
headerLen += this.segmentRef16Bit ? 6 : 5;
|
||||
headerChars = Math.ceil((headerLen + 1) / 2);
|
||||
segmentChars -= headerChars;
|
||||
}
|
||||
|
||||
let segments = Math.ceil(bodyChars / segmentChars);
|
||||
|
||||
return {
|
||||
dcs: RIL.PDU_DCS_MSG_CODING_16BITS_ALPHABET,
|
||||
encodedFullBodyLength: bodyChars * 2,
|
||||
userDataHeaderLength: headerLen,
|
||||
segmentMaxSeq: segments,
|
||||
segmentChars: segmentChars,
|
||||
};
|
||||
},
|
||||
|
||||
/**
|
||||
* Calculate user data length and its encoding.
|
||||
*
|
||||
* @param message
|
||||
* a message string to be encoded.
|
||||
* @param strict7BitEncoding
|
||||
* Optional. Enable Latin characters replacement with corresponding
|
||||
* ones in GSM SMS 7-bit default alphabet.
|
||||
*
|
||||
* @return an options object with some or all of following attributes set:
|
||||
*
|
||||
* @param dcs
|
||||
* Data coding scheme. One of the PDU_DCS_MSG_CODING_*BITS_ALPHABET
|
||||
* constants.
|
||||
* @param userDataHeaderLength
|
||||
* Length of embedded user data header, in bytes. The whole header
|
||||
* size will be userDataHeaderLength + 1; 0 for no header.
|
||||
* @param encodedFullBodyLength
|
||||
* Length of the message body when encoded with the given DCS. For
|
||||
* UCS2, in bytes; for 7-bit, in septets.
|
||||
* @param langIndex
|
||||
* Table index used for normal 7-bit encoded character lookup.
|
||||
* @param langShiftIndex
|
||||
* Table index used for escaped 7-bit encoded character lookup.
|
||||
* @param segmentMaxSeq
|
||||
* Max sequence number of a multi-part messages, or 1 for single one.
|
||||
* This number might not be accurate for a multi-part message until
|
||||
* it's processed by #_fragmentText() again.
|
||||
*/
|
||||
_calculateUserDataLength: function _calculateUserDataLength(message, strict7BitEncoding) {
|
||||
let options = this._calculateUserDataLength7Bit(message, strict7BitEncoding);
|
||||
if (!options) {
|
||||
options = this._calculateUserDataLengthUCS2(message);
|
||||
}
|
||||
|
||||
if (DEBUG) this.debug("_calculateUserDataLength: " + JSON.stringify(options));
|
||||
return options;
|
||||
},
|
||||
|
||||
/**
|
||||
* Fragment GSM 7-Bit encodable string for transmission.
|
||||
*
|
||||
* @param text
|
||||
* text string to be fragmented.
|
||||
* @param langTable
|
||||
* locking shift table string.
|
||||
* @param langShiftTable
|
||||
* single shift table string.
|
||||
* @param segmentSeptets
|
||||
* Number of available spetets per segment.
|
||||
* @param strict7BitEncoding
|
||||
* Optional. Enable Latin characters replacement with corresponding
|
||||
* ones in GSM SMS 7-bit default alphabet.
|
||||
*
|
||||
* @return an array of objects. See #_fragmentText() for detailed definition.
|
||||
*/
|
||||
_fragmentText7Bit: function _fragmentText7Bit(text, langTable, langShiftTable, segmentSeptets, strict7BitEncoding) {
|
||||
let ret = [];
|
||||
let body = "", len = 0;
|
||||
for (let i = 0, inc = 0; i < text.length; i++) {
|
||||
let c = text.charAt(i);
|
||||
if (strict7BitEncoding) {
|
||||
c = RIL.GSM_SMS_STRICT_7BIT_CHARMAP[c] || c;
|
||||
}
|
||||
|
||||
let septet = langTable.indexOf(c);
|
||||
if (septet == RIL.PDU_NL_EXTENDED_ESCAPE) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (septet >= 0) {
|
||||
inc = 1;
|
||||
} else {
|
||||
septet = langShiftTable.indexOf(c);
|
||||
if (septet == RIL.PDU_NL_RESERVED_CONTROL) {
|
||||
continue;
|
||||
}
|
||||
|
||||
inc = 2;
|
||||
if (septet < 0) {
|
||||
if (!strict7BitEncoding) {
|
||||
throw new Error("Given text cannot be encoded with GSM 7-bit Alphabet!");
|
||||
}
|
||||
|
||||
// Bug 816082, when strict7BitEncoding is enabled, we should replace
|
||||
// characters that can't be encoded with GSM 7-Bit alphabets with '*'.
|
||||
c = '*';
|
||||
if (langTable.indexOf(c) >= 0) {
|
||||
inc = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ((len + inc) > segmentSeptets) {
|
||||
ret.push({
|
||||
body: body,
|
||||
encodedBodyLength: len,
|
||||
});
|
||||
body = c;
|
||||
len = inc;
|
||||
} else {
|
||||
body += c;
|
||||
len += inc;
|
||||
}
|
||||
}
|
||||
|
||||
if (len) {
|
||||
ret.push({
|
||||
body: body,
|
||||
encodedBodyLength: len,
|
||||
});
|
||||
}
|
||||
|
||||
return ret;
|
||||
},
|
||||
|
||||
/**
|
||||
* Fragment UCS2 encodable string for transmission.
|
||||
*
|
||||
* @param text
|
||||
* text string to be fragmented.
|
||||
* @param segmentChars
|
||||
* Number of available characters per segment.
|
||||
*
|
||||
* @return an array of objects. See #_fragmentText() for detailed definition.
|
||||
*/
|
||||
_fragmentTextUCS2: function _fragmentTextUCS2(text, segmentChars) {
|
||||
let ret = [];
|
||||
for (let offset = 0; offset < text.length; offset += segmentChars) {
|
||||
let str = text.substr(offset, segmentChars);
|
||||
ret.push({
|
||||
body: str,
|
||||
encodedBodyLength: str.length * 2,
|
||||
});
|
||||
}
|
||||
|
||||
return ret;
|
||||
},
|
||||
|
||||
/**
|
||||
* Fragment string for transmission.
|
||||
*
|
||||
* Fragment input text string into an array of objects that contains
|
||||
* attributes `body`, substring for this segment, `encodedBodyLength`,
|
||||
* length of the encoded segment body in septets.
|
||||
*
|
||||
* @param text
|
||||
* Text string to be fragmented.
|
||||
* @param options
|
||||
* Optional pre-calculated option object. The output array will be
|
||||
* stored at options.segments if there are multiple segments.
|
||||
* @param strict7BitEncoding
|
||||
* Optional. Enable Latin characters replacement with corresponding
|
||||
* ones in GSM SMS 7-bit default alphabet.
|
||||
*
|
||||
* @return Populated options object.
|
||||
*/
|
||||
_fragmentText: function _fragmentText(text, options, strict7BitEncoding) {
|
||||
if (!options) {
|
||||
options = this._calculateUserDataLength(text, strict7BitEncoding);
|
||||
}
|
||||
|
||||
if (options.dcs == RIL.PDU_DCS_MSG_CODING_7BITS_ALPHABET) {
|
||||
const langTable = RIL.PDU_NL_LOCKING_SHIFT_TABLES[options.langIndex];
|
||||
const langShiftTable = RIL.PDU_NL_SINGLE_SHIFT_TABLES[options.langShiftIndex];
|
||||
options.segments = this._fragmentText7Bit(text,
|
||||
langTable, langShiftTable,
|
||||
options.segmentChars,
|
||||
strict7BitEncoding);
|
||||
} else {
|
||||
options.segments = this._fragmentTextUCS2(text,
|
||||
options.segmentChars);
|
||||
}
|
||||
|
||||
// Re-sync options.segmentMaxSeq with actual length of returning array.
|
||||
options.segmentMaxSeq = options.segments.length;
|
||||
|
||||
return options;
|
||||
},
|
||||
|
||||
getSegmentInfoForText: function getSegmentInfoForText(text) {
|
||||
let strict7BitEncoding;
|
||||
try {
|
||||
strict7BitEncoding = Services.prefs.getBoolPref("dom.sms.strict7BitEncoding");
|
||||
} catch (e) {
|
||||
strict7BitEncoding = false;
|
||||
}
|
||||
|
||||
let options = this._fragmentText(text, null, strict7BitEncoding);
|
||||
let charsInLastSegment;
|
||||
if (options.segmentMaxSeq) {
|
||||
let lastSegment = options.segments[options.segmentMaxSeq - 1];
|
||||
charsInLastSegment = lastSegment.encodedBodyLength;
|
||||
if (options.dcs == RIL.PDU_DCS_MSG_CODING_16BITS_ALPHABET) {
|
||||
// In UCS2 encoding, encodedBodyLength is in octets.
|
||||
charsInLastSegment /= 2;
|
||||
}
|
||||
} else {
|
||||
charsInLastSegment = 0;
|
||||
}
|
||||
|
||||
let result = gMobileMessageService.createSmsSegmentInfo(options.segmentMaxSeq,
|
||||
options.segmentChars,
|
||||
options.segmentChars - charsInLastSegment);
|
||||
return result;
|
||||
},
|
||||
|
||||
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);
|
||||
options.number = PhoneNumberUtils.normalize(number);
|
||||
let requestStatusReport;
|
||||
try {
|
||||
requestStatusReport =
|
||||
Services.prefs.getBoolPref("dom.sms.requestStatusReport");
|
||||
} catch (e) {
|
||||
requestStatusReport = true;
|
||||
}
|
||||
options.requestStatusReport = requestStatusReport && !silent;
|
||||
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
|
||||
.setMessageDeliveryByMessageId(domMessage.id,
|
||||
null,
|
||||
DOM_MOBILE_MESSAGE_DELIVERY_ERROR,
|
||||
RIL.GECKO_SMS_DELIVERY_STATUS_ERROR,
|
||||
null,
|
||||
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
|
||||
let context = {
|
||||
request: request,
|
||||
sms: domMessage,
|
||||
requestStatusReport: options.requestStatusReport,
|
||||
silent: silent
|
||||
};
|
||||
|
||||
// This is the entry point starting to send SMS.
|
||||
this.workerMessenger.send("sendSMS", options,
|
||||
(function(context, response) {
|
||||
if (response.errorMsg) {
|
||||
// Failed to send SMS out.
|
||||
let error = Ci.nsIMobileMessageCallback.UNKNOWN_ERROR;
|
||||
switch (message.errorMsg) {
|
||||
case RIL.ERROR_RADIO_NOT_AVAILABLE:
|
||||
error = Ci.nsIMobileMessageCallback.NO_SIGNAL_ERROR;
|
||||
break;
|
||||
}
|
||||
|
||||
if (context.silent) {
|
||||
context.request.notifySendMessageFailed(error);
|
||||
return false;
|
||||
}
|
||||
|
||||
gMobileMessageDatabaseService
|
||||
.setMessageDeliveryByMessageId(context.sms.id,
|
||||
null,
|
||||
DOM_MOBILE_MESSAGE_DELIVERY_ERROR,
|
||||
RIL.GECKO_SMS_DELIVERY_STATUS_ERROR,
|
||||
null,
|
||||
function notifyResult(rv, domMessage) {
|
||||
// TODO bug 832140 handle !Components.isSuccessCode(rv)
|
||||
context.request.notifySendMessageFailed(error);
|
||||
Services.obs.notifyObservers(domMessage, kSmsFailedObserverTopic, null);
|
||||
});
|
||||
return false;
|
||||
} // End of send failure.
|
||||
|
||||
if (response.deliveryStatus) {
|
||||
// Message delivery.
|
||||
gMobileMessageDatabaseService
|
||||
.setMessageDeliveryByMessageId(context.sms.id,
|
||||
null,
|
||||
context.sms.delivery,
|
||||
response.deliveryStatus,
|
||||
null,
|
||||
function notifyResult(rv, domMessage) {
|
||||
// TODO bug 832140 handle !Components.isSuccessCode(rv)
|
||||
let topic = (response.deliveryStatus == RIL.GECKO_SMS_DELIVERY_STATUS_SUCCESS)
|
||||
? kSmsDeliverySuccessObserverTopic
|
||||
: kSmsDeliveryErrorObserverTopic;
|
||||
Services.obs.notifyObservers(domMessage, topic, null);
|
||||
});
|
||||
|
||||
// Send transaction has ended completely.
|
||||
return false;
|
||||
} // End of message delivery.
|
||||
|
||||
// Message sent.
|
||||
if (context.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 = context.sms;
|
||||
context.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));
|
||||
// We don't wait for SMS-DELIVER-REPORT for silent one.
|
||||
return false;
|
||||
}
|
||||
|
||||
gMobileMessageDatabaseService
|
||||
.setMessageDeliveryByMessageId(context.sms.id,
|
||||
null,
|
||||
DOM_MOBILE_MESSAGE_DELIVERY_SENT,
|
||||
context.sms.deliveryStatus,
|
||||
null,
|
||||
(function notifyResult(rv, domMessage) {
|
||||
// TODO bug 832140 handle !Components.isSuccessCode(rv)
|
||||
this.broadcastSmsSystemMessage("sms-sent", domMessage);
|
||||
|
||||
if (context.requestStatusReport) {
|
||||
context.sms = domMessage;
|
||||
}
|
||||
|
||||
context.request.notifyMessageSent(domMessage);
|
||||
Services.obs.notifyObservers(domMessage, kSmsSentObserverTopic, null);
|
||||
}).bind(this));
|
||||
|
||||
// Only keep current context if we have requested for delivery report.
|
||||
return context.requestStatusReport;
|
||||
}).bind(this, context)); // End of |workerMessenger.send| callback.
|
||||
}).bind(this); // End of DB saveSendingMessage callback.
|
||||
|
||||
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, notifyResult);
|
||||
},
|
||||
|
||||
registerDataCallCallback: function registerDataCallCallback(callback) {
|
||||
if (this._datacall_callbacks) {
|
||||
if (this._datacall_callbacks.indexOf(callback) != -1) {
|
||||
|
|
|
@ -6,8 +6,6 @@
|
|||
|
||||
interface nsIDOMMozIccInfo;
|
||||
interface nsIDOMMozMobileConnectionInfo;
|
||||
interface nsIDOMMozSmsSegmentInfo;
|
||||
interface nsIMobileMessageCallback;
|
||||
|
||||
[scriptable, uuid(1e602d20-d066-4399-8997-daf36b3158ef)]
|
||||
interface nsIRILDataCallInfo : nsISupports
|
||||
|
@ -85,7 +83,7 @@ interface nsIRilSendWorkerMessageCallback : nsISupports
|
|||
boolean handleResponse(in jsval response);
|
||||
};
|
||||
|
||||
[scriptable, uuid(61a8ca67-6113-4cd0-b443-e045f09863ed)]
|
||||
[scriptable, uuid(b1af7aad-6547-427c-a878-e2ebf98a14d6)]
|
||||
interface nsIRadioInterface : nsISupports
|
||||
{
|
||||
readonly attribute nsIRilContext rilContext;
|
||||
|
@ -102,16 +100,6 @@ interface nsIRadioInterface : nsISupports
|
|||
|
||||
void updateRILNetworkInterface();
|
||||
|
||||
/**
|
||||
* SMS-related functionality.
|
||||
*/
|
||||
nsIDOMMozSmsSegmentInfo getSegmentInfoForText(in DOMString text);
|
||||
|
||||
void sendSMS(in DOMString number,
|
||||
in DOMString message,
|
||||
in boolean silent,
|
||||
in nsIMobileMessageCallback request);
|
||||
|
||||
void sendWorkerMessage(in DOMString type,
|
||||
[optional] in jsval message,
|
||||
[optional] in nsIRilSendWorkerMessageCallback callback);
|
||||
|
|
Загрузка…
Ссылка в новой задаче