From a4d1fef59dc21da5a406741f2b2ca7594b063d05 Mon Sep 17 00:00:00 2001 From: ferhatb Date: Tue, 23 Mar 2021 12:05:42 -0700 Subject: [PATCH 1/2] Add samsung browser detection --- .../lib/src/engine/browser_detection.dart | 28 +++++++++- .../engine/semantics/semantics_helper.dart | 7 +-- .../lib/src/engine/semantics/text_field.dart | 1 + .../src/engine/text_editing/text_editing.dart | 4 +- lib/web_ui/test/browser_detect_test.dart | 51 +++++++++++++++++++ .../text/canvas_paragraph_builder_test.dart | 4 +- lib/web_ui/test/text_editing_test.dart | 2 + 7 files changed, 91 insertions(+), 6 deletions(-) create mode 100644 lib/web_ui/test/browser_detect_test.dart diff --git a/lib/web_ui/lib/src/engine/browser_detection.dart b/lib/web_ui/lib/src/engine/browser_detection.dart index 88eed23c4110a..3bcf63640081f 100644 --- a/lib/web_ui/lib/src/engine/browser_detection.dart +++ b/lib/web_ui/lib/src/engine/browser_detection.dart @@ -23,6 +23,9 @@ enum BrowserEngine { /// The engine that powers Internet Explorer 11. ie11, + /// The engine that powers Samsung stock browser. It is based on blink. + samsung, + /// We were unable to detect the current browser engine. unknown, } @@ -56,7 +59,31 @@ BrowserEngine get browserEngine { BrowserEngine _detectBrowserEngine() { final String vendor = html.window.navigator.vendor; final String agent = html.window.navigator.userAgent.toLowerCase(); + return detectBrowserEngineByVendorAgent(vendor, agent); +} + +/// Detects samsung blink variants. +/// +/// Example patterns: +/// Note 2 : GT-N7100 +/// Note 3 : SM-N900T +/// Tab 4 : SM-T330NU +/// Galaxy S4: SHV-E330S +/// Galaxy Note2: SHV-E250L +/// Note: SAMSUNG-SGH-I717 +/// SPH/SCH are very old Palm models. +bool _isSamsungBrowser(String agent) { + final RegExp exp = new RegExp(r"SAMSUNG|SGH-[I|N|T]|GT-[I|N]|SM-[A|N|P|T|Z]|SHV-E|SCH-[I|J|R|S]|SPH-L"); + return exp.hasMatch(agent.toUpperCase()); +} + +@visibleForTesting +BrowserEngine detectBrowserEngineByVendorAgent(String vendor, String agent) { if (vendor == 'Google Inc.') { + // Samsung browser is based on blink, check for variant. + if (_isSamsungBrowser(agent)) { + return BrowserEngine.samsung; + } return BrowserEngine.blink; } else if (vendor == 'Apple Computer, Inc.') { return BrowserEngine.webkit; @@ -73,7 +100,6 @@ BrowserEngine _detectBrowserEngine() { // https://developer.mozilla.org/en-US/docs/Web/API/Navigator/vendor return BrowserEngine.firefox; } - // Assume unknown otherwise, but issue a warning. print('WARNING: failed to detect current browser engine.'); return BrowserEngine.unknown; diff --git a/lib/web_ui/lib/src/engine/semantics/semantics_helper.dart b/lib/web_ui/lib/src/engine/semantics/semantics_helper.dart index 0b9245b922c8d..505e26be827c4 100644 --- a/lib/web_ui/lib/src/engine/semantics/semantics_helper.dart +++ b/lib/web_ui/lib/src/engine/semantics/semantics_helper.dart @@ -311,9 +311,10 @@ class MobileSemanticsEnabler extends SemanticsEnabler { // In Chrome the debouncing works well enough to detect accessibility // request. final bool blinkEnableConditionPassed = - browserEngine == BrowserEngine.blink && - EngineSemanticsOwner.instance.gestureMode == - GestureMode.browserGestures; + (browserEngine == BrowserEngine.blink || + browserEngine == BrowserEngine.samsung) && + EngineSemanticsOwner.instance.gestureMode == + GestureMode.browserGestures; // In Safari debouncing doesn't work. Instead we look at where exactly // (within 1 pixel) the event landed. If it landed exactly in the middle of diff --git a/lib/web_ui/lib/src/engine/semantics/text_field.dart b/lib/web_ui/lib/src/engine/semantics/text_field.dart index c1e291b8d49c3..fe015103d485d 100644 --- a/lib/web_ui/lib/src/engine/semantics/text_field.dart +++ b/lib/web_ui/lib/src/engine/semantics/text_field.dart @@ -193,6 +193,7 @@ class TextField extends RoleManager { switch (browserEngine) { case BrowserEngine.blink: + case BrowserEngine.samsung: case BrowserEngine.edge: case BrowserEngine.ie11: case BrowserEngine.firefox: diff --git a/lib/web_ui/lib/src/engine/text_editing/text_editing.dart b/lib/web_ui/lib/src/engine/text_editing/text_editing.dart index d2a7eb0c6cf23..eb8304702f498 100644 --- a/lib/web_ui/lib/src/engine/text_editing/text_editing.dart +++ b/lib/web_ui/lib/src/engine/text_editing/text_editing.dart @@ -15,6 +15,7 @@ const int _kReturnKeyCode = 13; /// is autofilled. bool browserHasAutofillOverlay() => browserEngine == BrowserEngine.blink || + browserEngine == BrowserEngine.samsung || browserEngine == BrowserEngine.webkit; /// `transparentTextEditing` class is configured to make the autofill overlay @@ -1478,7 +1479,8 @@ class HybridTextEditing { this._defaultEditingElement = IOSTextEditingStrategy(this); } else if (browserEngine == BrowserEngine.webkit) { this._defaultEditingElement = SafariDesktopTextEditingStrategy(this); - } else if (browserEngine == BrowserEngine.blink && + } else if ((browserEngine == BrowserEngine.blink || + browserEngine == BrowserEngine.samsung) && operatingSystem == OperatingSystem.android) { this._defaultEditingElement = AndroidTextEditingStrategy(this); } else if (browserEngine == BrowserEngine.firefox) { diff --git a/lib/web_ui/test/browser_detect_test.dart b/lib/web_ui/test/browser_detect_test.dart new file mode 100644 index 0000000000000..9311b6c9e91af --- /dev/null +++ b/lib/web_ui/test/browser_detect_test.dart @@ -0,0 +1,51 @@ +// 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. + +// @dart = 2.12 +import 'package:test/bootstrap/browser.dart'; // ignore: import_of_legacy_library_into_null_safe +import 'package:test/test.dart'; // ignore: import_of_legacy_library_into_null_safe +import 'package:ui/src/engine.dart'; + +import 'package:ui/ui.dart'; + +void main() { + internalBootstrapBrowserTest(() => testMain); +} + +void testMain() { + test('Should detect Blink', () { + // Chrome Version 89.0.4389.90 (Official Build) (x86_64) / MacOS + BrowserEngine browserEngine = detectBrowserEngineByVendorAgent( + 'Google Inc.', + 'mozilla/5.0 (macintosh; intel mac os x 11_2_3) applewebkit/537.36 ' + '(khtml, like gecko) chrome/89.0.4389.90 safari/537.36'); + expect(browserEngine, BrowserEngine.blink); + }); + + test('Should detect Firefox', () { + // 85.0.2 (64-bit) / MacOS + BrowserEngine browserEngine = detectBrowserEngineByVendorAgent( + '', + 'mozilla/5.0 (macintosh; intel mac os x 10.16; rv:85.0) ' + 'gecko/20100101 firefox/85.0'); + expect(browserEngine, BrowserEngine.firefox); + }); + + test('Should detect Safari', () { + BrowserEngine browserEngine = detectBrowserEngineByVendorAgent( + 'Apple Computer, Inc.', + 'mozilla/5.0 (macintosh; intel mac os x 10_15_6) applewebkit/605.1.15 ' + '(khtml, like gecko) version/14.0.3 safari/605.1.15'); + expect(browserEngine, BrowserEngine.webkit); + }); + + test('Should detect Samsung browser', () { + // Samsung 13.2.1.70 on Galaxy Tab S6. + BrowserEngine browserEngine = detectBrowserEngineByVendorAgent( + 'Google Inc.', + 'mozilla/5.0 (x11; linux x86_64) applewebkit/537.36 (khtml, like gecko)' + ' samsungbrowser/13.2 chrome/83.0.4103.106 safari/537.36'); + expect(browserEngine, BrowserEngine.samsung); + }); +} diff --git a/lib/web_ui/test/text/canvas_paragraph_builder_test.dart b/lib/web_ui/test/text/canvas_paragraph_builder_test.dart index 9baad5a0f31f0..3cd1ff5627b63 100644 --- a/lib/web_ui/test/text/canvas_paragraph_builder_test.dart +++ b/lib/web_ui/test/text/canvas_paragraph_builder_test.dart @@ -15,7 +15,9 @@ String get defaultFontFamily { String fontFamily = canonicalizeFontFamily('Ahem')!; if (browserEngine == BrowserEngine.firefox) { fontFamily = fontFamily.replaceAll('"', '"'); - } else if (browserEngine == BrowserEngine.blink || browserEngine == BrowserEngine.webkit) { + } else if (browserEngine == BrowserEngine.blink || + browserEngine == BrowserEngine.samsung || + browserEngine == BrowserEngine.webkit) { fontFamily = fontFamily.replaceAll('"', ''); } return 'font-family: $fontFamily;'; diff --git a/lib/web_ui/test/text_editing_test.dart b/lib/web_ui/test/text_editing_test.dart index d573b1dbcacac..67f5941917cd0 100644 --- a/lib/web_ui/test/text_editing_test.dart +++ b/lib/web_ui/test/text_editing_test.dart @@ -1426,6 +1426,7 @@ void testMain() { // For `blink` and `webkit` browser engines the overlay would be hidden. if (browserEngine == BrowserEngine.blink || + browserEngine == BrowserEngine.samsung || browserEngine == BrowserEngine.webkit) { expect(textEditing.editingElement.domElement.classes, contains('transparentTextEditing')); @@ -1924,6 +1925,7 @@ void testMain() { // For `blink` and `webkit` browser engines the overlay would be hidden. if (browserEngine == BrowserEngine.blink || + browserEngine == BrowserEngine.samsung || browserEngine == BrowserEngine.webkit) { expect(firstElement.classes, contains('transparentTextEditing')); } else { From 4566e4691a1ea06b9795a86ce7c35e0300506dd3 Mon Sep 17 00:00:00 2001 From: ferhatb Date: Thu, 25 Mar 2021 10:47:38 -0700 Subject: [PATCH 2/2] Remove unused import --- lib/web_ui/test/browser_detect_test.dart | 2 -- 1 file changed, 2 deletions(-) diff --git a/lib/web_ui/test/browser_detect_test.dart b/lib/web_ui/test/browser_detect_test.dart index 9311b6c9e91af..23b9eb669a707 100644 --- a/lib/web_ui/test/browser_detect_test.dart +++ b/lib/web_ui/test/browser_detect_test.dart @@ -7,8 +7,6 @@ import 'package:test/bootstrap/browser.dart'; // ignore: import_of_legacy_librar import 'package:test/test.dart'; // ignore: import_of_legacy_library_into_null_safe import 'package:ui/src/engine.dart'; -import 'package:ui/ui.dart'; - void main() { internalBootstrapBrowserTest(() => testMain); }