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
Related
I'm showing a overlay window from service in my app. I want to hide the window when press back button. So to get the back button event I do the following code
class MyView extends MyLayout{
public MyView(Context context){
super(context);
LayoutInflater.from(context).inflater(R.layout.my_view,this);
}
}
Class MyLayout extends FrameLayout{
public MyLayout(Context context){
super(context);
}
#Override
public boolean dispatchKeyEvent(KeyEvent event) {
Log.e("key event", "" + event.getKeyCode());
return super.dispatchKeyEvent(event);
}
}
//service code
final WindowManager.LayoutParams params = new WindowManager.LayoutParams(
WindowManager.LayoutParams.MATCH_PARENT,
WindowManager.LayoutParams.MATCH_PARENT,
WindowManager.LayoutParams.TYPE_PHONE,
WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE | WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL | WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH
| WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS |
WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATION | WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS,
PixelFormat.TRANSLUCENT);
final MyView myview = new MyView(this);
windowManager.addView(myview,param);
But dispatchKeyEvent method never called on back button pressed. I Googled and found out this is the way to capture the back button event. Somehow it's not working in my case. What am I missing ?
If you just want to capture the back button pressed event use:
#override
public void onBackPressed(){
// Do what you need done here
// ... or pass super.onBackPressed();
}
Real problem is the window params. I need to only WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH flags which prevent other app to get key events. So the correct code is following
//service code
final WindowManager.LayoutParams params = new WindowManager.LayoutParams(
WindowManager.LayoutParams.MATCH_PARENT,
WindowManager.LayoutParams.MATCH_PARENT,
WindowManager.LayoutParams.TYPE_PHONE,
WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH | WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS |
WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATION | WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS,
PixelFormat.TRANSLUCENT);
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);
Is there a way to block touch on ANY application from a service? I've been thinking about getWindow(), but that is impossible in service. Also, I've been thinking about getting current activity and then use getWindow(). I hope you get the point of what am I tried to achieve.
Thanks to David Medenjak I have managed to solve the problem. This solution is working on Android APIs below 23 and it's going to make the screen black and block touches until you longpress on the screen.
WindowManager windowManager = (WindowManager) getSystemService(WINDOW_SERVICE);
ImageView black = new ImageView(this);
black.setImageResource(R.drawable.black);
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,
PixelFormat.TRANSLUCENT);
params.gravity = Gravity.TOP | Gravity.LEFT;
params.x = 0;
params.y = 0;
windowManager.addView(black, params);
black.getLayoutParams().height = windowManager.getDefaultDisplay().getHeight();
black.getLayoutParams().width = windowManager.getDefaultDisplay().getWidth();
black.setOnLongClickListener(new View.OnLongClickListener() {
#Override
public boolean onLongClick(View v) {
return false;
}
});
I have window view in bottom and when i click on any edittext, keyboard opens but below windows view (Windowview comes over keyboard).
Tried using adjustPan, adjustResize.
Tried using show hide the view as per keyboard visibility but it give Security Exception.
mTabParams = new WindowManager.LayoutParams(
ViewGroup.LayoutParams.MATCH_PARENT,
ViewGroup.LayoutParams.WRAP_CONTENT, WindowManager.LayoutParams.TYPE_SYSTEM_ALERT |
WindowManager.LayoutParams.TYPE_SYSTEM_OVERLAY,
WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL |
WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE,
PixelFormat.TRANSPARENT);
mTabParams.format = PixelFormat.TRANSLUCENT;
mTabParams.height = TAB_BAR_HEIGHT;
mTabParams.gravity = Gravity.BOTTOM;
mWindowmanager = (WindowManager) getSystemService(Context.WINDOW_SERVICE);
mWindowmanager.addView(mTabbarLayout, mTabParams);
This worked for me :
params = new WindowManager.LayoutParams(
WindowManager.LayoutParams.WRAP_CONTENT,
WindowManager.LayoutParams.WRAP_CONTENT,
WindowManager.LayoutParams.TYPE_PRIORITY_PHONE,
WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN |
WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE |
WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL |
WindowManager.LayoutParams.FLAG_SPLIT_TOUCH |
WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM,
PixelFormat.TRANSLUCENT);
This put the added view behind the keyboard.
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.