fuchsia: Don't send ViewportMetrics w/ 0 DPR (#21392)

This commit is contained in:
David Worsham 2020-10-06 17:57:28 -07:00 committed by GitHub
parent 9a7b556f91
commit d5dddf32e7
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 582 additions and 411 deletions

View File

@ -10,6 +10,13 @@ namespace flutter {
ViewportMetrics::ViewportMetrics() = default;
ViewportMetrics::ViewportMetrics(double p_device_pixel_ratio,
double p_physical_width,
double p_physical_height)
: device_pixel_ratio(p_device_pixel_ratio),
physical_width(p_physical_width),
physical_height(p_physical_height) {}
ViewportMetrics::ViewportMetrics(double p_device_pixel_ratio,
double p_physical_width,
double p_physical_height,
@ -44,11 +51,42 @@ ViewportMetrics::ViewportMetrics(double p_device_pixel_ratio,
physical_system_gesture_inset_left(p_physical_system_gesture_inset_left) {
}
ViewportMetrics::ViewportMetrics(double p_device_pixel_ratio,
double p_physical_width,
double p_physical_height)
: device_pixel_ratio(p_device_pixel_ratio),
physical_width(p_physical_width),
physical_height(p_physical_height) {}
bool operator==(const ViewportMetrics& a, const ViewportMetrics& b) {
return a.device_pixel_ratio == b.device_pixel_ratio &&
a.physical_width == b.physical_width &&
a.physical_height == b.physical_height &&
a.physical_padding_top == b.physical_padding_top &&
a.physical_padding_right == b.physical_padding_right &&
a.physical_padding_bottom == b.physical_padding_bottom &&
a.physical_padding_left == b.physical_padding_left &&
a.physical_view_inset_top == b.physical_view_inset_top &&
a.physical_view_inset_right == b.physical_view_inset_right &&
a.physical_view_inset_bottom == b.physical_view_inset_bottom &&
a.physical_view_inset_left == b.physical_view_inset_left &&
a.physical_system_gesture_inset_top ==
b.physical_system_gesture_inset_top &&
a.physical_system_gesture_inset_right ==
b.physical_system_gesture_inset_right &&
a.physical_system_gesture_inset_bottom ==
b.physical_system_gesture_inset_bottom &&
a.physical_system_gesture_inset_left ==
b.physical_system_gesture_inset_left;
}
std::ostream& operator<<(std::ostream& os, const ViewportMetrics& a) {
os << "DPR: " << a.device_pixel_ratio << " "
<< "Size: [" << a.physical_width << "W " << a.physical_height << "H] "
<< "Padding: [" << a.physical_padding_top << "T "
<< a.physical_padding_right << "R " << a.physical_padding_bottom << "B "
<< a.physical_padding_left << "L] "
<< "Insets: [" << a.physical_view_inset_top << "T "
<< a.physical_view_inset_right << "R " << a.physical_view_inset_bottom
<< "B " << a.physical_view_inset_left << "L] "
<< "Gesture Insets: [" << a.physical_system_gesture_inset_top << "T "
<< a.physical_system_gesture_inset_right << "R "
<< a.physical_system_gesture_inset_bottom << "B "
<< a.physical_system_gesture_inset_left << "L]";
return os;
}
} // namespace flutter

View File

@ -5,10 +5,15 @@
#ifndef FLUTTER_LIB_UI_WINDOW_VIEWPORT_METRICS_H_
#define FLUTTER_LIB_UI_WINDOW_VIEWPORT_METRICS_H_
#include <ostream>
namespace flutter {
struct ViewportMetrics {
ViewportMetrics();
ViewportMetrics(double p_device_pixel_ratio,
double p_physical_width,
double p_physical_height);
ViewportMetrics(double p_device_pixel_ratio,
double p_physical_width,
double p_physical_height,
@ -25,12 +30,6 @@ struct ViewportMetrics {
double p_physical_system_gesture_inset_bottom,
double p_physical_system_gesture_inset_left);
// Create a ViewportMetrics instance that doesn't include depth, padding, or
// insets.
ViewportMetrics(double p_device_pixel_ratio,
double p_physical_width,
double p_physical_height);
double device_pixel_ratio = 1.0;
double physical_width = 0;
double physical_height = 0;
@ -48,24 +47,8 @@ struct ViewportMetrics {
double physical_system_gesture_inset_left = 0;
};
struct LogicalSize {
double width = 0.0;
double height = 0.0;
};
struct LogicalInset {
double left = 0.0;
double top = 0.0;
double right = 0.0;
double bottom = 0.0;
};
struct LogicalMetrics {
LogicalSize size;
double scale = 1.0;
LogicalInset padding;
LogicalInset view_inset;
};
bool operator==(const ViewportMetrics& a, const ViewportMetrics& b);
std::ostream& operator<<(std::ostream& os, const ViewportMetrics& a);
} // namespace flutter

View File

@ -14,10 +14,11 @@
#include "flutter/fml/logging.h"
#include "flutter/lib/ui/window/pointer_data.h"
#include "flutter/lib/ui/window/window.h"
#include "third_party/rapidjson/include/rapidjson/document.h"
#include "third_party/rapidjson/include/rapidjson/stringbuffer.h"
#include "third_party/rapidjson/include/rapidjson/writer.h"
#include "logging.h"
#include "rapidjson/document.h"
#include "rapidjson/stringbuffer.h"
#include "rapidjson/writer.h"
#include "runtime/dart/utils/inlines.h"
#include "vsync_waiter.h"
@ -214,7 +215,8 @@ void PlatformView::OnScenicError(std::string error) {
void PlatformView::OnScenicEvent(
std::vector<fuchsia::ui::scenic::Event> events) {
TRACE_EVENT0("flutter", "PlatformView::OnScenicEvent");
bool should_update_metrics = false;
bool metrics_changed = false;
for (const auto& event : events) {
switch (event.Which()) {
case fuchsia::ui::scenic::Event::Tag::kGfx:
@ -223,31 +225,52 @@ void PlatformView::OnScenicEvent(
const fuchsia::ui::gfx::Metrics& metrics =
event.gfx().metrics().metrics;
const float new_view_pixel_ratio = metrics.scale_x;
if (new_view_pixel_ratio <= 0.f) {
FML_DLOG(ERROR)
<< "Got an invalid pixel ratio from Scenic; ignoring: "
<< new_view_pixel_ratio;
break;
}
// Avoid metrics update when possible -- it is computationally
// expensive.
if (view_pixel_ratio_ != new_view_pixel_ratio) {
view_pixel_ratio_ = new_view_pixel_ratio;
should_update_metrics = true;
if (view_pixel_ratio_.has_value() &&
*view_pixel_ratio_ == new_view_pixel_ratio) {
FML_DLOG(ERROR)
<< "Got an identical pixel ratio from Scenic; ignoring: "
<< new_view_pixel_ratio;
break;
}
view_pixel_ratio_ = new_view_pixel_ratio;
metrics_changed = true;
break;
}
case fuchsia::ui::gfx::Event::Tag::kViewPropertiesChanged: {
const fuchsia::ui::gfx::BoundingBox& bounding_box =
event.gfx().view_properties_changed().properties.bounding_box;
const float new_view_width =
std::max(bounding_box.max.x - bounding_box.min.x, 0.0f);
const float new_view_height =
std::max(bounding_box.max.y - bounding_box.min.y, 0.0f);
const std::pair<float, float> new_view_size = {
std::max(bounding_box.max.x - bounding_box.min.x, 0.0f),
std::max(bounding_box.max.y - bounding_box.min.y, 0.0f)};
if (new_view_size.first <= 0.f || new_view_size.second <= 0.f) {
FML_DLOG(ERROR)
<< "Got an invalid view size from Scenic; ignoring: "
<< new_view_size.first << " " << new_view_size.second;
break;
}
// Avoid metrics update when possible -- it is computationally
// expensive.
if (view_width_ != new_view_width ||
view_height_ != new_view_width) {
view_width_ = new_view_width;
view_height_ = new_view_height;
should_update_metrics = true;
if (view_logical_size_.has_value() &&
*view_logical_size_ == new_view_size) {
FML_DLOG(ERROR)
<< "Got an identical view size from Scenic; ignoring: "
<< new_view_size.first << " " << new_view_size.second;
break;
}
view_logical_size_ = new_view_size;
metrics_changed = true;
break;
}
case fuchsia::ui::gfx::Event::Tag::kViewConnected:
@ -298,19 +321,22 @@ void PlatformView::OnScenicEvent(
}
}
if (should_update_metrics) {
if (view_pixel_ratio_.has_value() && view_logical_size_.has_value() &&
metrics_changed) {
const float pixel_ratio = *view_pixel_ratio_;
const std::pair<float, float> logical_size = *view_logical_size_;
SetViewportMetrics({
view_pixel_ratio_, // device_pixel_ratio
view_width_ * view_pixel_ratio_, // physical_width
view_height_ * view_pixel_ratio_, // physical_height
0.0f, // physical_padding_top
0.0f, // physical_padding_right
0.0f, // physical_padding_bottom
0.0f, // physical_padding_left
0.0f, // physical_view_inset_top
0.0f, // physical_view_inset_right
0.0f, // physical_view_inset_bottom
0.0f, // physical_view_inset_left
pixel_ratio, // device_pixel_ratio
logical_size.first * pixel_ratio, // physical_width
logical_size.second * pixel_ratio, // physical_height
0.0f, // physical_padding_top
0.0f, // physical_padding_right
0.0f, // physical_padding_bottom
0.0f, // physical_padding_left
0.0f, // physical_view_inset_top
0.0f, // physical_view_inset_right
0.0f, // physical_view_inset_bottom
0.0f, // physical_view_inset_left
0.0f, // p_physical_system_gesture_inset_top
0.0f, // p_physical_system_gesture_inset_right
0.0f, // p_physical_system_gesture_inset_bottom
@ -421,6 +447,9 @@ bool PlatformView::OnHandlePointerEvent(
PointerTraceHACK(pointer.radius_major, pointer.radius_minor);
TRACE_FLOW_END("input", "dispatch_event_to_client", trace_id);
const float pixel_ratio =
view_pixel_ratio_.has_value() ? *view_pixel_ratio_ : 0.f;
flutter::PointerData pointer_data;
pointer_data.Clear();
pointer_data.time_stamp = pointer.event_time / 1000;
@ -428,8 +457,8 @@ bool PlatformView::OnHandlePointerEvent(
pointer_data.kind = GetKindFromPointerType(pointer.type);
pointer_data.device = pointer.pointer_id;
// Pointer events are in logical pixels, so scale to physical.
pointer_data.physical_x = pointer.x * view_pixel_ratio_;
pointer_data.physical_y = pointer.y * view_pixel_ratio_;
pointer_data.physical_x = pointer.x * pixel_ratio;
pointer_data.physical_y = pointer.y * pixel_ratio;
// Buttons are single bit values starting with kMousePrimaryButton = 1.
pointer_data.buttons = static_cast<uint64_t>(pointer.buttons);
@ -601,7 +630,10 @@ void PlatformView::DispatchSemanticsAction(int32_t node_id,
void PlatformView::UpdateSemantics(
flutter::SemanticsNodeUpdates update,
flutter::CustomAccessibilityActionUpdates actions) {
accessibility_bridge_->AddSemanticsNodeUpdate(update, view_pixel_ratio_);
const float pixel_ratio =
view_pixel_ratio_.has_value() ? *view_pixel_ratio_ : 0.f;
accessibility_bridge_->AddSemanticsNodeUpdate(update, pixel_ratio);
}
// Channel handler for kAccessibilityChannel

View File

@ -9,6 +9,7 @@
#include <fuchsia/ui/scenic/cpp/fidl.h>
#include <lib/fidl/cpp/binding.h>
#include <lib/fit/function.h>
#include <lib/ui/scenic/cpp/id.h>
#include <map>
#include <set>
@ -19,8 +20,6 @@
#include "accessibility_bridge.h"
#include <lib/ui/scenic/cpp/id.h> // nogncheck
namespace flutter_runner {
using OnEnableWireframe = fit::function<void(bool)>;
@ -29,16 +28,22 @@ using OnUpdateView = fit::function<void(int64_t, bool, bool)>;
using OnDestroyView = fit::function<void(int64_t)>;
using OnCreateSurface = fit::function<std::unique_ptr<flutter::Surface>()>;
// The per engine component residing on the platform thread is responsible for
// all platform specific integrations.
// PlatformView is the per-engine component residing on the platform thread that
// is responsible for all platform specific integrations -- particularly
// integration with the platform's accessibility, input, and windowing features.
//
// PlatformView communicates with the Dart code via "platform messages" handled
// in HandlePlatformMessage. This communication is bidirectional. Platform
// messages are notably responsible for communication related to input and
// external views / windowing.
//
// The PlatformView implements SessionListener and gets Session events but it
// does *not* actually own the Session itself; that is owned by the Compositor
// thread.
// does *not* actually own the Session itself; that is owned by the
// FuchsiaExternalViewEmbedder on the raster thread.
class PlatformView final : public flutter::PlatformView,
public AccessibilityBridge::Delegate,
private fuchsia::ui::scenic::SessionListener,
public fuchsia::ui::input::InputMethodEditorClient,
public AccessibilityBridge::Delegate {
private fuchsia::ui::input::InputMethodEditorClient {
public:
PlatformView(flutter::PlatformView::Delegate& delegate,
std::string debug_label,
@ -73,51 +78,6 @@ class PlatformView final : public flutter::PlatformView,
flutter::PointerDataDispatcherMaker GetDispatcherMaker() override;
private:
const std::string debug_label_;
// TODO(MI4-2490): remove once ViewRefControl is passed to Scenic and kept
// alive there
const fuchsia::ui::views::ViewRef view_ref_;
fuchsia::ui::views::FocuserPtr focuser_;
std::unique_ptr<AccessibilityBridge> accessibility_bridge_;
fidl::Binding<fuchsia::ui::scenic::SessionListener> session_listener_binding_;
fit::closure session_listener_error_callback_;
OnEnableWireframe wireframe_enabled_callback_;
OnCreateView on_create_view_callback_;
OnUpdateView on_update_view_callback_;
OnDestroyView on_destroy_view_callback_;
OnCreateSurface on_create_surface_callback_;
int current_text_input_client_ = 0;
fidl::Binding<fuchsia::ui::input::InputMethodEditorClient> ime_client_;
fuchsia::ui::input::InputMethodEditorPtr ime_;
fuchsia::ui::input::ImeServicePtr text_sync_service_;
fuchsia::sys::ServiceProviderPtr parent_environment_service_provider_;
// last_text_state_ is the last state of the text input as reported by the IME
// or initialized by Flutter. We set it to null if Flutter doesn't want any
// input, since then there is no text input state at all.
std::unique_ptr<fuchsia::ui::input::TextInputState> last_text_state_;
std::set<int> down_pointers_;
std::map<
std::string /* channel */,
fit::function<void(
fml::RefPtr<flutter::PlatformMessage> /* message */)> /* handler */>
platform_message_handlers_;
// These are the channels that aren't registered and have been notified as
// such. Notifying via logs multiple times results in log-spam. See:
// https://github.com/flutter/flutter/issues/55966
std::set<std::string /* channel */> unregistered_channels_;
fml::TimeDelta vsync_offset_;
zx_handle_t vsync_event_handle_ = 0;
float view_width_ = 0.0f; // Width in logical pixels.
float view_height_ = 0.0f; // Height in logical pixels.
float view_pixel_ratio_ = 0.0f; // Logical / physical pixel ratio.
void RegisterPlatformMessageHandlers();
// |fuchsia::ui::input::InputMethodEditorClient|
@ -185,6 +145,57 @@ class PlatformView final : public flutter::PlatformView,
void HandleFlutterPlatformViewsChannelPlatformMessage(
fml::RefPtr<flutter::PlatformMessage> message);
const std::string debug_label_;
// TODO(MI4-2490): remove once ViewRefControl is passed to Scenic and kept
// alive there
const fuchsia::ui::views::ViewRef view_ref_;
fuchsia::ui::views::FocuserPtr focuser_;
std::unique_ptr<AccessibilityBridge> accessibility_bridge_;
// Logical size and logical->physical ratio. These are optional to provide
// an "unset" state during program startup, before Scenic has sent any
// metrics-related events to provide initial values for these.
//
// The engine internally uses a default size of (0.f 0.f) with a default 1.f
// ratio, so there is no need to emit events until Scenic has actually sent a
// valid size and ratio.
std::optional<std::pair<float, float>> view_logical_size_;
std::optional<float> view_pixel_ratio_;
fidl::Binding<fuchsia::ui::scenic::SessionListener> session_listener_binding_;
fit::closure session_listener_error_callback_;
OnEnableWireframe wireframe_enabled_callback_;
OnCreateView on_create_view_callback_;
OnUpdateView on_update_view_callback_;
OnDestroyView on_destroy_view_callback_;
OnCreateSurface on_create_surface_callback_;
int current_text_input_client_ = 0;
fidl::Binding<fuchsia::ui::input::InputMethodEditorClient> ime_client_;
fuchsia::ui::input::InputMethodEditorPtr ime_;
fuchsia::ui::input::ImeServicePtr text_sync_service_;
fuchsia::sys::ServiceProviderPtr parent_environment_service_provider_;
// last_text_state_ is the last state of the text input as reported by the IME
// or initialized by Flutter. We set it to null if Flutter doesn't want any
// input, since then there is no text input state at all.
std::unique_ptr<fuchsia::ui::input::TextInputState> last_text_state_;
std::set<int> down_pointers_;
std::map<
std::string /* channel */,
fit::function<void(
fml::RefPtr<flutter::PlatformMessage> /* message */)> /* handler */>
platform_message_handlers_;
// These are the channels that aren't registered and have been notified as
// such. Notifying via logs multiple times results in log-spam. See:
// https://github.com/flutter/flutter/issues/55966
std::set<std::string /* channel */> unregistered_channels_;
fml::TimeDelta vsync_offset_;
zx_handle_t vsync_event_handle_ = 0;
FML_DISALLOW_COPY_AND_ASSIGN(PlatformView);
};

View File

@ -4,50 +4,35 @@
#include "flutter/shell/platform/fuchsia/flutter/platform_view.h"
#include <fuchsia/ui/gfx/cpp/fidl.h>
#include <fuchsia/ui/scenic/cpp/fidl.h>
#include <fuchsia/ui/views/cpp/fidl.h>
#include <lib/async-loop/cpp/loop.h>
#include <lib/async-loop/default.h>
#include <lib/async/default.h>
#include <lib/fidl/cpp/binding_set.h>
#include <lib/fidl/cpp/interface_request.h>
#include <lib/sys/cpp/testing/service_directory_provider.h>
#include <lib/ui/scenic/cpp/view_ref_pair.h>
#include <memory>
#include <ostream>
#include <string>
#include <vector>
#include "flutter/flow/embedded_views.h"
#include "flutter/lib/ui/window/platform_message.h"
#include "flutter/lib/ui/window/window.h"
#include "flutter/lib/ui/window/viewport_metrics.h"
#include "gmock/gmock.h"
#include "gtest/gtest.h"
#include "surface.h"
#include "task_runner_adapter.h"
namespace flutter_runner_test::flutter_runner_a11y_test {
class PlatformViewTests : public testing::Test {
protected:
PlatformViewTests() : loop_(&kAsyncLoopConfigAttachToCurrentThread) {}
async_dispatcher_t* dispatcher() { return loop_.dispatcher(); }
void RunLoopUntilIdle() {
loop_.RunUntilIdle();
loop_.ResetQuit();
}
private:
async::Loop loop_;
FML_DISALLOW_COPY_AND_ASSIGN(PlatformViewTests);
};
namespace flutter_runner::testing {
namespace {
class MockExternalViewEmbedder : public flutter::ExternalViewEmbedder {
public:
MockExternalViewEmbedder() = default;
~MockExternalViewEmbedder() override = default;
SkCanvas* GetRootCanvas() override { return nullptr; }
std::vector<SkCanvas*> GetCurrentCanvases() override {
return std::vector<SkCanvas*>();
@ -82,7 +67,9 @@ class MockPlatformViewDelegate : public flutter::PlatformView::Delegate {
void OnPlatformViewSetNextFrameCallback(const fml::closure& closure) {}
// |flutter::PlatformView::Delegate|
void OnPlatformViewSetViewportMetrics(
const flutter::ViewportMetrics& metrics) {}
const flutter::ViewportMetrics& metrics) {
metrics_ = metrics;
}
// |flutter::PlatformView::Delegate|
void OnPlatformViewDispatchPlatformMessage(
fml::RefPtr<flutter::PlatformMessage> message) {
@ -113,43 +100,45 @@ class MockPlatformViewDelegate : public flutter::PlatformView::Delegate {
// |flutter::PlatformView::Delegate|
std::unique_ptr<std::vector<std::string>> ComputePlatformViewResolvedLocale(
const std::vector<std::string>& supported_locale_data) {
std::unique_ptr<std::vector<std::string>> out =
std::make_unique<std::vector<std::string>>();
return out;
return nullptr;
}
bool SemanticsEnabled() const { return semantics_enabled_; }
int32_t SemanticsFeatures() const { return semantics_features_; }
flutter::Surface* surface() const { return surface_.get(); }
fml::RefPtr<flutter::PlatformMessage>& message() { return message_; }
flutter::PlatformMessage* message() const { return message_.get(); }
const flutter::ViewportMetrics& metrics() const { return metrics_; }
int32_t semantics_features() const { return semantics_features_; }
bool semantics_enabled() const { return semantics_enabled_; }
private:
std::unique_ptr<flutter::Surface> surface_;
bool semantics_enabled_ = false;
int32_t semantics_features_ = 0;
fml::RefPtr<flutter::PlatformMessage> message_;
flutter::ViewportMetrics metrics_;
int32_t semantics_features_ = 0;
bool semantics_enabled_ = false;
};
class MockFocuser : public fuchsia::ui::views::Focuser {
public:
MockFocuser() = default;
~MockFocuser() override = default;
MockFocuser(bool fail_request_focus = false)
: fail_request_focus_(fail_request_focus) {}
bool request_focus_called = false;
bool fail_request_focus = false;
bool request_focus_called() const { return request_focus_called_; }
private:
void RequestFocus(fuchsia::ui::views::ViewRef view_ref,
RequestFocusCallback callback) override {
request_focus_called = true;
request_focus_called_ = true;
auto result =
fail_request_focus
fail_request_focus_
? fuchsia::ui::views::Focuser_RequestFocus_Result::WithErr(
fuchsia::ui::views::Error::DENIED)
: fuchsia::ui::views::Focuser_RequestFocus_Result::WithResponse(
fuchsia::ui::views::Focuser_RequestFocus_Response());
callback(std::move(result));
}
bool request_focus_called_ = false;
bool fail_request_focus_ = false;
};
class MockResponse : public flutter::PlatformMessageResponse {
@ -158,25 +147,228 @@ class MockResponse : public flutter::PlatformMessageResponse {
MOCK_METHOD0(CompleteEmpty, void());
};
TEST_F(PlatformViewTests, ChangesAccessibilitySettings) {
} // namespace
class PlatformViewTests : public ::testing::Test {
protected:
PlatformViewTests() : loop_(&kAsyncLoopConfigAttachToCurrentThread) {}
async_dispatcher_t* dispatcher() { return loop_.dispatcher(); }
void RunLoopUntilIdle() {
loop_.RunUntilIdle();
loop_.ResetQuit();
}
private:
async::Loop loop_;
FML_DISALLOW_COPY_AND_ASSIGN(PlatformViewTests);
};
// This test makes sure that the PlatformView correctly returns a Surface
// instance that can surface the provided gr_context and view_embedder.
TEST_F(PlatformViewTests, CreateSurfaceTest) {
sys::testing::ServiceDirectoryProvider services_provider(dispatcher());
MockPlatformViewDelegate delegate;
zx::eventpair a, b;
zx::eventpair::create(/* flags */ 0u, &a, &b);
auto view_ref = fuchsia::ui::views::ViewRef({
.reference = std::move(a),
});
flutter::TaskRunners task_runners =
flutter::TaskRunners("test_runners", nullptr, nullptr, nullptr, nullptr);
EXPECT_FALSE(delegate.SemanticsEnabled());
EXPECT_EQ(delegate.SemanticsFeatures(), 0);
flutter::TaskRunners task_runners =
flutter::TaskRunners("test_runners", // label
nullptr, // platform
flutter_runner::CreateFMLTaskRunner(
async_get_default_dispatcher()), // raster
nullptr, // ui
nullptr // io
);
// Test create surface callback function.
sk_sp<GrDirectContext> gr_context =
GrDirectContext::MakeMock(nullptr, GrContextOptions());
MockExternalViewEmbedder view_embedder;
auto CreateSurfaceCallback = [&view_embedder, gr_context]() {
return std::make_unique<flutter_runner::Surface>(
"PlatformViewTest", &view_embedder, gr_context.get());
};
auto platform_view = flutter_runner::PlatformView(
delegate, // delegate
"test_platform_view", // label
std::move(view_ref), // view_ref
fuchsia::ui::views::ViewRef(), // view_ref
std::move(task_runners), // task_runners
services_provider.service_directory(), // runner_services
nullptr, // parent_environment_service_provider_handle
nullptr, // session_listener_request
nullptr, // focuser,
nullptr, // on_session_listener_error_callback
nullptr, // on_enable_wireframe_callback,
nullptr, // on_create_view_callback,
nullptr, // on_update_view_callback,
nullptr, // on_destroy_view_callback,
CreateSurfaceCallback, // on_create_surface_callback,
fml::TimeDelta::Zero(), // vsync_offset
ZX_HANDLE_INVALID // vsync_event_handle
);
platform_view.NotifyCreated();
RunLoopUntilIdle();
EXPECT_EQ(gr_context.get(), delegate.surface()->GetContext());
EXPECT_EQ(&view_embedder, delegate.surface()->GetExternalViewEmbedder());
}
// This test makes sure that the PlatformView correctly registers Scenic
// MetricsEvents sent to it via FIDL, correctly parses the metrics it receives,
// and calls the SetViewportMetrics callback with the appropriate parameters.
TEST_F(PlatformViewTests, SetViewportMetrics) {
constexpr float invalid_pixel_ratio = -0.75f;
constexpr float valid_pixel_ratio = 0.75f;
constexpr float invalid_max_bound = -0.75f;
constexpr float valid_max_bound = 0.75f;
MockPlatformViewDelegate delegate;
EXPECT_EQ(delegate.metrics(), flutter::ViewportMetrics());
fuchsia::ui::scenic::SessionListenerPtr session_listener;
std::vector<fuchsia::ui::scenic::Event> events;
sys::testing::ServiceDirectoryProvider services_provider(dispatcher());
flutter::TaskRunners task_runners("test_runners", nullptr, nullptr, nullptr,
nullptr);
flutter_runner::PlatformView platform_view(
delegate, // delegate
"test_platform_view", // label
fuchsia::ui::views::ViewRef(), // view_ref
std::move(task_runners), // task_runners
services_provider.service_directory(), // runner_services
nullptr, // parent_environment_service_provider_handle
session_listener.NewRequest(), // session_listener_request
nullptr, // focuser,
nullptr, // on_session_listener_error_callback
nullptr, // on_enable_wireframe_callback,
nullptr, // on_create_view_callback,
nullptr, // on_update_view_callback,
nullptr, // on_destroy_view_callback,
nullptr, // on_create_surface_callback,
fml::TimeDelta::Zero(), // vsync_offset
ZX_HANDLE_INVALID // vsync_event_handle
);
RunLoopUntilIdle();
EXPECT_EQ(delegate.metrics(), flutter::ViewportMetrics());
// Test updating with an invalid pixel ratio. The final metrics should be
// unchanged.
events.clear();
events.emplace_back(fuchsia::ui::scenic::Event::WithGfx(
fuchsia::ui::gfx::Event::WithMetrics(fuchsia::ui::gfx::MetricsEvent{
.node_id = 0,
.metrics =
fuchsia::ui::gfx::Metrics{
.scale_x = invalid_pixel_ratio,
.scale_y = 1.f,
.scale_z = 1.f,
},
})));
session_listener->OnScenicEvent(std::move(events));
RunLoopUntilIdle();
EXPECT_EQ(delegate.metrics(), flutter::ViewportMetrics());
// Test updating with an invalid size. The final metrics should be unchanged.
events.clear();
events.emplace_back(
fuchsia::ui::scenic::Event::WithGfx(
fuchsia::ui::gfx::Event::WithViewPropertiesChanged(
fuchsia::ui::gfx::ViewPropertiesChangedEvent{
.view_id = 0,
.properties =
fuchsia::ui::gfx::ViewProperties{
.bounding_box =
fuchsia::ui::gfx::BoundingBox{
.min =
fuchsia::ui::gfx::vec3{
.x = 0.f,
.y = 0.f,
.z = 0.f,
},
.max =
fuchsia::ui::gfx::vec3{
.x = invalid_max_bound,
.y = invalid_max_bound,
.z = invalid_max_bound,
},
},
},
})));
session_listener->OnScenicEvent(std::move(events));
RunLoopUntilIdle();
EXPECT_EQ(delegate.metrics(), flutter::ViewportMetrics());
// Test updating the size only. The final metrics should be unchanged until
// both pixel ratio and size are updated.
events.clear();
events.emplace_back(
fuchsia::ui::scenic::Event::WithGfx(
fuchsia::ui::gfx::Event::WithViewPropertiesChanged(
fuchsia::ui::gfx::ViewPropertiesChangedEvent{
.view_id = 0,
.properties =
fuchsia::ui::gfx::ViewProperties{
.bounding_box =
fuchsia::ui::gfx::BoundingBox{
.min =
fuchsia::ui::gfx::vec3{
.x = 0.f,
.y = 0.f,
.z = 0.f,
},
.max =
fuchsia::ui::gfx::vec3{
.x = valid_max_bound,
.y = valid_max_bound,
.z = valid_max_bound,
},
},
},
})));
session_listener->OnScenicEvent(std::move(events));
RunLoopUntilIdle();
EXPECT_EQ(delegate.metrics(), flutter::ViewportMetrics());
// Test updating the pixel ratio only. The final metrics should change now.
events.clear();
events.emplace_back(fuchsia::ui::scenic::Event::WithGfx(
fuchsia::ui::gfx::Event::WithMetrics(fuchsia::ui::gfx::MetricsEvent{
.node_id = 0,
.metrics =
fuchsia::ui::gfx::Metrics{
.scale_x = valid_pixel_ratio,
.scale_y = 1.f,
.scale_z = 1.f,
},
})));
session_listener->OnScenicEvent(std::move(events));
RunLoopUntilIdle();
EXPECT_EQ(delegate.metrics(),
flutter::ViewportMetrics(valid_pixel_ratio,
valid_pixel_ratio * valid_max_bound,
valid_pixel_ratio * valid_max_bound));
}
// This test makes sure that the PlatformView correctly registers semantics
// settings changes applied to it and calls the SetSemanticsEnabled /
// SetAccessibilityFeatures callbacks with the appropriate parameters.
TEST_F(PlatformViewTests, ChangesAccessibilitySettings) {
sys::testing::ServiceDirectoryProvider services_provider(dispatcher());
MockPlatformViewDelegate delegate;
flutter::TaskRunners task_runners =
flutter::TaskRunners("test_runners", nullptr, nullptr, nullptr, nullptr);
EXPECT_FALSE(delegate.semantics_enabled());
EXPECT_EQ(delegate.semantics_features(), 0);
auto platform_view = flutter_runner::PlatformView(
delegate, // delegate
"test_platform_view", // label
fuchsia::ui::views::ViewRef(), // view_ref
std::move(task_runners), // task_runners
services_provider.service_directory(), // runner_services
nullptr, // parent_environment_service_provider_handle
@ -196,28 +388,22 @@ TEST_F(PlatformViewTests, ChangesAccessibilitySettings) {
platform_view.SetSemanticsEnabled(true);
EXPECT_TRUE(delegate.SemanticsEnabled());
EXPECT_EQ(delegate.SemanticsFeatures(),
EXPECT_TRUE(delegate.semantics_enabled());
EXPECT_EQ(delegate.semantics_features(),
static_cast<int32_t>(
flutter::AccessibilityFeatureFlag::kAccessibleNavigation));
platform_view.SetSemanticsEnabled(false);
EXPECT_FALSE(delegate.SemanticsEnabled());
EXPECT_EQ(delegate.SemanticsFeatures(), 0);
EXPECT_FALSE(delegate.semantics_enabled());
EXPECT_EQ(delegate.semantics_features(), 0);
}
// Test to make sure that PlatformView correctly registers messages sent on
// the "flutter/platform_views" channel, correctly parses the JSON it receives
// and calls the EnableWireframeCallback with the appropriate args.
// This test makes sure that the PlatformView forwards messages on the
// "flutter/platform_views" channel for EnableWireframe.
TEST_F(PlatformViewTests, EnableWireframeTest) {
sys::testing::ServiceDirectoryProvider services_provider(dispatcher());
MockPlatformViewDelegate delegate;
zx::eventpair a, b;
zx::eventpair::create(/* flags */ 0u, &a, &b);
auto view_ref = fuchsia::ui::views::ViewRef({
.reference = std::move(a),
});
flutter::TaskRunners task_runners =
flutter::TaskRunners("test_runners", nullptr, nullptr, nullptr, nullptr);
@ -232,7 +418,7 @@ TEST_F(PlatformViewTests, EnableWireframeTest) {
auto platform_view = flutter_runner::PlatformView(
delegate, // delegate
"test_platform_view", // label
std::move(view_ref), // view_refs
fuchsia::ui::views::ViewRef(), // view_ref
std::move(task_runners), // task_runners
services_provider.service_directory(), // runner_services
nullptr, // parent_environment_service_provider_handle
@ -274,17 +460,11 @@ TEST_F(PlatformViewTests, EnableWireframeTest) {
EXPECT_TRUE(wireframe_enabled);
}
// Test to make sure that PlatformView correctly registers messages sent on
// the "flutter/platform_views" channel, correctly parses the JSON it receives
// and calls the CreateViewCallback with the appropriate args.
// This test makes sure that the PlatformView forwards messages on the
// "flutter/platform_views" channel for Createview.
TEST_F(PlatformViewTests, CreateViewTest) {
sys::testing::ServiceDirectoryProvider services_provider(dispatcher());
MockPlatformViewDelegate delegate;
zx::eventpair a, b;
zx::eventpair::create(/* flags */ 0u, &a, &b);
auto view_ref = fuchsia::ui::views::ViewRef({
.reference = std::move(a),
});
flutter::TaskRunners task_runners =
flutter::TaskRunners("test_runners", nullptr, nullptr, nullptr, nullptr);
@ -299,7 +479,7 @@ TEST_F(PlatformViewTests, CreateViewTest) {
auto platform_view = flutter_runner::PlatformView(
delegate, // delegate
"test_platform_view", // label
std::move(view_ref), // view_refs
fuchsia::ui::views::ViewRef(), // view_ref
std::move(task_runners), // task_runners
services_provider.service_directory(), // runner_services
nullptr, // parent_environment_service_provider_handle
@ -343,17 +523,11 @@ TEST_F(PlatformViewTests, CreateViewTest) {
EXPECT_TRUE(create_view_called);
}
// Test to make sure that PlatformView correctly registers messages sent on
// the "flutter/platform_views" channel, correctly parses the JSON it receives
// and calls the UdpateViewCallback with the appropriate args.
// This test makes sure that the PlatformView forwards messages on the
// "flutter/platform_views" channel for UpdateView.
TEST_F(PlatformViewTests, UpdateViewTest) {
sys::testing::ServiceDirectoryProvider services_provider(dispatcher());
MockPlatformViewDelegate delegate;
zx::eventpair a, b;
zx::eventpair::create(/* flags */ 0u, &a, &b);
auto view_ref = fuchsia::ui::views::ViewRef({
.reference = std::move(a),
});
flutter::TaskRunners task_runners =
flutter::TaskRunners("test_runners", nullptr, nullptr, nullptr, nullptr);
@ -368,7 +542,7 @@ TEST_F(PlatformViewTests, UpdateViewTest) {
auto platform_view = flutter_runner::PlatformView(
delegate, // delegate
"test_platform_view", // label
std::move(view_ref), // view_refs
fuchsia::ui::views::ViewRef(), // view_ref
std::move(task_runners), // task_runners
services_provider.service_directory(), // runner_services
nullptr, // parent_environment_service_provider_handle
@ -412,17 +586,11 @@ TEST_F(PlatformViewTests, UpdateViewTest) {
EXPECT_TRUE(update_view_called);
}
// Test to make sure that PlatformView correctly registers messages sent on
// the "flutter/platform_views" channel, correctly parses the JSON it receives
// and calls the DestroyViewCallback with the appropriate args.
// This test makes sure that the PlatformView forwards messages on the
// "flutter/platform_views" channel for DestroyView.
TEST_F(PlatformViewTests, DestroyViewTest) {
sys::testing::ServiceDirectoryProvider services_provider(dispatcher());
MockPlatformViewDelegate delegate;
zx::eventpair a, b;
zx::eventpair::create(/* flags */ 0u, &a, &b);
auto view_ref = fuchsia::ui::views::ViewRef({
.reference = std::move(a),
});
flutter::TaskRunners task_runners =
flutter::TaskRunners("test_runners", nullptr, nullptr, nullptr, nullptr);
@ -437,7 +605,7 @@ TEST_F(PlatformViewTests, DestroyViewTest) {
auto platform_view = flutter_runner::PlatformView(
delegate, // delegate
"test_platform_view", // label
std::move(view_ref), // view_refs
fuchsia::ui::views::ViewRef(), // view_ref
std::move(task_runners), // task_runners
services_provider.service_directory(), // runner_services
nullptr, // parent_environment_service_provider_handle
@ -479,173 +647,9 @@ TEST_F(PlatformViewTests, DestroyViewTest) {
EXPECT_TRUE(destroy_view_called);
}
// Test to make sure that PlatformView correctly registers messages sent on
// the "flutter/platform_views" channel, correctly parses the JSON it receives
// and calls the focuser's RequestFocus with the appropriate args.
TEST_F(PlatformViewTests, RequestFocusTest) {
sys::testing::ServiceDirectoryProvider services_provider(dispatcher());
MockPlatformViewDelegate delegate;
zx::eventpair a, b;
zx::eventpair::create(/* flags */ 0u, &a, &b);
auto view_ref = fuchsia::ui::views::ViewRef({
.reference = std::move(a),
});
flutter::TaskRunners task_runners =
flutter::TaskRunners("test_runners", nullptr, nullptr, nullptr, nullptr);
MockFocuser mock_focuser;
fidl::BindingSet<fuchsia::ui::views::Focuser> focuser_bindings;
auto focuser_handle = focuser_bindings.AddBinding(&mock_focuser);
auto platform_view = flutter_runner::PlatformView(
delegate, // delegate
"test_platform_view", // label
std::move(view_ref), // view_refs
std::move(task_runners), // task_runners
services_provider.service_directory(), // runner_services
nullptr, // parent_environment_service_provider_handle
nullptr, // session_listener_request
std::move(focuser_handle), // focuser,
nullptr, // on_session_listener_error_callback
nullptr, // on_enable_wireframe_callback,
nullptr, // on_create_view_callback,
nullptr, // on_update_view_callback,
nullptr, // on_destroy_view_callback,
nullptr, // on_create_surface_callback,
fml::TimeDelta::Zero(), // vsync_offset
ZX_HANDLE_INVALID // vsync_event_handle
);
// Cast platform_view to its base view so we can have access to the public
// "HandlePlatformMessage" function.
auto base_view = dynamic_cast<flutter::PlatformView*>(&platform_view);
EXPECT_TRUE(base_view);
// JSON for the message to be passed into the PlatformView.
char buff[254];
snprintf(buff, sizeof(buff),
"{"
" \"method\":\"View.requestFocus\","
" \"args\": {"
" \"viewRef\":%u"
" }"
"}",
b.get());
// Define a custom gmock matcher to capture the response to platform message.
struct DataArg {
void Complete(std::unique_ptr<fml::Mapping> data) {
this->data = std::move(data);
}
std::unique_ptr<fml::Mapping> data;
};
DataArg data_arg;
fml::RefPtr<MockResponse> response = fml::MakeRefCounted<MockResponse>();
EXPECT_CALL(*response, Complete(testing::_))
.WillOnce(testing::Invoke(&data_arg, &DataArg::Complete));
fml::RefPtr<flutter::PlatformMessage> message =
fml::MakeRefCounted<flutter::PlatformMessage>(
"flutter/platform_views",
std::vector<uint8_t>(buff, buff + sizeof(buff)), response);
base_view->HandlePlatformMessage(message);
RunLoopUntilIdle();
EXPECT_TRUE(mock_focuser.request_focus_called);
auto result = std::string((const char*)data_arg.data->GetMapping(),
data_arg.data->GetSize());
EXPECT_EQ(std::string("[0]"), result);
}
// Test to make sure that PlatformView correctly registers messages sent on
// the "flutter/platform_views" channel, correctly parses the JSON it receives
// and calls the focuser's RequestFocus with the appropriate args.
TEST_F(PlatformViewTests, RequestFocusFailTest) {
sys::testing::ServiceDirectoryProvider services_provider(dispatcher());
MockPlatformViewDelegate delegate;
zx::eventpair a, b;
zx::eventpair::create(/* flags */ 0u, &a, &b);
auto view_ref = fuchsia::ui::views::ViewRef({
.reference = std::move(a),
});
flutter::TaskRunners task_runners =
flutter::TaskRunners("test_runners", nullptr, nullptr, nullptr, nullptr);
MockFocuser mock_focuser;
mock_focuser.fail_request_focus = true;
fidl::BindingSet<fuchsia::ui::views::Focuser> focuser_bindings;
auto focuser_handle = focuser_bindings.AddBinding(&mock_focuser);
auto platform_view = flutter_runner::PlatformView(
delegate, // delegate
"test_platform_view", // label
std::move(view_ref), // view_refs
std::move(task_runners), // task_runners
services_provider.service_directory(), // runner_services
nullptr, // parent_environment_service_provider_handle
nullptr, // session_listener_request
std::move(focuser_handle), // focuser,
nullptr, // on_session_listener_error_callback
nullptr, // on_enable_wireframe_callback,
nullptr, // on_create_view_callback,
nullptr, // on_update_view_callback,
nullptr, // on_destroy_view_callback,
nullptr, // on_create_surface_callback,
fml::TimeDelta::Zero(), // vsync_offset
ZX_HANDLE_INVALID // vsync_event_handle
);
// Cast platform_view to its base view so we can have access to the public
// "HandlePlatformMessage" function.
auto base_view = dynamic_cast<flutter::PlatformView*>(&platform_view);
EXPECT_TRUE(base_view);
// JSON for the message to be passed into the PlatformView.
char buff[254];
snprintf(buff, sizeof(buff),
"{"
" \"method\":\"View.requestFocus\","
" \"args\": {"
" \"viewRef\":%u"
" }"
"}",
b.get());
// Define a custom gmock matcher to capture the response to platform message.
struct DataArg {
void Complete(std::unique_ptr<fml::Mapping> data) {
this->data = std::move(data);
}
std::unique_ptr<fml::Mapping> data;
};
DataArg data_arg;
fml::RefPtr<MockResponse> response = fml::MakeRefCounted<MockResponse>();
EXPECT_CALL(*response, Complete(testing::_))
.WillOnce(testing::Invoke(&data_arg, &DataArg::Complete));
fml::RefPtr<flutter::PlatformMessage> message =
fml::MakeRefCounted<flutter::PlatformMessage>(
"flutter/platform_views",
std::vector<uint8_t>(buff, buff + sizeof(buff)), response);
base_view->HandlePlatformMessage(message);
RunLoopUntilIdle();
EXPECT_TRUE(mock_focuser.request_focus_called);
auto result = std::string((const char*)data_arg.data->GetMapping(),
data_arg.data->GetSize());
std::ostringstream out;
out << "["
<< static_cast<std::underlying_type_t<fuchsia::ui::views::Error>>(
fuchsia::ui::views::Error::DENIED)
<< "]";
EXPECT_EQ(out.str(), result);
}
// Test to make sure that PlatformView forward messages on the
// "flutter/platform_views" channel, for viewConnected/viewDisconnected and
// viewStateChanged events.
// This test makes sure that the PlatformView forwards messages on the
// "flutter/platform_views" channel for ViewConnected, ViewDisconnected, and
// ViewStateChanged events.
TEST_F(PlatformViewTests, ViewEventsTest) {
MockPlatformViewDelegate delegate;
@ -661,7 +665,7 @@ TEST_F(PlatformViewTests, ViewEventsTest) {
auto platform_view = flutter_runner::PlatformView(
delegate, // delegate
"test_platform_view", // label
fuchsia::ui::views::ViewRef{}, // view_ref
fuchsia::ui::views::ViewRef(), // view_ref
std::move(task_runners), // task_runners
services_provider.service_directory(), // runner_services
nullptr, // parent_environment_service_provider_handle
@ -728,58 +732,161 @@ TEST_F(PlatformViewTests, ViewEventsTest) {
EXPECT_EQ(expected, call);
}
// Test to make sure that PlatformView correctly returns a Surface instance
// that can surface the provided gr_context and view_embedder.
TEST_F(PlatformViewTests, CreateSurfaceTest) {
// This test makes sure that the PlatformView forwards messages on the
// "flutter/platform_views" channel for RequestFocus.
TEST_F(PlatformViewTests, RequestFocusTest) {
sys::testing::ServiceDirectoryProvider services_provider(dispatcher());
MockPlatformViewDelegate delegate;
zx::eventpair a, b;
zx::eventpair::create(/* flags */ 0u, &a, &b);
auto view_ref = fuchsia::ui::views::ViewRef({
.reference = std::move(a),
});
flutter::TaskRunners task_runners =
flutter::TaskRunners("test_runners", // label
nullptr, // platform
flutter_runner::CreateFMLTaskRunner(
async_get_default_dispatcher()), // raster
nullptr, // ui
nullptr // io
);
flutter::TaskRunners("test_runners", nullptr, nullptr, nullptr, nullptr);
// Test create surface callback function.
sk_sp<GrDirectContext> gr_context =
GrDirectContext::MakeMock(nullptr, GrContextOptions());
MockExternalViewEmbedder view_embedder;
auto CreateSurfaceCallback = [&view_embedder, gr_context]() {
return std::make_unique<flutter_runner::Surface>(
"PlatformViewTest", &view_embedder, gr_context.get());
};
MockFocuser mock_focuser;
fidl::BindingSet<fuchsia::ui::views::Focuser> focuser_bindings;
auto focuser_handle = focuser_bindings.AddBinding(&mock_focuser);
auto platform_view = flutter_runner::PlatformView(
delegate, // delegate
"test_platform_view", // label
std::move(view_ref), // view_refs
fuchsia::ui::views::ViewRef(), // view_ref
std::move(task_runners), // task_runners
services_provider.service_directory(), // runner_services
nullptr, // parent_environment_service_provider_handle
nullptr, // session_listener_request
nullptr, // focuser,
nullptr, // on_session_listener_error_callback
nullptr, // on_enable_wireframe_callback,
nullptr, // on_create_view_callback,
nullptr, // on_update_view_callback,
nullptr, // on_destroy_view_callback,
CreateSurfaceCallback, // on_create_surface_callback,
fml::TimeDelta::Zero(), // vsync_offset
ZX_HANDLE_INVALID // vsync_event_handle
nullptr, // parent_environment_service_provider_handle
nullptr, // session_listener_request
std::move(focuser_handle), // focuser,
nullptr, // on_session_listener_error_callback
nullptr, // on_enable_wireframe_callback,
nullptr, // on_create_view_callback,
nullptr, // on_update_view_callback,
nullptr, // on_destroy_view_callback,
nullptr, // on_create_surface_callback,
fml::TimeDelta::Zero(), // vsync_offset
ZX_HANDLE_INVALID // vsync_event_handle
);
platform_view.NotifyCreated();
// Cast platform_view to its base view so we can have access to the public
// "HandlePlatformMessage" function.
auto base_view = dynamic_cast<flutter::PlatformView*>(&platform_view);
EXPECT_TRUE(base_view);
// This "Mock" ViewRef serves as the target for the RequestFocus operation.
auto mock_view_ref_pair = scenic::ViewRefPair::New();
// JSON for the message to be passed into the PlatformView.
char buff[254];
snprintf(buff, sizeof(buff),
"{"
" \"method\":\"View.requestFocus\","
" \"args\": {"
" \"viewRef\":%u"
" }"
"}",
mock_view_ref_pair.view_ref.reference.get());
// Define a custom gmock matcher to capture the response to platform message.
struct DataArg {
void Complete(std::unique_ptr<fml::Mapping> data) {
this->data = std::move(data);
}
std::unique_ptr<fml::Mapping> data;
};
DataArg data_arg;
fml::RefPtr<MockResponse> response = fml::MakeRefCounted<MockResponse>();
EXPECT_CALL(*response, Complete(::testing::_))
.WillOnce(::testing::Invoke(&data_arg, &DataArg::Complete));
fml::RefPtr<flutter::PlatformMessage> message =
fml::MakeRefCounted<flutter::PlatformMessage>(
"flutter/platform_views",
std::vector<uint8_t>(buff, buff + sizeof(buff)), response);
base_view->HandlePlatformMessage(message);
RunLoopUntilIdle();
EXPECT_EQ(gr_context.get(), delegate.surface()->GetContext());
EXPECT_EQ(&view_embedder, delegate.surface()->GetExternalViewEmbedder());
EXPECT_TRUE(mock_focuser.request_focus_called());
auto result = std::string((const char*)data_arg.data->GetMapping(),
data_arg.data->GetSize());
EXPECT_EQ(std::string("[0]"), result);
}
} // namespace flutter_runner_test::flutter_runner_a11y_test
// This test makes sure that the PlatformView correctly replies with an error
// response when a RequestFocus call fails.
TEST_F(PlatformViewTests, RequestFocusFailTest) {
sys::testing::ServiceDirectoryProvider services_provider(dispatcher());
MockPlatformViewDelegate delegate;
flutter::TaskRunners task_runners =
flutter::TaskRunners("test_runners", nullptr, nullptr, nullptr, nullptr);
MockFocuser mock_focuser(true /*fail_request_focus*/);
fidl::BindingSet<fuchsia::ui::views::Focuser> focuser_bindings;
auto focuser_handle = focuser_bindings.AddBinding(&mock_focuser);
auto platform_view = flutter_runner::PlatformView(
delegate, // delegate
"test_platform_view", // label
fuchsia::ui::views::ViewRef(), // view_ref
std::move(task_runners), // task_runners
services_provider.service_directory(), // runner_services
nullptr, // parent_environment_service_provider_handle
nullptr, // session_listener_request
std::move(focuser_handle), // focuser,
nullptr, // on_session_listener_error_callback
nullptr, // on_enable_wireframe_callback,
nullptr, // on_create_view_callback,
nullptr, // on_update_view_callback,
nullptr, // on_destroy_view_callback,
nullptr, // on_create_surface_callback,
fml::TimeDelta::Zero(), // vsync_offset
ZX_HANDLE_INVALID // vsync_event_handle
);
// Cast platform_view to its base view so we can have access to the public
// "HandlePlatformMessage" function.
auto base_view = dynamic_cast<flutter::PlatformView*>(&platform_view);
EXPECT_TRUE(base_view);
// This "Mock" ViewRef serves as the target for the RequestFocus operation.
auto mock_view_ref_pair = scenic::ViewRefPair::New();
// JSON for the message to be passed into the PlatformView.
char buff[254];
snprintf(buff, sizeof(buff),
"{"
" \"method\":\"View.requestFocus\","
" \"args\": {"
" \"viewRef\":%u"
" }"
"}",
mock_view_ref_pair.view_ref.reference.get());
// Define a custom gmock matcher to capture the response to platform message.
struct DataArg {
void Complete(std::unique_ptr<fml::Mapping> data) {
this->data = std::move(data);
}
std::unique_ptr<fml::Mapping> data;
};
DataArg data_arg;
fml::RefPtr<MockResponse> response = fml::MakeRefCounted<MockResponse>();
EXPECT_CALL(*response, Complete(::testing::_))
.WillOnce(::testing::Invoke(&data_arg, &DataArg::Complete));
fml::RefPtr<flutter::PlatformMessage> message =
fml::MakeRefCounted<flutter::PlatformMessage>(
"flutter/platform_views",
std::vector<uint8_t>(buff, buff + sizeof(buff)), response);
base_view->HandlePlatformMessage(message);
RunLoopUntilIdle();
EXPECT_TRUE(mock_focuser.request_focus_called());
auto result = std::string((const char*)data_arg.data->GetMapping(),
data_arg.data->GetSize());
std::ostringstream out;
out << "["
<< static_cast<std::underlying_type_t<fuchsia::ui::views::Error>>(
fuchsia::ui::views::Error::DENIED)
<< "]";
EXPECT_EQ(out.str(), result);
}
} // namespace flutter_runner::testing