I am using Window Service to draw Overlay over screen. But my Overlay not covering the whole screen, It leaves out Status bar and Navigation Bar.
I have tried different approaches to solve it, but didn't find any solution. But the solution is available, as some Apps (Edge Lighting) on Play Store drawing border over full screen(Even on Android O).
My code snippet to achieve the task.
Window Manager
int Layout_Flag;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
Layout_Flag = WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY;
}else {
Layout_Flag = WindowManager.LayoutParams.TYPE_SYSTEM_ALERT;
}
final WindowManager.LayoutParams params = new WindowManager.LayoutParams(
WindowManager.LayoutParams.MATCH_PARENT,
WindowManager.LayoutParams.MATCH_PARENT,
Layout_Flag,
WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE | WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED,
PixelFormat.TRANSLUCENT);
params.gravity = Gravity.CENTER;
windowManager = (WindowManager) getSystemService(WINDOW_SERVICE);
windowManager.addView(customView, params);
Drawing Edge
`override fun onDraw(canvas: Canvas) {
super.onDraw(canvas)
// draw a shape
val width = measuredWidth
val height = measuredHeight
val strokeWidthCalculation = paint.strokeWidth / 2
path?.moveTo(strokeWidthCalculation, strokeWidthCalculation)
path?.lineTo(width - strokeWidthCalculation, strokeWidthCalculation)
path?.lineTo(width - strokeWidthCalculation, height - strokeWidthCalculation)
path?.lineTo(strokeWidthCalculation, height - strokeWidthCalculation)
path?.close()
paint.pathEffect = cornerPathEffect
canvas.drawPath(path!!, paint)
}`
Result
sample image, not covering status and navigation bar
In order to achieve it, the fourth parameter of WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS.
That's it.
The whole complete code:
val LAYOUT_FLAG: Int
LAYOUT_FLAG = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY
} else {
WindowManager.LayoutParams.TYPE_TOAST
}
params = WindowManager.LayoutParams(
WindowManager.LayoutParams.MATCH_PARENT,
WindowManager.LayoutParams.MATCH_PARENT,
LAYOUT_FLAG, // NOTE
WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN
or WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE,
PixelFormat.TRANSLUCENT
)
Related
I made overlay view and I set this layout params like that.
DisplayMetrics matrix = new DisplayMetrics();
mManager.getDefaultDisplay().getMetrics(matrix);
mParams = new WindowManager.LayoutParams(
WindowManager.LayoutParams.WRAP_CONTENT,
WindowManager.LayoutParams.WRAP_CONTENT,
WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY,
WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE | WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN,
PixelFormat.TRANSLUCENT
);
mParams.alpha = 0.8f;
mParams.gravity = Gravity.TOP | Gravity.LEFT;
mParams.x = 0;
mParams.y = 0;
But in this case, in tablet or fold model, overlay view is drawn from status bar.
Any other phone are not.. It didn't approach status bar..
how do i solve it??
I want to make overlay view is not drawn at status bar. Only under the status bar.
I put params.y to specific value but all tablet and foldable model have not same status bar.
So It is not what i want.
I am using window manager to show a popup from service, but my popup view is not visible. It is blank. Does someone have any idea why this is happening?
I have written android.permission.SYSTEM_ALERT_WINDOW permission in manifest too. My code looks like this.
int LAYOUT_FLAG;
if (Build.VERSION.SDK_INT >= 26) {
LAYOUT_FLAG = WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY;
} else if (Build.VERSION.SDK_INT >= 22) {
LAYOUT_FLAG = WindowManager.LayoutParams.TYPE_TOAST;
} else {
LAYOUT_FLAG = WindowManager.LayoutParams.TYPE_PHONE;
}
WindowManager.LayoutParams p = new WindowManager.LayoutParams(
// Shrink the window to wrap the content rather than filling the screen
WindowManager.LayoutParams.MATCH_PARENT,
WindowManager.LayoutParams.MATCH_PARENT,
// Display it on top of other application windows, but only for the current user
LAYOUT_FLAG,
// Don't let it grab the input focus
WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE,
// Make the underlying application window visible through any transparent parts
PixelFormat.TRANSLUCENT);
// Define the position of the window within the screen
p.gravity = Gravity.TOP | Gravity.RIGHT;
p.x = 0;
p.y = 100;
windowManager = (WindowManager) context.getSystemService(WINDOW_SERVICE);
LayoutInflater layoutInflater =
(LayoutInflater) context.getSystemService(LAYOUT_INFLATER_SERVICE);
binding = DataBindingUtil.inflate(layoutInflater, R.layout.activity_lock, null, false);
windowManager.addView(binding.getRoot(), p);
It requires 'draw over other apps' permission by the user. Please search in the settings for this permission and allow it for your app.
How can an overlay (of type TYPE_APPLICATION_OVERLAY) be drawn underneath the Navigation bar in Android?
I'm trying to cover the entire screen with a translucent view that allows users to interact with the UI underneath the overlay, but the Navigation bar retains its color.
The status bar was not an issue since I used the following flag - WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS
I'm trying to achieve the above using the following code -
overlay.setBackgroundResource(R.color.colorOverlayGray)
overlay.fitsSystemWindows = false
val layoutFlag = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY
} else {
WindowManager.LayoutParams.TYPE_PHONE
}
val params = WindowManager.LayoutParams(
WindowManager.LayoutParams.MATCH_PARENT,
WindowManager.LayoutParams.MATCH_PARENT,
layoutFlag,
WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE or
WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS or
WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN or
WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE or
WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS,
PixelFormat.TRANSLUCENT
)
params.gravity = Gravity.START or Gravity.TOP
windowManager.addView(overlay, params)
Figured it out. The issue was that I was using MATCH_PARENT as the height, but the height needs to be greater than that.
So now I'm calculating the height of the screen as such -
val displayMetrics = DisplayMetrics()
windowManager.defaultDisplay.getMetrics(displayMetrics)
val height = displayMetrics.heightPixels
And adding the height of the system navigation bar to that.
(Please note that the following code will work in an activity)
var navBarHeight = 0
window.decorView.setOnApplyWindowInsetsListener { view, insets ->
navBarHeight = insets.systemWindowInsetBottom
view.onApplyWindowInsets(insets)
}
And now setting the LayoutParams as such -
val params = WindowManager.LayoutParams(
WindowManager.LayoutParams.MATCH_PARENT,
height + navBarHeight,
WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY,
WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE or
WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS or
WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE or
WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS,
PixelFormat.TRANSLUCENT
)
You can get the height of the display, including navbar, with getRealMetrics():
val displayMetrics = DisplayMetrics()
windowManager.defaultDisplay.getRealMetrics(displayMetrics)
val overlayHeight = displayMetrics.heightPixels
val overlayWidth = displayMetrics.widthPixels
then create window params:
params = WindowManager.LayoutParams(
overlayWidth,
overlayHeight,
WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY,
OVERLAY_FLAGS,
PixelFormat.TRANSLUCENT
)
My Android (8.0+) app is implementing a narrow overlay along the bottom of the screen, but when a user sets an overscan value, it disappears. How can I make my view respect what is actually visible so Gravity.BOTTOM will not be clipped? I have tried countless combinations of flags, but nothing seems to ackknowledge the overscan value.
Point screen_size = new Point();
WindowManager.LayoutParams mParams;
WindowManager mWindowManager = getSystemService(WINDOW_SERVICE);
mWindowManager.getDefaultDisplay().getRealSize(screen_size);
layout = new LinearLayout(getApplicationContext());
layout.setOnTouchListener(this);
// color for debug.
layout.setBackgroundColor(0x55ff0000);
mParams = new WindowManager.LayoutParams(
screen_size.x,
40,
0,
0,
WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY,
WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE,
PixelFormat.TRANSLUCENT);
mParams.gravity = Gravity.BOTTOM;
mWindowManager.addView(layout, mParams);
In my app I use a BroadcastReceiver to catch incoming calls. So when someone calls and in case that I have the phone number stored in my application's DB, I display a window with the name of the caller.
The problem is that in some devices this window is not displayed if the device's screen is off before the phone rings.(If the screen of the device is on, when the phone rings, the window is displayed).
I also delay the drawing of the window for 3 seconds, but this doesn't seem to work.
To display the window I use the following code, where mView is a RelativeLayout with a TextView. This code runs in a Service.
WindowManager.LayoutParams mParams = new WindowManager.LayoutParams(
WindowManager.LayoutParams.MATCH_PARENT,
dpToPx(72),
WindowManager.LayoutParams.TYPE_PHONE,
WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE |
WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL,
PixelFormat.TRANSLUCENT);
mParams.gravity = Gravity.TOP;
WindowManager mWindowManager = (WindowManager)getSystemService(WINDOW_SERVICE);
mWindowManager.addView(mView, mParams);
After several failing tries I found it.
I had to replace the flag TYPE_PHONEwith TYPE_SYSTEM_OVERLAY.
try this, this will surely work
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
Layout_Flag = WindowManager.LayoutParams.TYPE_SYSTEM_ALERT;
}
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
Layout_Flag = WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY;
}
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) {
Layout_Flag = WindowManager.LayoutParams.TYPE_SYSTEM_ALERT;
}
final WindowManager.LayoutParams params = new WindowManager.LayoutParams(
WindowManager.LayoutParams.MATCH_PARENT,
WindowManager.LayoutParams.MATCH_PARENT,
Layout_Flag,
WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE | WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED,
PixelFormat.TRANSLUCENT);
params.gravity = Gravity.CENTER;
mWindowManager = (WindowManager) getSystemService(WINDOW_SERVICE);
try {
mWindowManager.addView(windowView, params);