python-for-android: Multiple bugs with Android immersive mode, especially after pause/resume

p4a 0.5.3, kivy 1.10.0) Reproducer code: https://gist.github.com/hackalog/c02703f78f09cf606cf5c1f32c074f23

How to reproduce:

  • build the apk and install it to the device:
p4a apk --name=immersive --private . --version=1 --requirements=hostpython2,kivy,android \
  --orientation=landscape --package=bug.immersive
  • Start the app. Tap “refresh”
  • BUG 1 Tap “fullscreen”. Screen will shift so the top is offscreen; i.e. pos (0,0) is not shifted down to where the android soft buttons used to be. updating the canvas (by tapping any button, or pressing the “update canvas” button, which explicity does an ask_update() will fix this.
  • Leave the app by swiping up from the bottom and hitting the circle button.
  • relaunch the app
  • Note, android soft menu bar has reappeared. App is positioned under the menu bar (BUG 2) *Press “fullscreen”. Soft menu will disappear, but note app window is not full-sized (black space at top, resolution wrong) BUG 3
  • Worse, notice that your touch events on the buttons are offset by the size of the black bar (pos is out of sync with displayed graphics)

This was reproduced on a Google Pixel C tablet with android 6.0.1 (Build MXC89L)

About this issue

  • Original URL
  • State: open
  • Created 7 years ago
  • Reactions: 2
  • Comments: 33 (13 by maintainers)

Most upvoted comments

This sounds like it could possibly be resolved by a simple update to latest SDL2 and SDLActivity. If I had to guess, that’s where I would assume the bug is (in SDLActivity/the java wrapper, specifically). I’m still busy with a few other pull requests but plan to tackle this soon (in case nobody else has picked it up yet once I get to it), since this will also solve a lot of other issues like missing key events for certain physical keys, CTRL not working on physical keyboards and other problems that appear to be resolved in later SDL2 versions for Android

@hackalog its seems you may have some interest in this, here is a simple example and some opinion.

After on_start() the black bar is at the bottom; after on_resume() the black bar is at the top. The existence of the black bar is the issue, it’s location is an artifact that will disappear when it gets the size is right.

Moving self.set_background_color() to the end of on_start() does not change the issue. So Window.size is unchanged after changing the app window size. I suggest this is the issue.

Looked at this way, Window.size is not static. And Kivy may not know Window.size till the end of on_start()/on_resume(). And I’d guess Kivy gets app Window.size from Android as in general Kivy could not know the size of the Navigation bar on some device.

Perhaps the issue can be addressed by re-making that Android call returning Window.size (explicitly or implicitly) at the end of on_start()/on_resume(). The BIG assumption here is that Kivy evaluation order does not assume Window.size is static - and I have no clue on that!

Note: on the latest p4a this requires the workaround to Issue #1504 else p4a crashes.

Edit: I also tried putting set_android_immersive_sticky() in build() and removing on_start() and on_resume(). The behavior was the same as with on_start() and on_resume(). To me this suggests p4a gets the device size before build().

from kivy.app import App
from kivy.uix.label import Label
from kivy.graphics import Color, Rectangle
from kivy.core.window import Window
try:
    from jnius import autoclass
    from android.runnable import run_on_ui_thread
except:
    def run_on_ui_thread(f):
        def f2(*args, **kwargs):
            pass
        return f2

class Demo(App):

    @run_on_ui_thread
    def set_android_immersive_sticky(self):
        AndroidView = autoclass('android.view.View')
        AndroidPythonActivity = autoclass('org.kivy.android.PythonActivity')
        view = AndroidPythonActivity.mActivity.getWindow().getDecorView()
        view.setSystemUiVisibility(
            AndroidView.SYSTEM_UI_FLAG_LAYOUT_STABLE |
            AndroidView.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION |
            AndroidView.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN |
            AndroidView.SYSTEM_UI_FLAG_HIDE_NAVIGATION |
            AndroidView.SYSTEM_UI_FLAG_FULLSCREEN |
            AndroidView.SYSTEM_UI_FLAG_IMMERSIVE_STICKY)

    
    # Kivy default background color is same color as Android Navigation Bar
    # Change Label background so it is easier to see what is happening
    def set_background_color(self):
        with self.label.canvas.before:
            Color(0.5, 0.0, 0.5)
            Rectangle(size=Window.size)  # BUT THIS IS NOT THE size WE GET :(

    def on_start(self):
        self.set_android_immersive_sticky()
        
    def on_resume(self):
        self.set_android_immersive_sticky()

    def build(self):
        self.label = Label(text = 'Greetings Earthlings')
        self.set_background_color()
        return self.label

if __name__ == '__main__':
    Demo().run()

.p4a

--dist_name=ex
--private .
--package=com.example.ex
--name Ex
--requirements=python3,kivy,android
--arch=armeabi-v7a
--sdk_dir /home/me/androidtools/sdk
--ndk_dir /home/me/androidtools/android-ndk-r17c
--ndk_version 17c
--android_api 28
--ndk-api 21
--version 0.0.1

This is also probably related to a problem with rotation - as I remember, if you start in portrait mode, enable rotation, rotate to landscape, pause and reopen the app, the app remains landscape but the kivy ‘window’ is portrait, and half off the screen. There are probably other similar variant problems as well.