@@ -196,13 +196,7 @@ public void onFlutterUiNoLongerDisplayed() {
196196 }
197197 };
198198
199- private final Consumer <WindowLayoutInfo > windowInfoListener =
200- new Consumer <WindowLayoutInfo >() {
201- @ Override
202- public void accept (WindowLayoutInfo layoutInfo ) {
203- setWindowInfoListenerDisplayFeatures (layoutInfo );
204- }
205- };
199+ private Consumer <WindowLayoutInfo > windowInfoListener ;
206200
207201 /**
208202 * Constructs a {@code FlutterView} programmatically, without any XML attributes.
@@ -514,6 +508,10 @@ protected void onAttachedToWindow() {
514508 this .windowInfoRepo = createWindowInfoRepo ();
515509 Activity activity = ViewUtils .getActivity (getContext ());
516510 if (windowInfoRepo != null && activity != null ) {
511+ // Creating windowInfoListener on-demand instead of at initialization is necessary in order to
512+ // prevent it from capturing the wrong instance of `this` when spying for testing.
513+ // See https://github.com/mockito/mockito/issues/3479
514+ windowInfoListener = this ::setWindowInfoListenerDisplayFeatures ;
517515 windowInfoRepo .addWindowLayoutInfoListener (
518516 activity , ContextCompat .getMainExecutor (getContext ()), windowInfoListener );
519517 }
@@ -526,9 +524,10 @@ protected void onAttachedToWindow() {
526524 */
527525 @ Override
528526 protected void onDetachedFromWindow () {
529- if (windowInfoRepo != null ) {
527+ if (windowInfoRepo != null && windowInfoListener != null ) {
530528 windowInfoRepo .removeWindowLayoutInfoListener (windowInfoListener );
531529 }
530+ windowInfoListener = null ;
532531 this .windowInfoRepo = null ;
533532 super .onDetachedFromWindow ();
534533 }
@@ -539,12 +538,12 @@ protected void onDetachedFromWindow() {
539538 */
540539 @ TargetApi (API_LEVELS .API_28 )
541540 protected void setWindowInfoListenerDisplayFeatures (WindowLayoutInfo layoutInfo ) {
542- List <DisplayFeature > displayFeatures = layoutInfo .getDisplayFeatures ();
543- List <FlutterRenderer .DisplayFeature > result = new ArrayList <>();
541+ List <DisplayFeature > newDisplayFeatures = layoutInfo .getDisplayFeatures ();
542+ List <FlutterRenderer .DisplayFeature > flutterDisplayFeatures = new ArrayList <>();
544543
545544 // Data from WindowInfoTracker display features. Fold and hinge areas are
546545 // populated here.
547- for (DisplayFeature displayFeature : displayFeatures ) {
546+ for (DisplayFeature displayFeature : newDisplayFeatures ) {
548547 Log .v (
549548 TAG ,
550549 "WindowInfoTracker Display Feature reported with bounds = "
@@ -567,31 +566,17 @@ protected void setWindowInfoListenerDisplayFeatures(WindowLayoutInfo layoutInfo)
567566 } else {
568567 state = DisplayFeatureState .UNKNOWN ;
569568 }
570- result .add (new FlutterRenderer .DisplayFeature (displayFeature .getBounds (), type , state ));
569+ flutterDisplayFeatures .add (
570+ new FlutterRenderer .DisplayFeature (displayFeature .getBounds (), type , state ));
571571 } else {
572- result .add (
572+ flutterDisplayFeatures .add (
573573 new FlutterRenderer .DisplayFeature (
574574 displayFeature .getBounds (),
575575 DisplayFeatureType .UNKNOWN ,
576576 DisplayFeatureState .UNKNOWN ));
577577 }
578578 }
579-
580- // Data from the DisplayCutout bounds. Cutouts for cameras and other sensors are
581- // populated here. DisplayCutout was introduced in API 28.
582- if (Build .VERSION .SDK_INT >= API_LEVELS .API_28 ) {
583- WindowInsets insets = getRootWindowInsets ();
584- if (insets != null ) {
585- DisplayCutout cutout = insets .getDisplayCutout ();
586- if (cutout != null ) {
587- for (Rect bounds : cutout .getBoundingRects ()) {
588- Log .v (TAG , "DisplayCutout area reported with bounds = " + bounds .toString ());
589- result .add (new FlutterRenderer .DisplayFeature (bounds , DisplayFeatureType .CUTOUT ));
590- }
591- }
592- }
593- }
594- viewportMetrics .displayFeatures = result ;
579+ viewportMetrics .setDisplayFeatures (flutterDisplayFeatures );
595580 sendViewportMetricsToFlutter ();
596581 }
597582
@@ -784,6 +769,22 @@ navigationBarVisible && guessBottomKeyboardInset(insets) == 0
784769 viewportMetrics .viewInsetLeft = 0 ;
785770 }
786771
772+ // Data from the DisplayCutout bounds. Cutouts for cameras and other sensors are
773+ // populated here. DisplayCutout was introduced in API 28.
774+ List <FlutterRenderer .DisplayFeature > displayCutouts = new ArrayList <>();
775+ if (Build .VERSION .SDK_INT >= API_LEVELS .API_28 ) {
776+ DisplayCutout cutout = insets .getDisplayCutout ();
777+ if (cutout != null ) {
778+ for (Rect bounds : cutout .getBoundingRects ()) {
779+ Log .v (TAG , "DisplayCutout area reported with bounds = " + bounds .toString ());
780+ displayCutouts .add (
781+ new FlutterRenderer .DisplayFeature (
782+ bounds , DisplayFeatureType .CUTOUT , DisplayFeatureState .UNKNOWN ));
783+ }
784+ }
785+ }
786+ viewportMetrics .setDisplayCutouts (displayCutouts );
787+
787788 // The caption bar inset is a new addition, and the APIs called to query it utilize a list of
788789 // bounding Rects instead of an Insets object, which is a newer API method, as compared to the
789790 // existing Insets-based method calls above.
0 commit comments