From 34a0d1247c57739d9252cf2d188724d5598aa693 Mon Sep 17 00:00:00 2001 From: Yaakov Schectman Date: Thu, 1 Aug 2024 17:06:39 -0400 Subject: [PATCH 01/15] Add FlutterViewDelegate --- .../embedding/android/FlutterView.java | 53 +++++++++++++++++++ 1 file changed, 53 insertions(+) diff --git a/shell/platform/android/io/flutter/embedding/android/FlutterView.java b/shell/platform/android/io/flutter/embedding/android/FlutterView.java index 7272b5125ba05..5ab7bb82a6293 100644 --- a/shell/platform/android/io/flutter/embedding/android/FlutterView.java +++ b/shell/platform/android/io/flutter/embedding/android/FlutterView.java @@ -72,6 +72,7 @@ import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.util.ArrayList; +import java.util.Collections; import java.util.HashSet; import java.util.List; import java.util.Set; @@ -1449,6 +1450,39 @@ public void removeFlutterEngineAttachmentListener( .send(); } + /** A delegate class that performs the task of retrieving the bounding rect values. */ + public static class FlutterViewDelegate { + + @VisibleForTesting + public WindowInsets getWindowInsets(Context context) { + Log.w(TAG, "getWindowInsets called for " + Build.VERSION.SDK_INT); + Activity activity = ViewUtils.getActivity(context); + if (activity == null || Build.VERSION.SDK_INT < 23) { + return null; + } + return activity.getWindow().getDecorView().getRootWindowInsets(); + } + + @VisibleForTesting + public List getCaptionBarInsets(Context context) { + Log.w(TAG, "getCaptionBarInsets called for " + Build.VERSION.SDK_INT); + WindowInsets insets = getWindowInsets(context); + if (insets == null || Build.VERSION.SDK_INT < 35) { + return Collections.emptyList(); + } + Log.w(TAG, "Called inner method: " + insets.getBoundingRects(WindowInsets.Type.captionBar())); + return insets.getBoundingRects(WindowInsets.Type.captionBar()); + } + } + + private FlutterViewDelegate delegate = new FlutterViewDelegate(); + + /** Set the FlutterViewDelegate, such as to a mock for testing. */ + @VisibleForTesting + public void setDelegate(FlutterViewDelegate delegate) { + this.delegate = delegate; + } + private void sendViewportMetricsToFlutter() { if (!isAttachedToFlutterEngine()) { Log.w( @@ -1460,6 +1494,16 @@ private void sendViewportMetricsToFlutter() { viewportMetrics.devicePixelRatio = getResources().getDisplayMetrics().density; viewportMetrics.physicalTouchSlop = ViewConfiguration.get(getContext()).getScaledTouchSlop(); + + if (Build.VERSION.SDK_INT >= API_LEVELS.API_35) { + List boundingRects = delegate.getCaptionBarInsets(getContext()); + if (boundingRects != null && boundingRects.size() == 1) { + viewportMetrics.viewPaddingTop = boundingRects.get(0).bottom; + } + } else { + Log.w(TAG, "API level " + Build.VERSION.SDK_INT + " is too low to query bounding rects."); + } + flutterEngine.getRenderer().setViewportMetrics(viewportMetrics); } @@ -1485,6 +1529,15 @@ public void setVisibility(int visibility) { } } + /** + * Allow access to the viewport metrics so that tests can set them to be valid with nonzero + * dimensions. + */ + @VisibleForTesting + public FlutterRenderer.ViewportMetrics getViewportMetrics() { + return viewportMetrics; + } + /** * Listener that is notified when a {@link io.flutter.embedding.engine.FlutterEngine} is attached * to/detached from a given {@code FlutterView}. From de75b74e4963f1f35cc64e957807587e2ed2733f Mon Sep 17 00:00:00 2001 From: Yaakov Schectman Date: Thu, 1 Aug 2024 17:10:02 -0400 Subject: [PATCH 02/15] Use max --- .../android/io/flutter/embedding/android/FlutterView.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/shell/platform/android/io/flutter/embedding/android/FlutterView.java b/shell/platform/android/io/flutter/embedding/android/FlutterView.java index 5ab7bb82a6293..6a571614a042a 100644 --- a/shell/platform/android/io/flutter/embedding/android/FlutterView.java +++ b/shell/platform/android/io/flutter/embedding/android/FlutterView.java @@ -1498,7 +1498,8 @@ private void sendViewportMetricsToFlutter() { if (Build.VERSION.SDK_INT >= API_LEVELS.API_35) { List boundingRects = delegate.getCaptionBarInsets(getContext()); if (boundingRects != null && boundingRects.size() == 1) { - viewportMetrics.viewPaddingTop = boundingRects.get(0).bottom; + viewportMetrics.viewPaddingTop = + Math.max(boundingRects.get(0).bottom, viewportMetrics.viewPaddingTop); } } else { Log.w(TAG, "API level " + Build.VERSION.SDK_INT + " is too low to query bounding rects."); From 21c6111eb94f499362b07bb6af64af256ab43ecf Mon Sep 17 00:00:00 2001 From: Yaakov Schectman Date: Thu, 1 Aug 2024 17:11:59 -0400 Subject: [PATCH 03/15] Remove debug logs --- .../android/io/flutter/embedding/android/FlutterView.java | 3 --- 1 file changed, 3 deletions(-) diff --git a/shell/platform/android/io/flutter/embedding/android/FlutterView.java b/shell/platform/android/io/flutter/embedding/android/FlutterView.java index 6a571614a042a..7957a1f38c37b 100644 --- a/shell/platform/android/io/flutter/embedding/android/FlutterView.java +++ b/shell/platform/android/io/flutter/embedding/android/FlutterView.java @@ -1455,7 +1455,6 @@ public static class FlutterViewDelegate { @VisibleForTesting public WindowInsets getWindowInsets(Context context) { - Log.w(TAG, "getWindowInsets called for " + Build.VERSION.SDK_INT); Activity activity = ViewUtils.getActivity(context); if (activity == null || Build.VERSION.SDK_INT < 23) { return null; @@ -1465,12 +1464,10 @@ public WindowInsets getWindowInsets(Context context) { @VisibleForTesting public List getCaptionBarInsets(Context context) { - Log.w(TAG, "getCaptionBarInsets called for " + Build.VERSION.SDK_INT); WindowInsets insets = getWindowInsets(context); if (insets == null || Build.VERSION.SDK_INT < 35) { return Collections.emptyList(); } - Log.w(TAG, "Called inner method: " + insets.getBoundingRects(WindowInsets.Type.captionBar())); return insets.getBoundingRects(WindowInsets.Type.captionBar()); } } From 7dc6abd31742f9f784a1686a51641f6e9485d624 Mon Sep 17 00:00:00 2001 From: Yaakov Schectman Date: Mon, 5 Aug 2024 14:49:36 -0400 Subject: [PATCH 04/15] Feedback --- .../io/flutter/embedding/android/FlutterView.java | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/shell/platform/android/io/flutter/embedding/android/FlutterView.java b/shell/platform/android/io/flutter/embedding/android/FlutterView.java index 7957a1f38c37b..007fa1eb8a739 100644 --- a/shell/platform/android/io/flutter/embedding/android/FlutterView.java +++ b/shell/platform/android/io/flutter/embedding/android/FlutterView.java @@ -1453,19 +1453,25 @@ public void removeFlutterEngineAttachmentListener( /** A delegate class that performs the task of retrieving the bounding rect values. */ public static class FlutterViewDelegate { + /** + * Return the WindowInsets object for the provided Context, or null if there is no associated + * activity. + */ + @RequiresApi(api = API_LEVELS.API_23) @VisibleForTesting public WindowInsets getWindowInsets(Context context) { Activity activity = ViewUtils.getActivity(context); - if (activity == null || Build.VERSION.SDK_INT < 23) { + if (activity == null) { return null; } return activity.getWindow().getDecorView().getRootWindowInsets(); } + @RequiresApi(api = API_LEVELS.API_35) @VisibleForTesting public List getCaptionBarInsets(Context context) { WindowInsets insets = getWindowInsets(context); - if (insets == null || Build.VERSION.SDK_INT < 35) { + if (insets == null) { return Collections.emptyList(); } return insets.getBoundingRects(WindowInsets.Type.captionBar()); From ee464bd703ca14c48d0552954f1c032c7fc0774a Mon Sep 17 00:00:00 2001 From: Yaakov Schectman Date: Tue, 6 Aug 2024 13:49:22 -0400 Subject: [PATCH 05/15] FlutterViewDelegate to own class --- ci/licenses_golden/licenses_flutter | 4 ++ shell/platform/android/BUILD.gn | 2 + .../embedding/android/FlutterView.java | 28 ----------- .../android/FlutterViewDelegate.java | 46 +++++++++++++++++++ 4 files changed, 52 insertions(+), 28 deletions(-) create mode 100644 shell/platform/android/io/flutter/embedding/android/FlutterViewDelegate.java diff --git a/ci/licenses_golden/licenses_flutter b/ci/licenses_golden/licenses_flutter index f73dac77ae003..ca9d6e46d2844 100644 --- a/ci/licenses_golden/licenses_flutter +++ b/ci/licenses_golden/licenses_flutter @@ -43358,6 +43358,7 @@ ORIGIN: ../../../flutter/shell/platform/android/io/flutter/embedding/android/Flu ORIGIN: ../../../flutter/shell/platform/android/io/flutter/embedding/android/FlutterSurfaceView.java + ../../../flutter/LICENSE ORIGIN: ../../../flutter/shell/platform/android/io/flutter/embedding/android/FlutterTextureView.java + ../../../flutter/LICENSE ORIGIN: ../../../flutter/shell/platform/android/io/flutter/embedding/android/FlutterView.java + ../../../flutter/LICENSE +ORIGIN: ../../../flutter/shell/platform/android/io/flutter/embedding/android/FlutterViewDelegate.java + ../../../flutter/LICENSE ORIGIN: ../../../flutter/shell/platform/android/io/flutter/embedding/android/KeyChannelResponder.java + ../../../flutter/LICENSE ORIGIN: ../../../flutter/shell/platform/android/io/flutter/embedding/android/KeyData.java + ../../../flutter/LICENSE ORIGIN: ../../../flutter/shell/platform/android/io/flutter/embedding/android/KeyEmbedderResponder.java + ../../../flutter/LICENSE @@ -43477,6 +43478,7 @@ ORIGIN: ../../../flutter/shell/platform/android/io/flutter/view/FlutterMain.java ORIGIN: ../../../flutter/shell/platform/android/io/flutter/view/FlutterNativeView.java + ../../../flutter/LICENSE ORIGIN: ../../../flutter/shell/platform/android/io/flutter/view/FlutterRunArguments.java + ../../../flutter/LICENSE ORIGIN: ../../../flutter/shell/platform/android/io/flutter/view/FlutterView.java + ../../../flutter/LICENSE +ORIGIN: ../../../flutter/shell/platform/android/io/flutter/view/FlutterViewDelegate.java + ../../../flutter/LICENSE ORIGIN: ../../../flutter/shell/platform/android/io/flutter/view/TextureRegistry.java + ../../../flutter/LICENSE ORIGIN: ../../../flutter/shell/platform/android/io/flutter/view/VsyncWaiter.java + ../../../flutter/LICENSE ORIGIN: ../../../flutter/shell/platform/android/jni/jni_mock.h + ../../../flutter/LICENSE @@ -46250,6 +46252,7 @@ FILE: ../../../flutter/shell/platform/android/io/flutter/embedding/android/Flutt FILE: ../../../flutter/shell/platform/android/io/flutter/embedding/android/FlutterSurfaceView.java FILE: ../../../flutter/shell/platform/android/io/flutter/embedding/android/FlutterTextureView.java FILE: ../../../flutter/shell/platform/android/io/flutter/embedding/android/FlutterView.java +FILE: ../../../flutter/shell/platform/android/io/flutter/embedding/android/FlutterViewDelegate.java FILE: ../../../flutter/shell/platform/android/io/flutter/embedding/android/KeyChannelResponder.java FILE: ../../../flutter/shell/platform/android/io/flutter/embedding/android/KeyData.java FILE: ../../../flutter/shell/platform/android/io/flutter/embedding/android/KeyEmbedderResponder.java @@ -46379,6 +46382,7 @@ FILE: ../../../flutter/shell/platform/android/io/flutter/view/FlutterMain.java FILE: ../../../flutter/shell/platform/android/io/flutter/view/FlutterNativeView.java FILE: ../../../flutter/shell/platform/android/io/flutter/view/FlutterRunArguments.java FILE: ../../../flutter/shell/platform/android/io/flutter/view/FlutterView.java +FILE: ../../../flutter/shell/platform/android/io/flutter/view/FlutterViewDelegate.java FILE: ../../../flutter/shell/platform/android/io/flutter/view/TextureRegistry.java FILE: ../../../flutter/shell/platform/android/io/flutter/view/VsyncWaiter.java FILE: ../../../flutter/shell/platform/android/jni/jni_mock.h diff --git a/shell/platform/android/BUILD.gn b/shell/platform/android/BUILD.gn index 433af900f8cbf..2e584c3e05531 100644 --- a/shell/platform/android/BUILD.gn +++ b/shell/platform/android/BUILD.gn @@ -228,6 +228,7 @@ android_java_sources = [ "io/flutter/embedding/android/FlutterSurfaceView.java", "io/flutter/embedding/android/FlutterTextureView.java", "io/flutter/embedding/android/FlutterView.java", + "io/flutter/embedding/android/FlutterViewDelegate.java", "io/flutter/embedding/android/KeyChannelResponder.java", "io/flutter/embedding/android/KeyData.java", "io/flutter/embedding/android/KeyEmbedderResponder.java", @@ -357,6 +358,7 @@ android_java_sources = [ "io/flutter/view/FlutterNativeView.java", "io/flutter/view/FlutterRunArguments.java", "io/flutter/view/FlutterView.java", + "io/flutter/view/FlutterViewDelegate.java", "io/flutter/view/TextureRegistry.java", "io/flutter/view/VsyncWaiter.java", ] diff --git a/shell/platform/android/io/flutter/embedding/android/FlutterView.java b/shell/platform/android/io/flutter/embedding/android/FlutterView.java index 007fa1eb8a739..b2abf43b55a64 100644 --- a/shell/platform/android/io/flutter/embedding/android/FlutterView.java +++ b/shell/platform/android/io/flutter/embedding/android/FlutterView.java @@ -1450,34 +1450,6 @@ public void removeFlutterEngineAttachmentListener( .send(); } - /** A delegate class that performs the task of retrieving the bounding rect values. */ - public static class FlutterViewDelegate { - - /** - * Return the WindowInsets object for the provided Context, or null if there is no associated - * activity. - */ - @RequiresApi(api = API_LEVELS.API_23) - @VisibleForTesting - public WindowInsets getWindowInsets(Context context) { - Activity activity = ViewUtils.getActivity(context); - if (activity == null) { - return null; - } - return activity.getWindow().getDecorView().getRootWindowInsets(); - } - - @RequiresApi(api = API_LEVELS.API_35) - @VisibleForTesting - public List getCaptionBarInsets(Context context) { - WindowInsets insets = getWindowInsets(context); - if (insets == null) { - return Collections.emptyList(); - } - return insets.getBoundingRects(WindowInsets.Type.captionBar()); - } - } - private FlutterViewDelegate delegate = new FlutterViewDelegate(); /** Set the FlutterViewDelegate, such as to a mock for testing. */ diff --git a/shell/platform/android/io/flutter/embedding/android/FlutterViewDelegate.java b/shell/platform/android/io/flutter/embedding/android/FlutterViewDelegate.java new file mode 100644 index 0000000000000..ba4dfb6d15731 --- /dev/null +++ b/shell/platform/android/io/flutter/embedding/android/FlutterViewDelegate.java @@ -0,0 +1,46 @@ +// 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. + +package io.flutter.embedding.android; + +import android.app.Activity; +import android.content.Context; +import android.graphics.Rect; +import android.view.WindowInsets; + +import androidx.annotation.RequiresApi; +import androidx.annotation.VisibleForTesting; + +import java.util.Collections; +import java.util.List; + +import io.flutter.Build; +import io.flutter.util.ViewUtils; + +/** A delegate class that performs the task of retrieving the bounding rect values. */ +public class FlutterViewDelegate { + /** + * Return the WindowInsets object for the provided Context, or null if there is no associated + * activity. + */ + @RequiresApi(api = Build.API_LEVELS.API_23) + @VisibleForTesting + public WindowInsets getWindowInsets(Context context) { + Activity activity = ViewUtils.getActivity(context); + if (activity == null) { + return null; + } + return activity.getWindow().getDecorView().getRootWindowInsets(); + } + + @RequiresApi(api = Build.API_LEVELS.API_35) + @VisibleForTesting + public List getCaptionBarInsets(Context context) { + WindowInsets insets = getWindowInsets(context); + if (insets == null) { + return Collections.emptyList(); + } + return insets.getBoundingRects(WindowInsets.Type.captionBar()); + } +} \ No newline at end of file From 91abf9bc6c07f75e972d9a3e77815753d17620f7 Mon Sep 17 00:00:00 2001 From: Yaakov Schectman Date: Tue, 6 Aug 2024 16:11:37 -0400 Subject: [PATCH 06/15] Formatting --- .../embedding/android/FlutterView.java | 1 - .../android/FlutterViewDelegate.java | 47 +++++++++---------- 2 files changed, 22 insertions(+), 26 deletions(-) diff --git a/shell/platform/android/io/flutter/embedding/android/FlutterView.java b/shell/platform/android/io/flutter/embedding/android/FlutterView.java index b2abf43b55a64..c8bce40e3d9ac 100644 --- a/shell/platform/android/io/flutter/embedding/android/FlutterView.java +++ b/shell/platform/android/io/flutter/embedding/android/FlutterView.java @@ -72,7 +72,6 @@ import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.util.ArrayList; -import java.util.Collections; import java.util.HashSet; import java.util.List; import java.util.Set; diff --git a/shell/platform/android/io/flutter/embedding/android/FlutterViewDelegate.java b/shell/platform/android/io/flutter/embedding/android/FlutterViewDelegate.java index ba4dfb6d15731..f7b9443c649a2 100644 --- a/shell/platform/android/io/flutter/embedding/android/FlutterViewDelegate.java +++ b/shell/platform/android/io/flutter/embedding/android/FlutterViewDelegate.java @@ -8,39 +8,36 @@ import android.content.Context; import android.graphics.Rect; import android.view.WindowInsets; - import androidx.annotation.RequiresApi; import androidx.annotation.VisibleForTesting; - -import java.util.Collections; -import java.util.List; - import io.flutter.Build; import io.flutter.util.ViewUtils; +import java.util.Collections; +import java.util.List; /** A delegate class that performs the task of retrieving the bounding rect values. */ public class FlutterViewDelegate { - /** - * Return the WindowInsets object for the provided Context, or null if there is no associated - * activity. - */ - @RequiresApi(api = Build.API_LEVELS.API_23) - @VisibleForTesting - public WindowInsets getWindowInsets(Context context) { - Activity activity = ViewUtils.getActivity(context); - if (activity == null) { - return null; - } - return activity.getWindow().getDecorView().getRootWindowInsets(); + /** + * Return the WindowInsets object for the provided Context, or null if there is no associated + * activity. + */ + @RequiresApi(api = Build.API_LEVELS.API_23) + @VisibleForTesting + public WindowInsets getWindowInsets(Context context) { + Activity activity = ViewUtils.getActivity(context); + if (activity == null) { + return null; } + return activity.getWindow().getDecorView().getRootWindowInsets(); + } - @RequiresApi(api = Build.API_LEVELS.API_35) - @VisibleForTesting - public List getCaptionBarInsets(Context context) { - WindowInsets insets = getWindowInsets(context); - if (insets == null) { - return Collections.emptyList(); - } - return insets.getBoundingRects(WindowInsets.Type.captionBar()); + @RequiresApi(api = Build.API_LEVELS.API_35) + @VisibleForTesting + public List getCaptionBarInsets(Context context) { + WindowInsets insets = getWindowInsets(context); + if (insets == null) { + return Collections.emptyList(); } + return insets.getBoundingRects(WindowInsets.Type.captionBar()); + } } \ No newline at end of file From ec13d36e9fc38d558856829ee7f59f4cf36a9eb3 Mon Sep 17 00:00:00 2001 From: Yaakov Schectman Date: Tue, 6 Aug 2024 16:25:04 -0400 Subject: [PATCH 07/15] Remove mistake lien --- shell/platform/android/BUILD.gn | 1 - 1 file changed, 1 deletion(-) diff --git a/shell/platform/android/BUILD.gn b/shell/platform/android/BUILD.gn index 2e584c3e05531..65797086ff0fe 100644 --- a/shell/platform/android/BUILD.gn +++ b/shell/platform/android/BUILD.gn @@ -358,7 +358,6 @@ android_java_sources = [ "io/flutter/view/FlutterNativeView.java", "io/flutter/view/FlutterRunArguments.java", "io/flutter/view/FlutterView.java", - "io/flutter/view/FlutterViewDelegate.java", "io/flutter/view/TextureRegistry.java", "io/flutter/view/VsyncWaiter.java", ] From 243486c4d549d94efc06578eff79357f4ed89cd9 Mon Sep 17 00:00:00 2001 From: Yaakov Schectman Date: Tue, 6 Aug 2024 17:11:56 -0400 Subject: [PATCH 08/15] PR Feedback --- .../android/io/flutter/embedding/android/FlutterView.java | 1 - .../io/flutter/embedding/android/FlutterViewDelegate.java | 7 ++++++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/shell/platform/android/io/flutter/embedding/android/FlutterView.java b/shell/platform/android/io/flutter/embedding/android/FlutterView.java index c8bce40e3d9ac..dca3cc87ff1af 100644 --- a/shell/platform/android/io/flutter/embedding/android/FlutterView.java +++ b/shell/platform/android/io/flutter/embedding/android/FlutterView.java @@ -1451,7 +1451,6 @@ public void removeFlutterEngineAttachmentListener( private FlutterViewDelegate delegate = new FlutterViewDelegate(); - /** Set the FlutterViewDelegate, such as to a mock for testing. */ @VisibleForTesting public void setDelegate(FlutterViewDelegate delegate) { this.delegate = delegate; diff --git a/shell/platform/android/io/flutter/embedding/android/FlutterViewDelegate.java b/shell/platform/android/io/flutter/embedding/android/FlutterViewDelegate.java index f7b9443c649a2..cbd0b422aacbd 100644 --- a/shell/platform/android/io/flutter/embedding/android/FlutterViewDelegate.java +++ b/shell/platform/android/io/flutter/embedding/android/FlutterViewDelegate.java @@ -7,6 +7,7 @@ import android.app.Activity; import android.content.Context; import android.graphics.Rect; +import android.view.Window; import android.view.WindowInsets; import androidx.annotation.RequiresApi; import androidx.annotation.VisibleForTesting; @@ -28,7 +29,11 @@ public WindowInsets getWindowInsets(Context context) { if (activity == null) { return null; } - return activity.getWindow().getDecorView().getRootWindowInsets(); + Window window = activity.getWindow(); + if (window == null) { + return null; + } + return window.getDecorView().getRootWindowInsets(); } @RequiresApi(api = Build.API_LEVELS.API_35) From 64f7bac7bd772f07e97460a45d73ef540168bf85 Mon Sep 17 00:00:00 2001 From: Yaakov Schectman Date: Tue, 6 Aug 2024 17:32:04 -0400 Subject: [PATCH 09/15] Test/PR feedback --- ci/licenses_golden/licenses_flutter | 2 -- .../io/flutter/embedding/android/FlutterViewDelegate.java | 5 +++-- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/ci/licenses_golden/licenses_flutter b/ci/licenses_golden/licenses_flutter index ca9d6e46d2844..7284429ca4859 100644 --- a/ci/licenses_golden/licenses_flutter +++ b/ci/licenses_golden/licenses_flutter @@ -43478,7 +43478,6 @@ ORIGIN: ../../../flutter/shell/platform/android/io/flutter/view/FlutterMain.java ORIGIN: ../../../flutter/shell/platform/android/io/flutter/view/FlutterNativeView.java + ../../../flutter/LICENSE ORIGIN: ../../../flutter/shell/platform/android/io/flutter/view/FlutterRunArguments.java + ../../../flutter/LICENSE ORIGIN: ../../../flutter/shell/platform/android/io/flutter/view/FlutterView.java + ../../../flutter/LICENSE -ORIGIN: ../../../flutter/shell/platform/android/io/flutter/view/FlutterViewDelegate.java + ../../../flutter/LICENSE ORIGIN: ../../../flutter/shell/platform/android/io/flutter/view/TextureRegistry.java + ../../../flutter/LICENSE ORIGIN: ../../../flutter/shell/platform/android/io/flutter/view/VsyncWaiter.java + ../../../flutter/LICENSE ORIGIN: ../../../flutter/shell/platform/android/jni/jni_mock.h + ../../../flutter/LICENSE @@ -46382,7 +46381,6 @@ FILE: ../../../flutter/shell/platform/android/io/flutter/view/FlutterMain.java FILE: ../../../flutter/shell/platform/android/io/flutter/view/FlutterNativeView.java FILE: ../../../flutter/shell/platform/android/io/flutter/view/FlutterRunArguments.java FILE: ../../../flutter/shell/platform/android/io/flutter/view/FlutterView.java -FILE: ../../../flutter/shell/platform/android/io/flutter/view/FlutterViewDelegate.java FILE: ../../../flutter/shell/platform/android/io/flutter/view/TextureRegistry.java FILE: ../../../flutter/shell/platform/android/io/flutter/view/VsyncWaiter.java FILE: ../../../flutter/shell/platform/android/jni/jni_mock.h diff --git a/shell/platform/android/io/flutter/embedding/android/FlutterViewDelegate.java b/shell/platform/android/io/flutter/embedding/android/FlutterViewDelegate.java index cbd0b422aacbd..76af670217dbf 100644 --- a/shell/platform/android/io/flutter/embedding/android/FlutterViewDelegate.java +++ b/shell/platform/android/io/flutter/embedding/android/FlutterViewDelegate.java @@ -19,8 +19,9 @@ /** A delegate class that performs the task of retrieving the bounding rect values. */ public class FlutterViewDelegate { /** - * Return the WindowInsets object for the provided Context, or null if there is no associated - * activity. + * Return the WindowInsets object for the provided Context. Returns null if there is no associated + * activity, the window of the associated activity is null, or the root window insets of the + * activity's window is null. */ @RequiresApi(api = Build.API_LEVELS.API_23) @VisibleForTesting From 49475fb750269cc31f06d459fb2688bbb56ac424 Mon Sep 17 00:00:00 2001 From: Yaakov Schectman Date: Fri, 9 Aug 2024 15:20:46 -0400 Subject: [PATCH 10/15] Explanatory comment --- .../android/io/flutter/embedding/android/FlutterView.java | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/shell/platform/android/io/flutter/embedding/android/FlutterView.java b/shell/platform/android/io/flutter/embedding/android/FlutterView.java index dca3cc87ff1af..9498d2b17f0df 100644 --- a/shell/platform/android/io/flutter/embedding/android/FlutterView.java +++ b/shell/platform/android/io/flutter/embedding/android/FlutterView.java @@ -1471,6 +1471,10 @@ private void sendViewportMetricsToFlutter() { if (Build.VERSION.SDK_INT >= API_LEVELS.API_35) { List boundingRects = delegate.getCaptionBarInsets(getContext()); if (boundingRects != null && boundingRects.size() == 1) { + // The value getCaptionBarInset returns is only the bounding rects of the caption bar. + // When assigning the new value of viewPaddingTop, the maximum is taken with its old value + // to ensure that any previous top padding that is greater than that from the caption bar + // is not destroyed by this operation. viewportMetrics.viewPaddingTop = Math.max(boundingRects.get(0).bottom, viewportMetrics.viewPaddingTop); } From 9a428c5c745ce53f5f21b921e04ac285d6c708dd Mon Sep 17 00:00:00 2001 From: Yaakov Schectman Date: Tue, 13 Aug 2024 09:10:48 -0400 Subject: [PATCH 11/15] Delegate maximizing viewport metric padding --- .../io/flutter/embedding/android/FlutterView.java | 10 +--------- .../embedding/android/FlutterViewDelegate.java | 14 ++++++++++++++ 2 files changed, 15 insertions(+), 9 deletions(-) diff --git a/shell/platform/android/io/flutter/embedding/android/FlutterView.java b/shell/platform/android/io/flutter/embedding/android/FlutterView.java index 9498d2b17f0df..35b3a8cb4034c 100644 --- a/shell/platform/android/io/flutter/embedding/android/FlutterView.java +++ b/shell/platform/android/io/flutter/embedding/android/FlutterView.java @@ -1469,15 +1469,7 @@ private void sendViewportMetricsToFlutter() { viewportMetrics.physicalTouchSlop = ViewConfiguration.get(getContext()).getScaledTouchSlop(); if (Build.VERSION.SDK_INT >= API_LEVELS.API_35) { - List boundingRects = delegate.getCaptionBarInsets(getContext()); - if (boundingRects != null && boundingRects.size() == 1) { - // The value getCaptionBarInset returns is only the bounding rects of the caption bar. - // When assigning the new value of viewPaddingTop, the maximum is taken with its old value - // to ensure that any previous top padding that is greater than that from the caption bar - // is not destroyed by this operation. - viewportMetrics.viewPaddingTop = - Math.max(boundingRects.get(0).bottom, viewportMetrics.viewPaddingTop); - } + delegate.growViewportMetricsToCaptionBar(getContext(), viewportMetrics); } else { Log.w(TAG, "API level " + Build.VERSION.SDK_INT + " is too low to query bounding rects."); } diff --git a/shell/platform/android/io/flutter/embedding/android/FlutterViewDelegate.java b/shell/platform/android/io/flutter/embedding/android/FlutterViewDelegate.java index 76af670217dbf..c133db256b7a5 100644 --- a/shell/platform/android/io/flutter/embedding/android/FlutterViewDelegate.java +++ b/shell/platform/android/io/flutter/embedding/android/FlutterViewDelegate.java @@ -12,6 +12,7 @@ import androidx.annotation.RequiresApi; import androidx.annotation.VisibleForTesting; import io.flutter.Build; +import io.flutter.embedding.engine.renderer.FlutterRenderer; import io.flutter.util.ViewUtils; import java.util.Collections; import java.util.List; @@ -46,4 +47,17 @@ public List getCaptionBarInsets(Context context) { } return insets.getBoundingRects(WindowInsets.Type.captionBar()); } + + @RequiresApi(api = Build.API_LEVELS.API_35) + public void growViewportMetricsToCaptionBar(Context context, FlutterRenderer.ViewportMetrics viewportMetrics) { + List boundingRects = getCaptionBarInsets(context); + if (boundingRects.size() != 1) { + return; + } + // The value getCaptionBarInset returns is only the bounding rects of the caption bar. + // When assigning the new value of viewPaddingTop, the maximum is taken with its old value + // to ensure that any previous top padding that is greater than that from the caption bar + // is not destroyed by this operation. + viewportMetrics.viewPaddingTop = Math.max(viewportMetrics.viewPaddingTop, boundingRects.get(0).bottom); + } } \ No newline at end of file From e0d38da162a60565922f91e831335305ef3a4601 Mon Sep 17 00:00:00 2001 From: Yaakov Schectman Date: Fri, 16 Aug 2024 13:52:23 -0400 Subject: [PATCH 12/15] Format --- .../io/flutter/embedding/android/FlutterViewDelegate.java | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/shell/platform/android/io/flutter/embedding/android/FlutterViewDelegate.java b/shell/platform/android/io/flutter/embedding/android/FlutterViewDelegate.java index c133db256b7a5..99f9c2847c9a7 100644 --- a/shell/platform/android/io/flutter/embedding/android/FlutterViewDelegate.java +++ b/shell/platform/android/io/flutter/embedding/android/FlutterViewDelegate.java @@ -49,7 +49,8 @@ public List getCaptionBarInsets(Context context) { } @RequiresApi(api = Build.API_LEVELS.API_35) - public void growViewportMetricsToCaptionBar(Context context, FlutterRenderer.ViewportMetrics viewportMetrics) { + public void growViewportMetricsToCaptionBar( + Context context, FlutterRenderer.ViewportMetrics viewportMetrics) { List boundingRects = getCaptionBarInsets(context); if (boundingRects.size() != 1) { return; @@ -58,6 +59,7 @@ public void growViewportMetricsToCaptionBar(Context context, FlutterRenderer.Vie // When assigning the new value of viewPaddingTop, the maximum is taken with its old value // to ensure that any previous top padding that is greater than that from the caption bar // is not destroyed by this operation. - viewportMetrics.viewPaddingTop = Math.max(viewportMetrics.viewPaddingTop, boundingRects.get(0).bottom); + viewportMetrics.viewPaddingTop = + Math.max(viewportMetrics.viewPaddingTop, boundingRects.get(0).bottom); } } \ No newline at end of file From a0a1cbc3813e49e86b7ebdc227203e6df285e1c3 Mon Sep 17 00:00:00 2001 From: Yaakov Schectman Date: Fri, 16 Aug 2024 13:57:22 -0400 Subject: [PATCH 13/15] PR feedback --- .../android/io/flutter/embedding/android/FlutterView.java | 2 +- .../io/flutter/embedding/android/FlutterViewDelegate.java | 7 +++++-- .../flutter/embedding/engine/renderer/FlutterRenderer.java | 3 +++ 3 files changed, 9 insertions(+), 3 deletions(-) diff --git a/shell/platform/android/io/flutter/embedding/android/FlutterView.java b/shell/platform/android/io/flutter/embedding/android/FlutterView.java index 35b3a8cb4034c..f547fe743bcd8 100644 --- a/shell/platform/android/io/flutter/embedding/android/FlutterView.java +++ b/shell/platform/android/io/flutter/embedding/android/FlutterView.java @@ -1452,7 +1452,7 @@ public void removeFlutterEngineAttachmentListener( private FlutterViewDelegate delegate = new FlutterViewDelegate(); @VisibleForTesting - public void setDelegate(FlutterViewDelegate delegate) { + public void setDelegate(@NonNull FlutterViewDelegate delegate) { this.delegate = delegate; } diff --git a/shell/platform/android/io/flutter/embedding/android/FlutterViewDelegate.java b/shell/platform/android/io/flutter/embedding/android/FlutterViewDelegate.java index 99f9c2847c9a7..2c18022a79cb1 100644 --- a/shell/platform/android/io/flutter/embedding/android/FlutterViewDelegate.java +++ b/shell/platform/android/io/flutter/embedding/android/FlutterViewDelegate.java @@ -17,7 +17,11 @@ import java.util.Collections; import java.util.List; -/** A delegate class that performs the task of retrieving the bounding rect values. */ +/** + * A delegate class that performs the task of retrieving the bounding rect values. Logic that is + * independent of the engine, or that tests must access in the absence of an engine, shall reside + * within this class. + */ public class FlutterViewDelegate { /** * Return the WindowInsets object for the provided Context. Returns null if there is no associated @@ -39,7 +43,6 @@ public WindowInsets getWindowInsets(Context context) { } @RequiresApi(api = Build.API_LEVELS.API_35) - @VisibleForTesting public List getCaptionBarInsets(Context context) { WindowInsets insets = getWindowInsets(context); if (insets == null) { diff --git a/shell/platform/android/io/flutter/embedding/engine/renderer/FlutterRenderer.java b/shell/platform/android/io/flutter/embedding/engine/renderer/FlutterRenderer.java index 445e331845c13..c4e3df02c1cd7 100644 --- a/shell/platform/android/io/flutter/embedding/engine/renderer/FlutterRenderer.java +++ b/shell/platform/android/io/flutter/embedding/engine/renderer/FlutterRenderer.java @@ -1271,6 +1271,9 @@ public static final class ViewportMetrics { public float devicePixelRatio = 1.0f; public int width = 0; public int height = 0; + // The fields prefixed with viewPadding and viewInset are used to calculate the padding, + // viewPadding, and viewInsets of ViewConfiguration in Dart. This calculation is performed at + // https://github.com/flutter/engine/blob/main/lib/ui/hooks.dart#L139-L155. public int viewPaddingTop = 0; public int viewPaddingRight = 0; public int viewPaddingBottom = 0; From 87cd3941da8e6d161d6900a9fba94158f4ec2b5f Mon Sep 17 00:00:00 2001 From: Yaakov Schectman Date: Mon, 19 Aug 2024 14:15:20 -0400 Subject: [PATCH 14/15] Comments --- .../embedding/android/FlutterViewDelegate.java | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/shell/platform/android/io/flutter/embedding/android/FlutterViewDelegate.java b/shell/platform/android/io/flutter/embedding/android/FlutterViewDelegate.java index 2c18022a79cb1..96e892eafce2f 100644 --- a/shell/platform/android/io/flutter/embedding/android/FlutterViewDelegate.java +++ b/shell/platform/android/io/flutter/embedding/android/FlutterViewDelegate.java @@ -24,9 +24,10 @@ */ public class FlutterViewDelegate { /** - * Return the WindowInsets object for the provided Context. Returns null if there is no associated - * activity, the window of the associated activity is null, or the root window insets of the - * activity's window is null. + * Return the WindowInsets object for the provided Context. A Context will only have a window if + * it is an instance of Activity. If context does not have a window, or it is not an activity, + * this method will return null. Otherwise, this method will return the WindowInsets for the + * provided activity's window. */ @RequiresApi(api = Build.API_LEVELS.API_23) @VisibleForTesting @@ -55,6 +56,10 @@ public List getCaptionBarInsets(Context context) { public void growViewportMetricsToCaptionBar( Context context, FlutterRenderer.ViewportMetrics viewportMetrics) { List boundingRects = getCaptionBarInsets(context); + int padding = viewportMetrics.viewPaddingTop; + for (Rect rect : boundingRects) { + padding = Math.max(padding, rect.bottom); + } if (boundingRects.size() != 1) { return; } @@ -62,7 +67,8 @@ public void growViewportMetricsToCaptionBar( // When assigning the new value of viewPaddingTop, the maximum is taken with its old value // to ensure that any previous top padding that is greater than that from the caption bar // is not destroyed by this operation. - viewportMetrics.viewPaddingTop = - Math.max(viewportMetrics.viewPaddingTop, boundingRects.get(0).bottom); + // Any potential update that will allow the caption bar to be positioned somewhere other than + // the top of the app window will require that this method be rewritten. + viewportMetrics.viewPaddingTop = padding; } } \ No newline at end of file From 4cbc7a421cd566489112d4814fb9a49750b393aa Mon Sep 17 00:00:00 2001 From: Yaakov Schectman Date: Mon, 19 Aug 2024 15:30:17 -0400 Subject: [PATCH 15/15] Move caption bar logic --- .../io/flutter/embedding/android/FlutterView.java | 15 +++++++++------ .../embedding/android/FlutterViewDelegate.java | 9 +++------ 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/shell/platform/android/io/flutter/embedding/android/FlutterView.java b/shell/platform/android/io/flutter/embedding/android/FlutterView.java index f547fe743bcd8..37d9621c6b945 100644 --- a/shell/platform/android/io/flutter/embedding/android/FlutterView.java +++ b/shell/platform/android/io/flutter/embedding/android/FlutterView.java @@ -772,6 +772,15 @@ navigationBarVisible && guessBottomKeyboardInset(insets) == 0 viewportMetrics.viewInsetLeft = 0; } + // The caption bar inset is a new addition, and the APIs called to query it utilize a list of + // bounding Rects instead of an Insets object, which is a newer API method, as compared to the + // existing Insets-based method calls above. + if (Build.VERSION.SDK_INT >= API_LEVELS.API_35) { + delegate.growViewportMetricsToCaptionBar(getContext(), viewportMetrics); + } else { + Log.w(TAG, "API level " + Build.VERSION.SDK_INT + " is too low to query bounding rects."); + } + Log.v( TAG, "Updating window insets (onApplyWindowInsets()):\n" @@ -1468,12 +1477,6 @@ private void sendViewportMetricsToFlutter() { viewportMetrics.devicePixelRatio = getResources().getDisplayMetrics().density; viewportMetrics.physicalTouchSlop = ViewConfiguration.get(getContext()).getScaledTouchSlop(); - if (Build.VERSION.SDK_INT >= API_LEVELS.API_35) { - delegate.growViewportMetricsToCaptionBar(getContext(), viewportMetrics); - } else { - Log.w(TAG, "API level " + Build.VERSION.SDK_INT + " is too low to query bounding rects."); - } - flutterEngine.getRenderer().setViewportMetrics(viewportMetrics); } diff --git a/shell/platform/android/io/flutter/embedding/android/FlutterViewDelegate.java b/shell/platform/android/io/flutter/embedding/android/FlutterViewDelegate.java index 96e892eafce2f..ea773ffaf0ca7 100644 --- a/shell/platform/android/io/flutter/embedding/android/FlutterViewDelegate.java +++ b/shell/platform/android/io/flutter/embedding/android/FlutterViewDelegate.java @@ -56,12 +56,9 @@ public List getCaptionBarInsets(Context context) { public void growViewportMetricsToCaptionBar( Context context, FlutterRenderer.ViewportMetrics viewportMetrics) { List boundingRects = getCaptionBarInsets(context); - int padding = viewportMetrics.viewPaddingTop; + int viewPaddingTop = viewportMetrics.viewPaddingTop; for (Rect rect : boundingRects) { - padding = Math.max(padding, rect.bottom); - } - if (boundingRects.size() != 1) { - return; + viewPaddingTop = Math.max(viewPaddingTop, rect.bottom); } // The value getCaptionBarInset returns is only the bounding rects of the caption bar. // When assigning the new value of viewPaddingTop, the maximum is taken with its old value @@ -69,6 +66,6 @@ public void growViewportMetricsToCaptionBar( // is not destroyed by this operation. // Any potential update that will allow the caption bar to be positioned somewhere other than // the top of the app window will require that this method be rewritten. - viewportMetrics.viewPaddingTop = padding; + viewportMetrics.viewPaddingTop = viewPaddingTop; } } \ No newline at end of file