mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-10-25 19:25:43 +00:00
Bug 817972 - Make Gecko Bluetooth capable of queueing file-sending requests, r=gyeh
This commit is contained in:
parent
6bbda083e4
commit
15a3719abc
@ -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();
|
||||
}
|
||||
|
||||
mTransferMode = 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;
|
||||
@ -537,11 +513,11 @@ BluetoothOppManager::DeleteReceivedFile()
|
||||
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));
|
||||
@ -600,17 +576,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 +614,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 +653,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)
|
||||
{
|
||||
@ -845,6 +863,17 @@ BluetoothOppManager::ServerDataHandler(UnixSocketRawData* aMessage)
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
BluetoothOppManager::ClearQueue()
|
||||
{
|
||||
mCurrentBlobIndex = -1;
|
||||
mBlob = nullptr;
|
||||
|
||||
while (!mBlobs.IsEmpty()) {
|
||||
mBlobs.RemoveElement(mBlobs[0]);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
BluetoothOppManager::ClientDataHandler(UnixSocketRawData* aMessage)
|
||||
{
|
||||
@ -884,7 +913,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 +948,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 +1028,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 +1119,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 +1137,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];
|
||||
@ -1125,7 +1162,6 @@ 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 +1185,6 @@ void
|
||||
BluetoothOppManager::ReplyToDisconnect()
|
||||
{
|
||||
if (!mConnected) return;
|
||||
mConnected = false;
|
||||
|
||||
// Section 3.3.2 "Disconnect", IrOBEX 1.2
|
||||
// [opcode:1][length:2][Headers:var]
|
||||
|
@ -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);
|
||||
|
||||
@ -88,6 +89,7 @@ public:
|
||||
private:
|
||||
BluetoothOppManager();
|
||||
void StartFileTransfer();
|
||||
void StartSendingNextFile();
|
||||
void FileTransferComplete();
|
||||
void UpdateProgress();
|
||||
void ReceivingFileConfirmation();
|
||||
@ -102,6 +104,8 @@ private:
|
||||
void AfterOppDisconnected();
|
||||
void ValidateFileName();
|
||||
bool IsReservedChar(PRUnichar c);
|
||||
void ClearQueue();
|
||||
void RetrieveSentFileName();
|
||||
|
||||
/**
|
||||
* OBEX session status.
|
||||
@ -170,7 +174,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
|
||||
|
@ -2719,7 +2719,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");
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user