Displaying a foreground service below status bar - android

I'm trying to creat a foreground service window that doesn't cross or display content underneath the statusbar. It looks ok in portrait mode, but once the screen is rotated, the view extends to go even behind the statusbar. Not sure what I'm missing here!
fullscreenCheckerHiddenWindow = LayoutInflater.from(ctx).inflate(R.layout.fullscreen_checker_hidden_window, null);
int flag;
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.O) {
flag = WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY;
} else {
flag = WindowManager.LayoutParams.TYPE_PHONE;
}
fullscreenWindowParams = new WindowManager.LayoutParams(
50,
ViewGroup.LayoutParams.MATCH_PARENT,
flag,
WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN |
WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE |
WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE,
PixelFormat.TRANSLUCENT);
fullscreenWindowParams.gravity = Gravity.TOP | Gravity.LEFT;

Related

Cannot intercept touch on overlay service

I am trying to block touch on a device using service and a transparent overlay.
The code seems to work fine on Android Oreo but doesn't work properly on devices running Android version below Oreo:
private void setWindowParams(){
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.O) {
params = new WindowManager.LayoutParams(
WindowManager.LayoutParams.MATCH_PARENT,
WindowManager.LayoutParams.MATCH_PARENT,
WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY,
WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
| WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL
| WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH,
PixelFormat.TRANSLUCENT);
} else {
params = new WindowManager.LayoutParams(
WindowManager.LayoutParams.MATCH_PARENT,
WindowManager.LayoutParams.MATCH_PARENT,
WindowManager.LayoutParams.TYPE_SYSTEM_OVERLAY,
WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
| WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL
| WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH,
PixelFormat.TRANSLUCENT);
}
wm = (WindowManager) getSystemService(WINDOW_SERVICE);
FrameLayout noTouchUi = new FrameLayout(this);
wm.addView(noTouchUi,params);
}
Here I setup a FrameLayout noTouchUi to intercept touch as an overlay using service using onTouchListener
noTouchUi.setOnTouchListener(new View.OnTouchListener() {
#Override
public boolean onTouch(View v, MotionEvent event) {
Log.d(TAG,"touch event");
return true;
}
});
This works properly on Android 8, but doesn't work on Android 7, the overlay shows up properly, but the items behind overlay gets clicked. What I want to do is block that click.
Change the type from:
WindowManager.LayoutParams.TYPE_SYSTEM_OVERLAY
to:
WindowManager.LayoutParams.TYPE_PHONE
and remove flags:
WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL
and:
WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH

Android: Request focus on view (WebView) added via WindowManager

I am showing a webView as an alertDialog from a service when my app is not running on foreground, therefore, My webView is attached to the screen via WindowManager.addView() method.
The webView has an input field which I want to be accessible by the user. Unfortunately, when the user clicks on the input field, it is not showing the keyboard for users to allow input.
My webView is inside a cardView who's params are as follows:
public WindowManager.LayoutParams getParamsForOpenWebView() {
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.O) {
WindowManager.LayoutParams params = new WindowManager.LayoutParams(
WindowManager.LayoutParams.MATCH_PARENT,
WindowManager.LayoutParams.MATCH_PARENT,
WindowManager.LayoutParams.TYPE_PHONE,
WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM
| WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL
| WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH
| WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS,
PixelFormat.TRANSLUCENT);
params.gravity = Gravity.START | Gravity.TOP;
params.x = left;
params.y = top;
return params;
} else {
WindowManager.LayoutParams params = new WindowManager.LayoutParams(
WindowManager.LayoutParams.MATCH_PARENT,
WindowManager.LayoutParams.MATCH_PARENT,
WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY,
WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM
| WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL
| WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH
| WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS,
PixelFormat.TRANSLUCENT);
params.gravity = Gravity.START | Gravity.TOP;
params.x = left;
params.y = 200;
return params;
}
}
If I connect the phone to my laptop and use the laptop keyboard to add inputs to the input field, it works fine but it's just that the keyboard on the phone does not pop-up.
Also, the input is inside the webView therefore I cannot use View.requestFocus() to get focus unlike in case of an EditText.
I would really appreciate any help regarding how to request focus to the webView to allow inputs.
Found an answer to the question myself after a while.
I tried a lot of combinations of different flags but none worked, unless I tried
WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL
| WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH
| WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS
These flags gave the results I wanted and hope it helps someone who goes through the same.

Softkeyboard does not appear when a Screenoverlay is active

I'm using a transparent screenoverlay to detect when a user long presses the power key of their phone (or rather, when the shutdown option dialog appears), this is working fine.
Unfortunately, when this screenoverlay is active, the soft keyboard stops appearing and that is a problem for me. How can I prevent that?
The code I'm using is heavily based on this: Detect power button long press
public void warnOnShutdown() {
if (Settings.canDrawOverlays(this)) {
LinearLayout linearLayout = new LinearLayout(getApplicationContext()) {
public void onCloseSystemDialogs(String reason) {
if ("globalactions".equals(reason)) {
AntitheftStateManager.setShuttingDown(AntitheftService.this, true);
}
}
#Override
public boolean dispatchKeyEvent(KeyEvent event) {
return super.dispatchKeyEvent(event);
}
};
linearLayout.setFocusable(true);
View view = LayoutInflater.from(this).inflate(R.layout.system_overlay, linearLayout);
WindowManager windowManager = (WindowManager) getSystemService(WINDOW_SERVICE);
//params
WindowManager.LayoutParams params = new WindowManager.LayoutParams(
100,
100,
WindowManager.LayoutParams.TYPE_SYSTEM_ALERT,
WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL
| WindowManager.LayoutParams.FLAG_FULLSCREEN
| WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN
| WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON,
PixelFormat.TRANSLUCENT);
params.gravity = Gravity.LEFT | Gravity.CENTER_VERTICAL;
windowManager.addView(view, params);
}
}
Layout:
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="1dp"
android:layout_height="1dp"
android:orientation="vertical">
</LinearLayout>
Edit:
I should probably mention that the LinearLayout is attached to the window manager from a service, that means that the keyboard is not just blocked for my app, it's blocked for the whole phone as long as the service is running.
That's what happens when someone elses code is taken at face value. Turns out that changing the type from TYPE_SYSTEM_ALERT to TYPE_SYSTEM_OVERLAY solved my problem.
WindowManager.LayoutParams params = new WindowManager.LayoutParams(
100,
100,
WindowManager.LayoutParams.TYPE_SYSTEM_OVERLAY,
WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL
| WindowManager.LayoutParams.FLAG_FULLSCREEN
| WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN
| WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON,
PixelFormat.TRANSLUCENT);

Status bar and overlay

I'm showing a custom overlay with this parameter inflating the view from a service:
params = new WindowManager.LayoutParams(WindowManager
.LayoutParams
.MATCH_PARENT,
statusBarHeight, WindowManager.LayoutParams.TYPE_SYSTEM_OVERLAY, WindowManager
.LayoutParams.FLAG_NOT_TOUCH_MODAL | WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN
| WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE | WindowManager.LayoutParams
.FLAG_NOT_FOCUSABLE, 0);
params.gravity = Gravity.CENTER | Gravity.TOP;
The problem is that if the status bar is expanded, the overlay is over the quick settings menu. How can I avoid that? I'm using android 6.
Instead of TYPE_SYSTEM_OVERLAY use TYPE_SYSTEM_ERROR.
params = 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);
params.gravity = Gravity.TOP|Gravity.CENTER;
mWindowManager = (WindowManager) getSystemService(WINDOW_SERVICE);
mWindowManager.addView(mView, mLP);
This should solve your issue.

How to hide the Navigation bar using a system overlay window

LockScreenReceiver.java
public class LockScreenReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
//If the screen was just turned on or it just booted up, start your Lock Activity
if(action.equals(Intent.ACTION_SCREEN_OFF) || action.equals(Intent.ACTION_BOOT_COMPLETED))
{
//Create a window manager params
WindowManager.LayoutParams params = new WindowManager.LayoutParams(
WindowManager.LayoutParams.MATCH_PARENT,
WindowManager.LayoutParams.MATCH_PARENT,
WindowManager.LayoutParams.TYPE_SYSTEM_ALERT,
WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
| WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL
| WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH,
PixelFormat.TRANSLUCENT);
//makeFullScreen((Activity) context);
WindowManager wm = (WindowManager) context.getSystemService(context.WINDOW_SERVICE);
LayoutInflater inflater = (LayoutInflater) context.getSystemService(context.LAYOUT_INFLATER_SERVICE);
final View myView = inflater.inflate(R.layout.my_view, null);
myView.setOnTouchListener(new View.OnTouchListener() {
#Override
public boolean onTouch(View v, MotionEvent event) {
Log.d("TAG", "touch me");
myView.setVisibility(View.GONE);
return true;
}
});
// Add layout to window manager
wm.addView(myView, params);
}
}
}
What i am having:
I have output as shown below, which is a view on click of it, its visibility is gone
What i am trying to do:
I want to hide the bar that has back,center button when the above view is loaded.
How to achieve this?
WindowManager.LayoutParams lp = new WindowManager.LayoutParams();
lp.format = PixelFormat.RGBA_8888;
lp.flags = WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED
| WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN
| WindowManager.LayoutParams.FLAG_FULLSCREEN;
lp.screenOrientation = ActivityInfo.SCREEN_ORIENTATION_PORTRAIT;
lp.height = ViewGroup.LayoutParams.MATCH_PARENT;
lp.width = ViewGroup.LayoutParams.MATCH_PARENT;
int flag = View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY
| View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
| View.SYSTEM_UI_FLAG_HIDE_NAVIGATION;
mRootView.setSystemUiVisibility(flag);
mWindowManager.addView(mRootView, getLayoutParams());
Don not use WindowManager.LayoutParams.FLAG_NOT_FOCUSABLEļ¼Œ this flag will make navigation bar always show. I don't kown why.
You can hide the navigation bar on Android 4.0 and higher using the SYSTEM_UI_FLAG_HIDE_NAVIGATION flag. This snippet hides both the navigation bar and the status bar:
View decorView = getWindow().getDecorView();
// Hide both the navigation bar and the status bar.
// SYSTEM_UI_FLAG_FULLSCREEN is only available on Android 4.1 and higher, but as
// a general rule, you should design your app to hide the status bar whenever you
// hide the navigation bar.
int uiOptions = View.SYSTEM_UI_FLAG_HIDE_NAVIGATION
| View.SYSTEM_UI_FLAG_FULLSCREEN;
decorView.setSystemUiVisibility(uiOptions);
source: here
Starting from Android 4.4 KitKat, you can use "immersive" full-screen mode. Here's the detail and some sample codes.
https://developer.android.com/training/system-ui/immersive.html
try with Immersive mode -SYSTEM_UI_FLAG_IMMERSIVE flag for setSystemUiVisibility()

Categories

Resources