blob: f4887fdb4aa3f62d08a50e501c504f98a8e94399 [file] [log] [blame]
// Copyright 2014 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "ui/events/ozone/device/device_manager_manual.h"
#include "base/bind.h"
#include "base/callback.h"
#include "base/files/file_enumerator.h"
#include "base/location.h"
#include "base/logging.h"
#include "base/sequenced_task_runner.h"
#include "base/task/post_task.h"
#include "base/task_runner_util.h"
#include "base/threading/sequenced_task_runner_handle.h"
#include "ui/events/ozone/device/device_event.h"
#include "ui/events/ozone/device/device_event_observer.h"
namespace ui {
namespace {
const base::FilePath::CharType kDevInput[] = FILE_PATH_LITERAL("/dev/input");
void ScanDevicesOnWorkerThread(std::vector<base::FilePath>* result) {
base::FileEnumerator file_enum(base::FilePath(kDevInput), false,
base::FileEnumerator::FILES,
FILE_PATH_LITERAL("event*[0-9]"));
for (base::FilePath path = file_enum.Next(); !path.empty();
path = file_enum.Next()) {
result->push_back(path);
}
}
} // namespace
DeviceManagerManual::DeviceManagerManual()
: blocking_task_runner_(
base::CreateSequencedTaskRunnerWithTraits({base::MayBlock()})),
watcher_(new base::FilePathWatcher,
base::OnTaskRunnerDeleter(blocking_task_runner_)),
weak_ptr_factory_(this) {}
DeviceManagerManual::~DeviceManagerManual() {}
void DeviceManagerManual::ScanDevices(DeviceEventObserver* observer) {
if (!is_watching_) {
is_watching_ = true;
StartWatching();
}
InitiateScanDevices();
}
void DeviceManagerManual::AddObserver(DeviceEventObserver* observer) {
observers_.AddObserver(observer);
// Notify the new observer about existing devices.
for (const auto& path : devices_) {
DeviceEvent event(DeviceEvent::INPUT, DeviceEvent::ADD, path);
observer->OnDeviceEvent(event);
}
}
void DeviceManagerManual::RemoveObserver(DeviceEventObserver* observer) {
observers_.RemoveObserver(observer);
}
void DeviceManagerManual::StartWatching() {
base::PostTaskAndReplyWithResult(
blocking_task_runner_.get(), FROM_HERE,
base::BindOnce(
&base::FilePathWatcher::Watch, base::Unretained(watcher_.get()),
base::FilePath(kDevInput), false,
base::BindRepeating(&DeviceManagerManual::OnWatcherEventOnUiSequence,
base::SequencedTaskRunnerHandle::Get(),
weak_ptr_factory_.GetWeakPtr())),
base::BindOnce([](bool watch_started) {
if (!watch_started)
LOG(ERROR) << "Failed to start FilePathWatcher";
}));
}
void DeviceManagerManual::InitiateScanDevices() {
std::vector<base::FilePath>* result = new std::vector<base::FilePath>();
base::PostTaskWithTraitsAndReply(
FROM_HERE,
{base::MayBlock(), base::TaskShutdownBehavior::CONTINUE_ON_SHUTDOWN},
base::BindOnce(&ScanDevicesOnWorkerThread, result),
base::BindOnce(&DeviceManagerManual::OnDevicesScanned,
weak_ptr_factory_.GetWeakPtr(), base::Owned(result)));
}
void DeviceManagerManual::OnDevicesScanned(
std::vector<base::FilePath>* result) {
std::set<base::FilePath> new_devices;
// Reported newly added devices.
for (const auto& path : *result) {
new_devices.insert(path);
// Don't report devices already added.
if (devices_.find(path) != devices_.end())
continue;
DeviceEvent event(DeviceEvent::INPUT, DeviceEvent::ADD, path);
for (DeviceEventObserver& observer : observers_) {
observer.OnDeviceEvent(event);
}
}
// Report removed devices.
for (const auto& path : devices_) {
if (new_devices.find(path) != new_devices.end())
continue;
DeviceEvent event(DeviceEvent::INPUT, DeviceEvent::REMOVE, path);
for (DeviceEventObserver& observer : observers_) {
observer.OnDeviceEvent(event);
}
}
devices_.swap(new_devices);
}
void DeviceManagerManual::OnWatcherEvent(const base::FilePath& path,
bool error) {
// We need to restart watching if there's an error.
if (error) {
StartWatching();
}
InitiateScanDevices();
}
// static
void DeviceManagerManual::OnWatcherEventOnUiSequence(
scoped_refptr<base::TaskRunner> ui_thread_runner,
base::WeakPtr<DeviceManagerManual> device_manager,
const base::FilePath& path,
bool error) {
ui_thread_runner->PostTask(
FROM_HERE, BindOnce(&DeviceManagerManual::OnWatcherEvent, device_manager,
path, error));
}
} // namespace ui