Filter touchscreen events - android

My android application should work in envioriment with lots of EMI. Unfortunately EMI sometimes triggers touchscreen events. Those triggers seems to be random, so it's possible to filter them out.
I want to create overlay window that receives all touchscreen events, filters them and passes to my activity's controls or system's statusbar.
I've created transparent overlay window to have something to start with:
WindowManager.LayoutParams wmParams = new WindowManager.LayoutParams(
WindowManager.LayoutParams.FLAG_FULLSCREEN,
WindowManager.LayoutParams.FLAG_FULLSCREEN,
WindowManager.LayoutParams.TYPE_SYSTEM_ALERT,
WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN,
PixelFormat.TRANSLUCENT);
WindowManager wm = (WindowManager) getApplicationContext().getSystemService(Context.WINDOW_SERVICE);
LayoutInflater inflater = (LayoutInflater)getApplicationContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE);
ViewGroup mTopView = (ViewGroup) inflater.inflate(R.layout.touch_filter_overlay, null);
wm.addView(mTopView, wmParams);
I think I can subclass ViewGroup to receive messages, but how can I then send processed messages to background controls?
Maybe there is another solution to my problem?
Thank you!

The false screen detection and filtering is also the responsibility of the touch screen sensor, on the electronics component.
Some touch screen sensors are using dedicated electronics filters, plus high-end filtering algorithms to reject the false touches.
That's why I suggest you change your smartphone, and find one that is EMI proof.

Related

How do I make my full-screen overlay remain full-screen after orientation changes?

I am making an app that creates tiny sprite animations that walk around your screen.
I have a main activity, with a button "start service". This starts a service, which (in onCreate()) creates a full-screen view and attaches it to the root window manager.
This part works perfectly. It fills the screen, and you can leave the app, and the animations will still be visible over everything.
The problem emerges when you rotate the device.
Sprites have moved to the middle of the screen, but this is an unrelated issue; the important thing here is the dark bounding box — this box shows you the canvas I am allowed to draw into, and it needs to fill the whole screen
The view is still portrait-mode, even though all other layouts seem to have updated correctly.
Part of the problem comes from how I have specified the dimensions of the view. I used flags to specify "full screen", but this did not set the view's width and height to match the screen's dimensions. Thus I had to set those manually at startup.
I don't know a way to update the width and height of the view once the view is created, but I feel that I need to, since the dimensions of the view determine the dimensions of the canvas.
My service creates the view like so:
public class WalkerService extends Service {
private WalkerView view;
#Override
public void onCreate() {
super.onCreate();
final WindowManager wm = (WindowManager)getSystemService(WINDOW_SERVICE);
final DisplayMetrics metrics = new DisplayMetrics();
wm.getDefaultDisplay().getMetrics(metrics);
view = new WalkerView(this); // extends SurfaceView
final WindowManager.LayoutParams params = new WindowManager.LayoutParams(
WindowManager.LayoutParams.FLAG_FULLSCREEN,
WindowManager.LayoutParams.FLAG_FULLSCREEN,
WindowManager.LayoutParams.TYPE_SYSTEM_OVERLAY, // TYPE_SYSTEM_ALERT is denied in apiLevel >=19
WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN,
PixelFormat.TRANSLUCENT
);
view.setFitsSystemWindows(false); // allow us to draw over status bar, navigation bar
// here I _manually_ set the dimensions, because otherwise it defaults to a square (something like 1024x1024)
params.width = metrics.widthPixels;
params.height = metrics.heightPixels;
wm.addView(view, params);
}
}
I have tried listening for orientation changes, and rotating the view when that happens:
#Override
public void onConfigurationChanged(Configuration newConfig) {
super.onConfigurationChanged(newConfig);
view.setRotation(
newConfig.orientation == Configuration.ORIENTATION_LANDSCAPE
? 90.0f
: 0.0f
);
}
But setRotation() didn't seem to affect width and height of my view, nor did they change the angle at which the canvas was rendered.
Am I fundamentally misunderstanding how to create a full-screen overlay? How can I maintain the ability to draw over the entire screen, regardless of orientation (and even when my app is not the active app)?
Maybe it's related to the fact that I attach my view to the Window Service's window manager — perhaps this means my view has an odd parent (I could imagine that maybe the root view would not be affected by orientation, or would have no defined boundaries for children to stretch to fill).
Full source code is public on GitHub in case I've omitted any useful information here.
WalkerView.java may be particularly relevant, so here it is.
I was misled by the answer to a previous question "How to create always-top fullscreen overlay activity in Android". Maybe it worked for an older API level? I'm using API level 24.
That particular answer had recommended:
final WindowManager.LayoutParams params = new WindowManager.LayoutParams(
WindowManager.LayoutParams.FLAG_FULLSCREEN,
WindowManager.LayoutParams.FLAG_FULLSCREEN,
WindowManager.LayoutParams.TYPE_SYSTEM_ALERT,
WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN,
PixelFormat.TRANSLUCENT
);
There is a problem with this. The constructors that exist for WindowManager.LayoutParams are as follows:
So the WindowManager.LayoutParams.FLAG_FULLSCREEN flag gets used as an explicit value for int w and int h. This is no good!
I found that the correct construction for a full-screen overlay is like so:
final WindowManager.LayoutParams params = new WindowManager.LayoutParams(
WindowManager.LayoutParams.TYPE_SYSTEM_OVERLAY, // TYPE_SYSTEM_ALERT is denied in apiLevel >=19
WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN | WindowManager.LayoutParams.FLAG_FULLSCREEN,
PixelFormat.TRANSLUCENT
);
This means we no longer explicitly specify a width and height. The layout relies entirely on our flags instead.
Yes, WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN is a required flag still; it is necessary if you want to draw over decorations such as the status bar.
WindowManager.LayoutParams.TYPE_SYSTEM_OVERLAY should be used instead of TYPE_SYSTEM_ALERT in API level >=19.
Bonus notes (if you're reading this, you're probably trying to make a full-screen overlay):
Your manifest will need the following permissions (explanation here):
<uses-permission android:name="android.permission.ACTION_MANAGE_OVERLAY_PERMISSION"/>
<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW"/>
My understanding is that SYSTEM_ALERT_WINDOW is the actual permission required, but that ACTION_MANAGE_OVERLAY_PERMISSION is needed also: it lets you request at runtime that the user grant the SYSTEM_ALERT_WINDOW privilege.
I think your situation can be solved with an alternative approach.
Create a Full Screen custom view (you can set the appropriate flag in the constructor of the custom view)
Override onSizeChanged() in the custom view. This will give you the Canvas height and width. This is optional. If you want to fill the whole custom view with a translucent color, this won't be necessary.
Use the width and height from above, or simply use canvas.drawColor() in the onDraw() of the custom view.
This will ensure that whenever the view is recreated, it will be redrawn to fill the whole screen(canvas).

Prevent user touches on part of an Android device screen while allowing them elsewhere

Basically what I'm trying to do is prevent users from interacting with part of the screen in Android by covering that area with a transparent View. Looking at other SO posts, I was able to come up with a solution that partially works. For example, to cover the left half of the screen I could do this:
Context mContext = getApplicationContext();
WindowManager mWindowManager = (WindowManager) mContext.getSystemService(Context.WINDOW_SERVICE);
Display display = mWindowManager.getDefaultDisplay();
Point size = new Point();
display.getSize(size);
int mScreenWidth = size.x;
int mScreenHeight = size.y;
View leftBox = new View(mContext);
WindowManager.LayoutParams leftBoxParams = new WindowManager.LayoutParams();
leftBoxParams.height = mScreenHeight;
leftBoxParams.width = mScreenWidth/2;
leftBoxParams.gravity = Gravity.LEFT;
leftBoxParams.type = WindowManager.LayoutParams.TYPE_SYSTEM_ALERT;
leftBoxParams.flags = WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE | WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN;
leftBoxParams.alpha = 0.0f;
leftBox.setBackgroundColor(Color.TRANSPARENT);
mWindowManager.addView(leftBox, leftBoxParams);
The above works correctly for most cases: If there is a button on the left side of the screen, the user can't touch it, and a button on the right is still accessible. However, in the case that the user touches the accessible button on the right while also touching anywhere on the left side of the screen, the button will never receive a click event. This means that if the user is resting his hand on the left half of the screen, the right side becomes basically unusable.
It's important to note that I'm creating the transparent View within an AsyncTask, and things underneath the overlay may be part of other applications, not just mine.
From the Android developer site, it seems like FLAG_NOT_TOUCH_MODAL would be what I'm looking for:
Window flag: even when this window is focusable (its FLAG_NOT_FOCUSABLE is not set), allow any pointer events outside of the window to be sent to the windows behind it.
However, neither this flag nor FLAG_NOT_FOCUSABLE fix the behavior I'm seeing. Any suggestion about why I'm seeing this behavior or how I might fix it is greatly appreciated.

Android 5+ screen locks can't add view with WindowManager

I've got an Identified call app which worked very good till android 5+.
Basically I've got a BroadcastReceiver which "do his thing" when phone rings after identifying the call I add a small view.
on a new galaxy edge s6 it doesn't work when the phone is locked.
here is my related code
wm = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
final WindowManager.LayoutParams params = new WindowManager.LayoutParams(
WindowManager.LayoutParams.WRAP_CONTENT,
WindowManager.LayoutParams.WRAP_CONTENT,
WindowManager.LayoutParams.TYPE_SYSTEM_ALERT, // TYPE_PHONE
WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE,
PixelFormat.TRANSLUCENT);
params.gravity = Gravity.CENTER;
wm.addView(app.PhoneLayout, params);
app.PhoneLayout contains the layout after inflating etc..
Does anyone have any idea why such thing happen? and how am I able to fix that so that my view will be shown even when the phone is locked?
It's working fine on older devices.
Hope someone can share his thoughts on this

Using windowManager parameters to have keyboard

I am using these parameters to show an image on the screen. (this is running on a service cause of that i am using windowmanager instead of usual way- the image comes and goes continuesly)
WindowManager.LayoutParams params = new WindowManager.LayoutParams(
WindowManager.LayoutParams.MATCH_PARENT,
WindowManager.LayoutParams.MATCH_PARENT,
WindowManager.LayoutParams.TYPE_PHONE,
WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE,
PixelFormat.TRANSLUCENT
);
The Point is when I use FLAG_NOT_TOUCHABLE it allows user's touch go through the Picture, Which is fine and it is what I want. but when there is a need for text entry the keyboard keeps disappering (I want it to be there so I am able to input text even though the Picture is overlapping). this works for buttons and other input but the the keybord vanishes. How can I keep both?
changing WindowManager.LayoutParams.TYPE_PHONE to WindowManager.LayoutParams.TYPE_SYSTEM_OVERLAY solved the problem.

Weird behaviour with updateViewLayout in Android Jelly Bean service

I have started working on an app that uses an overlay service to display a utility sidebar on the phone.
What I did was to add a small arrow handle to the right side of the screen, and when the user swipes over it, the sidebar shows up.
This worked without issue up to Jelly Bean. Starting with JB, the entire process of showing the sidebar started to become animated. Which would be very cool, if it were not animating all over the place.
What I did to show and hide the sidebar was a simple updateViewLayout command as below.
WindowManager.LayoutParams params = new WindowManager.LayoutParams(
handlesize, WindowManager.LayoutParams.WRAP_CONTENT,
WindowManager.LayoutParams.TYPE_SYSTEM_ALERT,
WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
| WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL,
PixelFormat.TRANSLUCENT);
params.gravity = Gravity.RIGHT|Gravity.CENTER_VERTICAL;
wm.updateViewLayout(mOverlay, params);
handleButton.setImageResource(R.drawable.handle);
isCompact=true;
This piece of code hides the sidebar. The handlesize variable is the width of the handle. The wm variable is the window manager. So basically, what I do is only show the width of the handle, so anything else that might be next to the handle(the sidebar is not visible). I also use WRAP_CONTENT for the height, to make sure the only part that absorbs touch events is the area used by the handle, so as to not block off the entire right hand side of the screen from registering touches.
WindowManager.LayoutParams params = new WindowManager.LayoutParams(
WindowManager.LayoutParams.WRAP_CONTENT,
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.RIGHT|Gravity.CENTER_VERTICAL;
wm.updateViewLayout(mOverlay, params);
handleButton.setImageResource(R.drawable.handle_back);
isCompact=false;
This is the code that displays the sidebar. The width of the whole view is set to WRAP_CONTENT, so it shows all the content, and the height is set to MATCH_PARENT, because the sidebar is full height when it's visible.
Now normally, this code should instantly switch between one width and height set to the other width and height set, nothing in between. But since Jelly Bean, this has started doing this through some weird animation. I'm not sure, but it may have something to do with Project Butter.
In the link below, you can see some frames of the animation.
http://i.stack.imgur.com/QzZGO.png
If I set the height of the view, even when closed, to MATCH_PARENT, then the animation is just on the horizontal plane, so right to left, which does look nice. The problem with that is I don't want to block the entire right hand side of the screen. There are a lot of uses for sliding from the right in other apps that might run under the service, like switching tabs in Chrome.
So my question is, do you have any idea what I should do to stop this behavior, or, even better, to use it to my advantage in order to make the sidebar do some smooth animations, but in a way that works on Android 2.2 and above?
Thanks a lot!
Since JB Android has added window animations to layout changes. If you disable window animation in Developer settings, the behavior will stop. Also, you cannot disable/enable this programmatically (requires system permission if I remember correctly), so the solution is to remove the view completely and attach it again. Instead of wm.updateViewLayout(view,params) you have to wm.removeView(view) and then wm.addView(view,params).

Categories

Resources