Merge birch to m-c.

This commit is contained in:
Ryan VanderMeulen 2013-04-26 16:41:11 -04:00
commit 3d2ee34e4c
20 changed files with 500 additions and 269 deletions

View File

@ -28,6 +28,7 @@ pref("browser.cache.memory.capacity", 1024); // kilobytes
/* image cache prefs */
pref("image.cache.size", 1048576); // bytes
pref("image.high_quality_downscaling.enabled", false);
pref("canvas.image.cache.limit", 10485760); // 10 MB
/* offline cache prefs */
pref("browser.offline-apps.notify", false);

View File

@ -351,7 +351,7 @@ let FormAssistant = {
case "Forms:Input:Value": {
target.value = json.value;
let event = content.document.createEvent('HTMLEvents');
let event = target.ownerDocument.createEvent('HTMLEvents');
event.initEvent('input', true, false);
target.dispatchEvent(event);
break;
@ -377,7 +377,7 @@ let FormAssistant = {
// only fire onchange event if any selected option is changed
if (valueChanged) {
let event = content.document.createEvent('HTMLEvents');
let event = target.ownerDocument.createEvent('HTMLEvents');
event.initEvent('change', true, true);
target.dispatchEvent(event);
}

View File

@ -13,6 +13,7 @@
#include "nsTHashtable.h"
#include "mozilla/dom/HTMLCanvasElement.h"
#include "nsContentUtils.h"
#include "mozilla/Preferences.h"
namespace mozilla {
@ -42,6 +43,8 @@ struct ImageCacheEntryData {
nsExpirationState* GetExpirationState() { return &mState; }
size_t SizeInBytes() { return mSize.width * mSize.height * 4; }
// Key
nsRefPtr<Element> mImage;
nsIImageLoadingContent* mILC;
@ -79,13 +82,21 @@ public:
nsAutoPtr<ImageCacheEntryData> mData;
};
static bool sPrefsInitialized = false;
static int32_t sCanvasImageCacheLimit = 0;
class ImageCache MOZ_FINAL : public nsExpirationTracker<ImageCacheEntryData,4> {
public:
// We use 3 generations of 1 second each to get a 2-3 seconds timeout.
enum { GENERATION_MS = 1000 };
ImageCache()
: nsExpirationTracker<ImageCacheEntryData,4>(GENERATION_MS)
, mTotal(0)
{
if (!sPrefsInitialized) {
sPrefsInitialized = true;
Preferences::AddIntVarCache(&sCanvasImageCacheLimit, "canvas.image.cache.limit", 0);
}
mCache.Init();
}
~ImageCache() {
@ -94,12 +105,14 @@ public:
virtual void NotifyExpired(ImageCacheEntryData* aObject)
{
mTotal -= aObject->SizeInBytes();
RemoveObject(aObject);
// Deleting the entry will delete aObject since the entry owns aObject
mCache.RemoveEntry(ImageCacheKey(aObject->mImage, aObject->mCanvas));
}
nsTHashtable<ImageCacheEntry> mCache;
size_t mTotal;
};
static ImageCache* gImageCache = nullptr;
@ -127,6 +140,7 @@ CanvasImageCache::NotifyDrawImage(Element* aImage,
if (entry) {
if (entry->mData->mSurface) {
// We are overwriting an existing entry.
gImageCache->mTotal -= entry->mData->SizeInBytes();
gImageCache->RemoveObject(entry->mData);
}
gImageCache->AddObject(entry->mData);
@ -139,7 +153,16 @@ CanvasImageCache::NotifyDrawImage(Element* aImage,
entry->mData->mILC = ilc;
entry->mData->mSurface = aSurface;
entry->mData->mSize = aSize;
gImageCache->mTotal += entry->mData->SizeInBytes();
}
if (!sCanvasImageCacheLimit)
return;
// Expire the image cache early if its larger than we want it to be.
while (gImageCache->mTotal > size_t(sCanvasImageCacheLimit))
gImageCache->AgeOneGeneration();
}
gfxASurface*

View File

@ -54,10 +54,10 @@ NS_INTERFACE_MAP_END_INHERITING(nsDOMEventTargetHelper)
NS_IMPL_ADDREF_INHERITED(BluetoothAdapter, nsDOMEventTargetHelper)
NS_IMPL_RELEASE_INHERITED(BluetoothAdapter, nsDOMEventTargetHelper)
class GetPairedDevicesTask : public BluetoothReplyRunnable
class GetDevicesTask : public BluetoothReplyRunnable
{
public:
GetPairedDevicesTask(BluetoothAdapter* aAdapterPtr,
GetDevicesTask(BluetoothAdapter* aAdapterPtr,
nsIDOMDOMRequest* aReq) :
BluetoothReplyRunnable(aReq),
mAdapterPtr(aAdapterPtr)
@ -237,6 +237,12 @@ BluetoothAdapter::SetPropertyByValue(const BluetoothNamedValue& aValue)
Root();
} else if (name.EqualsLiteral("Devices")) {
mDeviceAddresses = value.get_ArrayOfnsString();
uint32_t length = mDeviceAddresses.Length();
for (int i = 0; i < length; i++) {
mDeviceAddresses[i] = GetAddressFromObjectPath(mDeviceAddresses[i]);
}
nsresult rv;
nsIScriptContext* sc = GetContextForEventHandlers(&rv);
NS_ENSURE_SUCCESS_VOID(rv);
@ -453,23 +459,40 @@ BluetoothAdapter::SetDiscoverableTimeout(const uint32_t aDiscoverableTimeout,
}
NS_IMETHODIMP
BluetoothAdapter::GetPairedDevices(nsIDOMDOMRequest** aRequest)
BluetoothAdapter::GetConnectedDevices(uint16_t aProfileId,
nsIDOMDOMRequest** aRequest)
{
MOZ_ASSERT(NS_IsMainThread());
nsCOMPtr<nsIDOMDOMRequest> req;
nsresult rv;
rv = PrepareDOMRequest(GetOwner(), getter_AddRefs(req));
nsresult rv = PrepareDOMRequest(GetOwner(), getter_AddRefs(req));
NS_ENSURE_SUCCESS(rv, NS_ERROR_FAILURE);
nsRefPtr<BluetoothReplyRunnable> results =
new GetPairedDevicesTask(this, req);
new GetDevicesTask(this, req);
BluetoothService* bs = BluetoothService::Get();
NS_ENSURE_TRUE(bs, NS_ERROR_FAILURE);
if (NS_FAILED(bs->GetPairedDevicePropertiesInternal(mDeviceAddresses,
results))) {
NS_WARNING("GetPairedDevices failed!");
return NS_ERROR_FAILURE;
}
rv = bs->GetConnectedDevicePropertiesInternal(aProfileId, results);
NS_ENSURE_SUCCESS(rv, NS_ERROR_FAILURE);
req.forget(aRequest);
return NS_OK;
}
NS_IMETHODIMP
BluetoothAdapter::GetPairedDevices(nsIDOMDOMRequest** aRequest)
{
nsCOMPtr<nsIDOMDOMRequest> req;
nsresult rv = PrepareDOMRequest(GetOwner(), getter_AddRefs(req));
NS_ENSURE_SUCCESS(rv, NS_ERROR_FAILURE);
nsRefPtr<BluetoothReplyRunnable> results =
new GetDevicesTask(this, req);
BluetoothService* bs = BluetoothService::Get();
NS_ENSURE_TRUE(bs, NS_ERROR_FAILURE);
rv = bs->GetPairedDevicePropertiesInternal(mDeviceAddresses, results);
NS_ENSURE_SUCCESS(rv, NS_ERROR_FAILURE);
req.forget(aRequest);
return NS_OK;
@ -481,8 +504,7 @@ BluetoothAdapter::PairUnpair(bool aPair,
nsIDOMDOMRequest** aRequest)
{
nsCOMPtr<nsIDOMDOMRequest> req;
nsresult rv;
rv = PrepareDOMRequest(GetOwner(), getter_AddRefs(req));
nsresult rv = PrepareDOMRequest(GetOwner(), getter_AddRefs(req));
NS_ENSURE_SUCCESS(rv, NS_ERROR_FAILURE);
nsRefPtr<BluetoothVoidReplyRunnable> results =
@ -530,8 +552,7 @@ BluetoothAdapter::SetPinCode(const nsAString& aDeviceAddress,
nsIDOMDOMRequest** aRequest)
{
nsCOMPtr<nsIDOMDOMRequest> req;
nsresult rv;
rv = PrepareDOMRequest(GetOwner(), getter_AddRefs(req));
nsresult rv = PrepareDOMRequest(GetOwner(), getter_AddRefs(req));
NS_ENSURE_SUCCESS(rv, NS_ERROR_FAILURE);
nsRefPtr<BluetoothVoidReplyRunnable> results =
@ -553,8 +574,7 @@ BluetoothAdapter::SetPasskey(const nsAString& aDeviceAddress, uint32_t aPasskey,
nsIDOMDOMRequest** aRequest)
{
nsCOMPtr<nsIDOMDOMRequest> req;
nsresult rv;
rv = PrepareDOMRequest(GetOwner(), getter_AddRefs(req));
nsresult rv = PrepareDOMRequest(GetOwner(), getter_AddRefs(req));
NS_ENSURE_SUCCESS(rv, NS_ERROR_FAILURE);
nsRefPtr<BluetoothVoidReplyRunnable> results =
@ -577,8 +597,7 @@ BluetoothAdapter::SetPairingConfirmation(const nsAString& aDeviceAddress,
nsIDOMDOMRequest** aRequest)
{
nsCOMPtr<nsIDOMDOMRequest> req;
nsresult rv;
rv = PrepareDOMRequest(GetOwner(), getter_AddRefs(req));
nsresult rv = PrepareDOMRequest(GetOwner(), getter_AddRefs(req));
NS_ENSURE_SUCCESS(rv, NS_ERROR_FAILURE);
nsRefPtr<BluetoothVoidReplyRunnable> results =
@ -602,8 +621,7 @@ BluetoothAdapter::SetAuthorization(const nsAString& aDeviceAddress, bool aAllow,
nsIDOMDOMRequest** aRequest)
{
nsCOMPtr<nsIDOMDOMRequest> req;
nsresult rv;
rv = PrepareDOMRequest(GetOwner(), getter_AddRefs(req));
nsresult rv = PrepareDOMRequest(GetOwner(), getter_AddRefs(req));
NS_ENSURE_SUCCESS(rv, NS_ERROR_FAILURE);
nsRefPtr<BluetoothVoidReplyRunnable> results =
@ -626,8 +644,7 @@ BluetoothAdapter::Connect(const nsAString& aDeviceAddress,
nsIDOMDOMRequest** aRequest)
{
nsCOMPtr<nsIDOMDOMRequest> req;
nsresult rv;
rv = PrepareDOMRequest(GetOwner(), getter_AddRefs(req));
nsresult rv = PrepareDOMRequest(GetOwner(), getter_AddRefs(req));
NS_ENSURE_SUCCESS(rv, NS_ERROR_FAILURE);
BluetoothService* bs = BluetoothService::Get();
@ -646,8 +663,7 @@ BluetoothAdapter::Disconnect(uint16_t aProfileId,
nsIDOMDOMRequest** aRequest)
{
nsCOMPtr<nsIDOMDOMRequest> req;
nsresult rv;
rv = PrepareDOMRequest(GetOwner(), getter_AddRefs(req));
nsresult rv = PrepareDOMRequest(GetOwner(), getter_AddRefs(req));
NS_ENSURE_SUCCESS(rv, NS_ERROR_FAILURE);
nsRefPtr<BluetoothVoidReplyRunnable> results =
@ -667,8 +683,7 @@ BluetoothAdapter::SendFile(const nsAString& aDeviceAddress,
nsIDOMDOMRequest** aRequest)
{
nsCOMPtr<nsIDOMDOMRequest> req;
nsresult rv;
rv = PrepareDOMRequest(GetOwner(), getter_AddRefs(req));
nsresult rv = PrepareDOMRequest(GetOwner(), getter_AddRefs(req));
NS_ENSURE_SUCCESS(rv, NS_ERROR_FAILURE);
nsRefPtr<BluetoothVoidReplyRunnable> results =
@ -694,8 +709,7 @@ BluetoothAdapter::StopSendingFile(const nsAString& aDeviceAddress,
nsIDOMDOMRequest** aRequest)
{
nsCOMPtr<nsIDOMDOMRequest> req;
nsresult rv;
rv = PrepareDOMRequest(GetOwner(), getter_AddRefs(req));
nsresult rv = PrepareDOMRequest(GetOwner(), getter_AddRefs(req));
NS_ENSURE_SUCCESS(rv, NS_ERROR_FAILURE);
nsRefPtr<BluetoothVoidReplyRunnable> results =
@ -715,8 +729,7 @@ BluetoothAdapter::ConfirmReceivingFile(const nsAString& aDeviceAddress,
nsIDOMDOMRequest** aRequest)
{
nsCOMPtr<nsIDOMDOMRequest> req;
nsresult rv;
rv = PrepareDOMRequest(GetOwner(), getter_AddRefs(req));
nsresult rv = PrepareDOMRequest(GetOwner(), getter_AddRefs(req));
NS_ENSURE_SUCCESS(rv, NS_ERROR_FAILURE);
nsRefPtr<BluetoothVoidReplyRunnable> results =

View File

@ -1455,3 +1455,9 @@ BluetoothHfpManager::IsConnected()
return false;
}
void
BluetoothHfpManager::GetAddress(nsAString& aDeviceAddress)
{
return mSocket->GetAddress(aDeviceAddress);
}

View File

@ -75,6 +75,7 @@ public:
void HandleCallStateChanged(uint32_t aCallIndex, uint16_t aCallState,
const nsAString& aNumber, bool aSend);
bool IsConnected();
void GetAddress(nsAString& aDeviceAddress);
private:
class GetVolumeTask;

View File

@ -230,6 +230,7 @@ BluetoothOppManager::BluetoothOppManager() : mConnected(false)
, mSendTransferCompleteFlag(false)
, mSuccessFlag(false)
, mWaitingForConfirmationFlag(false)
, mCurrentBlobIndex(-1)
{
mConnectedDeviceAddress.AssignLiteral(BLUETOOTH_ADDRESS_NONE);
Listen();
@ -275,10 +276,7 @@ BluetoothOppManager::Connect(const nsAString& aDeviceObjectPath,
}
BluetoothService* bs = BluetoothService::Get();
if (!bs) {
NS_WARNING("BluetoothService not available!");
return false;
}
NS_ENSURE_TRUE(bs, false);
nsString uuid;
BluetoothUuidHelper::GetString(BluetoothServiceClass::OBJECT_PUSH, uuid);
@ -354,69 +352,50 @@ BluetoothOppManager::Listen()
return true;
}
bool
BluetoothOppManager::SendFile(BlobParent* aActor)
void
BluetoothOppManager::StartSendingNextFile()
{
if (mBlob) {
// Means there's a sending process. Reply error.
return false;
}
MOZ_ASSERT(NS_IsMainThread());
MOZ_ASSERT(!IsTransferring());
MOZ_ASSERT(mBlobs.Length() > mCurrentBlobIndex + 1);
/*
* Process of sending a file:
* - Keep blob because OPP connection has not been established yet.
* - Try to retrieve file name from the blob or assign one if failed to get.
* - Create an OPP connection by SendConnectRequest()
* - After receiving the response, start to read file and send.
*/
mBlob = aActor->GetBlob();
mBlob = mBlobs[++mCurrentBlobIndex];
sFileName.Truncate();
nsCOMPtr<nsIDOMFile> file = do_QueryInterface(mBlob);
if (file) {
file->GetName(sFileName);
}
/**
* We try our best to get the file extention to avoid interoperability issues.
* However, once we found that we are unable to get suitable extension or
* information about the content type, sending a pre-defined file name without
* extension would be fine.
*/
if (sFileName.IsEmpty()) {
sFileName.AssignLiteral("Unknown");
}
int32_t offset = sFileName.RFindChar('/');
if (offset != kNotFound) {
sFileName = Substring(sFileName, offset + 1);
}
offset = sFileName.RFindChar('.');
if (offset == kNotFound) {
nsCOMPtr<nsIMIMEService> mimeSvc = do_GetService(NS_MIMESERVICE_CONTRACTID);
if (mimeSvc) {
nsString mimeType;
mBlob->GetType(mimeType);
nsCString extension;
nsresult rv =
mimeSvc->GetPrimaryExtension(NS_LossyConvertUTF16toASCII(mimeType),
EmptyCString(),
extension);
if (NS_SUCCEEDED(rv)) {
sFileName.AppendLiteral(".");
AppendUTF8toUTF16(extension, sFileName);
}
}
}
SendConnectRequest();
mTransferMode = false;
// Before sending content, we have to send a header including
// information such as file name, file length and content type.
ExtractBlobHeaders();
StartFileTransfer();
if (mCurrentBlobIndex == 0) {
// We may have more than one file waiting for transferring, but only one
// CONNECT request would be sent. Therefore check if this is the very first
// file at the head of queue.
SendConnectRequest();
} else {
SendPutHeaderRequest(sFileName, sFileLength);
AfterFirstPut();
}
mIsServer = false;
}
bool
BluetoothOppManager::SendFile(const nsAString& aDeviceAddress,
BlobParent* aActor)
{
MOZ_ASSERT(NS_IsMainThread());
if (mCurrentBlobIndex >= 0) {
if (mConnectedDeviceAddress != aDeviceAddress) {
return false;
}
mBlobs.AppendElement(aActor->GetBlob().get());
return true;
}
mBlobs.AppendElement(aActor->GetBlob().get());
StartSendingNextFile();
return true;
}
@ -431,17 +410,13 @@ BluetoothOppManager::StopSendingFile()
bool
BluetoothOppManager::ConfirmReceivingFile(bool aConfirm)
{
if (!mConnected) return false;
NS_ENSURE_TRUE(mConnected, false);
NS_ENSURE_TRUE(mWaitingForConfirmationFlag, false);
MOZ_ASSERT(mPacketLeftLength == 0);
if (!mWaitingForConfirmationFlag) {
NS_WARNING("We are not waiting for a confirmation now.");
return false;
}
mWaitingForConfirmationFlag = false;
NS_ASSERTION(mPacketLeftLength == 0,
"Should not be in the middle of receiving a PUT packet.");
// For the first packet of first file
bool success = false;
if (aConfirm) {
@ -490,9 +465,10 @@ BluetoothOppManager::AfterOppDisconnected()
mConnected = false;
mLastCommand = 0;
mBlob = nullptr;
mPacketLeftLength = 0;
ClearQueue();
// We can't reset mSuccessFlag here since this function may be called
// before we send system message of transfer complete
// mSuccessFlag = false;
@ -534,14 +510,46 @@ BluetoothOppManager::DeleteReceivedFile()
f->Remove(false);
}
DeviceStorageFile*
BluetoothOppManager::CreateDeviceStorageFile(nsIFile* aFile)
{
nsString fullFilePath;
aFile->GetPath(fullFilePath);
MOZ_ASSERT(StringBeginsWith(fullFilePath, NS_LITERAL_STRING(TARGET_ROOT)));
nsDependentSubstring storagePath =
Substring(fullFilePath, strlen(TARGET_ROOT));
nsCOMPtr<nsIMIMEService> mimeSvc = do_GetService(NS_MIMESERVICE_CONTRACTID);
NS_ENSURE_TRUE(mimeSvc, nullptr);
nsCString mimeType;
nsresult rv = mimeSvc->GetTypeFromFile(aFile, mimeType);
if (NS_FAILED(rv)) {
return nullptr;
}
if (StringBeginsWith(mimeType, NS_LITERAL_CSTRING("image/"))) {
return new DeviceStorageFile(NS_LITERAL_STRING("pictures"), storagePath);
} else if (StringBeginsWith(mimeType, NS_LITERAL_CSTRING("video/"))) {
return new DeviceStorageFile(NS_LITERAL_STRING("movies"), storagePath);
} else if (StringBeginsWith(mimeType, NS_LITERAL_CSTRING("audio/"))) {
return new DeviceStorageFile(NS_LITERAL_STRING("music"), storagePath);
} else {
NS_WARNING("Couldn't recognize the mimetype of received file.");
return nullptr;
}
}
bool
BluetoothOppManager::CreateFile()
{
MOZ_ASSERT(mPacketLeftLength == 0);
nsString path;
path.AssignLiteral(TARGET_FOLDER);
MOZ_ASSERT(mPacketLeftLength == 0);
nsCOMPtr<nsIFile> f;
nsresult rv;
rv = NS_NewLocalFile(path + sFileName, false, getter_AddRefs(f));
@ -563,36 +571,10 @@ BluetoothOppManager::CreateFile()
*/
f->GetLeafName(sFileName);
nsString fullFileName;
f->GetPath(fullFileName);
MOZ_ASSERT(StringBeginsWith(fullFileName, NS_LITERAL_STRING(TARGET_ROOT)));
nsDependentSubstring storagePath = Substring(fullFileName, strlen(TARGET_ROOT));
mDsFile = nullptr;
nsCOMPtr<nsIMIMEService> mimeSvc = do_GetService(NS_MIMESERVICE_CONTRACTID);
if (mimeSvc) {
nsCString mimeType;
nsresult rv = mimeSvc->GetTypeFromFile(f, mimeType);
if (NS_SUCCEEDED(rv)) {
if (StringBeginsWith(mimeType, NS_LITERAL_CSTRING("image/"))) {
mDsFile = new DeviceStorageFile(NS_LITERAL_STRING("pictures"), storagePath);
} else if (StringBeginsWith(mimeType, NS_LITERAL_CSTRING("video/"))) {
mDsFile = new DeviceStorageFile(NS_LITERAL_STRING("movies"), storagePath);
} else if (StringBeginsWith(mimeType, NS_LITERAL_CSTRING("audio/"))) {
mDsFile = new DeviceStorageFile(NS_LITERAL_STRING("music"), storagePath);
} else {
NS_WARNING("Couldn't recognize the mimetype of received file.");
}
}
}
mDsFile = CreateDeviceStorageFile(f);
NS_NewLocalFileOutputStream(getter_AddRefs(mOutputStream), f);
if (!mOutputStream) {
NS_WARNING("Couldn't new an output stream");
return false;
}
NS_ENSURE_TRUE(mOutputStream, false);
return true;
}
@ -600,17 +582,11 @@ BluetoothOppManager::CreateFile()
bool
BluetoothOppManager::WriteToFile(const uint8_t* aData, int aDataLength)
{
if (!mOutputStream) {
NS_WARNING("No available output stream");
return false;
}
NS_ENSURE_TRUE(mOutputStream, false);
uint32_t wrote = 0;
mOutputStream->Write((const char*)aData, aDataLength, &wrote);
if (aDataLength != wrote) {
NS_WARNING("Writing to the file failed");
return false;
}
NS_ENSURE_TRUE(aDataLength == wrote, false);
return true;
}
@ -644,6 +620,8 @@ BluetoothOppManager::ExtractPacketHeaders(const ObexHeaderSet& aHeader)
bool
BluetoothOppManager::ExtractBlobHeaders()
{
RetrieveSentFileName();
nsresult rv = mBlob->GetType(sContentType);
if (NS_FAILED(rv)) {
NS_WARNING("Can't get content type");
@ -681,6 +659,52 @@ BluetoothOppManager::ExtractBlobHeaders()
return true;
}
void
BluetoothOppManager::RetrieveSentFileName()
{
sFileName.Truncate();
nsCOMPtr<nsIDOMFile> file = do_QueryInterface(mBlob);
if (file) {
file->GetName(sFileName);
}
/**
* We try our best to get the file extention to avoid interoperability issues.
* However, once we found that we are unable to get suitable extension or
* information about the content type, sending a pre-defined file name without
* extension would be fine.
*/
if (sFileName.IsEmpty()) {
sFileName.AssignLiteral("Unknown");
}
int32_t offset = sFileName.RFindChar('/');
if (offset != kNotFound) {
sFileName = Substring(sFileName, offset + 1);
}
offset = sFileName.RFindChar('.');
if (offset == kNotFound) {
nsCOMPtr<nsIMIMEService> mimeSvc = do_GetService(NS_MIMESERVICE_CONTRACTID);
if (mimeSvc) {
nsString mimeType;
mBlob->GetType(mimeType);
nsCString extension;
nsresult rv =
mimeSvc->GetPrimaryExtension(NS_LossyConvertUTF16toASCII(mimeType),
EmptyCString(),
extension);
if (NS_SUCCEEDED(rv)) {
sFileName.AppendLiteral(".");
AppendUTF8toUTF16(extension, sFileName);
}
}
}
}
bool
BluetoothOppManager::IsReservedChar(PRUnichar c)
{
@ -737,7 +761,7 @@ BluetoothOppManager::ServerDataHandler(UnixSocketRawData* aMessage)
&pktHeaders);
ReplyToConnect();
AfterOppConnected();
mTransferMode = true;
mIsServer = true;
} else if (opCode == ObexRequestCode::Disconnect ||
opCode == ObexRequestCode::Abort) {
// Section 3.3.2 "Disconnect", IrOBEX 1.2
@ -839,12 +863,24 @@ BluetoothOppManager::ServerDataHandler(UnixSocketRawData* aMessage)
if (mPutFinalFlag) {
mSuccessFlag = true;
FileTransferComplete();
NotifyAboutFileChange();
}
} else {
NS_WARNING("Unhandled ObexRequestCode");
}
}
void
BluetoothOppManager::ClearQueue()
{
mCurrentBlobIndex = -1;
mBlob = nullptr;
while (!mBlobs.IsEmpty()) {
mBlobs.RemoveElement(mBlobs[0]);
}
}
void
BluetoothOppManager::ClientDataHandler(UnixSocketRawData* aMessage)
{
@ -884,7 +920,17 @@ BluetoothOppManager::ClientDataHandler(UnixSocketRawData* aMessage)
if (mLastCommand == ObexRequestCode::PutFinal) {
mSuccessFlag = true;
FileTransferComplete();
SendDisconnectRequest();
if (mInputStream) {
mInputStream->Close();
mInputStream = nullptr;
}
if (mCurrentBlobIndex + 1 == mBlobs.Length()) {
SendDisconnectRequest();
} else {
StartSendingNextFile();
}
} else if (mLastCommand == ObexRequestCode::Abort) {
SendDisconnectRequest();
FileTransferComplete();
@ -909,16 +955,8 @@ BluetoothOppManager::ClientDataHandler(UnixSocketRawData* aMessage)
mRemoteMaxPacketLength =
(((int)(aMessage->mData[5]) << 8) | aMessage->mData[6]);
/*
* Before sending content, we have to send a header including
* information such as file name, file length and content type.
*/
if (ExtractBlobHeaders()) {
sInstance->SendPutHeaderRequest(sFileName, sFileLength);
}
sInstance->SendPutHeaderRequest(sFileName, sFileLength);
} else if (mLastCommand == ObexRequestCode::Put) {
// Send PutFinal packet when we get response
if (sWaitingToSendPutFinal) {
SendPutFinalRequest();
return;
@ -997,6 +1035,8 @@ void
BluetoothOppManager::SendPutHeaderRequest(const nsAString& aFileName,
int aFileSize)
{
if (!mConnected) return;
uint8_t* req = new uint8_t[mRemoteMaxPacketLength];
int len = aFileName.Length();
@ -1086,6 +1126,8 @@ BluetoothOppManager::SendPutFinalRequest()
void
BluetoothOppManager::SendDisconnectRequest()
{
if (!mConnected) return;
// Section 3.3.2 "Disconnect", IrOBEX 1.2
// [opcode:1][length:2][Headers:var]
uint8_t req[255];
@ -1102,6 +1144,8 @@ BluetoothOppManager::SendDisconnectRequest()
void
BluetoothOppManager::SendAbortRequest()
{
if (!mConnected) return;
// Section 3.3.5 "Abort", IrOBEX 1.2
// [opcode:1][length:2][Headers:var]
uint8_t req[255];
@ -1121,11 +1165,16 @@ BluetoothOppManager::IsTransferring()
return (mConnected && !mSendTransferCompleteFlag);
}
void
BluetoothOppManager::GetAddress(nsAString& aDeviceAddress)
{
return mSocket->GetAddress(aDeviceAddress);
}
void
BluetoothOppManager::ReplyToConnect()
{
if (mConnected) return;
mConnected = true;
// Section 3.3.1 "Connect", IrOBEX 1.2
// [opcode:1][length:2][version:1][flags:1][MaxPktSizeWeCanReceive:2]
@ -1149,7 +1198,6 @@ void
BluetoothOppManager::ReplyToDisconnect()
{
if (!mConnected) return;
mConnected = false;
// Section 3.3.2 "Disconnect", IrOBEX 1.2
// [opcode:1][length:2][Headers:var]
@ -1215,7 +1263,7 @@ BluetoothOppManager::FileTransferComplete()
parameters.AppendElement(BluetoothNamedValue(name, v));
name.AssignLiteral("received");
v = mTransferMode;
v = mIsServer;
parameters.AppendElement(BluetoothNamedValue(name, v));
name.AssignLiteral("fileName");
@ -1251,7 +1299,7 @@ BluetoothOppManager::StartFileTransfer()
parameters.AppendElement(BluetoothNamedValue(name, v));
name.AssignLiteral("received");
v = mTransferMode;
v = mIsServer;
parameters.AppendElement(BluetoothNamedValue(name, v));
name.AssignLiteral("fileName");
@ -1285,7 +1333,7 @@ BluetoothOppManager::UpdateProgress()
parameters.AppendElement(BluetoothNamedValue(name, v));
name.AssignLiteral("received");
v = mTransferMode;
v = mIsServer;
parameters.AppendElement(BluetoothNamedValue(name, v));
name.AssignLiteral("processedLength");
@ -1332,6 +1380,18 @@ BluetoothOppManager::ReceivingFileConfirmation()
}
}
void
BluetoothOppManager::NotifyAboutFileChange()
{
NS_NAMED_LITERAL_STRING(data, "modified");
nsCOMPtr<nsIObserverService> obs =
mozilla::services::GetObserverService();
NS_ENSURE_TRUE_VOID(obs);
obs->NotifyObservers(mDsFile, "file-watcher-notify", data.get());
}
void
BluetoothOppManager::OnConnectSuccess(BluetoothSocket* aSocket)
{
@ -1410,22 +1470,11 @@ BluetoothOppManager::OnDisconnect(BluetoothSocket* aSocket)
* and notify the transfer has been completed (but failed). We also call
* AfterOppDisconnected here to ensure all variables will be cleaned.
*/
if (!mSuccessFlag) {
if (mTransferMode) {
if (mIsServer) {
DeleteReceivedFile();
}
FileTransferComplete();
} else if (mTransferMode && mDsFile) {
NS_NAMED_LITERAL_STRING(data, "modified");
nsCOMPtr<nsIObserverService> obs =
mozilla::services::GetObserverService();
if (obs) {
obs->NotifyObservers(mDsFile, "file-watcher-notify", data.get());
} else {
NS_WARNING("Couldn't get ObserverService");
}
}
AfterOppDisconnected();

View File

@ -9,9 +9,10 @@
#include "BluetoothCommon.h"
#include "BluetoothSocketObserver.h"
#include "DeviceStorage.h"
#include "mozilla/dom/ipc/Blob.h"
#include "mozilla/ipc/UnixSocket.h"
#include "DeviceStorage.h"
#include "nsCOMArray.h"
class nsIOutputStream;
class nsIInputStream;
@ -54,7 +55,7 @@ public:
void Disconnect();
bool Listen();
bool SendFile(BlobParent* aBlob);
bool SendFile(const nsAString& aDeviceAddress, BlobParent* aBlob);
bool StopSendingFile();
bool ConfirmReceivingFile(bool aConfirm);
@ -72,6 +73,7 @@ public:
// Return true if there is an ongoing file-transfer session, please see
// Bug 827267 for more information.
bool IsTransferring();
void GetAddress(nsAString& aDeviceAddress);
// Implement interface BluetoothSocketObserver
void ReceiveSocketData(
@ -88,6 +90,7 @@ public:
private:
BluetoothOppManager();
void StartFileTransfer();
void StartSendingNextFile();
void FileTransferComplete();
void UpdateProgress();
void ReceivingFileConfirmation();
@ -102,6 +105,10 @@ private:
void AfterOppDisconnected();
void ValidateFileName();
bool IsReservedChar(PRUnichar c);
void ClearQueue();
void RetrieveSentFileName();
DeviceStorageFile* CreateDeviceStorageFile(nsIFile* aFile);
void NotifyAboutFileChange();
/**
* OBEX session status.
@ -159,7 +166,7 @@ private:
* True: Receive file (Server)
* False: Send file (Client)
*/
bool mTransferMode;
bool mIsServer;
/**
* Set when receiving the first PUT packet and wait for
@ -170,7 +177,9 @@ private:
nsAutoArrayPtr<uint8_t> mBodySegment;
nsAutoArrayPtr<uint8_t> mReceivedDataBuffer;
int mCurrentBlobIndex;
nsCOMPtr<nsIDOMBlob> mBlob;
nsCOMArray<nsIDOMBlob> mBlobs;
/**
* A seperate member thread is required because our read calls can block

View File

@ -131,7 +131,17 @@ public:
GetPairedDevicePropertiesInternal(const nsTArray<nsString>& aDeviceAddresses,
BluetoothReplyRunnable* aRunnable) = 0;
/**
/**
* Returns the properties of connected devices regarding to specific profile,
* implemented via a platform specific methood.
*
* @return NS_OK on success, NS_ERROR_FAILURE otherwise
*/
virtual nsresult
GetConnectedDevicePropertiesInternal(uint16_t aProfileId,
BluetoothReplyRunnable* aRunnable) = 0;
/**
* Stop device discovery (platform specific implementation)
*
* @return NS_OK if discovery stopped correctly, false otherwise

View File

@ -197,8 +197,10 @@ BluetoothParent::RecvPBluetoothRequestConstructor(
return actor->DoRequest(aRequest.get_PairRequest());
case Request::TUnpairRequest:
return actor->DoRequest(aRequest.get_UnpairRequest());
case Request::TDevicePropertiesRequest:
return actor->DoRequest(aRequest.get_DevicePropertiesRequest());
case Request::TPairedDevicePropertiesRequest:
return actor->DoRequest(aRequest.get_PairedDevicePropertiesRequest());
case Request::TConnectedDevicePropertiesRequest:
return actor->DoRequest(aRequest.get_ConnectedDevicePropertiesRequest());
case Request::TSetPinCodeRequest:
return actor->DoRequest(aRequest.get_SetPinCodeRequest());
case Request::TSetPasskeyRequest:
@ -372,15 +374,26 @@ BluetoothRequestParent::DoRequest(const UnpairRequest& aRequest)
}
bool
BluetoothRequestParent::DoRequest(const DevicePropertiesRequest& aRequest)
BluetoothRequestParent::DoRequest(const PairedDevicePropertiesRequest& aRequest)
{
MOZ_ASSERT(mService);
MOZ_ASSERT(mRequestType == Request::TDevicePropertiesRequest);
MOZ_ASSERT(mRequestType == Request::TPairedDevicePropertiesRequest);
nsresult rv =
mService->GetPairedDevicePropertiesInternal(aRequest.addresses(),
mReplyRunnable.get());
NS_ENSURE_SUCCESS(rv, false);
return true;
}
bool
BluetoothRequestParent::DoRequest(const ConnectedDevicePropertiesRequest& aRequest)
{
MOZ_ASSERT(mService);
MOZ_ASSERT(mRequestType == Request::TConnectedDevicePropertiesRequest);
nsresult rv =
mService->GetConnectedDevicePropertiesInternal(aRequest.profileId(),
mReplyRunnable.get());
NS_ENSURE_SUCCESS(rv, false);
return true;
}

View File

@ -146,7 +146,9 @@ protected:
DoRequest(const UnpairRequest& aRequest);
bool
DoRequest(const DevicePropertiesRequest& aRequest);
DoRequest(const PairedDevicePropertiesRequest& aRequest);
bool
DoRequest(const ConnectedDevicePropertiesRequest& aRequest);
bool
DoRequest(const SetPinCodeRequest& aRequest);

View File

@ -110,12 +110,20 @@ BluetoothServiceChildProcess::GetDevicePropertiesInternal(
return NS_ERROR_NOT_IMPLEMENTED;
}
nsresult
BluetoothServiceChildProcess::GetConnectedDevicePropertiesInternal(
uint16_t aProfileId,
BluetoothReplyRunnable* aRunnable)
{
SendRequest(aRunnable, ConnectedDevicePropertiesRequest(aProfileId));
return NS_OK;
}
nsresult
BluetoothServiceChildProcess::GetPairedDevicePropertiesInternal(
const nsTArray<nsString>& aDeviceAddresses,
BluetoothReplyRunnable* aRunnable)
{
DevicePropertiesRequest request;
PairedDevicePropertiesRequest request;
request.addresses().AppendElements(aDeviceAddresses);
SendRequest(aRunnable, request);

View File

@ -52,6 +52,10 @@ public:
MOZ_OVERRIDE;
virtual nsresult
GetConnectedDevicePropertiesInternal(uint16_t aProfileId,
BluetoothReplyRunnable* aRunnable)
MOZ_OVERRIDE;
virtual nsresult
StopDiscoveryInternal(BluetoothReplyRunnable* aRunnable) MOZ_OVERRIDE;
virtual nsresult

View File

@ -88,10 +88,14 @@ struct DenyAuthorizationRequest
nsString path;
};
struct DevicePropertiesRequest
struct PairedDevicePropertiesRequest
{
nsString[] addresses;
};
struct ConnectedDevicePropertiesRequest
{
uint16_t profileId;
};
struct ConnectRequest
{
@ -140,7 +144,8 @@ union Request
DenyPairingConfirmationRequest;
ConfirmAuthorizationRequest;
DenyAuthorizationRequest;
DevicePropertiesRequest;
ConnectedDevicePropertiesRequest;
PairedDevicePropertiesRequest;
ConnectRequest;
DisconnectRequest;
SendFileRequest;

View File

@ -147,6 +147,7 @@ static int32_t sIsPairing = 0;
static nsString sAdapterPath;
typedef void (*UnpackFunc)(DBusMessage*, DBusError*, BluetoothValue&, nsAString&);
typedef bool (*FilterFunc)(const BluetoothValue&);
class RemoveDeviceTask : public nsRunnable {
public:
@ -191,6 +192,34 @@ private:
nsRefPtr<BluetoothReplyRunnable> mRunnable;
};
static bool
GetConnectedDevicesFilter(const BluetoothValue& aValue)
{
// We don't have to filter device here
return true;
}
static bool
GetPairedDevicesFilter(const BluetoothValue& aValue)
{
// Check property 'Paired' and only paired device will be returned
if (aValue.type() != BluetoothValue::TArrayOfBluetoothNamedValue) {
NS_WARNING("Not a BluetoothNamedValue array!");
return false;
}
const InfallibleTArray<BluetoothNamedValue>& deviceProperties =
aValue.get_ArrayOfBluetoothNamedValue();
uint32_t length = deviceProperties.Length();
for (uint32_t p = 0; p < length; ++p) {
if (deviceProperties[p].name().EqualsLiteral("Paired")) {
return deviceProperties[p].value().get_bool();
}
}
return false;
}
class SendDiscoveryTask : public nsRunnable {
public:
SendDiscoveryTask(const char* aMessageName,
@ -1911,14 +1940,16 @@ private:
BluetoothSignal mSignal;
};
class BluetoothPairedDevicePropertiesRunnable : public nsRunnable
class BluetoothArrayOfDevicePropertiesRunnable : public nsRunnable
{
public:
BluetoothPairedDevicePropertiesRunnable(
BluetoothArrayOfDevicePropertiesRunnable(
const nsTArray<nsString>& aDeviceAddresses,
BluetoothReplyRunnable* aRunnable,
const nsTArray<nsString>& aDeviceAddresses)
: mRunnable(dont_AddRef(aRunnable)),
mDeviceAddresses(aDeviceAddresses)
FilterFunc aFilterFunc)
: mDeviceAddresses(aDeviceAddresses)
, mRunnable(dont_AddRef(aRunnable))
, mFilterFunc(aFilterFunc)
{
}
@ -1930,51 +1961,39 @@ public:
dbus_error_init(&err);
BluetoothValue values = InfallibleTArray<BluetoothNamedValue>();
nsAutoString errorStr;
for (uint32_t i = 0; i < mDeviceAddresses.Length(); i++) {
BluetoothValue v;
if (!GetPropertiesInternal(mDeviceAddresses[i], DBUS_DEVICE_IFACE, v)) {
nsAutoString errorStr;
nsString objectPath = GetObjectPathFromAddress(sAdapterPath, mDeviceAddresses[i]);
if (!GetPropertiesInternal(objectPath, DBUS_DEVICE_IFACE, v)) {
errorStr.AssignLiteral("Getting properties failed!");
NS_WARNING(NS_ConvertUTF16toUTF8(errorStr).get());
mRunnable->SetReply(new BluetoothReply(BluetoothReplyError(errorStr)));
if (NS_FAILED(NS_DispatchToMainThread(mRunnable))) {
NS_WARNING("Failed to dispatch to main thread!");
}
DispatchBluetoothReply(mRunnable, values, errorStr);
return NS_OK;
}
// We have to manually attach the path to the rest of the elements
v.get_ArrayOfBluetoothNamedValue().AppendElement(
BluetoothNamedValue(NS_LITERAL_STRING("Path"), mDeviceAddresses[i])
BluetoothNamedValue(NS_LITERAL_STRING("Path"), objectPath)
);
InfallibleTArray<BluetoothNamedValue>& deviceProperties =
v.get_ArrayOfBluetoothNamedValue();
for (uint32_t p = 0;
p < v.get_ArrayOfBluetoothNamedValue().Length(); ++p) {
BluetoothNamedValue& property = v.get_ArrayOfBluetoothNamedValue()[p];
// Only paired devices will be return back to main thread
if (property.name().EqualsLiteral("Paired")) {
bool paired = property.value();
if (paired) {
values.get_ArrayOfBluetoothNamedValue().AppendElement(
BluetoothNamedValue(mDeviceAddresses[i], deviceProperties)
);
}
break;
}
if (mFilterFunc(v)) {
values.get_ArrayOfBluetoothNamedValue().AppendElement(
BluetoothNamedValue(mDeviceAddresses[i],
v.get_ArrayOfBluetoothNamedValue())
);
}
}
mRunnable->SetReply(new BluetoothReply(BluetoothReplySuccess(values)));
if (NS_FAILED(NS_DispatchToMainThread(mRunnable))) {
NS_WARNING("Failed to dispatch to main thread!");
}
DispatchBluetoothReply(mRunnable, values, errorStr);
return NS_OK;
}
private:
nsRefPtr<BluetoothReplyRunnable> mRunnable;
nsTArray<nsString> mDeviceAddresses;
nsRefPtr<BluetoothReplyRunnable> mRunnable;
FilterFunc mFilterFunc;
};
nsresult
@ -1996,6 +2015,55 @@ BluetoothDBusService::GetDevicePropertiesInternal(const BluetoothSignal& aSignal
return NS_OK;
}
nsresult
BluetoothDBusService::GetConnectedDevicePropertiesInternal(uint16_t aProfileId,
BluetoothReplyRunnable* aRunnable)
{
nsAutoString errorStr;
BluetoothValue values = InfallibleTArray<BluetoothNamedValue>();
if (!IsReady()) {
errorStr.AssignLiteral("Bluetooth service is not ready yet!");
DispatchBluetoothReply(aRunnable, values, errorStr);
return NS_OK;
}
nsTArray<nsString> deviceAddresses;
if (aProfileId == BluetoothServiceClass::HANDSFREE ||
aProfileId == BluetoothServiceClass::HEADSET) {
BluetoothHfpManager* hfp = BluetoothHfpManager::Get();
if (hfp->IsConnected()) {
nsString address;
hfp->GetAddress(address);
deviceAddresses.AppendElement(address);
}
} else if (aProfileId == BluetoothServiceClass::OBJECT_PUSH) {
BluetoothOppManager* opp = BluetoothOppManager::Get();
if (opp->IsTransferring()) {
nsString address;
opp->GetAddress(address);
deviceAddresses.AppendElement(address);
}
} else {
errorStr.AssignLiteral("Unknown profile");
DispatchBluetoothReply(aRunnable, values, errorStr);
return NS_OK;
}
nsRefPtr<BluetoothReplyRunnable> runnable = aRunnable;
nsRefPtr<nsRunnable> func(
new BluetoothArrayOfDevicePropertiesRunnable(deviceAddresses,
runnable,
GetConnectedDevicesFilter));
if (NS_FAILED(mBluetoothCommandThread->Dispatch(func, NS_DISPATCH_NORMAL))) {
NS_WARNING("Cannot dispatch task!");
return NS_ERROR_FAILURE;
}
runnable.forget();
return NS_OK;
}
nsresult
BluetoothDBusService::GetPairedDevicePropertiesInternal(
const nsTArray<nsString>& aDeviceAddresses,
@ -2011,7 +2079,9 @@ BluetoothDBusService::GetPairedDevicePropertiesInternal(
nsRefPtr<BluetoothReplyRunnable> runnable = aRunnable;
nsRefPtr<nsRunnable> func(
new BluetoothPairedDevicePropertiesRunnable(runnable, aDeviceAddresses));
new BluetoothArrayOfDevicePropertiesRunnable(aDeviceAddresses,
runnable,
GetPairedDevicesFilter));
if (NS_FAILED(mBluetoothCommandThread->Dispatch(func, NS_DISPATCH_NORMAL))) {
NS_WARNING("Cannot dispatch task!");
return NS_ERROR_FAILURE;
@ -2487,7 +2557,8 @@ BluetoothDBusService::Connect(const nsAString& aDeviceAddress,
DispatchBluetoothReply(aRunnable, v, errorStr);
}
} else {
NS_WARNING("Unknown Profile");
errorStr.AssignLiteral("Unknown profile");
DispatchBluetoothReply(aRunnable, v, errorStr);
}
}
@ -2719,7 +2790,7 @@ BluetoothDBusService::SendFile(const nsAString& aDeviceAddress,
BluetoothValue v = true;
nsAutoString errorStr;
if (!opp->SendFile(aBlobParent)) {
if (!opp->SendFile(aDeviceAddress, aBlobParent)) {
errorStr.AssignLiteral("Calling SendFile() failed");
}

View File

@ -32,10 +32,15 @@ public:
virtual bool IsEnabledInternal();
virtual nsresult GetDefaultAdapterPathInternal(BluetoothReplyRunnable* aRunnable);
virtual nsresult GetDefaultAdapterPathInternal(
BluetoothReplyRunnable* aRunnable);
virtual nsresult GetPairedDevicePropertiesInternal(const nsTArray<nsString>& aDeviceAddresses,
BluetoothReplyRunnable* aRunnable);
virtual nsresult GetConnectedDevicePropertiesInternal(uint16_t aProfileId,
BluetoothReplyRunnable* aRunnable);
virtual nsresult GetPairedDevicePropertiesInternal(
const nsTArray<nsString>& aDeviceAddresses,
BluetoothReplyRunnable* aRunnable);
virtual nsresult StartDiscoveryInternal(BluetoothReplyRunnable* aRunnable);

View File

@ -10,7 +10,7 @@ interface nsIDOMDOMRequest;
interface nsIDOMBlob;
interface nsIDOMBluetoothDevice;
[scriptable, builtinclass, uuid(4321647b-0d45-4231-920b-8d238b6d1700)]
[scriptable, builtinclass, uuid(88a5638f-f55a-4d67-8437-392d0a9a87c7)]
interface nsIDOMBluetoothAdapter : nsIDOMEventTarget
{
readonly attribute DOMString address;
@ -36,6 +36,7 @@ interface nsIDOMBluetoothAdapter : nsIDOMEventTarget
nsIDOMDOMRequest pair(in nsIDOMBluetoothDevice aDevice);
nsIDOMDOMRequest unpair(in nsIDOMBluetoothDevice aDevice);
nsIDOMDOMRequest getPairedDevices();
nsIDOMDOMRequest getConnectedDevices(in unsigned short aProfile);
nsIDOMDOMRequest setPinCode(in DOMString aDeviceAddress, in DOMString aPinCode);
nsIDOMDOMRequest setPasskey(in DOMString aDeviceAddress, in unsigned long aPasskey);
nsIDOMDOMRequest setPairingConfirmation(in DOMString aDeviceAddress, in bool aConfirmation);

View File

@ -347,10 +347,13 @@ ContactDB.prototype = {
cursor.value.search.parsedTel = [];
cursor.value.properties.tel.forEach(
function(tel) {
cursor.value.search.parsedTel.push(parsed.nationalNumber);
cursor.value.search.parsedTel.push(PhoneNumberUtils.normalize(parsed.nationalFormat));
cursor.value.search.parsedTel.push(parsed.internationalNumber);
cursor.value.search.parsedTel.push(PhoneNumberUtils.normalize(parsed.internationalFormat));
let parsed = PhoneNumberUtils.parse(tel.value.toString());
if (parsed) {
cursor.value.search.parsedTel.push(parsed.nationalNumber);
cursor.value.search.parsedTel.push(PhoneNumberUtils.normalize(parsed.nationalFormat));
cursor.value.search.parsedTel.push(parsed.internationalNumber);
cursor.value.search.parsedTel.push(PhoneNumberUtils.normalize(parsed.internationalFormat));
}
cursor.value.search.parsedTel.push(PhoneNumberUtils.normalize(tel.value.toString()));
}
);
@ -457,29 +460,20 @@ ContactDB.prototype = {
for (let i = 0; i <= aContact.properties[field].length; i++) {
if (aContact.properties[field][i]) {
if (field == "tel") {
// Special case telephone number.
// "+1-234-567" should also be found with 1234, 234-56, 23456
let number = aContact.properties.tel[i].value.toString();
let normalized = PhoneNumberUtils.normalize(number);
// We use an object here to avoid duplicates
let containsSearch = {};
let matchSearch = {};
// Chop off the first characters
let number = aContact.properties[field][i].value;
let search = {};
if (number) {
number = number.toString();
contact.search.exactTel.push(PhoneNumberUtils.normalize(number));
contact.search.parsedTel.push(PhoneNumberUtils.normalize(number));
for (let i = 0; i < number.length; i++) {
search[number.substring(i, number.length)] = 1;
}
// Store +1-234-567 as ["1234567", "234567"...]
let digits = number.match(/\d/g);
if (digits && number.length != digits.length) {
digits = digits.join('');
for(let i = 0; i < digits.length; i++) {
search[digits.substring(i, digits.length)] = 1;
}
}
if (DEBUG) debug("lookup: " + JSON.stringify(contact.search[field]));
let parsedNumber = PhoneNumberUtils.parse(number.toString());
if (normalized) {
// exactTel holds normalized version of entered phone number.
// normalized: +1 (949) 123 - 4567 -> +19491234567
contact.search.exactTel.push(normalized);
// matchSearch holds normalized version of entered phone number,
// nationalNumber, nationalFormat, internationalNumber, internationalFormat
matchSearch[normalized] = 1;
let parsedNumber = PhoneNumberUtils.parse(number);
if (parsedNumber) {
if (DEBUG) {
debug("InternationalFormat: " + parsedNumber.internationalFormat);
@ -487,28 +481,37 @@ ContactDB.prototype = {
debug("NationalNumber: " + parsedNumber.nationalNumber);
debug("NationalFormat: " + parsedNumber.nationalFormat);
}
matchSearch[parsedNumber.nationalNumber] = 1;
matchSearch[parsedNumber.internationalNumber] = 1;
matchSearch[PhoneNumberUtils.normalize(parsedNumber.nationalFormat)] = 1;
matchSearch[PhoneNumberUtils.normalize(parsedNumber.internationalFormat)] = 1
}
contact.search.parsedTel.push(parsedNumber.nationalNumber);
contact.search.parsedTel.push(PhoneNumberUtils.normalize(parsedNumber.nationalFormat));
contact.search.parsedTel.push(parsedNumber.internationalNumber);
contact.search.parsedTel.push(PhoneNumberUtils.normalize(parsedNumber.internationalFormat));
if (parsedNumber.internationalNumber &&
number !== parsedNumber.internationalNumber) {
let digits = parsedNumber.internationalNumber.match(/\d/g);
if (digits) {
digits = digits.join('');
for(let i = 0; i < digits.length; i++) {
search[digits.substring(i, digits.length)] = 1;
}
// containsSearch holds incremental search values for:
// normalized number, national format, international format
for (let i = 0; i < normalized.length; i++) {
containsSearch[normalized.substring(i, normalized.length)] = 1;
}
if (parsedNumber) {
if (parsedNumber.nationalFormat) {
let number = PhoneNumberUtils.normalize(parsedNumber.nationalFormat);
for (let i = 0; i < number.length; i++) {
containsSearch[number.substring(i, number.length)] = 1;
}
}
if (parsedNumber.internationalFormat) {
let number = PhoneNumberUtils.normalize(parsedNumber.internationalFormat);
for (let i = 0; i < number.length; i++) {
containsSearch[number.substring(i, number.length)] = 1;
}
}
} else {
dump("Warning: No international number found for " + number + "\n");
}
}
for (let num in search) {
contact.search[field].push(num);
for (let num in containsSearch) {
contact.search.tel.push(num);
}
for (let num in matchSearch) {
contact.search.parsedTel.push(num);
}
} else if (field == "impp" || field == "email") {
let value = aContact.properties[field][i].value;
@ -846,10 +849,7 @@ ContactDB.prototype = {
// not case sensitive
let tmp = options.filterValue.toString().toLowerCase();
if (key === 'tel') {
let digits = tmp.match(/\d/g);
if (digits) {
tmp = digits.join('');
}
tmp = PhoneNumberUtils.normalize(tmp);
}
let range = this._global.IDBKeyRange.bound(tmp, tmp + "\uFFFF");
let index = store.index(key + "LowerCase");

View File

@ -79,6 +79,12 @@ const BrowserElementIsPreloaded = true;
/* Applications Specific Helper */
Cc["@mozilla.org/settingsManager;1"].getService(Ci["nsIDOMSettingsManager"]);
try {
if (Services.prefs.getBoolPref("dom.sysmsg.enabled")) {
Cc["@mozilla.org/system-message-manager;1"].getService(Ci["nsIDOMNavigatorSystemMessages"]);
}
} catch(e) {
}
// This is a produc-specific file that's sometimes unavailable.
try {

View File

@ -3921,6 +3921,10 @@ pref("image.multithreaded_decoding.enabled", true);
// automatically determined based on the system's number of cores.
pref("image.multithreaded_decoding.limit", -1);
// Limit for the canvas image cache. 0 means we don't limit the size of the
// cache.
pref("canvas.image.cache.limit", 0);
// WebGL prefs
pref("gl.msaa-level", 2);
pref("webgl.force-enabled", false);