Skip to content
This repository was archived by the owner on Feb 25, 2025. It is now read-only.

Commit d6bc4dc

Browse files
Use getBoundingRects to add support inset MediaQuery/SafeArea when in freeform mode controls are shown. (#54294)
Original Title: Add FlutterViewDelegate and BoundingRect methods Check the bounding rect for caption bar when sending viewport metrics to Flutter to account for freeform mode. Use the more recent `getBoundingRects` over `getInsets`. Tests will need to be kept separate until Robolectric publishes a version that supports API level 35. Roboletric tests for this pr will be part of google testing until then. Pr for tests here https://critique.corp.google.com/cl/657302386. flutter/flutter#146658 ## Pre-launch Checklist - [x] I read the [Contributor Guide] and followed the process outlined there for submitting PRs. - [x] I read the [Tree Hygiene] wiki page, which explains my responsibilities. - [x] I read and followed the [Flutter Style Guide] and the [C++, Objective-C, Java style guides]. - [x] I listed at least one issue that this PR fixes in the description above. - [x] I added new tests to check the change I am making or feature I am adding, or the PR is [test-exempt]. See [testing the engine] for instructions on writing and running engine tests. - [x] I updated/added relevant documentation (doc comments with `///`). - [ ] I signed the [CLA]. - [x] All existing and new tests are passing.
1 parent a09e43c commit d6bc4dc

File tree

5 files changed

+103
-0
lines changed

5 files changed

+103
-0
lines changed

ci/licenses_golden/licenses_flutter

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44060,6 +44060,7 @@ ORIGIN: ../../../flutter/shell/platform/android/io/flutter/embedding/android/Flu
4406044060
ORIGIN: ../../../flutter/shell/platform/android/io/flutter/embedding/android/FlutterSurfaceView.java + ../../../flutter/LICENSE
4406144061
ORIGIN: ../../../flutter/shell/platform/android/io/flutter/embedding/android/FlutterTextureView.java + ../../../flutter/LICENSE
4406244062
ORIGIN: ../../../flutter/shell/platform/android/io/flutter/embedding/android/FlutterView.java + ../../../flutter/LICENSE
44063+
ORIGIN: ../../../flutter/shell/platform/android/io/flutter/embedding/android/FlutterViewDelegate.java + ../../../flutter/LICENSE
4406344064
ORIGIN: ../../../flutter/shell/platform/android/io/flutter/embedding/android/KeyChannelResponder.java + ../../../flutter/LICENSE
4406444065
ORIGIN: ../../../flutter/shell/platform/android/io/flutter/embedding/android/KeyData.java + ../../../flutter/LICENSE
4406544066
ORIGIN: ../../../flutter/shell/platform/android/io/flutter/embedding/android/KeyEmbedderResponder.java + ../../../flutter/LICENSE
@@ -46946,6 +46947,7 @@ FILE: ../../../flutter/shell/platform/android/io/flutter/embedding/android/Flutt
4694646947
FILE: ../../../flutter/shell/platform/android/io/flutter/embedding/android/FlutterSurfaceView.java
4694746948
FILE: ../../../flutter/shell/platform/android/io/flutter/embedding/android/FlutterTextureView.java
4694846949
FILE: ../../../flutter/shell/platform/android/io/flutter/embedding/android/FlutterView.java
46950+
FILE: ../../../flutter/shell/platform/android/io/flutter/embedding/android/FlutterViewDelegate.java
4694946951
FILE: ../../../flutter/shell/platform/android/io/flutter/embedding/android/KeyChannelResponder.java
4695046952
FILE: ../../../flutter/shell/platform/android/io/flutter/embedding/android/KeyData.java
4695146953
FILE: ../../../flutter/shell/platform/android/io/flutter/embedding/android/KeyEmbedderResponder.java

shell/platform/android/BUILD.gn

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -228,6 +228,7 @@ android_java_sources = [
228228
"io/flutter/embedding/android/FlutterSurfaceView.java",
229229
"io/flutter/embedding/android/FlutterTextureView.java",
230230
"io/flutter/embedding/android/FlutterView.java",
231+
"io/flutter/embedding/android/FlutterViewDelegate.java",
231232
"io/flutter/embedding/android/KeyChannelResponder.java",
232233
"io/flutter/embedding/android/KeyData.java",
233234
"io/flutter/embedding/android/KeyEmbedderResponder.java",

shell/platform/android/io/flutter/embedding/android/FlutterView.java

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -772,6 +772,15 @@ navigationBarVisible && guessBottomKeyboardInset(insets) == 0
772772
viewportMetrics.viewInsetLeft = 0;
773773
}
774774

775+
// The caption bar inset is a new addition, and the APIs called to query it utilize a list of
776+
// bounding Rects instead of an Insets object, which is a newer API method, as compared to the
777+
// existing Insets-based method calls above.
778+
if (Build.VERSION.SDK_INT >= API_LEVELS.API_35) {
779+
delegate.growViewportMetricsToCaptionBar(getContext(), viewportMetrics);
780+
} else {
781+
Log.w(TAG, "API level " + Build.VERSION.SDK_INT + " is too low to query bounding rects.");
782+
}
783+
775784
Log.v(
776785
TAG,
777786
"Updating window insets (onApplyWindowInsets()):\n"
@@ -1449,6 +1458,13 @@ public void removeFlutterEngineAttachmentListener(
14491458
.send();
14501459
}
14511460

1461+
private FlutterViewDelegate delegate = new FlutterViewDelegate();
1462+
1463+
@VisibleForTesting
1464+
public void setDelegate(@NonNull FlutterViewDelegate delegate) {
1465+
this.delegate = delegate;
1466+
}
1467+
14521468
private void sendViewportMetricsToFlutter() {
14531469
if (!isAttachedToFlutterEngine()) {
14541470
Log.w(
@@ -1460,6 +1476,7 @@ private void sendViewportMetricsToFlutter() {
14601476

14611477
viewportMetrics.devicePixelRatio = getResources().getDisplayMetrics().density;
14621478
viewportMetrics.physicalTouchSlop = ViewConfiguration.get(getContext()).getScaledTouchSlop();
1479+
14631480
flutterEngine.getRenderer().setViewportMetrics(viewportMetrics);
14641481
}
14651482

@@ -1485,6 +1502,15 @@ public void setVisibility(int visibility) {
14851502
}
14861503
}
14871504

1505+
/**
1506+
* Allow access to the viewport metrics so that tests can set them to be valid with nonzero
1507+
* dimensions.
1508+
*/
1509+
@VisibleForTesting
1510+
public FlutterRenderer.ViewportMetrics getViewportMetrics() {
1511+
return viewportMetrics;
1512+
}
1513+
14881514
/**
14891515
* Listener that is notified when a {@link io.flutter.embedding.engine.FlutterEngine} is attached
14901516
* to/detached from a given {@code FlutterView}.
Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
// Copyright 2013 The Flutter Authors. All rights reserved.
2+
// Use of this source code is governed by a BSD-style license that can be
3+
// found in the LICENSE file.
4+
5+
package io.flutter.embedding.android;
6+
7+
import android.app.Activity;
8+
import android.content.Context;
9+
import android.graphics.Rect;
10+
import android.view.Window;
11+
import android.view.WindowInsets;
12+
import androidx.annotation.RequiresApi;
13+
import androidx.annotation.VisibleForTesting;
14+
import io.flutter.Build;
15+
import io.flutter.embedding.engine.renderer.FlutterRenderer;
16+
import io.flutter.util.ViewUtils;
17+
import java.util.Collections;
18+
import java.util.List;
19+
20+
/**
21+
* A delegate class that performs the task of retrieving the bounding rect values. Logic that is
22+
* independent of the engine, or that tests must access in the absence of an engine, shall reside
23+
* within this class.
24+
*/
25+
public class FlutterViewDelegate {
26+
/**
27+
* Return the WindowInsets object for the provided Context. A Context will only have a window if
28+
* it is an instance of Activity. If context does not have a window, or it is not an activity,
29+
* this method will return null. Otherwise, this method will return the WindowInsets for the
30+
* provided activity's window.
31+
*/
32+
@RequiresApi(api = Build.API_LEVELS.API_23)
33+
@VisibleForTesting
34+
public WindowInsets getWindowInsets(Context context) {
35+
Activity activity = ViewUtils.getActivity(context);
36+
if (activity == null) {
37+
return null;
38+
}
39+
Window window = activity.getWindow();
40+
if (window == null) {
41+
return null;
42+
}
43+
return window.getDecorView().getRootWindowInsets();
44+
}
45+
46+
@RequiresApi(api = Build.API_LEVELS.API_35)
47+
public List<Rect> getCaptionBarInsets(Context context) {
48+
WindowInsets insets = getWindowInsets(context);
49+
if (insets == null) {
50+
return Collections.emptyList();
51+
}
52+
return insets.getBoundingRects(WindowInsets.Type.captionBar());
53+
}
54+
55+
@RequiresApi(api = Build.API_LEVELS.API_35)
56+
public void growViewportMetricsToCaptionBar(
57+
Context context, FlutterRenderer.ViewportMetrics viewportMetrics) {
58+
List<Rect> boundingRects = getCaptionBarInsets(context);
59+
int viewPaddingTop = viewportMetrics.viewPaddingTop;
60+
for (Rect rect : boundingRects) {
61+
viewPaddingTop = Math.max(viewPaddingTop, rect.bottom);
62+
}
63+
// The value getCaptionBarInset returns is only the bounding rects of the caption bar.
64+
// When assigning the new value of viewPaddingTop, the maximum is taken with its old value
65+
// to ensure that any previous top padding that is greater than that from the caption bar
66+
// is not destroyed by this operation.
67+
// Any potential update that will allow the caption bar to be positioned somewhere other than
68+
// the top of the app window will require that this method be rewritten.
69+
viewportMetrics.viewPaddingTop = viewPaddingTop;
70+
}
71+
}

shell/platform/android/io/flutter/embedding/engine/renderer/FlutterRenderer.java

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1271,6 +1271,9 @@ public static final class ViewportMetrics {
12711271
public float devicePixelRatio = 1.0f;
12721272
public int width = 0;
12731273
public int height = 0;
1274+
// The fields prefixed with viewPadding and viewInset are used to calculate the padding,
1275+
// viewPadding, and viewInsets of ViewConfiguration in Dart. This calculation is performed at
1276+
// https://github.com/flutter/engine/blob/main/lib/ui/hooks.dart#L139-L155.
12741277
public int viewPaddingTop = 0;
12751278
public int viewPaddingRight = 0;
12761279
public int viewPaddingBottom = 0;

0 commit comments

Comments
 (0)