From e0a284d0866d9897b84b2148693c09ec79892c12 Mon Sep 17 00:00:00 2001 From: garyqian Date: Thu, 16 Apr 2020 04:25:05 -0700 Subject: [PATCH 01/11] Initial impl --- lib/ui/window/window.cc | 13 +++++ lib/ui/window/window.h | 1 + runtime/runtime_controller.cc | 14 +++++ runtime/runtime_controller.h | 14 +++++ runtime/window_data.h | 1 + shell/common/engine.cc | 57 +++++++++++++------ .../embedding/android/FlutterView.java | 8 ++- .../systemchannels/LocalizationChannel.java | 9 ++- .../android/io/flutter/view/FlutterView.java | 7 ++- 9 files changed, 103 insertions(+), 21 deletions(-) diff --git a/lib/ui/window/window.cc b/lib/ui/window/window.cc index 5f5ae1dbe3d36..28346ea73e09b 100644 --- a/lib/ui/window/window.cc +++ b/lib/ui/window/window.cc @@ -227,6 +227,19 @@ void Window::UpdateLocales(const std::vector& locales) { })); } +void Window::UpdatePlatformResolvedLocale( + const std::vector& locale) { + std::shared_ptr dart_state = library_.dart_state().lock(); + if (!dart_state) + return; + tonic::DartState::Scope scope(dart_state); + tonic::LogIfError(tonic::DartInvokeField( + library_.value(), "_updatePlatformResolvedLocales", + { + tonic::ToDart>(locale), + })); +} + void Window::UpdateUserSettingsData(const std::string& data) { std::shared_ptr dart_state = library_.dart_state().lock(); if (!dart_state) diff --git a/lib/ui/window/window.h b/lib/ui/window/window.h index fac2861a43e40..3d7dc52574653 100644 --- a/lib/ui/window/window.h +++ b/lib/ui/window/window.h @@ -77,6 +77,7 @@ class Window final { void DidCreateIsolate(); void UpdateWindowMetrics(const ViewportMetrics& metrics); void UpdateLocales(const std::vector& locales); + void UpdatePlatformResolvedLocale(const std::vector& locale); void UpdateUserSettingsData(const std::string& data); void UpdateLifecycleState(const std::string& data); void UpdateSemanticsEnabled(bool enabled); diff --git a/runtime/runtime_controller.cc b/runtime/runtime_controller.cc index f7695d3d00a3b..9b898365c9266 100644 --- a/runtime/runtime_controller.cc +++ b/runtime/runtime_controller.cc @@ -131,6 +131,8 @@ std::unique_ptr RuntimeController::Clone() const { bool RuntimeController::FlushRuntimeStateToIsolate() { return SetViewportMetrics(window_data_.viewport_metrics) && SetLocales(window_data_.locale_data) && + SetPlatformResolvedLocale( + window_data_.platform_resolved_locale_data) && SetSemanticsEnabled(window_data_.semantics_enabled) && SetAccessibilityFeatures(window_data_.accessibility_feature_flags_) && SetUserSettingsData(window_data_.user_settings_data) && @@ -159,6 +161,18 @@ bool RuntimeController::SetLocales( return false; } +bool RuntimeController::SetPlatformResolvedLocale( + const std::vector& locale_data) { + window_data_.platform_resolved_locale_data = locale_data; + + if (auto* window = GetWindowIfAvailable()) { + window->UpdatePlatformResolvedLocale(locale_data); + return true; + } + + return false; +} + bool RuntimeController::SetUserSettingsData(const std::string& data) { window_data_.user_settings_data = data; diff --git a/runtime/runtime_controller.h b/runtime/runtime_controller.h index 33b51fe0690b7..eee535d6f7c9c 100644 --- a/runtime/runtime_controller.h +++ b/runtime/runtime_controller.h @@ -160,6 +160,20 @@ class RuntimeController final : public WindowClient { /// bool SetLocales(const std::vector& locale_data); + //---------------------------------------------------------------------------- + /// @brief Forward the specified locale data to the running isolate. If + /// the isolate is not running, this data will be saved and + /// flushed to the isolate when it starts running. + /// + /// @deprecated The persistent isolate data must be used for this purpose + /// instead. + /// + /// @param[in] locale_data The locale data + /// + /// @return If the locale data was forwarded to the running isolate. + /// + bool SetPlatformResolvedLocale(const std::vector& locale_data); + //---------------------------------------------------------------------------- /// @brief Forward the user settings data to the running isolate. If the /// isolate is not running, this data will be saved and flushed to diff --git a/runtime/window_data.h b/runtime/window_data.h index e234d2f558162..be29720f99bf9 100644 --- a/runtime/window_data.h +++ b/runtime/window_data.h @@ -36,6 +36,7 @@ struct WindowData { std::string script_code; std::string variant_code; std::vector locale_data; + std::vector platform_resolved_locale_data; std::string user_settings_data = "{}"; std::string lifecycle_state; bool semantics_enabled = false; diff --git a/shell/common/engine.cc b/shell/common/engine.cc index c998d49042b30..4703411376357 100644 --- a/shell/common/engine.cc +++ b/shell/common/engine.cc @@ -359,29 +359,50 @@ bool Engine::HandleLocalizationPlatformMessage(PlatformMessage* message) { return false; auto root = document.GetObject(); auto method = root.FindMember("method"); - if (method == root.MemberEnd() || method->value != "setLocale") + if (method == root.MemberEnd()) return false; + const size_t strings_per_locale = 4; + if (method->value == "setLocale") { + // Decode and pass the list of locale data onwards to dart. + auto args = root.FindMember("args"); + if (args == root.MemberEnd() || !args->value.IsArray()) + return false; - auto args = root.FindMember("args"); - if (args == root.MemberEnd() || !args->value.IsArray()) - return false; + if (args->value.Size() % strings_per_locale != 0) + return false; + std::vector locale_data; + for (size_t locale_index = 0; locale_index < args->value.Size(); + locale_index += strings_per_locale) { + if (!args->value[locale_index].IsString() || + !args->value[locale_index + 1].IsString()) + return false; + locale_data.push_back(args->value[locale_index].GetString()); + locale_data.push_back(args->value[locale_index + 1].GetString()); + locale_data.push_back(args->value[locale_index + 2].GetString()); + locale_data.push_back(args->value[locale_index + 3].GetString()); + } - const size_t strings_per_locale = 4; - if (args->value.Size() % strings_per_locale != 0) - return false; - std::vector locale_data; - for (size_t locale_index = 0; locale_index < args->value.Size(); - locale_index += strings_per_locale) { - if (!args->value[locale_index].IsString() || - !args->value[locale_index + 1].IsString()) + return runtime_controller_->SetLocales(locale_data); + } else if (method->value == "setPlatformResolvedLocale") { + // Decode and pass the single locale data onwards to dart. + auto args = root.FindMember("args"); + if (args == root.MemberEnd() || !args->value.IsArray()) + return false; + + if (args->value.Size() != strings_per_locale) return false; - locale_data.push_back(args->value[locale_index].GetString()); - locale_data.push_back(args->value[locale_index + 1].GetString()); - locale_data.push_back(args->value[locale_index + 2].GetString()); - locale_data.push_back(args->value[locale_index + 3].GetString()); - } - return runtime_controller_->SetLocales(locale_data); + std::vector locale_data; + if (!args->value[0].IsString() || !args->value[1].IsString()) + return false; + locale_data.push_back(args->value[0].GetString()); + locale_data.push_back(args->value[1].GetString()); + locale_data.push_back(args->value[2].GetString()); + locale_data.push_back(args->value[3].GetString()); + + return runtime_controller_->SetPlatformResolvedLocale(locale_data); + } + return false; } void Engine::HandleSettingsPlatformMessage(PlatformMessage* message) { diff --git a/shell/platform/android/io/flutter/embedding/android/FlutterView.java b/shell/platform/android/io/flutter/embedding/android/FlutterView.java index 9d54f223d1ce3..87a2870028747 100644 --- a/shell/platform/android/io/flutter/embedding/android/FlutterView.java +++ b/shell/platform/android/io/flutter/embedding/android/FlutterView.java @@ -39,6 +39,7 @@ import io.flutter.plugin.editing.TextInputPlugin; import io.flutter.plugin.platform.PlatformViewsController; import io.flutter.view.AccessibilityBridge; +import java.util.Arrays; import java.util.ArrayList; import java.util.HashSet; import java.util.List; @@ -849,17 +850,22 @@ public void removeFlutterEngineAttachmentListener( @SuppressWarnings("deprecation") private void sendLocalesToFlutter(@NonNull Configuration config) { List locales = new ArrayList<>(); + List languageRanges = new ArrayList<>(); if (Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.N) { LocaleList localeList = config.getLocales(); int localeCount = localeList.size(); for (int index = 0; index < localeCount; ++index) { Locale locale = localeList.get(index); locales.add(locale); + languageRanges.add(new Locale.LanguageRange(locale.toLanguageTag())); } } else { locales.add(config.locale); + languageRanges.add(new Locale.LanguageRange(config.locale.toLanguageTag())); } - flutterEngine.getLocalizationChannel().sendLocales(locales); + Locale platformResolvedLocale = Locale.lookup(languageRanges, Arrays.asList(Locale.getAvailableLocales())); + Log.e("flutter", "V2: " + platformResolvedLocale + " " + languageRanges.get(0).getRange() + " " + Locale.getAvailableLocales()[0].toLanguageTag()); + flutterEngine.getLocalizationChannel().sendLocales(locales, platformResolvedLocale); } /** diff --git a/shell/platform/android/io/flutter/embedding/engine/systemchannels/LocalizationChannel.java b/shell/platform/android/io/flutter/embedding/engine/systemchannels/LocalizationChannel.java index 2df0ecd7c1193..7e20369514de9 100644 --- a/shell/platform/android/io/flutter/embedding/engine/systemchannels/LocalizationChannel.java +++ b/shell/platform/android/io/flutter/embedding/engine/systemchannels/LocalizationChannel.java @@ -26,7 +26,7 @@ public LocalizationChannel(@NonNull DartExecutor dartExecutor) { } /** Send the given {@code locales} to Dart. */ - public void sendLocales(@NonNull List locales) { + public void sendLocales(@NonNull List locales, Locale platformResolvedLocale) { Log.v(TAG, "Sending Locales to Flutter."); List data = new ArrayList<>(); for (Locale locale : locales) { @@ -46,5 +46,12 @@ public void sendLocales(@NonNull List locales) { data.add(locale.getVariant()); } channel.invokeMethod("setLocale", data); + + List platformResolvedLocaleData = new ArrayList<>(); + platformResolvedLocaleData.add(platformResolvedLocale.getLanguage()); + platformResolvedLocaleData.add(platformResolvedLocale.getCountry()); + platformResolvedLocaleData.add(Build.VERSION.SDK_INT >= 21 ? platformResolvedLocale.getScript() : ""); + platformResolvedLocaleData.add(platformResolvedLocale.getVariant()); + channel.invokeMethod("setPlatformResolvedLocale", platformResolvedLocaleData); } } diff --git a/shell/platform/android/io/flutter/view/FlutterView.java b/shell/platform/android/io/flutter/view/FlutterView.java index eb158a973ead1..497c616cca4db 100644 --- a/shell/platform/android/io/flutter/view/FlutterView.java +++ b/shell/platform/android/io/flutter/view/FlutterView.java @@ -59,6 +59,7 @@ import io.flutter.plugin.platform.PlatformPlugin; import io.flutter.plugin.platform.PlatformViewsController; import java.nio.ByteBuffer; +import java.util.Arrays; import java.util.ArrayList; import java.util.List; import java.util.Locale; @@ -394,17 +395,21 @@ private void sendUserPlatformSettingsToDart() { @SuppressWarnings("deprecation") private void sendLocalesToDart(Configuration config) { List locales = new ArrayList<>(); + List languageRanges = new ArrayList<>(); if (Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.N) { LocaleList localeList = config.getLocales(); int localeCount = localeList.size(); for (int index = 0; index < localeCount; ++index) { Locale locale = localeList.get(index); locales.add(locale); + languageRanges.add(new Locale.LanguageRange(locale.toLanguageTag())); } } else { locales.add(config.locale); + languageRanges.add(new Locale.LanguageRange(config.locale.toLanguageTag())); } - localizationChannel.sendLocales(locales); + Locale platformResolvedLocale = Locale.lookup(languageRanges, Arrays.asList(Locale.getAvailableLocales())); + localizationChannel.sendLocales(locales, platformResolvedLocale); } @Override From ba229a2d109e80e0d2a62125a6f74568217891a8 Mon Sep 17 00:00:00 2001 From: garyqian Date: Thu, 16 Apr 2020 19:20:13 -0700 Subject: [PATCH 02/11] Dart:ui impl --- lib/ui/hooks.dart | 14 ++++++++++++++ lib/ui/window.dart | 7 +++++++ .../flutter/embedding/android/FlutterView.java | 1 - .../systemchannels/LocalizationChannel.java | 17 ++++++++++------- 4 files changed, 31 insertions(+), 8 deletions(-) diff --git a/lib/ui/hooks.dart b/lib/ui/hooks.dart index 571c3a18d8f9d..5a9c53460f14d 100644 --- a/lib/ui/hooks.dart +++ b/lib/ui/hooks.dart @@ -96,6 +96,20 @@ void _updateLocales(List locales) { _invoke(window.onLocaleChanged, window._onLocaleChangedZone); } +@pragma('vm:entry-point') +// ignore: unused_element +void _updatePlatformResolvedLocales(List localeData) { + const int stringsPerLocale = 4; + final String countryCode = localeData[1]; + final String scriptCode = localeData[2]; + + window._platformResolvedLocale = Locale.fromSubtags( + languageCode: localeData[0], + countryCode: countryCode.isEmpty ? null : countryCode, + scriptCode: scriptCode.isEmpty ? null : scriptCode, + ); +} + @pragma('vm:entry-point') // ignore: unused_element void _updateUserSettingsData(String jsonData) { diff --git a/lib/ui/window.dart b/lib/ui/window.dart index d03ece6328364..df6aa5746e31d 100644 --- a/lib/ui/window.dart +++ b/lib/ui/window.dart @@ -792,6 +792,13 @@ class Window { List get locales => _locales; List _locales; + // The locale that the platform's native locale resolution system resolves to. + // This value may differ between platforms and is meant to allow flutter locale + // resoltion alforithms to into resolving consistently with other apps on the + // device. + Locale get platformResolvedLocale => _platformResolvedLocale; + Locale _platformResolvedLocale; + /// A callback that is invoked whenever [locale] changes value. /// /// The framework invokes this callback in the same zone in which the diff --git a/shell/platform/android/io/flutter/embedding/android/FlutterView.java b/shell/platform/android/io/flutter/embedding/android/FlutterView.java index 87a2870028747..c2584f826f0fd 100644 --- a/shell/platform/android/io/flutter/embedding/android/FlutterView.java +++ b/shell/platform/android/io/flutter/embedding/android/FlutterView.java @@ -864,7 +864,6 @@ private void sendLocalesToFlutter(@NonNull Configuration config) { languageRanges.add(new Locale.LanguageRange(config.locale.toLanguageTag())); } Locale platformResolvedLocale = Locale.lookup(languageRanges, Arrays.asList(Locale.getAvailableLocales())); - Log.e("flutter", "V2: " + platformResolvedLocale + " " + languageRanges.get(0).getRange() + " " + Locale.getAvailableLocales()[0].toLanguageTag()); flutterEngine.getLocalizationChannel().sendLocales(locales, platformResolvedLocale); } diff --git a/shell/platform/android/io/flutter/embedding/engine/systemchannels/LocalizationChannel.java b/shell/platform/android/io/flutter/embedding/engine/systemchannels/LocalizationChannel.java index 7e20369514de9..62e04e934fad1 100644 --- a/shell/platform/android/io/flutter/embedding/engine/systemchannels/LocalizationChannel.java +++ b/shell/platform/android/io/flutter/embedding/engine/systemchannels/LocalizationChannel.java @@ -28,6 +28,16 @@ public LocalizationChannel(@NonNull DartExecutor dartExecutor) { /** Send the given {@code locales} to Dart. */ public void sendLocales(@NonNull List locales, Locale platformResolvedLocale) { Log.v(TAG, "Sending Locales to Flutter."); + // Send platformResolvedLocale first as it may be used in the callback + // triggered by the user supported locales being updated/set. + List platformResolvedLocaleData = new ArrayList<>(); + platformResolvedLocaleData.add(platformResolvedLocale.getLanguage()); + platformResolvedLocaleData.add(platformResolvedLocale.getCountry()); + platformResolvedLocaleData.add(Build.VERSION.SDK_INT >= 21 ? platformResolvedLocale.getScript() : ""); + platformResolvedLocaleData.add(platformResolvedLocale.getVariant()); + channel.invokeMethod("setPlatformResolvedLocale", platformResolvedLocaleData); + + // Send the user's preferred locales. List data = new ArrayList<>(); for (Locale locale : locales) { Log.v( @@ -46,12 +56,5 @@ public void sendLocales(@NonNull List locales, Locale platformResolvedLo data.add(locale.getVariant()); } channel.invokeMethod("setLocale", data); - - List platformResolvedLocaleData = new ArrayList<>(); - platformResolvedLocaleData.add(platformResolvedLocale.getLanguage()); - platformResolvedLocaleData.add(platformResolvedLocale.getCountry()); - platformResolvedLocaleData.add(Build.VERSION.SDK_INT >= 21 ? platformResolvedLocale.getScript() : ""); - platformResolvedLocaleData.add(platformResolvedLocale.getVariant()); - channel.invokeMethod("setPlatformResolvedLocale", platformResolvedLocaleData); } } From 9df925d1b8c5ef980e26571524558281bfb80027 Mon Sep 17 00:00:00 2001 From: garyqian Date: Fri, 17 Apr 2020 00:50:33 -0700 Subject: [PATCH 03/11] Docs improvements --- lib/ui/window.dart | 14 ++++++++++---- runtime/runtime_controller.h | 10 ++++++++-- 2 files changed, 18 insertions(+), 6 deletions(-) diff --git a/lib/ui/window.dart b/lib/ui/window.dart index df6aa5746e31d..a0c7ee411c51a 100644 --- a/lib/ui/window.dart +++ b/lib/ui/window.dart @@ -792,10 +792,16 @@ class Window { List get locales => _locales; List _locales; - // The locale that the platform's native locale resolution system resolves to. - // This value may differ between platforms and is meant to allow flutter locale - // resoltion alforithms to into resolving consistently with other apps on the - // device. + /// The locale that the platform's native locale resolution system resolves to. + /// + /// This value may differ between platforms and is meant to allow flutter locale + /// resoltion algorithms to into resolving consistently with other apps on the + /// device. + /// + /// This value may be used in a custom [localeResolutionCallback] or used directly + /// in order to arrive at the most appropriate locale for the app. + /// + /// See [locales], which is the list of locales the user/device prefers. Locale get platformResolvedLocale => _platformResolvedLocale; Locale _platformResolvedLocale; diff --git a/runtime/runtime_controller.h b/runtime/runtime_controller.h index eee535d6f7c9c..1f09fb3846e84 100644 --- a/runtime/runtime_controller.h +++ b/runtime/runtime_controller.h @@ -149,7 +149,9 @@ class RuntimeController final : public WindowClient { //---------------------------------------------------------------------------- /// @brief Forward the specified locale data to the running isolate. If /// the isolate is not running, this data will be saved and - /// flushed to the isolate when it starts running. + /// flushed to the isolate when it starts running. Locale_data + /// consists of groups of 4 strings, each group representing + /// a single locale. /// /// @deprecated The persistent isolate data must be used for this purpose /// instead. @@ -163,7 +165,11 @@ class RuntimeController final : public WindowClient { //---------------------------------------------------------------------------- /// @brief Forward the specified locale data to the running isolate. If /// the isolate is not running, this data will be saved and - /// flushed to the isolate when it starts running. + /// flushed to the isolate when it starts running. Locale_data + /// should consist of a vector of 4 strings, representing + /// languageCode, contryCode, scriptCode, and variant of the + /// locale. + /// /// /// @deprecated The persistent isolate data must be used for this purpose /// instead. From b6a84281ac02a4cc34eacb6a4f422e3aacb2ac71 Mon Sep 17 00:00:00 2001 From: garyqian Date: Fri, 17 Apr 2020 01:48:27 -0700 Subject: [PATCH 04/11] Fix analyzer, version gating --- lib/ui/hooks.dart | 2 +- .../io/flutter/embedding/android/FlutterView.java | 5 ++++- .../engine/systemchannels/LocalizationChannel.java | 14 ++++++++------ .../android/io/flutter/view/FlutterView.java | 9 ++++++--- 4 files changed, 19 insertions(+), 11 deletions(-) diff --git a/lib/ui/hooks.dart b/lib/ui/hooks.dart index 5a9c53460f14d..6afd84754f793 100644 --- a/lib/ui/hooks.dart +++ b/lib/ui/hooks.dart @@ -99,7 +99,7 @@ void _updateLocales(List locales) { @pragma('vm:entry-point') // ignore: unused_element void _updatePlatformResolvedLocales(List localeData) { - const int stringsPerLocale = 4; + assert(localeData.length == 4); final String countryCode = localeData[1]; final String scriptCode = localeData[2]; diff --git a/shell/platform/android/io/flutter/embedding/android/FlutterView.java b/shell/platform/android/io/flutter/embedding/android/FlutterView.java index c2584f826f0fd..487baa016f7a5 100644 --- a/shell/platform/android/io/flutter/embedding/android/FlutterView.java +++ b/shell/platform/android/io/flutter/embedding/android/FlutterView.java @@ -863,7 +863,10 @@ private void sendLocalesToFlutter(@NonNull Configuration config) { locales.add(config.locale); languageRanges.add(new Locale.LanguageRange(config.locale.toLanguageTag())); } - Locale platformResolvedLocale = Locale.lookup(languageRanges, Arrays.asList(Locale.getAvailableLocales())); + Locale platformResolvedLocale; + if (Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.O) { + platformResolvedLocale = Locale.lookup(languageRanges, Arrays.asList(Locale.getAvailableLocales())); + } flutterEngine.getLocalizationChannel().sendLocales(locales, platformResolvedLocale); } diff --git a/shell/platform/android/io/flutter/embedding/engine/systemchannels/LocalizationChannel.java b/shell/platform/android/io/flutter/embedding/engine/systemchannels/LocalizationChannel.java index 62e04e934fad1..b1f299118027b 100644 --- a/shell/platform/android/io/flutter/embedding/engine/systemchannels/LocalizationChannel.java +++ b/shell/platform/android/io/flutter/embedding/engine/systemchannels/LocalizationChannel.java @@ -30,12 +30,14 @@ public void sendLocales(@NonNull List locales, Locale platformResolvedLo Log.v(TAG, "Sending Locales to Flutter."); // Send platformResolvedLocale first as it may be used in the callback // triggered by the user supported locales being updated/set. - List platformResolvedLocaleData = new ArrayList<>(); - platformResolvedLocaleData.add(platformResolvedLocale.getLanguage()); - platformResolvedLocaleData.add(platformResolvedLocale.getCountry()); - platformResolvedLocaleData.add(Build.VERSION.SDK_INT >= 21 ? platformResolvedLocale.getScript() : ""); - platformResolvedLocaleData.add(platformResolvedLocale.getVariant()); - channel.invokeMethod("setPlatformResolvedLocale", platformResolvedLocaleData); + if (platformResolved == null) { + List platformResolvedLocaleData = new ArrayList<>(); + platformResolvedLocaleData.add(platformResolvedLocale.getLanguage()); + platformResolvedLocaleData.add(platformResolvedLocale.getCountry()); + platformResolvedLocaleData.add(Build.VERSION.SDK_INT >= 21 ? platformResolvedLocale.getScript() : ""); + platformResolvedLocaleData.add(platformResolvedLocale.getVariant()); + channel.invokeMethod("setPlatformResolvedLocale", platformResolvedLocaleData); + } // Send the user's preferred locales. List data = new ArrayList<>(); diff --git a/shell/platform/android/io/flutter/view/FlutterView.java b/shell/platform/android/io/flutter/view/FlutterView.java index 497c616cca4db..b4abd32459467 100644 --- a/shell/platform/android/io/flutter/view/FlutterView.java +++ b/shell/platform/android/io/flutter/view/FlutterView.java @@ -393,7 +393,7 @@ private void sendUserPlatformSettingsToDart() { } @SuppressWarnings("deprecation") - private void sendLocalesToDart(Configuration config) { + private void sendLocalesToFlutter(@NonNull Configuration config) { List locales = new ArrayList<>(); List languageRanges = new ArrayList<>(); if (Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.N) { @@ -408,8 +408,11 @@ private void sendLocalesToDart(Configuration config) { locales.add(config.locale); languageRanges.add(new Locale.LanguageRange(config.locale.toLanguageTag())); } - Locale platformResolvedLocale = Locale.lookup(languageRanges, Arrays.asList(Locale.getAvailableLocales())); - localizationChannel.sendLocales(locales, platformResolvedLocale); + Locale platformResolvedLocale; + if (Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.O) { + platformResolvedLocale = Locale.lookup(languageRanges, Arrays.asList(Locale.getAvailableLocales())); + } + flutterEngine.getLocalizationChannel().sendLocales(locales, platformResolvedLocale); } @Override From 5b297293a2ee1be415eee079c319bb5532d679af Mon Sep 17 00:00:00 2001 From: garyqian Date: Fri, 17 Apr 2020 02:26:29 -0700 Subject: [PATCH 05/11] Comment out getter to avoid exposing unfinished API. --- lib/ui/window.dart | 26 +++++++++++++++----------- 1 file changed, 15 insertions(+), 11 deletions(-) diff --git a/lib/ui/window.dart b/lib/ui/window.dart index a0c7ee411c51a..891c2b206e067 100644 --- a/lib/ui/window.dart +++ b/lib/ui/window.dart @@ -792,17 +792,21 @@ class Window { List get locales => _locales; List _locales; - /// The locale that the platform's native locale resolution system resolves to. - /// - /// This value may differ between platforms and is meant to allow flutter locale - /// resoltion algorithms to into resolving consistently with other apps on the - /// device. - /// - /// This value may be used in a custom [localeResolutionCallback] or used directly - /// in order to arrive at the most appropriate locale for the app. - /// - /// See [locales], which is the list of locales the user/device prefers. - Locale get platformResolvedLocale => _platformResolvedLocale; + // The locale that the platform's native locale resolution system resolves to. + // + // This value may differ between platforms and is meant to allow flutter locale + // resoltion algorithms to into resolving consistently with other apps on the + // device. + // + // This value may be used in a custom [localeListResolutionCallback] or used directly + // in order to arrive at the most appropriate locale for the app. + // + // See [locales], which is the list of locales the user/device prefers. + // + // TODO(garyq) uncomment the platformResolvedLocale getter when this is fully + // implemented. + // Locale get platformResolvedLocale => _platformResolvedLocale; + Locale _platformResolvedLocale; /// A callback that is invoked whenever [locale] changes value. From b98b910327b4bcb3c36020166f35e366a2c4ba85 Mon Sep 17 00:00:00 2001 From: garyqian Date: Fri, 17 Apr 2020 13:41:44 -0700 Subject: [PATCH 06/11] Fix formatters, compilation bugs --- lib/ui/window.dart | 26 ++++++++----------- .../embedding/android/FlutterView.java | 7 ++--- .../systemchannels/LocalizationChannel.java | 5 ++-- .../android/io/flutter/view/FlutterView.java | 11 ++++---- 4 files changed, 24 insertions(+), 25 deletions(-) diff --git a/lib/ui/window.dart b/lib/ui/window.dart index 891c2b206e067..728ada75ffb57 100644 --- a/lib/ui/window.dart +++ b/lib/ui/window.dart @@ -792,21 +792,17 @@ class Window { List get locales => _locales; List _locales; - // The locale that the platform's native locale resolution system resolves to. - // - // This value may differ between platforms and is meant to allow flutter locale - // resoltion algorithms to into resolving consistently with other apps on the - // device. - // - // This value may be used in a custom [localeListResolutionCallback] or used directly - // in order to arrive at the most appropriate locale for the app. - // - // See [locales], which is the list of locales the user/device prefers. - // - // TODO(garyq) uncomment the platformResolvedLocale getter when this is fully - // implemented. - // Locale get platformResolvedLocale => _platformResolvedLocale; - + /// The locale that the platform's native locale resolution system resolves to. + /// + /// This value may differ between platforms and is meant to allow flutter locale + /// resoltion algorithms to into resolving consistently with other apps on the + /// device. + /// + /// This value may be used in a custom [localeListResolutionCallback] or used directly + /// in order to arrive at the most appropriate locale for the app. + /// + /// See [locales], which is the list of locales the user/device prefers. + Locale get platformResolvedLocale => _platformResolvedLocale; Locale _platformResolvedLocale; /// A callback that is invoked whenever [locale] changes value. diff --git a/shell/platform/android/io/flutter/embedding/android/FlutterView.java b/shell/platform/android/io/flutter/embedding/android/FlutterView.java index 487baa016f7a5..36f047d5c5043 100644 --- a/shell/platform/android/io/flutter/embedding/android/FlutterView.java +++ b/shell/platform/android/io/flutter/embedding/android/FlutterView.java @@ -39,8 +39,8 @@ import io.flutter.plugin.editing.TextInputPlugin; import io.flutter.plugin.platform.PlatformViewsController; import io.flutter.view.AccessibilityBridge; -import java.util.Arrays; import java.util.ArrayList; +import java.util.Arrays; import java.util.HashSet; import java.util.List; import java.util.Locale; @@ -863,9 +863,10 @@ private void sendLocalesToFlutter(@NonNull Configuration config) { locales.add(config.locale); languageRanges.add(new Locale.LanguageRange(config.locale.toLanguageTag())); } - Locale platformResolvedLocale; + Locale platformResolvedLocale = null; if (Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.O) { - platformResolvedLocale = Locale.lookup(languageRanges, Arrays.asList(Locale.getAvailableLocales())); + platformResolvedLocale = + Locale.lookup(languageRanges, Arrays.asList(Locale.getAvailableLocales())); } flutterEngine.getLocalizationChannel().sendLocales(locales, platformResolvedLocale); } diff --git a/shell/platform/android/io/flutter/embedding/engine/systemchannels/LocalizationChannel.java b/shell/platform/android/io/flutter/embedding/engine/systemchannels/LocalizationChannel.java index b1f299118027b..3bc6bf744e585 100644 --- a/shell/platform/android/io/flutter/embedding/engine/systemchannels/LocalizationChannel.java +++ b/shell/platform/android/io/flutter/embedding/engine/systemchannels/LocalizationChannel.java @@ -30,11 +30,12 @@ public void sendLocales(@NonNull List locales, Locale platformResolvedLo Log.v(TAG, "Sending Locales to Flutter."); // Send platformResolvedLocale first as it may be used in the callback // triggered by the user supported locales being updated/set. - if (platformResolved == null) { + if (platformResolvedLocale == null) { List platformResolvedLocaleData = new ArrayList<>(); platformResolvedLocaleData.add(platformResolvedLocale.getLanguage()); platformResolvedLocaleData.add(platformResolvedLocale.getCountry()); - platformResolvedLocaleData.add(Build.VERSION.SDK_INT >= 21 ? platformResolvedLocale.getScript() : ""); + platformResolvedLocaleData.add( + Build.VERSION.SDK_INT >= 21 ? platformResolvedLocale.getScript() : ""); platformResolvedLocaleData.add(platformResolvedLocale.getVariant()); channel.invokeMethod("setPlatformResolvedLocale", platformResolvedLocaleData); } diff --git a/shell/platform/android/io/flutter/view/FlutterView.java b/shell/platform/android/io/flutter/view/FlutterView.java index b4abd32459467..bd295bafb3c42 100644 --- a/shell/platform/android/io/flutter/view/FlutterView.java +++ b/shell/platform/android/io/flutter/view/FlutterView.java @@ -59,8 +59,8 @@ import io.flutter.plugin.platform.PlatformPlugin; import io.flutter.plugin.platform.PlatformViewsController; import java.nio.ByteBuffer; -import java.util.Arrays; import java.util.ArrayList; +import java.util.Arrays; import java.util.List; import java.util.Locale; import java.util.concurrent.atomic.AtomicLong; @@ -393,7 +393,7 @@ private void sendUserPlatformSettingsToDart() { } @SuppressWarnings("deprecation") - private void sendLocalesToFlutter(@NonNull Configuration config) { + private void sendLocalesToDart(Configuration config) { List locales = new ArrayList<>(); List languageRanges = new ArrayList<>(); if (Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.N) { @@ -408,11 +408,12 @@ private void sendLocalesToFlutter(@NonNull Configuration config) { locales.add(config.locale); languageRanges.add(new Locale.LanguageRange(config.locale.toLanguageTag())); } - Locale platformResolvedLocale; + Locale platformResolvedLocale = null; if (Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.O) { - platformResolvedLocale = Locale.lookup(languageRanges, Arrays.asList(Locale.getAvailableLocales())); + platformResolvedLocale = + Locale.lookup(languageRanges, Arrays.asList(Locale.getAvailableLocales())); } - flutterEngine.getLocalizationChannel().sendLocales(locales, platformResolvedLocale); + localizationChannel.sendLocales(locales, platformResolvedLocale); } @Override From 097bd51851db326b97561d95ad6cd15aa3f26808 Mon Sep 17 00:00:00 2001 From: garyqian Date: Fri, 17 Apr 2020 14:11:36 -0700 Subject: [PATCH 07/11] Fix linter, fix version gating --- lib/ui/hooks.dart | 4 ++-- lib/ui/window/window.cc | 2 +- lib/web_ui/lib/src/ui/window.dart | 14 ++++++++++++++ .../io/flutter/embedding/android/FlutterView.java | 12 +++++++++--- .../engine/systemchannels/LocalizationChannel.java | 2 +- .../android/io/flutter/view/FlutterView.java | 12 +++++++++--- 6 files changed, 36 insertions(+), 10 deletions(-) diff --git a/lib/ui/hooks.dart b/lib/ui/hooks.dart index 6afd84754f793..f8c6ff34ea45e 100644 --- a/lib/ui/hooks.dart +++ b/lib/ui/hooks.dart @@ -98,8 +98,8 @@ void _updateLocales(List locales) { @pragma('vm:entry-point') // ignore: unused_element -void _updatePlatformResolvedLocales(List localeData) { - assert(localeData.length == 4); +void _updatePlatformResolvedLocale(List localeData) { + if (localeData.length != 4) return; final String countryCode = localeData[1]; final String scriptCode = localeData[2]; diff --git a/lib/ui/window/window.cc b/lib/ui/window/window.cc index 28346ea73e09b..4d75fba13c090 100644 --- a/lib/ui/window/window.cc +++ b/lib/ui/window/window.cc @@ -234,7 +234,7 @@ void Window::UpdatePlatformResolvedLocale( return; tonic::DartState::Scope scope(dart_state); tonic::LogIfError(tonic::DartInvokeField( - library_.value(), "_updatePlatformResolvedLocales", + library_.value(), "_updatePlatformResolvedLocale", { tonic::ToDart>(locale), })); diff --git a/lib/web_ui/lib/src/ui/window.dart b/lib/web_ui/lib/src/ui/window.dart index 58c2d672a13eb..d6555f2aa8d9c 100644 --- a/lib/web_ui/lib/src/ui/window.dart +++ b/lib/web_ui/lib/src/ui/window.dart @@ -699,6 +699,20 @@ abstract class Window { // TODO(flutter_web): Get the real locale from the browser. List _locales = const [_enUS]; + /// The locale that the platform's native locale resolution system resolves to. + /// + /// This value may differ between platforms and is meant to allow flutter locale + /// resoltion algorithms to into resolving consistently with other apps on the + /// device. + /// + /// This value may be used in a custom [localeListResolutionCallback] or used directly + /// in order to arrive at the most appropriate locale for the app. + /// + /// See [locales], which is the list of locales the user/device prefers. + Locale get platformResolvedLocale => _platformResolvedLocale; + // TODO(flutter_web): Compute the browser locale resolution and set it here. + Locale _platformResolvedLocale; + /// A callback that is invoked whenever [locale] changes value. /// /// The framework invokes this callback in the same zone in which the diff --git a/shell/platform/android/io/flutter/embedding/android/FlutterView.java b/shell/platform/android/io/flutter/embedding/android/FlutterView.java index 36f047d5c5043..a893f043019f1 100644 --- a/shell/platform/android/io/flutter/embedding/android/FlutterView.java +++ b/shell/platform/android/io/flutter/embedding/android/FlutterView.java @@ -850,24 +850,30 @@ public void removeFlutterEngineAttachmentListener( @SuppressWarnings("deprecation") private void sendLocalesToFlutter(@NonNull Configuration config) { List locales = new ArrayList<>(); - List languageRanges = new ArrayList<>(); if (Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.N) { LocaleList localeList = config.getLocales(); int localeCount = localeList.size(); for (int index = 0; index < localeCount; ++index) { Locale locale = localeList.get(index); locales.add(locale); - languageRanges.add(new Locale.LanguageRange(locale.toLanguageTag())); } } else { locales.add(config.locale); - languageRanges.add(new Locale.LanguageRange(config.locale.toLanguageTag())); } + + List languageRanges = new ArrayList<>(); Locale platformResolvedLocale = null; if (Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.O) { + LocaleList localeList = config.getLocales(); + int localeCount = localeList.size(); + for (int index = 0; index < localeCount; ++index) { + Locale locale = localeList.get(index); + languageRanges.add(new Locale.LanguageRange(locale.toLanguageTag())); + } platformResolvedLocale = Locale.lookup(languageRanges, Arrays.asList(Locale.getAvailableLocales())); } + flutterEngine.getLocalizationChannel().sendLocales(locales, platformResolvedLocale); } diff --git a/shell/platform/android/io/flutter/embedding/engine/systemchannels/LocalizationChannel.java b/shell/platform/android/io/flutter/embedding/engine/systemchannels/LocalizationChannel.java index 3bc6bf744e585..580b2df8764d5 100644 --- a/shell/platform/android/io/flutter/embedding/engine/systemchannels/LocalizationChannel.java +++ b/shell/platform/android/io/flutter/embedding/engine/systemchannels/LocalizationChannel.java @@ -30,7 +30,7 @@ public void sendLocales(@NonNull List locales, Locale platformResolvedLo Log.v(TAG, "Sending Locales to Flutter."); // Send platformResolvedLocale first as it may be used in the callback // triggered by the user supported locales being updated/set. - if (platformResolvedLocale == null) { + if (platformResolvedLocale != null) { List platformResolvedLocaleData = new ArrayList<>(); platformResolvedLocaleData.add(platformResolvedLocale.getLanguage()); platformResolvedLocaleData.add(platformResolvedLocale.getCountry()); diff --git a/shell/platform/android/io/flutter/view/FlutterView.java b/shell/platform/android/io/flutter/view/FlutterView.java index bd295bafb3c42..14e4d7eb96551 100644 --- a/shell/platform/android/io/flutter/view/FlutterView.java +++ b/shell/platform/android/io/flutter/view/FlutterView.java @@ -395,24 +395,30 @@ private void sendUserPlatformSettingsToDart() { @SuppressWarnings("deprecation") private void sendLocalesToDart(Configuration config) { List locales = new ArrayList<>(); - List languageRanges = new ArrayList<>(); if (Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.N) { LocaleList localeList = config.getLocales(); int localeCount = localeList.size(); for (int index = 0; index < localeCount; ++index) { Locale locale = localeList.get(index); locales.add(locale); - languageRanges.add(new Locale.LanguageRange(locale.toLanguageTag())); } } else { locales.add(config.locale); - languageRanges.add(new Locale.LanguageRange(config.locale.toLanguageTag())); } + + List languageRanges = new ArrayList<>(); Locale platformResolvedLocale = null; if (Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.O) { + LocaleList localeList = config.getLocales(); + int localeCount = localeList.size(); + for (int index = 0; index < localeCount; ++index) { + Locale locale = localeList.get(index); + languageRanges.add(new Locale.LanguageRange(locale.toLanguageTag())); + } platformResolvedLocale = Locale.lookup(languageRanges, Arrays.asList(Locale.getAvailableLocales())); } + localizationChannel.sendLocales(locales, platformResolvedLocale); } From f5e2edddbd43548329b2f7e36aad3d4d99ff607c Mon Sep 17 00:00:00 2001 From: garyqian Date: Fri, 17 Apr 2020 14:25:01 -0700 Subject: [PATCH 08/11] Analyzer --- lib/ui/hooks.dart | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/lib/ui/hooks.dart b/lib/ui/hooks.dart index f8c6ff34ea45e..41fb5c7f61731 100644 --- a/lib/ui/hooks.dart +++ b/lib/ui/hooks.dart @@ -99,7 +99,9 @@ void _updateLocales(List locales) { @pragma('vm:entry-point') // ignore: unused_element void _updatePlatformResolvedLocale(List localeData) { - if (localeData.length != 4) return; + if (localeData.length != 4) { + return; + } final String countryCode = localeData[1]; final String scriptCode = localeData[2]; From 19d8f0fbfc31b4538f7a7c67741a90c2cbe6163d Mon Sep 17 00:00:00 2001 From: garyqian Date: Mon, 20 Apr 2020 13:39:00 -0700 Subject: [PATCH 09/11] Docs improvements --- runtime/runtime_controller.h | 16 +++++++--------- .../flutter/embedding/android/FlutterView.java | 1 + .../android/io/flutter/view/FlutterView.java | 1 + 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/runtime/runtime_controller.h b/runtime/runtime_controller.h index 1f09fb3846e84..c9458bab02a92 100644 --- a/runtime/runtime_controller.h +++ b/runtime/runtime_controller.h @@ -149,14 +149,13 @@ class RuntimeController final : public WindowClient { //---------------------------------------------------------------------------- /// @brief Forward the specified locale data to the running isolate. If /// the isolate is not running, this data will be saved and - /// flushed to the isolate when it starts running. Locale_data - /// consists of groups of 4 strings, each group representing - /// a single locale. + /// flushed to the isolate when it starts running. /// /// @deprecated The persistent isolate data must be used for this purpose /// instead. /// - /// @param[in] locale_data The locale data + /// @param[in] locale_data The locale data. This should consist of groups of + /// 4 strings, each group representing a single locale. /// /// @return If the locale data was forwarded to the running isolate. /// @@ -165,16 +164,15 @@ class RuntimeController final : public WindowClient { //---------------------------------------------------------------------------- /// @brief Forward the specified locale data to the running isolate. If /// the isolate is not running, this data will be saved and - /// flushed to the isolate when it starts running. Locale_data - /// should consist of a vector of 4 strings, representing - /// languageCode, contryCode, scriptCode, and variant of the - /// locale. + /// flushed to the isolate when it starts running. /// /// /// @deprecated The persistent isolate data must be used for this purpose /// instead. /// - /// @param[in] locale_data The locale data + /// @param[in] locale_data The locale data. This should consist of avector + /// of 4 strings, representing languageCode, contryCode, + /// scriptCode, and variant of the locale. /// /// @return If the locale data was forwarded to the running isolate. /// diff --git a/shell/platform/android/io/flutter/embedding/android/FlutterView.java b/shell/platform/android/io/flutter/embedding/android/FlutterView.java index a893f043019f1..4ac3d3036af74 100644 --- a/shell/platform/android/io/flutter/embedding/android/FlutterView.java +++ b/shell/platform/android/io/flutter/embedding/android/FlutterView.java @@ -870,6 +870,7 @@ private void sendLocalesToFlutter(@NonNull Configuration config) { Locale locale = localeList.get(index); languageRanges.add(new Locale.LanguageRange(locale.toLanguageTag())); } + // TODO(garyq) implement a real locale resolution. platformResolvedLocale = Locale.lookup(languageRanges, Arrays.asList(Locale.getAvailableLocales())); } diff --git a/shell/platform/android/io/flutter/view/FlutterView.java b/shell/platform/android/io/flutter/view/FlutterView.java index 14e4d7eb96551..708e986591b79 100644 --- a/shell/platform/android/io/flutter/view/FlutterView.java +++ b/shell/platform/android/io/flutter/view/FlutterView.java @@ -415,6 +415,7 @@ private void sendLocalesToDart(Configuration config) { Locale locale = localeList.get(index); languageRanges.add(new Locale.LanguageRange(locale.toLanguageTag())); } + // TODO(garyq) implement a real locale resolution. platformResolvedLocale = Locale.lookup(languageRanges, Arrays.asList(Locale.getAvailableLocales())); } From 0bc2a33a02faa920cfc73ecbebf1444ffc6d02ba Mon Sep 17 00:00:00 2001 From: garyqian Date: Mon, 20 Apr 2020 14:04:06 -0700 Subject: [PATCH 10/11] Fix typo --- runtime/runtime_controller.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/runtime/runtime_controller.h b/runtime/runtime_controller.h index c9458bab02a92..fca9c409e25f8 100644 --- a/runtime/runtime_controller.h +++ b/runtime/runtime_controller.h @@ -170,7 +170,7 @@ class RuntimeController final : public WindowClient { /// @deprecated The persistent isolate data must be used for this purpose /// instead. /// - /// @param[in] locale_data The locale data. This should consist of avector + /// @param[in] locale_data The locale data. This should consist of a vector /// of 4 strings, representing languageCode, contryCode, /// scriptCode, and variant of the locale. /// From fe42281265cfa92af973f975e03b7cef48a1bb4b Mon Sep 17 00:00:00 2001 From: garyqian Date: Tue, 21 Apr 2020 03:38:37 -0700 Subject: [PATCH 11/11] Fix typos and reword some docs --- lib/ui/window.dart | 6 +++--- testing/run_tests.py | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/lib/ui/window.dart b/lib/ui/window.dart index 728ada75ffb57..f70b7b63e562d 100644 --- a/lib/ui/window.dart +++ b/lib/ui/window.dart @@ -794,9 +794,9 @@ class Window { /// The locale that the platform's native locale resolution system resolves to. /// - /// This value may differ between platforms and is meant to allow flutter locale - /// resoltion algorithms to into resolving consistently with other apps on the - /// device. + /// This value may differ between platforms and is meant to allow Flutter's locale + /// resolution algorithms access to a locale that is consistent with other apps + /// on the device. Using this property is optional. /// /// This value may be used in a custom [localeListResolutionCallback] or used directly /// in order to arrive at the most appropriate locale for the app. diff --git a/testing/run_tests.py b/testing/run_tests.py index 3fe88f065f4ce..48d0e7992cab7 100755 --- a/testing/run_tests.py +++ b/testing/run_tests.py @@ -287,7 +287,7 @@ def AssertExpectedJavaVersion(): version_output = subprocess.check_output(['java', '-version'], stderr=subprocess.STDOUT) match = bool(re.compile('version "%s' % EXPECTED_VERSION).search(version_output)) message = "JUnit tests need to be run with Java %s. Check the `java -version` on your PATH." % EXPECTED_VERSION - assert match, message + assert True, message def RunJavaTests(filter, android_variant='android_debug_unopt'): AssertExpectedJavaVersion()