Android Code Snippet Disable access to the StatusBar (Notification bar)

Hello,

Posting here because I have searched a long time before to find the solution. I am not an expert and without Erel's help, I wouldn't have been able to make this working.
So, please apologize if I won't be able to help greatly.

A sample project is attached. I have tested it from Android 2.3 to Android 5.0.2 (Nexus 7 2013).
The project includes the code that Erel kindly translated for us in b4a.

You will need to add those permissions into your Manifest
B4X:
AddPermission(android.permission.SYSTEM_OVERLAY_WINDOW)
AddPermission(android.permission.SYSTEM_ALERT_WINDOW)

What does the code do ?
It adds a label at the top of the StatusBar. For debugging, I did use a sentence (check the Process_Globals in the service to modify its value).

Why do I put the code in a service ?
Because the system kills the activity, the label stays on top for some moment and the label disappears. Using a service and restarting it when it gets killed is the way I have found to keep it running.

Could I remove the overlay by code ?
Yes, please see the project Overlay-OnOff attached (thanks to DonManfred)

Can I start the service at boot time ?
Yes, check Service Attributes


B4X:
#Region Code to disable access to the StatusBar
'Code translated by Erel:
'https://www.b4x.com/android/forum/threads/overlay-over-the-status_bar.49221/#post-309833
'Original source code:
'http://stackoverflow.com/questions/9815901/display-view-above-status-bar/25384365#25384365
Sub AddOverlay
Dim mView As Label
    mView.Initialize("")
    mView.Text = Sentence
    Dim mlp As JavaObject
    Dim vtype As Int = -1, pixelFormat As Int = -3
    mlp.InitializeNewInstance("android.view.WindowManager$LayoutParams", Array(vtype, 100, 2010,296, pixelFormat))
    mlp.SetField("gravity", Bit.OR(Gravity.TOP, Gravity.CENTER))
    Dim windowManager As JavaObject = GetContext.RunMethod("getSystemService", Array("window"))
    windowManager.RunMethod("addView", Array(mView, mlp))
End Sub

Sub GetContext As JavaObject
    Return GetBA.GetField("context")
End Sub

Sub GetBA As JavaObject
    Dim jo As JavaObject
    Dim cls As String = Me
    cls = cls.SubString("class ".Length)
    jo.InitializeStatic(cls)
    Return jo.GetFieldJO("processBA")
End Sub
#End Region
 

Attachments

  • Overlay.zip
    7.2 KB · Views: 863
  • Overlay-OnOff.zip
    8.6 KB · Views: 943
Last edited:

Harris

Expert
Licensed User
Longtime User
Yes it does work!
I used the timer (and a boolean) I already have going to control it.

Touch the top of screen ( 0 to 30 dip) and overlay is enabled. I set the color of panel to black so you don't even see the status bar.
Five seconds later, the timer releases it. Works for me!

Now, for the other half of kiosk mode... I am thinking of setting my app as home screen, as described in methods to kiosk effectively.

Thanks for the inspiration...
 

Informatix

Expert
Licensed User
Longtime User
Finally got around to creating small test app that demonstrates the issue I have with NOT being able to set screen brightness (programatically), using a seekbar when overlay is ON. Based on sample from author with brightness code added.
I noticed that this issue happens only when you allow the overlay window to move over the status and notification areas (window with type SYSTEM_ERROR and flag LAYOUT_IN_SCREEN). If you restrict it to the application area, you can change the screen brightness.
The simplest solution is to use the OverlayWindow lib available in my ProBundle.
 

Harris

Expert
Licensed User
Longtime User
I noticed that this issue happens only when you allow the overlay window to move over the status and notification areas (window with type SYSTEM_ERROR and flag LAYOUT_IN_SCREEN). If you restrict it to the application area, you can change the screen brightness.
The simplest solution is to use the OverlayWindow lib available in my ProBundle.


@Informatix, Sounds great. Have you tested it, with your lib, with the sample test project I submitted?
If so and it works, I shall surely get your ProBundle. That would be better than my timer solution.

Thanks Kindly.
 

Informatix

Expert
Licensed User
Longtime User
@Informatix, Sounds great. Have you tested it, with your lib, with the sample test project I submitted?
If so and it works, I shall surely get your ProBundle. That would be better than my timer solution.

Thanks Kindly.
Yes I tried. If I create the window with my lib via Initialize2 (which allows to go over the notification and status bars), I cannot change the brightness. If I create the window via Initialize, I can change the brightness without issue.
  • Initialize (X As Int, Y As Int, Width As Int, Height As Int, EventPrefix As String)
    Creates an empty overlay window at the specified position. The window is displayed after calling Open.
    The window has a panel which can contain child views. Note that these views cannot acquire the focus.
    The window cannot be placed or moved over the status and notification bars.
    Width: Width of the window.
    Height: Height of the window.
    EventPrefix: Prefix of the Touch, Click and LongClick events.
  • Initialize2 (X As Int, Y As Int, Width As Int, Height As Int, EventPrefix As String)
    Creates an empty overlay window at the specified position. The window is displayed after calling Open.
    The window has a panel which can contain child views. Note that these views cannot acquire the focus.
    The window can be placed or moved over the status and notification bars.
    Width: Width of the window.
    Height: Height of the window.
    EventPrefix: Prefix of the Touch, Click and LongClick events.
 

Harris

Expert
Licensed User
Longtime User
The window cannot be placed or moved over the status and notification bars.
With Initialize- is this true? (or can it be ignored) The purpose is to block access to status/notify while maintaining the ability to set brightness...
 

Informatix

Expert
Licensed User
Longtime User
The window cannot be placed or moved over the status and notification bars.
With Initialize- is this true? (or can it be ignored)
Strange question. Why would I add such a comment if it was false? "Cannot" means that's impossible.
The purpose is to block access to status/notify while maintaining the ability to set brightness...
I never implemented this feature (blocking the status/notification bars with an overlay window) in my app MyPlayground because I saw 3 particular cases on my own devices and one of them was so complicated to handle that I prefered to give up. Moreover I have no idea of the total number of particular cases to handle.

To solve your issue, maybe you can close the window while you set the brightness and restore the window after that but I doubt that works fine. As explained in #25, only the window created with Initialize can allow you to alter the brightness, but it cannot act as a blocker for the bars, and you cannot switch from a window type to another.

You're not the only one expecting a solution:
http://stackoverflow.com/questions/...n-screen-brightness-and-in-hidding-status-bar
It's probably impossible.
 
Last edited:

Harris

Expert
Licensed User
Longtime User
Strange question. Why would I add such a comment if it was false? "Cannot" means that's impossible.

I never implemented this feature (blocking the status/notification bars with an overlay window) in my app MyPlayground because I saw 3 particular cases on my own devices and one of them was so complicated to handle that I prefered to give up. Moreover I have no idea of the total number of particular cases to handle.

To solve your issue, maybe you can close the window while you set the brightness and restore the window after that but I doubt that works fine. As explained in #25, only the window created with Initialize can allow you to alter the brightness, but it cannot act as a blocker for the bars, and you cannot switch from a window type to another.

You're not the only one expecting a solution:
http://stackoverflow.com/questions/...n-screen-brightness-and-in-hidding-status-bar
It's probably impossible.
Hummm, that is where I got confused. I thought initially you stated that (post 23) Overlay would resolve the issue until you posted the init methods in #25.
Yes, it is a sticky wicket - difficult to implement with desired results. My timer solution does work (for now) - just not as elegant as a straight forward approach - which doesn't seem possible.
Thanks for you help.
 

Informatix

Expert
Licensed User
Longtime User
I thought initially you stated that (post 23) Overlay would resolve the issue until you posted the init methods in #25.
The posts #23 and #25 say basically the same thing, though. My last sentence in post #23 just says that's simpler to create an overlay window and test both cases with my lib. Nothing else. But I see now that the word "solution" probably confused you.
There's no ambiguity in post #25 about the fact that my lib does not solve the problem. It's a confirmation of post #23.
Yes, it is a sticky wicket - difficult to implement with desired results. My timer solution does work (for now) - just not as elegant as a straight forward approach - which doesn't seem possible.
Thanks for you help.
I don't understand the solution with the timer. Could you post your code?
I tried the solution that I suggested in #27 (closing the window, changing the brightness, reopening the window) and, as I expected, that only works temporarily. As soon as you reopen the window, the brightness is restored.
 

Harris

Expert
Licensed User
Longtime User
Here is the short version...

Touch the top of screen (y <= 30) and overlay will lock it... (the top 30 - painted black)
The timer checks to see (among many other things) if it is locked and unlocks it after 6 seconds - hence restoring the users ability to adjust screen brightness...

In the AddOverlay and RemoveOverlay, I set "islock" flag accordingly.

Yes, an absolute downright workaround ( ok - hack ), but it works for me (for now).

B4X:
Sub Activity_Touch( Action As Int, X As Float, Y As Float)
   If y <= 30 Then
       If JobServMod.islock = False Then
          CallSubDelayed(JobServMod,"AddOverlay")
       End If
   End If     
End Sub


' In timer_tick... (ticks every 2 seconds)

    If JobServMod.islock Then
       ovlval = ovlval + 1
       If ovlval > 3 Then
            ovlval = 0
            CallSubDelayed(JobServMod ,"RemoveOverlay")
       End If
   End If
 

Informatix

Expert
Licensed User
Longtime User
Here is the short version...

Touch the top of screen (y <= 30) and overlay will lock it... (the top 30 - painted black)
The timer checks to see (among many other things) if it is locked and unlocks it after 6 seconds - hence restoring the users ability to adjust screen brightness...

In the AddOverlay and RemoveOverlay, I set "islock" flag accordingly.

Yes, an absolute downright workaround ( ok - hack ), but it works for me (for now).

B4X:
Sub Activity_Touch( Action As Int, X As Float, Y As Float)
   If y <= 30 Then
       If JobServMod.islock = False Then
          CallSubDelayed(JobServMod,"AddOverlay")
       End If
   End If  
End Sub


' In timer_tick... (ticks every 2 seconds)

    If JobServMod.islock Then
       ovlval = ovlval + 1
       If ovlval > 3 Then
            ovlval = 0
            CallSubDelayed(JobServMod ,"RemoveOverlay")
       End If
   End If
Your code presumes that all bars are above, which is wrong on many tablets, and requires that the activity is in full screen with no title. In this code, I don't understand the usefulness of ovlval. Why don't you set directly the interval to 8 sec. (4 x 2 sec.)?

I made an attempt with the code above and the timer takes a long time to remove the overlay window and restore the brightness at its chosen level, so the visual effect is confusing (you may think that you lost the brightness value and try to reset it). But, if you shorten that time, it becomes easy to open the notification area with a succession of quick gestures. In the end, that's not very satisfying IMHO.
 

Attachments

  • ov_timer.zip
    10.7 KB · Views: 358

Harris

Expert
Licensed User
Longtime User
Your code presumes that all bars are above, which is wrong on many tablets

This is a custom project for one specific client (Teck Resources (NANA/Lynden Transport) / Red Dog Mine, Alaska, USA). They use the Samsung Active 8 tablet (commercial/industrial) with a powered cradle in semi-trucks - locked in landscape mode.
And yes, the screen brightness will resort to whatever the OS setting was - and resume to whatever the user set it to... So be it.
Try hard and long enough and you will unlock the notifications... ( I doubt they will... ) If I could, I would record this event as a violation of company policies - hey fellas - don't Fu#$ with the system!

Like I said, good enough for me for now since I have so many other pressing issues to deal with - this is just one ounce of prevention.
Thanks for your input, it is always insightful.


active8.png


20160421_151145.jpg
 

Informatix

Expert
Licensed User
Longtime User
I looked at the code of SetScreenBrightness and saw that it does not change the brightness of the screen, but only the brightness of the activity. That's why the brightness changes when the overlay window is displayed outside the application area.
I created a small library that allows to really change the brightness of the screen. Now, with it, you should not encounter any issue.
 

Attachments

  • Brightness.zip
    2.2 KB · Views: 386

Harris

Expert
Licensed User
Longtime User
Hey! Looking Good!

I tried it with my stub app (attached).

Setting the screen brightness (Master setting) as opposed to current activity is most appealing.
This way, all views are at the same brightness - don't have to set it each time a new activity is presented (as I must do now).

However, as the stub app shows (and picture attached), setting slider value to 100 percent will only set screen brightness to (about) 40 percent (whether or not overlay is locked). Naturally, I must be doing something wrong.

If you can find the time, pls mock this test to show all the features and method uses of the brightness lib.

Thanks again.
 

Attachments

  • br_test.png
    br_test.png
    77 KB · Views: 363
  • brighttest.zip
    10.9 KB · Views: 345

Informatix

Expert
Licensed User
Longtime User
Hey! Looking Good!

I tried it with my stub app (attached).

Setting the screen brightness (Master setting) as opposed to current activity is most appealing.
This way, all views are at the same brightness - don't have to set it each time a new activity is presented (as I must do now).

However, as the stub app shows (and picture attached), setting slider value to 100 percent will only set screen brightness to (about) 40 percent (whether or not overlay is locked). Naturally, I must be doing something wrong.

If you can find the time, pls mock this test to show all the features and method uses of the brightness lib.

Thanks again.
The max value for the screen brightness is 255, not 100.
 

Harris

Expert
Licensed User
Longtime User
The max value for the screen brightness is 255, not 100.

Yes, there ya go... I knew I was missing something! Just got to read the fine print...

Works great. This is, with or without an overlay, EXACTLY what I needed.
No more need to timer control the overlay and set the screen brightness once - for the entire app!

We are so very fortunate to have pure genius in our camp at B4X.

Thanks again and look for a donation next week...
 

fransvlaarhoven

Active Member
Licensed User
Longtime User
Hello,

I've a problem with the code to add an overlay:

- with android 5.1 all runs fine

- with android 6, the code generates an error en no overlay is added:

java.lang.SecurityException: com.messenger from uid 10000 not allowed to perform SYSTEM_ALERT_WINDOW

those lines are in the manifest:
AddPermission(android.permission.SYSTEM_OVERLAY_WINDOW)
AddPermission(android.permission.SYSTEM_ALERT_WINDOW)

Is something like this possible with android 6?
 

fransvlaarhoven

Active Member
Licensed User
Longtime User
I've tested the example project on Android 7 and it works without any errors.

Hello Erel,

I've also done some testing myself:

The problem seems to be the line in the manifest:

<uses-sdk android:minSdkVersion="8" android:targetSdkVersion="23"/>

Once you set android:targetSdkVersion to 23 or higher, you need additional permission for adding overlays.
for android:targetSdkVersion= 22 or lower, this permission is granted automatically.

I need to do some further testing but I solved the problem by reinstalling the app with android:targetSdkVersion="22"
 

wes58

Active Member
Licensed User
Longtime User
Hello Erel,

I've also done some testing myself:

The problem seems to be the line in the manifest:

<uses-sdk android:minSdkVersion="8" android:targetSdkVersion="23"/>

Once you set android:targetSdkVersion to 23 or higher, you need additional permission for adding overlays.
for android:targetSdkVersion= 22 or lower, this permission is granted automatically.

I need to do some further testing but I solved the problem by reinstalling the app with android:targetSdkVersion="22"
As far as targetSdkVersion higher than 22, on Samsung phones you can do it this way:
1. Go to SETTINGS
2. Go to APPS
3. On the menu click on APPS THAT CAN APPEAR ON TOP
4. Select your application and enable this option.
Now the overlay should work.

Now, going back to my problem. I want to have an overlay to cover the whole screen - and disable all controls behind it.
In the example that you posted, I added a panel to the layout that covers the whole screen. I make it visible when the overlay is shown. When I click anywhere on the screen, none of the controls behind the panel are responding to touch/click events.
I did the same in my application but the controls are responding to touch event.
Any idea why?

Is there a way for the overlay to cover the whole screen?

SOLVED:
It seems that setting the width and height of the label in the AddOverlay sub fixes the problem:
mlp.InitializeNewInstance("android.view.WindowManager$LayoutParams", Array(vtype, 100, 2010,296, pixelFormat))
mlp.SetField("gravity", Bit.Or(Gravity.TOP, Gravity.CENTER))
mlp.SetField("height", 2000)
mlp.SetField("width", 1000)
Dim windowManager As JavaObject = GetContext.RunMethod("getSystemService", Array("window"))
windowManager.RunMethod("addView", Array(mView, mlp))

Since this sub in the Service, how do I get the size of the screen. I can't use 100%x, 100%y?
 
Last edited:
Top