blob: 43d445668a8b43b55487022e56ff7bf6eff8c9cc [file] [log] [blame]
// 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