Android Question Immersive Mode

yo3ggx

Active Member
Licensed User
I have tried everything described in different threads related to Immersive Mode. In my case the layout is built through B4A code, not loaded.
The behavior is heretic.
The navigation bar is hidden, but the layout is sometimes resized, sometimes not.
I need to change the orientation one time in order to fill up the screen with the layout, but event then, controls are in the right position, but the drawing on the canvas is extended more than normal, on one direction.
My device is an LG G3 with Android 5.0.1.

This is what I have now:

B4X:
Sub Globals
  Dim ActivityParent As JavaObject
...
End Sub

Sub ForceImmersiveMode
    If Ph.SdkVersion >= 19 Then
        ' available flags:
        ' SYSTEM_UI_FLAG_IMMERSIVE_STICKY = 4096 (0x01000)
        ' SYSTEM_UI_FLAG_IMMERSIVE = 2048 (0x0800)
        ' SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN = 1024 (0x0400)
        ' SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION = 512 (0x0200)
        ' SYSTEM_UI_FLAG_LAYOUT_STABLE = 256 (0x0100)
        ' SYSTEM_UI_FLAG_FULLSCREEN = 4 (0x04)
        ' SYSTEM_UI_FLAG_HIDE_NAVIGATION = 2 (0x02)
       
        Dim flag As Int
        flag = SYSTEM_UI_FLAG_IMMERSIVE_STICKY + SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN + SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION + SYSTEM_UI_FLAG_FULLSCREEN + SYSTEM_UI_FLAG_HIDE_NAVIGATION    ' 5894 (0x01706)
        
        Dim r As Reflector
        r.Target = r.GetActivity
        r.Target = r.RunMethod("getWindow")
        r.Target = r.RunMethod("getDecorView")
        r.RunMethod2("setSystemUiVisibility", flag, "java.lang.int")
        Dim ajo As Panel = Activity
        Dim width As Int = ActivityParent.RunMethod("getMeasuredWidth", Null)
        Dim height As Int = ActivityParent.RunMethod("getMeasuredHeight", Null)
        If width = 0 Or height = 0 Then Return
        ajo.Width = width 'update the "activity" width and height
        ajo.Height = height
        If pnlRxTx.IsInitialized Then
            pnlRxTx.Width = width
            pnlRxTx.Height = height
        End If
    End If
End Sub

Sub Activity_Create(FirstTime As Boolean)
    Dim jo As JavaObject = Activity
    jo.RunMethodJO("getContext", Null).RunMethodJO("getWindow", Null).RunMethod("setSoftInputMode", Array As Object(0x20))
    ActivityParent = jo.RunMethodJO("getParent", Null)
    ForceImmersiveMode
...
End Sub
Any idea how to make it work as expected?

Thanks.
 

yo3ggx

Active Member
Licensed User
After changing the setSystemUiVisibility call to the original routine.
B4X:
Dim jo As JavaObject = Activity
jo.RunMethod("setSystemUiVisibility", Array As Object(flag))
now it works as expected in Portrait mode, but not in Landscape mode.
First screen from the application is not extended. After first layout change everything works as expected.
There is something similar with IME.AddHeightChangedEvent that can be used for landscape mode?

I am so close...:)
 
Last edited:

Declan

Well-Known Member
Licensed User
I am using an edited version on this code to hide the Navigation Bar on a 7" tablet.
This is a dedicated device for the app and is always in Portrait orientation.
However, I have an issue to sort out:
When I swipe down from the top of the screen, the Navigation Bar reappears.
How can I prevent the user from doing this as the user must never have access to the Navigation Bar?
My code:
B4X:
Sub Process_Globals
    Dim ActivityParent As JavaObject
End Sub

Sub Globals
    'These global variables will be redeclared each time the activity is created.
    'These variables can only be accessed from this module.
End Sub

Sub Activity_Create(FirstTime As Boolean)
    Activity.LoadLayout("Layout1")
   
    Dim jo As JavaObject = Activity
    jo.RunMethodJO("getContext", Null).RunMethodJO("getWindow", Null).RunMethod("setSoftInputMode", Array As Object(0x20))
    ActivityParent = jo.RunMethodJO("getParent", Null)
    ForceImmersiveMode
End Sub

Sub  ForceImmersiveMode
        ' available flags:
         'SYSTEM_UI_FLAG_IMMERSIVE_STICKY = 4096 (0x01000)
         'SYSTEM_UI_FLAG_IMMERSIVE = 2048 (0x0800)
         'SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN = 1024 (0x0400)
         'SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION = 512 (0x0200)
         'SYSTEM_UI_FLAG_LAYOUT_STABLE = 256 (0x0100)
         'SYSTEM_UI_FLAG_FULLSCREEN = 4 (0x04)
         'SYSTEM_UI_FLAG_HIDE_NAVIGATION = 2 (0x02)
      
        Dim flag As Int
        flag = 5894 '(0x01706)'SYSTEM_UI_FLAG_IMMERSIVE_STICKY + SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN + SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION + SYSTEM_UI_FLAG_FULLSCREEN + SYSTEM_UI_FLAG_HIDE_NAVIGATION    ' 5894 (0x01706)
       
        Dim r As Reflector
        r.Target = r.GetActivity
        r.Target = r.RunMethod("getWindow")
        r.Target = r.RunMethod("getDecorView")
        r.RunMethod2("setSystemUiVisibility", flag, "java.lang.int")
        Dim ajo As Panel = Activity
        Dim width As Int = ActivityParent.RunMethod("getMeasuredWidth", Null)
        Dim height As Int = ActivityParent.RunMethod("getMeasuredHeight", Null)
        If width = 0 Or height = 0 Then Return
        ajo.Width = width 'update the "activity" width and height
        ajo.Height = height
        ajo.Color = Colors.white
End Sub
 

Declan

Well-Known Member
Licensed User
You cannot prevent it. The user can always bring back the navigation bar.
Ok, but would I be able to "trap" any action should the user press one of the navigation bar buttons?
I could then ignore the button press.
 

Declan

Well-Known Member
Licensed User
Reading up on the Kiosk tutorial, I am running Android 5.1, can I implement Task Locking which I understand is a function of Android 5?
My app would still need to have access to networking to connect to a remote MySQL database with RDC.
Would implementing Task Locking (if possible) still allow these connections?
 

Declan

Well-Known Member
Licensed User
Thanks Erel,
Reading up on the link you sent, I understand that I must set either the startLockTask() if the app is not a device owner, or the setLockTaskPackages() id the app is the device owner.
Programmatically: To activate screen pinning programmatically, call startLockTask() from your app. If the requesting app is not a device owner, the user is prompted for confirmation. A device owner app can call the setLockTaskPackages() method to enable apps to be pinnable without the user confirmation step.
It would make sense to use the setLockTaskPackages() option, which would also require setting the device owner.
As mentioned in your post:
It is possible to call these methods with JavaObject. I didn't succeed with becoming a device owner with the dpm tool. It seems that this tool doesn't support receivers that are implemented as inner classes (which is the case with the Administrator library).
This is the command that you should run to make it a device owner:
Code:
adb shell dpm set-device-owner <your package name>/anywheresoftware.b4a.objects.AdminManager$AdminReceiver
How would I call these methods (setLockTaskPackages and set-device-owner) with JavaObject?
 

Declan

Well-Known Member
Licensed User
Having read the link you sent:
The device that I am using does not have NFC, so I will have to use adb shell method.
One point that I am confused about is:
Once I have this all running on the device and my app is set as the device owner, I assume that my app is the only app that will run on the device.
If this is so, then would I still be able to run B4A Bridge in the background as I develop my app.

This is way out of my league:
It will probably require writing a new library.
 

Yvon Steinthal

Active Member
Licensed User
I am using an edited version on this code to hide the Navigation Bar on a 7" tablet.
This is a dedicated device for the app and is always in Portrait orientation.
However, I have an issue to sort out:
When I swipe down from the top of the screen, the Navigation Bar reappears.
How can I prevent the user from doing this as the user must never have access to the Navigation Bar?
My code:
B4X:
Sub Process_Globals
    Dim ActivityParent As JavaObject
End Sub

Sub Globals
    'These global variables will be redeclared each time the activity is created.
    'These variables can only be accessed from this module.
End Sub

Sub Activity_Create(FirstTime As Boolean)
    Activity.LoadLayout("Layout1")
  
    Dim jo As JavaObject = Activity
    jo.RunMethodJO("getContext", Null).RunMethodJO("getWindow", Null).RunMethod("setSoftInputMode", Array As Object(0x20))
    ActivityParent = jo.RunMethodJO("getParent", Null)
    ForceImmersiveMode
End Sub

Sub  ForceImmersiveMode
        ' available flags:
         'SYSTEM_UI_FLAG_IMMERSIVE_STICKY = 4096 (0x01000)
         'SYSTEM_UI_FLAG_IMMERSIVE = 2048 (0x0800)
         'SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN = 1024 (0x0400)
         'SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION = 512 (0x0200)
         'SYSTEM_UI_FLAG_LAYOUT_STABLE = 256 (0x0100)
         'SYSTEM_UI_FLAG_FULLSCREEN = 4 (0x04)
         'SYSTEM_UI_FLAG_HIDE_NAVIGATION = 2 (0x02)
     
        Dim flag As Int
        flag = 5894 '(0x01706)'SYSTEM_UI_FLAG_IMMERSIVE_STICKY + SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN + SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION + SYSTEM_UI_FLAG_FULLSCREEN + SYSTEM_UI_FLAG_HIDE_NAVIGATION    ' 5894 (0x01706)
      
        Dim r As Reflector
        r.Target = r.GetActivity
        r.Target = r.RunMethod("getWindow")
        r.Target = r.RunMethod("getDecorView")
        r.RunMethod2("setSystemUiVisibility", flag, "java.lang.int")
        Dim ajo As Panel = Activity
        Dim width As Int = ActivityParent.RunMethod("getMeasuredWidth", Null)
        Dim height As Int = ActivityParent.RunMethod("getMeasuredHeight", Null)
        If width = 0 Or height = 0 Then Return
        ajo.Width = width 'update the "activity" width and height
        ajo.Height = height
        ajo.Color = Colors.white
End Sub

I seem to have a problem with the height of the overall activity, as if the system toolbar was still there and the height was not resized... Aside from that everything seems to be working as intended...help?
 

Yvon Steinthal

Active Member
Licensed User
After changing the setSystemUiVisibility call to the original routine.
B4X:
Dim jo As JavaObject = Activity
jo.RunMethod("setSystemUiVisibility", Array As Object(flag))
now it works as expected in Portrait mode, but not in Landscape mode.
First screen from the application is not extended. After first layout change everything works as expected.
There is something similar with IME.AddHeightChangedEvent that can be used for landscape mode?

I am so close...:)
I dont understand what you changed in your original code...

EDIT: I found a way with a double reflector, keep the bottom bar down, extend the activity height...
 
Last edited:
Top