Display view above status bar? - android

I recently saw an image of an app that was capable of displaying a view above the status bar and was also able to cover it with a view.
I know you can get a view right below the status bar from a view with align parent top. But how would you get a view on top of the status bar??
Example

Disable the System Status Bar - Without Root
After two full days of searching through SO posts and reading the Android docs over and over.. Here is the solution that I came up with. (tested)
mView= new TextView(this);
mView.setText(".........................................................................");
mLP = new WindowManager.LayoutParams(
WindowManager.LayoutParams.MATCH_PARENT,
100,
// Allows the view to be on top of the StatusBar
WindowManager.LayoutParams.TYPE_SYSTEM_ERROR,
// Keeps the button presses from going to the background window
WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE |
// Enables the notification to recieve touch events
WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL |
// Draws over status bar
WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN,
PixelFormat.TRANSLUCENT);
mLP.gravity = Gravity.TOP|Gravity.CENTER;
mWindowManager = (WindowManager) getSystemService(WINDOW_SERVICE);
mWindowManager.addView(mView, mLP);
Dont forget the permissions:
<uses-permission android:name="android.permission.SYSTEM_OVERLAY_WINDOW" />
Note:
Tested upto kitkat.

The answer by #Sadeshkumar is incorrect for ICS and above (perhaps GB as well).
A view created with TYPE_SYSTEM_ALERT and FLAG_LAYOUT_IN_SCREEN is covered by the StatusBar.
To get an overlay on top of the StatusBar, you need to use TYPE_SYSTEM_OVERLAY instead of TYPE_SYSTEM_ALERT.
The problem being then, how to get clicks/touches?

A view created with TYPE_SYSTEM_ERROR and FLAG_LAYOUT_IN_SCREEN is covered by the StatusBar.

int statusBarHeight = (int) Math.ceil(25 * getResources().getDisplayMetrics().density);
View statusBarView = new View(MyActivity.this);
statusBarView.setBackgroundColor(Color.GREEN);
WindowManager.LayoutParams params = null;
params = new WindowManager.LayoutParams(WindowManager.LayoutParams.FILL_PARENT,statusBarHeight,WindowManager.LayoutParams.TYPE_SYSTEM_ALERT,WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL |WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN, PixelFormat.TRANSLUCENT);
params.gravity = Gravity.RIGHT | Gravity.TOP;
WindowManager wm = (WindowManager) getSystemService(WINDOW_SERVICE);
wm.addView(statusBarView, params);

Related

Bringing a view to the absolute front (even over alert dialogs)

I need one view to always be at the forefront, even over alert dialogs. I figured there might be two ways to achieve this:
Somehow create the alert dialog as part of an existing view, instead of being its own activity
Some sort of flag on the view to bring it to the front of everything including alert dialogs
Is this possible? If so how?
WindowManager with LayoutParams and Flag as TYPE_SYSTEM_ERROR. Shows over lockscreens too.
WindowManager windowManager = (WindowManager)getSystemService(WINDOW_SERVICE);
WindowManager.LayoutParams params = new WindowManager.LayoutParams(
WindowManager.LayoutParams.WRAP_CONTENT,
WindowManager.LayoutParams.WRAP_CONTENT,
WindowManager.LayoutParams.TYPE_SYSTEM_ERROR,
WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
PixelFormat.TRANSLUCENT);
params.gravity = Gravity.TOP | Gravity.LEFT;
params.x = 100; // position on screen (optional)
params.y = 100;
Add Views:
windowManager.addView(yourView, params);
Edit:
To avoid covering LockScreens: remove TYPE_SYSTEM_ERROR flag and add following:
WindowManager.LayoutParams.TYPE_PHONE
For this to work, you will need to add the following permission to your AndroidManifest.xml too:
<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW"/>
You don't need to request it at Runtime on most of devices except Android Marshmallow 6.0.0. There is a special way to request it than regular requests. It is checked using:
if (Settings.canDrawOverlays()) {
// you have permission
} else {
// send an intent with action "ACTION_MANAGE_OVERLAY_PERMISSION"
}

Blocking status bar in top down swiping

I've a full screen application covering the entire screen, top status bar included.
Since a top / down swipe is enabled to show some options to the user, it happens that swiping from top to down, the status bar is showing (as when you want to see notifications and swipe top down).
Is there a way to avoid this ?
Use type TYPE_SYSTEM_ERROR for WindowManager.LayoutParams, to create hide impossible fullscreen view.
Swipes for show status bar and navigation will be blocked.
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mMainLayout = (RelativeLayout) LayoutInflater.from(this).inflate(R.layout.activity_fullscreen, null);
requestWindowFeature(Window.FEATURE_NO_TITLE);
getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN);
WindowManager.LayoutParams handleParams = new WindowManager.LayoutParams(
WindowManager.LayoutParams.MATCH_PARENT,
WindowManager.LayoutParams.MATCH_PARENT,
WindowManager.LayoutParams.TYPE_SYSTEM_ERROR,
WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE |
WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL |
WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN,
PixelFormat.TRANSLUCENT);
handleParams.gravity = Gravity.TOP;
WindowManager windowManager = (WindowManager) getSystemService(WINDOW_SERVICE);
windowManager.addView(mMainLayout, handleParams);
}
And you should be show it after display power on (unlock screen) if needs. Add code:
getWindow().addFlags(WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED);
There are a couple of options. Before the line
super.onCreate(savedInstanceState)
add the following:
requestWindowFeature(Window.FEATURE_NO_TITLE);
getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,
WindowManager.LayoutParams.FLAG_FULLSCREEN);
This should completely get rid of the status bar. Basicaly the feature no title removes the top toolbar, and to ensure fullscreen size we are setting fullscreen flags for height and width.
As far as preventing from swiping at all, there is a trick that can be used. Basically place an invisible view at the top once you are in true fullscreen that prevents any swiping. For example,
View disableStatusBarView = new View(context);
WindowManager.LayoutParams handleParams = new WindowManager.LayoutParams(
WindowManager.LayoutParams.FILL_PARENT,
<height of the status bar>,
// This allows the view to be displayed over the status bar
WindowManager.LayoutParams.TYPE_SYSTEM_ALERT,
// this is to keep button presses going to the background window
WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE |
// this is to enable the notification to recieve touch events
WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL |
// Draws over status bar
WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN,
PixelFormat.TRANSLUCENT);
handleParams.gravity = Gravity.TOP;
context.getWindow().addView(disableStatusBarView, handleParams);
This creates an invisible view over the status bar that will receive the touch events and block the events from reaching the status bar, therefore preventing it to be expanded.
Alternatively, and this works the best, is to override the windowFocusChanged method. Essentially you are NOT preventing the status bar from expanding, but YOU ARE preventing use. Because once expanded, it is closed. I say that this works best because with the invisible view methodology, you may want to consider the dimensions of the screen to really make it effective for all device. So there is more work.
First, declare permission in manifest
<uses-permission android:name="android.permission.EXPAND_STATUS_BAR"/>
Then Override onWindowFocusChanged method,
public void onWindowFocusChanged(boolean hasFocus)
{
try
{
if(!hasFocus)
{
Object service = getSystemService("statusbar");
Class<?> statusbarManager = Class.forName("android.app.StatusBarManager");
Method collapse = statusbarManager.getMethod("collapse");
collapse .setAccessible(true);
collapse .invoke(service);
}
}
catch(Exception ex)
{
}
}

Android Create "Ghost" Image (Touch-through)

I have created a service which will overlay an image on top of the whole screen.
This part is the code which will overlay an image on top of the whole screen:
#Override public void onCreate() {
super.onCreate();
windowManager = (WindowManager) getSystemService(WINDOW_SERVICE);
img = new ImageView(this);
img.setImageResource(R.drawable.image); // Image is .png format
WindowManager.LayoutParams params = new WindowManager.LayoutParams(
WindowManager.LayoutParams.WRAP_CONTENT,
WindowManager.LayoutParams.WRAP_CONTENT,
WindowManager.LayoutParams.TYPE_PHONE,
WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE,
PixelFormat.TRANSLUCENT);
params.gravity = Gravity.CENTER | Gravity.CENTER;
params.x = 0;
params.y = 0;
windowManager.addView(img, params);
}
However, any space which the image covers in untouchable. I want the image to be just overlaid, without affecting any other components on the screen, similar to what this does:
How can I make the area beneath the image touchable (touch-through)?
Edit
It seems that the transparent space of the image fills a square, and covers the screen (FYI).
So my ultimate goal is, to make the image touch-through.
I have tried the popupWindow class, recommended by a few SO users, but its purpose does not fulfill my needs and does not work.
I found that WindowManager.LayoutParams.TYPE_SYSTEM_OVERLAY solves the issue.
Try
img.setClickable(false);
http://developer.android.com/reference/android/view/View.html#setClickable(boolean)
Try setting the param flags to:
WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE |
WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL |
WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH
I've tried this with success before. The last two will help send touch events to the views behind it.

How to disable Notification Bar?

I would like to Disable Notification Bar using the en, but when i tried to put this code in my OnCreat method in the main Activity, i have some problem. I don't know what to put in <height of the status bar>, what is params i tried to put handleParams, i have the some problem and a problem using
context.getWindow().addView(view, params); is unkown and i can't use context.getWindow()
View disableStatusBar = new View(context);
WindowManager.LayoutParams handleParams = new WindowManager.LayoutParams(
WindowManager.LayoutParams.FILL_PARENT,
<height of the status bar>,
// This allows the view to be displayed over the status bar
WindowManager.LayoutParams.TYPE_SYSTEM_ALERT,
// this is to keep button presses going to the background window
WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE |
// this is to enable the notification to recieve touch events
WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL |
// Draws over status bar
WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN,
PixelFormat.TRANSLUCENT);
params.gravity = Gravity.TOP;
context.getWindow().addView(view, params);
Just add to your manifest:
android:theme="#android:style/Theme.NoTitleBar.Fullscreen"

Switching between TYPE_SYSTEM_ALERT AND TYPE_SYSTEM_OVERLAY , and capturing the touch events not working properly

I made a View in service which runs always on top of every application in android.
Initially, the behaviour of service is TYPE_SYSTEM_ALERT .
WindowManager.LayoutParams layparams = new WindowManager.LayoutParams(
WindowManager.LayoutParams.WRAP_CONTENT,WindowManager.LayoutParams.WRAP_CONTENT,
WindowManager.LayoutParams.TYPE_SYSTEM_ALERT,
WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH,
PixelFormat.TRANSLUCENT);
layparams .gravity = Gravity.CENTER_VERTICAL| Gravity.CENTER_HORIZONTAL;
wm = (WindowManager) getSystemService(WINDOW_SERVICE);
wm.addView(serviceView, layparams );
I am changing the behaviour of service at run time means switching between TYPE_SYSTEM_ALERT AND TYPE_SYSTEM_OVERLAY on touch. Switch take place when I touch outside the view parameters and when touch inside the view parameters.
layparams .type = WindowManager.LayoutParams.TYPE_SYSTEM_OVERLAY;
Using updateViewLayout(serviceView, layparams )
PROBLEM: Is when I touch outside of view , the first touch just activate TYPE_SYSTEM_OVERLAY and after then outside app works fine. When TYPE_SYSTEM_OVERLAY is working , after that when you touch within the view it will trigger the action of object behind the view not the action of the view. But when u once touch the view TYPE_SYSTEM_ALERT will be applied and now the View will behave normally .
Current Implementation : I have to touch twice to work that particular thing when switch take place between layout parameters.
use this one... works perfectly on ICS and above
params.type = WindowManager.LayoutParams.TYPE_SYSTEM_ERROR;//This one is necessary.
params.flags = WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE |
WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH |
WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL |
WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS;
params.gravity = Gravity.TOP | Gravity.RIGHT;
params.x = 0;
params.y = -params.height;
windowManager.addView(tile, params);
you can do this by calling updateViewLayout() on instance of WindowManager class.
wm = (WindowManager) getSystemService(WINDOW_SERVICE);
// create new layout params
WindowManager.LayoutParams newlayparams = new WindowManager.LayoutParams(
WindowManager.LayoutParams.WRAP_CONTENT,WindowManager.LayoutParams.WRAP_CONTENT,
WindowManager.LayoutParams.TYPE_SYSTEM_OVERLAY,
WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH,
PixelFormat.TRANSLUCENT);
//update new layout
wm.updateViewLayout(serviceView, newlayparams);
Hope it help!

Categories

Resources