| // Copyright 2021 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_VIEW_TREE_GEOMETRY_PROVIDER_H_ |
| #define SRC_UI_SCENIC_LIB_VIEW_TREE_GEOMETRY_PROVIDER_H_ |
| |
| #include <fuchsia/ui/observation/geometry/cpp/fidl.h> |
| #include <lib/fidl/cpp/binding_set.h> |
| #include <lib/sys/cpp/component_context.h> |
| |
| #include <deque> |
| #include <unordered_map> |
| |
| #include "src/lib/fxl/macros.h" |
| #include "src/ui/scenic/lib/view_tree/snapshot_types.h" |
| |
| namespace view_tree { |
| // This class is responsible for registering and maintaining server endpoints for |
| // fuchsia.ui.observation.geometry.ViewTreeWatcher protocol clients. This class also listens for new |
| // snapshots generated every frame, and sends a processed version of them to these registered |
| // clients. |
| class GeometryProvider { |
| public: |
| GeometryProvider() = default; |
| // Adds a server side endpoint to |endpoints_| for lifecycle management. |
| void Register( |
| fidl::InterfaceRequest<fuchsia::ui::observation::geometry::ViewTreeWatcher> endpoint, |
| zx_koid_t context_view); |
| |
| // Adds a server side endpoint provided by |
| // fuchsia.ui.observation.test.Registry.RegisterGlobalViewTreeWatcher to |endpoints_|. Endpoints |
| // registered by this method get a global access to the view tree. |
| void RegisterGlobalViewTreeWatcher( |
| fidl::InterfaceRequest<fuchsia::ui::observation::geometry::ViewTreeWatcher> endpoint); |
| |
| // Inject a new snapshot of the ViewTree. Adds the snapshot to each ProviderEndpoint's |
| // |view_tree_snapshots_| and send a response to the respective clients if the required conditions |
| // are met. See SendResponseMaybe() for more details on the required conditions. |
| void OnNewViewTreeSnapshot(std::shared_ptr<const view_tree::Snapshot> snapshot); |
| |
| // Generates a fuchsia.ui.observation.geometry.ViewTreeSnapshot from the |snapshot| by |
| // extracting information about the |context_view| and its descendant views from |
| // |snapshot|. |
| static fuchsia::ui::observation::geometry::ViewTreeSnapshotPtr ExtractObservationSnapshot( |
| std::optional<zx_koid_t> endpoint_context_view, |
| std::shared_ptr<const view_tree::Snapshot> snapshot); |
| |
| private: |
| using ProviderEndpointId = int64_t; |
| |
| // This class implements the server side endpoint for |
| // fuchsia.ui.observation.geometry.ViewTreeWatcher clients and manages a deque of snapshot updates |
| // to be sent to the client on receiving a Watch() call. |
| class ProviderEndpoint : public fuchsia::ui::observation::geometry::ViewTreeWatcher { |
| public: |
| explicit ProviderEndpoint( |
| fidl::InterfaceRequest<fuchsia::ui::observation::geometry::ViewTreeWatcher> provider, |
| std::optional<zx_koid_t> context_view, ProviderEndpointId id, |
| fit::function<void()> destroy_instance_function); |
| |
| ProviderEndpoint(ProviderEndpoint&& original) noexcept; |
| |
| // |fuchsia.ui.observation.geometry.ViewTreeWatcher.Watch|. |
| void Watch( |
| fuchsia::ui::observation::geometry::ViewTreeWatcher::WatchCallback callback) override; |
| |
| // Adds the latest snapshot to |view_tree_snapshots_|. |
| // |
| // If the size of |view_tree_snapshots_| exceeds |fuchsia.ui.observation.geometry.BUFFER_SIZE|, |
| // it replaces the oldest snapshot with the new one. If there were any pending callback because |
| // of a client calling Watch() when there were no pending snapshots, it gets triggered with the |
| // latest |view_tree_snapshots_|. |
| void AddViewTreeSnapshot( |
| fuchsia::ui::observation::geometry::ViewTreeSnapshotPtr view_tree_snapshot); |
| |
| bool IsAlive() const { return endpoint_.is_bound(); } |
| |
| std::optional<zx_koid_t> context_view() const { return context_view_; } |
| |
| private: |
| // Checks whether the required conditions for sending the response to the client are met and |
| // then sends the response. |
| void SendResponseMaybe(); |
| |
| // Trigger the |pending_callback_| to send the response to the client. If the size of the |
| // response exceeds ZX_CHANNEL_MAX_MSG_BYTES, older |
| // `fuchsia.ui.observation.geometry.ViewTreeSnapshot`s in the response are dropped. |
| void SendResponse(); |
| |
| // Closes the fidl channel. This triggers the destruction of the ProviderEndpoint object through |
| // the |destroy_instance_function_|. NOTE: No further method calls or member accesses should be |
| // made after CloseChannel(), since they might be made on a destroyed object. |
| void CloseChannel(); |
| |
| // Resets the state of an |endpoint_| for subsequent |Watch| calls. |
| void Reset(); |
| |
| // Server-side endpoint. |
| fidl::Binding<fuchsia::ui::observation::geometry::ViewTreeWatcher> endpoint_; |
| |
| // A deque containing pending snapshot updates for a client. The size of the deque cannot exceed |
| // |fuchsia::ui::observation::geometry::BUFFER_SIZE|. |
| std::deque<fuchsia::ui::observation::geometry::ViewTreeSnapshotPtr> view_tree_snapshots_; |
| |
| // If the last |Watch| call did not immediately trigger a callback, it gets stored here and is |
| // triggered whenever a new snapshot gets generated. |
| fuchsia::ui::observation::geometry::ViewTreeWatcher::WatchCallback pending_callback_; |
| |
| std::optional<const zx_koid_t> context_view_; |
| |
| // Key for storing the associated server endpoint in |endpoints_|. |
| const ProviderEndpointId id_; |
| |
| // A closure which gets triggered whenever the server endpoint closes. The closure is |
| // responsible for removing the ProviderEndpoint from |endpoints_|. |
| fit::function<void()> destroy_instance_function_; |
| |
| // Errors faced while executing the |pending_callback_|. |error_| must be reset after |
| // |pending_callback_| is executed for subsequent |Watch| calls. |
| fuchsia::ui::observation::geometry::Error error_; |
| }; |
| |
| // Generates a fuchsia.ui.observation.geometry.ViewDescriptor from the |snapshot|'s view node by |
| // extracting information about the |view_ref_koid| from the view node. |
| // The view nodes corresponding to views with 0x0 size are *not* reported. |
| static fuchsia::ui::observation::geometry::ViewDescriptor ExtractViewDescriptor( |
| zx_koid_t view_ref_koid, zx_koid_t context_view, |
| std::shared_ptr<const view_tree::Snapshot> snapshot); |
| |
| std::unordered_map<ProviderEndpointId, ProviderEndpoint> endpoints_; |
| |
| // Incremented when Register() is called. |
| ProviderEndpointId endpoint_counter_ = 0; |
| |
| FXL_DISALLOW_COPY_ASSIGN_AND_MOVE(GeometryProvider); |
| }; |
| |
| } // namespace view_tree |
| |
| #endif // SRC_UI_SCENIC_LIB_VIEW_TREE_GEOMETRY_PROVIDER_H_ |