| // 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/headless_root_presenter/activity_notifier.h" |
| |
| #include <fuchsia/ui/activity/cpp/fidl.h> |
| #include <fuchsia/ui/input/cpp/fidl.h> |
| #include <lib/async/cpp/task.h> |
| #include <lib/async/cpp/time.h> |
| #include <lib/async/dispatcher.h> |
| #include <lib/syslog/cpp/macros.h> |
| #include <lib/zx/time.h> |
| #include <zircon/status.h> |
| |
| #include <optional> |
| |
| namespace root_presenter { |
| |
| using fuchsia::ui::activity::DiscreteActivity; |
| using fuchsia::ui::activity::GenericActivity; |
| using fuchsia::ui::input::InputEvent; |
| using fuchsia::ui::input::MediaButtonsEvent; |
| |
| ActivityNotifierImpl::ActivityNotifierImpl(async_dispatcher_t* dispatcher, zx::duration interval, |
| sys::ComponentContext& context) |
| : dispatcher_(dispatcher), interval_(interval) { |
| activity_tracker_service_ = context.svc()->Connect<fuchsia::ui::activity::Tracker>(); |
| activity_tracker_service_.set_error_handler([this](zx_status_t error) { |
| FX_LOGS(ERROR) << "Activity service died (" << zx_status_get_string(error) << "), no longer " |
| << "sending activity events."; |
| activity_tracker_service_ = nullptr; |
| }); |
| } |
| |
| void ActivityNotifierImpl::ReceiveInputEvent(const InputEvent& event) { |
| if (auto activity = ActivityForInputEvent(event)) { |
| MaybeEnqueueActivity(*std::move(activity)); |
| } |
| } |
| |
| void ActivityNotifierImpl::ReceiveMediaButtonsEvent(const MediaButtonsEvent& event) { |
| if (auto activity = ActivityForMediaButtonsEvent(event)) { |
| MaybeEnqueueActivity(*std::move(activity)); |
| } |
| } |
| |
| void ActivityNotifierImpl::MaybeEnqueueActivity(fuchsia::ui::activity::DiscreteActivity activity) { |
| if (pending_activity_ || !activity_tracker_service_) { |
| return; |
| } |
| pending_activity_ = std::move(activity); |
| if (!notify_task_.is_pending()) { |
| notify_task_.Post(dispatcher_); |
| } |
| } |
| |
| void ActivityNotifierImpl::NotifyForPendingActivity() { |
| if (pending_activity_ && activity_tracker_service_) { |
| auto now = async::Now(dispatcher_); |
| activity_tracker_service_->ReportDiscreteActivity( |
| std::move(*pending_activity_), now.get(), [this]() { |
| notify_task_.PostDelayed(dispatcher_, interval_); |
| pending_activity_ = std::nullopt; |
| }); |
| } else { |
| // |notify_task_| is intentionally not re-scheduled if no input was received recently. It |
| // will be scheduled again on the next call to |ReceiveInput|. |
| pending_activity_ = std::nullopt; |
| } |
| } |
| |
| std::optional<DiscreteActivity> ActivityNotifierImpl::ActivityForInputEvent( |
| const InputEvent& event) { |
| switch (event.Which()) { |
| case InputEvent::Tag::kKeyboard: |
| case InputEvent::Tag::kPointer: { |
| GenericActivity generic; |
| return DiscreteActivity::WithGeneric(std::move(generic)); |
| } |
| case InputEvent::Tag::kFocus: |
| default: { |
| return std::nullopt; |
| } |
| } |
| } |
| |
| std::optional<DiscreteActivity> ActivityNotifierImpl::ActivityForMediaButtonsEvent( |
| const MediaButtonsEvent& event) { |
| GenericActivity generic; |
| return DiscreteActivity::WithGeneric(std::move(generic)); |
| } |
| |
| } // namespace root_presenter |