dotnet / android

.NET for Android provides open-source bindings of the Android SDK for use with .NET managed languages such as C#
MIT License
1.92k stars 526 forks source link

GetRealMetrics is deprecated in every case, Android 30+ #6422

Closed FANMixco closed 2 years ago

FANMixco commented 2 years ago

I'm trying to upgrade a section of my code and I'm targeting Android 30. This is my original code:

private double GetScreenSize()
{
    float yInches;
    float xInches;
    using (DisplayMetrics metrics = new DisplayMetrics())
    {
        WindowManager.DefaultDisplay.GetMetrics(metrics);
        yInches = metrics.HeightPixels / metrics.Ydpi;
        xInches = metrics.WidthPixels / metrics.Xdpi;
    }

    return Math.Round(Math.Sqrt(xInches * xInches + yInches * yInches), 0);
}

Then, I'm trying to upgrade the code to this one:

private double GetScreenSize()
{
    float yInches;
    float xInches;
    using (DisplayMetrics metrics = new DisplayMetrics())
    {
        if (Build.VERSION.SdkInt >= BuildVersionCodes.R)
        {
            this.Display.GetRealMetrics(metrics);
            yInches = metrics.HeightPixels / metrics.Ydpi;
            xInches = metrics.WidthPixels / metrics.Xdpi;
        }
        else
        {
            WindowManager.DefaultDisplay.GetMetrics(metrics);
            yInches = metrics.HeightPixels / metrics.Ydpi;
            xInches = metrics.WidthPixels / metrics.Xdpi;
        }
    }

    return Math.Round(Math.Sqrt(xInches * xInches + yInches * yInches), 0);
}

Regardless of my actions, my code is still considered as Obsolete:

Screen Shot 2021-10-25 at 07 26 25

Now, Google suggests you use:

This method was deprecated in API level 30. Use Context#getDisplay() instead.

Source: https://developer.android.com/reference/android/view/WindowManager

But I cannot find it anywhere:

Screen Shot 2021-10-25 at 07 32 41 Screen Shot 2021-10-25 at 07 31 41

Any idea what am I doing wrong? Or if any binding is missing? Thanks for your support.

VS Version:

Visual Studio Community 2022 for Mac Preview Version 17.0 Preview (17.0 build 4172) Installation UUID: fcfcde8b-5cfa-49c4-a7db-98f70b9bbd75 GTK+ 2.24.23

Mono Framework MDK Runtime: Mono 6.12.0 (2020-02/5ce143a1a88) (64-bit) Package version: 612000158

Roslyn (Language Service) 4.0.0-5.21474.9+3b44b6750e1d481037b65f054e6ecf58e271d5ec

NuGet Version: 6.0.0.220

.NET SDK SDK: /usr/local/share/dotnet/sdk/6.0.100-rc.1.21463.6/Sdks SDK Versions: 6.0.100-rc.1.21463.6 5.0.402 5.0.401 3.1.414 3.1.413 2.1.810 MSBuild SDKs: /Applications/Visual Studio (Preview).app/Contents/MonoBundle/MSBuild/Current/bin/Sdks

.NET Core Runtime Runtime: /usr/local/share/dotnet/dotnet Runtime Versions: 6.0.0-rc.1.21451.13 5.0.11 5.0.10 3.1.20 3.1.19 2.1.22

.NET 5.0 SDK SDK: 5.0.402

.NET Core 3.1 SDK SDK: 3.1.414

Xamarin.Profiler Version: 1.7.0.0 Location: /Applications/Xamarin Profiler.app/Contents/MacOS/Xamarin Profiler

Updater Version: 11

Apple Developer Tools Xcode 13.0 (19234) Build 13A233

Xamarin.Mac Version: 7.14.0.27 (Visual Studio Community) Hash: 2566861a9 Branch: d16-10 Build date: 2021-07-27 02:34:12-0400

Xamarin.Android Version: 12.1.0.2 (Visual Studio Community) Commit: xamarin-android/d17-0/0a6f9bd Android SDK: /Users/fanmixco/Library/Developer/Xamarin/android-sdk-macosx Supported Android versions: None installed

SDK Tools Version: 26.1.1 SDK Platform Tools Version: 31.0.3 SDK Build Tools Version: 30.0.3

Build Information: Mono: c633fe9 Java.Interop: xamarin/java.interop/d17-0@8f7ddcd ProGuard: Guardsquare/proguard/v7.0.1@912d149 SQLite: xamarin/sqlite/3.36.0@a575761 Xamarin.Android Tools: xamarin/xamarin-android-tools/main@a5194e9

Microsoft OpenJDK for Mobile Java SDK: /Library/Java/JavaVirtualMachines/microsoft-11.jdk/Contents/Home 11.0.12 Android Designer EPL code available here: https://github.com/xamarin/AndroidDesigner.EPL

Android SDK Manager Version: 17.1.0.14 Hash: 9c65d8a Branch: remotes/origin/backport-pr-548-to-main~1 Build date: 2021-10-08 15:54:06 UTC

Android Device Manager Version: 17.1.0.13 Hash: 1de1208 Branch: remotes/origin/HEAD Build date: 2021-10-08 15:54:06 UTC

Xamarin.iOS Version: 15.0.0.6 (Visual Studio Community) Hash: 2771277e0 Branch: xcode13-ios Build date: 2021-09-23 10:36:08-0400

Xamarin Designer Version: 17.0.0.155 Hash: 4c5cc93be Branch: remotes/origin/main Build date: 2021-10-08 15:54:03 UTC

Build Information Release ID: 1700004172 Git revision: 8c96c59aa6e5227a473ce15cfbd98fe1ee8bf492 Build date: 2021-10-08 11:52:56-04 Build branch: release-17.0

Operating System Mac OS X 11.6.0 Darwin 20.6.0 Darwin Kernel Version 20.6.0 Mon Aug 30 06:12:21 PDT 2021 root:xnu-7195.141.6~3/RELEASE_X86_64 x86_64

AmrAlSayed0 commented 2 years ago

Yes, this is expected. Using older deprecated APIs will always produce a warning. If you're guarding it with runtime API check like you did in your code then it's fine. On newer devices with API 30+ the 2nd part of the if statement will run, on older APIs, the new methods and classes aren't even available to be called so you will have to use the deprecated methods.

Just suppress the warning in-source for that particular call.

FANMixco commented 2 years ago

Hi @AmrAlSayed0, I know that. My question is: "What is the current code for the SDK 30+? Or why am I getting the warning if my code is correct?" My solution is based on ones that you can find in StackOverflow that in theory are updated for the SDK 30+, for example:

val outMetrics = DisplayMetrics()

    if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.R) {
        val display = activity.display
        display?.getRealMetrics(outMetrics)
    } else {
        @Suppress("DEPRECATION")
        val display = activity.windowManager.defaultDisplay
        @Suppress("DEPRECATION")
        display.getMetrics(outMetrics)
    }

Source: https://stackoverflow.com/questions/63276134/getter-for-defaultdisplay-display-is-deprecated-deprecated-in-java

Any suggestion?

xDaijobu commented 2 years ago

Hi @AmrAlSayed0, I know that. My question is: "What is the current code for the SDK 30+? Or why am I getting the warning if my code is correct?" My solution is based on ones that you can find in StackOverflow that in theory are updated for the SDK 30+, for example:

val outMetrics = DisplayMetrics()

    if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.R) {
        val display = activity.display
        display?.getRealMetrics(outMetrics)
    } else {
        @Suppress("DEPRECATION")
        val display = activity.windowManager.defaultDisplay
        @Suppress("DEPRECATION")
        display.getMetrics(outMetrics)
    }

Source: https://stackoverflow.com/questions/63276134/getter-for-defaultdisplay-display-is-deprecated-deprecated-in-java

Any suggestion?

Currently Device Display Information available via official Xamarin.Essentials nuget package, see: https://docs.microsoft.com/en-us/xamarin/essentials/device-display

Bonus: https://github.com/xamarin/Essentials/blob/8657192a8963877e389a533b8feb324af6f89c8b/Xamarin.Essentials/DeviceDisplay/DeviceDisplay.android.cs#L37-L39

i hope this could help you

FANMixco commented 2 years ago

After a while, I created this code based on multiple answers:

    private double GetScreenSize()
    {
        float yInches;
        float xInches;
        if (Build.VERSION.SdkInt >= BuildVersionCodes.R)
        {
            var windowMetrics = WindowMetricsCalculator.Companion.OrCreate.ComputeCurrentWindowMetrics(Activity);
            var currentBounds = windowMetrics.Bounds;

            var metrics2 = RequireActivity().WindowManager.CurrentWindowMetrics;
            var insets = metrics2.WindowInsets.GetInsets(WindowInsets.Type.SystemBars());

            yInches = (metrics2.Bounds.Height() - insets.Bottom - insets.Top) / Context.Resources.DisplayMetrics.Ydpi;
            xInches = (metrics2.Bounds.Width() - insets.Left - insets.Right) / Context.Resources.DisplayMetrics.Xdpi;
        }
        else
        {
            using DisplayMetrics metrics = new DisplayMetrics();

    #pragma warning disable CS0618 // Type or member is obsolete
            Activity.WindowManager.DefaultDisplay.GetMetrics(metrics);
    #pragma warning restore CS0618 // Type or member is obsolete
            yInches = metrics.HeightPixels / metrics.Ydpi;
            xInches = metrics.WidthPixels / metrics.Xdpi;
        }

        return Math.Round(Math.Sqrt(xInches * xInches + yInches * yInches), 0);
    }

You require this library:

https://www.nuget.org/packages/Xamarin.AndroidX.Window/