| // 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/task_scheduler/post_task.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); |
| } |
| } |
| } |
| |
| DeviceManagerManual::DeviceManagerManual() : 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() { |
| if (!watcher_.Watch(base::FilePath(kDevInput), false, |
| base::Bind(&DeviceManagerManual::OnWatcherEvent, |
| weak_ptr_factory_.GetWeakPtr()))) { |
| 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(); |
| } |
| |
| } // namespace ui |