[Android] Volume buttons not working properly

Here is the code:

function onKeyEvent( event ) local phase = event.phase local keyName = event.keyName if ( "back" == keyName and phase == "up" ) then audio.play(myG.sounds.backButton) if ( storyboard.currentScene == "scene-MainMenu" ) then native.requestExit() else if ( storyboard.isOverlay ) then storyboard.hideOverlay(true) storyboard.isOverlay = false else local lastScene = storyboard.returnTo if ( lastScene ) then storyboard.gotoScene( lastScene ) else native.requestExit() end end end end if ( keyName == "volumeUp" ) then return false elseif ( keyName == "volumeDown" ) then return false end return true end Runtime:addEventListener( "key", onKeyEvent )

The code works when you press the volume up or down button.  However, if you  hold  down on either the volume up/down button nothing changes.  In pretty much every other app (example: YouTube), if you hold down on the volume button the volume will continue increasing/decreasing.   Any thoughts?

Print phase property and check output on debug console

As expected it prints the correlating phase, either “up” or “down”.  But only once per button press/hold (even with the “return true” at the very end removed)

Hmmm so write some function which rises and decrease volume. On down phase create timer which will call this function in infinite loop. On up phase just cancel timer :slight_smile:

Leave return true at the end. If you do not do this corona will take it as if you didn’t taken care of handling it. If so corona will apply default action. Eg for return button on android this will close app (into background)

Or maybe CL staff can tell me what I’m doing wrong, or fix it on the backend.  Surely we shouldn’t have to write basic built-in OS functions?

If detecting button only fires on state change then there is no workaround, but maybe there is other way - dunno

Button handlers, like touch handlers only fire one event per action.  You get one down event when you press and hold the button and one up event when you let go.   This is how keyboard handlers work.

By returning false, you’re telling Corona to not handle it but let the OS handle it.  So it should use the OS to control the volume.   If you want to control the volume of your app using them and have it change while holding it down, then you have to set a flag on button down and use a runtime listener or timers to adjust the sound until you get the “up” event.

So I was right :smiley:

I guess my question is why can’t the volume keys just work?  Why do we even need to program them?  Seems like they should just work as intended, and if we want them to do something else we should have to write code to that.  

JonPM,

I work on the Android code here.  Yes, what you’ve stated is true.  Holding down the volume key does not continuously lower/raise the volume.  It only steps the volume up/down 1 level.  There is no work-around.  It’s been like this for 2 years.  You’re actually the 1st Corona developer to notice it.

There is actually a technical reason involving multithreading as to why this behavior exists.  But that said, nobody has ever had their apps rejected by reviewers or received bad reviews on the app store regarding this behavioral difference.  So, we stuck with this behavior.  We don’t consider it a bug since the volume controls still work.  Changing it to match would require significant effort on our part.  So, we’ve left it the way it is.

Thanks for the response Joshua.  When you say there is no work-around do you mean the methods advised above (i.e. using a timer) won’t work either?  

I wasn’t really concerned about the app getting rejected, but more concerned with user experience.  I must admit my rant was out of frustration, as I am spoiled by Corona because it usually makes everything much more simpler and “automated”.  To see a “basic” function out of order is a little disheartening.  In the end it isn’t that big of a deal.  I just prefer things to work as they should, as I’m sure you do too.    

You definitely need to return false for the volume keys.  That allows the operating system to handle the change of volume, which you can see when the Android volume control popup show onscreen.  However, it still won’t allow the volume to increase/decrease continuously.  In fact, I highly recommend that you return true *only* for the keys which you are handling and return false by default.  Otherwise, you might encounter other unexpected behaviors.

If you want to know the nitty gritty details, then here is the reason why the volume does not get raised/decreased continuously.  In Corona, the Lua runtime does not run on the main UI thread, but on a separate thread.  Android key events are raised on the main UI thread.  So, what we have to do is handle *all* key events received by the main UI, queue the events to be raised on the Lua thread, call the Lua listener for each queued key event, queue key events back onto the main UI thread that were not handled in Lua (ie: returned false), and finally re-dispatch the key events back to the activity/window to be handled by Android.  We can’t call Lua listener directly from another thread, because this would cause race conditions and possibly crashes, making the above process necessary.  The unfortunate side effect is that we lose Android default volume handling by handling all key events in native code and then re-dispatching them back to the window.  Instead, the behavior we get is the volume being raised/lowered by a single step.

In the future, it would be much more worth it to have the Lua running on the main UI thread, because that would vastly simplify the above process, simplify enterprise/plugin development, and help us introduce other features that require main UI thread access.  But there are other technical details, namely OpenGL not running on the main UI thread by default on Android, that’s holding us back on that at the moment.  However, that’s something I want to experiment with later this year.

in any case, I hope the above helps explain this.

Print phase property and check output on debug console

As expected it prints the correlating phase, either “up” or “down”.  But only once per button press/hold (even with the “return true” at the very end removed)

Hmmm so write some function which rises and decrease volume. On down phase create timer which will call this function in infinite loop. On up phase just cancel timer :slight_smile:

Leave return true at the end. If you do not do this corona will take it as if you didn’t taken care of handling it. If so corona will apply default action. Eg for return button on android this will close app (into background)

Or maybe CL staff can tell me what I’m doing wrong, or fix it on the backend.  Surely we shouldn’t have to write basic built-in OS functions?

If detecting button only fires on state change then there is no workaround, but maybe there is other way - dunno

Button handlers, like touch handlers only fire one event per action.  You get one down event when you press and hold the button and one up event when you let go.   This is how keyboard handlers work.

By returning false, you’re telling Corona to not handle it but let the OS handle it.  So it should use the OS to control the volume.   If you want to control the volume of your app using them and have it change while holding it down, then you have to set a flag on button down and use a runtime listener or timers to adjust the sound until you get the “up” event.

So I was right :smiley:

I guess my question is why can’t the volume keys just work?  Why do we even need to program them?  Seems like they should just work as intended, and if we want them to do something else we should have to write code to that.