Bug 903403 - [sms][mms] Make getSegmentInfoForText() Asynchronous to Improve Typing Performance. r=vicamo, sr=mounir

This commit is contained in:
Gene Lian 2013-08-09 21:25:53 +08:00
parent 93eb04a526
commit 1a6639563f
23 changed files with 319 additions and 163 deletions

View File

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

View File

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

View File

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

View File

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

View File

@ -101,12 +101,19 @@ MobileMessageManager::Shutdown()
NS_IMETHODIMP NS_IMETHODIMP
MobileMessageManager::GetSegmentInfoForText(const nsAString& aText, MobileMessageManager::GetSegmentInfoForText(const nsAString& aText,
nsIDOMMozSmsSegmentInfo** aResult) nsIDOMDOMRequest** aRequest)
{ {
nsCOMPtr<nsISmsService> smsService = do_GetService(SMS_SERVICE_CONTRACTID); nsCOMPtr<nsISmsService> smsService = do_GetService(SMS_SERVICE_CONTRACTID);
NS_ENSURE_TRUE(smsService, NS_ERROR_FAILURE); 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 nsresult

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -96,19 +96,11 @@ SmsIPCService::HasSupport(bool* aHasSupport)
} }
NS_IMETHODIMP NS_IMETHODIMP
SmsIPCService::GetSegmentInfoForText(const nsAString & aText, SmsIPCService::GetSegmentInfoForText(const nsAString& aText,
nsIDOMMozSmsSegmentInfo** aResult) nsIMobileMessageCallback* aRequest)
{ {
PSmsChild* smsChild = GetSmsChild(); return SendRequest(GetSegmentInfoForTextRequest(nsString(aText)),
NS_ENSURE_TRUE(smsChild, NS_ERROR_FAILURE); aRequest);
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;
} }
NS_IMETHODIMP NS_IMETHODIMP

View File

@ -311,35 +311,6 @@ SmsParent::RecvHasSupport(bool* aHasSupport)
return true; 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 bool
SmsParent::RecvAddSilentNumber(const nsString& aNumber) SmsParent::RecvAddSilentNumber(const nsString& aNumber)
{ {
@ -393,6 +364,8 @@ SmsParent::RecvPSmsRequestConstructor(PSmsRequestParent* aActor,
return actor->DoRequest(aRequest.get_DeleteMessageRequest()); return actor->DoRequest(aRequest.get_DeleteMessageRequest());
case IPCSmsRequest::TMarkMessageReadRequest: case IPCSmsRequest::TMarkMessageReadRequest:
return actor->DoRequest(aRequest.get_MarkMessageReadRequest()); return actor->DoRequest(aRequest.get_MarkMessageReadRequest());
case IPCSmsRequest::TGetSegmentInfoForTextRequest:
return actor->DoRequest(aRequest.get_GetSegmentInfoForTextRequest());
default: default:
MOZ_CRASH("Unknown type!"); MOZ_CRASH("Unknown type!");
} }
@ -577,6 +550,24 @@ SmsRequestParent::DoRequest(const MarkMessageReadRequest& aRequest)
return true; 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 nsresult
SmsRequestParent::SendReply(const MessageReply& aReply) SmsRequestParent::SendReply(const MessageReply& aReply)
{ {
@ -674,6 +665,19 @@ SmsRequestParent::NotifyMarkMessageReadFailed(int32_t aError)
return SendReply(ReplyMarkeMessageReadFail(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 * MobileMessageCursorParent
******************************************************************************/ ******************************************************************************/

View File

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

View File

@ -49,13 +49,31 @@ let tasks = {
function addTest(text, segments, charsPerSegment, charsAvailableInLastSegment) { function addTest(text, segments, charsPerSegment, charsAvailableInLastSegment) {
tasks.push(function () { tasks.push(function () {
log("Testing '" + text + "' ..."); log("Testing '" + text + "' ...");
let info = manager.getSegmentInfoForText(text); let domRequest = manager.getSegmentInfoForText(text);
is(info.segments, segments, "info.segments"); ok(domRequest, "DOMRequest object returned.");
is(info.charsPerSegment, charsPerSegment, "info.charsPerSegment");
is(info.charsAvailableInLastSegment, charsAvailableInLastSegment,
"info.charsAvailableInLastSegment");
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 () { tasks.push(function () {
log("Testing '" + text + "' ..."); log("Testing '" + text + "' ...");
try { try {
let info = manager.getSegmentInfoForText(text); let domRequest = manager.getSegmentInfoForText(text);
ok(false, "Not thrown"); ok(false, "Not thrown.");
tasks.finish(); tasks.finish();
} catch (e) { } catch (e) {
tasks.next(); tasks.next();

View File

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

@ -2994,7 +2994,7 @@ RadioInterface.prototype = {
return options; return options;
}, },
getSegmentInfoForText: function getSegmentInfoForText(text) { getSegmentInfoForText: function getSegmentInfoForText(text, request) {
let strict7BitEncoding; let strict7BitEncoding;
try { try {
strict7BitEncoding = Services.prefs.getBoolPref("dom.sms.strict7BitEncoding"); strict7BitEncoding = Services.prefs.getBoolPref("dom.sms.strict7BitEncoding");
@ -3015,10 +3015,11 @@ RadioInterface.prototype = {
charsInLastSegment = 0; charsInLastSegment = 0;
} }
let result = gMobileMessageService.createSmsSegmentInfo(options.segmentMaxSeq, let result = gMobileMessageService
options.segmentChars, .createSmsSegmentInfo(options.segmentMaxSeq,
options.segmentChars - charsInLastSegment); options.segmentChars,
return result; options.segmentChars - charsInLastSegment);
request.notifySegmentInfoForTextGot(result);
}, },
sendSMS: function sendSMS(number, message, silent, request) { sendSMS: function sendSMS(number, message, silent, request) {

View File

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

View File

@ -1658,16 +1658,18 @@ AndroidBridge::SetURITitle(const nsAString& aURI, const nsAString& aTitle)
nsresult nsresult
AndroidBridge::GetSegmentInfoForText(const nsAString& aText, AndroidBridge::GetSegmentInfoForText(const nsAString& aText,
dom::mobilemessage::SmsSegmentInfoData* aData) nsIMobileMessageCallback* aRequest)
{ {
#ifndef MOZ_WEBSMS_BACKEND #ifndef MOZ_WEBSMS_BACKEND
return NS_ERROR_FAILURE; return NS_ERROR_FAILURE;
#else #else
ALOG_BRIDGE("AndroidBridge::GetSegmentInfoForText"); ALOG_BRIDGE("AndroidBridge::GetSegmentInfoForText");
aData->segments() = 0; dom::mobilemessage::SmsSegmentInfoData data;
aData->charsPerSegment() = 0;
aData->charsAvailableInLastSegment() = 0; data.segments() = 0;
data.charsPerSegment() = 0;
data.charsAvailableInLastSegment() = 0;
JNIEnv *env = GetJNIEnv(); JNIEnv *env = GetJNIEnv();
if (!env) if (!env)
@ -1686,13 +1688,17 @@ AndroidBridge::GetSegmentInfoForText(const nsAString& aText,
jint* info = env->GetIntArrayElements(arr, JNI_FALSE); jint* info = env->GetIntArrayElements(arr, JNI_FALSE);
aData->segments() = info[0]; // msgCount data.segments() = info[0]; // msgCount
aData->charsPerSegment() = info[2]; // codeUnitsRemaining data.charsPerSegment() = info[2]; // codeUnitsRemaining
// segmentChars = (codeUnitCount + codeUnitsRemaining) / msgCount // 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); 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 #endif
} }

View File

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