Skip to content
This repository was archived by the owner on Feb 25, 2025. It is now read-only.

Commit b9d6479

Browse files
committed
Wires the locale provided by Fuchsia.
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" ) ```
1 parent 73c6a4a commit b9d6479

File tree

10 files changed

+243
-4
lines changed

10 files changed

+243
-4
lines changed

ci/licenses_golden/licenses_flutter

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -951,6 +951,9 @@ FILE: ../../../flutter/shell/platform/fuchsia/flutter/compositor_context.h
951951
FILE: ../../../flutter/shell/platform/fuchsia/flutter/engine.cc
952952
FILE: ../../../flutter/shell/platform/fuchsia/flutter/engine.h
953953
FILE: ../../../flutter/shell/platform/fuchsia/flutter/flutter_runner_fakes.h
954+
FILE: ../../../flutter/shell/platform/fuchsia/flutter/fuchsia_intl.cc
955+
FILE: ../../../flutter/shell/platform/fuchsia/flutter/fuchsia_intl.h
956+
FILE: ../../../flutter/shell/platform/fuchsia/flutter/fuchsia_intl_unittest.cc
954957
FILE: ../../../flutter/shell/platform/fuchsia/flutter/isolate_configurator.cc
955958
FILE: ../../../flutter/shell/platform/fuchsia/flutter/isolate_configurator.h
956959
FILE: ../../../flutter/shell/platform/fuchsia/flutter/kernel/extract_far.dart

shell/platform/fuchsia/flutter/BUILD.gn

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -256,6 +256,9 @@ executable("flutter_runner_unittests") {
256256
"accessibility_bridge.h",
257257
"accessibility_bridge_unittest.cc",
258258
"flutter_runner_fakes.h",
259+
"fuchsia_intl.cc",
260+
"fuchsia_intl.h",
261+
"fuchsia_intl_unittest.cc",
259262
"logging.h",
260263
"platform_view.cc",
261264
"platform_view.h",
@@ -298,6 +301,13 @@ fuchsia_archive("flutter_runner_tests") {
298301

299302
binary = "$target_name"
300303

304+
resources = [
305+
{
306+
path = rebase_path("//third_party/icu/common/icudtl.dat")
307+
dest = "icudtl.dat"
308+
},
309+
]
310+
301311
meta_dir = "$flutter_root/shell/platform/fuchsia/flutter/meta"
302312

303313
libraries = common_libs

shell/platform/fuchsia/flutter/engine.cc

Lines changed: 53 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
#include "engine.h"
66

77
#include <lib/async/cpp/task.h>
8+
#include <zircon/status.h>
89
#include <sstream>
910

1011
#include "flutter/common/task_runners.h"
@@ -14,6 +15,7 @@
1415
#include "flutter/runtime/dart_vm_lifecycle.h"
1516
#include "flutter/shell/common/rasterizer.h"
1617
#include "flutter/shell/common/run_configuration.h"
18+
#include "fuchsia_intl.h"
1719
#include "platform_view.h"
1820
#include "runtime/dart/utils/files.h"
1921
#include "task_runner_adapter.h"
@@ -39,6 +41,13 @@ static void UpdateNativeThreadLabelNames(const std::string& label,
3941
set_thread_name(runners.GetIOTaskRunner(), label, ".io");
4042
}
4143

44+
static fml::RefPtr<flutter::PlatformMessage> MakeLocalizationPlatformMessage(
45+
const fuchsia::intl::Profile& intl_profile) {
46+
return fml::MakeRefCounted<flutter::PlatformMessage>(
47+
"flutter/localization", MakeLocalizationPlatformMessageData(intl_profile),
48+
nullptr);
49+
}
50+
4251
Engine::Engine(Delegate& delegate,
4352
std::string thread_label,
4453
std::shared_ptr<sys::ServiceDirectory> svc,
@@ -110,8 +119,7 @@ Engine::Engine(Delegate& delegate,
110119
on_create_platform_view = fml::MakeCopyable(
111120
[debug_label = thread_label_,
112121
view_ref_control = std::move(view_ref_control),
113-
view_ref = std::move(view_ref),
114-
runner_services = std::move(runner_services),
122+
view_ref = std::move(view_ref), runner_services,
115123
parent_environment_service_provider =
116124
std::move(parent_environment_service_provider),
117125
session_listener_request = std::move(session_listener_request),
@@ -256,6 +264,49 @@ Engine::Engine(Delegate& delegate,
256264
// notification. Fire one eagerly.
257265
shell_->GetPlatformView()->NotifyCreated();
258266

267+
// Connect to the intl property provider.
268+
{
269+
intl_property_provider_.set_error_handler([](zx_status_t status) {
270+
FML_LOG(ERROR) << "Failed to connect to "
271+
<< fuchsia::intl::PropertyProvider::Name_ << ": "
272+
<< zx_status_get_string(status);
273+
});
274+
275+
// Note that we're using the runner's services, not the component's.
276+
// Flutter locales should be updated regardless of whether the component has
277+
// direct access to the fuchsia.intl.PropertyProvider service.
278+
ZX_ASSERT(runner_services->Connect(intl_property_provider_.NewRequest()) ==
279+
ZX_OK);
280+
281+
auto get_profile_callback = [flutter_runner_engine =
282+
weak_factory_.GetWeakPtr()](
283+
const fuchsia::intl::Profile& profile) {
284+
if (!flutter_runner_engine) {
285+
return;
286+
}
287+
if (!profile.has_locales()) {
288+
FML_LOG(WARNING) << "Got intl Profile without locales";
289+
}
290+
auto message = MakeLocalizationPlatformMessage(profile);
291+
FML_VLOG(-1) << "Sending LocalizationPlatformMessage";
292+
flutter_runner_engine->shell_->GetPlatformView()->DispatchPlatformMessage(
293+
message);
294+
};
295+
296+
FML_VLOG(-1) << "Requesting intl Profile";
297+
298+
// Make the initial request
299+
intl_property_provider_->GetProfile(get_profile_callback);
300+
301+
// And register for changes
302+
intl_property_provider_.events().OnChange = [this, runner_services,
303+
get_profile_callback]() {
304+
FML_VLOG(-1) << fuchsia::intl::PropertyProvider::Name_ << ": OnChange";
305+
runner_services->Connect(intl_property_provider_.NewRequest());
306+
intl_property_provider_->GetProfile(get_profile_callback);
307+
};
308+
}
309+
259310
// Launch the engine in the appropriate configuration.
260311
auto run_configuration = flutter::RunConfiguration::InferFromSettings(
261312
settings_, task_runners.GetIOTaskRunner());

shell/platform/fuchsia/flutter/engine.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
#ifndef FLUTTER_SHELL_PLATFORM_FUCHSIA_ENGINE_H_
66
#define FLUTTER_SHELL_PLATFORM_FUCHSIA_ENGINE_H_
77

8+
#include <fuchsia/intl/cpp/fidl.h>
89
#include <fuchsia/io/cpp/fidl.h>
910
#include <fuchsia/ui/gfx/cpp/fidl.h>
1011
#include <fuchsia/ui/views/cpp/fidl.h>
@@ -58,6 +59,8 @@ class Engine final {
5859
std::unique_ptr<flutter::Shell> shell_;
5960
zx::event vsync_event_;
6061
fml::WeakPtrFactory<Engine> weak_factory_;
62+
// A stub for the FIDL protocol fuchsia.intl.PropertyProvider.
63+
fuchsia::intl::PropertyProviderPtr intl_property_provider_;
6164

6265
void OnMainIsolateStart();
6366

shell/platform/fuchsia/flutter/engine_flutter_runner.gni

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,8 @@ template("flutter_runner") {
5050
"compositor_context.h",
5151
"engine.cc",
5252
"engine.h",
53+
"fuchsia_intl.cc",
54+
"fuchsia_intl.h",
5355
"isolate_configurator.cc",
5456
"isolate_configurator.h",
5557
"logging.h",
@@ -111,6 +113,7 @@ template("flutter_runner") {
111113
"$fuchsia_sdk_root/fidl:fuchsia.accessibility.semantics",
112114
"$fuchsia_sdk_root/fidl:fuchsia.fonts",
113115
"$fuchsia_sdk_root/fidl:fuchsia.images",
116+
"$fuchsia_sdk_root/fidl:fuchsia.intl",
114117
"$fuchsia_sdk_root/fidl:fuchsia.io",
115118
"$fuchsia_sdk_root/fidl:fuchsia.modular",
116119
"$fuchsia_sdk_root/fidl:fuchsia.sys",
Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
// Copyright 2013 The Flutter Authors. All rights reserved.
2+
// Use of this source code is governed by a BSD-style license that can be
3+
// found in the LICENSE file.
4+
5+
#include "fuchsia_intl.h"
6+
7+
#include <sstream>
8+
#include <string>
9+
#include <vector>
10+
11+
#include "loop.h"
12+
#include "rapidjson/document.h"
13+
#include "rapidjson/stringbuffer.h"
14+
#include "rapidjson/writer.h"
15+
#include "runner.h"
16+
#include "runtime/dart/utils/tempfs.h"
17+
#include "third_party/icu/source/common/unicode/bytestream.h"
18+
#include "third_party/icu/source/common/unicode/errorcode.h"
19+
#include "third_party/icu/source/common/unicode/locid.h"
20+
#include "third_party/icu/source/common/unicode/strenum.h"
21+
#include "third_party/icu/source/common/unicode/stringpiece.h"
22+
#include "third_party/icu/source/common/unicode/uloc.h"
23+
24+
using icu::Locale;
25+
26+
namespace flutter_runner {
27+
28+
using fuchsia::intl::Profile;
29+
30+
std::vector<uint8_t> MakeLocalizationPlatformMessageData(
31+
const Profile& intl_profile) {
32+
rapidjson::Document document;
33+
auto& allocator = document.GetAllocator();
34+
document.SetObject();
35+
document.AddMember("method", "setLocale", allocator);
36+
rapidjson::Value args(rapidjson::kArrayType);
37+
38+
for (const auto& locale_id : intl_profile.locales()) {
39+
UErrorCode error_code = U_ZERO_ERROR;
40+
icu::Locale locale = icu::Locale::forLanguageTag(locale_id.id, error_code);
41+
if (U_FAILURE(error_code)) {
42+
FML_LOG(ERROR) << "Error parsing locale ID \"" << locale_id.id << "\"";
43+
continue;
44+
}
45+
args.PushBack(rapidjson::Value().SetString(locale.getLanguage(), allocator),
46+
allocator);
47+
48+
auto country = locale.getCountry() != nullptr ? locale.getCountry() : "";
49+
args.PushBack(rapidjson::Value().SetString(country, allocator), allocator);
50+
51+
auto script = locale.getScript() != nullptr ? locale.getScript() : "";
52+
args.PushBack(rapidjson::Value().SetString(script, allocator), allocator);
53+
54+
std::string variant =
55+
locale.getVariant() != nullptr ? locale.getVariant() : "";
56+
// ICU4C capitalizes the variant for backward compatibility, even though
57+
// the preferred form is lowercase. So we lowercase here.
58+
std::transform(begin(variant), end(variant), begin(variant),
59+
[](unsigned char c) { return std::tolower(c); });
60+
args.PushBack(rapidjson::Value().SetString(variant, allocator), allocator);
61+
}
62+
63+
document.AddMember("args", args, allocator);
64+
65+
rapidjson::StringBuffer buffer;
66+
rapidjson::Writer<rapidjson::StringBuffer> writer(buffer);
67+
document.Accept(writer);
68+
auto data = reinterpret_cast<const uint8_t*>(buffer.GetString());
69+
return std::vector<uint8_t>(data, data + buffer.GetSize());
70+
}
71+
72+
} // namespace flutter_runner
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
// Copyright 2013 The Flutter Authors. All rights reserved.
2+
// Use of this source code is governed by a BSD-style license that can be
3+
// found in the LICENSE file.
4+
5+
#ifndef FLUTTER_SHELL_PLATFORM_FUCHSIA_FUCHSIA_INTL_H_
6+
#define FLUTTER_SHELL_PLATFORM_FUCHSIA_FUCHSIA_INTL_H_
7+
8+
#include <fuchsia/intl/cpp/fidl.h>
9+
10+
namespace flutter_runner {
11+
12+
// Make a byte vector containing the JSON string used for a localization
13+
// PlatformMessage, using the locale list in the given Profile.
14+
//
15+
// This method does not return a `fml::RefPtr<flutter::PlatformMessage>` for
16+
// testing convenience; that would require an unreasonably large set of
17+
// dependencies for the unit tests.
18+
std::vector<uint8_t> MakeLocalizationPlatformMessageData(
19+
const fuchsia::intl::Profile& intl_profile);
20+
21+
} // namespace flutter_runner
22+
23+
#endif // FLUTTER_SHELL_PLATFORM_FUCHSIA_FUCHSIA_INTL_H_
Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
// Copyright 2013 The Flutter Authors. All rights reserved.
2+
// Use of this source code is governed by a BSD-style license that can be
3+
// found in the LICENSE file.
4+
5+
#include <fuchsia/intl/cpp/fidl.h>
6+
#include <gtest/gtest.h>
7+
8+
#include "flutter/fml/icu_util.h"
9+
10+
#include "fuchsia_intl.h"
11+
12+
using fuchsia::intl::CalendarId;
13+
using fuchsia::intl::LocaleId;
14+
using fuchsia::intl::Profile;
15+
using fuchsia::intl::TemperatureUnit;
16+
using fuchsia::intl::TimeZoneId;
17+
18+
namespace flutter_runner {
19+
namespace {
20+
21+
class FuchsiaIntlTest : public testing::Test {
22+
public:
23+
static void SetUpTestCase() {
24+
testing::Test::SetUpTestCase();
25+
// The icudtl data must be present as a resource in the package for this
26+
// load to succeed.
27+
fml::icu::InitializeICU("/pkg/data/icudtl.dat");
28+
}
29+
};
30+
31+
TEST_F(FuchsiaIntlTest, MakeLocalizationPlatformMessageData_SimpleLocale) {
32+
Profile profile{};
33+
profile.set_locales({LocaleId{.id = "en-US"}});
34+
const std::string expected =
35+
R"({"method":"setLocale","args":["en","US","",""]})";
36+
const auto actual = MakeLocalizationPlatformMessageData(profile);
37+
ASSERT_EQ(expected, std::string(actual.begin(), actual.end()));
38+
}
39+
40+
TEST_F(FuchsiaIntlTest, MakeLocalizationPlatformMessageData_OneLocale) {
41+
Profile profile{};
42+
profile
43+
.set_locales({LocaleId{.id = "en-US-u-ca-gregory-fw-sun-hc-h12-ms-"
44+
"ussystem-nu-latn-tz-usnyc"}})
45+
.set_calendars({CalendarId{.id = "und-u-gregory"}})
46+
.set_time_zones({TimeZoneId{.id = "America/New_York"}})
47+
.set_temperature_unit(TemperatureUnit::FAHRENHEIT);
48+
const std::string expected =
49+
R"({"method":"setLocale","args":["en","US","",""]})";
50+
const auto actual = MakeLocalizationPlatformMessageData(profile);
51+
ASSERT_EQ(expected, std::string(actual.begin(), actual.end()));
52+
}
53+
54+
TEST_F(FuchsiaIntlTest, MakeLocalizationPlatformMessageData_MultipleLocales) {
55+
Profile profile{};
56+
profile
57+
.set_locales({LocaleId{.id = "en-US-u-ca-gregory-fw-sun-hc-h12-ms-"
58+
"ussystem-nu-latn-tz-usnyc"},
59+
LocaleId{.id = "sl-Latn-IT-nedis"},
60+
LocaleId{.id = "zh-Hans"}, LocaleId{.id = "sr-Cyrl-CS"}})
61+
.set_calendars({CalendarId{.id = "und-u-gregory"}})
62+
.set_time_zones({TimeZoneId{.id = "America/New_York"}})
63+
.set_temperature_unit(TemperatureUnit::FAHRENHEIT);
64+
const std::string expected =
65+
R"({"method":"setLocale","args":["en","US","","","sl","IT","Latn","nedis",)"
66+
R"("zh","","Hans","","sr","CS","Cyrl",""]})";
67+
const auto actual = MakeLocalizationPlatformMessageData(profile);
68+
ASSERT_EQ(expected, std::string(actual.begin(), actual.end()));
69+
}
70+
71+
} // namespace
72+
} // namespace flutter_runner

shell/platform/fuchsia/flutter/meta/flutter_aot_runner.cmx

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,10 +11,11 @@
1111
"services": [
1212
"fuchsia.accessibility.SettingsManager",
1313
"fuchsia.accessibility.semantics.SemanticsManager",
14-
"fuchsia.device.NameProvider",
1514
"fuchsia.deprecatedtimezone.Timezone",
15+
"fuchsia.device.NameProvider",
1616
"fuchsia.feedback.CrashReporter",
1717
"fuchsia.fonts.Provider",
18+
"fuchsia.intl.PropertyProvider",
1819
"fuchsia.net.NameLookup",
1920
"fuchsia.netstack.Netstack",
2021
"fuchsia.posix.socket.Provider",

shell/platform/fuchsia/flutter/meta/flutter_jit_runner.cmx

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,10 +11,11 @@
1111
"services": [
1212
"fuchsia.accessibility.SettingsManager",
1313
"fuchsia.accessibility.semantics.SemanticsManager",
14-
"fuchsia.device.NameProvider",
1514
"fuchsia.deprecatedtimezone.Timezone",
15+
"fuchsia.device.NameProvider",
1616
"fuchsia.feedback.CrashReporter",
1717
"fuchsia.fonts.Provider",
18+
"fuchsia.intl.PropertyProvider",
1819
"fuchsia.net.NameLookup",
1920
"fuchsia.netstack.Netstack",
2021
"fuchsia.posix.socket.Provider",

0 commit comments

Comments
 (0)