blob: a8f2b0a7fb6013ae8dead33f30f777e7dfdd7e75 [file] [log] [blame]
// Copyright 2020 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.
#ifndef SRC_UI_SCENIC_LIB_INPUT_INJECTOR_H_
#define SRC_UI_SCENIC_LIB_INPUT_INJECTOR_H_
#include <fuchsia/ui/pointerinjector/cpp/fidl.h>
#include <lib/async/cpp/task.h>
#include <lib/fidl/cpp/binding.h>
#include <lib/inspect/cpp/inspect.h>
#include <deque>
#include <unordered_map>
#include "src/lib/fxl/macros.h"
#include "src/ui/scenic/lib/input/internal_pointer_event.h"
#include "src/ui/scenic/lib/input/stream_id.h"
namespace scenic_impl::input {
// Non-FIDL-type struct for keeping client defined settings.
struct InjectorSettings {
fuchsia::ui::pointerinjector::DispatchPolicy dispatch_policy =
fuchsia::ui::pointerinjector::DispatchPolicy(0u);
uint32_t device_id = 0u;
fuchsia::ui::pointerinjector::DeviceType device_type =
fuchsia::ui::pointerinjector::DeviceType(0u);
zx_koid_t context_koid = ZX_KOID_INVALID;
zx_koid_t target_koid = ZX_KOID_INVALID;
std::optional<fuchsia::input::report::Axis> scroll_v_range;
std::optional<fuchsia::input::report::Axis> scroll_h_range;
std::vector<uint8_t> button_identifiers;
};
// Utility that Injectors use to send diagnostics to Inspect.
class InjectorInspector {
public:
explicit InjectorInspector(inspect::Node inspect_node);
void OnPointerInjectorEvent(const fuchsia::ui::pointerinjector::Event& event);
// How long to track injection history.
static constexpr uint64_t kNumMinutesOfHistory = 10;
private:
struct InspectHistory {
// The minute this was recorded during. Used as the key for appending new values.
uint64_t minute_key;
// Number of injected events during |minute_key|.
uint64_t num_injected_events;
};
void UpdateHistory(zx::time now);
void ReportStats(inspect::Inspector& inspector) const;
inspect::Node node_;
inspect::LazyNode history_stats_node_;
inspect::ExponentialUintHistogram viewport_event_latency_;
inspect::ExponentialUintHistogram pointer_event_latency_;
std::deque<InspectHistory> history_;
FXL_DISALLOW_COPY_AND_ASSIGN(InjectorInspector);
};
// Implementation of the |fuchsia::ui::pointerinjector::Device| interface. One instance per channel.
class Injector : public fuchsia::ui::pointerinjector::Device {
public:
Injector(inspect::Node inspect_node, InjectorSettings settings, Viewport viewport,
fidl::InterfaceRequest<fuchsia::ui::pointerinjector::Device> device,
fit::function<bool(/*descendant*/ zx_koid_t, /*ancestor*/ zx_koid_t)>
is_descendant_and_connected,
fit::function<void()> on_channel_closed);
// Check the validity of a Viewport.
// Returns ZX_OK if valid, otherwise logs an error message and return appropriate error code.
static zx_status_t IsValidViewport(const fuchsia::ui::pointerinjector::Viewport& viewport);
// |fuchsia::ui::pointerinjector::Device|
void Inject(std::vector<fuchsia::ui::pointerinjector::Event> events,
InjectCallback callback) override;
protected:
// Forwards the event to device-specific handler in InputSystem (and eventually the client).
virtual void ForwardEvent(const fuchsia::ui::pointerinjector::Event& event,
StreamId stream_id) = 0;
// Sends an appropriate Cancel event.
virtual void CancelStream(uint32_t pointer_id, StreamId stream_id) = 0;
const InjectorSettings& settings() const { return settings_; }
const Viewport& viewport() const { return viewport_; }
private:
// Return value is either both valid, {ZX_OK, valid stream id} or both
// invalid: {error, kInvalidStreamId}
std::pair<zx_status_t, StreamId> ValidatePointerSample(
const fuchsia::ui::pointerinjector::PointerSample& pointer_sample);
// Tracks event streams. Returns the id of the event stream if the stream is valid
// and kInvalidStreamId otherwise.
// Event streams are expected to start with an ADD, followed by a number of CHANGE events, and
// ending in either a REMOVE or a CANCEL. Anything else is invalid.
StreamId ValidateEventStream(uint32_t pointer_id, fuchsia::ui::pointerinjector::EventPhase phase);
// Injects a CANCEL event for each ongoing stream and stops tracking them.
void CancelOngoingStreams();
// Closes the fidl channel. This triggers the destruction of the Injector object through the
// error handler set in InputSystem.
// NOTE: No further method calls or member accesses should be made after CloseChannel(), since
// they might be made on a destroyed object.
void CloseChannel(zx_status_t epitaph);
// Client-defined data.
const InjectorSettings settings_;
Viewport viewport_;
fidl::Binding<fuchsia::ui::pointerinjector::Device> binding_;
// Tracks stream's status (per stream id) as it moves through its state machine. Used to
// validate each event's phase.
// - ADD: add stream to set
// - CHANGE: no-op
// - REMOVE/CANCEL: remove stream from set.
// Hence, each stream here matches ADD - CHANGE*.
std::unordered_map<uint32_t, StreamId> ongoing_streams_;
fit::function<bool(/*descendant*/ zx_koid_t, /*ancestor*/ zx_koid_t)>
is_descendant_and_connected_;
// Called both when an error is triggered by either the remote or the local side of the channel.
// Triggers destruction of this object.
const fit::function<void()> on_channel_closed_;
InjectorInspector inspector_;
};
} // namespace scenic_impl::input
#endif // SRC_UI_SCENIC_LIB_INPUT_INJECTOR_H_