author | Ryan VanderMeulen <ryanvm@gmail.com> |
Fri, 26 Apr 2013 16:46:46 -0400 | |
changeset 130110 | 0e45f1b9521f016bea4531379fa5c650c31c35ea |
parent 130109 | 6255ed636db10e67ced1e6043781e1c5a650b682 (current diff) |
parent 129950 | 34fabb5ccebfe170f84aaa84ee08fae96f40e068 (diff) |
child 130111 | e01f456f8a47ce980f7043d777669e270338cfd7 |
child 130115 | 45d40d37b1df7d139536a1292e716d0dfb3ac138 |
child 130170 | a063b169750883a3416f8f0169cd8d34c07ccb70 |
push id | 24596 |
push user | ryanvm@gmail.com |
push date | Sat, 27 Apr 2013 01:20:57 +0000 |
treeherder | mozilla-central@0e45f1b9521f [default view] [failures only] |
perfherder | [talos] [build metrics] [platform microbench] (compared to previous push) |
milestone | 23.0a1 |
first release with | nightly linux32
0e45f1b9521f
/
23.0a1
/
20130427030919
/
files
nightly linux64
0e45f1b9521f
/
23.0a1
/
20130427030919
/
files
nightly mac
0e45f1b9521f
/
23.0a1
/
20130427030919
/
files
nightly win32
0e45f1b9521f
/
23.0a1
/
20130427030919
/
files
nightly win64
0e45f1b9521f
/
23.0a1
/
20130427030919
/
files
|
last release without | nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
|
releases | nightly linux32
23.0a1
/
20130427030919
/
pushlog to previous
nightly linux64
23.0a1
/
20130427030919
/
pushlog to previous
nightly mac
23.0a1
/
20130427030919
/
pushlog to previous
nightly win32
23.0a1
/
20130427030919
/
pushlog to previous
nightly win64
23.0a1
/
20130427030919
/
pushlog to previous
|
--- a/b2g/app/b2g.js +++ b/b2g/app/b2g.js @@ -23,16 +23,17 @@ pref("browser.cache.disk.smart_size.enab pref("browser.cache.disk.smart_size.first_run", false); pref("browser.cache.memory.enable", true); 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); pref("browser.cache.offline.enable", true); pref("offline-apps.allow_by_default", true); /* protocol warning prefs */ pref("network.protocol-handler.warn-external.tel", false);
--- a/b2g/chrome/content/forms.js +++ b/b2g/chrome/content/forms.js @@ -346,17 +346,17 @@ let FormAssistant = { return; } let json = msg.json; switch (msg.name) { 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; } case "Forms:Select:Choice": let options = target.options; let valueChanged = false; @@ -372,17 +372,17 @@ let FormAssistant = { options.item(i).selected = newValue; valueChanged = true; } } } // 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); } break; case "Forms:Select:Blur": { this.setFocusedElement(null); break;
--- a/content/canvas/src/CanvasImageCache.cpp +++ b/content/canvas/src/CanvasImageCache.cpp @@ -8,16 +8,17 @@ #include "nsExpirationTracker.h" #include "imgIRequest.h" #include "gfxASurface.h" #include "gfxPoint.h" #include "mozilla/dom/Element.h" #include "nsTHashtable.h" #include "mozilla/dom/HTMLCanvasElement.h" #include "nsContentUtils.h" +#include "mozilla/Preferences.h" namespace mozilla { using namespace dom; struct ImageCacheKey { ImageCacheKey(Element* aImage, HTMLCanvasElement* aCanvas) : mImage(aImage), mCanvas(aCanvas) {} @@ -37,16 +38,18 @@ struct ImageCacheEntryData { ImageCacheEntryData(const ImageCacheKey& aKey) : mImage(aKey.mImage) , mILC(nullptr) , mCanvas(aKey.mCanvas) {} nsExpirationState* GetExpirationState() { return &mState; } + size_t SizeInBytes() { return mSize.width * mSize.height * 4; } + // Key nsRefPtr<Element> mImage; nsIImageLoadingContent* mILC; nsRefPtr<HTMLCanvasElement> mCanvas; // Value nsCOMPtr<imgIRequest> mRequest; nsRefPtr<gfxASurface> mSurface; gfxIntSize mSize; @@ -74,37 +77,47 @@ public: { return HashGeneric(key->mImage, key->mCanvas); } enum { ALLOW_MEMMOVE = true }; 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() { AgeAllGenerations(); } 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; class CanvasImageCacheShutdownObserver MOZ_FINAL : public nsIObserver { public: NS_DECL_ISUPPORTS @@ -122,29 +135,39 @@ CanvasImageCache::NotifyDrawImage(Elemen gImageCache = new ImageCache(); nsContentUtils::RegisterShutdownObserver(new CanvasImageCacheShutdownObserver()); } ImageCacheEntry* entry = gImageCache->mCache.PutEntry(ImageCacheKey(aImage, aCanvas)); 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); nsCOMPtr<nsIImageLoadingContent> ilc = do_QueryInterface(aImage); if (ilc) { ilc->GetRequest(nsIImageLoadingContent::CURRENT_REQUEST, getter_AddRefs(entry->mData->mRequest)); } 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* CanvasImageCache::Lookup(Element* aImage, HTMLCanvasElement* aCanvas, gfxIntSize* aSize) { if (!gImageCache)
--- a/dom/bluetooth/BluetoothAdapter.cpp +++ b/dom/bluetooth/BluetoothAdapter.cpp @@ -49,20 +49,20 @@ NS_IMPL_CYCLE_COLLECTION_UNLINK_END NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(BluetoothAdapter) NS_INTERFACE_MAP_ENTRY(nsIDOMBluetoothAdapter) NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(BluetoothAdapter) 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) { MOZ_ASSERT(aReq && aAdapterPtr); } virtual bool ParseSuccessfulReply(JS::Value* aValue) @@ -232,16 +232,22 @@ BluetoothAdapter::SetPropertyByValue(con mUuids, &mJsUuids))) { NS_WARNING("Cannot set JS UUIDs object!"); return; } 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); if (NS_FAILED(nsTArrayToJSArray(sc->GetNativeContext(), mDeviceAddresses, &mJsDeviceAddresses))) { NS_WARNING("Cannot set JS Devices object!"); @@ -448,46 +454,62 @@ BluetoothAdapter::SetDiscoverableTimeout return FirePropertyAlreadySet(GetOwner(), aRequest); } BluetoothValue value(aDiscoverableTimeout); BluetoothNamedValue property(NS_LITERAL_STRING("DiscoverableTimeout"), value); return SetProperty(GetOwner(), property, aRequest); } 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; } nsresult BluetoothAdapter::PairUnpair(bool aPair, nsIDOMBluetoothDevice* aDevice, 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 = new BluetoothVoidReplyRunnable(req); nsAutoString addr; aDevice->GetAddress(addr); @@ -525,18 +547,17 @@ BluetoothAdapter::Unpair(nsIDOMBluetooth } nsresult BluetoothAdapter::SetPinCode(const nsAString& aDeviceAddress, const nsAString& aPinCode, 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 = new BluetoothVoidReplyRunnable(req); BluetoothService* bs = BluetoothService::Get(); NS_ENSURE_TRUE(bs, NS_ERROR_FAILURE); if(!bs->SetPinCodeInternal(aDeviceAddress, aPinCode, results)) { @@ -548,18 +569,17 @@ BluetoothAdapter::SetPinCode(const nsASt return NS_OK; } nsresult 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 = new BluetoothVoidReplyRunnable(req); BluetoothService* bs = BluetoothService::Get(); NS_ENSURE_TRUE(bs, NS_ERROR_FAILURE); if(bs->SetPasskeyInternal(aDeviceAddress, aPasskey, results)) { @@ -572,18 +592,17 @@ BluetoothAdapter::SetPasskey(const nsASt } nsresult BluetoothAdapter::SetPairingConfirmation(const nsAString& aDeviceAddress, bool aConfirmation, 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 = new BluetoothVoidReplyRunnable(req); BluetoothService* bs = BluetoothService::Get(); NS_ENSURE_TRUE(bs, NS_ERROR_FAILURE); if(!bs->SetPairingConfirmationInternal(aDeviceAddress, @@ -597,18 +616,17 @@ BluetoothAdapter::SetPairingConfirmation return NS_OK; } nsresult 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 = new BluetoothVoidReplyRunnable(req); BluetoothService* bs = BluetoothService::Get(); NS_ENSURE_TRUE(bs, NS_ERROR_FAILURE); if(!bs->SetAuthorizationInternal(aDeviceAddress, aAllow, results)) { @@ -621,18 +639,17 @@ BluetoothAdapter::SetAuthorization(const } NS_IMETHODIMP BluetoothAdapter::Connect(const nsAString& aDeviceAddress, 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); BluetoothService* bs = BluetoothService::Get(); NS_ENSURE_TRUE(bs, NS_ERROR_FAILURE); nsRefPtr<BluetoothVoidReplyRunnable> results = new BluetoothVoidReplyRunnable(req); bs->Connect(aDeviceAddress, aProfileId, results); @@ -641,18 +658,17 @@ BluetoothAdapter::Connect(const nsAStrin return NS_OK; } NS_IMETHODIMP 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 = new BluetoothVoidReplyRunnable(req); BluetoothService* bs = BluetoothService::Get(); NS_ENSURE_TRUE(bs, NS_ERROR_FAILURE); bs->Disconnect(aProfileId, results); @@ -662,18 +678,17 @@ BluetoothAdapter::Disconnect(uint16_t aP } NS_IMETHODIMP BluetoothAdapter::SendFile(const nsAString& aDeviceAddress, nsIDOMBlob* aBlob, 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 = new BluetoothVoidReplyRunnable(req); BlobChild* actor = mozilla::dom::ContentChild::GetSingleton()->GetOrCreateActorForBlob(aBlob); if (!actor) { @@ -689,18 +704,17 @@ BluetoothAdapter::SendFile(const nsAStri return NS_OK; } NS_IMETHODIMP 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 = new BluetoothVoidReplyRunnable(req); BluetoothService* bs = BluetoothService::Get(); NS_ENSURE_TRUE(bs, NS_ERROR_FAILURE); bs->StopSendingFile(aDeviceAddress, results); @@ -710,18 +724,17 @@ BluetoothAdapter::StopSendingFile(const } nsresult BluetoothAdapter::ConfirmReceivingFile(const nsAString& aDeviceAddress, bool aConfirmation, 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 = new BluetoothVoidReplyRunnable(req); BluetoothService* bs = BluetoothService::Get(); NS_ENSURE_TRUE(bs, NS_ERROR_FAILURE); bs->ConfirmReceivingFile(aDeviceAddress, aConfirmation, results);
--- a/dom/bluetooth/BluetoothHfpManager.cpp +++ b/dom/bluetooth/BluetoothHfpManager.cpp @@ -1450,8 +1450,14 @@ BluetoothHfpManager::IsConnected() { if (mSocket) { return mSocket->GetConnectionStatus() == SocketConnectionStatus::SOCKET_CONNECTED; } return false; } + +void +BluetoothHfpManager::GetAddress(nsAString& aDeviceAddress) +{ + return mSocket->GetAddress(aDeviceAddress); +}
--- a/dom/bluetooth/BluetoothHfpManager.h +++ b/dom/bluetooth/BluetoothHfpManager.h @@ -70,16 +70,17 @@ public: bool Listen(); /** * @param aSend A boolean indicates whether we need to notify headset or not */ void HandleCallStateChanged(uint32_t aCallIndex, uint16_t aCallState, const nsAString& aNumber, bool aSend); bool IsConnected(); + void GetAddress(nsAString& aDeviceAddress); private: class GetVolumeTask; class SendRingIndicatorTask; friend class GetVolumeTask; friend class SendRingIndicatorTask; friend class BluetoothHfpManagerObserver;
--- a/dom/bluetooth/BluetoothOppManager.cpp +++ b/dom/bluetooth/BluetoothOppManager.cpp @@ -225,16 +225,17 @@ BluetoothOppManager::BluetoothOppManager , mBodySegmentLength(0) , mReceivedDataBufferOffset(0) , mAbortFlag(false) , mNewFileFlag(false) , mPutFinalFlag(false) , mSendTransferCompleteFlag(false) , mSuccessFlag(false) , mWaitingForConfirmationFlag(false) + , mCurrentBlobIndex(-1) { mConnectedDeviceAddress.AssignLiteral(BLUETOOTH_ADDRESS_NONE); Listen(); } BluetoothOppManager::~BluetoothOppManager() { } @@ -270,20 +271,17 @@ BluetoothOppManager::Connect(const nsASt } if (mL2capSocket) { mL2capSocket->Disconnect(); mL2capSocket = nullptr; } 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); mRunnable = aRunnable; mSocket = new BluetoothSocket(this, BluetoothSocketType::RFCOMM, true, true); @@ -349,104 +347,81 @@ BluetoothOppManager::Listen() mL2capSocket = nullptr; return false; } } 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); + + mBlob = mBlobs[++mCurrentBlobIndex]; - /* - * 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(); + // Before sending content, we have to send a header including + // information such as file name, file length and content type. + ExtractBlobHeaders(); + StartFileTransfer(); - sFileName.Truncate(); - - nsCOMPtr<nsIDOMFile> file = do_QueryInterface(mBlob); - if (file) { - file->GetName(sFileName); + 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(); } - /** - * 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"); - } + mIsServer = false; +} - int32_t offset = sFileName.RFindChar('/'); - if (offset != kNotFound) { - sFileName = Substring(sFileName, offset + 1); +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; } - 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; - StartFileTransfer(); - + mBlobs.AppendElement(aActor->GetBlob().get()); + StartSendingNextFile(); return true; } bool BluetoothOppManager::StopSendingFile() { mAbortFlag = true; return true; } bool BluetoothOppManager::ConfirmReceivingFile(bool aConfirm) { - if (!mConnected) return false; + NS_ENSURE_TRUE(mConnected, false); + NS_ENSURE_TRUE(mWaitingForConfirmationFlag, false); - if (!mWaitingForConfirmationFlag) { - NS_WARNING("We are not waiting for a confirmation now."); - return false; - } + MOZ_ASSERT(mPacketLeftLength == 0); + 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) { StartFileTransfer(); if (CreateFile()) { success = WriteToFile(mBodySegment.get(), mBodySegmentLength); } } @@ -485,19 +460,20 @@ BluetoothOppManager::AfterOppConnected() void BluetoothOppManager::AfterOppDisconnected() { MOZ_ASSERT(NS_IsMainThread()); 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; if (mInputStream) { mInputStream->Close(); mInputStream = nullptr; } @@ -529,24 +505,56 @@ BluetoothOppManager::DeleteReceivedFile( if (mOutputStream) { mOutputStream->Close(); mOutputStream = nullptr; } 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)); if (NS_FAILED(rv)) { NS_WARNING("Couldn't new a local file"); return false; } @@ -558,64 +566,32 @@ BluetoothOppManager::CreateFile() /* * The function CreateUnique() may create a file with a different file * name from the original sFileName. Therefore we have to retrieve * the file name again. */ 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; } 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; } // Virtual function of class SocketConsumer void BluetoothOppManager::ExtractPacketHeaders(const ObexHeaderSet& aHeader) { @@ -639,16 +615,18 @@ BluetoothOppManager::ExtractPacketHeader aHeader.GetBodyLength(&mBodySegmentLength); } } bool BluetoothOppManager::ExtractBlobHeaders() { + RetrieveSentFileName(); + nsresult rv = mBlob->GetType(sContentType); if (NS_FAILED(rv)) { NS_WARNING("Can't get content type"); SendDisconnectRequest(); return false; } uint64_t fileLength; @@ -676,16 +654,62 @@ BluetoothOppManager::ExtractBlobHeaders( NS_WARNING("Can't create thread"); SendDisconnectRequest(); return false; } 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) { return (c < 0x0020 || c == PRUnichar('?') || c == PRUnichar('|') || c == PRUnichar('<') || c == PRUnichar('>') || c == PRUnichar('"') || c == PRUnichar(':') || c == PRUnichar('/') || c == PRUnichar('*') || c == PRUnichar('\\')); } @@ -732,17 +756,17 @@ BluetoothOppManager::ServerDataHandler(U // Section 3.3.1 "Connect", IrOBEX 1.2 // [opcode:1][length:2][version:1][flags:1][MaxPktSizeWeCanReceive:2] // [Headers:var] ParseHeaders(&aMessage->mData[7], receivedLength - 7, &pktHeaders); ReplyToConnect(); AfterOppConnected(); - mTransferMode = true; + mIsServer = true; } else if (opCode == ObexRequestCode::Disconnect || opCode == ObexRequestCode::Abort) { // Section 3.3.2 "Disconnect", IrOBEX 1.2 // Section 3.3.5 "Abort", IrOBEX 1.2 // [opcode:1][length:2][Headers:var] ParseHeaders(&aMessage->mData[3], receivedLength - 3, &pktHeaders); @@ -834,23 +858,35 @@ BluetoothOppManager::ServerDataHandler(U UpdateProgress(); mUpdateProgressCounter = sSentFileLength / kUpdateProgressBase + 1; } // Success to receive a file and notify completion 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) { uint8_t opCode; int packetLength; if (mPacketLeftLength > 0) { opCode = mPutFinalFlag ? ObexRequestCode::PutFinal : ObexRequestCode::Put; packetLength = mPacketLeftLength; @@ -879,17 +915,27 @@ BluetoothOppManager::ClientDataHandler(U NS_WARNING(str.get()); FileTransferComplete(); return; } 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(); } else if (mLastCommand == ObexRequestCode::Disconnect) { AfterOppDisconnected(); // Most devices will directly terminate connection after receiving // Disconnect request, so we make a delay here. If the socket hasn't been // disconnected, we will close it. @@ -904,26 +950,18 @@ BluetoothOppManager::ClientDataHandler(U AfterOppConnected(); // Keep remote information mRemoteObexVersion = aMessage->mData[3]; mRemoteConnectionFlags = aMessage->mData[4]; 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; } if (mAbortFlag) { SendAbortRequest(); return; @@ -992,16 +1030,18 @@ BluetoothOppManager::SendConnectRequest( memcpy(s->mData, req, s->mSize); mSocket->SendSocketData(s); } void BluetoothOppManager::SendPutHeaderRequest(const nsAString& aFileName, int aFileSize) { + if (!mConnected) return; + uint8_t* req = new uint8_t[mRemoteMaxPacketLength]; int len = aFileName.Length(); uint8_t* fileName = new uint8_t[(len + 1) * 2]; const PRUnichar* fileNamePtr = aFileName.BeginReading(); for (int i = 0; i < len; i++) { fileName[i * 2] = (uint8_t)(fileNamePtr[i] >> 8); @@ -1081,32 +1121,36 @@ BluetoothOppManager::SendPutFinalRequest sWaitingToSendPutFinal = false; delete [] req; } void BluetoothOppManager::SendDisconnectRequest() { + if (!mConnected) return; + // Section 3.3.2 "Disconnect", IrOBEX 1.2 // [opcode:1][length:2][Headers:var] uint8_t req[255]; int index = 3; SetObexPacketInfo(req, ObexRequestCode::Disconnect, index); mLastCommand = ObexRequestCode::Disconnect; UnixSocketRawData* s = new UnixSocketRawData(index); memcpy(s->mData, req, s->mSize); mSocket->SendSocketData(s); } void BluetoothOppManager::SendAbortRequest() { + if (!mConnected) return; + // Section 3.3.5 "Abort", IrOBEX 1.2 // [opcode:1][length:2][Headers:var] uint8_t req[255]; int index = 3; SetObexPacketInfo(req, ObexRequestCode::Abort, index); mLastCommand = ObexRequestCode::Abort; @@ -1117,20 +1161,25 @@ BluetoothOppManager::SendAbortRequest() bool 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] // [Headers:var] uint8_t req[255]; int index = 7; req[3] = 0x10; // version=1.0 @@ -1144,17 +1193,16 @@ BluetoothOppManager::ReplyToConnect() memcpy(s->mData, req, s->mSize); mSocket->SendSocketData(s); } void BluetoothOppManager::ReplyToDisconnect() { if (!mConnected) return; - mConnected = false; // Section 3.3.2 "Disconnect", IrOBEX 1.2 // [opcode:1][length:2][Headers:var] uint8_t req[255]; int index = 3; SetObexPacketInfo(req, ObexResponseCode::Success, index); @@ -1210,17 +1258,17 @@ BluetoothOppManager::FileTransferComplet v = mConnectedDeviceAddress; parameters.AppendElement(BluetoothNamedValue(name, v)); name.AssignLiteral("success"); v = mSuccessFlag; parameters.AppendElement(BluetoothNamedValue(name, v)); name.AssignLiteral("received"); - v = mTransferMode; + v = mIsServer; parameters.AppendElement(BluetoothNamedValue(name, v)); name.AssignLiteral("fileName"); v = sFileName; parameters.AppendElement(BluetoothNamedValue(name, v)); name.AssignLiteral("fileLength"); v = sSentFileLength; @@ -1246,17 +1294,17 @@ BluetoothOppManager::StartFileTransfer() InfallibleTArray<BluetoothNamedValue> parameters; type.AssignLiteral("bluetooth-opp-transfer-start"); name.AssignLiteral("address"); v = mConnectedDeviceAddress; parameters.AppendElement(BluetoothNamedValue(name, v)); name.AssignLiteral("received"); - v = mTransferMode; + v = mIsServer; parameters.AppendElement(BluetoothNamedValue(name, v)); name.AssignLiteral("fileName"); v = sFileName; parameters.AppendElement(BluetoothNamedValue(name, v)); name.AssignLiteral("fileLength"); v = sFileLength; @@ -1280,17 +1328,17 @@ BluetoothOppManager::UpdateProgress() InfallibleTArray<BluetoothNamedValue> parameters; type.AssignLiteral("bluetooth-opp-update-progress"); name.AssignLiteral("address"); v = mConnectedDeviceAddress; parameters.AppendElement(BluetoothNamedValue(name, v)); name.AssignLiteral("received"); - v = mTransferMode; + v = mIsServer; parameters.AppendElement(BluetoothNamedValue(name, v)); name.AssignLiteral("processedLength"); v = sSentFileLength; parameters.AppendElement(BluetoothNamedValue(name, v)); name.AssignLiteral("fileLength"); v = sFileLength; @@ -1328,16 +1376,28 @@ BluetoothOppManager::ReceivingFileConfir if (!BroadcastSystemMessage(type, parameters)) { NS_WARNING("Failed to send [bluetooth-opp-receiving-file-confirmation]"); return; } } 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) { MOZ_ASSERT(aSocket); /** * If the created connection is an inbound connection, close another server * socket because currently only one file-transfer session is allowed. After * that, we need to make sure that both server socket would be nulled out. @@ -1405,32 +1465,21 @@ BluetoothOppManager::OnDisconnect(Blueto /** * It is valid for a bluetooth device which is transfering file via OPP * closing socket without sending OBEX disconnect request first. So we * delete the broken file when we failed to receive a file from the remote, * 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(); mConnectedDeviceAddress.AssignLiteral(BLUETOOTH_ADDRESS_NONE); mSuccessFlag = false; mSocket = nullptr; Listen();
--- a/dom/bluetooth/BluetoothOppManager.h +++ b/dom/bluetooth/BluetoothOppManager.h @@ -4,19 +4,20 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this file, * You can obtain one at http://mozilla.org/MPL/2.0/. */ #ifndef mozilla_dom_bluetooth_bluetoothoppmanager_h__ #define mozilla_dom_bluetooth_bluetoothoppmanager_h__ #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; BEGIN_BLUETOOTH_NAMESPACE class BluetoothReplyRunnable; class BluetoothSocket; @@ -49,17 +50,17 @@ public: * either call Disconnect() to close RFCOMM connection or start another * file-sending thread via calling SendFile() again. */ bool Connect(const nsAString& aDeviceObjectPath, BluetoothReplyRunnable* aRunnable); void Disconnect(); bool Listen(); - bool SendFile(BlobParent* aBlob); + bool SendFile(const nsAString& aDeviceAddress, BlobParent* aBlob); bool StopSendingFile(); bool ConfirmReceivingFile(bool aConfirm); void SendConnectRequest(); void SendPutHeaderRequest(const nsAString& aFileName, int aFileSize); void SendPutRequest(uint8_t* aFileBody, int aFileBodyLength); void SendPutFinalRequest(); void SendDisconnectRequest(); @@ -67,46 +68,52 @@ public: void ExtractPacketHeaders(const ObexHeaderSet& aHeader); bool ExtractBlobHeaders(); nsresult HandleShutdown(); // 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( BluetoothSocket* aSocket, nsAutoPtr<mozilla::ipc::UnixSocketRawData>& aMessage) MOZ_OVERRIDE; virtual void OnConnectSuccess(BluetoothSocket* aSocket) MOZ_OVERRIDE; virtual void OnConnectError(BluetoothSocket* aSocket) MOZ_OVERRIDE; virtual void OnDisconnect(BluetoothSocket* aSocket) MOZ_OVERRIDE; void OnConnectSuccess() MOZ_OVERRIDE; void OnConnectError() MOZ_OVERRIDE; void OnDisconnect() MOZ_OVERRIDE; private: BluetoothOppManager(); void StartFileTransfer(); + void StartSendingNextFile(); void FileTransferComplete(); void UpdateProgress(); void ReceivingFileConfirmation(); bool CreateFile(); bool WriteToFile(const uint8_t* aData, int aDataLength); void DeleteReceivedFile(); void ReplyToConnect(); void ReplyToDisconnect(); void ReplyToPut(bool aFinal, bool aContinue); void AfterOppConnected(); void AfterFirstPut(); void AfterOppDisconnected(); void ValidateFileName(); bool IsReservedChar(PRUnichar c); + void ClearQueue(); + void RetrieveSentFileName(); + DeviceStorageFile* CreateDeviceStorageFile(nsIFile* aFile); + void NotifyAboutFileChange(); /** * OBEX session status. * Set when OBEX session is established. */ bool mConnected; nsString mConnectedDeviceAddress; @@ -154,28 +161,30 @@ private: * Set when a transfer is successfully completed. */ bool mSuccessFlag; /** * True: Receive file (Server) * False: Send file (Client) */ - bool mTransferMode; + bool mIsServer; /** * Set when receiving the first PUT packet and wait for * ConfirmReceivingFile() to be called. */ bool mWaitingForConfirmationFlag; 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 * execution, which is not allowed to happen on the IOThread. * */ nsCOMPtr<nsIThread> mReadFileThread; nsCOMPtr<nsIOutputStream> mOutputStream;
--- a/dom/bluetooth/BluetoothService.h +++ b/dom/bluetooth/BluetoothService.h @@ -126,17 +126,27 @@ public: * specific method. * * @return NS_OK on success, NS_ERROR_FAILURE otherwise */ virtual nsresult 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 */ virtual nsresult StopDiscoveryInternal(BluetoothReplyRunnable* aRunnable) = 0; /**
--- a/dom/bluetooth/ipc/BluetoothParent.cpp +++ b/dom/bluetooth/ipc/BluetoothParent.cpp @@ -192,18 +192,20 @@ BluetoothParent::RecvPBluetoothRequestCo case Request::TStartDiscoveryRequest: return actor->DoRequest(aRequest.get_StartDiscoveryRequest()); case Request::TStopDiscoveryRequest: return actor->DoRequest(aRequest.get_StopDiscoveryRequest()); case Request::TPairRequest: 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: return actor->DoRequest(aRequest.get_SetPasskeyRequest()); case Request::TConfirmPairingConfirmationRequest: return actor->DoRequest(aRequest.get_ConfirmPairingConfirmationRequest()); case Request::TConfirmAuthorizationRequest: return actor->DoRequest(aRequest.get_ConfirmAuthorizationRequest()); @@ -367,25 +369,36 @@ BluetoothRequestParent::DoRequest(const mService->RemoveDeviceInternal(aRequest.address(), mReplyRunnable.get()); NS_ENSURE_SUCCESS(rv, false); return true; } 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; } bool BluetoothRequestParent::DoRequest(const SetPinCodeRequest& aRequest) { MOZ_ASSERT(mService);
--- a/dom/bluetooth/ipc/BluetoothParent.h +++ b/dom/bluetooth/ipc/BluetoothParent.h @@ -141,17 +141,19 @@ protected: bool DoRequest(const PairRequest& aRequest); bool DoRequest(const UnpairRequest& aRequest); bool - DoRequest(const DevicePropertiesRequest& aRequest); + DoRequest(const PairedDevicePropertiesRequest& aRequest); + bool + DoRequest(const ConnectedDevicePropertiesRequest& aRequest); bool DoRequest(const SetPinCodeRequest& aRequest); bool DoRequest(const SetPasskeyRequest& aRequest); bool
--- a/dom/bluetooth/ipc/BluetoothServiceChildProcess.cpp +++ b/dom/bluetooth/ipc/BluetoothServiceChildProcess.cpp @@ -106,21 +106,29 @@ nsresult BluetoothServiceChildProcess::GetDevicePropertiesInternal( const BluetoothSignal& aSignal) { MOZ_NOT_REACHED("Should never be called from child"); 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); return NS_OK; } nsresult BluetoothServiceChildProcess::StopDiscoveryInternal(
--- a/dom/bluetooth/ipc/BluetoothServiceChildProcess.h +++ b/dom/bluetooth/ipc/BluetoothServiceChildProcess.h @@ -47,16 +47,20 @@ public: GetDefaultAdapterPathInternal(BluetoothReplyRunnable* aRunnable) MOZ_OVERRIDE; virtual nsresult GetPairedDevicePropertiesInternal(const nsTArray<nsString>& aDeviceAddresses, BluetoothReplyRunnable* aRunnable) MOZ_OVERRIDE; virtual nsresult + GetConnectedDevicePropertiesInternal(uint16_t aProfileId, + BluetoothReplyRunnable* aRunnable) + MOZ_OVERRIDE; + virtual nsresult StopDiscoveryInternal(BluetoothReplyRunnable* aRunnable) MOZ_OVERRIDE; virtual nsresult StartDiscoveryInternal(BluetoothReplyRunnable* aRunnable) MOZ_OVERRIDE; virtual nsresult SetProperty(BluetoothObjectType aType, const BluetoothNamedValue& aValue,
--- a/dom/bluetooth/ipc/PBluetooth.ipdl +++ b/dom/bluetooth/ipc/PBluetooth.ipdl @@ -83,20 +83,24 @@ struct ConfirmAuthorizationRequest nsString path; }; struct DenyAuthorizationRequest { nsString path; }; -struct DevicePropertiesRequest +struct PairedDevicePropertiesRequest { nsString[] addresses; }; +struct ConnectedDevicePropertiesRequest +{ + uint16_t profileId; +}; struct ConnectRequest { nsString address; uint16_t profileId; }; struct DisconnectRequest @@ -135,17 +139,18 @@ union Request PairRequest; UnpairRequest; SetPinCodeRequest; SetPasskeyRequest; ConfirmPairingConfirmationRequest; DenyPairingConfirmationRequest; ConfirmAuthorizationRequest; DenyAuthorizationRequest; - DevicePropertiesRequest; + ConnectedDevicePropertiesRequest; + PairedDevicePropertiesRequest; ConnectRequest; DisconnectRequest; SendFileRequest; StopSendingFileRequest; ConfirmReceivingFileRequest; DenyReceivingFileRequest; };
--- a/dom/bluetooth/linux/BluetoothDBusService.cpp +++ b/dom/bluetooth/linux/BluetoothDBusService.cpp @@ -142,16 +142,17 @@ static const char* sBluetoothDBusSignals */ static nsAutoPtr<RawDBusConnection> gThreadConnection; static nsDataHashtable<nsStringHashKey, DBusMessage* > sPairingReqTable; static nsDataHashtable<nsStringHashKey, DBusMessage* > sAuthorizeReqTable; 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: RemoveDeviceTask(const nsACString& aDeviceObjectPath, BluetoothReplyRunnable* aRunnable) : mDeviceObjectPath(aDeviceObjectPath) , mRunnable(aRunnable) { @@ -186,16 +187,44 @@ public: return NS_OK; } private: nsCString mDeviceObjectPath; 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, BluetoothReplyRunnable* aRunnable) : mMessageName(aMessageName) , mRunnable(aRunnable) { MOZ_ASSERT(aMessageName); @@ -1906,80 +1935,70 @@ public: return NS_OK; } 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) { } nsresult Run() { MOZ_ASSERT(!NS_IsMainThread()); DBusError err; 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: + nsTArray<nsString> mDeviceAddresses; nsRefPtr<BluetoothReplyRunnable> mRunnable; - nsTArray<nsString> mDeviceAddresses; + FilterFunc mFilterFunc; }; nsresult BluetoothDBusService::GetDevicePropertiesInternal(const BluetoothSignal& aSignal) { NS_ASSERTION(NS_IsMainThread(), "Must be called from main thread!"); if (!mConnection || !gThreadConnection) { @@ -1992,31 +2011,82 @@ BluetoothDBusService::GetDevicePropertie NS_WARNING("Cannot dispatch task!"); return NS_ERROR_FAILURE; } 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, BluetoothReplyRunnable* aRunnable) { if (!IsReady()) { BluetoothValue v; nsAutoString errorStr; errorStr.AssignLiteral("Bluetooth service is not ready yet!"); DispatchBluetoothReply(aRunnable, v, errorStr); return NS_OK; } 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; } runnable.forget(); return NS_OK; } @@ -2482,17 +2552,18 @@ BluetoothDBusService::Connect(const nsAS BluetoothOppManager* opp = BluetoothOppManager::Get(); if (!opp->Connect(GetObjectPathFromAddress(sAdapterPath, aDeviceAddress), aRunnable)) { errorStr.AssignLiteral("BluetoothOppManager has been connected/is \ connecting!"); DispatchBluetoothReply(aRunnable, v, errorStr); } } else { - NS_WARNING("Unknown Profile"); + errorStr.AssignLiteral("Unknown profile"); + DispatchBluetoothReply(aRunnable, v, errorStr); } } void BluetoothDBusService::Disconnect(const uint16_t aProfileId, BluetoothReplyRunnable* aRunnable) { if (aProfileId == BluetoothServiceClass::HANDSFREE || @@ -2714,17 +2785,17 @@ BluetoothDBusService::SendFile(const nsA // Currently we only support one device sending one file at a time, // so we don't need aDeviceAddress here because the target device // has been determined when calling 'Connect()'. Nevertheless, keep // it for future use. BluetoothOppManager* opp = BluetoothOppManager::Get(); BluetoothValue v = true; nsAutoString errorStr; - if (!opp->SendFile(aBlobParent)) { + if (!opp->SendFile(aDeviceAddress, aBlobParent)) { errorStr.AssignLiteral("Calling SendFile() failed"); } DispatchBluetoothReply(aRunnable, v, errorStr); } void BluetoothDBusService::StopSendingFile(const nsAString& aDeviceAddress,
--- a/dom/bluetooth/linux/BluetoothDBusService.h +++ b/dom/bluetooth/linux/BluetoothDBusService.h @@ -27,20 +27,25 @@ public: bool IsReady(); virtual nsresult StartInternal(); virtual nsresult StopInternal(); 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); virtual nsresult StopDiscoveryInternal(BluetoothReplyRunnable* aRunnable); virtual nsresult GetDevicePropertiesInternal(const BluetoothSignal& aSignal);
--- a/dom/bluetooth/nsIDOMBluetoothAdapter.idl +++ b/dom/bluetooth/nsIDOMBluetoothAdapter.idl @@ -5,17 +5,17 @@ * You can obtain one at http://mozilla.org/MPL/2.0/. */ #include "nsIDOMEventTarget.idl" 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; [binaryname(AdapterClass)] readonly attribute unsigned long class; readonly attribute bool discovering; [implicit_jscontext] readonly attribute jsval devices; @@ -31,16 +31,17 @@ interface nsIDOMBluetoothAdapter : nsIDO nsIDOMDOMRequest setName(in DOMString name); nsIDOMDOMRequest setDiscoverable(in bool discoverable); nsIDOMDOMRequest setDiscoverableTimeout(in unsigned long timeout); nsIDOMDOMRequest startDiscovery(); nsIDOMDOMRequest stopDiscovery(); 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); nsIDOMDOMRequest setAuthorization(in DOMString aDeviceAddress, in bool aAllow); /** * Connect/Disconnect to a specific service of a target remote device. * To check the value of service UUIDs, please check "Bluetooth Assigned
--- a/dom/contacts/fallback/ContactDB.jsm +++ b/dom/contacts/fallback/ContactDB.jsm @@ -342,20 +342,23 @@ ContactDB.prototype = { objectStore.createIndex("telMatch", "search.parsedTel", {multiEntry: true}); objectStore.openCursor().onsuccess = function(event) { let cursor = event.target.result; if (cursor) { if (cursor.value.properties.tel) { 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())); } ); cursor.update(cursor.value); } cursor.continue(); } }; @@ -452,68 +455,68 @@ ContactDB.prototype = { for (let field in aContact.properties) { contact.properties[field] = aContact.properties[field]; // Add search fields if (aContact.properties[field] && contact.search[field]) { 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); debug("InternationalNumber: " + parsedNumber.internationalNumber); debug("NationalNumber: " + parsedNumber.nationalNumber); debug("NationalFormat: " + parsedNumber.nationalFormat); } - - 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)); + matchSearch[parsedNumber.nationalNumber] = 1; + matchSearch[parsedNumber.internationalNumber] = 1; + matchSearch[PhoneNumberUtils.normalize(parsedNumber.nationalFormat)] = 1; + matchSearch[PhoneNumberUtils.normalize(parsedNumber.internationalFormat)] = 1 + } - 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; } } - } else { - dump("Warning: No international number found for " + number + "\n"); + if (parsedNumber.internationalFormat) { + let number = PhoneNumberUtils.normalize(parsedNumber.internationalFormat); + for (let i = 0; i < number.length; i++) { + containsSearch[number.substring(i, number.length)] = 1; + } + } } } - 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; if (value && typeof value == "string") { contact.search[field].push(value.toLowerCase()); } } else { let val = aContact.properties[field][i]; @@ -841,20 +844,17 @@ ContactDB.prototype = { let index = store.index("telMatch"); let normalized = PhoneNumberUtils.normalize(options.filterValue) request = index.mozGetAll(normalized, limit); } else { // 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"); request = index.mozGetAll(range, limit); } if (!txn.result) txn.result = {};
--- a/dom/ipc/preload.js +++ b/dom/ipc/preload.js @@ -74,16 +74,22 @@ const BrowserElementIsPreloaded = true; Cc["@mozilla.org/system-info;1"].getService(Ci["nsIPropertyBag2"]); Cc["@mozilla.org/thread-manager;1"].getService(Ci["nsIThreadManager"]); Cc["@mozilla.org/toolkit/app-startup;1"].getService(Ci["nsIAppStartup"]); Cc["@mozilla.org/uriloader;1"].getService(Ci["nsIURILoader"]); Cc["@mozilla.org/contentsecuritypolicy;1"].createInstance(Ci["nsIContentSecurityPolicy"]); /* 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 { Services.scriptloader.loadSubScript("chrome://browser/content/forms.js", global); } catch (e) { } Services.scriptloader.loadSubScript("chrome://global/content/BrowserElementPanning.js", global); Services.scriptloader.loadSubScript("chrome://global/content/BrowserElementChildPreload.js", global);
--- a/modules/libpref/src/init/all.js +++ b/modules/libpref/src/init/all.js @@ -3927,16 +3927,20 @@ pref("image.mem.max_decoded_image_kb", 5 // Whether we decode images on multiple background threads rather than the // foreground thread. pref("image.multithreaded_decoding.enabled", true); // How many threads we'll use for multithreaded decoding. If < 0, will be // 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); pref("webgl.disabled", false); pref("webgl.shader_validator", true); pref("webgl.prefer-native-gl", false); pref("webgl.min_capability_mode", false); pref("webgl.disable-extensions", false);
--- a/security/manager/boot/src/nsSTSPreloadList.errors +++ b/security/manager/boot/src/nsSTSPreloadList.errors @@ -1,38 +1,39 @@ accounts.google.com: max-age too low: 2592000 aladdinschools.appspot.com: did not receive HSTS header -alpha.irccloud.com: did not receive HSTS header api.mega.co.nz: could not connect to host api.recurly.com: did not receive HSTS header +api.simple.com: did not receive HSTS header apis.google.com: did not receive HSTS header appengine.google.com: did not receive HSTS header betnet.fr: could not connect to host bigshinylock.minazo.net: could not connect to host braintreegateway.com: could not connect to host braintreepayments.com: did not receive HSTS header browserid.org: did not receive HSTS header cert.se: max-age too low: 2628001 checkout.google.com: did not receive HSTS header +chrome-devtools-frontend.appspot.com: did not receive HSTS header chrome.google.com: did not receive HSTS header chromiumcodereview.appspot.com: did not receive HSTS header code.google.com: did not receive HSTS header codereview.appspot.com: did not receive HSTS header codereview.chromium.org: did not receive HSTS header crypto.is: did not receive HSTS header dl.google.com: did not receive HSTS header docs.google.com: did not receive HSTS header download.jitsi.org: did not receive HSTS header drive.google.com: did not receive HSTS header dropcam.com: did not receive HSTS header emailprivacytester.com: max-age too low: 8640000 encrypted.google.com: did not receive HSTS header epoxate.com: max-age too low: 259200 -factor.cc: could not connect to host fatzebra.com.au: did not receive HSTS header +fj.simple.com: did not receive HSTS header gmail.com: did not receive HSTS header googlemail.com: did not receive HSTS header googleplex.com: could not connect to host greplin.com: did not receive HSTS header grepular.com: max-age too low: 8640000 groups.google.com: did not receive HSTS header health.google.com: did not receive HSTS header history.google.com: did not receive HSTS header @@ -41,18 +42,18 @@ iop.intuit.com: max-age too low: 86400 irccloud.com: did not receive HSTS header jitsi.org: did not receive HSTS header jottit.com: did not receive HSTS header kiwiirc.com: max-age too low: 5256000 ledgerscope.net: max-age too low: 86400 linx.net: did not receive HSTS header lists.mayfirst.org: did not receive HSTS header mail.google.com: did not receive HSTS header +makeyourlaws.org: could not connect to host market.android.com: did not receive HSTS header -mega.co.nz: could not connect to host my.alfresco.com: did not receive HSTS header mydigipass.com: did not receive HSTS header neonisi.com: could not connect to host openshift.redhat.com: did not receive HSTS header ottospora.nl: could not connect to host packagist.org: max-age too low: 2592000 passwd.io: could not connect to host plus.google.com: did not receive HSTS header @@ -85,9 +86,8 @@ www.lastpass.com: did not receive HSTS h www.ledgerscope.net: max-age too low: 86400 www.logentries.com: did not receive HSTS header www.makeyourlaws.org: did not receive HSTS header www.moneybookers.com: did not receive HSTS header www.neonisi.com: could not connect to host www.paycheckrecords.com: did not receive HSTS header www.paypal.com: max-age too low: 14400 www.sandbox.mydigipass.com: could not connect to host -www.twitter.com: did not receive HSTS header
--- a/security/manager/boot/src/nsSTSPreloadList.inc +++ b/security/manager/boot/src/nsSTSPreloadList.inc @@ -3,46 +3,49 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ /*****************************************************************************/ /* This is an automatically generated file. If you're not */ /* nsStrictTransportSecurityService.cpp, you shouldn't be #including it. */ /*****************************************************************************/ #include "mozilla/StandardInteger.h" -const PRTime gPreloadListExpirationTime = INT64_C(1374654832387000); +const PRTime gPreloadListExpirationTime = INT64_C(1377890142384000); class nsSTSPreload { public: const char *mHost; const bool mIncludeSubdomains; }; static const nsSTSPreload kSTSPreloadList[] = { + { "alpha.irccloud.com", false }, { "api.intercom.io", false }, { "app.recurly.com", false }, { "arivo.com.br", true }, + { "bassh.net", true }, { "blog.torproject.org", false }, { "bugzilla.mozilla.org", true }, { "business.medbank.com.mt", true }, { "check.torproject.org", false }, { "cloudsecurityalliance.org", true }, + { "controlcenter.gigahost.dk", true }, { "crate.io", true }, { "crm.onlime.ch", false }, { "crypto.cat", false }, { "csawctf.poly.edu", true }, { "developer.mydigipass.com", false }, { "dist.torproject.org", false }, { "dm.lookout.com", false }, { "dm.mylookout.com", false }, { "ebanking.indovinabank.com.vn", false }, { "entropia.de", false }, { "espra.com", true }, - { "factor.cc", true }, + { "factor.cc", false }, { "gocardless.com", true }, { "howrandom.org", true }, { "id.mayfirst.org", false }, { "intercom.io", false }, { "itriskltd.com", true }, { "keyerror.com", true }, { "lastpass.com", false }, { "lockify.com", true }, @@ -55,25 +58,27 @@ static const nsSTSPreload kSTSPreloadLis { "mattmccutchen.net", true }, { "mega.co.nz", false }, { "members.mayfirst.org", false }, { "members.nearlyfreespeech.net", false }, { "my.onlime.ch", false }, { "mylookout.com", false }, { "neg9.org", false }, { "passwd.io", true }, + { "pay.gigahost.dk", true }, { "paymill.com", true }, { "paymill.de", true }, { "piratenlogin.de", true }, { "pixi.me", true }, { "riseup.net", true }, { "roundcube.mayfirst.org", false }, { "sandbox.mydigipass.com", false }, { "serverdensity.io", true }, { "silentcircle.com", true }, + { "simple.com", false }, { "stocktrade.de", false }, { "stripe.com", true }, { "support.mayfirst.org", false }, { "surfeasy.com", false }, { "therapynotes.com", false }, { "twitter.com", false }, { "ubertt.org", true }, { "webmail.gigahost.dk", false }, @@ -87,13 +92,15 @@ static const nsSTSPreload kSTSPreloadLis { "www.entropia.de", false }, { "www.gov.uk", false }, { "www.intercom.io", false }, { "www.irccloud.com", false }, { "www.lookout.com", false }, { "www.mydigipass.com", false }, { "www.mylookout.com", false }, { "www.noisebridge.net", false }, + { "www.simple.com", false }, { "www.surfeasy.com", false }, { "www.therapynotes.com", false }, { "www.torproject.org", false }, + { "www.twitter.com", false }, { "zoo24.de", true }, };