Skip to content
This repository was archived by the owner on Feb 25, 2025. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions ci/licenses_golden/licenses_flutter
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
10 changes: 10 additions & 0 deletions shell/platform/fuchsia/flutter/BUILD.gn
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand Down Expand Up @@ -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
Expand Down
55 changes: 53 additions & 2 deletions shell/platform/fuchsia/flutter/engine.cc
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand All @@ -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"
Expand All @@ -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,
Expand Down Expand Up @@ -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),
Expand Down Expand Up @@ -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());
Expand Down
3 changes: 3 additions & 0 deletions shell/platform/fuchsia/flutter/engine.h
Original file line number Diff line number Diff line change
Expand Up @@ -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>
Expand Down Expand Up @@ -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();

Expand Down
3 changes: 3 additions & 0 deletions shell/platform/fuchsia/flutter/engine_flutter_runner.gni
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand Down Expand Up @@ -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",
Expand Down
72 changes: 72 additions & 0 deletions shell/platform/fuchsia/flutter/fuchsia_intl.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
// 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
23 changes: 23 additions & 0 deletions shell/platform/fuchsia/flutter/fuchsia_intl.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
// 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_
72 changes: 72 additions & 0 deletions shell/platform/fuchsia/flutter/fuchsia_intl_unittest.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
// 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
3 changes: 2 additions & 1 deletion shell/platform/fuchsia/flutter/meta/flutter_aot_runner.cmx
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand Down
3 changes: 2 additions & 1 deletion shell/platform/fuchsia/flutter/meta/flutter_jit_runner.cmx
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand Down