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

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"
}

Related

Android overlapping views when using WindowManager

I'm using WindowManager to add views to the users screen using an IntentService, as shown here:
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.BOTTOM | Gravity.CENTER;
params.x = 0;
params.y = 100;
windowManager.addView(cardView, params);
When I first launch the IntentService, the view is created as expected. However, when I re-launch the IntentService, a new view is added but the previous view remains.
How can I remove all the views that I have already added before adding a new view? I know that if I kill the IntentService then the views disappear, but how do I delete all other instances of my IntentService except the instance that I have just launched?
This is what it looks like when I first call the IntentService:
By the time the IntentService has been called multiple times, a shadow appears because there are so many view stacked on top of each other:
When the service ends, you need to remove your previous views in the onDestroy() function.
if(cardview!=null){
WindowManager windowManager = (WindowManager) getSystemService(WINDOW_SERVICE);
windowManager.removeView(mView);
}

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 make a Facebook Messenger-like notification like this in Android

I want to implement notifications like the one in the following image.
Notification appears any time. I think it's of course a background service waiting for new messages from the server then shows this. What I think this is an activity implemented as dialog with this custom UI. Am I correct? And is it a normal startActivity method from the service? And how do I do the transition animation to make it appears slowly from left to right with zooming when show up?
Check out this link http://www.piwai.info/chatheads-basics. He provides information about how to add them on your screen.
The trick is to add a View to the WindowManager like following code
private WindowManager windowManager;
private ImageView chatHead;
public void addView()
{
windowManager = (WindowManager) getSystemService(WINDOW_SERVICE);
chatHead = new ImageView(this);
chatHead.setImageResource(R.drawable.android_head);
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.TOP | Gravity.LEFT;
params.x = 0;
params.y = 100;
windowManager.addView(chatHead, params);
}
Don't forget to add the permission <uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW"/>

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!

Display view above status bar?

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);

Categories

Resources