Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
55c4ce0
update example app
bparrishMines Mar 5, 2026
6bb5a99
implementation
bparrishMines Mar 6, 2026
8e10a01
Merge branch 'main' of github.com:flutter/packages into webview_safe_…
bparrishMines Mar 6, 2026
3b3d6c6
formatting
bparrishMines Mar 6, 2026
32856f9
java test
bparrishMines Mar 6, 2026
ce2a9b3
update unit tests
bparrishMines Mar 6, 2026
bc04474
add destruction back
bparrishMines Mar 6, 2026
57ca57c
version bump and undo example app
bparrishMines Mar 6, 2026
49a3867
formatting
bparrishMines Mar 6, 2026
74bfe0f
docs
bparrishMines Mar 6, 2026
cfdf061
fix docs
bparrishMines Mar 6, 2026
07c8699
update pigeon
bparrishMines Mar 6, 2026
31fa299
fix docs again
bparrishMines Mar 6, 2026
a8a415b
Merge branch 'main' of github.com:flutter/packages into webview_safe_…
bparrishMines Mar 13, 2026
b367d63
improve code logic
bparrishMines Mar 13, 2026
77b40da
other windowinsets
bparrishMines Mar 16, 2026
1bb6433
fix tests
bparrishMines Mar 16, 2026
4d02edb
Merge branch 'main' of github.com:flutter/packages into webview_safe_…
bparrishMines Mar 16, 2026
bb20265
add remove back
bparrishMines Mar 16, 2026
f42bb7b
fix main.dart
bparrishMines Mar 16, 2026
651a4f8
remove padding comment
bparrishMines Mar 16, 2026
204e405
change name of enum
bparrishMines Mar 18, 2026
681eb73
fix unit tests
bparrishMines Mar 18, 2026
6a6b394
Merge branch 'main' of github.com:flutter/packages into webview_safe_…
bparrishMines Mar 25, 2026
c93e0e6
add optional method
bparrishMines Mar 27, 2026
4e1915d
undo main changes
bparrishMines Mar 27, 2026
819f6d1
Merge branch 'main' of github.com:flutter/packages into webview_safe_…
bparrishMines Mar 27, 2026
bdf08ae
fix space
bparrishMines Mar 27, 2026
5c89d64
Merge branch 'main' of github.com:flutter/packages into webview_safe_…
bparrishMines Apr 3, 2026
c1511d2
test all values of androidwebviewinsets separately
bparrishMines Apr 3, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions packages/webview_flutter/webview_flutter_android/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,8 @@
## 4.11.0

* Adds support to opt out of Android inset changes. See
`AndroidWebViewController.setInsetsForWebContentToIgnore`.

## 4.10.15

* Fixes dartdoc comments that accidentally used HTML.
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
// Copyright 2013 The Flutter Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// Autogenerated from Pigeon (v26.1.4), do not edit directly.
// Autogenerated from Pigeon (v26.2.0), do not edit directly.
// See also: https://pub.dev/packages/pigeon
@file:Suppress("UNCHECKED_CAST", "ArrayInDataClass")

Expand Down Expand Up @@ -708,6 +708,7 @@ private class AndroidWebkitLibraryPigeonProxyApiBaseCodec(
value is OverScrollMode ||
value is SslErrorType ||
value is MixedContentMode ||
value is WindowInsetsType ||
value == null) {
super.writeValue(stream, value)
return
Expand Down Expand Up @@ -1098,6 +1099,47 @@ enum class MixedContentMode(val raw: Int) {
}
}

/**
* Defines different types of sources causing window insets.
*
* See https://developer.android.com/reference/androidx/core/view/WindowInsetsCompat.Type
*/
enum class WindowInsetsType(val raw: Int) {
/**
* All system bars.
*
* Includes statusBars(), captionBar() as well as navigationBars(), systemOverlays(), but not
* ime().
*/
SYSTEM_BARS(0),
/** An inset type representing the area that used by DisplayCutout. */
DISPLAY_CUTOUT(1),
/** An insets type representing the window of a caption bar. */
CAPTION_BAR(2),
/** An insets type representing the window of an InputMethod. */
IME(3),
MANDATORY_SYSTEM_GESTURES(4),
/** An insets type representing any system bars for navigation. */
NAVIGATION_BARS(5),
/** An insets type representing any system bars for displaying status. */
STATUS_BARS(6),
/**
* An insets type representing the system gesture insets.
*
* The system gesture insets represent the area of a window where system gestures have priority
* and may consume some or all touch input, e.g. due to the a system bar occupying it, or it being
* reserved for touch-only gestures.
*/
SYSTEM_GESTURES(7),
TAPPABLE_ELEMENT(8);

companion object {
fun ofRaw(raw: Int): WindowInsetsType? {
return values().firstOrNull { it.raw == raw }
}
}
}

private open class AndroidWebkitLibraryPigeonCodec : StandardMessageCodec() {
override fun readValueOfType(type: Byte, buffer: ByteBuffer): Any? {
return when (type) {
Expand All @@ -1116,6 +1158,9 @@ private open class AndroidWebkitLibraryPigeonCodec : StandardMessageCodec() {
133.toByte() -> {
return (readValue(buffer) as Long?)?.let { MixedContentMode.ofRaw(it.toInt()) }
}
134.toByte() -> {
return (readValue(buffer) as Long?)?.let { WindowInsetsType.ofRaw(it.toInt()) }
}
else -> super.readValueOfType(type, buffer)
}
}
Expand All @@ -1142,6 +1187,10 @@ private open class AndroidWebkitLibraryPigeonCodec : StandardMessageCodec() {
stream.write(133)
writeValue(stream, value.raw.toLong())
}
is WindowInsetsType -> {
stream.write(134)
writeValue(stream, value.raw.toLong())
}
else -> super.writeValue(stream, value)
}
}
Expand Down Expand Up @@ -5316,6 +5365,18 @@ abstract class PigeonApiView(
/** Set the over-scroll mode for this view. */
abstract fun setOverScrollMode(pigeon_instance: android.view.View, mode: OverScrollMode)

/**
* Sets the listener to the native method `ViewCompat.setOnApplyWindowInsetsListener` to mark the
* passed insets to zero.
*
* This is a convenience method because `View.OnApplyWindowInsetsListener` requires implementing a
* callback that requires a synchronous return value.
*/
abstract fun setInsetListenerToSetInsetsToZero(
pigeon_instance: android.view.View,
types: List<WindowInsetsType>
)

companion object {
@Suppress("LocalVariableName")
fun setUpMessageHandlers(binaryMessenger: BinaryMessenger, api: PigeonApiView?) {
Expand Down Expand Up @@ -5460,6 +5521,30 @@ abstract class PigeonApiView(
channel.setMessageHandler(null)
}
}
run {
val channel =
BasicMessageChannel<Any?>(
binaryMessenger,
"dev.flutter.pigeon.webview_flutter_android.View.setInsetListenerToSetInsetsToZero",
codec)
if (api != null) {
channel.setMessageHandler { message, reply ->
val args = message as List<Any?>
val pigeon_instanceArg = args[0] as android.view.View
val typesArg = args[1] as List<WindowInsetsType>
val wrapped: List<Any?> =
try {
api.setInsetListenerToSetInsetsToZero(pigeon_instanceArg, typesArg)
listOf(null)
} catch (exception: Throwable) {
AndroidWebkitLibraryPigeonUtils.wrapError(exception)
}
reply.reply(wrapped)
}
} else {
channel.setMessageHandler(null)
}
}
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,10 @@

import android.view.View;
import androidx.annotation.NonNull;
import androidx.core.graphics.Insets;
import androidx.core.view.ViewCompat;
import androidx.core.view.WindowInsetsCompat;
import java.util.List;

/**
* Flutter API implementation for `View`.
Expand Down Expand Up @@ -67,4 +71,55 @@ public void setOverScrollMode(@NonNull View pigeon_instance, @NonNull OverScroll
throw getPigeonRegistrar().createUnknownEnumException(OverScrollMode.UNKNOWN);
}
}

@Override
public void setInsetListenerToSetInsetsToZero(
@NonNull View pigeon_instance, @NonNull List<? extends WindowInsetsType> types) {
if (types.isEmpty()) {
ViewCompat.setOnApplyWindowInsetsListener(
pigeon_instance, (view, windowInsets) -> windowInsets);
return;
}

int typeMaskAccumulator = 0;
for (WindowInsetsType type : types) {
switch (type) {
case SYSTEM_BARS:
typeMaskAccumulator |= WindowInsetsCompat.Type.systemBars();
break;
case DISPLAY_CUTOUT:
typeMaskAccumulator |= WindowInsetsCompat.Type.displayCutout();
break;
case CAPTION_BAR:
typeMaskAccumulator |= WindowInsetsCompat.Type.captionBar();
break;
case IME:
typeMaskAccumulator |= WindowInsetsCompat.Type.ime();
break;
case MANDATORY_SYSTEM_GESTURES:
typeMaskAccumulator |= WindowInsetsCompat.Type.mandatorySystemGestures();
break;
case NAVIGATION_BARS:
typeMaskAccumulator |= WindowInsetsCompat.Type.navigationBars();
break;
case STATUS_BARS:
typeMaskAccumulator |= WindowInsetsCompat.Type.statusBars();
break;
case SYSTEM_GESTURES:
typeMaskAccumulator |= WindowInsetsCompat.Type.systemGestures();
break;
case TAPPABLE_ELEMENT:
typeMaskAccumulator |= WindowInsetsCompat.Type.tappableElement();
break;
}
}
final int insetsTypeMask = typeMaskAccumulator;

ViewCompat.setOnApplyWindowInsetsListener(
pigeon_instance,
(view, windowInsets) ->
new WindowInsetsCompat.Builder(windowInsets)
.setInsets(insetsTypeMask, Insets.NONE)
.build());
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,21 @@
package io.flutter.plugins.webviewflutter;

import static org.junit.Assert.assertEquals;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.mockStatic;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;

import android.view.View;
import androidx.core.graphics.Insets;
import androidx.core.view.OnApplyWindowInsetsListener;
import androidx.core.view.ViewCompat;
import androidx.core.view.WindowInsetsCompat;
import java.util.List;
import org.junit.Test;
import org.mockito.ArgumentCaptor;
import org.mockito.MockedStatic;

public class ViewTest {
@Test
Expand Down Expand Up @@ -82,4 +91,32 @@ public void setOverScrollMode() {

verify(instance).setOverScrollMode(View.OVER_SCROLL_ALWAYS);
}

@Test
public void setInsetListenerToSetInsetsToZero() {
final PigeonApiView api = new TestProxyApiRegistrar().getPigeonApiView();

final View instance = mock(View.class);
final WindowInsetsCompat originalInsets =
new WindowInsetsCompat.Builder()
.setInsets(WindowInsetsCompat.Type.systemBars(), Insets.of(1, 2, 3, 4))
.setInsets(WindowInsetsCompat.Type.displayCutout(), Insets.of(4, 5, 6, 7))
.build();

try (MockedStatic<ViewCompat> viewCompatMockedStatic = mockStatic(ViewCompat.class)) {
api.setInsetListenerToSetInsetsToZero(
instance, List.of(WindowInsetsType.SYSTEM_BARS, WindowInsetsType.DISPLAY_CUTOUT));

final ArgumentCaptor<OnApplyWindowInsetsListener> listenerCaptor =
ArgumentCaptor.forClass(OnApplyWindowInsetsListener.class);
viewCompatMockedStatic.verify(
() -> ViewCompat.setOnApplyWindowInsetsListener(eq(instance), listenerCaptor.capture()));

final WindowInsetsCompat newInsets =
listenerCaptor.getValue().onApplyWindowInsets(instance, originalInsets);

assertEquals(Insets.NONE, newInsets.getInsets(WindowInsetsCompat.Type.systemBars()));
assertEquals(Insets.NONE, newInsets.getInsets(WindowInsetsCompat.Type.displayCutout()));
}
}
}
Loading
Loading