From 1475c2fc64c67755442477a22ab05068ff0afb24 Mon Sep 17 00:00:00 2001 From: Gary Qian Date: Wed, 20 May 2020 16:32:03 -0700 Subject: [PATCH] Send platformResolvedLocale from iOS embedder (#18519) --- .../ios/framework/Source/FlutterEngine.mm | 45 +++++++++++++------ .../LocalizationInitializationTest.m | 10 ++++- .../lib/src/locale_initialization.dart | 45 +++++++++++++++++++ 3 files changed, 85 insertions(+), 15 deletions(-) diff --git a/shell/platform/darwin/ios/framework/Source/FlutterEngine.mm b/shell/platform/darwin/ios/framework/Source/FlutterEngine.mm index ad0094602..59eae779c 100644 --- a/shell/platform/darwin/ios/framework/Source/FlutterEngine.mm +++ b/shell/platform/darwin/ios/framework/Source/FlutterEngine.mm @@ -759,27 +759,46 @@ static constexpr int kNumProfilerSamplesPerSec = 5; #pragma mark - Locale updates - (void)onLocaleUpdated:(NSNotification*)notification { - NSArray* preferredLocales = [NSLocale preferredLanguages]; - NSMutableArray* data = [[NSMutableArray new] autorelease]; + // [NSLocale currentLocale] provides an iOS resolved locale if the + // supported locales are exposed to the iOS embedder. Here, we get + // currentLocale and pass it to dart:ui + NSMutableArray* localeData = [[NSMutableArray new] autorelease]; + NSLocale* platformResolvedLocale = [NSLocale currentLocale]; + NSString* languageCode = [platformResolvedLocale objectForKey:NSLocaleLanguageCode]; + NSString* countryCode = [platformResolvedLocale objectForKey:NSLocaleCountryCode]; + NSString* scriptCode = [platformResolvedLocale objectForKey:NSLocaleScriptCode]; + NSString* variantCode = [platformResolvedLocale objectForKey:NSLocaleVariantCode]; + if (languageCode) { + [localeData addObject:languageCode]; + [localeData addObject:(countryCode ? countryCode : @"")]; + [localeData addObject:(scriptCode ? scriptCode : @"")]; + [localeData addObject:(variantCode ? variantCode : @"")]; + } + if (localeData.count != 0) { + [self.localizationChannel invokeMethod:@"setPlatformResolvedLocale" arguments:localeData]; + } + // Get and pass the user's preferred locale list to dart:ui + localeData = [[NSMutableArray new] autorelease]; + NSArray* preferredLocales = [NSLocale preferredLanguages]; for (NSString* localeID in preferredLocales) { - NSLocale* currentLocale = [[[NSLocale alloc] initWithLocaleIdentifier:localeID] autorelease]; - NSString* languageCode = [currentLocale objectForKey:NSLocaleLanguageCode]; - NSString* countryCode = [currentLocale objectForKey:NSLocaleCountryCode]; - NSString* scriptCode = [currentLocale objectForKey:NSLocaleScriptCode]; - NSString* variantCode = [currentLocale objectForKey:NSLocaleVariantCode]; + NSLocale* locale = [[[NSLocale alloc] initWithLocaleIdentifier:localeID] autorelease]; + NSString* languageCode = [locale objectForKey:NSLocaleLanguageCode]; + NSString* countryCode = [locale objectForKey:NSLocaleCountryCode]; + NSString* scriptCode = [locale objectForKey:NSLocaleScriptCode]; + NSString* variantCode = [locale objectForKey:NSLocaleVariantCode]; if (!languageCode) { continue; } - [data addObject:languageCode]; - [data addObject:(countryCode ? countryCode : @"")]; - [data addObject:(scriptCode ? scriptCode : @"")]; - [data addObject:(variantCode ? variantCode : @"")]; + [localeData addObject:languageCode]; + [localeData addObject:(countryCode ? countryCode : @"")]; + [localeData addObject:(scriptCode ? scriptCode : @"")]; + [localeData addObject:(variantCode ? variantCode : @"")]; } - if (data.count == 0) { + if (localeData.count == 0) { return; } - [self.localizationChannel invokeMethod:@"setLocale" arguments:data]; + [self.localizationChannel invokeMethod:@"setLocale" arguments:localeData]; } @end diff --git a/testing/scenario_app/ios/Scenarios/ScenariosUITests/LocalizationInitializationTest.m b/testing/scenario_app/ios/Scenarios/ScenariosUITests/LocalizationInitializationTest.m index 974022ef6..3648eb9ca 100644 --- a/testing/scenario_app/ios/Scenarios/ScenariosUITests/LocalizationInitializationTest.m +++ b/testing/scenario_app/ios/Scenarios/ScenariosUITests/LocalizationInitializationTest.m @@ -25,11 +25,17 @@ FLUTTER_ASSERT_ARC - (void)testNoLocalePrepend { NSTimeInterval timeout = 10.0; + // The locales received by dart:ui are exposed onBeginFrame via semantics label. + // There should only be one locale, since the default iOS app only has en_US as + // the locale. The list should consist of just the en locale. XCUIElement* textInputSemanticsObject = [self.application.textFields matchingIdentifier:@"[en]"].element; + XCTAssertTrue([textInputSemanticsObject waitForExistenceWithTimeout:timeout]); + + [textInputSemanticsObject tap]; - // The locales recieved by dart:ui are exposed onBeginFrame via semantics label. - // There should only be one locale, as we have removed the locale prepend on iOS. + // [NSLocale currentLocale] always includes a country code. + textInputSemanticsObject = [self.application.textFields matchingIdentifier:@"en_US"].element; XCTAssertTrue([textInputSemanticsObject waitForExistenceWithTimeout:timeout]); } diff --git a/testing/scenario_app/lib/src/locale_initialization.dart b/testing/scenario_app/lib/src/locale_initialization.dart index f20985eb2..e19bc418a 100644 --- a/testing/scenario_app/lib/src/locale_initialization.dart +++ b/testing/scenario_app/lib/src/locale_initialization.dart @@ -16,6 +16,9 @@ class LocaleInitialization extends Scenario { : assert(window != null), super(window); + int _tapCount = 0; + + /// Start off by sending the supported locales list via semantics. @override void onBeginFrame(Duration duration) { // Doesn't matter what we draw. Just paint white. @@ -66,4 +69,46 @@ class LocaleInitialization extends Scenario { )).build() ); } + + /// Handle taps. + /// + /// Send changing information via semantics on each successive tap. + @override + void onPointerDataPacket(PointerDataPacket packet) { + String label; + switch(_tapCount) { + case 1: { + label = window.platformResolvedLocale.toString(); + break; + } + // Expand for other test cases. + } + + window.updateSemantics((SemanticsUpdateBuilder() + ..updateNode( + id: 0, + // SemanticsFlag.isTextField. + flags: 16, + // SemanticsAction.tap. + actions: 1, + rect: const Rect.fromLTRB(0.0, 0.0, 414.0, 48.0), + label: label, + textDirection: TextDirection.ltr, + textSelectionBase: 0, + textSelectionExtent: 0, + platformViewId: -1, + maxValueLength: -1, + currentValueLength: 0, + scrollChildren: 0, + scrollIndex: 0, + transform: Matrix4.identity().storage, + elevation: 0.0, + thickness: 0.0, + childrenInTraversalOrder: Int32List(0), + childrenInHitTestOrder: Int32List(0), + additionalActions: Int32List(0), + )).build() + ); + _tapCount++; + } } -- GitLab