Skip to content

Commit 4a14ee2

Browse files
[webview_flutter_android][webview_flutter_wkwebview] Adds platform implementations to set over-scroll mode (#9101)
Platform implementation for flutter/flutter#57090 ## Pre-Review Checklist [^1]: Regular contributors who have demonstrated familiarity with the repository guidelines only need to comment if the PR is not auto-exempted by repo tooling.
1 parent 6dbd03d commit 4a14ee2

File tree

18 files changed

+301
-9
lines changed

18 files changed

+301
-9
lines changed

packages/webview_flutter/webview_flutter_android/CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,7 @@
1+
## 4.4.0
2+
3+
* Adds support to set the over-scroll mode for the WebView. See `AndroidWebViewController.setOverScrollMode`.
4+
15
## 4.3.5
26

37
* Adds internal wrapper methods for native `WebViewClient`.

packages/webview_flutter/webview_flutter_android/android/src/main/java/io/flutter/plugins/webviewflutter/AndroidWebkitLibrary.g.kt

Lines changed: 61 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -642,6 +642,7 @@ private class AndroidWebkitLibraryPigeonProxyApiBaseCodec(
642642
value is String ||
643643
value is FileChooserMode ||
644644
value is ConsoleMessageLevel ||
645+
value is OverScrollMode ||
645646
value is SslErrorType ||
646647
value == null) {
647648
super.writeValue(stream, value)
@@ -814,6 +815,31 @@ enum class ConsoleMessageLevel(val raw: Int) {
814815
}
815816
}
816817

818+
/**
819+
* The over-scroll mode for a view.
820+
*
821+
* See https://developer.android.com/reference/android/view/View#OVER_SCROLL_ALWAYS.
822+
*/
823+
enum class OverScrollMode(val raw: Int) {
824+
/** Always allow a user to over-scroll this view, provided it is a view that can scroll. */
825+
ALWAYS(0),
826+
/**
827+
* Allow a user to over-scroll this view only if the content is large enough to meaningfully
828+
* scroll, provided it is a view that can scroll.
829+
*/
830+
IF_CONTENT_SCROLLS(1),
831+
/** Never allow a user to over-scroll this view. */
832+
NEVER(2),
833+
/** The type is not recognized by this wrapper. */
834+
UNKNOWN(3);
835+
836+
companion object {
837+
fun ofRaw(raw: Int): OverScrollMode? {
838+
return values().firstOrNull { it.raw == raw }
839+
}
840+
}
841+
}
842+
817843
/**
818844
* Type of error for a SslCertificate.
819845
*
@@ -852,6 +878,9 @@ private open class AndroidWebkitLibraryPigeonCodec : StandardMessageCodec() {
852878
return (readValue(buffer) as Long?)?.let { ConsoleMessageLevel.ofRaw(it.toInt()) }
853879
}
854880
131.toByte() -> {
881+
return (readValue(buffer) as Long?)?.let { OverScrollMode.ofRaw(it.toInt()) }
882+
}
883+
132.toByte() -> {
855884
return (readValue(buffer) as Long?)?.let { SslErrorType.ofRaw(it.toInt()) }
856885
}
857886
else -> super.readValueOfType(type, buffer)
@@ -868,10 +897,14 @@ private open class AndroidWebkitLibraryPigeonCodec : StandardMessageCodec() {
868897
stream.write(130)
869898
writeValue(stream, value.raw)
870899
}
871-
is SslErrorType -> {
900+
is OverScrollMode -> {
872901
stream.write(131)
873902
writeValue(stream, value.raw)
874903
}
904+
is SslErrorType -> {
905+
stream.write(132)
906+
writeValue(stream, value.raw)
907+
}
875908
else -> super.writeValue(stream, value)
876909
}
877910
}
@@ -4780,6 +4813,9 @@ abstract class PigeonApiView(
47804813
/** Return the scrolled position of this view. */
47814814
abstract fun getScrollPosition(pigeon_instance: android.view.View): WebViewPoint
47824815

4816+
/** Set the over-scroll mode for this view. */
4817+
abstract fun setOverScrollMode(pigeon_instance: android.view.View, mode: OverScrollMode)
4818+
47834819
companion object {
47844820
@Suppress("LocalVariableName")
47854821
fun setUpMessageHandlers(binaryMessenger: BinaryMessenger, api: PigeonApiView?) {
@@ -4852,6 +4888,30 @@ abstract class PigeonApiView(
48524888
channel.setMessageHandler(null)
48534889
}
48544890
}
4891+
run {
4892+
val channel =
4893+
BasicMessageChannel<Any?>(
4894+
binaryMessenger,
4895+
"dev.flutter.pigeon.webview_flutter_android.View.setOverScrollMode",
4896+
codec)
4897+
if (api != null) {
4898+
channel.setMessageHandler { message, reply ->
4899+
val args = message as List<Any?>
4900+
val pigeon_instanceArg = args[0] as android.view.View
4901+
val modeArg = args[1] as OverScrollMode
4902+
val wrapped: List<Any?> =
4903+
try {
4904+
api.setOverScrollMode(pigeon_instanceArg, modeArg)
4905+
listOf(null)
4906+
} catch (exception: Throwable) {
4907+
wrapError(exception)
4908+
}
4909+
reply.reply(wrapped)
4910+
}
4911+
} else {
4912+
channel.setMessageHandler(null)
4913+
}
4914+
}
48554915
}
48564916
}
48574917

packages/webview_flutter/webview_flutter_android/android/src/main/java/io/flutter/plugins/webviewflutter/ViewProxyApi.java

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,12 @@ public ViewProxyApi(@NonNull ProxyApiRegistrar pigeonRegistrar) {
1919
super(pigeonRegistrar);
2020
}
2121

22+
@NonNull
23+
@Override
24+
public ProxyApiRegistrar getPigeonRegistrar() {
25+
return (ProxyApiRegistrar) super.getPigeonRegistrar();
26+
}
27+
2228
@Override
2329
public void scrollTo(@NonNull View pigeon_instance, long x, long y) {
2430
pigeon_instance.scrollTo((int) x, (int) y);
@@ -34,4 +40,21 @@ public void scrollBy(@NonNull View pigeon_instance, long x, long y) {
3440
public WebViewPoint getScrollPosition(@NonNull View pigeon_instance) {
3541
return new WebViewPoint(pigeon_instance.getScrollX(), pigeon_instance.getScrollY());
3642
}
43+
44+
@Override
45+
public void setOverScrollMode(@NonNull View pigeon_instance, @NonNull OverScrollMode mode) {
46+
switch (mode) {
47+
case ALWAYS:
48+
pigeon_instance.setOverScrollMode(View.OVER_SCROLL_ALWAYS);
49+
break;
50+
case IF_CONTENT_SCROLLS:
51+
pigeon_instance.setOverScrollMode(View.OVER_SCROLL_IF_CONTENT_SCROLLS);
52+
break;
53+
case NEVER:
54+
pigeon_instance.setOverScrollMode(View.OVER_SCROLL_NEVER);
55+
break;
56+
case UNKNOWN:
57+
throw getPigeonRegistrar().createUnknownEnumException(OverScrollMode.UNKNOWN);
58+
}
59+
}
3760
}

packages/webview_flutter/webview_flutter_android/android/src/test/java/io/flutter/plugins/webviewflutter/ViewTest.java

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,4 +49,15 @@ public void getScrollPosition() {
4949
assertEquals(value.getX(), api.getScrollPosition(instance).getX());
5050
assertEquals(value.getY(), api.getScrollPosition(instance).getY());
5151
}
52+
53+
@Test
54+
public void setOverScrollMode() {
55+
final PigeonApiView api = new TestProxyApiRegistrar().getPigeonApiView();
56+
57+
final View instance = mock(View.class);
58+
final OverScrollMode mode = io.flutter.plugins.webviewflutter.OverScrollMode.ALWAYS;
59+
api.setOverScrollMode(instance, mode);
60+
61+
verify(instance).setOverScrollMode(View.OVER_SCROLL_ALWAYS);
62+
}
5263
}

packages/webview_flutter/webview_flutter_android/example/pubspec.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ dependencies:
1717
# The example app is bundled with the plugin so we use a path dependency on
1818
# the parent directory to use the current plugin's version.
1919
path: ../
20-
webview_flutter_platform_interface: ^2.10.0
20+
webview_flutter_platform_interface: ^2.11.0
2121

2222
dev_dependencies:
2323
espresso: ^0.4.0

packages/webview_flutter/webview_flutter_android/lib/src/android_webkit.g.dart

Lines changed: 56 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -521,6 +521,25 @@ enum ConsoleMessageLevel {
521521
unknown,
522522
}
523523

524+
/// The over-scroll mode for a view.
525+
///
526+
/// See https://developer.android.com/reference/android/view/View#OVER_SCROLL_ALWAYS.
527+
enum OverScrollMode {
528+
/// Always allow a user to over-scroll this view, provided it is a view that
529+
/// can scroll.
530+
always,
531+
532+
/// Allow a user to over-scroll this view only if the content is large enough
533+
/// to meaningfully scroll, provided it is a view that can scroll.
534+
ifContentScrolls,
535+
536+
/// Never allow a user to over-scroll this view.
537+
never,
538+
539+
/// The type is not recognized by this wrapper.
540+
unknown,
541+
}
542+
524543
/// Type of error for a SslCertificate.
525544
///
526545
/// See https://developer.android.com/reference/android/net/http/SslError#SSL_DATE_INVALID.
@@ -560,9 +579,12 @@ class _PigeonCodec extends StandardMessageCodec {
560579
} else if (value is ConsoleMessageLevel) {
561580
buffer.putUint8(130);
562581
writeValue(buffer, value.index);
563-
} else if (value is SslErrorType) {
582+
} else if (value is OverScrollMode) {
564583
buffer.putUint8(131);
565584
writeValue(buffer, value.index);
585+
} else if (value is SslErrorType) {
586+
buffer.putUint8(132);
587+
writeValue(buffer, value.index);
566588
} else {
567589
super.writeValue(buffer, value);
568590
}
@@ -578,6 +600,9 @@ class _PigeonCodec extends StandardMessageCodec {
578600
final int? value = readValue(buffer) as int?;
579601
return value == null ? null : ConsoleMessageLevel.values[value];
580602
case 131:
603+
final int? value = readValue(buffer) as int?;
604+
return value == null ? null : OverScrollMode.values[value];
605+
case 132:
581606
final int? value = readValue(buffer) as int?;
582607
return value == null ? null : SslErrorType.values[value];
583608
default:
@@ -6586,6 +6611,36 @@ class View extends PigeonInternalProxyApiBaseClass {
65866611
}
65876612
}
65886613

6614+
/// Set the over-scroll mode for this view.
6615+
Future<void> setOverScrollMode(OverScrollMode mode) async {
6616+
final _PigeonInternalProxyApiBaseCodec pigeonChannelCodec =
6617+
_pigeonVar_codecView;
6618+
final BinaryMessenger? pigeonVar_binaryMessenger = pigeon_binaryMessenger;
6619+
const String pigeonVar_channelName =
6620+
'dev.flutter.pigeon.webview_flutter_android.View.setOverScrollMode';
6621+
final BasicMessageChannel<Object?> pigeonVar_channel =
6622+
BasicMessageChannel<Object?>(
6623+
pigeonVar_channelName,
6624+
pigeonChannelCodec,
6625+
binaryMessenger: pigeonVar_binaryMessenger,
6626+
);
6627+
final Future<Object?> pigeonVar_sendFuture =
6628+
pigeonVar_channel.send(<Object?>[this, mode]);
6629+
final List<Object?>? pigeonVar_replyList =
6630+
await pigeonVar_sendFuture as List<Object?>?;
6631+
if (pigeonVar_replyList == null) {
6632+
throw _createConnectionError(pigeonVar_channelName);
6633+
} else if (pigeonVar_replyList.length > 1) {
6634+
throw PlatformException(
6635+
code: pigeonVar_replyList[0]! as String,
6636+
message: pigeonVar_replyList[1] as String?,
6637+
details: pigeonVar_replyList[2],
6638+
);
6639+
} else {
6640+
return;
6641+
}
6642+
}
6643+
65896644
@override
65906645
View pigeon_copy() {
65916646
return View.pigeon_detached(

packages/webview_flutter/webview_flutter_android/lib/src/android_webview_controller.dart

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -731,6 +731,24 @@ class AndroidWebViewController extends PlatformWebViewController {
731731
_onJavaScriptPrompt = onJavaScriptTextInputDialog;
732732
return _webChromeClient.setSynchronousReturnValueForOnJsPrompt(true);
733733
}
734+
735+
@override
736+
Future<void> setOverScrollMode(WebViewOverScrollMode mode) {
737+
return switch (mode) {
738+
WebViewOverScrollMode.always => _webView.setOverScrollMode(
739+
android_webview.OverScrollMode.always,
740+
),
741+
WebViewOverScrollMode.ifContentScrolls => _webView.setOverScrollMode(
742+
android_webview.OverScrollMode.ifContentScrolls,
743+
),
744+
WebViewOverScrollMode.never => _webView.setOverScrollMode(
745+
android_webview.OverScrollMode.never,
746+
),
747+
// This prevents future additions from causing a breaking change.
748+
// ignore: unreachable_switch_case
749+
_ => throw UnsupportedError('Android does not support $mode.'),
750+
};
751+
}
734752
}
735753

736754
/// Android implementation of [PlatformWebViewPermissionRequest].

packages/webview_flutter/webview_flutter_android/pigeons/android_webkit.dart

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,25 @@ enum ConsoleMessageLevel {
8080
unknown,
8181
}
8282

83+
/// The over-scroll mode for a view.
84+
///
85+
/// See https://developer.android.com/reference/android/view/View#OVER_SCROLL_ALWAYS.
86+
enum OverScrollMode {
87+
/// Always allow a user to over-scroll this view, provided it is a view that
88+
/// can scroll.
89+
always,
90+
91+
/// Allow a user to over-scroll this view only if the content is large enough
92+
/// to meaningfully scroll, provided it is a view that can scroll.
93+
ifContentScrolls,
94+
95+
/// Never allow a user to over-scroll this view.
96+
never,
97+
98+
/// The type is not recognized by this wrapper.
99+
unknown,
100+
}
101+
83102
/// Type of error for a SslCertificate.
84103
///
85104
/// See https://developer.android.com/reference/android/net/http/SslError#SSL_DATE_INVALID.
@@ -832,6 +851,9 @@ abstract class View {
832851

833852
/// Return the scrolled position of this view.
834853
WebViewPoint getScrollPosition();
854+
855+
/// Set the over-scroll mode for this view.
856+
void setOverScrollMode(OverScrollMode mode);
835857
}
836858

837859
/// A callback interface used by the host application to set the Geolocation

packages/webview_flutter/webview_flutter_android/pubspec.yaml

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ name: webview_flutter_android
22
description: A Flutter plugin that provides a WebView widget on Android.
33
repository: https://github.com/flutter/packages/tree/main/packages/webview_flutter/webview_flutter_android
44
issue_tracker: https://github.com/flutter/flutter/issues?q=is%3Aissue+is%3Aopen+label%3A%22p%3A+webview%22
5-
version: 4.3.5
5+
version: 4.4.0
66

77
environment:
88
sdk: ^3.6.0
@@ -20,14 +20,14 @@ flutter:
2020
dependencies:
2121
flutter:
2222
sdk: flutter
23-
webview_flutter_platform_interface: ^2.10.0
23+
webview_flutter_platform_interface: ^2.11.0
2424

2525
dev_dependencies:
2626
build_runner: ^2.1.4
2727
flutter_test:
2828
sdk: flutter
2929
mockito: ^5.4.4
30-
pigeon: ^25.2.0
30+
pigeon: ^25.3.0
3131

3232
topics:
3333
- html

packages/webview_flutter/webview_flutter_android/test/android_webview_controller_test.dart

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1624,6 +1624,21 @@ void main() {
16241624
verify(mockSettings.setTextZoom(100)).called(1);
16251625
});
16261626

1627+
test('setOverScrollMode', () async {
1628+
final MockWebView mockWebView = MockWebView();
1629+
final AndroidWebViewController controller = createControllerWithMocks(
1630+
mockWebView: mockWebView,
1631+
);
1632+
1633+
await controller.setOverScrollMode(WebViewOverScrollMode.always);
1634+
1635+
verify(
1636+
mockWebView.setOverScrollMode(
1637+
android_webview.OverScrollMode.always,
1638+
),
1639+
).called(1);
1640+
});
1641+
16271642
test('webViewIdentifier', () {
16281643
final MockWebView mockWebView = MockWebView();
16291644

0 commit comments

Comments
 (0)