blob: 4153cde5980817b7508b6902d01fafbebec6eb72 [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 <fuchsia/ui/scenic/cpp/fidl.h>
#include <lib/ui/scenic/cpp/resources.h>
#include <lib/ui/scenic/cpp/session.h>
#include <lib/ui/scenic/cpp/view_ref_pair.h>
#include <lib/ui/scenic/cpp/view_token_pair.h>
#include <memory>
#include <gtest/gtest.h>
#include "src/ui/scenic/lib/input/tests/util.h"
// This test exercises dispatch logic when a session goes out of scope. A dead session can
// manifest, for example, as a null EventReporter*.
//
// The geometry of the display and layer are constrained to a 5x5 square. Just one 5x5 view is
// overlaid on top, and one rect shape placed in the center to be visible to the hit tester.
//
// Touch events are sent to the center of the display. When the session goes out of scope,
// subsequent touch events should *not* induce a crash.
//
// We have the following correspondence of coordinates:
//
// Event Device View Notes
// Add (2,2) (2.5, 2.5) Initial hit test
// Down (2,2) (2.5, 2.5) Latch for future MOVE events
// ---- (session death) ----
// Move (2,2) N/A
//
// NOTE: This test is carefully constructed to avoid Vulkan functionality.
namespace lib_ui_input_tests {
namespace {
using fuchsia::ui::input::InputEvent;
using fuchsia::ui::input::PointerEventPhase;
using fuchsia::ui::input::PointerEventType;
// Class fixture for TEST_F. Sets up a 5x5 "display" for GfxSystem.
class DeliveryInterruptionTest : public InputSystemTest {
protected:
uint32_t test_display_width_px() const override { return 5; }
uint32_t test_display_height_px() const override { return 5; }
};
TEST_F(DeliveryInterruptionTest, SessionDied) {
auto [view_token, view_holder_token] = scenic::ViewTokenPair::New();
auto [root_session, root_resources] = CreateScene();
uint32_t compositor_id = root_resources.compositor.id();
{
scenic::Session* const session = root_session.session();
scenic::ViewHolder holder(session, std::move(view_holder_token), "view holder");
// NOTE: The view holder itself does not require translation to be aligned with the layer.
holder.SetViewProperties(k5x5x1);
root_resources.scene.AddChild(holder);
RequestToPresent(session);
}
{
SessionWrapper client = CreateClient("view", std::move(view_token));
// Scene is now set up, send in the input.
{
scenic::Session* const session = root_session.session();
PointerCommandGenerator pointer(compositor_id, /*device id*/ 1,
/*pointer id*/ 1, PointerEventType::TOUCH);
// Sent in as device (display) coordinates.
session->Enqueue(pointer.Add(2.5, 2.5));
session->Enqueue(pointer.Down(2.5, 2.5));
RequestToPresent(session);
}
// Verify client's inputs have expected touch events.
{
const std::vector<InputEvent>& events = client.events();
EXPECT_EQ(events.size(), 3u);
EXPECT_TRUE(events[0].is_pointer());
EXPECT_TRUE(PointerMatches(events[0].pointer(), 1u, PointerEventPhase::ADD, 2.5, 2.5));
EXPECT_TRUE(events[1].is_focus());
EXPECT_TRUE(events[1].focus().focused);
EXPECT_TRUE(events[2].is_pointer());
EXPECT_TRUE(PointerMatches(events[2].pointer(), 1u, PointerEventPhase::DOWN, 2.5, 2.5));
}
}
// The client's session has now gone out of scope. Scenic's input system still has a latch onto
// this session.
RunLoopUntilIdle();
{
scenic::Session* const session = root_session.session();
PointerCommandGenerator pointer(compositor_id, /*device id*/ 1, /*pointer id*/ 1,
PointerEventType::TOUCH);
// Sent in as device (display) coordinates.
session->Enqueue(pointer.Move(2, 2));
RequestToPresent(session);
}
// No crash.
}
} // namespace
} // namespace lib_ui_input_tests