blob: 1e2666ee83d20e3ddf99d39df96c1dfb1cc3d622 [file] [log] [blame]
// Copyright 2013 The Flutter 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 FLUTTER_SHELL_PLATFORM_FUCHSIA_POINTER_INJECTOR_DELEGATE_H_
#define FLUTTER_SHELL_PLATFORM_FUCHSIA_POINTER_INJECTOR_DELEGATE_H_
#include <fuchsia/ui/pointerinjector/cpp/fidl.h>
#include <fuchsia/ui/views/cpp/fidl.h>
#include <queue>
#include <unordered_map>
#include <vector>
#include "flutter/fml/macros.h"
#include "flutter/fml/memory/weak_ptr.h"
#include "flutter/lib/ui/window/platform_message.h"
#include "third_party/rapidjson/include/rapidjson/document.h"
namespace flutter_runner {
// This class is responsible for handling the platform messages related to
// pointer events and managing the lifecycle of
// |fuchsia.ui.pointerinjector.Device| client side endpoint for embedded views.
class PointerInjectorDelegate {
public:
static constexpr auto kPointerInjectorMethodPrefix =
"View.pointerinjector.inject";
PointerInjectorDelegate(fuchsia::ui::pointerinjector::RegistryHandle registry,
fuchsia::ui::views::ViewRef host_view_ref,
bool is_flatland)
: registry_(std::make_shared<fuchsia::ui::pointerinjector::RegistryPtr>(
registry.Bind())),
host_view_ref_(std::make_shared<fuchsia::ui::views::ViewRef>(
std::move(host_view_ref))),
is_flatland_(is_flatland) {}
// Handles the following pointer event related platform message requests:
// View.Pointerinjector.inject
// - Attempts to dispatch a pointer event to the given viewRef. Completes
// with [0] when the pointer event is sent to the given viewRef.
bool HandlePlatformMessage(
rapidjson::Value request,
fml::RefPtr<flutter::PlatformMessageResponse> response);
// Adds an endpoint for |view_id| in |valid_views_| for lifecycle management.
// Called in |GFXPlatformView::OnCreateView()| and
// |FlatlandPlatformView::OnChildViewViewRef()|.
void OnCreateView(
uint64_t view_id,
std::optional<fuchsia::ui::views::ViewRef> view_ref = std::nullopt);
// Closes the |fuchsia.ui.pointerinjector.Device| channel for |view_id| and
// cleans up resources.
void OnDestroyView(uint64_t view_id) { valid_views_.erase(view_id); }
private:
using ViewId = int64_t;
struct PointerInjectorRequest {
// The position of the pointer event in viewport's coordinate system.
float x = 0.f, y = 0.f;
// |fuchsia.ui.pointerinjector.PointerSample.pointer_id|.
uint32_t pointer_id = 0;
// |fuchsia.ui.pointerinjector.PointerSample.phase|.
fuchsia::ui::pointerinjector::EventPhase phase =
fuchsia::ui::pointerinjector::EventPhase::ADD;
// |fuchsia.ui.pointerinjector.Event.trace_flow_id|.
uint64_t trace_flow_id = 0;
// The view for which dispatch is attempted for the pointer event. For
// flatland views, this value is set as std::nullopt.
std::optional<fuchsia::ui::views::ViewRef> view_ref;
// Logical size of the view's coordinate system.
std::array<float, 2> logical_size = {0.f, 0.f};
// |fuchsia.ui.pointerinjector.Event.timestamp|.
zx_time_t timestamp = 0;
};
// This class is responsible for dispatching pointer events to a view by first
// registering the injector device using
// |fuchsia.ui.pointerinjector.Registry.Register| and then injecting the
// pointer event using |fuchsia.ui.pointerinjector.Device.Inject|.
class PointerInjectorEndpoint {
public:
PointerInjectorEndpoint(
std::shared_ptr<fuchsia::ui::pointerinjector::RegistryPtr> registry,
std::shared_ptr<fuchsia::ui::views::ViewRef> host_view_ref,
std::optional<fuchsia::ui::views::ViewRef> view_ref)
: registry_(std::move(registry)),
host_view_ref_(std::move(host_view_ref)),
view_ref_(std::move(view_ref)),
weak_factory_(this) {
// Try to re-register the |device_| if the |device_| gets closed due to
// some error.
device_.set_error_handler(
[weak = weak_factory_.GetWeakPtr()](auto status) {
FML_LOG(WARNING)
<< "fuchsia.ui.pointerinjector.Device closed " << status;
if (!weak) {
return;
}
// Clear all the stale pointer events in |injector_events_| and
// reset the state of |weak| so that any future calls do not inject
// any stale pointer events.
weak->Reset();
});
}
// Registers |device_| if it has not been registered and calls
// |DispatchPendingEvents()| to dispatch |request| to the view.
void InjectEvent(PointerInjectorRequest request);
private:
// Registers with the pointer injector service.
//
// Sets |registered_| to true immediately after submitting the registration
// request. This means that the registration request may still be in-flight
// on the server side when the function returns. Events can safely be
// injected into the channel while registration is pending ("feed forward").
void RegisterInjector(const PointerInjectorRequest& request);
// Recursively calls |fuchsia.ui.pointerinjector.Device.Inject| to dispatch
// the pointer events in |injector_events_| to the view.
void DispatchPendingEvents();
void EnqueueEvent(fuchsia::ui::pointerinjector::Event event);
// Resets |registered_|, |injection_in_flight_| and |injector_events_| so
// that |device_| can be re-registered and future calls to
// |fuchsia.ui.pointerinjector.Device.Inject| do not include any stale
// pointer events.
void Reset();
// Set to true if there is a |fuchsia.ui.pointerinjector.Device.Inject| call
// in progress. If true, the |fuchsia.ui.pointerinjector.Event| is buffered
// in |injector_events_|.
bool injection_in_flight_ = false;
// Set to true if |device_| has been registered using
// |fuchsia.ui.pointerinjector.Registry.Register|. False otherwise.
bool registered_ = false;
std::shared_ptr<fuchsia::ui::pointerinjector::RegistryPtr> registry_;
// ViewRef for the main flutter app launching the embedded child views.
std::shared_ptr<fuchsia::ui::views::ViewRef> host_view_ref_;
// ViewRef for a flatland view. For GFX this value is set as std::nullopt.
// Set in |OnCreateView|.
std::optional<fuchsia::ui::views::ViewRef> view_ref_;
fuchsia::ui::pointerinjector::DevicePtr device_;
// A queue containing all the pending |fuchsia.ui.pointerinjector.Event|s
// which have to be dispatched to the view.
// Note: The size of a vector inside |injector_events_| should not exceed
// |fuchsia.ui.pointerinjector.MAX_INJECT|.
std::queue<std::vector<fuchsia::ui::pointerinjector::Event>>
injector_events_;
fml::WeakPtrFactory<PointerInjectorEndpoint>
weak_factory_; // Must be the last member.
FML_DISALLOW_COPY_AND_ASSIGN(PointerInjectorEndpoint);
};
void Complete(fml::RefPtr<flutter::PlatformMessageResponse> response,
std::string value);
// Generates a |fuchsia.ui.pointerinjector.Event| from |request| by extracting
// information like timestamp, trace flow id and pointer sample from
// |request|.
static fuchsia::ui::pointerinjector::Event ExtractPointerEvent(
PointerInjectorRequest request);
// A map of valid views keyed by its view id. A view can receive pointer
// events only if it is present in |valid_views_|.
std::unordered_map<ViewId, PointerInjectorEndpoint> valid_views_;
std::shared_ptr<fuchsia::ui::pointerinjector::RegistryPtr> registry_;
// ViewRef for the main flutter app launching the embedded child views.
std::shared_ptr<fuchsia::ui::views::ViewRef> host_view_ref_;
bool is_flatland_ = false;
FML_DISALLOW_COPY_AND_ASSIGN(PointerInjectorDelegate);
};
} // namespace flutter_runner
#endif // FLUTTER_SHELL_PLATFORM_FUCHSIA_POINTER_INJECTOR_DELEGATE_H_