Bluetooth File Transfer Example▲
Sélectionnez
/**
**************************************************************************
**
** Copyright (C) 2017 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the QtBluetooth module of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:BSD$
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** BSD License Usage
** Alternatively, you may use this file under the terms of the BSD license
** as follows:
**
** "Redistribution and use in source and binary forms, with or without
** modification, are permitted provided that the following conditions are
** met:
** * Redistributions of source code must retain the above copyright
** notice, this list of conditions and the following disclaimer.
** * Redistributions in binary form must reproduce the above copyright
** notice, this list of conditions and the following disclaimer in
** the documentation and/or other materials provided with the
** distribution.
** * Neither the name of The Qt Company Ltd nor the names of its
** contributors may be used to endorse or promote products derived
** from this software without specific prior written permission.
**
**
** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
**
** $QT_END_LICENSE$
**
***************************************************************************
*/
#include
"remoteselector.h"
#include
"ui_remoteselector.h"
#include <qbluetoothdeviceinfo.h>
#include <qbluetoothaddress.h>
#include <qbluetoothtransferrequest.h>
#include <qbluetoothtransferreply.h>
#include <qbluetoothlocaldevice.h>
#include <QMovie>
#include <QMessageBox>
#include <QFileDialog>
#include <QCheckBox>
#include
"progress.h"
#include
"pindisplay.h"
QT_USE_NAMESPACE
RemoteSelector::
RemoteSelector(QWidget *
parent)
:
QDialog(parent), ui(new
Ui::
RemoteSelector),
m_localDevice(new
QBluetoothLocalDevice), m_pindisplay(0
),
m_pairingError(false
)
{
ui-&
gt;setupUi(this
);
//Using default Bluetooth adapter
QBluetoothAddress adapterAddress =
m_localDevice-&
gt;address();
/*
* In case of multiple Bluetooth adapters it is possible to
* set which adapter will be used by providing MAC Address.
* Example code:
*
* QBluetoothAddress adapterAddress("XX:XX:XX:XX:XX:XX");
* m_discoveryAgent = new QBluetoothServiceDiscoveryAgent(adapterAddress);
*/
m_discoveryAgent =
new
QBluetoothServiceDiscoveryAgent(adapterAddress);
connect(m_discoveryAgent, SIGNAL(serviceDiscovered(QBluetoothServiceInfo)),
this
, SLOT(serviceDiscovered(QBluetoothServiceInfo)));
connect(m_discoveryAgent, SIGNAL(finished()), this
, SLOT(discoveryFinished()));
connect(m_discoveryAgent, SIGNAL(canceled()), this
, SLOT(discoveryFinished()));
ui-&
gt;remoteDevices-&
gt;setColumnWidth(3
, 75
);
ui-&
gt;remoteDevices-&
gt;setColumnWidth(4
, 100
);
connect(m_localDevice, SIGNAL(pairingDisplayPinCode(QBluetoothAddress,QString)),
this
, SLOT(displayPin(QBluetoothAddress,QString)));
connect(m_localDevice, SIGNAL(pairingDisplayConfirmation(QBluetoothAddress,QString)),
this
, SLOT(displayConfirmation(QBluetoothAddress,QString)));
connect(m_localDevice, SIGNAL(pairingFinished(QBluetoothAddress,QBluetoothLocalDevice::
Pairing)),
this
, SLOT(pairingFinished(QBluetoothAddress,QBluetoothLocalDevice::
Pairing)));
connect(m_localDevice, SIGNAL(error(QBluetoothLocalDevice::
Error)),
this
, SLOT(pairingError(QBluetoothLocalDevice::
Error)));
ui-&
gt;busyWidget-&
gt;setMovie(new
QMovie(":/icons/busy.gif"
));
ui-&
gt;busyWidget-&
gt;movie()-&
gt;start();
ui-&
gt;pairingBusy-&
gt;setMovie(new
QMovie(":/icons/pairing.gif"
));
ui-&
gt;pairingBusy-&
gt;hide();
ui-&
gt;remoteDevices-&
gt;clearContents();
ui-&
gt;remoteDevices-&
gt;setRowCount(0
);
}
RemoteSelector::
~
RemoteSelector()
{
delete
ui;
delete
m_discoveryAgent;
delete
m_localDevice;
}
void
RemoteSelector::
startDiscovery(const
QBluetoothUuid &
amp;uuid)
{
ui-&
gt;stopButton-&
gt;setDisabled(false
);
if
(m_discoveryAgent-&
gt;isActive())
m_discoveryAgent-&
gt;stop();
m_discoveryAgent-&
gt;setUuidFilter(uuid);
m_discoveryAgent-&
gt;start();
if
(!
m_discoveryAgent-&
gt;isActive() ||
m_discoveryAgent-&
gt;error() !=
QBluetoothServiceDiscoveryAgent::
NoError) {
ui-&
gt;status-&
gt;setText(tr("Cannot find remote services."
));
}
else
{
ui-&
gt;status-&
gt;setText(tr("Scanning..."
));
ui-&
gt;busyWidget-&
gt;show();
ui-&
gt;busyWidget-&
gt;movie()-&
gt;start();
}
}
QBluetoothServiceInfo RemoteSelector::
service() const
{
return
m_service;
}
void
RemoteSelector::
serviceDiscovered(const
QBluetoothServiceInfo &
amp;serviceInfo)
{
#if 0
qDebug() &
lt;&
lt; "Discovered service on"
&
lt;&
lt; serviceInfo.device().name() &
lt;&
lt; serviceInfo.device().address().toString();
qDebug() &
lt;&
lt; "
\t
Service name:"
&
lt;&
lt; serviceInfo.serviceName();
qDebug() &
lt;&
lt; "
\t
Description:"
&
lt;&
lt; serviceInfo.attribute(QBluetoothServiceInfo::
ServiceDescription).toString();
qDebug() &
lt;&
lt; "
\t
Provider:"
&
lt;&
lt; serviceInfo.attribute(QBluetoothServiceInfo::
ServiceProvider).toString();
qDebug() &
lt;&
lt; "
\t
L2CAP protocol service multiplexer:"
&
lt;&
lt; serviceInfo.protocolServiceMultiplexer();
qDebug() &
lt;&
lt; "
\t
RFCOMM server channel:"
&
lt;&
lt; serviceInfo.serverChannel();
#endif
QString remoteName;
if
(serviceInfo.device().name().isEmpty())
remoteName =
serviceInfo.device().address().toString();
else
remoteName =
serviceInfo.device().name();
// QListWidgetItem *item =
// new QListWidgetItem(QString::fromLatin1("%1\t%2\t%3").arg(serviceInfo.device().address().toString(),
// serviceInfo.device().name(), serviceInfo.serviceName()));
QMutableMapIterator&
lt;int
, QBluetoothServiceInfo&
gt; i(m_discoveredServices);
while
(i.hasNext()){
i.next();
if
(serviceInfo.device().address() ==
i.value().device().address()){
i.setValue(serviceInfo);
return
;
}
}
int
row =
ui-&
gt;remoteDevices-&
gt;rowCount();
ui-&
gt;remoteDevices-&
gt;insertRow(row);
QTableWidgetItem *
item =
new
QTableWidgetItem(serviceInfo.device().address().toString());
ui-&
gt;remoteDevices-&
gt;setItem(row, 0
, item);
item =
new
QTableWidgetItem(serviceInfo.device().name());
ui-&
gt;remoteDevices-&
gt;setItem(row, 1
, item);
item =
new
QTableWidgetItem(serviceInfo.serviceName());
ui-&
gt;remoteDevices-&
gt;setItem(row, 2
, item);
QBluetoothLocalDevice::
Pairing p;
p =
m_localDevice-&
gt;pairingStatus(serviceInfo.device().address());
ui-&
gt;remoteDevices-&
gt;blockSignals(true
);
item =
new
QTableWidgetItem();
if
((p&
amp;QBluetoothLocalDevice::
Paired) ||
(p&
amp;QBluetoothLocalDevice::
AuthorizedPaired))
item-&
gt;setCheckState(Qt::
Checked);
else
item-&
gt;setCheckState(Qt::
Unchecked);
ui-&
gt;remoteDevices-&
gt;setItem(row, 3
, item);
item =
new
QTableWidgetItem();
if
(p&
amp;QBluetoothLocalDevice::
AuthorizedPaired)
item-&
gt;setCheckState(Qt::
Checked);
else
item-&
gt;setCheckState(Qt::
Unchecked);
ui-&
gt;remoteDevices-&
gt;setItem(row, 4
, item);
ui-&
gt;remoteDevices-&
gt;blockSignals(false
);
m_discoveredServices.insert(row, serviceInfo);
}
void
RemoteSelector::
discoveryFinished()
{
ui-&
gt;status-&
gt;setText(tr("Select the device to send to."
));
ui-&
gt;stopButton-&
gt;setDisabled(true
);
ui-&
gt;busyWidget-&
gt;movie()-&
gt;stop();
ui-&
gt;busyWidget-&
gt;hide();
}
void
RemoteSelector::
startDiscovery()
{
startDiscovery(QBluetoothUuid(QBluetoothUuid::
ObexObjectPush));
}
void
RemoteSelector::
on_refreshPB_clicked()
{
startDiscovery();
ui-&
gt;stopButton-&
gt;setDisabled(false
);
}
void
RemoteSelector::
on_fileSelectPB_clicked()
{
ui-&
gt;fileName-&
gt;setText(QFileDialog::
getOpenFileName());
if
(m_service.isValid())
ui-&
gt;sendButton-&
gt;setDisabled(false
);
}
void
RemoteSelector::
on_sendButton_clicked()
{
QBluetoothTransferManager mgr;
QBluetoothTransferRequest req(m_service.device().address());
m_file =
new
QFile(ui-&
gt;fileName-&
gt;text());
Progress *
p =
new
Progress;
p-&
gt;setStatus("Sending to: "
+
m_service.device().name(), "Waiting for start"
);
p-&
gt;show();
QBluetoothTransferReply *
reply =
mgr.put(req, m_file);
//mgr is default parent
//ensure that mgr doesn't take reply down when leaving scope
reply-&
gt;setParent(this
);
if
(reply-&
gt;error()){
qDebug() &
lt;&
lt; "Failed to send file"
;
p-&
gt;finished(reply);
reply-&
gt;deleteLater();
return
;
}
connect(reply, SIGNAL(transferProgress(qint64,qint64)), p, SLOT(uploadProgress(qint64,qint64)));
connect(reply, SIGNAL(finished(QBluetoothTransferReply*
)), p, SLOT(finished(QBluetoothTransferReply*
)));
connect(p, SIGNAL(rejected()), reply, SLOT(abort()));
}
void
RemoteSelector::
on_stopButton_clicked()
{
m_discoveryAgent-&
gt;stop();
}
QString RemoteSelector::
addressToName(const
QBluetoothAddress &
amp;address)
{
QMapIterator&
lt;int
, QBluetoothServiceInfo&
gt; i(m_discoveredServices);
while
(i.hasNext()){
i.next();
if
(i.value().device().address() ==
address)
return
i.value().device().name();
}
return
address.toString();
}
void
RemoteSelector::
displayPin(const
QBluetoothAddress &
amp;address, QString pin)
{
if
(m_pindisplay)
m_pindisplay-&
gt;deleteLater();
m_pindisplay =
new
pinDisplay(QString("Enter pairing pin on: %1"
).arg(addressToName(address)), pin, this
);
m_pindisplay-&
gt;show();
}
void
RemoteSelector::
displayConfirmation(const
QBluetoothAddress &
amp;address, QString pin)
{
Q_UNUSED(address);
if
(m_pindisplay)
m_pindisplay-&
gt;deleteLater();
m_pindisplay =
new
pinDisplay(QString("Confirm this pin is the same"
), pin, this
);
connect(m_pindisplay, SIGNAL(accepted()), this
, SLOT(displayConfAccepted()));
connect(m_pindisplay, SIGNAL(rejected()), this
, SLOT(displayConfReject()));
m_pindisplay-&
gt;setOkCancel();
m_pindisplay-&
gt;show();
}
void
RemoteSelector::
displayConfAccepted()
{
m_localDevice-&
gt;pairingConfirmation(true
);
}
void
RemoteSelector::
displayConfReject()
{
m_localDevice-&
gt;pairingConfirmation(false
);
}
void
RemoteSelector::
pairingFinished(const
QBluetoothAddress &
amp;address, QBluetoothLocalDevice::
Pairing status)
{
QBluetoothServiceInfo service;
int
row =
0
;
ui-&
gt;pairingBusy-&
gt;hide();
ui-&
gt;pairingBusy-&
gt;movie()-&
gt;stop();
ui-&
gt;remoteDevices-&
gt;blockSignals(true
);
for
(int
i =
0
; i &
lt; m_discoveredServices.count(); i++
){
if
(m_discoveredServices.value(i).device().address() ==
address){
service =
m_discoveredServices.value(i);
row =
i;
break
;
}
}
if
(m_pindisplay)
delete
m_pindisplay;
QMessageBox msgBox;
if
(m_pairingError) {
msgBox.setText("Pairing failed with "
+
address.toString());
}
else
if
(status ==
QBluetoothLocalDevice::
Paired
||
status ==
QBluetoothLocalDevice::
AuthorizedPaired) {
msgBox.setText("Paired successfully with "
+
address.toString());
}
else
{
msgBox.setText("Pairing released with "
+
address.toString());
}
if
(service.isValid()){
if
(status ==
QBluetoothLocalDevice::
AuthorizedPaired){
ui-&
gt;remoteDevices-&
gt;item(row, 3
)-&
gt;setCheckState(Qt::
Checked);
ui-&
gt;remoteDevices-&
gt;item(row, 4
)-&
gt;setCheckState(Qt::
Checked);
}
else
if
(status ==
QBluetoothLocalDevice::
Paired){
ui-&
gt;remoteDevices-&
gt;item(row, 3
)-&
gt;setCheckState(Qt::
Checked);
ui-&
gt;remoteDevices-&
gt;item(row, 4
)-&
gt;setCheckState(Qt::
Unchecked);
}
else
{
ui-&
gt;remoteDevices-&
gt;item(row, 3
)-&
gt;setCheckState(Qt::
Unchecked);
ui-&
gt;remoteDevices-&
gt;item(row, 4
)-&
gt;setCheckState(Qt::
Unchecked);
}
}
m_pairingError =
false
;
msgBox.exec();
ui-&
gt;remoteDevices-&
gt;blockSignals(false
);
}
void
RemoteSelector::
pairingError(QBluetoothLocalDevice::
Error error)
{
if
(error !=
QBluetoothLocalDevice::
PairingError)
return
;
m_pairingError =
true
;
pairingFinished(m_service.device().address(), QBluetoothLocalDevice::
Unpaired);
}
void
RemoteSelector::
on_remoteDevices_cellClicked(int
row, int
column)
{
Q_UNUSED(column);
m_service =
m_discoveredServices.value(row);
if
(!
ui-&
gt;fileName-&
gt;text().isEmpty()) {
ui-&
gt;sendButton-&
gt;setDisabled(false
);
}
}
void
RemoteSelector::
on_remoteDevices_itemChanged(QTableWidgetItem*
item)
{
int
row =
item-&
gt;row();
int
column =
item-&
gt;column();
m_service =
m_discoveredServices.value(row);
if
(column &
lt; 3
)
return
;
if
(item-&
gt;checkState() ==
Qt::
Unchecked &
amp;&
amp; column ==
3
){
m_localDevice-&
gt;requestPairing(m_service.device().address(), QBluetoothLocalDevice::
Unpaired);
return
; // don't continue and start movie
}
else
if
((item-&
gt;checkState() ==
Qt::
Checked &
amp;&
amp; column ==
3
) ||
(item-&
gt;checkState() ==
Qt::
Unchecked &
amp;&
amp; column ==
4
)){
m_localDevice-&
gt;requestPairing(m_service.device().address(), QBluetoothLocalDevice::
Paired);
ui-&
gt;remoteDevices-&
gt;blockSignals(true
);
ui-&
gt;remoteDevices-&
gt;item(row, column)-&
gt;setCheckState(Qt::
PartiallyChecked);
ui-&
gt;remoteDevices-&
gt;blockSignals(false
);
}
else
if
(item-&
gt;checkState() ==
Qt::
Checked &
amp;&
amp; column ==
4
){
m_localDevice-&
gt;requestPairing(m_service.device().address(), QBluetoothLocalDevice::
AuthorizedPaired);
ui-&
gt;remoteDevices-&
gt;blockSignals(true
);
ui-&
gt;remoteDevices-&
gt;item(row, column)-&
gt;setCheckState(Qt::
PartiallyChecked);
ui-&
gt;remoteDevices-&
gt;blockSignals(false
);
}
ui-&
gt;pairingBusy-&
gt;show();
ui-&
gt;pairingBusy-&
gt;movie()-&
gt;start();
}