| // Copyright 2019 The Fuchsia 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 "src/ui/bin/root_presenter/media_buttons_handler.h" |
| |
| #include <fuchsia/ui/input/cpp/fidl.h> |
| #include <fuchsia/ui/policy/cpp/fidl.h> |
| #include <lib/fostr/fidl/fuchsia/ui/input/formatting.h> |
| #include <zircon/types.h> |
| |
| #include <src/ui/bin/root_presenter/constants.h> |
| |
| using fuchsia::ui::policy::MediaButtonsListenerPtr; |
| |
| namespace root_presenter { |
| namespace { |
| |
| void ChattyReportLog(const fuchsia::ui::input::InputReport& report) { |
| static uint32_t chatty = 0; |
| if (chatty++ < ChattyMax()) { |
| FX_LOGS(INFO) << "RP-MediaReport[" << chatty << "/" << ChattyMax() << "]: " << report; |
| } |
| } |
| |
| void ChattyEventLog(const fuchsia::ui::input::MediaButtonsEvent& event, |
| fuchsia::ui::policy::MediaButtonsListenerPtr& listener) { |
| static uint32_t chatty = 0; |
| if (chatty++ < ChattyMax()) { |
| zx_koid_t koid = ZX_KOID_INVALID; |
| |
| { |
| zx_info_handle_basic_t info{}; |
| size_t actual_count = 0; |
| size_t avail_count = 0; |
| zx_status_t status = listener.channel().get_info(ZX_INFO_HANDLE_BASIC, &info, sizeof(info), |
| &actual_count, &avail_count); |
| if (status == ZX_OK) { |
| koid = info.koid; |
| } |
| } |
| FX_LOGS(INFO) << "RP-MediaEvent[" << chatty << "/" << ChattyMax() << "]: dest=" << koid << ", " |
| << event; |
| } |
| } |
| |
| } // namespace |
| |
| bool MediaButtonsHandler::OnDeviceAdded(ui_input::InputDeviceImpl* input_device) { |
| if (!input_device->descriptor()->media_buttons) { |
| return false; |
| } |
| |
| FX_VLOGS(1) << "MediaButtonsHandler::OnDeviceAdded: device_id=" << input_device->id(); |
| |
| ui_input::OnMediaButtonsEventCallback callback = [this](fuchsia::ui::input::InputReport report) { |
| OnEvent(std::move(report)); |
| }; |
| auto state = std::make_unique<ui_input::DeviceState>( |
| input_device->id(), input_device->descriptor(), std::move(callback)); |
| |
| ui_input::DeviceState* state_ptr = state.get(); |
| auto device_pair = std::make_pair(input_device, std::move(state)); |
| state_ptr->OnRegistered(); |
| device_states_by_id_.emplace(input_device->id(), std::move(device_pair)); |
| |
| return true; |
| } |
| |
| bool MediaButtonsHandler::OnReport(uint32_t device_id, |
| fuchsia::ui::input::InputReport input_report) { |
| ChattyReportLog(input_report); |
| |
| if (device_states_by_id_.count(device_id) == 0) { |
| FX_VLOGS(1) << "OnReport: Unknown device " << device_id; |
| return false; |
| } |
| |
| ui_input::DeviceState* state = device_states_by_id_[device_id].second.get(); |
| fuchsia::math::Size unused; |
| |
| state->Update(std::move(input_report), unused); |
| |
| return true; |
| } |
| |
| bool MediaButtonsHandler::OnDeviceRemoved(uint32_t device_id) { |
| FX_VLOGS(1) << "MediaButtonsHandler::OnDeviceRemoved: device_id=" << device_id; |
| if (device_states_by_id_.count(device_id) == 0) { |
| FX_VLOGS(1) << "OnReport: Unknown device " << device_id; |
| return false; |
| } |
| |
| device_states_by_id_[device_id].second->OnUnregistered(); |
| device_states_by_id_.erase(device_id); |
| |
| return true; |
| } |
| |
| fuchsia::ui::input::MediaButtonsEvent CreateMediaButtonsEvent( |
| const fuchsia::ui::input::InputReport& report) { |
| fuchsia::ui::input::MediaButtonsEvent event; |
| int8_t volume_gain = 0; |
| if (report.media_buttons->volume_up) { |
| volume_gain++; |
| } |
| if (report.media_buttons->volume_down) { |
| volume_gain--; |
| } |
| event.set_volume(volume_gain); |
| event.set_mic_mute(report.media_buttons->mic_mute); |
| event.set_camera_disable(report.media_buttons->camera_disable); |
| event.set_pause(report.media_buttons->pause); |
| return event; |
| } |
| |
| void MediaButtonsHandler::OnEvent(fuchsia::ui::input::InputReport report) { |
| FX_CHECK(report.media_buttons); |
| for (auto& listener : media_buttons_listeners_) { |
| fuchsia::ui::input::MediaButtonsEvent event = CreateMediaButtonsEvent(report); |
| ChattyEventLog(event, listener); |
| listener->OnMediaButtonsEvent(std::move(event)); |
| } |
| } |
| |
| void MediaButtonsHandler::RegisterListener( |
| fidl::InterfaceHandle<fuchsia::ui::policy::MediaButtonsListener> listener_handle) { |
| MediaButtonsListenerPtr listener; |
| |
| listener.Bind(std::move(listener_handle)); |
| |
| // Auto-remove listeners if the interface closes. |
| listener.set_error_handler([this, listener = listener.get()](zx_status_t status) { |
| media_buttons_listeners_.erase( |
| std::remove_if(media_buttons_listeners_.begin(), media_buttons_listeners_.end(), |
| [listener](const MediaButtonsListenerPtr& item) -> bool { |
| return item.get() == listener; |
| }), |
| media_buttons_listeners_.end()); |
| }); |
| |
| // Send the last seen report to the listener so they have the information |
| // about the media button's state. |
| for (auto it = device_states_by_id_.begin(); it != device_states_by_id_.end(); it++) { |
| const ui_input::InputDeviceImpl* device_impl = it->second.first; |
| const fuchsia::ui::input::InputReport* report = device_impl->LastReport(); |
| if (report) { |
| listener->OnMediaButtonsEvent(CreateMediaButtonsEvent(*report)); |
| } |
| } |
| |
| media_buttons_listeners_.push_back(std::move(listener)); |
| } |
| } // namespace root_presenter |