corona icon indicating copy to clipboard operation
corona copied to clipboard

display.safeAreaInsets does not detect soft navigation bar on Android 10+

Open vmirzoyan opened this issue 4 years ago • 25 comments

A typical business app on Android sits above the software defined navigation bar at the bottom of the screen.

Actual result: When running Android 10+ on the Google Pixel 3, display.safeAreaInsets does not take into account the bottom soft navigation bar. As a result, the app UI is blocked by the navigation bar.

Expected result: display.safeAreaInsets should account for the bottom soft navigation bar because it is NOT a safe area to place UI elements.

This issue is only evident when testing on the device itself and cannot be reproduce in the Corona simulator.

vmirzoyan avatar Mar 29 '20 15:03 vmirzoyan

Is this still an issue after release 2020.3619?

sekodev avatar Oct 06 '20 09:10 sekodev

Is this still an issue after release 2020.3619?

I think, unfortunately, it is. This needs fixing. I thing currently safe area apis only try to account for screen bezels. Software elements on android are ignored. This is not how it supposed to be.

Shchvova avatar Jan 26 '21 19:01 Shchvova

Under the hood, Solar2d uses DisplayCutouts Android class to compute safe area, this class is merely about notches in display, thats why it works correctly for top camera notch but not for bottom inset where it returns 0 always. No notch there, no display cutouts.

displayCutout() is only about display cut outs , it, by definition, doesn't take into account navigation or status bar. Currently Solar2d uses DisplayCutout class to determine safe area for android.

Instead, the intended way to get system bars insets is using WindowInsets.

This gives a tuple with the insets:

Insets insets = WindowInsets.getInsets(Type.systemBars ())

insets.bottom will be the nav bar and insets.top will be top status bar

if additionally we want a new stand-alone API for navigation bar height only then:

Insets insets =  WindowInsets.getInsets(Type.navigationBars ())
return insets.bottom

References:

  1. getSystemWindowInsetBottom
  2. blog post

Earnes-Tg avatar Jan 27 '21 19:01 Earnes-Tg

Something new: https://forums.solar2d.com/t/height-of-android-navigation-bar-solved/353073

sekodev avatar Jan 28 '21 23:01 sekodev

The next step is to understand when this navbar is on and when not. We need some kind of flag in order to determine the presence of a software navigation panel.

maxserduk avatar Jan 29 '21 05:01 maxserduk

As I said, instead of this work around, the official way ( According to Google engineer ) is using this:

Insets insets =  WindowInsets.getInsets(Type.navigationBars ())
return insets.bottom

it covers all cases: nav bar keys, nav gesture bar, all according to whatever user chose in his device settings as navigation mechanism, or even no bar at all and just physical keys.

Earnes-Tg avatar Jan 29 '21 15:01 Earnes-Tg

Hey guys. So I made a build and trying to test this stuff... Android system ui visibility/status bar/safety insets are stupid topic, because you touch one everything crumbles. So I made some changes, and it seems rather OK from the first glance, I would really appreciate help in testing. Here is my main.lua I'm testing with. And to test replace contents of Native/Corona/android/lib/gradle with this aar.

P.S. WindowInsets.getInsets(Type.navigationBars ()) is all good and fine, but starts to work only in Android 11 (we are not there yet)

Shchvova avatar Feb 03 '21 15:02 Shchvova

Thanks Vlad, True getInsets(Type.navigationBars ())is from API 30, from API 20 to 30 it's getSystemWindowInsetBottom()

Also regarding "touch one everything crumbles", that's why I suggested maybe adding a new API that merely returns the value of getSystemWindowInsetBottom() , those who want to take the bottom software bars into account call it.

Earnes-Tg avatar Feb 04 '21 04:02 Earnes-Tg

#220

Storeynathaniel avatar Feb 04 '21 05:02 Storeynathaniel

We already have apis for this: display.getSafeAreaInsets() And convenience APIs to make usage easier: display.safeScreenOriginX display.safeScreenOriginY display.safeActualContentWidth display.safeActualContentHeight I think everything should work at this point. Please test and tell me if something isn't working out.

Shchvova avatar Feb 04 '21 06:02 Shchvova

Please

Storeynathaniel avatar Feb 04 '21 07:02 Storeynathaniel

I know we have this API display.getSafeAreaInsets(), but it relies on a native android API that counts for physical notches only and not software bars. Of course the best solution is to make it add software bars into account too. But since this, as you suggested, breaks other thing. I suggested an additional API that directly maps to Android API that returns navbars hieght, to keep backward API display.getSafeAreaInsets compatible.

but if u decided to fix getSafeAreaInsets() then it's better.

does it now use getSystemWindowInsetBottom inside getSafeAreaInsets

Update: I tried the version you uploaded

Unfortunately, it still doesn't work.

  display.setStatusBar( display.HiddenStatusBar )
   
   local sceneGroup = self.view
   local CENTER = { x = display.contentWidth/2, y = display.contentHeight/2 }
   local H = display.contentHeight
   local W = display.contentWidth


   local greenBG = display.newRect(sceneGroup,CENTER.x,CENTER.y,W,H)
   greenBG:setFillColor(0,0.4,0)

   local topInset, leftInset, bottomInset, rightInset = display.getSafeAreaInsets()

   local blueSafeArea = display.newRect(sceneGroup,CENTER.x,CENTER.y,W,H-topInset-bottomInset)
   blueSafeArea:setFillColor(0,0,0,0)
   blueSafeArea:setStrokeColor(0,0,1)
   blueSafeArea.strokeWidth=8

   local info = display.newText{
       parent = sceneGroup,
       x = CENTER.x,
       y = CENTER.y,
       fontSize=50,
       text=
         "topInset = ".. math.floor(topInset)
       .."\nbottomInset = "..math.floor(bottomInset)
       .."\ncontentHeight="..math.floor(display.contentHeight)
       .."\nActualContentHeight="..math.floor(display.actualContentHeight)
       .."\nsafeActualContentHeight="..math.floor(display.safeActualContentHeight)

   }

The problem remains that bottomInset is zero

Earnes-Tg avatar Feb 04 '21 10:02 Earnes-Tg

Hey, @Earnes-Tg, may I ask you to run the project I provided here: https://gist.githubusercontent.com/Shchvova/28c8e067bb80555cd2db433a07bb4d95/raw/6d909ae78e75c24bc72eaee9fea4181995c4b4e6/main.lua

Shchvova avatar Feb 04 '21 15:02 Shchvova

Run

Storeynathaniel avatar Feb 04 '21 21:02 Storeynathaniel

@Shchvova , sure

02-05 10:52:05.775 27273 13481 I Corona  : -0	-0	400	888
02-05 10:52:05.795 27273 13481 I Corona  : 0	25	400	863
02-05 10:52:05.798 27273 13481 I Corona  : 25	0	0	0

IMG_7051

As you can see, it shows "bottom inset" is zero , and safeActualContentHeight is just hieght minus notch are at top.

Did you utilize getSystemWindowInsetBottom inside getSafeAreaInsets ?

Earnes-Tg avatar Feb 05 '21 08:02 Earnes-Tg

Yes. Here's code which retrieves insets: https://github.com/Shchvova/corona/blob/fe67e75af2a6f340123c769496990e667beaf701/platform/android/sdk/src/com/ansca/corona/NativeToJavaBridge.java#L1567-L1576 You can try without stable insets here.

Would you like to do some debugging? It is not that complicated how to do it, if you want I can guide you through it, in Discord with voice chat and screen sharing if you want to.

EDIT: also, try changing system UI visibility, those texts are buttons.

Shchvova avatar Feb 05 '21 10:02 Shchvova

  1. Yeah no problem, let's arrange that, Monday ?

  2. I looked at the code thanks. seem the one without stable insets to be the way to go but still it doesn't work.

I did "git clone" and have Corona in local directory. is there a command that generates Corona.aar to test something real quick

Earnes-Tg avatar Feb 05 '21 20:02 Earnes-Tg

I created a demo Android App to make sure I understood how Android handles this. I've managed to get it report bottom inset correctly.

navbar

gesture-nav

immersive

Here's what I concluded, and might help us get close to the the solution.

When in default mode visiblity ( not the immersive ) we have to use two flags that will make it return bottom inset correctly, without them bottom inset always returns zero.

setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION | View.SYSTEM_UI_FLAG_LAYOUT_STABLE); I set this in OnCreate()

Now for Corona: Maybe you can set them in file: corona/platform/android/sdk/src/com/ansca/corona/Controller.java inside function void setSystemUiVisibility(final String visibility)

replace this:

 } else if (visibility.equals("default")) {
                                        // Clear all flags
                                        vis = 0x00000000;

with this:

 } else if (visibility.equals("default")) {
                                        // Clear all flags
                                        vis = View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION | View.SYSTEM_UI_FLAG_LAYOUT_STABLE;

if you can, build an aar for me with this change ( without the stable you mentioned above ! )

Earnes-Tg avatar Feb 05 '21 21:02 Earnes-Tg

If you have android studio it is rather easy to do it yourself. It is described here: https://github.com/coronalabs/corona/tree/master/platform/android#how-to-build-coronas-android-software But in short, you can do it in severals steps:

  1. Clone with recursive flag: git clone --recursive https://github.com/coronalabs/corona.git
  2. Put your project into new platform/test/assets2 directory, so you'll have platform/test/assets2/main.lua <- this would be a launch project
  3. Drag&Drop platform/android directory onto Android Studio to open it, and press Play button to build. Do not update plugin as Studio suggests, but do install NDK 18, it is required to build the AAR. Build can take 5-20 minutes depending on your hardware. Incremental build take seconds. First time is a long one though.
  4. That's that. You can debug stuff by putting breakpoints and pressing Debug button 🐞.

Shchvova avatar Feb 06 '21 07:02 Shchvova

Using the version Vlad sent me, I've got this in Solar2d, It meets my requirements.

https://user-images.githubusercontent.com/4797458/108200723-88ef9d00-7127-11eb-8022-852029f646b3.mp4

You can see it works for:

  • soft keys mode
  • gesture mode
  • immersive mode. for my various apps/uses cases it works.

Earnes-Tg avatar Feb 17 '21 11:02 Earnes-Tg

is that already available in the latest solar2d build?

maciej-czekala avatar Mar 19 '21 23:03 maciej-czekala

When it will be available in general build?

maciej-czekala avatar Apr 18 '21 22:04 maciej-czekala

The changes weren't accepted by Vlad. I've researched this at the time and provided my insight. it worked for soft keys and gesture mode and immersive mode where bottom inset was 90,15,0 respectively I placed admob banner with y=bottomInset and looked great

Earnes-Tg avatar Jun 07 '21 09:06 Earnes-Tg

Hello. Any updates on getting this fix into a general build @Shchvova ?

I'm also building a general purpose app, and am facing the same issue with the bottom navigation bar. Thank you.

TestingDude91 avatar Jul 09 '21 01:07 TestingDude91

Hi, any update on that?

maciej-czekala avatar Sep 12 '22 13:09 maciej-czekala

This is fixed with 2022.3681+

scottrules44 avatar Oct 16 '22 02:10 scottrules44

Awesome!!! Thanks. I will check it out.

Regarda

W dniu niedz., 16.10.2022 o 04:35 Scott Harrison @.***> napisał(a):

Closed #46 https://github.com/coronalabs/corona/issues/46 as completed.

— Reply to this email directly, view it on GitHub https://github.com/coronalabs/corona/issues/46#event-7595767954, or unsubscribe https://github.com/notifications/unsubscribe-auth/ABODERNDWIPKG3KWQ67DWNLWDNSWTANCNFSM4LWAAV7A . You are receiving this because you commented.Message ID: @.***>

-- Pozdrawiam Maciej Czekała

maciej-czekala avatar Oct 16 '22 07:10 maciej-czekala