Merge b2g-inbound and mozilla-central on a CLOSED TREE

This commit is contained in:
Wes Kocher 2013-09-04 17:22:09 -07:00
commit e6a4969b2b
43 changed files with 1356 additions and 967 deletions

View File

@ -4,7 +4,7 @@
* 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;"
"use strict";
const Cc = Components.classes;
const Ci = Components.interfaces;
@ -21,47 +21,65 @@ XPCOMUtils.defineLazyGetter(this, "libcutils", function () {
});
#endif
// Once Bug 731746 - Allow chrome JS object to implement nsIDOMEventTarget
// is resolved this helper could be removed.
var SettingsListener = {
_callbacks: {},
// Timer to remove the lock.
_timer: null,
init: function sl_init() {
if ('mozSettings' in navigator && navigator.mozSettings) {
navigator.mozSettings.onsettingchange = this.onchange.bind(this);
}
},
// lock stores here
_lock: null,
onchange: function sl_onchange(evt) {
var callback = this._callbacks[evt.settingName];
if (callback) {
callback(evt.settingValue);
/**
* getSettingsLock: create a lock or retrieve one that we saved.
* mozSettings.createLock() is expensive and lock should be reused
* whenever possible.
*/
getSettingsLock: function sl_getSettingsLock() {
// Each time there is a getSettingsLock call, we postpone the removal.
clearTimeout(this._timer);
this._timer = setTimeout((function() {
this._lock = null;
}).bind(this), 0);
// If there is a lock present we return that.
if (this._lock) {
return this._lock;
}
// If there isn't we create a new one.
let settings = window.navigator.mozSettings;
return (this._lock = settings.createLock());
},
observe: function sl_observe(name, defaultValue, callback) {
var settings = window.navigator.mozSettings;
if (!settings) {
window.setTimeout(function() { callback(defaultValue); });
return;
let settings = window.navigator.mozSettings;
let req;
try {
req = this.getSettingsLock().get(name);
} catch (e) {
// It is possible (but rare) for getSettingsLock() to return
// a SettingsLock object that is no longer valid.
// Until https://bugzilla.mozilla.org/show_bug.cgi?id=793239
// is fixed, we just catch the resulting exception and try
// again with a fresh lock
console.warn('Stale lock in settings.js.',
'See https://bugzilla.mozilla.org/show_bug.cgi?id=793239');
this._lock = null;
req = this.getSettingsLock().get(name);
}
if (!callback || typeof callback !== 'function') {
throw new Error('Callback is not a function');
}
var req = settings.createLock().get(name);
req.addEventListener('success', (function onsuccess() {
callback(typeof(req.result[name]) != 'undefined' ?
req.result[name] : defaultValue);
}));
this._callbacks[name] = callback;
settings.addObserver(name, function settingChanged(evt) {
callback(evt.settingValue);
});
}
};
SettingsListener.init();
// =================== Console ======================
SettingsListener.observe('debug.console.enabled', true, function(value) {

View File

@ -1,4 +1,4 @@
{
"revision": "752ced5b3cc3208f79806eccf8d8768910f17f2b",
"revision": "4296bbf526e4ed8d0ae443f20947bd2d7189aa0e",
"repo_path": "/integration/gaia-central"
}

View File

@ -646,7 +646,10 @@ BluetoothHfpManager::HandleIccInfoChanged()
nsCOMPtr<nsIDOMMozIccInfo> iccInfo;
icc->GetIccInfo(getter_AddRefs(iccInfo));
NS_ENSURE_TRUE_VOID(iccInfo);
iccInfo->GetMsisdn(mMsisdn);
nsCOMPtr<nsIDOMMozGsmIccInfo> gsmIccInfo = do_QueryInterface(iccInfo);
NS_ENSURE_TRUE_VOID(gsmIccInfo);
gsmIccInfo->GetMsisdn(mMsisdn);
}
void

View File

@ -25,6 +25,7 @@
#include "mozilla/dom/ContentParent.h"
#include "mozilla/dom/bluetooth/BluetoothTypes.h"
#include "mozilla/ipc/UnixSocket.h"
#include "mozilla/LazyIdleThread.h"
#include "nsContentUtils.h"
#include "nsCxPusher.h"
#include "nsIObserverService.h"
@ -54,6 +55,7 @@
#define PROP_BLUETOOTH_ENABLED "bluetooth.isEnabled"
#define DEFAULT_THREAD_TIMEOUT_MS 3000
#define DEFAULT_SHUTDOWN_TIMER_MS 5000
bool gBluetoothDebugFlag = false;
@ -145,19 +147,8 @@ public:
gBluetoothService->DistributeSignal(signal);
}
if (!mEnabled || gInShutdown) {
// Shut down the command thread if it still exists.
if (gBluetoothService->mBluetoothCommandThread) {
nsCOMPtr<nsIThread> thread;
gBluetoothService->mBluetoothCommandThread.swap(thread);
if (NS_FAILED(thread->Shutdown())) {
NS_WARNING("Failed to shut down the bluetooth command thread!");
}
}
if (gInShutdown) {
gBluetoothService = nullptr;
}
if (gInShutdown) {
gBluetoothService = nullptr;
}
return NS_OK;
@ -461,22 +452,13 @@ BluetoothService::StartStopBluetooth(bool aStart, bool aIsStartup)
return NS_ERROR_FAILURE;
}
if (!mBluetoothCommandThread) {
if (!mBluetoothThread) {
// Don't create a new thread after we've begun shutdown since bluetooth
// can't be running.
return NS_OK;
}
}
nsresult rv;
if (!mBluetoothCommandThread) {
MOZ_ASSERT(!gInShutdown);
rv = NS_NewNamedThread("BluetoothCmd",
getter_AddRefs(mBluetoothCommandThread));
NS_ENSURE_SUCCESS(rv, rv);
}
if (!aStart) {
BluetoothHfpManager* hfp = BluetoothHfpManager::Get();
hfp->Disconnect();
@ -485,8 +467,14 @@ BluetoothService::StartStopBluetooth(bool aStart, bool aIsStartup)
opp->Disconnect();
}
if (!mBluetoothThread) {
mBluetoothThread = new LazyIdleThread(DEFAULT_THREAD_TIMEOUT_MS,
NS_LITERAL_CSTRING("Bluetooth"),
LazyIdleThread::ManualShutdown);
}
nsCOMPtr<nsIRunnable> runnable = new ToggleBtTask(aStart, aIsStartup);
rv = mBluetoothCommandThread->Dispatch(runnable, NS_DISPATCH_NORMAL);
nsresult rv = mBluetoothThread->Dispatch(runnable, NS_DISPATCH_NORMAL);
NS_ENSURE_SUCCESS(rv, rv);
return NS_OK;
@ -814,13 +802,3 @@ BluetoothService::Notify(const BluetoothSignal& aData)
OBJECT_TO_JSVAL(obj),
JS::UndefinedValue());
}
void
BluetoothService::DispatchToCommandThread(nsRunnable* aRunnable)
{
MOZ_ASSERT(NS_IsMainThread());
MOZ_ASSERT(aRunnable);
MOZ_ASSERT(mBluetoothCommandThread);
mBluetoothCommandThread->Dispatch(aRunnable, NS_DISPATCH_NORMAL);
}

View File

@ -47,7 +47,7 @@ public:
NS_DECL_ISUPPORTS
NS_DECL_NSIOBSERVER
/**
/**
* Add a message handler object from message distribution observer.
* Must be called from the main thread.
*
@ -58,7 +58,7 @@ public:
RegisterBluetoothSignalHandler(const nsAString& aNodeName,
BluetoothSignalObserver* aMsgHandler);
/**
/**
* Remove a message handler object from message distribution observer.
* Must be called from the main thread.
*
@ -69,7 +69,7 @@ public:
UnregisterBluetoothSignalHandler(const nsAString& aNodeName,
BluetoothSignalObserver* aMsgHandler);
/**
/**
* Remove a message handlers for the given observer.
* Must be called from the main thread.
*
@ -78,7 +78,7 @@ public:
void
UnregisterAllSignalHandlers(BluetoothSignalObserver* aMsgHandler);
/**
/**
* Distribute a signal to the observer list
*
* @param aSignal Signal object to distribute
@ -150,7 +150,7 @@ public:
virtual nsresult
StopDiscoveryInternal(BluetoothReplyRunnable* aRunnable) = 0;
/**
/**
* Start device discovery (platform specific implementation)
*
* @return NS_OK if discovery stopped correctly, false otherwise
@ -307,9 +307,6 @@ public:
void
RemoveObserverFromTable(const nsAString& key);
void
DispatchToCommandThread(nsRunnable* aRunnable);
protected:
BluetoothService()
: mEnabled(false)
@ -328,7 +325,7 @@ protected:
nsresult
StartStopBluetooth(bool aStart, bool aIsStartup);
/**
/**
* Platform specific startup functions go here. Usually deals with member
* variables, so not static. Guaranteed to be called outside of main thread.
*
@ -387,26 +384,21 @@ protected:
static BluetoothService*
Create();
/**
* Due to the fact that some operations require multiple calls, a
* CommandThread is created that can run blocking, platform-specific calls
* where either no asynchronous equivilent exists, or else where multiple
* asynchronous calls would require excessive runnable bouncing between main
* thread and IO thread.
*
* For instance, when we retrieve an Adapter object, we would like it to come
* with all of its properties filled in and registered as an agent, which
* requires a minimum of 3 calls to platform specific code on some platforms.
*
*/
nsCOMPtr<nsIThread> mBluetoothCommandThread;
typedef nsClassHashtable<nsStringHashKey, BluetoothSignalObserverList >
BluetoothSignalObserverTable;
BluetoothSignalObserverTable mBluetoothSignalObserverTable;
bool mEnabled;
private:
/**
* Due to the fact that the startup and shutdown of the Bluetooth system
* can take an indefinite amount of time, a command thread is created
* that can run blocking calls. The thread is not intended for regular
* Bluetooth operations though.
*/
nsCOMPtr<nsIThread> mBluetoothThread;
};
END_BLUETOOTH_NAMESPACE

View File

@ -183,6 +183,12 @@ const ContentPanning = {
this.position.set(screenX, screenY);
KineticPanning.record(new Point(0, 0), evt.timeStamp);
// We prevent start events to avoid sending a focus event at the end of this
// touch series. See bug 889717.
if (this.panning || this.preventNextClick) {
evt.preventDefault();
}
},
onTouchEnd: function cp_onTouchEnd(evt) {
@ -214,10 +220,15 @@ const ContentPanning = {
}
if (this.target && click && (this.panning || this.preventNextClick)) {
let target = this.target;
let view = target.ownerDocument ? target.ownerDocument.defaultView
: target;
view.addEventListener('click', this, true, true);
if (this.hybridEvents) {
let target = this.target;
let view = target.ownerDocument ? target.ownerDocument.defaultView
: target;
view.addEventListener('click', this, true, true);
} else {
// We prevent end events to avoid sending a focus event. See bug 889717.
evt.preventDefault();
}
}
this._finishPanning();

View File

@ -4,10 +4,17 @@
#include "nsISupports.idl"
[scriptable, uuid(a45c0fe0-c911-11e2-8b8b-0800200c9a66)]
[scriptable, uuid(dd9f229c-e5a6-453a-8388-950af0ff9918)]
interface nsIDOMMozIccInfo : nsISupports
{
/**
/**
* Integrated Circuit Card Type.
*
* Possible values: "sim", "usim", "ruim".
*/
readonly attribute DOMString iccType;
/**
* Integrated Circuit Card Identifier.
*/
readonly attribute DOMString iccid;
@ -36,10 +43,28 @@ interface nsIDOMMozIccInfo : nsISupports
* Service provider name must be a part of displayed carrier name.
*/
readonly attribute boolean isDisplaySpnRequired;
};
[scriptable, uuid(3c237e39-7af3-4748-baf4-4a3b6c3e0e66)]
interface nsIDOMMozGsmIccInfo : nsIDOMMozIccInfo
{
/**
* Mobile Station ISDN Number (MSISDN) of the subscriber's, aka
* Mobile Station ISDN Number (MSISDN) of the subscriber, aka
* his phone number.
*/
readonly attribute DOMString msisdn;
};
[scriptable, uuid(013e973e-8b56-4525-b634-d23166b86edb)]
interface nsIDOMMozCdmaIccInfo : nsIDOMMozIccInfo
{
/**
* Mobile Directory Number (MDN) of the subscriber, aka his phone number.
*/
readonly attribute DOMString mdn;
/**
* Mobile Identification Number (MIN) of the subscriber.
*/
readonly attribute DOMString min;
};

View File

@ -280,6 +280,8 @@ interface nsIDOMMozIccManager : nsIDOMEventTarget
/**
* Information stored in the device's ICC card.
*
* Null if the card is not detected.
*/
readonly attribute nsIDOMMozIccInfo iccInfo;

View File

@ -17,6 +17,8 @@ ifr.onload = function() {
iccInfo = icc.iccInfo;
is(iccInfo.iccType, "sim");
// The emulator's hard coded iccid value.
// See it here {B2G_HOME}/external/qemu/telephony/sim_card.c#L299.
is(iccInfo.iccid, 89014103211118510720);
@ -30,15 +32,7 @@ ifr.onload = function() {
// See {B2G_HOME}/external/qemu/telephony/sim_card.c, in asimcard_io()
is(iccInfo.msisdn, "15555215554");
testDisplayConditionChange(testSPN, [
// [MCC, MNC, isDisplayNetworkNameRequired, isDisplaySpnRequired]
[123, 456, false, true], // Not in HPLMN.
[234, 136, true, true], // Not in HPLMN, but in PLMN specified in SPDI.
[123, 456, false, true], // Not in HPLMN. Triggering iccinfochange
[466, 92, true, true], // Not in HPLMN, but in another PLMN specified in SPDI.
[123, 456, false, true], // Not in HPLMN. Triggering iccinfochange
[310, 260, true, true], // inside HPLMN.
], finalize);
runNextTest();
};
document.body.appendChild(ifr);
@ -60,6 +54,25 @@ function setEmulatorMccMnc(mcc, mnc) {
});
}
function setAirplaneModeEnabled(enabled) {
let settings = ifr.contentWindow.navigator.mozSettings;
let setLock = settings.createLock();
let obj = {
"ril.radio.disabled": enabled
};
let setReq = setLock.set(obj);
log("set airplane mode to " + enabled);
setReq.addEventListener("success", function onSetSuccess() {
log("set 'ril.radio.disabled' to " + enabled);
});
setReq.addEventListener("error", function onSetError() {
ok(false, "cannot set 'ril.radio.disabled' to " + enabled);
});
}
function waitForIccInfoChange(callback) {
icc.addEventListener("iccinfochange", function handler() {
icc.removeEventListener("iccinfochange", handler);
@ -67,9 +80,15 @@ function waitForIccInfoChange(callback) {
});
}
function finalize() {
SpecialPowers.removePermission("mobileconnection", document);
finish();
function waitForCardStateChange(expectedCardState, callback) {
icc.addEventListener("cardstatechange", function oncardstatechange() {
log("card state changes to " + icc.cardState);
if (icc.cardState === expectedCardState) {
log("got expected card state: " + icc.cardState);
icc.removeEventListener("cardstatechange", oncardstatechange);
callback();
}
});
}
// Test display condition change.
@ -93,3 +112,45 @@ function testSPN(mcc, mnc, expectedIsDisplayNetworkNameRequired,
});
setEmulatorMccMnc(mcc, mnc);
}
// Test iccInfo when card is not ready
function testCardIsNotReady() {
// Enable airplane mode
setAirplaneModeEnabled(true);
waitForCardStateChange(null, function callback() {
is(icc.iccInfo, null);
// Disable airplane mode
setAirplaneModeEnabled(false);
waitForCardStateChange("ready", runNextTest);
});
}
let tests = [
testDisplayConditionChange.bind(this, testSPN, [
// [MCC, MNC, isDisplayNetworkNameRequired, isDisplaySpnRequired]
[123, 456, false, true], // Not in HPLMN.
[234, 136, true, true], // Not in HPLMN, but in PLMN specified in SPDI.
[123, 456, false, true], // Not in HPLMN. Triggering iccinfochange
[466, 92, true, true], // Not in HPLMN, but in another PLMN specified in SPDI.
[123, 456, false, true], // Not in HPLMN. Triggering iccinfochange
[310, 260, true, true], // inside HPLMN.
], runNextTest),
testCardIsNotReady
];
function runNextTest() {
let test = tests.shift();
if (!test) {
finalize();
return;
}
test();
}
function finalize() {
SpecialPowers.removePermission("mobileconnection", document);
finish();
}

View File

@ -11,10 +11,10 @@ interface nsIDOMDOMCursor;
interface nsIDOMDOMRequest;
interface nsIDOMBlob;
[scriptable, builtinclass, uuid(efff5276-0f3f-4137-9b16-66e894400e01)]
[scriptable, builtinclass, uuid(3f81dcbc-00cf-11e3-ae66-538115636543)]
interface nsIDOMMozMobileMessageManager : nsIDOMEventTarget
{
nsIDOMMozSmsSegmentInfo getSegmentInfoForText(in DOMString text);
nsIDOMDOMRequest getSegmentInfoForText(in DOMString text);
// The first parameter can be either a DOMString (only one number) or an array
// of DOMStrings.

View File

@ -3,6 +3,7 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "nsISupports.idl"
#include "nsIDOMSmsSegmentInfo.idl"
dictionary SmsThreadListItem
{
@ -13,7 +14,7 @@ dictionary SmsThreadListItem
unsigned long long unreadCount;
};
[scriptable, uuid(ea5fb581-bee7-40a6-b2dc-c98b99a2dc49)]
[scriptable, uuid(399125a8-00d2-11e3-8d12-3fba4465c097)]
interface nsIMobileMessageCallback : nsISupports
{
/**
@ -48,4 +49,7 @@ interface nsIMobileMessageCallback : nsISupports
void notifyMessageMarkedRead(in boolean read);
void notifyMarkMessageReadFailed(in long error);
void notifySegmentInfoForTextGot(in nsIDOMMozSmsSegmentInfo info);
void notifyGetSegmentInfoForTextFailed(in long error);
};

View File

@ -13,12 +13,13 @@ interface nsIMobileMessageCallback;
#define SMS_SERVICE_CONTRACTID "@mozilla.org/sms/smsservice;1"
%}
[scriptable, builtinclass, uuid(f0d5d11b-0326-4cb1-bb76-a3f912212287)]
[scriptable, builtinclass, uuid(0f3f75ec-00dd-11e3-87ac-0b1d5c79afdf)]
interface nsISmsService : nsISupports
{
boolean hasSupport();
nsIDOMMozSmsSegmentInfo getSegmentInfoForText(in DOMString text);
void getSegmentInfoForText(in DOMString text,
in nsIMobileMessageCallback request);
void send(in DOMString number,
in DOMString message,

View File

@ -8,6 +8,7 @@
#include "nsCxPusher.h"
#include "nsIDOMMozSmsMessage.h"
#include "nsIDOMMozMmsMessage.h"
#include "nsIDOMSmsSegmentInfo.h"
#include "nsIScriptGlobalObject.h"
#include "nsPIDOMWindow.h"
#include "MmsMessage.h"
@ -39,14 +40,22 @@ MobileMessageCallback::~MobileMessageCallback()
nsresult
MobileMessageCallback::NotifySuccess(JS::Handle<JS::Value> aResult)
MobileMessageCallback::NotifySuccess(JS::Handle<JS::Value> aResult, bool aAsync)
{
if (aAsync) {
nsCOMPtr<nsIDOMRequestService> rs =
do_GetService(DOMREQUEST_SERVICE_CONTRACTID);
NS_ENSURE_TRUE(rs, NS_ERROR_FAILURE);
return rs->FireSuccessAsync(mDOMRequest, aResult);
}
mDOMRequest->FireSuccess(aResult);
return NS_OK;
}
nsresult
MobileMessageCallback::NotifySuccess(nsISupports *aMessage)
MobileMessageCallback::NotifySuccess(nsISupports *aMessage, bool aAsync)
{
nsresult rv;
nsIScriptContext* scriptContext = mDOMRequest->GetContextForEventHandlers(&rv);
@ -66,38 +75,48 @@ MobileMessageCallback::NotifySuccess(nsISupports *aMessage)
wrappedMessage.address());
NS_ENSURE_SUCCESS(rv, rv);
return NotifySuccess(wrappedMessage);
return NotifySuccess(wrappedMessage, aAsync);
}
nsresult
MobileMessageCallback::NotifyError(int32_t aError)
MobileMessageCallback::NotifyError(int32_t aError, bool aAsync)
{
nsAutoString errorStr;
switch (aError) {
case nsIMobileMessageCallback::NO_SIGNAL_ERROR:
mDOMRequest->FireError(NS_LITERAL_STRING("NoSignalError"));
errorStr = NS_LITERAL_STRING("NoSignalError");
break;
case nsIMobileMessageCallback::NOT_FOUND_ERROR:
mDOMRequest->FireError(NS_LITERAL_STRING("NotFoundError"));
errorStr = NS_LITERAL_STRING("NotFoundError");
break;
case nsIMobileMessageCallback::UNKNOWN_ERROR:
mDOMRequest->FireError(NS_LITERAL_STRING("UnknownError"));
errorStr = NS_LITERAL_STRING("UnknownError");
break;
case nsIMobileMessageCallback::INTERNAL_ERROR:
mDOMRequest->FireError(NS_LITERAL_STRING("InternalError"));
errorStr = NS_LITERAL_STRING("InternalError");
break;
case nsIMobileMessageCallback::NO_SIM_CARD_ERROR:
mDOMRequest->FireError(NS_LITERAL_STRING("NoSimCardError"));
errorStr = NS_LITERAL_STRING("NoSimCardError");
break;
case nsIMobileMessageCallback::RADIO_DISABLED_ERROR:
mDOMRequest->FireError(NS_LITERAL_STRING("RadioDisabledError"));
errorStr = NS_LITERAL_STRING("RadioDisabledError");
break;
case nsIMobileMessageCallback::INVALID_ADDRESS_ERROR:
mDOMRequest->FireError(NS_LITERAL_STRING("InvalidAddressError"));
errorStr = NS_LITERAL_STRING("InvalidAddressError");
break;
default: // SUCCESS_NO_ERROR is handled above.
MOZ_CRASH("Should never get here!");
}
if (aAsync) {
nsCOMPtr<nsIDOMRequestService> rs =
do_GetService(DOMREQUEST_SERVICE_CONTRACTID);
NS_ENSURE_TRUE(rs, NS_ERROR_FAILURE);
return rs->FireErrorAsync(mDOMRequest, errorStr);
}
mDOMRequest->FireError(errorStr);
return NS_OK;
}
@ -173,6 +192,18 @@ MobileMessageCallback::NotifyMarkMessageReadFailed(int32_t aError)
return NotifyError(aError);
}
NS_IMETHODIMP
MobileMessageCallback::NotifySegmentInfoForTextGot(nsIDOMMozSmsSegmentInfo *aInfo)
{
return NotifySuccess(aInfo, true);
}
NS_IMETHODIMP
MobileMessageCallback::NotifyGetSegmentInfoForTextFailed(int32_t aError)
{
return NotifyError(aError, true);
}
} // namesapce mobilemessage
} // namespace dom
} // namespace mozilla

View File

@ -29,9 +29,9 @@ private:
nsRefPtr<DOMRequest> mDOMRequest;
nsresult NotifySuccess(JS::Handle<JS::Value> aResult);
nsresult NotifySuccess(nsISupports *aMessage);
nsresult NotifyError(int32_t aError);
nsresult NotifySuccess(JS::Handle<JS::Value> aResult, bool aAsync = false);
nsresult NotifySuccess(nsISupports *aMessage, bool aAsync = false);
nsresult NotifyError(int32_t aError, bool aAsync = false);
};
} // namespace mobilemessage

View File

@ -101,12 +101,19 @@ MobileMessageManager::Shutdown()
NS_IMETHODIMP
MobileMessageManager::GetSegmentInfoForText(const nsAString& aText,
nsIDOMMozSmsSegmentInfo** aResult)
nsIDOMDOMRequest** aRequest)
{
nsCOMPtr<nsISmsService> smsService = do_GetService(SMS_SERVICE_CONTRACTID);
NS_ENSURE_TRUE(smsService, NS_ERROR_FAILURE);
return smsService->GetSegmentInfoForText(aText, aResult);
nsRefPtr<DOMRequest> request = new DOMRequest(GetOwner());
nsCOMPtr<nsIMobileMessageCallback> msgCallback =
new MobileMessageCallback(request);
nsresult rv = smsService->GetSegmentInfoForText(aText, msgCallback);
NS_ENSURE_SUCCESS(rv, rv);
request.forget(aRequest);
return NS_OK;
}
nsresult

View File

@ -55,5 +55,11 @@ SmsSegmentInfo::GetCharsAvailableInLastSegment(int32_t* aCharsAvailableInLastSeg
return NS_OK;
}
const SmsSegmentInfoData&
SmsSegmentInfo::GetData() const
{
return mData;
}
} // namespace dom
} // namespace mozilla

View File

@ -22,8 +22,11 @@ public:
SmsSegmentInfo(int32_t aSegments,
int32_t aCharsPerSegment,
int32_t aCharsAvailableInLastSegment);
SmsSegmentInfo(const mobilemessage::SmsSegmentInfoData& aData);
const mobilemessage::SmsSegmentInfoData& GetData() const;
private:
mobilemessage::SmsSegmentInfoData mData;
};

View File

@ -23,19 +23,16 @@ SmsService::HasSupport(bool* aHasSupport)
}
NS_IMETHODIMP
SmsService::GetSegmentInfoForText(const nsAString & aText,
nsIDOMMozSmsSegmentInfo** aResult)
SmsService::GetSegmentInfoForText(const nsAString& aText,
nsIMobileMessageCallback* aRequest)
{
if (!AndroidBridge::Bridge()) {
return NS_ERROR_FAILURE;
}
SmsSegmentInfoData data;
nsresult rv = AndroidBridge::Bridge()->GetSegmentInfoForText(aText, &data);
nsresult rv = AndroidBridge::Bridge()->GetSegmentInfoForText(aText, aRequest);
NS_ENSURE_SUCCESS(rv, rv);
nsCOMPtr<nsIDOMMozSmsSegmentInfo> info = new SmsSegmentInfo(data);
info.forget(aResult);
return NS_OK;
}

View File

@ -22,8 +22,8 @@ SmsService::HasSupport(bool* aHasSupport)
}
NS_IMETHODIMP
SmsService::GetSegmentInfoForText(const nsAString & aText,
nsIDOMMozSmsSegmentInfo** aResult)
SmsService::GetSegmentInfoForText(const nsAString& aText,
nsIMobileMessageCallback* aRequest)
{
NS_ERROR("We should not be here!");
return NS_ERROR_FAILURE;

View File

@ -11,6 +11,8 @@ Cu.import("resource://gre/modules/WspPduHelper.jsm", WSP);
Cu.import("resource://gre/modules/mms_consts.js");
Cu.import("resource://gre/modules/PhoneNumberUtils.jsm");
let DEBUG; // set to true to see debug messages
this.MMS_VERSION = (function () {
@ -178,6 +180,33 @@ this.Address = {
EncodedStringValue.encode(data, str);
},
/**
* @param address
* Address string which want to find the type.
*
* @return Address type.
*/
resolveType: function resolveType(address) {
if (address.match(this.REGEXP_EMAIL)) {
return "email";
}
if (address.match(this.REGEXP_IPV4)) {
return "IPv4";
}
if (address.match(this.REGEXP_IPV6)) {
return "IPv6";
}
let normalizedAddress = PhoneNumberUtils.normalize(address, false);
if (PhoneNumberUtils.isPlainPhoneNumber(normalizedAddress)) {
return "PLMN";
}
return "Others";
},
};
defineLazyRegExp(Address, "REGEXP_DECODE_PLMN", "^(\\+?[\\d.-]+)\\/TYPE=(PLMN)$");
@ -191,6 +220,10 @@ defineLazyRegExp(Address, "REGEXP_ENCODE_CUSTOM_TYPE", "^\\w+$");
defineLazyRegExp(Address, "REGEXP_ENCODE_CUSTOM_ADDR", "^[\\w\\+\\-.%]+$");
defineLazyRegExp(Address, "REGEXP_NUM", "^[\\+*#]\\d+$");
defineLazyRegExp(Address, "REGEXP_ALPHANUM", "^\\w+$");
defineLazyRegExp(Address, "REGEXP_PLMN", "^\\?[\\d.-]$");
defineLazyRegExp(Address, "REGEXP_IPV4", "^\\d{1,3}(?:\\.\\d{1,3}){3}$");
defineLazyRegExp(Address, "REGEXP_IPV6", "^[\\da-fA-F]{4}(?::[\\da-fA-F]{4}){7}$");
defineLazyRegExp(Address, "REGEXP_EMAIL", "@");
/**
* Header-field = MMS-header | Application-header

View File

@ -1687,18 +1687,22 @@ MmsService.prototype = {
if (receivers.length != 0) {
let headersTo = headers["to"] = [];
for (let i = 0; i < receivers.length; i++) {
let normalizedAddress = PhoneNumberUtils.normalize(receivers[i], false);
if (DEBUG) debug("createSavableFromParams: normalize phone number " +
"from " + receivers[i] + " to " + normalizedAddress);
headersTo.push({"address": normalizedAddress, "type": "PLMN"});
// Check if the address is valid to send MMS.
if (!PhoneNumberUtils.isPlainPhoneNumber(normalizedAddress)) {
if (DEBUG) debug("Error! Address is invalid to send MMS: " +
normalizedAddress);
let receiver = receivers[i];
let type = MMS.Address.resolveType(receiver);
let address;
if (type == "PLMN") {
address = PhoneNumberUtils.normalize(receiver, false);
if (!PhoneNumberUtils.isPlainPhoneNumber(address)) {
isAddrValid = false;
}
if (DEBUG) debug("createSavableFromParams: normalize phone number " +
"from " + receiver + " to " + address);
} else {
address = receiver;
isAddrValid = false;
if (DEBUG) debug("Error! Address is invalid to send MMS: " + address);
}
headersTo.push({"address": address, "type": type});
}
}
if (aParams.subject) {

View File

@ -31,12 +31,12 @@ SmsService::HasSupport(bool* aHasSupport)
}
NS_IMETHODIMP
SmsService::GetSegmentInfoForText(const nsAString & aText,
nsIDOMMozSmsSegmentInfo** aResult)
SmsService::GetSegmentInfoForText(const nsAString& aText,
nsIMobileMessageCallback* aRequest)
{
NS_ENSURE_TRUE(mRadioInterface, NS_ERROR_FAILURE);
return mRadioInterface->GetSegmentInfoForText(aText, aResult);
return mRadioInterface->GetSegmentInfoForText(aText, aRequest);
}
NS_IMETHODIMP

View File

@ -62,6 +62,11 @@ struct MarkMessageReadRequest
bool value;
};
struct GetSegmentInfoForTextRequest
{
nsString text;
};
struct CreateThreadCursorRequest
{
};
@ -73,6 +78,7 @@ union IPCSmsRequest
GetMessageRequest;
DeleteMessageRequest;
MarkMessageReadRequest;
GetSegmentInfoForTextRequest;
};
union IPCMobileMessageCursor
@ -122,9 +128,6 @@ parent:
sync HasSupport()
returns (bool aHasSupport);
sync GetSegmentInfoForText(nsString aText)
returns (SmsSegmentInfoData aResult);
AddSilentNumber(nsString aNumber);
RemoveSilentNumber(nsString aNumber);
};

View File

@ -66,6 +66,16 @@ struct ReplyMarkeMessageReadFail
int32_t error;
};
struct ReplyGetSegmentInfoForText
{
SmsSegmentInfoData infoData;
};
struct ReplyGetSegmentInfoForTextFail
{
int32_t error;
};
union MessageReply
{
ReplyMessageSend;
@ -76,6 +86,8 @@ union MessageReply
ReplyMessageDeleteFail;
ReplyMarkeMessageRead;
ReplyMarkeMessageReadFail;
ReplyGetSegmentInfoForText;
ReplyGetSegmentInfoForTextFail;
};
} // namespace mobilemessage

View File

@ -5,6 +5,7 @@
#include "SmsChild.h"
#include "SmsMessage.h"
#include "MmsMessage.h"
#include "SmsSegmentInfo.h"
#include "Constants.h"
#include "nsIObserverService.h"
#include "mozilla/Services.h"
@ -22,7 +23,7 @@ CreateMessageFromMessageData(const MobileMessageData& aData)
{
nsCOMPtr<nsISupports> message;
switch(aData. type()) {
switch(aData.type()) {
case MobileMessageData::TMmsMessageData:
message = new MmsMessage(aData.get_MmsMessageData());
break;
@ -203,6 +204,17 @@ SmsRequestChild::Recv__delete__(const MessageReply& aReply)
case MessageReply::TReplyMarkeMessageReadFail:
mReplyRequest->NotifyMarkMessageReadFailed(aReply.get_ReplyMarkeMessageReadFail().error());
break;
case MessageReply::TReplyGetSegmentInfoForText: {
const SmsSegmentInfoData& data =
aReply.get_ReplyGetSegmentInfoForText().infoData();
nsCOMPtr<nsIDOMMozSmsSegmentInfo> info = new SmsSegmentInfo(data);
mReplyRequest->NotifySegmentInfoForTextGot(info);
}
break;
case MessageReply::TReplyGetSegmentInfoForTextFail:
mReplyRequest->NotifyGetSegmentInfoForTextFailed(
aReply.get_ReplyGetSegmentInfoForTextFail().error());
break;
default:
MOZ_CRASH("Received invalid response parameters!");
}

View File

@ -96,19 +96,11 @@ SmsIPCService::HasSupport(bool* aHasSupport)
}
NS_IMETHODIMP
SmsIPCService::GetSegmentInfoForText(const nsAString & aText,
nsIDOMMozSmsSegmentInfo** aResult)
SmsIPCService::GetSegmentInfoForText(const nsAString& aText,
nsIMobileMessageCallback* aRequest)
{
PSmsChild* smsChild = GetSmsChild();
NS_ENSURE_TRUE(smsChild, NS_ERROR_FAILURE);
SmsSegmentInfoData data;
bool ok = smsChild->SendGetSegmentInfoForText(nsString(aText), &data);
NS_ENSURE_TRUE(ok, NS_ERROR_FAILURE);
nsCOMPtr<nsIDOMMozSmsSegmentInfo> info = new SmsSegmentInfo(data);
info.forget(aResult);
return NS_OK;
return SendRequest(GetSegmentInfoForTextRequest(nsString(aText)),
aRequest);
}
NS_IMETHODIMP

View File

@ -311,35 +311,6 @@ SmsParent::RecvHasSupport(bool* aHasSupport)
return true;
}
bool
SmsParent::RecvGetSegmentInfoForText(const nsString& aText,
SmsSegmentInfoData* aResult)
{
aResult->segments() = 0;
aResult->charsPerSegment() = 0;
aResult->charsAvailableInLastSegment() = 0;
nsCOMPtr<nsISmsService> smsService = do_GetService(SMS_SERVICE_CONTRACTID);
NS_ENSURE_TRUE(smsService, true);
nsCOMPtr<nsIDOMMozSmsSegmentInfo> info;
nsresult rv = smsService->GetSegmentInfoForText(aText, getter_AddRefs(info));
NS_ENSURE_SUCCESS(rv, true);
int segments, charsPerSegment, charsAvailableInLastSegment;
if (NS_FAILED(info->GetSegments(&segments)) ||
NS_FAILED(info->GetCharsPerSegment(&charsPerSegment)) ||
NS_FAILED(info->GetCharsAvailableInLastSegment(&charsAvailableInLastSegment))) {
NS_ERROR("Can't get attribute values from nsIDOMMozSmsSegmentInfo");
return true;
}
aResult->segments() = segments;
aResult->charsPerSegment() = charsPerSegment;
aResult->charsAvailableInLastSegment() = charsAvailableInLastSegment;
return true;
}
bool
SmsParent::RecvAddSilentNumber(const nsString& aNumber)
{
@ -393,6 +364,8 @@ SmsParent::RecvPSmsRequestConstructor(PSmsRequestParent* aActor,
return actor->DoRequest(aRequest.get_DeleteMessageRequest());
case IPCSmsRequest::TMarkMessageReadRequest:
return actor->DoRequest(aRequest.get_MarkMessageReadRequest());
case IPCSmsRequest::TGetSegmentInfoForTextRequest:
return actor->DoRequest(aRequest.get_GetSegmentInfoForTextRequest());
default:
MOZ_CRASH("Unknown type!");
}
@ -577,6 +550,24 @@ SmsRequestParent::DoRequest(const MarkMessageReadRequest& aRequest)
return true;
}
bool
SmsRequestParent::DoRequest(const GetSegmentInfoForTextRequest& aRequest)
{
nsresult rv = NS_ERROR_FAILURE;
nsCOMPtr<nsISmsService> smsService = do_GetService(SMS_SERVICE_CONTRACTID);
if (smsService) {
rv = smsService->GetSegmentInfoForText(aRequest.text(), this);
}
if (NS_FAILED(rv)) {
return NS_SUCCEEDED(NotifyGetSegmentInfoForTextFailed(
nsIMobileMessageCallback::INTERNAL_ERROR));
}
return true;
}
nsresult
SmsRequestParent::SendReply(const MessageReply& aReply)
{
@ -674,6 +665,19 @@ SmsRequestParent::NotifyMarkMessageReadFailed(int32_t aError)
return SendReply(ReplyMarkeMessageReadFail(aError));
}
NS_IMETHODIMP
SmsRequestParent::NotifySegmentInfoForTextGot(nsIDOMMozSmsSegmentInfo *aInfo)
{
SmsSegmentInfo* info = static_cast<SmsSegmentInfo*>(aInfo);
return SendReply(ReplyGetSegmentInfoForText(info->GetData()));
}
NS_IMETHODIMP
SmsRequestParent::NotifyGetSegmentInfoForTextFailed(int32_t aError)
{
return SendReply(ReplyGetSegmentInfoForTextFail(aError));
}
/*******************************************************************************
* MobileMessageCursorParent
******************************************************************************/

View File

@ -34,9 +34,6 @@ protected:
virtual bool
RecvHasSupport(bool* aHasSupport) MOZ_OVERRIDE;
virtual bool
RecvGetSegmentInfoForText(const nsString& aText, SmsSegmentInfoData* aResult) MOZ_OVERRIDE;
virtual bool
RecvAddSilentNumber(const nsString& aNumber) MOZ_OVERRIDE;
@ -120,6 +117,9 @@ protected:
bool
DoRequest(const MarkMessageReadRequest& aRequest);
bool
DoRequest(const GetSegmentInfoForTextRequest& aRequest);
nsresult
SendReply(const MessageReply& aReply);
};

View File

@ -49,13 +49,31 @@ let tasks = {
function addTest(text, segments, charsPerSegment, charsAvailableInLastSegment) {
tasks.push(function () {
log("Testing '" + text + "' ...");
let info = manager.getSegmentInfoForText(text);
is(info.segments, segments, "info.segments");
is(info.charsPerSegment, charsPerSegment, "info.charsPerSegment");
is(info.charsAvailableInLastSegment, charsAvailableInLastSegment,
"info.charsAvailableInLastSegment");
let domRequest = manager.getSegmentInfoForText(text);
ok(domRequest, "DOMRequest object returned.");
tasks.next();
domRequest.onsuccess = function(e) {
log("Received 'onsuccess' DOMRequest event.");
let result = e.target.result;
if (!result) {
ok(false, "getSegmentInfoForText() result is not valid.");
tasks.finish();
return;
}
is(result.segments, segments, "info.segments");
is(result.charsPerSegment, charsPerSegment, "info.charsPerSegment");
is(result.charsAvailableInLastSegment, charsAvailableInLastSegment,
"info.charsAvailableInLastSegment");
tasks.next();
};
domRequest.onerror = function(e) {
ok(false, "Failed to call getSegmentInfoForText().");
tasks.finish();
};
});
}
@ -63,9 +81,9 @@ function addTestThrows(text) {
tasks.push(function () {
log("Testing '" + text + "' ...");
try {
let info = manager.getSegmentInfoForText(text);
let domRequest = manager.getSegmentInfoForText(text);
ok(false, "Not thrown");
ok(false, "Not thrown.");
tasks.finish();
} catch (e) {
tasks.next();

View File

@ -12,7 +12,8 @@ const LEN_UCS2_WITH_16BIT_REF = 66;
SpecialPowers.setBoolPref("dom.sms.enabled", true);
let currentStrict7BitEncoding = false;
SpecialPowers.setBoolPref("dom.sms.strict7BitEncoding", currentStrict7BitEncoding);
SpecialPowers.setBoolPref("dom.sms.strict7BitEncoding",
currentStrict7BitEncoding);
SpecialPowers.addPermission("sms", true, document);
let manager = window.navigator.mozMobileMessage;
@ -23,107 +24,165 @@ function times(str, n) {
return (new Array(n + 1)).join(str);
}
function doTest(text, strict7BitEncoding, expected) {
if (strict7BitEncoding != currentStrict7BitEncoding) {
currentStrict7BitEncoding = strict7BitEncoding;
SpecialPowers.setBoolPref("dom.sms.strict7BitEncoding", currentStrict7BitEncoding);
let tasks = {
// List of test fuctions. Each of them should call |tasks.next()| when
// completed or |tasks.finish()| to jump to the last one.
_tasks: [],
_nextTaskIndex: 0,
push: function push(func) {
this._tasks.push(func);
},
next: function next() {
let index = this._nextTaskIndex++;
let task = this._tasks[index];
try {
task();
} catch (ex) {
ok(false, "test task[" + index + "] throws: " + ex);
// Run last task as clean up if possible.
if (index != this._tasks.length - 1) {
this.finish();
}
}
},
finish: function finish() {
this._tasks[this._tasks.length - 1]();
},
run: function run() {
this.next();
}
};
let result = manager.getSegmentInfoForText(text);
ok(result, "result of GetSegmentInfoForText is valid");
is(result.segments, expected[0], "segments");
is(result.charsPerSegment, expected[1], "charsPerSegment");
is(result.charsAvailableInLastSegment, expected[2], "charsAvailableInLastSegment");
}
function addTest(text, strict7BitEncoding, expected) {
tasks.push(function () {
if (strict7BitEncoding != currentStrict7BitEncoding) {
currentStrict7BitEncoding = strict7BitEncoding;
SpecialPowers.setBoolPref("dom.sms.strict7BitEncoding",
currentStrict7BitEncoding);
}
function cleanUp() {
SpecialPowers.removePermission("sms", document);
SpecialPowers.clearUserPref("dom.sms.enabled");
SpecialPowers.clearUserPref("dom.sms.strict7BitEncoding");
finish();
let domRequest = manager.getSegmentInfoForText(text);
ok(domRequest, "DOMRequest object returned.");
domRequest.onsuccess = function(e) {
log("Received 'onsuccess' DOMRequest event.");
let result = e.target.result;
if (!result) {
ok(false, "getSegmentInfoForText() result is not valid.");
tasks.finish();
return;
}
is(result.segments, expected[0], "segments");
is(result.charsPerSegment, expected[1], "charsPerSegment");
is(result.charsAvailableInLastSegment, expected[2],
"charsAvailableInLastSegment");
tasks.next();
};
domRequest.onerror = function(e) {
ok(false, "Failed to call getSegmentInfoForText().");
tasks.finish();
};
});
}
// GSM 7Bit Alphabets:
//
// 'a' is in GSM default locking shift table, so it takes 1 septet.
doTest("a", false, [1, LEN_7BIT, LEN_7BIT - 1]);
addTest("a", false, [1, LEN_7BIT, LEN_7BIT - 1]);
// '\u20ac' is in GSM default single shift table, so it takes 2 septets.
doTest("\u20ac", false, [1, LEN_7BIT, LEN_7BIT - 2]);
addTest("\u20ac", false, [1, LEN_7BIT, LEN_7BIT - 2]);
// SP is defined in both locking shift and single shift tables.
doTest(" ", false, [1, LEN_7BIT, LEN_7BIT - 1]);
addTest(" ", false, [1, LEN_7BIT, LEN_7BIT - 1]);
// Some combinations.
doTest("a\u20ac", false, [1, LEN_7BIT, LEN_7BIT - 3]);
doTest("a ", false, [1, LEN_7BIT, LEN_7BIT - 2]);
doTest("\u20aca", false, [1, LEN_7BIT, LEN_7BIT - 3]);
doTest("\u20ac ", false, [1, LEN_7BIT, LEN_7BIT - 3]);
doTest(" \u20ac", false, [1, LEN_7BIT, LEN_7BIT - 3]);
doTest(" a", false, [1, LEN_7BIT, LEN_7BIT - 2]);
addTest("a\u20ac", false, [1, LEN_7BIT, LEN_7BIT - 3]);
addTest("a ", false, [1, LEN_7BIT, LEN_7BIT - 2]);
addTest("\u20aca", false, [1, LEN_7BIT, LEN_7BIT - 3]);
addTest("\u20ac ", false, [1, LEN_7BIT, LEN_7BIT - 3]);
addTest(" \u20ac", false, [1, LEN_7BIT, LEN_7BIT - 3]);
addTest(" a", false, [1, LEN_7BIT, LEN_7BIT - 2]);
// GSM 7Bit Alphabets (multipart):
//
// Exactly 160 locking shift table chararacters.
doTest(times("a", LEN_7BIT), false, [1, LEN_7BIT, 0]);
addTest(times("a", LEN_7BIT), false, [1, LEN_7BIT, 0]);
// 161 locking shift table chararacters. We'll have |161 - 153 = 8| septets in
// the 2nd segment.
doTest(times("a", LEN_7BIT + 1), false,
[2, LEN_7BIT_WITH_8BIT_REF, LEN_7BIT_WITH_8BIT_REF - 8]);
addTest(times("a", LEN_7BIT + 1), false,
[2, LEN_7BIT_WITH_8BIT_REF, LEN_7BIT_WITH_8BIT_REF - 8]);
// |LEN_7BIT_WITH_8BIT_REF * 2| locking shift table chararacters.
doTest(times("a", LEN_7BIT_WITH_8BIT_REF * 2), false,
[2, LEN_7BIT_WITH_8BIT_REF, 0]);
addTest(times("a", LEN_7BIT_WITH_8BIT_REF * 2), false,
[2, LEN_7BIT_WITH_8BIT_REF, 0]);
// |LEN_7BIT_WITH_8BIT_REF * 2 + 1| locking shift table chararacters.
doTest(times("a", LEN_7BIT_WITH_8BIT_REF * 2 + 1), false,
[3, LEN_7BIT_WITH_8BIT_REF, LEN_7BIT_WITH_8BIT_REF - 1]);
addTest(times("a", LEN_7BIT_WITH_8BIT_REF * 2 + 1), false,
[3, LEN_7BIT_WITH_8BIT_REF, LEN_7BIT_WITH_8BIT_REF - 1]);
// Exactly 80 single shift table chararacters.
doTest(times("\u20ac", LEN_7BIT / 2), false, [1, LEN_7BIT, 0]);
addTest(times("\u20ac", LEN_7BIT / 2), false, [1, LEN_7BIT, 0]);
// 81 single shift table chararacters. Because |Math.floor(153 / 2) = 76|, it
// should left 5 septets in the 2nd segment.
doTest(times("\u20ac", LEN_7BIT / 2 + 1), false,
[2, LEN_7BIT_WITH_8BIT_REF, LEN_7BIT_WITH_8BIT_REF - 10]);
addTest(times("\u20ac", LEN_7BIT / 2 + 1), false,
[2, LEN_7BIT_WITH_8BIT_REF, LEN_7BIT_WITH_8BIT_REF - 10]);
// |1 + 2 * 76| single shift table chararacters. We have only |153 - 76 * 2 = 1|
// space left, but each single shift table character takes 2, so it will be
// filled in the 3rd segment.
doTest(times("\u20ac", 1 + 2 * Math.floor(LEN_7BIT_WITH_8BIT_REF / 2)), false,
[3, LEN_7BIT_WITH_8BIT_REF, LEN_7BIT_WITH_8BIT_REF - 2]);
addTest(times("\u20ac", 1 + 2 * Math.floor(LEN_7BIT_WITH_8BIT_REF / 2)), false,
[3, LEN_7BIT_WITH_8BIT_REF, LEN_7BIT_WITH_8BIT_REF - 2]);
// |2 * 76| single shift table chararacters + 1 locking shift table chararacter.
doTest("a" + times("\u20ac", 2 * Math.floor(LEN_7BIT_WITH_8BIT_REF / 2)), false,
[2, LEN_7BIT_WITH_8BIT_REF, 1]);
doTest(times("\u20ac", 2 * Math.floor(LEN_7BIT_WITH_8BIT_REF / 2)) + "a", false,
[2, LEN_7BIT_WITH_8BIT_REF, 0]);
addTest("a" + times("\u20ac", 2 * Math.floor(LEN_7BIT_WITH_8BIT_REF / 2)), false,
[2, LEN_7BIT_WITH_8BIT_REF, 1]);
addTest(times("\u20ac", 2 * Math.floor(LEN_7BIT_WITH_8BIT_REF / 2)) + "a", false,
[2, LEN_7BIT_WITH_8BIT_REF, 0]);
// UCS2:
//
// '\u6afb' should be encoded as UCS2.
doTest("\u6afb", false, [1, LEN_UCS2, LEN_UCS2 - 1]);
addTest("\u6afb", false, [1, LEN_UCS2, LEN_UCS2 - 1]);
// Combination of GSM 7bit alphabets.
doTest("\u6afba", false, [1, LEN_UCS2, LEN_UCS2 - 2]);
doTest("\u6afb\u20ac", false, [1, LEN_UCS2, LEN_UCS2 - 2]);
doTest("\u6afb ", false, [1, LEN_UCS2, LEN_UCS2 - 2]);
addTest("\u6afba", false, [1, LEN_UCS2, LEN_UCS2 - 2]);
addTest("\u6afb\u20ac", false, [1, LEN_UCS2, LEN_UCS2 - 2]);
addTest("\u6afb ", false, [1, LEN_UCS2, LEN_UCS2 - 2]);
// UCS2 (multipart):
//
// Exactly 70 UCS2 chararacters.
doTest(times("\u6afb", LEN_UCS2), false, [1, LEN_UCS2, 0]);
addTest(times("\u6afb", LEN_UCS2), false, [1, LEN_UCS2, 0]);
// 71 UCS2 chararacters. We'll have |71 - 67 = 4| chararacters in the 2nd
// segment.
doTest(times("\u6afb", LEN_UCS2 + 1), false,
[2, LEN_UCS2_WITH_8BIT_REF, LEN_UCS2_WITH_8BIT_REF - 4]);
addTest(times("\u6afb", LEN_UCS2 + 1), false,
[2, LEN_UCS2_WITH_8BIT_REF, LEN_UCS2_WITH_8BIT_REF - 4]);
// |LEN_UCS2_WITH_8BIT_REF * 2| ucs2 chararacters.
doTest(times("\u6afb", LEN_UCS2_WITH_8BIT_REF * 2), false,
[2, LEN_UCS2_WITH_8BIT_REF, 0]);
addTest(times("\u6afb", LEN_UCS2_WITH_8BIT_REF * 2), false,
[2, LEN_UCS2_WITH_8BIT_REF, 0]);
// |LEN_7BIT_WITH_8BIT_REF * 2 + 1| ucs2 chararacters.
doTest(times("\u6afb", LEN_UCS2_WITH_8BIT_REF * 2 + 1), false,
[3, LEN_UCS2_WITH_8BIT_REF, LEN_UCS2_WITH_8BIT_REF - 1]);
addTest(times("\u6afb", LEN_UCS2_WITH_8BIT_REF * 2 + 1), false,
[3, LEN_UCS2_WITH_8BIT_REF, LEN_UCS2_WITH_8BIT_REF - 1]);
// Strict 7-Bit Encoding:
//
// Should have no effect on GSM default alphabet characters.
doTest("\u0041", true, [1, LEN_7BIT, LEN_7BIT - 1]);
addTest("\u0041", true, [1, LEN_7BIT, LEN_7BIT - 1]);
// "\u00c0"(À) should be mapped to "\u0041"(A).
doTest("\u00c0", true, [1, LEN_7BIT, LEN_7BIT - 1]);
addTest("\u00c0", true, [1, LEN_7BIT, LEN_7BIT - 1]);
// Mixing mapped characters with unmapped ones.
doTest("\u00c0\u0041", true, [1, LEN_7BIT, LEN_7BIT - 2]);
doTest("\u0041\u00c0", true, [1, LEN_7BIT, LEN_7BIT - 2]);
addTest("\u00c0\u0041", true, [1, LEN_7BIT, LEN_7BIT - 2]);
addTest("\u0041\u00c0", true, [1, LEN_7BIT, LEN_7BIT - 2]);
// UCS2 characters should be mapped to '*'.
doTest("\u1234", true, [1, LEN_7BIT, LEN_7BIT - 1]);
addTest("\u1234", true, [1, LEN_7BIT, LEN_7BIT - 1]);
cleanUp();
// WARNING: All tasks should be pushed before this!!!
tasks.push(function cleanUp() {
SpecialPowers.removePermission("sms", document);
SpecialPowers.clearUserPref("dom.sms.enabled");
SpecialPowers.clearUserPref("dom.sms.strict7BitEncoding");
finish();
});
tasks.run();

View File

@ -209,7 +209,7 @@ interface nsIDOMMozMobileConnection : nsIDOMEventTarget
*
* Otherwise, the request's onerror will be called, and the request's error
* will be either 'RadioNotAvailable', 'RequestNotSupported',
* 'IllegalSIMorME', or 'GenericFailure'
* 'IllegalSIMorME', 'InvalidParameter', or 'GenericFailure'
*/
nsIDOMDOMRequest setCallForwardingOption(in nsIDOMMozMobileCFInfo CFInfo);
@ -226,7 +226,7 @@ interface nsIDOMMozMobileConnection : nsIDOMEventTarget
*
* Otherwise, the request's onerror will be called, and the request's error
* will be either 'RadioNotAvailable', 'RequestNotSupported',
* or 'GenericFailure'.
* 'InvalidParameter', or 'GenericFailure'.
*/
nsIDOMDOMRequest getCallForwardingOption(in unsigned short reason);
@ -241,7 +241,7 @@ interface nsIDOMMozMobileConnection : nsIDOMEventTarget
*
* Otherwise, the request's onerror will be called, and the request's error
* will be either 'RadioNotAvailable', 'RequestNotSupported',
* 'IllegalSIMorME', 'InvalidCallBarringOption' or 'GenericFailure'
* 'IllegalSIMorME', 'InvalidParameter', or 'GenericFailure'
*/
nsIDOMDOMRequest setCallBarringOption(in jsval option);
@ -259,7 +259,7 @@ interface nsIDOMMozMobileConnection : nsIDOMEventTarget
*
* Otherwise, the request's onerror will be called, and the request's error
* will be either 'RadioNotAvailable', 'RequestNotSupported',
* 'InvalidCallBarringOption' or 'GenericFailure'.
* 'InvalidParameter', or 'GenericFailure'.
*/
nsIDOMDOMRequest getCallBarringOption(in jsval option);

View File

@ -53,7 +53,7 @@ function testSetCallBarringOptionError(option) {
+ JSON.stringify(option));
};
request.onerror = function(event) {
is(event.target.error.name, 'InvalidCallBarringOption', JSON.stringify(option));
is(event.target.error.name, 'InvalidParameter', JSON.stringify(option));
nextTest();
};
}

View File

@ -48,7 +48,7 @@ this.PhoneNumberUtils = {
// Get SIM mcc
let iccInfo = mobileConnection.iccInfo;
if (!mcc && iccInfo.mcc) {
if (!mcc && iccInfo && iccInfo.mcc) {
mcc = iccInfo.mcc;
}

View File

@ -426,8 +426,11 @@ GonkGPSGeolocationProvider::RequestSetID(uint32_t flags)
nsCOMPtr<nsIDOMMozIccInfo> iccInfo;
rilCtx->GetIccInfo(getter_AddRefs(iccInfo));
if (iccInfo) {
type = AGPS_SETID_TYPE_MSISDN;
iccInfo->GetMsisdn(id);
nsCOMPtr<nsIDOMMozGsmIccInfo> gsmIccInfo = do_QueryInterface(iccInfo);
if (gsmIccInfo) {
type = AGPS_SETID_TYPE_MSISDN;
gsmIccInfo->GetMsisdn(id);
}
}
}

View File

@ -45,8 +45,10 @@ if (DEBUG) {
const RILCONTENTHELPER_CID =
Components.ID("{472816e1-1fd6-4405-996c-806f9ea68174}");
const ICCINFO_CID =
Components.ID("{fab2c0f0-d73a-11e2-8b8b-0800200c9a66}");
const GSMICCINFO_CID =
Components.ID("{e0fa785b-ad3f-46ed-bc56-fcb0d6fe4fa8}");
const CDMAICCINFO_CID =
Components.ID("{3d1f844f-9ec5-48fb-8907-aed2e5421709}");
const MOBILECONNECTIONINFO_CID =
Components.ID("{a35cfd39-2d93-4489-ac7d-396475dacb27}");
const MOBILENETWORKINFO_CID =
@ -148,24 +150,50 @@ MobileIccCardLockRetryCount.prototype = {
function IccInfo() {}
IccInfo.prototype = {
QueryInterface: XPCOMUtils.generateQI([Ci.nsIDOMMozIccInfo]),
classID: ICCINFO_CID,
classInfo: XPCOMUtils.generateCI({
classID: ICCINFO_CID,
classDescription: "IccInfo",
flags: Ci.nsIClassInfo.DOM_OBJECT,
interfaces: [Ci.nsIDOMMozIccInfo]
}),
// nsIDOMMozIccInfo
iccType: null,
iccid: null,
mcc: null,
mnc: null,
spn: null,
isDisplayNetworkNameRequired: null,
isDisplaySpnRequired: null
};
function GsmIccInfo() {}
GsmIccInfo.prototype = {
__proto__: IccInfo.prototype,
QueryInterface: XPCOMUtils.generateQI([Ci.nsIDOMMozGsmIccInfo]),
classID: GSMICCINFO_CID,
classInfo: XPCOMUtils.generateCI({
classID: GSMICCINFO_CID,
classDescription: "MozGsmIccInfo",
flags: Ci.nsIClassInfo.DOM_OBJECT,
interfaces: [Ci.nsIDOMMozGsmIccInfo]
}),
// nsIDOMMozGsmIccInfo
msisdn: null
};
function CdmaIccInfo() {}
CdmaIccInfo.prototype = {
__proto__: IccInfo.prototype,
QueryInterface: XPCOMUtils.generateQI([Ci.nsIDOMMozCdmaIccInfo]),
classID: CDMAICCINFO_CID,
classInfo: XPCOMUtils.generateCI({
classID: CDMAICCINFO_CID,
classDescription: "MozCdmaIccInfo",
flags: Ci.nsIClassInfo.DOM_OBJECT,
interfaces: [Ci.nsIDOMMozCdmaIccInfo]
}),
// nsIDOMMozCdmaIccInfo
mdn: null,
min: null
};
function VoicemailInfo() {}
VoicemailInfo.prototype = {
number: null,
@ -404,7 +432,7 @@ function RILContentHelper() {
this.rilContext = {
cardState: RIL.GECKO_CARDSTATE_UNKNOWN,
networkSelectionMode: RIL.GECKO_NETWORK_SELECTION_UNKNOWN,
iccInfo: new IccInfo(),
iccInfo: null,
voiceConnectionInfo: new MobileConnectionInfo(),
dataConnectionInfo: new MobileConnectionInfo()
};
@ -472,7 +500,31 @@ RILContentHelper.prototype = {
}
this.updateInfo(srcNetwork, network);
},
},
/**
* We need to consider below cases when update iccInfo:
* 1. Should clear iccInfo to null if there is no card detected.
* 2. Need to create corresponding object based on iccType.
*/
updateIccInfo: function updateIccInfo(newInfo) {
// Card is not detected, clear iccInfo to null.
if (!newInfo || !newInfo.iccType) {
this.rilContext.iccInfo = null;
return;
}
// If iccInfo is null, new corresponding object based on iccType.
if (!this.rilContext.iccInfo) {
if (newInfo.iccType === "ruim" || newInfo.iccType === "csim") {
this.rilContext.iccInfo = new CdmaIccInfo();
} else {
this.rilContext.iccInfo = new GsmIccInfo();
}
}
this.updateInfo(newInfo, this.rilContext.iccInfo);
},
_windowsMap: null,
@ -494,7 +546,7 @@ RILContentHelper.prototype = {
}
this.rilContext.cardState = rilContext.cardState;
this.rilContext.networkSelectionMode = rilContext.networkSelectionMode;
this.updateInfo(rilContext.iccInfo, this.rilContext.iccInfo);
this.updateIccInfo(rilContext.iccInfo);
this.updateConnectionInfo(rilContext.voice, this.rilContext.voiceConnectionInfo);
this.updateConnectionInfo(rilContext.data, this.rilContext.dataConnectionInfo);
@ -643,7 +695,8 @@ RILContentHelper.prototype = {
let requestId = this.getRequestId(request);
if (!mode) {
this.dispatchFireRequestError(requestId, "InvalidParameter");
this.dispatchFireRequestError(requestId,
RIL.GECKO_ERROR_INVALID_PARAMETER);
return request;
}
@ -1006,7 +1059,8 @@ RILContentHelper.prototype = {
let requestId = this.getRequestId(request);
if (!this._isValidCFReason(reason)){
this.dispatchFireRequestError(requestId, "Invalid call forwarding reason.");
this.dispatchFireRequestError(requestId,
RIL.GECKO_ERROR_INVALID_PARAMETER);
return request;
}
@ -1032,7 +1086,8 @@ RILContentHelper.prototype = {
if (!cfInfo ||
!this._isValidCFReason(cfInfo.reason) ||
!this._isValidCFAction(cfInfo.action)){
this.dispatchFireRequestError(requestId, "Invalid call forwarding rule definition.");
this.dispatchFireRequestError(requestId,
RIL.GECKO_ERROR_INVALID_PARAMETER);
return request;
}
@ -1061,7 +1116,8 @@ RILContentHelper.prototype = {
if (DEBUG) debug("getCallBarringOption: " + JSON.stringify(option));
if (!this._isValidCallBarringOption(option)) {
this.dispatchFireRequestError(requestId, "InvalidCallBarringOption");
this.dispatchFireRequestError(requestId,
RIL.GECKO_ERROR_INVALID_PARAMETER);
return request;
}
@ -1087,7 +1143,8 @@ RILContentHelper.prototype = {
if (DEBUG) debug("setCallBarringOption: " + JSON.stringify(option));
if (!this._isValidCallBarringOption(option, true)) {
this.dispatchFireRequestError(requestId, "InvalidCallBarringOption");
this.dispatchFireRequestError(requestId,
RIL.GECKO_ERROR_INVALID_PARAMETER);
return request;
}
@ -1541,7 +1598,7 @@ RILContentHelper.prototype = {
break;
}
case "RIL:IccInfoChanged":
this.updateInfo(msg.json.data, this.rilContext.iccInfo);
this.updateIccInfo(msg.json.data);
this._deliverEvent("_iccListeners", "notifyIccInfoChanged", null);
break;
case "RIL:VoiceInfoChanged":

View File

@ -2222,21 +2222,14 @@ RadioInterface.prototype = {
let oldIccInfo = this.rilContext.iccInfo;
this.rilContext.iccInfo = message;
let iccInfoChanged = !oldIccInfo ||
oldIccInfo.iccid != message.iccid ||
oldIccInfo.mcc != message.mcc ||
oldIccInfo.mnc != message.mnc ||
oldIccInfo.spn != message.spn ||
oldIccInfo.isDisplayNetworkNameRequired != message.isDisplayNetworkNameRequired ||
oldIccInfo.isDisplaySpnRequired != message.isDisplaySpnRequired ||
oldIccInfo.msisdn != message.msisdn;
if (!iccInfoChanged) {
if (!this.isInfoChanged(message, oldIccInfo)) {
return;
}
// RIL:IccInfoChanged corresponds to a DOM event that gets fired only
// when the MCC or MNC codes have changed.
// when iccInfo has changed.
gMessageManager.sendIccMessage("RIL:IccInfoChanged",
this.clientId, message);
this.clientId,
message.iccType ? message : null);
// Update lastKnownSimMcc.
if (message.mcc) {
@ -2994,7 +2987,7 @@ RadioInterface.prototype = {
return options;
},
getSegmentInfoForText: function getSegmentInfoForText(text) {
getSegmentInfoForText: function getSegmentInfoForText(text, request) {
let strict7BitEncoding;
try {
strict7BitEncoding = Services.prefs.getBoolPref("dom.sms.strict7BitEncoding");
@ -3015,10 +3008,11 @@ RadioInterface.prototype = {
charsInLastSegment = 0;
}
let result = gMobileMessageService.createSmsSegmentInfo(options.segmentMaxSeq,
options.segmentChars,
options.segmentChars - charsInLastSegment);
return result;
let result = gMobileMessageService
.createSmsSegmentInfo(options.segmentMaxSeq,
options.segmentChars,
options.segmentChars - charsInLastSegment);
request.notifySegmentInfoForTextGot(result);
},
sendSMS: function sendSMS(number, message, silent, request) {

View File

@ -6,7 +6,6 @@
interface nsIDOMMozIccInfo;
interface nsIDOMMozMobileConnectionInfo;
interface nsIDOMMozSmsSegmentInfo;
interface nsIMobileMessageCallback;
[scriptable, uuid(1e602d20-d066-4399-8997-daf36b3158ef)]
@ -79,7 +78,7 @@ interface nsIRilContext : nsISupports
readonly attribute nsIDOMMozMobileConnectionInfo data;
};
[scriptable, uuid(5efcd358-080e-46d6-a7f7-4f36c204eec3)]
[scriptable, uuid(a50d65aa-00da-11e3-b954-7bfb233d98fc)]
interface nsIRadioInterface : nsISupports
{
readonly attribute nsIRilContext rilContext;
@ -99,7 +98,8 @@ interface nsIRadioInterface : nsISupports
/**
* SMS-related functionality.
*/
nsIDOMMozSmsSegmentInfo getSegmentInfoForText(in DOMString text);
void getSegmentInfoForText(in DOMString text,
in nsIMobileMessageCallback request);
void sendSMS(in DOMString number,
in DOMString message,

View File

@ -370,6 +370,15 @@ this.CARD_APPTYPE_ISIM = 5;
this.CARD_MAX_APPS = 8;
this.GECKO_CARD_TYPE = [
null,
"sim",
"usim",
"ruim",
"csim",
"isim"
];
this.NETWORK_STATE_UNKNOWN = "unknown";
this.NETWORK_STATE_AVAILABLE = "available";
this.NETWORK_STATE_CONNECTED = "connected";

View File

@ -96,7 +96,99 @@ let RILQUIRKS_HAVE_QUERY_ICC_LOCK_RETRY_COUNT = libcutils.property_get("ro.moz.r
// Marker object.
let PENDING_NETWORK_TYPE = {};
let Buf = require("resource://gre/modules/workers/worker_buf.js");
let Buf = {
__proto__: (function(){
return require("resource://gre/modules/workers/worker_buf.js").Buf;
})(),
mToken: 0,
mTokenRequestMap: null,
init: function init() {
this._init();
// This gets incremented each time we send out a parcel.
this.mToken = 1;
// Maps tokens we send out with requests to the request type, so that
// when we get a response parcel back, we know what request it was for.
this.mTokenRequestMap = {};
},
/**
* Process one parcel.
*/
processParcel: function processParcel() {
let response_type = this.readUint32();
let request_type, options;
if (response_type == RESPONSE_TYPE_SOLICITED) {
let token = this.readUint32();
let error = this.readUint32();
options = this.mTokenRequestMap[token];
if (!options) {
if (DEBUG) {
debug("Suspicious uninvited request found: " + token + ". Ignored!");
}
return;
}
delete this.mTokenRequestMap[token];
request_type = options.rilRequestType;
options.rilRequestError = error;
if (DEBUG) {
debug("Solicited response for request type " + request_type +
", token " + token + ", error " + error);
}
} else if (response_type == RESPONSE_TYPE_UNSOLICITED) {
request_type = this.readUint32();
if (DEBUG) debug("Unsolicited response for request type " + request_type);
} else {
if (DEBUG) debug("Unknown response type: " + response_type);
return;
}
RIL.handleParcel(request_type, this.mReadAvailable, options);
},
/**
* Start a new outgoing parcel.
*
* @param type
* Integer specifying the request type.
* @param options [optional]
* Object containing information about the request, e.g. the
* original main thread message object that led to the RIL request.
*/
newParcel: function newParcel(type, options) {
if (DEBUG) debug("New outgoing parcel of type " + type);
// We're going to leave room for the parcel size at the beginning.
this.mOutgoingIndex = this.PARCEL_SIZE_SIZE;
this.writeUint32(type);
this.writeUint32(this.mToken);
if (!options) {
options = {};
}
options.rilRequestType = type;
options.rilRequestError = null;
this.mTokenRequestMap[this.mToken] = options;
this.mToken++;
return this.mToken;
},
simpleRequest: function simpleRequest(type, options) {
this.newParcel(type, options);
this.sendParcel();
},
onSendParcel: function onSendParcel(parcel) {
postRILMessage(CLIENT_ID, parcel);
}
};
/**
* The RIL state machine.
@ -1222,6 +1314,10 @@ let RIL = {
Buf.simpleRequest(REQUEST_EXIT_EMERGENCY_CALLBACK_MODE, options);
},
getCdmaSubscription: function getCdmaSubscription() {
Buf.simpleRequest(REQUEST_CDMA_SUBSCRIPTION);
},
exitEmergencyCbMode: function exitEmergencyCbMode(options) {
// The function could be called by an API from RadioInterfaceLayer or by
// ril_worker itself. From ril_worker, we won't pass the parameter
@ -2837,6 +2933,9 @@ let RIL = {
if (newCardState == this.cardState) {
return;
}
this.iccInfo = {iccType: null};
ICCUtilsHelper.handleICCInfoChange();
this.cardState = newCardState;
this.sendChromeMessage({rilMessageType: "cardstatechange",
cardState: this.cardState});
@ -2888,6 +2987,8 @@ let RIL = {
// This was moved down from CARD_APPSTATE_READY
this.requestNetworkInfo();
if (newCardState == GECKO_CARDSTATE_READY) {
this.iccInfo.iccType = GECKO_CARD_TYPE[this.appType];
// For type SIM, we need to check EF_phase first.
// Other types of ICC we can send Terminal_Profile immediately.
if (this.appType == CARD_APPTYPE_SIM) {
@ -5671,7 +5772,21 @@ RIL[REQUEST_GSM_SMS_BROADCAST_ACTIVATION] = null;
RIL[REQUEST_CDMA_GET_BROADCAST_SMS_CONFIG] = null;
RIL[REQUEST_CDMA_SET_BROADCAST_SMS_CONFIG] = null;
RIL[REQUEST_CDMA_SMS_BROADCAST_ACTIVATION] = null;
RIL[REQUEST_CDMA_SUBSCRIPTION] = null;
RIL[REQUEST_CDMA_SUBSCRIPTION] = function REQUEST_CDMA_SUBSCRIPTION(length, options) {
if (options.rilRequestError) {
return;
}
let result = Buf.readStringList();
this.iccInfo.mdn = result[0];
// The result[1] is Home SID. (Already be handled in readCDMAHome())
// The result[2] is Home NID. (Already be handled in readCDMAHome())
this.iccInfo.min = result[3];
// The result[4] is PRL version.
ICCUtilsHelper.handleICCInfoChange();
};
RIL[REQUEST_CDMA_WRITE_SMS_TO_RUIM] = null;
RIL[REQUEST_CDMA_DELETE_SMS_ON_RUIM] = null;
RIL[REQUEST_DEVICE_IDENTITY] = function REQUEST_DEVICE_IDENTITY(length, options) {
@ -10985,11 +11100,11 @@ let ICCRecordHelper = {
function callback(options) {
let contact = GsmPDUHelper.readAlphaIdDiallingNumber(options.recordSize);
if (!contact ||
(RIL.iccInfo.mbdn !== undefined &&
RIL.iccInfo.mbdn === contact.number)) {
(RIL.iccInfoPrivate.mbdn !== undefined &&
RIL.iccInfoPrivate.mbdn === contact.number)) {
return;
}
RIL.iccInfo.mbdn = contact.number;
RIL.iccInfoPrivate.mbdn = contact.number;
if (DEBUG) {
debug("MBDN, alphaId="+contact.alphaId+" number="+contact.number);
}
@ -12668,6 +12783,7 @@ let RuimRecordHelper = {
RIL.getIMSI();
this.readCST();
this.readCDMAHome();
RIL.getCdmaSubscription();
},
/**
@ -12792,9 +12908,6 @@ let RuimRecordHelper = {
// Initialize buffers. This is a separate function so that unit tests can
// re-initialize the buffers at will.
Buf.init();
Buf.setOutputStream(function (parcel) {
postRILMessage(CLIENT_ID, parcel);
});
function onRILMessage(data) {
Buf.processIncoming(data);

File diff suppressed because it is too large Load Diff

View File

@ -479,11 +479,13 @@ public:
}
}
mConnection->CleanUp();
return NS_OK;
}
private:
DBusThread* mConnection;
nsRefPtr<DBusThread> mConnection;
};
static StaticRefPtr<DBusThread> gDBusThread;
@ -532,30 +534,23 @@ StopDBus()
MOZ_ASSERT(!NS_IsMainThread());
NS_ENSURE_TRUE(gDBusServiceThread, true);
if (gDBusThread) {
nsRefPtr<DBusThread> dbusThread(gDBusThread);
gDBusThread = nullptr;
if (dbusThread) {
static const char data = DBUS_EVENT_LOOP_EXIT;
ssize_t wret = TEMP_FAILURE_RETRY(write(gDBusThread->mControlFdW.get(),
ssize_t wret = TEMP_FAILURE_RETRY(write(dbusThread->mControlFdW.get(),
&data, sizeof(data)));
NS_ENSURE_TRUE(wret == 1, false);
}
#ifdef DEBUG
LOG("DBus Thread Joining\n");
#endif
if (NS_FAILED(gDBusServiceThread->Shutdown())) {
NS_WARNING("DBus thread shutdown failed!");
}
nsRefPtr<nsIThread> dbusServiceThread(gDBusServiceThread);
gDBusServiceThread = nullptr;
#ifdef DEBUG
LOG("DBus Thread Joined\n");
#endif
if (gDBusThread) {
gDBusThread->CleanUp();
gDBusThread = nullptr;
}
nsRefPtr<nsIRunnable> runnable =
NS_NewRunnableMethod(dbusServiceThread, &nsIThread::Shutdown);
nsresult rv = NS_DispatchToMainThread(runnable);
NS_ENSURE_SUCCESS(rv, false);
return true;
}
@ -563,13 +558,16 @@ StopDBus()
nsresult
DispatchToDBusThread(nsIRunnable* event)
{
MOZ_ASSERT(gDBusServiceThread);
MOZ_ASSERT(gDBusThread);
nsRefPtr<nsIThread> dbusServiceThread(gDBusServiceThread);
nsRefPtr<DBusThread> dbusThread(gDBusThread);
nsresult rv = gDBusServiceThread->Dispatch(event, NS_DISPATCH_NORMAL);
NS_ENSURE_TRUE(dbusServiceThread.get() && dbusThread.get(),
NS_ERROR_NOT_INITIALIZED);
nsresult rv = dbusServiceThread->Dispatch(event, NS_DISPATCH_NORMAL);
NS_ENSURE_SUCCESS(rv, rv);
gDBusThread->WakeUp();
dbusThread->WakeUp();
return NS_OK;
}

View File

@ -1658,16 +1658,18 @@ AndroidBridge::SetURITitle(const nsAString& aURI, const nsAString& aTitle)
nsresult
AndroidBridge::GetSegmentInfoForText(const nsAString& aText,
dom::mobilemessage::SmsSegmentInfoData* aData)
nsIMobileMessageCallback* aRequest)
{
#ifndef MOZ_WEBSMS_BACKEND
return NS_ERROR_FAILURE;
#else
ALOG_BRIDGE("AndroidBridge::GetSegmentInfoForText");
aData->segments() = 0;
aData->charsPerSegment() = 0;
aData->charsAvailableInLastSegment() = 0;
dom::mobilemessage::SmsSegmentInfoData data;
data.segments() = 0;
data.charsPerSegment() = 0;
data.charsAvailableInLastSegment() = 0;
JNIEnv *env = GetJNIEnv();
if (!env)
@ -1686,13 +1688,17 @@ AndroidBridge::GetSegmentInfoForText(const nsAString& aText,
jint* info = env->GetIntArrayElements(arr, JNI_FALSE);
aData->segments() = info[0]; // msgCount
aData->charsPerSegment() = info[2]; // codeUnitsRemaining
data.segments() = info[0]; // msgCount
data.charsPerSegment() = info[2]; // codeUnitsRemaining
// segmentChars = (codeUnitCount + codeUnitsRemaining) / msgCount
aData->charsAvailableInLastSegment() = (info[1] + info[2]) / info[0];
data.charsAvailableInLastSegment() = (info[1] + info[2]) / info[0];
env->ReleaseIntArrayElements(arr, info, JNI_ABORT);
return NS_OK;
// TODO Bug 908598 - Should properly use |QueueSmsRequest(...)| to queue up
// the nsIMobileMessageCallback just like other functions.
nsCOMPtr<nsIDOMMozSmsSegmentInfo> info = new SmsSegmentInfo(data);
return aRequest->NotifySegmentInfoForTextGot(info);
#endif
}

View File

@ -356,7 +356,7 @@ public:
void GetCurrentBatteryInformation(hal::BatteryInformation* aBatteryInfo);
nsresult GetSegmentInfoForText(const nsAString& aText,
dom::mobilemessage::SmsSegmentInfoData* aData);
nsIMobileMessageCallback* aRequest);
void SendMessage(const nsAString& aNumber, const nsAString& aText,
nsIMobileMessageCallback* aRequest);
void GetMessage(int32_t aMessageId, nsIMobileMessageCallback* aRequest);