提交 400e3b00 编写于 作者: F Filip Filmar 提交者: Chinmay Garde

Wires the locale provided by Fuchsia. (#13045)

The FIDL service `fuchsia.intl.PropertyProvider` is a service that
the flutter runner can use to obtain information on system preferred
locales.

This change sends a platform message "setLocale" on the channel
"flutter/localization", based on the values provided by the above
mentioned FIDL service.

Credit: most of this was initially written by @kpozin; I ported it
to out-of-tree flutter engine.

Tested:

1. Compile and publish the unit tests package as shown in
   the script below.
2. In a Fuchsia repository (pointed to by `$FUCHSIA_DIR`), run
   `fx serve`
3. `fx shell run fuchsia-pkg://fuchsia.com/flutter_runner_tests#meta/flutter_runner_tests.cmx`

The script used to update the unit tests.

```bash

set -x

FLUTTER_ENGINE_DIR="${FLUTTER_ENGINE_DIR:-$HOME/fx/flutter/engine/src}"
readonly OUT_DIR="${FLUTTER_ENGINE_DIR}/out"

(
  cd ${FLUTTER_ENGINE_DIR}
  ./flutter/tools/gn --fuchsia --fuchsia-cpu x64 --unoptimized
  ninja -j 100 -C "${OUT_DIR}/fuchsia_debug_unopt_x64"
  cp "${OUT_DIR}/compile_commands.json" "${FLUTTER_ENGINE_DIR}"

  echo "Publishing the tests package"
  "${FLUTTER_ENGINE_DIR}/fuchsia/sdk/linux/tools/pm" publish \
    -a -r $FUCHSIA_DIR/out/release/amber-files \
    -f "${FLUTTER_ENGINE_DIR}/out/fuchsia_debug_unopt_x64/flutter_runner_tests-0.far"
)
```
上级 1663ac9e
......@@ -951,6 +951,9 @@ FILE: ../../../flutter/shell/platform/fuchsia/flutter/compositor_context.h
FILE: ../../../flutter/shell/platform/fuchsia/flutter/engine.cc
FILE: ../../../flutter/shell/platform/fuchsia/flutter/engine.h
FILE: ../../../flutter/shell/platform/fuchsia/flutter/flutter_runner_fakes.h
FILE: ../../../flutter/shell/platform/fuchsia/flutter/fuchsia_intl.cc
FILE: ../../../flutter/shell/platform/fuchsia/flutter/fuchsia_intl.h
FILE: ../../../flutter/shell/platform/fuchsia/flutter/fuchsia_intl_unittest.cc
FILE: ../../../flutter/shell/platform/fuchsia/flutter/isolate_configurator.cc
FILE: ../../../flutter/shell/platform/fuchsia/flutter/isolate_configurator.h
FILE: ../../../flutter/shell/platform/fuchsia/flutter/kernel/extract_far.dart
......
......@@ -256,6 +256,9 @@ executable("flutter_runner_unittests") {
"accessibility_bridge.h",
"accessibility_bridge_unittest.cc",
"flutter_runner_fakes.h",
"fuchsia_intl.cc",
"fuchsia_intl.h",
"fuchsia_intl_unittest.cc",
"logging.h",
"platform_view.cc",
"platform_view.h",
......@@ -298,6 +301,13 @@ fuchsia_archive("flutter_runner_tests") {
binary = "$target_name"
resources = [
{
path = rebase_path("//third_party/icu/common/icudtl.dat")
dest = "icudtl.dat"
},
]
meta_dir = "$flutter_root/shell/platform/fuchsia/flutter/meta"
libraries = common_libs
......
......@@ -5,6 +5,7 @@
#include "engine.h"
#include <lib/async/cpp/task.h>
#include <zircon/status.h>
#include <sstream>
#include "flutter/common/task_runners.h"
......@@ -14,6 +15,7 @@
#include "flutter/runtime/dart_vm_lifecycle.h"
#include "flutter/shell/common/rasterizer.h"
#include "flutter/shell/common/run_configuration.h"
#include "fuchsia_intl.h"
#include "platform_view.h"
#include "runtime/dart/utils/files.h"
#include "task_runner_adapter.h"
......@@ -39,6 +41,13 @@ static void UpdateNativeThreadLabelNames(const std::string& label,
set_thread_name(runners.GetIOTaskRunner(), label, ".io");
}
static fml::RefPtr<flutter::PlatformMessage> MakeLocalizationPlatformMessage(
const fuchsia::intl::Profile& intl_profile) {
return fml::MakeRefCounted<flutter::PlatformMessage>(
"flutter/localization", MakeLocalizationPlatformMessageData(intl_profile),
nullptr);
}
Engine::Engine(Delegate& delegate,
std::string thread_label,
std::shared_ptr<sys::ServiceDirectory> svc,
......@@ -110,8 +119,7 @@ Engine::Engine(Delegate& delegate,
on_create_platform_view = fml::MakeCopyable(
[debug_label = thread_label_,
view_ref_control = std::move(view_ref_control),
view_ref = std::move(view_ref),
runner_services = std::move(runner_services),
view_ref = std::move(view_ref), runner_services,
parent_environment_service_provider =
std::move(parent_environment_service_provider),
session_listener_request = std::move(session_listener_request),
......@@ -255,6 +263,49 @@ Engine::Engine(Delegate& delegate,
// notification. Fire one eagerly.
shell_->GetPlatformView()->NotifyCreated();
// Connect to the intl property provider.
{
intl_property_provider_.set_error_handler([](zx_status_t status) {
FML_LOG(ERROR) << "Failed to connect to "
<< fuchsia::intl::PropertyProvider::Name_ << ": "
<< zx_status_get_string(status);
});
// Note that we're using the runner's services, not the component's.
// Flutter locales should be updated regardless of whether the component has
// direct access to the fuchsia.intl.PropertyProvider service.
ZX_ASSERT(runner_services->Connect(intl_property_provider_.NewRequest()) ==
ZX_OK);
auto get_profile_callback = [flutter_runner_engine =
weak_factory_.GetWeakPtr()](
const fuchsia::intl::Profile& profile) {
if (!flutter_runner_engine) {
return;
}
if (!profile.has_locales()) {
FML_LOG(WARNING) << "Got intl Profile without locales";
}
auto message = MakeLocalizationPlatformMessage(profile);
FML_VLOG(-1) << "Sending LocalizationPlatformMessage";
flutter_runner_engine->shell_->GetPlatformView()->DispatchPlatformMessage(
message);
};
FML_VLOG(-1) << "Requesting intl Profile";
// Make the initial request
intl_property_provider_->GetProfile(get_profile_callback);
// And register for changes
intl_property_provider_.events().OnChange = [this, runner_services,
get_profile_callback]() {
FML_VLOG(-1) << fuchsia::intl::PropertyProvider::Name_ << ": OnChange";
runner_services->Connect(intl_property_provider_.NewRequest());
intl_property_provider_->GetProfile(get_profile_callback);
};
}
// Launch the engine in the appropriate configuration.
auto run_configuration = flutter::RunConfiguration::InferFromSettings(
settings_, task_runners.GetIOTaskRunner());
......
......@@ -5,6 +5,7 @@
#ifndef FLUTTER_SHELL_PLATFORM_FUCHSIA_ENGINE_H_
#define FLUTTER_SHELL_PLATFORM_FUCHSIA_ENGINE_H_
#include <fuchsia/intl/cpp/fidl.h>
#include <fuchsia/io/cpp/fidl.h>
#include <fuchsia/ui/gfx/cpp/fidl.h>
#include <fuchsia/ui/views/cpp/fidl.h>
......@@ -58,6 +59,8 @@ class Engine final {
std::unique_ptr<flutter::Shell> shell_;
zx::event vsync_event_;
fml::WeakPtrFactory<Engine> weak_factory_;
// A stub for the FIDL protocol fuchsia.intl.PropertyProvider.
fuchsia::intl::PropertyProviderPtr intl_property_provider_;
void OnMainIsolateStart();
......
......@@ -50,6 +50,8 @@ template("flutter_runner") {
"compositor_context.h",
"engine.cc",
"engine.h",
"fuchsia_intl.cc",
"fuchsia_intl.h",
"isolate_configurator.cc",
"isolate_configurator.h",
"logging.h",
......@@ -111,6 +113,7 @@ template("flutter_runner") {
"$fuchsia_sdk_root/fidl:fuchsia.accessibility.semantics",
"$fuchsia_sdk_root/fidl:fuchsia.fonts",
"$fuchsia_sdk_root/fidl:fuchsia.images",
"$fuchsia_sdk_root/fidl:fuchsia.intl",
"$fuchsia_sdk_root/fidl:fuchsia.io",
"$fuchsia_sdk_root/fidl:fuchsia.modular",
"$fuchsia_sdk_root/fidl:fuchsia.sys",
......
// 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 "fuchsia_intl.h"
#include <sstream>
#include <string>
#include <vector>
#include "loop.h"
#include "rapidjson/document.h"
#include "rapidjson/stringbuffer.h"
#include "rapidjson/writer.h"
#include "runner.h"
#include "runtime/dart/utils/tempfs.h"
#include "third_party/icu/source/common/unicode/bytestream.h"
#include "third_party/icu/source/common/unicode/errorcode.h"
#include "third_party/icu/source/common/unicode/locid.h"
#include "third_party/icu/source/common/unicode/strenum.h"
#include "third_party/icu/source/common/unicode/stringpiece.h"
#include "third_party/icu/source/common/unicode/uloc.h"
using icu::Locale;
namespace flutter_runner {
using fuchsia::intl::Profile;
std::vector<uint8_t> MakeLocalizationPlatformMessageData(
const Profile& intl_profile) {
rapidjson::Document document;
auto& allocator = document.GetAllocator();
document.SetObject();
document.AddMember("method", "setLocale", allocator);
rapidjson::Value args(rapidjson::kArrayType);
for (const auto& locale_id : intl_profile.locales()) {
UErrorCode error_code = U_ZERO_ERROR;
icu::Locale locale = icu::Locale::forLanguageTag(locale_id.id, error_code);
if (U_FAILURE(error_code)) {
FML_LOG(ERROR) << "Error parsing locale ID \"" << locale_id.id << "\"";
continue;
}
args.PushBack(rapidjson::Value().SetString(locale.getLanguage(), allocator),
allocator);
auto country = locale.getCountry() != nullptr ? locale.getCountry() : "";
args.PushBack(rapidjson::Value().SetString(country, allocator), allocator);
auto script = locale.getScript() != nullptr ? locale.getScript() : "";
args.PushBack(rapidjson::Value().SetString(script, allocator), allocator);
std::string variant =
locale.getVariant() != nullptr ? locale.getVariant() : "";
// ICU4C capitalizes the variant for backward compatibility, even though
// the preferred form is lowercase. So we lowercase here.
std::transform(begin(variant), end(variant), begin(variant),
[](unsigned char c) { return std::tolower(c); });
args.PushBack(rapidjson::Value().SetString(variant, allocator), allocator);
}
document.AddMember("args", args, allocator);
rapidjson::StringBuffer buffer;
rapidjson::Writer<rapidjson::StringBuffer> writer(buffer);
document.Accept(writer);
auto data = reinterpret_cast<const uint8_t*>(buffer.GetString());
return std::vector<uint8_t>(data, data + buffer.GetSize());
}
} // namespace flutter_runner
// 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_FUCHSIA_INTL_H_
#define FLUTTER_SHELL_PLATFORM_FUCHSIA_FUCHSIA_INTL_H_
#include <fuchsia/intl/cpp/fidl.h>
namespace flutter_runner {
// Make a byte vector containing the JSON string used for a localization
// PlatformMessage, using the locale list in the given Profile.
//
// This method does not return a `fml::RefPtr<flutter::PlatformMessage>` for
// testing convenience; that would require an unreasonably large set of
// dependencies for the unit tests.
std::vector<uint8_t> MakeLocalizationPlatformMessageData(
const fuchsia::intl::Profile& intl_profile);
} // namespace flutter_runner
#endif // FLUTTER_SHELL_PLATFORM_FUCHSIA_FUCHSIA_INTL_H_
// 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 <fuchsia/intl/cpp/fidl.h>
#include <gtest/gtest.h>
#include "flutter/fml/icu_util.h"
#include "fuchsia_intl.h"
using fuchsia::intl::CalendarId;
using fuchsia::intl::LocaleId;
using fuchsia::intl::Profile;
using fuchsia::intl::TemperatureUnit;
using fuchsia::intl::TimeZoneId;
namespace flutter_runner {
namespace {
class FuchsiaIntlTest : public testing::Test {
public:
static void SetUpTestCase() {
testing::Test::SetUpTestCase();
// The icudtl data must be present as a resource in the package for this
// load to succeed.
fml::icu::InitializeICU("/pkg/data/icudtl.dat");
}
};
TEST_F(FuchsiaIntlTest, MakeLocalizationPlatformMessageData_SimpleLocale) {
Profile profile{};
profile.set_locales({LocaleId{.id = "en-US"}});
const std::string expected =
R"({"method":"setLocale","args":["en","US","",""]})";
const auto actual = MakeLocalizationPlatformMessageData(profile);
ASSERT_EQ(expected, std::string(actual.begin(), actual.end()));
}
TEST_F(FuchsiaIntlTest, MakeLocalizationPlatformMessageData_OneLocale) {
Profile profile{};
profile
.set_locales({LocaleId{.id = "en-US-u-ca-gregory-fw-sun-hc-h12-ms-"
"ussystem-nu-latn-tz-usnyc"}})
.set_calendars({CalendarId{.id = "und-u-gregory"}})
.set_time_zones({TimeZoneId{.id = "America/New_York"}})
.set_temperature_unit(TemperatureUnit::FAHRENHEIT);
const std::string expected =
R"({"method":"setLocale","args":["en","US","",""]})";
const auto actual = MakeLocalizationPlatformMessageData(profile);
ASSERT_EQ(expected, std::string(actual.begin(), actual.end()));
}
TEST_F(FuchsiaIntlTest, MakeLocalizationPlatformMessageData_MultipleLocales) {
Profile profile{};
profile
.set_locales({LocaleId{.id = "en-US-u-ca-gregory-fw-sun-hc-h12-ms-"
"ussystem-nu-latn-tz-usnyc"},
LocaleId{.id = "sl-Latn-IT-nedis"},
LocaleId{.id = "zh-Hans"}, LocaleId{.id = "sr-Cyrl-CS"}})
.set_calendars({CalendarId{.id = "und-u-gregory"}})
.set_time_zones({TimeZoneId{.id = "America/New_York"}})
.set_temperature_unit(TemperatureUnit::FAHRENHEIT);
const std::string expected =
R"({"method":"setLocale","args":["en","US","","","sl","IT","Latn","nedis",)"
R"("zh","","Hans","","sr","CS","Cyrl",""]})";
const auto actual = MakeLocalizationPlatformMessageData(profile);
ASSERT_EQ(expected, std::string(actual.begin(), actual.end()));
}
} // namespace
} // namespace flutter_runner
......@@ -11,10 +11,11 @@
"services": [
"fuchsia.accessibility.SettingsManager",
"fuchsia.accessibility.semantics.SemanticsManager",
"fuchsia.device.NameProvider",
"fuchsia.deprecatedtimezone.Timezone",
"fuchsia.device.NameProvider",
"fuchsia.feedback.CrashReporter",
"fuchsia.fonts.Provider",
"fuchsia.intl.PropertyProvider",
"fuchsia.net.NameLookup",
"fuchsia.netstack.Netstack",
"fuchsia.posix.socket.Provider",
......
......@@ -11,10 +11,11 @@
"services": [
"fuchsia.accessibility.SettingsManager",
"fuchsia.accessibility.semantics.SemanticsManager",
"fuchsia.device.NameProvider",
"fuchsia.deprecatedtimezone.Timezone",
"fuchsia.device.NameProvider",
"fuchsia.feedback.CrashReporter",
"fuchsia.fonts.Provider",
"fuchsia.intl.PropertyProvider",
"fuchsia.net.NameLookup",
"fuchsia.netstack.Netstack",
"fuchsia.posix.socket.Provider",
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册