Permalink
Browse files

Handle MTP connection failures more gracefully. (#6256)

Currently, the failure to connect to an MTP device results in the UI displaying
an open device that appears empty. This change introduces a method
ConnectedDevice::ConnectAsync() that is expected to handle any connecting tasks
that could block asynchronously. Upon completion, this emits a ConnectFinished
signal that indicates success or failure. The row in the UI is only updated
after the successful response is received. Upon failure, DeviceManager will
clean up and the row in UI is left in the pre-connect state.

Currently, only the MtpDevice utilizes this mechanism. All other devices use a
default implementation that immediately reports success.
  • Loading branch information...
jbroadus authored and hatstand committed Jan 15, 2019
1 parent 8d78dae commit 6c159481ed9d7da7a0d11922737c6f848738560a
@@ -88,6 +88,8 @@ void ConnectedDevice::InitBackendDirectory(const QString& mount_point,
}
}

void ConnectedDevice::ConnectAsync() { emit ConnectFinished(unique_id_, true); }

void ConnectedDevice::Eject() {
manager_->UnmountAsync(manager_->FindDeviceById(unique_id_));
}
@@ -46,6 +46,7 @@ class ConnectedDevice : public QObject,
~ConnectedDevice();

virtual void Init() = 0;
virtual void ConnectAsync();
// For some devices (e.g. CD devices) we don't have callbacks to be notified
// when something change: we can call this method to refresh device's state
virtual void Refresh() {}
@@ -67,6 +68,7 @@ class ConnectedDevice : public QObject,
signals:
void TaskStarted(int id);
void SongCountUpdated(int count);
void ConnectFinished(const QString& id, bool success);

protected:
void InitBackendDirectory(const QString& mount_point, bool first_time,
@@ -622,13 +622,25 @@ std::shared_ptr<ConnectedDevice> DeviceManager::Connect(int row) {
SLOT(DeviceTaskStarted(int)));
connect(info.device_.get(), SIGNAL(SongCountUpdated(int)),
SLOT(DeviceSongCountUpdated(int)));
connect(info.device_.get(), SIGNAL(ConnectFinished(const QString&, bool)),
SLOT(DeviceConnectFinished(const QString&, bool)));
ret->ConnectAsync();
}

emit DeviceConnected(row);

return ret;
}

void DeviceManager::DeviceConnectFinished(const QString& id, bool success) {
int row = FindDeviceById(id);
if (row != -1) {
if (success) {
emit DeviceConnected(row);
} else {
devices_[row].device_.reset();
}
}
}

std::shared_ptr<ConnectedDevice> DeviceManager::GetConnectedDevice(
int row) const {
return devices_[row].device_;
@@ -109,6 +109,7 @@ class DeviceManager : public QAbstractListModel {
void TasksChanged();
void DeviceSongCountUpdated(int count);
void LoadAllDevices();
void DeviceConnectFinished(const QString& id, bool success);

private:
// Devices can be in three different states:
@@ -56,17 +56,20 @@ void MtpDevice::Init() {

connect(loader_, SIGNAL(Error(QString)), SLOT(LoaderError(QString)));
connect(loader_, SIGNAL(TaskStarted(int)), SIGNAL(TaskStarted(int)));
connect(loader_, SIGNAL(LoadFinished()), SLOT(LoadFinished()));
connect(loader_, SIGNAL(LoadFinished(bool)), SLOT(LoadFinished(bool)));
connect(loader_thread_, SIGNAL(started()), loader_, SLOT(LoadDatabase()));
}

void MtpDevice::ConnectAsync() {
db_busy_.lock();
loader_thread_->start();
}

void MtpDevice::LoadFinished() {
void MtpDevice::LoadFinished(bool success) {
loader_->deleteLater();
loader_ = nullptr;
db_busy_.unlock();
emit ConnectFinished(unique_id_, success);
}

void MtpDevice::LoaderError(const QString& message) { app_->AddError(message); }
@@ -45,6 +45,7 @@ class MtpDevice : public ConnectedDevice {
}

void Init();
void ConnectAsync();

bool GetSupportedFiletypes(QList<Song::FileType>* ret);
int GetFreeSpace();
@@ -59,7 +60,7 @@ class MtpDevice : public ConnectedDevice {
void FinishDelete(bool success);

private slots:
void LoadFinished();
void LoadFinished(bool success);
void LoaderError(const QString& message);

private:
@@ -42,12 +42,12 @@ void MtpLoader::LoadDatabase() {
int task_id = task_manager_->StartTask(tr("Loading MTP device"));
emit TaskStarted(task_id);

TryLoad();
bool success = TryLoad();

moveToThread(original_thread_);

task_manager_->SetTaskFinished(task_id);
emit LoadFinished();
emit LoadFinished(success);
}

bool MtpLoader::TryLoad() {
@@ -41,7 +41,7 @@ class MtpLoader : public QObject {
signals:
void Error(const QString& message);
void TaskStarted(int task_id);
void LoadFinished();
void LoadFinished(bool success);

private:
bool TryLoad();

0 comments on commit 6c15948

Please sign in to comment.