Skip to content

Commit

Permalink
[Embedder] Send key data through message channel (flutter#29795)
Browse files Browse the repository at this point in the history
 This PR changes how embedder API's SendKeyData sends ui.KeyData to the framework. The packets are now sent over the existing platform messenger, reusing the entirety of its code path and functionalities while keeping the embedder API unchanged
  • Loading branch information
dkwingsmt authored Nov 19, 2021
1 parent 5727fc1 commit d8a3b06
Show file tree
Hide file tree
Showing 26 changed files with 228 additions and 298 deletions.
5 changes: 0 additions & 5 deletions lib/ui/hooks.dart
Original file line number Diff line number Diff line change
Expand Up @@ -88,11 +88,6 @@ void _dispatchPointerDataPacket(ByteData packet) {
PlatformDispatcher.instance._dispatchPointerDataPacket(packet);
}

@pragma('vm:entry-point')
void _dispatchKeyData(ByteData packet, int responseId) {
PlatformDispatcher.instance._dispatchKeyData(packet, responseId);
}

@pragma('vm:entry-point')
void _dispatchSemanticsAction(int id, int action, ByteData? args) {
PlatformDispatcher.instance._dispatchSemanticsAction(id, action, args);
Expand Down
43 changes: 23 additions & 20 deletions lib/ui/platform_dispatcher.dart
Original file line number Diff line number Diff line change
Expand Up @@ -28,9 +28,6 @@ typedef TimingsCallback = void Function(List<FrameTiming> timings);
/// Signature for [PlatformDispatcher.onPointerDataPacket].
typedef PointerDataPacketCallback = void Function(PointerDataPacket packet);

// Signature for the response to KeyDataCallback.
typedef _KeyDataResponseCallback = void Function(int responseId, bool handled);

/// Signature for [PlatformDispatcher.onKeyData].
///
/// The callback should return true if the key event has been handled by the
Expand Down Expand Up @@ -59,6 +56,11 @@ typedef PlatformConfigurationChangedCallback = void Function(PlatformConfigurati
// A gesture setting value that indicates it has not been set by the engine.
const double _kUnsetGestureSetting = -1.0;

// A message channel to receive KeyData from the platform.
//
// See embedder.cc::kFlutterKeyDataChannel for more information.
const String _kFlutterKeyDataChannel = 'flutter/keydata';

/// Platform event dispatcher singleton.
///
/// The most basic interface to the host operating system's interface.
Expand Down Expand Up @@ -349,9 +351,19 @@ class PlatformDispatcher {
return PointerDataPacket(data: data);
}

/// Called by [_dispatchKeyData].
void _respondToKeyData(int responseId, bool handled)
native 'PlatformConfiguration_respondToKeyData';
static ChannelCallback _keyDataListener(KeyDataCallback onKeyData, Zone zone) =>
(ByteData? packet, PlatformMessageResponseCallback callback) {
_invoke1<KeyData>(
(KeyData keyData) {
final bool handled = onKeyData(keyData);
final Uint8List response = Uint8List(1);
response[0] = handled ? 1 : 0;
callback(response.buffer.asByteData());
},
zone,
_unpackKeyData(packet!),
);
};

/// A callback that is invoked when key data is available.
///
Expand All @@ -362,22 +374,13 @@ class PlatformDispatcher {
/// framework and should not be propagated further.
KeyDataCallback? get onKeyData => _onKeyData;
KeyDataCallback? _onKeyData;
Zone _onKeyDataZone = Zone.root;
set onKeyData(KeyDataCallback? callback) {
_onKeyData = callback;
_onKeyDataZone = Zone.current;
}

// Called from the engine, via hooks.dart
void _dispatchKeyData(ByteData packet, int responseId) {
_invoke2<KeyData, _KeyDataResponseCallback>(
(KeyData data, _KeyDataResponseCallback callback) {
callback(responseId, onKeyData != null && onKeyData!(data));
},
_onKeyDataZone,
_unpackKeyData(packet),
_respondToKeyData,
);
if (callback != null) {
channelBuffers.setListener(_kFlutterKeyDataChannel, _keyDataListener(callback, Zone.current));
} else {
channelBuffers.clearListener(_kFlutterKeyDataChannel);
}
}

// If this value changes, update the encoding code in the following files:
Expand Down
38 changes: 0 additions & 38 deletions lib/ui/window/platform_configuration.cc
Original file line number Diff line number Diff line change
Expand Up @@ -181,15 +181,6 @@ void GetPersistentIsolateData(Dart_NativeArguments args) {
persistent_isolate_data->GetSize()));
}

void RespondToKeyData(Dart_Handle window, int response_id, bool handled) {
UIDartState::Current()->platform_configuration()->CompleteKeyDataResponse(
response_id, handled);
}

void _RespondToKeyData(Dart_NativeArguments args) {
tonic::DartCallStatic(&RespondToKeyData, args);
}

Dart_Handle ToByteData(const fml::Mapping& buffer) {
return tonic::DartByteData::Create(buffer.GetMapping(), buffer.GetSize());
}
Expand Down Expand Up @@ -360,13 +351,6 @@ void PlatformConfiguration::DispatchSemanticsAction(int32_t id,
args_handle}));
}

uint64_t PlatformConfiguration::RegisterKeyDataResponse(
KeyDataResponse callback) {
uint64_t response_id = next_key_response_id_++;
pending_key_responses_[response_id] = std::move(callback);
return response_id;
}

void PlatformConfiguration::BeginFrame(fml::TimePoint frameTime,
uint64_t frame_number) {
std::shared_ptr<tonic::DartState> dart_state =
Expand Down Expand Up @@ -444,27 +428,6 @@ void PlatformConfiguration::CompletePlatformMessageResponse(
response->Complete(std::make_unique<fml::DataMapping>(std::move(data)));
}

void PlatformConfiguration::CompleteKeyDataResponse(uint64_t response_id,
bool handled) {
if (response_id == 0) {
return;
}
auto it = pending_key_responses_.find(response_id);
FML_DCHECK(it != pending_key_responses_.end());
if (it == pending_key_responses_.end()) {
return;
}
KeyDataResponse callback = std::move(it->second);
pending_key_responses_.erase(it);
// The key result callback must be called on the platform thread. This is
// mainly because iOS needs to block the platform message loop with a nested
// loop to respond to key events synchronously, and if the callback is called
// from another thread, it won't stop the nested message loop, causing a
// deadlock.
UIDartState::Current()->GetTaskRunners().GetPlatformTaskRunner()->PostTask(
[handled, callback]() { callback(handled); });
}

Dart_Handle ComputePlatformResolvedLocale(Dart_Handle supportedLocalesHandle) {
std::vector<std::string> supportedLocales =
tonic::DartConverter<std::vector<std::string>>::FromDart(
Expand Down Expand Up @@ -495,7 +458,6 @@ void PlatformConfiguration::RegisterNatives(
true},
{"PlatformConfiguration_respondToPlatformMessage",
_RespondToPlatformMessage, 3, true},
{"PlatformConfiguration_respondToKeyData", _RespondToKeyData, 3, true},
{"PlatformConfiguration_render", Render, 3, true},
{"PlatformConfiguration_updateSemantics", UpdateSemantics, 2, true},
{"PlatformConfiguration_setIsolateDebugName", SetIsolateDebugName, 2,
Expand Down
40 changes: 0 additions & 40 deletions lib/ui/window/platform_configuration.h
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,6 @@ class FontCollection;
class PlatformMessage;
class Scene;

typedef std::function<void(bool /* handled */)> KeyDataResponse;

//--------------------------------------------------------------------------
/// @brief An enum for defining the different kinds of accessibility features
/// that can be enabled by the platform.
Expand Down Expand Up @@ -327,24 +325,6 @@ class PlatformConfiguration final {
SemanticsAction action,
fml::MallocMapping args);

//----------------------------------------------------------------------------
/// @brief Registers a callback to be invoked when the framework has
/// decided whether to handle an event. This callback originates
/// in the platform view and has been forwarded through the engine
/// to here.
///
/// This method will move and store the `callback`, associate it
/// with a self-incrementing identifier, the response ID, then
/// return the ID, which is typically used by
/// Window::DispatchKeyDataPacket.
///
/// @param[in] callback The callback to be registered.
///
/// @return The response ID to be associated with the callback. Using this
/// ID in CompleteKeyDataResponse will invoke the callback.
///
uint64_t RegisterKeyDataResponse(KeyDataResponse callback);

//----------------------------------------------------------------------------
/// @brief Notifies the framework that it is time to begin working on a
/// new frame previously scheduled via a call to
Expand Down Expand Up @@ -439,21 +419,6 @@ class PlatformConfiguration final {
///
void CompletePlatformMessageEmptyResponse(int response_id);

//----------------------------------------------------------------------------
/// @brief Responds to a previously registered key data message from the
/// framework to the engine.
///
/// For each response_id, this method should be called exactly
/// once. Responding to a response_id that has not been registered
/// or has been invoked will lead to a fatal error.
///
/// @param[in] response_id The unique id that identifies the original platform
/// message to respond to, created by
/// RegisterKeyDataResponse.
/// @param[in] handled Whether the key data is handled.
///
void CompleteKeyDataResponse(uint64_t response_id, bool handled);

private:
PlatformConfigurationClient* client_;
tonic::DartPersistentValue update_locales_;
Expand All @@ -462,7 +427,6 @@ class PlatformConfiguration final {
tonic::DartPersistentValue update_semantics_enabled_;
tonic::DartPersistentValue update_accessibility_features_;
tonic::DartPersistentValue dispatch_platform_message_;
tonic::DartPersistentValue dispatch_key_message_;
tonic::DartPersistentValue dispatch_semantics_action_;
tonic::DartPersistentValue begin_frame_;
tonic::DartPersistentValue draw_frame_;
Expand All @@ -474,10 +438,6 @@ class PlatformConfiguration final {
int next_response_id_ = 1;
std::unordered_map<int, fml::RefPtr<PlatformMessageResponse>>
pending_responses_;

// ID starts at 1 because an ID of 0 indicates that no response is expected.
uint64_t next_key_response_id_ = 1;
std::unordered_map<uint64_t, KeyDataResponse> pending_key_responses_;
};

} // namespace flutter
Expand Down
19 changes: 0 additions & 19 deletions lib/ui/window/window.cc
Original file line number Diff line number Diff line change
Expand Up @@ -36,25 +36,6 @@ void Window::DispatchPointerDataPacket(const PointerDataPacket& packet) {
library_.value(), "_dispatchPointerDataPacket", {data_handle}));
}

void Window::DispatchKeyDataPacket(const KeyDataPacket& packet,
uint64_t response_id) {
std::shared_ptr<tonic::DartState> dart_state = library_.dart_state().lock();
if (!dart_state) {
return;
}
tonic::DartState::Scope scope(dart_state);

const std::vector<uint8_t>& buffer = packet.data();
Dart_Handle data_handle =
tonic::DartByteData::Create(buffer.data(), buffer.size());
if (Dart_IsError(data_handle)) {
return;
}
tonic::LogIfError(
tonic::DartInvokeField(library_.value(), "_dispatchKeyData",
{data_handle, tonic::ToDart(response_id)}));
}

void Window::UpdateWindowMetrics(const ViewportMetrics& metrics) {
viewport_metrics_ = metrics;

Expand Down
8 changes: 0 additions & 8 deletions lib/ui/window/window.h
Original file line number Diff line number Diff line change
Expand Up @@ -31,14 +31,6 @@ class Window final {
// Dispatch a packet to the framework that indicates one or a few pointer
// events.
void DispatchPointerDataPacket(const PointerDataPacket& packet);
// Dispatch a packet to the framework that indicates a key event.
//
// The `response_id` is used to label the response of whether the key event
// is handled by the framework, typically the return value of
// PlatformConfiguration::RegisterKeyDataResponse.
// It should be used later in
// PlatformConfiguration::CompleteKeyDataResponse.
void DispatchKeyDataPacket(const KeyDataPacket& packet, uint64_t response_id);
void UpdateWindowMetrics(const ViewportMetrics& metrics);

private:
Expand Down
14 changes: 0 additions & 14 deletions runtime/runtime_controller.cc
Original file line number Diff line number Diff line change
Expand Up @@ -238,20 +238,6 @@ bool RuntimeController::DispatchPointerDataPacket(
return false;
}

bool RuntimeController::DispatchKeyDataPacket(const KeyDataPacket& packet,
KeyDataResponse callback) {
if (auto* platform_configuration = GetPlatformConfigurationIfAvailable()) {
TRACE_EVENT1("flutter", "RuntimeController::DispatchKeyDataPacket", "mode",
"basic");
uint64_t response_id =
platform_configuration->RegisterKeyDataResponse(std::move(callback));
platform_configuration->get_window(0)->DispatchKeyDataPacket(packet,
response_id);
return true;
}
return false;
}

bool RuntimeController::DispatchSemanticsAction(int32_t id,
SemanticsAction action,
fml::MallocMapping args) {
Expand Down
14 changes: 0 additions & 14 deletions runtime/runtime_controller.h
Original file line number Diff line number Diff line change
Expand Up @@ -385,20 +385,6 @@ class RuntimeController : public PlatformConfigurationClient {
///
bool DispatchPointerDataPacket(const PointerDataPacket& packet);

//----------------------------------------------------------------------------
/// @brief Dispatch the specified pointer data message to the running
/// root isolate.
///
/// @param[in] packet The key data message to dispatch to the isolate.
/// @param[in] callback Called when the framework has decided whether
/// to handle this key data.
///
/// @return If the key data message was dispatched. This may fail is
/// an isolate is not running.
///
bool DispatchKeyDataPacket(const KeyDataPacket& packet,
KeyDataResponse callback);

//----------------------------------------------------------------------------
/// @brief Dispatch the semantics action to the specified accessibility
/// node.
Expand Down
8 changes: 0 additions & 8 deletions shell/common/engine.cc
Original file line number Diff line number Diff line change
Expand Up @@ -434,14 +434,6 @@ void Engine::DispatchPointerDataPacket(
pointer_data_dispatcher_->DispatchPacket(std::move(packet), trace_flow_id);
}

void Engine::DispatchKeyDataPacket(std::unique_ptr<KeyDataPacket> packet,
KeyDataResponse callback) {
TRACE_EVENT0("flutter", "Engine::DispatchKeyDataPacket");
if (runtime_controller_) {
runtime_controller_->DispatchKeyDataPacket(*packet, std::move(callback));
}
}

void Engine::DispatchSemanticsAction(int id,
SemanticsAction action,
fml::MallocMapping args) {
Expand Down
15 changes: 0 additions & 15 deletions shell/common/engine.h
Original file line number Diff line number Diff line change
Expand Up @@ -735,21 +735,6 @@ class Engine final : public RuntimeDelegate, PointerDataDispatcher::Delegate {
void DispatchPointerDataPacket(std::unique_ptr<PointerDataPacket> packet,
uint64_t trace_flow_id);

//----------------------------------------------------------------------------
/// @brief Notifies the engine that the embedder has sent it a key data
/// packet. A key data packet contains one key event. This call
/// originates in the platform view and the shell has forwarded
/// the same to the engine on the UI task runner here. The engine
/// will decide whether to handle this event, and send the
/// result using `callback`, which will be called exactly once.
///
/// @param[in] packet The key data packet.
/// @param[in] callback Called when the framework has decided whether
/// to handle this key data.
///
void DispatchKeyDataPacket(std::unique_ptr<KeyDataPacket> packet,
KeyDataResponse callback);

//----------------------------------------------------------------------------
/// @brief Notifies the engine that the embedder encountered an
/// accessibility related action on the specified node. This call
Expand Down
6 changes: 0 additions & 6 deletions shell/common/platform_view.cc
Original file line number Diff line number Diff line change
Expand Up @@ -39,12 +39,6 @@ void PlatformView::DispatchPointerDataPacket(
pointer_data_packet_converter_.Convert(std::move(packet)));
}

void PlatformView::DispatchKeyDataPacket(std::unique_ptr<KeyDataPacket> packet,
KeyDataResponse callback) {
delegate_.OnPlatformViewDispatchKeyDataPacket(std::move(packet),
std::move(callback));
}

void PlatformView::DispatchSemanticsAction(int32_t id,
SemanticsAction action,
fml::MallocMapping args) {
Expand Down
25 changes: 0 additions & 25 deletions shell/common/platform_view.h
Original file line number Diff line number Diff line change
Expand Up @@ -127,20 +127,6 @@ class PlatformView {
virtual void OnPlatformViewDispatchPointerDataPacket(
std::unique_ptr<PointerDataPacket> packet) = 0;

//--------------------------------------------------------------------------
/// @brief Notifies the delegate that the platform view has encountered
/// a key event. This key event and the callback needs to be
/// forwarded to the running root isolate hosted by the engine
/// on the UI thread.
///
/// @param[in] packet The key data packet containing one key event.
/// @param[in] callback Called when the framework has decided whether
/// to handle this key data.
///
virtual void OnPlatformViewDispatchKeyDataPacket(
std::unique_ptr<KeyDataPacket> packet,
std::function<void(bool /* handled */)> callback) = 0;

//--------------------------------------------------------------------------
/// @brief Notifies the delegate that the platform view has encountered
/// an accessibility related action on the specified node. This
Expand Down Expand Up @@ -591,17 +577,6 @@ class PlatformView {
///
void DispatchPointerDataPacket(std::unique_ptr<PointerDataPacket> packet);

//----------------------------------------------------------------------------
/// @brief Dispatches key events from the embedder to the framework. Each
/// key data packet contains one physical event and multiple
/// logical key events. Each call to this method wakes up the UI
/// thread.
///
/// @param[in] packet The key data packet to dispatch to the framework.
///
void DispatchKeyDataPacket(std::unique_ptr<KeyDataPacket> packet,
Delegate::KeyDataResponse callback);

//--------------------------------------------------------------------------
/// @brief Used by the embedder to specify a texture that it wants the
/// rasterizer to composite within the Flutter layer tree. All
Expand Down
Loading

0 comments on commit d8a3b06

Please sign in to comment.