immersiveSticky and display.screenOriginX

That’s probably his issue, having specifically mentioned trouble with .screenOriginXY.

@jhow, fwiw,   i have my config.lua set to dynamically set the content dimensions so as to guarantee an aspect ratio that always fits the width (short dimension, portrait orientation), and letterboxes the height (long dimension, portrait orientation).  i then set yAlign to “top” instead of the typical “center”, so that my “y==0” is always at screen top (immersive or not), then I can ignore .screenOriginY and just deal with a single variable for dynamic layout:  the total letterboxed height.

(i leave xAlign at “center”, and still don’t have to deal with screenOriginX either because I know that the specified content aspect ratio will guarantee a “fit width, letterbox height” arrangement, so “x==0” is always at screen left too, AND contentWidth is always at screen right – x is easy, at least until someone invents a 1:1 aspect device, i don’t think my config supports that at present :D)

Just glad to know you’re thinking about it!  :)

Only “clue” i’ve experienced is the task-resume behaves different than the icon-resume - don’t know if you could maybe monitor both for their event flow and compare?  Maybe there’s a poorly-documented listener somewhere waiting to be implemented??  Just a wild guess.

Hello @Joshua Quick,

Thank you for your response. Unfortunately, I still have some things I’d like clarified:

I do use Corona’s letterbox scaling, as stated in my config.lua. But, I do not necessarily keep every asset within the content area (as defined here). In many cases, I use display.screenOriginX as an element to help position my assets so they are closer to the side of the screen (I use landscapeRight orientation). I also use display.screenOriginX for many other things, which I will discuss later.

I am a bit unclear on what you mean by " if you want to fill in the letterbox area with your own graphics to get rid of the letterbox bars". Do you mean… if I want to place assets in the letterbox area that exists outside of the content area (ie. the area outside the orange rectangle in the below image)? If so, then as I mentioned above, yes I do this using display.screenOriginX. I also make use of display.screenOriginX in many other cases… for example, to help me size the width of certain assets. 

Now back to my question, though:

Likely due to my own unclear wording, I think you may have interpreted this as “Should I, the developer, handle the resize?”. What I meant was… Is there a way to have immersive or immersiveSticky mode activated without the screen itself ever resizing?

Maybe an example would help?

On one of my devices… when the black ui bar is shown (for example, 1. before setting to immersiveSticky, or 2. when a native ui occurs like showAlert or volume up/down touch), display.screenOriginX is logged as -48 and thus the screen dimensions end up being 576 x 320. Let’s call that configuration A. If I then set immersive mode and Corona resizes everything, display.screenOriginX is logged as -26.5 and the screen dimensions end up being 533 x 320… hence the visual assets towards the sides get cut off (since they were originally created and positioned when the dimensions were 576 x 320 and display.screenOriginX was -48). 

But let’s say, immersive mode has already been set in this session and I enter my next scene… In the new scene, everything is created and positioned properly (ie. according to the newer screen dimensions 533 x 320). Let’s call this configuration B. But, say I use some native ui element like the volume up button. Then, the black bar comes back and the screen size changes to 576 x 320 when all my objects were positioned and sized according to when the screen was 533 x 320 and display.screenOriginX was -26.5.

Now, I understand from what you mentioned earlier, all these newly mispositioned and mis-sized assets should be handled by me within the resize event handler. Unfortunately, this would require me to update almost everything in my code that is instantiated using display.screenOriginX. This includes, visual asset and ui element positioning and sizing. This also affects code for when to spawn and kill offscreen objects. Now that the screen size can change live, the boundaries for what’s considered offscreen can change mid game (at the simple click of a volume button). This is a lot of work. Which brings me to my earlier inquiry:

Instead of me always having to handle this resize and accommodate every code block and asset affected by display.screenOriginX (which would include changing a significant portion of my files and scenes)… is there a way immersive/immersiveSticky mode can avoid the resize altogether? Using my example from above, could we somehow automatically  start  and keep the app at configuration B and never resize away from configuration B? This would mean that all my assets would be set up for the more zoomed-in view of immersive mode. If the black bar were to come up, it would just overlay what’s at the bottom of the screen (as opposed to changing the entire screen size to configuration A)

I’ve noticed games that do this with their immersive sticky mode. As an example, if you take a look at Sonic Dash, their screen never changes size. In the below screen, the left image shows the game when the black bar is away and the center image shows the game when the black bar is shown. The right image places them both with a bit of transparency on top of each other to show that the screens are the same exact size (ie. there was no resize at all).

On the other hand, if I showed you the same thing with our app, then you would see that the size of everything changes (due to the resize). If there was a way in which I can utilize immersive/immersiveSticky without the resize, it would save me a lot of work and time (ie. having to update every little scene in my app to tediously accommodate any live screen size change).

So in conclusion, can you please provide us with a way to use immersive and immersiveSticky modes where the screen does not automatically resize and instead stays the same size?

Hello @davebollinger,

One hundred percent agree with this. This should be handled automatically. If we previously set immersiveSticky, why wouldn’t the black bar go away? Could this be considered a bug?

In my config.lua, I have width and height at 320 and 480 respectively. How did you go about changing them dynamically and how did you know the correct values to change them to? You’re not talking about using “adaptive” mode, right?

I’m assuming making this type of change (dynamic dimensions and new alignment) would require me to update a significant portion of my app to accommodate these new configurations, correct? Ie. having to reposition items that were previously positioned under other configurations, etc.? I tried playing around with the aligns in my config.lua, but it seemed to throw some positions off a bit.

Thank you for taking the time to respond

>> Is there a way to have immersive or immersiveSticky mode activated  without  the  screen  itself ever  resizing?

Enabling immersive mode will always trigger a resize event.  That makes sense because the navigation bar and status bar disappear, causing the app’s window to become taller or wider.

You do *not* have to re-layout your app during a resize event if you’re app is set up for letterbox scaling *and* it never renders in the letterbox area.  In which case, Corona will automatically rescale your app’s content window to fit.  But… if you are rendering in the letterbox area, then odds are the letterbox rectangles have increased or decreased in size, which means you’ll need to relayout your content within the letterbox rectangles.  That’s a task for you and is not something we can do automatically for you.

>> i s there a way immersive/immersiveSticky mode can avoid the resize altogether?

The “resize” event will always happen.  Even for that Sonic app that you showed me (yes, it’s true!).  That’s unavoidable and is just how it works on the native side on Android.  It’s up to the developer to decide on how to deal with it.  If you do *not* want your content to rescale due to the resize, then you’ll need to either turn Corona’s global content scaling off or switch to “adaptive” content scaling.  If you turn off content scaling, then you’ll be working on physical screen pixels and you can control scaling yourself via groups.  When going in/out of immersive mode, then you’ll find that the app window’s pixel width or height will change and it’s up to you on how to re-layout your content during these events.  You can center your content, but then the content will shift when going in/out of immersive mode.  Or you can top align your content, in which case the content won’t shift, but you’ll you need to fill the sides of the screen with more content to fill in where the navigation bar disappeared.

Bottom line, dealing with a resizing screen is a lot of work and time.  That’s just how it is *and* it’s a very common event on Android.  Especially on Android tablets with apps that support both portrait and landscape orientations (hint: the navigation bar rotates with the app, changing the aspect ratio).  That’s why most native Android developers work with layout frameworks to dynamically layout the screen in various ways.  But this is something Java developers are already used to.  If you don’t want to do the work for this, then my suggestion is to live with the content scale change or give up on immersive mode.

let’s see i can get away with posting “commented code” instead of writing out long boring sentences :D…  here’s the approach:

-- we assume that no devices exist with "more square" aspect ratios: -- (or you could just use 1.0 if paranoid that something squarer may come along eventually) -- NB: aspect ratio is defined as long-dimension / short-dimension, as per landscape orientation -- even though here (in config.lua) we otherwise specify things as per portrait orientation local minimumDeviceAspectRatio = 4.0 / 3.0 -- fe iPad, Nexus9 -- so that letterboxing is guaranteed to: fit width, letterbox height (or exactly fit 4:3) -- (ie, we will never do the opposite: fit height, letterbox width) -- so, specify the exact content width you want: local contentWidth = 320 -- now derive a value for content height that will exactly fit the theoretical -- "minimum aspect device", thus being "not tall enough" on all other known devices. -- (math.floor() is used to intentionally trunc height down, rather than up as per math.ceil(), -- or god forbid math.floor(n+0.5) rounding, again to guarantee "fit width" given height too small, -- determine any resulting fractional height later via display.actualContentHeight) local minimalAspectHeight = math.floor(contentWidth \* minimumDeviceAspectRatio) application = { content = { width = contentWidth, height = minimalAspectHeight, scale = "letterbox", xAlign = "center", -- doesn't matter, width fits, display.screenOriginX should always be 0 yAlign = "top", -- force the y-origin to zero, ie display.screenOriginY should always be 0 }, } -- now, within your code... -- use display.actualContentWidth for width (which will just be the constant above, since it fits) -- and display.actualContentHeight for height (which will be \*at least\* minimalAspectHeight, since -- it either exactly fits 4:3 device, or has been extended via letterboxing on all other devices) -- fe on a 4:3 device, the above sample values would return 320x426.666 as your actualContentW/H -- fe on a 16:9 device, the above sample values would return 320x568.888 as your actualContentW/H -- (and on android, of course, with/out the immersive nav bar, -- as available device pixel dimensions change, so does actualContentHeight accordingly)

@Joshua Quick,

Does the resize happen when the transition of the nav bar is complete? (As opposed to immediately once setProperty is called).

For example, say I’m switching from non-immersive to immersive. The resize occurs once the nav bar has finished moving off the screen?

Like wise, if I’m switching from immersive to non-immersive. The resize occurs once the nav bar has finished moving up into place on screen?

Thank you.

@Josh 

Thank you for your patience on this topic. 

One thing that still confuses me is, based on my reading of the Android documentation, the resize event shouldn’t even be firing at all: https://developer.android.com/training/system-ui/immersive.html

However, if you’d like the system bars to automatically hide again after a few moments, you can instead use theSYSTEM_UI_FLAG_IMMERSIVE_STICKY flag. Note that the “sticky” version of the flag doesn’t trigger any listeners, as system bars temporarily shown in this mode are in a transient state.

Unless I am reading it wrong, it seems that with the sticky immersive mode, we really should be able to just set it once and not worried about any potential resizing? 

Thanks!
Andrew

It absolutely does trigger a *resize* event.  I know.  I’ve seen it.

The bottom navigation bar is *not* overlaid on top of the app window (ie: the Android activity window).  It steals screen real-estate and your app window is sized just above it.  When you tell the OS to go into immersive mode, the bottom navigation bar is removed, causing your app window to be resized to fill the screen.  That’s how it works.  Meaning that your app window’s width and height is smaller than the actual screen width and height until it is put into immersive mode.  The Android OS can’t predict the future.  It doesn’t know to hide the navigation bar until you tell it to dynamically, which again, causes your app window to be resized.

So, the only other Android OS oddity you have to deal with is when your app gets suspended/resumed.  The Android OS has a nasty habit of overlaying the bottom navigation bar on top of the app and not resizing the window to fit.  Google has accepted this as a bug on their end (I’ve provided a link to it earlier in this forum thread) and we haven’t found a work-around for it.  Nor has Google provided one.  So, unless you can find a work-around for this issue in the OS on your end, my advise is to not waste anymore time on this and not use immersive mode.  At this point, I don’t think immersive mode is worth using until Google fixes it on their end.

Hi @Joshua Quick,

Would you mind answering this question?

I don’t know if it happens before or after the transition.  But it doesn’t really matter either.  It’s up to the Android OS to resize the activity window and its views to best-fit the screen.  Native Android developers such as us have no control over it.  Corona gets notified about this resize event via the following Java method…

   [http://developer.android.com/reference/android/opengl/GLSurfaceView.Renderer.html#onSurfaceChanged(javax.microedition.khronos.opengles.GL10](http://developer.android.com/reference/android/opengl/GLSurfaceView.Renderer.html#onSurfaceChanged(javax.microedition.khronos.opengles.GL10), int, int)

@Josh

Thanks for the info. It does sound like a real mess to implement… sigh…

One of the big reasons we are pushing this hard on this topic is because we are working with Google on a feature opportunity within Google Play, and they have listed this as one of their requirements. Here is their feedback to us.

[Must Do]The app should hide the status and navigation bars using immersive full-screen mode. The user can reveal the system bars with an inward swipe along the region where the system bars normally appear.  For more info:
https://developer.android.com/training/system-ui/immersive.html

We will try to push back with Google, and see if there is any sort of “partial” implementation that we can do that would be a good user experience and still meeting their requirements.

Thx!

Well, since you are in contact with Google, then perhaps you can ask them if you know of a work-around to this bug case then?

   https://code.google.com/p/android/issues/detail?id=170752&q=IMMERSIVE&colspec=ID%20Type%20Status%20Owner%20Summary%20Stars

Because this issue is happening to other native Android developers as well.  It doesn’t seem like all apps are effected by this issue.  So, there has to be something we can do to make it work.  We just don’t know what it is.

We probably need to take care to distinguish immersive from immersive sticky…  (the sticky version being the title of this thread, and is what I’m using too)

>> The bottom navigation bar is *not* overlaid on top of the app window

We’re talking “immersive sticky” here, which sure has every appearance and functional indication of being overlaid.

Go install Angry Birds Transformers, for example.  From the “world” screen, swipe up to reveal the nav bar, which will appear semi-transparent over the app (as immersive sticky is supposed to).  Not only can you still SEE the app underneath it, you can still INTERACT with the app underneath it – scroll the world, for example, with semi-transparent visibility where scrolling “under” the nav bar.

The nav bar will just sit there “over” your app for about 3 seconds if you don’t interact with it, then it goes away again.  No apparent resize ever occurs.

That’s the expected behaviour from immersive sticky.  Only if you actually interact with the nav bar do you potentially trigger a resize (fe, by tasking away from your app, so for sure then you’d get resized! :D)

But THAT isn’t the problem for Corona - Corona handles THAT part just fine!  (that is, it works just as described, not that you are much in control, but at least the OS didn’t sideswipe you)  Go install one of my Corona apps (and you might as well click some ads while you’re in there :D) and you can swipe up to see transparent nav bar over not-resized-app.

Where Corona’s problem is is on restore/resume.  Maybe there’s some aspect of a (potentially already existing) focus listener, or systemuivisibility listener, or layout listener, or god-only-know-what-else listener that needs to be “amended” in some way to deal with immersive sticky?  That’s the best shot-in-the-dark that I myself can offer for ya.

EDIT:  oh, potentially ignore all except last paragraph of my previous reply… it escaped my attention that you two are apparently talking about the menu-not-an-overlay and subsequent resize… PRIOR AND JUST FOLLOWING the first request for immersive sticky.  so nevermind  :D

What they seem to be discussing there is what occurs DURING immersive sticky when the menu bar is revealed.  You’ve still got to establish it first though, and that’ll change the available screen dimensions, thus needing an initial resize.

Dave is right.  It doesn’t matter if you use immersive or immersiveSticky.  In either case, it triggers a resize event due to the navigation bar being removed from the screen.

Perhaps a simpler means for you to deal with this resize issue is for you to not render any content until after you enable immersiveSticky mode.  You’ll have to wait for the 1st resize event to be dispatched before creating your display objects and rendering the scene.  This way, you’ll be guaranteed to set up your scene in fullscreen mode and not worry about the resize anymore.  And in case you are running on a forked Android OS that doesn’t follow the rules and already has your app displayed in fullscreen mode (the 1st generation Kindle Fire comes to mind, but it doesn’t support immersive mode), you may want to set up a timer to render the scene in case the resize event never occurs.

And regarding the restore/resume issue with immersive mode, I’m not sure what we can do about it.  There is absolutely no clue from the OS that I’m aware that tells us it’s rendering that nav bar on top.  The OS is sizing the activity window like the navigation bar isn’t there when in fact it is… and that’s the OS bug/issue we’re dealing with.  Disabling and re-enabling immersive or immersiveSticky doesn’t work-around that OS issue.  Only navigating away and back to the app fixes it, like Dave said.

re BBABFRFTLRI (black bar at bottom following resume from task list restoring immersive – proving conclusively that I am the master at coining useful abbreviations  :D)

my wish is to strike the right “tone” to continue posing this as an interesting challenge to engineering to solve, without sounding accusatory for not having yet solved it.  i’ll likely fail and sound like a jerk anyway - just know that’s not my intent, ok?

on the one hand, we have that issue you linked to - one guy, and his buddy who added the second star, with no community followup whatsoever.  which is not to dismiss it, as we know it can be an issue, but suggests that it’s not a widespread issue affecting everyone.

on the other hand, we have any number of “AAA” game titles from major commercial vendors, using a variety of engines (and some are suspected native, i don’t really know all the dev back-stories), that don’t seem to experience the problem.  Unity for one, seems to have solved it, as i do know that some of my installed “reference” apps were built with it.

again, my intent is not to accuse like “unity solved it, you didn’t, nyah, nyah, nyah!”.  but rather to point to the weight of evidence suggesting that it CAN be solved, and so keep you interested in puzzling it out – thanks!  :)

@Josh - I’ve posed the question to my contact at Google. Will let you know if I get anything back. My contact is on the marketing editorial team, so we’ll have to see…

Thanks again for your help!

>> I’ve posed the question to my contact at Google. Will let you know if I get anything back.

Thanks Andrew.  I’m sure someone at Google knows how to work-around the issue.  This is probably the most productive way at finding a solution to it.  Like I said earlier in this forum thread, we did try to find a work-around on our end, but didn’t find one.  At this point, we rather focus our time on Android development tasks that we know we can achieve that will help as many Corona developers as possible.  Our biggest items right now is helping developers transition Google in-app purchasing from v2 to v3 (v2 is no longer supported by Google), supporting the newest major rev of the facebook SDK before their old SDK stops working, and targeting the newest Android API Level.  Those are all big items that’ll benefit the majority of Corona developers and I’d hate for us to burn a week trying to *attempt* to find a work-around for this immersive mode issue (and possibly failing) when we know we can put this time to good use that’s hotly demanded by other Corona developers.  We don’t have infinite time and resources, so, we’re doing the best we can to satisfy as many Corona developers as we can.