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

Remove usages of WindowManager's getDefaultDisplay #55002

Merged
merged 12 commits into from
Sep 25, 2024
3 changes: 3 additions & 0 deletions shell/platform/android/io/flutter/Build.java
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,13 @@

package io.flutter;

import androidx.annotation.VisibleForTesting;

/** A replacement of utilities from android.os.Build. */
public class Build {
/** For use in place of the Android Build.VERSION_CODES class. */
public static class API_LEVELS {
@VisibleForTesting public static final int FLUTTER_MIN = 21;
public static final int API_21 = 21;
public static final int API_22 = 22;
public static final int API_23 = 23;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,13 +14,15 @@
import android.database.ContentObserver;
import android.graphics.Insets;
import android.graphics.Rect;
import android.hardware.display.DisplayManager;
import android.os.Build;
import android.os.Handler;
import android.os.Looper;
import android.provider.Settings;
import android.text.format.DateFormat;
import android.util.AttributeSet;
import android.util.SparseArray;
import android.view.Display;
import android.view.DisplayCutout;
import android.view.KeyEvent;
import android.view.MotionEvent;
Expand All @@ -31,7 +33,6 @@
import android.view.ViewGroup;
import android.view.ViewStructure;
import android.view.WindowInsets;
import android.view.WindowManager;
import android.view.accessibility.AccessibilityManager;
import android.view.accessibility.AccessibilityNodeProvider;
import android.view.autofill.AutofillValue;
Expand Down Expand Up @@ -597,26 +598,35 @@ protected void setWindowInfoListenerDisplayFeatures(WindowLayoutInfo layoutInfo)
// android may decide to place the software navigation bars on the side. When the nav
// bar is hidden, the reported insets should be removed to prevent extra useless space
// on the sides.
private enum ZeroSides {
@VisibleForTesting
public enum ZeroSides {
NONE,
LEFT,
RIGHT,
BOTH
}

private ZeroSides calculateShouldZeroSides() {
/**
* This method can be run on APIs 30 and above but its intended use is for 30 and below.
*
* @return some ZeroSides enum
*/
@androidx.annotation.DeprecatedSinceApi(api = API_LEVELS.API_30)
@VisibleForTesting
public ZeroSides calculateShouldZeroSides() {
// We get both orientation and rotation because rotation is all 4
// rotations relative to default rotation while orientation is portrait
// or landscape. By combining both, we can obtain a more precise measure
// of the rotation.
Context context = getContext();
int orientation = context.getResources().getConfiguration().orientation;
int rotation =
((WindowManager) context.getSystemService(Context.WINDOW_SERVICE))
.getDefaultDisplay()
.getRotation();

if (orientation == Configuration.ORIENTATION_LANDSCAPE) {
int rotation =
((DisplayManager) context.getSystemService(Context.DISPLAY_SERVICE))
.getDisplay(Display.DEFAULT_DISPLAY)
.getRotation();

if (rotation == Surface.ROTATION_90) {
return ZeroSides.RIGHT;
} else if (rotation == Surface.ROTATION_270) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
import android.graphics.Rect;
import android.graphics.Region;
import android.hardware.HardwareBuffer;
import android.hardware.display.DisplayManager;
import android.media.Image;
import android.media.Image.Plane;
import android.media.ImageReader;
Expand All @@ -39,13 +40,13 @@
import android.view.Surface;
import android.view.View;
import android.view.WindowInsets;
import android.view.WindowManager;
import android.widget.FrameLayout;
import androidx.core.util.Consumer;
import androidx.test.core.app.ApplicationProvider;
import androidx.test.ext.junit.runners.AndroidJUnit4;
import androidx.window.layout.FoldingFeature;
import androidx.window.layout.WindowLayoutInfo;
import io.flutter.Build.API_LEVELS;
import io.flutter.embedding.engine.FlutterEngine;
import io.flutter.embedding.engine.FlutterJNI;
import io.flutter.embedding.engine.loader.FlutterLoader;
Expand Down Expand Up @@ -438,6 +439,48 @@ public void systemInsetHandlesFullscreenNavbarRightBelowSDK23() {
validateViewportMetricPadding(viewportMetricsCaptor, 100, 0, 0, 0);
}

@Test
@Config(minSdk = API_LEVELS.FLUTTER_MIN, maxSdk = API_LEVELS.API_29, qualifiers = "port")
public void calculateShouldZeroSidesInPortrait() {
FlutterView flutterView = spy(new FlutterView(ctx));
assertEquals(FlutterView.ZeroSides.NONE, flutterView.calculateShouldZeroSides());
}

@Test
@Config(minSdk = API_LEVELS.FLUTTER_MIN, maxSdk = API_LEVELS.API_29, qualifiers = "land")
public void calculateShouldZeroSidesInLandscapeNeutralRotation() {
FlutterView flutterView = spy(new FlutterView(ctx));
setExpectedDisplayRotation(Surface.ROTATION_0);
assertEquals(FlutterView.ZeroSides.BOTH, flutterView.calculateShouldZeroSides());

setExpectedDisplayRotation(Surface.ROTATION_180);
assertEquals(FlutterView.ZeroSides.BOTH, flutterView.calculateShouldZeroSides());
}

@Test
@Config(minSdk = API_LEVELS.FLUTTER_MIN, maxSdk = API_LEVELS.API_29, qualifiers = "land")
public void calculateShouldZeroSidesInLandscapeRotation90() {
FlutterView flutterView = spy(new FlutterView(ctx));
setExpectedDisplayRotation(Surface.ROTATION_90);
assertEquals(FlutterView.ZeroSides.RIGHT, flutterView.calculateShouldZeroSides());
}

@Test
@Config(minSdk = API_LEVELS.API_21, maxSdk = API_LEVELS.API_22, qualifiers = "land")
public void calculateShouldZeroSidesInLandscapeRotation270API22() {
FlutterView flutterView = spy(new FlutterView(ctx));
setExpectedDisplayRotation(Surface.ROTATION_270);
assertEquals(FlutterView.ZeroSides.RIGHT, flutterView.calculateShouldZeroSides());
}

@Test
@Config(minSdk = API_LEVELS.API_23, maxSdk = API_LEVELS.API_29, qualifiers = "land")
public void calculateShouldZeroSidesInLandscapeRotation270API23Plus() {
FlutterView flutterView = spy(new FlutterView(ctx));
setExpectedDisplayRotation(Surface.ROTATION_270);
assertEquals(FlutterView.ZeroSides.LEFT, flutterView.calculateShouldZeroSides());
}

@SuppressWarnings("deprecation")
// getSystemUiVisibility, getWindowSystemUiVisibility required to test pre api 30 behavior.
@Test
Expand Down Expand Up @@ -615,9 +658,6 @@ public void systemInsetDisplayCutoutSimple() {
public void itRegistersAndUnregistersToWindowManager() {
Context context = Robolectric.setupActivity(Activity.class);
FlutterView flutterView = spy(new FlutterView(context));
ShadowDisplay display =
Shadows.shadowOf(
((WindowManager) ctx.getSystemService(Context.WINDOW_SERVICE)).getDefaultDisplay());
WindowInfoRepositoryCallbackAdapterWrapper windowInfoRepo =
mock(WindowInfoRepositoryCallbackAdapterWrapper.class);
// For reasoning behing using doReturn instead of when, read "Important gotcha" at
Expand Down Expand Up @@ -646,9 +686,6 @@ public void itRegistersAndUnregistersToWindowManager() {
public void itSendsHingeDisplayFeatureToFlutter() {
Context context = Robolectric.setupActivity(Activity.class);
FlutterView flutterView = spy(new FlutterView(context));
ShadowDisplay display =
Shadows.shadowOf(
((WindowManager) ctx.getSystemService(Context.WINDOW_SERVICE)).getDefaultDisplay());
when(flutterView.getContext()).thenReturn(context);
WindowInfoRepositoryCallbackAdapterWrapper windowInfoRepo =
mock(WindowInfoRepositoryCallbackAdapterWrapper.class);
Expand Down Expand Up @@ -1102,10 +1139,10 @@ public SettingsChannel.MessageBuilder answer(InvocationOnMock invocation)

@SuppressWarnings("deprecation")
private void setExpectedDisplayRotation(int rotation) {
ShadowDisplay display =
ShadowDisplay myDisplay =
Shadows.shadowOf(
((WindowManager) ctx.getSystemService(Context.WINDOW_SERVICE)).getDefaultDisplay());
display.setRotation(rotation);
((DisplayManager) ctx.getSystemService(Context.DISPLAY_SERVICE)).getDisplay(0));
myDisplay.setRotation(rotation);
}

private void validateViewportMetricPadding(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,11 @@ public void windowManagerHandler_forwardsAllOtherCallsToDelegate() {
@SuppressWarnings("Unchecked cast")
Consumer<Boolean> mockListener = (Consumer<Boolean>) mock(Consumer.class);

// Windowmanager's getDefaultDisplay() function is deprecated in API 30 level 30.
// See Android docs here:
// https://developer.android.com/reference/android/view/WindowManager#getDefaultDisplay()
// We expect this behavior because this unit test expects a blind forward that includes
// deprecated function calls. See comment above for more details.
windowManagerHandler.getDefaultDisplay();
verify(mockWindowManager).getDefaultDisplay();

Expand Down
17 changes: 14 additions & 3 deletions tools/android_lint/baseline.xml
Original file line number Diff line number Diff line change
@@ -1,5 +1,16 @@
<?xml version="1.0" encoding="UTF-8"?>
<issues format="6" by="lint 8.1.0 [10406996] " type="baseline" client="" dependencies="true" name="" variant="all" version="8.1.0 [10406996] ">
<issues format="6" by="lint 8.3.0 [11479570] " type="baseline" client="" dependencies="true" name="" variant="all" version="8.3.0 [11479570] ">

<issue
id="DeprecatedSinceApi"
message="This method is deprecated as of API level 30"
errorLine1=" zeroSides = calculateShouldZeroSides();"
errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~">
<location
file="../../../flutter/shell/platform/android/io/flutter/embedding/android/FlutterView.java"
line="759"
column="21"/>
</issue>

<issue
id="HardcodedDebugMode"
Expand All @@ -19,7 +30,7 @@
errorLine2=" ~~~~~~~~~~~~">
<location
file="../../../flutter/shell/platform/android/io/flutter/view/FlutterView.java"
line="445"
line="474"
column="18"/>
</issue>

Expand All @@ -30,7 +41,7 @@
errorLine2=" ~~~~~~~~~~~~">
<location
file="../../../flutter/shell/platform/android/io/flutter/embedding/android/FlutterView.java"
line="928"
line="896"
column="18"/>
</issue>

Expand Down