From 6683dbfddbac98a4f980d96398dea0b5f17fc52d Mon Sep 17 00:00:00 2001 From: garyqian Date: Thu, 11 Oct 2018 17:19:52 -0700 Subject: [PATCH 1/4] Locale Passing --- lib/ui/hooks.dart | 16 ++++++ lib/ui/window.dart | 6 ++- lib/ui/window/window.cc | 15 ++++++ lib/ui/window/window.h | 3 ++ runtime/runtime_controller.cc | 31 +++++++++++ runtime/runtime_controller.h | 21 ++++++++ shell/common/engine.cc | 29 ++++++---- .../android/io/flutter/view/FlutterView.java | 12 +++++ .../framework/Source/FlutterViewController.mm | 54 ++++++++++++++----- 9 files changed, 164 insertions(+), 23 deletions(-) diff --git a/lib/ui/hooks.dart b/lib/ui/hooks.dart index 20980a0a1c41f..dd8e918ebfe33 100644 --- a/lib/ui/hooks.dart +++ b/lib/ui/hooks.dart @@ -53,6 +53,22 @@ void _updateLocale(String languageCode, String countryCode, String scriptCode, S _invoke(window.onLocaleChanged, window._onLocaleChangedZone); } +@pragma('vm:entry-point') +void _updateLocales(List locales) { + final int stringsPerLocale = 4; + int numLocales = (locales.length / stringsPerLocale).toInt(); + window._locales = new List(numLocales); + for (int localeIndex = 0; localeIndex < numLocales; ++localeIndex) { + // TODO(garyq): pass on the script and variant codes, which are the third and fourth elements + window._locales[localeIndex] = new Locale(locales[localeIndex * stringsPerLocale], + locales[localeIndex * stringsPerLocale + 1]); + } + print(window._locales); + window._locale = new Locale(locales[0], locales[1]); + _invoke(window.onLocaleChanged, window._onLocaleChangedZone); + print("FINISHED"); +} + @pragma('vm:entry-point') void _updateUserSettingsData(String jsonData) { final Map data = json.decode(jsonData); diff --git a/lib/ui/window.dart b/lib/ui/window.dart index 0b1318c997aaf..43d926cae4840 100644 --- a/lib/ui/window.dart +++ b/lib/ui/window.dart @@ -440,6 +440,10 @@ class Window { Locale get locale => _locale; Locale _locale; + + List get locales => _locales; + List _locales; + /// A callback that is invoked whenever [locale] changes value. /// /// The framework invokes this callback in the same zone in which the @@ -745,7 +749,7 @@ class Window { // Store the zone in which the callback is being registered. final Zone registrationZone = Zone.current; - + // assert(false); return (ByteData data) { registrationZone.runUnaryGuarded(callback, data); }; diff --git a/lib/ui/window/window.cc b/lib/ui/window/window.cc index 95be0076198cc..a27c6a60c50ec 100644 --- a/lib/ui/window/window.cc +++ b/lib/ui/window/window.cc @@ -4,6 +4,7 @@ #include "flutter/lib/ui/window/window.h" +#include "flutter/fml/logging.h" #include "flutter/lib/ui/compositing/scene.h" #include "flutter/lib/ui/ui_dart_state.h" #include "flutter/lib/ui/window/platform_message_response_dart.h" @@ -180,6 +181,20 @@ void Window::UpdateLocale(const std::string& language_code, }); } +void Window::UpdateLocales(const std::vector& locales) { + std::shared_ptr dart_state = library_.dart_state().lock(); + if (!dart_state) + return; + tonic::DartState::Scope scope(dart_state); + for (auto str : locales) { + FML_LOG(ERROR) << str; + } + DartInvokeField(library_.value(), "_updateLocales", + { + tonic::ToDart>(locales), + }); +} + 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 eb2a8c6613d07..4acfddaaa7356 100644 --- a/lib/ui/window/window.h +++ b/lib/ui/window/window.h @@ -5,7 +5,9 @@ #ifndef FLUTTER_LIB_UI_WINDOW_WINDOW_H_ #define FLUTTER_LIB_UI_WINDOW_WINDOW_H_ +#include #include +#include #include "flutter/fml/time/time_point.h" #include "flutter/lib/ui/semantics/semantics_update.h" @@ -63,6 +65,7 @@ class Window final { const std::string& country_code, const std::string& script_code, const std::string& variant_code); + void UpdateLocales(const std::vector& locales); void UpdateUserSettingsData(const std::string& data); void UpdateSemanticsEnabled(bool enabled); void UpdateAccessibilityFeatures(int32_t flags); diff --git a/runtime/runtime_controller.cc b/runtime/runtime_controller.cc index 7e0bd024c66cc..cec7989ccc07a 100644 --- a/runtime/runtime_controller.cc +++ b/runtime/runtime_controller.cc @@ -4,6 +4,7 @@ #include "flutter/runtime/runtime_controller.h" +#include "flutter/fml/logging.h" #include "flutter/fml/message_loop.h" #include "flutter/fml/trace_event.h" #include "flutter/lib/ui/compositing/scene.h" @@ -158,6 +159,36 @@ bool RuntimeController::SetLocale(const std::string& language_code, return false; } +bool RuntimeController::SetLocales( + const std::vector& locale_data) { + const size_t strings_per_locale = 4; + FML_DLOG(ERROR) << "RUNTIME CONTROLLER SET LOCALES"; + for (auto str : locale_data) { + FML_LOG(ERROR) << str; + } + for (size_t locale_index = 0; + locale_index < locale_data.size() / strings_per_locale; ++locale_index) { + window_data_.locales.emplace_back( + locale_data[locale_index * strings_per_locale], + locale_data[locale_index * strings_per_locale + 1], + locale_data[locale_index * strings_per_locale + 2], + locale_data[locale_index * strings_per_locale + 3]); + } + // window_data_.language_code = language_code; + // window_data_.country_code = country_code; + // window_data_.script_code = script_code; + // window_data_.variant_code = variant_code; + + if (auto window = GetWindowIfAvailable()) { + window->UpdateLocales(locale_data); + return true; + } + + // return false; + + return true; +} + 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 67c7f3e44cb83..deb23c22dea03 100644 --- a/runtime/runtime_controller.h +++ b/runtime/runtime_controller.h @@ -6,6 +6,7 @@ #define FLUTTER_RUNTIME_RUNTIME_CONTROLLER_H_ #include +#include #include "flutter/common/task_runners.h" #include "flutter/flow/layers/layer_tree.h" @@ -15,6 +16,8 @@ #include "flutter/lib/ui/window/pointer_data_packet.h" #include "flutter/lib/ui/window/window.h" #include "flutter/runtime/dart_vm.h" +#include "rapidjson/document.h" +#include "rapidjson/stringbuffer.h" namespace blink { class Scene; @@ -44,6 +47,7 @@ class RuntimeController final : public WindowClient { const std::string& country_code, const std::string& script_code, const std::string& variant_code); + bool SetLocales(const std::vector& locale_data); bool SetUserSettingsData(const std::string& data); @@ -78,12 +82,29 @@ class RuntimeController final : public WindowClient { std::pair GetRootIsolateReturnCode(); private: + struct Locale { + Locale(std::string language_code_, + std::string country_code_, + std::string script_code_, + std::string variant_code_) + : language_code(language_code_), + country_code(country_code_), + script_code(script_code_), + variant_code(variant_code_) {} + + std::string language_code; + std::string country_code; + std::string script_code; + std::string variant_code; + }; + struct WindowData { ViewportMetrics viewport_metrics; std::string language_code; std::string country_code; std::string script_code; std::string variant_code; + std::vector locales; std::string user_settings_data = "{}"; bool semantics_enabled = false; bool assistive_technology_enabled = false; diff --git a/shell/common/engine.cc b/shell/common/engine.cc index 5e1f53a55912d..93874b853247a 100644 --- a/shell/common/engine.cc +++ b/shell/common/engine.cc @@ -7,6 +7,7 @@ #include #include #include +#include #include "flutter/common/settings.h" #include "flutter/fml/eintr_wrapper.h" @@ -325,17 +326,27 @@ bool Engine::HandleLocalizationPlatformMessage( if (args == root.MemberEnd() || !args->value.IsArray()) return false; - const auto& language = args->value[0]; - const auto& country = args->value[1]; - const auto& script = args->value[2]; - const auto& variant = args->value[3]; - - if (!language.IsString() || !country.IsString()) + if (args->value.Size() % 4 != 0) return false; - return runtime_controller_->SetLocale(language.GetString(), - country.GetString(), script.GetString(), - variant.GetString()); + std::vector locale_data; + for (size_t index = 0; index < args->value.Size(); ++index) { + locale_data.push_back(args->value[index].GetString()); + FML_DLOG(ERROR) << locale_data[locale_data.size() - 1]; + } + // for (autoĆ·) + // const auto& language = args->value[0]; + // const auto& country = args->value[1]; + // const auto& script = args->value[2]; + // const auto& variant = args->value[3]; + + // if (!language.IsString() || !country.IsString()) + // return false; + + // return runtime_controller_->SetLocales( + // language.GetString(), country.GetString(), script.GetString(), + // variant.GetString()); + return runtime_controller_->SetLocales(locale_data); } void Engine::HandleSettingsPlatformMessage(blink::PlatformMessage* message) { diff --git a/shell/platform/android/io/flutter/view/FlutterView.java b/shell/platform/android/io/flutter/view/FlutterView.java index 8778877486875..c6ea1a132b234 100644 --- a/shell/platform/android/io/flutter/view/FlutterView.java +++ b/shell/platform/android/io/flutter/view/FlutterView.java @@ -171,6 +171,7 @@ public void surfaceDestroyed(SurfaceHolder holder) { mTextInputPlugin = new TextInputPlugin(this); setLocale(getResources().getConfiguration().locale); + setLocales(getResources().getConfiguration().getLocales()); setUserSettings(); } @@ -320,6 +321,17 @@ private void setLocale(Locale locale) { mFlutterLocalizationChannel.invokeMethod("setLocale", Arrays.asList(locale.getLanguage(), locale.getCountry(), locale.getScript(), locale.getVariant())); } + private void setLocales(LocaleList locales) { + List data = new ArrayList(); + for (int index = 0; index < locales.size(); ++index) { + data.add(locales.get(index).getLanguage); + data.add(locales.get(index).getCountry); + data.add(locales.get(index).getScript); + data.add(locales.get(index).getVariant); + } + mFlutterLocalizationChannel.invokeMethod("setLocale", data); + } + @Override protected void onConfigurationChanged(Configuration newConfig) { super.onConfigurationChanged(newConfig); diff --git a/shell/platform/darwin/ios/framework/Source/FlutterViewController.mm b/shell/platform/darwin/ios/framework/Source/FlutterViewController.mm index 471e88e2dc5ca..32b9a2ea2ca19 100644 --- a/shell/platform/darwin/ios/framework/Source/FlutterViewController.mm +++ b/shell/platform/darwin/ios/framework/Source/FlutterViewController.mm @@ -891,19 +891,47 @@ - (void)onMemoryWarning:(NSNotification*)notification { #pragma mark - Locale updates - (void)onLocaleUpdated:(NSNotification*)notification { - NSLocale* currentLocale = [NSLocale currentLocale]; - NSString* languageCode = [currentLocale objectForKey:NSLocaleLanguageCode]; - NSString* countryCode = [currentLocale objectForKey:NSLocaleCountryCode]; - NSString* scriptCode = [currentLocale objectForKey:NSLocaleScriptCode]; - NSString* variantCode = [currentLocale objectForKey:NSLocaleVariantCode]; - if (languageCode && countryCode) - // We pass empty strings for undefined scripts and variants to ensure the JSON encoder/decoder - // functions properly. - [_localizationChannel.get() invokeMethod:@"setLocale" - arguments:@[ - languageCode, countryCode, scriptCode ? scriptCode : @"", - variantCode ? variantCode : @"" - ]]; + NSArray* preferredLocales = [NSLocale preferredLanguages]; + NSMutableArray* data = [NSMutableArray new]; + for (NSString* localeID in preferredLocales) { + NSLocale* currentLocale = [[NSLocale alloc] initWithLocaleIdentifier:localeID]; + NSString* languageCode = [currentLocale objectForKey:NSLocaleLanguageCode]; + NSString* countryCode = [currentLocale objectForKey:NSLocaleCountryCode]; + NSString* scriptCode = [currentLocale objectForKey:NSLocaleScriptCode]; + NSString* variantCode = [currentLocale objectForKey:NSLocaleVariantCode]; + if (!languageCode || !countryCode) { + continue; + } + [data addObject:languageCode]; + [data addObject:countryCode]; + [data addObject:(scriptCode ? scriptCode : @"")]; + [data addObject:(variantCode ? variantCode : @"")]; + + // // functions properly. + // [_localizationChannel.get() invokeMethod:@"setLocale" + // arguments:@[ + // languageCode, countryCode, scriptCode ? scriptCode : @"", + // variantCode ? variantCode : @"" + // ]]; + } + if (data.count == 0) { + return; + } + [_localizationChannel.get() invokeMethod:@"setLocale" arguments:data]; + // NSLocale* currentLocale = [NSLocale currentLocale]; + // NSString* languageCode = [currentLocale objectForKey:NSLocaleLanguageCode]; + // NSString* countryCode = [currentLocale objectForKey:NSLocaleCountryCode]; + // NSString* scriptCode = [currentLocale objectForKey:NSLocaleScriptCode]; + // NSString* variantCode = [currentLocale objectForKey:NSLocaleVariantCode]; + // if (languageCode && countryCode) + // // We pass empty strings for undefined scripts and variants to ensure the JSON + // encoder/decoder + // // functions properly. + // [_localizationChannel.get() invokeMethod:@"setLocale" + // arguments:@[ + // languageCode, countryCode, scriptCode ? scriptCode : @"", + // variantCode ? variantCode : @"" + // ]]; } #pragma mark - Set user settings From d6a1ab7a3e24a8bd78364238430444fe1cf0c8e4 Mon Sep 17 00:00:00 2001 From: garyqian Date: Tue, 16 Oct 2018 10:40:46 -0700 Subject: [PATCH 2/4] Pass full locale list and script and variant codes to framework --- lib/ui/hooks.dart | 18 ++------ lib/ui/window.dart | 28 +++++++++--- lib/ui/window/window.cc | 22 ---------- lib/ui/window/window.h | 4 -- runtime/runtime_controller.cc | 43 +------------------ runtime/runtime_controller.h | 6 +-- shell/common/engine.cc | 29 ++++++------- .../android/io/flutter/view/FlutterView.java | 1 - .../framework/Source/FlutterViewController.mm | 21 --------- 9 files changed, 42 insertions(+), 130 deletions(-) diff --git a/lib/ui/hooks.dart b/lib/ui/hooks.dart index dd8e918ebfe33..7f8a8af0327d5 100644 --- a/lib/ui/hooks.dart +++ b/lib/ui/hooks.dart @@ -42,31 +42,21 @@ void _updateWindowMetrics(double devicePixelRatio, typedef _LocaleClosure = String Function(); -String _localeClosure() => window._locale.toString(); +String _localeClosure() => window.locale.toString(); @pragma('vm:entry-point') _LocaleClosure _getLocaleClosure() => _localeClosure; -@pragma('vm:entry-point') -void _updateLocale(String languageCode, String countryCode, String scriptCode, String variantCode) { - window._locale = new Locale(languageCode, countryCode); - _invoke(window.onLocaleChanged, window._onLocaleChangedZone); -} - @pragma('vm:entry-point') void _updateLocales(List locales) { final int stringsPerLocale = 4; int numLocales = (locales.length / stringsPerLocale).toInt(); window._locales = new List(numLocales); - for (int localeIndex = 0; localeIndex < numLocales; ++localeIndex) { - // TODO(garyq): pass on the script and variant codes, which are the third and fourth elements - window._locales[localeIndex] = new Locale(locales[localeIndex * stringsPerLocale], - locales[localeIndex * stringsPerLocale + 1]); + for (int localeIndex = 0; localeIndex < numLocales; localeIndex += stringsPerLocale) { + window._locales[localeIndex] = new Locale(locales[localeIndex], + locales[localeIndex + 1]); } - print(window._locales); - window._locale = new Locale(locales[0], locales[1]); _invoke(window.onLocaleChanged, window._onLocaleChangedZone); - print("FINISHED"); } @pragma('vm:entry-point') diff --git a/lib/ui/window.dart b/lib/ui/window.dart index 43d926cae4840..e40eef5a2153f 100644 --- a/lib/ui/window.dart +++ b/lib/ui/window.dart @@ -426,21 +426,37 @@ class Window { _onMetricsChangedZone = Zone.current; } - /// The system-reported locale. + /// The system-reported default locale of the device. /// /// This establishes the language and formatting conventions that application /// should, if possible, use to render their user interface. /// + /// This is the first locale selected by the user and should be the user's + /// primary locale. + /// + /// This is equivalent to `locales[0]` and will provide an empty non-null locale + /// if the [locales] list has not been set or is empty. + Locale get locale { + if (_locales != null && _locales.length != 0) { + return _locales[0]; + } + return new Locale("", ""); + } + + /// The full system-reported supported locales of the device. + /// + /// This establishes the language and formatting conventions that application + /// should, if possible, use to render their user interface. + /// + /// The list is ordered in order of priority, with lower-indexed locales being + /// preferred over higher-indexed ones. The zeroth element is the default [locale]. + /// /// The [onLocaleChanged] callback is called whenever this value changes. /// /// See also: /// /// * [WidgetsBindingObserver], for a mechanism at the widgets layer to /// observe when this value changes. - Locale get locale => _locale; - Locale _locale; - - List get locales => _locales; List _locales; @@ -749,7 +765,7 @@ class Window { // Store the zone in which the callback is being registered. final Zone registrationZone = Zone.current; - // assert(false); + return (ByteData data) { registrationZone.runUnaryGuarded(callback, data); }; diff --git a/lib/ui/window/window.cc b/lib/ui/window/window.cc index a27c6a60c50ec..ce4626afa74e7 100644 --- a/lib/ui/window/window.cc +++ b/lib/ui/window/window.cc @@ -4,7 +4,6 @@ #include "flutter/lib/ui/window/window.h" -#include "flutter/fml/logging.h" #include "flutter/lib/ui/compositing/scene.h" #include "flutter/lib/ui/ui_dart_state.h" #include "flutter/lib/ui/window/platform_message_response_dart.h" @@ -163,32 +162,11 @@ void Window::UpdateWindowMetrics(const ViewportMetrics& metrics) { }); } -void Window::UpdateLocale(const std::string& language_code, - const std::string& country_code, - const std::string& script_code, - const std::string& variant_code) { - std::shared_ptr dart_state = library_.dart_state().lock(); - if (!dart_state) - return; - tonic::DartState::Scope scope(dart_state); - - DartInvokeField(library_.value(), "_updateLocale", - { - StdStringToDart(language_code), - StdStringToDart(country_code), - StdStringToDart(script_code), - StdStringToDart(variant_code), - }); -} - void Window::UpdateLocales(const std::vector& locales) { std::shared_ptr dart_state = library_.dart_state().lock(); if (!dart_state) return; tonic::DartState::Scope scope(dart_state); - for (auto str : locales) { - FML_LOG(ERROR) << str; - } DartInvokeField(library_.value(), "_updateLocales", { tonic::ToDart>(locales), diff --git a/lib/ui/window/window.h b/lib/ui/window/window.h index 4acfddaaa7356..bc1e3ba267f73 100644 --- a/lib/ui/window/window.h +++ b/lib/ui/window/window.h @@ -61,10 +61,6 @@ class Window final { void DidCreateIsolate(); void UpdateWindowMetrics(const ViewportMetrics& metrics); - void UpdateLocale(const std::string& language_code, - const std::string& country_code, - const std::string& script_code, - const std::string& variant_code); void UpdateLocales(const std::vector& locales); void UpdateUserSettingsData(const std::string& data); void UpdateSemanticsEnabled(bool enabled); diff --git a/runtime/runtime_controller.cc b/runtime/runtime_controller.cc index cec7989ccc07a..92fb962437969 100644 --- a/runtime/runtime_controller.cc +++ b/runtime/runtime_controller.cc @@ -4,7 +4,6 @@ #include "flutter/runtime/runtime_controller.h" -#include "flutter/fml/logging.h" #include "flutter/fml/message_loop.h" #include "flutter/fml/trace_event.h" #include "flutter/lib/ui/compositing/scene.h" @@ -125,8 +124,7 @@ std::unique_ptr RuntimeController::Clone() const { bool RuntimeController::FlushRuntimeStateToIsolate() { return SetViewportMetrics(window_data_.viewport_metrics) && - SetLocale(window_data_.language_code, window_data_.country_code, - window_data_.script_code, window_data_.variant_code) && + SetLocales(window_data_.locale_data) && SetSemanticsEnabled(window_data_.semantics_enabled) && SetAccessibilityFeatures(window_data_.accessibility_feature_flags_); } @@ -141,51 +139,14 @@ bool RuntimeController::SetViewportMetrics(const ViewportMetrics& metrics) { return false; } -bool RuntimeController::SetLocale(const std::string& language_code, - const std::string& country_code, - const std::string& script_code, - const std::string& variant_code) { - window_data_.language_code = language_code; - window_data_.country_code = country_code; - window_data_.script_code = script_code; - window_data_.variant_code = variant_code; - - if (auto window = GetWindowIfAvailable()) { - window->UpdateLocale(window_data_.language_code, window_data_.country_code, - window_data_.script_code, window_data_.variant_code); - return true; - } - - return false; -} - bool RuntimeController::SetLocales( const std::vector& locale_data) { - const size_t strings_per_locale = 4; - FML_DLOG(ERROR) << "RUNTIME CONTROLLER SET LOCALES"; - for (auto str : locale_data) { - FML_LOG(ERROR) << str; - } - for (size_t locale_index = 0; - locale_index < locale_data.size() / strings_per_locale; ++locale_index) { - window_data_.locales.emplace_back( - locale_data[locale_index * strings_per_locale], - locale_data[locale_index * strings_per_locale + 1], - locale_data[locale_index * strings_per_locale + 2], - locale_data[locale_index * strings_per_locale + 3]); - } - // window_data_.language_code = language_code; - // window_data_.country_code = country_code; - // window_data_.script_code = script_code; - // window_data_.variant_code = variant_code; + window_data_.locale_data = locale_data; if (auto window = GetWindowIfAvailable()) { window->UpdateLocales(locale_data); return true; } - - // return false; - return true; } diff --git a/runtime/runtime_controller.h b/runtime/runtime_controller.h index deb23c22dea03..532499cb51e1d 100644 --- a/runtime/runtime_controller.h +++ b/runtime/runtime_controller.h @@ -43,10 +43,6 @@ class RuntimeController final : public WindowClient { bool SetViewportMetrics(const ViewportMetrics& metrics); - bool SetLocale(const std::string& language_code, - const std::string& country_code, - const std::string& script_code, - const std::string& variant_code); bool SetLocales(const std::vector& locale_data); bool SetUserSettingsData(const std::string& data); @@ -104,7 +100,7 @@ class RuntimeController final : public WindowClient { std::string country_code; std::string script_code; std::string variant_code; - std::vector locales; + std::vector locale_data; std::string user_settings_data = "{}"; bool semantics_enabled = false; bool assistive_technology_enabled = false; diff --git a/shell/common/engine.cc b/shell/common/engine.cc index 93874b853247a..d6002a6d40318 100644 --- a/shell/common/engine.cc +++ b/shell/common/engine.cc @@ -326,26 +326,23 @@ bool Engine::HandleLocalizationPlatformMessage( if (args == root.MemberEnd() || !args->value.IsArray()) return false; - if (args->value.Size() % 4 != 0) + const size_t strings_per_locale = 4; + if (args->value.Size() % strings_per_locale != 0) return false; std::vector locale_data; - for (size_t index = 0; index < args->value.Size(); ++index) { - locale_data.push_back(args->value[index].GetString()); - FML_DLOG(ERROR) << locale_data[locale_data.size() - 1]; + for (size_t locale_index = 0; + locale_index < args->value.Size() / strings_per_locale; + 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()); } - // for (autoĆ·) - // const auto& language = args->value[0]; - // const auto& country = args->value[1]; - // const auto& script = args->value[2]; - // const auto& variant = args->value[3]; - - // if (!language.IsString() || !country.IsString()) - // return false; - - // return runtime_controller_->SetLocales( - // language.GetString(), country.GetString(), script.GetString(), - // variant.GetString()); + return runtime_controller_->SetLocales(locale_data); } diff --git a/shell/platform/android/io/flutter/view/FlutterView.java b/shell/platform/android/io/flutter/view/FlutterView.java index c6ea1a132b234..ae431afc44f32 100644 --- a/shell/platform/android/io/flutter/view/FlutterView.java +++ b/shell/platform/android/io/flutter/view/FlutterView.java @@ -170,7 +170,6 @@ public void surfaceDestroyed(SurfaceHolder holder) { mImm = (InputMethodManager) getContext().getSystemService(Context.INPUT_METHOD_SERVICE); mTextInputPlugin = new TextInputPlugin(this); - setLocale(getResources().getConfiguration().locale); setLocales(getResources().getConfiguration().getLocales()); setUserSettings(); } diff --git a/shell/platform/darwin/ios/framework/Source/FlutterViewController.mm b/shell/platform/darwin/ios/framework/Source/FlutterViewController.mm index ad53fc7a9e42c..05b9a7d502124 100644 --- a/shell/platform/darwin/ios/framework/Source/FlutterViewController.mm +++ b/shell/platform/darwin/ios/framework/Source/FlutterViewController.mm @@ -915,32 +915,11 @@ - (void)onLocaleUpdated:(NSNotification*)notification { [data addObject:countryCode]; [data addObject:(scriptCode ? scriptCode : @"")]; [data addObject:(variantCode ? variantCode : @"")]; - - // // functions properly. - // [_localizationChannel.get() invokeMethod:@"setLocale" - // arguments:@[ - // languageCode, countryCode, scriptCode ? scriptCode : @"", - // variantCode ? variantCode : @"" - // ]]; } if (data.count == 0) { return; } [_localizationChannel.get() invokeMethod:@"setLocale" arguments:data]; - // NSLocale* currentLocale = [NSLocale currentLocale]; - // NSString* languageCode = [currentLocale objectForKey:NSLocaleLanguageCode]; - // NSString* countryCode = [currentLocale objectForKey:NSLocaleCountryCode]; - // NSString* scriptCode = [currentLocale objectForKey:NSLocaleScriptCode]; - // NSString* variantCode = [currentLocale objectForKey:NSLocaleVariantCode]; - // if (languageCode && countryCode) - // // We pass empty strings for undefined scripts and variants to ensure the JSON - // encoder/decoder - // // functions properly. - // [_localizationChannel.get() invokeMethod:@"setLocale" - // arguments:@[ - // languageCode, countryCode, scriptCode ? scriptCode : @"", - // variantCode ? variantCode : @"" - // ]]; } #pragma mark - Set user settings From 82b892f0b2ab36a00d082d77ff3a513e23b065f2 Mon Sep 17 00:00:00 2001 From: garyqian Date: Tue, 16 Oct 2018 15:10:47 -0700 Subject: [PATCH 3/4] Working Android locale list passing and fallback --- lib/ui/hooks.dart | 6 +-- lib/ui/window.dart | 19 ++++---- shell/common/engine.cc | 4 +- .../android/io/flutter/view/FlutterView.java | 48 +++++++++++++------ 4 files changed, 49 insertions(+), 28 deletions(-) diff --git a/lib/ui/hooks.dart b/lib/ui/hooks.dart index 7f8a8af0327d5..2fe93e4e626fd 100644 --- a/lib/ui/hooks.dart +++ b/lib/ui/hooks.dart @@ -52,9 +52,9 @@ void _updateLocales(List locales) { final int stringsPerLocale = 4; int numLocales = (locales.length / stringsPerLocale).toInt(); window._locales = new List(numLocales); - for (int localeIndex = 0; localeIndex < numLocales; localeIndex += stringsPerLocale) { - window._locales[localeIndex] = new Locale(locales[localeIndex], - locales[localeIndex + 1]); + for (int localeIndex = 0; localeIndex < numLocales; localeIndex++) { + window._locales[localeIndex] = new Locale(locales[localeIndex * stringsPerLocale], + locales[localeIndex * stringsPerLocale + 1]); } _invoke(window.onLocaleChanged, window._onLocaleChangedZone); } diff --git a/lib/ui/window.dart b/lib/ui/window.dart index e40eef5a2153f..fa0431b3113d8 100644 --- a/lib/ui/window.dart +++ b/lib/ui/window.dart @@ -152,6 +152,9 @@ class Locale { /// the region subtag should be uppercase. const Locale(this._languageCode, [ this._countryCode ]) : assert(_languageCode != null); + /// Empty locale constant. This is an invalid locale. + static const Locale none = const Locale('', ''); + /// The primary language subtag for the locale. /// /// This must not be null. @@ -431,16 +434,16 @@ class Window { /// This establishes the language and formatting conventions that application /// should, if possible, use to render their user interface. /// - /// This is the first locale selected by the user and should be the user's - /// primary locale. - /// - /// This is equivalent to `locales[0]` and will provide an empty non-null locale + /// This is the first locale selected by the user and is the user's + /// primary locale (the locale the device UI is displayed in) + /// + /// This is equivalent to `locales.first` and will provide an empty non-null locale /// if the [locales] list has not been set or is empty. Locale get locale { - if (_locales != null && _locales.length != 0) { - return _locales[0]; + if (_locales != null && _locales.isNotEmpty) { + return _locales.first; } - return new Locale("", ""); + return Locale.none; } /// The full system-reported supported locales of the device. @@ -449,7 +452,7 @@ class Window { /// should, if possible, use to render their user interface. /// /// The list is ordered in order of priority, with lower-indexed locales being - /// preferred over higher-indexed ones. The zeroth element is the default [locale]. + /// preferred over higher-indexed ones. The first element is the primary [locale]. /// /// The [onLocaleChanged] callback is called whenever this value changes. /// diff --git a/shell/common/engine.cc b/shell/common/engine.cc index d6002a6d40318..3ab484c46f37c 100644 --- a/shell/common/engine.cc +++ b/shell/common/engine.cc @@ -329,10 +329,8 @@ bool Engine::HandleLocalizationPlatformMessage( 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() / strings_per_locale; + 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()) diff --git a/shell/platform/android/io/flutter/view/FlutterView.java b/shell/platform/android/io/flutter/view/FlutterView.java index ae431afc44f32..4f1f151d74705 100644 --- a/shell/platform/android/io/flutter/view/FlutterView.java +++ b/shell/platform/android/io/flutter/view/FlutterView.java @@ -37,6 +37,7 @@ import org.json.JSONException; import org.json.JSONObject; +import java.lang.reflect.Method; import java.net.URI; import java.nio.ByteBuffer; import java.nio.ByteOrder; @@ -170,7 +171,8 @@ public void surfaceDestroyed(SurfaceHolder holder) { mImm = (InputMethodManager) getContext().getSystemService(Context.INPUT_METHOD_SERVICE); mTextInputPlugin = new TextInputPlugin(this); - setLocales(getResources().getConfiguration().getLocales()); + + setLocales(getResources().getConfiguration()); setUserSettings(); } @@ -316,25 +318,43 @@ private void setUserSettings() { mFlutterSettingsChannel.send(message); } - private void setLocale(Locale locale) { - mFlutterLocalizationChannel.invokeMethod("setLocale", Arrays.asList(locale.getLanguage(), locale.getCountry(), locale.getScript(), locale.getVariant())); - } - - private void setLocales(LocaleList locales) { - List data = new ArrayList(); - for (int index = 0; index < locales.size(); ++index) { - data.add(locales.get(index).getLanguage); - data.add(locales.get(index).getCountry); - data.add(locales.get(index).getScript); - data.add(locales.get(index).getVariant); + private void setLocales(Configuration config) { + if (Build.VERSION.SDK_INT >= 24) { + try { + // Passes the full list of locales for android API >= 24 with reflection. + Object localeList = config.getClass().getDeclaredMethod("getLocales").invoke(config); + Method localeListGet = localeList.getClass().getDeclaredMethod("get", int.class); + Method localeListSize = localeList.getClass().getDeclaredMethod("size"); + int localeCount = (int)localeListSize.invoke(localeList); + List data = new ArrayList(); + for (int index = 0; index < localeCount; ++index) { + Locale locale = (Locale)localeListGet.invoke(localeList, index); + data.add(locale.getLanguage()); + data.add(locale.getCountry()); + data.add(locale.getScript()); + data.add(locale.getVariant()); + } + mFlutterLocalizationChannel.invokeMethod("setLocale", data); + return; + } catch (Exception exception) { + // Any exception is a failure. Resort to fallback of sending only one locale. + } } - mFlutterLocalizationChannel.invokeMethod("setLocale", data); + // Fallback single locale passing for android API < 24. Should work always. + Locale locale = config.locale; + List data = new ArrayList(); + data.add(locale.getLanguage()); + data.add(locale.getCountry()); + data.add(locale.getScript()); + data.add(locale.getVariant()); + mFlutterLocalizationChannel.invokeMethod("setLocale", Arrays.asList(locale.getLanguage(), locale.getCountry(), locale.getScript(), locale.getVariant())); + } @Override protected void onConfigurationChanged(Configuration newConfig) { super.onConfigurationChanged(newConfig); - setLocale(newConfig.locale); + setLocales(newConfig); setUserSettings(); } From a5390e4cf70518f2bd4a0ef47e9e6ffadb56eb20 Mon Sep 17 00:00:00 2001 From: GaryQian Date: Tue, 16 Oct 2018 17:06:48 -0700 Subject: [PATCH 4/4] Fix tests --- lib/ui/hooks.dart | 4 ++-- testing/dart/window_hooks_integration_test.dart | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/ui/hooks.dart b/lib/ui/hooks.dart index 2fe93e4e626fd..d3d81b7f3cc7d 100644 --- a/lib/ui/hooks.dart +++ b/lib/ui/hooks.dart @@ -49,8 +49,8 @@ _LocaleClosure _getLocaleClosure() => _localeClosure; @pragma('vm:entry-point') void _updateLocales(List locales) { - final int stringsPerLocale = 4; - int numLocales = (locales.length / stringsPerLocale).toInt(); + const int stringsPerLocale = 4; + final int numLocales = locales.length ~/ stringsPerLocale; window._locales = new List(numLocales); for (int localeIndex = 0; localeIndex < numLocales; localeIndex++) { window._locales[localeIndex] = new Locale(locales[localeIndex * stringsPerLocale], diff --git a/testing/dart/window_hooks_integration_test.dart b/testing/dart/window_hooks_integration_test.dart index b56aaeee4d1e9..1e362f403ceb2 100644 --- a/testing/dart/window_hooks_integration_test.dart +++ b/testing/dart/window_hooks_integration_test.dart @@ -100,7 +100,7 @@ void main() { }; }); - _updateLocale('en', 'US', '', ''); + _updateLocales(['en', 'US', '', '']); expect(runZone, isNotNull); expect(runZone, same(innerZone)); expect(locale, equals(const Locale('en', 'US')));