| // 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. |
| |
| #ifndef SRC_VIRTUALIZATION_TESTS_FAKE_SCENIC_H_ |
| #define SRC_VIRTUALIZATION_TESTS_FAKE_SCENIC_H_ |
| |
| #include <fuchsia/ui/scenic/cpp/fidl.h> |
| #include <fuchsia/ui/scenic/cpp/fidl_test_base.h> |
| #include <lib/fidl/cpp/binding.h> |
| #include <lib/fidl/cpp/binding_set.h> |
| #include <lib/fit/defer.h> |
| #include <lib/fit/function.h> |
| #include <string.h> |
| |
| #include <optional> |
| #include <unordered_map> |
| #include <vector> |
| |
| // This file implements a minimal fuchsia::ui::scenic::Scenic implementation. |
| // |
| // It is: |
| // |
| // * Capable of broadcasting input events (such as keystrokes) to sessions. |
| // |
| // * Implements a bare-minimum Scenic graphics API to allow a client to |
| // create a simple View, create a framebuffer, and take screenshots of |
| // that framebuffer. |
| // |
| // Caveat emptor: because this is strictly for tests, the fakes will |
| // FX_CHECK-fail if clients send it unexpected data. We also require that, for |
| // screenshots to be taken, there be a single memory resource containing the |
| // relevant data. |
| |
| // Key codes used in keyboard events. |
| // |
| // Scenic uses HID key codes, such as the table at: |
| // <https://source.android.com/devices/input/keyboard-devices> |
| // |
| // We only represent a small number of possible keys; those required for tests. |
| enum class KeyboardEventHidUsage : uint16_t { |
| KEY_A = 0x04, |
| KEY_B = 0x05, |
| KEY_C = 0x06, |
| KEY_RETURN = 0x28, |
| KEY_ESC = 0x29, |
| KEY_LSHIFT = 0xe1, |
| }; |
| |
| // Raw screenshot data. |
| struct Screenshot { |
| // Height and width of the image, in pixels. |
| int height; |
| int width; |
| // Raw pixel data, 4 bytes per pixel, stored in RGBO format, one row at |
| // a time. |
| std::vector<std::byte> data; |
| }; |
| |
| class FakeSession : public fuchsia::ui::scenic::testing::Session_TestBase { |
| public: |
| FakeSession(fidl::InterfaceRequest<fuchsia::ui::scenic::Session> request, |
| fidl::InterfaceHandle<fuchsia::ui::scenic::SessionListener> listener); |
| |
| // Send an event or list of events to any attached listener. |
| void SendEvent(fuchsia::ui::scenic::Event events); |
| |
| // Call the given callback if the connection has an error. |
| void set_error_handler(fit::function<void(zx_status_t)> error_handler); |
| |
| // Take a screenshot of the current video output. |
| // |
| // |output| must be non-null, and will be initialized if the return code is |
| // ZX_OK. |
| zx_status_t CaptureScreenshot(Screenshot* output); |
| |
| // Height and Width of the virtual screen. |
| static constexpr int kScreenWidthPixels = 1024; |
| static constexpr int kScreenHeightPixels = 768; |
| |
| protected: |
| // |fuchsia::ui::scenic::Session| |
| void Present(uint64_t presentation_time, ::std::vector<::zx::event> acquire_fences, |
| ::std::vector<::zx::event> release_fences, PresentCallback callback) override; |
| |
| // |fuchsia::ui::scenic::Session| |
| void Enqueue(std::vector<fuchsia::ui::scenic::Command> cmds) override; |
| |
| // |fuchsia::ui::scenic::testing::Session_TestBase| |
| void NotImplemented_(const std::string& name) final; |
| |
| private: |
| // Find all resources of the given type. |
| std::vector<const fuchsia::ui::gfx::CreateResourceCmd*> FindResourceByType( |
| fuchsia::ui::gfx::ResourceArgs::Tag type); |
| |
| // Handler client events. |
| void HandleGfxCommand(fuchsia::ui::gfx::Command cmd); |
| void HandleGfxCreateResource(fuchsia::ui::gfx::CreateResourceCmd cmd); |
| void HandleGfxReleaseResource(const fuchsia::ui::gfx::ReleaseResourceCmd& cmd); |
| void HandleSetEventMask(const fuchsia::ui::gfx::SetEventMaskCmd& cmd); |
| void HandleCreateView(uint32_t id); |
| |
| // Send a graphics event to the client. |
| void SendGfxEvent(fuchsia::ui::gfx::Event event); |
| |
| // Resources created by our client. |
| std::unordered_map<uint32_t, fuchsia::ui::gfx::CreateResourceCmd> resources_; |
| |
| // Client connection. |
| fidl::InterfacePtr<fuchsia::ui::scenic::SessionListener> listener_; |
| fidl::Binding<fuchsia::ui::scenic::Session> binding_; |
| }; |
| |
| class FakeScenic : public fuchsia::ui::scenic::testing::Scenic_TestBase { |
| public: |
| FakeScenic() = default; |
| |
| fidl::InterfaceRequestHandler<fuchsia::ui::scenic::Scenic> GetHandler(); |
| |
| // Send an events to any attached listener. |
| void SendEvent(fuchsia::ui::scenic::Event event); |
| |
| // Send a keyboard events to any attached listener. |
| void SendKeyEvent(KeyboardEventHidUsage usage, fuchsia::ui::input::KeyboardEventPhase phase); |
| |
| // Send a keyboard "PRESS" and "RELEASE" event for the given key to any |
| // attached listener. |
| void SendKeyPress(KeyboardEventHidUsage usage); |
| |
| // Take a screenshot. |
| // |
| // |output| must be non-null, and will be initialized if the return code is |
| // ZX_OK. |
| zx_status_t CaptureScreenshot(Screenshot* output); |
| |
| protected: |
| // |fuchsia::ui::scenic::Scenic| |
| void CreateSession(fidl::InterfaceRequest<fuchsia::ui::scenic::Session> session_request, |
| fidl::InterfaceHandle<fuchsia::ui::scenic::SessionListener> listener) override; |
| |
| // |fuchsia::ui::scenic::testing::Scenic_TestBase| |
| void NotImplemented_(const std::string& name) final; |
| |
| private: |
| // We only support a single session at a time. A session is active iff |
| // session_ != nullopt. |
| std::optional<FakeSession> session_; |
| |
| fidl::BindingSet<fuchsia::ui::scenic::Scenic> bindings_; |
| }; |
| |
| #endif // SRC_VIRTUALIZATION_TESTS_FAKE_SCENIC_H_ |