forked from flutter/engine
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Emit viewRefFocused events in the flutter runner. (flutter#26791)
Fulfill HostView.getCurrentFocusState and HostView.getNextFocusState platform message requests to deliver focus-related events to dart code. Consolidate focus functionality (including requestFocus handling) to a new "FocusDelegate" class. See https://cs.opensource.google/fuchsia/fuchsia/+/main:sdk/fidl/fuchsia.ui.views/view_ref_focused.fidl for details about focus state transitions and their meanings. See https://fxbug.dev/77481.
- Loading branch information
1 parent
90105f3
commit 9d4d73e
Showing
13 changed files
with
652 additions
and
164 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,94 @@ | ||
// Copyright 2013 The Flutter 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 <ostream> | ||
|
||
#include "focus_delegate.h" | ||
|
||
namespace flutter_runner { | ||
|
||
void FocusDelegate::WatchLoop(std::function<void(bool)> callback) { | ||
if (watch_loop_) { | ||
FML_LOG(ERROR) << "FocusDelegate::WatchLoop() cannot be called twice."; | ||
return; | ||
} | ||
|
||
watch_loop_ = [this, callback = std::move(callback)](auto focus_state) { | ||
callback(is_focused_ = focus_state.focused()); | ||
if (next_focus_request_) { | ||
CompleteCurrentFocusState(std::exchange(next_focus_request_, nullptr)); | ||
} | ||
view_ref_focused_->Watch(watch_loop_); | ||
}; | ||
view_ref_focused_->Watch(watch_loop_); | ||
} | ||
|
||
void FocusDelegate::CompleteCurrentFocusState( | ||
fml::RefPtr<flutter::PlatformMessageResponse> response) { | ||
std::string result(is_focused_ ? "[true]" : "[false]"); | ||
response->Complete(std::make_unique<fml::DataMapping>( | ||
std::vector<uint8_t>(result.begin(), result.end()))); | ||
} | ||
|
||
void FocusDelegate::CompleteNextFocusState( | ||
fml::RefPtr<flutter::PlatformMessageResponse> response) { | ||
if (next_focus_request_) { | ||
FML_LOG(ERROR) << "An outstanding PlatformMessageResponse already exists " | ||
"for the next focus state!"; | ||
response->CompleteEmpty(); | ||
} else { | ||
next_focus_request_ = std::move(response); | ||
} | ||
} | ||
|
||
void FocusDelegate::RequestFocus( | ||
rapidjson::Value request, | ||
fml::RefPtr<flutter::PlatformMessageResponse> response) { | ||
auto args_it = request.FindMember("args"); | ||
if (args_it == request.MemberEnd() || !args_it->value.IsObject()) { | ||
FML_LOG(ERROR) << "No arguments found."; | ||
return; | ||
} | ||
const auto& args = args_it->value; | ||
|
||
auto view_ref = args.FindMember("viewRef"); | ||
if (!view_ref->value.IsUint64()) { | ||
FML_LOG(ERROR) << "Argument 'viewRef' is not a int64"; | ||
return; | ||
} | ||
|
||
zx_handle_t handle = view_ref->value.GetUint64(); | ||
zx_handle_t out_handle; | ||
zx_status_t status = | ||
zx_handle_duplicate(handle, ZX_RIGHT_SAME_RIGHTS, &out_handle); | ||
if (status != ZX_OK) { | ||
FML_LOG(ERROR) << "Argument 'viewRef' is not valid"; | ||
return; | ||
} | ||
auto ref = fuchsia::ui::views::ViewRef({ | ||
.reference = zx::eventpair(out_handle), | ||
}); | ||
focuser_->RequestFocus( | ||
std::move(ref), | ||
[view_ref = view_ref->value.GetUint64(), response = std::move(response)]( | ||
fuchsia::ui::views::Focuser_RequestFocus_Result result) { | ||
if (!response.get()) { | ||
return; | ||
} | ||
int result_code = | ||
result.is_err() | ||
? static_cast< | ||
std::underlying_type_t<fuchsia::ui::views::Error>>( | ||
result.err()) | ||
: 0; | ||
|
||
std::ostringstream out; | ||
out << "[" << result_code << "]"; | ||
std::string output = out.str(); | ||
response->Complete(std::make_unique<fml::DataMapping>( | ||
std::vector<uint8_t>(output.begin(), output.end()))); | ||
}); | ||
} | ||
|
||
} // namespace flutter_runner |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,66 @@ | ||
// Copyright 2013 The Flutter 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 FLUTTER_SHELL_PLATFORM_FUCHSIA_FOCUS_DELEGATE_H_ | ||
#define FLUTTER_SHELL_PLATFORM_FUCHSIA_FOCUS_DELEGATE_H_ | ||
|
||
#include <fuchsia/sys/cpp/fidl.h> | ||
#include <fuchsia/ui/views/cpp/fidl.h> | ||
|
||
#include "flutter/fml/macros.h" | ||
#include "flutter/lib/ui/window/platform_message.h" | ||
#include "third_party/rapidjson/include/rapidjson/document.h" | ||
|
||
namespace flutter_runner { | ||
|
||
class FocusDelegate { | ||
public: | ||
FocusDelegate(fidl::InterfaceHandle<fuchsia::ui::views::ViewRefFocused> | ||
view_ref_focused, | ||
fidl::InterfaceHandle<fuchsia::ui::views::Focuser> focuser) | ||
: view_ref_focused_(view_ref_focused.Bind()), focuser_(focuser.Bind()) {} | ||
|
||
virtual ~FocusDelegate() = default; | ||
|
||
/// Continuously watches the host viewRef for focus events, invoking a | ||
/// callback each time. | ||
/// | ||
/// This can only be called once. | ||
virtual void WatchLoop(std::function<void(bool)> callback); | ||
|
||
/// Completes the platform message request with the FocusDelegate's most | ||
/// recent focus state. | ||
virtual void CompleteCurrentFocusState( | ||
fml::RefPtr<flutter::PlatformMessageResponse> response); | ||
|
||
/// Completes the platform message request with the FocusDelegate's next focus | ||
/// state. | ||
/// | ||
/// Only one outstanding request may exist at a time. Any others will be | ||
/// completed empty. | ||
virtual void CompleteNextFocusState( | ||
fml::RefPtr<flutter::PlatformMessageResponse> response); | ||
|
||
/// Completes a platform message request by attempting to give focus for a | ||
/// given viewRef. | ||
virtual void RequestFocus( | ||
rapidjson::Value request, | ||
fml::RefPtr<flutter::PlatformMessageResponse> response); | ||
|
||
private: | ||
fuchsia::ui::views::ViewRefFocusedPtr view_ref_focused_; | ||
fuchsia::ui::views::FocuserPtr focuser_; | ||
|
||
std::function<void(fuchsia::ui::views::FocusState)> watch_loop_; | ||
bool is_focused_; | ||
fml::RefPtr<flutter::PlatformMessageResponse> next_focus_request_; | ||
|
||
void Complete(fml::RefPtr<flutter::PlatformMessageResponse> response, | ||
bool value); | ||
|
||
FML_DISALLOW_COPY_AND_ASSIGN(FocusDelegate); | ||
}; | ||
|
||
} // namespace flutter_runner | ||
#endif // FLUTTER_SHELL_PLATFORM_FUCHSIA_FOCUS_DELEGATE_H_ |
Oops, something went wrong.